[
  {
    "path": ".github/workflows/ccpp.yml",
    "content": "name: C/C++ CI\n\non: [push]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - path: ./BaseService/build\n      run: ./cmake ../code\n    - name: make\n      run: make\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "# BaseService\n微信小游戏服务器，房间及卡牌类游戏服务器。支持websocket及tcp连接，lua编写游戏逻辑，运行于C++服务器，跨平台。C++底层已支持多款线上产品。\n\n使用lua编写游戏逻辑，不需要编写C++代码。函数支持不停机热更新。\n\n# 依赖库\n\nhttps://gitee.com/li9chuan/ExternalLib\n\n# Wiki\n\nhttps://gitee.com/li9chuan/EQipaiServer/wikis\n\n# QQ： 9703021\n\n"
  },
  {
    "path": "code/CMakeLists.txt",
    "content": "#-----------------------------------------------------------------------------\n#\n# NeL\n#  Authors: Nevrax and the NeL Community\n#  Version: 0.8.0\n#\n# Notes:\n#   * Changing install location: add -DCMAKE_INSTALL_PREFIX:PATH=/my/new/path\n#   * Changing specific install location variables:\n#       * NL_ETC_PREFIX (default: $CMAKE_INSTALL_PREFIX/etc)\n#       * NL_SHARE_PREFIX (default: $CMAKE_INSTALL_PREFIX/share)\n#       * NL_BIN_PREFIX (default: $CMAKE_INSTALL_PREFIX/bin)\n#       * NL_SBIN_PREFIX  (default: $CMAKE_INSTALL_PREFIX/sbin)\n#       * NL_LIB_PREFIX  (default: $CMAKE_INSTALL_PREFIX/lib)\n#       * NL_DRIVER_PREFIX  (default: $CMAKE_INSTALL_PREFIX/lib (windows) or $CMAKE_INSTALL_PREFIX/lib/nel)\n#   * Enable building of documentation: add -DBUILD_DOCUMENTATION:BOOL=ON - new make target: DoxygenDoc\n#   * Updating version: update header (above) but also update NL_VERSION below.\n#   * To build binary archive, use the 'package' target.\n#     To build source archive, use the 'package_source' target.\n\n#-----------------------------------------------------------------------------\n# Load some macros.\nSET(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules;${CMAKE_MODULE_PATH}\")\n#-----------------------------------------------------------------------------\n# Set CMake 2.6 Policies.\nIF(COMMAND cmake_policy)\n  # Works around warnings libraries linked against that don't\n  # have absolute paths (e.g. -lpthread)\n  cmake_policy(SET CMP0003 NEW)\n\n  # Works around warnings about escaped quotes in ADD_DEFINITIONS\n  # statements\n  cmake_policy(SET CMP0005 OLD)\nENDIF(COMMAND cmake_policy)\n\nINCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/nel.cmake)\nINCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/ConfigureChecks.cmake)\nINCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/CheckDepends.cmake)\nINCLUDE(${CMAKE_ROOT}/Modules/Documentation.cmake OPTIONAL)\n\n# Force out of source builds.\nCHECK_OUT_OF_SOURCE()\n\nCMAKE_MINIMUM_REQUIRED(VERSION 2.6)\nPROJECT(BaseService CXX C)\nSET(NL_VERSION_MAJOR 0)\nSET(NL_VERSION_MINOR 8)\nSET(NL_VERSION_PATCH 0)\nSET(NL_VERSION \"${NL_VERSION_MAJOR}.${NL_VERSION_MINOR}.${NL_VERSION_PATCH}\")\n\n#-----------------------------------------------------------------------------\n# Redirect output files\nSET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\nSET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\n\n# DLL should be in the same directory as EXE under Windows\nIF(WIN32)\n  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\nELSE(WIN32)\n  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)\nENDIF(WIN32)\n\nIF(WIN32)\n  IF(WITH_MFC)\n    FIND_PACKAGE(MFC QUIET)\n  ENDIF(WITH_MFC)\n\n  IF(NOT DEFINED ENV{QTDIR})\n    SET(ENV{QTDIR} \"c:/qt/4.6.3\")\n  ENDIF(NOT DEFINED ENV{QTDIR})\nENDIF(WIN32)\n\n# set platfrom defind\nIF(${CMAKE_SYSTEM_NAME} MATCHES \"FreeBSD\")\n  SET(FreeBSD ON)\nENDIF(${CMAKE_SYSTEM_NAME} MATCHES \"FreeBSD\")\n\n#-----------------------------------------------------------------------------\n# Set default config options\n#\n\nNL_SETUP_DEFAULT_OPTIONS()\nNL_SETUP_NEL_DEFAULT_OPTIONS()\nNL_SETUP_NELNS_DEFAULT_OPTIONS()\n\nNL_SETUP_PREFIX_PATHS()\nEVA_SETUP_PREFIX_PATHS()\n\nNL_CONFIGURE_CHECKS()\n\nNL_SETUP_BUILD()\nNL_SETUP_BUILD_FLAGS()\n\n#-----------------------------------------------------------------------------\n#Platform specifics\n\nSETUP_EXTERNAL()\nNL_GEN_REVISION_H()\n\nIF(WIN32)\n  SET(WINSOCK2_LIB ws2_32.lib)\n  SET(WINLDAP_LIB  wldap32.lib)\n\n  IF(WITH_MFC)\n    FIND_PACKAGE(CustomMFC REQUIRED)\n  ENDIF(WITH_MFC)\nENDIF(WIN32)\n\n\nFIND_PACKAGE(Threads REQUIRED)\nFIND_PACKAGE(LibXml2 REQUIRED)\nFIND_PACKAGE(ProtoBuf REQUIRED)\nFIND_PACKAGE(Lua53 REQUIRED)\n#FIND_PACKAGE(PBC REQUIRED)\nFIND_PACKAGE(LibEvent REQUIRED)\n\nFIND_PACKAGE(OpenSSL REQUIRED)\n#SET(OPENSSL_USE_STATIC_LIBS TRUE)   # openssl使用静态库\nFIND_PACKAGE(ZLIB REQUIRED)\n\nADD_DEFINITIONS(-DLUA_COMPAT_MODULE)    # for lua_bind\n\n#FIND_PACKAGE(TinyXml REQUIRED)\n#FIND_PACKAGE(PNG REQUIRED)\n#FIND_PACKAGE(Jpeg)\n\nIF(WITH_STATIC)\n  # libxml2 could need winsock2 library\n  SET(LIBXML2_DEFINITIONS ${LIBXML2_DEFINITIONS} -DLIBXML_STATIC)\n  SET(LIBXML2_LIBRARIES ${LIBXML2_LIBRARIES} ${WINSOCK2_LIB} ${WINLDAP_LIB})\n\n  # on Mac OS X libxml2 requieres iconv\n  IF(FREEBSD OR APPLE)\n    FIND_PACKAGE(Iconv REQUIRED)\n    SET(LIBXML2_LIBRARIES ${LIBXML2_LIBRARIES} ${ICONV_LIBRARIES})\n    INCLUDE_DIRECTORIES(${ICONV_INCLUDE_DIR})\n    MESSAGE(STATUS \"ICONV: ${ICONV_INCLUDE_DIR} ${ICONV_LIBRARIES}\")\n  ENDIF(FREEBSD OR APPLE)\nENDIF(WITH_STATIC)\n\nINCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/PCHSupport.cmake)\n\nIF(FINAL_VERSION)\n  ADD_DEFINITIONS(-DFINAL_VERSION=1)\nENDIF(FINAL_VERSION)\n\nADD_DEFINITIONS(-DNL_MAP_ASSERT)\n\nIF(WITH_SSE2)\n  ADD_DEFINITIONS(-DNL_HAS_SSE2)\n  IF(WITH_SSE3)\n    ADD_DEFINITIONS(-DNL_HAS_SSE3)\n  ENDIF(WITH_SSE3)\nENDIF(WITH_SSE2)\n\nIF(WITH_EVA)\n  ADD_DEFINITIONS(-DEVA)\nENDIF(WITH_EVA)\n\nIF(WITH_NEL)\n  IF(WITH_NEL_TESTS)\n    FIND_PACKAGE(CppTest)\n  ENDIF(WITH_NEL_TESTS)\n\n  INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/nel/include ${LIBXML2_INCLUDE_DIR})\n  ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n  ADD_SUBDIRECTORY(nel)\nENDIF(WITH_NEL)\n\nIF(WITH_NELNS)\n  ADD_SUBDIRECTORY(nelns)\nENDIF(WITH_NELNS)\n\nIF(WITH_EVA)\n  ADD_SUBDIRECTORY(EVA)\nENDIF(WITH_EVA)\n\n# To build the documention, you will have to enable it\n# and then do the equivalent of \"make DoxygenDoc\".\nIF(BUILD_DOCUMENTATION)\n    IF(DOT)\n        SET(HAVE_DOT YES)\n    ELSE(DOT)\n        SET(HAVE_DOT NO)\n    ENDIF(DOT)\n    # This processes our Doxyfile.in and substitutes paths to generate\n    # a final Doxyfile\n    CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/doc/Doxyfile.cmake.in ${CMAKE_BINARY_DIR}/doc/Doxyfile)\n\n    ADD_CUSTOM_TARGET(DoxygenDoc ${DOXYGEN} ${CMAKE_BINARY_DIR}/doc/Doxyfile)\nENDIF(BUILD_DOCUMENTATION)\n\nIF(WITH_NEL_TESTS)\n  ENABLE_TESTING()\n  ADD_TEST(nel_unit_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/nel_unit_test --html)\n  IF(BUILD_DASHBOARD)\n    INCLUDE(Dart)\n    SET(SVNCOMMAND svn)\n    SET(SVNSOURCEDIR http://dev.ryzom.com/svn/trunk/nel)\n    SET(GENERATELOGS svn2cl)\n  ENDIF(BUILD_DASHBOARD)\nENDIF(WITH_NEL_TESTS)\n\n# packaging information\nSET(CPACK_PACKAGE_DESCRIPTION_SUMMARY \"NeL MMORPG Framework\")\nSET(CPACK_PACKAGE_VENDOR \"NeL\")\nSET(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_SOURCE_DIR}/README)\nSET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/COPYING)\nSET(CPACK_PACKAGE_VERSION_MAJOR \"${NL_VERSION_MAJOR}\")\nSET(CPACK_PACKAGE_VERSION_MINOR \"${NL_VERSION_MINOR}\")\nSET(CPACK_PACKAGE_VERSION_PATCH \"${NL_VERSION_PATCH}\")\nSET(CPACK_INSTALL_CMAKE_PROJECTS \"${CMAKE_BINARY_DIR};NeL;ALL;/\")\nSET(CPACK_PACKAGE_EXECUTABLES \"nel${NL_VERSION}\" \"nel\")\n\n# NSIS Specific Packing Setup\nSET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY \"NeL\")\nSET(CPACK_NSIS_MODIFY_PATH \"ON\")\nSET(CPACK_NSIS_MUI_ICON ${CMAKE_SOURCE_DIR}/resources/nevraxpill.ico)\nSET(CPACK_NSIS_MUI_UNIICON ${CMAKE_SOURCE_DIR}/resources/nevraxpill.ico)\nSET(CPACK_PACKAGE_ICON ${CMAKE_SOURCE_DIR}/resources\\\\\\\\nel.bmp)\nSET(CPACK_NSIS_DISPLAY_NAME \"${CPACK_PACKAGE_INSTALL_DIRECTORY} NeL\")\nSET(CPACK_NSIS_HELP_LINK \"http:\\\\\\\\\\\\\\\\dev.ryzom.com\")\nSET(CPACK_NSIS_URL_INFO_ABOUT \"http:\\\\\\\\\\\\\\\\dev.ryzom.com\\\\\\\\projects\\\\\\\\nel\\\\\\\\wiki\")\nSET(CPACK_NSIS_CONTACT \"matt.raykowski@gmail.com\")\n\n## Source Packages\nSET(CPACK_PACKAGE_FILE_NAME \"nel-${NL_VERSION}\")\nSET(CPACK_SOURCE_PACKAGE_FILE_NAME \"nel-${NL_VERSION}\")\nIF(WIN32)\n  #SET(CPACK_GENERATOR \"NSIS\")\n  SET(CPACK_GENERATOR \"NSIS;ZIP\")\n  SET(CPACK_SOURCE_GENERATOR \"ZIP\")\nELSE(WIN32)\n  SET(CPACK_GENERATOR \"TGZ\")\n  SET(CPACK_SOURCE_GENERATOR \"TGZ\")\nENDIF(WIN32)\nset(CPACK_SOURCE_IGNORE_FILES\n\t\"~$\"\n\t\"\\\\\\\\.cvsignore$\"\n\t\"^${CMAKE_SOURCE_DIR}.*/CVS/\"\n\t\"^${CMAKE_SOURCE_DIR}.*/\\\\\\\\.svn/\"\n\t\"^${CMAKE_SOURCE_DIR}/debian/\"\n\t\"^${CMAKE_SOURCE_DIR}/old/\")\nIF(WIN32)\n  IF(NOT CMAKE_BUILD_TYPE STREQUAL \"Release\")\n    SET(CMAKE_INSTALL_DEBUG_LIBRARIES TRUE)\n  ELSE(NOT CMAKE_BUILD_TYPE STREQUAL \"Release\")\n  ENDIF(NOT CMAKE_BUILD_TYPE STREQUAL \"Release\")\n\n  # Only the tools require MFC.\n  IF(WITH_TOOLS)\n    SET(CMAKE_INSTALL_MFC_LIBRARIES TRUE)\n  ENDIF(WITH_TOOLS)\n  INCLUDE(InstallRequiredSystemLibraries)\nENDIF(WIN32)\n\nINCLUDE(CPack)\n\nINCLUDE(CMakePackaging.txt)\n\n## Debian Packages\n#INCLUDE(UseDebian)\n#IF(DEBIAN_FOUND)\n#  ADD_DEBIAN_TARGETS(nel)\n#ENDIF(DEBIAN_FOUND)\n"
  },
  {
    "path": "code/CMakeModules/AndroidToolChain.cmake",
    "content": "IF(DEFINED CMAKE_CROSSCOMPILING)\n  # subsequent toolchain loading is not really needed\n  RETURN()\nENDIF()\n\n# Standard settings\nSET(CMAKE_SYSTEM_NAME Linux)\nSET(CMAKE_SYSTEM_VERSION 1) # TODO: determine target Linux version\nSET(UNIX ON)\nSET(LINUX ON)\nSET(ANDROID ON)\n\nIF(NOT NDK_ROOT)\n  SET(NDK_ROOT $ENV{NDK_ROOT})\n\n  IF(CMAKE_HOST_WIN32)\n    FILE(TO_CMAKE_PATH ${NDK_ROOT} NDK_ROOT)\n  ENDIF(CMAKE_HOST_WIN32)\nENDIF(NOT NDK_ROOT)\n\nIF(NOT TARGET_CPU)\n  SET(TARGET_CPU \"armv7\")\nENDIF(NOT TARGET_CPU)\n\nIF(TARGET_CPU STREQUAL \"armv7\")\n  SET(LIBRARY_ARCHITECTURE \"armeabi-v7a\")\n  SET(CMAKE_SYSTEM_PROCESSOR \"armv7\")\n  SET(TOOLCHAIN_ARCH \"arm\")\n  SET(GCC_TOOLCHAIN_PREFIX \"arm-linux-androideabi\")\n  SET(TOOLCHAIN_BIN_PREFIX \"arm\")\n  SET(MINIMUM_NDK_TARGET 4)\nELSEIF(TARGET_CPU STREQUAL \"armv5\")\n  SET(LIBRARY_ARCHITECTURE \"armeabi\")\n  SET(CMAKE_SYSTEM_PROCESSOR \"armv5\")\n  SET(TOOLCHAIN_ARCH \"arm\")\n  SET(GCC_TOOLCHAIN_PREFIX \"arm-linux-androideabi\")\n  SET(TOOLCHAIN_BIN_PREFIX \"arm\")\n  SET(MINIMUM_NDK_TARGET 4)\nELSEIF(TARGET_CPU STREQUAL \"x86\")\n  SET(LIBRARY_ARCHITECTURE \"x86\")\n  SET(CMAKE_SYSTEM_PROCESSOR \"x86\")\n  SET(TOOLCHAIN_ARCH \"x86\")\n  SET(GCC_TOOLCHAIN_PREFIX \"x86\")\n  SET(TOOLCHAIN_BIN_PREFIX \"i686\")\n  SET(MINIMUM_NDK_TARGET 9)\nELSEIF(TARGET_CPU STREQUAL \"mips\")\n  SET(LIBRARY_ARCHITECTURE \"mips\")\n  SET(CMAKE_SYSTEM_PROCESSOR \"mips\")\n  SET(TOOLCHAIN_ARCH \"mips\")\n  SET(GCC_TOOLCHAIN_PREFIX \"mipsel-linux-android\")\n  SET(TOOLCHAIN_BIN_PREFIX \"mipsel\")\n  SET(MINIMUM_NDK_TARGET 9)\nENDIF(TARGET_CPU STREQUAL \"armv7\")\n\nSET(ANDROID_COMPILER \"GCC\")\n\nIF(NDK_TOOLCHAIN_VERSION STREQUAL \"clang\")\n  SET(ANDROID_COMPILER \"clang\")\n  SET(CLANG_TOOLCHAIN_PREFIX \"llvm\")\n  SET(CLANG ON)\nELSE()\n  SET(GCC_TOOLCHAIN_VERSION ${NDK_TOOLCHAIN_VERSION})\nENDIF()\n\nIF(NOT NDK_TARGET)\n  SET(NDK_TARGET ${MINIMUM_NDK_TARGET})\nENDIF(NOT NDK_TARGET)\n\nIF(CMAKE_HOST_WIN32)\n  SET(TOOLCHAIN_HOST \"windows\")\n  SET(TOOLCHAIN_BIN_SUFFIX \".exe\")\nELSEIF(CMAKE_HOST_APPLE)\n  SET(TOOLCHAIN_HOST \"apple\")\n  SET(TOOLCHAIN_BIN_SUFFIX \"\")\nELSEIF(CMAKE_HOST_UNIX)\n  SET(TOOLCHAIN_HOST \"linux\")\n  SET(TOOLCHAIN_BIN_SUFFIX \"\")\nENDIF(CMAKE_HOST_WIN32)\n\nMACRO(SEARCH_TOOLCHAIN _COMPILER)\n  SET(${_COMPILER}_TOOLCHAIN_VERSIONS)\n  FILE(GLOB _TOOLCHAIN_VERSIONS \"${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-*\")\n  IF(_TOOLCHAIN_VERSIONS)\n    LIST(SORT _TOOLCHAIN_VERSIONS)\n    LIST(REVERSE _TOOLCHAIN_VERSIONS)\n    FOREACH(_TOOLCHAIN_VERSION ${_TOOLCHAIN_VERSIONS})\n      STRING(REGEX REPLACE \".+${_PREFIX}-([0-9.]+)\" \"\\\\1\" _TOOLCHAIN_VERSION \"${_TOOLCHAIN_VERSION}\")\n      IF(_TOOLCHAIN_VERSION MATCHES \"^([0-9.]+)$\")\n        LIST(APPEND ${_COMPILER}_TOOLCHAIN_VERSIONS ${_TOOLCHAIN_VERSION})\n      ENDIF()\n    ENDFOREACH()\n  ENDIF()\n\n  IF(NOT ${_COMPILER}_TOOLCHAIN_VERSIONS)\n    MESSAGE(FATAL_ERROR \"No Android ${_COMPILER} toolchain found in default search path ${NDK_ROOT}/toolchains\")\n  ENDIF()\n\n  IF(${_COMPILER}_TOOLCHAIN_VERSIONS)\n    LIST(FIND ${_COMPILER}_TOOLCHAIN_VERSIONS \"${${_COMPILER}_TOOLCHAIN_VERSION}\" _INDEX)\n    IF(_INDEX EQUAL -1)\n      LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION)\n    ENDIF()\n  ELSE()\n    LIST(GET ${_COMPILER}_TOOLCHAIN_VERSIONS 0 ${_COMPILER}_TOOLCHAIN_VERSION)\n  ENDIF()\n\n  SET(${_COMPILER}_TOOLCHAIN_ROOT \"${NDK_ROOT}/toolchains/${${_COMPILER}_TOOLCHAIN_PREFIX}-${${_COMPILER}_TOOLCHAIN_VERSION}/prebuilt/${TOOLCHAIN_HOST}\")\n\n  IF(NOT EXISTS \"${${_COMPILER}_TOOLCHAIN_ROOT}\")\n    FILE(GLOB _TOOLCHAIN_PREFIXES \"${${_COMPILER}_TOOLCHAIN_ROOT}*\")\n    IF(_TOOLCHAIN_PREFIXES)\n      LIST(GET _TOOLCHAIN_PREFIXES 0 ${_COMPILER}_TOOLCHAIN_ROOT)\n    ENDIF(_TOOLCHAIN_PREFIXES)\n  ENDIF()\nENDMACRO()\n\nIF(CLANG)\n  SEARCH_TOOLCHAIN(CLANG)\n\n  MESSAGE(STATUS \"Target Android NDK ${NDK_TARGET} and use clang ${CLANG_TOOLCHAIN_VERSION}\")\nENDIF()\n\nSEARCH_TOOLCHAIN(GCC)\n\nMESSAGE(STATUS \"Target Android NDK ${NDK_TARGET} and use GCC ${GCC_TOOLCHAIN_VERSION}\")\nMESSAGE(STATUS \"Found Android LLVM toolchain in ${CLANG_TOOLCHAIN_ROOT}\")\nMESSAGE(STATUS \"Found Android GCC toolchain in ${GCC_TOOLCHAIN_ROOT}\")\n\nSET(PLATFORM_ROOT \"${NDK_ROOT}/platforms/android-${NDK_TARGET}/arch-${TOOLCHAIN_ARCH}\")\n\nMESSAGE(STATUS \"Found Android platform in ${PLATFORM_ROOT}\")\n\n# include dirs\nSET(PLATFORM_INCLUDE_DIR \"${PLATFORM_ROOT}/usr/include\")\nSET(STL_DIR \"${NDK_ROOT}/sources/cxx-stl/gnu-libstdc++\")\n\nIF(EXISTS \"${STL_DIR}/${GCC_TOOLCHAIN_VERSION}\")\n  # NDK version >= 8b\n  SET(STL_DIR \"${STL_DIR}/${GCC_TOOLCHAIN_VERSION}\")\nENDIF(EXISTS \"${STL_DIR}/${GCC_TOOLCHAIN_VERSION}\")\n\n# Determine bin prefix for toolchain\nFILE(GLOB _TOOLCHAIN_BIN_PREFIXES \"${GCC_TOOLCHAIN_ROOT}/bin/${TOOLCHAIN_BIN_PREFIX}-*-gcc${TOOLCHAIN_BIN_SUFFIX}\")\nIF(_TOOLCHAIN_BIN_PREFIXES)\n  LIST(GET _TOOLCHAIN_BIN_PREFIXES 0 _TOOLCHAIN_BIN_PREFIX)\n  STRING(REGEX REPLACE \"${GCC_TOOLCHAIN_ROOT}/bin/([a-z0-9-]+)-gcc${TOOLCHAIN_BIN_SUFFIX}\" \"\\\\1\" TOOLCHAIN_BIN_PREFIX \"${_TOOLCHAIN_BIN_PREFIX}\")\nENDIF(_TOOLCHAIN_BIN_PREFIXES)\n\nSET(STL_INCLUDE_DIR \"${STL_DIR}/include\")\nSET(STL_LIBRARY_DIR \"${STL_DIR}/libs/${LIBRARY_ARCHITECTURE}\")\nSET(STL_INCLUDE_CPU_DIR \"${STL_LIBRARY_DIR}/include\")\nSET(STL_LIBRARY \"${STL_LIBRARY_DIR}/libgnustl_static.a\")\n\nMESSAGE(STATUS \"STL include dir: ${STL_INCLUDE_DIR}\")\nMESSAGE(STATUS \"STL library dir: ${STL_LIBRARY_DIR}\")\n\nSET(CMAKE_FIND_ROOT_PATH ${CLANG_TOOLCHAIN_ROOT} ${GCC_TOOLCHAIN_ROOT} ${PLATFORM_ROOT}/usr ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX} $ENV{EXTERNAL_ANDROID_PATH} CACHE string  \"Android find search path root\")\n\nSET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)\nSET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nSET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n\nMACRO(SET_TOOLCHAIN_BINARY _NAME _BINARY)\n  IF(\"${_BINARY}\" MATCHES \"clang\")\n    SET(${_NAME} ${CLANG_TOOLCHAIN_ROOT}/bin/${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH \"\" FORCE )\n  ELSE()\n    SET(${_NAME} ${GCC_TOOLCHAIN_ROOT}/bin/${TOOLCHAIN_BIN_PREFIX}-${_BINARY}${TOOLCHAIN_BIN_SUFFIX} CACHE PATH \"\" FORCE)\n  ENDIF()\nENDMACRO(SET_TOOLCHAIN_BINARY)\n\n# Force the compilers to GCC for Android\ninclude (CMakeForceCompiler)\n\nIF(CLANG)\n  SET_TOOLCHAIN_BINARY(CMAKE_C_COMPILER clang)\n  SET_TOOLCHAIN_BINARY(CMAKE_CXX_COMPILER clang++)\n\n  CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} clang)\n  CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} clang)\n\n  MESSAGE(STATUS \"Using clang compiler\")\nELSE()\n  SET_TOOLCHAIN_BINARY(CMAKE_C_COMPILER gcc)\n  SET_TOOLCHAIN_BINARY(CMAKE_CXX_COMPILER g++)\n\n  CMAKE_FORCE_C_COMPILER(${CMAKE_C_COMPILER} GNU)\n  CMAKE_FORCE_CXX_COMPILER(${CMAKE_CXX_COMPILER} GNU)\n\n  MESSAGE(STATUS \"Using GCC compiler\")\nENDIF()\n\nSET_TOOLCHAIN_BINARY(CMAKE_STRIP strip)\nSET_TOOLCHAIN_BINARY(CMAKE_AR ar)\nSET_TOOLCHAIN_BINARY(CMAKE_LINKER ld)\nSET_TOOLCHAIN_BINARY(CMAKE_NM nm)\nSET_TOOLCHAIN_BINARY(CMAKE_OBJCOPY objcopy)\nSET_TOOLCHAIN_BINARY(CMAKE_OBJDUMP objdump)\nSET_TOOLCHAIN_BINARY(CMAKE_RANLIB ranlib)\n"
  },
  {
    "path": "code/CMakeModules/CheckDepends.cmake",
    "content": "# Macros to check if a library needs to be manually linked to another one\n# because it's using a symbol from it but it's not linked to\n\n# CHECK_UNDEFINED_SYMBOL\n# Macro to check if a library is calling an undefined symbol\n#\n# Syntax:\n# CHECK_UNDEFINED_SYMBOL(MYLIBRARY SYMBOL SYMBOL_FOUND)\n# SYMBOL_FOUND will be set to TRUE if UNDEFINED\n#\n# Example:\n# CHECK_UNDEFINED_SYMBOL(PNG_LIBRARY inflate INFLATE_FOUND)\n#\nMACRO(CHECK_UNDEFINED_SYMBOL MYLIBRARY SYMBOL SYMBOL_FOUND)\n  SET(${SYMBOL_FOUND} TRUE)\n  IF(WIN32)\n    # Always TRUE under Windows because we are using static libraries\n  ELSEIF(APPLE)\n    SET(CMAKE_NM nm)\n    IF(CMAKE_NM)\n      # Use nm to check if a library is using an external symbol\n      EXEC_PROGRAM(${CMAKE_NM} ARGS \"-gu ${${MYLIBRARY}} | grep ${SYMBOL}\" OUTPUT_VARIABLE NM_SYMBOL)\n#      MESSAGE(STATUS \"Checking for undefined symbol ${SYMBOL} in ${${MYLIBRARY}}\")\n      IF(NOT NM_SYMBOL MATCHES ${SYMBOL})\n        SET(${SYMBOL_FOUND} FALSE)\n#        MESSAGE(STATUS \"Defined symbol ${SYMBOL} detected in ${${MYLIBRARY}}\")\n      ENDIF(NOT NM_SYMBOL MATCHES ${SYMBOL})\n    ENDIF(CMAKE_NM)\n  ELSEIF(UNIX)\n    SET(CMAKE_OBJDUMP objdump)\n    IF(CMAKE_OBJDUMP)\n      # Use objdump to check if a library is using an external symbol\n      #MESSAGE(STATUS \"exec ${CMAKE_OBJDUMP} -T ${${MYLIBRARY}} | grep ${SYMBOL}\")\n      EXEC_PROGRAM(${CMAKE_OBJDUMP} ARGS \"-T ${${MYLIBRARY}} | grep ${SYMBOL}\" OUTPUT_VARIABLE OBJDUMP_SYMBOL)\n      IF(NOT OBJDUMP_SYMBOL MATCHES \"UND\")\n        #MESSAGE(STATUS \"${${MYLIBRARY}} does not use symbol ${SYMBOL}\")\n        SET(${SYMBOL_FOUND} FALSE)\n      ELSE(NOT OBJDUMP_SYMBOL MATCHES \"UND\")\n        #MESSAGE(STATUS \"${${MYLIBRARY}} uses symbol ${SYMBOL}\")\n      ENDIF(NOT OBJDUMP_SYMBOL MATCHES \"UND\")\n    ENDIF(CMAKE_OBJDUMP)\n  ENDIF(WIN32)\nENDMACRO(CHECK_UNDEFINED_SYMBOL)\n\n# CHECK_LINKED_LIBRARY\n# Macro to check if a library is linked to another one\n#\n# Syntax:\n# CHECK_LINKED_LIBRARY(MYLIBRARY OTHERLIBRARY LIBRARY_FOUND)\n# LIBRARY_FOUND will be set to TRUE if LINKED\n#\n# Example:\n# CHECK_LINKED_LIBRARY(PNG_LIBRARY ZLIB_LIBRARY ZLIB_FOUND)\n#\nMACRO(CHECK_LINKED_LIBRARY MYLIBRARY OTHERLIBRARY LIBRARY_FOUND)\n  SET(${LIBRARY_FOUND} FALSE)\n  IF(WIN32)\n    # Always FALSE under Windows because we are using static libraries\n  ELSEIF(APPLE)\n    SET(CMAKE_OTOOL otool)\n    IF(CMAKE_OTOOL)\n      # Use otool to check if a library is linked to another library\n      GET_FILENAME_COMPONENT(LIBNAME \"${${OTHERLIBRARY}}\" NAME_WE)\n      EXEC_PROGRAM(${CMAKE_OTOOL} ARGS \"-L ${${MYLIBRARY}} | grep ${LIBNAME}\" OUTPUT_VARIABLE OTOOL_LIBRARY)\n#      MESSAGE(STATUS \"Checking if ${LIBNAME} is linked to ${${MYLIBRARY}}\")\n      IF(OTOOL_LIBRARY MATCHES \"${LIBNAME}\")\n        SET(${LIBRARY_FOUND} TRUE)\n#        MESSAGE(STATUS \"Library ${LIBNAME} already linked to ${${MYLIBRARY}}\")\n      ENDIF(OTOOL_LIBRARY MATCHES \"${LIBNAME}\")\n    ENDIF(CMAKE_OTOOL)\n  ELSEIF(UNIX)\n    SET(CMAKE_OBJDUMP objdump)\n    IF(CMAKE_OBJDUMP)\n      GET_FILENAME_COMPONENT(LIBNAME \"${${OTHERLIBRARY}}\" NAME)\n      # TODO: under Solaris use dump -Lv <lib>\n      # Use objdump to check if a library is linked to another library\n      #MESSAGE(STATUS \"exec ${CMAKE_OBJDUMP} -p ${${MYLIBRARY}} | grep ${LIBNAME}\")\n      EXEC_PROGRAM(${CMAKE_OBJDUMP} ARGS \"-p ${${MYLIBRARY}} | grep ${LIBNAME}\" OUTPUT_VARIABLE OBJDUMP_LIBRARY)\n      IF(OBJDUMP_LIBRARY MATCHES \"NEEDED\")\n        #MESSAGE(STATUS \"${${MYLIBRARY}} references to ${LIBNAME}.\")\n        SET(${LIBRARY_FOUND} TRUE)\n      ELSE(OBJDUMP_LIBRARY MATCHES \"NEEDED\")\n        #MESSAGE(STATUS \"${${MYLIBRARY}} does not reference to ${LIBNAME}!\")\n      ENDIF(OBJDUMP_LIBRARY MATCHES \"NEEDED\")\n    ENDIF(CMAKE_OBJDUMP)\n  ENDIF(WIN32)\nENDMACRO(CHECK_LINKED_LIBRARY)\n\nMACRO(CHECK_DEPENDS MYLIBRARY OTHERLIBRARY SYMBOL MUSTLINK)\n  CHECK_UNDEFINED_SYMBOL(MYLIBRARY SYMBOL SYMBOL_FOUND)\n\n  IF(SYMBOL_FOUND)\n    CHECK_LINKED_LIBRARY(MYLIBRARY OTHERLIBRARY LIBRARY_FOUND)\n  ENDIF(SYMBOL_FOUND)\n\n  IF(SYMBOL_FOUND AND NOT LIBRARY_FOUND)\n    SET(${MUSTLINK} YES)\n  ELSE(SYMBOL_FOUND AND NOT LIBRARY_FOUND)\n    SET(${MUSTLINK} NO)\n  ENDIF(SYMBOL_FOUND AND NOT LIBRARY_FOUND)\nENDMACRO(CHECK_DEPENDS)\n\n# LINK_DEPENDS\n# Macro to link a library if a symbol is used but is not already linked to it\n#\n# Syntax:\n# LINK_DEPENDS(LIBRARIES MYLIBRARY OTHERLIBRARY SYMBOL)\n# OTHERLIBRARY_LINKED will be set to TRUE or FALSE\n#\n# Example:\n# LINK_DEPENDS(PNG_LIBRARIES PNG_LIBRARY ZLIB_LIBRARY inflate)\n#\nMACRO(LINK_DEPENDS LIBRARIES MYLIBRARY OTHERLIBRARY SYMBOL)\n  SET(MUST_LINK FALSE)\n  IF(${MYLIBRARY} AND ${OTHERLIBRARY} AND NOT ${OTHERLIBRARY}_LINKED)\n    IF(WIN32 OR WITH_STATIC)\n      # In static, we link all libraries because it will keep only used symbols\n      SET(MUST_LINK TRUE)\n    ELSE(WIN32 OR WITH_STATIC)\n      CHECK_UNDEFINED_SYMBOL(${MYLIBRARY} ${SYMBOL} SYMBOL_FOUND)\n\n      IF(SYMBOL_FOUND)\n        CHECK_LINKED_LIBRARY(${MYLIBRARY} ${OTHERLIBRARY} LIBRARY_FOUND)\n      ENDIF(SYMBOL_FOUND)\n\n      IF(SYMBOL_FOUND AND NOT LIBRARY_FOUND)\n        MESSAGE(STATUS \"Underlinking found: ${${MYLIBRARY}} needs ${${OTHERLIBRARY}} but is not linked to, manually linking...\")\n        SET(MUST_LINK TRUE)\n      ENDIF(SYMBOL_FOUND AND NOT LIBRARY_FOUND)\n    ENDIF(WIN32 OR WITH_STATIC)\n  ENDIF(${MYLIBRARY} AND ${OTHERLIBRARY} AND NOT ${OTHERLIBRARY}_LINKED)\n  IF(MUST_LINK)\n    MESSAGE(STATUS \"Linking with ${${OTHERLIBRARY}}\")\n    SET(${LIBRARIES} ${${LIBRARIES}} ${${OTHERLIBRARY}})\n    SET(${OTHERLIBRARY}_LINKED TRUE)\n  ENDIF(MUST_LINK)\nENDMACRO(LINK_DEPENDS)\n\n"
  },
  {
    "path": "code/CMakeModules/ConfigureChecks.cmake",
    "content": "MACRO(NL_CONFIGURE_CHECKS)\n  INCLUDE(CheckIncludeFiles)\n  INCLUDE(CheckFunctionExists)\n  INCLUDE(CheckLibraryExists)\n  INCLUDE(CheckTypeSize)\n  \n  CHECK_INCLUDE_FILES (\"execinfo.h\" HAVE_EXECINFO_H)\n  CHECK_INCLUDE_FILES (\"stdint.h\" HAVE_STDINT_H)\n  CHECK_INCLUDE_FILES (\"sys/types.h\" HAVE_SYS_TYPES_H)\n  CHECK_INCLUDE_FILES (\"inttypes.h\" HAVE_INTTYPES_H)\n  CHECK_INCLUDE_FILES (\"unistd.h\" HAVE_UNISTD_H)\n  CHECK_INCLUDE_FILES (\"utime.h\" HAVE_UTIME_H)\n  \n  CHECK_INCLUDE_FILES (\"dl.h\" HAVE_DL_H)\n  CHECK_INCLUDE_FILES (\"limits.h\" HAVE_LIMITS_H)\n  CHECK_INCLUDE_FILES (\"malloc.h\" HAVE_MALLOC_H)\n  CHECK_INCLUDE_FILES (\"sys/param.h\" HAVE_SYS_PARAM_H)\n  CHECK_INCLUDE_FILES (\"sys/param.h;sys/mount.h\" HAVE_SYS_MOUNT_H)\n  CHECK_INCLUDE_FILES (\"sys/statvfs.h\" HAVE_SYS_STATVFS_H)\n  \n  CHECK_INCLUDE_FILES (\"pthread.h\" HAVE_PTHREAD)\n  \n  CHECK_TYPE_SIZE(\"size_t\" SIZEOF_SIZE_T)\n  #if (NOT HAVE_SIZEOF_SIZE_T)\n  #  MESSAGE(FATAL_ERROR \"size_t is not present on this architecture - aborting\")\n  #endif (NOT HAVE_SIZEOF_SIZE_T)\n  MESSAGE(STATUS \"DEBUG size_t is ${SIZEOF_SIZE_T}\")\n  \n  CHECK_TYPE_SIZE(\"off_t\" SIZEOF_OFF_T)\n  MESSAGE(STATUS \"DEBUG off_t is ${SIZEOF_OFF_T}\")\n  \n  CHECK_FUNCTION_EXISTS(\"backtrace\" HAVE_BACKTRACE)\n  CHECK_FUNCTION_EXISTS(\"getsockname\" HAVE_GETSOCKNAME)\n  CHECK_FUNCTION_EXISTS(\"inet_ntoa\" HAVE_INET_NTOA)\n  CHECK_FUNCTION_EXISTS(\"inet_ntop\" HAVE_INET_NTOP)\n  CHECK_FUNCTION_EXISTS(\"inet_pton\" HAVE_INET_PTON)\n  CHECK_FUNCTION_EXISTS(\"regcomp\" HAVE_REGCOMP)\n  CHECK_FUNCTION_EXISTS(\"strerror\" HAVE_STRERROR)\n  CHECK_FUNCTION_EXISTS(\"strlcat\" HAVE_STRLCAT)\n  CHECK_FUNCTION_EXISTS(\"strptime\" HAVE_STRPTIME)\n  CHECK_FUNCTION_EXISTS(\"strtok_r\" HAVE_STRTOK_R)\n  CHECK_FUNCTION_EXISTS(\"strtoull\" HAVE_STRTOULL)\n  CHECK_FUNCTION_EXISTS(\"statvfs\" HAVE_STATVFS)\n  CHECK_FUNCTION_EXISTS(\"stat64\" HAVE_STAT64)\n\n  # 3D drivers\n  IF(WITH_DRIVER_OPENGL)\n    SET(NL_OPENGL_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_OPENGL)\n\n  IF(WITH_DRIVER_OPENGLES)\n    SET(NL_OPENGLES_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_OPENGLES)\n  \n  IF(WITH_DRIVER_DIRECT3D)\n    SET(NL_DIRECT3D_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_DIRECT3D)\n\n  # sound drivers\n  IF(WITH_DRIVER_FMOD)\n    SET(NL_FMOD_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_FMOD)\n\n  IF(WITH_DRIVER_OPENAL)\n    SET(NL_OPENAL_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_OPENAL)\n\n  IF(WITH_DRIVER_DSOUND)\n    SET(NL_DSOUND_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_DSOUND)\n\n  IF(WITH_DRIVER_XAUDIO2)\n    SET(NL_XAUDIO2_AVAILABLE 1)\n  ENDIF(WITH_DRIVER_XAUDIO2)\n\n  CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)\n  INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})\n  ADD_DEFINITIONS(-DHAVE_CONFIG_H)\nENDMACRO(NL_CONFIGURE_CHECKS)\n"
  },
  {
    "path": "code/CMakeModules/Find3dsMaxSDK.cmake",
    "content": "# - Find DirectInput\n# Find the DirectSound includes and libraries\n#\n#  MAXSDK_DIR         - 3DSMAX SDK root directory\n#  MAXSDK_INCLUDE_DIR - where to find baseinterface.h\n#  MAXSDK_LIBRARIES   - List of libraries when using 3DSMAX.\n#  MAXSDK_FOUND       - True if MAX SDK found.\n\nif(MAXSDK_INCLUDE_DIR)\n  # Already in cache, be silent\n  SET(MAXSDK_FIND_QUIETLY TRUE)\nendif(MAXSDK_INCLUDE_DIR)\n\nFIND_PATH(MAXSDK_DIR\n  \"include/maxversion.h\"\n  HINTS\n  \"$ENV{MAXSDK_DIR}\"\n  PATHS\n  \"$ENV{ADSK_3DSMAX_SDK_2012}/maxsdk\"\n  \"$ENV{3DSMAX_2011_SDK_PATH}/maxsdk\"\n  \"$ENV{PROGRAMFILES}/Autodesk/3ds Max 2010 SDK/maxsdk\"\n  \"$ENV{PROGRAMFILES}/Autodesk/3ds Max 2009 SDK/maxsdk\"\n  \"$ENV{PROGRAMFILES}/Autodesk/3ds Max 2008 SDK/maxsdk\"\n  \"$ENV{PROGRAMFILES}/Autodesk/3ds Max 9 SDK/maxsdk\"\n)\n\nFIND_PATH(MAXSDK_INCLUDE_DIR\n  max.h\n  HINTS\n  ${MAXSDK_DIR}/include\n)\n\nFIND_PATH(MAXSDK_CS_INCLUDE_DIR bipexp.h\n  HINTS\n  ${MAXSDK_DIR}/include/CS\n)\n\nIF(TARGET_X64)\n  SET(MAXSDK_LIBRARY_DIRS ${MAXSDK_DIR}/x64/lib)\nELSE(TARGET_X64)\n  SET(MAXSDK_LIBRARY_DIRS ${MAXSDK_DIR}/lib)\nENDIF(TARGET_X64)\n\nMACRO(FIND_3DS_LIBRARY MYLIBRARY MYLIBRARYNAME)          \n  FIND_LIBRARY(${MYLIBRARY}\n    NAMES ${MYLIBRARYNAME}\n    HINTS\n    ${MAXSDK_LIBRARY_DIRS}\n  )\nENDMACRO(FIND_3DS_LIBRARY MYLIBRARY MYLIBRARYNAME)\n\nFIND_3DS_LIBRARY(MAXSDK_CORE_LIBRARY core)\nFIND_3DS_LIBRARY(MAXSDK_GEOM_LIBRARY geom)\nFIND_3DS_LIBRARY(MAXSDK_GFX_LIBRARY gfx)\nFIND_3DS_LIBRARY(MAXSDK_MESH_LIBRARY mesh)\nFIND_3DS_LIBRARY(MAXSDK_MAXUTIL_LIBRARY maxutil)\nFIND_3DS_LIBRARY(MAXSDK_MAXSCRIPT_LIBRARY maxscrpt)\nFIND_3DS_LIBRARY(MAXSDK_PARAMBLK2_LIBRARY paramblk2)\nFIND_3DS_LIBRARY(MAXSDK_BMM_LIBRARY bmm)\n\n# Handle the QUIETLY and REQUIRED arguments and set MAXSDK_FOUND to TRUE if\n# all listed variables are TRUE.\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(MAXSDK DEFAULT_MSG\n    MAXSDK_INCLUDE_DIR MAXSDK_CORE_LIBRARY)\n\nif(MAXSDK_FOUND)\n    SET(MAXSDK_LIBRARIES\n      ${MAXSDK_CORE_LIBRARY}\n      ${MAXSDK_GEOM_LIBRARY}\n      ${MAXSDK_GFX_LIBRARY}\n      ${MAXSDK_MESH_LIBRARY}\n      ${MAXSDK_MAXUTIL_LIBRARY}\n      ${MAXSDK_MAXSCRIPT_LIBRARY}\n      ${MAXSDK_PARAMBLK2_LIBRARY}\n      ${MAXSDK_BMM_LIBRARY} )\n\nelse(MAXSDK_FOUND)\n    set(MAXSDK_LIBRARIES)\nendif(MAXSDK_FOUND)\n\nmark_as_advanced(MAXSDK_INCLUDE_DIR MAXSDK_LIBRARY)\n"
  },
  {
    "path": "code/CMakeModules/FindCEGUI.cmake",
    "content": "# - Locate CEGUI library\n# This module defines\n#  CEGUI_LIBRARY, the library to link against\n#  CEGUI_FOUND, if false, do not try to link to CEGUI\n#  CEGUI_INCLUDE_DIRS, where to find headers.\n\nIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS)\n  # in cache already\n  SET(CEGUI_FIND_QUIETLY TRUE)\nENDIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS)\n\n\nFIND_PATH(CEGUI_INCLUDE_DIRS\n  CEGUI\n  PATHS\n  $ENV{CEGUI_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES cegui CEGUI\n)\n\nFIND_LIBRARY(CEGUI_LIBRARY\n  NAMES CEGUIBase\n  PATHS\n  $ENV{CEGUI_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nGET_FILENAME_COMPONENT(CEGUI_LIB_DIR ${CEGUI_LIBRARY} PATH CACHE)\n\nIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS)\n  SET(CEGUI_FOUND \"YES\")\n  SET(CEGUI_INCLUDE_DIRS \"${CEGUI_INCLUDE_DIRS}/CEGUI\")\n  IF(NOT CEGUI_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found CEGUI: ${CEGUI_LIBRARY}\")\n  ENDIF(NOT CEGUI_FIND_QUIETLY)\nELSE(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS)\n  IF(NOT CEGUI_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find CEGUI!\")\n  ENDIF(NOT CEGUI_FIND_QUIETLY)\nENDIF(CEGUI_LIBRARY AND CEGUI_INCLUDE_DIRS)\n"
  },
  {
    "path": "code/CMakeModules/FindCppTest.cmake",
    "content": "#\n# Find the CppTest includes and library\n#\n# This module defines\n# CPPTEST_INCLUDE_DIR, where to find tiff.h, etc.\n# CPPTEST_LIBRARIES, where to find the CppTest libraries.\n# CPPTEST_FOUND, If false, do not try to use CppTest.\n\n# also defined, but not for general use are\nIF(CPPTEST_LIBRARIES AND CPPTEST_INCLUDE_DIR)\n  # in cache already\n  SET(CPPTEST_FIND_QUIETLY TRUE)\nENDIF(CPPTEST_LIBRARIES AND CPPTEST_INCLUDE_DIR)\n\nFIND_PATH(CPPTEST_INCLUDE_DIR \n  cpptest.h\n  PATHS\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES cppunit cpptest\n)\n\nSET(LIBRARY_NAME_RELEASE cpptest)\nSET(LIBRARY_NAME_DEBUG cpptestd)\n\nIF(WITH_STLPORT)\n  SET(LIBRARY_NAME_RELEASE cpptest_stlport ${LIBRARY_NAME_RELEASE})\n  SET(LIBRARY_NAME_DEBUG cpptest_stlportd ${LIBRARY_NAME_DEBUG})\nENDIF(WITH_STLPORT)\n\nFIND_LIBRARY(CPPTEST_LIBRARY_RELEASE\n  ${LIBRARY_NAME_RELEASE}\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(CPPTEST_LIBRARY_DEBUG\n  ${LIBRARY_NAME_DEBUG}\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(CPPTEST_INCLUDE_DIR)\n  IF(CPPTEST_LIBRARY_RELEASE)\n    SET(CPPTEST_FOUND TRUE)\n\n    SET(CPPTEST_LIBRARIES \"optimized;${CPPTEST_LIBRARY_RELEASE}\")\n    IF(CPPTEST_LIBRARY_DEBUG)\n      SET(CPPTEST_LIBRARIES \"${CPPTEST_LIBRARIES};debug;${CPPTEST_LIBRARY_DEBUG}\")\n    ENDIF(CPPTEST_LIBRARY_DEBUG)\n  ENDIF(CPPTEST_LIBRARY_RELEASE)\nENDIF(CPPTEST_INCLUDE_DIR)\n\nIF(CPPTEST_FOUND)\n  IF(NOT CPPTEST_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found CppTest: ${CPPTEST_LIBRARIES}\")\n  ENDIF(NOT CPPTEST_FIND_QUIETLY)\nELSE(CPPTEST_FOUND)\n  IF(NOT CPPTEST_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find CppTest!\")\n  ENDIF(NOT CPPTEST_FIND_QUIETLY)\nENDIF(CPPTEST_FOUND)\n\nMARK_AS_ADVANCED(CPPTEST_LIBRARY_RELEASE CPPTEST_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindCrashRpt.cmake",
    "content": "# - Locate CrashRpt library\n# This module defines\n#  CrashRpt_LIBRARIES, the libraries to link against\n#  CrashRpt_FOUND, if false, do not try to link to CrashRpt\n#  CrashRpt_INCLUDE_DIR, where to find headers.\n\nIF(CrashRpt_LIBRARIES AND CrashRpt_INCLUDE_DIR)\n  # in cache already\n  SET(CrashRpt_FIND_QUIETLY TRUE)\nENDIF(CrashRpt_LIBRARIES AND CrashRpt_INCLUDE_DIR)\n\nFIND_PATH(CrashRpt_INCLUDE_DIR CrashRpt.h\n  PATH_SUFFIXES crashrpt CrashRpt\n  $ENV{CrashRpt_DIR}/include\n)\n\nFIND_LIBRARY(CrashRpt_LIBRARIES\n  NAMES CrashRpt1402\n  PATHS\n  $ENV{CrashRpt_DIR}/lib\n)\n\nIF(CrashRpt_INCLUDE_DIR)\n  IF(CrashRpt_LIBRARIES)\n    SET(CrashRpt_FOUND TRUE)\n  ENDIF(CrashRpt_LIBRARIES)\nENDIF(CrashRpt_INCLUDE_DIR)\n\nIF(CrashRpt_FOUND)\n  IF(NOT CrashRpt_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found CrashRpt: ${CrashRpt_INCLUDE_DIR} ${CrashRpt_LIBRARIES}\")\n  ENDIF(NOT CrashRpt_FIND_QUIETLY)\nELSE(CrashRpt_FOUND)\n  IF(NOT CrashRpt_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find CrashRpt!\")\n  ENDIF(NOT CrashRpt_FIND_QUIETLY)\nENDIF(CrashRpt_FOUND)\n\nMARK_AS_ADVANCED(CrashRpt_LIBRARIES)\n"
  },
  {
    "path": "code/CMakeModules/FindCurl.cmake",
    "content": "# - Locate Curl library\n# This module defines\n# CURL_INCLUDE_DIRS   - where to find curl/curl.h, etc.\n# CURL_LIBRARIES      - List of libraries when using curl.\n# CURL_FOUND          - True if curl found.\n# CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8)\n\nIF(CURL_LIBRARY AND CURL_INCLUDE_DIR)\n  # in cache already\n  SET(CURL_FIND_QUIETLY TRUE)\nENDIF(CURL_LIBRARY AND CURL_INCLUDE_DIR)\n\nFIND_PATH(CURL_INCLUDE_DIR curl.h\n  PATH_SUFFIXES curl\n  $ENV{CURL_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  /usr/local/include/curl\n  /mingw/include\n)\n\nSET(LIBRARY_NAME_RELEASE curl libcurl)\nSET(LIBRARY_NAME_DEBUG curl libcurl)\n\nFIND_LIBRARY(CURL_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{CURL_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/lib64\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/curl\n  /mingw/lib\n)\n\nFIND_LIBRARY(CURL_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{CURL_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/curl\n  /mingw/lib\n)\n\nIF(CURL_INCLUDE_DIR)\n  IF(CURL_LIBRARY_RELEASE AND CURL_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(CURL_FOUND TRUE)\n    SET(CURL_LIBRARY optimized ${CURL_LIBRARY_RELEASE} debug ${CURL_LIBRARY_DEBUG})\n  ELSEIF(CURL_LIBRARY_RELEASE)\n    # Normal case\n    SET(CURL_FOUND TRUE)\n    SET(CURL_LIBRARY ${CURL_LIBRARY_RELEASE})\n  ELSEIF(CURL_LIBRARY_DEBUG)\n    # Case where Curl is compiled from sources (debug version is compiled by default)\n    SET(CURL_FOUND TRUE)\n    SET(CURL_LIBRARY ${CURL_LIBRARY_DEBUG})\n  ENDIF(CURL_LIBRARY_RELEASE AND CURL_LIBRARY_DEBUG)\nENDIF(CURL_INCLUDE_DIR)\n\nIF(CURL_FOUND)\n  IF(NOT CURL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Curl: ${CURL_INCLUDE_DIR} ${CURL_LIBRARY}\")\n  ENDIF(NOT CURL_FIND_QUIETLY)\nELSE(CURL_FOUND)\n  IF(NOT CURL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Curl! INCLUDE: ${CURL_INCLUDE_DIR}  LIB:${CURL_LIBRARY}  \")\n  ENDIF(NOT CURL_FIND_QUIETLY)\nENDIF(CURL_FOUND)\n\nMARK_AS_ADVANCED(CURL_LIBRARY_RELEASE CURL_LIBRARY_DEBUG)\n\n\nIF(WIN32)\n  ADD_DEFINITIONS(-DCURL_STATICLIB)\nENDIF(WIN32)\n\n\n\n"
  },
  {
    "path": "code/CMakeModules/FindCustomMFC.cmake",
    "content": "# - Locate MFC libraries\n# This module defines\n#  MFC_FOUND, if false, do not try to link to MFC\n#  MFC_LIBRARY_DIR, where to find libraries\n#  MFC_INCLUDE_DIR, where to find headers\n\nIF(CustomMFC_FIND_REQUIRED)\n  SET(MFC_FIND_REQUIRED TRUE)\nENDIF(CustomMFC_FIND_REQUIRED)\n\nIF(NOT MFC_DIR)\n  # If MFC have been found, remember their directory\n  IF(VC_DIR)\n    SET(MFC_STANDARD_DIR \"${VC_DIR}/atlmfc\")\n  ENDIF(VC_DIR)\n\n  FIND_PATH(MFC_DIR\n    include/afxwin.h\n    HINTS\n    ${MFC_STANDARD_DIR}\n  )\nENDIF(NOT MFC_DIR)\n\n# Display an error message if MFC are not found, MFC_FOUND is updated\n# User will be able to update MFC_DIR to the correct directory\nINCLUDE(FindPackageHandleStandardArgs)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(MFC DEFAULT_MSG MFC_DIR)\n\nIF(MFC_FOUND)\n  SET(MFC_INCLUDE_DIR \"${MFC_DIR}/include\")\n  INCLUDE_DIRECTORIES(${MFC_INCLUDE_DIR})\n\n  # Using 32 or 64 bits libraries\n  IF(TARGET_X64)\n    SET(MFC_LIBRARY_DIR \"${MFC_DIR}/lib/amd64\")\n  ELSE(TARGET_X64)\n    SET(MFC_LIBRARY_DIR \"${MFC_DIR}/lib\")\n  ENDIF(TARGET_X64)\n\n  # Add MFC libraries directory to default library path\n  LINK_DIRECTORIES(${MFC_LIBRARY_DIR})\n\n  # Set definitions for using MFC in DLL\n  SET(MFC_DEFINITIONS -D_AFXDLL)\n\n  # Set CMake flag to use MFC DLL\n  SET(CMAKE_MFC_FLAG 2)\nENDIF(MFC_FOUND)\n\n# TODO: create a macro which set MFC_DEFINITIONS, MFC_LIBRARY_DIR and MFC_INCLUDE_DIR for a project\n"
  },
  {
    "path": "code/CMakeModules/FindDInput.cmake",
    "content": "# - Find DirectInput\n# Find the DirectSound includes and libraries\n#\n#  DINPUT_INCLUDE_DIR - where to find dinput.h\n#  DINPUT_LIBRARIES   - List of libraries when using DirectInput.\n#  DINPUT_FOUND       - True if DirectInput found.\n\nif(DINPUT_INCLUDE_DIR)\n    # Already in cache, be silent\n    set(DINPUT_FIND_QUIETLY TRUE)\nendif(DINPUT_INCLUDE_DIR)\n\nfind_path(DINPUT_INCLUDE_DIR dinput.h \n  \"$ENV{DXSDK_DIR}\" \n  \"$ENV{DXSDK_DIR}/Include\"\n)\n\nfind_library(DINPUT_LIBRARY \n  NAMES dinput dinput8 \n  PATHS\n  \"$ENV{DXSDK_DIR}\"\n  \"$ENV{DXSDK_DIR}/Lib\"\n  \"$ENV{DXSDK_DIR}/Lib/x86\"\n)\n\n# Handle the QUIETLY and REQUIRED arguments and set DINPUT_FOUND to TRUE if\n# all listed variables are TRUE.\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(DINPUT DEFAULT_MSG\n    DINPUT_INCLUDE_DIR DINPUT_LIBRARY)\n\nif(DINPUT_FOUND)\n    set(DINPUT_LIBRARIES ${DINPUT_LIBRARY})\nelse(DINPUT_FOUND)\n    set(DINPUT_LIBRARIES)\nendif(DINPUT_FOUND)\n\nmark_as_advanced(DINPUT_INCLUDE_DIR DINPUT_LIBRARY)\n"
  },
  {
    "path": "code/CMakeModules/FindDSound.cmake",
    "content": "# - Find DirectSound\n# Find the DirectSound includes and libraries\n#\n#  DSOUND_INCLUDE_DIR - where to find dsound.h\n#  DSOUND_LIBRARIES   - List of libraries when using dsound.\n#  DSOUND_FOUND       - True if dsound found.\n\nif(DSOUND_INCLUDE_DIR)\n    # Already in cache, be silent\n    set(DSOUND_FIND_QUIETLY TRUE)\nendif(DSOUND_INCLUDE_DIR)\n\nfind_path(DSOUND_INCLUDE_DIR dsound.h \n  \"$ENV{DXSDK_DIR}\" \n  \"$ENV{DXSDK_DIR}/Include\"\n)\n\nfind_library(DSOUND_LIBRARY dsound\n  \"$ENV{DXSDK_DIR}\"\n  \"$ENV{DXSDK_DIR}/Lib\"\n  \"$ENV{DXSDK_DIR}/Lib/x86\"\n)\n\n# Handle the QUIETLY and REQUIRED arguments and set DSOUND_FOUND to TRUE if\n# all listed variables are TRUE.\ninclude(FindPackageHandleStandardArgs)\nfind_package_handle_standard_args(DSOUND DEFAULT_MSG\n    DSOUND_INCLUDE_DIR DSOUND_LIBRARY)\n\nif(DSOUND_FOUND)\n    set(DSOUND_LIBRARIES ${DSOUND_LIBRARY})\nelse(DSOUND_FOUND)\n    set(DSOUND_LIBRARIES)\nendif(DSOUND_FOUND)\n\nmark_as_advanced(DSOUND_INCLUDE_DIR DSOUND_LIBRARY)\n"
  },
  {
    "path": "code/CMakeModules/FindDirectXSDK.cmake",
    "content": "# - Find DirectX\n# Find the DirectX includes and libraries\n#\n#  DXSDK_INCLUDE_DIR - where to find baseinterface.h\n#  DXSDK_LIBRARIES   - List of libraries when using 3DSMAX.\n#  DXSDK_FOUND       - True if MAX SDK found.\n\nIF(DXSDK_DIR)\n  # Already in cache, be silent\n  SET(DXSDK_FIND_QUIETLY TRUE)\nENDIF(DXSDK_DIR)\n\nFIND_PATH(DXSDK_DIR\n  \"Include/dxsdkver.h\"\n  PATHS\n  \"$ENV{DXSDK_DIR}\"\n  \"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)\"\n  \"C:/Program Files/Microsoft DirectX SDK (June 2010)\"\n  \"C:/Program Files (x86)/Microsoft DirectX SDK (February 2010)\"\n  \"C:/Program Files/Microsoft DirectX SDK (February 2010)\"\n  \"C:/Program Files (x86)/Microsoft DirectX SDK (November 2007)\"\n  \"C:/Program Files/Microsoft DirectX SDK (November 2007)\"\n  \"C:/Program Files (x86)/Microsoft DirectX SDK\"\n  \"C:/Program Files/Microsoft DirectX SDK\"\n)\n\nMACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME)        \n  FIND_LIBRARY(${MYLIBRARY}\n    NAMES ${MYLIBRARYNAME}\n    HINTS\n    \"${DXSDK_LIBRARY_DIR}\"\n    )\nENDMACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME)\n\nIF(DXSDK_DIR)\n  SET(DXSDK_INCLUDE_DIR \"${DXSDK_DIR}/Include\")\n\n  IF(TARGET_X64)\n    SET(DXSDK_LIBRARY_DIRS ${DXSDK_DIR}/Lib/x64 ${DXSDK_DIR}/lib/amd64)\n  ELSE(TARGET_X64)\n    SET(DXSDK_LIBRARY_DIRS ${DXSDK_DIR}/Lib/x86 ${DXSDK_DIR}/lib)\n  ENDIF(TARGET_X64)\n\n  FIND_PATH(DXSDK_LIBRARY_DIR\n    dxguid.lib\n    PATHS\n    ${DXSDK_LIBRARY_DIRS})\n\n  FIND_DXSDK_LIBRARY(DXSDK_GUID_LIBRARY dxguid)\n  FIND_DXSDK_LIBRARY(DXSDK_DINPUT_LIBRARY dinput8)\n  FIND_DXSDK_LIBRARY(DXSDK_DSOUND_LIBRARY dsound)\n  FIND_DXSDK_LIBRARY(DXSDK_XAUDIO_LIBRARY x3daudio)\n  FIND_DXSDK_LIBRARY(DXSDK_D3DX9_LIBRARY d3dx9)\n  FIND_DXSDK_LIBRARY(DXSDK_D3D9_LIBRARY d3d9)\nENDIF(DXSDK_DIR)\n\n# Handle the QUIETLY and REQUIRED arguments and set DXSDK_FOUND to TRUE if\n# all listed variables are TRUE.\nINCLUDE(FindPackageHandleStandardArgs)\n\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(DirectXSDK DEFAULT_MSG DXSDK_DIR DXSDK_GUID_LIBRARY DXSDK_DINPUT_LIBRARY)\n\nMARK_AS_ADVANCED(DXSDK_INCLUDE_DIR\n  DXSDK_GUID_LIBRARY\n  DXSDK_DINPUT_LIBRARY\n  DXSDK_DSOUND_LIBRARY\n  DXSDK_XAUDIO_LIBRARY\n  DXSDK_D3DX9_LIBRARY\n  DXSDK_D3D9_LIBRARY)\n"
  },
  {
    "path": "code/CMakeModules/FindEFXUtil.cmake",
    "content": "# - Locate EFX-Util library\n# This module defines\n#  EFXUTIL_LIBRARY, the library to link against\n#  EFXUTIL_FOUND, if false, do not try to link to EFX-Util\n#  EFXUTIL_INCLUDE_DIR, where to find headers.\n\nIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR)\n  # in cache already\n  SET(EFXUTIL_FIND_QUIETLY TRUE)\nENDIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR)\n\n\nFIND_PATH(EFXUTIL_INCLUDE_DIR\n  EFX-Util.h\n  PATHS\n  $ENV{EFXUTIL_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES AL\n)\n\nFIND_LIBRARY(EFXUTIL_LIBRARY\n  NAMES EFX-Util efxutil libefxutil\n  PATHS\n  $ENV{EFXUTIL_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR)\n  SET(EFXUTIL_FOUND \"YES\")\n  IF(NOT EFXUTIL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found EFX-Util: ${EFXUTIL_LIBRARY}\")\n  ENDIF(NOT EFXUTIL_FIND_QUIETLY)\nELSE(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR)\n  IF(NOT EFXUTIL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find EFX-Util!\")\n  ENDIF(NOT EFXUTIL_FIND_QUIETLY)\nENDIF(EFXUTIL_LIBRARY AND EFXUTIL_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindExternal.cmake",
    "content": "# Look for a directory containing external libraries.\n#\n# The following values are defined\n# EXTERNAL_PATH         - where to find external\n# EXTERNAL_INCLUDE_PATH - where to find external includes\n# EXTERNAL_BINARY_PATH  - where to find external binaries\n# EXTERNAL_LIBRARY_PATH - where to find external libraries\n# EXTERNAL_FOUND        - True if the external libraries are available\n\nSET(EXTERNAL_TEMP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external ${CMAKE_CURRENT_SOURCE_DIR}/../external ${CMAKE_CURRENT_SOURCE_DIR}/3rdParty ${CMAKE_CURRENT_SOURCE_DIR}/../3rdParty ${EXTERNAL_PATH})\nSET(EXTERNAL_TEMP_FILE \"include/libwww/wwwconf.h\")\nSET(EXTERNAL_NAME \"external\")\n\n# If using STLport preprend external_stlport\nIF(WITH_STLPORT)\n  SET(EXTERNAL_TEMP_PATH ${CMAKE_CURRENT_SOURCE_DIR}/external_stlport ${CMAKE_CURRENT_SOURCE_DIR}/../external_stlport ${EXTERNAL_TEMP_PATH})\n  SET(EXTERNAL_TEMP_FILE \"include/stlport/string\")\n  SET(EXTERNAL_NAME \"external with STLport\")\nENDIF(WITH_STLPORT)\n\nFIND_PATH(EXTERNAL_PATH\n  ${EXTERNAL_TEMP_FILE}\n  PATHS\n  $ENV{EXTERNAL_PATH}\n  ${EXTERNAL_TEMP_PATH}\n  /usr/local\n  /usr\n  /sw\n  /opt/local\n  /opt/csw\n  /opt\n)\n\nIF(EXTERNAL_PATH)\n  SET(EXTERNAL_FOUND TRUE)\n  SET(EXTERNAL_INCLUDE_PATH \"${EXTERNAL_PATH}/include\")\n\n  # Using 32 or 64 bits binaries\n  IF(TARGET_X64 AND WIN32)\n    SET(EXTERNAL_BINARY_PATH \"${EXTERNAL_PATH}/bin64\")\n  ELSE(TARGET_X64 AND WIN32)\n    SET(EXTERNAL_BINARY_PATH \"${EXTERNAL_PATH}/bin\")\n  ENDIF(TARGET_X64 AND WIN32)\n\n  # Using 32 or 64 bits libraries\n  IF(TARGET_X64 AND WIN32)\n    SET(EXTERNAL_LIBRARY_PATH \"${EXTERNAL_PATH}/lib64\")\n  ELSE(TARGET_X64 AND WIN32)\n    SET(EXTERNAL_LIBRARY_PATH \"${EXTERNAL_PATH}/lib\")\n  ENDIF(TARGET_X64 AND WIN32)\n\n  SET(CMAKE_INCLUDE_PATH \"${EXTERNAL_INCLUDE_PATH};${CMAKE_INCLUDE_PATH}\")\n  # Stupid hack for FindOpenAL.cmake\n  SET(CMAKE_INCLUDE_PATH \"${EXTERNAL_PATH};${CMAKE_INCLUDE_PATH}\")\n  SET(CMAKE_LIBRARY_PATH \"${EXTERNAL_LIBRARY_PATH};${CMAKE_LIBRARY_PATH}\")\nENDIF(EXTERNAL_PATH)\n\nIF(EXTERNAL_FOUND)\n  IF(NOT External_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found ${EXTERNAL_NAME}: ${EXTERNAL_PATH}\")\n  ENDIF(NOT External_FIND_QUIETLY)\nELSE(EXTERNAL_FOUND)\n  IF(External_FIND_REQUIRED)\n    MESSAGE(FATAL_ERROR \"Unable to find ${EXTERNAL_NAME}!\")\n  ELSE(External_FIND_REQUIRED)\n    IF(NOT External_FIND_QUIETLY)\n      MESSAGE(STATUS \"Warning: Unable to find ${EXTERNAL_NAME}!\")\n    ENDIF(NOT External_FIND_QUIETLY)\n  ENDIF(External_FIND_REQUIRED)\nENDIF(EXTERNAL_FOUND)\n\nMARK_AS_ADVANCED(EXTERNAL_INCLUDE_PATH EXTERNAL_BINARY_PATH EXTERNAL_LIBRARY_PATH)\n"
  },
  {
    "path": "code/CMakeModules/FindFMOD.cmake",
    "content": "# - Locate FMOD library\n# This module defines\n#  FMOD_LIBRARY, the library to link against\n#  FMOD_FOUND, if false, do not try to link to FMOD\n#  FMOD_INCLUDE_DIR, where to find headers.\n\nIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR)\n  # in cache already\n  SET(FMOD_FIND_QUIETLY TRUE)\nENDIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR)\n\n\nFIND_PATH(FMOD_INCLUDE_DIR\n  fmod.h\n  PATHS\n  $ENV{FMOD_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES fmod fmod3\n)\n\nIF(TARGET_X64)\n  SET(FMOD_LIBRARY_NAMES fmod64 fmod)\nELSE(TARGET_X64)\n  SET(FMOD_LIBRARY_NAMES fmodvc fmod)\nENDIF(TARGET_X64)\n\nFIND_LIBRARY(FMOD_LIBRARY\n  NAMES\n  ${FMOD_LIBRARY_NAMES}\n  PATHS\n  $ENV{FMOD_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR)\n  SET(FMOD_FOUND \"YES\")\n  IF(NOT FMOD_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found FMOD: ${FMOD_LIBRARY}\")\n  ENDIF(NOT FMOD_FIND_QUIETLY)\nELSE(FMOD_LIBRARY AND FMOD_INCLUDE_DIR)\n  IF(NOT FMOD_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find FMOD!\")\n  ENDIF(NOT FMOD_FIND_QUIETLY)\nENDIF(FMOD_LIBRARY AND FMOD_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindFreeType.cmake",
    "content": "# - Locate FreeType library\n# This module defines\n#  FREETYPE_LIBRARIES, libraries to link against\n#  FREETYPE_FOUND, if false, do not try to link to FREETYPE\n#  FREETYPE_INCLUDE_DIRS, where to find headers.\n\nIF(FREETYPE_LIBRARIES AND FREETYPE_INCLUDE_DIRS)\n  # in cache already\n  SET(Freetype_FIND_QUIETLY TRUE)\nENDIF(FREETYPE_LIBRARIES AND FREETYPE_INCLUDE_DIRS)\n\nFIND_PATH(FREETYPE_INCLUDE_DIRS\n  freetype\n  PATHS\n  $ENV{FREETYPE_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES freetype2\n)\n\nIF(NOT FREETYPE_INCLUDE_DIRS)\n  SET(FREETYPE_INCLUDE_DIRS \"\")\nENDIF(NOT FREETYPE_INCLUDE_DIRS)\n\n# ft2build.h does not reside in the freetype include dir\nFIND_PATH(FREETYPE_ADDITIONAL_INCLUDE_DIR\n  ft2build.h\n  PATHS\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES freetype2\n)\n\n# combine both include directories into one variable\nIF(FREETYPE_ADDITIONAL_INCLUDE_DIR)\n  SET(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${FREETYPE_ADDITIONAL_INCLUDE_DIR})\nENDIF(FREETYPE_ADDITIONAL_INCLUDE_DIR)\n\nFIND_LIBRARY(FREETYPE_LIBRARY_RELEASE\n  NAMES freetype libfreetype freetype219 freetype246\n  PATHS\n  $ENV{FREETYPE_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/lib/x86_64-linux-gnu\n)\n\nFIND_LIBRARY(FREETYPE_LIBRARY_DEBUG\n  NAMES freetyped libfreetyped freetype219d freetype246d\n  PATHS\n  $ENV{FREETYPE_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/lib/x86_64-linux-gnu\n)\n\nIF(FREETYPE_INCLUDE_DIRS)\n  IF(FREETYPE_LIBRARY_RELEASE AND FREETYPE_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(FREETYPE_FOUND ON)\n    SET(FREETYPE_LIBRARIES optimized ${FREETYPE_LIBRARY_RELEASE} debug ${FREETYPE_LIBRARY_DEBUG})\n  ELSEIF(FREETYPE_LIBRARY_RELEASE)\n    # Normal case\n    SET(FREETYPE_FOUND ON)\n    SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY_RELEASE})\n  ELSEIF(FREETYPE_LIBRARY_DEBUG)\n    # Case where Freetype is compiled from sources (debug version is compiled by default)\n    SET(FREETYPE_FOUND ON)\n    SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY_DEBUG})\n  ENDIF(FREETYPE_LIBRARY_RELEASE AND FREETYPE_LIBRARY_DEBUG)\nENDIF(FREETYPE_INCLUDE_DIRS)\n\nIF(FREETYPE_FOUND)\n  IF(WITH_STATIC_EXTERNAL AND APPLE)\n    FIND_PACKAGE(BZip2)\n    IF(BZIP2_FOUND)\n      SET(FREETYPE_INCLUDE_DIRS ${FREETYPE_INCLUDE_DIRS} ${BZIP2_INCLUDE_DIR})\n      SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARIES} ${BZIP2_LIBRARIES})\n    ENDIF(BZIP2_FOUND)\n  ENDIF(WITH_STATIC_EXTERNAL AND APPLE)\n  IF(NOT Freetype_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found FreeType: ${FREETYPE_LIBRARIES}\")\n  ENDIF(NOT Freetype_FIND_QUIETLY)\nELSE(FREETYPE_LIBRARY AND FREETYPE_INCLUDE_DIRS)\n  IF(NOT Freetype_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find FreeType!\")\n  ENDIF(NOT Freetype_FIND_QUIETLY)\nENDIF(FREETYPE_FOUND)\n"
  },
  {
    "path": "code/CMakeModules/FindGTK2.cmake",
    "content": "# - Try to find GTK2\n# Once done this will define\n#\n#  GTK2_FOUND - System has GTK2\n#  GTK2_INCLUDE_DIRS - GTK2 include directory\n#  GTK2_LIBRARIES - Link these to use GTK2\n#  GTK2_LIBRARY_DIRS - The path to where the GTK2 library files are.\n#  GTK2_DEFINITIONS - Compiler switches required for using GTK2\n#\n#  Copyright (c) 2007 Andreas Schneider <mail@cynapses.org>\n#\n#  Redistribution and use is allowed according to the terms of the New\n#  BSD license.\n#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n#\n\nset(GTK2_DEBUG ON)\n\nmacro(GTK2_DEBUG_MESSAGE _message)\n  if (GTK2_DEBUG)\n    message(STATUS \"(DEBUG) ${_message}\")\n  endif (GTK2_DEBUG)\nendmacro(GTK2_DEBUG_MESSAGE _message)\n\nif (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS)\n  # in cache already\n  set(GTK2_FOUND TRUE)\nelse (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS)\n  if (UNIX)\n    # use pkg-config to get the directories and then use these values\n    # in the FIND_PATH() and FIND_LIBRARY() calls\n    include(UsePkgConfig)\n\n    pkgconfig(gtk+-2.0 _GTK2IncDir _GTK2LinkDir _GTK2LinkFlags _GTK2Cflags)\n\n    find_path(GTK2_GTK_INCLUDE_DIR\n      NAMES\n        gtk/gtk.h\n      PATHS\n        $ENV{GTK2_HOME}\n        ${_GTK2IncDir}\n        /usr/include/gtk-2.0\n        /usr/local/include/gtk-2.0\n        /opt/include/gtk-2.0\n        /opt/gnome/include/gtk-2.0\n        /sw/include/gtk-2.0\n    )\n    gtk2_debug_message(\"GTK2_GTK_INCLUDE_DIR is ${GTK2_GTK_INCLUDE_DIR}\")\n\n    # Some Linux distributions (e.g. Red Hat) have glibconfig.h\n    # and glib.h in different directories, so we need to look\n    # for both.\n    #  - Atanas Georgiev <atanas@cs.columbia.edu>\n    pkgconfig(glib-2.0 _GLIB2IncDir _GLIB2LinkDir _GLIB2LinkFlags _GLIB2Cflags)\n    pkgconfig(gmodule-2.0 _GMODULE2IncDir _GMODULE2LinkDir _GMODULE2LinkFlags _GMODULE2Cflags)\n\n    find_path(GTK2_GLIBCONFIG_INCLUDE_DIR\n      NAMES\n        glibconfig.h\n      PATHS\n        ${_GLIB2IncDir}\n        ${_GMODULE2IncDir}\n        /opt/gnome/lib64/glib-2.0/include\n        /opt/gnome/lib/glib-2.0/include\n        /opt/lib/glib-2.0/include\n        /usr/lib64/glib-2.0/include\n        /usr/lib/glib-2.0/include\n        /sw/lib/glib-2.0/include\n        /usr/lib/x86_64-linux-gnu/glib-2.0/include\n\t\t/usr/lib/arm-linux-gnueabihf/glib-2.0/include\n    )\n    gtk2_debug_message(\"GTK2_GLIBCONFIG_INCLUDE_DIR is ${GTK2_GLIBCONFIG_INCLUDE_DIR}\")\n\n    find_path(GTK2_GLIB_INCLUDE_DIR\n      NAMES\n        glib.h\n      PATHS\n        ${_GLIB2IncDir}\n        ${_GMODULE2IncDir}\n        /opt/include/glib-2.0\n        /opt/gnome/include/glib-2.0\n        /usr/include/glib-2.0\n        /sw/include/glib-2.0\n    )\n    gtk2_debug_message(\"GTK2_GLIB_INCLUDE_DIR is ${GTK2_GLIB_INCLUDE_DIR}\")\n\n    pkgconfig(gdk-2.0 _GDK2IncDir _GDK2LinkDir _GDK2LinkFlags _GDK2Cflags)\n\n    find_path(GTK2_GDK_INCLUDE_DIR\n      NAMES\n        gdkconfig.h\n      PATHS\n        ${_GDK2IncDir}\n        /opt/gnome/lib/gtk-2.0/include\n        /opt/gnome/lib64/gtk-2.0/include\n        /opt/lib/gtk-2.0/include\n        /usr/lib/gtk-2.0/include\n        /usr/lib64/gtk-2.0/include\n        /sw/lib/gtk-2.0/include\n        /usr/lib/x86_64-linux-gnu/gtk-2.0/include\n\t\t/usr/lib/arm-linux-gnueabihf/gtk-2.0/include\n    )\n    gtk2_debug_message(\"GTK2_GDK_INCLUDE_DIR is ${GTK2_GDK_INCLUDE_DIR}\")\n\n    find_path(GTK2_GDK_PIXBUF_INCLUDE_DIR\n      NAMES\n        gdk-pixbuf/gdk-pixbuf.h\n      PATHS\n        ${_GDK2IncDir}\n        /opt/gnome/lib/gtk-2.0/include\n        /opt/gnome/lib64/gtk-2.0/include\n        /opt/lib/gtk-2.0/include\n        /usr/lib/gtk-2.0/include\n        /usr/lib64/gtk-2.0/include\n        /sw/lib/gtk-2.0/include\n        /usr/include/gdk-pixbuf-2.0\n    )\n    gtk2_debug_message(\"GTK2_GDK_PIXBUF_INCLUDE_DIR is ${GTK2_GDK_PIXBUF_INCLUDE_DIR}\")\n\n    find_path(GTK2_GTKGL_INCLUDE_DIR\n      NAMES\n        gtkgl/gtkglarea.h\n      PATHS\n        ${_GLIB2IncDir}\n        /usr/include\n\t\t/usr/include/gtkgl-2.0\n        /usr/local/include\n        /usr/openwin/share/include\n        /opt/gnome/include\n        /opt/include\n        /sw/include\n    )\n    gtk2_debug_message(\"GTK2_GTKGL_INCLUDE_DIR is ${GTK2_GTKGL_INCLUDE_DIR}\")\n\n    pkgconfig(libglade-2.0 _GLADEIncDir _GLADELinkDir _GLADELinkFlags _GLADECflags)\n\n    find_path(GTK2_GLADE_INCLUDE_DIR\n      NAMES\n        glade/glade.h\n      PATHS\n        ${_GLADEIncDir}\n        /opt/gnome/include/libglade-2.0\n        /usr/include/libglade-2.0\n        /opt/include/libglade-2.0\n        /sw/include/libglade-2.0\n    )\n    gtk2_debug_message(\"GTK2_GLADE_INCLUDE_DIR is ${GTK2_GLADE_INCLUDE_DIR}\")\n\n    pkgconfig(pango _PANGOIncDir _PANGOLinkDir _PANGOLinkFlags _PANGOCflags)\n\n    find_path(GTK2_PANGO_INCLUDE_DIR\n      NAMES\n        pango/pango.h\n      PATHS\n        ${_PANGOIncDir}\n        /usr/include/pango-1.0\n        /opt/gnome/include/pango-1.0\n        /opt/include/pango-1.0\n        /sw/include/pango-1.0\n    )\n    gtk2_debug_message(\"GTK2_PANGO_INCLUDE_DIR is ${GTK2_PANGO_INCLUDE_DIR}\")\n\n    pkgconfig(cairo _CAIROIncDir _CAIROLinkDir _CAIROLinkFlags _CAIROCflags)\n\n    find_path(GTK2_CAIRO_INCLUDE_DIR\n      NAMES\n        cairo.h\n      PATHS\n        ${_CAIROIncDir}\n        /opt/gnome/include/cairo\n        /usr/include\n        /usr/include/cairo\n        /opt/include\n        /opt/include/cairo\n        /sw/include\n        /sw/include/cairo\n    )\n    gtk2_debug_message(\"GTK2_CAIRO_INCLUDE_DIR is ${GTK2_CAIRO_INCLUDE_DIR}\")\n\n    pkgconfig(atk _ATKIncDir _ATKLinkDir _ATKLinkFlags _ATKCflags)\n\n    find_path(GTK2_ATK_INCLUDE_DIR\n      NAMES\n        atk/atk.h\n      PATHS\n        ${_ATKIncDir}\n        /opt/gnome/include/atk-1.0\n        /usr/include/atk-1.0\n        /opt/include/atk-1.0\n        /sw/include/atk-1.0\n    )\n    gtk2_debug_message(\"GTK2_ATK_INCLUDE_DIR is ${GTK2_ATK_INCLUDE_DIR}\")\n\n    find_library(GTK2_GTK_LIBRARY\n      NAMES\n        gtk-x11-2.0\n      PATHS\n        ${_GTK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GTK_LIBRARY is ${GTK2_GTK_LIBRARY}\")\n\n    find_library(GTK2_GDK_LIBRARY\n      NAMES\n        gdk-x11-2.0\n      PATHS\n        ${_GDK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GDK_LIBRARY is ${GTK2_GDK_LIBRARY}\")\n\n    find_library(GTK2_GDK_PIXBUF_LIBRARY\n      NAMES\n        gdk_pixbuf-2.0\n      PATHS\n        ${_GDK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GDK_PIXBUF_LIBRARY is ${GTK2_GDK_PIXBUF_LIBRARY}\")\n\n    find_library(GTK2_GMODULE_LIBRARY\n      NAMES\n        gmodule-2.0\n      PATHS\n        ${_GMODULE2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GMODULE_LIBRARY is ${GTK2_GMODULE_LIBRARY}\")\n\n    find_library(GTK2_GTHREAD_LIBRARY\n      NAMES\n        gthread-2.0\n      PATHS\n        ${_GTK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GTHREAD_LIBRARY is ${GTK2_GTHREAD_LIBRARY}\")\n\n    find_library(GTK2_GOBJECT_LIBRARY\n      NAMES\n        gobject-2.0\n      PATHS\n        ${_GTK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GOBJECT_LIBRARY is ${GTK2_GOBJECT_LIBRARY}\")\n\n    find_library(GTK2_GLIB_LIBRARY\n      NAMES\n        glib-2.0\n      PATHS\n        ${_GLIB2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GLIB_LIBRARY is ${GTK2_GLIB_LIBRARY}\")\n\n    find_library(GTK2_GTKGL_LIBRARY\n      NAMES\n        gtkgl-2.0\n      PATHS\n        ${_GTK2LinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GTKGL_LIBRARY is ${GTK2_GTKGL_LIBRARY}\")\n\n    find_library(GTK2_GLADE_LIBRARY\n      NAMES\n        glade-2.0\n      PATHS\n        ${_GLADELinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_GLADE_LIBRARY is ${GTK2_GLADE_LIBRARY}\")\n\n    find_library(GTK2_PANGO_LIBRARY\n      NAMES\n        pango-1.0\n      PATHS\n        ${_PANGOLinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_PANGO_LIBRARY is ${GTK2_PANGO_LIBRARY}\")\n\n    find_library(GTK2_CAIRO_LIBRARY\n      NAMES\n        pangocairo-1.0\n      PATHS\n        ${_CAIROLinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_PANGO_LIBRARY is ${GTK2_CAIRO_LIBRARY}\")\n\n    find_library(GTK2_ATK_LIBRARY\n      NAMES\n        atk-1.0\n      PATHS\n        ${_ATKinkDir}\n        /usr/lib\n        /usr/local/lib\n        /usr/openwin/lib\n        /usr/X11R6/lib\n        /opt/gnome/lib\n        /opt/lib\n        /sw/lib\n    )\n    gtk2_debug_message(\"GTK2_ATK_LIBRARY is ${GTK2_ATK_LIBRARY}\")\n\n    set(GTK2_INCLUDE_DIRS\n      ${GTK2_GTK_INCLUDE_DIR}\n      ${GTK2_GLIBCONFIG_INCLUDE_DIR}\n      ${GTK2_GLIB_INCLUDE_DIR}\n      ${GTK2_GDK_INCLUDE_DIR}\n      ${GTK2_GDK_PIXBUF_INCLUDE_DIR}\n      ${GTK2_GLADE_INCLUDE_DIR}\n      ${GTK2_PANGO_INCLUDE_DIR}\n      ${GTK2_CAIRO_INCLUDE_DIR}\n      ${GTK2_ATK_INCLUDE_DIR}\n    )\n\n    if (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR)\n      if (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR)\n        if (GTK2_GMODULE_LIBRARY)\n          if (GTK2_GTHREAD_LIBRARY)\n            if (GTK2_GOBJECT_LIBRARY)\n              if (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR)\n                if (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR)\n                  if (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR)\n                    if (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR)\n\n                      # set GTK2 libraries\n                      set (GTK2_LIBRARIES\n                        ${GTK2_GTK_LIBRARY}\n                        ${GTK2_GDK_LIBRARY}\n                        ${GTK2_GDK_PIXBUF_LIBRARY}\n                        ${GTK2_GMODULE_LIBRARY}\n                        ${GTK2_GTHREAD_LIBRARY}\n                        ${GTK2_GOBJECT_LIBRARY}\n                        ${GTK2_GLADE_LIBRARY}\n                        ${GTK2_PANGO_LIBRARY}\n                        ${GTK2_CAIRO_LIBRARY}\n                        ${GTK2_ATK_LIBRARY}\n                      )\n\n                      # check for gtkgl support\n                      if (GTK2_GTKGL_LIBRARY AND GTK2_GTKGL_INCLUDE_DIR)\n                        set(GTK2_GTKGL_FOUND TRUE)\n\n                        set(GTK2_INCLUDE_DIRS\n                          ${GTK2_INCLUDE_DIRS}\n                          ${GTK2_GTKGL_INCLUDE_DIR}\n                        )\n\n                        set(GTK2_LIBRARIES\n                          ${GTK2_LIBRARIES}\n                          ${GTK2_GTKGL_LIBRARY}\n                        )\n                      endif (GTK2_GTKGL_LIBRARY AND GTK2_GTKGL_INCLUDE_DIR)\n\n                    else (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR)\n                      message(SEND_ERROR \"Could not find ATK\")\n                    endif (GTK2_ATK_LIBRARY AND GTK2_ATK_INCLUDE_DIR)\n                  else (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR)\n                    message(SEND_ERROR \"Could not find CAIRO\")\n                  endif (GTK2_CAIRO_LIBRARY AND GTK2_CAIRO_INCLUDE_DIR)\n                else (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR)\n                  message(SEND_ERROR \"Could not find PANGO\")\n                endif (GTK2_PANGO_LIBRARY AND GTK2_PANGO_INCLUDE_DIR)\n              else (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR)\n                message(SEND_ERROR \"Could not find GLADE\")\n              endif (GTK2_GLADE_LIBRARY AND GTK2_GLADE_INCLUDE_DIR)\n            else (GTK2_GOBJECT_LIBRARY)\n              message(SEND_ERROR \"Could not find GOBJECT\")\n            endif (GTK2_GOBJECT_LIBRARY)\n          else (GTK2_GTHREAD_LIBRARY)\n            message(SEND_ERROR \"Could not find GTHREAD\")\n          endif (GTK2_GTHREAD_LIBRARY)\n        else (GTK2_GMODULE_LIBRARY)\n          message(SEND_ERROR \"Could not find GMODULE\")\n        endif (GTK2_GMODULE_LIBRARY)\n      else (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR)\n        message(SEND_ERROR \"Could not find GDK (GDK_PIXBUF)\")\n      endif (GTK2_GDK_LIBRARY AND GTK2_GDK_PIXBUF_LIBRARY AND GTK2_GDK_INCLUDE_DIR AND GTK2_GDK_PIXBUF_INCLUDE_DIR)\n    else (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR)\n      message(SEND_ERROR \"Could not find GTK2-X11\")\n    endif (GTK2_GTK_LIBRARY AND GTK2_GTK_INCLUDE_DIR)\n\n    if (GTK2_INCLUDE_DIRS AND GTK2_LIBRARIES)\n       set(GTK2_FOUND TRUE)\n    endif (GTK2_INCLUDE_DIRS AND GTK2_LIBRARIES)\n\n    if (GTK2_FOUND)\n      if (NOT GTK2_FIND_QUIETLY)\n        message(STATUS \"Found GTK2: ${GTK2_LIBRARIES}\")\n      endif (NOT GTK2_FIND_QUIETLY)\n    else (GTK2_FOUND)\n      if (GTK2_FIND_REQUIRED)\n        message(FATAL_ERROR \"Could not find GTK2\")\n      endif (GTK2_FIND_REQUIRED)\n    endif (GTK2_FOUND)\n\n    # show the GTK2_INCLUDE_DIRS and GTK2_LIBRARIES variables only in the advanced view\n    mark_as_advanced(GTK2_INCLUDE_DIRS GTK2_LIBRARIES)\n\n  endif (UNIX)\nendif (GTK2_LIBRARIES AND GTK2_INCLUDE_DIRS)\n\n"
  },
  {
    "path": "code/CMakeModules/FindIconv.cmake",
    "content": "# - Try to find Iconv \n# Once done this will define \n# \n#  ICONV_FOUND - system has Iconv \n#  ICONV_INCLUDE_DIR - the Iconv include directory \n#  ICONV_LIBRARIES - Link these to use Iconv \n#  ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const\n# \ninclude(CheckCCompilerFlag)\ninclude(CheckCSourceCompiles)\n\nIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)\n  # Already in cache, be silent\n  SET(ICONV_FIND_QUIETLY TRUE)\nENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)\n\nFIND_PATH(ICONV_INCLUDE_DIR iconv.h HINTS /sw/include/ PATHS /opt/local) \n \nFIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv c PATHS /opt/local)\n \nIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) \n   SET(ICONV_FOUND TRUE) \nENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES) \n\nset(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})\nset(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})\nIF(ICONV_FOUND)\n  check_c_compiler_flag(\"-Werror\" ICONV_HAVE_WERROR)\n  set (CMAKE_C_FLAGS_BACKUP \"${CMAKE_C_FLAGS}\")\n  if(ICONV_HAVE_WERROR)\n    set (CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Werror\")\n  endif(ICONV_HAVE_WERROR)\n  check_c_source_compiles(\"\n  #include <iconv.h>\n  int main(){\n    iconv_t conv = 0;\n    const char* in = 0;\n    size_t ilen = 0;\n    char* out = 0;\n    size_t olen = 0;\n    iconv(conv, &in, &ilen, &out, &olen);\n    return 0;\n  }\n\" ICONV_SECOND_ARGUMENT_IS_CONST )\n  set (CMAKE_C_FLAGS \"${CMAKE_C_FLAGS_BACKUP}\")\nENDIF(ICONV_FOUND)\nset(CMAKE_REQUIRED_INCLUDES)\nset(CMAKE_REQUIRED_LIBRARIES)\n\nIF(ICONV_FOUND) \n  IF(NOT ICONV_FIND_QUIETLY) \n    MESSAGE(STATUS \"Found Iconv: ${ICONV_LIBRARIES}\") \n  ENDIF(NOT ICONV_FIND_QUIETLY) \nELSE(ICONV_FOUND) \n  IF(Iconv_FIND_REQUIRED) \n    MESSAGE(FATAL_ERROR \"Could not find Iconv\") \n  ENDIF(Iconv_FIND_REQUIRED) \nENDIF(ICONV_FOUND) \n\nMARK_AS_ADVANCED(\n  ICONV_INCLUDE_DIR\n  ICONV_LIBRARIES\n  ICONV_SECOND_ARGUMENT_IS_CONST\n)\n"
  },
  {
    "path": "code/CMakeModules/FindJpeg.cmake",
    "content": "# - Locate Jpeg library\n# This module defines\n#  JPEG_LIBRARY, the library to link against\n#  JPEG_FOUND, if false, do not try to link to JPEG\n#  JPEG_INCLUDE_DIR, where to find headers.\n\nIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR)\n  # in cache already\n  SET(JPEG_FIND_QUIETLY TRUE)\nENDIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR)\n\n\nFIND_PATH(JPEG_INCLUDE_DIR\n  jpeglib.h\n  PATHS\n  $ENV{JPEG_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES jpeg\n)\n\nFIND_LIBRARY(JPEG_LIBRARY\n  NAMES jpeg libjpeg\n  PATHS\n  $ENV{JPEG_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR)\n  SET(JPEG_FOUND \"YES\")\n  IF(NOT JPEG_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Jpeg: ${JPEG_LIBRARY}\")\n  ENDIF(NOT JPEG_FIND_QUIETLY)\nELSE(JPEG_LIBRARY AND JPEG_INCLUDE_DIR)\n  IF(NOT JPEG_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Jpeg!\")\n  ENDIF(NOT JPEG_FIND_QUIETLY)\nENDIF(JPEG_LIBRARY AND JPEG_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindLibEvent.cmake",
    "content": "# - Locate LibEvent library\n# This module defines\n# LIBEVENT_INCLUDE_DIRS   - where to find libevent/libevent.h, etc.\n# LIBEVENT_LIBRARIES      - List of libraries when using libevent.\n# LIBEVENT_FOUND          - True if libevent found.\n# LIBEVENT_VERSION_STRING - the version of libevent found (since CMake 2.8.8)\n\nIF(LIBEVENT_LIBRARY AND LIBEVENT_INCLUDE_DIR)\n  # in cache already\n  SET(LIBEVENT_FIND_QUIETLY TRUE)\nENDIF(LIBEVENT_LIBRARY AND LIBEVENT_INCLUDE_DIR)\n\nFIND_PATH(LIBEVENT_INCLUDE_DIR evutil.h\n  PATH_SUFFIXES libevent\n  $ENV{LIBEVENT_DIR}/include\n  /usr/local/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  /usr/local/include/libevent\n  /mingw/include\n)\n\nSET(LIBRARY_NAME_RELEASE libevent libevent.a)\nSET(LIBRARY_NAME_DEBUG libevent libevent.a)\n\nFIND_LIBRARY(LIBEVENT_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{LIBEVENT_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/lib64\n  /usr/local/X11R6/lib\n  /usr/local/lib/libevent\n)\n\nFIND_LIBRARY(LIBEVENT_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{LIBEVENT_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/lib/libevent\n)\n\nIF(NOT WIN32)\n    SET(LIBRARY_NAME_PTHREADS libevent_pthreads libevent_pthreads.a)\n    FIND_LIBRARY(PTHREADS_LIBRARIE_RELEASE\n      NAMES ${LIBRARY_NAME_PTHREADS}\n      PATHS\n      $ENV{LIBEVENT_DIR}/lib\n      /usr/local/lib\n    )\n    \n    ADD_DEFINITIONS(-DEVENT__HAVE_PTHREADS)\nENDIF()\n\nIF(LIBEVENT_INCLUDE_DIR)\n  IF(LIBEVENT_LIBRARY_RELEASE AND LIBEVENT_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(LIBEVENT_FOUND TRUE)\n    \n    IF(WIN32)\n        SET(LIBEVENT_LIBRARY optimized ${LIBEVENT_LIBRARY_RELEASE} debug ${LIBEVENT_LIBRARY_DEBUG})\n    ELSE()\n        #SET(LIBEVENT_LIBRARY \"${LIBEVENT_LIBRARY_RELEASE};${PTHREADS_LIBRARIE_RELEASE}\" CACHE STRING \"LibEvent Libraries\")\n        SET(LIBEVENT_LIBRARY \"${LIBEVENT_LIBRARY_RELEASE};${PTHREADS_LIBRARIE_RELEASE}\")\n    ENDIF()\n    \n  ELSEIF(LIBEVENT_LIBRARY_RELEASE)\n    # Normal case\n    SET(LIBEVENT_FOUND TRUE)\n    SET(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARY_RELEASE})\n  ELSEIF(LIBEVENT_LIBRARY_DEBUG)\n    # Case where LibEvent is compiled from sources (debug version is compiled by default)\n    SET(LIBEVENT_FOUND TRUE)\n    SET(LIBEVENT_LIBRARY ${LIBEVENT_LIBRARY_DEBUG})\n  ENDIF(LIBEVENT_LIBRARY_RELEASE AND LIBEVENT_LIBRARY_DEBUG)\nENDIF(LIBEVENT_INCLUDE_DIR)\n\nIF(LIBEVENT_FOUND)\n  IF(NOT LIBEVENT_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found LibEvent: ${LIBEVENT_INCLUDE_DIR} ${LIBEVENT_LIBRARY}\")\n  ENDIF(NOT LIBEVENT_FIND_QUIETLY)\nELSE(LIBEVENT_FOUND)\n  IF(NOT LIBEVENT_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find LibEvent! INCLUDE: ${LIBEVENT_INCLUDE_DIR}  LIB:${LIBEVENT_LIBRARY}  \")\n  ENDIF(NOT LIBEVENT_FIND_QUIETLY)\nENDIF(LIBEVENT_FOUND)\n\nMARK_AS_ADVANCED(LIBEVENT_LIBRARY_RELEASE LIBEVENT_LIBRARY_DEBUG)\n\n#   libevent_openssl\nFIND_LIBRARY(LIBEVENT_OPENSSL_LIBRARY\n  NAMES libevent_openssl libevent_openssl.a\n  PATHS\n  $ENV{LIBEVENT_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/lib64\n  /usr/local/lib/libevent\n)\n\nADD_DEFINITIONS(-DEVENT__HAVE_OPENSSL)\n\nMESSAGE(STATUS \"LIBEVENT_OPENSSL_LIBRARY: ${LIBEVENT_OPENSSL_LIBRARY}\")\n\n\n\n\n\n\n"
  },
  {
    "path": "code/CMakeModules/FindLibOVR.cmake",
    "content": "# - Locate LibOVR library\n# This module defines\n#  LIBOVR_LIBRARIES, the libraries to link against\n#  LIBOVR_FOUND, if false, do not try to link to LIBOVR\n#  LIBOVR_INCLUDE_DIR, where to find headers.\n\nIF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR)\n  # in cache already\n  SET(LIBOVR_FIND_QUIETLY TRUE)\nENDIF(LIBOVR_LIBRARIES AND LIBOVR_INCLUDE_DIR)\n\nFIND_PATH(LIBOVR_INCLUDE_DIR\n  OVR.h\n  PATHS\n  $ENV{LIBOVR_DIR}/Include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\nIF(UNIX)\n  IF(TARGET_X64)\n    SET(LIBOVR_LIBRARY_BUILD_PATH \"Lib/Linux/Release/x86_64\")\n  ELSE(TARGET_X64)\n    SET(LIBOVR_LIBRARY_BUILD_PATH \"Lib/Linux/Release/i386\")\n  ENDIF(TARGET_X64)\nELSEIF(APPLE)\n  SET(LIBOVR_LIBRARY_BUILD_PATH \"Lib/MacOS/Release\")\nELSEIF(WIN32)\n  IF(TARGET_X64)\n    SET(LIBOVR_LIBRARY_BUILD_PATH \"Lib/x64\")\n  ELSE(TARGET_X64)\n    SET(LIBOVR_LIBRARY_BUILD_PATH \"Lib/Win32\")\n  ENDIF(TARGET_X64)\nENDIF(UNIX)\n\nFIND_LIBRARY(LIBOVR_LIBRARY\n  NAMES ovr libovr\n  PATHS\n  $ENV{LIBOVR_DIR}/${LIBOVR_LIBRARY_BUILD_PATH}\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR)\n  IF(NOT LIBOVR_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found LibOVR: ${LIBOVR_LIBRARY}\")\n  ENDIF(NOT LIBOVR_FIND_QUIETLY)\n  SET(LIBOVR_FOUND \"YES\")\n  SET(LIBOVR_DEFINITIONS \"-DHAVE_LIBOVR\")\n  IF(UNIX)\n    SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY} X11 Xinerama udev pthread)\n  ELSE(UNIX)\n    SET(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY})\n  ENDIF(UNIX)\nELSE(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR)\n  IF(NOT LIBOVR_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find LibOVR!\")\n  ENDIF(NOT LIBOVR_FIND_QUIETLY)\nENDIF(LIBOVR_LIBRARY AND LIBOVR_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindLibVR.cmake",
    "content": "# - Locate LibVR library\n# This module defines\n#  LIBVR_LIBRARIES, the libraries to link against\n#  LIBVR_FOUND, if false, do not try to link to LIBVR\n#  LIBVR_INCLUDE_DIR, where to find headers.\n\nIF(LIBVR_LIBRARIES AND LIBVR_INCLUDE_DIR)\n  # in cache already\n  SET(LIBVR_FIND_QUIETLY TRUE)\nENDIF(LIBVR_LIBRARIES AND LIBVR_INCLUDE_DIR)\n\nFIND_PATH(LIBVR_INCLUDE_DIR hmd.h\n  PATH_SUFFIXES include/LibVR\n)\n\nFIND_LIBRARY(LIBVR_LIBRARY\n  NAMES vr\n  PATH_SUFFIXES lib\n  PATHS\n)\n\nIF(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR)\n  IF(NOT LIBVR_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found LibVR: ${LIBVR_LIBRARY}\")\n  ENDIF(NOT LIBVR_FIND_QUIETLY)\n  SET(LIBVR_FOUND \"YES\")\n  SET(LIBVR_DEFINITIONS \"-DHAVE_LIBVR\")\nELSE(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR)\n  IF(NOT LIBVR_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find LibVR!\")\n  ENDIF(NOT LIBVR_FIND_QUIETLY)\nENDIF(LIBVR_LIBRARY AND LIBVR_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindLibwww.cmake",
    "content": "#\n# Find the W3C libwww includes and library\n#\n# This module defines\n# LIBWWW_INCLUDE_DIR, where to find tiff.h, etc.\n# LIBWWW_LIBRARY, where to find the Libwww library.\n# LIBWWW_FOUND, If false, do not try to use Libwww.\n\nOPTION(WITH_LIBWWW_STATIC \"Use only static libraries for libwww\" OFF)\n\n# also defined, but not for general use are\nIF(LIBWWW_LIBRARIES AND LIBWWW_INCLUDE_DIR)\n  # in cache already\n  SET(Libwww_FIND_QUIETLY TRUE)\nENDIF(LIBWWW_LIBRARIES AND LIBWWW_INCLUDE_DIR)\n\nFIND_PATH(LIBWWW_INCLUDE_DIR\n  WWWInit.h\n  PATHS\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES libwww w3c-libwww\n)\n\n# when installing libwww on mac os x using macports the file wwwconf.h resides\n# in /opt/local/include and not in the real libwww include dir :/\nFIND_PATH(LIBWWW_ADDITIONAL_INCLUDE_DIR\n  wwwconf.h\n  PATHS\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\n# combine both include directories into one variable\nIF(LIBWWW_ADDITIONAL_INCLUDE_DIR)\n  SET(LIBWWW_INCLUDE_DIR ${LIBWWW_INCLUDE_DIR} ${LIBWWW_ADDITIONAL_INCLUDE_DIR})\nENDIF(LIBWWW_ADDITIONAL_INCLUDE_DIR)\n\n# helper to find all the libwww sub libraries\nMACRO(FIND_WWW_LIBRARY MYLIBRARY OPTION FILE)\n  IF(WITH_LIBWWW_STATIC AND UNIX AND NOT APPLE AND NOT WITH_STATIC_EXTERNAL)\n    SET(CMAKE_FIND_LIBRARY_SUFFIXES_OLD ${CMAKE_FIND_LIBRARY_SUFFIXES})\n    SET(CMAKE_FIND_LIBRARY_SUFFIXES \".a\")\n  ENDIF(WITH_LIBWWW_STATIC AND UNIX AND NOT APPLE AND NOT WITH_STATIC_EXTERNAL)\n\n  FIND_LIBRARY(${MYLIBRARY}_RELEASE\n    NAMES ${FILE}\n    PATHS\n    /usr/local/lib\n    /usr/lib\n    /usr/lib/x86_64-linux-gnu\n    /usr/local/X11R6/lib\n    /usr/X11R6/lib\n    /sw/lib\n    /opt/local/lib\n    /opt/csw/lib\n    /opt/lib\n    /usr/freeware/lib64\n  )\n\n  FIND_LIBRARY(${MYLIBRARY}_DEBUG\n    NAMES ${FILE}d\n    PATHS\n    /usr/local/lib\n    /usr/lib\n    /usr/lib/x86_64-linux-gnu\n    /usr/local/X11R6/lib\n    /usr/X11R6/lib\n    /sw/lib\n    /opt/local/lib\n    /opt/csw/lib\n    /opt/lib\n    /usr/freeware/lib64\n  )\n\n  IF(CMAKE_FIND_LIBRARY_SUFFIXES_OLD)\n    SET(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_OLD})\n  ENDIF(CMAKE_FIND_LIBRARY_SUFFIXES_OLD)\n\n  IF(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG)\n    IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n      SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} optimized ${${MYLIBRARY}_RELEASE} debug ${${MYLIBRARY}_DEBUG})\n    ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n  ELSEIF(${MYLIBRARY}_RELEASE)\n    IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n      SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} ${${MYLIBRARY}_RELEASE})\n    ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n  ELSEIF(${MYLIBRARY}_DEBUG)\n    IF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n      SET(LIBWWW_LIBRARIES ${LIBWWW_LIBRARIES} ${${MYLIBRARY}_DEBUG})\n    ENDIF(${OPTION} STREQUAL REQUIRED OR WITH_STATIC OR WITH_LIBWWW_STATIC)\n  ELSE(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG)\n    IF(NOT Libwww_FIND_QUIETLY AND NOT WIN32)\n      MESSAGE(STATUS \"Warning: Libwww: Library not found: ${MYLIBRARY}\")\n    ENDIF(NOT Libwww_FIND_QUIETLY AND NOT WIN32)\n  ENDIF(${MYLIBRARY}_RELEASE AND ${MYLIBRARY}_DEBUG)\n\n  MARK_AS_ADVANCED(${MYLIBRARY}_RELEASE ${MYLIBRARY}_DEBUG)\nENDMACRO(FIND_WWW_LIBRARY)\n\nMACRO(LINK_WWW_LIBRARY MYLIBRARY OTHERLIBRARY SYMBOL)\n  IF(NOT WITH_LIBWWW_STATIC AND NOT  WITH_STATIC_EXTERNAL)\n    LINK_DEPENDS(LIBWWW_LIBRARIES ${MYLIBRARY} ${OTHERLIBRARY} ${SYMBOL})\n  ENDIF(NOT WITH_LIBWWW_STATIC AND NOT  WITH_STATIC_EXTERNAL)\nENDMACRO(LINK_WWW_LIBRARY)\n\n# Find and link required libs for static or dynamic\nFIND_WWW_LIBRARY(LIBWWWAPP_LIBRARY REQUIRED wwwapp) # cache core file ftp gopher html http mime news stream telnet trans utils zip xml xmlparse\nFIND_WWW_LIBRARY(LIBWWWCORE_LIBRARY REQUIRED wwwcore) # utils\nFIND_WWW_LIBRARY(LIBWWWFILE_LIBRARY REQUIRED wwwfile) # core trans utils html\nFIND_WWW_LIBRARY(LIBWWWHTML_LIBRARY REQUIRED wwwhtml) # core utils\nFIND_WWW_LIBRARY(LIBWWWHTTP_LIBRARY REQUIRED wwwhttp) # md5 core mime stream utils\nFIND_WWW_LIBRARY(LIBWWWMIME_LIBRARY REQUIRED wwwmime) # core cache stream utils\n\n# Required for static or if underlinking\nFIND_WWW_LIBRARY(LIBWWWCACHE_LIBRARY OPTIONAL wwwcache) # core trans utils\nFIND_WWW_LIBRARY(LIBWWWSTREAM_LIBRARY OPTIONAL wwwstream) # core file utils\n\nFIND_WWW_LIBRARY(LIBWWWTRANS_LIBRARY REQUIRED wwwtrans) # core utils\nFIND_WWW_LIBRARY(LIBWWWUTILS_LIBRARY REQUIRED wwwutils)\n\n\n# Required only if underlinking\n\n# Unused protocols\nFIND_WWW_LIBRARY(LIBWWWFTP_LIBRARY OPTIONAL wwwftp) # core file utils\nFIND_WWW_LIBRARY(LIBWWWGOPHER_LIBRARY OPTIONAL wwwgopher) # core html utils file\nFIND_WWW_LIBRARY(LIBWWWNEWS_LIBRARY OPTIONAL wwwnews) # core html mime stream utils\nFIND_WWW_LIBRARY(LIBWWWTELNET_LIBRARY OPTIONAL wwwtelnet) # core utils\n\n# Other used by app\nFIND_WWW_LIBRARY(LIBWWWDIR_LIBRARY OPTIONAL wwwdir) # file\nFIND_WWW_LIBRARY(LIBWWWINIT_LIBRARY OPTIONAL wwwinit) # app cache core file html utils\nFIND_WWW_LIBRARY(LIBWWWMUX_LIBRARY OPTIONAL wwwmux) # core stream trans utils\nFIND_WWW_LIBRARY(LIBWWWXML_LIBRARY OPTIONAL wwwxml) # core utils xmlparse\nFIND_WWW_LIBRARY(LIBWWWZIP_LIBRARY OPTIONAL wwwzip) # core utils\nFIND_WWW_LIBRARY(LIBXMLPARSE_LIBRARY OPTIONAL xmlparse) # xmltok\n\n# Other used by other\nFIND_WWW_LIBRARY(LIBXMLTOK_LIBRARY OPTIONAL xmltok)\nFIND_WWW_LIBRARY(LIBWWWSSL_LIBRARY OPTIONAL wwwssl)\nFIND_WWW_LIBRARY(LIBMD5_LIBRARY OPTIONAL md5)\nFIND_WWW_LIBRARY(LIBPICS_LIBRARY OPTIONAL pics)\n\n# Other external libraries\nFIND_PACKAGE(EXPAT QUIET)\nFIND_PACKAGE(OpenSSL QUIET)\nFIND_WWW_LIBRARY(LIBREGEX_LIBRARY OPTIONAL gnu_regex)\n\n# Now link all libs together\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWCACHE_LIBRARY HTLoadCache)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWCACHE_LIBRARY HTCacheAppend)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWFTP_LIBRARY HTLoadFTP)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWGOPHER_LIBRARY HTLoadGopher)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWNEWS_LIBRARY HTLoadNews)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWTELNET_LIBRARY HTLoadTelnet)\n\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWSTREAM_LIBRARY HTStreamToChunk)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWSTREAM_LIBRARY HTGuess_new)\nLINK_WWW_LIBRARY(LIBWWWFILE_LIBRARY LIBWWWDIR_LIBRARY HTDir_new)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWINIT_LIBRARY HTProtocolInit)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWXML_LIBRARY HTXML_new)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBWWWZIP_LIBRARY HTZLib_inflate)\n\n# libwwwxml can be linked to xmlparse or expat\nLINK_WWW_LIBRARY(LIBWWWXML_LIBRARY LIBXMLPARSE_LIBRARY XML_ParserCreate)\n\nIF(LIBXMLPARSE_LIBRARY_LINKED)\n  LINK_WWW_LIBRARY(LIBXMLPARSE_LIBRARY EXPAT_LIBRARY XmlInitEncoding)\nELSE(LIBXMLPARSE_LIBRARY_LINKED)\n  LINK_WWW_LIBRARY(LIBWWWXML_LIBRARY EXPAT_LIBRARY XML_ParserCreate)\nENDIF(LIBXMLPARSE_LIBRARY_LINKED)\n\nLINK_WWW_LIBRARY(LIBWWWHTTP_LIBRARY LIBMD5_LIBRARY MD5Init)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY LIBREGEX_LIBRARY regexec)\nLINK_WWW_LIBRARY(LIBWWWAPP_LIBRARY OPENSSL_LIBRARIES SSL_new)\n\nINCLUDE(FindPackageHandleStandardArgs)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Libwww DEFAULT_MSG\n  LIBWWW_LIBRARIES\n  LIBWWW_INCLUDE_DIR\n)\n"
  },
  {
    "path": "code/CMakeModules/FindLua51.cmake",
    "content": "# Locate Lua library\n# This module defines\n#  LUA51_FOUND, if false, do not try to link to Lua\n#  LUA_LIBRARIES\n#  LUA_INCLUDE_DIR, where to find lua.h\n#  LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)\n#\n# Note that the expected include convention is\n#  #include \"lua.h\"\n# and not\n#  #include <lua/lua.h>\n# This is because, the lua location is not standardized and may exist\n# in locations other than lua/\n\n#=============================================================================\n# Copyright 2007-2009 Kitware, Inc.\n#\n# Distributed under the OSI-approved BSD License (the \"License\");\n# see accompanying file Copyright.txt for details.\n#\n# This software is distributed WITHOUT ANY WARRANTY; without even the\n# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the License for more information.\n#=============================================================================\n# (To distribute this file outside of CMake, substitute the full\n#  License text for the above reference.)\n\nfind_path(LUA_INCLUDE_DIR lua.h\n  HINTS\n    ENV LUA_DIR\n  PATH_SUFFIXES include/lua51 include/lua5.1 include/lua-5.1 include/lua include\n  PATHS\n  ~/Library/Frameworks\n  /Library/Frameworks\n  /sw # Fink\n  /opt/local # DarwinPorts\n  /opt/csw # Blastwave\n  /opt\n)\n\nfind_library(LUA_LIBRARY\n  NAMES lua51 lua5.1 lua-5.1 lua\n  HINTS\n    ENV LUA_DIR\n  PATH_SUFFIXES lib\n  PATHS\n  ~/Library/Frameworks\n  /Library/Frameworks\n  /sw\n  /opt/local\n  /opt/csw\n  /opt\n  /usr/lib/x86_64-linux-gnu\n  /usr/lib/arm-linux-gnueabihf\n)\n\nif(LUA_LIBRARY)\n  # include the math library for Unix\n  if(UNIX AND NOT APPLE AND NOT BEOS)\n    find_library(LUA_MATH_LIBRARY m)\n    set( LUA_LIBRARIES \"${LUA_LIBRARY};${LUA_MATH_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  # For Windows and Mac, don't need to explicitly include the math library\n  else()\n    set( LUA_LIBRARIES \"${LUA_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  endif()\nendif()\n\nif(LUA_INCLUDE_DIR AND EXISTS \"${LUA_INCLUDE_DIR}/lua.h\")\n  file(STRINGS \"${LUA_INCLUDE_DIR}/lua.h\" lua_version_str REGEX \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua .+\\\"\")\n\n  string(REGEX REPLACE \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua ([^\\\"]+)\\\".*\" \"\\\\1\" LUA_VERSION_STRING \"${lua_version_str}\")\n  unset(lua_version_str)\nendif()\n\ninclude(FindPackageHandleStandardArgs)\n# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if\n# all listed variables are TRUE\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua51\n                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR\n                                  VERSION_VAR LUA_VERSION_STRING)\n\nmark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)\n\n"
  },
  {
    "path": "code/CMakeModules/FindLua52.cmake",
    "content": "# Locate Lua library\n# This module defines\n#  LUA52_FOUND, if false, do not try to link to Lua\n#  LUA_LIBRARIES\n#  LUA_INCLUDE_DIR, where to find lua.h\n#  LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)\n#\n# Note that the expected include convention is\n#  #include \"lua.h\"\n# and not\n#  #include <lua/lua.h>\n# This is because, the lua location is not standardized and may exist\n# in locations other than lua/\n\n#=============================================================================\n# Copyright 2007-2009 Kitware, Inc.\n#\n# Distributed under the OSI-approved BSD License (the \"License\");\n# see accompanying file Copyright.txt for details.\n#\n# This software is distributed WITHOUT ANY WARRANTY; without even the\n# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the License for more information.\n#=============================================================================\n# (To distribute this file outside of CMake, substitute the full\n#  License text for the above reference.)\n\nfind_path(LUA_INCLUDE_DIR lua.h\n  HINTS\n    ENV LUA_DIR\n  PATH_SUFFIXES include/lua52 include/lua5.2 include/lua-5.2 include/lua include\n  PATHS\n  ~/Library/Frameworks\n  /Library/Frameworks\n  /sw # Fink\n  /opt/local # DarwinPorts\n  /opt/csw # Blastwave\n  /opt\n)\n\nfind_library(LUA_LIBRARY\n  NAMES lua52 lua5.2 lua-5.2 lua\n  HINTS\n    ENV LUA_DIR\n  PATH_SUFFIXES lib\n  PATHS\n  ~/Library/Frameworks\n  /Library/Frameworks\n  /sw\n  /opt/local\n  /opt/csw\n  /opt\n)\n\nif(LUA_LIBRARY)\n  # include the math library for Unix\n  if(UNIX AND NOT APPLE AND NOT BEOS)\n    find_library(LUA_MATH_LIBRARY m)\n    set( LUA_LIBRARIES \"${LUA_LIBRARY};${LUA_MATH_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  # For Windows and Mac, don't need to explicitly include the math library\n  else()\n    set( LUA_LIBRARIES \"${LUA_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  endif()\nendif()\n\nif(LUA_INCLUDE_DIR AND EXISTS \"${LUA_INCLUDE_DIR}/lua.h\")\n  file(STRINGS \"${LUA_INCLUDE_DIR}/lua.h\" lua_version_str REGEX \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua .+\\\"\")\n\n  string(REGEX REPLACE \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua ([^\\\"]+)\\\".*\" \"\\\\1\" LUA_VERSION_STRING \"${lua_version_str}\")\n  unset(lua_version_str)\nendif()\n\ninclude(FindPackageHandleStandardArgs)\n# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if\n# all listed variables are TRUE\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua52\n                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR\n                                  VERSION_VAR LUA_VERSION_STRING)\n\nmark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)\n\n"
  },
  {
    "path": "code/CMakeModules/FindLua53.cmake",
    "content": "# Locate Lua library\n# This module defines\n#  LUA51_FOUND, if false, do not try to link to Lua\n#  LUA_LIBRARIES\n#  LUA_INCLUDE_DIR, where to find lua.h\n#  LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)\n#\n# Note that the expected include convention is\n#  #include \"lua.h\"\n# and not\n#  #include <lua/lua.h>\n# This is because, the lua location is not standardized and may exist\n# in locations other than lua/\n\n#=============================================================================\n# Copyright 2007-2009 Kitware, Inc.\n#\n# Distributed under the OSI-approved BSD License (the \"License\");\n# see accompanying file Copyright.txt for details.\n#\n# This software is distributed WITHOUT ANY WARRANTY; without even the\n# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the License for more information.\n#=============================================================================\n# (To distribute this file outside of CMake, substitute the full\n#  License text for the above reference.)\n\nfind_path(LUA_INCLUDE_DIR lua.h\n  PATH_SUFFIXES lua53\n  PATHS\n  /usr/local/include\n  ~/Library/Frameworks\n)\n\nfind_library(LUA_LIBRARY\n  NAMES lua53 liblua.a\n  PATH_SUFFIXES lib\n  PATHS\n  /usr/local/lib\n)\n\nif(LUA_LIBRARY)\n  # include the math library for Unix\n  if(UNIX AND NOT APPLE AND NOT BEOS)\n    find_library(LUA_MATH_LIBRARY m)\n    set( LUA_LIBRARIES \"${LUA_LIBRARY};${LUA_MATH_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  # For Windows and Mac, don't need to explicitly include the math library\n  else()\n    set( LUA_LIBRARIES \"${LUA_LIBRARY}\" CACHE STRING \"Lua Libraries\")\n  endif()\nendif()\n\nif(LUA_INCLUDE_DIR AND EXISTS \"${LUA_INCLUDE_DIR}/lua.h\")\n  file(STRINGS \"${LUA_INCLUDE_DIR}/lua.h\" lua_version_str REGEX \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua .+\\\"\")\n\n  string(REGEX REPLACE \"^#define[ \\t]+LUA_RELEASE[ \\t]+\\\"Lua ([^\\\"]+)\\\".*\" \"\\\\1\" LUA_VERSION_STRING \"${lua_version_str}\")\n  unset(lua_version_str)\nendif()\n\ninclude(FindPackageHandleStandardArgs)\n# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if\n# all listed variables are TRUE\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua53\n                                  REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR\n                                  VERSION_VAR LUA_VERSION_STRING)\n\nmark_as_advanced(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY)\n\n"
  },
  {
    "path": "code/CMakeModules/FindLuabind.cmake",
    "content": "# - Locate Luabind library\n# This module defines\n#  LUABIND_LIBRARIES, the libraries to link against\n#  LUABIND_FOUND, if false, do not try to link to LUABIND\n#  LUABIND_INCLUDE_DIR, where to find headers.\n\nMACRO(FIND_CORRECT_LUA_VERSION)\n  # Check Lua version linked to Luabind under Linux\n  IF(LUABIND_LIBRARY_RELEASE MATCHES \"\\\\.so\")\n    INCLUDE(CheckDepends)\n\n    SET(LUA52_LIBRARY \"liblua5.2\")\n    CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND)\n    \n    IF(NOT LUALIB_FOUND)\n      # fedora (v20)\n      SET(LUA52_LIBRARY \"liblua-5.2\")\n      CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA52_LIBRARY LUALIB_FOUND)\n    ENDIF(NOT LUALIB_FOUND)\n\n    IF(LUALIB_FOUND)\n      MESSAGE(STATUS \"Luabind is using Lua 5.2\")\n      FIND_PACKAGE(Lua52 REQUIRED)\n    ELSE(LUALIB_FOUND)\n      SET(LUA51_LIBRARY \"liblua5.1\")\n      CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA51_LIBRARY LUALIB_FOUND)\n\n      IF(LUALIB_FOUND)\n        MESSAGE(STATUS \"Luabind is using Lua 5.1\")\n        FIND_PACKAGE(Lua51 REQUIRED)\n      ELSE(LUALIB_FOUND)\n        SET(LUA50_LIBRARY \"liblua5.0\")\n        CHECK_LINKED_LIBRARY(LUABIND_LIBRARY_RELEASE LUA50_LIBRARY LUALIB_FOUND)\n\n        IF(LUALIB_FOUND)\n          MESSAGE(STATUS \"Luabind is using Lua 5.0\")\n          FIND_PACKAGE(Lua50 REQUIRED)\n        ELSE(LUALIB_FOUND)\n          MESSAGE(FATAL_ERROR \"Can't determine Lua version used by Luabind\")\n        ENDIF(LUALIB_FOUND)\n      ENDIF(LUALIB_FOUND)\n    ENDIF(LUALIB_FOUND)\n  ELSE(LUABIND_LIBRARY_RELEASE MATCHES \"\\\\.so\")\n    # TODO: find a way to detect Lua version\n    IF(WITH_LUA52)\n      FIND_PACKAGE(Lua52 REQUIRED)\n    ELSEIF(WITH_LUA51)\n      FIND_PACKAGE(Lua51 REQUIRED)\n    ELSE(WITH_LUA52)\n      FIND_PACKAGE(Lua50 REQUIRED)\n    ENDIF(WITH_LUA52)\n  ENDIF(LUABIND_LIBRARY_RELEASE MATCHES \"\\\\.so\")\nENDMACRO(FIND_CORRECT_LUA_VERSION)\n\nIF(LUABIND_LIBRARIES AND LUABIND_INCLUDE_DIR)\n  # in cache already\n  SET(Luabind_FIND_QUIETLY TRUE)\nENDIF(LUABIND_LIBRARIES AND LUABIND_INCLUDE_DIR)\n\nFIND_PATH(LUABIND_INCLUDE_DIR\n  luabind/luabind.hpp\n  PATHS\n  $ENV{LUABIND_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\nSET(LIBRARY_NAME_RELEASE)\nSET(LIBRARY_NAME_DEBUG)\n\nIF(WITH_LUA52)\n  IF(WITH_STLPORT)\n    LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua52)\n    LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua52d)\n  ENDIF(WITH_STLPORT)\n\n  LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua52)\n  LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua52d)\nENDIF()\n\nIF(WITH_LUA51)\n  IF(WITH_STLPORT)\n    LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua51)\n    LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua51d)\n  ENDIF(WITH_STLPORT)\n\n  LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua51)\n  LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua51d)\nENDIF()\n\nIF(WITH_LUA50)\n  IF(WITH_STLPORT)\n    LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport_lua50)\n    LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlport_lua50d)\n  ENDIF(WITH_STLPORT)\n\n  LIST(APPEND LIBRARY_NAME_RELEASE luabind_lua50)\n  LIST(APPEND LIBRARY_NAME_DEBUG luabind_lua50d)\nENDIF()\n\nIF(WITH_STLPORT)\n  LIST(APPEND LIBRARY_NAME_RELEASE luabind_stlport)\n  LIST(APPEND LIBRARY_NAME_DEBUG luabind_stlportd)\nENDIF(WITH_STLPORT)\n\n# generic libraries names\nLIST(APPEND LIBRARY_NAME_RELEASE luabind libluabind)\nLIST(APPEND LIBRARY_NAME_DEBUG luabind_d luabindd libluabind_d libluabindd)\n\nFIND_LIBRARY(LUABIND_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{LUABIND_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(LUABIND_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{LUABIND_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_PACKAGE(Boost REQUIRED)\n\nIF(LUABIND_INCLUDE_DIR AND Boost_INCLUDE_DIR)\n  IF(LUABIND_LIBRARY_RELEASE AND LUABIND_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(LUABIND_FOUND TRUE)\n    SET(LUABIND_LIBRARIES optimized ${LUABIND_LIBRARY_RELEASE} debug ${LUABIND_LIBRARY_DEBUG})\n  ELSEIF(LUABIND_LIBRARY_RELEASE)\n    # Normal case\n    SET(LUABIND_FOUND TRUE)\n    SET(LUABIND_LIBRARIES ${LUABIND_LIBRARY_RELEASE})\n  ELSEIF(LUABIND_LIBRARY_DEBUG)\n    # Case where Luabind is compiled from sources (debug version is compiled by default)\n    SET(LUABIND_FOUND TRUE)\n    SET(LUABIND_LIBRARIES ${LUABIND_LIBRARY_DEBUG})\n  ENDIF(LUABIND_LIBRARY_RELEASE AND LUABIND_LIBRARY_DEBUG)\nENDIF(LUABIND_INCLUDE_DIR AND Boost_INCLUDE_DIR)\n\nIF(LUABIND_FOUND)\n  SET(LUABIND_INCLUDE_DIR ${LUABIND_INCLUDE_DIR} ${Boost_INCLUDE_DIR})\n  # Check if luabind/version.hpp exists\n  FIND_FILE(LUABIND_VERSION_FILE luabind/version.hpp PATHS ${LUABIND_INCLUDE_DIR})\n  IF(LUABIND_VERSION_FILE)\n    SET(LUABIND_DEFINITIONS \"-DHAVE_LUABIND_VERSION\")\n  ENDIF(LUABIND_VERSION_FILE)\n\n  FIND_CORRECT_LUA_VERSION()\n\n  IF(NOT Luabind_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Luabind: ${LUABIND_LIBRARIES}\")\n  ENDIF(NOT Luabind_FIND_QUIETLY)\nELSE(LUABIND_FOUND)\n  IF(NOT Luabind_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Luabind!\")\n  ENDIF(NOT Luabind_FIND_QUIETLY)\nENDIF(LUABIND_FOUND)\n\nMARK_AS_ADVANCED(LUABIND_LIBRARY_RELEASE LUABIND_LIBRARY_DEBUG Boost_LIB_DIAGNOSTIC_DEFINITIONS)\n"
  },
  {
    "path": "code/CMakeModules/FindMSVC.cmake",
    "content": "# - Find MS Visual C++\n#\n#  VC_INCLUDE_DIR  - where to find headers\n#  VC_INCLUDE_DIRS - where to find headers\n#  VC_LIBRARY_DIR  - where to find libraries\n#  VC_FOUND        - True if MSVC found.\n\nMACRO(DETECT_VC_VERSION_HELPER _ROOT _VERSION)\n  # Software/Wow6432Node/...\n  GET_FILENAME_COMPONENT(VC${_VERSION}_DIR \"[${_ROOT}\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VC7;${_VERSION}]\" ABSOLUTE)\n\n  IF(VC${_VERSION}_DIR AND VC${_VERSION}_DIR STREQUAL \"/registry\")\n    SET(VC${_VERSION}_DIR)\n    GET_FILENAME_COMPONENT(VC${_VERSION}_DIR \"[${_ROOT}\\\\SOFTWARE\\\\Microsoft\\\\VisualStudio\\\\SxS\\\\VS7;${_VERSION}]\" ABSOLUTE)\n    IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL \"/registry\")\n      SET(VC${_VERSION}_DIR \"${VC${_VERSION}_DIR}VC/\")\n    ENDIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL \"/registry\")\n  ENDIF(VC${_VERSION}_DIR AND VC${_VERSION}_DIR STREQUAL \"/registry\")\n\n  IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL \"/registry\")\n    SET(VC${_VERSION}_FOUND ON)\n    DETECT_EXPRESS_VERSION(${_VERSION})\n    IF(NOT MSVC_FIND_QUIETLY)\n      SET(_VERSION_STR ${_VERSION})\n      IF(MSVC_EXPRESS)\n        SET(_VERSION_STR \"${_VERSION_STR} Express\")\n      ENDIF(MSVC_EXPRESS)\n      MESSAGE(STATUS \"Found Visual C++ ${_VERSION_STR} in ${VC${_VERSION}_DIR}\")\n    ENDIF(NOT MSVC_FIND_QUIETLY)\n  ELSEIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL \"/registry\")\n    SET(VC${_VERSION}_FOUND OFF)\n    SET(VC${_VERSION}_DIR \"\")\n  ENDIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL \"/registry\")\nENDMACRO(DETECT_VC_VERSION_HELPER)\n\nMACRO(DETECT_VC_VERSION _VERSION)\n  SET(VC${_VERSION}_FOUND OFF)\n  DETECT_VC_VERSION_HELPER(\"HKEY_CURRENT_USER\" ${_VERSION})\n\n  IF(NOT VC${_VERSION}_FOUND)\n    DETECT_VC_VERSION_HELPER(\"HKEY_LOCAL_MACHINE\" ${_VERSION})\n  ENDIF(NOT VC${_VERSION}_FOUND)\n\n  IF(VC${_VERSION}_FOUND)\n    SET(VC_FOUND ON)\n    SET(VC_DIR \"${VC${_VERSION}_DIR}\")\n  ENDIF(VC${_VERSION}_FOUND)\nENDMACRO(DETECT_VC_VERSION)\n\nMACRO(DETECT_EXPRESS_VERSION _VERSION)\n  GET_FILENAME_COMPONENT(MSVC_EXPRESS \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\VCExpress\\\\${_VERSION}\\\\Setup\\\\VC;ProductDir]\" ABSOLUTE)\n\n  IF(MSVC_EXPRESS AND NOT MSVC_EXPRESS STREQUAL \"/registry\")\n    SET(MSVC_EXPRESS ON)\n  ENDIF(MSVC_EXPRESS AND NOT MSVC_EXPRESS STREQUAL \"/registry\")\nENDMACRO(DETECT_EXPRESS_VERSION)\n\nIF(MSVC12)\n  DETECT_VC_VERSION(\"12.0\")\n  SET(MSVC_TOOLSET \"120\")\n\n  IF(NOT MSVC12_REDIST_DIR)\n    # If you have VC++ 2013 Express, put x64/Microsoft.VC120.CRT/*.dll in ${EXTERNAL_PATH}/redist\n    SET(MSVC12_REDIST_DIR \"${EXTERNAL_PATH}/redist\")\n  ENDIF(NOT MSVC12_REDIST_DIR)\nELSEIF(MSVC11)\n  DETECT_VC_VERSION(\"11.0\")\n  SET(MSVC_TOOLSET \"110\")\n\n  IF(NOT MSVC11_REDIST_DIR)\n    # If you have VC++ 2012 Express, put x64/Microsoft.VC110.CRT/*.dll in ${EXTERNAL_PATH}/redist\n    SET(MSVC11_REDIST_DIR \"${EXTERNAL_PATH}/redist\")\n  ENDIF(NOT MSVC11_REDIST_DIR)\nELSEIF(MSVC10)\n  DETECT_VC_VERSION(\"10.0\")\n  SET(MSVC_TOOLSET \"100\")\n\n  IF(NOT MSVC10_REDIST_DIR)\n    # If you have VC++ 2010 Express, put x64/Microsoft.VC100.CRT/*.dll in ${EXTERNAL_PATH}/redist\n    SET(MSVC10_REDIST_DIR \"${EXTERNAL_PATH}/redist\")\n  ENDIF(NOT MSVC10_REDIST_DIR)\nELSEIF(MSVC90)\n  DETECT_VC_VERSION(\"9.0\")\n  SET(MSVC_TOOLSET \"90\")\nELSEIF(MSVC80)\n  DETECT_VC_VERSION(\"8.0\")\n  SET(MSVC_TOOLSET \"80\")\nENDIF(MSVC12)\n\n# If you plan to use VC++ compilers with WINE, set VC_DIR environment variable\nIF(NOT VC_DIR)\n  SET(VC_DIR $ENV{VC_DIR})\nENDIF(NOT VC_DIR)\n\nIF(NOT VC_DIR)\n  STRING(REGEX REPLACE \"/bin/.+\" \"\" VC_DIR ${CMAKE_CXX_COMPILER})\nENDIF(NOT VC_DIR)\n\nSET(VC_INCLUDE_DIR \"${VC_DIR}/include\")\nSET(VC_INCLUDE_DIRS ${VC_INCLUDE_DIR})\nINCLUDE_DIRECTORIES(${VC_INCLUDE_DIR})\n"
  },
  {
    "path": "code/CMakeModules/FindMercurial.cmake",
    "content": "# - Extract information from a subversion working copy\n# The module defines the following variables:\n#  Mercurial_HG_EXECUTABLE - path to hg command line client\n#  Mercurial_VERSION_HG - version of hg command line client\n#  Mercurial_FOUND - true if the command line client was found\n#  MERCURIAL_FOUND - same as Mercurial_FOUND, set for compatiblity reasons\n#\n# The minimum required version of Mercurial can be specified using the\n# standard syntax, e.g. FIND_PACKAGE(Mercurial 1.4)\n#\n# If the command line client executable is found two macros are defined:\n#  Mercurial_WC_INFO(<dir> <var-prefix>)\n#  Mercurial_WC_LOG(<dir> <var-prefix>)\n# Mercurial_WC_INFO extracts information of a subversion working copy at\n# a given location. This macro defines the following variables:\n#  <var-prefix>_WC_URL - url of the repository (at <dir>)\n#  <var-prefix>_WC_ROOT - root url of the repository\n#  <var-prefix>_WC_REVISION - current revision\n#  <var-prefix>_WC_LAST_CHANGED_AUTHOR - author of last commit\n#  <var-prefix>_WC_LAST_CHANGED_DATE - date of last commit\n#  <var-prefix>_WC_LAST_CHANGED_REV - revision of last commit\n#  <var-prefix>_WC_INFO - output of command `hg info <dir>'\n# Mercurial_WC_LOG retrieves the log message of the base revision of a\n# subversion working copy at a given location. This macro defines the\n# variable:\n#  <var-prefix>_LAST_CHANGED_LOG - last log of base revision\n# Example usage:\n#  FIND_PACKAGE(Mercurial)\n#  IF(MERCURIAL_FOUND)\n#    Mercurial_WC_INFO(${PROJECT_SOURCE_DIR} Project)\n#    MESSAGE(\"Current revision is ${Project_WC_REVISION}\")\n#    Mercurial_WC_LOG(${PROJECT_SOURCE_DIR} Project)\n#    MESSAGE(\"Last changed log is ${Project_LAST_CHANGED_LOG}\")\n#  ENDIF(MERCURIAL_FOUND)\n\n#=============================================================================\n# Copyright 2006-2009 Kitware, Inc.\n# Copyright 2006 Tristan Carel\n#\n# Distributed under the OSI-approved BSD License (the \"License\");\n# see accompanying file Copyright.txt for details.\n#\n# This software is distributed WITHOUT ANY WARRANTY; without even the\n# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n# See the License for more information.\n#=============================================================================\n# (To distribute this file outside of CMake, substitute the full\n#  License text for the above reference.)\n\nFIND_PROGRAM(Mercurial_HG_EXECUTABLE hg\n  DOC \"mercurial command line client\"\n  PATHS\n    /opt/local/bin\n    \"C:/Program Files/TortoiseHg\"\n    \"C:/Program Files (x86)/TortoiseHg\"\n  )\nMARK_AS_ADVANCED(Mercurial_HG_EXECUTABLE)\n\nIF(Mercurial_HG_EXECUTABLE)\n  EXECUTE_PROCESS(COMMAND ${Mercurial_HG_EXECUTABLE} --version\n    OUTPUT_VARIABLE Mercurial_VERSION_HG\n    OUTPUT_STRIP_TRAILING_WHITESPACE)\n\t\n  STRING(REGEX REPLACE \".*version ([\\\\.0-9]+).*\"\n    \"\\\\1\" Mercurial_VERSION_HG \"${Mercurial_VERSION_HG}\")\n\n  MACRO(Mercurial_WC_INFO dir prefix)\n    EXECUTE_PROCESS(COMMAND ${Mercurial_HG_EXECUTABLE} tip --template \"{rev};{node};{tags};{author}\"\n      WORKING_DIRECTORY ${dir}\n      OUTPUT_VARIABLE ${prefix}_WC_INFO\n      ERROR_VARIABLE Mercurial_hg_info_error\n      RESULT_VARIABLE Mercurial_hg_info_result\n      OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n    IF(NOT ${Mercurial_hg_info_result} EQUAL 0)\n      MESSAGE(SEND_ERROR \"Command \\\"${Mercurial_HG_EXECUTABLE} tip\\\" failed with output:\\n${Mercurial_hg_info_error}\")\n    ELSE(NOT ${Mercurial_hg_info_result} EQUAL 0)\n      LIST(LENGTH ${prefix}_WC_INFO _COUNT)\n      IF(_COUNT EQUAL 4)\n        LIST(GET ${prefix}_WC_INFO 0 ${prefix}_WC_REVISION)\n        LIST(GET ${prefix}_WC_INFO 1 ${prefix}_WC_CHANGESET)\n        LIST(GET ${prefix}_WC_INFO 2 ${prefix}_WC_BRANCH)\n        LIST(GET ${prefix}_WC_INFO 3 ${prefix}_WC_LAST_CHANGED_AUTHOR)\n      ELSE(_COUNT EQUAL 4)\n        MESSAGE(STATUS \"Bad output from HG\")\n        SET(${prefix}_WC_REVISION \"unknown\")\n        SET(${prefix}_WC_CHANGESET \"unknown\")\n        SET(${prefix}_WC_BRANCH \"unknown\")\n      ENDIF(_COUNT EQUAL 4)\n    ENDIF(NOT ${Mercurial_hg_info_result} EQUAL 0)\n\n  ENDMACRO(Mercurial_WC_INFO)\n\n  MACRO(Mercurial_WC_LOG dir prefix)\n    # This macro can block if the certificate is not signed:\n    # hg ask you to accept the certificate and wait for your answer\n    # This macro requires a hg server network access (Internet most of the time)\n    # and can also be slow since it access the hg server\n    EXECUTE_PROCESS(COMMAND\n      ${Mercurial_HG_EXECUTABLE} --non-interactive log -r BASE ${dir}\n      OUTPUT_VARIABLE ${prefix}_LAST_CHANGED_LOG\n      ERROR_VARIABLE Mercurial_hg_log_error\n      RESULT_VARIABLE Mercurial_hg_log_result\n      OUTPUT_STRIP_TRAILING_WHITESPACE)\n\n    IF(NOT ${Mercurial_hg_log_result} EQUAL 0)\n      MESSAGE(SEND_ERROR \"Command \\\"${Mercurial_HG_EXECUTABLE} log -r BASE ${dir}\\\" failed with output:\\n${Mercurial_hg_log_error}\")\n    ENDIF(NOT ${Mercurial_hg_log_result} EQUAL 0)\n  ENDMACRO(Mercurial_WC_LOG)\nENDIF(Mercurial_HG_EXECUTABLE)\n\nINCLUDE(FindPackageHandleStandardArgs)\nFIND_PACKAGE_HANDLE_STANDARD_ARGS(Mercurial DEFAULT_MSG Mercurial_HG_EXECUTABLE)\n"
  },
  {
    "path": "code/CMakeModules/FindMySQL.cmake",
    "content": "# - Find MySQL\n# Find the MySQL includes and client library\n# This module defines\n#  MYSQL_INCLUDE_DIR, where to find mysql.h\n#  MYSQL_LIBRARIES, the libraries needed to use MySQL.\n#  MYSQL_FOUND, If false, do not try to use MySQL.\n#\n# Copyright (c) 2006, Jaroslaw Staniek, <js@iidea.pl>\n#\n# Redistribution and use is allowed according to the terms of the BSD license.\n# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n\nIF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES)\n   SET(MYSQL_FOUND TRUE)\n\nELSE()\n\n  FIND_PATH(MYSQL_INCLUDE_DIR mysql.h\n      PATH_SUFFIXES mysql\n      /usr/include/mysql\n      /usr/local/include/mysql\n      /opt/local/include/mysql5/mysql\n      $ENV{ProgramFiles}/MySQL/*/include\n      $ENV{SystemDrive}/MySQL/*/include)\n\n  IF(WIN32 AND MSVC)\n    FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysql mysqlclient\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n\n    FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES libmysqld mysqlclientd\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n  ELSE()\n    FIND_LIBRARY(MYSQL_LIBRARY_RELEASE NAMES libmysqlclient mysqlclient\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n\n    FIND_LIBRARY(MYSQL_LIBRARY_DEBUG NAMES mysqlclientd\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n  ENDIF()\n\n  IF(MYSQL_INCLUDE_DIR)\n    IF(MYSQL_LIBRARY_RELEASE)\n      IF(MYSQL_LIBRARY_DEBUG)\n        SET(MYSQL_LIBRARIES optimized ${MYSQL_LIBRARY_RELEASE} debug ${MYSQL_LIBRARY_DEBUG})\n      ELSE()\n\t    SET(MYSQL_LIBRARIES ${MYSQL_LIBRARY_RELEASE})\n      ENDIF()\n      FIND_PACKAGE(OpenSSL)\n      IF(OPENSSL_FOUND)\n        SET(MYSQL_LIBRARIES ${MYSQL_LIBRARIES} ${OPENSSL_LIBRARIES})\n      ENDIF()\n    ENDIF()\n  ENDIF()\n\n  IF(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES)\n    SET(MYSQL_FOUND TRUE)\n    MESSAGE(STATUS \"Found MySQL: ${MYSQL_INCLUDE_DIR}, ${MYSQL_LIBRARIES}\")\n  ELSE()\n    SET(MYSQL_FOUND FALSE)\n    MESSAGE(STATUS \"MySQL not found.\")\n  ENDIF()\n\n  MARK_AS_ADVANCED(MYSQL_LIBRARY_RELEASE MYSQL_LIBRARY_DEBUG)\n\nENDIF()\n"
  },
  {
    "path": "code/CMakeModules/FindMysqlConnector.cmake",
    "content": "# - Find MySQL\n# Find the MySQL includes and client library\n# This module defines\n#  MYSQL_INCLUDE_DIR, where to find mysql.h\n#  MYSQL_LIBRARIES, the libraries needed to use MySQL.\n#  MYSQL_FOUND, If false, do not try to use MySQL.\n#\n# Copyright (c) 2006, Jaroslaw Staniek, <js@iidea.pl>\n#\n# Redistribution and use is allowed according to the terms of the BSD license.\n# For details see the accompanying COPYING-CMAKE-SCRIPTS file.\n\nIF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n   SET(MYSQLCONNECTOR_FOUND TRUE)\n\nELSE(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n\n  FIND_PATH(MYSQLCONNECTOR_INCLUDE_DIR mysql_connection.h\n      PATH_SUFFIXES mysqlconnector\n      /usr/include/mysqlcppconn-static)\n\n# mysqlcppconn-static.lib\n  IF(WIN32 AND MSVC)\n    FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE NAMES mysqlcppconn-static\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n\n    FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG NAMES mysqlcppconn-static\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n  ELSE(WIN32 AND MSVC)\n    FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE NAMES mysqlcppconn-static\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n\n    FIND_LIBRARY(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG NAMES mysqlcppconn-static\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n  ENDIF(WIN32 AND MSVC)\n  \n# mysqlcppconn.lib\n  IF(WIN32 AND MSVC)\n    FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_RELEASE NAMES \"mysqlcppconn.lib\"\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n\n    FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_DEBUG NAMES \"mysqlcppconn.lib\"\n      PATHS\n      $ENV{ProgramFiles}/MySQL/*/lib/opt\n      $ENV{SystemDrive}/MySQL/*/lib/opt)\n  ELSE(WIN32 AND MSVC)\n    FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_RELEASE NAMES \"mysqlcppconn.lib\"\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n\n    FIND_LIBRARY(MYSQLCONNECTOR_LIBRARY_DEBUG NAMES \"mysqlcppconn.lib\"\n      PATHS\n      /usr/lib\n      /usr/local/lib\n      /usr/lib/mysql\n      /usr/local/lib/mysql\n      /opt/local/lib/mysql5/mysql\n      )\n  ENDIF(WIN32 AND MSVC)\n  \n  IF(MYSQLCONNECTOR_INCLUDE_DIR)\n    IF(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE AND MYSQLCONNECTOR_LIBRARY_RELEASE)\n      SET(MYSQLCONNECTOR_LIBRARIES optimized ${MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE} ${MYSQLCONNECTOR_LIBRARY_RELEASE})\n      IF(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG AND MYSQLCONNECTOR_LIBRARY_DEBUG)\n        SET(MYSQLCONNECTOR_LIBRARIES ${MYSQLCONNECTOR_LIBRARIES} debug ${MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG} ${MYSQLCONNECTOR_LIBRARY_DEBUG})\n      ENDIF(MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG AND MYSQLCONNECTOR_LIBRARY_DEBUG)\n      FIND_PACKAGE(OpenSSL)\n      IF(OPENSSL_FOUND)\n        SET(MYSQLCONNECTOR_LIBRARIES ${MYSQLCONNECTOR_LIBRARIES} ${OPENSSL_LIBRARIES})\n      ENDIF(OPENSSL_FOUND)\n    ENDIF(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE AND MYSQLCONNECTOR_LIBRARY_RELEASE)\n  ENDIF(MYSQLCONNECTOR_INCLUDE_DIR)\n  \n  IF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n\tSET(MYSQLCONNECTOR_INCLUDE_DIR ${MYSQLCONNECTOR_INCLUDE_DIR})\n    SET(MYSQL_FOUND TRUE)\n    MESSAGE(STATUS \"Found MySQL Connector: ${MYSQLCONNECTOR_INCLUDE_DIR}, ${MYSQLCONNECTOR_LIBRARIES}\")\n  ELSE(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n    SET(MYSQL_FOUND FALSE)\n    MESSAGE(STATUS \"MySQL not found.\")\n  ENDIF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n\n  MARK_AS_ADVANCED(MYSQLCONNECTOR_STATIC_LIBRARY_RELEASE MYSQLCONNECTOR_STATIC_LIBRARY_DEBUG MYSQLCONNECTOR_LIBRARY_RELEASE MYSQLCONNECTOR_LIBRARY_DEBUG)\n\nENDIF(MYSQLCONNECTOR_INCLUDE_DIR AND MYSQLCONNECTOR_LIBRARIES)\n\n\n\n"
  },
  {
    "path": "code/CMakeModules/FindOgg.cmake",
    "content": "# - Locate Ogg library\n# This module defines\n#  OGG_LIBRARY, the library to link against\n#  OGG_FOUND, if false, do not try to link to OGG\n#  OGG_INCLUDE_DIR, where to find headers.\n\nIF(OGG_LIBRARY AND OGG_INCLUDE_DIR)\n  # in cache already\n  SET(OGG_FIND_QUIETLY TRUE)\nENDIF(OGG_LIBRARY AND OGG_INCLUDE_DIR)\n\n\nFIND_PATH(OGG_INCLUDE_DIR\n  ogg/ogg.h\n  PATHS\n  $ENV{OGG_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\nFIND_LIBRARY(OGG_LIBRARY\n  NAMES ogg libogg\n  PATHS\n  $ENV{OGG_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(OGG_LIBRARY AND OGG_INCLUDE_DIR)\n  SET(OGG_FOUND \"YES\")\n  IF(NOT OGG_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Ogg: ${OGG_LIBRARY}\")\n  ENDIF(NOT OGG_FIND_QUIETLY)\nELSE(OGG_LIBRARY AND OGG_INCLUDE_DIR)\n  IF(NOT OGG_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Ogg!\")\n  ENDIF(NOT OGG_FIND_QUIETLY)\nENDIF(OGG_LIBRARY AND OGG_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindOpenGLES.cmake",
    "content": "# - Try to find OpenGL ES\n# Once done this will define\n#  \n#  OPENGLES_FOUND        - system has OpenGL ES\n#  OPENGLES_EGL_FOUND    - system has EGL\n#  OPENGLES_LIBRARIES    - Link these to use OpenGL ES and EGL\n#   \n# If you want to use just GL ES you can use these values\n#  OPENGLES_GLES_LIBRARY - Path to OpenGL ES Library\n#  OPENGLES_EGL_LIBRARY  - Path to EGL Library\n\nFIND_LIBRARY(OPENGLES_GLES_LIBRARY\n  NAMES GLESv1_CM libGLESv1_CM gles_cm libgles_cm\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(OPENGLES_EGL_LIBRARY\n  NAMES EGL libEGL\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(OPENGLES_GLES_LIBRARY)\n  SET(OPENGLES_FOUND \"YES\")\n  SET(OPENGLES_LIBRARIES ${OPENGLES_GLES_LIBRARY} ${OPENGLES_LIBRARIES})\n  IF(OPENGLES_EGL_LIBRARY)\n    SET(OPENGLES_EGL_FOUND \"YES\")\n    SET(OPENGLES_LIBRARIES ${OPENGLES_EGL_LIBRARY} ${OPENGLES_LIBRARIES})\n  ELSE(OPENGLES_EGL_LIBRARY)\n    SET(OPENGLES_EGL_FOUND \"NO\")\n  ENDIF(OPENGLES_EGL_LIBRARY)\nENDIF(OPENGLES_GLES_LIBRARY)\n"
  },
  {
    "path": "code/CMakeModules/FindOpenSSL.cmake",
    "content": "# - Locate OpenSSL library\n# This module defines\n# OPENSSL_INCLUDE_DIRS   - where to find openssl/ssl.h, etc.\n# OPENSSL_LIBRARIES      - List of libraries when using openssl.\n# OPENSSL_FOUND          - True if openssl found.\n# OPENSSL_VERSION_STRING - the version of openssl found (since CMake 2.8.8)\n\nIF(OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIR)\n  # in cache already\n  SET(OPENSSL_FIND_QUIETLY TRUE)\nENDIF(OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIR)\n\nFIND_PATH(OPENSSL_INCLUDE_DIR ssl.h\n  PATH_SUFFIXES openssl\n  $ENV{OPENSSL_DIR}/include\n  /usr/local/include\n  /usr/local/include/openssl\n)\n\nSET(LIBRARY_NAME_RELEASE libssl libssl.a)\nSET(LIBRARY_NAME_DEBUG libssl libssl.a)\n\nFIND_LIBRARY(OPENSSL_LIBRARIE_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{OPENSSL_DIR}/lib\n  /usr/local/lib64\n)\n\nFIND_LIBRARY(OPENSSL_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{OPENSSL_DIR}/lib\n  /usr/local/lib64\n)\n\nSET(LIBRARY_NAME_CRYPTO libcrypto libcrypto.a)\nFIND_LIBRARY(CRYPTO_LIBRARIE_RELEASE\n  NAMES ${LIBRARY_NAME_CRYPTO}\n  PATHS\n  $ENV{OPENSSL_DIR}/lib\n  /usr/local/lib64\n)\n\nIF(OPENSSL_INCLUDE_DIR)\n  IF(OPENSSL_LIBRARIE_RELEASE AND CRYPTO_LIBRARIE_RELEASE)\n    # Case where both Release and Debug versions are provided\n    SET(OPENSSL_FOUND TRUE)\n    #SET(OPENSSL_LIBRARIES optimized ${OPENSSL_LIBRARIE_RELEASE} debug ${OPENSSL_LIBRARY_DEBUG})\n    SET(OPENSSL_LIBRARIES \"${OPENSSL_LIBRARIE_RELEASE};${CRYPTO_LIBRARIE_RELEASE}\" CACHE STRING \"OpenSSL Libraries\")\n  ENDIF(OPENSSL_LIBRARIE_RELEASE AND CRYPTO_LIBRARIE_RELEASE)\nENDIF(OPENSSL_INCLUDE_DIR)\n\nIF(OPENSSL_FOUND)\n  IF(NOT OPENSSL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found OpenSSL: ${OPENSSL_INCLUDE_DIR} ${OPENSSL_LIBRARIES}\")\n  ENDIF(NOT OPENSSL_FIND_QUIETLY)\nELSE(OPENSSL_FOUND)\n  IF(NOT OPENSSL_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find OpenSSL! INCLUDE: ${OPENSSL_INCLUDE_DIR}  LIB:${OPENSSL_LIBRARIES}  \")\n  ENDIF(NOT OPENSSL_FIND_QUIETLY)\nENDIF(OPENSSL_FOUND)\n\nMARK_AS_ADVANCED(OPENSSL_LIBRARIE_RELEASE OPENSSL_LIBRARY_DEBUG)\n\n\n\n\n\n"
  },
  {
    "path": "code/CMakeModules/FindPBC.cmake",
    "content": "# - Locate PBC library\n# This module defines\n# PBC_INCLUDE_DIRS   - where to find pbc/pbc.h, etc.\n# PBC_LIBRARIES      - List of libraries when using pbc.\n# PBC_FOUND          - True if pbc found.\n# PBC_VERSION_STRING - the version of pbc found (since CMake 2.8.8)\n\nFIND_PATH(PBC_INCLUDE_DIR pbc.h\n  PATH_SUFFIXES pbc\n  $ENV{PBC_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  /usr/local/include/pbc\n  /mingw/include\n)\n\nSET(LIBRARY_NAME_RELEASE pbc)\nSET(LIBRARY_NAME_DEBUG pbc)\n\nFIND_LIBRARY(PBC_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{PBC_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/lib64\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/pbc\n  /mingw/lib\n)\n\nFIND_LIBRARY(PBC_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{PBC_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/pbc\n  /mingw/lib\n)\n\nIF(PBC_INCLUDE_DIR)\n  IF(PBC_LIBRARY_RELEASE AND PBC_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(PBC_FOUND TRUE)\n    SET(PBC_LIBRARY optimized ${PBC_LIBRARY_RELEASE} debug ${PBC_LIBRARY_DEBUG})\n  ELSEIF(PBC_LIBRARY_RELEASE)\n    # Normal case\n    SET(PBC_FOUND TRUE)\n    SET(PBC_LIBRARY ${PBC_LIBRARY_RELEASE})\n  ELSEIF(PBC_LIBRARY_DEBUG)\n    # Case where PBC is compiled from sources (debug version is compiled by default)\n    SET(PBC_FOUND TRUE)\n    SET(PBC_LIBRARY ${PBC_LIBRARY_DEBUG})\n  ENDIF(PBC_LIBRARY_RELEASE AND PBC_LIBRARY_DEBUG)\nENDIF(PBC_INCLUDE_DIR)\n\nIF(PBC_FOUND)\n    MESSAGE(STATUS \"Found PBC: ${PBC_INCLUDE_DIR} ${PBC_LIBRARY}\")\nELSE(PBC_FOUND)\n    MESSAGE(STATUS \"Warning: Unable to find PBC! INCLUDE: ${PBC_INCLUDE_DIR}  LIB:${PBC_LIBRARY}  \")\nENDIF(PBC_FOUND)\n\nMARK_AS_ADVANCED(PBC_LIBRARY_RELEASE PBC_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindProtoBuf.cmake",
    "content": "# - Locate ProtoBuf library\n# This module defines\n#  PROTOBUF_LIBRARIES, the libraries to link against\n#  PROTOBUF_FOUND, if false, do not try to link to PROTO_BUF\n#  PROTOBUF_INCLUDE_DIR, where to find headers.\n\nIF(PROTOBUF_LIBRARIES AND PROTOBUF_INCLUDE_DIR)\n  # in cache already\n  SET(PROTOBUF_FIND_QUIETLY TRUE)\nENDIF(PROTOBUF_LIBRARIES AND PROTOBUF_INCLUDE_DIR)\n\nFIND_PATH(PROTOBUF_INCLUDE_DIR generated_message_util.h\n  PATH_SUFFIXES google/protobuf\n  $ENV{PROTOBUF_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  /usr/local/include/google/protobuf\n  /usr/local/include/google-protobuf\n)\n\nSET(LIBRARY_NAME_RELEASE protobuf libprotobuf)\nSET(LIBRARY_NAME_DEBUG protobufd libprotobufd)\n\t\nIF(WITH_STLPORT AND WIN32)\n\tSET(LIBRARY_NAME_RELEASE libprotobuf_stlport ${LIBRARY_NAME_RELEASE})\n\tSET(LIBRARY_NAME_DEBUG libprotobuf_stlportd ${LIBRARY_NAME_RELEASE})\nENDIF(WITH_STLPORT AND WIN32)\n\nSET(PROTOBUF_LIBRARY_RELEASE NOTFOUND)\nSET(PROTOBUF_LIBRARY_DEBUG NOTFOUND)\n\nFIND_LIBRARY(PROTOBUF_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{PROTOBUF_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/google-protobuf\n)\n\nFIND_LIBRARY(PROTOBUF_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{PROTOBUF_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/google-protobuf\n)\n\nIF(PROTOBUF_INCLUDE_DIR)\n  IF(PROTOBUF_LIBRARY_RELEASE AND PROTOBUF_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(PROTOBUF_FOUND TRUE)\n    SET(PROTOBUF_LIBRARIES optimized ${PROTOBUF_LIBRARY_RELEASE} debug ${PROTOBUF_LIBRARY_DEBUG})\n  ELSEIF(PROTOBUF_LIBRARY_RELEASE)\n    # Normal case\n    SET(PROTOBUF_FOUND TRUE)\n    SET(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARY_RELEASE})\n  ELSEIF(PROTOBUF_LIBRARY_DEBUG)\n    # Case where ProtoBuf is compiled from sources (debug version is compiled by default)\n    SET(PROTOBUF_FOUND TRUE)\n    SET(PROTOBUF_LIBRARIES ${PROTOBUF_LIBRARY_DEBUG})\n  ENDIF(PROTOBUF_LIBRARY_RELEASE AND PROTOBUF_LIBRARY_DEBUG)\nENDIF(PROTOBUF_INCLUDE_DIR)\n\nIF(PROTOBUF_FOUND)\n  IF(NOT PROTOBUF_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found ProtoBuf: ${PROTOBUF_INCLUDE_DIR} ${PROTOBUF_LIBRARIES}\")\n  ENDIF(NOT PROTOBUF_FIND_QUIETLY)\nELSE(PROTOBUF_FOUND)\n  IF(NOT PROTOBUF_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find ProtoBuf!\")\n  ENDIF(NOT PROTOBUF_FIND_QUIETLY)\nENDIF(PROTOBUF_FOUND)\n\nMARK_AS_ADVANCED(PROTOBUF_LIBRARY_RELEASE PROTOBUF_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindS3TC.cmake",
    "content": "# - Locate S3TC library\n# This module defines\n#  S3TC_LIBRARY, the library to link against\n#  S3TC_FOUND, if false, do not try to link to S3TC\n#  S3TC_INCLUDE_DIR, where to find headers.\n\nIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)\n  # in cache already\n  SET(S3TC_FIND_QUIETLY TRUE)\nENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)\n\n\nFIND_PATH(S3TC_INCLUDE_DIR\n  s3_intrf.h\n  PATHS\n  $ENV{S3TC_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES S3TC\n)\n\nFIND_LIBRARY(S3TC_LIBRARY\n  NAMES s3tc libs3tc\n  PATHS\n  $ENV{S3TC_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)\n  SET(S3TC_FOUND \"YES\")\n  IF(NOT S3TC_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found S3TC: ${S3TC_LIBRARY}\")\n  ENDIF(NOT S3TC_FIND_QUIETLY)\nELSE(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)\n  IF(NOT S3TC_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find S3TC!\")\n  ENDIF(NOT S3TC_FIND_QUIETLY)\nENDIF(S3TC_LIBRARY AND S3TC_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindSTLport.cmake",
    "content": "# Look for a directory containing STLport.\n#\n# The following values are defined\n# STLPORT_INCLUDE_DIR - where to find vector, etc.\n# STLPORT_LIBRARIES   - link against these to use STLport\n# STLPORT_FOUND       - True if the STLport is available.\n\n# also defined, but not for general use are\nIF(STLPORT_LIBRARIES AND STLPORT_INCLUDE_DIR)\n  # in cache already\n  SET(STLPORT_FIND_QUIETLY TRUE)\nENDIF(STLPORT_LIBRARIES AND STLPORT_INCLUDE_DIR)\n\nFIND_PATH(STLPORT_INCLUDE_DIR \n  iostream\n  PATHS\n  /usr/local/include/stlport\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES stlport\n)\n\nFIND_LIBRARY(STLPORT_LIBRARY_DEBUG\n  NAMES\n  stlport_cygwin_debug\n  stlport_cygwin_stldebug\n  stlport_gcc_debug\n  stlport_gcc_stldebug\n  stlportstld_x\n  stlportstld_x.5.2\n  stlportd\n  stlportd.5.2\n  stlportd_statix\n  stlportd_static\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(STLPORT_LIBRARY_RELEASE\n  NAMES\n  stlport_cygwin\n  stlport_gcc\n  stlport\n  stlport_x\n  stlport_x.5.2\n  stlport.5.2\n  stlport_statix\n  stlport_static\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(STLPORT_INCLUDE_DIR)\n  IF(STLPORT_LIBRARY_RELEASE)\n    SET(STLPORT_FOUND TRUE)\n\n    SET(STLPORT_LIBRARIES ${STLPORT_LIBRARY_RELEASE})\n    IF(STLPORT_LIBRARY_DEBUG)\n      SET(STLPORT_LIBRARIES optimized ${STLPORT_LIBRARIES} debug ${STLPORT_LIBRARY_DEBUG})\n    ENDIF(STLPORT_LIBRARY_DEBUG)\n  ENDIF(STLPORT_LIBRARY_RELEASE)\nENDIF(STLPORT_INCLUDE_DIR)\n\nIF(STLPORT_FOUND)\n  IF(NOT STLPORT_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found STLport: ${STLPORT_INCLUDE_DIR}   ${STLPORT_LIBRARIES}\")\n  ENDIF(NOT STLPORT_FIND_QUIETLY)\nELSE(STLPORT_FOUND)\n  IF(NOT STLPORT_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find STLport!\")\n  ENDIF(NOT STLPORT_FIND_QUIETLY)\nENDIF(STLPORT_FOUND)\n\nMARK_AS_ADVANCED(STLPORT_LIBRARY_RELEASE STLPORT_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindSquish.cmake",
    "content": "#\n# Find the LibSquish includes and library\n#\n# This module defines\n# SQUISH_INCLUDE_DIR, where to find squish.h\n# SQUISH_LIBRARIES, where to find the Squish libraries.\n# SQUISH_FOUND, If false, do not try to use Squish.\n\n# also defined, but not for general use are\nIF(SQUISH_LIBRARIES AND SQUISH_INCLUDE_DIR)\n  # in cache already\n  SET(SQUISH_FIND_QUIETLY TRUE)\nENDIF(SQUISH_LIBRARIES AND SQUISH_INCLUDE_DIR)\n\nFIND_PATH(SQUISH_INCLUDE_DIR\n  squish.h\n  PATHS\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  PATH_SUFFIXES cppunit\n)\n\nFIND_LIBRARY(SQUISH_LIBRARY_RELEASE\n  squish\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(SQUISH_LIBRARY_DEBUG\n  squishd\n  PATHS\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(SQUISH_INCLUDE_DIR)\n  IF(SQUISH_LIBRARY_RELEASE)\n    SET(SQUISH_FOUND \"YES\")\n    SET(SQUISH_LIBRARIES \"optimized;${SQUISH_LIBRARY_RELEASE}\")\n    IF(SQUISH_LIBRARY_DEBUG)\n      SET(SQUISH_LIBRARIES \"${SQUISH_LIBRARIES};debug;${SQUISH_LIBRARY_DEBUG}\")\n    ELSE(SQUISH_LIBRARY_DEBUG)\n      SET(SQUISH_LIBRARIES \"${SQUISH_LIBRARIES};debug;${SQUISH_LIBRARY_RELEASE}\")\n      MESSAGE(\"Debug Squish NOT found, using the release version!\")\n    ENDIF(SQUISH_LIBRARY_DEBUG)\n  ENDIF(SQUISH_LIBRARY_RELEASE)\nENDIF(SQUISH_INCLUDE_DIR)\n\nIF(SQUISH_FOUND)\n  IF(NOT SQUISH_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Squish: ${SQUISH_LIBRARIES}\")\n  ENDIF(NOT SQUISH_FIND_QUIETLY)\n  FILE(STRINGS ${SQUISH_INCLUDE_DIR}/squish.h METRIC REGEX \"metric = 0\")\n  IF(METRIC)\n    SET(SQUISH_COMPRESS_HAS_METRIC ON)\n    SET(SQUISH_DEFINITIONS -DSQUISH_COMPRESS_HAS_METRIC)\n  ENDIF(METRIC)\nELSE(SQUISH_FOUND)\n  IF(NOT SQUISH_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Squish!\")\n  ENDIF(NOT SQUISH_FIND_QUIETLY)\nENDIF(SQUISH_FOUND)\n\nMARK_AS_ADVANCED(SQUISH_LIBRARY_RELEASE SQUISH_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindTinyXml.cmake",
    "content": "# - Locate TinyXml library\n# This module defines\n#  TINYXML_LIBRARIES, the libraries to link against\n#  TINYXML_FOUND, if false, do not try to link to TINYXML\n#  TINYXML_INCLUDE_DIR, where to find headers.\n\nIF(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR)\n  # in cache already\n  SET(TINYXML_FIND_QUIETLY TRUE)\nENDIF(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR)\n\nFIND_PATH(TINYXML_INCLUDE_DIR tinyxml.h\n  PATH_SUFFIXES tinyxml\n  $ENV{TINYXML_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\nSET(LIBRARY_NAME_RELEASE tinyxml libtinyxml)\nSET(LIBRARY_NAME_DEBUG tinyxml_d tinyxmld libtinyxml_d libtinyxmld)\n\nFIND_LIBRARY(TINYXML_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{TINYXML_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(TINYXML_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{TINYXML_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(TINYXML_INCLUDE_DIR)\n  IF(TINYXML_LIBRARY_RELEASE AND TINYXML_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(TINYXML_FOUND TRUE)\n    SET(TINYXML_LIBRARIES optimized ${TINYXML_LIBRARY_RELEASE} debug ${TINYXML_LIBRARY_DEBUG})\n  ELSEIF(TINYXML_LIBRARY_RELEASE)\n    # Normal case\n    SET(TINYXML_FOUND TRUE)\n    SET(TINYXML_LIBRARIES ${TINYXML_LIBRARY_RELEASE})\n  ELSEIF(TINYXML_LIBRARY_DEBUG)\n    # Case where TinyXml is compiled from sources (debug version is compiled by default)\n    SET(TINYXML_FOUND TRUE)\n    SET(TINYXML_LIBRARIES ${TINYXML_LIBRARY_DEBUG})\n  ENDIF(TINYXML_LIBRARY_RELEASE AND TINYXML_LIBRARY_DEBUG)\nENDIF(TINYXML_INCLUDE_DIR)\n\nIF(TINYXML_FOUND)\n  IF(NOT TINYXML_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found TinyXml: ${TINYXML_INCLUDE_DIR} ${TINYXML_LIBRARIES}\")\n  ENDIF(NOT TINYXML_FIND_QUIETLY)\nELSE(TINYXML_FOUND)\n  IF(NOT TINYXML_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find TinyXml!\")\n  ENDIF(NOT TINYXML_FIND_QUIETLY)\nENDIF(TINYXML_FOUND)\n\nMARK_AS_ADVANCED(TINYXML_LIBRARY_RELEASE TINYXML_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindToLua.cmake",
    "content": "# - Locate ToLua library\n# This module defines\n#  TOLUA_LIBRARIES, the libraries to link against\n#  TOLUA_FOUND, if false, do not try to link to TOLUA\n#  TOLUA_INCLUDE_DIR, where to find headers.\n\nIF(TOLUA_LIBRARIES AND TOLUA_INCLUDE_DIR)\n  # in cache already\n  SET(TOLUA_FIND_QUIETLY TRUE)\nENDIF(TOLUA_LIBRARIES AND TOLUA_INCLUDE_DIR)\n\nFIND_PACKAGE(Lua51 REQUIRED)\n\nFIND_PATH(TOLUA_INCLUDE_DIR tolua++.h\n  PATH_SUFFIXES tolua lua51\n  $ENV{TOLUA_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n  /usr/local/include/lua51\n  /mingw/include\n)\n\nSET(LIBRARY_NAME_RELEASE tolua++5.1 libtolua++.a libtolua++5.1.a libtolua++.so)\nSET(LIBRARY_NAME_DEBUG tolua++5.1 libtolua++.a libtolua++5.1.a libtolua++.so)\n\nFIND_LIBRARY(TOLUA_LIBRARY_RELEASE\n  NAMES ${LIBRARY_NAME_RELEASE}\n  PATHS\n  $ENV{TOLUA_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/lib64\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/lua51\n  /mingw/lib\n)\n\nFIND_LIBRARY(TOLUA_LIBRARY_DEBUG\n  NAMES ${LIBRARY_NAME_DEBUG}\n  PATHS\n  $ENV{TOLUA_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n  /usr/local/lib/lua51\n  /mingw/lib\n)\n\nIF(TOLUA_INCLUDE_DIR)\n  IF(TOLUA_LIBRARY_RELEASE AND TOLUA_LIBRARY_DEBUG)\n    # Case where both Release and Debug versions are provided\n    SET(TOLUA_FOUND TRUE)\n    SET(TOLUA_LIBRARIES optimized ${TOLUA_LIBRARY_RELEASE} debug ${TOLUA_LIBRARY_DEBUG})\n  ELSEIF(TOLUA_LIBRARY_RELEASE)\n    # Normal case\n    SET(TOLUA_FOUND TRUE)\n    SET(TOLUA_LIBRARIES ${TOLUA_LIBRARY_RELEASE})\n  ELSEIF(TOLUA_LIBRARY_DEBUG)\n    # Case where ToLua is compiled from sources (debug version is compiled by default)\n    SET(TOLUA_FOUND TRUE)\n    SET(TOLUA_LIBRARIES ${TOLUA_LIBRARY_DEBUG})\n  ENDIF(TOLUA_LIBRARY_RELEASE AND TOLUA_LIBRARY_DEBUG)\nENDIF(TOLUA_INCLUDE_DIR)\n\nIF(TOLUA_FOUND)\n  IF(NOT TOLUA_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found ToLua: ${TOLUA_INCLUDE_DIR} ${TOLUA_LIBRARIES}\")\n  ENDIF(NOT TOLUA_FIND_QUIETLY)\nELSE(TOLUA_FOUND)\n  IF(NOT TOLUA_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find ToLua! INCLUDE: ${TOLUA_INCLUDE_DIR}  LIB:${TOLUA_LIBRARIES}  \")\n  ENDIF(NOT TOLUA_FIND_QUIETLY)\nENDIF(TOLUA_FOUND)\n\nMARK_AS_ADVANCED(TOLUA_LIBRARY_RELEASE TOLUA_LIBRARY_DEBUG)\n"
  },
  {
    "path": "code/CMakeModules/FindVorbis.cmake",
    "content": "# - Locate Vorbis library\n# This module defines\n#  VORBIS_LIBRARY, the library to link against\n#  VORBIS_FOUND, if false, do not try to link to VORBIS\n#  VORBIS_INCLUDE_DIR, where to find headers.\n\nIF(VORBIS_LIBRARY AND VORBIS_INCLUDE_DIR)\n  # in cache already\n  SET(VORBIS_FIND_QUIETLY TRUE)\nENDIF(VORBIS_LIBRARY AND VORBIS_INCLUDE_DIR)\n\n\nFIND_PATH(VORBIS_INCLUDE_DIR\n  vorbis/vorbisfile.h\n  PATHS\n  $ENV{VORBIS_DIR}/include\n  /usr/local/include\n  /usr/include\n  /sw/include\n  /opt/local/include\n  /opt/csw/include\n  /opt/include\n)\n\nFIND_LIBRARY(VORBIS_LIBRARY\n  NAMES vorbis libvorbis\n  PATHS\n  $ENV{VORBIS_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nFIND_LIBRARY(VORBISFILE_LIBRARY\n  NAMES vorbisfile libvorbisfile\n  PATHS\n  $ENV{VORBIS_DIR}/lib\n  /usr/local/lib\n  /usr/lib\n  /usr/local/X11R6/lib\n  /usr/X11R6/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR)\n  SET(VORBIS_FOUND \"YES\")\n  SET(VORBIS_LIBRARIES ${VORBIS_LIBRARY} ${VORBISFILE_LIBRARY})\n  IF(NOT VORBIS_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found Vorbis: ${VORBIS_LIBRARY}\")\n  ENDIF(NOT VORBIS_FIND_QUIETLY)\nELSE(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR)\n  IF(NOT VORBIS_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Vorbis!\")\n  ENDIF(NOT VORBIS_FIND_QUIETLY)\nENDIF(VORBIS_LIBRARY AND VORBISFILE_LIBRARY AND VORBIS_INCLUDE_DIR)\n"
  },
  {
    "path": "code/CMakeModules/FindWindowsSDK.cmake",
    "content": "# - Find Windows Platform SDK\n# Find the Windows includes\n#\n#  WINSDK_INCLUDE_DIR - where to find Windows.h\n#  WINSDK_INCLUDE_DIRS - where to find all Windows headers\n#  WINSDK_LIBRARY_DIR - where to find libraries\n#  WINSDK_FOUND       - True if Windows SDK found.\n\nIF(WINSDK_FOUND)\n  # If Windows SDK already found, skip it\n  RETURN()\nENDIF()\n\n# Values can be CURRENT or any existing versions 7.1, 8.0A, etc...\nSET(WINSDK_VERSION \"CURRENT\" CACHE STRING \"Windows SDK version to prefer\")\n\nMACRO(DETECT_WINSDK_VERSION_HELPER _ROOT _VERSION)\n  GET_FILENAME_COMPONENT(WINSDK${_VERSION}_DIR \"[${_ROOT}\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v${_VERSION};InstallationFolder]\" ABSOLUTE)\n\n  IF(WINSDK${_VERSION}_DIR AND NOT WINSDK${_VERSION}_DIR STREQUAL \"/registry\" AND EXISTS \"${WINSDK${_VERSION}_DIR}/Include\")\n    SET(WINSDK${_VERSION}_FOUND ON)\n    GET_FILENAME_COMPONENT(WINSDK${_VERSION}_VERSION_FULL \"[${_ROOT}\\\\SOFTWARE\\\\Microsoft\\\\Microsoft SDKs\\\\Windows\\\\v${_VERSION};ProductVersion]\" NAME)\n    IF(NOT WindowsSDK_FIND_QUIETLY)\n      MESSAGE(STATUS \"Found Windows SDK ${_VERSION} in ${WINSDK${_VERSION}_DIR}\")\n    ENDIF()\n  ELSE()\n    SET(WINSDK${_VERSION}_DIR \"\")\n  ENDIF()\nENDMACRO()\n\nMACRO(DETECT_WINKIT_VERSION _VERSION _SUFFIX)\n  GET_FILENAME_COMPONENT(WINSDK${_VERSION}_DIR \"[HKEY_LOCAL_MACHINE\\\\SOFTWARE\\\\Microsoft\\\\Windows Kits\\\\Installed Roots;KitsRoot${_SUFFIX}]\" ABSOLUTE)\n\n  IF(WINSDK${_VERSION}_DIR AND NOT WINSDK${_VERSION}_DIR STREQUAL \"/registry\")\n    SET(WINSDK${_VERSION}_FOUND ON)\n    SET(WINSDK${_VERSION}_VERSION_FULL \"${_VERSION}\")\n    IF(NOT WindowsSDK_FIND_QUIETLY)\n      MESSAGE(STATUS \"Found Windows Kit ${_VERSION} in ${WINSDK${_VERSION}_DIR}\")\n    ENDIF()\n    LIST(APPEND WINSDK_DETECTED_VERSIONS ${_VERSION})\n  ELSE()\n    SET(WINSDK${_VERSION}_DIR \"\")\n  ENDIF()\nENDMACRO()\n\nMACRO(DETECT_WINSDK_VERSION _VERSION)\n  SET(WINSDK${_VERSION}_FOUND OFF)\n  DETECT_WINSDK_VERSION_HELPER(\"HKEY_CURRENT_USER\" ${_VERSION})\n\n  IF(NOT WINSDK${_VERSION}_FOUND)\n    DETECT_WINSDK_VERSION_HELPER(\"HKEY_LOCAL_MACHINE\" ${_VERSION})\n  ENDIF()\nENDMACRO()\n\nSET(WINSDK_DETECTED_VERSIONS)\n\n# Fixed versions for Windows Kits (VC++ from 2012)\nDETECT_WINKIT_VERSION(\"10.0\" \"10\")\nDETECT_WINKIT_VERSION(\"8.1\" \"81\")\nDETECT_WINKIT_VERSION(\"8.0\" \"\")\n\n# For VC++ up to 2010\nSET(WINSDK_VERSIONS \"7.1\" \"7.1A\" \"7.0\" \"7.0A\" \"6.1\" \"6.0\" \"6.0A\")\n\n# Search all supported Windows SDKs\nFOREACH(_VERSION ${WINSDK_VERSIONS})\n  DETECT_WINSDK_VERSION(${_VERSION})\n\n  IF(WINSDK${_VERSION}_FOUND)\n    LIST(APPEND WINSDK_DETECTED_VERSIONS ${_VERSION})\n  ENDIF()\nENDFOREACH()\n\nSET(WINSDK_SUFFIXES)\n\nIF(TARGET_ARM64)\n  SET(WINSDK8_SUFFIX \"arm64\")\nELSEIF(TARGET_ARM)\n  SET(WINSDK8_SUFFIX \"arm\")\nELSEIF(TARGET_X64)\n  SET(WINSDK8_SUFFIX \"x64\")\n  SET(WINSDK_SUFFIXES \"x64\" \"amd64\")\nELSEIF(TARGET_X86)\n  SET(WINSDK8_SUFFIX \"x86\")\nENDIF()\n\nSET(WINSDKCURRENT_VERSION_INCLUDE $ENV{INCLUDE})\n\nIF(WINSDKCURRENT_VERSION_INCLUDE)\n  FILE(TO_CMAKE_PATH \"${WINSDKCURRENT_VERSION_INCLUDE}\" WINSDKCURRENT_VERSION_INCLUDE)\nENDIF()\n\nSET(WINSDKENV_DIR $ENV{WINSDK_DIR})\n\nIF(NOT WINSDKENV_DIR)\n  SET(WINSDKENV_DIR $ENV{WindowsSDKDir})\nENDIF()\n\nMACRO(FIND_WINSDK_VERSION_HEADERS)\n  IF(WINSDK_DIR AND NOT WINSDK_VERSION)\n    # Search version in headers\n    FIND_FILE(_MSI_FILE Msi.h\n      PATHS\n      ${WINSDK_DIR}/Include/um\n      ${WINSDK_DIR}/Include\n    )\n\n    IF(_MSI_FILE)\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 8.1\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WINBLUE\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"8.1\")\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 8.0\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WIN8\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"8.0\")\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 7.0\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WIN7\")\n\n        IF(_CONTENT)\n          FIND_FILE(_WINSDKVER_FILE winsdkver.h WinSDKVer.h\n            PATHS\n            ${WINSDK_DIR}/Include/um\n            ${WINSDK_DIR}/Include\n          )\n\n          IF(_WINSDKVER_FILE)\n            # Load WinSDKVer.h content\n            FILE(STRINGS ${_WINSDKVER_FILE} _CONTENT REGEX \"^#define NTDDI_MAXVER\")\n\n            # Get NTDDI_MAXVER value\n            STRING(REGEX REPLACE \"^.*0x([0-9A-Fa-f]+).*$\" \"\\\\1\" _WINSDKVER \"${_CONTENT}\")\n\n            # In Windows SDK 7.1, NTDDI_MAXVER is wrong\n            IF(_WINSDKVER STREQUAL \"06010000\")\n              SET(WINSDK_VERSION \"7.1\")\n            ELSEIF(_WINSDKVER STREQUAL \"0601\")\n              SET(WINSDK_VERSION \"7.0A\")\n            ELSE()\n              MESSAGE(FATAL_ERROR \"Can't determine Windows SDK version with NTDDI_MAXVER 0x${_WINSDKVER}\")\n            ENDIF()\n          ELSE()\n            SET(WINSDK_VERSION \"7.0\")\n          ENDIF()\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 6.0\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_VISTA\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"6.0\")\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 5.2\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WS03SP1\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"5.2\")\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 5.1\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WINXP\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"5.1\")\n        ENDIF()\n      ENDIF()\n\n      IF(NOT WINSDK_VERSION)\n        # Look for Windows SDK 5.0\n        FILE(STRINGS ${_MSI_FILE} _CONTENT REGEX \"^#ifndef NTDDI_WIN2K\")\n\n        IF(_CONTENT)\n          SET(WINSDK_VERSION \"5.0\")\n        ENDIF()\n      ENDIF()\n    ELSE()\n      MESSAGE(FATAL_ERROR \"Unable to find Msi.h in ${WINSDK_DIR}\")\n    ENDIF()\n  ENDIF()\nENDMACRO()\n\nMACRO(USE_CURRENT_WINSDK)\n  SET(WINSDK_DIR \"\")\n  SET(WINSDK_VERSION \"\")\n  SET(WINSDK_VERSION_FULL \"\")\n\n  # Use WINSDK environment variable\n  IF(WINSDKENV_DIR)\n    FIND_PATH(WINSDK_DIR Windows.h\n      HINTS\n      ${WINSDKENV_DIR}/Include/um\n      ${WINSDKENV_DIR}/Include\n    )\n  ENDIF()\n\n  # Use INCLUDE environment variable\n  IF(NOT WINSDK_DIR AND WINSDKCURRENT_VERSION_INCLUDE)\n    FOREACH(_INCLUDE ${WINSDKCURRENT_VERSION_INCLUDE})\n      FILE(TO_CMAKE_PATH ${_INCLUDE} _INCLUDE)\n\n      # Look for Windows.h because there are several paths\n      IF(EXISTS ${_INCLUDE}/Windows.h)\n        STRING(REGEX REPLACE \"/(include|INCLUDE|Include)(.*)\" \"\" WINSDK_DIR ${_INCLUDE})\n        MESSAGE(STATUS \"Found Windows SDK in INCLUDE environment variable: ${WINSDK_DIR}\")\n        BREAK()\n      ENDIF()\n    ENDFOREACH()\n  ENDIF()\n\n  IF(WINSDK_DIR)\n    # Compare WINSDK_DIR with registered Windows SDKs\n    FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS})\n      IF(WINSDK_DIR STREQUAL \"${WINSDK${_VERSION}_DIR}\")\n        SET(WINSDK_VERSION ${_VERSION})\n        SET(WINSDK_VERSION_FULL \"${WINSDK${WINSDK_VERSION}_VERSION_FULL}\")\n        BREAK()\n      ENDIF()\n    ENDFOREACH()\n\n    FIND_WINSDK_VERSION_HEADERS()\n  ENDIF()\n\n  IF(NOT WINSDK_DIR)\n    # Use Windows SDK versions installed with VC++ when possible\n    IF(MSVC_VERSION GREATER 1909)\n      # Special case, use Kits for SDK\n      SET(WINSDK_VERSION \"10.0\")\n      SET(WINSDK_DIR ${WINSDK_UCRT_DIR})\n    ELSEIF(MSVC14)\n      SET(WINSDK_VERSION \"8.1\")\n    ELSEIF(MSVC12)\n      SET(WINSDK_VERSION \"8.1\")\n    ELSEIF(MSVC11)\n      SET(WINSDK_VERSION \"8.0\")\n    ELSEIF(MSVC10)\n      IF(NOT TARGET_X64 OR NOT MSVC_EXPRESS)\n        SET(WINSDK_VERSION \"7.0A\")\n      ENDIF()\n    ELSEIF(MSVC90)\n      IF(NOT MSVC_EXPRESS)\n        SET(WINSDK_VERSION \"6.0A\")\n      ENDIF()\n    ELSEIF(MSVC80)\n      SET(WINSDK_MSVC80_COMPATIBLES \"7.1\" \"7.1A\" \"7.0\" \"7.0A\" \"6.1\" \"6.0\" \"6.0A\" \"5.2A\")\n\n      # look for each Windows SDK supported by VC++ 2005 (7.1 is the latest)\n      FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS})\n        # look if this version of Windows SDK is installed\n        LIST(FIND WINSDK_MSVC80_COMPATIBLES ${_VERSION} _FOUND)\n        IF(NOT _FOUND EQUAL -1)\n          SET(WINSDK_VERSION \"${_VERSION}\")\n          BREAK()\n        ENDIF()\n      ENDFOREACH()\n\n      IF(NOT MSVC_EXPRESS AND NOT WINSDK_VERSION)\n        SET(WINSDK_VERSION \"5.2A\")\n      ENDIF()\n    ELSE()\n      MESSAGE(FATAL_ERROR \"Your compiler is either too old or too recent, please update this CMake module.\")\n    ENDIF()\n\n    # Use installed Windows SDK\n    IF(NOT WINSDK_VERSION)\n      IF(WINSDK8.1_FOUND)\n        SET(WINSDK_VERSION \"8.1\")\n      ELSEIF(WINSDK8.0_FOUND)\n        SET(WINSDK_VERSION \"8.0\")\n      ELSEIF(WINSDK7.1_FOUND)\n        SET(WINSDK_VERSION \"7.1\")\n      ELSEIF(WINSDK7.0_FOUND)\n        SET(WINSDK_VERSION \"7.0\")\n      ELSEIF(WINSDK6.1_FOUND)\n        SET(WINSDK_VERSION \"6.1\")\n      ELSEIF(WINSDK6.0_FOUND)\n        SET(WINSDK_VERSION \"6.0\")\n      ELSE()\n        MESSAGE(FATAL_ERROR \"You have no compatible Windows SDK installed.\")\n      ENDIF()\n    ENDIF()\n\n    # Look for correct registered Windows SDK version\n    FOREACH(_VERSION ${WINSDK_DETECTED_VERSIONS})\n      IF(WINSDK_VERSION STREQUAL _VERSION)\n        SET(WINSDK_VERSION_FULL \"${WINSDK${WINSDK_VERSION}_VERSION_FULL}\")\n        SET(WINSDK_DIR \"${WINSDK${WINSDK_VERSION}_DIR}\")\n        BREAK()\n      ENDIF()\n    ENDFOREACH()\n  ENDIF()\nENDMACRO()\n\nIF(MSVC14)\n  # Under VC++ 2015 and 2017, stdio.h, stdlib.h, etc... are part of UCRT\n  SET(WINSDK_UCRT_VERSION \"10.0\")\nENDIF()\n\n# Look for correct UCRT\nIF(WINSDK_UCRT_VERSION AND WINSDK${WINSDK_UCRT_VERSION}_FOUND)\n  SET(WINSDK_UCRT_DIR \"${WINSDK${WINSDK_UCRT_VERSION}_DIR}\")\nENDIF()\n\nIF(WINSDK_UCRT_DIR)\n  # determine exact UCRT version\n  SET(WINSDK_UCRT_INCLUDE_ROOT_DIR ${WINSDK_UCRT_DIR}/Include)\n  SET(WINSDK_UCRT_LIB_ROOT_DIR ${WINSDK_UCRT_DIR}/Lib)\n\n  FILE(GLOB UCRT_SUBDIRS RELATIVE ${WINSDK_UCRT_INCLUDE_ROOT_DIR} ${WINSDK_UCRT_INCLUDE_ROOT_DIR}/*)\n  SET(UCRT_VERSION)\n\n  FOREACH(UCRT_SUBDIR ${UCRT_SUBDIRS})\n    IF(NOT UCRT_VERSION OR UCRT_SUBDIR VERSION_GREATER UCRT_VERSION)\n      SET(UCRT_VERSION ${UCRT_SUBDIR})\n    ENDIF()\n  ENDFOREACH()\n\n  IF(UCRT_VERSION)\n    MESSAGE(STATUS \"Using Windows UCRT ${UCRT_VERSION}\")\n\n    SET(WINSDK10_INCLUDE_DIR ${WINSDK_UCRT_INCLUDE_ROOT_DIR}/${UCRT_VERSION})\n    SET(WINSDK10_LIBRARY_DIR ${WINSDK_UCRT_LIB_ROOT_DIR}/${UCRT_VERSION})\n\n    # directory where UCRT headers are found\n    FIND_PATH(WINSDK_UCRT_INCLUDE_DIR corecrt.h\n      HINTS\n      ${WINSDK10_INCLUDE_DIR}/ucrt\n    )\n\n    # directory where UCRT libraries are found\n    FIND_PATH(WINSDK_UCRT_LIBRARY_DIR ucrt.lib\n      HINTS\n      ${WINSDK10_LIBRARY_DIR}/ucrt/${WINSDK8_SUFFIX}\n    )\n  ENDIF()\nENDIF()\n\nIF(WINSDK_VERSION STREQUAL \"CURRENT\")\n  USE_CURRENT_WINSDK()\nELSE()\n  IF(WINSDK${WINSDK_VERSION}_FOUND)\n    SET(WINSDK_VERSION_FULL \"${WINSDK${WINSDK_VERSION}_VERSION_FULL}\")\n    SET(WINSDK_DIR \"${WINSDK${WINSDK_VERSION}_DIR}\")\n  ELSE()\n    USE_CURRENT_WINSDK()\n  ENDIF()\nENDIF()\n\nIF(WINSDK_DIR)\n  MESSAGE(STATUS \"Using Windows SDK ${WINSDK_VERSION}\")\nELSE()\n  MESSAGE(FATAL_ERROR \"Unable to find Windows SDK!\")\nENDIF()\n\n# directory where Win32 headers are found\nFIND_PATH(WINSDK_INCLUDE_DIR Windows.h\n  HINTS\n  ${WINSDK_DIR}/Include/${UCRT_VERSION}/um\n  ${WINSDK_DIR}/Include/um\n  ${WINSDK_DIR}/Include\n  NO_DEFAULT_PATH\n)\n\nMESSAGE(STATUS \"Found Windows.h in ${WINSDK_INCLUDE_DIR}\")\n\n# directory where WinRT headers are found\nFIND_PATH(WINSDK_WINRT_INCLUDE_DIR winstring.h\n  HINTS\n  ${WINSDK_DIR}/Include/${UCRT_VERSION}/winrt\n  ${WINSDK_DIR}/Include/winrt\n  NO_DEFAULT_PATH\n)\n\nMESSAGE(STATUS \"Found winstring.h in ${WINSDK_WINRT_INCLUDE_DIR}\")\n\n# directory where DirectX headers are found\nFIND_PATH(WINSDK_SHARED_INCLUDE_DIR d3d9.h\n  HINTS\n  ${WINSDK_DIR}/Include/${UCRT_VERSION}/shared\n  ${WINSDK_DIR}/Include/shared\n  NO_DEFAULT_PATH\n)\n\nMESSAGE(STATUS \"Found d3d9.h in ${WINSDK_SHARED_INCLUDE_DIR}\")\n\n# directory where OpenGL headers are found\nFIND_PATH(WINSDK_OPENGL_INCLUDE_DIR GL.h\n  HINTS\n  ${WINSDK_INCLUDE_DIR}/gl\n  ${WINSDK_DIR}/Include/um/gl\n  ${WINSDK_DIR}/Include/gl\n  NO_DEFAULT_PATH\n)\n\nMESSAGE(STATUS \"Found GL.h in ${WINSDK_OPENGL_INCLUDE_DIR}\")\n\nSET(WINSDK_LIBRARY_DIRS\n  ${WINSDK_DIR}/Lib/${UCRT_VERSION}/um/${WINSDK8_SUFFIX}\n  ${WINSDK_DIR}/Lib/winv6.3/um/${WINSDK8_SUFFIX}\n  ${WINSDK_DIR}/Lib/win8/um/${WINSDK8_SUFFIX}\n)\n\nIF(WINSDK_SUFFIXES)\n  FOREACH(_SUFFIX ${WINSDK_SUFFIXES})\n    LIST(APPEND WINSDK_LIBRARY_DIRS ${WINSDK_DIR}/Lib/${_SUFFIX})\n  ENDFOREACH()\nELSE()\n  LIST(APPEND WINSDK_LIBRARY_DIRS ${WINSDK_DIR}/Lib)\nENDIF()\n\n# directory where all libraries are found\nFIND_PATH(WINSDK_LIBRARY_DIR ComCtl32.lib\n  HINTS\n  ${WINSDK_LIBRARY_DIRS}\n  NO_DEFAULT_PATH\n)\n\nMESSAGE(STATUS \"Found ComCtl32.lib in ${WINSDK_LIBRARY_DIR}\")\n\nSET(WINSDK_BINARY_DIRS\n  ${WINSDK_DIR}/Bin/${UCRT_VERSION}/${WINSDK8_SUFFIX}\n  ${WINSDK_DIR}/Bin/${WINSDK8_SUFFIX}\n  ${WINSDK_DIR}/Bin/x86\n  ${WINSDK_DIR}/Bin\n)\n\n# signtool is used to sign executables\nFIND_PROGRAM(WINSDK_SIGNTOOL signtool\n  HINTS\n  ${WINSDK_BINARY_DIRS}\n  NO_DEFAULT_PATH\n)\n\n# midl is used to generate IDL interfaces\nFIND_PROGRAM(WINSDK_MIDL midl\n  HINTS\n  ${WINSDK_BINARY_DIRS}\n  NO_DEFAULT_PATH\n)\n\nIF(WINSDK_INCLUDE_DIR)\n  SET(WINSDK_FOUND ON)\n\n  IF(WINSDK_UCRT_INCLUDE_DIR)\n    SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_UCRT_INCLUDE_DIR})\n  ENDIF()\n\n  IF(WINSDK_SHARED_INCLUDE_DIR)\n    SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_SHARED_INCLUDE_DIR})\n  ENDIF()\n\n  SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_INCLUDE_DIR})\n\n  IF(WINSDK_OPENGL_INCLUDE_DIR)\n    SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_OPENGL_INCLUDE_DIR})\n  ENDIF()\n\n  IF(WINSDK_WINRT_INCLUDE_DIR)\n    SET(WINSDK_INCLUDE_DIRS ${WINSDK_INCLUDE_DIRS} ${WINSDK_WINRT_INCLUDE_DIR})\n  ENDIF()\n\n  INCLUDE_DIRECTORIES(${WINSDK_INCLUDE_DIRS})\n\n  IF(WINSDK_UCRT_LIBRARY_DIR)\n    SET(CMAKE_LIBRARY_PATH ${WINSDK_UCRT_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})\n  ENDIF()\n\n  SET(CMAKE_LIBRARY_PATH ${WINSDK_LIBRARY_DIR} ${CMAKE_LIBRARY_PATH})\n\n  # Fix for using Windows SDK 7.1 with Visual C++ 2012, 2013, 2015 and 2017\n  IF(WINSDK_VERSION STREQUAL \"7.1\" AND (MSVC11 OR MSVC12 OR MSVC14))\n    ADD_DEFINITIONS(-D_USING_V110_SDK71_)\n  ENDIF()\nELSE()\n  IF(NOT WindowsSDK_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find Windows SDK!\")\n  ENDIF()\nENDIF()"
  },
  {
    "path": "code/CMakeModules/FindXF86VidMode.cmake",
    "content": "# - Locate Jpeg library\n# This module defines\n#  XF86VidMode_LIBRARY, the library to link against\n#  XF86VidMode_FOUND, if false, do not try to link to XF86VidMode\n#  XF86VidMode_INCLUDE_DIR, where to find headers.\n\nIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR)\n  # in cache already\n  SET(XF86VidMode_FIND_QUIETLY TRUE)\nENDIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR)\n\n\nFIND_PATH(XF86VidMode_INCLUDE_DIR\n  xf86vmode.h\n  PATHS\n  $ENV{XF86VidMode_DIR}/include\n  /usr/include/X11/\n  /usr/X11R6/include/\n  PATH_SUFFIXES extensions \n)\n\nFIND_LIBRARY(XF86VidMode_LIBRARY\n  Xxf86vm \n  PATHS\n  $ENV{XF86VidMode_DIR}/lib\n  /usr/X11R6/lib\n  /usr/lib\n  /sw/lib\n  /opt/local/lib\n  /opt/csw/lib\n  /opt/lib\n  /usr/freeware/lib64\n)\n\nIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR)\n  SET(XF86VidMode_FOUND \"YES\")\n  SET(XF86VidMode_DEFINITIONS -DXF86VIDMODE)\n  IF(NOT XF86VidMode_FIND_QUIETLY)\n    MESSAGE(STATUS \"Found XF86VidMode: ${XF86VidMode_LIBRARY}\")\n  ENDIF(NOT XF86VidMode_FIND_QUIETLY)\nELSE(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR)\n  IF(NOT XF86VidMode_FIND_QUIETLY)\n    MESSAGE(STATUS \"Warning: Unable to find XF86VidMode!\")\n  ENDIF(NOT XF86VidMode_FIND_QUIETLY)\nENDIF(XF86VidMode_LIBRARY AND XF86VidMode_INCLUDE_DIR)\n\n"
  },
  {
    "path": "code/CMakeModules/GetRevision.cmake",
    "content": "CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3)\n\n# ROOT_DIR should be set to root of the repository (where to find the .svn or .hg directory)\n# SOURCE_DIR should be set to root of your code (where to find CMakeLists.txt)\n\nIF(SOURCE_DIR)\n  # Replace spaces by semi-columns\n  IF(CMAKE_MODULE_PATH)\n    STRING(REPLACE \" \" \";\" CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH})\n  ENDIF(CMAKE_MODULE_PATH)\n\n  SET(CMAKE_MODULE_PATH ${SOURCE_DIR}/CMakeModules ${CMAKE_MODULE_PATH})\n\n  IF(NOT ROOT_DIR AND SOURCE_DIR)\n    SET(ROOT_DIR ${SOURCE_DIR})\n  ENDIF()\n\n  IF(NOT SOURCE_DIR AND ROOT_DIR)\n    SET(SOURCE_DIR ${ROOT_DIR})\n  ENDIF()\nELSE()\n  SET(SOURCE_DIR ${CMAKE_SOURCE_DIR})\n  SET(ROOT_DIR ${CMAKE_SOURCE_DIR})\nENDIF()\n\nMACRO(NOW RESULT)\n  IF (WIN32)\n    EXECUTE_PROCESS(COMMAND \"wmic\" \"os\" \"get\" \"localdatetime\" OUTPUT_VARIABLE DATETIME)\n    IF(NOT DATETIME MATCHES \"ERROR\")\n      STRING(REGEX REPLACE \".*\\n([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9]).*\" \"\\\\1-\\\\2-\\\\3 \\\\4:\\\\5:\\\\6\" ${RESULT} \"${DATETIME}\")\n    ENDIF()\n  ELSEIF(UNIX)\n    EXECUTE_PROCESS(COMMAND \"date\" \"+%Y-%m-%d %H:%M:%S\" OUTPUT_VARIABLE DATETIME)\n    STRING(REGEX REPLACE \"([0-9: -]+).*\" \"\\\\1\" ${RESULT} \"${DATETIME}\")\n  ELSE()\n    MESSAGE(SEND_ERROR \"date not implemented\")\n    SET(${RESULT} \"0000-00-00 00:00:00\")\n  ENDIF()\nENDMACRO(NOW)\n\nIF(EXISTS \"${ROOT_DIR}/.svn/\")\n  FIND_PACKAGE(Subversion QUIET)\n\n  IF(SUBVERSION_FOUND)\n    Subversion_WC_INFO(${ROOT_DIR} ER)\n    SET(REVISION ${ER_WC_REVISION})\n  ENDIF(SUBVERSION_FOUND)\n\n  FIND_PACKAGE(TortoiseSVN QUIET)\n\n  IF(TORTOISESVN_FOUND)\n    TORTOISESVN_GET_REVISION(${ROOT_DIR} REVISION)\n  ENDIF(TORTOISESVN_FOUND)\nENDIF(EXISTS \"${ROOT_DIR}/.svn/\")\n\nIF(EXISTS \"${ROOT_DIR}/.hg/\")\n  FIND_PACKAGE(Mercurial)\n\n  IF(MERCURIAL_FOUND)\n    Mercurial_WC_INFO(${ROOT_DIR} ER)\n    SET(REVISION ${ER_WC_REVISION})\n    SET(CHANGESET ${ER_WC_CHANGESET})\n    SET(BRANCH ${ER_WC_BRANCH})\n  ENDIF()\nENDIF()\n\n# if processing exported sources, use \"revision\" file if exists\nIF(SOURCE_DIR AND NOT DEFINED REVISION)\n  SET(REVISION_FILE ${SOURCE_DIR}/revision)\n  IF(EXISTS ${REVISION_FILE})\n    FILE(STRINGS ${REVISION_FILE} REVISION LIMIT_COUNT 1)\n    MESSAGE(STATUS \"Read revision ${REVISION} from file\")\n  ENDIF()\nENDIF()\n\nIF(SOURCE_DIR AND DEFINED REVISION)\n  IF(EXISTS ${SOURCE_DIR}/revision.h.in)\n    MESSAGE(STATUS \"Revision: ${REVISION}\")\n    NOW(BUILD_DATE)\n    CONFIGURE_FILE(${SOURCE_DIR}/revision.h.in revision.h.txt)\n    EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy revision.h.txt revision.h) # copy_if_different\n  ENDIF()\nENDIF()\n"
  },
  {
    "path": "code/CMakeModules/PCHSupport.cmake",
    "content": "# - Try to find precompiled headers support for GCC 3.4 and 4.x (and MSVC)\n# Once done this will define:\n#\n# Variable:\n#   PCHSupport_FOUND\n#\n#   ADD_PRECOMPILED_HEADER  _targetName _inputh _inputcpp\n#   ADD_PRECOMPILED_HEADER_TO_TARGET _targetName _input _pch_output_to_use\n#   ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp\n\nIF(MSVC)\n  SET(PCHSupport_FOUND TRUE)\nELSE(MSVC)\n  IF(CMAKE_COMPILER_IS_GNUCXX)\n    EXEC_PROGRAM(${CMAKE_CXX_COMPILER}\n      ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion\n      OUTPUT_VARIABLE gcc_compiler_version)\n\n    IF(gcc_compiler_version MATCHES \"^4\\\\.1(\\\\.[0-9]+)?\")\n      SET(PCHSupport_FOUND FALSE)\n    ELSEIF(gcc_compiler_version MATCHES \"^4\\\\.[0-9]+(\\\\.[0-9]+)?\")\n      SET(PCHSupport_FOUND TRUE)\n    ENDIF(gcc_compiler_version MATCHES \"^4\\\\.1(\\\\.[0-9]+)?\")\n  ELSE(CMAKE_COMPILER_IS_GNUCXX)\n    # TODO: make tests for other compilers than GCC\n    SET(PCHSupport_FOUND TRUE)\n  ENDIF(CMAKE_COMPILER_IS_GNUCXX)\nENDIF(MSVC)\n\n# Set PCH_FLAGS for common flags, PCH_ARCH_XXX_FLAGS for specific archs flags and PCH_ARCHS for archs\nMACRO(PCH_SET_COMPILE_FLAGS _target)\n  SET(PCH_FLAGS)\n  SET(PCH_ARCHS)\n\n  SET(_FLAGS)\n  LIST(APPEND _FLAGS ${CMAKE_CXX_FLAGS})\n\n  STRING(TOUPPER \"${CMAKE_BUILD_TYPE}\" _UPPER_BUILD)\n  LIST(APPEND _FLAGS \" ${CMAKE_CXX_FLAGS_${_UPPER_BUILD}}\")\n\n  GET_TARGET_PROPERTY(_targetType ${_target} TYPE)\n\n  IF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY)\n    LIST(APPEND _FLAGS \" ${CMAKE_SHARED_LIBRARY_CXX_FLAGS}\")\n  ELSE(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY)\n    GET_TARGET_PROPERTY(_pic ${_target} POSITION_INDEPENDENT_CODE)\n    IF(_pic)\n      LIST(APPEND _FLAGS \" ${CMAKE_CXX_COMPILE_OPTIONS_PIE}\")\n    ENDIF(_pic)\n  ENDIF(${_targetType} STREQUAL SHARED_LIBRARY OR ${_targetType} STREQUAL MODULE_LIBRARY)\n\n  GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES)\n  FOREACH(item ${DIRINC})\n    LIST(APPEND _FLAGS \" -I\\\"${item}\\\"\")\n  ENDFOREACH(item)\n\n  # Required for CMake 2.6\n  SET(GLOBAL_DEFINITIONS)\n  GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS)\n  IF(DEFINITIONS)\n    FOREACH(item ${DEFINITIONS})\n      LIST(APPEND GLOBAL_DEFINITIONS \" -D${item}\")\n    ENDFOREACH(item)\n  ENDIF(DEFINITIONS)\n\n  GET_DIRECTORY_PROPERTY(DEFINITIONS COMPILE_DEFINITIONS_${_UPPER_BUILD})\n  IF(DEFINITIONS)\n    FOREACH(item ${DEFINITIONS})\n      LIST(APPEND GLOBAL_DEFINITIONS \" -D${item}\")\n    ENDFOREACH(item)\n  ENDIF(DEFINITIONS)\n\n  GET_TARGET_PROPERTY(oldProps ${_target} COMPILE_FLAGS)\n  IF(oldProps)\n    LIST(APPEND _FLAGS \" ${oldProps}\")\n  ENDIF(oldProps)\n\n  GET_TARGET_PROPERTY(oldPropsBuild ${_target} COMPILE_FLAGS_${_UPPER_BUILD})\n  IF(oldPropsBuild)\n    LIST(APPEND _FLAGS \" ${oldPropsBuild}\")\n  ENDIF(oldPropsBuild)\n\n  GET_TARGET_PROPERTY(DIRINC ${_target} INCLUDE_DIRECTORIES)\n  IF(DIRINC)\n    FOREACH(item ${DIRINC})\n      LIST(APPEND _FLAGS \" -I\\\"${item}\\\"\")\n    ENDFOREACH(item)\n  ENDIF(DIRINC)\n\n  GET_TARGET_PROPERTY(DEFINITIONS ${_target} COMPILE_DEFINITIONS)\n  IF(DEFINITIONS)\n    FOREACH(item ${DEFINITIONS})\n      LIST(APPEND GLOBAL_DEFINITIONS \" -D${item}\")\n    ENDFOREACH(item)\n  ENDIF(DEFINITIONS)\n\n  GET_TARGET_PROPERTY(DEFINITIONS ${_target} COMPILE_DEFINITIONS_${_UPPER_BUILD})\n  IF(DEFINITIONS)\n    FOREACH(item ${DEFINITIONS})\n      LIST(APPEND GLOBAL_DEFINITIONS \" -D${item}\")\n    ENDFOREACH(item)\n  ENDIF(DEFINITIONS)\n\n  GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS)\n  GET_DIRECTORY_PROPERTY(_directory_definitions DIRECTORY ${CMAKE_SOURCE_DIR} DEFINITIONS)\n  LIST(APPEND _FLAGS \" ${GLOBAL_DEFINITIONS}\")\n  LIST(APPEND _FLAGS \" ${_directory_flags}\")\n  LIST(APPEND _FLAGS \" ${_directory_definitions}\")\n\n  # Format definitions\n  IF(MSVC)\n    # Fix path with space\n    SEPARATE_ARGUMENTS(_FLAGS UNIX_COMMAND \"${_FLAGS}\")\n  ELSE(MSVC)\n    STRING(REGEX REPLACE \" +\" \" \" _FLAGS ${_FLAGS})\n    SEPARATE_ARGUMENTS(_FLAGS)\n  ENDIF(MSVC)\n\n  IF(CLANG)\n    # Determining all architectures and get common flags\n    SET(_ARCH_NEXT)\n    SET(_XARCH_NEXT)\n    FOREACH(item ${_FLAGS})\n      IF(_ARCH_NEXT)\n        LIST(FIND PCH_ARCHS ${item} ITEM_FOUND)\n        IF(ITEM_FOUND EQUAL -1)\n          LIST(APPEND PCH_ARCHS ${item})\n          STRING(TOUPPER \"${item}\" _UPPER_ARCH)\n          SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS \"-arch\" ${item})\n        ENDIF(ITEM_FOUND EQUAL -1)\n        SET(_ARCH_NEXT OFF)\n      ELSEIF(_XARCH_NEXT)\n        SET(_XARCH_NEXT OFF)\n      ELSE(_ARCH_NEXT)\n        IF(item MATCHES \"^-arch\")\n          SET(_ARCH_NEXT ON)\n        ELSEIF(item MATCHES \"^-Xarch_\")\n          STRING(REGEX REPLACE \"-Xarch_([a-z0-9_]+)\" \"\\\\1\" item ${item})\n          LIST(FIND PCH_ARCHS ${item} ITEM_FOUND)\n          IF(ITEM_FOUND EQUAL -1)\n            LIST(APPEND PCH_ARCHS ${item})\n            STRING(TOUPPER \"${item}\" _UPPER_ARCH)\n            SET(PCH_ARCH_${_UPPER_ARCH}_FLAGS \"-arch\" ${item})\n          ENDIF(ITEM_FOUND EQUAL -1)\n          SET(_XARCH_NEXT ON)\n        ELSE(item MATCHES \"^-arch\")\n          LIST(APPEND PCH_FLAGS ${item})\n        ENDIF(item MATCHES \"^-arch\")\n      ENDIF(_ARCH_NEXT)\n    ENDFOREACH(item)\n\n    # Get architcture specific flags\n    SET(_XARCH_NEXT)\n    FOREACH(item ${_FLAGS})\n      IF(_XARCH_NEXT)\n        STRING(TOUPPER \"${_XARCH_NEXT}\" _UPPER_XARCH)\n        LIST(APPEND PCH_ARCH_${_UPPER_XARCH}_FLAGS ${item})\n        SET(_XARCH_NEXT OFF)\n      ELSE(_XARCH_NEXT)\n        IF(item MATCHES \"^-Xarch_\")\n          STRING(SUBSTRING \"${item}\" 7 -1 _XARCH_NEXT)\n        ENDIF(item MATCHES \"^-Xarch_\")\n      ENDIF(_XARCH_NEXT)\n    ENDFOREACH(item)\n\n    # Remove duplicated architectures\n    IF(_ARCHS AND PCH_ARCHS)\n      LIST(REMOVE_DUPLICATES PCH_ARCHS)\n    ENDIF(_ARCHS AND PCH_ARCHS)\n  ELSE(CLANG)\n    SET(PCH_FLAGS ${_FLAGS})\n  ENDIF(CLANG)\n\n  IF(PCH_FLAGS)\n    LIST(REMOVE_DUPLICATES PCH_FLAGS)\n  ENDIF(PCH_FLAGS)\nENDMACRO(PCH_SET_COMPILE_FLAGS)\n\nMACRO(GET_PDB_FILENAME _out_filename _target)\n  # determine output directory based on target type\n  GET_TARGET_PROPERTY(_targetType ${_target} TYPE)\n  IF(${_targetType} STREQUAL EXECUTABLE)\n    SET(_targetOutput ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})\n  ELSEIF(${_targetType} STREQUAL STATIC_LIBRARY)\n    SET(_targetOutput ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})\n  ELSE(${_targetType} STREQUAL EXECUTABLE)\n    SET(_targetOutput ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})\n  ENDIF(${_targetType} STREQUAL EXECUTABLE)\n\n  # determine target postfix\n  STRING(TOUPPER \"${CMAKE_BUILD_TYPE}_POSTFIX\" _postfix_var_name)\n  GET_TARGET_PROPERTY(_targetPostfix ${_target} ${_postfix_var_name})\n  IF(${_targetPostfix} MATCHES NOTFOUND)\n    SET(_targetPostfix \"\")\n  ENDIF(${_targetPostfix} MATCHES NOTFOUND)\n\n  SET(${_out_filename} \"${_targetOutput}/${_target}${_targetPostfix}.pdb\")\nENDMACRO(GET_PDB_FILENAME)\n\nMACRO(PCH_SET_COMPILE_COMMAND _inputcpp _compile_FLAGS)\n  IF(CMAKE_CXX_COMPILER_ARG1)\n    # remove leading space in compiler argument\n    STRING(REGEX REPLACE \"^ +\" \"\" pchsupport_compiler_cxx_arg1 ${CMAKE_CXX_COMPILER_ARG1})\n  ELSE(CMAKE_CXX_COMPILER_ARG1)\n    SET(pchsupport_compiler_cxx_arg1 \"\")\n  ENDIF(CMAKE_CXX_COMPILER_ARG1)\n\n  IF(MSVC)\n    GET_PDB_FILENAME(PDB_FILE ${_PCH_current_target})\n    SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} /Yc /Fp\"${PCH_OUTPUT}\" ${_inputcpp} /Fd\"${PDB_FILE}\" /c /Fo\"${PCH_OUTPUT}.obj\")\n    # Ninja PCH Support\n    # http://public.kitware.com/pipermail/cmake-developers/2012-March/003653.html\n    SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES OBJECT_OUTPUTS \"${PCH_OUTPUT}.obj\")\n  ELSE(MSVC)\n    SET(HEADER_FORMAT \"c++-header\")\n    SET(_FLAGS \"\")\n    IF(APPLE)\n      SET(HEADER_FORMAT \"objective-${HEADER_FORMAT}\")\n      SET(_FLAGS -fobjc-abi-version=2 -fobjc-legacy-dispatch)\n    ENDIF(APPLE)\n    SET(PCH_COMMAND ${CMAKE_CXX_COMPILER} ${pchsupport_compiler_cxx_arg1} ${_compile_FLAGS} ${_FLAGS} -x ${HEADER_FORMAT} -o ${PCH_OUTPUT} -c ${PCH_INPUT})\n  ENDIF(MSVC)\nENDMACRO(PCH_SET_COMPILE_COMMAND)\n\nMACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT _targetName _input _arch _language)\n  SET(_OUTPUT_DIR \"${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch\")\n\n  IF(MSVC)\n    FILE(MAKE_DIRECTORY ${_OUTPUT_DIR})\n    GET_FILENAME_COMPONENT(_name ${_input} NAME_WE)\n    SET(PCH_INPUT ${_input})\n    SET(PCH_OUTPUT \"${_OUTPUT_DIR}/${_name}.pch\")\n  ELSE(MSVC)\n    IF(NOT \"${_arch}\" STREQUAL \"\")\n      SET(_OUTPUT_DIR \"${_OUTPUT_DIR}_${_arch}\")\n    ENDIF(NOT \"${_arch}\" STREQUAL \"\")\n\n    IF(NOT \"${_language}\" STREQUAL \"\")\n      SET(_OUTPUT_DIR \"${_OUTPUT_DIR}_${_language}\")\n    ENDIF(NOT \"${_language}\" STREQUAL \"\")\n\n    GET_FILENAME_COMPONENT(_name ${_input} NAME)\n\n    # Copy .h to output dir\n    SET(PCH_INPUT \"${_OUTPUT_DIR}/${_name}\")\n    ADD_CUSTOM_COMMAND(OUTPUT ${PCH_INPUT}\n        COMMAND ${CMAKE_COMMAND} -E copy_if_different ${_input} ${PCH_INPUT}\n        DEPENDS ${_input}\n        COMMENT \"[${_targetName}] Update precompiled header - done\"\n    )\n\n    IF(CLANG)\n      SET(PCH_EXT \"pth\")\n    ELSE(CLANG)\n      SET(PCH_EXT \"gch\")\n    ENDIF(CLANG)\n\n    # For GCC and Clang, PCH needs to be in the same directory as .h\n    SET(PCH_OUTPUT \"${_OUTPUT_DIR}/${_name}.${PCH_EXT}\")\n  ENDIF(MSVC)\nENDMACRO(PCH_SET_PRECOMPILED_HEADER_OUTPUT)\n\n# Add common flags\nMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET _targetName)\n  GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS)\n\n  IF(${oldProps} MATCHES NOTFOUND)\n    SET(oldProps \"\")\n  ENDIF(${oldProps} MATCHES NOTFOUND)\n\n  IF(MSVC)\n    SET(_target_cflags \"${oldProps} /Yu\\\"${PCH_INPUT}\\\" /FI\\\"${PCH_INPUT}\\\" /Fp\\\"${PCH_OUTPUT}\\\"\")\n    # Ninja PCH Support\n    # http://public.kitware.com/pipermail/cmake-developers/2012-March/003653.html\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES OBJECT_DEPENDS \"${PCH_OUTPUT}\")\n\n    # NMAKE-VS2012 Error LNK2011 (NMAKE-VS2010 do not complain)\n    # we need to link the pch.obj file, see http://msdn.microsoft.com/en-us/library/3ay26wa2(v=vs.110).aspx\n    GET_TARGET_PROPERTY(_STATIC_LIBRARY_FLAGS ${_targetName} STATIC_LIBRARY_FLAGS)\n    IF(NOT _STATIC_LIBRARY_FLAGS)\n      SET(_STATIC_LIBRARY_FLAGS)\n    ENDIF(NOT _STATIC_LIBRARY_FLAGS)\n    SET(_STATIC_LIBRARY_FLAGS \"${PCH_OUTPUT}.obj ${_STATIC_LIBRARY_FLAGS}\")\n\n    GET_TARGET_PROPERTY(_LINK_FLAGS ${_targetName} LINK_FLAGS)\n    IF(NOT _LINK_FLAGS)\n      SET(_LINK_FLAGS)\n    ENDIF(NOT _LINK_FLAGS)\n    SET(_LINK_FLAGS \"${PCH_OUTPUT}.obj ${_LINK_FLAGS}\")\n\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES STATIC_LIBRARY_FLAGS ${_STATIC_LIBRARY_FLAGS} LINK_FLAGS ${_LINK_FLAGS})\n  ELSE(MSVC)\n    # for use with distcc and gcc >4.0.1 if preprocessed files are accessible\n    # on all remote machines set\n    # PCH_ADDITIONAL_COMPILER_FLAGS to -fpch-preprocess\n    SET(PCH_ADDITIONAL_COMPILER_FLAGS)\n    LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT)\n\n    # If no arch is specified, create common flags\n    IF(PCH_ARCHS_COUNT LESS 2)\n      SET(PCH_ADDITIONAL_COMPILER_FLAGS \"-include ${PCH_INPUT} ${PCH_ADDITIONAL_COMPILER_FLAGS}\")\n    ENDIF(PCH_ARCHS_COUNT LESS 2)\n\n    IF(APPLE)\n      SET(PCH_ADDITIONAL_COMPILER_FLAGS \"-fobjc-abi-version=2 -fobjc-legacy-dispatch -x objective-c++ ${PCH_ADDITIONAL_COMPILER_FLAGS}\")\n    ENDIF(APPLE)\n    \n    IF(WITH_PCH_DEBUG)\n      SET(PCH_ADDITIONAL_COMPILER_FLAGS \"-H ${PCH_ADDITIONAL_COMPILER_FLAGS}\")\n    ENDIF(WITH_PCH_DEBUG)\n\n    SET(_target_cflags \"${oldProps} ${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch\")\n  ENDIF(MSVC)\n\n  SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_target_cflags})\nENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET)\n\n# Add specific flags for an arch\nMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH _targetName _arch)\n  LIST(LENGTH PCH_ARCHS PCH_ARCHS_COUNT)\n\n  IF(PCH_ARCHS_COUNT GREATER 1)\n    GET_TARGET_PROPERTY(_FLAGS ${_targetName} COMPILE_FLAGS)\n\n    IF(${_FLAGS} MATCHES NOTFOUND)\n      SET(_FLAGS \"\")\n    ENDIF(${_FLAGS} MATCHES NOTFOUND)\n\n    SET(_FLAGS \"${_FLAGS} -Xarch_${_arch} -include${PCH_INPUT}\")\n\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS ${_FLAGS})\n  ENDIF(PCH_ARCHS_COUNT GREATER 1)\nENDMACRO(ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH)\n\nMACRO(PCH_CREATE_TARGET _targetName _targetNamePCH)\n  ADD_CUSTOM_COMMAND(OUTPUT ${PCH_OUTPUT} COMMAND ${PCH_COMMAND} COMMENT \"Generating ${_targetNamePCH}\" DEPENDS ${PCH_INPUT})\n  ADD_CUSTOM_TARGET(${_targetNamePCH} DEPENDS ${PCH_INPUT} ${PCH_OUTPUT})\n  ADD_DEPENDENCIES(${_targetName} ${_targetNamePCH})\nENDMACRO(PCH_CREATE_TARGET _targetName _inputh _inputcpp)\n\nMACRO(ADD_PRECOMPILED_HEADER _targetName _inputh _inputcpp)\n  SET(_PCH_current_target ${_targetName})\n\n  IF(NOT CMAKE_BUILD_TYPE)\n    MESSAGE(FATAL_ERROR\n      \"This is the ADD_PRECOMPILED_HEADER macro. \"\n      \"You must set CMAKE_BUILD_TYPE!\"\n    )\n  ENDIF(NOT CMAKE_BUILD_TYPE)\n\n  PCH_SET_COMPILE_FLAGS(${_targetName})\n\n  IF(PCH_ARCHS)\n    SET(PCH_OUTPUTS)\n    FOREACH(_ARCH ${PCH_ARCHS})\n      STRING(TOUPPER \"${_ARCH}\" _UPPER_ARCH)\n\n      PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} ${_ARCH} \"\")\n      LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT})\n\n      PCH_SET_COMPILE_COMMAND(${_inputcpp} \"${PCH_ARCH_${_UPPER_ARCH}_FLAGS};${PCH_FLAGS}\")\n      PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch_${_ARCH})\n\n      ADD_PRECOMPILED_HEADER_TO_TARGET_ARCH(${_targetName} ${_ARCH})\n    ENDFOREACH(_ARCH)\n  ELSE(PCH_ARCHS)\n    PCH_SET_PRECOMPILED_HEADER_OUTPUT(${_targetName} ${_inputh} \"\" \"\")\n    LIST(APPEND PCH_OUTPUTS ${PCH_OUTPUT})\n\n    PCH_SET_COMPILE_COMMAND(${_inputcpp} \"${PCH_FLAGS}\")\n    PCH_CREATE_TARGET(${_targetName} ${_targetName}_pch)\n  ENDIF(PCH_ARCHS)\n\n  ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName})\n\n  SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES \"${PCH_OUTPUTS}\")\nENDMACRO(ADD_PRECOMPILED_HEADER)\n\nMACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _inputh _inputcpp)\n  IF(NOT PCHSupport_FOUND)\n    MESSAGE(STATUS \"PCH disabled because compiler doesn't support them\")\n    RETURN()\n  ENDIF(NOT PCHSupport_FOUND)\n\n  # 0 => creating a new target for PCH, works for all makefiles\n  # 1 => setting PCH for VC++ project, works for VC++ projects\n  # 2 => setting PCH for XCode project, works for XCode projects\n  IF(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    SET(PCH_METHOD 1)\n  ELSEIF(CMAKE_GENERATOR MATCHES \"Xcode\")\n    SET(PCH_METHOD 2)\n  ELSE(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n    SET(PCH_METHOD 0)\n  ENDIF(CMAKE_GENERATOR MATCHES \"Visual Studio\")\n\n  IF(PCH_METHOD EQUAL 1)\n    # Auto include the precompile (useful for moc processing, since the use of\n    # precompiled is specified at the target level\n    # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt)\n\n    GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS)\n    IF(${oldProps} MATCHES NOTFOUND)\n      SET(oldProps \"\")\n    ENDIF(${oldProps} MATCHES NOTFOUND)\n\n    SET(newProperties \"${oldProps} /Yu\\\"${_inputh}\\\" /FI\\\"${_inputh}\\\"\")\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS \"${newProperties}\")\n\n    #also inlude ${oldProps} to have the same compile options\n    SET_SOURCE_FILES_PROPERTIES(${_inputcpp} PROPERTIES COMPILE_FLAGS \"${oldProps} /Yc\\\"${_inputh}\\\"\")\n  ELSEIF(PCH_METHOD EQUAL 2)\n    # For Xcode, cmake needs my patch to process\n    # GCC_PREFIX_HEADER and GCC_PRECOMPILE_PREFIX_HEADER as target properties\n\n    # When buiding out of the tree, precompiled may not be located\n    # Use full path instead.\n    GET_FILENAME_COMPONENT(fullPath ${_inputh} ABSOLUTE)\n\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PREFIX_HEADER \"${fullPath}\")\n    SET_TARGET_PROPERTIES(${_targetName} PROPERTIES XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER \"YES\")\n  ELSE(PCH_METHOD EQUAL 1)\n    #Fallback to the \"old\" precompiled suppport\n    ADD_PRECOMPILED_HEADER(${_targetName} ${_inputh} ${_inputcpp})\n  ENDIF(PCH_METHOD EQUAL 1)\n\n  IF(TARGET ${_targetName}_static)\n    ADD_NATIVE_PRECOMPILED_HEADER(${_targetName}_static ${_inputh} ${_inputcpp})\n  ENDIF(TARGET ${_targetName}_static)\nENDMACRO(ADD_NATIVE_PRECOMPILED_HEADER)\n"
  },
  {
    "path": "code/CMakeModules/iOSToolChain.cmake",
    "content": "# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake\n# files which are included with CMake 2.8.4\n# It has been altered for iOS development\n#\n# Options:\n#\n# IOS_VERSION = last(default) or specific one (4.3, 5.0, 4.1)\n#   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders\n#   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.\n#   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.\n#\n# IOS_PLATFORM = OS (default) or SIMULATOR or ALL\n#   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders\n#   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.\n#   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.\n#\n# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder\n#   By default this location is automatcially chosen based on the IOS_PLATFORM value above.\n#   If set manually, it will override the default location and force the user of a particular Developer Platform\n#\n# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder\n#   By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.\n#   In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.\n#   If set manually, this will force the use of a specific SDK version\n\nIF(DEFINED CMAKE_CROSSCOMPILING)\n  # subsequent toolchain loading is not really needed\n  RETURN()\nENDIF()\n\n# Standard settings\nSET(CMAKE_SYSTEM_NAME Darwin)\nSET(CMAKE_SYSTEM_VERSION 1) # TODO: determine target Darwin version\nSET(UNIX ON)\nSET(APPLE ON)\nSET(IOS ON)\n\n# Force the compilers to Clang for iOS\ninclude (CMakeForceCompiler)\nCMAKE_FORCE_C_COMPILER (clang Clang)\nCMAKE_FORCE_CXX_COMPILER (clang++ Clang)\n\n# Setup iOS platform\nif (NOT DEFINED IOS_PLATFORM)\n  set (IOS_PLATFORM \"OS\")\nendif (NOT DEFINED IOS_PLATFORM)\nset (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING \"Type of iOS Platform\")\n\nSET(IOS_PLATFORM_LOCATION \"iPhoneOS.platform\")\nSET(IOS_SIMULATOR_PLATFORM_LOCATION \"iPhoneSimulator.platform\")\n\n# Check the platform selection and setup for developer root\nif (${IOS_PLATFORM} STREQUAL \"OS\")\n  # This causes the installers to properly locate the output libraries\n  set (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphoneos\")\nelseif (${IOS_PLATFORM} STREQUAL \"SIMULATOR\")\n  # This causes the installers to properly locate the output libraries\n  set (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphonesimulator\")\nelseif (${IOS_PLATFORM} STREQUAL \"ALL\")\n  # This causes the installers to properly locate the output libraries\n  set (CMAKE_XCODE_EFFECTIVE_PLATFORMS \"-iphonesimulator;-iphoneos\")\nelse (${IOS_PLATFORM} STREQUAL \"OS\")\n  message (FATAL_ERROR \"Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR\")\nendif (${IOS_PLATFORM} STREQUAL \"OS\")\nset (CMAKE_XCODE_EFFECTIVE_PLATFORMS ${CMAKE_XCODE_EFFECTIVE_PLATFORMS} CACHE PATH \"iOS Platform\")\n\n# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT\n# Note Xcode 4.3 changed the installation location, choose the most recent one available\nSET(XCODE_POST_43_ROOT \"/Applications/Xcode.app/Contents/Developer/Platforms\")\nSET(XCODE_PRE_43_ROOT \"/Developer/Platforms\")\n\nIF(NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)\n  IF(EXISTS ${XCODE_POST_43_ROOT})\n    SET(CMAKE_XCODE_ROOT ${XCODE_POST_43_ROOT})\n  ELSEIF(EXISTS ${XCODE_PRE_43_ROOT})\n    SET(CMAKE_XCODE_ROOT ${XCODE_PRE_43_ROOT})\n  ENDIF(EXISTS ${XCODE_POST_43_ROOT})\n  IF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer)\n    SET(CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer)\n  ENDIF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_PLATFORM_LOCATION}/Developer)\n  IF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer)\n    SET(CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer)\n  ENDIF(EXISTS ${CMAKE_XCODE_ROOT}/${IOS_SIMULATOR_PLATFORM_LOCATION}/Developer)\nENDIF(NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)\nSET(CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH \"Location of iOS Platform\")\nSET(CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT ${CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT} CACHE PATH \"Location of iOS Simulator Platform\")\n\nMACRO(GET_AVAILABLE_SDK_VERSIONS ROOT VERSIONS)\n  FILE(GLOB _CMAKE_IOS_SDKS \"${ROOT}/SDKs/iPhoneOS*\")\n  IF(_CMAKE_IOS_SDKS)\n    LIST(SORT _CMAKE_IOS_SDKS)\n    LIST(REVERSE _CMAKE_IOS_SDKS)\n    FOREACH(_CMAKE_IOS_SDK ${_CMAKE_IOS_SDKS})\n      STRING(REGEX REPLACE \".+iPhoneOS([0-9.]+)\\\\.sdk\" \"\\\\1\" _IOS_SDK \"${_CMAKE_IOS_SDK}\")\n      LIST(APPEND ${VERSIONS} ${_IOS_SDK})\n    ENDFOREACH(_CMAKE_IOS_SDK)\n  ENDIF(_CMAKE_IOS_SDKS)\nENDMACRO(GET_AVAILABLE_SDK_VERSIONS)\n\n# Find and use the most recent iOS sdk \nIF(NOT DEFINED CMAKE_IOS_SDK_ROOT)\n  # Search for a specific version of a SDK\n  GET_AVAILABLE_SDK_VERSIONS(${CMAKE_IOS_DEVELOPER_ROOT} IOS_VERSIONS)\n\n  IF(NOT IOS_VERSIONS)\n    MESSAGE(FATAL_ERROR \"No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.\")\n  ENDIF(NOT IOS_VERSIONS)\n  \n  IF(IOS_VERSION)\n    LIST(FIND IOS_VERSIONS \"${IOS_VERSION}\" _INDEX)\n    IF(_INDEX EQUAL -1)\n      LIST(GET IOS_VERSIONS 0 IOS_SDK_VERSION)\n    ELSE(_INDEX EQUAL -1)\n      SET(IOS_SDK_VERSION ${IOS_VERSION})\n    ENDIF(_INDEX EQUAL -1)\n  ELSE(IOS_VERSION)\n    LIST(GET IOS_VERSIONS 0 IOS_VERSION)\n    SET(IOS_SDK_VERSION ${IOS_VERSION})\n  ENDIF(IOS_VERSION)\n\n  MESSAGE(STATUS \"Target iOS ${IOS_VERSION} and use SDK ${IOS_SDK_VERSION}\")\n\n  SET(CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/iPhoneOS${IOS_SDK_VERSION}.sdk)\n  SET(CMAKE_IOS_SIMULATOR_SDK_ROOT ${CMAKE_IOS_SIMULATOR_DEVELOPER_ROOT}/SDKs/iPhoneSimulator${IOS_SDK_VERSION}.sdk)\nendif (NOT DEFINED CMAKE_IOS_SDK_ROOT)\n\nSET(CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH \"Location of the selected iOS SDK\")\nSET(CMAKE_IOS_SIMULATOR_SDK_ROOT ${CMAKE_IOS_SIMULATOR_SDK_ROOT} CACHE PATH \"Location of the selected iOS Simulator SDK\")\n\nSET(IOS_VERSION ${IOS_VERSION} CACHE STRING \"iOS target version\")\n\n# Set the sysroot default to the most recent SDK\nSET(CMAKE_IOS_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH \"Sysroot used for iOS support\")\nSET(CMAKE_IOS_SIMULATOR_SYSROOT ${CMAKE_IOS_SIMULATOR_SDK_ROOT} CACHE PATH \"Sysroot used for iOS Simulator support\")\n\nIF(CMAKE_GENERATOR MATCHES Xcode)\n  SET(ARCHS \"$(ARCHS_STANDARD_32_BIT)\")\n  IF(${IOS_PLATFORM} STREQUAL \"OS\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"armv7\")\n  ELSEIF(${IOS_PLATFORM} STREQUAL \"SIMULATOR\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"x86\")\n  ELSEIF(${IOS_PLATFORM} STREQUAL \"ALL\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"armv7\")\n  ENDIF(${IOS_PLATFORM} STREQUAL \"OS\")\nELSE(CMAKE_GENERATOR MATCHES Xcode)\n  IF(${IOS_PLATFORM} STREQUAL \"OS\")\n    SET(ARCHS \"armv7\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"armv7\")\n  ELSEIF(${IOS_PLATFORM} STREQUAL \"SIMULATOR\")\n    # iPhone simulator targets i386\n    SET(ARCHS \"i386\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"x86\")\n  ELSEIF(${IOS_PLATFORM} STREQUAL \"ALL\")\n    SET(ARCHS \"armv7;i386\")\n    SET(CMAKE_SYSTEM_PROCESSOR \"armv7\")\n  ENDIF(${IOS_PLATFORM} STREQUAL \"OS\")\nENDIF(CMAKE_GENERATOR MATCHES Xcode)\n\n# set the architecture for iOS - using ARCHS_STANDARD_32_BIT sets armv7,armv7s and appears to be XCode's standard. \n# The other value that works is ARCHS_UNIVERSAL_IPHONE_OS but that sets armv7 only\nset (CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE string  \"Build architecture for iOS\")\n\n# Set the find root to the iOS developer roots and to user defined paths\nset (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX} $ENV{EXTERNAL_IOS_PATH} CACHE string  \"iOS find search path root\")\n\n# default to searching for frameworks first\nset (CMAKE_FIND_FRAMEWORK FIRST)\n\n# set up the default search directories for frameworks\nset (CMAKE_SYSTEM_FRAMEWORK_PATH\n  ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks\n  ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks\n  ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks\n)\n\n# only search the iOS sdks, not the remainder of the host filesystem\nset (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)\nset (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)\nset (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)\n\n#SET(CMAKE_SYSTEM_INCLUDE_PATH /include /usr/include)\n#SET(CMAKE_SYSTEM_LIBRARY_PATH /lib /usr/lib)\n#SET(CMAKE_SYSTEM_PROGRAM_PATH /bin /usr/bin)\n"
  },
  {
    "path": "code/CMakeModules/nel.cmake",
    "content": "# Force Release configuration for compiler checks\nSET(CMAKE_TRY_COMPILE_CONFIGURATION \"Release\")\n\n# Force Release configuration by default\nIF(NOT CMAKE_BUILD_TYPE)\n  SET(CMAKE_BUILD_TYPE \"Release\" CACHE STRING \"\" FORCE)\nENDIF(NOT CMAKE_BUILD_TYPE)\n\n# Declare CMAKE_CONFIGURATION_TYPES before PROJECT\nSET(CMAKE_CONFIGURATION_TYPES \"Debug;Release\" CACHE STRING \"\" FORCE)\n\n###\n# Helper macro that generates .pc and installs it.\n# Argument: name - the name of the .pc package, e.g. \"nel-pacs.pc\"\n###\nMACRO(NL_GEN_PC name)\n  IF(NOT WIN32 AND WITH_INSTALL_LIBRARIES)\n    CONFIGURE_FILE(${name}.in \"${CMAKE_CURRENT_BINARY_DIR}/${name}\")\n    INSTALL(FILES \"${CMAKE_CURRENT_BINARY_DIR}/${name}\" DESTINATION ${NL_LIB_PREFIX}/pkgconfig)\n  ENDIF(NOT WIN32 AND WITH_INSTALL_LIBRARIES)\nENDMACRO(NL_GEN_PC)\n\n###\n# Helper macro that generates revision.h from revision.h.in\n###\nMACRO(NL_GEN_REVISION_H)\n  IF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h.in)\n    SET(TOOL_FOUND OFF)\n\n    IF(EXISTS \"${CMAKE_SOURCE_DIR}/../.svn/\")\n      FIND_PACKAGE(Subversion)\n\n      IF(SUBVERSION_FOUND)\n        SET(TOOL_FOUND ON)\n      ENDIF(SUBVERSION_FOUND)\n    ENDIF(EXISTS \"${CMAKE_SOURCE_DIR}/../.svn/\")\n\n    IF(EXISTS \"${CMAKE_SOURCE_DIR}/../.hg/\")\n      FIND_PACKAGE(Mercurial)\n\n      IF(MERCURIAL_FOUND)\n        SET(TOOL_FOUND ON)\n      ENDIF(MERCURIAL_FOUND)\n    ENDIF(EXISTS \"${CMAKE_SOURCE_DIR}/../.hg/\")\n\n    # if already generated\n    IF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h)\n      # copy it\n      MESSAGE(STATUS \"Copying provided revision.h...\")\n      FILE(COPY ${CMAKE_SOURCE_DIR}/revision.h DESTINATION ${CMAKE_BINARY_DIR})\n      SET(HAVE_REVISION_H ON)\n    ENDIF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h)\n\n    IF(TOOL_FOUND)\n      # a custom target that is always built\n      ADD_CUSTOM_TARGET(revision ALL\n        COMMAND ${CMAKE_COMMAND}\n        -DSOURCE_DIR=${CMAKE_SOURCE_DIR}\n        -DROOT_DIR=${CMAKE_SOURCE_DIR}/..\n        -DCMAKE_MODULE_PATH=${CMAKE_SOURCE_DIR}/CMakeModules\n        -P ${CMAKE_SOURCE_DIR}/CMakeModules/GetRevision.cmake)\n\n      # revision.h is a generated file\n      SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/revision.h\n        PROPERTIES GENERATED TRUE\n        HEADER_FILE_ONLY TRUE)\n      SET(HAVE_REVISION_H ON)\n    ENDIF(TOOL_FOUND)\n\n    IF(HAVE_REVISION_H)\n      INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})\n      ADD_DEFINITIONS(-DHAVE_REVISION_H)\n    ENDIF(HAVE_REVISION_H)\n  ENDIF(EXISTS ${CMAKE_SOURCE_DIR}/revision.h.in)\nENDMACRO(NL_GEN_REVISION_H)\n\n###\n#\n###\nMACRO(NL_TARGET_LIB name)\n  IF(WITH_STATIC)\n    ADD_LIBRARY(${name} STATIC ${ARGN})\n  ELSE(WITH_STATIC)\n    ADD_LIBRARY(${name} SHARED ${ARGN})\n  ENDIF(WITH_STATIC)\nENDMACRO(NL_TARGET_LIB)\n\n###\n#\n###\nMACRO(NL_TARGET_DRIVER name)\n  IF(WITH_STATIC_DRIVERS)\n    ADD_LIBRARY(${name} STATIC ${ARGN})\n  ELSE(WITH_STATIC_DRIVERS)\n    ADD_LIBRARY(${name} MODULE ${ARGN})\n  ENDIF(WITH_STATIC_DRIVERS)\nENDMACRO(NL_TARGET_DRIVER)\n\n###\n# Helper macro that sets the default library properties.\n# Argument: name - the target name whose properties are being set\n# Argument:\n###\nMACRO(NL_DEFAULT_PROPS name label)\n  IF(HAVE_REVISION_H)\n    # explicitly say that the target depends on revision.h\n    ADD_DEPENDENCIES(${name} revision)\n  ENDIF(HAVE_REVISION_H)\n\n  # Note: This is just a workaround for a CMake bug generating VS10 files with a colon in the project name.\n  # CMake Bug ID: http://www.cmake.org/Bug/view.php?id=11819\n  STRING(REGEX REPLACE \"\\\\:\" \" -\" proj_label ${label})\n  SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${proj_label})\n  GET_TARGET_PROPERTY(type ${name} TYPE)\n  IF(${type} STREQUAL SHARED_LIBRARY)\n    # Set versions only if target is a shared library\n    SET_TARGET_PROPERTIES(${name} PROPERTIES\n      VERSION ${NL_VERSION} SOVERSION ${NL_VERSION_MAJOR})\n    IF(NL_LIB_PREFIX)\n      SET_TARGET_PROPERTIES(${name} PROPERTIES INSTALL_NAME_DIR ${NL_LIB_PREFIX})\n    ENDIF(NL_LIB_PREFIX)\n  ENDIF(${type} STREQUAL SHARED_LIBRARY)\n\n  IF(${type} STREQUAL EXECUTABLE AND WIN32 AND NOT MINGW)\n    SET_TARGET_PROPERTIES(${name} PROPERTIES\n      VERSION ${NL_VERSION}\n      SOVERSION ${NL_VERSION_MAJOR}\n      COMPILE_FLAGS \"/GA\"\n      LINK_FLAGS \"/VERSION:${NL_VERSION_MAJOR}.${NL_VERSION_MINOR}\")\n  ENDIF(${type} STREQUAL EXECUTABLE AND WIN32 AND NOT MINGW)\nENDMACRO(NL_DEFAULT_PROPS)\n\n###\n# Adds the target suffix on Windows.\n# Argument: name - the library's target name.\n###\nMACRO(NL_ADD_LIB_SUFFIX name)\n  IF(WIN32)\n    SET_TARGET_PROPERTIES(${name} PROPERTIES DEBUG_POSTFIX \"_d\" RELEASE_POSTFIX \"_r\")\n  ENDIF(WIN32)\nENDMACRO(NL_ADD_LIB_SUFFIX)\n\n###\n# Adds the runtime link flags for Win32 binaries and links STLport.\n# Argument: name - the target to add the link flags to.\n###\nMACRO(NL_ADD_RUNTIME_FLAGS name)\n  IF(WIN32)\n#    SET_TARGET_PROPERTIES(${name} PROPERTIES\n#      LINK_FLAGS_DEBUG \"${CMAKE_LINK_FLAGS_DEBUG}\"\n#      LINK_FLAGS_RELEASE \"${CMAKE_LINK_FLAGS_RELEASE}\")\n  ENDIF(WIN32)\n  IF(WITH_STLPORT)\n    TARGET_LINK_LIBRARIES(${name} ${STLPORT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})\n  ENDIF(WITH_STLPORT)\nENDMACRO(NL_ADD_RUNTIME_FLAGS)\n\nMACRO(NL_ADD_STATIC_VID_DRIVERS name)\n  IF(WITH_STATIC_DRIVERS)\n    IF(WIN32)\n      IF(WITH_DRIVER_DIRECT3D)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_direct3d_win)\n      ENDIF(WITH_DRIVER_DIRECT3D)\n    ENDIF(WIN32)\n\n    IF(WITH_DRIVER_OPENGL)\n      IF(WIN32)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_opengl_win)\n      ELSE(WIN32)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_opengl)\n      ENDIF(WIN32)\n    ENDIF(WITH_DRIVER_OPENGL)\n\n    IF(WITH_DRIVER_OPENGLES)\n      IF(WIN32)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_opengles_win)\n      ELSE(WIN32)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_opengles)\n      ENDIF(WIN32)\n    ENDIF(WITH_DRIVER_OPENGLES)\n  ENDIF(WITH_STATIC_DRIVERS)\nENDMACRO(NL_ADD_STATIC_VID_DRIVERS)\n\nMACRO(NL_ADD_STATIC_SND_DRIVERS name)\n  IF(WITH_STATIC_DRIVERS)\n    IF(WIN32)\n      IF(WITH_DRIVER_DSOUND)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_dsound_win)\n      ENDIF(WITH_DRIVER_DSOUND)\n\n      IF(WITH_DRIVER_XAUDIO2)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_xaudio2_win)\n      ENDIF(WITH_DRIVER_XAUDIO2)\n\n      IF(WITH_DRIVER_OPENAL)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_openal_win)\n      ENDIF(WITH_DRIVER_OPENAL)\n\n      IF(WITH_DRIVER_FMOD)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_fmod_win)\n      ENDIF(WITH_DRIVER_FMOD)\n    ELSE(WIN32)\n      IF(WITH_DRIVER_OPENAL)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_openal)\n      ENDIF(WITH_DRIVER_OPENAL)\n\n      IF(WITH_DRIVER_FMOD)\n        TARGET_LINK_LIBRARIES(${name} nel_drv_fmod)\n      ENDIF(WITH_DRIVER_FMOD)\n    ENDIF(WIN32)\n\n  ENDIF(WITH_STATIC_DRIVERS)\nENDMACRO(NL_ADD_STATIC_SND_DRIVERS)\n\n###\n# Checks build vs. source location. Prevents In-Source builds.\n###\nMACRO(CHECK_OUT_OF_SOURCE)\n  IF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})\n    MESSAGE(FATAL_ERROR \"\n\nCMake generation for this project is not allowed within the source directory!\nRemove the CMakeCache.txt file and try again from another folder, e.g.:\n\n   rm CMakeCache.txt\n   mkdir cmake\n   cd cmake\n   cmake ..\n    \")\n  ENDIF(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})\n\nENDMACRO(CHECK_OUT_OF_SOURCE)\n\nMACRO(NL_SETUP_DEFAULT_OPTIONS)\n  ###\n  # Features\n  ###\n  OPTION(WITH_LOGGING             \"With Logging\"                                  ON )\n  OPTION(WITH_COVERAGE            \"With Code Coverage Support\"                    OFF)\n  OPTION(WITH_PCH                 \"With Precompiled Headers\"                      ON )\n  OPTION(FINAL_VERSION            \"Build in Final Version mode\"                   OFF)\n\n  # Default to static building on Windows.\n  #IF(WIN32)\n    OPTION(WITH_STATIC            \"With static libraries.\"                        ON )\n  #ELSE(WIN32)\n  #  OPTION(WITH_STATIC            \"With static libraries.\"                        OFF)\n  #ENDIF(WIN32)\n  #IF (WITH_STATIC)\n    OPTION(WITH_STATIC_LIBXML2    \"With static libxml2\"                           ON )\n  #ELSE(WITH_STATIC)\n  #  OPTION(WITH_STATIC_LIBXML2    \"With static libxml2\"                           OFF)\n  #ENDIF(WITH_STATIC)\n  OPTION(WITH_STATIC_DRIVERS      \"With static drivers.\"                          OFF)\n  IF(WIN32)\n    OPTION(WITH_EXTERNAL          \"With provided external.\"                       ON )\n  ELSE(WIN32)\n    OPTION(WITH_EXTERNAL          \"With provided external.\"                       OFF)\n  ENDIF(WIN32)\n  OPTION(WITH_STATIC_EXTERNAL     \"With static external libraries\"                OFF)\n  OPTION(WITH_INSTALL_LIBRARIES   \"Install development files.\"                    OFF)\n  \n  \n  IF(WIN32)\n    OPTION(WITH_GTK                 \"With GTK Support\"                            OFF)\n  ELSE(WIN32)\n    OPTION(WITH_GTK                 \"With GTK Support\"                            OFF)\n  ENDIF(WIN32)\n\n  ###\n  # Optional support\n  ###\n  OPTION(WITH_SYMBOLS             \"Keep debug symbols in binaries\"                ON )\n  #IF(WIN32)\n    OPTION(WITH_STLPORT           \"With STLport support.\"                         OFF )\n  #ELSE(WIN32)\n  #  OPTION(WITH_STLPORT           \"With STLport support.\"                         OFF)\n  #ENDIF(WIN32)\n\n  OPTION(BUILD_DASHBOARD          \"Build to the CDash dashboard\"                  OFF)\n\n  OPTION(WITH_NEL                 \"Build NeL (nearly always required).\"           ON )\n#  OPTION(WITH_NELNS               \"Build NeL Network Services.\"                   OFF)\n  OPTION(WITH_EVA                 \"Build EVA.\"                                    ON)\n  OPTION(WITH_TOOLS               \"Build Tools.\"                                  OFF)\n\nENDMACRO(NL_SETUP_DEFAULT_OPTIONS)\n\nMACRO(NL_SETUP_NEL_DEFAULT_OPTIONS)\n  ###\n  # Core libraries\n  ###\n  OPTION(WITH_NET                 \"Build NLNET\"                                   ON )\n#  OPTION(WITH_GEORGES             \"Build NLGEORGES\"                               ON)\n#  OPTION(WITH_LIGO                \"Build NLLIGO\"                                  OFF)\n#  OPTION(WITH_LOGIC               \"Build NLLOGIC\"                                 OFF)\n\n  ###\n  # Optional support\n  ###\n  OPTION(WITH_NEL_TOOLS           \"Build NeL Tools\"                               OFF)\n  OPTION(WITH_NEL_SAMPLES         \"Build NeL Samples\"                             OFF)\n  OPTION(WITH_NEL_TESTS           \"Build NeL Unit Tests\"                          OFF)\n  \n  #OPTION(WITH_LUA51               \"Build EVA using Lua 5.1\"                        ON )\n  #OPTION(WITH_LUA52               \"Build EVA using Lua 5.2\"                        OFF)\n  \n  OPTION(WITH_SSE2                \"With SSE2\"                                     OFF )\n  OPTION(WITH_SSE3                \"With SSE3\"                                     ON )\n  \n  \n  IF(NOT MSVC)\n    OPTION(WITH_GCC_FPMATH_BOTH   \"With GCC -mfpmath=both\"                        OFF)\n    OPTION(WITH_GCC_FPERMISSIVE   \"With GCC -fpermissive\"                         ON)\n  ENDIF(NOT MSVC)\nENDMACRO(NL_SETUP_NEL_DEFAULT_OPTIONS)\n\nMACRO(NL_SETUP_NELNS_DEFAULT_OPTIONS)\n  ###\n  # Core libraries\n  ###\n  #OPTION(WITH_NELNS_SERVER        \"Build NeLNS Services\"                          OFF )\n  #OPTION(WITH_NELNS_LOGIN_SYSTEM  \"Build NeLNS Login System Tools\"                OFF )\n  \n  ###\n  # Optional support\n  ###\n  \n  OPTION(WITH_ROBOT               \"Build Robot\"                                    OFF)\n\nENDMACRO(NL_SETUP_NELNS_DEFAULT_OPTIONS)\n\n\nMACRO(ADD_PLATFORM_FLAGS _FLAGS)\n  SET(PLATFORM_CFLAGS \"${PLATFORM_CFLAGS} ${_FLAGS}\")\n  SET(PLATFORM_CXXFLAGS \"${PLATFORM_CXXFLAGS} ${_FLAGS}\")\nENDMACRO()\n\nMACRO(ADD_PLATFORM_LINKFLAGS _FLAGS)\n  SET(PLATFORM_LINKFLAGS \"${PLATFORM_LINKFLAGS} ${_FLAGS}\")\nENDMACRO()\n\nMACRO(NL_SETUP_BUILD)\n\n  #-----------------------------------------------------------------------------\n  # Setup the buildmode variables.\n  #\n  # None                  = NL_RELEASE\n  # Debug                 = NL_DEBUG\n  # Release               = NL_RELEASE\n\n  IF(CMAKE_BUILD_TYPE MATCHES \"Debug\")\n    SET(NL_BUILD_MODE \"NL_DEBUG\")\n  ELSE()\n    IF(CMAKE_BUILD_TYPE MATCHES \"Release\")\n      SET(NL_BUILD_MODE \"NL_RELEASE\")\n    ELSE()\n      SET(NL_BUILD_MODE \"NL_RELEASE\")\n      # enforce release mode if it's neither Debug nor Release\n      SET(CMAKE_BUILD_TYPE \"Release\" CACHE STRING \"\" FORCE)\n    ENDIF()\n  ENDIF()\n\n  IF(CMAKE_CXX_LIBRARY_ARCHITECTURE)\n    SET(HOST_CPU ${CMAKE_CXX_LIBRARY_ARCHITECTURE})\n  ELSE()\n    SET(HOST_CPU ${CMAKE_HOST_SYSTEM_PROCESSOR})\n  ENDIF()\n\n  IF(HOST_CPU MATCHES \"(amd|AMD|x86_)64\")\n    SET(HOST_CPU \"x86_64\")\n  ELSEIF(HOST_CPU MATCHES \"i.86\")\n    SET(HOST_CPU \"x86\")\n  ENDIF()\n\n  # Determine target CPU\n\n  # If not specified, use the same CPU as host\n  IF(NOT TARGET_CPU)\n    SET(TARGET_CPU ${HOST_CPU})\n  ENDIF()\n\n  IF(TARGET_CPU MATCHES \"(amd|AMD|x86_)64\")\n    SET(TARGET_CPU \"x86_64\")\n  ELSEIF(TARGET_CPU MATCHES \"i.86\")\n    SET(TARGET_CPU \"x86\")\n  ENDIF()\n\n  IF(${CMAKE_CXX_COMPILER_ID} MATCHES \"Clang\")\n    SET(CLANG ON)\n    MESSAGE(STATUS \"Using Clang ${CMAKE_CXX_COMPILER_VERSION} compiler\")\n  ENDIF()\n\n  IF(CMAKE_GENERATOR MATCHES \"Xcode\")\n    SET(XCODE ON)\n    MESSAGE(STATUS \"Generating Xcode project\")\n  ENDIF()\n\n  IF(CMAKE_GENERATOR MATCHES \"NMake\")\n    SET(NMAKE ON)\n    MESSAGE(STATUS \"Generating NMake project\")\n  ENDIF()\n\n  IF(CMAKE_GENERATOR MATCHES \"Ninja\")\n    SET(NINJA ON)\n    MESSAGE(STATUS \"Generating Ninja project\")\n  ENDIF()\n\n  # If target and host CPU are the same\n  IF(\"${HOST_CPU}\" STREQUAL \"${TARGET_CPU}\" AND NOT CMAKE_CROSSCOMPILING)\n    # x86-compatible CPU\n    IF(HOST_CPU MATCHES \"x86\")\n      IF(NOT CMAKE_SIZEOF_VOID_P)\n        INCLUDE (CheckTypeSize)\n        CHECK_TYPE_SIZE(\"void*\"  CMAKE_SIZEOF_VOID_P)\n      ENDIF()\n\n      # Using 32 or 64 bits libraries\n      IF(CMAKE_SIZEOF_VOID_P EQUAL 8)\n        SET(TARGET_CPU \"x86_64\")\n      ELSE()\n        SET(TARGET_CPU \"x86\")\n      ENDIF()\n    ELSEIF(HOST_CPU MATCHES \"arm\")\n      SET(TARGET_CPU \"arm\")\n    ELSE()\n      SET(TARGET_CPU \"unknown\")\n      MESSAGE(STATUS \"Unknown architecture: ${HOST_CPU}\")\n    ENDIF()\n    # TODO: add checks for PPC\n  ELSE()\n    MESSAGE(STATUS \"Compiling on ${HOST_CPU} for ${TARGET_CPU}\")\n  ENDIF()\n\n  # Use values from environment variables\n  SET(PLATFORM_CFLAGS \"$ENV{CFLAGS} $ENV{CPPFLAGS} ${PLATFORM_CFLAGS}\")\n  SET(PLATFORM_CXXFLAGS \"$ENV{CXXFLAGS} $ENV{CPPFLAGS} ${PLATFORM_CXXFLAGS}\")\n  SET(PLATFORM_LINKFLAGS \"$ENV{LDFLAGS} ${PLATFORM_LINKFLAGS}\")\n\n  # Remove -g and -O flag because we are managing them ourself\n  STRING(REPLACE \"-g\" \"\" PLATFORM_CFLAGS ${PLATFORM_CFLAGS})\n  STRING(REPLACE \"-g\" \"\" PLATFORM_CXXFLAGS ${PLATFORM_CXXFLAGS})\n  STRING(REGEX REPLACE \"-O[0-9s]\" \"\" PLATFORM_CFLAGS ${PLATFORM_CFLAGS})\n  STRING(REGEX REPLACE \"-O[0-9s]\" \"\" PLATFORM_CXXFLAGS ${PLATFORM_CXXFLAGS})\n\n  # Strip spaces\n  STRING(STRIP ${PLATFORM_CFLAGS} PLATFORM_CFLAGS)\n  STRING(STRIP ${PLATFORM_CXXFLAGS} PLATFORM_CXXFLAGS)\n  STRING(STRIP ${PLATFORM_LINKFLAGS} PLATFORM_LINKFLAGS)\n\n  IF(NOT CMAKE_OSX_ARCHITECTURES)\n    IF(TARGET_CPU STREQUAL \"x86_64\")\n      SET(TARGET_X64 1)\n      SET(TARGET_X86 1)\n    ELSEIF(TARGET_CPU STREQUAL \"x86\")\n      SET(TARGET_X86 1)\n    ELSEIF(TARGET_CPU STREQUAL \"arm64\")\n      SET(TARGET_ARM 1)\n      SET(TARGET_ARM64 1)\n    ELSEIF(TARGET_CPU STREQUAL \"armv7s\")\n      SET(TARGET_ARM 1)\n      SET(TARGET_ARMV7S 1)\n    ELSEIF(TARGET_CPU STREQUAL \"armv7\")\n      SET(TARGET_ARM 1)\n      SET(TARGET_ARMV7 1)\n    ELSEIF(TARGET_CPU STREQUAL \"armv6\")\n      SET(TARGET_ARM 1)\n      SET(TARGET_ARMV6 1)\n    ELSEIF(TARGET_CPU STREQUAL \"armv5\")\n      SET(TARGET_ARM 1)\n      SET(TARGET_ARMV5 1)\n    ELSEIF(TARGET_CPU STREQUAL \"arm\")\n      SET(TARGET_ARM 1)\n    ELSEIF(TARGET_CPU STREQUAL \"mips\")\n      SET(TARGET_MIPS 1)\n    ENDIF()\n\n    IF(TARGET_ARM)\n      IF(TARGET_ARM64)\n        ADD_PLATFORM_FLAGS(\"-DHAVE_ARM64\")\n      ENDIF()\n\n      IF(TARGET_ARMV7S)\n        ADD_PLATFORM_FLAGS(\"-DHAVE_ARMV7S\")\n      ENDIF()\n\n      IF(TARGET_ARMV7)\n        ADD_PLATFORM_FLAGS(\"-DHAVE_ARMV7\")\n      ENDIF()\n\n      IF(TARGET_ARMV6)\n        ADD_PLATFORM_FLAGS(\"-HAVE_ARMV6\")\n      ENDIF()\n\n      ADD_PLATFORM_FLAGS(\"-DHAVE_ARM\")\n    ENDIF()\n\n    IF(TARGET_X86)\n      ADD_PLATFORM_FLAGS(\"-DHAVE_X86\")\n    ENDIF()\n\n    IF(TARGET_X64)\n      ADD_PLATFORM_FLAGS(\"-DHAVE_X64 -DHAVE_X86_64\")\n    ENDIF()\n\n    IF(TARGET_MIPS)\n      ADD_PLATFORM_FLAGS(\"-DHAVE_MIPS\")\n    ENDIF()\n  ENDIF()\n\n  # Fix library paths suffixes for Debian MultiArch\n  IF(LIBRARY_ARCHITECTURE)\n    SET(CMAKE_LIBRARY_PATH /lib/${LIBRARY_ARCHITECTURE} /usr/lib/${LIBRARY_ARCHITECTURE} ${CMAKE_LIBRARY_PATH})\n    IF(TARGET_X64)\n      SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib64 /usr/lib64)\n    ELSEIF(TARGET_X86)\n      SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} /lib32 /usr/lib32)\n    ENDIF()\n  ENDIF()\n\n  IF(APPLE AND NOT IOS)\n    SET(CMAKE_INCLUDE_PATH /opt/local/include ${CMAKE_INCLUDE_PATH})\n    SET(CMAKE_LIBRARY_PATH /opt/local/lib ${CMAKE_LIBRARY_PATH})\n  ENDIF()\n\n  IF(WITH_LOGGING)\n    ADD_PLATFORM_FLAGS(\"-DENABLE_LOGS\")\n  ENDIF()\n\n  IF(MSVC)\n    # Ignore default include paths\n    ADD_PLATFORM_FLAGS(\"/X\")\n\n    IF(MSVC14)\n      ADD_PLATFORM_FLAGS(\"/Gy-\")\n      # /Ox is working with VC++ 2015 and 2017, but custom optimizations don't exist\n      SET(RELEASE_CFLAGS \"/Ox /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Od /Ob1 /GF- ${DEBUG_CFLAGS}\")\n\n      # Special cases for VC++ 2017\n      IF(MSVC_VERSION EQUAL \"1911\")\n        SET(MSVC1411 ON)\n      ELSEIF(MSVC_VERSION EQUAL \"1910\")\n        SET(MSVC1410 ON)\n      ENDIF()\n    ELSEIF(MSVC12)\n      ADD_PLATFORM_FLAGS(\"/Gy-\")\n      # /Ox is working with VC++ 2013, but custom optimizations don't exist\n      SET(RELEASE_CFLAGS \"/Ox /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Od /Ob1 /GF- ${DEBUG_CFLAGS}\")\n    ELSEIF(MSVC11)\n      ADD_PLATFORM_FLAGS(\"/Gy-\")\n      # /Ox is working with VC++ 2012, but custom optimizations don't exist\n      SET(RELEASE_CFLAGS \"/Ox /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Od /Ob1 /GF- ${DEBUG_CFLAGS}\")\n    ELSEIF(MSVC10)\n      ADD_PLATFORM_FLAGS(\"/Gy-\")\n      # /Ox is working with VC++ 2010, but custom optimizations don't exist\n      SET(RELEASE_CFLAGS \"/Ox /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Od /Ob1 /GF- ${DEBUG_CFLAGS}\")\n    ELSEIF(MSVC90)\n      ADD_PLATFORM_FLAGS(\"/Gy-\")\n      # don't use a /O[012x] flag if you want custom optimizations\n      SET(RELEASE_CFLAGS \"/Ob2 /Oi /Ot /Oy /GT /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Ob1 /GF- ${DEBUG_CFLAGS}\")\n    ELSEIF(MSVC80)\n      ADD_PLATFORM_FLAGS(\"/Gy- /Wp64\")\n      # don't use a /O[012x] flag if you want custom optimizations\n      SET(RELEASE_CFLAGS \"/Ox /GF /GS- ${RELEASE_CFLAGS}\")\n      # without inlining it's unusable, use custom optimizations again\n      SET(DEBUG_CFLAGS \"/Od /Ob1 ${DEBUG_CFLAGS}\")\n    ELSE()\n      MESSAGE(FATAL_ERROR \"Can't determine compiler version ${MSVC_VERSION}\")\n    ENDIF()\n\n    ADD_PLATFORM_FLAGS(\"/D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS /D_WIN32 /DWIN32 /D_WINDOWS /wd4250\")\n\n    # huge PCH\n    ADD_PLATFORM_FLAGS(\"/Zm1000\")\n\n    IF(TARGET_X64)\n      # Fix a bug with Intellisense\n      ADD_PLATFORM_FLAGS(\"/D_WIN64\")\n      # Fix a compilation error for some big C++ files\n      ADD_PLATFORM_FLAGS(\"/bigobj\")\n    ELSE()\n      # Allows 32 bits applications to use 3 GB of RAM\n      ADD_PLATFORM_LINKFLAGS(\"/LARGEADDRESSAWARE\")\n    ENDIF()\n\n    # Exceptions are only set for C++\n    SET(PLATFORM_CXXFLAGS \"${PLATFORM_CXXFLAGS} /EHa\")\n\n    IF(WITH_SYMBOLS)\n      SET(NL_RELEASE_CFLAGS \"/Zi ${NL_RELEASE_CFLAGS}\")\n      SET(NL_RELEASE_LINKFLAGS \"/DEBUG ${NL_RELEASE_LINKFLAGS}\")\n    ELSE()\n      SET(NL_RELEASE_LINKFLAGS \"/RELEASE ${NL_RELEASE_LINKFLAGS}\")\n    ENDIF()\n\n    SET(NL_DEBUG_CFLAGS \"/Zi /MDd /RTC1 /D_DEBUG ${DEBUG_CFLAGS} ${NL_DEBUG_CFLAGS}\")\n    SET(NL_RELEASE_CFLAGS \"/MD /DNDEBUG ${RELEASE_CFLAGS} ${NL_RELEASE_CFLAGS}\")\n    SET(NL_DEBUG_LINKFLAGS \"/DEBUG /OPT:NOREF /OPT:NOICF /NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib ${MSVC_INCREMENTAL_YES_FLAG} ${NL_DEBUG_LINKFLAGS}\")\n    SET(NL_RELEASE_LINKFLAGS \"/OPT:REF /OPT:ICF /INCREMENTAL:NO /NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib ${NL_RELEASE_LINKFLAGS}\")\n\n    IF(WITH_WARNINGS)\n      SET(DEBUG_CFLAGS \"/W4 ${DEBUG_CFLAGS}\")\n    ELSE()\n      SET(DEBUG_CFLAGS \"/W3 ${DEBUG_CFLAGS}\")\n    ENDIF()\n  ELSE()\n    IF(WIN32)\n      ADD_PLATFORM_FLAGS(\"-DWIN32 -D_WIN32\")\n\n      IF(CLANG)\n        ADD_PLATFORM_FLAGS(\"-nobuiltininc\")\n      ENDIF()\n    ENDIF()\n\n    IF(WITH_SSE3)\n      ADD_PLATFORM_FLAGS(\"-msse3\")\n    ENDIF()\n\n    IF(WITH_GCC_FPMATH_BOTH)\n      ADD_PLATFORM_FLAGS(\"-mfpmath=both\")\n    ENDIF()\n    \n    IF(WITH_GCC_FPERMISSIVE)\n      ADD_PLATFORM_FLAGS(\"-fpermissive\")\n    ENDIF()\n    \n\n    IF(APPLE)\n      SET(OBJC_FLAGS -fobjc-abi-version=2 -fobjc-legacy-dispatch -fobjc-weak)\n    \n      IF(NOT XCODE)\n        IF(CMAKE_OSX_ARCHITECTURES)\n          SET(TARGETS_COUNT 0)\n          SET(_ARCHS)\n          FOREACH(_ARCH ${CMAKE_OSX_ARCHITECTURES})\n            IF(_ARCH STREQUAL \"i386\")\n              SET(_ARCHS \"${_ARCHS} i386\")\n              SET(TARGET_X86 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSEIF(_ARCH STREQUAL \"x86_64\")\n              SET(_ARCHS \"${_ARCHS} x86_64\")\n              SET(TARGET_X64 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSEIF(_ARCH STREQUAL \"armv7s\")\n              SET(_ARCHS \"${_ARCHS} armv7s\")\n              SET(TARGET_ARMV7S 1)\n              SET(TARGET_ARM 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSEIF(_ARCH STREQUAL \"armv7\")\n              SET(_ARCHS \"${_ARCHS} armv7\")\n              SET(TARGET_ARMV7 1)\n              SET(TARGET_ARM 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSEIF(_ARCH STREQUAL \"armv6\")\n              SET(_ARCHS \"${_ARCHS} armv6\")\n              SET(TARGET_ARMV6 1)\n              SET(TARGET_ARM 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSEIF(_ARCH STREQUAL \"mips\")\n              SET(_ARCHS \"${_ARCHS} mips\")\n              SET(TARGET_MIPS 1)\n              MATH(EXPR TARGETS_COUNT \"${TARGETS_COUNT}+1\")\n            ELSE()\n              SET(_ARCHS \"${_ARCHS} unknwon(${_ARCH})\")\n            ENDIF()\n          ENDFOREACH(_ARCH)\n          MESSAGE(STATUS \"Compiling under Mac OS X for ${TARGETS_COUNT} architectures: ${_ARCHS}\")\n        ELSE()\n          SET(TARGETS_COUNT 0)\n        ENDIF()\n\n        IF(TARGETS_COUNT EQUAL 1)\n          IF(TARGET_ARM)\n            IF(TARGET_ARMV7S)\n              ADD_PLATFORM_FLAGS(\"-arch armv7s -DHAVE_ARMV7S\")\n            ENDIF()\n\n            IF(TARGET_ARMV7)\n              ADD_PLATFORM_FLAGS(\"-arch armv7 -DHAVE_ARMV7\")\n            ENDIF()\n\n            IF(TARGET_ARMV6)\n              ADD_PLATFORM_FLAGS(\"-arch armv6 -DHAVE_ARMV6\")\n            ENDIF()\n\n            IF(TARGET_ARMV5)\n              ADD_PLATFORM_FLAGS(\"-arch armv5 -DHAVE_ARMV5\")\n            ENDIF()\n\n            ADD_PLATFORM_FLAGS(\"-mthumb -DHAVE_ARM\")\n          ENDIF()\n\n          IF(TARGET_X64)\n            ADD_PLATFORM_FLAGS(\"-arch x86_64 -DHAVE_X64 -DHAVE_X86_64 -DHAVE_X86\")\n          ELSEIF(TARGET_X86)\n            ADD_PLATFORM_FLAGS(\"-arch i386 -DHAVE_X86\")\n          ENDIF()\n\n          IF(TARGET_MIPS)\n            ADD_PLATFORM_FLAGS(\"-arch mips -DHAVE_MIPS\")\n          ENDIF()\n        ELSEIF(TARGETS_COUNT EQUAL 0)\n          # Not using CMAKE_OSX_ARCHITECTURES, HAVE_XXX already defined before\n          IF(TARGET_ARM)\n            IF(TARGET_ARMV7S)\n              ADD_PLATFORM_FLAGS(\"-arch armv7s\")\n            ENDIF()\n\n            IF(TARGET_ARMV7)\n              ADD_PLATFORM_FLAGS(\"-arch armv7\")\n            ENDIF()\n\n            IF(TARGET_ARMV6)\n              ADD_PLATFORM_FLAGS(\"-arch armv6\")\n            ENDIF()\n\n            IF(TARGET_ARMV5)\n              ADD_PLATFORM_FLAGS(\"-arch armv5\")\n            ENDIF()\n\n            ADD_PLATFORM_FLAGS(\"-mthumb\")\n          ENDIF()\n\n          IF(TARGET_X64)\n            ADD_PLATFORM_FLAGS(\"-arch x86_64\")\n          ELSEIF(TARGET_X86)\n            ADD_PLATFORM_FLAGS(\"-arch i386\")\n          ENDIF()\n\n          IF(TARGET_MIPS)\n            ADD_PLATFORM_FLAGS(\"-arch mips\")\n          ENDIF()\n        ELSE()\n          IF(TARGET_ARMV6)\n            ADD_PLATFORM_FLAGS(\"-Xarch_armv6 -mthumb -Xarch_armv6 -DHAVE_ARM -Xarch_armv6 -DHAVE_ARMV6\")\n          ENDIF()\n\n          IF(TARGET_ARMV7)\n            ADD_PLATFORM_FLAGS(\"-Xarch_armv7 -mthumb -Xarch_armv7 -DHAVE_ARM -Xarch_armv7 -DHAVE_ARMV7\")\n          ENDIF()\n\n          IF(TARGET_X86)\n            ADD_PLATFORM_FLAGS(\"-Xarch_i386 -DHAVE_X86\")\n          ENDIF()\n\n          IF(TARGET_X64)\n            ADD_PLATFORM_FLAGS(\"-Xarch_x86_64 -DHAVE_X64 -Xarch_x86_64 -DHAVE_X86_64\")\n          ENDIF()\n\n          IF(TARGET_MIPS)\n            ADD_PLATFORM_FLAGS(\"-Xarch_mips -DHAVE_MIPS\")\n          ENDIF()\n        ENDIF()\n\n        IF(IOS)\n          SET(CMAKE_OSX_SYSROOT \"\" CACHE PATH \"\" FORCE)\n\n          IF(IOS_VERSION)\n            PARSE_VERSION_STRING(${IOS_VERSION} IOS_VERSION_MAJOR IOS_VERSION_MINOR IOS_VERSION_PATCH)\n            CONVERT_VERSION_NUMBER(${IOS_VERSION_MAJOR} ${IOS_VERSION_MINOR} ${IOS_VERSION_PATCH} IOS_VERSION_NUMBER)\n\n            ADD_PLATFORM_FLAGS(\"-D__IPHONE_OS_VERSION_MIN_REQUIRED=${IOS_VERSION_NUMBER}\")\n          ENDIF()\n\n          IF(CMAKE_IOS_SYSROOT)\n            IF(TARGET_ARMV7S)\n              IF(TARGETS_COUNT GREATER 1)\n                SET(XARCH \"-Xarch_armv7s \")\n              ENDIF()\n\n              ADD_PLATFORM_FLAGS(\"${XARCH}-isysroot${CMAKE_IOS_SYSROOT}\")\n              ADD_PLATFORM_FLAGS(\"${XARCH}-miphoneos-version-min=${IOS_VERSION}\")\n              ADD_PLATFORM_LINKFLAGS(\"${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}\")\n            ENDIF()\n\n            IF(TARGET_ARMV7)\n              IF(TARGETS_COUNT GREATER 1)\n                SET(XARCH \"-Xarch_armv7 \")\n              ENDIF()\n\n              ADD_PLATFORM_FLAGS(\"${XARCH}-isysroot${CMAKE_IOS_SYSROOT}\")\n              ADD_PLATFORM_FLAGS(\"${XARCH}-miphoneos-version-min=${IOS_VERSION}\")\n              ADD_PLATFORM_LINKFLAGS(\"${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}\")\n            ENDIF()\n\n            IF(TARGET_ARMV6)\n              IF(TARGETS_COUNT GREATER 1)\n                SET(XARCH \"-Xarch_armv6 \")\n              ENDIF()\n\n              ADD_PLATFORM_FLAGS(\"${XARCH}-isysroot${CMAKE_IOS_SYSROOT}\")\n              ADD_PLATFORM_FLAGS(\"${XARCH}-miphoneos-version-min=${IOS_VERSION}\")\n              ADD_PLATFORM_LINKFLAGS(\"${XARCH}-Wl,-iphoneos_version_min,${IOS_VERSION}\")\n            ENDIF()\n          ENDIF()\n\n          IF(CMAKE_IOS_SIMULATOR_SYSROOT AND TARGET_X86)\n            IF(TARGETS_COUNT GREATER 1)\n              SET(XARCH \"-Xarch_i386 \")\n            ENDIF()\n\n            ADD_PLATFORM_FLAGS(\"${XARCH}-isysroot${CMAKE_IOS_SIMULATOR_SYSROOT}\")\n            ADD_PLATFORM_FLAGS(\"${XARCH}-mios-simulator-version-min=${IOS_VERSION}\")\n            IF(CMAKE_OSX_DEPLOYMENT_TARGET)\n              ADD_PLATFORM_LINKFLAGS(\"${XARCH}-Wl,-macosx_version_min,${CMAKE_OSX_DEPLOYMENT_TARGET}\")\n            ENDIF()\n          ENDIF()\n        ELSE()\n          # Always force -mmacosx-version-min to override environement variable\n          IF(CMAKE_OSX_DEPLOYMENT_TARGET)\n            IF(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS \"10.7\")\n              MESSAGE(FATAL_ERROR \"Minimum target for OS X is 10.7 but you're using ${CMAKE_OSX_DEPLOYMENT_TARGET}\")\n            ENDIF()\n            ADD_PLATFORM_LINKFLAGS(\"-Wl,-macosx_version_min,${CMAKE_OSX_DEPLOYMENT_TARGET}\")\n          ENDIF()\n        ENDIF()\n\n        # use libc++ under OX X to be able to use new C++ features (and else it'll use GCC 4.2.1 STL)\n        # minimum target is now OS X 10.7\n        SET(PLATFORM_CXXFLAGS \"${PLATFORM_CXXFLAGS} -stdlib=libc++\")\n\n        ADD_PLATFORM_LINKFLAGS(\"-Wl,-headerpad_max_install_names\")\n\n        IF(HAVE_FLAG_SEARCH_PATHS_FIRST)\n          ADD_PLATFORM_LINKFLAGS(\"-Wl,-search_paths_first\")\n        ENDIF()\n      ENDIF()\n    ELSE()\n      IF(HOST_CPU STREQUAL \"x86_64\" AND TARGET_CPU STREQUAL \"x86\")\n        ADD_PLATFORM_FLAGS(\"-m32 -march=i686\")\n      ENDIF()\n\n      IF(HOST_CPU STREQUAL \"x86\" AND TARGET_CPU STREQUAL \"x86_64\")\n        ADD_PLATFORM_FLAGS(\"-m64\")\n      ENDIF()\n    ENDIF()\n\n    # use c++0x standard to use std::unique_ptr and std::shared_ptr\n    SET(PLATFORM_CXXFLAGS \"${PLATFORM_CXXFLAGS} -std=c++0x\")\n\n    ADD_PLATFORM_FLAGS(\"-D_REENTRANT\")\n\n    # hardening\n    ADD_PLATFORM_FLAGS(\"-D_FORTIFY_SOURCE=2\")\n\n    IF(NOT WITH_LOW_MEMORY)\n      ADD_PLATFORM_FLAGS(\"-pipe\")\n    ENDIF()\n\n    IF(WITH_COVERAGE)\n      ADD_PLATFORM_FLAGS(\"-fprofile-arcs -ftest-coverage\")\n    ENDIF()\n\n    IF(WITH_WARNINGS)\n      ADD_PLATFORM_FLAGS(\"-Wall\")\n    ELSE()\n      # Check wrong formats in printf-like functions\n      ADD_PLATFORM_FLAGS(\"-Wformat -Werror=format-security\")\n    ENDIF()\n\n    # never display these warnings because they are minor\n    ADD_PLATFORM_FLAGS(\"-Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-value\")\n\n    IF(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER \"6.0.0\")\n      ADD_PLATFORM_FLAGS(\"-Wno-unused-local-typedefs\")\n    ELSEIF(CLANG)\n      ADD_PLATFORM_FLAGS(\"-Wno-unused-private-field -Wno-unused-local-typedef\")\n    ENDIF()\n\n    IF(ANDROID)\n      ADD_PLATFORM_FLAGS(\"--sysroot=${PLATFORM_ROOT}\")\n      ADD_PLATFORM_FLAGS(\"-ffunction-sections -funwind-tables\")\n      ADD_PLATFORM_FLAGS(\"-DANDROID\")\n      ADD_PLATFORM_FLAGS(\"-Wa,--noexecstack\")\n\n      IF(TARGET_ARM)\n        ADD_PLATFORM_FLAGS(\"-fpic\")\n        ADD_PLATFORM_FLAGS(\"-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__\")\n\n        IF(TARGET_ARMV7)\n          ADD_PLATFORM_FLAGS(\"-march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16\")\n          ADD_PLATFORM_LINKFLAGS(\"-march=armv7-a -Wl,--fix-cortex-a8\")\n        ELSEIF(TARGET_ARMV5)\n          ADD_PLATFORM_FLAGS(\"-march=armv5te -mtune=xscale -msoft-float\")\n        ENDIF()\n\n        SET(TARGET_THUMB ON)\n        IF(TARGET_THUMB)\n          ADD_PLATFORM_FLAGS(\"-mthumb -finline-limit=64\")\n          SET(DEBUG_CFLAGS \"${DEBUG_CFLAGS} -marm\")\n        ELSE()\n          ADD_PLATFORM_FLAGS(\"-funswitch-loops -finline-limit=300\")\n        ENDIF()\n      ELSEIF(TARGET_X86)\n        # Optimizations for Intel Atom\n        ADD_PLATFORM_FLAGS(\"-march=i686 -mtune=atom -mstackrealign -msse3 -mfpmath=sse -m32 -flto -ffast-math -funroll-loops\")\n        ADD_PLATFORM_FLAGS(\"-funswitch-loops -finline-limit=300\")\n      ELSEIF(TARGET_MIPS)\n        ADD_PLATFORM_FLAGS(\"-fpic -finline-functions -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers\")\n        SET(RELEASE_CFLAGS \"${RELEASE_CFLAGS} -funswitch-loops -finline-limit=300\")\n      ENDIF()\n      ADD_PLATFORM_LINKFLAGS(\"-Wl,-z,noexecstack\")\n      ADD_PLATFORM_LINKFLAGS(\"-L${PLATFORM_ROOT}/usr/lib\")\n    ENDIF()\n\n    IF(APPLE)\n      ADD_PLATFORM_FLAGS(\"-gdwarf-2 -D_DARWIN_UNLIMITED_STREAMS\")\n    ENDIF()\n\n    # Fix \"relocation R_X86_64_32 against..\" error on x64 platforms\n    IF(NOT MINGW)\n      ADD_PLATFORM_FLAGS(\"-fPIC\")\n    ENDIF()\n\n    SET(PLATFORM_CXXFLAGS \"${PLATFORM_CXXFLAGS} -ftemplate-depth-48\")\n\n    # hardening\n    ADD_PLATFORM_FLAGS(\"-fstack-protector --param=ssp-buffer-size=4\")\n\n    # If -fstack-protector or -fstack-protector-all enabled, enable too new warnings and fix possible link problems\n    IF(WITH_WARNINGS)\n      ADD_PLATFORM_FLAGS(\"-Wstack-protector\")\n    ENDIF()\n\n    # Fix undefined reference to `__stack_chk_fail' error\n    ADD_PLATFORM_LINKFLAGS(\"-lc\")\n\n    IF(NOT APPLE)\n      ADD_PLATFORM_LINKFLAGS(\"-Wl,--no-undefined -Wl,--as-needed\")\n    ENDIF()\n\n    IF(NOT APPLE)\n      # hardening\n      ADD_PLATFORM_LINKFLAGS(\"-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now\")\n    ENDIF()\n\n    IF(WITH_SYMBOLS)\n      SET(NL_RELEASE_CFLAGS \"${NL_RELEASE_CFLAGS} -g\")\n    ELSE()\n      IF(APPLE)\n        SET(NL_RELEASE_LINKFLAGS \"-Wl,-dead_strip ${NL_RELEASE_LINKFLAGS}\")\n      ELSE()\n        SET(NL_RELEASE_LINKFLAGS \"-Wl,-s ${NL_RELEASE_LINKFLAGS}\")\n      ENDIF()\n    ENDIF()\n\n    SET(NL_DEBUG_CFLAGS \"-g -DNL_DEBUG -D_DEBUG ${NL_DEBUG_CFLAGS}\")\n    SET(NL_RELEASE_CFLAGS \"-DNL_RELEASE -DNDEBUG -O3 ${NL_RELEASE_CFLAGS}\")\n  ENDIF()\nENDMACRO()\n\nMACRO(NL_SETUP_BUILD_FLAGS)\n  SET(CMAKE_C_FLAGS ${PLATFORM_CFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_CXX_FLAGS ${PLATFORM_CXXFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_EXE_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_MODULE_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_SHARED_LINKER_FLAGS ${PLATFORM_LINKFLAGS} CACHE STRING \"\" FORCE)\n\n  ## Debug\n  SET(CMAKE_C_FLAGS_DEBUG ${NL_DEBUG_CFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_CXX_FLAGS_DEBUG ${NL_DEBUG_CFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_EXE_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG ${NL_DEBUG_LINKFLAGS} CACHE STRING \"\" FORCE)\n\n  ## Release\n  SET(CMAKE_C_FLAGS_RELEASE ${NL_RELEASE_CFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_CXX_FLAGS_RELEASE ${NL_RELEASE_CFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_EXE_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING \"\" FORCE)\n  SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE ${NL_RELEASE_LINKFLAGS} CACHE STRING \"\" FORCE)\nENDMACRO(NL_SETUP_BUILD_FLAGS)\n\n# Macro to create x_ABSOLUTE_PREFIX from x_PREFIX\nMACRO(NL_MAKE_ABSOLUTE_PREFIX NAME_RELATIVE NAME_ABSOLUTE)\n  IF(IS_ABSOLUTE \"${${NAME_RELATIVE}}\")\n    SET(${NAME_ABSOLUTE} ${${NAME_RELATIVE}})\n  ELSE()\n    IF(WITH_UNIX_STRUCTURE)\n      SET(${NAME_ABSOLUTE} ${CMAKE_INSTALL_PREFIX}/${${NAME_RELATIVE}})\n    ELSE()\n      SET(${NAME_ABSOLUTE} ${${NAME_RELATIVE}})\n    ENDIF()\n  ENDIF()\nENDMACRO(NL_MAKE_ABSOLUTE_PREFIX)\n\nMACRO(NL_SETUP_PREFIX_PATHS)\n  ## Allow override of install_prefix/etc path.\n  IF(NOT NL_ETC_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(NL_ETC_PREFIX \"etc/nel\" CACHE PATH \"Installation path for configurations\")\n    ELSE()\n      SET(NL_ETC_PREFIX \".\" CACHE PATH \"Installation path for configurations\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_ETC_PREFIX NL_ETC_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/share path.\n  IF(NOT NL_SHARE_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(NL_SHARE_PREFIX \"share/nel\" CACHE PATH \"Installation path for data.\")\n    ELSE()\n      SET(NL_SHARE_PREFIX \".\" CACHE PATH \"Installation path for data.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_SHARE_PREFIX NL_SHARE_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/sbin path.\n  IF(NOT NL_SBIN_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(NL_SBIN_PREFIX \"sbin\" CACHE PATH \"Installation path for admin tools and services.\")\n    ELSE()\n      SET(NL_SBIN_PREFIX \".\" CACHE PATH \"Installation path for admin tools and services.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_SBIN_PREFIX NL_SBIN_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/bin path.\n  IF(NOT NL_BIN_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(NL_BIN_PREFIX \"bin\" CACHE PATH \"Installation path for tools and applications.\")\n    ELSE()\n      SET(NL_BIN_PREFIX \".\" CACHE PATH \"Installation path for tools and applications.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_BIN_PREFIX NL_BIN_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/lib path.\n  IF(NOT NL_LIB_PREFIX)\n    IF(LIBRARY_ARCHITECTURE)\n      SET(NL_LIB_PREFIX \"lib/${LIBRARY_ARCHITECTURE}\" CACHE PATH \"Installation path for libraries.\")\n    ELSE()\n      SET(NL_LIB_PREFIX \"lib\" CACHE PATH \"Installation path for libraries.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_LIB_PREFIX NL_LIB_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/lib path.\n  IF(NOT NL_DRIVER_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      IF(LIBRARY_ARCHITECTURE)\n        SET(NL_DRIVER_PREFIX \"lib/${LIBRARY_ARCHITECTURE}/nel\" CACHE PATH \"Installation path for drivers.\")\n      ELSE()\n        SET(NL_DRIVER_PREFIX \"lib/nel\" CACHE PATH \"Installation path for drivers.\")\n      ENDIF()\n    ELSE()\n      SET(NL_DRIVER_PREFIX \".\" CACHE PATH \"Installation path for drivers.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(NL_DRIVER_PREFIX NL_DRIVER_ABSOLUTE_PREFIX)\nENDMACRO(NL_SETUP_PREFIX_PATHS)\n\nMACRO(EVA_SETUP_PREFIX_PATHS)\n  ## Allow override of install_prefix/etc path.\n  IF(NOT EVA_ETC_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(EVA_ETC_PREFIX \"etc/ryzom\" CACHE PATH \"Installation path for configurations\")\n    ELSE()\n      SET(EVA_ETC_PREFIX \".\" CACHE PATH \"Installation path for configurations\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_ETC_PREFIX EVA_ETC_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/share path.\n  IF(NOT EVA_SHARE_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(EVA_SHARE_PREFIX \"share/ryzom\" CACHE PATH \"Installation path for data.\")\n    ELSE()\n      SET(EVA_SHARE_PREFIX \".\" CACHE PATH \"Installation path for data.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_SHARE_PREFIX EVA_SHARE_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/sbin path.\n  IF(NOT EVA_SBIN_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(EVA_SBIN_PREFIX \"sbin\" CACHE PATH \"Installation path for admin tools and services.\")\n    ELSE()\n      SET(EVA_SBIN_PREFIX \".\" CACHE PATH \"Installation path for admin tools and services.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_SBIN_PREFIX EVA_SBIN_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/bin path.\n  IF(NOT EVA_BIN_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(EVA_BIN_PREFIX \"bin\" CACHE PATH \"Installation path for tools.\")\n    ELSE()\n      SET(EVA_BIN_PREFIX \".\" CACHE PATH \"Installation path for tools and applications.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_BIN_PREFIX EVA_BIN_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/lib path.\n  IF(NOT EVA_LIB_PREFIX)\n    IF(LIBRARY_ARCHITECTURE)\n      SET(EVA_LIB_PREFIX \"lib/${LIBRARY_ARCHITECTURE}\" CACHE PATH \"Installation path for libraries.\")\n    ELSE()\n      SET(EVA_LIB_PREFIX \"lib\" CACHE PATH \"Installation path for libraries.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_LIB_PREFIX EVA_LIB_ABSOLUTE_PREFIX)\n\n  ## Allow override of install_prefix/games path.\n  IF(NOT EVA_GAMES_PREFIX)\n    IF(WITH_UNIX_STRUCTURE)\n      SET(EVA_GAMES_PREFIX \"games\" CACHE PATH \"Installation path for client.\")\n    ELSE()\n      SET(EVA_GAMES_PREFIX \".\" CACHE PATH \"Installation path for tools and applications.\")\n    ENDIF()\n  ENDIF()\n  NL_MAKE_ABSOLUTE_PREFIX(EVA_GAMES_PREFIX EVA_GAMES_ABSOLUTE_PREFIX)\n\nENDMACRO(EVA_SETUP_PREFIX_PATHS)\n\nMACRO(SETUP_EXTERNAL)\n  IF(WITH_EXTERNAL)\n    FIND_PACKAGE(External REQUIRED)\n  ENDIF()\n\n  IF(WIN32)\n    FIND_PACKAGE(External REQUIRED)\n\n    # If using custom boost, we need to define the right variables used by official boost CMake module\n    IF(DEFINED BOOST_DIR)\n      SET(BOOST_INCLUDEDIR ${BOOST_DIR}/include)\n      SET(BOOST_LIBRARYDIR ${BOOST_DIR}/lib)\n    ENDIF()\n  ELSE()\n    FIND_PACKAGE(External QUIET)\n\n    IF(APPLE)\n      IF(WITH_STATIC_EXTERNAL)\n        # Look only for static libraries because systems libraries are using Frameworks\n        SET(CMAKE_FIND_LIBRARY_SUFFIXES .a)\n      ELSE()\n        SET(CMAKE_FIND_LIBRARY_SUFFIXES .dylib .so .a)\n      ENDIF()\n    ELSE()\n      IF(WITH_STATIC_EXTERNAL)\n        SET(CMAKE_FIND_LIBRARY_SUFFIXES .a .so)\n      ELSE()\n        SET(CMAKE_FIND_LIBRARY_SUFFIXES .so .a)\n      ENDIF()\n    ENDIF()\n  ENDIF()\n\n  # Android, iOS and Mac OS X have pthread, but no need to link to libpthread\n  IF(ANDROID OR APPLE)\n    SET(CMAKE_USE_PTHREADS_INIT 1)\n    SET(Threads_FOUND TRUE)\n  ELSE()\n    SET(THREADS_HAVE_PTHREAD_ARG ON)\n    FIND_PACKAGE(Threads)\n    # TODO: replace all -l<lib> by absolute path to <lib> in CMAKE_THREAD_LIBS_INIT\n  ENDIF()\n\n  IF(WITH_STLPORT)\n    FIND_PACKAGE(STLport REQUIRED)\n    INCLUDE_DIRECTORIES(${STLPORT_INCLUDE_DIR})\n  ENDIF()\n\n  IF(WIN32)\n    # Must include DXSDK before WINSDK\n    #FIND_PACKAGE(DirectXSDK REQUIRED)\n    # IF(DXSDK_INCLUDE_DIR)\n    #   INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR})\n    # ENDIF()\n  ENDIF()\n\n  IF(MSVC)\n    FIND_PACKAGE(MSVC REQUIRED)\n    FIND_PACKAGE(WindowsSDK REQUIRED)\n  ENDIF()\nENDMACRO(SETUP_EXTERNAL)\n"
  },
  {
    "path": "code/CMakePackaging.txt",
    "content": "cpack_add_install_type(Full DISPLAY_NAME \"Full Install\")\ncpack_add_install_type(Developer DISPLAY_NAME \"Developer Install\")\ncpack_add_install_type(Runtime DISPLAY_NAME \"Runtime Files\")\n\ncpack_add_component_group(Drivers \n  EXPANDED \n  DESCRPTION \"The drivers needed to run NeL-based software.\")\ncpack_add_component_group(Samples \n  EXPANDED \n  DESCRPTION \"Sample applications and configurations demonstrating NeL.\")\ncpack_add_component_group(Tools \n  EXPANDED \n  DESCRPTION \"Tools for NeL development and media creation.\")\n\n\n\n###############\n#             #\n# Development #\n#             #\n###############\ncpack_add_component(libraries\n  DISPLAY_NAME \"Libraries\"\n  DESCRIPTION \"Libraries used to build programs with NeL\"\n  GROUP Development\n  INSTALL_TYPES Full Developer)\ncpack_add_component(headers\n  DISPLAY_NAME \"C++ Headers\"\n  DESCRIPTION \"C++ headers used to build programs with NeL\"\n  GROUP Development\n  INSTALL_TYPES Full Developer)\n\n###########\n#         #\n# Drivers #\n#         #\n###########\ncpack_add_component(drivers3d\n  DISPLAY_NAME \"3D Drivers\"\n  DESCRIPTION \"3D Drivers for running NeL based applications.\"\n  GROUP Drivers\n  INSTALL_TYPES Full Runtime)\ncpack_add_component(driverssound\n  DISPLAY_NAME \"Sound Drivers\"\n  DESCRIPTION \"Sound Drivers for running NeL based applications.\"\n  GROUP Drivers\n  INSTALL_TYPES Full Runtime)  \n\n#########\n#       #\n# Tools #\n#       #\n#########\ncpack_add_component(toolsmisc\n  DISPLAY_NAME \"Misc Tools\"\n  DESCRIPTION \"Misc. NeL Tools\"\n  GROUP Tools\n  INSTALL_TYPES Full Runtime)\ncpack_add_component(tools3d\n  DISPLAY_NAME \"3D Tools\"\n  DESCRIPTION \"3D NeL Tools\"\n  GROUP Tools\n  INSTALL_TYPES Full Runtime)\ncpack_add_component(toolsgeorges\n  DISPLAY_NAME \"Georges Tools\"\n  DESCRIPTION \"NeL Georges Tools\"\n  GROUP Tools\n  INSTALL_TYPES Full Runtime)\ncpack_add_component(toolspacs\n  DISPLAY_NAME \"PACS Tools\"\n  DESCRIPTION \"NeL PACS Tools\"\n  GROUP Tools\n  INSTALL_TYPES Full Runtime)\n  \n###########\n#         #\n# Samples #\n#         #\n###########\ncpack_add_component(samplespacs\n  DISPLAY_NAME \"PACS Samples\"\n  DESCRIPTION \"Sample applications demonstrating the PACS collision library.\"\n  GROUP Samples\n  INSTALL_TYPES Full)\ncpack_add_component(samples3d\n  DISPLAY_NAME \"3D Samples\"\n  DESCRIPTION \"Sample applications demonstrating the NeL 3D library.\"\n  GROUP Samples\n  INSTALL_TYPES Full)  \ncpack_add_component(samplesgeorges\n  DISPLAY_NAME \"Georges Samples\"\n  DESCRIPTION \"Sample applications demonstrating the Georges data loading module.\"\n  GROUP Samples\n  INSTALL_TYPES Full)   \ncpack_add_component(samplesmisc\n  DISPLAY_NAME \"Misc Samples\"\n  DESCRIPTION \"Sample applications demonstrating the core NeL functionality module.\"\n  GROUP Samples\n  INSTALL_TYPES Full)\ncpack_add_component(samplesnet\n  DISPLAY_NAME \"Net Samples\"\n  DESCRIPTION \"Sample applications demonstrating the NeL Network functionality.\"\n  GROUP Samples\n  INSTALL_TYPES Full)\ncpack_add_component(samplessound\n  DISPLAY_NAME \"Sound Samples\"\n  DESCRIPTION \"Sample applications demonstrating the NeL Sound functionality.\"\n  GROUP Samples\n  INSTALL_TYPES Full)\n"
  },
  {
    "path": "code/COPYING",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "code/CTestConfig.cmake",
    "content": "## This file should be placed in the root directory of your project.\n## Then modify the CMakeLists.txt file in the root directory of your\n## project to incorporate the testing dashboard.\n## # The following are required to uses Dart and the Cdash dashboard\n##   ENABLE_TESTING()\n##   INCLUDE(Dart)\nset(CTEST_PROJECT_NAME \"RyzomCore\")\nset(CTEST_NIGHTLY_START_TIME \"00:00:00 CST\")\nset(CTEST_UPDATE_TYPE \"hg\")\nset(CTEST_DROP_METHOD \"http\")\nset(CTEST_DROP_SITE \"ci.ryzomcore.org\")\nset(CTEST_DROP_LOCATION \"/submit.php?project=RyzomCore\")\nset(CTEST_DROP_SITE_CDASH TRUE)\n"
  },
  {
    "path": "code/EVA/CMakeLists.txt",
    "content": "INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/server )\n\n\n#SET(SERVER_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/server)\n\nIF(WITH_EVA)\n  ADD_DEFINITIONS(-DEVA)\nENDIF(WITH_EVA)\n\nADD_SUBDIRECTORY(server)\n\nIF(WITH_TOOLS)\n  ADD_SUBDIRECTORY(tools)\nENDIF(WITH_TOOLS)\n\n"
  },
  {
    "path": "code/EVA/server/CMakeLists.txt",
    "content": "FIND_PACKAGE(CURL)\nFIND_PACKAGE(MySQL)\n#FIND_PACKAGE(ToLua)\n# move to server_share/CMakeLists.txt\n\nINCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})\n\nADD_SUBDIRECTORY(server_share)\n#ADD_SUBDIRECTORY(admin_modules)\nADD_SUBDIRECTORY(naming_service)\nADD_SUBDIRECTORY(frontend_service)\nADD_SUBDIRECTORY(player_logic_service)\nADD_SUBDIRECTORY(schedule_service)\n#ADD_SUBDIRECTORY(admin_service)\n#ADD_SUBDIRECTORY(client_robot)\n\n#INSTALL(FILES common.cfg DESTINATION ~/service COMPONENT services)\n"
  },
  {
    "path": "code/EVA/server/_del_log.bat",
    "content": "@echo off\n\ndel *.log\ndel log /q\ndel aes_*.txt\ndel pid.state\n\ndel rns /q\nrd  rns /q\n\ndel aes /q\nrd  aes /q\n\ndel egs /q\nrd  egs /q\n\ndel ras /q\nrd  ras /q\n\ndel fes_0 /q\nrd  fes_0 /q\n\ndel lgc_0 /q\nrd  lgc_0 /q\n\ndel pds /q\nrd  pds /q\n\n"
  },
  {
    "path": "code/EVA/server/_robot_start .bat",
    "content": "@echo off\n\nREM This script will start all the services with good parameters\n\nREM set MODE=Debug\nREM set MODE=.\nset MODE=..\\..\\..\\build\\bin\\Debug\n\ntaskkill /IM client_robot.exe /F\n\nrem  ns\nstart %MODE%\\client_robot --nolog\nping -n 2 127.0.0.1 > NUL 2>&1\n\n\n"
  },
  {
    "path": "code/EVA/server/_robot_stop .bat",
    "content": "@echo off\n\nREM This script will kill all the services launched by _robot_start.bat\n\nrem  robot\ntaskkill /IM client_robot.exe /F\n\n"
  },
  {
    "path": "code/EVA/server/_shard_start.bat",
    "content": "@echo off\n\nREM This script will start all the services with good parameters\n\ncall _shard_stop.bat\n\nREM set MODE=Debug\nREM set MODE=.\nset MODE=..\\..\\..\\build\\bin\\Debug\n\nrem  ns\nstart %MODE%\\naming_service --nolog\nping -n 2 127.0.0.1 > NUL 2>&1\n\nrem  pls\nstart %MODE%\\player_logic_service --nolog\nping -n 2 127.0.0.1 > NUL 2>&1\n\nrem  fes\nstart %MODE%\\frontend_service --nolog\nping -n 2 127.0.0.1 > NUL 2>&1\n\nrem sch\nstart %MODE%\\schedule_service --nolog\nping -n 2 127.0.0.1 > NUL 2>&1\n\n"
  },
  {
    "path": "code/EVA/server/_shard_stop.bat",
    "content": "@echo off\n\nREM This script will kill all the services launched by _shard_start.bat\n\nrem  ns\ntaskkill /IM naming_service.exe /F\n\nrem  fes\ntaskkill /IM frontend_service.exe /F\n\nrem  pls\ntaskkill /IM player_logic_service.exe /F\n\nrem  pls\ntaskkill /IM schedule_service.exe /F\n\n"
  },
  {
    "path": "code/EVA/server/admin_executor_service.cfg",
    "content": "// Use with commandline: admin_service -A. -C. -L. --nobreak --fulladminname=admin_executor_service --shortadminname=AES\n\n#include \"common.cfg\"\n\n// I don't need a connection to a naming service\nDontUseNS = 1;\n\n// Address of the admin service (default port is 49996)\nASHost = \"localhost\";\nASPort=\"46701\";\n\n// ---- service NeL variables (used by ConfigFile class)\n\nAESAliasName= \"aes\";\n\nStartCommands=\n{\n\t// Create a gateway module\n\t\"moduleManager.createModule StandardGateway gw\",\n\t// add a layer 5 transport\n\t\"gw.transportAdd L5Transport l5\",\n\t// open the transport\n\t\"gw.transportCmd l5(open)\",\n\n\t/// Create default connection with admin executor service\n\t// Create a gateway module\n\t\"moduleManager.createModule StandardGateway gw_aes\",\n\t// create the admin executor service module\n\t\"moduleManager.createModule AdminExecutorServiceClient aes_client\",\n\t\"aes_client.plug gw_aes\",\n\n\t// create a layer 3 client to connect to aes gateway\n\t\"gw_aes.transportAdd L3Client aes_l3c\",\n\t\"gw_aes.transportCmd aes_l3c(connect addr=\"+AESHost+\":\"+AESPort+\")\",\n\n\t// create the admin executor service module\n\t\"moduleManager.createModule AdminExecutorService aes\",\n\n\t// create a gateway to connect to as\n\t\"moduleManager.createModule StandardGateway asc_gw\",\n\t// create a layer 3 client\n\t\"asc_gw.transportAdd L3Client l3c\",\n\t\"asc_gw.transportCmd l3c(connect addr=\"+ASHost+\":\"+ASPort+\")\",\n\n\t// create a gateway for services to connect\n\t\"moduleManager.createModule StandardGateway aes_gw\",\n\t// create a layer 3 server\n\t\"aes_gw.transportAdd L3Server l3s\",\n\t\"aes_gw.transportOptions l3s(PeerInvisible)\",\n\t\"aes_gw.transportCmd l3s(open port=\"+AESPort+\")\",\n\n\t// plug the as\n\t\"aes.plug asc_gw\",\n\t\"aes.plug aes_gw\",\n};\n\nStartCommands +=\n{\n\t\"aes.addRegisteredService ras 本地服务器\",\n\t\"aes.addRegisteredService aes 本地服务器\",\n\t\"aes.addRegisteredService rns 本地服务器\",\n\t\"aes.addRegisteredService pds 本地服务器\",\n\t\"aes.addRegisteredService egs 本地服务器\",\n\t\"aes.addRegisteredService fes_0 本地服务器\",\n\t\"aes.addRegisteredService lgc_0 本地服务器\",\n};\n\n///  server_daemon command\nras = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/admin_service.exe\", \"--fulladminname=admin_service --shortadminname=AS -C. -L. --nobreak --writepid\" };\naes = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/admin_service.exe\", \"--fulladminname=admin_executor_service --shortadminname=AES -C. -L. --nobreak --writepid\" };\nrns = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/naming_service.exe\", \"-C. -L. --nobreak --writepid\" };\npds = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/persistant_data_service.exe\", \"-C. -L. --nobreak --writepid\" };\negs = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/entities_game_service.exe\", \"-C. -L. --nobreak --writepid\" };\nfes_0 = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/frontend_service.exe\", \"-C. -L. --nobreak --writepid\" };\nlgc_0 = { \"D:/MT/trunk/code/EVA/server/\", \"D:/MT/trunk/build/bin/Debug/player_logic_service.exe\", \"-C. -L. --nobreak --writepid\" };\n\n///  for server_daemon\nRegisteredServices=\n{\n\t\"ras\",\n\t\"aes\",\n\t\"rns\",\n\t\"pds\",\n\t\"egs\",\n\t\"fes_0\",\n\t\"lgc_0\",\n};\n\n//\nDontUseStdIn = 0;\n\n// ---- service NeL variables (used by CVariable class)\n\n// If the update loop is too slow, a thread will produce an assertion.\n// By default, the value is set to 10 minutes.\n// Set to 0 for no assertion.\nUpdateAssertionThreadTimeout = 0;\n\n// ---- service custom variables (used by CVariable class)\n\n// in second, -1 for not restarting\nRestartDelay = 60;\n\n// how many second before aborting the request if not finished\nRequestTimeout = 5;\n\n// log path for advanced log report\nLogPath = \"/.\";\n\n// setup for deployment environment with exeternal configuration system responsible for launching apps and\n// for configuring AES services\nDontLaunchServicesDirectly = 1;\nUseExplicitAESRegistration = 1;\nKillServicesOnDisconnect = 1;\n\nShardName=\"dev\";\n"
  },
  {
    "path": "code/EVA/server/admin_modules/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nNL_TARGET_LIB(eva_adminmodules ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})\n\nTARGET_LINK_LIBRARIES(eva_adminmodules nelmisc nelnet)\nNL_DEFAULT_PROPS(eva_adminmodules \"Base, Library: Service Admin Modules\")\nNL_ADD_RUNTIME_FLAGS(eva_adminmodules)\nNL_ADD_LIB_SUFFIX(eva_adminmodules)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\n#INSTALL(TARGETS eva_adminmodules LIBRARY DESTINATION ${EVA_LIB_PREFIX} ARCHIVE DESTINATION ${EVA_LIB_PREFIX} COMPONENT libraries)\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS eva_adminmodules LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/EVA/server/admin_modules/admin_modules.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/** This file declare a pure nel module library */\n\n\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_builder_parts.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nextern void as_forceLink();\nextern void aes_forceLink();\nextern void aesclient_forceLink();\n\nvoid admin_modules_forceLink()\n{\n\tas_forceLink();\n\taes_forceLink();\n\taesclient_forceLink();\n}\n\n//NLMISC_DECL_PURE_LIB(CNelModuleLibrary);\n\n"
  },
  {
    "path": "code/EVA/server/admin_modules/admin_modules_itf.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/////////////////////////////////////////////////////////////////\n// WARNING : this is a generated file, don't change it !\n/////////////////////////////////////////////////////////////////\n\n#include \"admin_modules_itf.h\"\n\nnamespace ADMIN\n{\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\t\n\n\tconst CAdminServiceSkel::TMessageHandlerMap &CAdminServiceSkel::getMessageHandlers() const\n\t{\n\t\tstatic TMessageHandlerMap handlers;\n\t\tstatic bool init = false;\n\n\t\tif (!init)\n\t\t{\n\t\t\tstd::pair < TMessageHandlerMap::iterator, bool > res;\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"USU\"), &CAdminServiceSkel::upServiceUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"GU\"), &CAdminServiceSkel::graphUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"HRGU\"), &CAdminServiceSkel::highRezGraphUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"CR\"), &CAdminServiceSkel::commandResult_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tinit = true;\n\t\t}\n\n\t\treturn handlers;\t\t\t\n\t}\n\tbool CAdminServiceSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message)\n\t{\n\t\tconst TMessageHandlerMap &mh = getMessageHandlers();\n\n\t\tTMessageHandlerMap::const_iterator it(mh.find(message.getName()));\n\n\t\tif (it == mh.end())\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tTMessageHandler cmd = it->second;\n\t\t(this->*cmd)(sender, message);\n\n\t\treturn true;\n\t}\n\n\t\n\tvoid CAdminServiceSkel::upServiceUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminServiceSkel_upServiceUpdate_USU);\n\t\tstd::vector < TServiceStatus >\tserviceStatus;\n\t\t\tnlRead(__message, serialCont, serviceStatus);\n\t\tupServiceUpdate(sender, serviceStatus);\n\t}\n\n\tvoid CAdminServiceSkel::graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminServiceSkel_graphUpdate_GU);\n\t\tTGraphDatas\tgraphDatas;\n\t\t\tnlRead(__message, serial, graphDatas);\n\t\tgraphUpdate(sender, graphDatas);\n\t}\n\n\tvoid CAdminServiceSkel::highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminServiceSkel_highRezGraphUpdate_HRGU);\n\t\tTHighRezDatas\tgraphDatas;\n\t\t\tnlRead(__message, serial, graphDatas);\n\t\thighRezGraphUpdate(sender, graphDatas);\n\t}\n\n\tvoid CAdminServiceSkel::commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminServiceSkel_commandResult_CR);\n\t\tuint32\tcommandId;\n\t\t\tnlRead(__message, serial, commandId);\n\t\tstd::string\tserviceAlias;\n\t\t\tnlRead(__message, serial, serviceAlias);\n\t\tstd::string\tresult;\n\t\t\tnlRead(__message, serial, result);\n\t\tcommandResult(sender, commandId, serviceAlias, result);\n\t}\n\t\t// An AES send an update of the list of service up\n\tvoid CAdminServiceProxy::upServiceUpdate(NLNET::IModule *sender, const std::vector < TServiceStatus > &serviceStatus)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->upServiceUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), serviceStatus);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_upServiceUpdate(__message, serviceStatus);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// An AES send graph data update\n\tvoid CAdminServiceProxy::graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->graphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_graphUpdate(__message, graphDatas);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// An AES send high rez graph data update\n\tvoid CAdminServiceProxy::highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->highRezGraphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_highRezGraphUpdate(__message, graphDatas);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// AES send back the result of execution of a command\n\tvoid CAdminServiceProxy::commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->commandResult(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_commandResult(__message, commandId, serviceAlias, result);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminServiceProxy::buildMessageFor_upServiceUpdate(NLNET::CMessage &__message, const std::vector < TServiceStatus > &serviceStatus)\n\t{\n\t\t__message.setType(\"USU\");\n\t\t\tnlWrite(__message, serialCont, const_cast < std::vector < TServiceStatus >& > (serviceStatus));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminServiceProxy::buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas)\n\t{\n\t\t__message.setType(\"GU\");\n\t\t\tnlWrite(__message, serial, const_cast < TGraphDatas& > (graphDatas));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminServiceProxy::buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas)\n\t{\n\t\t__message.setType(\"HRGU\");\n\t\t\tnlWrite(__message, serial, const_cast < THighRezDatas& > (graphDatas));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminServiceProxy::buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result)\n\t{\n\t\t__message.setType(\"CR\");\n\t\t\tnlWrite(__message, serial, commandId);\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (result));\n\n\n\t\treturn __message;\n\t}\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\t\n\n\tconst CAdminExecutorServiceSkel::TMessageHandlerMap &CAdminExecutorServiceSkel::getMessageHandlers() const\n\t{\n\t\tstatic TMessageHandlerMap handlers;\n\t\tstatic bool init = false;\n\n\t\tif (!init)\n\t\t{\n\t\t\tstd::pair < TMessageHandlerMap::iterator, bool > res;\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SCO\"), &CAdminExecutorServiceSkel::setShardOrders_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SDS\"), &CAdminExecutorServiceSkel::shutdownShard_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"CC\"), &CAdminExecutorServiceSkel::controlCmd_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SCMD\"), &CAdminExecutorServiceSkel::serviceCmd_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"CR\"), &CAdminExecutorServiceSkel::commandResult_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"GU\"), &CAdminExecutorServiceSkel::graphUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"HRGU\"), &CAdminExecutorServiceSkel::highRezGraphUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SSU\"), &CAdminExecutorServiceSkel::serviceStatusUpdate_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tinit = true;\n\t\t}\n\n\t\treturn handlers;\t\t\t\n\t}\n\tbool CAdminExecutorServiceSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message)\n\t{\n\t\tconst TMessageHandlerMap &mh = getMessageHandlers();\n\n\t\tTMessageHandlerMap::const_iterator it(mh.find(message.getName()));\n\n\t\tif (it == mh.end())\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tTMessageHandler cmd = it->second;\n\t\t(this->*cmd)(sender, message);\n\n\t\treturn true;\n\t}\n\n\t\n\tvoid CAdminExecutorServiceSkel::setShardOrders_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_setShardOrders_SCO);\n\t\tstd::string\tshardName;\n\t\t\tnlRead(__message, serial, shardName);\n\t\tTShardOrders\tshardOrders;\n\t\t\tnlRead(__message, serial, shardOrders);\n\t\tsetShardOrders(sender, shardName, shardOrders);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::shutdownShard_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_shutdownShard_SDS);\n\t\tstd::string\tshardName;\n\t\t\tnlRead(__message, serial, shardName);\n\t\tuint32\tdelay;\n\t\t\tnlRead(__message, serial, delay);\n\t\tshutdownShard(sender, shardName, delay);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::controlCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_controlCmd_CC);\n\t\tuint32\tcommandId;\n\t\t\tnlRead(__message, serial, commandId);\n\t\tstd::string\tserviceAlias;\n\t\t\tnlRead(__message, serial, serviceAlias);\n\t\tstd::string\tcommand;\n\t\t\tnlRead(__message, serial, command);\n\t\tcontrolCmd(sender, commandId, serviceAlias, command);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_serviceCmd_SCMD);\n\t\tuint32\tcommandId;\n\t\t\tnlRead(__message, serial, commandId);\n\t\tstd::string\tserviceAlias;\n\t\t\tnlRead(__message, serial, serviceAlias);\n\t\tstd::string\tcommand;\n\t\t\tnlRead(__message, serial, command);\n\t\tserviceCmd(sender, commandId, serviceAlias, command);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_commandResult_CR);\n\t\tuint32\tcommandId;\n\t\t\tnlRead(__message, serial, commandId);\n\t\tstd::string\tserviceAlias;\n\t\t\tnlRead(__message, serial, serviceAlias);\n\t\tstd::string\tresult;\n\t\t\tnlRead(__message, serial, result);\n\t\tcommandResult(sender, commandId, serviceAlias, result);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_graphUpdate_GU);\n\t\tTGraphDatas\tgraphDatas;\n\t\t\tnlRead(__message, serial, graphDatas);\n\t\tgraphUpdate(sender, graphDatas);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_highRezGraphUpdate_HRGU);\n\t\tTHighRezDatas\tgraphDatas;\n\t\t\tnlRead(__message, serial, graphDatas);\n\t\thighRezGraphUpdate(sender, graphDatas);\n\t}\n\n\tvoid CAdminExecutorServiceSkel::serviceStatusUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceSkel_serviceStatusUpdate_SSU);\n\t\tstd::string\tstatus;\n\t\t\tnlRead(__message, serial, status);\n\t\tserviceStatusUpdate(sender, status);\n\t}\n\t\t// AS send orders for a shard\n\tvoid CAdminExecutorServiceProxy::setShardOrders(NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->setShardOrders(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), shardName, shardOrders);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_setShardOrders(__message, shardName, shardOrders);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// AS send a command to shutdown a shard with a delay\n\tvoid CAdminExecutorServiceProxy::shutdownShard(NLNET::IModule *sender, const std::string &shardName, uint32 delay)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->shutdownShard(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), shardName, delay);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_shutdownShard(__message, shardName, delay);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// AS send a control command to this AES\n\tvoid CAdminExecutorServiceProxy::controlCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->controlCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, command);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_controlCmd(__message, commandId, serviceAlias, command);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// Send a command to a service.\n\tvoid CAdminExecutorServiceProxy::serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->serviceCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, command);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_serviceCmd(__message, commandId, serviceAlias, command);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// AES client send back the result of execution of a command\n\tvoid CAdminExecutorServiceProxy::commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->commandResult(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, serviceAlias, result);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_commandResult(__message, commandId, serviceAlias, result);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// A service send graph data update\n\tvoid CAdminExecutorServiceProxy::graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->graphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_graphUpdate(__message, graphDatas);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// A service high rez graph data update\n\tvoid CAdminExecutorServiceProxy::highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->highRezGraphUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), graphDatas);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_highRezGraphUpdate(__message, graphDatas);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// A service send an update of of it's status string\n\tvoid CAdminExecutorServiceProxy::serviceStatusUpdate(NLNET::IModule *sender, const std::string &status)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->serviceStatusUpdate(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), status);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_serviceStatusUpdate(__message, status);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_setShardOrders(NLNET::CMessage &__message, const std::string &shardName, const TShardOrders &shardOrders)\n\t{\n\t\t__message.setType(\"SCO\");\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (shardName));\n\t\t\tnlWrite(__message, serial, shardOrders);\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_shutdownShard(NLNET::CMessage &__message, const std::string &shardName, uint32 delay)\n\t{\n\t\t__message.setType(\"SDS\");\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (shardName));\n\t\t\tnlWrite(__message, serial, delay);\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_controlCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t{\n\t\t__message.setType(\"CC\");\n\t\t\tnlWrite(__message, serial, commandId);\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (command));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t{\n\t\t__message.setType(\"SCMD\");\n\t\t\tnlWrite(__message, serial, commandId);\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (command));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result)\n\t{\n\t\t__message.setType(\"CR\");\n\t\t\tnlWrite(__message, serial, commandId);\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (result));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas)\n\t{\n\t\t__message.setType(\"GU\");\n\t\t\tnlWrite(__message, serial, const_cast < TGraphDatas& > (graphDatas));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas)\n\t{\n\t\t__message.setType(\"HRGU\");\n\t\t\tnlWrite(__message, serial, const_cast < THighRezDatas& > (graphDatas));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceProxy::buildMessageFor_serviceStatusUpdate(NLNET::CMessage &__message, const std::string &status)\n\t{\n\t\t__message.setType(\"SSU\");\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (status));\n\n\n\t\treturn __message;\n\t}\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\t\n\n\tconst CAdminExecutorServiceClientSkel::TMessageHandlerMap &CAdminExecutorServiceClientSkel::getMessageHandlers() const\n\t{\n\t\tstatic TMessageHandlerMap handlers;\n\t\tstatic bool init = false;\n\n\t\tif (!init)\n\t\t{\n\t\t\tstd::pair < TMessageHandlerMap::iterator, bool > res;\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SCMD\"), &CAdminExecutorServiceClientSkel::serviceCmd_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tres = handlers.insert(std::make_pair(std::string(\"SCMDNR\"), &CAdminExecutorServiceClientSkel::serviceCmdNoReturn_skel));\n\t\t\t// if this assert, you have a doubly message name in your interface definition !\n\t\t\tnlassert(res.second);\n\t\t\t\n\t\t\tinit = true;\n\t\t}\n\n\t\treturn handlers;\t\t\t\n\t}\n\tbool CAdminExecutorServiceClientSkel::fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message)\n\t{\n\t\tconst TMessageHandlerMap &mh = getMessageHandlers();\n\n\t\tTMessageHandlerMap::const_iterator it(mh.find(message.getName()));\n\n\t\tif (it == mh.end())\n\t\t{\n\t\t\treturn false;\n\t\t}\n\n\t\tTMessageHandler cmd = it->second;\n\t\t(this->*cmd)(sender, message);\n\n\t\treturn true;\n\t}\n\n\t\n\tvoid CAdminExecutorServiceClientSkel::serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceClientSkel_serviceCmd_SCMD);\n\t\tuint32\tcommandId;\n\t\t\tnlRead(__message, serial, commandId);\n\t\tstd::string\tcommand;\n\t\t\tnlRead(__message, serial, command);\n\t\tserviceCmd(sender, commandId, command);\n\t}\n\n\tvoid CAdminExecutorServiceClientSkel::serviceCmdNoReturn_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message)\n\t{\n\t\tH_AUTO(CAdminExecutorServiceClientSkel_serviceCmdNoReturn_SCMDNR);\n\t\tstd::string\tcommand;\n\t\t\tnlRead(__message, serial, command);\n\t\tserviceCmdNoReturn(sender, command);\n\t}\n\t\t// execute a command and return the result.\n\tvoid CAdminExecutorServiceClientProxy::serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &command)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->serviceCmd(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), commandId, command);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_serviceCmd(__message, commandId, command);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\t\t// Send a command to a service without waiting for the return value.\n\tvoid CAdminExecutorServiceClientProxy::serviceCmdNoReturn(NLNET::IModule *sender, const std::string &command)\n\t{\n\t\tif (_LocalModuleSkel && _LocalModule->isImmediateDispatchingSupported())\n\t\t{\n\t\t\t// immediate local synchronous dispatching\n\t\t\t_LocalModuleSkel->serviceCmdNoReturn(_ModuleProxy->getModuleGateway()->getPluggedModuleProxy(sender), command);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the message for remote dispatching and execution or local queing \n\t\t\tNLNET::CMessage __message;\n\t\t\t\n\t\t\tbuildMessageFor_serviceCmdNoReturn(__message, command);\n\n\t\t\t_ModuleProxy->sendModuleMessage(sender, __message);\n\t\t}\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceClientProxy::buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &command)\n\t{\n\t\t__message.setType(\"SCMD\");\n\t\t\tnlWrite(__message, serial, commandId);\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (command));\n\n\n\t\treturn __message;\n\t}\n\n\t// Message serializer. Return the message received in reference for easier integration\n\tconst NLNET::CMessage &CAdminExecutorServiceClientProxy::buildMessageFor_serviceCmdNoReturn(NLNET::CMessage &__message, const std::string &command)\n\t{\n\t\t__message.setType(\"SCMDNR\");\n\t\t\tnlWrite(__message, serial, const_cast < std::string& > (command));\n\n\n\t\treturn __message;\n\t}\n\n}\n"
  },
  {
    "path": "code/EVA/server/admin_modules/admin_modules_itf.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/////////////////////////////////////////////////////////////////\n// WARNING : this is a generated file, don't change it !\n/////////////////////////////////////////////////////////////////\n\n#ifndef ADMIN_MODULES_ITF\n#define ADMIN_MODULES_ITF\n#include \"nel/misc/types_nl.h\"\n#include <memory>\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/string_conversion.h\"\n#include \"nel/net/message.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_builder_parts.h\"\n#include \"nel/net/module_message.h\"\n#include \"nel/net/module_gateway.h\"\n\n#include \"server_share/callback_adaptor.h\"\n\n#include \"nel/misc/time_nl.h\"\n\nnamespace ADMIN\n{\n\n\tclass TGraphData;\n\n\tclass TGraphDatas;\n\n\tclass THighRezData;\n\n\tclass THighRezDatas;\n\n\tclass TServiceStatus;\n\n\t// This is the interface used by PHP to call methods\n\t// on the Admin service module\n\n\tclass CAdminServiceWebItf\n\t{\n\tprotected:\n\n\t\t/// the callback server adaptor\n\t\tstd::auto_ptr<ICallbackServerAdaptor>\t_CallbackServer;\n\n\t\tvoid getCallbakArray(NLNET::TCallbackItem *&arrayPtr, uint32 &arraySize)\n\t\t{\n\t\t\tstatic NLNET::TCallbackItem callbackArray[] =\n\t\t\t{\n\t\t\t\t{\t\"GCMD\",\tCAdminServiceWebItf::cb_globalCmd\t},\n\t\t\t\t{\t\"CCMD\",\tCAdminServiceWebItf::cb_controlCmd\t},\n\t\t\t\t{\t\"SCMD\",\tCAdminServiceWebItf::cb_serviceCmd\t},\n\t\t\t\t{\t\"GSO\",\tCAdminServiceWebItf::cb_getShardOrders\t},\n\t\t\t\t{\t\"GS\",\tCAdminServiceWebItf::cb_getStates\t},\n\t\t\t\t{\t\"GHRGI\",\tCAdminServiceWebItf::cb_getHighRezGraphInfo\t},\n\t\t\t\t{\t\"GHRG\",\tCAdminServiceWebItf::cb_getHighRezGraph\t},\n\n\t\t\t};\n\n\t\t\tarrayPtr = callbackArray;\n\t\t\tarraySize = sizeofarray(callbackArray);\n\t\t}\n\n\t\tstatic void _cbConnection(NLNET::TSockId from, void *arg)\n\t\t{\n\t\t\tH_AUTO(CAdminServiceWeb__cbConnection);\n\t\t\tCAdminServiceWebItf *_this = reinterpret_cast<CAdminServiceWebItf *>(arg);\n\n\t\t\t_this->on_CAdminServiceWeb_Connection(from);\n\t\t}\n\n\t\tstatic void _cbDisconnection(NLNET::TSockId from, void *arg)\n\t\t{\n\t\t\tH_AUTO(CAdminServiceWeb__cbDisconnection);\n\t\t\tCAdminServiceWebItf *_this = reinterpret_cast<CAdminServiceWebItf *>(arg);\n\n\t\t\t_this->on_CAdminServiceWeb_Disconnection(from);\n\t\t}\n\n\tpublic:\n\t\t/** Constructor, if you specify a replacement adaptor, then the object\n\t\t *\tbecome owner of the adaptor (and it will be released with the\n\t\t *\tinterface).\n\t\t */\n\t\tCAdminServiceWebItf(ICallbackServerAdaptor *replacementAdaptor = NULL)\n\t\t{\n\t\t\tif (replacementAdaptor == NULL)\n\t\t\t{\n\t\t\t\t// use default callback server\n\t\t\t\t_CallbackServer = std::auto_ptr<ICallbackServerAdaptor>(new CNelCallbackServerAdaptor(this));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// use the replacement one\n\t\t\t\t_CallbackServer = std::auto_ptr<ICallbackServerAdaptor>(replacementAdaptor);\n\t\t\t}\n\t\t}\n\n\t\tvirtual ~CAdminServiceWebItf()\n\t\t{\n\t\t}\n\n\t\t/// Open the interface socket in the specified port\n\t\tvoid openItf(uint16 port)\n\t\t{\n\t\t\tNLNET::TCallbackItem *arrayPtr;\n\t\t\tuint32 arraySize;\n\n\n\n\t\t\tgetCallbakArray(arrayPtr, arraySize);\n\t\t\t_CallbackServer->addCallbackArray(arrayPtr, arraySize);\n\n\t\t\t_CallbackServer->setConnectionCallback (_cbConnection, this);\n\t\t\t_CallbackServer->setDisconnectionCallback (_cbDisconnection, this);\n\n\t\t\t_CallbackServer->init(port);\n\t\t}\n\n\t\t/** Must be called evenly, update the network subclass to receive message\n\t\t *\tand dispatch method invokation.\n\t\t */\n\t\tvoid update()\n\t\t{\n\t\t\tH_AUTO(CAdminServiceWeb_update);\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t_CallbackServer->update();\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tnlwarning(\"CAdminServiceWeb : Exception launch in callback server update\");\n\t\t\t}\n\t\t}\n\n\n\t\tvoid commandResult(NLNET::TSockId dest, const std::string &serviceAlias, const std::string &result)\n\t\t{\n\t\t\tH_AUTO(commandResult_commandResult);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::commandResult called\");\n#endif\n\t\t\tNLNET::CMessage message(\"CMDR\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (result));\n\n\t\t\t_CallbackServer->send(message, dest);\n\t\t}\n\n\t\tstatic void cb_globalCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(globalCmd_on_globalCmd);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_globalCmd received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tcommand;\n\t\t\tnlRead(message, serial, command);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_globalCmd : calling on_globalCmd\");\n#endif\n\n\n\t\t\tcallback->on_globalCmd(from, command);\n\n\t\t}\n\n\t\tstatic void cb_controlCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(controlCmd_on_controlCmd);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_controlCmd received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tserviceAlias;\n\t\t\tstd::string\tcommand;\n\t\t\tnlRead(message, serial, serviceAlias);\n\t\t\tnlRead(message, serial, command);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_controlCmd : calling on_controlCmd\");\n#endif\n\n\n\t\t\tcallback->on_controlCmd(from, serviceAlias, command);\n\n\t\t}\n\n\t\tstatic void cb_serviceCmd (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(serviceCmd_on_serviceCmd);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_serviceCmd received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tserviceAlias;\n\t\t\tstd::string\tcommand;\n\t\t\tnlRead(message, serial, serviceAlias);\n\t\t\tnlRead(message, serial, command);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_serviceCmd : calling on_serviceCmd\");\n#endif\n\n\n\t\t\tcallback->on_serviceCmd(from, serviceAlias, command);\n\n\t\t}\n\n\t\tstatic void cb_getShardOrders (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(getShardOrders_on_getShardOrders);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getShardOrders received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getShardOrders : calling on_getShardOrders\");\n#endif\n\n\t\t\tstd::vector<std::string> retValue;\n\n\t\t\tretValue = callback->on_getShardOrders(from);\n\n\t\t\tNLNET::CMessage retMsg(\"R_GSO\");\n\n\t\t\tnlWrite(retMsg, serialCont, retValue);\n\n\n\t\t\tcallback->_CallbackServer->send(retMsg, from);\n\n\t\t}\n\n\t\tstatic void cb_getStates (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(getStates_on_getStates);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getStates received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getStates : calling on_getStates\");\n#endif\n\n\t\t\tstd::vector<std::string> retValue;\n\n\t\t\tretValue = callback->on_getStates(from);\n\n\t\t\tNLNET::CMessage retMsg(\"R_GS\");\n\n\t\t\tnlWrite(retMsg, serialCont, retValue);\n\n\n\t\t\tcallback->_CallbackServer->send(retMsg, from);\n\n\t\t}\n\n\t\tstatic void cb_getHighRezGraphInfo (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(getHighRezGraphInfo_on_getHighRezGraphInfo);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getHighRezGraphInfo received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tvarAddr;\n\t\t\tnlRead(message, serial, varAddr);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getHighRezGraphInfo : calling on_getHighRezGraphInfo\");\n#endif\n\n\t\t\tstd::vector<std::string> retValue;\n\n\t\t\tretValue = callback->on_getHighRezGraphInfo(from, varAddr);\n\n\t\t\tNLNET::CMessage retMsg(\"R_GHRGI\");\n\n\t\t\tnlWrite(retMsg, serialCont, retValue);\n\n\n\t\t\tcallback->_CallbackServer->send(retMsg, from);\n\n\t\t}\n\n\t\tstatic void cb_getHighRezGraph (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n\t\t\tH_AUTO(getHighRezGraph_on_getHighRezGraph);\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getHighRezGraph received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackServerAdaptor *adaptor = static_cast< ICallbackServerAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebItf *callback = (CAdminServiceWebItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tvarAddr;\n\t\t\tuint32\tstartDate;\n\t\t\tuint32\tendDate;\n\t\t\tuint32\tmilliStep;\n\t\t\tnlRead(message, serial, varAddr);\n\t\t\tnlRead(message, serial, startDate);\n\t\t\tnlRead(message, serial, endDate);\n\t\t\tnlRead(message, serial, milliStep);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWeb::cb_getHighRezGraph : calling on_getHighRezGraph\");\n#endif\n\n\t\t\tstd::vector<std::string> retValue;\n\n\t\t\tretValue = callback->on_getHighRezGraph(from, varAddr, startDate, endDate, milliStep);\n\n\t\t\tNLNET::CMessage retMsg(\"R_GHRG\");\n\n\t\t\tnlWrite(retMsg, serialCont, retValue);\n\n\n\t\t\tcallback->_CallbackServer->send(retMsg, from);\n\n\t\t}\n\n\n\t\t/// Connection callback : a new interface client connect\n\t\tvirtual void on_CAdminServiceWeb_Connection(NLNET::TSockId from) =0;\n\t\t/// Disconnection callback : one of the interface client disconnect\n\t\tvirtual void on_CAdminServiceWeb_Disconnection(NLNET::TSockId from) =0;\n\n\n\t\t// Send a command to the AS.\n\t\t// This is used to issue global commands like 'as.allStart' or 'as.allStop'.\n\t\t// The result is returned by the return message\n\t\t// serviceCmdResult.\n\t\tvirtual void on_globalCmd(NLNET::TSockId from, const std::string &command) =0;\n\n\t\t// Send a service related command to the executor\n\t\t// (not to the controled service)\n\t\t// The result is returned by the return message\n\t\t// controlCmdResult.\n\t\tvirtual void on_controlCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) =0;\n\n\t\t// Send a command to a service.\n\t\t// The result is returned by the return message\n\t\t// serviceCmdResult.\n\t\tvirtual void on_serviceCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command) =0;\n\n\t\t// Get the orders of each known shard.\n\t\t// The return value is a vector of string, one entry by shard\n\t\tvirtual std::vector<std::string> on_getShardOrders(NLNET::TSockId from) =0;\n\n\t\t// Get the last known state of all services.\n\t\t// The return value is a vector of string, one entry by service\n\t\tvirtual std::vector<std::string> on_getStates(NLNET::TSockId from) =0;\n\n\t\t// Get information about a high rez graph.\n\t\t// The return is a string array containing\n\t\t// the name of the var, the available sample\n\t\t// period as two unix date (start dans end)\n\t\t// and the number of samples available\n\t\t// If the var is not found, an empty array is returned\n\t\tvirtual std::vector<std::string> on_getHighRezGraphInfo(NLNET::TSockId from, const std::string &varAddr) =0;\n\n\t\t// Get the data for a high resolution graph.\n\t\t// The return is a string array, each\n\t\t// string containing 'time:milliOffset:value\n\t\t// Set endDate to 0 to specify a start date relative\n\t\t// to the last sample date. In this case, start date\n\t\t// is interpreted as the number of second before\n\t\t// the last sample.\n\t\tvirtual std::vector<std::string> on_getHighRezGraph(NLNET::TSockId from, const std::string &varAddr, uint32 startDate, uint32 endDate, uint32 milliStep) =0;\n\n\t};\n\n\t\t// This is the interface used by PHP to call methods\n\t// on the Admin service module\n\n\t/** This is the client side of the interface\n\t *\tDerive from this class to invoke method on the callback server\n\t */\n\n\tclass CAdminServiceWebClientItf\n\t{\n\tprotected:\n\n\t\t/// the callback client adaptor\n\t\tstd::auto_ptr < ICallbackClientAdaptor >\t_CallbackClient;\n\n\n\t\tvoid getCallbakArray(NLNET::TCallbackItem *&arrayPtr, uint32 &arraySize)\n\t\t{\n\n\t\t\tstatic NLNET::TCallbackItem callbackArray[] =\n\t\t\t{\n\t\t\t\t{\t\"CMDR\",\tCAdminServiceWebClientItf::cb_commandResult\t},\n\n\t\t\t};\n\n\t\t\tarrayPtr = callbackArray;\n\t\t\tarraySize = sizeofarray(callbackArray);\n\n\t\t}\n\n\t\tstatic void _cbDisconnection(NLNET::TSockId from, void *arg)\n\t\t{\n\t\t\tCAdminServiceWebClientItf *_this = reinterpret_cast<CAdminServiceWebClientItf *>(arg);\n\n\t\t\t_this->on_CAdminServiceWebClient_Disconnection(from);\n\t\t}\n\n\n\tpublic:\n\t\t/// Retreive the message name for a given callback name\n\t\tstatic const std::string &getMessageName(const std::string &methodName)\n\t\t{\n\t\t\tstatic std::map<std::string, std::string> messageNames;\n\t\t\tstatic bool initialized = false;\n\t\t\tif (!initialized)\n\t\t\t{\n\t\t\tmessageNames.insert(std::make_pair(std::string(\"on_commandResult\"), std::string(\"CMDR\")));\n\n\t\t\t\tinitialized = true;\n\t\t\t}\n\n\t\t\tstd::map < std::string, std::string>::const_iterator it(messageNames.find(methodName));\n\t\t\tif (it != messageNames.end())\n\t\t\t\treturn it->second;\n\n\n\t\t\tstatic std::string emptyString;\n\n\t\t\treturn emptyString;\n\n\t\t}\n\n\t\tCAdminServiceWebClientItf(ICallbackClientAdaptor *adaptorReplacement = NULL)\n\t\t{\n\t\t\tif (adaptorReplacement == NULL)\n\t\t\t{\n\t\t\t\t// use the default Nel adaptor\n\t\t\t\t_CallbackClient = std::auto_ptr < ICallbackClientAdaptor >(new CNelCallbackClientAdaptor(this));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// use the replacement one\n\t\t\t\t_CallbackClient = std::auto_ptr < ICallbackClientAdaptor >(adaptorReplacement);\n\t\t\t}\n\t\t}\n\n\t\t/// Connect the interface client to the callback server at the specified address and port\n\t\tvirtual void connectItf(NLNET::CInetAddress address)\n\t\t{\n\t\t\tNLNET::TCallbackItem *arrayPtr;\n\t\t\tuint32 arraySize;\n\n\t\t\tstatic bool callbackAdded = false;\n\t\t\tif (!callbackAdded)\n\t\t\t{\n\n\t\t\t\tgetCallbakArray(arrayPtr, arraySize);\n\t\t\t\t_CallbackClient->addCallbackArray(arrayPtr, arraySize);\n\t\t\t}\n\n\t\t\t_CallbackClient->setDisconnectionCallback (_cbDisconnection, this);\n\n\t\t\t_CallbackClient->connect(address);\n\t\t}\n\n\t\t/** Must be called evenly, update the network subclass to receive message\n\t\t *\tand dispatch invokation returns.\n\t\t */\n\t\tvirtual void update()\n\t\t{\n\t\t\tH_AUTO(CAdminServiceWeb_update);\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t_CallbackClient->update();\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tnlwarning(\"CAdminServiceWeb : Exception launch in callback client update\");\n\t\t\t}\n\t\t}\n\n\t\t// Send a command to the AS.\n\t\t// This is used to issue global commands like 'as.allStart' or 'as.allStop'.\n\t\t// The result is returned by the return message\n\t\t// serviceCmdResult.\n\n\t\tvoid globalCmd(const std::string &command)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::globalCmd called\");\n#endif\n\t\t\tNLNET::CMessage message(\"GCMD\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (command));\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Send a service related command to the executor\n\t\t// (not to the controled service)\n\t\t// The result is returned by the return message\n\t\t// controlCmdResult.\n\n\t\tvoid controlCmd(const std::string &serviceAlias, const std::string &command)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::controlCmd called\");\n#endif\n\t\t\tNLNET::CMessage message(\"CCMD\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (command));\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Send a command to a service.\n\t\t// The result is returned by the return message\n\t\t// serviceCmdResult.\n\n\t\tvoid serviceCmd(const std::string &serviceAlias, const std::string &command)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::serviceCmd called\");\n#endif\n\t\t\tNLNET::CMessage message(\"SCMD\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (serviceAlias));\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (command));\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Get the orders of each known shard.\n\t\t// The return value is a vector of string, one entry by shard\n\n\t\tvoid getShardOrders()\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::getShardOrders called\");\n#endif\n\t\t\tNLNET::CMessage message(\"GSO\");\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Get the last known state of all services.\n\t\t// The return value is a vector of string, one entry by service\n\n\t\tvoid getStates()\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::getStates called\");\n#endif\n\t\t\tNLNET::CMessage message(\"GS\");\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Get information about a high rez graph.\n\t\t// The return is a string array containing\n\t\t// the name of the var, the available sample\n\t\t// period as two unix date (start dans end)\n\t\t// and the number of samples available\n\t\t// If the var is not found, an empty array is returned\n\n\t\tvoid getHighRezGraphInfo(const std::string &varAddr)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::getHighRezGraphInfo called\");\n#endif\n\t\t\tNLNET::CMessage message(\"GHRGI\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (varAddr));\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\t\t// Get the data for a high resolution graph.\n\t\t// The return is a string array, each\n\t\t// string containing 'time:milliOffset:value\n\t\t// Set endDate to 0 to specify a start date relative\n\t\t// to the last sample date. In this case, start date\n\t\t// is interpreted as the number of second before\n\t\t// the last sample.\n\n\t\tvoid getHighRezGraph(const std::string &varAddr, uint32 startDate, uint32 endDate, uint32 milliStep)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::getHighRezGraph called\");\n#endif\n\t\t\tNLNET::CMessage message(\"GHRG\");\n\t\t\tnlWrite(message, serial, const_cast < std::string& > (varAddr));\n\t\t\tnlWrite(message, serial, startDate);\n\t\t\tnlWrite(message, serial, endDate);\n\t\t\tnlWrite(message, serial, milliStep);\n\n\t\t\t_CallbackClient->send(message);\n\t\t}\n\n\t\tstatic void cb_commandResult (NLNET::CMessage &message, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::cb_commandResult received from class '%s'\", typeid(netbase).name());\n#endif\n\t\t\tICallbackClientAdaptor *adaptor = static_cast< ICallbackClientAdaptor *>(netbase.getUserData());\n\n\t\t\tCAdminServiceWebClientItf *callback = (CAdminServiceWebClientItf *)adaptor->getContainerClass();\n\n\t\t\tif (callback  == NULL)\n\t\t\t\treturn;\n\t\t\tstd::string\tserviceAlias;\n\t\t\tstd::string\tresult;\n\t\t\tnlRead(message, serial, serviceAlias);\n\t\t\tnlRead(message, serial, result);\n\n\n#ifdef NL_DEBUG\n\t\t\tnldebug(\"CAdminServiceWebClient::cb_commandResult : calling on_commandResult\");\n#endif\n\n\t\t\tcallback->on_commandResult(from, serviceAlias, result);\n\t\t}\n\n\n\t\t/// Disconnection callback : the connection to the server is lost\n\t\tvirtual void on_CAdminServiceWebClient_Disconnection(NLNET::TSockId from) =0;\n\n\n\t\tvirtual void on_commandResult(NLNET::TSockId from, const std::string &serviceAlias, const std::string &result) =0;\n\n\t};\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass TGraphData\n\t{\n\tprotected:\n\t\t//\n\t\tstd::string\t_ServiceAlias;\n\t\t//\n\t\tstd::string\t_VarName;\n\t\t//\n\t\tuint32\t_SamplePeriod;\n\t\t//\n\t\tdouble\t_Value;\n\tpublic:\n\t\t//\n\t\tconst std::string &getServiceAlias() const\n\t\t{\n\t\t\treturn _ServiceAlias;\n\t\t}\n\n\t\tstd::string &getServiceAlias()\n\t\t{\n\t\t\treturn _ServiceAlias;\n\t\t}\n\n\n\t\tvoid setServiceAlias(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ServiceAlias = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getVarName() const\n\t\t{\n\t\t\treturn _VarName;\n\t\t}\n\n\t\tstd::string &getVarName()\n\t\t{\n\t\t\treturn _VarName;\n\t\t}\n\n\n\t\tvoid setVarName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_VarName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tuint32 getSamplePeriod() const\n\t\t{\n\t\t\treturn _SamplePeriod;\n\t\t}\n\n\t\tvoid setSamplePeriod(uint32 value)\n\t\t{\n\n\t\t\t\t_SamplePeriod = value;\n\n\t\t}\n\t\t\t//\n\t\tdouble getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\tvoid setValue(double value)\n\t\t{\n\n\t\t\t\t_Value = value;\n\n\t\t}\n\n\t\tbool operator == (const TGraphData &other) const\n\t\t{\n\t\t\treturn _ServiceAlias == other._ServiceAlias\n\t\t\t\t&& _VarName == other._VarName\n\t\t\t\t&& _SamplePeriod == other._SamplePeriod\n\t\t\t\t&& _Value == other._Value;\n\t\t}\n\n\n\t\t// constructor\n\t\tTGraphData()\n\t\t{\n\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(_ServiceAlias);\n\t\t\ts.serial(_VarName);\n\t\t\ts.serial(_SamplePeriod);\n\t\t\ts.serial(_Value);\n\n\t\t}\n\n\n\tprivate:\n\n\n\t};\n\n\n\t\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass TGraphDatas\n\t{\n\tprotected:\n\t\t//\n\t\tuint32\t_CurrentTime;\n\t\t//\n\t\tstd::vector < TGraphData >\t_Datas;\n\tpublic:\n\t\t//\n\t\tuint32 getCurrentTime() const\n\t\t{\n\t\t\treturn _CurrentTime;\n\t\t}\n\n\t\tvoid setCurrentTime(uint32 value)\n\t\t{\n\n\t\t\t\t_CurrentTime = value;\n\n\t\t}\n\t\t\t//\n\t\tconst std::vector < TGraphData > &getDatas() const\n\t\t{\n\t\t\treturn _Datas;\n\t\t}\n\n\t\tstd::vector < TGraphData > &getDatas()\n\t\t{\n\t\t\treturn _Datas;\n\t\t}\n\n\n\t\tvoid setDatas(const std::vector < TGraphData > &value)\n\t\t{\n\n\n\t\t\t\t_Datas = value;\n\n\n\t\t}\n\n\t\tbool operator == (const TGraphDatas &other) const\n\t\t{\n\t\t\treturn _CurrentTime == other._CurrentTime\n\t\t\t\t&& _Datas == other._Datas;\n\t\t}\n\n\n\t\t// constructor\n\t\tTGraphDatas()\n\t\t{\n\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(_CurrentTime);\n\t\t\ts.serialCont(_Datas);\n\n\t\t}\n\n\n\tprivate:\n\n\n\t};\n\n\n\t\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass THighRezData\n\t{\n\tprotected:\n\t\t//\n\t\tNLMISC::TTime\t_SampleTick;\n\t\t//\n\t\tdouble\t_Value;\n\tpublic:\n\t\t//\n\t\tNLMISC::TTime getSampleTick() const\n\t\t{\n\t\t\treturn _SampleTick;\n\t\t}\n\n\t\tvoid setSampleTick(NLMISC::TTime value)\n\t\t{\n\n\t\t\t\t_SampleTick = value;\n\n\t\t}\n\t\t\t//\n\t\tdouble getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\tvoid setValue(double value)\n\t\t{\n\n\t\t\t\t_Value = value;\n\n\t\t}\n\n\t\tbool operator == (const THighRezData &other) const\n\t\t{\n\t\t\treturn _SampleTick == other._SampleTick\n\t\t\t\t&& _Value == other._Value;\n\t\t}\n\n\n\t\t// constructor\n\t\tTHighRezData()\n\t\t{\n\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(_SampleTick);\n\t\t\ts.serial(_Value);\n\n\t\t}\n\n\n\tprivate:\n\n\n\t};\n\n\n\t\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass THighRezDatas\n\t{\n\tprotected:\n\t\t//\n\t\tstd::string\t_ServiceAlias;\n\t\t//\n\t\tstd::string\t_VarName;\n\t\t//\n\t\tuint32\t_CurrentTime;\n\t\t//\n\t\tstd::vector < THighRezData >\t_Datas;\n\tpublic:\n\t\t//\n\t\tconst std::string &getServiceAlias() const\n\t\t{\n\t\t\treturn _ServiceAlias;\n\t\t}\n\n\t\tstd::string &getServiceAlias()\n\t\t{\n\t\t\treturn _ServiceAlias;\n\t\t}\n\n\n\t\tvoid setServiceAlias(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ServiceAlias = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getVarName() const\n\t\t{\n\t\t\treturn _VarName;\n\t\t}\n\n\t\tstd::string &getVarName()\n\t\t{\n\t\t\treturn _VarName;\n\t\t}\n\n\n\t\tvoid setVarName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_VarName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tuint32 getCurrentTime() const\n\t\t{\n\t\t\treturn _CurrentTime;\n\t\t}\n\n\t\tvoid setCurrentTime(uint32 value)\n\t\t{\n\n\t\t\t\t_CurrentTime = value;\n\n\t\t}\n\t\t\t//\n\t\tconst std::vector < THighRezData > &getDatas() const\n\t\t{\n\t\t\treturn _Datas;\n\t\t}\n\n\t\tstd::vector < THighRezData > &getDatas()\n\t\t{\n\t\t\treturn _Datas;\n\t\t}\n\n\n\t\tvoid setDatas(const std::vector < THighRezData > &value)\n\t\t{\n\n\n\t\t\t\t_Datas = value;\n\n\n\t\t}\n\n\t\tbool operator == (const THighRezDatas &other) const\n\t\t{\n\t\t\treturn _ServiceAlias == other._ServiceAlias\n\t\t\t\t&& _VarName == other._VarName\n\t\t\t\t&& _CurrentTime == other._CurrentTime\n\t\t\t\t&& _Datas == other._Datas;\n\t\t}\n\n\n\t\t// constructor\n\t\tTHighRezDatas()\n\t\t{\n\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(_ServiceAlias);\n\t\t\ts.serial(_VarName);\n\t\t\ts.serial(_CurrentTime);\n\t\t\ts.serialCont(_Datas);\n\n\t\t}\n\n\n\tprivate:\n\n\n\t};\n\n\n\n\n\tstruct TShardOrders\n\t{\n\t\tenum TValues\n\t\t{\n\t\t\tso_autostart_on,\n\t\t\tso_autostart_off,\n\t\t\t/// the highest valid value in the enum\n\t\t\tlast_enum_item = so_autostart_off,\n\t\t\t/// a value equal to the last enum item +1\n\t\t\tend_of_enum,\n\n\t\t\tinvalid_val,\n\n\t\t\t/// Number of enumerated values\n\t\t\tnb_enum_items = 2\n\t\t};\n\n\t\t/// Index table to convert enum value to linear index table\n\t\tconst std::map<TValues, uint32> &getIndexTable() const\n\t\t{\n\t\t\tstatic std::map<TValues, uint32> indexTable;\n\t\t\tstatic bool init = false;\n\t\t\tif (!init)\n\t\t\t{\n\t\t\t\t// fill the index table\n\t\t\t\tindexTable.insert(std::make_pair(so_autostart_on, 0));\n\t\t\t\tindexTable.insert(std::make_pair(so_autostart_off, 1));\n\n\t\t\t\tinit = true;\n\t\t\t}\n\n\t\t\treturn indexTable;\n\t\t}\n\n\n\t\tstatic const NLMISC::CStringConversion<TValues> &getConversionTable()\n\t\t{\n\t\t\tNL_BEGIN_STRING_CONVERSION_TABLE(TValues)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(so_autostart_on)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(so_autostart_off)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(invalid_val)\n\t\t\t};\n\t\t\tstatic NLMISC::CStringConversion<TValues>\n\t\t\tconversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table)\n\t\t\t/ sizeof(TValues_nl_string_conversion_table[0]),  invalid_val);\n\n\t\t\treturn conversionTable;\n\t\t}\n\n\t\tTValues\t_Value;\n\n\tpublic:\n\t\tTShardOrders()\n\t\t\t: _Value(invalid_val)\n\t\t{\n\t\t}\n\t\tTShardOrders(TValues value)\n\t\t\t: _Value(value)\n\t\t{\n\t\t}\n\n\t\tTShardOrders(const std::string &str)\n\t\t{\n\t\t\t_Value = getConversionTable().fromString(str);\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serialEnum(_Value);\n\t\t}\n\n\t\tbool operator == (const TShardOrders &other) const\n\t\t{\n\t\t\treturn _Value == other._Value;\n\t\t}\n\t\tbool operator != (const TShardOrders &other) const\n\t\t{\n\t\t\treturn ! (_Value == other._Value);\n\t\t}\n\t\tbool operator < (const TShardOrders &other) const\n\t\t{\n\t\t\treturn _Value < other._Value;\n\t\t}\n\n\t\tbool operator <= (const TShardOrders &other) const\n\t\t{\n\t\t\treturn _Value <= other._Value;\n\t\t}\n\n\t\tbool operator > (const TShardOrders &other) const\n\t\t{\n\t\t\treturn !(_Value <= other._Value);\n\t\t}\n\t\tbool operator >= (const TShardOrders &other) const\n\t\t{\n\t\t\treturn !(_Value < other._Value);\n\t\t}\n\n\t\tconst std::string &toString() const\n\t\t{\n\t\t\treturn getConversionTable().toString(_Value);\n\t\t}\n\t\tstatic const std::string &toString(TValues value)\n\t\t{\n\t\t\treturn getConversionTable().toString(value);\n\t\t}\n\n\t\tTValues getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\t// return true if the actual value of the enum is valid, otherwise false\n\t\tbool isValid()\n\t\t{\n\t\t\tif (_Value == invalid_val)\n\t\t\t\treturn false;\n\n\t\t\t// not invalid, check other enum value\n\t\t\treturn getConversionTable().isValid(_Value);\n\t\t}\n\n\n\t\tuint32 asIndex()\n\t\t{\n\t\t\tstd::map<TValues, uint32>::const_iterator it(getIndexTable().find(_Value));\n\t\t\tnlassert(it != getIndexTable().end());\n\t\t\treturn it->second;\n\t\t}\n\n\t};\n\n\n\tstruct TRunningOrders\n\t{\n\t\tenum TValues\n\t\t{\n\t\t\tro_deactivated,\n\t\t\tro_activated,\n\t\t\t/// the highest valid value in the enum\n\t\t\tlast_enum_item = ro_activated,\n\t\t\t/// a value equal to the last enum item +1\n\t\t\tend_of_enum,\n\n\t\t\tinvalid_val,\n\n\t\t\t/// Number of enumerated values\n\t\t\tnb_enum_items = 2\n\t\t};\n\n\t\t/// Index table to convert enum value to linear index table\n\t\tconst std::map<TValues, uint32> &getIndexTable() const\n\t\t{\n\t\t\tstatic std::map<TValues, uint32> indexTable;\n\t\t\tstatic bool init = false;\n\t\t\tif (!init)\n\t\t\t{\n\t\t\t\t// fill the index table\n\t\t\t\tindexTable.insert(std::make_pair(ro_deactivated, 0));\n\t\t\t\tindexTable.insert(std::make_pair(ro_activated, 1));\n\n\t\t\t\tinit = true;\n\t\t\t}\n\n\t\t\treturn indexTable;\n\t\t}\n\n\n\t\tstatic const NLMISC::CStringConversion<TValues> &getConversionTable()\n\t\t{\n\t\t\tNL_BEGIN_STRING_CONVERSION_TABLE(TValues)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(ro_deactivated)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(ro_activated)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(invalid_val)\n\t\t\t};\n\t\t\tstatic NLMISC::CStringConversion<TValues>\n\t\t\tconversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table)\n\t\t\t/ sizeof(TValues_nl_string_conversion_table[0]),  invalid_val);\n\n\t\t\treturn conversionTable;\n\t\t}\n\n\t\tTValues\t_Value;\n\n\tpublic:\n\t\tTRunningOrders()\n\t\t\t: _Value(invalid_val)\n\t\t{\n\t\t}\n\t\tTRunningOrders(TValues value)\n\t\t\t: _Value(value)\n\t\t{\n\t\t}\n\n\t\tTRunningOrders(const std::string &str)\n\t\t{\n\t\t\t_Value = getConversionTable().fromString(str);\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serialEnum(_Value);\n\t\t}\n\n\t\tbool operator == (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn _Value == other._Value;\n\t\t}\n\t\tbool operator != (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn ! (_Value == other._Value);\n\t\t}\n\t\tbool operator < (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn _Value < other._Value;\n\t\t}\n\n\t\tbool operator <= (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn _Value <= other._Value;\n\t\t}\n\n\t\tbool operator > (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn !(_Value <= other._Value);\n\t\t}\n\t\tbool operator >= (const TRunningOrders &other) const\n\t\t{\n\t\t\treturn !(_Value < other._Value);\n\t\t}\n\n\t\tconst std::string &toString() const\n\t\t{\n\t\t\treturn getConversionTable().toString(_Value);\n\t\t}\n\t\tstatic const std::string &toString(TValues value)\n\t\t{\n\t\t\treturn getConversionTable().toString(value);\n\t\t}\n\n\t\tTValues getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\t// return true if the actual value of the enum is valid, otherwise false\n\t\tbool isValid()\n\t\t{\n\t\t\tif (_Value == invalid_val)\n\t\t\t\treturn false;\n\n\t\t\t// not invalid, check other enum value\n\t\t\treturn getConversionTable().isValid(_Value);\n\t\t}\n\n\n\t\tuint32 asIndex()\n\t\t{\n\t\t\tstd::map<TValues, uint32>::const_iterator it(getIndexTable().find(_Value));\n\t\t\tnlassert(it != getIndexTable().end());\n\t\t\treturn it->second;\n\t\t}\n\n\t};\n\n\n\tstruct TRunningState\n\t{\n\t\tenum TValues\n\t\t{\n\t\t\trs_stopped,\n\t\t\trs_running,\n\t\t\trs_online,\n\t\t\t/// the highest valid value in the enum\n\t\t\tlast_enum_item = rs_online,\n\t\t\t/// a value equal to the last enum item +1\n\t\t\tend_of_enum,\n\n\t\t\tinvalid_val,\n\n\t\t\t/// Number of enumerated values\n\t\t\tnb_enum_items = 3\n\t\t};\n\n\t\t/// Index table to convert enum value to linear index table\n\t\tconst std::map<TValues, uint32> &getIndexTable() const\n\t\t{\n\t\t\tstatic std::map<TValues, uint32> indexTable;\n\t\t\tstatic bool init = false;\n\t\t\tif (!init)\n\t\t\t{\n\t\t\t\t// fill the index table\n\t\t\t\tindexTable.insert(std::make_pair(rs_stopped, 0));\n\t\t\t\tindexTable.insert(std::make_pair(rs_running, 1));\n\t\t\t\tindexTable.insert(std::make_pair(rs_online, 2));\n\n\t\t\t\tinit = true;\n\t\t\t}\n\n\t\t\treturn indexTable;\n\t\t}\n\n\n\t\tstatic const NLMISC::CStringConversion<TValues> &getConversionTable()\n\t\t{\n\t\t\tNL_BEGIN_STRING_CONVERSION_TABLE(TValues)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rs_stopped)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rs_running)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rs_online)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(invalid_val)\n\t\t\t};\n\t\t\tstatic NLMISC::CStringConversion<TValues>\n\t\t\tconversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table)\n\t\t\t/ sizeof(TValues_nl_string_conversion_table[0]),  invalid_val);\n\n\t\t\treturn conversionTable;\n\t\t}\n\n\t\tTValues\t_Value;\n\n\tpublic:\n\t\tTRunningState()\n\t\t\t: _Value(invalid_val)\n\t\t{\n\t\t}\n\t\tTRunningState(TValues value)\n\t\t\t: _Value(value)\n\t\t{\n\t\t}\n\n\t\tTRunningState(const std::string &str)\n\t\t{\n\t\t\t_Value = getConversionTable().fromString(str);\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serialEnum(_Value);\n\t\t}\n\n\t\tbool operator == (const TRunningState &other) const\n\t\t{\n\t\t\treturn _Value == other._Value;\n\t\t}\n\t\tbool operator != (const TRunningState &other) const\n\t\t{\n\t\t\treturn ! (_Value == other._Value);\n\t\t}\n\t\tbool operator < (const TRunningState &other) const\n\t\t{\n\t\t\treturn _Value < other._Value;\n\t\t}\n\n\t\tbool operator <= (const TRunningState &other) const\n\t\t{\n\t\t\treturn _Value <= other._Value;\n\t\t}\n\n\t\tbool operator > (const TRunningState &other) const\n\t\t{\n\t\t\treturn !(_Value <= other._Value);\n\t\t}\n\t\tbool operator >= (const TRunningState &other) const\n\t\t{\n\t\t\treturn !(_Value < other._Value);\n\t\t}\n\n\t\tconst std::string &toString() const\n\t\t{\n\t\t\treturn getConversionTable().toString(_Value);\n\t\t}\n\t\tstatic const std::string &toString(TValues value)\n\t\t{\n\t\t\treturn getConversionTable().toString(value);\n\t\t}\n\n\t\tTValues getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\t// return true if the actual value of the enum is valid, otherwise false\n\t\tbool isValid()\n\t\t{\n\t\t\tif (_Value == invalid_val)\n\t\t\t\treturn false;\n\n\t\t\t// not invalid, check other enum value\n\t\t\treturn getConversionTable().isValid(_Value);\n\t\t}\n\n\n\t\tuint32 asIndex()\n\t\t{\n\t\t\tstd::map<TValues, uint32>::const_iterator it(getIndexTable().find(_Value));\n\t\t\tnlassert(it != getIndexTable().end());\n\t\t\treturn it->second;\n\t\t}\n\n\t};\n\n\n\tstruct TRunningTag\n\t{\n\t\tenum TValues\n\t\t{\n\t\t\trt_chain_crashing,\n\t\t\trt_locally_started,\n\t\t\trt_locally_stopped,\n\t\t\trt_globally_stopped,\n\t\t\trt_stopped_for_patch,\n\t\t\trt_externaly_started,\n\t\t\trt_slow_to_stop,\n\t\t\trt_slow_to_start,\n\t\t\t/// the highest valid value in the enum\n\t\t\tlast_enum_item = rt_slow_to_start,\n\t\t\t/// a value equal to the last enum item +1\n\t\t\tend_of_enum,\n\n\t\t\tinvalid_val,\n\n\t\t\t/// Number of enumerated values\n\t\t\tnb_enum_items = 8\n\t\t};\n\n\t\t/// Index table to convert enum value to linear index table\n\t\tconst std::map<TValues, uint32> &getIndexTable() const\n\t\t{\n\t\t\tstatic std::map<TValues, uint32> indexTable;\n\t\t\tstatic bool init = false;\n\t\t\tif (!init)\n\t\t\t{\n\t\t\t\t// fill the index table\n\t\t\t\tindexTable.insert(std::make_pair(rt_chain_crashing, 0));\n\t\t\t\tindexTable.insert(std::make_pair(rt_locally_started, 1));\n\t\t\t\tindexTable.insert(std::make_pair(rt_locally_stopped, 2));\n\t\t\t\tindexTable.insert(std::make_pair(rt_globally_stopped, 3));\n\t\t\t\tindexTable.insert(std::make_pair(rt_stopped_for_patch, 4));\n\t\t\t\tindexTable.insert(std::make_pair(rt_externaly_started, 5));\n\t\t\t\tindexTable.insert(std::make_pair(rt_slow_to_stop, 6));\n\t\t\t\tindexTable.insert(std::make_pair(rt_slow_to_start, 7));\n\n\t\t\t\tinit = true;\n\t\t\t}\n\n\t\t\treturn indexTable;\n\t\t}\n\n\n\t\tstatic const NLMISC::CStringConversion<TValues> &getConversionTable()\n\t\t{\n\t\t\tNL_BEGIN_STRING_CONVERSION_TABLE(TValues)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_chain_crashing)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_locally_started)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_locally_stopped)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_globally_stopped)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_stopped_for_patch)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_externaly_started)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_slow_to_stop)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(rt_slow_to_start)\n\t\t\t\tNL_STRING_CONVERSION_TABLE_ENTRY(invalid_val)\n\t\t\t};\n\t\t\tstatic NLMISC::CStringConversion<TValues>\n\t\t\tconversionTable(TValues_nl_string_conversion_table, sizeof(TValues_nl_string_conversion_table)\n\t\t\t/ sizeof(TValues_nl_string_conversion_table[0]),  invalid_val);\n\n\t\t\treturn conversionTable;\n\t\t}\n\n\t\tTValues\t_Value;\n\n\tpublic:\n\t\tTRunningTag()\n\t\t\t: _Value(invalid_val)\n\t\t{\n\t\t}\n\t\tTRunningTag(TValues value)\n\t\t\t: _Value(value)\n\t\t{\n\t\t}\n\n\t\tTRunningTag(const std::string &str)\n\t\t{\n\t\t\t_Value = getConversionTable().fromString(str);\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serialEnum(_Value);\n\t\t}\n\n\t\tbool operator == (const TRunningTag &other) const\n\t\t{\n\t\t\treturn _Value == other._Value;\n\t\t}\n\t\tbool operator != (const TRunningTag &other) const\n\t\t{\n\t\t\treturn ! (_Value == other._Value);\n\t\t}\n\t\tbool operator < (const TRunningTag &other) const\n\t\t{\n\t\t\treturn _Value < other._Value;\n\t\t}\n\n\t\tbool operator <= (const TRunningTag &other) const\n\t\t{\n\t\t\treturn _Value <= other._Value;\n\t\t}\n\n\t\tbool operator > (const TRunningTag &other) const\n\t\t{\n\t\t\treturn !(_Value <= other._Value);\n\t\t}\n\t\tbool operator >= (const TRunningTag &other) const\n\t\t{\n\t\t\treturn !(_Value < other._Value);\n\t\t}\n\n\t\tconst std::string &toString() const\n\t\t{\n\t\t\treturn getConversionTable().toString(_Value);\n\t\t}\n\t\tstatic const std::string &toString(TValues value)\n\t\t{\n\t\t\treturn getConversionTable().toString(value);\n\t\t}\n\n\t\tTValues getValue() const\n\t\t{\n\t\t\treturn _Value;\n\t\t}\n\n\t\t// return true if the actual value of the enum is valid, otherwise false\n\t\tbool isValid()\n\t\t{\n\t\t\tif (_Value == invalid_val)\n\t\t\t\treturn false;\n\n\t\t\t// not invalid, check other enum value\n\t\t\treturn getConversionTable().isValid(_Value);\n\t\t}\n\n\n\t\tuint32 asIndex()\n\t\t{\n\t\t\tstd::map<TValues, uint32>::const_iterator it(getIndexTable().find(_Value));\n\t\t\tnlassert(it != getIndexTable().end());\n\t\t\treturn it->second;\n\t\t}\n\n\t};\n\t\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass TServiceStatus\n\t{\n\tprotected:\n\t\t//\n\t\tstd::string\t_ShardName;\n\t\t//\n\t\tstd::string\t_ServiceLongName;\n\t\t//\n\t\tstd::string\t_ServiceShortName;\n\t\t//\n\t\tstd::string\t_ServiceAliasName;\n\t\t//\n\t\tTRunningState\t_RunningState;\n\t\t//\n\t\tTRunningOrders\t_RunningOrders;\n\t\t//\n\t\tstd::set < TRunningTag >\t_RunningTags;\n\t\t//\n\t\tstd::string\t_Status;\n\tpublic:\n\t\t//\n\t\tconst std::string &getShardName() const\n\t\t{\n\t\t\treturn _ShardName;\n\t\t}\n\n\t\tstd::string &getShardName()\n\t\t{\n\t\t\treturn _ShardName;\n\t\t}\n\n\n\t\tvoid setShardName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ShardName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getServiceLongName() const\n\t\t{\n\t\t\treturn _ServiceLongName;\n\t\t}\n\n\t\tstd::string &getServiceLongName()\n\t\t{\n\t\t\treturn _ServiceLongName;\n\t\t}\n\n\n\t\tvoid setServiceLongName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ServiceLongName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getServiceShortName() const\n\t\t{\n\t\t\treturn _ServiceShortName;\n\t\t}\n\n\t\tstd::string &getServiceShortName()\n\t\t{\n\t\t\treturn _ServiceShortName;\n\t\t}\n\n\n\t\tvoid setServiceShortName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ServiceShortName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getServiceAliasName() const\n\t\t{\n\t\t\treturn _ServiceAliasName;\n\t\t}\n\n\t\tstd::string &getServiceAliasName()\n\t\t{\n\t\t\treturn _ServiceAliasName;\n\t\t}\n\n\n\t\tvoid setServiceAliasName(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_ServiceAliasName = value;\n\n\n\t\t}\n\t\t\t//\n\t\tTRunningState getRunningState() const\n\t\t{\n\t\t\treturn _RunningState;\n\t\t}\n\n\t\tvoid setRunningState(TRunningState value)\n\t\t{\n\n\t\t\t\t_RunningState = value;\n\n\t\t}\n\t\t\t//\n\t\tTRunningOrders getRunningOrders() const\n\t\t{\n\t\t\treturn _RunningOrders;\n\t\t}\n\n\t\tvoid setRunningOrders(TRunningOrders value)\n\t\t{\n\n\t\t\t\t_RunningOrders = value;\n\n\t\t}\n\t\t\t//\n\t\tconst std::set < TRunningTag > &getRunningTags() const\n\t\t{\n\t\t\treturn _RunningTags;\n\t\t}\n\n\t\tstd::set < TRunningTag > &getRunningTags()\n\t\t{\n\t\t\treturn _RunningTags;\n\t\t}\n\n\n\t\tvoid setRunningTags(const std::set < TRunningTag > &value)\n\t\t{\n\n\n\t\t\t\t_RunningTags = value;\n\n\n\t\t}\n\t\t\t//\n\t\tconst std::string &getStatus() const\n\t\t{\n\t\t\treturn _Status;\n\t\t}\n\n\t\tstd::string &getStatus()\n\t\t{\n\t\t\treturn _Status;\n\t\t}\n\n\n\t\tvoid setStatus(const std::string &value)\n\t\t{\n\n\n\t\t\t\t_Status = value;\n\n\n\t\t}\n\n\t\tbool operator == (const TServiceStatus &other) const\n\t\t{\n\t\t\treturn _ShardName == other._ShardName\n\t\t\t\t&& _ServiceLongName == other._ServiceLongName\n\t\t\t\t&& _ServiceShortName == other._ServiceShortName\n\t\t\t\t&& _ServiceAliasName == other._ServiceAliasName\n\t\t\t\t&& _RunningState == other._RunningState\n\t\t\t\t&& _RunningOrders == other._RunningOrders\n\t\t\t\t&& _RunningTags == other._RunningTags\n\t\t\t\t&& _Status == other._Status;\n\t\t}\n\n\n\t\t// constructor\n\t\tTServiceStatus()\n\t\t{\n\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(_ShardName);\n\t\t\ts.serial(_ServiceLongName);\n\t\t\ts.serial(_ServiceShortName);\n\t\t\ts.serial(_ServiceAliasName);\n\t\t\ts.serial(_RunningState);\n\t\t\ts.serial(_RunningOrders);\n\t\t\ts.serialCont(_RunningTags);\n\t\t\ts.serial(_Status);\n\n\t\t}\n\n\n\tprivate:\n\n\n\t};\n\n\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminServiceSkel\n\t{\n\tpublic:\n\t\t/// the interceptor type\n\t\ttypedef NLNET::CInterceptorForwarder < CAdminServiceSkel>\tTInterceptor;\n\tprotected:\n\t\tCAdminServiceSkel()\n\t\t{\n\t\t\t// do early run time check for message table\n\t\t\tgetMessageHandlers();\n\t\t}\n\t\tvirtual ~CAdminServiceSkel()\n\t\t{\n\t\t}\n\n\t\tvoid init(NLNET::IModule *module)\n\t\t{\n\t\t\t_Interceptor.init(this, module);\n\t\t}\n\n\t\t// unused interceptors\n\t\tstd::string\t\t\tfwdBuildModuleManifest() const\t{ return std::string(); }\n\t\tvoid\t\t\t\tfwdOnModuleUp(NLNET::IModuleProxy *moduleProxy)  {}\n\t\tvoid\t\t\t\tfwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {}\n\t\tvoid\t\t\t\tfwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {}\n\n\t\t// process module message interceptor\n\t\tbool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\tprivate:\n\n\t\ttypedef void (CAdminServiceSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\t\ttypedef std::map<std::string, TMessageHandler>\tTMessageHandlerMap;\n\n\t\tconst TMessageHandlerMap &getMessageHandlers() const;\n\n\n\t\tvoid upServiceUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\t// declare one interceptor member of the skeleton\n\t\tTInterceptor\t_Interceptor;\n\n\t\t// declare the interceptor forwarder as friend of this class\n\t\tfriend \t\tclass NLNET::CInterceptorForwarder < CAdminServiceSkel>;\n\tpublic:\n\t\t/////////////////////////////////////////////////////////////////\n\t\t// WARNING : this is a generated file, don't change it !\n\t\t/////////////////////////////////////////////////////////////////\n\n\t\t// An AES send an update of the list of service up\n\t\tvirtual void upServiceUpdate(NLNET::IModuleProxy *sender, const std::vector < TServiceStatus > &serviceStatus) =0;\n\t\t// An AES send graph data update\n\t\tvirtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas) =0;\n\t\t// An AES send high rez graph data update\n\t\tvirtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) =0;\n\t\t// AES send back the result of execution of a command\n\t\tvirtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) =0;\n\n\n\t};\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminServiceProxy\n\t{\n\t\t/// Smart pointer on the module proxy\n\t\tNLNET::TModuleProxyPtr\t_ModuleProxy;\n\n\t\t// Pointer on the local module that implement the interface (if the proxy is for a local module)\n\t\tNLNET::TModulePtr\t\t\t\t\t_LocalModule;\n\t\t// Direct pointer on the server implementation interface for collocated module\n\t\tCAdminServiceSkel\t*_LocalModuleSkel;\n\n\n\tpublic:\n\t\tCAdminServiceProxy(NLNET::IModuleProxy *proxy)\n\t\t{\n\n\t\t\t_ModuleProxy = proxy;\n\n\t\t\t// initialize collocated servant interface\n\t\t\tif (proxy->getModuleDistance() == 0)\n\t\t\t{\n\t\t\t\t_LocalModule = proxy->getLocalModule();\n\t\t\t\tnlassert(_LocalModule != NULL);\n\t\t\t\tCAdminServiceSkel::TInterceptor *interceptor = NULL;\n\t\t\t\tinterceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor);\n\t\t\t\tnlassert(interceptor != NULL);\n\n\t\t\t\t_LocalModuleSkel = interceptor->getParent();\n\t\t\t\tnlassert(_LocalModuleSkel != NULL);\n\t\t\t}\n\t\t\telse\n\t\t\t\t_LocalModuleSkel = 0;\n\n\t\t}\n\t\tvirtual ~CAdminServiceProxy()\n\t\t{\n\t\t}\n\n\t\tNLNET::IModuleProxy *getModuleProxy()\n\t\t{\n\t\t\treturn _ModuleProxy;\n\t\t}\n\n\t\t// An AES send an update of the list of service up\n\t\tvoid upServiceUpdate(NLNET::IModule *sender, const std::vector < TServiceStatus > &serviceStatus);\n\t\t// An AES send graph data update\n\t\tvoid graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas);\n\t\t// An AES send high rez graph data update\n\t\tvoid highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas);\n\t\t// AES send back the result of execution of a command\n\t\tvoid commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_upServiceUpdate(NLNET::CMessage &__message, const std::vector < TServiceStatus > &serviceStatus);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result);\n\n\n\n\n\t};\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminExecutorServiceSkel\n\t{\n\tpublic:\n\t\t/// the interceptor type\n\t\ttypedef NLNET::CInterceptorForwarder < CAdminExecutorServiceSkel>\tTInterceptor;\n\tprotected:\n\t\tCAdminExecutorServiceSkel()\n\t\t{\n\t\t\t// do early run time check for message table\n\t\t\tgetMessageHandlers();\n\t\t}\n\t\tvirtual ~CAdminExecutorServiceSkel()\n\t\t{\n\t\t}\n\n\t\tvoid init(NLNET::IModule *module)\n\t\t{\n\t\t\t_Interceptor.init(this, module);\n\t\t}\n\n\t\t// unused interceptors\n\t\tstd::string\t\t\tfwdBuildModuleManifest() const\t{ return std::string(); }\n\t\tvoid\t\t\t\tfwdOnModuleUp(NLNET::IModuleProxy *moduleProxy)  {}\n\t\tvoid\t\t\t\tfwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {}\n\t\tvoid\t\t\t\tfwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {}\n\n\t\t// process module message interceptor\n\t\tbool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\tprivate:\n\n\t\ttypedef void (CAdminExecutorServiceSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\t\ttypedef std::map<std::string, TMessageHandler>\tTMessageHandlerMap;\n\n\t\tconst TMessageHandlerMap &getMessageHandlers() const;\n\n\n\t\tvoid setShardOrders_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid shutdownShard_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid controlCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid commandResult_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid graphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid highRezGraphUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid serviceStatusUpdate_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\t// declare one interceptor member of the skeleton\n\t\tTInterceptor\t_Interceptor;\n\n\t\t// declare the interceptor forwarder as friend of this class\n\t\tfriend \t\tclass NLNET::CInterceptorForwarder < CAdminExecutorServiceSkel>;\n\tpublic:\n\t\t/////////////////////////////////////////////////////////////////\n\t\t// WARNING : this is a generated file, don't change it !\n\t\t/////////////////////////////////////////////////////////////////\n\n\t\t// AS send orders for a shard\n\t\tvirtual void setShardOrders(NLNET::IModuleProxy *sender, const std::string &shardName, const TShardOrders &shardOrders) =0;\n\t\t// AS send a command to shutdown a shard with a delay\n\t\tvirtual void shutdownShard(NLNET::IModuleProxy *sender, const std::string &shardName, uint32 delay) =0;\n\t\t// AS send a control command to this AES\n\t\tvirtual void controlCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) =0;\n\t\t// Send a command to a service.\n\t\tvirtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command) =0;\n\t\t// AES client send back the result of execution of a command\n\t\tvirtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result) =0;\n\t\t// A service send graph data update\n\t\tvirtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas) =0;\n\t\t// A service high rez graph data update\n\t\tvirtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas) =0;\n\t\t// A service send an update of of it's status string\n\t\tvirtual void serviceStatusUpdate(NLNET::IModuleProxy *sender, const std::string &status) =0;\n\n\n\t};\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminExecutorServiceProxy\n\t{\n\t\t/// Smart pointer on the module proxy\n\t\tNLNET::TModuleProxyPtr\t_ModuleProxy;\n\n\t\t// Pointer on the local module that implement the interface (if the proxy is for a local module)\n\t\tNLNET::TModulePtr\t\t\t\t\t_LocalModule;\n\t\t// Direct pointer on the server implementation interface for collocated module\n\t\tCAdminExecutorServiceSkel\t*_LocalModuleSkel;\n\n\n\tpublic:\n\t\tCAdminExecutorServiceProxy(NLNET::IModuleProxy *proxy)\n\t\t{\n\n\t\t\t_ModuleProxy = proxy;\n\n\t\t\t// initialize collocated servant interface\n\t\t\tif (proxy->getModuleDistance() == 0)\n\t\t\t{\n\t\t\t\t_LocalModule = proxy->getLocalModule();\n\t\t\t\tnlassert(_LocalModule != NULL);\n\t\t\t\tCAdminExecutorServiceSkel::TInterceptor *interceptor = NULL;\n\t\t\t\tinterceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor);\n\t\t\t\tnlassert(interceptor != NULL);\n\n\t\t\t\t_LocalModuleSkel = interceptor->getParent();\n\t\t\t\tnlassert(_LocalModuleSkel != NULL);\n\t\t\t}\n\t\t\telse\n\t\t\t\t_LocalModuleSkel = 0;\n\n\t\t}\n\t\tvirtual ~CAdminExecutorServiceProxy()\n\t\t{\n\t\t}\n\n\t\tNLNET::IModuleProxy *getModuleProxy()\n\t\t{\n\t\t\treturn _ModuleProxy;\n\t\t}\n\n\t\t// AS send orders for a shard\n\t\tvoid setShardOrders(NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders);\n\t\t// AS send a command to shutdown a shard with a delay\n\t\tvoid shutdownShard(NLNET::IModule *sender, const std::string &shardName, uint32 delay);\n\t\t// AS send a control command to this AES\n\t\tvoid controlCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command);\n\t\t// Send a command to a service.\n\t\tvoid serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command);\n\t\t// AES client send back the result of execution of a command\n\t\tvoid commandResult(NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result);\n\t\t// A service send graph data update\n\t\tvoid graphUpdate(NLNET::IModule *sender, const TGraphDatas &graphDatas);\n\t\t// A service high rez graph data update\n\t\tvoid highRezGraphUpdate(NLNET::IModule *sender, const THighRezDatas &graphDatas);\n\t\t// A service send an update of of it's status string\n\t\tvoid serviceStatusUpdate(NLNET::IModule *sender, const std::string &status);\n\t\t// AS send orders for a shard\n\n\t\t// This is the broadcast version of the method.\n\t\ttemplate < class ProxyIterator >\n\t\tstatic void broadcast_setShardOrders(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, const std::string &shardName, const TShardOrders &shardOrders)\n\t\t{\n\t\t\tNLNET::CMessage message;\n\n\t\t\t// create the message to send to multiple dest\n\t\t\tbuildMessageFor_setShardOrders(message , shardName, shardOrders);\n\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNLNET::IModuleProxy *proxy = *first;\n\n\t\t\t\tproxy->sendModuleMessage(sender, message);\n\t\t\t}\n\n\t\t}\n\t\t// AS send a command to shutdown a shard with a delay\n\n\t\t// This is the broadcast version of the method.\n\t\ttemplate < class ProxyIterator >\n\t\tstatic void broadcast_shutdownShard(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, const std::string &shardName, uint32 delay)\n\t\t{\n\t\t\tNLNET::CMessage message;\n\n\t\t\t// create the message to send to multiple dest\n\t\t\tbuildMessageFor_shutdownShard(message , shardName, delay);\n\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNLNET::IModuleProxy *proxy = *first;\n\n\t\t\t\tproxy->sendModuleMessage(sender, message);\n\t\t\t}\n\n\t\t}\n\t\t// AS send a control command to this AES\n\n\t\t// This is the broadcast version of the method.\n\t\ttemplate < class ProxyIterator >\n\t\tstatic void broadcast_controlCmd(ProxyIterator first, ProxyIterator last, NLNET::IModule *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t\t{\n\t\t\tNLNET::CMessage message;\n\n\t\t\t// create the message to send to multiple dest\n\t\t\tbuildMessageFor_controlCmd(message , commandId, serviceAlias, command);\n\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNLNET::IModuleProxy *proxy = *first;\n\n\t\t\t\tproxy->sendModuleMessage(sender, message);\n\t\t\t}\n\n\t\t}\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_setShardOrders(NLNET::CMessage &__message, const std::string &shardName, const TShardOrders &shardOrders);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_shutdownShard(NLNET::CMessage &__message, const std::string &shardName, uint32 delay);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_controlCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &command);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_commandResult(NLNET::CMessage &__message, uint32 commandId, const std::string &serviceAlias, const std::string &result);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_graphUpdate(NLNET::CMessage &__message, const TGraphDatas &graphDatas);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_highRezGraphUpdate(NLNET::CMessage &__message, const THighRezDatas &graphDatas);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_serviceStatusUpdate(NLNET::CMessage &__message, const std::string &status);\n\n\n\n\n\t};\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminExecutorServiceClientSkel\n\t{\n\tpublic:\n\t\t/// the interceptor type\n\t\ttypedef NLNET::CInterceptorForwarder < CAdminExecutorServiceClientSkel>\tTInterceptor;\n\tprotected:\n\t\tCAdminExecutorServiceClientSkel()\n\t\t{\n\t\t\t// do early run time check for message table\n\t\t\tgetMessageHandlers();\n\t\t}\n\t\tvirtual ~CAdminExecutorServiceClientSkel()\n\t\t{\n\t\t}\n\n\t\tvoid init(NLNET::IModule *module)\n\t\t{\n\t\t\t_Interceptor.init(this, module);\n\t\t}\n\n\t\t// unused interceptors\n\t\tstd::string\t\t\tfwdBuildModuleManifest() const\t{ return std::string(); }\n\t\tvoid\t\t\t\tfwdOnModuleUp(NLNET::IModuleProxy *moduleProxy)  {}\n\t\tvoid\t\t\t\tfwdOnModuleDown(NLNET::IModuleProxy *moduleProxy) {}\n\t\tvoid\t\t\t\tfwdOnModuleSecurityChange(NLNET::IModuleProxy *moduleProxy) {}\n\n\t\t// process module message interceptor\n\t\tbool fwdOnProcessModuleMessage(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\tprivate:\n\n\t\ttypedef void (CAdminExecutorServiceClientSkel::*TMessageHandler)(NLNET::IModuleProxy *sender, const NLNET::CMessage &message);\n\t\ttypedef std::map<std::string, TMessageHandler>\tTMessageHandlerMap;\n\n\t\tconst TMessageHandlerMap &getMessageHandlers() const;\n\n\n\t\tvoid serviceCmd_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\tvoid serviceCmdNoReturn_skel(NLNET::IModuleProxy *sender, const NLNET::CMessage &__message);\n\n\t\t// declare one interceptor member of the skeleton\n\t\tTInterceptor\t_Interceptor;\n\n\t\t// declare the interceptor forwarder as friend of this class\n\t\tfriend \t\tclass NLNET::CInterceptorForwarder < CAdminExecutorServiceClientSkel>;\n\tpublic:\n\t\t/////////////////////////////////////////////////////////////////\n\t\t// WARNING : this is a generated file, don't change it !\n\t\t/////////////////////////////////////////////////////////////////\n\n\t\t// execute a command and return the result.\n\t\tvirtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &command) =0;\n\t\t// Send a command to a service without waiting for the return value.\n\t\tvirtual void serviceCmdNoReturn(NLNET::IModuleProxy *sender, const std::string &command) =0;\n\n\n\t};\n\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\tclass CAdminExecutorServiceClientProxy\n\t{\n\t\t/// Smart pointer on the module proxy\n\t\tNLNET::TModuleProxyPtr\t_ModuleProxy;\n\n\t\t// Pointer on the local module that implement the interface (if the proxy is for a local module)\n\t\tNLNET::TModulePtr\t\t\t\t\t_LocalModule;\n\t\t// Direct pointer on the server implementation interface for collocated module\n\t\tCAdminExecutorServiceClientSkel\t*_LocalModuleSkel;\n\n\n\tpublic:\n\t\tCAdminExecutorServiceClientProxy(NLNET::IModuleProxy *proxy)\n\t\t{\n\n\t\t\t_ModuleProxy = proxy;\n\n\t\t\t// initialize collocated servant interface\n\t\t\tif (proxy->getModuleDistance() == 0)\n\t\t\t{\n\t\t\t\t_LocalModule = proxy->getLocalModule();\n\t\t\t\tnlassert(_LocalModule != NULL);\n\t\t\t\tCAdminExecutorServiceClientSkel::TInterceptor *interceptor = NULL;\n\t\t\t\tinterceptor = static_cast < NLNET::CModuleBase* >(_LocalModule.getPtr())->getInterceptor(interceptor);\n\t\t\t\tnlassert(interceptor != NULL);\n\n\t\t\t\t_LocalModuleSkel = interceptor->getParent();\n\t\t\t\tnlassert(_LocalModuleSkel != NULL);\n\t\t\t}\n\t\t\telse\n\t\t\t\t_LocalModuleSkel = 0;\n\n\t\t}\n\t\tvirtual ~CAdminExecutorServiceClientProxy()\n\t\t{\n\t\t}\n\n\t\tNLNET::IModuleProxy *getModuleProxy()\n\t\t{\n\t\t\treturn _ModuleProxy;\n\t\t}\n\n\t\t// execute a command and return the result.\n\t\tvoid serviceCmd(NLNET::IModule *sender, uint32 commandId, const std::string &command);\n\t\t// Send a command to a service without waiting for the return value.\n\t\tvoid serviceCmdNoReturn(NLNET::IModule *sender, const std::string &command);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_serviceCmd(NLNET::CMessage &__message, uint32 commandId, const std::string &command);\n\n\t\t// Message serializer. Return the message received in reference for easier integration\n\t\tstatic const NLNET::CMessage &buildMessageFor_serviceCmdNoReturn(NLNET::CMessage &__message, const std::string &command);\n\n\n\n\n\t};\n\n}\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/admin_modules/admin_modules_itf.xml",
    "content": "<generator header_tag=\"ADMIN_MODULES_ITF\">\n\t\n\t<include file=\"nel/misc/time_nl.h\"/>\n\n\t<namespace name=\"ADMIN\">\n\n\t\t<!-- PHP interface of the admin service module-->\n\t\t<!-- ############################################################## -->\n\t\t<callback_interface name=\"CAdminServiceWeb\" caller=\"php\">\n\t\t\t<doc line=\"This is the interface used by PHP to call methods\"/>\n\t\t\t<doc line=\"on the Admin service module\"/>\n\t\t\t\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- globalCmd -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"globalCmd\" msg=\"GCMD\">\n\t\t\t\t<doc line=\"Send a command to the AS.\"/>\n\t\t\t\t<doc line=\"This is used to issue global commands like 'as.allStart' or 'as.allStop'.\"/>\n\t\t\t\t<doc line=\"The result is returned by the return message\"/>\n\t\t\t\t<doc line=\"serviceCmdResult.\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t</invoke>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- controlCmd -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"controlCmd\" msg=\"CCMD\">\n\t\t\t\t<doc line=\"Send a service related command to the executor \"/>\n\t\t\t\t<doc line=\"(not to the controled service)\"/>\n\t\t\t\t<doc line=\"The result is returned by the return message\"/>\n\t\t\t\t<doc line=\"controlCmdResult.\"/>\n\n\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t</invoke>\n\t\t\t\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- serviceCmd -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"serviceCmd\" msg=\"SCMD\">\n\t\t\t\t<doc line=\"Send a command to a service.\"/>\n\t\t\t\t<doc line=\"The result is returned by the return message\"/>\n\t\t\t\t<doc line=\"serviceCmdResult.\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t</invoke>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- commandResult -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t\t<return name=\"commandResult\" msg=\"CMDR\">\n\t\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t\t\t<param type=\"std::string\"\tname=\"result\" php_serial=\"String\" byref=\"true\"/>\n\t\t\t\t</return>\n\t\t\t\n\t\t\t\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- getShardOrders -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"getShardOrders\" msg=\"GSO\">\n\t\t\t\t<doc line=\"Get the orders of each known shard.\"/>\n\t\t\t\t<doc line=\"The return value is a vector of string, one entry by shard\"/>\n\n\t\t\t\t<return type=\"std::string\"\tphp_serial=\"String\" array=\"true\"/>\n\n\t\t\t</invoke>\n\t\t\t\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- getStates -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"getStates\" msg=\"GS\">\n\t\t\t\t<doc line=\"Get the last known state of all services.\"/>\n\t\t\t\t<doc line=\"The return value is a vector of string, one entry by service\"/>\n\n\t\t\t\t<return type=\"std::string\"\tphp_serial=\"String\" array=\"true\"/>\n\n\t\t\t</invoke>\n\t\t\t\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- getHighRezGraphInfo -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"getHighRezGraphInfo\" msg=\"GHRGI\">\n\t\t\t\t<doc line=\"Get information about a high rez graph.\"/>\n\t\t\t\t<doc line=\"The return is a string array containing\"/>\n\t\t\t\t<doc line=\"the name of the var, the available sample\"/>\n\t\t\t\t<doc line=\"period as two unix date (start dans end)\"/>\n\t\t\t\t<doc line=\"and the number of samples available\"/>\n\t\t\t\t<doc line=\"If the var is not found, an empty array is returned\"/>\n\n\n\t\t\t\t<return type=\"std::string\" php_serial=\"String\"\tarray=\"true\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"varAddr\" php_serial=\"String\" byref=\"true\"/>\n\n\t\t\t</invoke>\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- getHighRezGraph -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<invoke name=\"getHighRezGraph\" msg=\"GHRG\">\n\t\t\t\t<doc line=\"Get the data for a high resolution graph.\"/>\n\t\t\t\t<doc line=\"The return is a string array, each\"/>\n\t\t\t\t<doc line=\"string containing 'time:milliOffset:value\"/>\n\t\t\t\t<doc line=\"Set endDate to 0 to specify a start date relative\"/>\n\t\t\t\t<doc line=\"to the last sample date. In this case, start date\"/>\n\t\t\t\t<doc line=\"is interpreted as the number of second before\"/>\n\t\t\t\t<doc line=\"the last sample.\"/>\n\n\t\t\t\t<return type=\"std::string\" php_serial=\"String\"\tarray=\"true\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"varAddr\" php_serial=\"String\" byref=\"true\"/>\n\t\t\t\t<param type=\"uint32\"\t\tname=\"startDate\" />\n\t\t\t\t<param type=\"uint32\"\t\tname=\"endDate\" />\n\t\t\t\t<param type=\"uint32\"\t\tname=\"milliStep\" />\n\n\t\t\t</invoke>\n\t\t\t\n\t\t</callback_interface>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Item data for graph -->\n\t\t<!-- ############################################################## -->\n\t\t<class name=\"TGraphData\">\n\t\t\t<serial/>\n\n\t\t\t<property\ttype=\"std::string\"\tname=\"ServiceAlias\"\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"VarName\"\t\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"uint32\"\t\tname=\"SamplePeriod\"/>\n\t\t\t<property\ttype=\"double\"\t\tname=\"Value\"/>\n\t\t</class>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Group of data for graph -->\n\t\t<!-- ############################################################## -->\n\t\t<class name=\"TGraphDatas\">\n\t\t\t<serial/>\n\n\t\t\t<property\ttype=\"uint32\"\tname=\"CurrentTime\"/>\n\t\t\t<property\ttype=\"std::vector &lt; TGraphData &gt;\"\tname=\"Datas\" byref=\"true\" serial=\"Cont\"/>\n\t\t</class>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Item data for high rez graph -->\n\t\t<!-- ############################################################## -->\n\t\t<class name=\"THighRezData\">\n\t\t\t<serial/>\n\n\t\t\t<property\ttype=\"NLMISC::TTime\"\tname=\"SampleTick\"/>\n\t\t\t<property\ttype=\"double\"\t\t\tname=\"Value\"/>\n\t\t</class>\n\t\t<!-- ############################################################## -->\n\t\t<!-- Group of data for high rez graph -->\n\t\t<!-- ############################################################## -->\n\t\t<class name=\"THighRezDatas\">\n\t\t\t<serial/>\n\n\t\t\t<property\ttype=\"std::string\"\tname=\"ServiceAlias\"\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"VarName\"\t\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"uint32\"\t\tname=\"CurrentTime\"/>\n\n\t\t\t<property\ttype=\"std::vector &lt; THighRezData &gt;\"\tname=\"Datas\" byref=\"true\" serial=\"Cont\"/>\n\t\t</class>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Shard orders enum -->\n\t\t<!-- ############################################################## -->\n\t\t<enum name=\"TShardOrders\">\n\t\t\t<item name=\"so_autostart_on\"/>\n\t\t\t<item name=\"so_autostart_off\"/>\n\t\t</enum>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Service orders enum -->\n\t\t<!-- ############################################################## -->\n\t\t<enum name=\"TRunningOrders\">\n\t\t\t<item name=\"ro_deactivated\"/>\n\t\t\t<item name=\"ro_activated\"/>\n\t\t</enum>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Service running state enum-->\n\t\t<!-- ############################################################## -->\n\t\t<enum name=\"TRunningState\">\n\t\t\t<item name=\"rs_stopped\"/>\n\t\t\t<item name=\"rs_running\"/>\n\t\t\t<item name=\"rs_online\"/>\n<!--\t\t\t<item name=\"rs_stopped\"/>\n\t\t\t<item name=\"rs_starting\"/>\n-->\n<!--\t\t\t<item name=\"rs_connected\"/>-->\n<!--\t\t\t<item name=\"rs_online\"/>\n\t\t\t<item name=\"rs_stopping\"/>\n-->\t\t</enum>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Service running tag -->\n\t\t<!-- ############################################################## -->\n\t\t<enum name=\"TRunningTag\">\n\t\t\t<item name=\"rt_chain_crashing\"/>\n\t\t\t<item name=\"rt_locally_started\"/>\n\t\t\t<item name=\"rt_locally_stopped\"/>\n\t\t\t<item name=\"rt_globally_stopped\"/>\n\t\t\t<item name=\"rt_stopped_for_patch\"/>\n\t\t\t<item name=\"rt_externaly_started\"/>\n\t\t\t<item name=\"rt_slow_to_stop\"/>\n\t\t\t<item name=\"rt_slow_to_start\"/>\n\t\t</enum>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Service status -->\n\t\t<!-- ############################################################## -->\n\t\t<class name=\"TServiceStatus\">\n\t\t\t<serial/>\n\n\t\t\t<property\ttype=\"std::string\"\tname=\"ShardName\"\t\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"ServiceLongName\"\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"ServiceShortName\"\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"ServiceAliasName\"\tbyref=\"true\"/>\n\t\t\t<property\ttype=\"TRunningState\"\tname=\"RunningState\"\tenum=\"smart\"/>\n\t\t\t<property\ttype=\"TRunningOrders\"\tname=\"RunningOrders\"\tenum=\"smart\"/>\n\t\t\t<property\ttype=\"std::set &lt; TRunningTag &gt;\"\tname=\"RunningTags\"\tserial=\"Cont\" enum=\"smart\" byref=\"true\"/>\n\t\t\t<property\ttype=\"std::string\"\tname=\"Status\"\t\t\tbyref=\"true\"/>\n\t\t</class>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Module interface of the admin service module-->\n\t\t<!-- ############################################################## -->\n\t\t<module_interface name=\"CAdminService\">\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- up service update -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"upServiceUpdate\" msg=\"USU\">\n\t\t\t\t<doc line=\"An AES send an update of the list of service up\"/>\n\n\t\t\t\t<param type=\"std::vector &lt; TServiceStatus &gt;\"\tname=\"serviceStatus\"\tbyref=\"true\" serial=\"Cont\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- graphUpdate -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"graphUpdate\" msg=\"GU\">\n\t\t\t\t<doc line=\"An AES send graph data update\"/>\n\n\t\t\t\t<param type=\"TGraphDatas\"\t\t\tname=\"graphDatas\"\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- HR graphUpdate -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"highRezGraphUpdate\" msg=\"HRGU\">\n\t\t\t\t<doc line=\"An AES send high rez graph data update\"/>\n\n\t\t\t\t<param type=\"THighRezDatas\"\t\t\tname=\"graphDatas\"\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- updateAESStates -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n<!--\t\t\t<method name=\"updateAESStates\" msg=\"UAS\">\n\t\t\t\t<doc line=\"An AES send it's updated state strings\"/>\n\n\t\t\t\t<param type=\"std::vector &lt; std::string &gt;\"\tname=\"states\"\tbyref=\"true\" serial=\"Cont\"/>\n\t\t\t</method>\n-->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- aes return command result -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"commandResult\" msg=\"CR\">\n\t\t\t\t<doc line=\"AES send back the result of execution of a command\"/>\n\n\t\t\t\t<param type=\"uint32\"\t\tname=\"commandId\" />\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\t\tbyref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"result\"\t\t\tbyref=\"true\"/>\n\t\t\t</method>\n\t\t</module_interface>\n\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Module interface of the admin executor service module-->\n\t\t<!-- ############################################################## -->\n\t\t<module_interface name=\"CAdminExecutorService\">\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- global state from AS -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n<!--\t\t\t<method name=\"setGlobalOrders\" msg=\"SGO\" broadcast=\"true\">\n\t\t\t\t<doc line=\"AS send it's global running orders\"/>\n\n\t\t\t\t<param type=\"TRunningOrders\"\tname=\"globalOrders\" enum=\"smart\"/>\n\t\t\t</method>\n-->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- shard state from AS -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"setShardOrders\" msg=\"SCO\" broadcast=\"true\">\n\t\t\t\t<doc line=\"AS send orders for a shard\"/>\n\n\t\t\t\t<param type=\"std::string\"\t\tname=\"shardName\"\t\tbyref=\"true\"/>\n\t\t\t\t<param type=\"TShardOrders\"\tname=\"shardOrders\" enum=\"smart\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- shutdown shard from AS -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"shutdownShard\" msg=\"SDS\" broadcast=\"true\">\n\t\t\t\t<doc line=\"AS send a command to shutdown a shard with a delay\"/>\n\n\t\t\t\t<param type=\"std::string\"\t\tname=\"shardName\"\t\tbyref=\"true\"/>\n\t\t\t\t<param type=\"uint32\"\t\t\tname=\"delay\"/>\n\t\t\t</method>\n\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- controlCmd -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"controlCmd\" msg=\"CC\" broadcast=\"true\">\n\t\t\t\t<doc line=\"AS send a control command to this AES\"/>\n\n\t\t\t\t<param type=\"uint32\"\t\tname=\"commandId\" />\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\tbyref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- service command -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"serviceCmd\" msg=\"SCMD\">\n\t\t\t\t<doc line=\"Send a command to a service.\"/>\n\n\t\t\t\t<param type=\"uint32\"\t\tname=\"commandId\" />\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tphp_serial=\"String\" byref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- aes client return command result -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"commandResult\" msg=\"CR\">\n\t\t\t\t<doc line=\"AES client send back the result of execution of a command\"/>\n\n\t\t\t\t<param type=\"uint32\"\t\tname=\"commandId\" />\n\t\t\t\t<param type=\"std::string\"\tname=\"serviceAlias\"\t\tbyref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"result\"\t\t\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- graphUpdate -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"graphUpdate\" msg=\"GU\">\n\t\t\t\t<doc line=\"A service send graph data update\"/>\n\n\t\t\t\t<param type=\"TGraphDatas\"\t\t\tname=\"graphDatas\"\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- HR graphUpdate -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"highRezGraphUpdate\" msg=\"HRGU\">\n\t\t\t\t<doc line=\"A service high rez graph data update\"/>\n\n\t\t\t\t<param type=\"THighRezDatas\"\t\t\tname=\"graphDatas\"\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- serviceConnected-->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n<!--\t\t\t<method name=\"serviceConnected\" msg=\"SR\">\n\t\t\t\t<doc line=\"A service inform the AES that it is connected\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"longName\"\t\tbyref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"shortName\"\tbyref=\"true\"/>\n\t\t\t\t<param type=\"std::string\"\tname=\"aliasName\"\tbyref=\"true\"/>\n\t\t\t\t<param type=\"uint32\"\t\tname=\"pid\"/>\n\t\t\t</method>\n-->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- service status update -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"serviceStatusUpdate\" msg=\"SSU\">\n\t\t\t\t<doc line=\"A service send an update of of it's status string\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"status\"\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t</module_interface>\n\n\t\t<!-- ############################################################## -->\n\t\t<!-- Module interface of the admin executor service client module-->\n\t\t<!-- ############################################################## -->\n\t\t<module_interface name=\"CAdminExecutorServiceClient\">\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- service command -->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"serviceCmd\" msg=\"SCMD\">\n\t\t\t\t<doc line=\"execute a command and return the result.\"/>\n\n\t\t\t\t<param type=\"uint32\"\t\tname=\"commandId\" />\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tbyref=\"true\"/>\n\t\t\t</method>\n\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<!-- service command (one way)-->\n\t\t\t<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->\n\t\t\t<method name=\"serviceCmdNoReturn\" msg=\"SCMDNR\">\n\t\t\t\t<doc line=\"Send a command to a service without waiting for the return value.\"/>\n\n\t\t\t\t<param type=\"std::string\"\tname=\"command\"\t\tbyref=\"true\"/>\n\t\t\t</method>\n\n\n\t\t</module_interface>\n\t</namespace>\n</generator>\n"
  },
  {
    "path": "code/EVA/server/admin_modules/aes_client_module.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/misc/singleton.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_builder_parts.h\"\n#include \"nel/net/unified_network.h\"\n#include \"nel/net/service.h\"\n\n#include \"admin_modules_itf.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nvoid aesclient_forceLink() {}\n\nnamespace ADMIN\n{\n\tclass CAdminExecutorServiceClient \n\t\t:\t/*public CManualSingleton<CAdminExecutorService>,*/\n\t\t\tpublic CEmptyModuleServiceBehav<CEmptyModuleCommBehav<CEmptySocketBehav<CModuleBase> > >,\n\t\t\tpublic CAdminExecutorServiceClientSkel\n\t{\n\n\t\tenum\n\t\t{\n\t\t\t// Maximum time without sending report string (a kind of 'keep alive')\n\t\t\tMAX_DELAY_BETWEEN_REPORT = 30,\t// 30 seconds\n\t\t};\n\n\t\t/// Flag to inform AES that we don't want to be affected by shard orders\n\t\tbool\t\t\t\t_DontUseShardOrders;\n\n\t\t/// Admin executor service module\n\t\tTModuleProxyPtr\t\t_AdminExecutorService;\n\n\t\t/// Date of last state reporting to AES\n\t\tuint32\t\t\t\t_LastStateReport;\n\n\t\t/// Last date of status string update\n\t\tuint32\t\t\t\t_LastStatusStringReport;\n\t\t/// Last status string sent (to avoid double send)\n\t\tstring\t\t\t\t_LastSentStatus;\n\n\t\t/// The service alias (must be an unique name)\n\t\tstring\t\t\t\t_ServiceAlias;\n\n\t\t/// A cache of the value because reading it is very slow\n\t\tuint32\t\t\t\t_ProcessUsedMemory;\n\n\t\tstruct TGraphSample\n\t\t{\n\t\t\t// The date of the sample (in second)\n\t\t\tuint32\tTimeStamp;\n\t\t\t// The date of the sample (in ms)\n\t\t\tTTime\tHighRezTimeStamp;\n\t\t\t// sample value\n\t\t\tdouble\tSampleValue;\n\t\t};\n\t\tstruct TGraphVarInfo\n\t\t{\n\t\t\t/// Name of the graphed var\n\t\t\tstring\tVarName;\n\t\t\t/** Mean time between two sample in ms\n\t\t\t *\t(in fact, if will be the min period)\n\t\t\t *\tSet it to 1 to have a sample at each tick\n\t\t\t *\tIf the period is set less than 1000 ms,\n\t\t\t *\tthen the var is considered 'high rez'.\n\t\t\t *\tOtherwise, the period is rounded at the\n\t\t\t *\tnearest integer second.\n\t\t\t *\tFor 'high rez' var, the service buffer\n\t\t\t *\tthe relative timestamp in ms at each\n\t\t\t *\ttick loop and send update every seconds \n\t\t\t *\tto the AES service.\n\t\t\t *\tIn addition, HighRez var are also sent \n\t\t\t *\tevery second as normal sample.\n\t\t\t */\n\t\t\tuint32\tMeanSamplePeriod;\n\n\t\t\t/// Date of last sample (low rez)\n\t\t\tuint32\tLastSampleTimeStamp;\n\t\t\t/// Date of last sample (high rez)\n\t\t\tTTime\tLastHighRezTimeStamp;\n\n\t\t\t/// The vector of buffered samples\n\t\t\tvector<TGraphSample>\tSamples;\n\n\t\t\tTGraphVarInfo()\n\t\t\t\t:\tMeanSamplePeriod(1000),\n\t\t\t\t\tLastSampleTimeStamp(0),\n\t\t\t\t\tLastHighRezTimeStamp(0)\n\t\t\t{\n\t\t\t}\n\t\t};\n\n\t\t/// The list of variable to graph (build from service config file var 'GraphVars')\n\t\tvector<TGraphVarInfo>\t_GraphVars;\n\n\t\t/// Date of last graph\n\n\tpublic:\n\n\t\tCAdminExecutorServiceClient()\n\t\t\t:\t_DontUseShardOrders(false),\n\t\t\t\t_LastStateReport(0),\n\t\t\t\t_LastStatusStringReport(0),\n\t\t\t\t_ProcessUsedMemory(0)\n\t\t{\n\t\t\tCAdminExecutorServiceClientSkel::init(this);\n\n\t\t}\n\n\t\tstd::string makeServiceAlias()\n\t\t{\n\t\t\tstring serviceAlias = IService::getInstance()->getServiceAliasName();\n\t\t\tif (serviceAlias.empty())\n\t\t\t{\n\t\t\t\tserviceAlias = IService::getInstance()->getHostName()+\".\"+IService::getInstance()->getServiceUnifiedName();\n\t\t\t}\n\t\t\treturn serviceAlias;\n\t\t}\n\n\t\tstring getModuleManifest() const\n\t\t{\n\t\t\tuint32 pid = getpid ();\n\n\t\t\tstring serviceAlias = _ServiceAlias;\n\n\t\t\tCSString manifest;\n\n\t\t\tmanifest << \"LongName=\" << IService::getInstance()->getServiceLongName()\n\t\t\t\t<< \" ShortName=\" << IService::getInstance()->getServiceShortName()\n\t\t\t\t<< \" AliasName=\" << serviceAlias\n\t\t\t\t<< \" PID=\" << pid\n\t\t\t\t<< \" DontUseShardOrders=\" << _DontUseShardOrders;\n\n\t\t\treturn manifest;\n\t\t}\n\n\t\tbool initModule(const TParsedCommandLine &pcl)\n\t\t{\n\t\t\tif (!CModuleBase::initModule(pcl))\n\t\t\t\treturn false;\n\n\t\t\t// try to read the config file\n\t\t\tIService *service = IService::getInstance();\n\t\t\tif (service == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"Failed to get the IService singleton instance\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tCConfigFile::CVar *gv = service->ConfigFile.getVarPtr(\"GraphVars\");\n\t\t\tif (gv)\n\t\t\t{\n\t\t\t\t_GraphVars.clear();\n\t\t\t\tfor (uint i =0; i<gv->size()/2; ++i)\n\t\t\t\t{\n\t\t\t\t\tTGraphVarInfo gvi;\n\n\t\t\t\t\tgvi.VarName = gv->asString(i*2);\n\t\t\t\t\tgvi.MeanSamplePeriod = max(1, gv->asInt((i*2)+1));\n\n\t\t\t\t\t_GraphVars.push_back(gvi);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// precompute the service name\n\t\t\t_ServiceAlias = makeServiceAlias();\n\n\t\t\t// loop for an optional 'dontUseShardOrders' flag in init params\n\t\t\tconst TParsedCommandLine *duso = pcl.getParam(\"dontUseShardOrders\");\n\t\t\tif (duso != NULL)\n\t\t\t\t_DontUseShardOrders = (duso->ParamValue == \"true\" || duso->ParamName == \"1\");\n\n\t\t\treturn true;\n\t\t}\n\n\n\t\tvoid onModuleUp(IModuleProxy *proxy)\n\t\t{\n\t\t\tif (proxy->getModuleClassName() == \"AdminExecutorService\")\n\t\t\t{\n\t\t\t\tnldebug(\"CAdminExecutorServiceClient : admin executor service up as '%s'\", proxy->getModuleName().c_str());\n\t\t\t\t// we found the manager of AES\n\t\t\t\tif (_AdminExecutorService != NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"CAdminExecutorServiceClient : admin executor service already known as '%s', replacing with new one\", _AdminExecutorService->getModuleName().c_str());\n\t\t\t\t}\n\t\t\t\t_AdminExecutorService = proxy;\n\n//\t\t\t\t// send basic service info to AES\n//\t\t\t\tCAdminExecutorServiceProxy aes(proxy);\n//\n//\t\t\t\tuint32 pid = getpid ();\n//\n//\t\t\t\tstring serviceAlias = IService::getInstance()->getServiceAliasName();\n//\t\t\t\tif (serviceAlias.empty())\n//\t\t\t\t\tserviceAlias = getModuleFullyQualifiedName();\n//\n//\t\t\t\taes.serviceConnected(this, \n//\t\t\t\t\tIService::getInstance()->getServiceLongName(), \n//\t\t\t\t\tIService::getInstance()->getServiceShortName(),\n//\t\t\t\t\tserviceAlias,\n//\t\t\t\t\tpid);\n\t\t\t\t// for resend of the current status to the new AES\n\t\t\t\t_LastSentStatus = \"\";\n\t\t\t\tsendServiceStatus();\n\t\t\t}\n\t\t}\n\n\t\tvoid onModuleDown(IModuleProxy *proxy)\n\t\t{\n\t\t\tif (proxy == _AdminExecutorService)\n\t\t\t{\n\t\t\t\tnldebug(\"CAdminExecutorServiceClient : admin executor service '%s' is down\", proxy->getModuleName().c_str());\n\n\t\t\t\t_AdminExecutorService = NULL;\n\t\t\t}\n\t\t}\n\n\t\tvoid onModuleUpdate()\n\t\t{\n\t\t\tH_AUTO(CAdminExecutorServiceClient_onModuleUpdate);\n\n\t\t\tuint32 now = CTime::getSecondsSince1970();\n\t\t\tTTime timer = CTime::getLocalTime();\n\n\t\t\t// update every HR variables\n\t\t\tfor (uint i=0; i<_GraphVars.size(); ++i)\n\t\t\t{\n\t\t\t\tif (_GraphVars[i].MeanSamplePeriod < 1000)\n\t\t\t\t{\n\t\t\t\t\t// this is a HR var\n\t\t\t\t\tTGraphVarInfo &gvi = _GraphVars[i];\n\t\t\t\t\tif (gvi.LastHighRezTimeStamp + gvi.MeanSamplePeriod < timer)\n\t\t\t\t\t{\n\t\t\t\t\t\t// it's time to get a sample\n\t\t\t\t\t\t// create a sample\n\t\t\t\t\t\tgvi.Samples.push_back(TGraphSample());\n\t\t\t\t\t\tTGraphSample &gs = gvi.Samples.back();\n\t\t\t\t\t\t// inialise it\n\t\t\t\t\t\tgs.TimeStamp = now;\n\t\t\t\t\t\tgs.HighRezTimeStamp = timer;\n\t\t\t\t\t\tIVariable *var = dynamic_cast<IVariable*>(ICommand::getCommand(gvi.VarName));\n\t\t\t\t\t\tif (var != NULL)\n\t\t\t\t\t\t\tgs.SampleValue = atof(var->toString().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (_LastStateReport != now)\n\t\t\t{\n\n\t\t\t\tif ((now & 0xf) == 0)\n\t\t\t\t{\n\t\t\t\t\t// every 16 seconds because very slow\n\t\t\t\t\tIVariable *var = dynamic_cast<IVariable*>(ICommand::getCommand(\"ProcessUsedMemory\"));\n\t\t\t\t\tif (var != NULL)\n\t\t\t\t\t\tNLMISC::fromString(var->toString(), _ProcessUsedMemory);\n\t\t\t\t}\n\n\t\t\t\t// at least one second as passed, check for updates to send to \n\t\t\t\t// AES\n\n\t\t\t\tTGraphDatas\tgraphDatas;\n\t\t\t\tgraphDatas.setCurrentTime(now);\n\n\t\t\t\tTHighRezDatas highRezDatas;\n\t\t\t\thighRezDatas.setServiceAlias(_ServiceAlias);\n\t\t\t\thighRezDatas.setCurrentTime(now);\n\n\t\t\t\tvector<TGraphData>\t&datas = graphDatas.getDatas();\n\n\t\t\t\tfor (uint i=0; i<_GraphVars.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tif (_GraphVars[i].LastSampleTimeStamp+(_GraphVars[i].MeanSamplePeriod/1000) < now)\n\t\t\t\t\t{\n\t\t\t\t\t\tTGraphVarInfo &gvi = _GraphVars[i];\n\t\t\t\t\t\t// it's time to send update for this var\n\t\t\t\t\t\t// create a new sample entry\n\t\t\t\t\t\tdatas.push_back(TGraphData());\n\t\t\t\t\t\t// and fill it\n\t\t\t\t\t\tTGraphData &gd = datas.back();\n\t\t\t\t\t\tgd.setServiceAlias(_ServiceAlias);\n\t\t\t\t\t\tgd.setVarName(gvi.VarName);\n\t\t\t\t\t\tgd.setSamplePeriod(max(uint32(1), uint32(gvi.MeanSamplePeriod/1000)));\n\t\t\t\t\t\tif (gvi.Samples.empty())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// no sample collected yet, just ask a new one\n\t\t\t\t\t\t\tIVariable *var = dynamic_cast<IVariable*>(ICommand::getCommand(gvi.VarName));\n\t\t\t\t\t\t\tif (var != NULL)\n\t\t\t\t\t\t\t\tgd.setValue(atof(var->toString().c_str()));\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have some sample collected, just use the last one\n\t\t\t\t\t\t\tgd.setValue(gvi.Samples.back().SampleValue);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t// if it's a high rez sampler, send the complete buffer\n\t\t\t\t\t\tif (gvi.MeanSamplePeriod < 1000 && _AdminExecutorService != NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// build the message\n\t\t\t\t\t\t\thighRezDatas.setVarName(gvi.VarName);\n\t\t\t\t\t\t\thighRezDatas.getDatas().clear();\n\n\t\t\t\t\t\t\tfor (uint j=0; j<gvi.Samples.size(); ++j)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thighRezDatas.getDatas().push_back(THighRezData());\n\t\t\t\t\t\t\t\tTHighRezData &hrd = highRezDatas.getDatas().back();\n\t\t\t\t\t\t\t\thrd.setSampleTick(gvi.Samples[j].HighRezTimeStamp);\n\t\t\t\t\t\t\t\thrd.setValue(gvi.Samples[j].SampleValue);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!highRezDatas.getDatas().empty() && _AdminExecutorService != NULL)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// send the high rez data\n\t\t\t\t\t\t\t\tCAdminExecutorServiceProxy aes(_AdminExecutorService);\n\t\t\t\t\t\t\t\taes.highRezGraphUpdate(this, highRezDatas);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// we don't send normal update for high rez sampler\n\t\t\t\t\t\t\tdatas.pop_back();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// update the time stamp\n\t\t\t\t\t\tgvi.LastSampleTimeStamp = now;\n\t\t\t\t\t\t// clear the buffer\n\t\t\t\t\t\tgvi.Samples.clear();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if we have some data to send, send them\n\t\t\t\tif (!datas.empty() && _AdminExecutorService != NULL)\n\t\t\t\t{\n\t\t\t\t\tCAdminExecutorServiceProxy aes(_AdminExecutorService);\n\t\t\t\t\taes.graphUpdate(this, graphDatas);\n\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t// update the last report date\n\t\t\t\t_LastStateReport = now;\n\t\t\t}\n\n\t\t\t// send an update of the status (if needed)\n\t\t\tsendServiceStatus();\n\t\t}\n\n\t\tvoid sendServiceStatus()\n\t\t{\n\t\t\tCSString status;\n\t\t\tuint32 now = NLMISC::CTime::getSecondsSince1970();\n\n\t\t\tstatus << \"\\tServiceAlias=\" << _ServiceAlias;\n\n\t\t\t// build the status string\n\t\t\tIVariable *var = dynamic_cast<IVariable*>(ICommand::getCommand(\"State\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tState=\" <<var->toString();\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"UserSpeedLoop\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tUserSpeedLoop=\" <<var->toString();\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"TickSpeedLoop\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tTickSpeedLoop=\" <<var->toString();\n\n\t\t\tif (_ProcessUsedMemory != 0)\n\t\t\t\tstatus << \"\\tProcessUsedMemory=\" <<_ProcessUsedMemory;\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"Uptime\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tUpTime=\" <<var->toString();\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"NbPlayers\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tNbPlayers=\" <<var->toString();\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"NbEntities\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tNbEntities=\" <<var->toString();\n\n\t\t\tvar = dynamic_cast<IVariable*>(ICommand::getCommand(\"LocalEntities\"));\n\t\t\tif (var != NULL)\n\t\t\t\tstatus << \"\\tLocalEntities=\" <<var->toString();\n\n\t\t\tuint32 shardId = IService::getInstance()->getShardId();\n\t\t\tstatus << \"\\tShardId=\" <<toString(shardId);\n\n\t\t\t// add any service specific info\n\t\t\tif (IService::isServiceInitialized())\n\t\t\t{\n\t\t\t\tstatus << \"\\t\" << IService::getInstance()->getServiceStatusString();\n\t\t\t}\n\n\t\t\tif ((status != _LastSentStatus || (now - _LastStatusStringReport) > MAX_DELAY_BETWEEN_REPORT) \n\t\t\t\t&& _AdminExecutorService != NULL)\n\t\t\t{\n\t\t\t\tCAdminExecutorServiceProxy aes(_AdminExecutorService);\n\t\t\t\taes.serviceStatusUpdate(this, status);\n\n\t\t\t\t_LastSentStatus = status;\n\t\t\t\t_LastStatusStringReport = now;\n\t\t\t}\n\t\t}\n\n\t\t///////////////////////////////////////////////////////////////\n\t\t// implementation from Admin executor service client\n\t\t///////////////////////////////////////////////////////////////\n\n\t\t// execute a command and return the result.\n\t\tvirtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &command)\n\t\t{\n\t\t\t// create a displayer to gather the output of the command\n\t\t\tclass CStringDisplayer: public IDisplayer\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tvirtual void doDisplay( const CLog::TDisplayInfo& args, const char *message)\n\t\t\t\t{\n\t\t\t\t\t_Data += message;\n\t\t\t\t}\n\n\t\t\t\tstd::string _Data;\n\t\t\t};\n\t\t\tCStringDisplayer stringDisplayer;\n\t\t\tIService::getInstance()->CommandLog.addDisplayer(&stringDisplayer);\n\n\t\t\t// retrieve the command from the input message and execute it\n\t\t\tnlinfo (\"ADMIN: Executing command from network : '%s'\", command.c_str());\n\t\t\tICommand::execute (command, IService::getInstance()->CommandLog);\n\n\t\t\t// unhook our displayer as it's work is now done\n\t\t\tIService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer);\n\n\t\t\tstring serviceAlias = IService::getInstance()->getServiceAliasName();\n\t\t\tif (serviceAlias.empty())\n\t\t\t\tserviceAlias = getModuleFullyQualifiedName();\n\n\t\t\t// return the result to AES\n\t\t\tCAdminExecutorServiceProxy aes(sender);\n\t\t\taes.commandResult(this, commandId, serviceAlias, stringDisplayer._Data);\n\t\t}\n\n\t\t// execute a command without result\n\t\tvirtual void serviceCmdNoReturn(NLNET::IModuleProxy *sender, const std::string &command)\n\t\t{\n\t\t\t// retrieve the command from the input message and execute it\n\t\t\tnlinfo (\"ADMIN: Executing command from network : '%s'\", command.c_str());\n\t\t\tICommand::execute (command, IService::getInstance()->CommandLog);\n\t\t}\n\t};\n\n\tNLNET_REGISTER_MODULE_FACTORY(CAdminExecutorServiceClient, \"AdminExecutorServiceClient\");\n\n\n} // namespace ADMIN\n\n"
  },
  {
    "path": "code/EVA/server/admin_modules/aes_module.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/misc/singleton.h\"\n#include <time.h>\n#include \"nel/misc/path.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_builder_parts.h\"\n#include \"nel/net/unified_network.h\"\n#include \"nel/net/service.h\"\n\n#include \"server_share/utils.h\"\n\n#include \"admin_modules_itf.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nvoid aes_forceLink() {}\n\nnamespace ADMIN\n{\n\tconst char* LAUNCH_CTRL_START = \"LAUNCH\";\n\tconst char* LAUNCH_CTRL_STOP = \"STOP\";\n\n\tconst char *AESPersistentStateFilename = \"aes_state.txt\";\n\n\t/// We want 10 slot (you can change this, but need at least 3 slots)\n\tconst uint32 CRASH_COUNTER_SLOT = 10;\n\t/// The delay (in second) between slots roll. This value * CRASH_COUNTER_SLOT give the total sampling period\n\tconst uint32 CRASH_COUNTER_ROLL_DELAY = 10*60;\t// 10 mn\n\t/// If we have more than 5 start of a service in the sampling period, we tag the service as 'chain crashing'\n\tconst uint32 CRASH_COUNTER_CHAIN_THRESHOLD = 5;\n\n\t/** the name of the file written by the patch man to request a global shutdown\n\t *\tof all registered the services before switching to a new version.\n\t */\n\tCVariable<string> ShutdownRequestFileName(\"aes\",\"ShutdownRequestFileName\", \"name of the file to use for shutdown requests\", \"./global.launch_ctrl\", 0, true);\n\n\t/** A kind rolling buffer used to count services start from the runner\n\t *\tscript.\n\t */\n\tclass CRunnerLoopCounter\n\t{\n\t\t/// The slot table. Each slot accumulate the service start for a time frame\n\t\tuint32\t_Slots[CRASH_COUNTER_SLOT];\n\t\t/** The last value read from the runner script. This is used to compute \n\t\t *\tthe delta value to add to the first slot\n\t\t */\n\t\tuint32\t_LastValueRead;\n\t\t/// The total sum of all slot (could be recomputed on demand, but a little more efficient)\n\t\tuint32\t_CounterSum;\n\tpublic:\n\n\t\tCRunnerLoopCounter()\n\t\t{\n\t\t\t// we need at least 3 slots\n\t\t\tnlctassert(CRASH_COUNTER_SLOT >= 3);\n\n\t\t\t// init all slots with 0\n\t\t\tfor (uint i=0; i<CRASH_COUNTER_SLOT; ++i)\n\t\t\t{\n\t\t\t\t_Slots[i] = 0;\n\t\t\t}\n\n\t\t\t// init the last value with a magic value so that the first\n\t\t\t// update will not compute a delta but only take\n\t\t\t// the first value as initial reference\n\t\t\t_LastValueRead = 0xffffffff;\n\t\t\t_CounterSum = 0;\n\t\t}\n\n\t\t/** Updat the counter by submitting the current start counter\n\t\t *\twritten by the runner script.\n\t\t *\tNote that the runner script only increment the counter\n\t\t *\tso we need to compute the delta from _LastValueRead\n\t\t *\tbefore accumulating in the first slot.\n\t\t */\n\t\tvoid updateCounter(uint32 lastValue)\n\t\t{\n\t\t\tif (_LastValueRead == 0xffffffff || lastValue < _LastValueRead)\n\t\t\t{\n\t\t\t\t// this is the first sample, just init the last value read\n\t\t\t\t// or the counter have been reset to a smaller value\n\t\t\t\t_LastValueRead = lastValue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// not the first sample, compute the delta and accumulate\n\t\t\t\tuint32 delta = lastValue - _LastValueRead;\n\t\t\t\t_Slots[0] += delta;\n\t\t\t\t_LastValueRead = lastValue;\n\t\t\t\t// update summ\n\t\t\t\t_CounterSum += delta;\n\t\t\t}\n\t\t}\n\n\t\t/// Roll the slots. The last slot is ejected and\n\t\t/// each slot are copied in the next one (in\n\t\t/// inverse order obviously)\n\t\t/// The first slot in then set to 0\n\t\tvoid rollCounter()\n\t\t{\n\n\t\t\t_CounterSum -= _Slots[CRASH_COUNTER_SLOT-1];\n\n\t\t\tfor (uint i=CRASH_COUNTER_SLOT-1; i>0; --i)\n\t\t\t{\n\t\t\t\t_Slots[i] = _Slots[i-1];\n\t\t\t}\n\t\t\t_Slots[0] = 0;\n\t\t}\n\n\t\t/// Return the sum of all the slots\n\t\tuint32 getSum()\n\t\t{\n\t\t\treturn _CounterSum;\n\t\t}\n\n\t\t/// Return the sum of the first slot, the tree first slot and\n\t\t/// the total of all slots.\n\t\t/// This is useful to understand the behavoir of a crashing\n\t\t/// service over the sampling period.\n\t\tvoid getCounters(uint32 &oneSlot, uint32 &treeSlots, uint32 &allSlots)\n\t\t{\n\t\t\toneSlot = _Slots[0];\n\t\t\ttreeSlots = _Slots[0]+_Slots[1]+_Slots[2];\n\t\t\tallSlots = _CounterSum;\n\t\t}\n\n\n\t\t/// Reset all counter to zero\n\t\tvoid resetCounter()\n\t\t{\n\t\t\tfor (uint i=0; i<CRASH_COUNTER_SLOT; ++i)\n\t\t\t{\n\t\t\t\t_Slots[i] = 0;\n\t\t\t}\n\t\t\t_CounterSum = 0;\n\t\t}\n\n\t};\n\n\n\tclass CAdminExecutorService \n\t\t:\t/*public CManualSingleton<CAdminExecutorService>,*/\n\t\t\tpublic CEmptyModuleServiceBehav<CEmptyModuleCommBehav<CEmptySocketBehav<CModuleBase> > >,\n\t\t\tpublic CAdminExecutorServiceSkel,\n\t\t\tpublic IModuleTrackerCb\n\t{\n\tpublic:\n\t\tenum \n\t\t{\n\t\t\tSLOW_TO_START_THRESHOLD = 60,\t\t// 1 mn\n\t\t\tSLOW_TO_STOP_THRESHOLD = 60,\t\t// 1 mn\n\t\t\t_NagiosReportDelay = 60,\t\t\t// 1 mn\n\t\t};\n\n\tprivate:\n\t\n\t\ttypedef CModuleTracker<TModuleClassPred>\tTServiceTracker;\n\t\t// tracker for admin executor client modules\n\t\tTServiceTracker\t\t_ServiceTracker;\n\n\t\t/// Admin service module\n\t\tTModuleProxyPtr\t\t_AdminService;\n\n\t\t/// Date of last state reporting to AS\n\t\tuint32\t\t\t\t_LastStateReport;\n\n\t\t/// Date of last nagios report output\n\t\tuint32\t\t\t\t_LastNagiosReport;\n\n\t\ttypedef string\tTAliasName;\n\t\ttypedef string\tTShardName;\n\t\ttypedef set<TAliasName>\tTRegisteredServices;\n\t\t/// List of 'registered service', ie. those that are configured in aes cfg.\n\t\tTRegisteredServices\t\t_RegisteredServices;\n\n\t\t/// A set of data for each registered or connected service\n\t\tstruct TServiceState\n\t\t{\n\t\t\tstring\t\t\tShardName;\t\n\t\t\tbool\t\t\tDontUseShardOrders;\n\t\t\tTRunningState\tRunningState;\n\t\t\tset<TRunningTag> RunningTags;\t\n\t\t\tstring\t\t\tLongName;\n\t\t\tstring\t\t\tShortName;\n\t\t\tuint32\t\t\tPID;\n\t\t\tstring\t\t\tState;\n\t\t\tuint32\t\t\tLastStateDate;\n\t\t\tuint32\t\t\tStopRequestDate;\t\n\t\t\tuint32\t\t\tStartRequestDate;\n\t\t\tTModuleProxyPtr\tServiceModule;\n\t\t\tCRunnerLoopCounter\tRunnerLoopCounter;\n\n\t\t\tTServiceState()\n\t\t\t\t:\tDontUseShardOrders(false),\n\t\t\t\t\tRunningState(TRunningState::rs_stopped),\n\t\t\t\t\tPID(0),\n\t\t\t\t\tLastStateDate(0),\n\t\t\t\t\tStopRequestDate(0),\n\t\t\t\t\tStartRequestDate(0)\n\t\t\t{}\n\t\t};\n\n\t\ttypedef map<TAliasName, TServiceState>\tTServiceStates;\n\t\t/// States for each connected or registered service\n\t\tTServiceStates\t\t\t\t_ServiceStates;\n\n\t\ttypedef map<TModuleProxyPtr, TAliasName>\tTConnectedServiceIndex;\n\t\t/// Index of connected service proxy to alias name\n\t\tTConnectedServiceIndex\t\t_ConnectedServiceIndex;\n\n\t\ttypedef map<TAliasName, TRunningOrders>\tTPersistentServiceOrders;\n\t\t/// Persistent service state, i.e state that are restored after a stop/start of the aes\n\t\tTPersistentServiceOrders\t_PersistentServiceOrders;\n\t\t\n\t\ttypedef map<TShardName, TShardOrders>\tTShardsOrders;\n\t\t/// Shard orders (set by AS)\n\t\tTShardsOrders\t\t\t\t_ShardOrders;\n\n\t\t/// flag for shutdown request form patch manager.\n\t\tbool\t\t\t\t\t\t_ShutdownForPatch;\n\n\t\t/// A flag that mean we need to save the persistent state file\n\t\tbool\t\t\t\t\t\t_NeedToWriteStateFile;\n\n\t\t/// Date of last roll of the runner loop counters\n\t\tuint32\t\t\t\t\t\t_LastRunnerLoopCounterRoll;\n\n\t\t/// Data for each command pending result from a service\n\t\tstruct TPendingWebCommand\n\t\t{\n\t\t\t/// Date of reception of the command for timeout\n\t\t\tuint32\tReceptionDate;\n\t\t\t/// Name of the target service\n\t\t\tstring\tServiceAlias;\n\t\t\t/// Command\n\t\t\tstring\tCommand;\n\t\t};\n\t\ttypedef uint32\tTCommandId;\n\t\ttypedef map<TCommandId, TPendingWebCommand>\tTPendingWebCommands;\n\t\t/// A list of pending command sent to service and waiting result\n\t\tTPendingWebCommands\t_PendingWebCommands;\n\n\t\t/// information about shard being stopped\n\t\tstruct TStopingShardInfo\n\t\t{\n\t\t\t/// Name of the shard to stop\n\t\t\tstring\t\tShardName;\n\t\t\t/// Delay before stop\n\t\t\tuint32\t\tDelay;\n\t\t\t/// Begin date of countdown\n\t\t\tuint32\t\tBeginDate;\n\t\t};\n\n\t\ttypedef vector<TStopingShardInfo>\tTStopingShardInfos;\n\n\t\t/// The vector of shard to stop.\n\t\tTStopingShardInfos\t_StopingShards;\n\n\n\tpublic:\n\t\tCAdminExecutorService()\n\t\t\t:\t_ServiceTracker(TModuleClassPred(\"AdminExecutorServiceClient\")),\n\t\t\t\t_LastStateReport(0),\n\t\t\t\t_LastNagiosReport(0),\n\t\t\t\t_ShutdownForPatch(false),\n\t\t\t\t_NeedToWriteStateFile(false),\n\t\t\t\t_LastRunnerLoopCounterRoll(0)\n\t\t{\n\t\t\tCAdminExecutorServiceSkel::init(this);\n\t\t\t_ServiceTracker.init(this, this);\n\n\t\t}\n\n\t\tbool initModule(const TParsedCommandLine &pcl)\n\t\t{\n\t\t\tCModuleBase::initModule(pcl);\n\n\t\t\t// read the persistent state file if any\n\t\t\tstring filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+AESPersistentStateFilename;\n\t\t\tFILE *fp = fopen(filename.c_str(), \"rt\");\n\t\t\tif (fp != NULL)\n\t\t\t{\n\t\t\t\tchar buffer[1024];\n\t\t\t\tchar *ret;\n\t\t\t\twhile ((ret=fgets(buffer, 1024, fp)) != NULL)\n\t\t\t\t{\n\t\t\t\t\tCSString line(buffer);\n\t\t\t\t\tCSString cmd(line.firstWord(true));\n\n\t\t\t\t\tif (cmd == \"ServiceState\")\n\t\t\t\t\t{\n\t\t\t\t\t\tCSString serviceAlias = line.firstWord(true);\n\t\t\t\t\t\tCSString serviceOrders = line.firstWord(true);\n\n\t\t\t\t\t\tTRunningOrders runningOrders(serviceOrders);\n\t\t\t\t\t\tif (!serviceAlias.empty() && runningOrders != TRunningOrders::invalid_val)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// add this one in the list of persistent state\n\t\t\t\t\t\t\t_PersistentServiceOrders[serviceAlias] = runningOrders;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (cmd == \"ShardOrders\")\n\t\t\t\t\t{\n\t\t\t\t\t\tstring shardName(line.firstWord(true));\n\t\t\t\t\t\tTShardOrders shardOrders(line.firstWord(true));\n\t\t\t\t\t\tif (shardOrders != TShardOrders::invalid_val)\n\t\t\t\t\t\t\t_ShardOrders[shardName] = shardOrders;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// clear the flag because 'setGlobalState' has set it\n\t\t\t\t_NeedToWriteStateFile = false;\n\n\t\t\t\tfclose(fp);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid onModuleUp(IModuleProxy *proxy)\n\t\t{\n\t\t\tif (proxy->getModuleClassName() == \"AdminService\")\n\t\t\t{\n\t\t\t\tnldebug(\"CAdminExecutorService : admin service up as '%s'\", proxy->getModuleName().c_str());\n\t\t\t\t// we found the manager of AES\n\t\t\t\tif (_AdminService != NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"CAdminExecutorService : admin service already known as '%s', replacing with new one\", _AdminService->getModuleName().c_str());\n\t\t\t\t}\n\t\t\t\t_AdminService = proxy;\n\n\t\t\t\t// cleanup the persistent service state by removing any state not in registered or connected service\n\t\t\t\t{\n\t\t\t\t\tset<string>\tremoveList;\n\n\t\t\t\t\t// first, fill the list with all the persistent state service name\n\t\t\t\t\t{\n\t\t\t\t\t\tTPersistentServiceOrders::iterator first(_PersistentServiceOrders.begin()), last(_PersistentServiceOrders.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tremoveList.insert(first->first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// remove the registered service from the removelist\n\t\t\t\t\t{\n\t\t\t\t\t\tTRegisteredServices::iterator first(_RegisteredServices.begin()), last(_RegisteredServices.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tremoveList.erase(*first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// remove any connected service (even unregistered one)\n\t\t\t\t\t{\n\t\t\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tremoveList.erase(first->first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// no remove persistent state that left in the remove list\n\t\t\t\t\twhile (!removeList.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\t_PersistentServiceOrders.erase(*(removeList.begin()));\n\n\t\t\t\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\t\t\t\tremoveList.erase(removeList.begin());\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\t// send the current status\n\t\t\t\tsendUpServiceUpdate();\n\t\t\t}\n\n\t\t\tuint32 now = NLMISC::CTime::getSecondsSince1970();\n\t\t\t// check pending command timeout\n\t\t\tTPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTPendingWebCommand &pwc = first->second;\n\n\t\t\t\tif (now - pwc.ReceptionDate > 10)\n\t\t\t\t{\n\t\t\t\t\t// timeout\n\t\t\t\t\tif (_AdminService != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tCAdminServiceProxy as(_AdminService);\n\t\t\t\t\t\tas.commandResult(this, first->first, pwc.ServiceAlias, \"ERROR : AES : no reponse from service\");\n\t\t\t\t\t}\n\n\t\t\t\t\t_PendingWebCommands.erase(first);\n\n\t\t\t\t\t// check other pending commands at next update\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid onModuleDown(IModuleProxy *proxy)\n\t\t{\n\t\t\tif (proxy == _AdminService)\n\t\t\t{\n\t\t\t\tnldebug(\"CAdminExecutorService : admin service '%s' is down\", proxy->getModuleName().c_str());\n\n\t\t\t\t_AdminService = NULL;\n\t\t\t}\n\t\t}\n\n\t\tvoid onModuleUpdate()\n\t\t{\n\t\t\tH_AUTO(CAdminExecutorService_onModuleUpdate);\n\n\t\t\tuint32 now = CTime::getSecondsSince1970();\n\n\t\t\tif (_LastStateReport < now)\n\t\t\t{\n\t\t\t\t// every second\n\n\t\t\t\t// check services every second\n\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tstring aliasName = first->first;\n\t\t\t\t\tTServiceState &ss = first->second;\n\t\t\t\t\tif (_RegisteredServices.find(aliasName) != _RegisteredServices.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// this is a registered service, we need to control is running state\n\n\t\t\t\t\t\t// read the actual running state from the runner script written file\n\t\t\t\t\t\tif (getOfflineServiceState(aliasName) == \"RUNNING\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the service is running\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_locally_stopped);\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_globally_stopped);\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_stopped_for_patch);\n\n\t\t\t\t\t\t\tif (ss.StopRequestDate != 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// still not stopped, check for slow to stop service\n\t\t\t\t\t\t\t\tif (now - ss.StopRequestDate > SLOW_TO_STOP_THRESHOLD)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// add a running tag\n\t\t\t\t\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_slow_to_stop);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (ss.RunningState != TRunningState::rs_online)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// tag slow to start service\n\t\t\t\t\t\t\t\tif (now - ss.StartRequestDate > SLOW_TO_START_THRESHOLD)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// add a running tag\n\t\t\t\t\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_slow_to_start);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tss.RunningState = TRunningState::rs_running;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the service is stopped\n\t\t\t\t\t\t\tss.RunningState = TRunningState::rs_stopped;\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_locally_started);\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_externaly_started);\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_slow_to_stop);\n\n\t\t\t\t\t\t\t// clean the stop request date\n\t\t\t\t\t\t\tss.StopRequestDate = 0;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// try to obtains service orders from its shard\n\t\t\t\t\t\tTShardOrders shardOrders(TShardOrders::so_autostart_on);\n\t\t\t\t\t\tif (_ShardOrders.find(ss.ShardName) != _ShardOrders.end())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tshardOrders = _ShardOrders[ss.ShardName];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// little check, the service must have a entry in the service orders container.\n\t\t\t\t\t\tnlassert(_PersistentServiceOrders.find(aliasName) != _PersistentServiceOrders.end());\n\n\t\t\t\t\t\tTRunningOrders serviceOrders = _PersistentServiceOrders[aliasName];\n\n\t\t\t\t\t\t// look if service need to be started\n\t\t\t\t\t\tif (ss.RunningState == TRunningState::rs_stopped\t\t// its stopped\n\t\t\t\t\t\t\t&& serviceOrders == TRunningOrders::ro_activated\t// and activated\n\t\t\t\t\t\t\t&& shardOrders == TShardOrders::so_autostart_on\t\t// and shard is autostart on\n\t\t\t\t\t\t\t&& !ss.DontUseShardOrders\t\t\t\t\t\t\t// and this service follow its shard orders\n\t\t\t\t\t\t\t&& !_ShutdownForPatch\t\t\t\t\t\t\t\t// and no patch pending\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we must start this service !\n\t\t\t\t\t\t\tstartService(aliasName);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// look for service that need to be stopped\n\t\t\t\t\t\tif (ss.RunningState != TRunningState::rs_stopped\t\t// its not stopped\n\t\t\t\t\t\t\t&& (serviceOrders == TRunningOrders::ro_deactivated\t// and deactivated\n\t\t\t\t\t\t\t\t|| _ShutdownForPatch)\t\t\t\t\t\t\t// or patch pending\n\t\t\t\t\t\t\t&& ss.StopRequestDate == 0\t\t\t\t\t\t\t\t// no stop request send\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we must stop this service\n\t\t\t\t\t\t\tstopService(aliasName);\n\n\t\t\t\t\t\t\t// store the sop\n\t\t\t\t\t\t\tss.StopRequestDate = now;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// shuted down for patch ?\n\t\t\t\t\t\tif (_ShutdownForPatch)\n\t\t\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_stopped_for_patch);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_stopped_for_patch);\n\n\t\t\t\t\t\t// chain crashing ?\n\t\t\t\t\t\tif (ss.RunnerLoopCounter.getSum() > CRASH_COUNTER_CHAIN_THRESHOLD)\n\t\t\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_chain_crashing);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tss.RunningTags.erase(TRunningTag::rt_chain_crashing);\n\n\t\t\t\t\t\t// update the crash counter\n\t\t\t\t\t\tss.RunnerLoopCounter.updateCounter(getServiceStartLoopCounter(aliasName));\n\t\t\t\t\t}\n\t\t\t\t\n\n\n\t\t\t\t}\n\n\t\t\t\t// if we have an admin service connected, send it an update of service state\n\t\t\t\tif (_AdminService != NULL)\n\t\t\t\t\tsendUpServiceUpdate();\n\n\n\t\t\t\tif ((now & 0xf) == 0)\n\t\t\t\t{\n\t\t\t\t\t// every 8 seconds for low frequency work\n\n\t\t\t\t\t// check for shutdown request from patchman\n\t\t\t\t\tcheckShutdownRequest();\n\t\t\t\t}\n\n\t\t\t\t// check for shard to stop (and warning to send)\n\t\t\t\tcheckServiceToStop();\n\n\t\t\t\t// time to output the nagios report ?\n\t\t\t\tif (now > _LastNagiosReport+_NagiosReportDelay)\n\t\t\t\t{\n\t\t\t\t\t// write the nagios report\n\t\t\t\t\tFILE *fp = fopen(\"aes_nagios_report.txt\", \"wt\");\n\t\t\t\t\tif (fp != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// output the current date\n\t\t\t\t\t\ttime_t t = now;\n\t\t\t\t\t\tfprintf(fp, \"AESReportDate=%s\", ::ctime(&t));\n\n\t\t\t\t\t\tfprintf(fp, \"NBService=%u\\n\", (uint32)_ServiceStates.size());\n\t\t\t\t\t\t// output state of each service\n\t\t\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCSString serviceLine;\n\t\t\t\t\t\t\tTServiceState &ss = first->second;\n\t\t\t\t\t\t\tconst string &aliasName = first->first;\n\n\t\t\t\t\t\t\tCSString runningTags;\n\t\t\t\t\t\t\tset<TRunningTag>::iterator rtf(ss.RunningTags.begin()), rte(ss.RunningTags.end());\n\t\t\t\t\t\t\tfor (; rtf != rte; ++rtf)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\trunningTags<<\"<\"<<rtf->toString()<<\">\";\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end();\n\n\t\t\t\t\t\t\tserviceLine << \"ServiceAlias='\"<<aliasName<<\"' RunningState='\"<<ss.RunningState.toString()<<\"' RunningTag='\"<<runningTags<<\"'\";\n\t\t\t\t\t\t\tserviceLine << \" NoReportSince=\"<<now-ss.LastStateDate;\n\t\t\t\t\t\t\tserviceLine << \" State='\"<<ss.State<<\"'\";\n\n\t\t\t\t\t\t\tfprintf(fp, \"%s\\n\", serviceLine.c_str());\n\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tfclose(fp);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning(\"Can't open the nagios report file !\");\n\t\t\t\t\t}\n\n\t\t\t\t\t_LastNagiosReport = now;\n\t\t\t\t}\n\n\t\t\t\t\t\n\t\t\t\t// update the last report date\n\t\t\t\t_LastStateReport = now;\n\t\t\t}\n\n\t\t\t// check runner loop counter roll timer\n\t\t\tif (_LastRunnerLoopCounterRoll+CRASH_COUNTER_ROLL_DELAY < now)\n\t\t\t{\n\t\t\t\t// it's time to roll the crash counter\n\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tfirst->second.RunnerLoopCounter.rollCounter();\n\t\t\t\t}\n\n\t\t\t\t_LastRunnerLoopCounterRoll = now;\n\t\t\t}\n\n\t\t\tif (_NeedToWriteStateFile)\n\t\t\t{\n\t\t\t\t/// The persistent service orders need to be saved\n\t\t\t\tstring filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+AESPersistentStateFilename;\n\t\t\t\tFILE *fp = fopen(filename.c_str(), \"wt\");\n\t\t\t\tif (fp != NULL)\n\t\t\t\t{\n\t\t\t\t\t{\n\t\t\t\t\t\tCSString line;\n\t\t\t\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()),  last(_ShardOrders.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tline << \"ShardOrders \"<<first->first<<\" \"<<first->second.toString()<<\"\\n\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tfputs(line.c_str(), fp);\n\t\t\t\t\t}\n\n\t\t\t\t\t{\n\t\t\t\t\t\tTPersistentServiceOrders::iterator first(_PersistentServiceOrders.begin()), last(_PersistentServiceOrders.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCSString line;\n\t\t\t\t\t\t\tline << \"ServiceState \"<<first->first<<\" \"<<first->second.toString()<<\"\\n\";\n\t\t\t\t\t\t\tfputs(line.c_str(), fp);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// clear the flag because 'setGlobalState' has set it\n\t\t\t\t\t_NeedToWriteStateFile = false;\n\n\t\t\t\t\tfclose(fp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid sendUpServiceUpdate()\n\t\t{\n\t\t\tif (_AdminService != NULL)\n\t\t\t{\n\t\t\t\tvector<TServiceStatus>\tserviceStatus;\n\t\t\t\tset<TAliasName>\tmissingServices = _RegisteredServices;\n\t\t\t\t// send an updated list to AES\n\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tconst string &aliasName = first->first;\n\t\t\t\t\tbool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end();\n\t\t\t\t\tTServiceState &ss = first->second;\n\t\t\t\t\tserviceStatus.push_back(TServiceStatus());\n\t\t\t\t\tTServiceStatus &ts = serviceStatus.back();\n\t\t\t\t\tts.setShardName(ss.ShardName);\n\t\t\t\t\tts.setServiceLongName(ss.LongName);\n\t\t\t\t\tts.setServiceShortName(ss.ShortName);\n\t\t\t\t\tts.setServiceAliasName(aliasName);\n\t\t\t\t\tts.setRunningState(ss.RunningState);\n\t\t\t\t\tif (registered)\n\t\t\t\t\t\tts.setRunningOrders(_PersistentServiceOrders[aliasName]);\n\t\t\t\t\telse\n\t\t\t\t\t\tts.setRunningOrders(TRunningOrders::invalid_val);\n\t\t\t\t\tts.setRunningTags(ss.RunningTags);\n\t\t\t\t\tCSString state;\n\t\t\t\t\tstate << ss.State << \"\\tNoReportSince=\" << (NLMISC::CTime::getSecondsSince1970()-ss.LastStateDate);\n\n\t\t\t\t\t// add the host name\n\t\t\t\t\tstate << \"\\tHostname=\" << IService::getInstance()->getHostName();\n\n\t\t\t\t\tif (registered)\n\t\t\t\t\t{\n\t\t\t\t\t\t// this is a registered service, send the start counter\n\t\t\t\t\t\tuint32 oneSlot, treeSlots, allSlots;\n\t\t\t\t\t\tss.RunnerLoopCounter.getCounters(oneSlot, treeSlots, allSlots);\n\t\t\t\t\t\tstate << \"\\tStartCounter=\"<<oneSlot<<\" \"<<treeSlots<<\" \"<<allSlots;\n\t\t\t\t\t}\n\t\t\t\t\tts.setStatus(state);\n\n\t\t\t\t\tmissingServices.erase(aliasName);\n\t\t\t\t}\n\n\t\t\t\tCAdminServiceProxy as(_AdminService);\n\t\t\t\tas.upServiceUpdate(this, serviceStatus);\n\t\t\t}\n\t\t}\n\n\t\tIModuleProxy *findOnlineService(const std::string &serviceAlias)\n\t\t{\n\t\t\tTConnectedServiceIndex::iterator first(_ConnectedServiceIndex.begin()), last(_ConnectedServiceIndex.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (first->second == serviceAlias)\n\t\t\t\t{\n\t\t\t\t\t// ok, we found it\n\t\t\t\t\treturn first->first;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// not found\n\t\t\treturn NULL;\n\t\t}\n\n\t\tvoid checkShutdownRequest()\n\t\t{\n\t\t\t// if there's no ctrl file to be found then giveup\n\t\t\tif (!NLMISC::CFile::fileExists(ShutdownRequestFileName)) return;\n\n\t\t\t// if a shutdown ctrl file exists then read it's contents (if the file doesn't exist this returns an empty string)\n\t\t\tCSString fileContents;\n\t\t\tfileContents.readFromFile(ShutdownRequestFileName.c_str());\n\n\t\t\t// see if the file exists\n\t\t\tif (!fileContents.empty())\n\t\t\t{\n\t\t\t\tNLMISC::CFile::deleteFile(ShutdownRequestFileName);\n\t\t\t\tfileContents= fileContents.strip().splitToOneOfSeparators(\" \\t\\n\\r\\x1a\");\n\n\t\t\t\tNLMISC::fromString(fileContents, _ShutdownForPatch);\n\t\t\t\t_ShutdownForPatch = !_ShutdownForPatch;\n\t\t\t}\n\t\t}\n\n\t\tvoid checkServiceToStop()\n\t\t{\n\t\t\tuint32 now = CTime::getSecondsSince1970();\n\t\t\t// for each shard to stop\n\t\t\tfor (uint i=0; i<_StopingShards.size(); ++i)\n\t\t\t{\n\t\t\t\tconst TStopingShardInfo &stopShardInfo = _StopingShards[i];\n\t\t\t\t\n\t\t\t\tbool timeToStop = stopShardInfo.BeginDate + stopShardInfo.Delay <= now;\n\t\t\t\tuint32 timeLeft = (stopShardInfo.BeginDate + stopShardInfo.Delay) - now;\n\t\t\t\t// check every service\n\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTServiceState &serviceState = first->second;\n\n\t\t\t\t\tif (serviceState.ServiceModule != NULL &&  serviceState.ShardName == stopShardInfo.ShardName)\n\t\t\t\t\t{\n\t\t\t\t\t\t// this one belong to the shard to stop\n\t\t\t\t\t\tif (!timeToStop)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// send a warning every 30 s\n\t\t\t\t\t\t\tif (((now - stopShardInfo.BeginDate) % 30) == 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCAdminExecutorServiceClientProxy aec(serviceState.ServiceModule);\n\t\t\t\t\t\t\t\tnlinfo(\"Sending command 'quitDelay' to service '%s'\", first->first.c_str());\n\t\t\t\t\t\t\t\taec.serviceCmdNoReturn(this, toString(\"quitDelay %u\", timeLeft));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// stop the service\n\t\t\t\t\t\t\tstopService(first->first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (timeToStop)\n\t\t\t\t{\n\t\t\t\t\tnlinfo(\"All local service for shard %s are stopped\", stopShardInfo.ShardName.c_str());\n\t\t\t\t\t// shard stopped, erase this entry \n\t\t\t\t\t_StopingShards.erase(_StopingShards.begin()+i);\n\t\t\t\t\t--i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\t// the following routine reads the text string contained in the \".state\" file for this service\n\t\t// it's used to provide a 'state' value for services that are registered but are not connected\n\t\t// to give info on whether they've been launched, whether their launcher is online, etc\n\t\tstd::string getOfflineServiceState(const std::string& serviceAlias)\n\t\t{\n\t\t\t// open the file for reading\n\t\t\tFILE* f= fopen(getServiceStateFileName(serviceAlias).c_str(),\"rt\");\n\t\t\tif (f==NULL) return \"STOPPED\";\n\n\t\t\t// setup a buffer to hold the text read from the file\n\t\t\tuint32 fileSize= NLMISC::CFile::getFileSize(f);\n\t\t\tstd::string txt;\n\t\t\ttxt.resize(fileSize);\n\n\t\t\t// read the text from the file - note that the number of bytes read may be less than the\n\t\t\t// number of bytes requested because we've opened the file in text mode and not binary mode\n\t\t\tuint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f);\n\t\t\ttxt.resize(bytesRead);\n\t\t\tfclose(f);\n\n\t\t\t// return the text read from the file\n\t\t\treturn txt;\n\t\t}\n\n\t\t\n\t\t// the following routine reads the text string contained in the \"pid.state\" file for this service\n\t\t// it's used to provide a early pid information to the AES (before the service is connected)\n\t\tuint32 getOfflineServicePID(const std::string& serviceAlias)\n\t\t{\n\t\t\t// open the file for reading\n\t\t\tFILE* f= fopen(getServicePIDFileName(serviceAlias).c_str(),\"rt\");\n\t\t\tif (f==NULL) return 0;\n\n\t\t\t// setup a buffer to hold the text read from the file\n\t\t\tuint32 fileSize= NLMISC::CFile::getFileSize(f);\n\t\t\tstd::string txt;\n\t\t\ttxt.resize(fileSize);\n\n\t\t\t// read the text from the file - note that the number of bytes read may be less than the\n\t\t\t// number of bytes requested because we've opened the file in text mode and not binary mode\n\t\t\tuint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f);\n\t\t\ttxt.resize(bytesRead);\n\t\t\tfclose(f);\n\n\t\t\t// return the pid read from the file\n\t\t\tuint32 pid;\n\t\t\tNLMISC::fromString(txt, pid);\n\n\t\t\treturn pid;\n\t\t}\n\n\n\t\t// the following routine reads the text string contained in the \".start_counter\" file for this service\n\t\t// it's used to provide the number of start done by the runner loop on the service\n\t\t// This is used for the chain crash detector system.\n\t\tuint32 getServiceStartLoopCounter(const std::string& serviceAlias)\n\t\t{\n\t\t\t// open the file for reading\n\t\t\tFILE* f= fopen(getServiceLoopCounterFileName(serviceAlias).c_str(),\"rt\");\n\t\t\tif (f==NULL) \n\t\t\t\treturn 0;\n\n\t\t\t// setup a buffer to hold the text read from the file\n\t\t\tuint32 fileSize= NLMISC::CFile::getFileSize(f);\n\t\t\tstd::string txt;\n\t\t\ttxt.resize(fileSize);\n\n\t\t\t// read the text from the file - note that the number of bytes read may be less than the\n\t\t\t// number of bytes requested because we've opened the file in text mode and not binary mode\n\t\t\tuint32 bytesRead= (uint32)fread(&txt[0],1,fileSize,f);\n\t\t\ttxt.resize(bytesRead);\n\t\t\tfclose(f);\n\n\t\t\t// parse the text in the buffer\n\t\t\tuint32 counter;\n\t\t\tNLMISC::fromString(txt, counter);\n\n\t\t\treturn counter;\n\t\t}\n\n\t\t// retrieve service launch info in the config file\n\t\tbool getServiceLaunchInfo(const string& serviceAlias, string& path)\n\t\t{\n\t\t\tstring basePath;\n\t\t\tCConfigFile::CVar *launchDir = IService::getInstance()->ConfigFile.getVarPtr(\"AESLauncherDir\");\n\t\t\tif (launchDir != NULL)\n\t\t\t{\n\t\t\t\tbasePath = launchDir->asString()+\"/\";\n\t\t\t}\n\n\t\t\tif (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end())\n\t\t\t\treturn false;\n\t\t\tpath = basePath + serviceAlias+\"/\";\n\n\t\t\treturn true;\n\t\t}\n\n\t\t\n\t\tstd::string getServiceStateFileName(const std::string& serviceAlias)\n\t\t{\n\t\t\tstring servicePath;\n\t\t\tif (getServiceLaunchInfo(serviceAlias, servicePath))\n\t\t\t\treturn NLMISC::CPath::standardizePath(servicePath)+serviceAlias+\".state\";\n\t\t\telse\n\t\t\t\treturn string();\n\t\t}\n\n\t\tstd::string getServicePIDFileName(const std::string& serviceAlias)\n\t\t{\n\t\t\tstring servicePath;\n\t\t\tif (getServiceLaunchInfo(serviceAlias, servicePath))\n\t\t\t\treturn NLMISC::CPath::standardizePath(servicePath)+\"pid.state\";\n\t\t\telse\n\t\t\t\treturn string();\n\t\t}\n\n\t\tstd::string getServiceLoopCounterFileName(const std::string& serviceAlias)\n\t\t{\n\t\t\tstring servicePath;\n\t\t\tif (getServiceLaunchInfo(serviceAlias, servicePath))\n\t\t\t\treturn NLMISC::CPath::standardizePath(servicePath)+serviceAlias+\".start_count\";\n\t\t\telse\n\t\t\t\treturn string();\n\t\t}\n\n\t\tstd::string getServiceLaunchCtrlFileName(const std::string& serviceAlias,const std::string& serviceExecutionPath, bool deferred)\n\t\t{\n\t\t\treturn NLMISC::CPath::standardizePath(serviceExecutionPath)+serviceAlias+(deferred?\".deferred_\":\".\")+\"launch_ctrl\";\n\t\t}\n\n\n\t\tbool writeServiceLaunchCtrl(const std::string& serviceAlias, bool deferred, const std::string& txt)\n\t\t{\n\t\t\tstring path;\n\t\t\tif (!getServiceLaunchInfo(serviceAlias, path))\n\t\t\t\treturn false;\n\n\t\t\t// make sure the path exists\n\t\t\tNLMISC::CFile::createDirectoryTree(path);\n\n\t\t\t// open the file for writing\n\t\t\tFILE* f= fopen(getServiceLaunchCtrlFileName(serviceAlias, path, deferred).c_str(),\"wt\");\n\t\t\tif (f==NULL) return false;\n\n\t\t\t// write the text to the file\n\t\t\tfprintf(f,\"%s\",txt.c_str());\n\t\t\tfclose(f);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tbool startService(const std::string &serviceAlias)\n\t\t{\n\t\t\tif (_ServiceStates.find(serviceAlias) != _ServiceStates.end())\n\t\t\t{\n\t\t\t\tTServiceState &ss = _ServiceStates[serviceAlias];\n\t\t\t\tif (ss.RunningState != TRunningState::rs_stopped)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"startService '%s' : the service is already running\", serviceAlias.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// store the start date\n\t\t\t\tss.StartRequestDate = CTime::getSecondsSince1970();\n\n\t\t\t}\n\t\t\tif (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"startService '%s' : the service in not registered, can't start it\", serviceAlias.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// write the start command\n\t\t\tbool ret = writeServiceLaunchCtrl(serviceAlias, false, LAUNCH_CTRL_START);\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tbool stopService(const std::string &serviceAlias)\n\t\t{\n\t\t\t// check that the service is running\n\t\t\tTServiceStates::iterator it(_ServiceStates.find(serviceAlias));\n\t\t\tif (it == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"stopService : Failed to found service '%s' in the list of services\", serviceAlias.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tTServiceState &ss = it->second;\n\t\t\t// write the launch control to stop\n\t\t\tif (_RegisteredServices.find(serviceAlias) != _RegisteredServices.end())\n\t\t\t{\n\t\t\t\tif (!writeServiceLaunchCtrl(serviceAlias, false, LAUNCH_CTRL_STOP))\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"Failed to write launch control file for service '%s'\", serviceAlias.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tnlinfo(\"Service '%s' launch control file updated\", serviceAlias.c_str());\n\t\t\t}\n\n\t\t\t// set the stopre request date if needed\n\t\t\tif (ss.StopRequestDate != 0)\n\t\t\t{\n\t\t\t\tss.StopRequestDate = CTime::getSecondsSince1970();\n\t\t\t}\n\n\t\t\tif (ss.ServiceModule == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"stopService : The service '%s' is not connected, can't ask him to stop\", serviceAlias.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// send the \"quit\" command to the service\n\t\t\tCAdminExecutorServiceClientProxy aec(ss.ServiceModule);\n\t\t\tnlinfo(\"Sending command 'quit' to service '%s'\", serviceAlias.c_str());\n\t\t\taec.serviceCmdNoReturn(this, \"quit\");\n\n\t\t\treturn true;\n\t\t}\n\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// Virtuals from IModuleTrackerCb\n\t\t///////////////////////////////////////////////////////////////////////\n\n\t\tvirtual void onTrackedModuleUp(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tnldebug(\"Service module '%s' UP\", moduleProxy->getModuleName().c_str());\n\n\n\t\t\tTParsedCommandLine pcl;\n\t\t\tif (!pcl.parseParamList(moduleProxy->getModuleManifest()))\n\t\t\t{\n\t\t\t\tnlwarning(\"CAdminExecutorService:onTrackedModuleUp : failed to parse manifest\");\n\t\t\t}\n\n\t\t\tconst TParsedCommandLine *pclLongName = pcl.getParam(\"LongName\");\n\t\t\tconst TParsedCommandLine *pclShortName = pcl.getParam(\"ShortName\");\n\t\t\tconst TParsedCommandLine *pclAliasName = pcl.getParam(\"AliasName\");\n\t\t\tconst TParsedCommandLine *pclPID = pcl.getParam(\"PID\");\n\t\t\tconst TParsedCommandLine *pclDontUseShardOrders = pcl.getParam(\"DontUseShardOrders\");\n\n\t\t\tstring aliasName = pclAliasName != NULL ? pclAliasName->ParamValue : moduleProxy->getModuleName();\n\n\t\t\t// remove the temporary state and update connected service index\n\t\t\t_ServiceStates.erase(moduleProxy->getModuleName());\n\t\t\t_ConnectedServiceIndex[moduleProxy] = aliasName;\n\n\t\t\tnlinfo(\"AES client module %s for service %s is up\",\n\t\t\t\tmoduleProxy->getModuleName().c_str(),\n\t\t\t\taliasName.c_str());\n\n\t\t\t// create a new entry or get an existing one\n\t\t\tTServiceState &ss = _ServiceStates[aliasName];\n\t\t\t// update the service state\n\t\t\tss.RunningState = TRunningState::rs_online;\n\t\t\tif (pclDontUseShardOrders)\n\t\t\t\tNLMISC::fromString(pclDontUseShardOrders->ParamValue, ss.DontUseShardOrders);\n\t\t\telse\n\t\t\t\tss.DontUseShardOrders = false;\n\t\t\tss.LongName = pclLongName != NULL ? pclLongName->ParamValue : \"unknown\";\n\t\t\tss.ShortName = pclShortName != NULL ? pclShortName->ParamValue : \"unknown\";\n\n\t\t\tif (pclPID!= NULL)\n\t\t\t{\n\t\t\t\tNLMISC::fromString(pclPID->ParamValue, ss.PID);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tss.PID = 0;\n\t\t\t}\n\n\t\t\tss.State = \"\";\n\t\t\tss.LastStateDate = NLMISC::CTime::getSecondsSince1970();\n\t\t\tss.ServiceModule = moduleProxy;\n\t\t\tss.StartRequestDate = 0;\n\t\t\tss.RunningTags.erase(TRunningTag::rt_slow_to_start);\n\t\t\tif (_RegisteredServices.find(aliasName) == _RegisteredServices.end())\n\t\t\t{\n\t\t\t\tss.RunningTags.insert(TRunningTag::rt_externaly_started);\n\t\t\t}\n//\t\t\telse\n//\t\t\t{\n//\t\t\t\t// if this service is locally stopped or if the shard it belong to is stopped,\n//\t\t\t\t// then flag it as 'localy started'\n//\t\t\t\tif (_PersistentServiceOrders.find(aliasName) != _PersistentServiceOrders.end()\n//\t\t\t\t\t&& _PersistentServiceOrders[aliasName] == TRunningOrders::ro_stopped)\n//\t\t\t\t{\n//\t\t\t\t\t// flag it as started\n//\t\t\t\t\t_PersistentServiceOrders[aliasName] = TRunningOrders::ro_running;\n//\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_locally_started);\n//\t\t\t\t\t_NeedToWriteStateFile = true;\n//\t\t\t\t}\n//\t\t\t\telse if (_ShardOrders.find(ss.ShardName) != _ShardOrders.end() \n//\t\t\t\t\t&& _ShardOrders[ss.ShardName] == TRunningOrders::ro_stopped)\n//\t\t\t\t{\n//\t\t\t\t\t// the shard is stopped, flag the service as started\n//\t\t\t\t\t_PersistentServiceOrders[aliasName] = TRunningOrders::ro_running;\n//\t\t\t\t\tss.RunningTags.insert(TRunningTag::rt_locally_started);\n//\t\t\t\t\t_NeedToWriteStateFile = true;\n//\t\t\t\t}\n//\t\t\t}\n\n\t\t\tsendUpServiceUpdate();\t\t\t\n\t\t}\n\t\tvirtual void onTrackedModuleDown(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tnldebug(\"Service module '%s' DOWN\", moduleProxy->getModuleName().c_str());\n\n\t\t\tTConnectedServiceIndex::iterator it(_ConnectedServiceIndex.find(moduleProxy));\n\t\t\tif (it != _ConnectedServiceIndex.end())\n\t\t\t{\n\t\t\t\tstring &aliasName = it->second;\n\t\t\t\tnlinfo(\"AES client module %s of service %s is down\",\n\t\t\t\t\tmoduleProxy->getModuleName().c_str(),\n\t\t\t\t\taliasName.c_str());\n\t\t\t\tBOMB_IF(_ServiceStates.find(aliasName) == _ServiceStates.end(), \"Service down from \"<<moduleProxy->getModuleName()<<\" with alias \"<<aliasName<<\" not found in _ServiceStates table\", _ConnectedServiceIndex.erase(it); return);\n\t\t\t\tif (_RegisteredServices.find(aliasName) == _RegisteredServices.end())\n\t\t\t\t{\n\t\t\t\t\t// this is not a registered service, remove the status record\n\t\t\t\t\t_ServiceStates.erase(aliasName);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tTServiceState &ss = _ServiceStates[aliasName];\n\t\t\t\t\t// update the running state\n\t\t\t\t\tss.RunningState = TRunningState::rs_running;\n\n\t\t\t\t\tss.ServiceModule = NULL;\n\n\t\t\t\t\t// kill the service to be sure that it is really dead !\n\t\t\t\t\tif (ss.PID > 1)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo(\"Killing process %u (%s) because aes client module '%s' is down\",\n\t\t\t\t\t\t\tss.PID,\n\t\t\t\t\t\t\taliasName.c_str(),\n\t\t\t\t\t\t\tmoduleProxy->getModuleName().c_str());\n\t\t\t\t\t\tkillProgram(ss.PID);\n\t\t\t\t\t}\n\t\t\t\t}\n\nretry_pending_command_loop:\n\t\t\t\t// check for pending command\n\t\t\t\tTPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTPendingWebCommand &pwc = first->second;\n\t\t\t\t\tif (pwc.ServiceAlias == aliasName)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (_AdminService != NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCAdminServiceProxy as(_AdminService);\n\t\t\t\t\t\t\tas.commandResult(this, first->first, pwc.ServiceAlias, \"ERROR : AES : service connection lost during command\");\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_PendingWebCommands.erase(first);\n\t\t\t\t\t\t// goto to avoid iterator dodging\n\t\t\t\t\t\tgoto retry_pending_command_loop;\n\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// remove the index record\n\t\t\t\t_ConnectedServiceIndex.erase(it);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlinfo(\"AES client module %s is not associated with a service\",\n\t\t\t\t\tmoduleProxy->getModuleName().c_str());\n\t\t\t}\n\n\n\t\t\tsendUpServiceUpdate();\t\t\t\n\t\t}\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// Virtuals from CAdminExecutorServiceSkel\n\t\t///////////////////////////////////////////////////////////////////////\n\n\t\t// AS send orders for a shard\n\t\tvirtual void setShardOrders(NLNET::IModuleProxy *sender, const std::string &shardName, const TShardOrders &shardOrders)\n\t\t{\n\t\t\tnlinfo(\"AS setShardOrders for shard '%s' to '%s'\", shardName.c_str(), shardOrders.toString().c_str());\n\n\t\t\tif (_ShardOrders[shardName] == shardOrders)\n\t\t\t{\n\t\t\t\t// nothing to do\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t_ShardOrders[shardName] = shardOrders;\n\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\t// nothing more to do, if service need to be started, they are started\n\t\t\t// by the module update function\n\n\t\t}\n\n\t\t// AS send a command to shutdown a shard with a delay\n\t\tvirtual void shutdownShard(NLNET::IModuleProxy *sender, const std::string &shardName, uint32 delay)\n\t\t{\n\t\t\tTStopingShardInfo ssi;\n\t\t\tssi.ShardName = shardName;\n\t\t\tssi.Delay = delay;\n\t\t\tssi.BeginDate = CTime::getSecondsSince1970();\n\n\t\t\t_StopingShards.push_back(ssi);\n\n\t\t\tnlinfo(\"Received command to stop all service of shard %s in %us\", ssi.ShardName.c_str(), ssi.Delay);\n\n\t\t\t// force a first update (to send the first warning message or stop immediately)\n\t\t\tcheckServiceToStop();\n\n\t\t}\n\n\t\t// AS send a control command to this AES\n\t\tvirtual void controlCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t\t{\n\t\t\t// create a displayer to gather the output of the command\n\t\t\tclass CStringDisplayer: public IDisplayer\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tvirtual void doDisplay( const CLog::TDisplayInfo& args, const char *message)\n\t\t\t\t{\n\t\t\t\t\t_Data += message;\n\t\t\t\t}\n\n\t\t\t\tstd::string _Data;\n\t\t\t};\n\n\t\t\tnldebug(\"Control command from '%s' : '%s' '%s'\", \n\t\t\t\tsender->getModuleName().c_str(),\n\t\t\t\tserviceAlias.c_str(),\n\t\t\t\tcommand.c_str());\n\n\t\t\t// look in the list of service for a matching one\n\t\t\tIModuleProxy *service = findOnlineService(serviceAlias);\n\t\t\tif (service == NULL && _RegisteredServices.find(serviceAlias) == _RegisteredServices.end())\n\t\t\t{\n\t\t\t\tCAdminServiceProxy as(sender);\n\t\t\t\tas.commandResult(this, commandId, serviceAlias, \"ERROR : AES : service not found will dispatching the control command\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t// ok, we can execute the command concerning the service.\n\t\t\tCStringDisplayer stringDisplayer;\n\t\t\tIService::getInstance()->CommandLog.addDisplayer(&stringDisplayer);\n\n\t\t\t// build the command line\n\t\t\tCSString args(command);\n\t\t\tCSString cmdName = args.firstWord(true);\n\t\t\tCSString cmdLine;\n\t\t\tcmdLine << getCommandHandlerName() << \".\" << cmdName  << \" \" << serviceAlias << \" \" << args;\n\t\t\t// retrieve the command from the input message and execute it\n\t\t\tnlinfo (\"ADMIN: Executing control command : '%s' for service '%s'\", cmdLine.c_str(), serviceAlias.c_str());\n\t\t\tICommand::execute (cmdLine, IService::getInstance()->CommandLog);\n\n\t\t\t// unhook our displayer as it's work is now done\n\t\t\tIService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer);\n\n\t\t\t// send the result back to AS\n\t\t\tCAdminServiceProxy as(sender);\n\t\t\tas.commandResult(this, commandId, serviceAlias, stringDisplayer._Data);\n\t\t}\n\n\t\t//The return is sent back by another message\n\t\tvirtual void serviceCmd(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &command)\n\t\t{\n\t\t\t// look in the list of service for a matching one\n\t\t\tIModuleProxy *proxy = findOnlineService(serviceAlias);\n\t\t\tif (proxy == NULL)\n\t\t\t{\n\t\t\t\tCAdminServiceProxy as(sender);\n\t\t\t\tas.commandResult(this, commandId, serviceAlias, \"ERROR AES : unknown service\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ok, we found it !\n\t\t\tTPendingWebCommand pwc;\n\t\t\tpwc.Command = command;\n\t\t\tpwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970();\n\t\t\tpwc.ServiceAlias = serviceAlias;\n\n\t\t\t_PendingWebCommands.insert(make_pair(commandId, pwc));\n\n\t\t\tCAdminExecutorServiceClientProxy service(proxy);\n\t\t\tservice.serviceCmd(this, commandId, command);\n\t\t}\n\n\t\t// AES client send back the result of execution of a command\n\t\tvirtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceAlias, const std::string &result)\n\t\t{\n\t\t\t// check for waiting commands\n\t\t\tTPendingWebCommands::iterator it(_PendingWebCommands.find(commandId));\n\n\t\t\tif (it == _PendingWebCommands.end())\n\t\t\t{\n\t\t\t\tif (commandId != 0)\n\t\t\t\t\tnlwarning(\"CAdminExecutor::commandResult : service '%s' sent result for command ID %u but not in pending command table\",\n\t\t\t\t\tsender->getModuleName().c_str(),\n\t\t\t\t\tcommandId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// send the result back to AS\n\t\t\tif (_AdminService != NULL)\n\t\t\t{\n\t\t\t\tCAdminServiceProxy as(_AdminService);\n\n\t\t\t\tas.commandResult(this, commandId, serviceAlias, result);\n\t\t\t}\n\n\t\t\t_PendingWebCommands.erase(commandId);\n\t\t}\n\n\n\t\t// An AES send graph data update\n\t\tvirtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas)\n\t\t{\n\t\t\tif (_AdminService != NULL)\n\t\t\t{ \n\t\t\t\tCAdminServiceProxy as(_AdminService);\n\t\t\t\tas.graphUpdate(this, graphDatas);\n\t\t\t}\n\t\t}\n\n\t\t// A service high rez graph data update\n\t\tvirtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas)\n\t\t{\n\t\t\tif (_AdminService != NULL)\n\t\t\t{\n\t\t\t\tCAdminServiceProxy as(_AdminService);\n\t\t\t\tas.highRezGraphUpdate(this, graphDatas);\n\t\t\t}\n\t\t}\n\n\t\t// A service send an update of of it's status string\n\t\tvirtual void serviceStatusUpdate(NLNET::IModuleProxy *sender, const std::string &status)\n\t\t{\n\t\t\tTConnectedServiceIndex::iterator it(_ConnectedServiceIndex.find(sender));\n\t\t\tif (it == _ConnectedServiceIndex.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"serviceStatusUpdate : service '%s' send status but is unknown !\", sender->getModuleName().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstring &aliasName = it->second;\n\t\t\tTServiceStates::iterator it2(_ServiceStates.find(aliasName));\n\t\t\tBOMB_IF(it2 == _ServiceStates.end(), \"serviceStateUpdate : service '\"\n\t\t\t\t<<sender->getModuleName()\n\t\t\t\t<<\"' send an update, but alias '\"<<aliasName<<\"' is not found in service status\", return);\n\n\t\t\tTServiceState &ss = it2->second;\n\t\t\tss.State = status;\n\t\t\tss.LastStateDate = NLMISC::CTime::getSecondsSince1970();\n\t\t}\n\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// commands handlers\n\t\t///////////////////////////////////////////////////////////////////////\n\t\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CAdminExecutorService, CModuleBase)\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, dump, \"Dump a status report to appropriate output logger\", \"no args\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, addRegisteredService, \"add a registered service\", \"<serviceAlias> <shardName>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, removeRegisteredService, \"remove a registered service\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, startService, \"start a registered service\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, restartService, \"stop then start a registered service\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, stopService, \"stop a service (registered or not)\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, killService, \"kill a (possibly not responding) service (registered or not)\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, abortService, \"abort a (possibly not responding) service with SIGABORT (registered or not)\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, activateService, \"activate a service, i.e make it startable either manually or from a shard orders\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, deactivateService, \"deactivate a service, i.e make it unstartable (either manually or from a shard orders) and stop it if needed\", \"<serviceAlias>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, execScript, \"execute the predefined bash script '/home/nevrax/patchman/aes_runnable_script.sh' and give it the passed parameters\", \"<any parameter>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, resetStartCounter, \"reset the start counter to 0\", \"no params\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminExecutorService, stopShard, \"Stop all service of a given shard aftert the provided delay\", \"<shardName> <delay (in s)>\")\n\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\n\t\tNLMISC_CLASS_COMMAND_DECL(stopShard)\n\t\t{\n\t\t\tif (args.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tstring shardName = args[0];\n\t\t\tuint32 delay;\n\t\t\tNLMISC::fromString(args[1], delay);\n\n\t\t\tlog.displayNL(\"Received command to stop all service of shard %s in %us\", shardName.c_str(), delay);\n\n\t\t\tshutdownShard(NULL, shardName, delay);\n\n\t\t\treturn true;\n\t\t}\n\n\n\t\tNLMISC_CLASS_COMMAND_DECL(resetStartCounter)\n\t\t{\n\t\t\tif (args.size() != 0)\n\t\t\t\treturn false;\n\n\n\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTServiceState &ss = first->second;\n\t\t\t\t\n\t\t\t\tss.RunnerLoopCounter.resetCounter();\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\t\n\t\tNLMISC_CLASS_COMMAND_DECL(execScript)\n\t\t{\n\t\t\tstring cmdLine(\"/home/nevrax/patchman/aes_runnable_script.sh\");\n\n\t\t\t// add parameters\n\t\t\tfor (uint i=0; i<args.size(); ++i)\n\t\t\t{\n\t\t\t\tcmdLine += \" \"+args[i];\n\t\t\t}\n\n\t\t\t// add redirection\n\t\t\tstring logFile = CPath::getTemporaryDirectory() + \"aes_command_output.log\";\n\n\t\t\tcmdLine += \" > \"+logFile;\n\n\t\t\tlog.displayNL(\"Executing '%s'\", cmdLine.c_str());\n\t\t\t// execute the command\n\t\t\tint ret = system(cmdLine.c_str());\n\n\t\t\t// echo the output to the requester\n\t\t\tCSString output;\n\t\t\toutput.readFromFile(logFile);\n\n\t\t\tvector<CSString> lines;\n\t\t\toutput.splitLines(lines);\n\n\t\t\tlog.displayNL(\"Command returned value %d\", ret);\n\t\t\tlog.displayNL(\"-------------------- Command output begin -----------------------\");\n\t\t\tfor (uint i=0; i<lines.size(); ++i)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"%s\", lines[i].c_str());\n\t\t\t}\n\t\t\tlog.displayNL(\"-------------------- Command output end -----------------------\");\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(deactivateService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_PersistentServiceOrders.find(serviceAlias) == _PersistentServiceOrders.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unregistered service '%s', could not deactivate it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t_PersistentServiceOrders[serviceAlias] = TRunningOrders::ro_deactivated;\n\n\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\tlog.displayNL(\"Service '%s' deactivated\", serviceAlias.c_str());\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(activateService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_PersistentServiceOrders.find(serviceAlias) == _PersistentServiceOrders.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unregistered service '%s', could not activate it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t_PersistentServiceOrders[serviceAlias] = TRunningOrders::ro_activated;\n\n\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\tlog.displayNL(\"Service '%s' activated\", serviceAlias.c_str());\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(abortService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\t// check that the service is running\n\t\t\tTServiceStates::iterator it(_ServiceStates.find(serviceAlias));\n\t\t\tif (it == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Failed to found service '%s' in the list of running services\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTServiceState &ss = it->second;\n\t\t\tif (ss.RunningState == TRunningState::rs_stopped)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"The service to abort '%s' is currently stopped\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (ss.PID < 2)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"AES have no valid PID to abort the service '%s'\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// abort it\n\t\t\tlog.displayNL(\"Aborting service '%s' with pid %u\", serviceAlias.c_str(), ss.PID);\n\t\t\tabortProgram(ss.PID);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(killService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\t// check that the service is running\n\t\t\tTServiceStates::iterator it(_ServiceStates.find(serviceAlias));\n\t\t\tif (it == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Failed to found service '%s' in the list of running services\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTServiceState &ss = it->second;\n\t\t\tif (ss.RunningState == TRunningState::rs_stopped)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"The service to kill '%s' is currently stopped\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (ss.PID < 2)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"AES have no valid PID to kill the service '%s'\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// kill it\n\t\t\tlog.displayNL(\"Killing service '%s' with pid %u\", serviceAlias.c_str(), ss.PID);\n\t\t\tkillProgram(ss.PID);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(stopService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_ServiceStates.find(serviceAlias) == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknown service '%s', could not stop it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTServiceState &ss = _ServiceStates[serviceAlias];\n\t\t\t// look for a shard orders for this service\n\t\t\tTShardsOrders::iterator it(_ShardOrders.find(ss.ShardName));\n\t\t\tif (it != _ShardOrders.end())\n\t\t\t{\n\t\t\t\tTShardOrders &so = it->second;\n\t\t\t\tif (so == TShardOrders::so_autostart_on)\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"Can't stop service '%s' because shard '%s' is autostarting, considers either to deactivate the service or just restart it\",\n\t\t\t\t\t\tserviceAlias.c_str(),\n\t\t\t\t\t\tss.ShardName.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (stopService(serviceAlias))\n\t\t\t\tlog.displayNL(\"Failed to stop the service '%s'\", serviceAlias.c_str());\n\t\t\telse\n\t\t\t\tlog.displayNL(\"Service '%s' stop request done\", serviceAlias.c_str());\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(restartService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_RegisteredServices.find(serviceAlias) == _RegisteredServices.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"startService %s : the service in not registered, can't restart it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// look for service orders for this service\n\t\t\tif (_PersistentServiceOrders.find(serviceAlias) != _PersistentServiceOrders.end())\n\t\t\t{\n\t\t\t\tif (_PersistentServiceOrders[serviceAlias] == TRunningOrders::ro_deactivated)\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"Can't restart service '%s' because it is currently deactivated\", serviceAlias.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\n\n\t\t\t// check that the service is running\n\t\t\tTServiceStates::iterator it(_ServiceStates.find(serviceAlias));\n\t\t\tif (it == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Failed to found service '%s' in the list of running services\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// write the deferred start command\n\t\t\tif (!writeServiceLaunchCtrl(serviceAlias, true, LAUNCH_CTRL_START))\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Failed to write deferred start control file to restart service '%s'\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tlog.displayNL(\"Service '%s' start command written\", serviceAlias.c_str());\n\n\t\t\tif (it->second.ServiceModule == NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"The AES client module proxy is null ! can't send 'quit' command\");\n\t\t\t}\n\n\t\t\t// send the \"quit\" command to the service\n\t\t\tCAdminExecutorServiceClientProxy aec(it->second.ServiceModule);\n\t\t\taec.serviceCmd(this, 0, \"quit\");\n\t\t\tlog.displayNL(\"Service '%s' command 'quit' sent\", serviceAlias.c_str());\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(startService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_ServiceStates.find(serviceAlias) == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknown service '%s', could not start it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTServiceState &ss = _ServiceStates[serviceAlias];\n\n\t\t\t// look for service orders for this service\n\t\t\tif (_PersistentServiceOrders.find(serviceAlias) != _PersistentServiceOrders.end())\n\t\t\t{\n\t\t\t\tif (_PersistentServiceOrders[serviceAlias] == TRunningOrders::ro_deactivated)\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"Can't start service '%s' because it is curently deactivated\", serviceAlias.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// look for a shard orders for this service\n\t\t\tTShardsOrders::iterator it(_ShardOrders.find(ss.ShardName));\n\t\t\tif (it != _ShardOrders.end())\n\t\t\t{\n\t\t\t\tTShardOrders &so = it->second;\n\t\t\t\tif (so == TShardOrders::so_autostart_on)\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"Can't start service '%s' because shard '%s' is autostarting, consider to restart it\",\n\t\t\t\t\t\tserviceAlias.c_str(),\n\t\t\t\t\t\tss.ShardName.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!startService(serviceAlias))\n\t\t\t\tlog.displayNL(\"Failed to start service '%s'\", serviceAlias.c_str());\n\t\t\telse\n\t\t\t\tlog.displayNL(\"Service '%s' start command written\", serviceAlias.c_str());\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(removeRegisteredService)\n\t\t{\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\n\t\t\tif (_ServiceStates.find(serviceAlias) == _ServiceStates.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknown service '%s', could not start it\", serviceAlias.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTServiceState &ss = _ServiceStates[serviceAlias];\n\n\t\t\t_RegisteredServices.erase(serviceAlias);\n\n\t\t\tif (ss.RunningState == TRunningState::rs_stopped)\n\t\t\t{\n\t\t\t\t// remove the record\n\t\t\t\t_ServiceStates.erase(serviceAlias);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// just update some data related the registered service\t\t\t\t\n\t\t\t\tss.ShardName = \"\";\n\t\t\t\tss.RunningTags.erase(TRunningTag::rt_locally_started);\n\t\t\t\tss.RunningTags.erase(TRunningTag::rt_chain_crashing);\n\t\t\t\tss.RunningTags.insert(TRunningTag::rt_externaly_started);\n\t\t\t}\n\n\n\t\t\t_PersistentServiceOrders.erase(serviceAlias);\n\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\t// update the state of services to the AS\n\t\t\tsendUpServiceUpdate();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(addRegisteredService)\n\t\t{\n\t\t\tif (args.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tstring serviceAlias = args[0];\n\t\t\tstring shardName = args[1];\n\n\t\t\t_RegisteredServices.insert(serviceAlias);\n\t\t\t_ServiceStates.insert(make_pair(serviceAlias, TServiceState()));\n\t\t\t_ServiceStates[serviceAlias].ShardName = shardName;\n//\t\t\t_ServiceRunnerLoopCounters.insert(make_pair(serviceAlias, TRunnerLoopCounter()));\n\n\t\t\tif (_PersistentServiceOrders.find(serviceAlias) == _PersistentServiceOrders.end())\n\t\t\t{\n\t\t\t\t_PersistentServiceOrders[serviceAlias] = TRunningOrders::ro_activated;\n\t\t\t\t_NeedToWriteStateFile = true;\n\t\t\t}\n\n\t\t\t// update the state of services to the AS\n\t\t\tsendUpServiceUpdate();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(dump)\n\t\t{\n\t\t\tNLMISC_CLASS_COMMAND_CALL_BASE(CModuleBase, dump);\n\n\t\t\tlog.displayNL(\"===============================\");\n\t\t\tlog.displayNL(\" Dumping Admin executor states\");\n\t\t\tlog.displayNL(\"===============================\");\n\n\t\t\t{\n\t\t\t\tlog.displayNL(\"  There are %u known shard :\", _ShardOrders.size());\n\t\t\t\t{\n\t\t\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end());\n\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"  + Shard '%s' orders is '%s'\", first->first.c_str(), first->second.toString().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (_ShutdownForPatch)\n\t\t\t\t\tlog.displayNL(\"  All service are shuting down for patch !\");\n\t\t\t\tlog.displayNL(\"  There are %u known services :\", _ServiceStates.size());\n\t\t\t\tTServiceStates::iterator first(_ServiceStates.begin()), last(_ServiceStates.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTServiceState &ss = first->second;\n\t\t\t\t\tconst string &aliasName = first->first;\n\n\t\t\t\t\tCSString runningTags;\n\t\t\t\t\tset<TRunningTag>::iterator rtf(ss.RunningTags.begin()), rte(ss.RunningTags.end());\n\t\t\t\t\tfor (; rtf != rte; ++rtf)\n\t\t\t\t\t{\n\t\t\t\t\t\trunningTags<<\"<\"<<rtf->toString()<<\">\";\n\t\t\t\t\t}\n\n\t\t\t\t\tbool registered = _RegisteredServices.find(aliasName) != _RegisteredServices.end();\n\n\t\t\t\t\tlog.displayNL(\"    + Service alias='%s' (%s) ShardName = '%s' RunningState='%s' RunningTag='%s'\", \n\t\t\t\t\t\taliasName.c_str(),\n\t\t\t\t\t\tregistered ? \"REGISTERED\" : \"NOT REGISTERED\",\n\t\t\t\t\t\tss.ShardName.c_str(),\n\t\t\t\t\t\tss.RunningState.toString().c_str(),\n\t\t\t\t\t\trunningTags.c_str());\n\n\t\t\t\t\tlog.display(\"    |   %s\", ss.DontUseShardOrders ? \"DontUseShardOders\" : \"UseShardOrders\");\n\n\t\t\t\t\tif (ss.RunningState != TRunningState::rs_stopped)\n\t\t\t\t\t{\n\t\t\t\t\t\t// the pid should be valid\n\t\t\t\t\t\tlog.display(\" PID=%u\",\tss.PID);\n\t\t\t\t\t}\n\t\t\t\t\tif (registered)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.display(\" ServiceOrders=%s\", _PersistentServiceOrders[aliasName].toString().c_str());\n\t\t\t\t\t}\n\t\t\t\t\tlog.displayNL(\"\");\n\n\n\t\t\t\t\tif (ss.ServiceModule != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// dump a connected service\n\t\t\t\t\t\tlog.displayNL(\"    |   longName='%s' shortName='%s' moduleName='%s'\",\n\t\t\t\t\t\t\tss.LongName.c_str(),\n\t\t\t\t\t\t\tss.ShortName.c_str(),\n\t\t\t\t\t\t\tss.ServiceModule->getModuleName().c_str());\n\t\t\t\t\t\tlog.displayNL(\"    |   State '%s' (last received %sago)\", ss.State.c_str(), NLMISC::CTime::getHumanRelativeTime(NLMISC::CTime::getSecondsSince1970() - ss.LastStateDate).c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// dump a offline registered service\n\t\t\t\t\t\t// dump a connected service\n\t\t\t\t\t\tlog.displayNL(\"    |   longName='%s' shortName='%s' \",\n\t\t\t\t\t\t\tss.LongName.c_str(),\n\t\t\t\t\t\t\tss.ShortName.c_str());\n\t\t\t\t\t\tlog.displayNL(\"    |   State '%s' (last received %sago)\", ss.State.c_str(), NLMISC::CTime::getHumanRelativeTime(NLMISC::CTime::getSecondsSince1970() - ss.LastStateDate).c_str());\n\t\t\t\t\t}\n\t\t\t\t\tif (registered)\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 c1, c2, c3;\n\t\t\t\t\t\tss.RunnerLoopCounter.getCounters(c1, c2, c3);\n\t\t\t\t\t\tlog.displayNL(\"    |   Service Runner Start counter (%u mn:%u run, %u mn:%u run, %u mn:%u run)\",\n\t\t\t\t\t\t\tCRASH_COUNTER_ROLL_DELAY/60, c1,\n\t\t\t\t\t\t\t(CRASH_COUNTER_ROLL_DELAY*3)/60, c2,\n\t\t\t\t\t\t\t(CRASH_COUNTER_ROLL_DELAY*CRASH_COUNTER_SLOT)/60, c3);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\n\t};\n\n\tNLNET_REGISTER_MODULE_FACTORY(CAdminExecutorService, \"AdminExecutorService\");\n\n} // namespace ADMIN\n\n"
  },
  {
    "path": "code/EVA/server/admin_modules/as_module.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"nel/misc/types_nl.h\"\n#include <time.h>\n#include \"nel/misc/file.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/misc/mutable_container.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_builder_parts.h\"\n\n#include \"admin_modules_itf.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\nvoid as_forceLink() {}\n\nnamespace ADMIN\n{\n\n\t/// name of the persistent state file\n\tconst char *ASPersistentStateFilename = \"as_state.txt\";\n\n\tclass CAdminService \n\t\t:\tpublic CEmptyModuleServiceBehav<CEmptyModuleCommBehav<CEmptySocketBehav<CModuleBase> > >,\n\t\t\tCAdminServiceSkel,\n\t\t\tCAdminServiceWebItf,\n\t\t\tIModuleTrackerCb\n\t{\n\n\t\tenum \n\t\t{\n\t\t\t/// The maximum time without report from an AES before flagging it as 'not responding'\n\t\t\tAES_REPORT_WARNING_DELAY = 5,\n\t\t};\n\n\t\ttypedef CModuleTracker<TModuleClassPred>\tTAESTracker;\n\t\t/// Tracker for EAS modules\n\t\tTAESTracker\t\t_AESTracker;\n\n\t\tstruct TAESServices\n\t\t{\n\t\t\t/// The date of last report send by this AES. Used to display 'not responding' AES\n\t\t\tuint32\t\t\t\t\tLastReportDate;\n\t\t\t/// The list of service known by this AES\n\t\t\tvector<TServiceStatus>\tServiceStatus;\n\n\t\t\tTAESServices()\n\t\t\t\t:\tLastReportDate(0)\n\t\t\t{}\n\t\t};\n\n\t\t/// all known service status by known AES\n\t\ttypedef map<TModuleProxyPtr,  TAESServices>\tTKnownServices;\n\t\tTKnownServices\t_KnownServices;\n\n\t\t/// data for a command comming form web and waiting execution by the module task\n\t\tstruct TPendingWebCommand\n\t\t{\n\t\t\t/// Received command date\n\t\t\tuint32\t\tReceptionDate;\t\n\t\t\t/// Is this a control command (otherwise it's a service command)\n\t\t\tbool\t\tControlCommand;\n\t\t\t/// Sock id of the web connection that wait the command result\n\t\t\tTSockId\t\tRequester;\n\t\t\t/// Alias of the command target service\n\t\t\tstring\t\tServiceAlias;\n\t\t\t/// the command and it's parameters\n\t\t\tstring\t\tCommand;\n\t\t};\n\t\ttypedef uint32 TCommandId;\n\t\tTCommandId\t\t\t_NextCommandId;\n\t\ttypedef map<TCommandId, TPendingWebCommand>\tTPendingWebCommands;\n\t\t/// A stack of web command request to be treated by module task\n\t\tTPendingWebCommands\t_PendingWebCommands;\n\n\t\t/// The global running state of the domain\n//\t\tTRunningOrders\t_GlobalOrders;\n\n\t\ttypedef string\tTShardName;\n\n\t\ttypedef map<TShardName, TShardOrders> TShardsOrders;\n\t\t/// The running state of each shard\n\t\tTShardsOrders\t_ShardOrders;\n\n\t\t/// a flag to write the state file at next module update\n\t\tbool\t\t\t_NeedToWriteStateFile;\n\n\n\tpublic:\n\t\tCAdminService()\n\t\t\t:\t_AESTracker(TModuleClassPred(\"AdminExecutorService\")),\n\t\t\t\t_NextCommandId(0),\n//\t\t\t\t_GlobalOrders(TRunningOrders::ro_running),\n\t\t\t\t_NeedToWriteStateFile(false)\n\n\t\t{\n\t\t\tCAdminServiceSkel::init(this);\n\t\t\t_AESTracker.init(this, this);\n\t\t}\n\n\t\t~CAdminService()\n\t\t{}\n\n\t\tvoid setShardOrders(const std::string &shardName, TShardOrders newOrders)\n\t\t{\n\t\t\t_ShardOrders[shardName] = newOrders;\n//\t\t\tswitch(_GlobalOrders.getValue())\n//\t\t\t{\n//\t\t\tcase TRunningOrders::ro_stopped:\n//\t\t\t\tIService::getInstance()->addStatusTag(\"GLOBAL_STOPPED\");\n//\t\t\t\tbreak;\n//\t\t\tcase TRunningOrders::ro_running:\n//\t\t\t\tIService::getInstance()->removeStatusTag(\"GLOBAL_STOPPED\");\n//\t\t\t\tbreak;\n//\t\t\t}\n\n\t\t\t_NeedToWriteStateFile = true;\n\n\t\t\t// update all AES with the new state\n\t\t\tCAdminExecutorServiceProxy::broadcast_setShardOrders(_AESTracker.getTrackedModules().begin(), _AESTracker.getTrackedModules().end(), \n\t\t\t\tthis, shardName, newOrders);\n\t\t}\n\n\t\t/// Methods called by a module task to handle web command request\n\t\tvoid sendCommandToAES(TCommandId commandId, TPendingWebCommand &pwc)\n\t\t{\n\t\t\t// look in the list of known state to retrieve the target of the command\n\t\t\tTKnownServices::iterator first(_KnownServices.begin()), last(_KnownServices.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst vector<TServiceStatus> &status = first->second.ServiceStatus;\n\t\t\t\tfor (uint i=0; i<status.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tconst TServiceStatus &ss = status[i];\n\t\t\t\t\tif (ss.getServiceAliasName() == pwc.ServiceAlias)\n\t\t\t\t\t{\n\t\t\t\t\t\t// ok, we found it !\n\t\t\t\t\t\tCAdminExecutorServiceProxy aes(first->first);\n\n\t\t\t\t\t\tif (pwc.ControlCommand)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// this is a control command\n\t\t\t\t\t\t\taes.controlCmd(this, commandId, pwc.ServiceAlias, pwc.Command);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// this is a service command\n\t\t\t\t\t\t\taes.serviceCmd(this, commandId, pwc.ServiceAlias, pwc.Command);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// terminate here !\n\t\t\t\t\t\treturn;\n\t//-----------------------------------------------------\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// not found !\n\t\t\tCAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, \"ERROR : AS : unknown service alias\");\n\t\t\t// remove the pending command\n\t\t\t_PendingWebCommands.erase(commandId);\n\t\t}\n\n\n\t\tbool initModule(const TParsedCommandLine &pcl)\n\t\t{\n\t\t\tCModuleBase::initModule(pcl);\n\n\t\t\t// read the command line\n\t\t\tconst TParsedCommandLine *webPort = pcl.getParam(\"webPort\");\n\t\t\tnlassert(webPort != NULL);\n\t\t\tuint16 port;\n\t\t\tNLMISC::fromString(webPort->ParamValue, port);\n\t\t\t// open the web interface\n\t\t\tCAdminServiceWebItf::openItf(port);\n\n\t\t\t// read the persistent state file if any\n\t\t\tstring filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+ASPersistentStateFilename;\n\t\t\tFILE *fp = fopen(filename.c_str(), \"rt\");\n\t\t\tif (fp != NULL)\n\t\t\t{\n\t\t\t\tchar buffer[1024];\n\t\t\t\tchar *ret;\n\t\t\t\twhile ((ret=fgets(buffer, 1024, fp)) != NULL)\n\t\t\t\t{\n\t\t\t\t\tCSString line(buffer);\n\t\t\t\t\tstring cmd = line.firstWord(true);\n\n\t\t\t\t\tif (cmd == \"ShardOrders\")\n\t\t\t\t\t{\n\t\t\t\t\t\tstring shardName = line.firstWord(true);\n\t\t\t\t\t\tstring orders = line.firstWord(true);\n\t\t\t\t\t\tTShardOrders shardOrders(orders);\n\t\t\t\t\t\tif (shardOrders != TShardOrders::invalid_val)\n\t\t\t\t\t\t\tsetShardOrders(shardName, shardOrders);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// clear the flag because 'setGlobalState' has set it\n\t\t\t\t_NeedToWriteStateFile = false;\n\n\t\t\t\tfclose(fp);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid onModuleUpdate()\n\t\t{\n\t\t\tH_AUTO(CAdminService_onModuleUpdate);\n\n\t\t\tCAdminServiceWebItf::update();\n\n\t\t\tif (_NeedToWriteStateFile)\n\t\t\t{\n\t\t\t\tstring filename = CPath::standardizePath(IService::getInstance()->SaveFilesDirectory.toString(), true)+ASPersistentStateFilename;\n\t\t\t\tFILE *fp = fopen(filename.c_str(), \"wt\");\n\t\t\t\tif (fp != NULL)\n\t\t\t\t{\n\t\t\t\t\tCSString line;\n\t\t\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end());\n\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tline << \"ShardOrders \"<<first->first<<\" \"<<first->second.toString()<<\"\\n\";\n\t\t\t\t\t}\n\t\t\t\t\tfputs(line.c_str(), fp);\n\t\t\t\t\tfclose(fp);\n\n\t\t\t\t\t_NeedToWriteStateFile = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuint32 now = NLMISC::CTime::getSecondsSince1970();\n\n\t\t\t// check for timeout commands\n\t\t\tTPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTPendingWebCommand &pwc = first->second;\n\n\t\t\t\tif (now - pwc.ReceptionDate > 10)\n\t\t\t\t{\n\t\t\t\t\tCAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, \"ERROR : no response from service or AES\");\n\t\t\t\t\t_PendingWebCommands.erase(first);\n\t\t\t\t\t// check at next update for the rest\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t{\n\t\t\t\t// save one high rez graph at a time\n\t\t\t\tstatic string lastCheckedBuffer;\n\n\t\t\t\tTHighRezBuffers::iterator it(_HighRezBuffers.upper_bound(lastCheckedBuffer));\n\t\t\t\tif (it == _HighRezBuffers.end())\n\t\t\t\t\tlastCheckedBuffer = \"\";\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tlastCheckedBuffer = it->first;\n\t\t\t\t\tTHighRezBuffer &hrBuffer = it->second;\n\t\t\t\t\tif (hrBuffer.Dirty)\n\t\t\t\t\t{\n\t\t\t\t\t\t// save this buffer\n\t\t\t\t\t\tCMemStream sbuff;\n\t\t\t\t\t\t// write the updated buffer\n\t\t\t\t\t\tsbuff.serial(hrBuffer);\n\n\t\t\t\t\t\tstring filename = getHighRezBufferFilename(it->first);\n\t\t\t\t\t\tNLMISC::COFile of(filename);\n\n\t\t\t\t\t\tif (of.isOpen())\t// test added, because sometime on windows, the file fail to open !\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tof.serialBuffer((uint8*)sbuff.buffer(), sbuff.size());\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\thrBuffer.Dirty = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning(\"CAdminService::onUpdateModule : failed to open file %s for writing\", filename.c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// Virtuals from IModuleTrackerCb\n\t\t///////////////////////////////////////////////////////////////////////\n\n\t\tvirtual void onTrackedModuleUp(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tnldebug(\"AES module '%s' UP\", moduleProxy->getModuleName().c_str());\n\t\t\t\n\t\t\t// send it the current global state\n\t\t\tCAdminExecutorServiceProxy aes(moduleProxy);\n\n\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\taes.setShardOrders(this, first->first, first->second);\n\t\t\t}\n\t\t}\n\t\tvirtual void onTrackedModuleDown(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tnldebug(\"AES module '%s' DOWN\", moduleProxy->getModuleName().c_str());\n\n\t\t\t\n\t\t\t// check for any pending commands with this AES\n\t\t\tTAESServices &as = _KnownServices[moduleProxy];\n\t\t\tfor (uint i=0; i<as.ServiceStatus.size(); ++i)\n\t\t\t{\n\t\t\t\tTServiceStatus &ss = as.ServiceStatus[i];\n\t\t\t\tconst string &aliasName = ss.getServiceAliasName();\n\nretry_pending_command:\n\t\t\t\tTPendingWebCommands::iterator first(_PendingWebCommands.begin()), last(_PendingWebCommands.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTPendingWebCommand &pwc = first->second;\n\t\t\t\t\tif (pwc.ServiceAlias == aliasName)\n\t\t\t\t\t{\n\t\t\t\t\t\t// remove this command\n\t\t\t\t\t\tCAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, \"ERROR : connection lost with AES during command\");\n\t\t\t\t\t\tTCommandId commandId = first->first;\n\t\t\t\t\t\t_PendingWebCommands.erase(first);\n\n\t\t\t\t\t\t// restart the loop to avoid iterator dodging\n\t\t\t\t\t\tgoto retry_pending_command;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// remove any service status\n\t\t\t_KnownServices.erase(moduleProxy);\n\n\t\t}\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// Virtuals from CAdminServiceSkel\n\t\t///////////////////////////////////////////////////////////////////////\n\n\t\t// An AES send an update of the list of service up\n\t\tvirtual void upServiceUpdate(NLNET::IModuleProxy *sender, const std::vector < TServiceStatus > &serviceStatus)\n\t\t{\n\t\t\tif (_AESTracker.getTrackedModules().find(sender) == _AESTracker.getTrackedModules().end())\n\t\t\t{\n\t\t\t\tnlwarning(\"'%s' send upServiceUpdate but is not an valid AES\", sender->getModuleName().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_KnownServices[sender].LastReportDate = NLMISC::CTime::getSecondsSince1970();\n\t\t\t_KnownServices[sender].ServiceStatus = serviceStatus;\n\n\t\t\t// check that we have this shards in the shard orders table\n\t\t\tfor (uint i=0; i<serviceStatus.size(); ++i)\n\t\t\t{\n\t\t\t\tconst TServiceStatus &ss = serviceStatus[i];\n\n\t\t\t\tif (_ShardOrders.find(ss.getShardName()) == _ShardOrders.end())\n\t\t\t\t{\n\t\t\t\t\t// the shard is not in the table, add it\n\t\t\t\t\t_ShardOrders[ss.getShardName()] = TShardOrders::so_autostart_on;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// An AES send graph data update\n\t\tvirtual void graphUpdate(NLNET::IModuleProxy *sender, const TGraphDatas &graphDatas)\n\t\t{\n\t\t\t// dump the datas\n//\t\t\tnldebug(\"Received graph data for time %u\", \n//\t\t\t\tgraphDatas.getCurrentTime());\n//\n//\t\t\tfor (uint i=0; i<graphDatas.getDatas().size(); ++i)\n//\t\t\t{\n//\t\t\t\tnldebug(\"  %s.%s = %f\", \n//\t\t\t\t\tgraphDatas.getDatas()[i].getServiceName().c_str(), \n//\t\t\t\t\tgraphDatas.getDatas()[i].getVarName().c_str(), \n//\t\t\t\t\tgraphDatas.getDatas()[i].getValue());\n//\t\t\t}\n\n\t\t\tfor (uint i=0; i<graphDatas.getDatas().size(); ++i)\n\t\t\t{\n\t\t\t\tconst TGraphData &gd = graphDatas.getDatas()[i];\n\n\t\t\t\t// compute var filename\n\t\t\t\tCSString rrdfilename = CPath::standardizePath (IService::getInstance()->ConfigFile.getVar(\"RRDVarPath\").asString());\n\t\t\t\trrdfilename << gd.getServiceAlias() <<\".\" <<gd.getVarName()<<\".rrd\";\n\n\t\t\t\tCSString arg;\n\t\t\t\t\n\t\t\t\tif (!NLMISC::CFile::fileExists(rrdfilename))\n\t\t\t\t{\n\t\t\t\t\targ <<\"create \"<<rrdfilename\n\t\t\t\t\t\t<<\" --step \"<<toString(gd.getSamplePeriod())\n\t\t\t\t\t\t<<\" DS:var:GAUGE:\"<<toString(gd.getSamplePeriod()*2)\n\t\t\t\t\t\t<<\":U:U RRA:AVERAGE:0.5:1:1000 RRA:AVERAGE:0.5:10:1000 RRA:AVERAGE:0.5:100:1000\";\n\t\t\t\t\tlaunchProgram(IService::getInstance()->ConfigFile.getVar(\"RRDToolPath\").asString(), arg);\n\t\t\t\t\targ = \"\";\n\t\t\t\t}\n\n\t\t\t\targ<<\"update \"<<rrdfilename<<\" \"<<toString (graphDatas.getCurrentTime())<<\":\"<<toString(gd.getValue());\n\t\t\t\tlaunchProgram(IService::getInstance()->ConfigFile.getVar(\"RRDToolPath\").asString(), arg);\n\t\t\t}\n\t\t}\n\n\t\tenum\n\t\t{\n\t\t\tHR_BUFFER_SIZE = 5000,\n\t\t};\n\n\t\t/// Circular buffer to store high resolution samples\n\t\tstruct THighRezBuffer\n\t\t{\n\t\t\tbool\t\tDirty;\n\t\t\tuint32\t\tNBSample;\n\t\t\tuint32\t\tFrameStart;\n\t\t\tuint32\t\tFrameEnd;\t\t// == FrameStart if empty\n\n\t\t\tstruct THighRezItem\n\t\t\t{\n\t\t\t\tuint32\t\tDate;\n\t\t\t\tTTime\t\tSampleTick;\n\t\t\t\tdouble\t\tValue;\n\n\t\t\t\tvoid serial(NLMISC::IStream &s)\n\t\t\t\t{\n\t\t\t\t\ts.serial(Date);\n\t\t\t\t\ts.serial(SampleTick);\n\t\t\t\t\ts.serial(Value);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tvector<THighRezItem>\tDatas;\n\n\n\t\t\tTHighRezBuffer()\n\t\t\t\t:\tDirty(false),\n\t\t\t\t\tNBSample(HR_BUFFER_SIZE),\n\t\t\t\t\tFrameStart(0),\n\t\t\t\t\tFrameEnd(0)\n\t\t\t{\n\t\t\t\tDatas.resize(NBSample);\n\t\t\t}\n\n\t\t\tvoid serial(NLMISC::IStream &s)\n\t\t\t{\n\t\t\t\ts.serial(NBSample);\n\t\t\t\ts.serial(FrameStart);\n\t\t\t\ts.serial(FrameEnd);\n\t\t\t\ts.serialCont(Datas);\n\n\t\t\t\tif (s.isReading())\n\t\t\t\t{\n\t\t\t\t\t// make some adjustment in case of HR_BUFFER_SIZE change\n\t\t\t\t\tDatas.resize(HR_BUFFER_SIZE);\n\t\t\t\t\tFrameEnd %= HR_BUFFER_SIZE;\n\t\t\t\t\tFrameStart %= HR_BUFFER_SIZE;\n\t\t\t\t\tNBSample = HR_BUFFER_SIZE;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\ttypedef map<std::string , THighRezBuffer>\tTHighRezBuffers;\n\t\tTHighRezBuffers\t_HighRezBuffers;\n\n\t\tstring getHighRezBufferFilename(const std::string &varAddr)\n\t\t{\n\t\t\tCSString filename = CPath::standardizePath (IService::getInstance()->ConfigFile.getVar(\"RRDVarPath\").asString());\n\t\t\tfilename << varAddr<<\".hrd\";\n\t\n\t\t\treturn filename;\n\t\t}\n\n\t\t// An AES send high rez graph data update\n\t\tvirtual void highRezGraphUpdate(NLNET::IModuleProxy *sender, const THighRezDatas &graphDatas)\n\t\t{\n\t\t\t// dump the datas\n//\t\t\tnldebug(\"Received high rez graph info for var %s from service %s\", \n//\t\t\t\tgraphDatas.getServiceName().c_str(),\n//\t\t\t\tgraphDatas.getVarName().c_str());\n//\n//\t\t\tfor (uint i=0; i<graphDatas.getDatas().size(); ++i)\n//\t\t\t{\n//\t\t\t\tnldebug(\"  At %10\"NL_I64\"u\t%f\", \n//\t\t\t\t\tgraphDatas.getDatas()[i].getSampleTick(), \n//\t\t\t\t\tgraphDatas.getDatas()[i].getValue());\n//\t\t\t}\n\n\t\t\t// compute the var address\n\t\t\tCSString varAddr;\n\t\t\tvarAddr << graphDatas.getServiceAlias()<<\".\"<<graphDatas.getVarName();\n\n\n\t\t\t// check if the var is already known\n\t\t\tbool notExist = (_HighRezBuffers.find(varAddr) == _HighRezBuffers.end());\n\t\t\t// create it anyway\n\t\t\tTHighRezBuffer &hrBuffer = _HighRezBuffers[varAddr];\n\n\t\t\tif (notExist)\n\t\t\t{\n\t\t\t\t// compute var filename\n\t\t\t\tCSString filename = getHighRezBufferFilename(varAddr);\n\n\t\t\t\t// we don't know this var, try to load it from file\n\t\t\t\tif (CFile::isExists(filename))\n\t\t\t\t{\n\t\t\t\t\t// the file exist, load it\n\t\t\t\t\tCIFile ifile(filename);\n\t\t\t\t\thrBuffer.serial(ifile);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// store the new data in the buffer\n\t\t\tfor (uint i=0; i<graphDatas.getDatas().size(); ++i)\n\t\t\t{\n\t\t\t\tconst THighRezData &data = graphDatas.getDatas()[i];\n\n\t\t\t\t// mark this buffer as dirty\n\t\t\t\thrBuffer.Dirty = true;\n\t\t\t\t\n\t\t\t\tnlassert(hrBuffer.FrameEnd < hrBuffer.Datas.size());\n\t\t\t\thrBuffer.Datas[hrBuffer.FrameEnd].Date = graphDatas.getCurrentTime();\t\t\n\t\t\t\thrBuffer.Datas[hrBuffer.FrameEnd].SampleTick = data.getSampleTick();\n\t\t\t\thrBuffer.Datas[hrBuffer.FrameEnd].Value = data.getValue();\n\t\t\t\t\n\t\t\t\t// advance write pointer\n\t\t\t\t++hrBuffer.FrameEnd;\n\t\t\t\tif (hrBuffer.FrameEnd == HR_BUFFER_SIZE)\n\t\t\t\t\thrBuffer.FrameEnd = 0;\n\n\t\t\t\t// advance read pointer if needed\n\t\t\t\tif (hrBuffer.FrameEnd == hrBuffer.FrameStart)\n\t\t\t\t{\n\t\t\t\t\t++hrBuffer.FrameStart;\n\t\t\t\t\tif (hrBuffer.FrameStart == HR_BUFFER_SIZE)\n\t\t\t\t\t\thrBuffer.FrameStart = 0;\n\t\t\t\t}\n\t\t\t}\n\n//\t\t\t// write the updated buffer\n//\t\t\tNLMISC::COFile of(filename);\n//\t\t\tof.serial(hrBuffer);\n\t\t}\n\n\t\t// AES send back the result of execution of a command\n\t\tvirtual void commandResult(NLNET::IModuleProxy *sender, uint32 commandId, const std::string &serviceName, const std::string &result)\n\t\t{\n\t\t\tTPendingWebCommands::iterator it(_PendingWebCommands.find(commandId));\n\n\t\t\tif (it == _PendingWebCommands.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"CAdminService::commandResult : AES '%s' returned a command result from service '%s' with command ID %u that is not in pending table\",\n\t\t\t\t\tsender->getModuleClassName().c_str(),\n\t\t\t\t\tserviceName.c_str(),\n\t\t\t\t\tcommandId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tTPendingWebCommand &pwc = it->second;\n\n\t\t\tCAdminServiceWebItf::commandResult(pwc.Requester, pwc.ServiceAlias, result);\n\n\t\t\t// erase this command\n\t\t\t_PendingWebCommands.erase(it);\n\t\t}\n\n\t\t\n\t\t// An AES send it's updated state strings\n//\t\tvirtual void updateAESStates(NLNET::IModuleProxy *sender, const std::vector < std::string > &states)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n\n\t\t// AES send back the result of execution of a control command\n\t\tvirtual void controlCmdResult(NLNET::IModuleProxy *sender, const std::string &serviceName, const std::vector < std::string > &result)\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// Virtuals from CAdminServiceWebItf\n\t\t///////////////////////////////////////////////////////////////////////\n\n\t\t/// Connection callback : a new interface client connect\n\t\tvirtual void on_CAdminServiceWeb_Connection(NLNET::TSockId from)\n\t\t{\n\t\t}\n\t\t/// Disconnection callback : one of the interface client disconnect\n\t\tvirtual void on_CAdminServiceWeb_Disconnection(NLNET::TSockId from)\n\t\t{\n\t\t}\n\n\n\t\t// This is used to issue global commands like 'as.allStart' or 'as.allStop'.\n\t\t// The result is returned by the return message\n\t\t// serviceCmdResult.\n\t\tvirtual void on_globalCmd(NLNET::TSockId from, const std::string &command)\n\t\t{\n\t\t\t// create a displayer to gather the output of the command\n\t\t\tclass CStringDisplayer: public IDisplayer\n\t\t\t{\n\t\t\tpublic:\n\t\t\t\tvirtual void doDisplay( const CLog::TDisplayInfo& args, const char *message)\n\t\t\t\t{\n\t\t\t\t\t_Data += message;\n\t\t\t\t}\n\n\t\t\t\tstd::string _Data;\n\t\t\t};\n\n\t\t\tnldebug(\"Global command from web : '%s'\", \n\t\t\t\tcommand.c_str());\n\n\t\t\t// ok, we can execute the command concerning the service.\n\t\t\tCStringDisplayer stringDisplayer;\n\t\t\tIService::getInstance()->CommandLog.addDisplayer(&stringDisplayer);\n\n\t\t\t// build the command line\n\t\t\tCSString cmdLine;\n\t\t\tcmdLine << getCommandHandlerName() << \".\" << command;\n\t\t\t// retrieve the command from the input message and execute it\n\t\t\tnlinfo (\"ADMIN: Executing global command : '%s'\", cmdLine.c_str());\n\t\t\tICommand::execute (cmdLine, IService::getInstance()->CommandLog);\n\n\t\t\t// unhook our displayer as it's work is now done\n\t\t\tIService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer);\n\n\t\t\t// send the result back to the web\n\t\t\tCAdminServiceWebItf::commandResult(from, \"\", stringDisplayer._Data);\n\t\t}\n\n\t\t// Send a service related command to the executor \n\t\t// (not to the controled service)\n\t\t// The return value is a string containing the content\n\t\t// returned by the command.\n\t\tvirtual void on_controlCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command)\n\t\t{\n\t\t\t// push the request info\n\t\t\tTPendingWebCommand\tpwc;\n\t\t\tpwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970();\n\t\t\tpwc.Command = command;\n\t\t\tpwc.ControlCommand = true;\n\t\t\tpwc.Requester = from;\n\t\t\tpwc.ServiceAlias = serviceAlias;\n\n\t\t\t_PendingWebCommands.insert(make_pair(_NextCommandId,  pwc));\n\n\t\t\t// send the request to the AES\n\t\t\tsendCommandToAES(_NextCommandId++, pwc);\n\t\t}\n\n\t\t// Send a command to the AS.\n\t\t// Send a command to a service.\n\t\t// The return value is a string containing the content returned by the\n\t\tvirtual void on_serviceCmd(NLNET::TSockId from, const std::string &serviceAlias, const std::string &command)\n\t\t{\n\t\t\t// push the request info\n\t\t\tTPendingWebCommand\tpwc;\n\t\t\tpwc.ReceptionDate = NLMISC::CTime::getSecondsSince1970();\n\t\t\tpwc.Command = command;\n\t\t\tpwc.ControlCommand = false;\n\t\t\tpwc.Requester = from;\n\t\t\tpwc.ServiceAlias = serviceAlias;\n\n\t\t\t_PendingWebCommands.insert(make_pair(_NextCommandId,  pwc));\n\n\t\t\t// send the request to the AES\n\t\t\tsendCommandToAES(_NextCommandId++, pwc);\n\t\t}\n\n\n\t\t// Get the orders of each known shard.\n\t\t// The return value is a vector of string, one entry by shard\n\t\tvirtual std::vector<std::string> on_getShardOrders(NLNET::TSockId from)\n\t\t{\n\t\t\tvector<string> ret;\n\n\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCSString orders;\n\n\t\t\t\torders << \"ShardName=\" << first->first;\n\t\t\t\torders << \"\\tOrders=\" << first->second.toString();\n\n\t\t\t\tret.push_back(orders);\n\t\t\t}\n\t\t\t\n\n\t\t\treturn ret;\n\t\t}\n\n\t\t// Get the last known state of all services.\n\t\t// The return value is a vector of string, one entry by service\n\t\tvirtual std::vector<std::string> on_getStates(NLNET::TSockId from)\n\t\t{\n\t\t\tuint32 now = NLMISC::CTime::getSecondsSince1970();\n\t\t\tvector<string> ret;\n\t\t\tTAESTracker::TTrackedModules::iterator first(_AESTracker.getTrackedModules().begin()), last(_AESTracker.getTrackedModules().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModuleProxy *aes = *first;\n\t\t\t\tconst vector<TServiceStatus>\t&status = _KnownServices[*first].ServiceStatus;\n\n\t\t\t\tuint32 aesStallDelay = now - _KnownServices[*first].LastReportDate;\n\t\t\t\tbool aesStall = aesStallDelay > AES_REPORT_WARNING_DELAY;\n\n\t\t\t\tfor (uint i=0; i<status.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tCSString state;\n\t\t\t\t\tconst TServiceStatus &ss = status[i];\n\t\t\t\t\tstate << \"ShardName=\" << ss.getShardName();\n\t\t\t\t\tstate << \"\\tLongName=\" << ss.getServiceLongName();\n\t\t\t\t\tstate << \"\\tShortName=\" << ss.getServiceShortName();\n\t\t\t\t\tstate << \"\\tAliasName=\" << ss.getServiceAliasName();\n\t\t\t\t\tif (ss.getRunningOrders() != TRunningOrders::invalid_val)\n\t\t\t\t\t\tstate << \"\\tRunningOrders=\" << ss.getRunningOrders().toString();\n\t\t\t\t\tstate << \"\\tRunningState=\" << ss.getRunningState().toString();\n\t\t\t\t\tstate << \"\\tRunningTags=\";\n\t\t\t\t\tset < TRunningTag >::const_iterator frt(ss.getRunningTags().begin()), lrt(ss.getRunningTags().end());\n\t\t\t\t\tfor (; frt != lrt; ++frt)\n\t\t\t\t\t{\n\t\t\t\t\t\tstate << frt->toString() << \" \";\n\t\t\t\t\t}\n\t\t\t\t\tstate << \"\\t\" << status[i].getStatus();\n\n\t\t\t\t\tif (aesStall)\n\t\t\t\t\t{\n\t\t\t\t\t\tstate << \"\\tAESStall=\" << toString(aesStallDelay);\n\t\t\t\t\t}\n\t\t\t\t\tret.push_back(state);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\n\t\t// Get information about a high rez graph.\n\t\t// The return is a string array containing\n\t\t// the name of the var, the available sample\n\t\t// period as two unix date (start dans end)\n\t\t// and the number of samples available\n\t\t// If the var is not found, an empty array is returned\n\t\tvirtual std::vector<std::string> on_getHighRezGraphInfo(NLNET::TSockId from, const std::string &varAddr)\n\t\t{\n\t\t\tvector<string> ret;\n\t\t\tTHighRezBuffers::iterator it(_HighRezBuffers.find(varAddr));\n\t\t\tif (it == _HighRezBuffers.end())\n\t\t\t{\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tTHighRezBuffer &buffer = it->second;\n\n\t\t\tret.push_back(varAddr);\n\t\t\tif (buffer.FrameStart == buffer.FrameEnd)\n\t\t\t{\n\t\t\t\t// the buffer is empty\n\t\t\t\tret.push_back(0);\n\t\t\t\tret.push_back(0);\n\t\t\t\tret.push_back(0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tret.push_back(toString(buffer.Datas[buffer.FrameStart].Date));\n\t\t\t\tret.push_back(toString(buffer.Datas[(buffer.FrameEnd-1)%HR_BUFFER_SIZE].Date));\n\t\t\t\tret.push_back(toString((buffer.FrameEnd - buffer.FrameStart) % HR_BUFFER_SIZE));\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\t// Get the data for a high resolution graph.\n\t\t// The return is a string array, each\n\t\t// string containing 'time:milliOffset:value\n\t\tvirtual std::vector<std::string> on_getHighRezGraph(NLNET::TSockId from, const std::string &varAddr, uint32 startDate, uint32 endDate, uint32 milliStep)\n\t\t{\n\t\t\tvector<string> ret;\n\t\t\tTHighRezBuffers::iterator it(_HighRezBuffers.find(varAddr));\n\t\t\tif (it == _HighRezBuffers.end())\n\t\t\t{\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tTHighRezBuffer &buffer = it->second;\n\n\n\t\t\tif (buffer.FrameStart == buffer.FrameEnd)\n\t\t\t{\n\t\t\t\t// the buffer is empty\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\tif (endDate == 0)\n\t\t\t{\n\t\t\t\t// the end date is zero, this mean that start date is relative\n\t\t\t\t// to the last sample date.\n\t\t\t\tendDate = buffer.Datas[(buffer.FrameEnd-1)%HR_BUFFER_SIZE].Date;\n\t\t\t\tif (endDate > startDate)\n\t\t\t\t\tstartDate = endDate - startDate;\n\t\t\t\telse\n\t\t\t\t\tstartDate = 0;\n\t\t\t}\n\n\t\t\t// advance in the buffer until we found a time greater than start date\n\t\t\tuint32 startPointer = buffer.FrameStart;\n\t\t\twhile (startPointer != buffer.FrameEnd && buffer.Datas[startPointer].Date < startDate)\n\t\t\t{\n\t\t\t\t++startPointer;\n\t\t\t\tif (startPointer == HR_BUFFER_SIZE)\n\t\t\t\t\tstartPointer = 0;\n\t\t\t}\n\n\t\t\tif (startPointer == buffer.FrameEnd)\n\t\t\t\treturn ret;\n\n\t\t\t// retrieve starting times\n\t\t\tuint32 startTime = buffer.Datas[buffer.FrameStart].Date;\n\t\t\tTTime startMilli = buffer.Datas[buffer.FrameStart].SampleTick;\n\t\t\tTTime lastSampleTick = startMilli;\n\t\t\tdouble minSample = DBL_MAX;\n\t\t\tdouble maxSample = DBL_MIN;\n\t\t\tdouble meanSample = 0;\n\t\t\tuint32 nbMergedSample = 0;\n\n\t\t\t// now collect sample in the result until end of buffer or end date\n\t\t\tfor (uint32 i=startPointer; i != buffer.FrameEnd; ++i%=HR_BUFFER_SIZE)\n\t\t\t{\n\n\t\t\t\t// check for end of time slice\n\t\t\t\tif (buffer.Datas[i].Date >= endDate)\n\t\t\t\t{\n\t\t\t\t\t// stop the loop\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tdouble value = buffer.Datas[i].Value;\n\n\t\t\t\tif (value < minSample)\n\t\t\t\t\tminSample = value;\n\t\t\t\tif (value > maxSample)\n\t\t\t\t\tmaxSample = value;\n\t\t\t\tmeanSample += value;\n\t\t\t\t++nbMergedSample;\n\n\t\t\t\tif (buffer.Datas[i].SampleTick - lastSampleTick > milliStep)\n\t\t\t\t{\n\t\t\t\t\t// output this sample\n\t\t\t\t\tuint32 date = startTime + uint32((buffer.Datas[i].SampleTick - startMilli)/1000);\n\t\t\t\t\tret.push_back(toString(\"%u : %llu : %f %f %f\", date, buffer.Datas[i].SampleTick, minSample, meanSample/nbMergedSample, maxSample));\n\t\t\t\t\tlastSampleTick = buffer.Datas[i].SampleTick;\n\n\t\t\t\t\tminSample = DBL_MAX;\n\t\t\t\t\tmaxSample = DBL_MIN;\n\t\t\t\t\tmeanSample = 0;\n\t\t\t\t\tnbMergedSample = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\n\t\t///////////////////////////////////////////////////////////////////////\n\t\t//// commands handlers\n\t\t///////////////////////////////////////////////////////////////////////\n\t\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CAdminService, CModuleBase)\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, dump, \"Dump a status report to appropriate output logger\", \"no args\")\n//\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, allStart, \"set the state of the controled domain to started\", \"no args\")\n//\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, allStop, \"set the state of the controled domain to stopped\", \"no args\")\n//\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, startShard, \"start a shard in the controled domain\", \"<shardName>\")\n//\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, stopShard, \"stop a shard in the controled domain\", \"<shardName>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, setShardStartMode, \"set the autostart mode of a shard\", \"<shardName> on|off\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CAdminService, stopShard, \"stop all service of a shard with a programmable timer (can be 0 for immediate shutdown)\", \"<shardName> <delay (s)>\")\n\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\t\tNLMISC_CLASS_COMMAND_DECL(setShardStartMode)\n\t\t{\n\t\t\tif (args.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tstring shardName = args[0];\n\n\t\t\tif (_ShardOrders.find(shardName) == _ShardOrders.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknown shard '%s'\", shardName.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tTShardOrders shardOrders;\n\t\t\tif (args[1] == \"on\")\n\t\t\t\tshardOrders = TShardOrders::so_autostart_on;\n\t\t\telse if (args[1] == \"off\")\n\t\t\t\tshardOrders = TShardOrders::so_autostart_off;\n\t\t\telse\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Invalid option '%s', must be 'on' or 'off'\", args[1].c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tsetShardOrders(shardName, shardOrders);\n\n\t\t\treturn true;\n\t\t}\n\n\n\n//\t\tNLMISC_CLASS_COMMAND_DECL(startShard)\n//\t\t{\n//\t\t\tif (args.size() != 1)\n//\t\t\t\treturn false;\n//\n//\t\t\tstring shardName = args[0];\n//\n//\t\t\tif (_ShardOrders.find(shardName) == _ShardOrders.end())\n//\t\t\t{\n//\t\t\t\tlog.displayNL(\"Unknown shard '%s'\", shardName.c_str());\n//\t\t\t\treturn true;\n//\t\t\t}\n//\n//\t\t\tsetShardOrders(shardName, TRunningOrders::ro_running);\n//\n//\t\t\treturn true;\n//\t\t}\n\n//\t\tNLMISC_CLASS_COMMAND_DECL(stopShard)\n//\t\t{\n//\t\t\tif (args.size() != 1)\n//\t\t\t\treturn false;\n//\n//\t\t\tstring shardName = args[0];\n//\n//\t\t\tif (_ShardOrders.find(shardName) == _ShardOrders.end())\n//\t\t\t{\n//\t\t\t\tlog.displayNL(\"Unknown shard '%s'\", shardName.c_str());\n//\t\t\t\treturn true;\n//\t\t\t}\n//\n//\t\t\tsetShardOrders(shardName, TRunningOrders::ro_stopped);\n//\n//\t\t\treturn true;\n//\t\t}\n//\n\n//\t\tNLMISC_CLASS_COMMAND_DECL(allStart)\n//\t\t{\n//\t\t\tif (args.size() != 0)\n//\t\t\t\treturn false;\n//\n//\t\t\tsetGlobalOrders(TRunningOrders::ro_running);\n//\n//\t\t\treturn true;\n//\t\t}\n//\n//\t\tNLMISC_CLASS_COMMAND_DECL(allStop)\n//\t\t{\n//\t\t\tif (args.size() != 0)\n//\t\t\t\treturn false;\n//\n//\t\t\tsetGlobalOrders(TRunningOrders::ro_stopped);\n//\n//\t\t\treturn true;\n//\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(stopShard)\n\t\t{\n\t\t\tif (args.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tstring shardName = args[0];\n\t\t\tuint32 delay;\n\t\t\tNLMISC::fromString(args[1], delay);\n\n\t\t\tif (_ShardOrders.find(shardName) == _ShardOrders.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknown shard '%s'\", shardName.c_str());\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// dispatch the request to all AES (they will apply to the pertinent service)\n\t\t\tCAdminExecutorServiceProxy::broadcast_shutdownShard(_AESTracker.getTrackedModules().begin(), _AESTracker.getTrackedModules().end(), \n\t\t\t\tthis, shardName, delay);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t\n\t\tNLMISC_CLASS_COMMAND_DECL(dump)\n\t\t{\n\t\t\tNLMISC_CLASS_COMMAND_CALL_BASE(CModuleBase, dump);\n\n\t\t\tlog.displayNL(\"===============================\");\n\t\t\tlog.displayNL(\" Dumping Admin states\");\n\t\t\tlog.displayNL(\"===============================\");\n\n//\t\t\tlog.displayNL(\"  Global orders is '%s'\", _GlobalOrders.toString().c_str());\n\n\t\t\tlog.displayNL(\"  There are %u known shards :\", _ShardOrders.size());\n\t\t\t{\n\t\t\t\tTShardsOrders::iterator first(_ShardOrders.begin()), last(_ShardOrders.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"  + Shard '%s' is '%s'\", first->first.c_str(), first->second.toString().c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t\tlog.displayNL(\"  There are %u AES services :\", _AESTracker.getTrackedModules().size());\n\t\t\tTAESTracker::TTrackedModules::iterator first(_AESTracker.getTrackedModules().begin()), last(_AESTracker.getTrackedModules().end());\n\t\t\tfor (; first != last; ++first)\t\t\t{\n\t\t\t\tIModuleProxy *aes = *first;\n\t\t\t\tconst vector<TServiceStatus>\t&status = _KnownServices[*first].ServiceStatus;\n\t\t\t\tlog.displayNL(\"  + AES '%s', with %u connected services\", \n\t\t\t\t\taes->getModuleName().c_str(), \n\t\t\t\t\tstatus.size());\n\n\t\t\t\tfor (uint i=0; i<status.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tconst TServiceStatus &ss = status[i];\n\t\t\t\t\tlog.displayNL(\"  |  + Service '%s' (%s): state '%s'\", \n\t\t\t\t\t\tss.getServiceAliasName().c_str(), \n\t\t\t\t\t\tss.getServiceShortName().c_str(),\n\t\t\t\t\t\tss.getStatus().c_str());\n\t\t\t\t\tlog.display(\"  |  | Shard '%s' RunningState '%s'\", \n\t\t\t\t\t\tss.getShardName().c_str(),\n\t\t\t\t\t\tss.getRunningState().toString().c_str());\n\n\t\t\t\t\tif (ss.getRunningOrders() != TRunningOrders::invalid_val)\n\t\t\t\t\t\tlog.display(\"  RunningOrders '%s'\", \n\t\t\t\t\t\t\tss.getRunningOrders().toString().c_str());\n\n\t\t\t\t\tlog.displayNL(\"\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t};\n\n\tNLNET_REGISTER_MODULE_FACTORY(CAdminService, \"AdminService\");\n\n} //namespace ADMIN\n\n"
  },
  {
    "path": "code/EVA/server/admin_service/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(admin_service WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(  admin_service\n\t\t\t\t\t\tservershare\n\t\t\t\t\t\teva_adminmodules)\n\nNL_DEFAULT_PROPS(admin_service \"Base, Services: Admin Service (AS)\")\nNL_ADD_RUNTIME_FLAGS(admin_service)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nINSTALL(TARGETS admin_service RUNTIME DESTINATION sbin COMPONENT services)\n\n\n"
  },
  {
    "path": "code/EVA/server/admin_service/admin_service.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n//-----------------------------------------------------------------------------\n// includes\n//-----------------------------------------------------------------------------\n\n#include \"nel/net/service.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n// force admin module to link in\nextern void admin_modules_forceLink();\nvoid foo()\n{\n\tadmin_modules_forceLink();\n}\n\n//-----------------------------------------------------------------------------\n// class CServiceClass \n//-----------------------------------------------------------------------------\n\nclass CServiceClass : public NLNET::IService\n{\npublic :\n\tvoid init()\n\t{\n\t}\n\n\tbool update()\n\t{\n\t\treturn true;\n\t}\n\n\tvoid release()\n\t{\n\t}\n};\n\n\n\n\n//-----------------------------------------------\n//\tNLNET_SERVICE_MAIN\n//-----------------------------------------------\n\nstatic const char* getCompleteServiceName(const IService* theService)\n{\n\tstatic std::string s;\n\ts= \"admin_service\";\n\n\tif (theService->haveLongArg(\"adminname\"))\n\t{\n\t\ts+= \"_\"+theService->getLongArg(\"adminname\");\n\t}\n\n\tif (theService->haveLongArg(\"fulladminname\"))\n\t{\n\t\ts= theService->getLongArg(\"fulladminname\");\n\t}\n\n\treturn s.c_str();\n}\n\nstatic const char* getShortServiceName(const IService* theService)\n{\n\tstatic std::string s;\n\ts= \"RAS\";\n\n\tif (theService->haveLongArg(\"shortadminname\"))\n\t{\n\t\ts= theService->getLongArg(\"shortadminname\");\n\t}\n\t\n\treturn s.c_str();\n}\n\nNLNET_SERVICE_MAIN( CServiceClass, getShortServiceName(scn), getCompleteServiceName(scn), 0, EmptyCallbackArray, \"\", \"\" );\n\n"
  },
  {
    "path": "code/EVA/server/admin_service.cfg",
    "content": "// Use with commandline: admin_service --fulladminname=admin_service --shortadminname=AS -C. -L. --nobreak --writepid\n\n// ---- config local variables\n\nASWebPort=\"46700\";\nASPort=\"46701\";\n\n#include \"common.cfg\"\n\n// ---- service NeL variables (used by ConfigFile class)\nDontUseNS = 1;\nAESAliasName= \"ras\";\n\n//Paths = {\n//\t\".\",\n//};\n\n// ---- service custom variables (used by ConfigFile class)\n\n\r// ---- service custom variables (used by CVariable class)\n\nRRDToolPath = \"../tools/rrdtool/rrdtool.exe\";\nRRDVarPath = \"save_shard/rrd_graphs\";\n\n// Variables required to be defined by other cfgs\n//AESHost=\"localhost\";\n//ASWebPort=\"46700\";\n//ASPort=\"46701\";\n\nStartCommands +=\n{\n\t// create the admin service module and open the web interface\n\t\"moduleManager.createModule AdminService as webPort=\"+ASWebPort,\n\n\t// create a gateway for aes to connect\n\t\"moduleManager.createModule StandardGateway as_gw\",\n\t// create a layer 3 server\n\t\"as_gw.transportAdd L3Server l3s\",\n\t\"as_gw.transportOptions l3s(PeerInvisible)\",\n\t\"as_gw.transportCmd l3s(open port=\"+ASPort+\")\",\n\n\t// plug the as\n\t\"as.plug as_gw\",\n};\n"
  },
  {
    "path": "code/EVA/server/client_robot/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(client_robot WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(\tclient_robot\n\t\t\t\t\t\tservershare)\n\nNL_DEFAULT_PROPS(client_robot \"Base, Client: ClientRobot\")\nNL_ADD_RUNTIME_FLAGS(client_robot)\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/client_robot/client_robot.cpp",
    "content": "﻿#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif // HAVE_CONFIG_H\n\n#include <nel/misc/window_displayer.h>\n#include <server_share/server_def.h>\n#include <server_share/lua/lua_engine.h>\n#include <server_share/lua/script_mgr.h>\n#include <server_share/lua/lua_thread.h>\n#include <server_share/lua_net/lua_network.h>\n#include <server_share/i18n_def.h>\n#include <server_share/timer.h>\n#include <nel/net/naming_client.h>\n#include <server_share/lua_net/lua_callback_client.h>\n\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace std;\n\nclass CClientRobot : public NLNET::IService\n{\npublic:\n\n    /// Init the service, load the universal time.\n    void init ()\n    {\n        \n\n        TimerManager->init();\n        LuaNetworkMgr.Init();\n        ScriptMgr.init();\n        LuaThreadMgr.Init();\n        \n    }\n\n\n    bool update ()\n    {\n        NLMISC::TTicks curr_ticks = CTime::getLocalTime();\n\t\tLocalTime.SetCurrTime(curr_ticks);\n        TimerManager->tickUpdate();\n        ScriptMgr.update();\n        LuaNetworkMgr.Update();\n        LuaThreadMgr.Update();\n        return true;\n    }\n\n    void release ()\n    {\n\t\tTimerManager->release();\n        ScriptMgr.release();\n        LuaNetworkMgr.Release();\n        LuaThreadMgr.Release();\n    }\n\n};\n\n// Service instantiation\nNLNET_SERVICE_MAIN (CClientRobot, \"ROBOT\", \"client_robot\", 0, EmptyCallbackArray, \"\", \"\");\n\n\n\n"
  },
  {
    "path": "code/EVA/server/client_robot.cfg",
    "content": "RootConfigFilename = \"common.cfg\";\n\nAESAliasName = \"robot\";\nSId = 1;\n\nDontUseNS  = 1;\nDontUseAES = 1;\n\nDisplayedVariables += { \"\", \"@Info|info\" };\n\nStartLuaScript = \"_ClientRobotMain.lua\";\n\nPaths =\n{\n\t\"./script/__Robot/\",\t\t\t\t    // for lua root script\n};\n\n/*\nLuaWorkThread =\n{\n\t\"thd_player DBSubStart.lua\",\n};\n*/\n\n"
  },
  {
    "path": "code/EVA/server/common.cfg",
    "content": "// ---- config local variables\n\n// Used by ConfigFile in EGS and WS\nShardId = 0; \n\nUpdateTimeout = 20;\n\n// Used to connect to AES (this file) and to set up AES service (admin_executor_service.cfg)\nAESPort=\"46702\";\nAESHost=\"localhost\";\n\n// ---- service NeL variables (used by ConfigFile class)\n\nWindowStyle = \"WIN\";\n\n// don't connect to the old NeLNS AES\nDontUseAES = 1;\n\n// Configure module gateway for layer 5 module comm\n/*\nStartCommands +=\n{\n\t// Create a gateway module\n\t\"moduleManager.createModule StandardGateway gw\",\n\t// add a layer 5 transport\n\t\"gw.transportAdd L5Transport l5\",\n\t// open the transport\n\t\"gw.transportCmd l5(open)\",\n\n\t/// Create default connection with admin executor service\n\t// Create a gateway module\n\t\"moduleManager.createModule StandardGateway gw_aes\",\n\t// create the admin executor service module\n\t\"moduleManager.createModule AdminExecutorServiceClient aes_client\",\n\t\"aes_client.plug gw_aes\",\n\n\t// create a layer 3 client to connect to aes gateway\n\t\"gw_aes.transportAdd L3Client aes_l3c\",\n\t\"gw_aes.transportCmd aes_l3c(connect addr=\"+AESHost+\":\"+AESPort+\")\",\n};\n*/\n\n// by default, use localhost to find the naming service\nNSHost = \"localhost:49901\";\nNSPort = 49901;\n\n// A list of vars to graph for any service\nGraphVars +=\n{\n\t\"ProcessUsedMemory\", \"60000\",\t// every minute\n};\n\nIgnoredFiles = { \"continent.cfg\", \"__read_me.txt\", \"bandit.html\", \"flora_primr.primitive\" };\n\n// Set a mainland SessionId.\n// Live: Must be 0 for ring shards, non-zero (usually ShardId) for mainland shards\n// Dev: Can be non-zero to initially connect a client to a ring shard\nNoWSShardId = ShardId;\n\n// ---- service NeL variables (used by CVariable class)\n\n// Disable generation / display of nldebug messages\nDisableNLDebug = 0;\n\n// Disable nel net verbose logging\nVerboseNETTC = 1;\nVerboseLNETL0 = 1;\nVerboseLNETL1 = 1;\nVerboseLNETL2 = 1;\nVerboseLNETL3 = 1;\nVerboseLNETL4 = 1;\nVerboseLNETL5 = 1;\nVerboseLNETL6 = 1;\n\n// If the update loop is too slow, a thread will produce an assertion.\n// By default, the value is set to 10 minutes.\n// Set to 0 for no assertion.\nUpdateAssertionThreadTimeout = 6000000;\n\n// how to sleep between 2 network updates\n// 0 = pipe\n// 1 = usleep\n// 2 = nanosleep\n// 3 = sched_yield\n// 4 = nothing\nUseYieldMethod = 0;\n\nDefaultMaxExpectedBlockSize = 200000000; // 200 M !\nDefaultMaxSentBlockSize = 200000000; // 200 M !\n\n// Will SaveFilesDirectory will be converted to a full path?\nConvertSaveFilesDirectoryToFullPath = 1;\n\n// Where to save specific shard data (ie: player backup), relatively to SaveShardRoot\nSaveFilesDirectory\t= \"\";\n\n// where to save generic shard data (ie: packed_sheet)\nWriteFilesDirectory\t= \"data_shard\";\n\n// ---- service custom variables (used by ConfigFile class)\n\nNegFiltersDebug    += { \"NETL\", \"NET\" };\nNegFiltersInfo     += { \"NETL\" };\nNegFiltersWarning  += { };\n\n// where to send error reports\nDefaultEmailSMTP = \"smtp\";\nDefaultEmailFrom = \"sanguo@0xcc.com\";\nDefaultEmailTo = \"li9chuan@qq.com\";\n\nLogDirectory = \"./log/\";\n\nLanguage = \"cn\";\n\n\n"
  },
  {
    "path": "code/EVA/server/frontend_service/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(frontend_service WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(\tfrontend_service\n\t\t\t\t\t\t#eva_adminmodules\n\t\t\t\t\t\tservershare)\n\nNL_DEFAULT_PROPS(frontend_service \"Base, Services: Frontend Service (FES)\")\nNL_ADD_RUNTIME_FLAGS(frontend_service)\n\n#ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH AND NOT MINGW) # FIXME: PCH too large (> 130MB), crashes cc1plus under MinGW\n  ADD_NATIVE_PRECOMPILED_HEADER(frontend_service ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp)\nENDIF(WITH_PCH AND NOT MINGW)\n\nINSTALL(TARGETS frontend_service RUNTIME DESTINATION sbin COMPONENT services)\n"
  },
  {
    "path": "code/EVA/server/frontend_service/frontend_service.cpp",
    "content": "﻿#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif // HAVE_CONFIG_H\n\n#include <server_share/server_def.h>\n#include <server_share/client_msg_desc.h>\n#include <server_share/lua/script_mgr.h>\n#include <server_share/lua_net/lua_network.h>\n#include <nel/misc/window_displayer.h>\n#include <nel/net/naming_client.h>\n\n#include \"frontend_service.h\"\n#include <server_share/timer.h>\n#include <server_share/lua/lua_thread.h>\n#include <server_share/client_msg_desc.h>\n\n#ifdef NL_OS_WINDOWS\n#include <Windows.h>\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace DEF;\n\n//extern void admin_modules_forceLink();\n//void foo()  {   admin_modules_forceLink();  }\n\nNLMISC::CVariable<uint32>\tVAR_PLAYER_NUM(\"fes\", \"NbPlayers\"  , \"memo\", 0);\n\nvoid CFrontEndService::init()\n{\n    LocalTime.SetCurrTime( CTime::getLocalTime() );\n\n    //string fn = IService::getInstance()->SaveFilesDirectory.toString();\n    //fn += ConfigFile.getVar(\"LogDir\").asString();\n    //fn += \"frontend_service.stat\";\n    //nlinfo(\"Frontend stat in directory '%s'\", fn.c_str());\n    //NLMISC::CFileDisplayer *Fd = new NLMISC::CFileDisplayer(fn);\n    //Loger().addDisplayer(Fd);\n    //if (WindowDisplayer) Loger().addDisplayer (WindowDisplayer);\n\n    ///////////////////////////////////////////////////\n\n    MsgDesc.LoadMsgXml();\n\n    TimerManager->init();\n    LuaThreadMgr.Init();\n    LuaNetworkMgr.Init();\n    ScriptMgr.init();\n}\n\nbool CFrontEndService::update()\n{\n    LocalTime.SetCurrTime( CTime::getLocalTime() );\n\n    ///////////////////////////////////////\n\n    TimerManager->tickUpdate();\n    ScriptMgr.update();\n    LuaNetworkMgr.Update();\n    LuaThreadMgr.Update();\n\n    return true;\n}\n\nvoid CFrontEndService::release()\n{\n    TimerManager->release();\n    ScriptMgr.release();\n    LuaNetworkMgr.Release();\n    LuaThreadMgr.Release();\n\n    google::protobuf::ShutdownProtobufLibrary();\n}\n\n\n/****************************************************************************   \n * FRONTEND SERVICE MAIN Function\n *\n * This call create a main function for a service:\n *\n *    - based on the \"CFrontEndService\" class\n *    - having the short name \"FES\"\n *    - having the long name \"frontend_service\"\n *    - listening on the port \"0\" (dynamically determined)\n *    - and shard callback set to \"CallbackArray\"\n *\n ****************************************************************************/\nNLNET_SERVICE_MAIN (CFrontEndService, \"FES\", \"frontend_service\", 0, EmptyCallbackArray, \"\", \"\")\n\n/* end of file */\n"
  },
  {
    "path": "code/EVA/server/frontend_service/frontend_service.h",
    "content": "#ifndef FRONTEND_SERVICE_H\n#define FRONTEND_SERVICE_H\n\n// We're using the NeL Service framework and layer 5\n#include <nel/misc/stop_watch.h>\n#include <nel/net/service.h>\n\n#include <vector>\n#include <string>\n\n//typedef CHashMap< TDataSetIndex, std::string> TEntityNamesMap;\n\n/**\n * CFrontEndService, based on IService5\n */\nclass CFrontEndService : public NLNET::IService\n{\npublic:\n\n    CFrontEndService():ReceiveWatch(10),\n        SendWatch(10) {}\n\n    /// Return the instance of the service\n    static CFrontEndService *instance() { return (CFrontEndService*)IService::getInstance(); }\n\n    // Initialisation\n    void init();\n    bool update();\n    void release();\n\n    NLMISC::CStopWatch\tReceiveWatch;\t\t\t\t// All Receive Sub\n    NLMISC::CStopWatch  SendWatch;\t\t\t\t\t// All Send Sub\n};\n\n#define  FrontEndService  CFrontEndService::instance()\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/frontend_service/stdpch.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdpch.h\"\n"
  },
  {
    "path": "code/EVA/server/frontend_service/stdpch.h",
    "content": "#include \"nel/misc/types_nl.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n#include <math.h>\n#include <time.h>\n#include <assert.h>\n\n#include <string>\n#include <vector>\n#include <list>\n#include <map>\n#include <set>\n#include <algorithm>\n#include <sstream>\n#include <exception>\n#include <utility>\n#include <deque>\n#include <limits>\n#include <queue>\n#include <memory>\n#include <functional>\n\n#include <nel/misc/common.h>\n#include <nel/misc/debug.h>\n\n#include <nel/misc/stream.h>\n#include <nel/misc/time_nl.h>\n#include <nel/misc/vector.h>\n#include <nel/misc/matrix.h>\n#include <nel/misc/rgba.h>\n#include <nel/misc/sheet_id.h>\n#include <nel/misc/command.h>\n#include <nel/misc/config_file.h>\n#include <nel/misc/variable.h>\n#include <nel/misc/shared_memory.h>\n#include <nel/misc/file.h>\n#include <nel/misc/path.h>\n#include <nel/misc/singleton.h>\n#include <nel/misc/string_common.h>\n#include <nel/misc/sstring.h>\n#include <nel/misc/bit_mem_stream.h>\n#include <nel/misc/o_xml.h>\n#include <nel/misc/i_xml.h>\n\n#include <nel/net/unified_network.h>\n#include <nel/net/service.h>\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <WinSock2.h>\n#\tinclude <Windows.h>\n#endif\n"
  },
  {
    "path": "code/EVA/server/frontend_service.cfg",
    "content": "RootConfigFilename = \"common.cfg\";\n\nAESAliasName = \"fes_0\";\nSId = 66;\n\nNegFiltersDebug = { \"NET\" };\n\nGraphVars +=\n{\n\t\"FPSProcessMsg\", \"60000\",\t// every minute\n};\n\nStartLuaScript = \"_FESMain.lua\";\n\nPaths =\n{\n\t\"./script/_FES/\",\t\t\t\t\t\t\t// for lua root script\n};\n\nDisplayedVariables += { \"\", \"@Info|info\", \"@LoadMsg|loadmsg\" };\n\n\nMsgCount = true;\nSaveEvent = false;\n\n"
  },
  {
    "path": "code/EVA/server/msg.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<client_messages_description>\n\n<!--\n                客户端消息转发     li9chuan@qq.com   2014\n\t\t\t\t\n\t\t\t\tname         消息名字 (key)\n\t\t\t\tsendto       需要转发到的服务器，可填多个  sendto=\"PLS EGS PDS\"\n\t\t\t\tformat       转发消息结构 :\n\t\t\t\t\t\t\t\t\t\t\tUID   : 使用userid填充。\n\t\t\t\t\t\t\t\t\t\t\tJSON  : \n\t\t\t\t\t\t\t\t\t\t\tproto消息：填写protobuf定义的名字。\n\t\t\t\t\t\t\t\t\t\t\t基础数据类型：f(float) d(double) b(bool) s(string) s8 s16 s32 s64 u8 u16 u32 u64\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\tdescription  消息描述，可用作打印log。\n-->\n\n    <proto_src path=\"./script/DataTable/proto\">\n        <file name=\"define_attrib.proto\"/>\n        <file name=\"define_pro.proto\"/>\n        <file name=\"msg_client.proto\"/>\n\t\t<file name=\"msg_doudizhu.proto\"/>\n    </proto_src>\n\n    \n    <!-- Common  -->                                                                                               \n    <leaf name=\"JF\"             sendto=\"PLS\"        format=\"UID PB.MsgJoinFreedom\"                              description=\"Join Freedom\" />\n    <leaf name=\"LR\"             sendto=\"PLS\"        format=\"UID\"                                                description=\"Leave Room\" />\n    <leaf name=\"LR_TEST\"        sendto=\"PLS\"        format=\"UID\"                                                description=\"Leave Room\" />\n    <leaf name=\"CPRM\"           sendto=\"SCH\"        format=\"UID PB.MsgCreatePrivateRoom\"                        description=\"Create Private RoomGame\" />\n    <leaf name=\"EPRM\"           sendto=\"SCH\"        format=\"UID PB.MsgEnterPrivateRoom\"                         description=\"Enter Private RoomGame\" />\n    <leaf name=\"RRM\"            sendto=\"PLS\"        format=\"UID\"       \t\t\t   \t                            description=\"Release Private RoomGame\" />\n    <leaf name=\"RNM\"            sendto=\"PLS\"        format=\"UID PB.MsgString\"                                   description=\"改名\" />\n    <leaf name=\"RHP\"            sendto=\"PLS\"        format=\"UID PB.MsgString\"                                   description=\"改头像\" />\n    <leaf name=\"INVF\"           sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"被邀请加入游戏\" />\n    <leaf name=\"MSG_OK\"         sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"领取并删除Msg\" />\n    <leaf name=\"GIFT_TIME\"      sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"\" />\n    <leaf name=\"GIFT_GET\"       sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"玩家请求领取奖励\" />\n    <leaf name=\"FST_HELP\"       sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"第一次打开过了help\" />\n    <leaf name=\"REWARD_GET\"     sendto=\"PLS\"        format=\"UID\"                                                description=\"玩家请求视频播放后的奖励\" />\n    <leaf name=\"SEND_GIFT\"      sendto=\"PLS\"        format=\"UID PB.MsgParams\"                                   description=\"牌桌内发礼物特效\" />\n\n    <leaf name=\"GLL\"            sendto=\"PLS\"        format=\"UID\"                                                description=\"Game Log List\" />\n    <leaf name=\"GLF\"            sendto=\"PLS\"        format=\"UID\"                                                description=\"Game Log Favorite\" />\n    <leaf name=\"ULF\"            sendto=\"PLS\"        format=\"UID\"                                                description=\"获取收藏夹目录 仅数据\" />\n    <leaf name=\"GL\"             sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"Game Log\" />\n    <leaf name=\"RGL\"            sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"Remove Game Log List\" />\n    <leaf name=\"RGF\"            sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"Remove Game Log Favorite\" />\n    <leaf name=\"AGF\"            sendto=\"PLS\"        format=\"UID PB.MsgInt\"                                      description=\"Add Game Log To Favorite\" />\n    \n\n    <!-- 斗地主 --> \n    <leaf name=\"DDZ_SR\"         sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"斗地主开始准备\" />\n    <leaf name=\"DDZ_CR\"         sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"斗地主取消准备\" />\n    <leaf name=\"DDZ_CG\"         sendto=\"PLS\"        format=\"UID\"             \t                                description=\"斗地主继续下一局\" />\n    <leaf name=\"DDZ_RE\"         sendto=\"PLS\"        format=\"UID PB.MsgBool\" \t                                description=\"斗地主申请解散房间\" />\n    <leaf name=\"DDZ_PS\"         sendto=\"PLS\"        format=\"UID\"                                                description=\"玩家跳过出牌\" />\n    <leaf name=\"DDZ_OC\"         sendto=\"PLS\"        format=\"UID PB.MsgCards\"                                    description=\"斗地主出牌\" />\n    <leaf name=\"DDZ_RRM\"        sendto=\"PLS\"        format=\"UID\"                                                description=\"斗地主检查IP时离开房间\" />\n    <leaf name=\"DDZ_CLR\"        sendto=\"PLS\"        format=\"UID\"             \t   \t\t                        description=\"斗地主取消限制开始游戏\" />\n    <leaf name=\"DDZ_BLC\"        sendto=\"PLS\"        format=\"UID\"             \t   \t\t                        description=\"刷新斗地主房间信息, 断线重连\" />\n    <leaf name=\"DDZ_SMPS\"       sendto=\"PLS\"        format=\"UID PB.MsgMingPaiResult\"                            description=\"游戏开始前选择是否明牌\" />\n    <leaf name=\"DDZ_DZMP\"       sendto=\"PLS\"        format=\"UID PB.MsgMingPaiResult\"                            description=\"出牌前地主选择是否明牌\" />\n    <leaf name=\"DDZ_JB\"         sendto=\"PLS\"        format=\"UID PB.MsgJiaBeiResult\"                             description=\"加倍选择\" />\n    <leaf name=\"DDZ_QDZ\"        sendto=\"PLS\"        format=\"UID PB.MsgQiangDiZhuResult\"                         description=\"抢地主选择\" />\n    \n    <leaf name=\"HTS_INFO\"       sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"玩家请求自己的战绩\" />\n    <leaf name=\"HTS_SR\"         sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"红心大战开始准备\" />\n    <leaf name=\"HTS_CR\"         sendto=\"PLS\"        format=\"UID\"             \t\t   \t                        description=\"红心大战取消准备\" />\n    <leaf name=\"HTS_TR\"         sendto=\"PLS\"        format=\"UID PB.MsgCards\"                                    description=\"传牌\" />\n    <leaf name=\"HTS_PS\"         sendto=\"PLS\"        format=\"UID\"                                                description=\"玩家跳过出牌\" />\n    <leaf name=\"HTS_OC\"         sendto=\"PLS\"        format=\"UID PB.MsgCard\"                                     description=\"红心大战出牌\" />\n    \n    \n    \n</client_messages_description>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/naming_service/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(naming_service WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(\tnaming_service\n\t\t\t\t\t\t#eva_adminmodules\n\t\t\t\t\t\t${LIBXML2_LIBRARIES}\n\t\t\t\t\t\tnelmisc\n\t\t\t\t\t\tnelnet)\n\nNL_DEFAULT_PROPS(naming_service \"Base, Services: Naming Service (NS)\")\nNL_ADD_RUNTIME_FLAGS(naming_service)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nINSTALL(TARGETS naming_service RUNTIME DESTINATION sbin COMPONENT ns)\n#INSTALL(FILES naming_service.cfg common.cfg DESTINATION ~/service COMPONENT ns)\n"
  },
  {
    "path": "code/EVA/server/naming_service/naming_service.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n\n#include <list>\n#include <string>\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/displayer.h\"\n\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/module_manager.h\"\n\n//\n// Namespaces\n//\n\nusing namespace std;\n\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\nNLMISC_COMMAND(test, \"none\", \"none\")\n{\n\tlog.displayNL(\"Raw cmd line : '%s'\", rawCommandString.c_str());\n\tlog.displayNL(\"Dumping %u parameters :\", args.size());\n\tfor (uint i=0; i<args.size(); ++i)\n\t{\n\t\tlog.displayNL(\"  %u : '%s'\", i, args[i].c_str());\n\t}\n\treturn true;\n}\n\n\n//\n// Structures\n//\n\nstruct CServiceEntry\n{\n\tCServiceEntry (TSockId sock, const vector<CInetAddress> &a, const string &n, TServiceId s) : SockId(sock), Addr(a), Name(n), SId (s), WaitingUnregistration(false), RunningState(ServiceClose) { }\n\n\tTSockId\t\t\t\t\t\tSockId;\t\t\t// the connection between the service and the naming service\n\tvector<CInetAddress>\t\tAddr;\t\t\t// address to send to the service who wants to lookup this service\n\t\t\t\t\t\t\t\t\t\t\t\t// it s possible to have more than one addr, anyway, the naming service\n\t\t\t\t\t\t\t\t\t\t\t\t// will send good address depending of the sub net address of the service\n\tstring\t\t\t\t\t\tName;\t\t\t// name of the service\n\tTServiceId\t\t\t\t\tSId;\t\t\t// id of the service\n\n\tbool\t\t\t\tWaitingUnregistration;\t\t\t// true if this service is in unregistration process (wait other service ACK)\n\tTTime\t\t\t\tWaitingUnregistrationTime;\t\t// time of the beginning of the inregistration process\n\tlist<TServiceId>\tWaitingUnregistrationServices;\t// list of service that we wait the answer\n\n    TServiceRunningState        RunningState;\n};\n\n\n\n// Helper that emulates layer5's send()\n//void sendToService( uint16 sid, CMessage& msgout );\n\n// Helper that emulate layer5's getServiceName()\nstring getServiceName( TServiceId  sid );\n\n// Helper that returns the first address of a service\nCInetAddress getHostAddress( TServiceId  sid );\n\n// Asks a service to stop and tell every one\nvoid doUnregisterService (TServiceId sid);\n\n//extern void admin_modules_forceLink();\n//void foo()\n//{\n//\tadmin_modules_forceLink();\n//}\n\n/**\n * Manager for services instances\n * (Moved from the TICKS to the NS)\n * Implementable with layer 5, here implemented in NS (layer 3)\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2003\n */\nclass CServiceInstanceManager\n{\npublic:\n\t\n\t/// Constructor\n\tCServiceInstanceManager();\n\n\t/** Add the name of a service which must not be duplicated\n\t * If uniqueOnShard is true, only one service is allowed.\n\t * If uniqueOnShard is false, one service is allowed by physical machine.\n\t */\n\tvoid\t\taddUniqueService( const std::string& serviceName, bool uniqueOnShard )\n\t{\n\t\t_UniqueServices.insert( std::make_pair( serviceName, uniqueOnShard ) );\n\t}\n\n\t/// Check if a service is allowed to start (if so, add it)\n\tbool\t\tqueryStartService( const std::string& serviceName, TServiceId  serviceId, const std::vector<NLNET::CInetAddress> &addr, string& reason );\n\n\t/// Release a service instance\n\tvoid\t\treleaseService( NLNET::TServiceId serviceId );\n\n\t/// Display information\n\tvoid\t\tdisplayInfo( NLMISC::CLog *log = NLMISC::InfoLog ) const;\n\n\t/// Make all controlled services quit\n\tvoid\t\tkillAllServices();\n\nprivate:\n\n\t/// List of restricted services\n\tstd::map< std::string, bool >\t_UniqueServices;\n\n\t/// List of granted (online) services\n\tstd::set< TServiceId >\t\t\t\t_OnlineServices;\n};\n\n\nCServiceInstanceManager *SIMInstance = NULL;\n\n\n/*\n * Constructor\n */\nCServiceInstanceManager::CServiceInstanceManager()\n{\n\tnlassert( ! SIMInstance );\n\tSIMInstance = this;\n\n\t// Note: addCallbackArray() done in CRangeMirrorManager::init()\n}\n\n\n/*\n * Check if a service is allowed to start. Answer with a GSTS (Grant Start Service) message\n */\nbool\t\tCServiceInstanceManager::queryStartService( const std::string& serviceName, TServiceId  serviceId, const vector<CInetAddress> &addr, string& reason )\n{\n\tbool grantStarting = true;\n\tstd::map< std::string, bool >::iterator ius = _UniqueServices.find( serviceName );\n\tif ( ius != _UniqueServices.end() )\n\t{\n\t\t// Service is restricted\n\t\tset< TServiceId >::iterator ios;\n\t\tbool uniqueOnShard = (*ius).second;\n\t\tfor ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )\n\t\t{\n\t\t\tstring name = getServiceName( *ios );\n\t\t\tif ( name == serviceName )\n\t\t\t{\n\t\t\t\tif ( uniqueOnShard )\n\t\t\t\t{\n\t\t\t\t\t// Only one service by shard is allowed => deny\n\t\t\t\t\tgrantStarting = false;\n\t\t\t\t\treason = toString( \"Service %s already found as %hu, must be unique on shard\", serviceName.c_str(), ios->get() );\n\t\t\t\t\tnlinfo( reason.c_str() );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Only one service by physical machine is allowed\n\n\t\t\t\t\t// Implementation for layer5\n\t\t\t\t\t//TSockId hostid1, hostid2;\n\t\t\t\t\t/*CCallbackNetBase *cnb1 = CUnifiedNetwork::getInstance()->getNetBase( serviceId, hostid1 );\n\t\t\t\t\tCCallbackNetBase *cnb2 = CUnifiedNetwork::getInstance()->getNetBase( *ios, hostid2 );\n\t\t\t\t\tif ( cnb1->hostAddress( hostid1 ).internalIPAddress() == cnb2->hostAddress( hostid2 ).internalIPAddress() )*/\n\n\t\t\t\t\t// Implementation for NS\n\t\t\t\t\tif ( addr[0].internalIPAddress() == getHostAddress( *ios ).internalIPAddress() )\n\t\t\t\t\t{\n\t\t\t\t\t\tgrantStarting = false;\n\t\t\t\t\t\treason = toString( \"Service %s already found as %hu on same machine\", serviceName.c_str(), ios->get() );\n\t\t\t\t\t\tnlinfo( reason.c_str() );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( grantStarting )\n\t{\n\t\t_OnlineServices.insert( serviceId );\n\t}\n\treturn grantStarting;\n}\n\n\n/*\n * Release a service instance\n */\nvoid\t\tCServiceInstanceManager::releaseService( NLNET::TServiceId serviceId )\n{\n\t_OnlineServices.erase( serviceId ); // not a problem if not found\n}\n\n\n/*\n * Display information\n */\nvoid\t\tCServiceInstanceManager::displayInfo( NLMISC::CLog *log ) const\n{\n\tlog->displayNL( \"Restricted services:\" );\n\tstd::map< std::string, bool >::const_iterator ius;\n\tfor ( ius=_UniqueServices.begin(); ius!=_UniqueServices.end(); ++ius )\n\t{\n\t\tlog->displayNL( \"%s -> only one per %s\", (*ius).first.c_str(), (*ius).second?\"shard\":\"machine\" );\n\t}\n\tlog->displayNL( \"Online registered services:\" );\n\tstd::set< TServiceId >::const_iterator ios;\n\tfor ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )\n\t{\n\t\tlog->displayNL( \"%s\", CUnifiedNetwork::getInstance()->getServiceUnifiedName( *ios ).c_str() );\n\t}\n}\n\n\n/*\n * Make all controlled services quit\n */\nvoid\t\tCServiceInstanceManager::killAllServices()\n{\n\t// Send to all known online services\n\tstd::set< TServiceId >::const_iterator ios;\n\tfor ( ios=_OnlineServices.begin(); ios!=_OnlineServices.end(); ++ios )\n\t{\n\t\tdoUnregisterService( (TServiceId)(*ios) );\n\t}\n}\n\n\n\n//\n// Variables\n//\n\nlist<CServiceEntry>\tRegisteredServices;\t\t/// List of all registred services\n\nuint16\t\t\t\tMinBasePort = 51000;\t/// Ports begin at 51000\nuint16\t\t\t\tMaxBasePort = 52000;\t/// (note: in this implementation there can be no more than 1000 services)\n\nconst TServiceId\tBaseSId(128);\t\t\t/// Allocated SIds begin at 128 (except for Agent Service)\n\nconst TTime\t\t\tUnregisterTimeout = 10000;\t/// After 10s we remove an unregister service if every server didn't ACK the message\n\nCCallbackServer\t\t*CallbackServer = NULL;\n\n//\n// Functions\n//\n\nbool canAccess (const vector<CInetAddress> &addr, const CServiceEntry &entry, vector<CInetAddress> &accessibleAddr)\n{\n\taccessibleAddr.clear ();\n\t\n\tif (entry.WaitingUnregistration)\n\t\treturn false;\n\n\tfor (uint i = 0; i < addr.size(); i++)\n\t{\n\t\tuint32 net = addr[i].internalNetAddress();\n\t\tfor (uint j = 0; j < entry.Addr.size(); j++)\n\t\t{\n\t\t\tif (net == entry.Addr[j].internalNetAddress())\n\t\t\t{\n\t\t\t\taccessibleAddr.push_back (entry.Addr[j]);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (accessibleAddr.empty())\n\t{\n\t\tnldebug (\"service %s-%hu is not accessible by '%s'\", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (addr).c_str ());\n\t}\n\telse\n\t{\n\t\tnldebug (\"service %s-%hu is accessible by '%s'\", entry.Name.c_str(), entry.SId.get(), vectorCInetAddressToString (accessibleAddr).c_str ());\n\t}\n\n\treturn !accessibleAddr.empty ();\n}\n\nvoid displayRegisteredServices (CLog *log = InfoLog)\n{\n\tlog->displayNL (\"Display the %d registered services :\", RegisteredServices.size());\n\tfor (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tTSockId id = (*it).SockId;\n\t\tif (id == NULL)\n\t\t{\n\t\t\tlog->displayNL (\"> %s-%hu %s '%s' %s %d addr\", (*it).Name.c_str(), it->SId.get(), \"<NULL>\", \"<NULL>\", (*it).WaitingUnregistration?\"WaitUnreg\":\"\", (*it).Addr.size());\n\t\t\tfor(uint i = 0; i < (*it).Addr.size(); i++)\n\t\t\t\tlog->displayNL (\"              '%s'\", (*it).Addr[i].asString().c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog->displayNL (\"> %s-%hu %s '%s' %s %d addr\", (*it).Name.c_str(), it->SId.get(), (*it).SockId->asString().c_str(), CallbackServer->hostAddress((*it).SockId).asString().c_str(), (*it).WaitingUnregistration?\"WaitUnreg\":\"\", (*it).Addr.size());\n\t\t\tfor(uint i = 0; i < (*it).Addr.size(); i++)\n\t\t\t\tlog->displayNL (\"              '%s'\", (*it).Addr[i].asString().c_str());\n\t\t}\n\t}\n\tlog->displayNL (\"End of the list\");\n}\n\n\nlist<CServiceEntry>::iterator effectivelyRemove (list<CServiceEntry>::iterator &it)\n{\n\t// remove the service from the registered service list\n\tnlinfo (\"Effectively remove the service %s-%hu\", (*it).Name.c_str(), it->SId.get());\n\treturn RegisteredServices.erase (it);\n}\n\n/*\n * Helper procedure for cbLookupAlternate and cbUnregister.\n * Note: name is used for a LOGS.\n */\nlist<CServiceEntry>::iterator doRemove (list<CServiceEntry>::iterator it)\n{\n\tnldebug (\"Unregister the service %s-%hu '%s'\", (*it).Name.c_str(), it->SId.get(), (*it).Addr[0].asString().c_str());\n\t\n\t// tell to everybody that this service is unregistered\n\n\tCMessage msgout (\"UNB\");\n\tmsgout.serial ((*it).Name);\n\tmsgout.serial ((*it).SId);\n\n\tvector<CInetAddress> accessibleAddress;\n\tnlinfo (\"Broadcast the Unregistration of %s-%hu to all registered services\", (*it).Name.c_str(), it->SId.get());\n\tfor (list<CServiceEntry>::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++)\n\t{\n\t\tif (canAccess((*it).Addr, (*it3), accessibleAddress))\n\t\t{\n\t\t\tCallbackServer->send (msgout, (*it3).SockId);\n\t\t\t//CNetManager::send (\"NS\", msgout, (*it3).SockId);\n\t\t\tnldebug (\"Broadcast to %s-%hu\", (*it3).Name.c_str(), it3->SId.get());\n\t\t}\n\t}\n\n\t// new system, after the unregistation broadcast, we wait ACK from all services before really remove\n\t// the service, before, we tag the service as 'wait before unregister'\n\t// if everybody didn't answer before the time out, we remove it\n\n\t(*it).SockId = NULL;\n\n\t(*it).WaitingUnregistration = true;\n\t(*it).WaitingUnregistrationTime = CTime::getLocalTime();\n\n\t// we remove all services awaiting his ACK because this service is down so it'll never ACK\n\tfor (list<CServiceEntry>::iterator itr = RegisteredServices.begin(); itr != RegisteredServices.end (); itr++)\n\t{\n\t\tfor (list<TServiceId>::iterator itw = (*itr).WaitingUnregistrationServices.begin(); itw != (*itr).WaitingUnregistrationServices.end ();)\n\t\t{\n\t\t\tif ((*itw) == (*it).SId)\n\t\t\t{\n\t\t\t\titw = (*itr).WaitingUnregistrationServices.erase (itw);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\titw++;\n\t\t\t}\n\t\t}\n\t}\n\n\tstring res;\n\tfor (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)\n\t{\n\t\tif (!(*it2).WaitingUnregistration)\n\t\t{\n\t\t\t(*it).WaitingUnregistrationServices.push_back ((*it2).SId);\n\t\t\tres += toString((*it2).SId.get()) + \" \";\n\t\t}\n\t}\n\n\tnlinfo (\"Before removing the service %s-%hu, we wait the ACK of '%s'\", (*it).Name.c_str(), (*it).SId.get(), res.c_str());\n\t\n\tif ((*it).WaitingUnregistrationServices.empty())\n\t{\n\t\treturn effectivelyRemove (it);\n\t}\n\telse\n\t{\n\t\treturn ++it;\n\t}\n\n\t// Release from the service instance manager\n\tSIMInstance->releaseService( (*it).SId );\n}\n\nvoid doUnregisterService (TServiceId sid)\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).SId == sid)\n\t\t{\n\t\t\t// found it, remove it\n\t\t\tdoRemove (it);\n\t\t\treturn;\n\t\t}\n\t}\n\tnlwarning (\"Service %hu not found\", sid.get());\n}\n\nvoid doUnregisterService (TSockId from)\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end ();)\n\t{\n\t\tif ((*it).SockId == from)\n\t\t{\n\t\t\t// it's possible that one \"from\" have more than one registred service, so we have to find in all the list\n\t\t\t// found it, remove it\n\t\t\tit = doRemove (it);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tit++;\n\t\t}\n\t}\n}\n\n/*void doUnregisterService (const CInetAddress &addr)\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).Addr == addr)\n\t\t{\n\t\t\t// found it, remove it\n\t\t\tdoRemove (it);\n\t\t\treturn;\n\t\t}\n\t}\n\tnlwarning (\"Service %s not found\", addr.asString().c_str());\n}*/\n\n/*\n * Helper function for cbRegister.\n * If alloc_sid is true, sid is ignored\n * Returns false in case of failure of sid allocation or bad sid provided\n * Note: the reply is included in this function, because it must be done before things such as syncUniTime()\n */\nbool doRegister (const string &name, const vector<CInetAddress> &addr, TServiceId sid, TSockId from, CCallbackNetBase &netbase, bool reconnection = false)\n{\n\t// Find if the service is not already registered\n\tstring reason;\n\tuint8 ok = true;\n\tbool needRegister = true;\n\t/*for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).Addr.asIPString() == addr.asIPString() )\n\t\t{\n\t\t\t// we already have a service on this address, remplace it if it's the same name\n\t\t\tif ((*it).Name == name)\n\t\t\t{\n\t\t\t\t// it's the same service, replace it\n\t\t\t\t(*it).SockId = from;\n\t\t\t\tsid = (*it).SId;\n\t\t\t\tnlinfo (\"Replace the service %s\", name.c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning (\"Try to register %s to %s but the service %s already on this address. ignore it!\", name.c_str(), addr.asIPString().c_str(), (*it).Name.c_str());\n\t\t\t\tok = false;\n\t\t\t}\n\t\t\tneedRegister = false;\n\t\t\tbreak;\n\t\t}\n\t}*/\n\n\tif (needRegister)\n\t{\n\t\tif (sid.get() == 0)\n\t\t{\n\t\t\t// we have to find a sid\n\t\t\tsid = BaseSId;\n\t\t\tbool found = false;\n\t\t\twhile (!found)\n\t\t\t{\n\t\t\t\tlist<CServiceEntry>::iterator it;\n\t\t\t\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t\t\t{\n\t\t\t\t\tif ((*it).SId == sid)\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (it == RegisteredServices.end ())\n\t\t\t\t{\n\t\t\t\t\t// ok, we have an empty sid\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsid.set(sid.get()+1);\n\t\t\t\t\tif (sid.get() == 0) // round the clock\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning (\"Service identifier allocation overflow\");\n\t\t\t\t\t\tok = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// we have to check that the user provided sid is available\n\t\t\tlist<CServiceEntry>::iterator it;\n\t\t\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t\t{\n\t\t\t\tif ((*it).SId == sid)\n\t\t\t\t{\n\t\t\t\t\tnlwarning (\"Sid %d already used by another service\", sid.get());\n\t\t\t\t\tok = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (it != RegisteredServices.end ())\n\t\t\t{\n\t\t\t\tok = true;\n\t\t\t}\n\t\t}\n\n\t\t// if ok, register the service and send a broadcast to other people\n\t\tif (ok)\n\t\t{\n\t\t\t// Check if the instance is allowed to start, according to the restriction in the config file\t\t\t\n\t\t\tif ( SIMInstance->queryStartService( name, sid, addr, reason ) )\n\t\t\t{\n\t\t\t\t// add him in the registered list\n\t\t\t\tRegisteredServices.push_back (CServiceEntry(from, addr, name, sid));\n\n\t\t\t\t// tell to everybody but not him that this service is registered\n\t\t\t\tif (!reconnection)\n\t\t\t\t{\n\t\t\t\t\tCMessage msgout (\"RGB\");\n\t\t\t\t\tTServiceId::size_type s = 1;\n\t\t\t\t\tmsgout.serial (s);\n\t\t\t\t\tmsgout.serial (const_cast<string &>(name));\n\t\t\t\t\tmsgout.serial (sid);\n\t\t\t\t\t// we need to send all addr to all services even if the service can't access because we use the address index\n\t\t\t\t\t// to know which connection comes.\n\t\t\t\t\tmsgout.serialCont (const_cast<vector<CInetAddress> &>(addr));\n\t\t\t\t\tnlinfo (\"The service is %s-%d, broadcast the Registration to everybody\", name.c_str(), sid.get());\n\n\t\t\t\t\tvector<CInetAddress> accessibleAddress;\n\t\t\t\t\tfor (list<CServiceEntry>::iterator it3 = RegisteredServices.begin(); it3 != RegisteredServices.end (); it3++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// send only services that can be accessed and not itself\n\t\t\t\t\t\tif ((*it3).SId != sid && canAccess(addr, (*it3), accessibleAddress))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCallbackServer->send (msgout, (*it3).SockId);\n\t\t\t\t\t\t\t//CNetManager::send (\"NS\", msgout, (*it3).SockId);\n\t\t\t\t\t\t\tnldebug (\"Broadcast to %s-%hu\", (*it3).Name.c_str(), it3->SId.get());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// set the sid only if it s ok\n\t\t\t\tfrom->setAppId (sid.get());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Reply \"startup denied\", and do not send registration to other services\n\t\t\t\tok = false;\n\t\t\t}\n\t\t}\n\n\t\t// send the message to the service to say if it s ok or not\n\t\tif (!reconnection)\n\t\t{\n\t\t\t// send the answer to the client\n\t\t\tCMessage msgout (\"RG\");\n\t\t\tmsgout.serial (ok);\n\t\t\tif (ok)\n\t\t\t{\n\t\t\t\tmsgout.serial (sid);\n\n\t\t\t\t// send him all services available (also itself)\n\t\t\t\tTServiceId::size_type nb = 0;\n\n\t\t\t\tvector<CInetAddress> accessibleAddress;\n\n\t\t\t\tfor (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)\n\t\t\t\t{\n\t\t\t\t\t// send only services that are available\n\t\t\t\t\tif (canAccess(addr, (*it2), accessibleAddress))\n\t\t\t\t\t\tnb++;\n\t\t\t\t}\n\t\t\t\tmsgout.serial (nb);\n\n\t\t\t\tfor (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t\t\t{\n\t\t\t\t\t// send only services that are available\n\t\t\t\t\tif (canAccess(addr, (*it), accessibleAddress))\n\t\t\t\t\t{\n\t\t\t\t\t\tmsgout.serial ((*it).Name);\n\t\t\t\t\t\tmsgout.serial ((*it).SId);\n\t\t\t\t\t\tmsgout.serialCont ((*it).Addr);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmsgout.serial( reason );\n\t\t\t}\n\t\t\t\n\t\t\tnetbase.send (msgout, from);\n\t\t\tnetbase.flush (from);\n\t\t}\n\t}\n\n\t//displayRegisteredServices ();\n\n\treturn ok!=0;\n}\n\nvoid checkWaitingUnregistrationServices ()\n{\n\tfor (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end ();)\n\t{\n\t\tif ((*it).WaitingUnregistration && ((*it).WaitingUnregistrationServices.empty() || CTime::getLocalTime() > (*it).WaitingUnregistrationTime + UnregisterTimeout))\n\t\t{\n\t\t\tif ((*it).WaitingUnregistrationServices.empty())\n\t\t\t{\n\t\t\t\tnlinfo (\"Removing the service %s-%hu because all services ACKd the removal\", (*it).Name.c_str(), (*it).SId.get());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstring res;\n\t\t\t\tfor (list<TServiceId>::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++)\n\t\t\t\t{\n\t\t\t\t\tres += toString(it2->get()) + \" \";\n\t\t\t\t}\n\t\t\t\tnlwarning (\"Removing the service %s-%hu because time out occurs (service numbers %s didn't ACK)\", (*it).Name.c_str(), (*it).SId.get(), res.c_str());\n\t\t\t}\n\t\t\tit = effectivelyRemove (it);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tit++;\n\t\t}\n\t}\n}\n\n\n/**\n * Callback for service unregistration ACK. Mean that a service was ACK the unregistration broadcast\n */\nstatic void cbACKUnregistration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tTServiceId sid;\n\tmsgin.serial (sid);\n\n\tfor (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).SId == sid && (*it).WaitingUnregistration)\n\t\t{\n\t\t\tfor (list<TServiceId>::iterator it2 = (*it).WaitingUnregistrationServices.begin(); it2 != (*it).WaitingUnregistrationServices.end (); it2++)\n\t\t\t{\n\t\t\t\tif (*it2 == TServiceId(uint16(from->appId())))\n\t\t\t\t{\n\t\t\t\t\t// remove the acked service\n\t\t\t\t\t(*it).WaitingUnregistrationServices.erase (it2);\n\t\t\t\t\tcheckWaitingUnregistrationServices ();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/**\n * Callback for service registration when the naming service goes down and up (don't need to broadcast)\n */\nstatic void cbResendRegisteration (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tstring name;\n\tvector<CInetAddress> addr;\n\tTServiceId sid;\n\tmsgin.serial (name);\n\tmsgin.serialCont (addr);\n\tmsgin.serial (sid);\n\n\tdoRegister (name, addr, sid, from, netbase, true);\n}\n\n\n\n/**\n * Callback for service registration.\n *\n * Message expected : RG\n * - Name of service to register (string)\n * - Address of service (CInetAddress)\n *\n * Message emitted : RG\n * - Allocated service identifier (TServiceId) or 0 if failed\n */\nstatic void cbRegister (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tstring name;\n\tvector<CInetAddress> addr;\n\tTServiceId sid;\n\tmsgin.serial (name);\n\tmsgin.serialCont (addr);\n\tmsgin.serial (sid);\n\n\tdoRegister (name, addr, sid, from, netbase);\n}\n\n\n/**\n * Callback for service unregistration.\n *\n * Message expected : UNI\n * - Service identifier (TServiceId)\n */\nstatic void cbUnregisterSId (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tTServiceId sid;\n\tmsgin.serial( sid );\n\n\tdoUnregisterService (sid);\n\t//displayRegisteredServices ();\n}\n\n/**\n * Callback for service set state.\n *\n * Message expected : SSS\n */\nstatic void cbSetSerivceState (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n    TServiceId  sid;\n    uint32      state;\n    msgin.serial( sid );\n    msgin.serial( state );\n\n    CMessage msgout (\"USS\");\n    msgout.serial (sid);\n    msgout.serial (state);\n\n    for (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n    {\n        if ( it->SId == sid )\n        {\n            it->RunningState = (TServiceRunningState)state;\n        }\n\n        CallbackServer->send (msgout, (*it).SockId);\n    }\n}\n\n/*\n * Helper function for cbQueryPort\n *\n * \\warning QueryPort + Registration is not atomic so more than one service could ask a port before register\n */\nuint16 doAllocatePort (const CInetAddress &addr)\n{\n\tstatic uint16 nextAvailablePort = MinBasePort;\n\n\t// check if nextavailableport is free\n\n\tif (nextAvailablePort >= MaxBasePort) nextAvailablePort = MinBasePort;\n\n\tbool ok;\n\tdo\n\t{\n\t\tok = true;\n\t\tlist<CServiceEntry>::iterator it;\n\t\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t{\n\t\t\tif ((*it).Addr[0].port () == nextAvailablePort)\n\t\t\t{\n\t\t\t\tnextAvailablePort++;\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\twhile (!ok);\n\n\treturn nextAvailablePort++;\n}\n\n\n/**\n * Callback for port allocation\n * Note: if a service queries a port but does not register itself to the naming service, the\n * port will remain allocated and unused.\n *\n * Message expected : QP\n * - Name of service to register (string)\n * - Address of service (CInetAddress) (its port can be 0)\n *\n * Message emitted : QP\n * - Allocated port number (uint16)\n */\nstatic void cbQueryPort (CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t// Allocate port\n\tuint16 port = doAllocatePort (netbase.hostAddress (from));\n\n\t// Send port back\n\tCMessage msgout (\"QP\");\n\tmsgout.serial (port);\n\tnetbase.send (msgout, from);\n\n\tnlinfo (\"The service got port %hu\", port);\n}\n\n\n/*\n * Unregisters a service if it has not been done before.\n * Note: this callback is called whenever someone disconnects from the NS.\n * May be there are too many calls if many clients perform many transactional lookups.\n */\nstatic void cbDisconnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg )\n{\n\tdoUnregisterService (from);\n\t//displayRegisteredServices ();\n}\n\n/*\n * a service is connected, send him all services infos\n */\nstatic void cbConnect /*(const string &serviceName, TSockId from, void *arg)*/ ( TSockId from, void *arg )\n{\n\t// we have to wait the registred services message to send all services because it this points, we can't know which sub net\n\t// the service can use\n\n\t//displayRegisteredServices ();\n\n\t// set the appid with a bad id (-1)\n\tfrom->setAppId (~0);\n}\n\n/*// returns the list of accessible services with a list of address\nstatic void cbRegisteredServices(CMessage& msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tvector<CInetAddress> addr;\n\tmsgin.serialCont (addr);\n\n\tnlinfo (\"New service ask me the available services, sending him all services available\");\n\t// send to the new service the list of all services that this service can access (depending of his sub net)\n\n\tCMessage msgout (\"RGB\");\n\n\tuint8 nb = 0;\n\n\tvector<CInetAddress> accessibleAddress;\n\n\tfor (list<CServiceEntry>::iterator it2 = RegisteredServices.begin(); it2 != RegisteredServices.end (); it2++)\n\t{\n\t\t// send only services that are available\n\t\tif (canAccess(addr, (*it2), accessibleAddress))\n\t\t\tnb++;\n\t}\n\n\tmsgout.serial (nb);\n\n\tfor (list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\t// send only services that are available\n\t\tif (canAccess(addr, (*it), accessibleAddress))\n\t\t{\n\t\t\tmsgout.serial ((*it).Name);\n\t\t\tmsgout.serial ((*it).SId);\n\t\t\tmsgout.serialCont (accessibleAddress);\n\t\t}\n\t}\n\n\tCNetManager::send (\"NS\", msgout, from);\n}*/\n\n\n/*\n * Helper that emulates layer5 send()\n */\n/*void sendToService( uint16 sid, CMessage& msgout )\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).SId == sid)\n\t\t{\n\t\t\tCallbackServer->send (msgout, (*it).SockId);\n\t\t}\n\t}\n}*/\n\n\n/*\n * Helper that emulate layer5's getServiceName()\n */\nstring getServiceName( TServiceId  sid )\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).SId == sid)\n\t\t{\n\t\t\treturn (*it).Name;\n\t\t}\n\t}\n\treturn \"\"; // not found\n}\n\n\n/*\n * Helper that returns the first address of a service\n */\nCInetAddress getHostAddress( TServiceId  sid )\n{\n\tlist<CServiceEntry>::iterator it;\n\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).SId == sid)\n\t\t{\n\t\t\treturn (*it).Addr[0];\n\t\t}\n\t}\n\treturn CInetAddress();\n}\n\n\n//\n// Callback array\n//\n\nTCallbackItem CallbackArray[] =\n{\n\t{ \"RG\", cbRegister },\n\t{ \"RRG\", cbResendRegisteration },\n\t{ \"QP\", cbQueryPort },\n\t{ \"UNI\", cbUnregisterSId },\n\t{ \"ACK_UNI\", cbACKUnregistration },\n//\t{ \"RS\", cbRegisteredServices },\n\n    { \"SSS\", cbSetSerivceState },\n};\n\n\n//\n// Service\n//\n\nclass CNamingService : public NLNET::IService\n{\npublic:\n\n\t/**\n\t * Init\n\t */\n\tvoid init()\n\t{\n\t\t// if a baseport is available in the config file, get it\n\t\tCConfigFile::CVar *var;\n\t\tif ((var = ConfigFile.getVarPtr (\"BasePort\")) != NULL)\n\t\t{\n\t\t\tuint16 newBasePort = var->asInt ();\n\t\t\tnlinfo (\"Changing the MinBasePort number from %hu to %hu\", MinBasePort, newBasePort);\n\t\t\tsint32 delta = MaxBasePort - MinBasePort;\n\t\t\tnlassert (delta > 0);\n\t\t\tMinBasePort = newBasePort;\n\t\t\tMaxBasePort = MinBasePort + uint16 (delta);\n\t\t}\n\n\t\t// Parameters for the service instance manager\n\t\ttry\n\t\t{\n\t\t\tCConfigFile::CVar& uniqueServices = ConfigFile.getVar(\"UniqueOnShardServices\");\n\t\t\tfor ( uint i=0; i!=uniqueServices.size(); ++i )\n\t\t\t{\n\t\t\t\t_ServiceInstances.addUniqueService( uniqueServices.asString(i), true );\n\t\t\t}\n\t\t}\n\t\tcatch(const Exception &)\n\t\t{}\n\t\ttry\n\t\t{\n\t\t\tCConfigFile::CVar& uniqueServicesM = ConfigFile.getVar(\"UniqueByMachineServices\");\n\t\t\tfor ( uint i=0; i!=uniqueServicesM.size(); ++i )\n\t\t\t{\n\t\t\t\t_ServiceInstances.addUniqueService( uniqueServicesM.asString(i), false );\n\t\t\t}\n\t\t}\n\t\tcatch(const Exception &)\n\t\t{}\n\n/*\n\t\t// we don't try to associate message from client\n\t\tCNetManager::getNetBase (\"NS\")->ignoreAllUnknownId (true);\n\n\t\t// add the callback in case of disconnection\n\t\tCNetManager::setConnectionCallback (\"NS\", cbConnect, NULL);\n\t\t\n\t\t// add the callback in case of disconnection\n\t\tCNetManager::setDisconnectionCallback (\"NS\", cbDisconnect, NULL);\n*/\n\t\t// DEBUG\n\t\t// DebugLog->addDisplayer( new CStdDisplayer() );\n\n\t\tvector<CInetAddress> v = CInetAddress::localAddresses();\n\t\tnlinfo (\"%d detected local addresses:\", v.size());\n\t\tfor (uint i = 0; i < v.size(); i++)\n\t\t{\n\t\t\tnlinfo (\" %d - '%s'\",i, v[i].asString().c_str());\n\t\t}\n\n\t\tuint16 nsport = 50000;\n\t\tif ((var = ConfigFile.getVarPtr (\"NSPort\")) != NULL)\n\t\t{\n\t\t\tnsport = var->asInt ();\n\t\t}\n\n\t\tCallbackServer = new CCallbackServer;\n\t\tCallbackServer->init(nsport);\n\t\tCallbackServer->addCallbackArray(CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));\n\t\tCallbackServer->setConnectionCallback(cbConnect, NULL);\n\t\tCallbackServer->setDisconnectionCallback(cbDisconnect, NULL);\n\t}\n\n\t/**\n\t * Update\n\t */\n\tbool update ()\n\t{\n\t\tcheckWaitingUnregistrationServices ();\n\n\t\tCallbackServer->update ();\n\n\t\treturn true;\n\t}\n\n\tvoid release()\n\t{\n\t\tif (CallbackServer != NULL)\n\t\t\tdelete CallbackServer;\n\t\tCallbackServer = NULL;\n\t}\n\nprivate:\n\n\t/// Service instance manager singleton\n\tCServiceInstanceManager\t\t_ServiceInstances;\n};\n\n\nstatic const char* getCompleteServiceName(const IService* theService)\n{\n\tstatic std::string s;\n\ts= \"naming_service\";\n\n\tif (theService->haveLongArg(\"nsname\"))\n\t{\n\t\ts+= \"_\"+theService->getLongArg(\"nsname\");\n\t}\n\n\tif (theService->haveLongArg(\"fullnsname\"))\n\t{\n\t\ts= theService->getLongArg(\"fullnsname\");\n\t}\n\n\treturn s.c_str();\n}\n\nstatic const char* getShortServiceName(const IService* theService)\n{\n\tstatic std::string s;\n\ts= \"NS\";\n\n\tif (theService->haveLongArg(\"shortnsname\"))\n\t{\n\t\ts= theService->getLongArg(\"shortnsname\");\n\t}\n\t\n\treturn s.c_str();\n}\n//\n/// Naming Service\n//\nNLNET_SERVICE_MAIN( CNamingService, getShortServiceName(scn), getCompleteServiceName(scn), 0, EmptyCallbackArray, \"\", \"\")\n\n\n//\n// Commands\n//\n\n\nNLMISC_COMMAND (nsServices, \"displays the list of all registered services\", \"\")\n{\n\tif(args.size() != 0) return false;\n\n\tdisplayRegisteredServices (&log);\n\n\treturn true;\n}\n\nNLMISC_COMMAND (kill, \"kill a service and send an unregister broadcast to other service\", \"<ServiceShortName>|<ServiceId>\")\n{\n\tif(args.size() != 1) return false;\n\n\t// try with number\n\n\tuint16 serviceId;\n\tNLMISC::fromString(args[0], serviceId);\n\n\tTServiceId sid(serviceId);\n\n\tif(sid.get() == 0)\n\t{\n\t\t// not a number, try a name\n\t\tlist<CServiceEntry>::iterator it;\n\t\tfor (it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t{\n\t\t\tif ((*it).Name == args[0])\n\t\t\t{\n\t\t\t\tsid = (*it).SId;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (it == RegisteredServices.end())\n\t\t{\n\t\t\tlog.displayNL (\"Bad service name or id '%s'\", args[0].c_str());\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tdoUnregisterService (sid);\n\treturn true;\n}\n\nNLMISC_DYNVARIABLE(uint32, NbRegisteredServices, \"display the number of service that are registered in naming service\")\n{\n\tif (get) *pointer = (uint32)RegisteredServices.size();\n}\n\nNLMISC_COMMAND( displayServiceInstances, \"SIM: Display info on service instances\", \"\" )\n{\n\tSIMInstance->displayInfo( &log );\n\treturn true;\n}\n\nNLMISC_COMMAND( killAllServices, \"SIM: Make all the controlled services quit\", \"\" )\n{\n\tSIMInstance->killAllServices();\n\treturn true;\n}\n"
  },
  {
    "path": "code/EVA/server/naming_service.cfg",
    "content": "// link the common configuration file\n#include \"common.cfg\"\n\nDisplayedVariables += { \"\", \"@Services|nsServices\" };\n\nSId = 69;\n\nDontUseNS = 1;\nAESAliasName = \"rns\";\n\nNegFiltersDebug = { \"NETL\" };\nNegFiltersInfo = { \"NETL\" };\n\nUniqueOnShardServices = {};\nUniqueByMachineServices = {};\n\n"
  },
  {
    "path": "code/EVA/server/player_logic_service/CMakeLists.txt",
    "content": "FILE(GLOB SRC \t\t\t\t\t\t*.cpp *.h)\n\nADD_EXECUTABLE(player_logic_service WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(  player_logic_service\n                        #eva_adminmodules\n\t\t\t\t\t\tservershare\n\t\t\t\t\t\t)\n\nNL_DEFAULT_PROPS(player_logic_service \"Base, Services: Player Logic Service (PLS)\")\nNL_ADD_RUNTIME_FLAGS(player_logic_service)\n\n#ADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH AND NOT MINGW) # FIXME: PCH too large (> 130MB), crashes cc1plus under MinGW\n  ADD_NATIVE_PRECOMPILED_HEADER(player_logic_service ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp)\nENDIF(WITH_PCH AND NOT MINGW)\n\nINSTALL(TARGETS player_logic_service RUNTIME DESTINATION sbin COMPONENT services)\n"
  },
  {
    "path": "code/EVA/server/player_logic_service/player_logic_service.cpp",
    "content": "﻿#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif // HAVE_CONFIG_H\n\n#include <nel/misc/window_displayer.h>\n#include <server_share/server_def.h>\n#include <server_share/lua/lua_engine.h>\n#include <server_share/lua/script_mgr.h>\n#include <server_share/lua/lua_thread.h>\n#include <server_share/lua_net/lua_network.h>\n#include <server_share/i18n_def.h>\n#include <server_share/timer.h>\n\n#include <nel/net/naming_client.h>\n\n\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace std;\n\nCFileDisplayer *Fd = NULL;\nCStdDisplayer Sd;\n\n//extern void admin_modules_forceLink();\n//void foo()\n//{\n//    admin_modules_forceLink();\n//}\n\nvoid displayInfo ()\n{\n    ICommand::execute (\"info\", *NLMISC::InfoLog);\n}\n\nclass CPlayerLogicService : public NLNET::IService\n{\npublic:\n\n    /// Init the service, load the universal time.\n    void init ()\n    {\n        TimerManager->init();\n        LuaNetworkMgr.Init();\n        ScriptMgr.init();\n        LuaThreadMgr.Init();\n    }\n\n\n    bool update ()\n    {\n        NLMISC::TTicks curr_ticks = CTime::getLocalTime();\n\t\tLocalTime.SetCurrTime(curr_ticks);\n        TimerManager->tickUpdate();\n        ScriptMgr.update();\n        LuaNetworkMgr.Update();\n        LuaThreadMgr.Update();\n        return true;\n    }\n\n    void release ()\n    {\n\t\tTimerManager->release();\n        ScriptMgr.release();\n        LuaNetworkMgr.Release();\n        LuaThreadMgr.Release();\n\n        google::protobuf::ShutdownProtobufLibrary();\n    }\n\n};\n\n// Service instantiation\nNLNET_SERVICE_MAIN (CPlayerLogicService, LogicService.c_str(), \"player_logic_service\", 0, EmptyCallbackArray, \"\", \"\");\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/player_logic_service/player_logic_service.h",
    "content": "#ifndef PLAYER_LOGIC_SERVICE_H\n#define PLAYER_LOGIC_SERVICE_H\n\n// we have to include windows.h because mysql.h uses it but not include it\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/log.h\"\n\n#include \"nel/net/service.h\"\n\n\n\n\n#endif // PLAYER_LOGIC_SERVICE_H\n\n/* End of player_logic_service.h */\n"
  },
  {
    "path": "code/EVA/server/player_logic_service/stdpch.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdpch.h\"\n"
  },
  {
    "path": "code/EVA/server/player_logic_service/stdpch.h",
    "content": "#include \"nel/misc/types_nl.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n#include <math.h>\n#include <time.h>\n#include <assert.h>\n\n#include <string>\n#include <vector>\n#include <list>\n#include <map>\n#include <set>\n#include <algorithm>\n#include <sstream>\n#include <exception>\n#include <utility>\n#include <deque>\n#include <limits>\n#include <queue>\n#include <memory>\n#include <functional>\n\n#include <nel/misc/common.h>\n#include <nel/misc/debug.h>\n\n#include <nel/misc/stream.h>\n#include <nel/misc/time_nl.h>\n#include <nel/misc/vector.h>\n#include <nel/misc/command.h>\n#include <nel/misc/config_file.h>\n#include <nel/misc/variable.h>\n#include <nel/misc/shared_memory.h>\n#include <nel/misc/file.h>\n#include <nel/misc/path.h>\n#include <nel/misc/singleton.h>\n#include <nel/misc/string_common.h>\n#include <nel/misc/sstring.h>\n#include <nel/misc/bit_mem_stream.h>\n#include <nel/misc/o_xml.h>\n#include <nel/misc/i_xml.h>\n\n#include <nel/net/unified_network.h>\n#include <nel/net/service.h>\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <WinSock2.h>\n#\tinclude <Windows.h>\n#endif\n"
  },
  {
    "path": "code/EVA/server/player_logic_service.cfg",
    "content": "RootConfigFilename = \"common.cfg\";\n\nAESAliasName = \"lgc_0\";\nSId = 1;\n\nDisplayedVariables += { \"\", \"@Info|info\", \"@LoadConfig|loadconfig\", \"@Hotfix|hotfix\" };\n\nStartLuaScript = \"_PLSMain.lua\";\n\nPaths =\n{\n\t\"./script/_PLS/\",\t\t\t\t\t\t\t// for lua root script\n};\n\n"
  },
  {
    "path": "code/EVA/server/save_shard/rrd_graphs/hold_dir",
    "content": ""
  },
  {
    "path": "code/EVA/server/schedule_service/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(schedule_service WIN32 ${SRC})\n\nINCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(\tschedule_service\n\t\t\t\t\t\t#eva_adminmodules\n\t\t\t\t\t\tservershare)\n\nNL_DEFAULT_PROPS(schedule_service \"Base, Services: Schedule Service (SCH)\")\nNL_ADD_RUNTIME_FLAGS(schedule_service)\n\nINSTALL(TARGETS schedule_service RUNTIME DESTINATION sbin COMPONENT services)\n"
  },
  {
    "path": "code/EVA/server/schedule_service/schedule_service.cpp",
    "content": "﻿#ifdef HAVE_CONFIG_H\n#include \"config.h\"\n#endif // HAVE_CONFIG_H\n\n#include <server_share/tools.h>\n#include <server_share/server_def.h>\n#include <server_share/client_msg_desc.h>\n#include <server_share/lua/script_mgr.h>\n#include <server_share/lua_net/lua_network.h>\n#include <nel/misc/window_displayer.h>\n#include <nel/net/naming_client.h>\n\n#include <server_share/timer.h>\n#include <server_share/lua/lua_thread.h>\n\n#ifdef NL_OS_WINDOWS\n#include <Windows.h>\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace DEF;\n\n//extern void admin_modules_forceLink();\n//void foo()  {   admin_modules_forceLink();  }\n\nclass CScheduleService : public NLNET::IService\n{\npublic:\n    void init();\n    bool update();\n    void release();\n};\n\nvoid CScheduleService::init()\n{\n    LocalTime.SetCurrTime( CTime::getLocalTime() );\n\n    TimerManager->init();\n    LuaThreadMgr.Init();\n    LuaNetworkMgr.Init();\n    ScriptMgr.init();\n}\n\nbool CScheduleService::update()\n{\n    TimerManager->tickUpdate();\n    ScriptMgr.update();\n    LuaNetworkMgr.Update();\n    LuaThreadMgr.Update();\n\n    return true;\n}\n\nvoid CScheduleService::release()\n{\n    TimerManager->release();\n    ScriptMgr.release();\n    LuaNetworkMgr.Release();\n    LuaThreadMgr.Release();\n\n    google::protobuf::ShutdownProtobufLibrary();\n}\n\n\n/****************************************************************************   \n * SCHEDULE SERVICE MAIN Function\n *\n * This call create a main function for a service:\n *\n *    - based on the \"CScheduleService\" class\n *    - having the short name \"SCH\"\n *    - having the long name \"schedule_service\"\n *    - listening on the port \"0\" (dynamically determined)\n *    - and shard callback set to \"CallbackArray\"\n *\n ****************************************************************************/\nNLNET_SERVICE_MAIN (CScheduleService, \"SCH\", \"schedule_service\", 49971, EmptyCallbackArray, \"\", \"\")\n\n/* end of file */\n"
  },
  {
    "path": "code/EVA/server/schedule_service.cfg",
    "content": "RootConfigFilename = \"common.cfg\";\n\nAESAliasName = \"egs\";\nSId          =  65;\n\nNegFiltersDebug = { \"NET\" };\n\nStartLuaScript = \"_SCHMain.lua\";\n\nPaths =\n{\n\t\"./script/_SCH/\",\t\t\t\t\t\t\t// for lua root script\n};\n\nDisplayedVariables += { \"\", \"@Info|info\" };\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/.vs/ProjectSettings.json",
    "content": "{\n  \"CurrentProjectSetting\": null\n}"
  },
  {
    "path": "code/EVA/server/script/.vs/VSWorkspaceState.json",
    "content": "{\n  \"ExpandedNodes\": [\n    \"\",\n    \"\\\\Framework\",\n    \"\\\\Framework\\\\Net\",\n    \"\\\\_PLS\",\n    \"\\\\_PLS\\\\Games\",\n    \"\\\\_PLS\\\\Room\"\n  ],\n  \"PreviewInSolutionExplorer\": false\n}"
  },
  {
    "path": "code/EVA/server/script/BaseService.luaprj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<Project Name=\"BaseService.luaprj\" Cmd=\"E:\\BaseService\\build\\bin\\Debug\\client_robot.exe\" Arg=\"\" Dir=\"E:\\BaseService\\code\\EVA\\server\" Toggle=\"true\" >\n    <Filter RelativePath=\".\\Framework\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\Class.lua\" />\n        <LuaFile RelativePath=\".\\functions.lua\" />\n        <LuaFile RelativePath=\".\\List.lua\" />\n        <LuaFile RelativePath=\".\\Map.lua\" />\n        <LuaFile RelativePath=\".\\MiddleClass.lua\" />\n        <LuaFile RelativePath=\".\\Queue.lua\" />\n        <LuaFile RelativePath=\".\\Stack.lua\" />\n        <LuaFile RelativePath=\".\\StateFul.lua\" />\n        <Filter RelativePath=\".\\Event\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\EventController.lua\" />\n            <LuaFile RelativePath=\".\\EventRegister.lua\" />\n            <LuaFile RelativePath=\".\\EventTrigger.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Net\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\NetWorkHandler.lua\" />\n            <LuaFile RelativePath=\".\\BaseService.lua\" />\n            <LuaFile RelativePath=\".\\protobuf.lua\" />\n            <LuaFile RelativePath=\".\\CallbackServer.lua\" />\n        </Filter>\n        <LuaFile RelativePath=\".\\InitFramework.lua\" />\n        <LuaFile RelativePath=\".\\Utils.lua\" />\n        <LuaFile RelativePath=\".\\TimerMgr.lua\" />\n        <LuaFile RelativePath=\".\\CJsonUtil.lua\" />\n        <Filter RelativePath=\".\\Test\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\MainTest.lua\" />\n            <LuaFile RelativePath=\".\\FSMClass.lua\" />\n            <LuaFile RelativePath=\".\\TimerTest.lua\" />\n        </Filter>\n        <LuaFile RelativePath=\".\\SimpleStateMachine.lua\" />\n        <LuaFile RelativePath=\".\\MapMap.lua\" />\n        <Filter RelativePath=\".\\Hotfix\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\hotfix.lua\" />\n            <LuaFile RelativePath=\".\\HotfixHelper.lua\" />\n            <Filter RelativePath=\".\\internal\" Toggle=\"true\" >\n                <LuaFile RelativePath=\".\\functions_replacer.lua\" />\n                <LuaFile RelativePath=\".\\module_updater.lua\" />\n            </Filter>\n        </Filter>\n        <LuaFile RelativePath=\".\\MemoryReferenceInfo.lua\" />\n    </Filter>\n    <Filter RelativePath=\".\\SharedLib\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\StaticTableMgr.lua\" />\n        <LuaFile RelativePath=\".\\InitSharedLib.lua\" />\n        <Filter RelativePath=\".\\Event\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\EventType.lua\" />\n        </Filter>\n    </Filter>\n</Project>"
  },
  {
    "path": "code/EVA/server/script/DataTable/RoomConfig.json",
    "content": "{\n  \"RM_DDZ\": {\n    \"room_type\": \"RM_DDZ\",\n    \"game_type\": \"GM_DDZ\",\n    \"app_name\": \"APP_DDZ\",\n    \"min_ver\": 1.16,\n    \"match\": \"private\",\n    \"room_name\": \"斗地主\",\n    \"enter_level\": 0,\n    \"enter_score\": 0,\n    \"room_max\": 3,\n    \"room_min\": 3,\n    \"viewer_max\": 5,\n    \"is_goback\": 1,\n    \"auto_return\": 1,\n    \"room_time\": 28800,\n    \"room_icon\": \"icon_yule\",\n    \"room_bg\": \"Texture/BackGround/nj_mahjong_room_logo_4\",\n    \"game_icon\": \"Texture/BackGround/hall_game_icon_4\",\n    \"game_bg\": \"Texture/BackGround/hall_game_bg\",\n    \"enter_game_scene\": \"BlackJackScene\",\n    \"enter_room_scene\": \"jiuguan\"\n  }\n}"
  },
  {
    "path": "code/EVA/server/script/DataTable/RoomCreateCost.json",
    "content": "{\n  \"1001\": {\n    \"cost_id\": 1001,\n    \"room_type\": \"RM_DDZ\",\n    \"game_cnt\": 4,\n    \"item_id\": 5001,\n    \"cost_num\": 2\n  },\n  \"1002\": {\n    \"cost_id\": 1002,\n    \"room_type\": \"RM_DDZ\",\n    \"game_cnt\": 8,\n    \"item_id\": 5001,\n    \"cost_num\": 3\n  },\n  \"1003\": {\n    \"cost_id\": 1003,\n    \"room_type\": \"RM_DDZ\",\n    \"game_cnt\": 16,\n    \"item_id\": 5001,\n    \"cost_num\": 6\n  }\n}"
  },
  {
    "path": "code/EVA/server/script/DataTable/SpecialConfig.json",
    "content": "{\n  \"RM_DDZ\": {\n    \"multi_boom\": 3,\n    \"multi_ct\": 3,\n    \"add_times\": 2,\n    \"game_type\": \"GM_DDZ\"\n\n  }\n}"
  },
  {
    "path": "code/EVA/server/script/DataTable/proto/define_attrib.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nenum TAttribType\n{\n\tINVALID_ATTRIB                           =\t0;\n\n\tID\t=\t2001001\t;\n\tLEVEL_UP_EXP_INT\t=\t2001002\t;\n\tNAME_STRING\t=\t2001003\t;\n\tLIFE_INT\t=\t2001004\t;\n\tLIFE_CURR_INT\t=\t2001005\t;\n\n};\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/DataTable/proto/define_pro.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nenum TEvent\n{\n\tEventInvalid\t\t\t                = 0;  \t\t//  无效事件\n    EventPlayerUp\t                        = 2;  \t\t//  玩家升级\t \n\tEventCostMoney                          = 40; \t\t//  消费金钱\n\tEventLogin                              = 46;\t\t//  玩家登录\n};\n\n\n///  标识占据第几位   0-63\nenum TPlayerFlagBit\n{\n\tPLAYER_FLAG_TEST_0                      = 0;\t\t//\t玩家第一次做xx事的标识位\n\tPLAYER_FLAG_FIRST_CARD_ONE              = 1;\t\t//\t\n\tPLAYER_FLAG_FIRST_CARD_TEN              = 2;\t\t//\t\n\t\n};\n\nenum TErrorType\n{\n\tINVALID_TYPE                            = 0;\n\t\n\tACCOUNT_LOGGED                          = 1;\n\tSERVER_FULL                             = 2;\n\tSERVER_NOT_OPEN                         = 3;\n\tTEXT_SUCESS                             = 4;\n\tTEXT_FAIL                               = 5;\n\tPWD_ERROR                               = 6;\n\tPLAYER_ONLINE_TO_FES                    = 7;\n\tPLAYER_EXISTS                           = 8;\n\tPLAYER_RELOAD                           = 9;\n\tSUCESS                                  = 23;\n\tNO_AUTH_TYPE                            = 24;\n\tCONFIG_NOT_FOUND                        = 33;\t\t// 配置未找到\n\tNOT_ENOUGH_MONEY                        = 37;\t\t//\t金币不足\n\t\n\tPLAYER_BASE_ERROR                       = 128;\t\t//\t玩家基本数据不正确\n\t\n};\n\nenum TGender\n{\n\tMALE          = 0;\t//\t男性\n\tFEMALE        = 1;\t//\t女性\n};\n\n\n// 房间付费方式\nenum TGameConsumePay\n{\n\tTGC_GOLD \t= 0;\n\tTGC_SILVER\t= 1;\n}\n\n//房间付费机制\nenum TPaymentMechanism\n{\n    ROOM_OWNER_OPTION   = 0; // 房主;\n    AA_SYSTEM_OPTION    = 1; // AA制;\n    BIG_OWNER_OPTION    = 2; // 大赢家;\n\tVIP_TISSUE_OPTION   = 3; // 消耗高级牌友圈房卡;\n}\n\nenum TRoomCmdRecord\n{\n\tRC_ACTION_NULL \t\t\t\t\t= 0;        // 用户过牌;\n\tRC_ACTION_START_GAME\t\t\t= 1;\t\t// 游戏开始;      ( MsgRecordNodeList 中的 card_value[0] 为 会儿皮 )\n\tRC_ACTION_OPERATE_RESULT \t\t= 2;\t\t// 用户选择权限结果;\n\tRC_ACTION_SEND_CARD\t\t\t\t= 3;\t\t// 用户发牌;\n\tRC_ACTION_OUT_CARD\t\t\t\t= 4;\t\t// 用户出牌;\n\tRC_ACTION_SHOWDOWN_DIANPAO\t\t= 5;\t\t// 用户点炮胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) \n\tRC_ACTION_SHOWDOWN_ZIMO\t\t\t= 6;\t\t// 用户自摸胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN_QIANGGANGHU\t= 7;\t\t// 用户抢杠胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN_LIUJU\t\t= 8; \t\t// 用户流局胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN\t\t\t\t= 9; \t\t// 进入结算\n\tRC_ACTION_CONTRACT\t\t\t\t= 10; \t\t// 户承包关系;  ( MsgRecordNodeList 中的 TarGetID 为承包id 、 ActionID为被承包id )\n\tRC_ACTION_SEND_FLOWER_CARD\t\t= 11; \t\t// 用户抓牌花牌;  ( MsgRecordNodeList 中的 card_index 为 flower_num )\n\tRC_ACTION_START_FLOWER_CARD\t\t= 12; \t\t// 用户手牌补花;  ( MsgRecordNodeList 中的 card_index 为 flower_num )\n\tRC_ACTION_OPERATE_CHOICE\t\t= 13; \t\t// 用户选择权限;\n\tRC_ACTION_MINGLOU\t\t\t\t= 14; \t\t// 用户明楼;\n\tRC_ACTION_SEND_HAND_CARD\t\t= 15; \t\t// 用户发送手牌;\n\tRC_ACTION_CATHECTIC\t\t\t\t= 16; \t\t// 用户下注;\n\tRC_ACTION_HUNYOU\t\t\t    = 17; \t\t// 用户混悠;\n\tRC_ACTION_TRUST_STATE\t\t\t= 18; \t\t// 用户托管状态;\n}\n\n\nenum TShowDownEvent\n{\n\tEVENT_XIAOHU \t\t\t\t= 1;\t// 小胡;\n\tEVENT_MEIHUI \t\t\t\t= 2;\t// 没会;\n\tEVENT_HUIGUIWEI\t\t\t\t= 3;\t// 会归位;\n\tEVENT_GANGKAIHUA\t\t\t= 4;\t// 杠开花;\n\tEVENT_TIANHU \t\t\t\t= 5;\t// 天胡;\n\tEVENT_DIHU \t\t\t\t\t= 6;\t// 地胡;\n\tEVENT_SIGEHUI\t\t\t\t= 7;\t// 四个会;\n\tEVENT_QIDUI \t\t\t\t= 8;\t// 七对;\n\tEVENT_QINGQIDUI\t\t\t\t= 9;\t// 清七对;\n\tEVENT_HAOHUAQIDUI\t\t\t= 10;\t// 豪华七对;\n\tEVENT_CHAOHUAQIDUI  \t\t= 11;\t// 超豪华七对;\n\tEVENT_CHAOCHAOHAOHUAQIDUI\t= 12;\t// 超超豪华七对;\n\tEVENT_ZHUANGJIA \t\t\t= 13;\t// 庄家;\n\tEVENT_MINGGANG \t\t\t\t= 14;\t// 明杠;\n\tEVENT_ANGANG\t\t\t\t= 15;\t// 暗杠;\n\tEVENT_SIXIFENG\t\t\t\t= 16;\t// 四喜风;\n\tEVENT_SANZHIJIAN \t\t\t= 17;\t// 三支箭;\n\tEVENT_HUIMINGGANG\t\t\t= 18;\t// 会明杠;\n\tEVENT_HUIANGANG\t\t\t\t= 19;\t// 会暗杠;\n\tEVENT_MENG\t\t\t\t\t= 20;\t// 梦;\n\tEVENT_GENZHUANG\t\t\t\t= 21;\t// 跟庄(罚款);\n\tEVENT_SHISANYAO\t\t\t\t= 22;\t// 十三幺;\n\tEVENT_LONG\t\t\t\t\t= 23;\t// 一条龙;\n\tEVENT_QINGYISE\t\t\t\t= 24;\t// 清一色;\n\tEVENT_HUNYISE\t\t\t\t= 25;\t// 混一色;\n\tEVENT_PENGPENGHU\t\t\t= 26;\t// 碰碰胡;\n\tEVENT_JIANGYISE\t\t\t\t= 27;\t// 将一色;\n\tEVENT_HAIDILAOYUE\t\t\t= 28;\t// 海底捞月;\n\tEVENT_HUGANGFANG\t\t\t= 29;\t// 胡杠放;\n\tEVENT_WUHUAGUO   \t\t\t= 30;\t// 无花果;\n\tEVENT_TING\t\t\t\t\t= 31;\t// 听牌;\n\tEVENT_PFFLOWER              = 32;   // 碰风花;\n\tEVENT_KOU_PAI\t\t\t\t= 33;\t// 扣牌;\n\tEVENT_THREE_ZUAN            = 34;   // 三钻;\n    EVENT_FOUR_ZUAN             = 35;   // 四钻;\n\tEVENT_DIAOWUWAN             = 36;   // 吊五万;\n\tEVENT_ZHUOWUKUI             = 37;   // 捉五魁;\n\tEVENT_ZHI_GANG              = 38;   // 直杠;\n\tEVENT_DIANPAO               = 39;   // 点炮;\n\tEVENT_ZIMO                  = 40;   // 自摸;\n\tEVENT_QIANGGANGHU           = 41;   // 抢杠胡;\n\tEVENT_BASESCORE             = 42;   // 底分;\n\tEVENT_JIAPINGHU             = 43;   // 夹平胡;\n\tEVENT_SHISANBUKAO           = 44;   // 十三不靠;\n\tEVENT_PAOPEIPINGHU          = 45;   // 跑配平胡;\n\tEVENT_PAOPEIQIDUI           = 46;   // 跑配七对;\n\tEVENT_KANHUI\t            = 47;   // 砍会\n\tEVENT_MINGLOU\t            = 48;   // 明楼\n\tEVENT_XIAOGANGKAIHUA\t\t= 49;\t// 小杠开花;\n\tEVENT_HUANGZHUANG\t\t\t= 50;\t// 荒庄;\n\tEVENT_HAOHUAQQIDUI\t\t\t= 51;\t// 豪华清七对;\n\tEVENT_CHAOHUAQQIDUI  \t\t= 52;\t// 超豪华清七对;\n\tEVENT_CHAOCHAOHAOHUAQQIDUI\t= 53;\t// 超超豪华清七对;\n\tEVENT_PIAOCAI               = 54;   // 飘财;\n\tEVENT_BAOTOU                = 55;   // 爆头;\n\tEVENT_LAOZHUANG             = 56;   // 老庄;\n\tEVENT_DASANYUAN             = 57;   // 大三元\n\tEVENT_DIAOYU                = 58;   // 钓鱼\n\tEVENT_SUIJIYISE             = 59;   // 随机清一色\n\tEVENT_LANPAI                = 60;   // 烂牌\n\tEVENT_QIXINGLANPAI          = 61;   // 七星烂牌\n\tEVENT_SANCAISHEN\t        = 62;   // 三财神\n\tEVENT_QIFENGDAO\t\t        = 63;   // 七风倒\n\tEVENT_QIFENGBAIDA           = 64;   // 七风百搭\n\tEVENT_SHISANBAIDA           = 65;   // 十三白搭\n\tEVENT_QUANFENGZI            = 66;   // 全风子\n\tEVENT_DANDIAO\t            = 67;   // 单吊\n\tEVENT_WUCAI\t\t            = 68;   // 无财\n\tEVENT_QUANFENGZIPENGPENGHU  = 69;   // 全风子大碰胡\n\tEVENT_QUANFENGZIQIDUI       = 70;   // 全风子七对子\n\tEVENT_DIANPAOFEN       \t\t= 71;   // 点炮分\n\tEVENT_QIANGGANGHUFEN        = 72;   // 抢杠胡分\n\tEVENT_ZIMOFEN\t\t        = 73;   // 自摸分\n\tEVENT_DUIDUIHU\t\t\t\t= 74;\t// 对对胡\n\tEVENT_MEIBAIDA\t\t\t\t= 75;\t// 没百搭\n\tEVENT_SANBAIDA\t\t\t\t= 76;\t// 三百搭\n\tEVENT_DADIAOCHE\t\t\t\t= 77;\t// 大吊车\n\tEVENT_SHUANGPIAO            = 78;   // 双飘财\n\tEVENT_SANPIAO               = 79;   // 三飘财\n\tEVENT_LANBAIDA              = 80;   // 烂百搭\n\tEVENT_FENGZIBAIDA\t\t\t= 81;\t// 风字百搭\n\tEVENT_SIHUA\t\t\t\t\t= 82;\t// 四花牌\n\tEVENT_CHUNHUA\t\t\t\t= 83;\t// 纯花\n\tEVENT_PENGFENGHUA\t\t\t= 84;\t// 碰风花\n\tEVENT_GANGHUA\t\t\t\t= 85;\t// 杠花\n\tEVENT_HUNPENG\t\t\t\t= 86;\t// 混碰\n\tEVENT_QINGPENG\t\t\t\t= 87;\t// 清碰\n\tEVENT_HUNQIDUI\t\t\t\t= 88;\t// 混七对\n\tEVENT_HUAPAI                = 89;   // 花牌\n\tEVENT_GUODAN                = 90;   // 过蛋儿\n\tEVENT_MENQING               = 91;   // 闭门（门前清）\n\tEVENT_SANJIABIMEN           = 92;   // 三家闭门\n\tEVENT_SHOWBAYI              = 93;   // 手把一\n\tEVENT_SIGUIYI               = 94;   // 四归一\n\tEVENT_XUANFENGGANG          = 95;   // 旋风杠\n\tEVENT_JIEGANG               = 96;   // 借杠\n\tEVENT_ZIYISE                = 97;   // 随机字一色\n\tEVENT_TESHUYISE             = 98;   // 特殊清一色\n\tEVENT_19LAOTOUBAIDA\t\t\t= 99;\t// 19老头百搭\n\tEVENT_QIANGANGXIAOHU        = 100;  // 强杠小胡\n\tEVENT_BUQIUREN              = 101;  // 不求人清一色\n\tEVENT_CONTRACT\t\t\t\t= 102;\t// 承包\n\tEVENT_ZHAMA\t\t\t\t\t= 103;\t// 扎码\n\tEVENT_HUNBAZHANG            = 104;  // 胡八张\n\tEVENT_QUEYIMEN              = 105;  // 缺一门\n\tEVENT_HUIDIAO               = 106;  // 会吊\n\tEVENT_QINGHU                = 107;  // 清胡\n\tEVENT_HUIDIAOHUI            = 108;  // 会吊会\n\tEVENT_PIAOHU\t            = 109;  // 飘胡\n\tEVENT_THREEBIAN\t            = 110;  // 三边\n\tEVENT_FOURBIAN\t            = 111;  // 四边\n\tEVENT_SUHU                  = 112;  // 素胡\n\tEVENT_HUNDIAOHUN            = 113;  // 会吊会\n\tEVENT_DAIZHUANG             = 114;  // 带庄\n\tEVENT_JIA1FEN             \t= 115;  // 加1分\n\tEVENT_JIA2FEN             \t= 116;  // 加2分\n\tEVENT_WUZI             \t\t= 117;  // 无字;\n\tEVENT_KANZHANG             \t= 118;  // 坎张;\n\tEVENT_BIANZHANG             = 119;  // 边张;\n\tEVENT_SBALUOHAN             = 120;  // 十八罗汉\n\tEVENT_HONGZGBAO             = 121;  // 红中宝          \n\tEVENT_QUEYI\t                = 122;  // 缺一\n\tEVENT_LUANYAO               = 123;  // 乱幺;\n\tEVENT_BAO3QIANGGANGHU\t\t= 124;\t// 包三抢杠胡\n\tEVENT_ERWUBAJIANG           = 125;  // 258将\n\tEVENT_GUJIANG               = 126;  // 孤将\n\tEVENT_DUANYAOJIU            = 127;  // 断幺九\n\tEVENT_YIBIANGAO             = 128;  // 一边高\n\tEVENT_GULIANLIU             = 129;  // 孤连六\n\tEVENT_DAXIAOWU              = 130;  // 大小五\n\tEVENT_GOUSHAN               = 131;  // 够扇\n\tEVENT_ZHONGFABAI            = 132;  // 中发白\n\tEVENT_THREEZA               = 133;  // 三砸\n\tEVENT_FOURZA                = 134;  // 四砸\n\tEVENT_KAWUKUI               = 135;  // 卡五魁\n\tEVENT_ANXIAO                = 136;  // 暗潇\n\tEVENT_SANGEYI               = 137;  // 三个一\n\tEVENT_SANGEJIU              = 138;  // 三个九\n\tEVENT_SUQIDUI               = 139;  // 素七对\n\tEVENT_HUIDIAOQIXIAODUI      = 140;  // 会吊七小对\n\tEVENT_MANGUAN               = 141;  // 满贯\n\tEVENT_HUIBENLONG            = 142;  // 本会儿龙\n\tEVENT_DIAOWUKUI             = 143;  // 吊五魁\n\tEVENT_LAZHUANG              = 144;  // 拉庄\n\tEVENT_LIUGANG               = 145;  // 流杠\n\tEVENT_SULONG                = 146;  // 素龙\n\tEVENT_HUNLONG\t\t\t\t= 147;  // 混龙\n\tEVENT_HEIFENG\t\t\t\t= 148;  // 黑风\n\tEVENT_HONGFENG\t\t\t\t= 149;  // 红风\n\tEVENT_YIJIU     \t\t\t= 150;  // 一九\n\tEVENT_ZMH_PH\t\t\t\t= 151;\t// 桥东自摸屁胡\n\tEVENT_ZMH_MQ\t\t\t\t= 152;\t// 桥东自摸门清\n\tEVENT_QGH_PH\t\t\t\t= 153;\t// 桥东抢杠胡屁胡\n\tEVENT_QGH_MQ\t\t\t\t= 154;\t// 桥东抢杠胡门清\n\tEVENT_DPH_PH\t\t\t\t= 155;\t// 桥东点炮胡屁胡\n\tEVENT_DPH_MQ\t\t\t\t= 156;\t// 桥东点炮胡门清\n\tEVENT_QYS_LONG\t\t\t\t= 157;\t// 清一色+一条龙\n\tEVENT_LIANGXI\t\t\t\t= 158;\t// 亮喜\n\tEVENT_BUXI\t\t\t\t\t= 159;\t// 补喜\n\tEVENT_PENG\t\t\t\t\t= 160;\t// 碰\n\tEVENT_DAJIANG    \t\t\t= 161;\t// 大将\n\tEVENT_FENGYISE    \t\t\t= 162;\t// 风一色\n\tEVENT_QIDUIHUIDIAO          = 163;  // 七对会调\n\tEVENT_QIDUIHUIDIAOHUI       = 164;  // 七对会调会\n\tEVENT_DASIXI       \t\t\t= 165;  // 大四喜\n\tEVENT_XIAOSIXI       \t\t= 166;  // 小四喜\n\tEVENT_XIAOSANYUAN       \t= 167;  // 小三元\n\tEVENT_GANGGANGHU \t\t\t= 168;  // 杠杠胡\n\tEVENT_BUHUAHU \t\t\t\t= 169;  // 花上\n\tEVENT_LIANGTAIHUA \t\t\t= 170;  // 两台花\n\tEVENT_LIANGTAIHUAQUEYI \t\t= 171;  // 两台花缺一\n\tEVENT_HUAGANG\t\t \t\t= 172;  // 花杠\n\tEVENT_HUISCORE              = 173;  // 混儿加分\n\tEVENT_HUWEI                 = 174;  // 胡尾\n\tEVENT_ANKAN                 = 175;  // 暗坎\n\tEVENT_HUNERDIAO             = 176;  // 混儿吊\n\tEVENT_PINGHU                = 177;  // 平胡\n\tEVENT_HUNERYOU              = 178;  // 混儿悠\n\tEVENT_YITIAOZHENLONG        = 179;  // 一条真龙\n\tEVENT_YITIAOJIALONG         = 180;  // 一条假龙\n\tEVENT_HUANGJINGANG          = 181;  // 黄金杠\n\tEVENT_ZMH_PH_PINGHU\t\t\t= 182;\t// 桥东自摸屁胡，平胡（上面是大胡）\n\tEVENT_ZMH_MQ_PINGHU\t\t\t= 183;\t// 桥东自摸门清，平胡\n\tEVENT_QGH_PH_PINGHU\t\t\t= 184;\t// 桥东抢杠胡屁胡，平胡\n\tEVENT_QGH_MQ_PINGHU\t\t\t= 185;\t// 桥东抢杠胡门清，平胡\n\tEVENT_DPH_PH_PINGHU\t\t\t= 186;\t// 桥东点炮胡屁胡，平胡\n\tEVENT_DPH_MQ_PINGHU\t\t\t= 187;\t// 桥东点炮胡门清，平胡\n\tEVENT_PINGHU_MINGGANG\t\t= 188;\t// 平胡明杠（桥东用，相对于大胡）\n\tEVENT_PINGHU_ANGANG\t\t\t= 189;\t// 平胡暗杠（桥东）\n\tEVENT_DIANPAO_QIDUI\t\t\t= 190;\t// 点炮七对（桥东）\n\tEVENT_ZIMO_QIDUI\t\t\t= 191;\t// 自摸七对（桥东）\n\tEVENT_PINGHU_GENZHUANG\t\t= 192;\t// 平胡跟庄(罚款)（桥东用）;\n\tEVENT_FAGANG \t\t\t\t= 193;  // 满城罚杠;\n\tEVENT_ZIMOFENGKE            = 194;  // 自摸风刻(天台);\n\tEVENT_ZIMOFENGDIAO          = 195;  // 自摸风调(天台);\n\tEVENT_ZIMOKE                = 196;  // 自摸刻子(天台);\n\tEVENT_ZIMOJIA               = 197;  // 自摸夹子(天台);\n\tEVENT_ZIMODIAO              = 198;  // 自摸单调(天台);\n\tEVENT_DIANPAOKE             = 199;  // 点炮刻字(天台);\n\tEVENT_DIANPAODIAO           = 200;  // 点炮单调(天台);\n    EVENT_DIANPAOJIA            = 201;  // 点炮夹子(天台);\n\tEVENT_FENGKEZI              = 202;  // 风刻子(天台);\n\tEVENT_NORMALKEZI            = 203;  // 正常刻子(天台);\n\tEVENT_ZIJIAHUA              = 204;  // 自家花(天台);\n\tEVENT_SIGEHUA               = 205;  // 四个花(天台);\n\tEVENT_BAGEHUA               = 206;  // 八个花(天台);\n    EVENT_BIANKADIAOSANQI       = 207;  // 边卡吊三七;\n\tEVENT_ZIJIAPENG             = 208;  // 自家碰(天台);\n\tEVENT_ZIJIAKEZI             = 209;  // 自家刻(天台);\n\tEVENT_HONGZHONGPENG         = 210;  // 红中碰(天台);\n\tEVENT_HONGZHONGKEZI         = 211;  // 红中刻(天台);\n\tEVENT_FACAIPENG             = 212;  // 发财碰(天台);\n\tEVENT_FACAIKEZI             = 213;  // 发财刻(天台);\n\tEVENT_HUJUEZHANG            = 214;  // 胡绝张\n\tEVENT_YIBANGAO              = 215;  // 一般高\n\tEVENT_LIANLIU               = 216;  // 连六\n\tEVENT_QUANLAOTOU\t\t\t= 217;\t// 全老头\n\tEVENT_LUANLAOTOU\t\t\t= 218;\t// 乱老头\n\tEVENT_SANBAIDAZUOKE\t\t\t= 219;\t// 三百搭作刻\n\tEVENT_CHUBAIDA\t\t\t\t= 220;\t// 出百搭\n\tEVENT_CHAOQIANGGANGHU \t\t= 221;\t// 超抢杠胡(东台);\n\tEVENT_DUISHANGGANG \t\t\t= 222;\t// 对上杠(东台);\n\tEVENT_DUITIANTING \t\t\t= 223;\t// 对天听(东台);\n\tEVENT_DUIDANDIAO \t\t\t= 224;\t// 对单钓(东台);\n\tEVENT_SHANGGANG \t\t\t= 225;\t// 上杠(东台);\n\tEVENT_TIANTING \t\t\t\t= 226;\t// 天听(东台);\n\tEVENT_GANGSHANGDIANPAO \t\t= 227;\t// 杠上点炮(东台);\n\tEVENT_BAIDADUIZUOTOU\t\t= 228;\t// 百搭对作头（嘉善硬自摸）\n\tEVENT_SHUANGGANKAN\t\t\t= 229;\t// 双干坎（嘉善硬自摸）\n\tEVENT_GANGKAIHUIDIAOHUI\t\t= 230;\t// 杠开会吊会儿\n\tEVENT_HUIDIAOLONG\t\t\t= 231;\t// 会吊龙\n\tEVENT_HUIDIAOBENHUILONG\t\t= 232;\t// 会吊本会龙\n\tEVENT_ZHANGMAO\t\t\t\t= 233;\t// 长毛\n\tEVENT_ZIJIAGANG             = 234;  // 自家杠(天台);\n\tEVENT_HONGZHONGGANG         = 235;  // 红中杠(天台);\n\tEVENT_FACAIGANG             = 236;  // 发财杠(天台);\n\tEVENT_ZIJIADUI              = 237;  // 自家对子(天台);\n\tEVENT_FACAIDUI              = 238;  // 发财对子(天台);\n\tEVENT_HONGZHONGDUI          = 239;  // 红中对子(天台);\n\tEVENT_YIJIUCARD             = 240;  // 1，9 组合(清河);\n\tEVENT_HUADUIZIJIA           = 241;  // 花墩子+\n\tEVENT_HUADUIZIJIAN          = 242;  // 花墩子-\n\tEVENT_QYS_QIDUI\t\t\t\t= 243;\t// 清一色+七对\t\n\tEVENT_ZHONGMA\t\t\t\t= 244;  // 中马  (自由麻将)\n\tEVENT_PENGHOUGANG\t\t\t= 245;  // 碰后杠(自由麻将)\n\tEVENT_QYS_HUIDIAO\t\t\t= 246;  // 清一色混吊(易县麻将)\n\tEVENT_ZIMOWUHUN \t\t\t= 247;  // 自摸无混(易县麻将)\n\tEVENT_HENGYIHENGJIU\t\t\t= 248;\t// 清河横一横九\n\tENENT_CAIFENG\t\t\t\t= 249;\t// 清河彩风组合\n\tEVENT_DDZDIFEN              = 250;  // 斗地主底分\n\tEVENT_ZHADAN                = 251;  // 斗地主炸弹翻倍\n\tEVENT_CHUNTIAN              = 252;  // 斗地主春天翻倍\n\tEVENT_MINGPAI               = 253;  // 斗地主明牌翻倍\n\tEVENT_DIPAI                 = 254;  // 斗地主底牌翻倍\n\tEVENT_QIANGDIZHU            = 255;  // 斗地主抢地主翻倍\n\tEVENT_JIABEI                = 256;  // 斗地主加倍翻倍\n\tEVENT_JIAOFEN               = 257;  // 斗地主叫分翻倍\n\tEVENT_XIAOWANG              = 258;  // 斗地主底牌小王翻倍\n\tEVENT_DAWANG                = 259;  // 斗地主底牌大王翻倍\t\n\tEVENT_DUIZI                 = 260;  // 斗地主底牌对子翻倍\n\tEVENT_TONGHUA               = 261;  // 斗地主底牌同花翻倍\n\tEVENT_SHUNZI                = 262;  // 斗地主底牌顺子翻倍\n\tEVENT_SANZHANG              = 263;  // 斗地主底牌三张翻倍\n\tEVENT_TONGHUASHUN           = 264;  // 斗地主底牌同花顺翻倍\t\n\tEVENT_DAIYIJIU              = 265;  // 带一九\n\tEVENT_LONGQIDUI             = 266;  // 龙七对\n\tEVENT_GEN                   = 267;  // 根\n\tEVENT_JINGOUHU              = 268;  // 金钩胡\n\tEVENT_ZHONGZHANG            = 269;  // 中张\n\tEVENT_GANGSHANGPAO          = 270;  // 杠上炮\n\tEVENT_DIANPAOHU             = 271;  // 点炮胡\n\tEVENT_BEIZIMO               = 272;  // 被自摸\n\tEVENT_ZIMOHU                = 273;  // 自摸胡\n\tEVENT_GUAFENG               = 274;  // 刮风\n\tEVENT_BEIGUAFENG            = 275;  // 被刮风\n\tEVENT_XIAYU                 = 276;  // 下雨\n\tEVENT_BEIXIAYU              = 277;  // 被下雨\n\tEVENT_MIANXIAGANG           = 278;  // 面下杠(二次杠)\n\tEVENT_BEIMIANXIAGANG        = 279;  // 被面下杠(二次杠)\n\tEVENT_HUJIAOZHUANYI         = 280;  // 呼叫转移\n\tEVENT_BEIHUJIAOZHUANYI      = 281;  // 被呼叫转移\n\tEVENT_CHAHUAZHU             = 282;  // 查花猪\n\tEVENT_CHAJIAO               = 283;  // 查叫\n\tEVENT_BEICHAHUAZHU          = 284;  // 被查花猪\n\tEVENT_BEICHAJIAO            = 285;  // 被查叫\n\t\n}\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/DataTable/proto/msg_client.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nimport \"define_pro.proto\";\n\nmessage MsgLogin\n{\n  optional string       Version         = 1;\n  optional string       Channel         = 2;\n  optional string       AppName         = 3;\n  optional string       User            = 4;\n  optional string       NonceStr        = 5;\n  optional string       Token           = 6;\n  optional uint64       Timestamp       = 7;\n  optional uint64       UID             = 8;\n  optional string       RoomType        = 9;\n  \n  \n}\n\nmessage MsgPlayerInfo\n{\n  optional uint64       UID             = 1;\n  optional string       Nickname        = 2;\n  optional uint32       Portrait        = 3;\n  optional uint64       Money           = 4;\n  optional uint64       RMB             = 5;\n  optional uint32       Main            = 6;\n  optional uint64       FlagBit         = 7;\n}\n\nmessage MsgCreatePrivateRoom\n{\n\toptional uint32 \t\t\t\tconsume_id          = 1;\n\toptional TGameConsumePay \t\tconsume_kind\t \t= 2;\n\toptional string \t\t\t\troom_type\t        = 3;\n\toptional uint32 \t\t    \tspecial_kind        = 4;\n\toptional uint32 \t\t\t \tscore   \t        = 5;\n\toptional uint32 \t\t\t\tgame_versione\t\t= 6;\n\toptional TPaymentMechanism\t\tpay_ment\t\t    = 7;\n\toptional uint32\t\t\t\t\tplayer_number\t\t= 8;\n\toptional uint64\t\t\t\t\ttissue_id\t\t\t= 9;\n}\n\nmessage MsgEnterPrivateRoom\n{\n\toptional uint64\t\t\t\t\troom_id\t\t\t\t= 1;\n    optional string                 room_type           = 2;\n\toptional string \t\t\t\tapp_name\t\t\t= 3;\n\toptional uint32\t\t\t\t\tgame_version\t\t= 4;\n}\n\nmessage MsgCard\n{\n\toptional uint32                 card                = 1;\n}\n\nmessage MsgCards\n{\n    optional uint32                 type                = 1;\n\trepeated uint32                 cards               = 2;\n}\n\nmessage MsgInt\n{\n\toptional int64      value        = 1;\n}\n\nmessage MsgBool\n{\n\toptional bool       value        = 1;\n}\n\nmessage MsgString\n{\n\toptional string     str        = 1;\n}\n\nmessage MsgError\n{\n\toptional uint32     errno       = 1;\n    optional uint64     value       = 2;\n}\n\n////////////////////////////////   Record Start    //////////////////////\n\nmessage MsgRecordRoleInfo\n{\n\toptional uint64\t\t\tid        \t\t = 1;\n\toptional uint32\t\t\tseat        \t = 2;\n\toptional string\t\t\tusename   \t\t = 3;\n\toptional int64\t \t\tscore     \t\t = 4;\n\trepeated uint32 \t\thand_card \t\t = 5;\n\toptional string         nick_name\t\t = 6;\n\toptional uint32\t\t\tgame_state\t\t = 7;\n\toptional uint32\t\t\tseries\t\t\t = 8;\n\toptional int64\t\t\tcurrent_score    = 9;\n}\n\nmessage MsgRecordRoomInfo\n{\n\toptional uint32 \t    special_kind      = 1;\n\toptional uint64 \t\tbanker\t\t\t  = 2;\n\toptional uint32         score\t\t\t  = 3;\n\toptional uint32\t\t\tgame_count\t\t  = 4;\n\trepeated uint32         bottom_cards \t  = 5;\n}\n\nmessage MsgRecordEvent\n{\n\toptional uint32 \t\tevent_id \t\t = 1;\n\toptional uint32 \t\tcount\t \t\t = 2;\n\trepeated int32 \t\t\tscore\t     \t = 3;\n\trepeated uint32 \t\tscore_count    \t = 4;\n}\n\nmessage MsgRecordWeaveCard\n{\n \toptional uint32 \t\tcard       \t\t= 1;\n\toptional uint32\t\t\twik\t\t   \t\t= 2;\n\toptional uint32\t\t\tbarkind\t\t\t= 3;\n\trepeated uint32\t\t    mix_card\t\t= 4;    // 组合牌;\n}\n\nmessage MsgRecordShowDown\t\t\t\t\t\t\t\n{\n\toptional uint64\t\t\t\t\tid       \t\t = 1;\n\toptional int64\t\t\t\t\tscore    \t\t = 2;\n\toptional int64\t\t\t\t\tfixedscore\t\t = 3;\n\toptional int64\t\t\t\t\tparam1   \t  \t = 4;\n\toptional int64\t\t\t\t\tparam2\t \t\t = 5;\n\toptional uint32 \t\t\t\thucard\t\t\t = 6;\n\trepeated MsgRecordEvent \t\tevent    \t\t = 7;\n\toptional int64\t\t\t\t\tmoney\t\t\t = 8;\n\toptional int64          \t\tparam3\t\t\t = 9;\n\toptional int64          \t\tparam4\t\t\t = 10;\n\toptional int64          \t\tparam5\t\t\t = 11;\n\toptional int64          \t\tplay_id\t\t\t = 12;\n\trepeated uint32  \t\t\t\thand_card\t\t = 13;\n\trepeated MsgRecordWeaveCard \tweave_card       = 14;\n\trepeated uint32\t\t\t\t\thucard_list      = 15;\n}\n\nmessage MsgGDShowDownRole\n{\n\toptional uint64\t\trole_id \t \t= 1;\n\toptional uint32\t\tgame_count  \t= 2;\n\toptional uint32\t\tseries\t\t \t= 3;\n\toptional int32\t\tscore  \t     \t= 4;\n\toptional int32\t\tcurrent_score \t= 5;\n}\n\nmessage MsgGDRankInfo\n{\n\trepeated uint64\t\trank_list\t\t= 1;\n}\n\nmessage MsgRecordNodeList\n{\n\toptional uint32\t\t\t\t\tcmd_id  \t \t= 1;\t\t\n\trepeated uint32\t\t\t\t\tcard_value\t \t= 2;\n\toptional uint32\t\t\t\t\tcard_index   \t= 3;\n\toptional uint64\t\t\t\t\taction_id    \t= 4;\n\toptional uint32\t\t\t\t\taction_wik\t \t= 5;\n\toptional uint64\t\t\t\t\ttarget_id \t \t= 6;\n\toptional uint32\t\t\t\t\tnode_size\t \t= 7;\n\trepeated MsgRecordRoleInfo \t\trole_data \t  \t= 8;\n\toptional MsgRecordRoomInfo\t\troom_data\t  \t= 9;\n\trepeated MsgRecordShowDown\t\tshowdown_list \t= 10;\n\trepeated MsgRecordNodeList\t\tnext_node     \t= 11;\n\trepeated MsgGDShowDownRole\t\twin_role\t\t= 12;\n\trepeated MsgGDShowDownRole \t\tlost_role\t\t= 13;\n\toptional MsgGDRankInfo\t\t\troom_ranking\t= 14;\n}\n\n\n\n////////////////////////////////   Record End    ////////////////////////////\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/DataTable/proto/msg_doudizhu.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nimport \"msg_client.proto\";\n\nenum TDDZPlayerWik                                                     // 玩家权限\n{\n\tASK_DDZ_NULL                         = 1;                        // 空\n\tASK_DDZ_TISHI                        = 2;                        // 提示 \n\tASK_DDZ_BUCHU                        = 3;                        // 不出\n\tASK_DDZ_CHUPAI                       = 4;                        // 出牌\n\tASK_DDZ_DIZHU_MINGPAI                = 5;                        // 地主明牌\n};\n\nenum TDDZPlayerState                                                    // 玩家状态\n{\n\tSTATE_DDZ_READY                        = 1;                      // 准备\n\tSTATE_DDZ_GUOPAI                       = 2;                      // 过牌\n\tSTATE_DDZ_CHUNTIAN                     = 3;                      // 春天\n\tSTATE_DDZ_NEWROLE                      = 4;                      // 新玩家\n\tSTATE_DDZ_ROOM_OWNER                   = 5;                      // 房主\n\tSTATE_DDZ_RELIEVE\t\t\t           = 6;\t\t\t            // 解除房间状态;\n\tSTATE_DDZ_LEAVE                        = 7;                      // 离开状态                    \n    STATE_DDZ_LIMIT                        = 8;                      // 限制状态\n\tSTATE_DDZ_OFFLINE                      = 9;                     // 脱机状态;\n\tSTATE_DDZ_MINGPAI                      = 10;                     // 明牌 状态;\n\tSTATE_DDZ_DIZHU                        = 11;                     // 地主状态;\n\tSTATE_DDZ_NONGMING                     = 12;                     // 农民状态;\n\tSTATE_DDZ_JIABEI                       = 13;                    // 加倍状态\n\tSTATE_DDZ_QIANGDIZHU                   = 14;                    // 抢地主状态\n\tSTATE_DDZ_SELECT_JIABEI                = 15;                    // 选择加倍状态\n\tSTATE_DDZ_SELECT_MINGPAISTART          = 16;                    // 选择明牌开始状态\n\tSTATE_DDZ_FENGDING                     = 17;                   // 封顶状态\n\tSTATE_DDZ_CONTINUE_GAME                = 18;                   // 继续游戏状态\n};\n\nenum TDDZState                          \t\t\t\t\t\t\t// 游戏房间状态\n{\n\tTDDZStateWait        \t        \t= 0;\t\t\t\t\t\t// 等待开始\n\tTDDZStateCheckStartGame             = 1;                        // 检查是否可以开始游戏\n\tTDDZStateSelectMingCardStart        = 2;                        // 选择明牌开始阶段\n    TDDZStateStartGame   \t   \t        = 3;\t\t\t\t\t\t// 开始游戏\t\n\tTDDZStateSendCard\t \t            = 4; \t\t\t\t\t\t// 发送手牌\n\tTDDZStateQiangDiZhu\t \t            = 5; \t\t\t\t\t\t// 抢地主阶段\n\tTDDZStateSelectAddTimes\t        \t= 6; \t\t\t\t\t\t// 选择加倍阶段\n\tTDDZStateAction \t        \t\t= 7;\t\t\t\t\t\t// 玩家自由活动\n\tTDDZStateOutCard                    = 8;                        // 出牌状态\n\tTDDZStateShowDown\t\t         \t= 9;     \t\t\t\t\t// 游戏结算\n\tTDDZStateRelieveRoom                = 10;                       // 解散房间\n};\n\nenum TDDZCT                             \t\t\t\t\t    \t// 牌型\n{\n\tCT_DDZ_ERROR\t\t\t\t\t\t= 0;\t\t\t\t\t\t// 错误类型\n\tCT_DDZ_SINGLE\t\t\t\t\t\t= 1;\t\t\t\t\t\t// 单牌类型\n\tCT_DDZ_DOUBLE\t\t\t\t\t\t= 2;\t\t\t\t        // 对子类型\n\tCT_DDZ_THREE_TIAO\t\t\t\t\t= 3;\t\t\t\t\t    // 三条类型\n\tCT_DDZ_THREE_TIAO_WITH_ONE          = 4;    \t\t\t\t\t// 三带一单类型\n\tCT_DDZ_THREE_TIAO_WITH_YIDUI        = 5;    \t\t\t\t\t// 三带一对类型\n\tCT_DDZ_SHUN_ZI\t\t\t\t\t\t= 6;\t\t\t\t\t\t// 顺子类型\n\tCT_DDZ_LIAN_DUI\t\t\t\t        = 7;\t\t\t\t\t\t// 连对类型\n\tCT_DDZ_FEIJI_WITH_NULL              = 8;    \t\t\t\t\t// 飞机不带类型\n\tCT_DDZ_FEIJI_WITH_ONE               = 9;    \t\t\t\t\t// 飞机带单类型\n\tCT_DDZ_FEIJI_WITH_YIDUI             = 10;    \t\t\t\t\t// 飞机带对类型\n\tCT_DDZ_FOUR_WITHDOUBLE              = 11;    \t\t\t\t\t// 四带二类型\n\tCT_DDZ_FOUR_LIANGDUI                = 12;    \t\t\t\t\t// 四带二对类型\n\tCT_DDZ_ZHADAN_SIZHANG               = 13;   \t\t\t\t\t// 炸弹\n\tCT_DDZ_HUOJIAN\t\t\t\t \t    = 14;\t\t\t\t\t\t// 火箭\n};\n\nenum TDDZBottomType                             \t\t\t    // 底牌牌型\n{\n\tDDZ_BT_NULL\t\t\t\t\t\t= 0;\t\t\t\t\t\t// 无类型\n\tDDZ_BT_XIAO_KING\t\t\t    = 1;\t\t\t\t\t\t// 小王类型\n\tDDZ_BT_DA_KING\t\t\t\t    = 2;\t\t\t\t        // 大王类型\n\tDDZ_BT_DUIZI\t\t\t\t\t= 3;\t\t\t\t\t    // 对子类型\n\tDDZ_BT_TONGHUA                  = 4;    \t\t\t\t\t// 同花类型\n\tDDZ_BT_SHUNZI\t\t\t\t    = 5;\t\t\t\t\t\t// 顺子类型\n\tDDZ_BT_SANZHANG\t\t\t\t    = 6;\t\t\t\t\t\t// 三张类型\n\tDDZ_BT_TONGHUASHUN              = 7;    \t\t\t\t\t// 同花顺类型\n};\n\nenum TDDZQiangDiZhu                             \t\t\t   // 抢地主权限\n{\n\tDDZ_QDZ_JIAODIZHU\t\t\t\t   = 1;\t\t\t\t   // 叫地主\n\tDDZ_QDZ_BUJIAO\t\t\t\t\t   = 2;\t\t\t\t   // 不叫\n\tDDZ_QDZ_QIANGDIZHU\t\t\t\t   = 3;\t\t\t\t   // 抢地主\n\tDDZ_QDZ_BUQIANG\t\t\t\t\t   = 4;\t\t\t\t   // 不抢\n};\n\nenum TDDZJiaoFen                            \t\t\t       // 叫分权限\n{\n\tDDZ_JF_BUJIAO\t\t\t\t\t   = 1;\t\t\t\t   // 不叫\n\tDDZ_JF_JIAO_ONE\t\t\t\t       = 2;\t\t\t\t   // 叫一分\n\tDDZ_JF_JIAO_TWO\t\t\t\t       = 3;\t\t\t\t   // 叫二分\n\tDDZ_JF_JIAO_THREE\t\t\t\t   = 4;\t\t\t\t   // 叫三分\n};\n\nenum TDDZAddTimes                           \t\t\t       // 加倍选择\n{\n\tDDZ_AT_NULL\t\t\t\t\t       = 0;\t\t\t\t  \n\tDDZ_AT_BUJIABIE\t\t\t\t       = 1;\t\t\t\t       // 不加倍\n\tDDZ_AT_JIABIE\t\t\t           = 2;\t\t\t\t       // 加倍\n};\n\nenum TDDZMingPaiType                           \t\t\t       // 明牌选择\n{\n\tDDZ_MP_NULL\t\t\t\t\t       = 0;\t\t\t\t   \n\tDDZ_MP_NORMALSTART\t\t\t\t   = 1;\t\t\t\t       // 普通开始\n\tDDZ_MP_MINGPAISTART\t\t\t       = 2;\t\t\t\t       // 明牌开始\n};\n\nenum TGameSpecialKindDouDiZhu               // 斗地主房间玩法\n{\n\tTSK_DDZ_NULL\t   \t= 0;\n\tTSK_DDZ_QDZ\t   \t\t= 1;\t    // 抢地主\n\tTSK_DDZ_JF\t   \t\t= 2;\t    // 叫分\n\tTSK_DDZ_BFD\t   \t\t= 3;        // 不封顶\n\tTSK_DDZ_16\t   \t\t= 4;        // 16封顶\n\tTSK_DDZ_32        \t= 5;        // 32封顶\n\tTSK_DDZ_64   \t\t= 6;        // 64封顶\n\tTSK_DDZ_DIPAI     \t= 7;        // 底牌翻倍\n\tTSK_DDZ_JIABEI  \t= 8;        // 加倍\n\tTSK_DDZ_MINGPAI  \t= 9;        // 明牌\n}\n\nmessage MsgQiangDiZhu                                               // 抢地主信息(服务器发给客户端的)\n{\n\toptional uint64 playid                = 1;                      // 玩家id\n\toptional uint64 qingdizhu_wiki        = 2;                      // 玩家可操作的权限\n}\n\nmessage MsgQiangDiZhuResult                                          // 抢地主结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                  = 1;                       // 玩家id\n\toptional uint64 result                  = 2;                       // 玩家选择的结果\n\toptional uint64 state                   = 3;                       // 状态\n\trepeated uint32 dizhu_cards             = 4;             \t         // 刷新地主的手牌\n\toptional uint64 cardcount               = 5;                       // 手牌数量\n\toptional uint64 multiple                = 6;                       // 房间倍数\n}\n\nmessage MsgBRQiangDiZhuResult                                       // 抢地主最终结果(服务器广播的)\n{\n\trepeated MsgQiangDiZhuResult player_list  = 1;\n\toptional uint64 multiple                  = 2;                  // 房间倍数\n\trepeated MsgDiPaiMutiple dipai_multi_list = 3;                  // 底牌翻倍列表\n}\n\nmessage MsgDiPaiMutiple                                             // 底牌翻倍的类型事件\n{\n\toptional uint32 \t\t\tevent_id\t\t= 1;\n\toptional uint32 \t\t\tcount\t\t\t= 2;\n}\n\nmessage MsgMingPaiResult                                             // 选择明牌结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                      = 1;                        // 玩家id\n\toptional uint64 result                      = 2;                        // 玩家选择的结果\n\toptional uint64 state                       = 3;                        // 状态\n\trepeated uint32 dizhu_cards                 = 4;             \t        // 地主明牌时刷新手牌\n\toptional uint64 multiple                    = 5;                        // 房间倍数\n}\n\nmessage MsgJiaBeiResult                                              // 选择加倍结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                = 1;                       // 玩家id\n\toptional uint64 result                = 2;                       // 玩家选择的结果\n\toptional uint64 state                 = 3;                       // 状态\n}\n\nmessage MsgDDZPlayer                                                // 玩家信息\n{\n\toptional MsgPlayerInfo      player_base          = 1;\t\t\t// 玩家信息(房间信息填充)\n\toptional uint32 \t\t\tstate\t\t\t\t = 2;\t        // 玩家状态\n\toptional uint32 \t\t\thand_count\t\t\t = 3;           // 手牌数量\n\trepeated uint32             card_list            = 4;          \t// 手牌列表(房间信息、showdown填充)\n\toptional uint32 \t\t\tseats\t\t\t\t = 5;\t        // 座位(房间信息填充)\n\toptional int64              score                = 6;           // 玩家当前的积分\n\toptional int64      \t\tshow_down_score      = 7;           // 玩家该局游戏的加减分\n\toptional uint32             qingdizhu_wiki       = 8;           // 玩家抢地主的权限\n\toptional uint32             qingdizhu_value      = 9;           // 玩家抢地主的结果\n\toptional uint32             multiple             = 10;          // 玩家倍数,(结算时使用)\n\toptional uint32      \t\tintegral_num         = 11;          // 加券数\n\trepeated uint32             out_cards     \t\t = 12;          // 上把玩家出的牌信息\n\toptional uint32  \t        out_type\t\t\t = 13;          // 上把玩家的出牌种类\n}\n\nmessage MsgDDZActon\n{\n\toptional uint64  \t        new_actionid        = 1; \t\t\t    // 当前活动玩家\n\toptional uint64  \t        old_actionid\t\t= 2; \t\t\t    // 上把的活动玩家\n\trepeated uint32             last_out_cards      = 3;             \t// 上把玩家出的牌信息\n\toptional uint32  \t        last_out_type\t\t= 4;                // 上把玩家的出牌种类\n\toptional uint32             wik                 = 5;                // 当前活动玩家的权限  TDDZPlayerWik\n\trepeated MsgDDZPlayer       player_list         = 6;                // 玩家信息\n}\n\n\nmessage MsgDDZUserOutCard\n{\n\toptional uint64 \t            old_actionid\t    = 1;              // 旧玩家ID\n\toptional uint32  \t            out_type\t\t    = 2;              // 出牌种类\n\toptional uint32  \t            hand_count          = 3;              // 玩家手牌数量\n\trepeated uint32                 out_cards           = 4;              // 出牌列表\n\toptional uint64                 multiple            = 5;              // 房间倍数\n\trepeated uint32                 hand_cards          = 6;              // 明牌玩家剩余的手牌，客户端刷新使用\n}\n\nmessage MsgDDZRoom                                                      // 房间信息\n{       \n\toptional uint32                      \troom_state              = 1;     // 房间当前状态   TDDZState\n\toptional uint32 \t\t\t\t\t    state_time \t\t        = 2;     // 状态运行时间\n\trepeated MsgDDZPlayer\t\t\t        player_list\t\t        = 3;     // 玩家信息\n\toptional uint64 \t\t\t\t\t    action_id \t\t        = 4;     // 当前活动玩家\n\toptional uint64\t\t\t\t\t\t    room_id\t\t\t        = 5;     // 房间ID\n\toptional uint32                         game_count              = 6;     // 当前是该房间的第几局\n\toptional MsgCreatePrivateRoom\t\t    private_room \t        = 7;\t    // 私房信息;\n\toptional MsgDDZUserOutCard              last_outcard            = 8;     // 房间上家牌的信息\n\toptional uint32                         wik                     = 9;     // 当前活动玩家的权限  TDDZPlayerWik\n\toptional uint32                         bottom_cards            = 10;    // 底牌列表\n\toptional uint64                         multiple                = 11;    // 房间倍数\n\trepeated MsgDiPaiMutiple \t\t\t    dipai_multi_list        = 12;    // 底牌翻倍列表\n\toptional uint32\t\t\t\t\t\t    room_pay_type           = 13;    // 付费类型\n}\n\nmessage MsgDDZRoomShowDown                                              // 结算房间信息\n{       \n\toptional uint32                       room_state           = 1;     // 房间当前状态    TDDZState\n\toptional uint32 \t\t\t\t\t  state_time \t\t   = 2;     // 状态运行时间\n\trepeated MsgDDZPlayer\t\t\t      player_list\t\t   = 3;     // 玩家信息\n\toptional uint64\t\t\t\t\t\t  room_id\t\t\t   = 4;     // 房间ID\n\toptional uint32                       game_count           = 5;     // 当前是该房间的第几局\n\toptional uint32 \t\t\t          time \t\t           = 6;     // 时间 \n\toptional bool                         game_over            = 8;     // 是否结束\n\trepeated MsgDDZShowDownEvent\t      event_count\t  \t   = 9;\t\t// 结算事件;\n\trepeated MsgDDZIntegralCount\t\t  integral_list \t   = 10;\t// 积分卷;\n}\n\n// 积分卷\nmessage MsgDDZIntegralCount\n{\n\toptional uint64\t\t\t\troleid\t\t\t= 1;\n\toptional uint32 \t\t\tcount \t\t\t= 2;\n}\n\nmessage MsgDDZShowDownEvent                                            // 结算事件;\n{\n\toptional uint32 \t\t\tevent_id\t\t= 1;\n\toptional uint32 \t\t\tcount\t\t\t= 2;\n}"
  },
  {
    "path": "code/EVA/server/script/DataTable/proto/msg_service.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nmessage MsgGameType\n{\n    optional string         Type                    = 1;\n    optional uint32         Max                     = 2;\n    optional uint32         Curr                    = 3;    \n    \n}\n\nmessage MsgServiceInfo\n{\n    repeated MsgGameType    RoomList                = 1;\n    optional uint32         MaxPlayer               = 2;\n    optional uint32         CurrPlayer              = 3;\n    optional uint32         ServiceID               = 4;\n    optional string         ServiceName             = 5;\n\n}\n"
  },
  {
    "path": "code/EVA/server/script/DataTable/ssl/1_root_bundle.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIErjCCA5agAwIBAgIQBYAmfwbylVM0jhwYWl7uLjANBgkqhkiG9w0BAQsFADBh\nMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\nd3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\nQTAeFw0xNzEyMDgxMjI4MjZaFw0yNzEyMDgxMjI4MjZaMHIxCzAJBgNVBAYTAkNO\nMSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMR0wGwYDVQQL\nExREb21haW4gVmFsaWRhdGVkIFNTTDEdMBsGA1UEAxMUVHJ1c3RBc2lhIFRMUyBS\nU0EgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgWa9X+ph+wAm8\nYh1Fk1MjKbQ5QwBOOKVaZR/OfCh+F6f93u7vZHGcUU/lvVGgUQnbzJhR1UV2epJa\ne+m7cxnXIKdD0/VS9btAgwJszGFvwoqXeaCqFoP71wPmXjjUwLT70+qvX4hdyYfO\nJcjeTz5QKtg8zQwxaK9x4JT9CoOmoVdVhEBAiD3DwR5fFgOHDwwGxdJWVBvktnoA\nzjdTLXDdbSVC5jZ0u8oq9BiTDv7jAlsB5F8aZgvSZDOQeFrwaOTbKWSEInEhnchK\nZTD1dz6aBlk1xGEI5PZWAnVAba/ofH33ktymaTDsE6xRDnW97pDkimCRak6CEbfe\n3dXw6OV5AgMBAAGjggFPMIIBSzAdBgNVHQ4EFgQUf9OZ86BHDjEAVlYijrfMnt3K\nAYowHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQD\nAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAG\nAQH/AgEAMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\nZGlnaWNlcnQuY29tMEIGA1UdHwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj\nZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwTAYDVR0gBEUwQzA3Bglg\nhkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29t\nL0NQUzAIBgZngQwBAgEwDQYJKoZIhvcNAQELBQADggEBAK3dVOj5dlv4MzK2i233\nlDYvyJ3slFY2X2HKTYGte8nbK6i5/fsDImMYihAkp6VaNY/en8WZ5qcrQPVLuJrJ\nDSXT04NnMeZOQDUoj/NHAmdfCBB/h1bZ5OGK6Sf1h5Yx/5wR4f3TUoPgGlnU7EuP\nISLNdMRiDrXntcImDAiRvkh5GJuH4YCVE6XEntqaNIgGkRwxKSgnU3Id3iuFbW9F\nUQ9Qqtb1GX91AJ7i4153TikGgYCdwYkBURD8gSVe8OAco6IfZOYt/TEwii1Ivi1C\nqnuUlWpsF1LdQNIdfbW3TSe0BhQa7ifbVIfvPWHYOu3rkg1ZeMo6XRU9B4n5VyJY\nRmE=\n-----END CERTIFICATE-----"
  },
  {
    "path": "code/EVA/server/script/DataTable/ssl/2_ssl.ranatune.com.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIFjDCCBHSgAwIBAgIQCY9Me/5efgsfOXOdKT7DGDANBgkqhkiG9w0BAQsFADBy\nMQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg\nSW5jLjEdMBsGA1UECxMURG9tYWluIFZhbGlkYXRlZCBTU0wxHTAbBgNVBAMTFFRy\ndXN0QXNpYSBUTFMgUlNBIENBMB4XDTE4MDUwOTAwMDAwMFoXDTE5MDUwOTEyMDAw\nMFowGzEZMBcGA1UEAxMQc3NsLnJhbmF0dW5lLmNvbTCCASIwDQYJKoZIhvcNAQEB\nBQADggEPADCCAQoCggEBAL2AfBI702GiX1ig5O0ZLQSUoEqr8JZacdvh2m+H3xCb\nmaC6wmoi7ZT6VSGRz3dEdIVOL002YkrLE5Yd0qsenJK6QK/tWqpXYBkk+EOz0AlJ\nGH5mUGuen8qTtnypkHXjeji+NiNF1yPGXU0wdugYUVJSeqe/Py1PxozMSL+QOZUl\nxxSi9taF2G1wM3Hm3D4isfRZyqfwD0c+ftv60Ss4C81qLNBcPaeK+1gSnUtd5fz1\nG6y0zI/XRDc1Cwoz7A7LodCN0Qh1WjUA0X+q89AwrwjWUMGHeumMAjrIiypdGhZN\n/hS86ZXfhWWwIKJcF9VtcqkytnOL26fkT1TH4CiMl0ECAwEAAaOCAnMwggJvMB8G\nA1UdIwQYMBaAFH/TmfOgRw4xAFZWIo63zJ7dygGKMB0GA1UdDgQWBBSJyxcHZxbj\nc5C81VnsS+EYu4HfiDAbBgNVHREEFDASghBzc2wucmFuYXR1bmUuY29tMA4GA1Ud\nDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTAYDVR0g\nBEUwQzA3BglghkgBhv1sAQIwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln\naWNlcnQuY29tL0NQUzAIBgZngQwBAgEwgYEGCCsGAQUFBwEBBHUwczAlBggrBgEF\nBQcwAYYZaHR0cDovL29jc3AyLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcwAoY+aHR0\ncDovL2NhY2VydHMuZGlnaXRhbGNlcnR2YWxpZGF0aW9uLmNvbS9UcnVzdEFzaWFU\nTFNSU0FDQS5jcnQwCQYDVR0TBAIwADCCAQIGCisGAQQB1nkCBAIEgfMEgfAA7gB2\nAKS5CZC0GFgUh7sTosxncAo8NZgE+RvfuON3zQ7IDdwQAAABY0RokEYAAAQDAEcw\nRQIhAJt/LQ3PTVXKIgfxD6HRqrbhEoGBJZFR31yyXKIUguJ5AiAR45vJDn59PREN\nVhO+bL19jch96oxJJmekkuVdOVMZIwB0AG9Tdqwx8DEZ2JkApFEV/3cVHBHZAsEA\nKQaNsgiaN9kTAAABY0RokpgAAAQDAEUwQwIfVMA85Y5vSPWK6wFZ+uo9jxQnpgnf\n239Zy8fJDQoyOAIgNIkGET33PAVPQm/yBUW5AT3kDH99FqqLBwso7WQA7oUwDQYJ\nKoZIhvcNAQELBQADggEBAALuI5sUT8o92kah2IBDCdb5P5O2T34mP/+3v9E+4YrG\nR+gElUfeMTbfLcx6U+7KunhgTLzsqANUJ206mELG9xwfycB2qup4RSD66t3+ZYyM\nw3TlUIPE8fDWyyWeq2ZNNL+QM7KuyD2FtDfnpLdiqgw8BapXQU6jtsRPrv+GE7Cf\nAp7PrSKzGr5fvCgd7PPcIaWGH6oWD/HGGl6NHL9XK0afKvZHl6A6l09EtrRQqtP3\nPORhvx87GleEsu/B+QLpdHj+SLXvTV2sU05m1PIFntcyaQmBlrLqhPvUv2pSJnNT\nZYTVB5V6RLM363foeGvqHcN0bVlkv1MgRZLVPyh/cFg=\n-----END CERTIFICATE-----"
  },
  {
    "path": "code/EVA/server/script/DataTable/ssl/3_ssl.ranatune.com.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAvYB8EjvTYaJfWKDk7RktBJSgSqvwllpx2+Hab4ffEJuZoLrC\naiLtlPpVIZHPd0R0hU4vTTZiSssTlh3Sqx6ckrpAr+1aqldgGST4Q7PQCUkYfmZQ\na56fypO2fKmQdeN6OL42I0XXI8ZdTTB26BhRUlJ6p78/LU/GjMxIv5A5lSXHFKL2\n1oXYbXAzcebcPiKx9FnKp/APRz5+2/rRKzgLzWos0Fw9p4r7WBKdS13l/PUbrLTM\nj9dENzULCjPsDsuh0I3RCHVaNQDRf6rz0DCvCNZQwYd66YwCOsiLKl0aFk3+FLzp\nld+FZbAgolwX1W1yqTK2c4vbp+RPVMfgKIyXQQIDAQABAoIBAANJsDVkh3UKYzk7\nXudwdDIP9lU/VRL1viOakD62wrdz/KsPzHVZFmpLGtikkg77n4Ir1mkiejt6GSSV\nz0C37O9khwBqZ8QcdJrRE/PgQfn0REYWpjrsx1DVZeFVM5ABDq7++VtcsAgzTg17\nm5eIqvoIu28vQ7RIfd1V4sX8lYwtckiX+tBXLS5CSRYa87pxxXOI/WkcXCb9bvI4\nbKoGO99xDe92la8c42SL5B1fzZJ34l5xNHavimFwANdqfiAN5to+JFUxH5AZ3zES\ny3hQh4yB2L0q0pOcb/pwrM+WY4nzBba2I+h0nEsJmletAHmsvss9QOJL6MTHfoAC\ngr8ssLECgYEA4yAwZ+axap1moIy0xUzMOd31WWfbNNadTNaaTkrGTTVkhpimpGBU\nJ+uW387pkvXsu1eUl2qIWxOdzuIThbludlFg9Nb5ISFWWYi0JM4ekyXKiNEyGp45\n5GnmeCY2CQNvekKQrxDCcDwnr1xvnoU5fbfciN61HLiMfQtWqMYXuVECgYEA1ZfT\nr38FobVPODdLFvOzrEslHpYt7OvY49y9bBQfiOLer24szmGU59eH0b7VWCFtIrmb\nUy893pON8P3hJ2G6AWetZiFBvcoZ/Qy8SkppYcyVYrTXDx4UBxN59c0hghpiMzlV\npE0FYwcjS+hB9yt7veYq2k9b384si6I+fNdcgvECgYAEJtx7qb3ogwQTPz82tBav\noB0SC1H4f0vU0b90Wu2RD77MrxGsw44GRMo3QSMH6rLvIcS3l9zyPUOPOpa8xQz9\n4LLzBtL7Bg78CAGzAomQiwpOwfQ2hFnukPkDjT9Dnup0w669ZIMJZjAbhocL0Mei\nQrAnWFrbMYxv5LsqzqQ0YQKBgQCujijimIVKtXjrcUy9kiZ5HORWDde0cr5K4eAw\nDnYDEZ15cynM9DSUEDEgObvzDUY6hcMphUcjuiTbGTBDVfuEIG22NGGcsCjzA9Bx\nSkS7N02yYCYNZcBqVAFs3tqOj+9G+4lA/+zyFChFZadbTz8OX6cPyKFF0yHWb55v\nujURkQKBgErctBLWdL5v8JE5Vn56j46c8zChlEuhmjQ6XaWEDE/8jWLLsXn/Opq1\n7L5w4zdp/4iFWYgm57Lc7+iRU/MraEe1ugpRoQIrohVR2zi52kBNNBcUlUtv6r65\nDyQgrNxSPxKcLRnoZRtFiyNzk5IW+qalrfKKg8LFR0Q8145xIMD0\n-----END RSA PRIVATE KEY-----"
  },
  {
    "path": "code/EVA/server/script/Framework/CJsonUtil.lua",
    "content": "local json = require \"cjson\"\n\n-- Various common routines used by the Lua CJSON package\n--\n-- Mark Pulford <mark@kyne.com.au>\n\n-- Determine with a Lua table can be treated as an array.\n-- Explicitly returns \"not an array\" for very sparse arrays.\n-- Returns:\n-- -1   Not an array\n-- 0    Empty table\n-- >0   Highest index in the array\nlocal function is_array(table)\n    local max = 0\n    local count = 0\n    for k, v in pairs(table) do\n        if type(k) == \"number\" then\n            if k > max then max = k end\n            count = count + 1\n        else\n            return -1\n        end\n    end\n    if max > count * 2 then\n        return -1\n    end\n\n    return max\nend\n\nlocal serialise_value\n\nlocal function serialise_table(value, indent, depth)\n    local spacing, spacing2, indent2\n    if indent then\n        spacing = \"\\n\" .. indent\n        spacing2 = spacing .. \"  \"\n        indent2 = indent .. \"  \"\n    else\n        spacing, spacing2, indent2 = \" \", \" \", false\n    end\n    depth = depth + 1\n    if depth > 50 then\n        return \"Cannot serialise any further: too many nested tables\"\n    end\n\n    local max = is_array(value)\n\n    local comma = false\n    local fragment = { \"{\" .. spacing2 }\n    if max > 0 then\n        -- Serialise array\n        for i = 1, max do\n            if comma then\n                table.insert(fragment, \",\" .. spacing2)\n            end\n            table.insert(fragment, serialise_value(value[i], indent2, depth))\n            comma = true\n        end\n    elseif max < 0 then\n        -- Serialise table\n        for k, v in pairs(value) do\n            \n            if k ~= \"class\" then\n                if comma then\n                    table.insert(fragment, \",\" .. spacing2)\n                end\n                table.insert(fragment,\n                    --(\"[%s] = %s\"):format(serialise_value(k, indent2, depth),\n                    (\"%s : %s\"):format(serialise_value(k, indent2, depth),\n                                         serialise_value(v, indent2, depth)))\n                comma = true\n            end\n        end\n    end\n    table.insert(fragment, spacing .. \"}\")\n\n    return table.concat(fragment)\nend\n\nfunction serialise_value(value, indent, depth)\n    if indent == nil then indent = \"\" end\n    if depth == nil then depth = 0 end\n\n    if value == json.null then\n        return \"json.null\"\n    elseif type(value) == \"string\" then\n        return (\"%q\"):format(value)\n    elseif type(value) == \"nil\" or type(value) == \"number\" or\n           type(value) == \"boolean\" then\n        return tostring(value)\n    elseif type(value) == \"table\" then\n        return serialise_table(value, indent, depth)\n    else\n        return \"\\\"<\" .. type(value) .. \">\\\"\"\n    end\nend\n\nlocal function file_load(filename)\n    local file\n    if filename == nil then\n        file = io.stdin\n    else\n        local err\n        file, err = io.open(filename, \"rb\")\n        if file == nil then\n            error((\"Unable to read '%s': %s\"):format(filename, err))\n        end\n    end\n    local data = file:read(\"*a\")\n\n    if filename ~= nil then\n        file:close()\n    end\n\n    if data == nil then\n        error(\"Failed to read \" .. filename)\n    end\n\n    return data\nend\n\nlocal function file_save(filename, data)\n    local file\n    if filename == nil then\n        file = io.stdout\n    else\n        local err\n        file, err = io.open(filename, \"wb\")\n        if file == nil then\n            error((\"Unable to write '%s': %s\"):format(filename, err))\n        end\n    end\n    file:write(data)\n    if filename ~= nil then\n        file:close()\n    end\nend\n\nlocal function compare_values(val1, val2)\n    local type1 = type(val1)\n    local type2 = type(val2)\n    if type1 ~= type2 then\n        return false\n    end\n\n    -- Check for NaN\n    if type1 == \"number\" and val1 ~= val1 and val2 ~= val2 then\n        return true\n    end\n\n    if type1 ~= \"table\" then\n        return val1 == val2\n    end\n\n    -- check_keys stores all the keys that must be checked in val2\n    local check_keys = {}\n    for k, _ in pairs(val1) do\n        check_keys[k] = true\n    end\n\n    for k, v in pairs(val2) do\n        if not check_keys[k] then\n            return false\n        end\n\n        if not compare_values(val1[k], val2[k]) then\n            return false\n        end\n\n        check_keys[k] = nil\n    end\n    for k, _ in pairs(check_keys) do\n        -- Not the same if any keys from val1 were not found in val2\n        return false\n    end\n    return true\nend\n\nlocal test_count_pass = 0\nlocal test_count_total = 0\n\nlocal function run_test_summary()\n    return test_count_pass, test_count_total\nend\n\nlocal function run_test(testname, func, input, should_work, output)\n    local function status_line(name, status, value)\n        local statusmap = { [true] = \":success\", [false] = \":error\" }\n        if status ~= nil then\n            name = name .. statusmap[status]\n        end\n        nlinfo((\"[%s] %s\"):format(name, serialise_value(value, false)))\n    end\n\n    local result = {}\n    local tmp = { pcall(func, unpack(input)) }\n    local success = tmp[1]\n    for i = 2, table.maxn(tmp) do\n        result[i - 1] = tmp[i]\n    end\n\n    local correct = false\n    if success == should_work and compare_values(result, output) then\n        correct = true\n        test_count_pass = test_count_pass + 1\n    end\n    test_count_total = test_count_total + 1\n\n    local teststatus = { [true] = \"PASS\", [false] = \"FAIL\" }\n    nlinfo((\"==> Test [%d] %s: %s\"):format(test_count_total, testname,\n                                          teststatus[correct]))\n\n    status_line(\"Input\", nil, input)\n    if not correct then\n        status_line(\"Expected\", should_work, output)\n    end\n    status_line(\"Received\", success, result)\n    nlinfo()\n\n    return correct, result\nend\n\nlocal function run_test_group(tests)\n    local function run_helper(name, func, input)\n        if type(name) == \"string\" and #name > 0 then\n            nlinfo(\"==> \" .. name)\n        end\n        -- Not a protected call, these functions should never generate errors.\n        func(unpack(input or {}))\n        nlinfo()\n    end\n\n    for _, v in ipairs(tests) do\n        -- Run the helper if \"should_work\" is missing\n        if v[4] == nil then\n            run_helper(unpack(v))\n        else\n            run_test(unpack(v))\n        end\n    end\nend\n\n-- Run a Lua script in a separate environment\nlocal function run_script(script, env)\n    local env = env or {}\n    local func\n\n    -- Use setfenv() if it exists, otherwise assume Lua 5.2 load() exists\n    if _G.setfenv then\n        func = loadstring(script)\n        if func then\n            setfenv(func, env)\n        end\n    else\n        func = load(script, nil, nil, env)\n    end\n\n    if func == nil then\n            error(\"Invalid syntax.\")\n    end\n    func()\n\n    return env\nend\n\n-- Export functions\nreturn {\n    serialise_value = serialise_value,\n    file_load = file_load,\n    file_save = file_save,\n    compare_values = compare_values,\n    run_test_summary = run_test_summary,\n    run_test = run_test,\n    run_test_group = run_test_group,\n    run_script = run_script\n}\n\n-- vi:ai et sw=4 ts=4:\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Class.lua",
    "content": "function class(classname, super)\n    local superType = type(super)\n    local cls\n\n    if superType ~= \"function\" and superType ~= \"table\" then\n        superType = nil\n        super = nil\n    end\n\n    if superType == \"function\" or (super and super.__ctype == 1) then\n        -- inherited from native C++ Object\n        cls = {}\n\n        if superType == \"table\" then\n            -- copy fields from super\n            for k,v in pairs(super) do cls[k] = v end\n            cls.__create = super.__create\n            cls.super    = super\n        else\n            cls.__create = super\n            cls.ctor = function() end\n        end\n\n        cls.__cname = classname\n        cls.__ctype = 1\n\n\t\t\tfunction cls.new(...)\n            local instance = cls.__create(...)\n            -- copy fields from class to native object\n            for k,v in pairs(cls) do instance[k] = v end\n            instance.class = cls\n            instance:ctor(...)\n            return instance\n        end\n\n    else\n        -- inherited from Lua Object\n        if super then\n            cls = {}\n            setmetatable(cls, {__index = super})\n            cls.super = super\n        else\n            cls = {ctor = function() end}\n        end\n\n        cls.__cname = classname\n        cls.__ctype = 2 -- lua\n        cls.__index = cls\n\n        function cls.new(...)\n            local instance = setmetatable({}, cls)\n            instance.class = cls\n            instance:ctor(...)\n            return instance\n        end\n    end\n\n    return cls\nend"
  },
  {
    "path": "code/EVA/server/script/Framework/Event/EventController.lua",
    "content": "--========================================================= \n-- 消息派发\n--=========================================================\nEventController = singleton(\"EventController\");\n\nfunction EventController:Init()\n\tself._MessageQue = {};\nend\n\nfunction EventController:RegisterEvent(messageType, callback)\n    --if EventName[messageType] == nil or type(callback) ~= \"function\" then\n    --    return\n\t--end\n\tif (messageType == nil) then\n\t\tlogError(\"EventController.RegisterEvent messageType == nil\");\n\t\treturn;\n\tend\n\t\n\tif (callback == nil) then\n\t\tlocal sError = \"EventController.RegisterEvent callback == nil \";\n\t\tif (nil ~= messageType) then\n\t\t\tsError = sError .. \"messageType = \"..messageType;\n\t\tend\n\t\tlogError(sError);\n\t\treturn;\n\tend\n\t\n    if self._MessageQue[messageType] == nil then\n        self._MessageQue[messageType] = {}\n    end\n\t\n    local index = #self._MessageQue[messageType];\t\t\t--  table.getn =>  #   lua5.3\n    self._MessageQue[messageType][index+1] = callback\nend\n\nfunction EventController:TriggerEvent( msg_type, ... )\n\n    if self._MessageQue[msg_type] == nil then\n        return\n    end\n    for i,v in pairs(self._MessageQue[msg_type]) do\n\t\tif (v ~= nil)then\n\t\t\tv(...)\n\t\telse\n\t\tend\n    end\n\t\nend\n\nfunction EventController:RemoveEvent(messageType,callback)\n    --if EventName[messageType] == nil or type(callback) ~= \"function\" then\n    --    return\n    --end\n    for i,v in pairs(self._MessageQue[messageType]) do\n        if callback == v then\n            table.remove(self._MessageQue[messageType],i)\n            return\n        end\n    end\nend\n\nreturn EventController\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Event/EventRegister.lua",
    "content": "--========================================================= \n-- 消息注册管理\n--=========================================================\nlocal EventRegister = class(\"EventRegister\");\n\n-- 构造函数\nfunction EventRegister:ctor()\n    self._EventCallBackTable = {};        -- 事件回调表\nend\n\n\n-- 注册某个事件\nfunction EventRegister:RegisterEvent(Name, Obj, Func)\n\tif (nil == Name) then\n\t\tlogError(\"RegisterEvent Name == nil!\")\n\t\treturn;\n\tend\n\t\n    local Handler = handler(Obj, Func);\n    local EventTable = self:GetEventRegisterTable(Name);\n    if (nil ~= EventTable) then\n        local idx = #EventTable;\n        EventTable[idx + 1] = Handler;\n    else\n        local v = {};\n        v[1] = Handler;\n        self._EventCallBackTable[Name] = v;\n    end\n    \n\tEventController.Instance():RegisterEvent(Name, Handler);  \nend\n\n-- 获取事件注册表\nfunction EventRegister:GetEventRegisterTable(Name)\n\tfor k,v in pairs(self._EventCallBackTable) do\n        if(k == Name) then\n            return v;\n        end\n    end \n    return nil;\nend\n\n-- 删除所有事件\nfunction EventRegister:UnRegisterAllEvent()\n    for k,v in pairs(self._EventCallBackTable) do\n        for i = 1, #v do\n\t        EventController.Instance():RemoveEvent(k, v[i]);\n        end\n    end   \n    self._EventCallBackTable = {};\nend\n\n\nreturn EventRegister;"
  },
  {
    "path": "code/EVA/server/script/Framework/Event/EventTrigger.lua",
    "content": "EventTrigger = {};\nlocal this = EventTrigger;\n\nfunction EventTrigger.OnEvent( msg_type, ... )\t\n    EventController.Instance():TriggerEvent( msg_type, ... );\nend\n\n\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Hotfix/HotfixHelper.lua",
    "content": "--- Hotfix helper which hotfixes modified modules.\n\nlocal M = class(\"HotfixHelper\")\n\nlocal hotfix = require(\"Hotfix/hotfix\")\n\n-- global_objects which must not hotfix.\nlocal global_objects = {\n    arg,\n    assert,\n    bit32,\n    collectgarbage,\n    coroutine,\n    debug,\n    dofile,\n    error,\n    getmetatable,\n    io,\n    ipairs,\n    load,\n    loadfile,\n    loadstring,\n    math,\n    module,\n    next,\n    os,\n    package,\n    pairs,\n    pcall,\n    print,\n    rawequal,\n    rawget,\n    rawlen,\n    rawset,\n    require,\n    select,\n    setmetatable,\n    string,\n    table,\n    tonumber,\n    tostring,\n    type,\n    unpack,\n    utf8,\n    xpcall,\n}\n\nfunction M:Init()\n    --hotfix.log_debug = function(s) print(s) end\n    hotfix.log_debug = nlinfo\n    hotfix.add_protect(global_objects)\n    self.uptick = 0;\n    -- Map file path to file time to detect modification.\n    self.path_to_time = { };\nend\n\n--- Check modules and hotfix.\nfunction M:Update( curr_tick )\n\n    if curr_tick~=nil then\n        if curr_tick - self.uptick < 2000 then\n            return;\n        end\n        \n        self.uptick = curr_tick;    \n    end\n\n\n    local MOD_NAME = \"hotfix_module_names\"\n    if not package.searchpath(MOD_NAME, package.path) then return end\n    package.loaded[MOD_NAME] = nil  -- always reload it\n    local module_names = require(MOD_NAME)\n\n    for _, module_name in pairs(module_names) do\n        local path, err = package.searchpath(module_name, package.path)\n        -- Skip non-exist module.\n        if not path then\n            nlwarning(string.format(\"No such module: %s. %s\", module_name, err))\n            goto continue\n        end\n\n        --local file_time = lfs.attributes (path, \"modification\")\n        local file_time = Misc.GetFileModificationDate(path)\n        if file_time == self.path_to_time[path] then goto continue end\n\n        nlinfo(string.format(\"Hot fix module %s (%s)\", module_name, path))\n        self.path_to_time[path] = file_time\n        hotfix.hotfix_module(module_name)\n        ::continue::\n    end  -- for\nend  -- check()\n\nreturn M\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Hotfix/hotfix.lua",
    "content": "--[[\nLua 5.2/5.3 hotfix. Hot update functions and keep old data.\nAuthor: Jin Qing ( http://blog.csdn.net/jq0123 )\n--]]\n\nlocal M = {}\n\nlocal module_updater = require(\"Hotfix/internal/module_updater\")\nlocal functions_replacer = require(\"Hotfix/internal/functions_replacer\")\n\n-- Do not update and replace protected objects.\nlocal protected = {}\n\n-- To protect self.\nlocal function add_self_to_protect()\n    M.add_protect{\n        M,\n        M.hotfix_module,\n        M.log_error,\n        M.log_info,\n        M.log_debug,\n        M.add_protect,\n        M.remove_protect,\n        module_updater,\n        module_updater.log_debug,\n        module_updater.update_loaded_module,\n        functions_replacer,\n        functions_replacer.replace_all,\n    }\nend  -- add_self_to_protect\n\n-- Hotfix module with new module object.\n-- Update package.loaded[module_name] and replace all functions.\n-- module_obj is the newly loaded module object.\nlocal function hotfix_module_with_obj(module_name, module_obj)\n    assert(\"string\" == type(module_name))\n    add_self_to_protect()\n    module_updater.log_debug = M.log_debug\n\n    -- Step 1: Update package.loaded[module_name], recording updated functions.\n    local updated_function_map = module_updater.update_loaded_module(\n        module_name, protected, module_obj)\n    -- Step 2: Replace old functions with new ones in module_obj, _G and registry.\n    functions_replacer.replace_all(protected, updated_function_map, module_obj)\nend  -- hotfix_module_with_obj()\n\n-- Hotfix module.\n-- Skip unloaded module.\n-- Usage: hotfix_module(\"mymodule.sub_module\")\n-- Returns package.loaded[module_name].\nfunction M.hotfix_module(module_name)\n    assert(\"string\" == type(module_name))\n    if not package.loaded[module_name] then\n        M.log_debug(\"Skip unloaded module: \" .. module_name)\n        return package.loaded[module_name]\n    end\n    M.log_debug(\"Hot fix module: \" .. module_name)\n\n    local file_path = assert(package.searchpath(module_name, package.path))\n    local fp = assert(io.open(file_path))\n    local chunk = fp:read(\"*all\")\n    fp:close()\n\n    -- Load chunk.\n    local func = assert(load(chunk, '@'..file_path))\n    local ok, obj = assert(pcall(func))\n    if nil == obj then obj = true end  -- obj may be false\n\n    hotfix_module_with_obj(module_name, obj)\n    return package.loaded[module_name]\nend\n\n-- User can set log functions. Default is no log.\n-- Like: require(\"hotfix\").log_info = function(s) mylog:info(s) end\nfunction M.log_error(msg_str) end\nfunction M.log_info(msg_str) end\nfunction M.log_debug(msg_str) end\n\n-- Add objects to protect.\n-- Example: add_protect({table, math, print})\nfunction M.add_protect(object_array)\n    for _, obj in pairs(object_array) do\n        protected[obj] = true\n    end\nend  -- add_protect()\n\n-- Remove objects in protected set.\n-- Example: remove_protect({table, math, print})\nfunction M.remove_protect(object_array)\n    for _, obj in pairs(object_array) do\n        protected[obj] = nil\n    end\nend  -- remove_protect()\n\nreturn M\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Hotfix/internal/functions_replacer.lua",
    "content": "--- Replace functions of table or upvalue.\n-- Search for the old functions and replace them with new ones.\n\nlocal M = {}\n\n-- Objects whose functions have been replaced already.\n-- Each objects need to be replaced once.\nlocal replaced_obj = {}\n\n-- Map old functions to new functions.\n-- Used to replace functions finally.\n-- Set to hotfix.updated_func_map.\nlocal updated_func_map = {}\n\n-- Do not update and replace protected objects.\n-- Set to hotfix.protected.\nlocal protected = {}\n\nlocal replace_functions  -- forward declare\n\n-- Replace all updated functions in upvalues of function object.\nlocal function replace_functions_in_upvalues(function_object)\n    local obj = function_object\n    assert(\"function\" == type(obj))\n    assert(not protected[obj])\n    assert(obj ~= updated_func_map)\n\n    for i = 1, math.huge do\n        local name, value = debug.getupvalue(obj, i)\n        if not name then return end\n        local new_func = updated_func_map[value]\n        if new_func then\n            assert(\"function\" == type(value))\n            debug.setupvalue(obj, i, new_func)\n        else\n            replace_functions(value)\n        end\n    end  -- for\n    assert(false, \"Can not reach here!\")\nend  -- replace_functions_in_upvalues()\n\n-- Replace all updated functions in the table.\nlocal function replace_functions_in_table(table_object)\n    local obj = table_object\n    assert(\"table\" == type(obj))\n    assert(not protected[obj])\n    assert(obj ~= updated_func_map)\n    \n    replace_functions(debug.getmetatable(obj))\n    local new = {}  -- to assign new fields\n    for k, v in pairs(obj) do\n        local new_k = updated_func_map[k]\n        local new_v = updated_func_map[v]\n        if new_k then\n            obj[k] = nil  -- delete field\n            new[new_k] = new_v or v\n        else\n            obj[k] = new_v or v\n            replace_functions(k)\n        end\n        if not new_v then replace_functions(v) end\n    end  -- for k, v\n    for k, v in pairs(new) do obj[k] = v end\nend  -- replace_functions_in_table()\n\n-- Replace all updated functions.\n-- Record all replaced objects in replaced_obj.\nfunction replace_functions(obj)\n    if protected[obj] then return end\n    local obj_type = type(obj)\n    if \"function\" ~= obj_type and \"table\" ~= obj_type then return end\n    if replaced_obj[obj] then return end\n    replaced_obj[obj] = true\n    assert(obj ~= updated_func_map)\n\n    if \"function\" == obj_type then\n        replace_functions_in_upvalues(obj)\n    else  -- table\n        replace_functions_in_table(obj)\n    end\nend  -- replace_functions(obj)\n\n--- Replace all old functions with new ones.\n-- Replace in new_obj, _G and debug.getregistry().\n-- a_protected is a list of protected object.\n-- an_updated_func_map is a map from old function to new function.\n-- new_obj is the newly loaded module.\nfunction M.replace_all(a_protected, an_updated_func_map, new_obj)\n    protected = a_protected\n    updated_func_map = an_updated_func_map\n    assert(type(protected) == \"table\")\n    assert(type(updated_func_map) == \"table\")\n    if nil == next(updated_func_map) then\n        return\n    end\n\n    replaced_obj = {}\n    replace_functions(new_obj)  -- new_obj may be not in _G\n    replace_functions(_G)\n    replace_functions(debug.getregistry())\n    replaced_obj = {}\nend  -- M.replace_all()\n\nreturn M\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Hotfix/internal/module_updater.lua",
    "content": "--- Updater to update loaded module.\n-- Updating a table is to update metatable and sub-table of the old table,\n--   and to update functions of the old table, keeping value fields.\n-- Updating a function is to copy upvalues of old function to new function.\n-- Functions will be replaced later after updating.\n\nlocal M = {}\n\nlocal update_table\nlocal update_func\n\n-- Updated signature set to prevent self-reference dead loop.\nlocal updated_sig = {}\n\n-- Map old function to new functions.\nlocal updated_func_map = {}\n\n-- Do not update and replace protected objects.\n-- Set to hotfix.protected.\nlocal protected = {}\n\n-- Set to hotfix.log_debug.\nfunction M.log_debug(msg_str) end\n\n-- Check if function or table has been updated. Return true if updated.\nlocal function check_updated(new_obj, old_obj, name, deep)\n    local signature = string.format(\"new(%s) old(%s)\",\n        tostring(new_obj), tostring(old_obj))\n    M.log_debug(string.format(\"%sUpdate %s: %s\", deep, name, signature))\n\n    if new_obj == old_obj then\n        M.log_debug(deep .. \"  Same\")\n        return true\n    end\n    if updated_sig[signature] then\n        M.log_debug(deep .. \"  Already updated\")\n        return true\n    end\n    updated_sig[signature] = true\n    return false\nend\n\n-- Update new function with upvalues of old function.\n-- Parameter name and deep are only for log.\nfunction update_func(new_func, old_func, name, deep)\n    assert(\"function\" == type(new_func))\n    assert(\"function\" == type(old_func))\n    if protected[old_func] then return end\n    if check_updated(new_func, old_func, name, deep) then return end\n    deep = deep .. \"  \"\n    updated_func_map[old_func] = new_func\n\n    -- Get upvalues of old function.\n    local old_upvalue_map = {}\n    for i = 1, math.huge do\n        local name, value = debug.getupvalue(old_func, i)\n        if not name then break end\n        old_upvalue_map[name] = value\n    end\n\n    local function log_dbg(name, from, to)\n        M.log_debug(string.format(\"%ssetupvalue %s: (%s) -> (%s)\",\n            deep, name, tostring(from), tostring(to)))\n    end\n\n    -- Update new upvalues with old.\n    for i = 1, math.huge do\n        local name, value = debug.getupvalue(new_func, i)\n        if not name then break end\n        local old_value = old_upvalue_map[name]\n        if old_value then\n            local type_old_value = type(old_value)\n            if type_old_value ~= type(value) then\n                debug.setupvalue(new_func, i, old_value)\n                log_dbg(name, value, old_value)\n            elseif type_old_value == \"function\" then\n                update_func(value, old_value, name, deep)\n            elseif type_old_value == \"table\" then\n                update_table(value, old_value, name, deep)\n                debug.setupvalue(new_func, i, old_value)\n            else\n                debug.setupvalue(new_func, i, old_value)\n                log_dbg(name, value, old_value)\n            end\n        end  -- if old_value\n    end  -- for i\nend  -- update_func()\n\n-- Compare 2 tables and update the old table. Keep the old data.\nfunction update_table(new_table, old_table, name, deep)\n    assert(\"table\" == type(new_table))\n    assert(\"table\" == type(old_table))\n    if protected[old_table] then return end\n    if check_updated(new_table, old_table, name, deep) then return end\n    deep = deep .. \"  \"\n\n    -- Compare 2 tables, and update old table.\n    for key, value in pairs(new_table) do\n        local old_value = old_table[key]\n        local type_value = type(value)\n        if type_value ~= type(old_value) then\n            old_table[key] = value\n            M.log_debug(string.format(\"%sUpdate field %s: (%s) -> (%s)\",\n                deep, key, tostring(old_value), tostring(value)))\n        elseif type_value == \"function\" then\n            update_func(value, old_value, key, deep)\n        elseif type_value == \"table\" then\n            update_table(value, old_value, key, deep)\n        end\n    end  -- for\n\n    -- Update metatable.\n    local old_meta = debug.getmetatable(old_table)\n    local new_meta = debug.getmetatable(new_table)\n    if type(old_meta) == \"table\" and type(new_meta) == \"table\" then\n        update_table(new_meta, old_meta, name..\"'s Meta\", deep)\n    end\nend  -- update_table()\n\n-- Update new loaded object with package.loaded[module_name].\nlocal function update_loaded_module2(module_name, new_obj)\n    assert(nil ~= new_obj)\n    assert(\"string\" == type(module_name))\n    local old_obj = package.loaded[module_name]\n    local new_type = type(new_obj)\n    local old_type = type(old_obj)\n    if new_type == old_type then\n        if \"table\" == new_type then\n            update_table(new_obj, old_obj, module_name, \"\")\n            return\n        end\n        if \"function\" == new_type then\n            update_func(new_obj, old_obj, module_name, \"\")\n            return;\n        end\n    end  -- if new_type == old_type\n    M.log_debug(string.format(\"Directly replace module: old(%s) -> new(%s)\",\n        tostring(old_obj), tostring(new_obj)))\n    package.loaded[module_name] = new_obj\nend  -- update_loaded_module2()\n\n-- Update new loaded object with package.loaded[module_name].\n-- Return an updated function map (updated_func_map).\n-- new_module_obj is the newly loaded module object.\nfunction M.update_loaded_module(module_name, protected_objects, new_module_obj)\n    assert(type(module_name) == \"string\")\n    assert(type(protected_objects) == \"table\")\n\n    protected = protected_objects\n    updated_func_map = {}\n    updated_sig = {}\n    update_loaded_module2(module_name, new_module_obj)\n    updated_sig = {}\n    return updated_func_map\nend  -- update_loaded_module()\n\nreturn M\n"
  },
  {
    "path": "code/EVA/server/script/Framework/InitFramework.lua",
    "content": "--========================================================= \n-- 初始化基础通用工具\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = package.path .. BasePath .. \"Framework/?.lua;\";\npackage.path = package.path .. BasePath .. \"Framework/Event/?.lua;\";\npackage.path = package.path .. BasePath .. \"Framework/Net/?.lua;\";\n\n\nprotobuf    = require \"protobuf\"\nJson        = require \"cjson\"\nJsonUtil    = require \"CJsonUtil\"\n\n\n-- 工具库\nrequire(\"Class\")\nrequire(\"functions\")\n\nrequire(\"Map\")\nrequire(\"MapMap\")\n\n--require (\"bit\")\n\nrequire(\"Net/NetWorkHandler\")\nrequire(\"Net/BaseService\")\nrequire(\"TimerMgr\");\nrequire(\"Event/EventTrigger\");\n\n\n--List \t= require(\"Common/List\")\n--Queue   = require(\"Common/Queue\")\n--Map     = require(\"Common/Map\")\n\n-- protobuf\n--require (\"Common/ProtoBuffer/define_attrib_pb\")\n\n\n-- LuaFramework --\nIDGenerate                  = bin_types.IDGenerate;\nMysqlStmt                   = bin_types.MysqlStmt;\nMysqlConn                   = bin_types.MysqlConn;\nMysqlResult                 = bin_types.MysqlResult;\nCMessage                    = bin_types.LuaMessage.NewInstance;\n\n--[[\nUtil\t\t\t\t\t\t= LuaFramework.Util;\nNativeUtil\t\t\t\t\t= LuaFramework.NativeUtil;\nAppConst\t\t\t\t\t= LuaFramework.AppConst;\nLuaHelper\t\t\t\t\t= LuaFramework.LuaHelper;\nNetMessage\t\t\t\t\t= LuaFramework.NetMessage;\nRecordNodeTable\t\t\t\t= LuaFramework.RecordNodeTable;\n\n-- LuaHelper --\nNetWorkHelper\t\t\t\t= LuaHelper.GetNetManager();\nGameManager\t\t\t\t\t= LuaHelper.GetGameManager();\nPoolManager\t\t\t\t\t= LuaHelper.GetPoolManager();\nLuaManager\t\t\t\t\t= LuaHelper.GetLuaManger();\n\n--]]\n\n-- 表\n--require(\"Event/EventType\")\n\n\n\n-- 工具\n\n\n--LSModule\t\t\t\t\t= require(\"SDK/LService/LSModule\")\n--WebModule\t\t\t\t\t= require(\"SDK/Web/WebModule\")\n--HttpClient\t\t\t\t\t= require(\"Common/Net/HttpClient\")\nMemoryRefInfo               = require(\"MemoryReferenceInfo\")\nEventController             = require(\"Event/EventController\")\n--ServerManager             = require(\"Net/ServerManager\")\nEventRegister               = require(\"Event/EventRegister\")\nCallbackServer              = require(\"Net/CallbackServer\");\nStateMachine                = require(\"SimpleStateMachine\");\nHotfixHelper                = require(\"Hotfix/HotfixHelper\");\n\nenum = {}\n\n\n-- 初始化单例\nfunction OnInitFramework()\n\n    addr = io.open( BasePath..\"DataTable/ProtoMsg.pb\", \"rb\")\n    buffer = addr:read \"*a\"  \n    addr:close()  \n    protobuf.register(buffer) \n    local decode = protobuf.decode(\"google.protobuf.FileDescriptorSet\", buffer)\n\n    for _,v in ipairs(decode.file) do\n        if v.enum_type ~= nil then\n            for _,etp in ipairs(v.enum_type) do\n                local enum_val = etp.value;\n                for _,eval in ipairs(enum_val) do\n                    --nlinfo( \"    \" .. eval.name .. \"  \" .. eval.number );\n                    enum[eval.name] = eval.number;\n                end\n            end\n        end\n    end\n\n    --math.randomseed(tostring(os.time()):reverse():sub(1, 7)) \n    \n    local seed = os.time() + (Misc.GetLocalTime()*100000);\n    math.randomseed(seed) \n\n    EventController.Instance():Init()\n    TimerMgr:Init( Misc.GetLocalTime() );\n    \n    Hotfix = HotfixHelper:new();\n    Hotfix:Init();\nend\n\n\nOnInitFramework();\n"
  },
  {
    "path": "code/EVA/server/script/Framework/List.lua",
    "content": "local List = class(\"List\");\n\n-- 构造函数\nfunction List:ctor()\n\t-- body\n\t-- 元素列表\n    self._list = {};\n--    nlinfo(self._list);\nend\n\n\n\n-- 添加一个元素\nfunction List:Push(value)\n\t-- body\n\n\ttable.insert(self._list, value);\nend\n\n-- 插入一个元素\nfunction List:Insert(idx, value)\n\ttable.insert(self._list, idx, value);\nend\n\n-- 获取一个元素\nfunction List:Get(index)\n\t-- body\n\n\tif self:Count() <= 0 or index == nil or type(index) ~= \"number\" then\n\t\t--todo\n\n\t\treturn nil;\n\tend\n\n\treturn self._list[index];\nend\n\n-- 获取最后一个元素\nfunction List:GetLast()\n\treturn self:Get(self:Count());\nend\n\n-- 获取第一个元素\nfunction List:GetFirst()\n\treturn self:Get(1);\nend\n\n-- 删除对象\nfunction List:Remove(value)\n\tif value == nil then\n\t\treturn\n\tend\n\t-- body\n\tfor i=1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == value then\n\t\t\t--todo\n\t\t\ttable.remove(self._list, i);\n\t\t\ti = i - 1;\n\t\tend\n\tend\nend\n\n\n--删除单个对象\nfunction List:RemoveOne(value)\n\tif value == nil then\n\t\treturn\n\tend\n\tfor i=1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == value then\n\t\t\t--todo\n\t\t\ttable.remove(self._list, i);\n\t\t\tbreak;\n\t\tend\n\tend\nend\n\n-- 根据索引删除对象\nfunction List:RemoveByIndex(idx)\n\tif (idx < 1 or idx > self:Count()) then\n\t\treturn;\n\tend\n\t\n\ttable.remove(self._list, idx);\nend\n\n-- 自定义函数删除\n-- 注意会把nil一起删除掉，如果不需要可以改下\nfunction List:RemoveIf(fun, ...)\n\tlocal m = 1;\n\twhile m <= self:Count() do\n\t\tlocal nValue = self._list[m];\n\t\tif (nil ~= nValue) then\n\t\t\tif fun(nValue, ...) then\n\t\t\t\ttable.remove(self._list, m);\n\t\t\telse\n\t\t\t\tm = m + 1;\n\t\t\tend\n\t\telse\n\t\t\ttable.remove(self._list, m);\n\t\tend\n\tend\nend\n\n-- 删除所有对象\nfunction List:RemoveAll(Value)\n\tlocal m = 1;\n\twhile m <= self:Count() do\n\t\tlocal nValue = self._list[m];\n\t\tif (nValue == Value) then\n\t\t\ttable.remove(self._list, m);\n\t\telse\n\t\t\tm = m + 1;\n\t\tend\n\tend\nend\n\n-- 是否有某个元素\nfunction List:Contain(value)\n\tfor i=1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == value then\n\t\t\treturn true;\n\t\tend\n\tend\n\t\n\treturn false;\nend\n\n-- 替换列表中的元素\n-- 下标为空替换失败\nfunction List:ReplaceValue( index , value )\n\tlocal nValue = self._list[index];\n\tif  nil ~= nValue then\n\t\tself._list[index] = value;\n\tend \nend\n\n--获取列表中元素的个数\nfunction List:GetValueCount(value)\n\tlocal Count = 0;\n\tfor i=1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == value then\n\t\t\tCount = Count + 1;\n\t\tend\n\tend\n\treturn Count;\nend\n\n-- 获取元素的索引\n-- 找不到返回-1\nfunction List:IndexOf(value)\n\tfor i = 1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == value then\n\t\t\treturn i;\n\t\tend\n\tend\n\t\n\treturn -1;\nend\n\n-- 遍历所有成员\nfunction List:ForEach(fun, ...)\n\t-- body\n\tfor k,v in pairs(self._list) do\n\t\tfun(v, ...)\n\tend\nend\n\n-- 数量\nfunction List:Count()\n\t-- body\n\treturn #self._list;\nend\n\n-- 克隆一个\nfunction List:Clone()\n\tlocal t = List:new()\n\n\tfor i, v in pairs(self._list)  do\n\t\tt:Push(v)\n\tend\n\n\treturn t\nend\n\n-- list赋值\nfunction List:Assign(InList)\n\tself._list = {};\n\tfor i = 1, InList:Count() do\n\t\tself._list[i] = InList:Get(i);\n\tend\nend\n\n-- 追加\nfunction List:Append(InList)\n\tlocal CurCount = self:Count();\n\tfor i = 1, InList:Count() do\n\t\tself._list[i + CurCount] = InList:Get(i);\n\tend\nend\n\n-- 清除\nfunction List:Clear()\n\t-- body\n\tself._list={};\nend\n\n-- 排序\nfunction List:Sort( Action )\n\ttable.sort( self._list, Action );\nend\n\n\n-- 反序\nfunction List:Reverse()\n\tlocal TmpTab = {};\n\tlocal k = 1;\n\tfor i = #self._list, 1, -1 do\n\t\tTmpTab[k] = self._list[i];\n\t\tk = k + 1;\n\tend\n\tfor i = 1, #TmpTab do\n\t\tself._list[i] = TmpTab[i];\n\tend\n\tTmpTab = nil;\nend\n\n-- 求包含的元素个数\nfunction List:NumsOf(inValue)\n\tlocal Nums = 0;\n\tfor i = 1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif nValue == inValue then\n\t\t\tNums = Nums + 1;\n\t\tend\n\tend\n\t\n\treturn Nums;\nend\n\n-- 返回符合条件的项\nfunction List:GetIf(fun, ...)\n\tfor i = 1, self:Count() do\n\t\tlocal Value = self:Get(i);\n\t\tif (nil ~= Value) then\n\t\t\tif fun(Value, ...) then\n\t\t\t\treturn Value;\n\t\t\tend\n\t\tend\n\tend\n\t\n\treturn nil;\nend\n\n-- 返回符合条件项的数量\nfunction List:NumsIf(fun, ...)\n\tlocal Nums = 0;\n\tfor i = 1, self:Count() do\n\t\tlocal Value = self:Get(i);\n\t\tif (nil ~= Value) then\n\t\t\tif fun(Value, ...) then\n\t\t\t\tNums = Nums + 1;\n\t\t\tend\n\t\tend\n\tend\n\t\n\treturn Nums;\nend\n\n-- 返回所有符合条件的所有项\nfunction List:GetIfAll(fun, ...)\n\tlocal ret = {};\n\tfor i = 1, self:Count() do\n\t\tlocal Value = self:Get(i);\n\t\tif (nil ~= Value) then\n\t\t\tif fun(Value, ...) then\n\t\t\t\ttable.insert(ret, Value);\n\t\t\tend\n\t\tend\n\tend\n\t\n\treturn ret;\nend\n\nreturn List;"
  },
  {
    "path": "code/EVA/server/script/Framework/Map.lua",
    "content": "Map = class(\"Map\")\n\nlocal this = Map\n\nfunction this:ctor()\n\tself.map = {};\n    self.count = 0\nend\n\n-- Map 插入新值\nfunction this:Insert(k,v)\n    if nil == self.map[k] then\n        self.map[k] = v\n        self.count = self.count + 1\n    end\nend\n\n-- Map 插入新值并且切换旧值\nfunction this:Replace(k,v)\n\tif nil == self.map[k] then\n\t\tself.map[k] = v;\n\t\tself.count = self.count + 1;\n\telse\n\t\tself.map[k] = v;\n\tend\nend\n\nfunction this:Remove(k)\n    if nil ~= self.map[k] then\n        self.map[k] = nil\n        if self.count >0 then\n            self.count = self.count - 1\n        end\n    end\nend\n\nfunction this:ForEachRemove(field, value)\n\n    local newT = {} \n    \n\tfor k,v in pairs(self.map) do\n        if v[field]~=value then\n            newT[k] = v;\n        end\n    end \n    \n    self.map = newT;\nend\n\nfunction this:Find(k)\n    return self.map[k]\nend\n\nfunction this:Clear()\n    self.map = {};\n    self.count = 0\nend\n\n\n-- 遍历所有成员\nfunction this:ForEach(fun, ...)\n\t-- body\n\tfor k,v in pairs(self.map) do\n\t\tfun(k, v, ...)\n\tend\nend\n\n-- Map 获取字典的count\nfunction this:Count()\n\treturn self.count;\nend\n\nreturn Map;\n\n\n--local characters = Map:new()\n--characters:Insert(\"name1\",\" this Name:123\")\n--characters:Replace(\"name1\",\" this Name:2\" )\n--local name2 = characters:Find(\"name1\")\n--nlinfo(name2)\n--nlinfo(characters.count)\n--for k,v in pairs(characters) do\n--nlinfo(k,v)\n--end"
  },
  {
    "path": "code/EVA/server/script/Framework/MapMap.lua",
    "content": "MapMap = class(\"MapMap\")\n\nlocal this = MapMap\n\nfunction this:ctor()\n\tself._map = {};\n    self._count = 0\nend\n\n-- MapMap ֵ\nfunction this:Insert(k1, k2, v)\n    if nil == self._map[k1] then\n        local maptmp = Map:new();\n        maptmp:Insert(k2,v);\n        \n        self._map[k1] = maptmp;\n        self._count = self._count + 1\n    else\n        self._map[k1]:Insert(k2,v);\n    end\nend\n\n-- MapMap ֵлֵ\nfunction this:Replace(k1,k2,v)\n\tif nil == self._map[k1] then\n        local maptmp = Map:new();\n        maptmp:Insert(k2,v);\n        \n        self._map[k1] = maptmp;\n\t\tself._count = self._count + 1;\n\telse\n\t\tself._map[k1]:Replace(k2,v);\n\tend\nend\n\nfunction this:Remove(k1, k2)\n    if nil ~= self._map[k1] then\n        if k2==nil then\n            self._map[k1] = nil\n            self._count = self._count - 1\n        else\n            self._map[k1]:Remove(k2);\n        end\n    end\nend\n\nfunction this:Find(k1, k2)\n    local value = nil\n    if nil ~= self._map[k1] then\n        value = self._map[k1]:Find(k2);\n    end\n    return value\nend\n\nfunction this:Clear()\n    for k,_ in pairs(self.List) do\n        if nil ~= self.List[k] then\n            self.List[k] = nil\n        end\n    end\n    self._count = 0\nend\n\n\n-- гԱ\nfunction this:ForEach(fun, ...)\n\t-- body\n\tfor k,v in pairs(self._map) do\n\t\tfun(k, v, ...)\n\tend\nend\n\n-- MapMap ȡֵcount\nfunction this:Count()\n\treturn self._count;\nend\n\nreturn Map;\n\n\n--local characters = Map:new()\n--characters:Insert(\"name1\",\" this Name:123\")\n--characters:Replace(\"name1\",\" this Name:2\" )\n--local name2 = characters:Find(\"name1\")\n--nlinfo(name2)\n--nlinfo(characters._count)\n--for k,v in pairs(characters) do\n--nlinfo(k,v)\n--end"
  },
  {
    "path": "code/EVA/server/script/Framework/MemoryReferenceInfo.lua",
    "content": "--\n-- Collect memory reference info.\n--\n-- @filename  MemoryReferenceInfo.lua\n-- @author    WangYaoqi\n-- @date      2016-02-03\n\n-- The global config of the mri.\nlocal cConfig = \n{\n    m_bAllMemoryRefFileAddTime = true,\n    m_bSingleMemoryRefFileAddTime = true,\n    m_bComparedMemoryRefFileAddTime = true\n}\n\n-- Get the format string of date time.\nlocal function FormatDateTimeNow()\n\tlocal cDateTime = os.date(\"*t\")\n\tlocal strDateTime = string.format(\"%04d%02d%02d-%02d%02d%02d\", tostring(cDateTime.year), tostring(cDateTime.month), tostring(cDateTime.day),\n\t\ttostring(cDateTime.hour), tostring(cDateTime.min), tostring(cDateTime.sec))\n\treturn strDateTime\nend\n\n-- Get the string result without overrided __tostring.\nlocal function GetOriginalToStringResult(cObject)\n\tif not cObject then\n\t\treturn \"\"\n\tend\n\n\tlocal cMt = getmetatable(cObject)\n\tif not cMt then\n\t\treturn tostring(cObject)\n\tend\n\n\t-- Check tostring override.\n\tlocal strName = \"\"\n\tlocal cToString = rawget(cMt, \"__tostring\")\n\tif cToString then\n\t\trawset(cMt, \"__tostring\", nil)\n\t\tstrName = tostring(cObject)\n\t\trawset(cMt, \"__tostring\", cToString)\n\telse\n\t\tstrName = tostring(cObject)\n\tend\n\n\treturn strName\nend\n\n-- Create a container to collect the mem ref info results.\nlocal function CreateObjectReferenceInfoContainer()\n\t-- Create new container.\n\tlocal cContainer = {}\n\n\t-- Contain [table/function] - [reference count] info.\n\tlocal cObjectReferenceCount = {}\n\tsetmetatable(cObjectReferenceCount, {__mode = \"k\"})\n\n\t-- Contain [table/function] - [name] info.\n\tlocal cObjectAddressToName = {}\n\tsetmetatable(cObjectAddressToName, {__mode = \"k\"})\n\n\t-- Set members.\n\tcContainer.m_cObjectReferenceCount = cObjectReferenceCount\n\tcContainer.m_cObjectAddressToName = cObjectAddressToName\n\n\t-- For stack info.\n\tcContainer.m_nStackLevel = -1\n\tcContainer.m_strShortSrc = \"None\"\n\tcContainer.m_nCurrentLine = -1\n\n\treturn cContainer\nend\n\n-- Create a container to collect the mem ref info results from a dumped file.\n-- strFilePath - The file path.\nlocal function CreateObjectReferenceInfoContainerFromFile(strFilePath)\n\t-- Create a empty container.\n\tlocal cContainer = CreateObjectReferenceInfoContainer()\n\tcContainer.m_strShortSrc = strFilePath\n\n\t-- Cache ref info.\n\tlocal cRefInfo = cContainer.m_cObjectReferenceCount\n\tlocal cNameInfo = cContainer.m_cObjectAddressToName\n\n\t-- Read each line from file.\n\tlocal cFile = assert(io.open(strFilePath, \"rb\"))\n\tfor strLine in cFile:lines() do\n\t\tlocal strHeader = string.sub(strLine, 1, 2)\n\t\tif \"--\" ~= strHeader then\n\t\t\tlocal _, _, strAddr, strName, strRefCount= string.find(strLine, \"(.+)\\t(.*)\\t(%d+)\")\n\t\t\tif strAddr then\n\t\t\t\tcRefInfo[strAddr] = strRefCount\n\t\t\t\tcNameInfo[strAddr] = strName\n\t\t\tend\n\t\tend\n\tend\n\n    -- Close and clear file handler.\n    io.close(cFile)\n    cFile = nil\n\n\treturn cContainer\nend\n\n-- Create a container to collect the mem ref info results from a dumped file.\n-- strObjectName - The object name you need to collect info.\n-- cObject - The object you need to collect info.\nlocal function CreateSingleObjectReferenceInfoContainer(strObjectName, cObject)\n\t-- Create new container.\n\tlocal cContainer = {}\n\n\t-- Contain [address] - [true] info.\n\tlocal cObjectExistTag = {}\n\tsetmetatable(cObjectExistTag, {__mode = \"k\"})\n\n\t-- Contain [name] - [true] info.\n\tlocal cObjectAliasName = {}\n\n\t-- Contain [access] - [true] info.\n\tlocal cObjectAccessTag = {}\n\tsetmetatable(cObjectAccessTag, {__mode = \"k\"})\n\n\t-- Set members.\n\tcContainer.m_cObjectExistTag = cObjectExistTag\n\tcContainer.m_cObjectAliasName = cObjectAliasName\n\tcContainer.m_cObjectAccessTag = cObjectAccessTag\n\n\t-- For stack info.\n\tcContainer.m_nStackLevel = -1\n\tcContainer.m_strShortSrc = \"None\"\n\tcContainer.m_nCurrentLine = -1\n\n\t-- Init with object values.\n\tcContainer.m_strObjectName = strObjectName\n\tcContainer.m_strAddressName = ((\"string\" == type(cObject)) and (\"\\\"\" .. tostring(cObject) .. \"\\\"\")) or GetOriginalToStringResult(cObject)\n\tcContainer.m_cObjectExistTag[cObject] = true\n\n\treturn cContainer\nend\n\n-- Collect memory reference info from a root table or function.\n-- strName - The root object name that start to search, default is \"_G\" if leave this to nil.\n-- cObject - The root object that start to search, default is _G if leave this to nil.\n-- cDumpInfoContainer - The container of the dump result info.\nlocal function CollectObjectReferenceInMemory(strName, cObject, cDumpInfoContainer)\n\tif not cObject then\n\t\treturn\n\tend\n\n\tif not strName then\n\t\tstrName = \"\"\n\tend\n\n\t-- Check container.\n\tif (not cDumpInfoContainer) then\n\t\tcDumpInfoContainer = CreateObjectReferenceInfoContainer()\n\tend\n\n\t-- Check stack.\n\tif cDumpInfoContainer.m_nStackLevel > 0 then\n\t\tlocal cStackInfo = debug.getinfo(cDumpInfoContainer.m_nStackLevel, \"Sl\")\n\t\tif cStackInfo then\n\t\t\tcDumpInfoContainer.m_strShortSrc = cStackInfo.short_src\n\t\t\tcDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline\n\t\tend\n\n\t\tcDumpInfoContainer.m_nStackLevel = -1\n\tend\n\n\t-- Get ref and name info.\n\tlocal cRefInfoContainer = cDumpInfoContainer.m_cObjectReferenceCount\n\tlocal cNameInfoContainer = cDumpInfoContainer.m_cObjectAddressToName\n\t\n\tlocal strType = type(cObject)\n\tif \"table\" == strType then\n\t\t-- Check table with class name.\n\t\tif rawget(cObject, \"__cname\") then\n\t\t\tif \"string\" == type(cObject.__cname) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject.__cname .. \"]\"\n\t\t\tend\n\t\telseif rawget(cObject, \"class\") then\n\t\t\tif \"string\" == type(cObject.class) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject.class .. \"]\"\n\t\t\tend\n\t\telseif rawget(cObject, \"_className\") then\n\t\t\tif \"string\" == type(cObject._className) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject._className .. \"]\"\n\t\t\tend\n\t\tend\n\n\t\t-- Check if table is _G.\n\t\tif cObject == _G then\n\t\t\tstrName = strName .. \"[_G]\"\n\t\tend\n\n\t\t-- Get metatable.\n\t\tlocal bWeakK = false\n\t\tlocal bWeakV = false\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\t-- Check mode.\n\t\t\tlocal strMode = rawget(cMt, \"__mode\")\n\t\t\tif strMode then\n\t\t\t\tif \"k\" == strMode then\n\t\t\t\t\tbWeakK = true\n\t\t\t\telseif \"v\" == strMode then\n\t\t\t\t\tbWeakV = true\n\t\t\t\telseif \"kv\" == strMode then\n\t\t\t\t\tbWeakK = true\n\t\t\t\t\tbWeakV = true\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\n\t\t-- Add reference and name.\n\t\tcRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n\t\tif cNameInfoContainer[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Set name.\n\t\tcNameInfoContainer[cObject] = strName\n\n\t\t-- Dump table key and value.\n\t\tfor k, v in pairs(cObject) do\n\t\t\t-- Check key type.\n\t\t\tlocal strKeyType = type(k)\n\t\t\tif \"table\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:key.table]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"function\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:key.function]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"thread\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:key.thread]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"userdata\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:key.userdata]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telse\n\t\t\t\tCollectObjectReferenceInMemory(strName .. \".\" .. k, v, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tif cMt then\n\t\t\tCollectObjectReferenceInMemory(strName ..\".[metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n\telseif \"function\" == strType then\n\t\t-- Get function info.\n\t\tlocal cDInfo = debug.getinfo(cObject, \"Su\")\n\n\t\t-- Write this info.\n\t\tcRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n\t\tif cNameInfoContainer[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Set name.\n\t\tcNameInfoContainer[cObject] = strName .. \"[line:\" .. tostring(cDInfo.linedefined) .. \"@file:\" .. cDInfo.short_src .. \"]\"\n\n\t\t-- Get upvalues.\n\t\tlocal nUpsNum = cDInfo.nups\n\t\tfor i = 1, nUpsNum do\n\t\t\tlocal strUpName, cUpValue = debug.getupvalue(cObject, i)\n\t\t\tlocal strUpValueType = type(cUpValue)\n\t\t\t--print(strUpName, cUpValue)\n\t\t\tif \"table\" == strUpValueType then\n\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[ups:table:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"function\" == strUpValueType then\n\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[ups:function:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"thread\" == strUpValueType then\n\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[ups:thread:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"userdata\" == strUpValueType then\n\t\t\t\tCollectObjectReferenceInMemory(strName .. \".[ups:userdata:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectObjectReferenceInMemory(strName ..\".[function:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\telseif \"thread\" == strType then\n\t\t-- Add reference and name.\n\t\tcRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n\t\tif cNameInfoContainer[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Set name.\n\t\tcNameInfoContainer[cObject] = strName\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectObjectReferenceInMemory(strName ..\".[thread:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\tCollectObjectReferenceInMemory(strName ..\".[thread:metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n\telseif \"userdata\" == strType then\n\t\t-- Add reference and name.\n\t\tcRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n\t\tif cNameInfoContainer[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Set name.\n\t\tcNameInfoContainer[cObject] = strName\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectObjectReferenceInMemory(strName ..\".[userdata:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\tCollectObjectReferenceInMemory(strName ..\".[userdata:metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n    elseif \"string\" == strType then\n        -- Add reference and name.\n        cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n        if cNameInfoContainer[cObject] then\n            return\n        end\n\n        -- Set name.\n        cNameInfoContainer[cObject] = strName .. \"[\" .. strType .. \"]\"\n\telse\n\t\t-- For \"number\" and \"boolean\". (If you want to dump them, uncomment the followed lines.)\n\n\t\t-- -- Add reference and name.\n\t\t-- cRefInfoContainer[cObject] = (cRefInfoContainer[cObject] and (cRefInfoContainer[cObject] + 1)) or 1\n\t\t-- if cNameInfoContainer[cObject] then\n\t\t-- \treturn\n\t\t-- end\n\n\t\t-- -- Set name.\n\t\t-- cNameInfoContainer[cObject] = strName .. \"[\" .. strType .. \":\" .. tostring(cObject) .. \"]\"\n\tend\nend\n\n-- Collect memory reference info of a single object from a root table or function.\n-- strName - The root object name that start to search, can not be nil.\n-- cObject - The root object that start to search, can not be nil.\n-- cDumpInfoContainer - The container of the dump result info.\nlocal function CollectSingleObjectReferenceInMemory(strName, cObject, cDumpInfoContainer)\n\tif not cObject then\n\t\treturn\n\tend\n\n\tif not strName then\n\t\tstrName = \"\"\n\tend\n\n\t-- Check container.\n\tif (not cDumpInfoContainer) then\n\t\tcDumpInfoContainer = CreateObjectReferenceInfoContainer()\n\tend\n\n\t-- Check stack.\n\tif cDumpInfoContainer.m_nStackLevel > 0 then\n\t\tlocal cStackInfo = debug.getinfo(cDumpInfoContainer.m_nStackLevel, \"Sl\")\n\t\tif cStackInfo then\n\t\t\tcDumpInfoContainer.m_strShortSrc = cStackInfo.short_src\n\t\t\tcDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline\n\t\tend\n\n\t\tcDumpInfoContainer.m_nStackLevel = -1\n\tend\n\n\tlocal cExistTag = cDumpInfoContainer.m_cObjectExistTag\n\tlocal cNameAllAlias = cDumpInfoContainer.m_cObjectAliasName\n\tlocal cAccessTag = cDumpInfoContainer.m_cObjectAccessTag\n\t\n\tlocal strType = type(cObject)\n\tif \"table\" == strType then\n\t\t-- Check table with class name.\n\t\tif rawget(cObject, \"__cname\") then\n\t\t\tif \"string\" == type(cObject.__cname) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject.__cname .. \"]\"\n\t\t\tend\n\t\telseif rawget(cObject, \"class\") then\n\t\t\tif \"string\" == type(cObject.class) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject.class .. \"]\"\n\t\t\tend\n\t\telseif rawget(cObject, \"_className\") then\n\t\t\tif \"string\" == type(cObject._className) then\n\t\t\t\tstrName = strName .. \"[class:\" .. cObject._className .. \"]\"\n\t\t\tend\n\t\tend\n\n\t\t-- Check if table is _G.\n\t\tif cObject == _G then\n\t\t\tstrName = strName .. \"[_G]\"\n\t\tend\n\n\t\t-- Get metatable.\n\t\tlocal bWeakK = false\n\t\tlocal bWeakV = false\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\t-- Check mode.\n\t\t\tlocal strMode = rawget(cMt, \"__mode\")\n\t\t\tif strMode then\n\t\t\t\tif \"k\" == strMode then\n\t\t\t\t\tbWeakK = true\n\t\t\t\telseif \"v\" == strMode then\n\t\t\t\t\tbWeakV = true\n\t\t\t\telseif \"kv\" == strMode then\n\t\t\t\t\tbWeakK = true\n\t\t\t\t\tbWeakV = true\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\n\t\t-- Check if the specified object.\n\t\tif cExistTag[cObject] and (not cNameAllAlias[strName]) then\n\t\t\tcNameAllAlias[strName] = true\n\t\tend\n\n\t\t-- Add reference and name.\n\t\tif cAccessTag[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Get this name.\n\t\tcAccessTag[cObject] = true\n\n\t\t-- Dump table key and value.\n\t\tfor k, v in pairs(cObject) do\n\t\t\t-- Check key type.\n\t\t\tlocal strKeyType = type(k)\n\t\t\tif \"table\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:key.table]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"function\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:key.function]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"thread\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:key.thread]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telseif \"userdata\" == strKeyType then\n\t\t\t\tif not bWeakK then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:key.userdata]\", k, cDumpInfoContainer)\n\t\t\t\tend\n\n\t\t\t\tif not bWeakV then\n\t\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[table:value]\", v, cDumpInfoContainer)\n\t\t\t\tend\n\t\t\telse\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".\" .. k, v, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tif cMt then\n\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n\telseif \"function\" == strType then\n\t\t-- Get function info.\n\t\tlocal cDInfo = debug.getinfo(cObject, \"Su\")\n\t\tlocal cCombinedName = strName .. \"[line:\" .. tostring(cDInfo.linedefined) .. \"@file:\" .. cDInfo.short_src .. \"]\"\n\n\t\t-- Check if the specified object.\n\t\tif cExistTag[cObject] and (not cNameAllAlias[cCombinedName]) then\n\t\t\tcNameAllAlias[cCombinedName] = true\n\t\tend\n\n\t\t-- Write this info.\n\t\tif cAccessTag[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Set name.\n\t\tcAccessTag[cObject] = true\n\n\t\t-- Get upvalues.\n\t\tlocal nUpsNum = cDInfo.nups\n\t\tfor i = 1, nUpsNum do\n\t\t\tlocal strUpName, cUpValue = debug.getupvalue(cObject, i)\n\t\t\tlocal strUpValueType = type(cUpValue)\n\t\t\t--print(strUpName, cUpValue)\n\t\t\tif \"table\" == strUpValueType then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[ups:table:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"function\" == strUpValueType then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[ups:function:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"thread\" == strUpValueType then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[ups:thread:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\telseif \"userdata\" == strUpValueType then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName .. \".[ups:userdata:\" .. strUpName .. \"]\", cUpValue, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[function:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\telseif \"thread\" == strType then\n\t\t-- Check if the specified object.\n\t\tif cExistTag[cObject] and (not cNameAllAlias[strName]) then\n\t\t\tcNameAllAlias[strName] = true\n\t\tend\n\n\t\t-- Add reference and name.\n\t\tif cAccessTag[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Get this name.\n\t\tcAccessTag[cObject] = true\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[thread:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[thread:metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n\telseif \"userdata\" == strType then\n\t\t-- Check if the specified object.\n\t\tif cExistTag[cObject] and (not cNameAllAlias[strName]) then\n\t\t\tcNameAllAlias[strName] = true\n\t\tend\n\n\t\t-- Add reference and name.\n\t\tif cAccessTag[cObject] then\n\t\t\treturn\n\t\tend\n\n\t\t-- Get this name.\n\t\tcAccessTag[cObject] = true\n\n\t\t-- Dump environment table.\n\t\tlocal getfenv = debug.getfenv\n\t\tif getfenv then\n\t\t\tlocal cEnv = getfenv(cObject)\n\t\t\tif cEnv then\n\t\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[userdata:environment]\", cEnv, cDumpInfoContainer)\n\t\t\tend\n\t\tend\n\n\t\t-- Dump metatable.\n\t\tlocal cMt = getmetatable(cObject)\n\t\tif cMt then\n\t\t\tCollectSingleObjectReferenceInMemory(strName ..\".[userdata:metatable]\", cMt, cDumpInfoContainer)\n\t\tend\n    elseif \"string\" == strType then\n        -- Check if the specified object.\n        if cExistTag[cObject] and (not cNameAllAlias[strName]) then\n            cNameAllAlias[strName] = true\n        end\n\n        -- Add reference and name.\n        if cAccessTag[cObject] then\n            return\n        end\n\n        -- Get this name.\n        cAccessTag[cObject] = true\n    else\n        -- For \"number\" and \"boolean\" type, they are not object type, skip.\n\tend\nend\n\n-- The base method to dump a mem ref info result into a file.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- strRootObjectName - The header info to show the root object name, can be nil.\n-- cRootObject - The header info to show the root object address, can be nil.\n-- cDumpInfoResultsBase - The base dumped mem info result, nil means no compare and only output cDumpInfoResults, otherwise to compare with cDumpInfoResults.\n-- cDumpInfoResults - The compared dumped mem info result, dump itself only if cDumpInfoResultsBase is nil, otherwise dump compared results with cDumpInfoResultsBase.\nlocal function OutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject, cDumpInfoResultsBase, cDumpInfoResults)\n\t-- Check results.\n\tif not cDumpInfoResults then\n\t\treturn\n\tend\n\n\t-- Get time format string.\n\tlocal strDateTime = FormatDateTimeNow()\n\n\t-- Collect memory info.\n\tlocal cRefInfoBase = (cDumpInfoResultsBase and cDumpInfoResultsBase.m_cObjectReferenceCount) or nil\n\tlocal cNameInfoBase = (cDumpInfoResultsBase and cDumpInfoResultsBase.m_cObjectAddressToName) or nil\n\tlocal cRefInfo = cDumpInfoResults.m_cObjectReferenceCount\n\tlocal cNameInfo = cDumpInfoResults.m_cObjectAddressToName\n\t\n\t-- Create a cache result to sort by ref count.\n\tlocal cRes = {}\n\tlocal nIdx = 0\n\tfor k in pairs(cRefInfo) do\n\t\tnIdx = nIdx + 1\n\t\tcRes[nIdx] = k\n\tend\n\n\t-- Sort result.\n\ttable.sort(cRes, function (l, r)\n\t\treturn cRefInfo[l] > cRefInfo[r]\n\tend)\n\n\t-- Save result to file.\n\tlocal bOutputFile = strSavePath and (string.len(strSavePath) > 0)\n\tlocal cOutputHandle = nil\n\tlocal cOutputEntry = print\n\t\n\tif bOutputFile then\n\t\t-- Check save path affix.\n\t\tlocal strAffix = string.sub(strSavePath, -1)\n\t\tif (\"/\" ~= strAffix) and (\"\\\\\" ~= strAffix) then\n\t\t\tstrSavePath = strSavePath .. \"/\"\n\t\tend\n\n\t\t-- Combine file name.\n\t\tlocal strFileName = strSavePath .. \"LuaMemRefInfo-All\"\n\t\tif (not strExtraFileName) or (0 == string.len(strExtraFileName)) then\n            if cDumpInfoResultsBase then\n                if cConfig.m_bComparedMemoryRefFileAddTime then\n                    strFileName = strFileName .. \"-[\" .. strDateTime .. \"].txt\"\n                else\n                    strFileName = strFileName .. \".txt\"\n                end\n            else\n                if cConfig.m_bAllMemoryRefFileAddTime then\n                    strFileName = strFileName .. \"-[\" .. strDateTime .. \"].txt\"\n                else\n                    strFileName = strFileName .. \".txt\"\n                end\n            end\n\t\telse\n            if cDumpInfoResultsBase then\n                if cConfig.m_bComparedMemoryRefFileAddTime then\n                    strFileName = strFileName .. \"-[\" .. strDateTime .. \"]-[\" .. strExtraFileName .. \"].txt\"\n                else\n                    strFileName = strFileName .. \"-[\" .. strExtraFileName .. \"].txt\"\n                end\n            else\n                if cConfig.m_bAllMemoryRefFileAddTime then\n                    strFileName = strFileName .. \"-[\" .. strDateTime .. \"]-[\" .. strExtraFileName .. \"].txt\"\n                else\n                    strFileName = strFileName .. \"-[\" .. strExtraFileName .. \"].txt\"\n                end\n            end\n\t\tend\n\n\t\tlocal cFile = assert(io.open(strFileName, \"w\"))\n\t\tcOutputHandle = cFile\n\t\tcOutputEntry = cFile.write\n\tend\n\n\tlocal cOutputer = function (strContent)\n\t\tif cOutputHandle then\n\t\t\tcOutputEntry(cOutputHandle, strContent)\n\t\telse\n\t\t\tcOutputEntry(strContent)\n\t\tend\n\tend\n\n\t-- Write table header.\n\tif cDumpInfoResultsBase then\n\t\tcOutputer(\"--------------------------------------------------------\\n\")\n\t\tcOutputer(\"-- This is compared memory information.\\n\")\n\n\t\tcOutputer(\"--------------------------------------------------------\\n\")\n\t\tcOutputer(\"-- Collect base memory reference at line:\" .. tostring(cDumpInfoResultsBase.m_nCurrentLine) .. \"@file:\" .. cDumpInfoResultsBase.m_strShortSrc .. \"\\n\")\n\t\tcOutputer(\"-- Collect compared memory reference at line:\" .. tostring(cDumpInfoResults.m_nCurrentLine) .. \"@file:\" .. cDumpInfoResults.m_strShortSrc .. \"\\n\")\n\telse\n\t\tcOutputer(\"--------------------------------------------------------\\n\")\n\t\tcOutputer(\"-- Collect memory reference at line:\" .. tostring(cDumpInfoResults.m_nCurrentLine) .. \"@file:\" .. cDumpInfoResults.m_strShortSrc .. \"\\n\")\n\tend\n\n\tcOutputer(\"--------------------------------------------------------\\n\")\n\tcOutputer(\"-- [Table/Function/String Address/Name]\\t[Reference Path]\\t[Reference Count]\\n\")\n\tcOutputer(\"--------------------------------------------------------\\n\")\n\n\tif strRootObjectName and cRootObject then\n        if \"string\" == type(cRootObject) then\n            cOutputer(\"-- From Root Object: \\\"\" .. tostring(cRootObject) .. \"\\\" (\" .. strRootObjectName .. \")\\n\")\n        else\n            cOutputer(\"-- From Root Object: \" .. GetOriginalToStringResult(cRootObject) .. \" (\" .. strRootObjectName .. \")\\n\")\n        end\n\tend\n\n\t-- Save each info.\n\tfor i, v in ipairs(cRes) do\n\t\tif (not cDumpInfoResultsBase) or (not cRefInfoBase[v]) then\n\t\t\tif (nMaxRescords > 0) then\n\t\t\t\tif (i <= nMaxRescords) then\n                    if \"string\" == type(v) then\n                        local strOrgString = tostring(v)\n                        local nPattenBegin, nPattenEnd = string.find(strOrgString, \"string: \\\".*\\\"\")\n                        if ((not cDumpInfoResultsBase) and ((nil == nPattenBegin) or (nil == nPattenEnd))) then\n                            local strRepString = string.gsub(strOrgString, \"([\\n\\r])\", \"\\\\n\")\n                            cOutputer(\"string: \\\"\" .. strRepString .. \"\\\"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                        else\n                            cOutputer(tostring(v) .. \"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                        end\n                    else\n                        cOutputer(GetOriginalToStringResult(v) .. \"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                    end\n\t\t\t\tend\n\t\t\telse\n                if \"string\" == type(v) then\n                    local strOrgString = tostring(v)\n                    local nPattenBegin, nPattenEnd = string.find(strOrgString, \"string: \\\".*\\\"\")\n                    if ((not cDumpInfoResultsBase) and ((nil == nPattenBegin) or (nil == nPattenEnd))) then\n                        local strRepString = string.gsub(strOrgString, \"([\\n\\r])\", \"\\\\n\")\n                        cOutputer(\"string: \\\"\" .. strRepString .. \"\\\"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                    else\n                        cOutputer(tostring(v) .. \"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                    end\n\t\t\t\telse\n                    cOutputer(GetOriginalToStringResult(v) .. \"\\t\" .. cNameInfo[v] .. \"\\t\" .. tostring(cRefInfo[v]) .. \"\\n\")\n                end\n\t\t\tend\n\t\tend\n\tend\n\n\tif bOutputFile then\n\t\tio.close(cOutputHandle)\n        cOutputHandle = nil\n\tend\nend\n\n-- The base method to dump a mem ref info result of a single object into a file.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- cDumpInfoResults - The dumped results.\nlocal function OutputMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, cDumpInfoResults)\n\t-- Check results.\n\tif not cDumpInfoResults then\n\t\treturn\n\tend\n\n\t-- Get time format string.\n\tlocal strDateTime = FormatDateTimeNow()\n\n\t-- Collect memory info.\n\tlocal cObjectAliasName = cDumpInfoResults.m_cObjectAliasName\n\n\t-- Save result to file.\n\tlocal bOutputFile = strSavePath and (string.len(strSavePath) > 0)\n\tlocal cOutputHandle = nil\n\tlocal cOutputEntry = print\n\t\n\tif bOutputFile then\n\t\t-- Check save path affix.\n\t\tlocal strAffix = string.sub(strSavePath, -1)\n\t\tif (\"/\" ~= strAffix) and (\"\\\\\" ~= strAffix) then\n\t\t\tstrSavePath = strSavePath .. \"/\"\n\t\tend\n\n\t\t-- Combine file name.\n\t\tlocal strFileName = strSavePath .. \"LuaMemRefInfo-Single\"\n\t\tif (not strExtraFileName) or (0 == string.len(strExtraFileName)) then\n            if cConfig.m_bSingleMemoryRefFileAddTime then\n                strFileName = strFileName .. \"-[\" .. strDateTime .. \"].txt\"\n            else\n                strFileName = strFileName .. \".txt\"\n            end\n\t\telse\n            if cConfig.m_bSingleMemoryRefFileAddTime then\n                strFileName = strFileName .. \"-[\" .. strDateTime .. \"]-[\" .. strExtraFileName .. \"].txt\"\n            else\n                strFileName = strFileName .. \"-[\" .. strExtraFileName .. \"].txt\"\n            end\n\t\tend\n\n\t\tlocal cFile = assert(io.open(strFileName, \"w\"))\n\t\tcOutputHandle = cFile\n\t\tcOutputEntry = cFile.write\n\tend\n\n\tlocal cOutputer = function (strContent)\n\t\tif cOutputHandle then\n\t\t\tcOutputEntry(cOutputHandle, strContent)\n\t\telse\n\t\t\tcOutputEntry(strContent)\n\t\tend\n\tend\n\n\t-- Write table header.\n\tcOutputer(\"--------------------------------------------------------\\n\")\n\tcOutputer(\"-- Collect single object memory reference at line:\" .. tostring(cDumpInfoResults.m_nCurrentLine) .. \"@file:\" .. cDumpInfoResults.m_strShortSrc .. \"\\n\")\n\tcOutputer(\"--------------------------------------------------------\\n\")\n\n\t-- Calculate reference count.\n\tlocal nCount = 0\n\tfor k in pairs(cObjectAliasName) do\n\t\tnCount = nCount + 1\n\tend\n\n\t-- Output reference count.\n\tcOutputer(\"-- For Object: \" .. cDumpInfoResults.m_strAddressName .. \" (\" .. cDumpInfoResults.m_strObjectName .. \"), have \" .. tostring(nCount) .. \" reference in total.\\n\")\n\tcOutputer(\"--------------------------------------------------------\\n\")\n\n\t-- Save each info.\n\tfor k in pairs(cObjectAliasName) do\n\t\tif (nMaxRescords > 0) then\n\t\t\tif (i <= nMaxRescords) then\n\t\t\t\tcOutputer(k .. \"\\n\")\n\t\t\tend\n\t\telse\n\t\t\tcOutputer(k .. \"\\n\")\n\t\tend\n\tend\n\n\tif bOutputFile then\n\t\tio.close(cOutputHandle)\n        cOutputHandle = nil\n\tend\nend\n\n-- Fileter an existing result file and output it.\n-- strFilePath - The existing result file.\n-- strFilter - The filter string.\n-- bIncludeFilter - Include(true) or exclude(false) the filter.\n-- bOutputFile - Output to file(true) or console(false).\nlocal function OutputFilteredResult(strFilePath, strFilter, bIncludeFilter, bOutputFile)\n\tif (not strFilePath) or (0 == string.len(strFilePath)) then\n\t\tprint(\"You need to specify a file path.\")\n\t\treturn\n\tend\n\n\tif (not strFilter) or (0 == string.len(strFilter)) then\n\t\tprint(\"You need to specify a filter string.\")\n\t\treturn\n\tend\n\n\t-- Read file.\n\tlocal cFilteredResult = {}\n    local cReadFile = assert(io.open(strFilePath, \"rb\"))\n\tfor strLine in cReadFile:lines() do\n\t\tlocal nBegin, nEnd = string.find(strLine, strFilter)\n\t\tif nBegin and nEnd then\n\t\t\tif bIncludeFilter then\n                nBegin, nEnd = string.find(strLine, \"[\\r\\n]\")\n                if nBegin and nEnd  and (string.len(strLine) == nEnd) then\n                    table.insert(cFilteredResult, string.sub(strLine, 1, nBegin - 1))\n                else\n\t\t\t\t    table.insert(cFilteredResult, strLine)\n                end\n\t\t\tend\n\t\telse\n\t\t\tif not bIncludeFilter then\n                nBegin, nEnd = string.find(strLine, \"[\\r\\n]\")\n                if nBegin and nEnd and (string.len(strLine) == nEnd) then\n                    table.insert(cFilteredResult, string.sub(strLine, 1, nBegin - 1))\n                else\n\t\t\t\t    table.insert(cFilteredResult, strLine)\n                end\n\t\t\tend\n\t\tend\n\tend\n\n    -- Close and clear read file handle.\n    io.close(cReadFile)\n    cReadFile = nil\n\n\t-- Write filtered result.\n\tlocal cOutputHandle = nil\n\tlocal cOutputEntry = print\n\n\tif bOutputFile then\n\t\t-- Combine file name.\n\t\tlocal _, _, strResFileName = string.find(strFilePath, \"(.*)%.txt\")\n\t\tstrResFileName = strResFileName .. \"-Filter-\" .. ((bIncludeFilter and \"I\") or \"E\") .. \"-[\" .. strFilter .. \"].txt\"\n\n\t\tlocal cFile = assert(io.open(strResFileName, \"w\"))\n\t\tcOutputHandle = cFile\n\t\tcOutputEntry = cFile.write\n\tend\n\n\tlocal cOutputer = function (strContent)\n\t\tif cOutputHandle then\n\t\t\tcOutputEntry(cOutputHandle, strContent)\n\t\telse\n\t\t\tcOutputEntry(strContent)\n\t\tend\n\tend\n\n\t-- Output result.\n\tfor i, v in ipairs(cFilteredResult) do\n\t\tcOutputer(v .. \"\\n\")\n\tend\n\n\tif bOutputFile then\n\t\tio.close(cOutputHandle)\n        cOutputHandle = nil\n\tend\nend\n\n-- Dump memory reference at current time.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- strRootObjectName - The root object name that start to search, default is \"_G\" if leave this to nil.\n-- cRootObject - The root object that start to search, default is _G if leave this to nil.\nlocal function DumpMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject)\n\t-- Get time format string.\n\tlocal strDateTime = FormatDateTimeNow()\n\n\t-- Check root object.\n\tif cRootObject then\n\t\tif (not strRootObjectName) or (0 == string.len(strRootObjectName)) then\n\t\t\tstrRootObjectName = tostring(cRootObject)\n\t\tend\n\telse\n\t\tcRootObject = debug.getregistry()\n\t\tstrRootObjectName = \"registry\"\n\tend\n\n\t-- Create container.\n\tlocal cDumpInfoContainer = CreateObjectReferenceInfoContainer()\n\tlocal cStackInfo = debug.getinfo(2, \"Sl\")\n\tif cStackInfo then\n\t\tcDumpInfoContainer.m_strShortSrc = cStackInfo.short_src\n\t\tcDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline\n\tend\n\n\t-- Collect memory info.\n\tCollectObjectReferenceInMemory(strRootObjectName, cRootObject, cDumpInfoContainer)\n\t\n\t-- Dump the result.\n\tOutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject, nil, cDumpInfoContainer)\nend\n\n-- Dump compared memory reference results generated by DumpMemorySnapshot.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- cResultBefore - The base dumped results.\n-- cResultAfter - The compared dumped results.\nlocal function DumpMemorySnapshotCompared(strSavePath, strExtraFileName, nMaxRescords, cResultBefore, cResultAfter)\n\t-- Dump the result.\n\tOutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, nil, nil, cResultBefore, cResultAfter)\nend\n\n-- Dump compared memory reference file results generated by DumpMemorySnapshot.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- strResultFilePathBefore - The base dumped results file.\n-- strResultFilePathAfter - The compared dumped results file.\nlocal function DumpMemorySnapshotComparedFile(strSavePath, strExtraFileName, nMaxRescords, strResultFilePathBefore, strResultFilePathAfter)\n\t-- Read results from file.\n\tlocal cResultBefore = CreateObjectReferenceInfoContainerFromFile(strResultFilePathBefore)\n\tlocal cResultAfter = CreateObjectReferenceInfoContainerFromFile(strResultFilePathAfter)\n\n\t-- Dump the result.\n\tOutputMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, nil, nil, cResultBefore, cResultAfter)\nend\n\n-- Dump memory reference of a single object at current time.\n-- strSavePath - The save path of the file to store the result, must be a directory path, If nil or \"\" then the result will output to console as print does.\n-- strExtraFileName - If you want to add extra info append to the end of the result file, give a string, nothing will do if set to nil or \"\".\n-- nMaxRescords - How many rescords of the results in limit to save in the file or output to the console, -1 will give all the result.\n-- strObjectName - The object name reference you want to dump.\n-- cObject - The object reference you want to dump.\nlocal function DumpMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, strObjectName, cObject)\n\t-- Check object.\n\tif not cObject then\n\t\treturn\n\tend\n\n\tif (not strObjectName) or (0 == string.len(strObjectName)) then\n\t\tstrObjectName = GetOriginalToStringResult(cObject)\n\tend\n\n\t-- Get time format string.\n\tlocal strDateTime = FormatDateTimeNow()\n\n\t-- Create container.\n\tlocal cDumpInfoContainer = CreateSingleObjectReferenceInfoContainer(strObjectName, cObject)\n\tlocal cStackInfo = debug.getinfo(2, \"Sl\")\n\tif cStackInfo then\n\t\tcDumpInfoContainer.m_strShortSrc = cStackInfo.short_src\n\t\tcDumpInfoContainer.m_nCurrentLine = cStackInfo.currentline\n\tend\n\n\t-- Collect memory info.\n\tCollectSingleObjectReferenceInMemory(\"registry\", debug.getregistry(), cDumpInfoContainer)\n\t\n\t-- Dump the result.\n\tOutputMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, cDumpInfoContainer)\nend\n\n-- Return methods.\nlocal cPublications = {m_cConfig = nil, m_cMethods = {}, m_cHelpers = {}, m_cBases = {}}\n\ncPublications.m_cConfig = cConfig\n\ncPublications.m_cMethods.DumpMemorySnapshot = DumpMemorySnapshot\ncPublications.m_cMethods.DumpMemorySnapshotCompared = DumpMemorySnapshotCompared\ncPublications.m_cMethods.DumpMemorySnapshotComparedFile = DumpMemorySnapshotComparedFile\ncPublications.m_cMethods.DumpMemorySnapshotSingleObject = DumpMemorySnapshotSingleObject\n\ncPublications.m_cHelpers.FormatDateTimeNow = FormatDateTimeNow\ncPublications.m_cHelpers.GetOriginalToStringResult = GetOriginalToStringResult\n\ncPublications.m_cBases.CreateObjectReferenceInfoContainer = CreateObjectReferenceInfoContainer\ncPublications.m_cBases.CreateObjectReferenceInfoContainerFromFile = CreateObjectReferenceInfoContainerFromFile\ncPublications.m_cBases.CreateSingleObjectReferenceInfoContainer = CreateSingleObjectReferenceInfoContainer\ncPublications.m_cBases.CollectObjectReferenceInMemory = CollectObjectReferenceInMemory\ncPublications.m_cBases.CollectSingleObjectReferenceInMemory = CollectSingleObjectReferenceInMemory\ncPublications.m_cBases.OutputMemorySnapshot = OutputMemorySnapshot\ncPublications.m_cBases.OutputMemorySnapshotSingleObject = OutputMemorySnapshotSingleObject\ncPublications.m_cBases.OutputFilteredResult = OutputFilteredResult\n\nreturn cPublications\n"
  },
  {
    "path": "code/EVA/server/script/Framework/MiddleClass.lua",
    "content": "-- Example\n-- local class = require 'middleclass'\n-- local Fruit = class('Fruit') -- 'Fruit' is the class' name\n\n-- function Fruit:initialize(sweetness)\n--   self.sweetness = sweetness\n-- end\n\n-- Fruit.static.sweetness_threshold = 5 -- class variable (also admits methods)\n\n-- function Fruit:isSweet()\n--   return self.sweetness > Fruit.sweetness_threshold\n-- end\n\n-- local Lemon = class('Lemon', Fruit) -- subclassing\n\n-- function Lemon:initialize()\n--   Fruit.initialize(self, 1) -- invoking the superclass' initializer\n-- end\n\n-- local lemon = Lemon:new()   or Lemon()\n-- nlinfo(lemon:isSweet()) -- false\n-- \nlocal middleclass = {}\n\nlocal function _createIndexWrapper(aClass, f)\n    if f == nil then\n        return aClass.__instanceDict\n    else\n        return function(self, name)\n            local value = aClass.__instanceDict[name]\n            \n            if value ~= nil then\n                return value\n            elseif type(f) == \"function\" then\n                return (f(self, name))\n            else\n                return f[name]\n            end\n        end\n    end\nend\n\nlocal function _propagateInstanceMethod(aClass, name, f)\n    f = name == \"__index\" and _createIndexWrapper(aClass, f) or f\n    aClass.__instanceDict[name] = f\n    \n    for subclass in pairs(aClass.subclasses) do\n        if rawget(subclass.__declaredMethods, name) == nil then\n            _propagateInstanceMethod(subclass, name, f)\n        end\n    end\nend\n\nlocal function _declareInstanceMethod(aClass, name, f)\n    aClass.__declaredMethods[name] = f\n    \n    if f == nil and aClass.super then\n        f = aClass.super.__instanceDict[name]\n    end\n    \n    _propagateInstanceMethod(aClass, name, f)\nend\n\nlocal function _tostring(self) return \"class \" .. self.name end\nlocal function _call(self, ...) return self:new(...) end\n\nlocal function _createClass(name, super)\n    local dict = {}\n    dict.__index = dict\n    \n    local aClass = {name = name, super = super, static = {},\n        __instanceDict = dict, __declaredMethods = {},\n        subclasses = setmetatable({}, {__mode = 'k'})}\n    \n    if super then\n        setmetatable(aClass.static, {__index = function(_, k) return rawget(dict, k) or super.static[k] end})\n    else\n        setmetatable(aClass.static, {__index = function(_, k) return rawget(dict, k) end})\n    end\n    \n    setmetatable(aClass, {__index = aClass.static, __tostring = _tostring,\n        __call = _call, __newindex = _declareInstanceMethod})\n    \n    return aClass\nend\n\nlocal function _includeMixin(aClass, mixin)\n    assert(type(mixin) == 'table', \"mixin must be a table\")\n    \n    for name, method in pairs(mixin) do\n        if name ~= \"included\" and name ~= \"static\" then aClass[name] = method end\n    end\n    \n    for name, method in pairs(mixin.static or {}) do\n        aClass.static[name] = method\n    end\n    \n    if type(mixin.included) == \"function\" then mixin:included(aClass) end\n    return aClass\nend\n\nlocal DefaultMixin = {\n    __tostring = function(self) return \"instance of \" .. tostring(self.class) end,\n    \n    initialize = function(self, ...) end,\n    \n    isInstanceOf = function(self, aClass)\n        return type(aClass) == 'table' and (aClass == self.class or self.class:isSubclassOf(aClass))\n    end,\n    \n    static = {\n        allocate = function(self)\n            assert(type(self) == 'table', \"Make sure that you are using 'Class:allocate' instead of 'Class.allocate'\")\n            return setmetatable({class = self}, self.__instanceDict)\n        end,\n        \n        new = function(self, ...)\n            assert(type(self) == 'table', \"Make sure that you are using 'Class:new' instead of 'Class.new'\")\n            local instance = self:allocate()\n            instance:initialize(...)\n            return instance\n        end,\n        \n        subclass = function(self, name)\n            assert(type(self) == 'table', \"Make sure that you are using 'Class:subclass' instead of 'Class.subclass'\")\n            assert(type(name) == \"string\", \"You must provide a name(string) for your class\")\n            \n            local subclass = _createClass(name, self)\n            \n            for methodName, f in pairs(self.__instanceDict) do\n                _propagateInstanceMethod(subclass, methodName, f)\n            end\n            subclass.initialize = function(instance, ...) return self.initialize(instance, ...) end\n            \n            self.subclasses[subclass] = true\n            self:subclassed(subclass)\n            \n            return subclass\n        end,\n        \n        subclassed = function(self, other) end,\n        \n        isSubclassOf = function(self, other)\n            return type(other) == 'table' and\n                type(self.super) == 'table' and\n                (self.super == other or self.super:isSubclassOf(other))\n        end,\n        \n        include = function(self, ...)\n            assert(type(self) == 'table', \"Make sure you that you are using 'Class:include' instead of 'Class.include'\")\n            for _, mixin in ipairs({...}) do _includeMixin(self, mixin) end\n            return self\n        end\n    }\n}\n\nfunction middleclass.class(name, super)\n    assert(type(name) == 'string', \"A name (string) is needed for the new class\")\n    return super and super:subclass(name) or _includeMixin(_createClass(name), DefaultMixin)\nend\n\nsetmetatable(middleclass, {__call = function(_, ...) return middleclass.class(...) end})\n\nreturn middleclass\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Net/BaseService.lua",
    "content": "BaseService = {}\n\nfunction BaseService:Send( service_id, cmsg_or_type, proto_type, proto_msg )\n\n    local param_type = type(cmsg_or_type)\n    \n    if param_type==\"string\" then\n               \n        local lua_msg   = CMessage(cmsg_or_type);\n        \n        if type(proto_type)==\"table\" then           --  send table => json str\n            local json_str = Table2Json(proto_type);\n            lua_msg:wstring(json_str);\n        elseif type(proto_type)==\"string\" then      --  send proto msg\n            local proto_code      = protobuf.encode(proto_type, proto_msg);\n            lua_msg:wbuffer(proto_code, #proto_code);\n        end\n        Net.Send( service_id, lua_msg );\n        \n    elseif param_type==\"userdata\" then              --  send cmessage\n        Net.Send( service_id, cmsg_or_type );\n    end\n    \nend\n\nfunction BaseService:Broadcast( service_name, msg_out )\n    Net.Broadcast( service_name, msg_out );\nend\n\nfunction BaseService:SendToClient( player, cmsg_or_type, proto_type, proto_msg )\n\n\tif player==nil then\n\t\treturn\n\tend\n\t\n    if player.ConFES==nil then\n\t\treturn\n\tend\n\n\tlocal send_info = { player.ConFES, player.UID };\n    local param_type = type(cmsg_or_type)\n    \n    if param_type==\"string\" then\n               \n        local lua_msg   = CMessage(cmsg_or_type);\n        \n        if type(proto_type)==\"table\" then           --  send table => json str\n            local json_str = Table2Json(proto_type);\n            lua_msg:wstring(json_str);\n            nlwarning(json_str);\n        elseif type(proto_type)==\"string\" then      --  send proto msg\n            local proto_code      = protobuf.encode(proto_type, proto_msg);\n            lua_msg:wbuffer(proto_code, #proto_code);\n--            nlinfo(\"Msg:\"..cmsg_or_type..\" Buffer Len : \"..#proto_code);\n        end\n\n        Net.SendToClient( lua_msg, send_info );\n    elseif param_type==\"userdata\" then              --  send cmessage\n        Net.SendToClient( cmsg_or_type, send_info );\n    end\n\nend\n\n\nreturn BaseService\n\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Net/CallbackServer.lua",
    "content": "local CallbackServer = class(\"CallbackServer\")\n\nfunction CallbackServer:ctor()\n\tself.Service = nil;\n\tself.ConnectCallbackEvent = \"\";\n\tself.DisConnectCallbackEvent = \"\";\nend\n\nfunction CallbackServer:Init( name, protocal )\n\tself.ConnectCallbackEvent     = name .. \"Con\";\n\tself.DisConnectCallbackEvent  = name .. \"Dis\";\n\t\n    local listen_proc = string.lower(protocal);\n    self.Service = bin_types.LuaCallbackServer.NewInstance( name, listen_proc );\nend\n\nfunction CallbackServer:Listen( port )\n    self.Service:Listen(port);\nend\n\nfunction CallbackServer:LoadSslCA( ssl_ca )\n    self.Service:LoadSslCA(ssl_ca);\nend\nfunction CallbackServer:LoadSslCrt( ssl_crt )\n    self.Service:LoadSslCrt(ssl_crt);\nend\nfunction CallbackServer:LoadSslPrivateKey( ssl_prvkey )\n    self.Service:LoadSslPrivateKey(ssl_prvkey);\nend\n\nfunction CallbackServer:SetClientData( client_data )\n\tself.Service:SetClientData( client_data );\nend\n\nfunction CallbackServer:RemoveClientData( uid )\n\tself.Service:RemoveClientData(uid);\nend\n\nfunction CallbackServer:DisConnect( sock_id )\n\tself.Service:DisConnect(sock_id);\nend\n\nfunction CallbackServer:Send( sock_id, msg_or_type, proto_type, proto_msg )\n    local param_type = type(msg_or_type)\n    \n    if param_type==\"string\" then\n        local lua_msg   = CMessage(msg_or_type);\n        if proto_type~=nil then\n            local proto_code    = protobuf.encode(proto_type, proto_msg);\n            lua_msg:wbuffer(proto_code, #proto_code);\n        end\n        self.Service:Send( sock_id, lua_msg );\n    else\n        self.Service:Send( sock_id, msg_or_type );\n    end\nend\n\nreturn CallbackServer\n\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Net/NetWorkHandler.lua",
    "content": "NetWorkHandler = {};\nlocal this = NetWorkHandler;\n\n-- 收到连接，断开事件\nfunction NetWorkHandler.OnNetEvent( event_from, event_type, event_val )\t\n\tEventController.Instance():TriggerEvent( event_type, event_from, event_val );\nend\n\n-- 收到网络消息\nfunction NetWorkHandler.OnMessage( msg_from, lua_msg )\n    \n    --if lua_msg:name()~=\"SvrInfo\" then\n    --    nlinfo(\"recv msg:\"..lua_msg:name());\n    --end\n    \n    EventController.Instance():TriggerEvent( lua_msg:name(), msg_from, lua_msg );\nend\n\nfunction NetWorkHandler.OnError(state)\n\nend\n\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Net/protobuf.lua",
    "content": "local c = require \"protobuf.c\"\n\nlocal setmetatable = setmetatable\nlocal type = type\nlocal table = table\nlocal assert = assert\nlocal pairs = pairs\nlocal ipairs = ipairs\nlocal string = string\nlocal print = print\nlocal io = io\nlocal tinsert = table.insert\nlocal rawget = rawget\nlocal rawset = rawset\n\nlocal M = {}\n\nlocal _pattern_cache = {}\n\nlocal P,GC\n\nP = debug.getregistry().PROTOBUF_ENV\n\nif P then\n\tGC = c._gc()\nelse\n\tP= c._env_new()\n\tGC = c._gc(P)\nend\n\nM.GC = GC\n\nfunction M.lasterror()\n\treturn c._last_error(P)\nend\n\nlocal decode_type_cache = {}\nlocal _R_meta = {}\n\nfunction _R_meta:__index(key)\n\tlocal v = decode_type_cache[self._CType][key](self, key)\n\tself[key] = v\n\treturn v\nend\n\nlocal _reader = {}\n\nfunction _reader:real(key)\n\treturn c._rmessage_real(self._CObj , key , 0)\nend\n\nfunction _reader:string(key)\n\treturn c._rmessage_string(self._CObj , key , 0)\nend\n\nfunction _reader:bool(key)\n\treturn c._rmessage_int(self._CObj , key , 0) ~= 0\nend\n\nfunction _reader:message(key, message_type)\n\tlocal rmessage = c._rmessage_message(self._CObj , key , 0)\n\tif rmessage then\n\t\tlocal v = {\n\t\t\t_CObj = rmessage,\n\t\t\t_CType = message_type,\n\t\t\t_Parent = self,\n\t\t}\n\t\treturn setmetatable( v , _R_meta )\n\tend\nend\n\nfunction _reader:int(key)\n\treturn c._rmessage_int(self._CObj , key , 0)\nend\n\nfunction _reader:real_repeated(key)\n\tlocal cobj = self._CObj\n\tlocal n = c._rmessage_size(cobj , key)\n\tlocal ret = {}\n\tfor i=0,n-1 do\n\t\ttinsert(ret,  c._rmessage_real(cobj , key , i))\n\tend\n\treturn ret\nend\n\nfunction _reader:string_repeated(key)\n\tlocal cobj = self._CObj\n\tlocal n = c._rmessage_size(cobj , key)\n\tlocal ret = {}\n\tfor i=0,n-1 do\n\t\ttinsert(ret,  c._rmessage_string(cobj , key , i))\n\tend\n\treturn ret\nend\n\nfunction _reader:bool_repeated(key)\n\tlocal cobj = self._CObj\n\tlocal n = c._rmessage_size(cobj , key)\n\tlocal ret = {}\n\tfor i=0,n-1 do\n\t\ttinsert(ret,  c._rmessage_int(cobj , key , i) ~= 0)\n\tend\n\treturn ret\nend\n\nfunction _reader:message_repeated(key, message_type)\n\tlocal cobj = self._CObj\n\tlocal n = c._rmessage_size(cobj , key)\n\tlocal ret = {}\n\tfor i=0,n-1 do\n\t\tlocal m = {\n\t\t\t_CObj = c._rmessage_message(cobj , key , i),\n\t\t\t_CType = message_type,\n\t\t\t_Parent = self,\n\t\t}\n\t\ttinsert(ret, setmetatable( m , _R_meta ))\n\tend\n\treturn ret\nend\n\nfunction _reader:int_repeated(key)\n\tlocal cobj = self._CObj\n\tlocal n = c._rmessage_size(cobj , key)\n\tlocal ret = {}\n\tfor i=0,n-1 do\n\t\ttinsert(ret,  c._rmessage_int(cobj , key , i))\n\tend\n\treturn ret\nend\n\n--[[\n#define PBC_INT 1\n#define PBC_REAL 2\n#define PBC_BOOL 3\n#define PBC_ENUM 4\n#define PBC_STRING 5\n#define PBC_MESSAGE 6\n#define PBC_FIXED64 7\n#define PBC_FIXED32 8\n#define PBC_BYTES 9\n#define PBC_INT64 10\n#define PBC_UINT 11\n#define PBC_UNKNOWN 12\n#define PBC_REPEATED 128\n]]\n\n_reader[1] = function(msg) return _reader.int end\n_reader[2] = function(msg) return _reader.real end\n_reader[3] = function(msg) return _reader.bool end\n_reader[4] = function(msg) return _reader.string end\n_reader[5] = function(msg) return _reader.string end\n_reader[6] = function(msg)\n\tlocal message = _reader.message\n\treturn\tfunction(self,key)\n\t\t\treturn message(self, key, msg)\n\t\tend\nend\n_reader[7] = _reader[1]\n_reader[8] = _reader[1]\n_reader[9] = _reader[5]\n_reader[10] = _reader[7]\n_reader[11] = _reader[7]\n\n_reader[128+1] = function(msg) return _reader.int_repeated end\n_reader[128+2] = function(msg) return _reader.real_repeated end\n_reader[128+3] = function(msg) return _reader.bool_repeated end\n_reader[128+4] = function(msg) return _reader.string_repeated end\n_reader[128+5] = function(msg) return _reader.string_repeated end\n_reader[128+6] = function(msg)\n\tlocal message = _reader.message_repeated\n\treturn\tfunction(self,key)\n\t\t\treturn message(self, key, msg)\n\t\tend\nend\n_reader[128+7] = _reader[128+1]\n_reader[128+8] = _reader[128+1]\n_reader[128+9] = _reader[128+5]\n_reader[128+10] = _reader[128+7]\n_reader[128+11] = _reader[128+7]\n\nlocal _decode_type_meta = {}\n\nfunction _decode_type_meta:__index(key)\n\tlocal t, msg = c._env_type(P, self._CType, key)\n\tlocal func = assert(_reader[t],key)(msg)\n\tself[key] = func\n\treturn func\nend\n\nsetmetatable(decode_type_cache , {\n\t__index = function(self, key)\n\t\tlocal v = setmetatable({ _CType = key } , _decode_type_meta)\n\t\tself[key] = v\n\t\treturn v\n\tend\n})\n\nlocal function decode_message( message , buffer, length)\n\tlocal rmessage = c._rmessage_new(P, message, buffer, length)\n\tif rmessage then\n\t\tlocal self = {\n\t\t\t_CObj = rmessage,\n\t\t\t_CType = message,\n\t\t}\n\t\tc._add_rmessage(GC,rmessage)\n\t\treturn setmetatable( self , _R_meta )\n\tend\nend\n\n----------- encode ----------------\n\nlocal encode_type_cache = {}\n\nlocal function encode_message(CObj, message_type, t)\n\tlocal type = encode_type_cache[message_type]\n\tfor k,v in pairs(t) do\n\t\tlocal func = type[k]\n\t\tfunc(CObj, k , v)\n\tend\nend\n\nlocal _writer = {\n\treal = c._wmessage_real,\n\tenum = c._wmessage_string,\n\tstring = c._wmessage_string,\n\tint = c._wmessage_int,\n}\n\nfunction _writer:bool(k,v)\n\tc._wmessage_int(self, k, v and 1 or 0)\nend\n\nfunction _writer:message(k, v , message_type)\n\tlocal submessage = c._wmessage_message(self, k)\n\tencode_message(submessage, message_type, v)\nend\n\nfunction _writer:real_repeated(k,v)\n\tfor _,v in ipairs(v) do\n\t\tc._wmessage_real(self,k,v)\n\tend\nend\n\nfunction _writer:bool_repeated(k,v)\n\tfor _,v in ipairs(v) do\n\t\tc._wmessage_int(self, k, v and 1 or 0)\n\tend\nend\n\nfunction _writer:string_repeated(k,v)\n\tfor _,v in ipairs(v) do\n\t\tc._wmessage_string(self,k,v)\n\tend\nend\n\nfunction _writer:message_repeated(k,v, message_type)\n\tfor _,v in ipairs(v) do\n\t\tlocal submessage = c._wmessage_message(self, k)\n\t\tencode_message(submessage, message_type, v)\n\tend\nend\n\nfunction _writer:int_repeated(k,v)\n\tfor _,v in ipairs(v) do\n\t\tc._wmessage_int(self,k,v)\n\tend\nend\n\n_writer[1] = function(msg) return _writer.int end\n_writer[2] = function(msg) return _writer.real end\n_writer[3] = function(msg) return _writer.bool end\n_writer[4] = function(msg) return _writer.string end\n_writer[5] = function(msg) return _writer.string end\n_writer[6] = function(msg)\n\tlocal message = _writer.message\n\treturn\tfunction(self,key , v)\n\t\t\treturn message(self, key, v, msg)\n\t\tend\nend\n_writer[7] = _writer[1]\n_writer[8] = _writer[1]\n_writer[9] = _writer[5]\n_writer[10] = _writer[7]\n_writer[11] = _writer[7]\n\n_writer[128+1] = function(msg) return _writer.int_repeated end\n_writer[128+2] = function(msg) return _writer.real_repeated end\n_writer[128+3] = function(msg) return _writer.bool_repeated end\n_writer[128+4] = function(msg) return _writer.string_repeated end\n_writer[128+5] = function(msg) return _writer.string_repeated end\n_writer[128+6] = function(msg)\n\tlocal message = _writer.message_repeated\n\treturn\tfunction(self,key, v)\n\t\t\treturn message(self, key, v, msg)\n\t\tend\nend\n\n_writer[128+7] = _writer[128+1]\n_writer[128+8] = _writer[128+1]\n_writer[128+9] = _writer[128+5]\n_writer[128+10] = _writer[128+7]\n_writer[128+11] = _writer[128+7]\n\nlocal _encode_type_meta = {}\n\nfunction _encode_type_meta:__index(key)\n\tlocal t, msg = c._env_type(P, self._CType, key)\n\tlocal func = assert(_writer[t],key)(msg)\n\tself[key] = func\n\treturn func\nend\n\nsetmetatable(encode_type_cache , {\n\t__index = function(self, key)\n\t\tlocal v = setmetatable({ _CType = key } , _encode_type_meta)\n\t\tself[key] = v\n\t\treturn v\n\tend\n})\n\nfunction M.encode( message, t , func , ...)\n\tlocal encoder = c._wmessage_new(P, message)\n\tassert(encoder ,  message)\n\tencode_message(encoder, message, t)\n\tif func then\n\t\tlocal buffer, len = c._wmessage_buffer(encoder)\n\t\tlocal ret = func(buffer, len, ...)\n\t\tc._wmessage_delete(encoder)\n\t\treturn ret\n\telse\n\t\tlocal s = c._wmessage_buffer_string(encoder)\n\t\tc._wmessage_delete(encoder)\n\t\treturn s\n\tend\nend\n\n--------- unpack ----------\n\nlocal _pattern_type = {\n\t[1] = {\"%d\",\"i\"},\n\t[2] = {\"%F\",\"r\"},\n\t[3] = {\"%d\",\"b\"},\n\t[5] = {\"%s\",\"s\"},\n\t[6] = {\"%s\",\"m\"},\n\t[7] = {\"%D\",\"d\"},\n\t[128+1] = {\"%a\",\"I\"},\n\t[128+2] = {\"%a\",\"R\"},\n\t[128+3] = {\"%a\",\"B\"},\n\t[128+5] = {\"%a\",\"S\"},\n\t[128+6] = {\"%a\",\"M\"},\n\t[128+7] = {\"%a\",\"D\"},\n}\n\n_pattern_type[4] = _pattern_type[1]\n_pattern_type[8] = _pattern_type[1]\n_pattern_type[9] = _pattern_type[5]\n_pattern_type[10] = _pattern_type[7]\n_pattern_type[11] = _pattern_type[7]\n_pattern_type[128+4] = _pattern_type[128+1]\n_pattern_type[128+8] = _pattern_type[128+1]\n_pattern_type[128+9] = _pattern_type[128+5]\n_pattern_type[128+10] = _pattern_type[128+7]\n_pattern_type[128+11] = _pattern_type[128+7]\n\n\nlocal function _pattern_create(pattern)\n\tlocal iter = string.gmatch(pattern,\"[^ ]+\")\n\tlocal message = iter()\n\tlocal cpat = {}\n\tlocal lua = {}\n\tfor v in iter do\n\t\tlocal tidx = c._env_type(P, message, v)\n\t\tlocal t = _pattern_type[tidx]\n\t\tassert(t,tidx)\n\t\ttinsert(cpat,v .. \" \" .. t[1])\n\t\ttinsert(lua,t[2])\n\tend\n\tlocal cobj = c._pattern_new(P, message , \"@\" .. table.concat(cpat,\" \"))\n\tif cobj == nil then\n\t\treturn\n\tend\n\tc._add_pattern(GC, cobj)\n\tlocal pat = {\n\t\tCObj = cobj,\n\t\tformat = table.concat(lua),\n\t\tsize = 0\n\t}\n\tpat.size = c._pattern_size(pat.format)\n\n\treturn pat\nend\n\nsetmetatable(_pattern_cache, {\n\t__index = function(t, key)\n\t\tlocal v = _pattern_create(key)\n\t\tt[key] = v\n\t\treturn v\n\tend\n})\n\nfunction M.unpack(pattern, buffer, length)\n\tlocal pat = _pattern_cache[pattern]\n\treturn c._pattern_unpack(pat.CObj , pat.format, pat.size, buffer, length)\nend\n\nfunction M.pack(pattern, ...)\n\tlocal pat = _pattern_cache[pattern]\n\treturn c._pattern_pack(pat.CObj, pat.format, pat.size , ...)\nend\n\nfunction M.check(typename , field)\n\tif field == nil then\n\t\treturn c._env_type(P,typename)\n\telse\n\t\treturn c._env_type(P,typename,field) ~=0\n\tend\nend\n\n--------------\n\nlocal default_cache = {}\n\n-- todo : clear default_cache, v._CObj\n\nlocal function default_table(typename)\n\tlocal v = default_cache[typename]\n\tif v then\n\t\treturn v\n\tend\n\n\tlocal default_inst = assert(decode_message(typename , \"\"))\n\tv = { \n\t\t__index = function(tb, key)\n\t\t\tlocal ret = default_inst[key]\n\t\t\tif 'table' ~= type(ret) then\n\t\t\t\treturn ret\n\t\t\tend \n\t\t\tret = setmetatable({}, { __index = ret })\n\t\t\trawset(tb, key, ret)\n\t\t\treturn ret\n\t\tend\n\t}\n\n\tdefault_cache[typename]  = v\n\treturn v\nend\n\nlocal decode_message_mt = {}\n\nlocal function decode_message_cb(typename, buffer)\n\treturn setmetatable ( { typename, buffer } , decode_message_mt)\nend\n\nfunction M.decode(typename, buffer, length)\n\tlocal ret = {}\n\tlocal ok = c._decode(P, decode_message_cb , ret , typename, buffer, length)\n\tif ok then\n\t\treturn setmetatable(ret , default_table(typename))\n\telse\n\t\treturn false , c._last_error(P)\n\tend\nend\n\nlocal function expand(tbl)\n\tlocal typename = rawget(tbl , 1)\n\tlocal buffer = rawget(tbl , 2)\n\ttbl[1] , tbl[2] = nil , nil\n\tassert(c._decode(P, decode_message_cb , tbl , typename, buffer), typename)\n\tsetmetatable(tbl , default_table(typename))\nend\n\nfunction decode_message_mt.__index(tbl, key)\n\texpand(tbl)\n\treturn tbl[key]\nend\n\nfunction decode_message_mt.__pairs(tbl)\n\texpand(tbl)\n\treturn pairs(tbl)\nend\n\nlocal function set_default(typename, tbl)\n\tfor k,v in pairs(tbl) do\n\t\tif type(v) == \"table\" then\n\t\t\tlocal t, msg = c._env_type(P, typename, k)\n\t\t\tif t == 6 then\n\t\t\t\tset_default(msg, v)\n\t\t\telseif t == 128+6 then\n\t\t\t\tfor _,v in ipairs(v) do\n\t\t\t\t\tset_default(msg, v)\n\t\t\t\tend\n\t\t\tend\n\t\tend\n\tend\n\treturn setmetatable(tbl , default_table(typename))\nend\n\nfunction M.register(buffer)\n\tc._env_register(P, buffer)\nend\n\nfunction M.register_file(filename)\n\tlocal f = assert(io.open(filename , \"rb\"))\n\tlocal buffer = f:read \"*a\"\n\tc._env_register(P, buffer)\n\tf:close()\nend\n\nfunction M.enum_id(enum_type, enum_name)\n\treturn c._env_enum_id(P, enum_type, enum_name)\nend\n\nfunction M.extract(tbl)\n    local typename = rawget(tbl , 1)\n    local buffer = rawget(tbl , 2)\n    if type(typename) == \"string\" and type(buffer) == \"string\" then\n        if M.check(typename) then\n            expand(tbl)\n        end\n    end\n\n    for k, v in pairs(tbl) do\n        if type(v) == \"table\" then\n            M.extract(v)\n        end\n    end\nend\n\nM.default=set_default\n\nreturn M\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Queue.lua",
    "content": "\nQueue = class(\"Queue\")\n\n-- 构造函数\nfunction Queue:ctor()\n\t-- body\n\t-- 元素列表\n\tself._list = {};\nend\n\n-- 添加一个元素\nfunction Queue:Push(value)\n\t-- body\n\tif value ~= nil then\n\t\t--todo\n        local nPos = #self._list + 1;\n\t\ttable.insert(self._list, nPos, value);\n\tend\nend\n\n-- 弹出一个函数\nfunction Queue:Pop()\n\t-- body\n\tif self:Count() <= 0 then\n\t\t--todo\n\t\treturn nil;\n\tend\n\n\tlocal nValue = self._list[1];\n\ttable.remove(self._list, 1);\n\n\treturn nValue;\nend\n\n-- 删除对象\nfunction Queue:Remove(value)\n\t-- body\n\tfor i=1,self:Count() do\n\t\tlocal nValue = self._list[i];\n\t\tif v == value then\n\t\t\t--todo\n\t\t\ttable.remove(self._list, i);\n\t\t\ti = i - 1;\n\t\tend\n\tend\nend\n\n-- 数量\nfunction Queue:Count()\n\t-- body\n\treturn #self._list;\nend\n\n-- 清除\nfunction Queue:Clear()\n\t-- body\n\tself._list={};\nend\n\nreturn Queue;"
  },
  {
    "path": "code/EVA/server/script/Framework/SimpleStateMachine.lua",
    "content": "-- region *.lua\n-- Date\n-- 此文件由[BabeLua]插件自动生成\n--local class = require(\"MiddleClass\")\n\nlocal simple_state_machine = class(\"SimpleStateMachine\")\n\nsimple_state_machine.VERSION = \"2.2.0\"\n-- the event transitioned successfully from one state to another\nsimple_state_machine.SUCCEEDED = 1\n-- the event was successfull but no state transition was necessary\nsimple_state_machine.NOTRANSITION = 2\n-- the event was cancelled by the caller in a beforeEvent callback\nsimple_state_machine.CANCELLED = 3\n-- the event is asynchronous and the caller is in control of when the transition occurs\nsimple_state_machine.PENDING = 4\n-- the event was failure\nsimple_state_machine.FAILURE = 5\n-- caller tried to fire an event that was innapropriate in the current state\nsimple_state_machine.INVALID_TRANSITION_ERROR = \"INVALID_TRANSITION_ERROR\"\n-- caller tried to fire an event while an async transition was still pending\nsimple_state_machine.PENDING_TRANSITION_ERROR = \"PENDING_TRANSITION_ERROR\"\n-- caller provided callback function threw an exception\nsimple_state_machine.INVALID_CALLBACK_ERROR = \"INVALID_CALLBACK_ERROR\"\n\nsimple_state_machine.WILDCARD = \"*\"\nsimple_state_machine.ASYNC = \"ASYNC\"\n\nfunction simple_state_machine:initialize()\nend\n\nfunction simple_state_machine:setup_state(cfg)\n    assert(type(cfg) == \"table\", \"simple_state_machine:setup_state() - invalid config\")\n    \n    -- cfg.initial allow for a simple string,\n    -- or an table with { state = \"foo\", event = \"setup\", defer = true|false }\n    if type(cfg.initial) == \"string\" then\n        self._initial = {state = cfg.initial}\n    else\n        self._initial = cfg.initial\n    end\n    \n    self._terminal = cfg.terminal or cfg.final\n    self._events = cfg.events or {}\n    self._callbacks = cfg.callbacks or {}\n    self._map = {}\n    self._current = \"none\"\n    self._in_transition = false\n    \n    if self._initial then\n        self._initial.event = self._initial.event or \"startup\"\n        self:_add_event({name = self._initial.event, from = \"none\", to = self._initial.state})\n    end\n    \n    for _, event in ipairs(self._events) do\n        self:_add_event(event)\n    end\n    \n    if self._initial and not self._initial.defer then\n        self:do_event(self._initial.event)\n    end\n    \n    return self._target\nend\n\nfunction simple_state_machine:is_ready()\n    return self._current ~= \"none\"\nend\n\nfunction simple_state_machine:get_state()\n    return self._current\nend\n\nfunction simple_state_machine:is_state(state)\n    if type(state) == \"table\" then\n        for _, s in ipairs(state) do\n            if s == self._current then\n                return true\n            end\n        end\n        return false\n    else\n        return self._current == state\n    end\nend\n\nfunction simple_state_machine:can_do_event(event_name)\n    return not self._in_transition and\n        (self._map[event_name][self._current] ~= nil or self._map[event_name][simple_state_machine.WILDCARD] ~= nil)\nend\n\nfunction simple_state_machine:cannot_do_event(event_name)\n    return not self:can_do_event(event_name)\nend\n\nfunction simple_state_machine:is_finished_state()\n    return self:is_state(self._terminal)\nend\n\nfunction simple_state_machine:do_event_force(name, ...)\n    local from = self._current\n    local map = self._map[name]\n    local to = (map[from] or map[simple_state_machine.WILDCARD]) or from\n    local args = {...}\n    \n    local event = {\n        name = name,\n        from = from,\n        to = to,\n        args = args\n    }\n    \n    if self._in_transition then\n        self._in_transition = false\n    end\n    \n    self:_before_event(event)\n    \n    if from == to then\n        self:_after_event(event)\n        return simple_state_machine.NOTRANSITION\n    end\n    \n    self._current = to\n    self:_enter_state(event)\n    self:_change_state(event)\n    self:_after_event(event)\n    return simple_state_machine.SUCCEEDED\nend\n\nfunction simple_state_machine:do_event(name, ...)\n    assert(self._map[name] ~= nil, string.format(\"simple_state_machine:DoEvent() - invalid event %s\", tostring(name)))\n    \n    local from = self._current\n    local map = self._map[name]\n    local to = (map[from] or map[simple_state_machine.WILDCARD]) or from\n    local args = {...}\n    \n    local event = {\n        name = name,\n        from = from,\n        to = to,\n        args = args,\n    }\n    \n    if self._in_transition then\n        self:_on_error(event, simple_state_machine.PENDING_TRANSITION_ERROR,\n            \"event \" .. name .. \" inappropriate because previous transition did not complete\")\n        return simple_state_machine.FAILURE\n    end\n    \n    if self:cannot_do_event(name) then\n        self:_on_error(event, simple_state_machine.INVALID_TRANSITION_ERROR,\n            \"event \" .. name .. \" inappropriate in current state \" .. self._current)\n        return simple_state_machine.FAILURE\n    end\n    \n    if self:_before_event(event) == false then\n        return simple_state_machine.CANCELLED\n    end\n    \n    if from == to then\n        self:_after_event(event)\n        return simple_state_machine.NOTRANSITION\n    end\n    \n    event.transition = function()\n        self._in_transition = false\n        self._current = to\n        -- this method should only ever be called once\n        self:_enter_state(event)\n        self:_change_state(event)\n        self:_after_event(event)\n        return simple_state_machine.SUCCEEDED\n    end\n    \n    event.cancel = function()\n            -- provide a way for caller to cancel async transition if desired\n            event.transition = nil\n            self:_after_event(event)\n    end\n    \n    self._in_transition = true\n    local leave = self:_leave_state(event)\n    if leave == false then\n        event.transition = nil\n        event.cancel = nil\n        self._in_transition = false\n        return simple_state_machine.CANCELLED\n    elseif string.upper(tostring(leave)) == simple_state_machine.ASYNC then\n        return simple_state_machine.PENDING\n    else\n        -- need to check in case user manually called transition()\n        -- but forgot to return StateMachine.ASYNC\n        if event.transition then\n            return event.transition()\n        else\n            self._in_transition = false\n        end\n    end\nend\n\nfunction simple_state_machine:_add_event(event)\n    local from = {}\n    if type(event.from) == \"table\" then\n        for _, name in ipairs(event.from) do\n            from[name] = true\n        end\n    elseif event.from then\n        from[event.from] = true\n    else\n        -- allow \"wildcard\" transition if \"from\" is not specified\n        from[simple_state_machine.WILDCARD] = true\n    end\n    \n    self._map[event.name] = self._map[event.name] or {}\n    local map = self._map[event.name]\n    for fromName, _ in pairs(from) do\n        map[fromName] = event.to or fromName\n    end\nend\n\nlocal function _do_callback(callback, event)\n    if callback then\n        return callback(event)\n    end\nend\n\nfunction simple_state_machine:_before_any_event(event)\n    return _do_callback(self._callbacks[\"onbeforeevent\"], event)\nend\n\nfunction simple_state_machine:_after_any_event(event)\n    return _do_callback(self._callbacks[\"onafterevent\"], event)\nend\n\nfunction simple_state_machine:_leave_any_state(event)\n    return _do_callback(self._callbacks[\"onleavestate\"], event)\nend\n\nfunction simple_state_machine:_enter_any_state(event)\n    return _do_callback(self._callbacks[\"onenterstate\"] or self._callbacks[\"onstate\"], event)\nend\n\nfunction simple_state_machine:_change_state(event)\n    return _do_callback(self._callbacks[\"onchangestate\"], event)\nend\n\nfunction simple_state_machine:_before_this_event(event)\n    return _do_callback(self._callbacks[\"onbefore\" .. event.name], event)\nend\n\nfunction simple_state_machine:_after_this_event(event)\n    return _do_callback(self._callbacks[\"onafter\" .. event.name] or self._callbacks[\"on\" .. event.name], event)\nend\n\nfunction simple_state_machine:_leave_this_state(event)\n    return _do_callback(self._callbacks[\"onleave\" .. event.from], event)\nend\n\nfunction simple_state_machine:_enter_this_state(event)\n    return _do_callback(self._callbacks[\"onenter\" .. event.to] or self._callbacks[\"on\" .. event.to], event)\nend\n\nfunction simple_state_machine:_before_event(event)\n    if self:_before_this_event(event) == false or self:_before_any_event(event) == false then\n        return false\n    end\nend\n\nfunction simple_state_machine:_after_event(event)\n    self:_after_this_event(event)\n    self:_after_any_event(event)\nend\n\nfunction simple_state_machine:_leave_state(event, transition)\n    local specific = self:_leave_this_state(event, transition)\n    local general = self:_leave_any_state(event, transition)\n    if specific == false or general == false then\n        return false\n    elseif string.upper(tostring(specific)) == simple_state_machine.ASYNC\n        or string.upper(tostring(general)) == simple_state_machine.ASYNC then\n        return simple_state_machine.ASYNC\n    end\nend\n\nfunction simple_state_machine:_enter_state(event)\n    self:_enter_this_state(event)\n    self:_enter_any_state(event)\nend\n\nfunction simple_state_machine:_on_error(event, error, message)\n    nlinfo(\"%s [simple_state_machine] ERROR: error %s, event %s, from %s to %s\", tostring(self._target), tostring(error), event.name, event.from, event.to)\n    nlinfo(message)\nend\n\nreturn simple_state_machine"
  },
  {
    "path": "code/EVA/server/script/Framework/Stack.lua",
    "content": "stack = { }\n\nfunction stack:create()\n    local t = { }\n    t._et = { }\n\n    function t:push(...)\n        if ... then\n            local targs = { ...}\n            for _, v in ipairs(targs) do\n                table.insert(self._et, v)\n            end\n        end\n    end\n\n    function t:pop(num)\n        local num = num or 1\n        local entries = { }\n        for i = 1, num do\n            if #self._et ~= 0 then\n                table.insert(entries, self._et[#self._et])\n                table.remove(self._et)\n            else\n                break\n            end\n        end\n        return unpack(entries)\n    end\n\n    function t:peek()\n        if #self._et ~= 0 then\n            return self._et[#self._et]\n        end\n        return nil\n    end\n\n    function t:clear()\n        while #self._et ~= 0 do\n            table.remove(self._et)\n        end\n    end\n\n    function t:getn()\n        return #self._et\n    end\n\n    function t:list()\n        for i, v in pairs(self._et) do\n            nlinfo(i, v)\n        end\n    end\n\n    return t\nend"
  },
  {
    "path": "code/EVA/server/script/Framework/StateFul.lua",
    "content": "-- # Example\n-- ``` lua\n-- local class    = require 'middleclass'\n-- local Stateful = require 'stateful'\n-- local Enemy = class('Enemy')\n-- Enemy:include(Stateful)\n-- function Enemy:initialize(health)\n--   self.health = health\n-- end\n-- function Enemy:speak()\n--   return 'My health is' .. tostring(self.health)\n-- end\n-- local Immortal = Enemy:addState('Immortal')\n-- -- overriden function\n-- function Immortal:speak()\n--   return 'I am UNBREAKABLE!!'\n-- end\n-- -- added function\n-- function Immortal:die()\n--   return 'I can not die now!'\n-- end\n-- local peter = Enemy:new(10)\n-- peter:speak() -- My health is 10\n-- peter:gotoState('Immortal')\n-- peter:speak() -- I am UNBREAKABLE!!\n-- peter:die() -- I can not die now!\n-- peter:gotoState(nil)\n-- peter:speak() -- My health is 10\n-- ```\nlocal Stateful = {static = {}}\n\nlocal _callbacks = {\n    enteredState = 1,\n    exitedState = 1,\n    pushedState = 1,\n    poppedState = 1,\n    pausedState = 1,\n    continuedState = 1\n}\n\nlocal _BaseState = {}\n\nlocal function _addStatesToClass(klass, superStates)\n    klass.static.states = {}\n    for stateName, state in pairs(superStates or {}) do\n        klass:addState(stateName, state)\n    end\nend\n\nlocal function _getStatefulMethod(instance, name)\n    if not _callbacks[name] then\n        local stack = rawget(instance, '__stateStack')\n        if not stack then return end\n        for i = #stack, 1, -1 do\n            if stack[i][name] then return stack[i][name] end\n        end\n    end\nend\n\nlocal function _getNewInstanceIndex(prevIndex)\n    if type(prevIndex) == 'function' then\n        return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex(instance, name) end\n    end\n    return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex[name] end\nend\n\nlocal function _getNewAllocateMethod(oldAllocateMethod)\n    return function(klass, ...)\n        local instance = oldAllocateMethod(klass, ...)\n        instance.__stateStack = {}\n        return instance\n    end\nend\n\nlocal function _modifyInstanceIndex(klass)\n    klass.__instanceDict.__index = _getNewInstanceIndex(klass.__instanceDict.__index)\nend\n\nlocal function _getNewSubclassMethod(prevSubclass)\n    return function(klass, name)\n        local subclass = prevSubclass(klass, name)\n        _addStatesToClass(subclass, klass.states)\n        _modifyInstanceIndex(subclass)\n        return subclass\n    end\nend\n\nlocal function _modifySubclassMethod(klass)\n    klass.static.subclass = _getNewSubclassMethod(klass.static.subclass)\nend\n\nlocal function _modifyAllocateMethod(klass)\n    klass.static.allocate = _getNewAllocateMethod(klass.static.allocate)\nend\n\nlocal function _assertType(val, name, expected_type, type_to_s)\n    assert(type(val) == expected_type, \"Expected \" .. name .. \" to be of type \" .. (type_to_s or expected_type) .. \". Was \" .. tostring(val) .. \"(\" .. type(val) .. \")\")\nend\n\nlocal function _assertInexistingState(klass, stateName)\n    assert(klass.states[stateName] == nil, \"State \" .. tostring(stateName) .. \" already exists on \" .. tostring(klass))\nend\n\nlocal function _assertExistingState(self, state, stateName)\n    assert(state, \"The state \" .. stateName .. \" was not found in \" .. tostring(self.class))\nend\n\nlocal function _invokeCallback(self, state, callbackName, ...)\n    if state and state[callbackName] then state[callbackName](self, ...) end\nend\n\nlocal function _getCurrentState(self)\n    return self.__stateStack[#self.__stateStack]\nend\n\nlocal function _getStateFromClassByName(self, stateName)\n    local state = self.class.static.states[stateName]\n    _assertExistingState(self, state, stateName)\n    return state\nend\n\nlocal function _getStateIndexFromStackByName(self, stateName)\n    if stateName == nil then return #self.__stateStack end\n    local target = _getStateFromClassByName(self, stateName)\n    for i = #self.__stateStack, 1, -1 do\n        if self.__stateStack[i] == target then return i end\n    end\nend\n\nlocal function _getStateName(self, target)\n    for name, state in pairs(self.class.static.states) do\n        if state == target then return name end\n    end\nend\n\nfunction Stateful:included(klass)\n    _addStatesToClass(klass)\n    _modifyInstanceIndex(klass)\n    _modifySubclassMethod(klass)\n    _modifyAllocateMethod(klass)\nend\n\nfunction Stateful.static:addState(stateName, superState)\n    superState = superState or _BaseState\n    _assertType(stateName, 'stateName', 'string')\n    _assertInexistingState(self, stateName)\n    self.static.states[stateName] = setmetatable({}, {__index = superState})\n    return self.static.states[stateName]\nend\n\nfunction Stateful:gotoState(stateName, ...)\n    \n    self:popAllStates()\n    \n    if stateName == nil then\n        self.__stateStack = {}\n    else\n        _assertType(stateName, 'stateName', 'string', 'string or nil')\n        \n        local newState = _getStateFromClassByName(self, stateName)\n        self.__stateStack = {newState}\n        _invokeCallback(self, newState, 'enteredState', ...)\n    end\n\nend\n\nfunction Stateful:pushState(stateName)\n    local oldState = _getCurrentState(self)\n    _invokeCallback(self, oldState, 'pausedState')\n    \n    local newState = _getStateFromClassByName(self, stateName)\n    table.insert(self.__stateStack, newState)\n    \n    _invokeCallback(self, newState, 'pushedState')\n    _invokeCallback(self, newState, 'enteredState')\nend\n\nfunction Stateful:popState(stateName)\n    \n    local oldStateIndex = _getStateIndexFromStackByName(self, stateName)\n    local oldState\n    if oldStateIndex then\n        oldState = self.__stateStack[oldStateIndex]\n        \n        _invokeCallback(self, oldState, 'poppedState')\n        _invokeCallback(self, oldState, 'exitedState')\n        \n        table.remove(self.__stateStack, oldStateIndex)\n    end\n    \n    local newState = _getCurrentState(self)\n    \n    if oldState ~= newState then\n        _invokeCallback(self, newState, 'continuedState')\n    end\nend\n\nfunction Stateful:popAllStates()\n    local size = #self.__stateStack\n    for i = 1, size do self:popState() end\nend\n\nfunction Stateful:getStateStackDebugInfo()\n    local info, state = {}, nil\n    for i = #self.__stateStack, 1, -1 do\n        state = self.__stateStack[i]\n        table.insert(info, _getStateName(self, state))\n    end\n    return info\nend\n\nreturn Stateful\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Test/FSMClass.lua",
    "content": "local FSMClass = class(\"FSMClass\")\n\n-- 构造函数;\nfunction FSMClass:ctor()\n    \n    self._GameFSM \t\t\t= StateMachine:new();\n\n    self._GameFSM:setup_state({\n        events = \n\t\t{\n            {name = \"TChessStateWait\" \t\t\t        }, -- 等待游戏开始\n\t\t\t{name = \"TChessStateStartGame\"\t\t \t\t}, -- 开始游戏\n\t\t\t{name = \"TChessStateAction\" \t\t\t    }, -- 玩家自由出牌状态\n\t\t\t{name = \"TChessStateShowDown\" \t\t\t    }, -- 玩家结算状态\n            {name = \"TChessStateLeaveRoom\" \t\t    \t}, -- 离开\n        },\n        callbacks =\n\t\t{\n\t\t\tonTChessStateWait   \t\t= handler(self, self.DoGameFSMWait),\n\t\t\tonTChessStateStartGame  \t= handler(self, self.DoGameFSMStartGame),\n\t\t}\n    })\nend\n\nfunction FSMClass:SwitchState( event, ... )\n\tif (self._GameFSM ~= nil) then\n\t\tself._GameFSM:do_event( event, ... );\n\tend\nend\n\nfunction FSMClass:DoGameFSMWait( event )\n    nlinfo( \"FSMClass:DoGameFSMWait\" .. event.args[1] );\nend\n\nfunction FSMClass:DoGameFSMStartGame( event )\n    nlinfo( \"FSMClass:DoGameFSMStartGame\".. event.args[1] );\nend\n\nreturn FSMClass;"
  },
  {
    "path": "code/EVA/server/script/Framework/Test/MainTest.lua",
    "content": "\n\nlocal BasePath = \"E:/BaseService/code/EVA/server/script/\";\npackage.path = BasePath .. \"Framework/Test/?.lua;\" .. BasePath .. \"Framework/?.lua;\";\n\nrequire(\"Class\")\nrequire(\"functions\")\nrequire(\"TimerMgr\")\n\n\nStateMachine                = require(\"SimpleStateMachine\");\n\n\nlocal FSMClass  = require(\"FSMClass\");\nlocal TimerTest = require(\"TimerTest\");\n\n\n\nTimerMgr:Init( os.time()*1000 );\n\n\nlocal test_timer = TimerTest:new();\n\n\n\nwhile true do\n\n    TimerMgr:Update( os.time()*1000 );\nend\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Test/TimerTest.lua",
    "content": "\nlocal TimerTest = class(\"TimerTest\")\n\nfunction TimerTest:ctor()\n\tself.val = 0; \n    \n    TimerMgr:AddTimer(1000, self, self.CallBack);\nend\n\nfunction TimerTest:CallBack()\n\n    \n    \n    \n    local timerid = TimerMgr:AddTimer(1000, self, self.CallBack);\n    \n    self.val = self.val+1;\n    print(\"======\"..self.val..\"   id:\"..timerid);\n\nend\n\n--释放函数\nfunction TimerTest:Release()\n    \nend\n\n\nreturn TimerTest;\n"
  },
  {
    "path": "code/EVA/server/script/Framework/TimerMgr.lua",
    "content": "utils = require(\"Utils\")\n\nTimerMgr = {}\n\nlocal tbinsert  = table.insert\nlocal ums2t     = utils.ms2t\n\nfunction TimerMgr:Init(cycle)\n    \n    self.timerid    = 1;\n    self._removemap = {};\n    self._cycle = cycle\n    self._slots = {}\n    self._slots[1] = {}\n    self._slots[2] = {}\n    self._slots[3] = {}\n    self._slots[4] = {}\n    utils.tinsert_n(self._slots[1], {}, 24)\n    utils.tinsert_n(self._slots[2], {}, 60)\n    utils.tinsert_n(self._slots[3], {}, 60)\n    utils.tinsert_n(self._slots[4], {}, 1000)\n    \n    --setmetatable(results,{__mode = \"v\"})\nend\n\nfunction TimerMgr:GetTime()\n    return self._cycle;\nend\n\nfunction TimerMgr:Update(cycle)\n\tlocal h1, m1, s1, ms1 = ums2t(self._cycle)\n\tself._cycle = cycle\n\tlocal h2, m2, s2, ms2 = ums2t(self._cycle)\n\n\n\tself:__UpdateT__(24, 1, h1, h2, handler(self, self.__UpdateH__))\n\tself:__UpdateT__(60, 2, m1, m2, handler(self, self.__UpdateM__))\n\tself:__UpdateT__(60, 3, s1, s2, handler(self, self.__UpdateS__))\n\tself:__UpdateT__(1000, 4, ms1, ms2, handler(self, self.__UpdateMS__))\n\n    --[[\n\tself:__UpdateT__(24, 1, h1, h2, utils.bind(self.__UpdateH__, self))\n\tself:__UpdateT__(60, 2, m1, m2, utils.bind(self.__UpdateM__, self))\n\tself:__UpdateT__(60, 3, s1, s2, utils.bind(self.__UpdateS__, self))\n\tself:__UpdateT__(1000, 4, ms1, ms2, utils.bind(self.__UpdateMS__, self))\n    --]]\nend\n\nfunction TimerMgr:AddTimer(delay, obj, func)\n    self.timerid = self.timerid + 1;\n    local Handler = handler(obj, func);\n\tself:__Insert__(delay + 1, self.timerid, Handler )\n    return self.timerid;\nend\n\nfunction TimerMgr:RemoveTimer( timerid )\n    if timerid~=nil then\n        self._removemap[timerid]=true;\n    end\nend\n\nfunction TimerMgr:__Insert__(delay, timerid, func)\n\tif 0 == delay then\n        if self._removemap[timerid]==nil then\n            func()\n        else\n            self._removemap[timerid] = nil;\n        end\n\telse\n\t\tlocal h1, m1, s1, ms1 = ums2t(delay)\n\t\tlocal h2, m2, s2, ms2 = ums2t(delay + self._cycle)\n\t\tlocal tick = {\tfunc    = func, \n                        id      = timerid,\n\t\t\t\t\t\ttime    = { h = h2, m = m2, s = s2, ms = ms2 } }\n\t\tif h1 ~= 0 then\n\t\t\ttbinsert(self._slots[1][h2 == 0 and 24 or h2], tick)\n\t\telseif m1 ~= 0 then\n\t\t\ttbinsert(self._slots[2][m2 == 0 and 60 or m2], tick)\n\t\telseif s1 ~= 0 then\n\t\t\ttbinsert(self._slots[3][s2 == 0 and 60 or s2], tick)\n\t\telseif ms1 ~= 0 then\n\t\t\ttbinsert(self._slots[4][ms2 == 0 and 1000 or ms2], tick)\n\t\tend\n\tend\nend\n\nfunction TimerMgr:__UpdateT__(cycle, index, first, last, func)\n\tlocal slots = self._slots[index]\n\twhile first ~= last do\n\t\tfirst = first + 1\n        \n        local func_cnt = #slots[first];\n        if func_cnt>0 then\n            for i = 1, func_cnt do\n                func(slots[first][i])\n            end\n            slots[first] = {}\n        end\n\n\t\tfirst = first % cycle\n\tend\nend\n\nfunction TimerMgr:__UpdateH__(v)\n    local delay = v.time.m * 60000 + v.time.s * 1000 + v.time.ms;\n\tself:__Insert__(delay, v.id, v.func)\nend\n\nfunction TimerMgr:__UpdateM__(v)\n    local delay = v.time.s * 1000 + v.time.ms;\n\tself:__Insert__(delay, v.id, v.func)\nend\n\nfunction TimerMgr:__UpdateS__(v)\n\tself:__Insert__(v.time.ms, v.id, v.func)\nend\n\nfunction TimerMgr:__UpdateMS__(v)\n\tself:__Insert__(0, v.id, v.func)\nend\n\nreturn TimerMgr\n"
  },
  {
    "path": "code/EVA/server/script/Framework/Utils.lua",
    "content": "local _M = {}\n\nfunction _M.bind(func, ...)\n\tlocal args = {...}\n\treturn function(...)\n\t\tfunc(table.unpack(args), ...)\n\tend\nend\n\nfunction _M.dump(value, dep)\n\tdep = dep or \"\"\n\tlocal ret = \"\"\n\tif type(value) == \"table\" then\n\t\tret = ret .. \"{\\n\"\n\t\tfor k, v in pairs(value) do\n\t\t\tret = string.format(\"%s%s\\t[%s] = %s\\n\", ret, dep, k, dump(v, dep .. \"\\t\"))\n\t\tend\n\t\tret = ret .. dep .. \"},\\n\"\n\telse\n\t\tret = ret .. tostring(value) .. \", \"\n\tend\n\treturn ret\nend\n\nfunction _M.clone(src)\n\tlocal ret = {}\n\tif type(src) == \"table\" then\n\t\tfor k, v in pairs(src) do\n\t\t\tret[k] = _M.clone(v)\n\t\tend\n\telse\n\t\tret = src\n\tend\n\treturn ret\nend\n\nfunction _M.tinsert_n(src, val, n)\n\tfor i = 1, n do\n\t\ttable.insert(src, _M.clone(val))\n\tend\nend\n\nfunction _M.ms2t(cycle)\n\tlocal s = math.floor(cycle / 1000)\n\tlocal m = math.floor(cycle / 60000)\n\tlocal h = math.floor(cycle / 3600000)\n\tlocal ms = cycle - h * 3600000 - m * 60000 - s * 1000\n\treturn math.floor(h % 24), math.floor(m % 60), math.floor(s % 60), math.floor(ms % 1000)\nend\n\nfunction _M.t2ms(h, m, s, ms)\n\treturn h * 3600000 + m * 60000 + s * 1000 + ms\nend\n\nreturn _M"
  },
  {
    "path": "code/EVA/server/script/Framework/functions.lua",
    "content": "\n\n--[[\n实际上，除了 C++ 回调 Lua 函数之外，在其他所有需要回调的地方都可以使用 handler()。\n\n@param mixed obj Lua 对象\n@param function method 对象方法\n\n@return function\n\n]]--\n\nfunction handler(obj, method)\n\tif (nil == obj or nil == method) then\n\t\tlogError(\"handler param == nil\");\n\t\treturn nil;\n\tend\n    return function(...)\n        return method(obj, ...)\n    end\nend\n\nfunction checktable(value)\n    if type(value) ~= \"table\" then value = {} end\n    return value\nend\n\nfunction md5(value)\n    return Misc.MD5( value, string.len(value) );\nend\n\nfunction nldebug( str )\n\tDebug.Debug(str,2);\nend\n\nfunction nlinfo( str )\n\tDebug.Info(str,2);\nend\n\nfunction nlwarning( str )\n\tDebug.Warning(str,2);\nend\n\nfunction nlstop( str )\n\tDebug.Stop(str,2);\nend\n\nfunction shuffle(tbl)\n    \n    local tbl_count = #tbl;\n    for i=1,tbl_count do\n        local ridx  = math.random(1, tbl_count);\n        if i~=ridx then\n            local temp  = tbl[i];\n            tbl[i]      = tbl[ridx];\n            tbl[ridx]   = temp;\n        end\n    end\nend\n\nfunction GetServiceID()\n\treturn Net.GetServiceID();\nend\n\nfunction PrintTable( tbl, indent, depth )\n    Debug.Info(JsonUtil.serialise_value(tbl, indent, depth), 2);\n    --[[\n    if tbl==nil then\n        return;\n    end\n    \n    local msg = \"\"\n    depth = depth or 1\n    local indent_str = \"\"\n    \n    for i = 2, depth do\n        indent_str = indent_str..\"    \"\n    end\n\n    nlinfo(indent_str .. \"{\")\n    for k,v in pairs(tbl) do\n        if k ~= \"class\" then\n            local item_str = string.format(\"%s%s = %s\", indent_str .. \" \",tostring(k), tostring(v))\n            nlinfo(item_str)\n            \n            if type(v) == \"table\" then\n                PrintTable(v, depth + 1)\n            end\n        end\n    end\n    nlinfo(indent_str .. \"}\")\n    \n    --]]\nend\n\nfunction Table2Json( tbl )\n    return JsonUtil.serialise_value(tbl);\nend\n\nfunction Json2Table( str )\n    return Json.decode(str);\nend\n\n-- start --\n\n--------------------------------\n-- 从表格中删除指定值，返回删除的值的个数\n-- @function [parent=#table] removebyvalue\n-- @param table array 表格\n-- @param mixed value 要删除的值\n-- @param boolean removeall 是否删除所有相同的值\n-- @return integer#integer \n\n--[[--\n\n从表格中删除指定值，返回删除的值的个数\n\n~~~ lua\n\nlocal array = {\"a\", \"b\", \"c\", \"c\"}\nnlinfo(table.removebyvalue(array, \"c\", true)) -- 输出 2\n\n~~~\n\n]]\n\n-- end --\nfunction table.removebyvalue(array, value, removeall)\n    local c, i, max = 0, 1, #array\n    while i <= max do\n        if array[i] == value then\n            table.remove(array, i)\n            c = c + 1\n            i = i - 1\n            max = max - 1\n            if not removeall then break end\n        end\n        i = i + 1\n    end\n    return c\nend\n\nfunction get_data_by_sec(sec)\n    sec = sec < 0 and 0 or sec\n    local data =\n    {\n        day = math.floor(sec / 3600 / 24),\n        hour = math.floor(sec / 3600) % 24,\n        min = math.floor(sec % 3600 / 60),\n        sec = sec % 60,\n    }\n    return data\nend\n\n-- 单例模式\nfunction singleton(classname, super)\n    local cls = {}\n    if super then\n        for k,v in pairs(super) do cls[k] = v end\n        cls.super = super\n    else\n        cls.ctor = function() end\n    end\n\n    cls.__cname = classname\n    cls.__index = cls\n\n    local Instance = setmetatable({class = cls}, cls)\n    function cls.Instance()\n        return Instance\n    end\n    return cls\nend\n\n-- 分割字符串\nfunction SplitStr(str, reps)\n\tlocal resultStrList = {}\n    string.gsub(str,'[^'..reps..']+',function ( w )\n        table.insert(resultStrList,w)\n    end)\n    return resultStrList\nend\n\nfunction urlEncode(s)  \n     s = string.gsub(s, \"([^%w%.%- ])\", function(c) return string.format(\"%%%02X\", string.byte(c)) end)  \n    return string.gsub(s, \" \", \"+\")  \nend  \n  \nfunction urlDecode(s)  \n    s = string.gsub(s, '%%(%x%x)', function(h) return string.char(tonumber(h, 16)) end)  \n    return s  \nend \n\n-- 检查表中是否存在\nfunction IsInTable(value, tbl)\n\tif nil == tbl then return false; end\n\tfor k,v in pairs(tbl) do\n\t\tif v == value then\n\t\t\treturn true;\n\t\tend\n\tend\n\treturn false;\nend\n\nfunction ReverseTable(tab)  \n    local tmp = {}  \n    for i = 1, #tab do  \n        local key = #tab  \n        tmp[i] = table.remove(tab)  \n    end  \n  \n    return tmp  \nend\n\n\n-- 位标识符操作  Start\nfunction GetBit( curr, enum_val )\n    return (curr & (1<<enum_val)) > 0;\nend\n\nfunction SetBit( curr, enum_val )\n    return curr | (1<<enum_val)\nend\n\nfunction ClearBit( curr, enum_val )\n    if (curr & (1<<enum_val)) > 0 then\n        curr = curr ~ (1<<enum_val);\n    end\n    return curr;\nend\n\nfunction SetBits( curr, enum_tb )\n    for _,v in ipairs(enum_tb) do\n        curr = curr | (1<<v);\n    end\n    return curr\nend\n\nfunction ClearBits( curr, enum_tb )\n    for _,enum_val in ipairs(enum_tb) do\n        if (curr & (1<<enum_val)) > 0 then\n            curr = curr ~ (1<<enum_val);\n        end\n    end\n    return curr;\nend\n\n-- 位标识符操作  End\n\nfunction DumpMemorySnapshot()\n    collectgarbage(\"collect\")\n    MemoryRefInfo.m_cMethods.DumpMemorySnapshot(\"./\", \"All\", -1)\nend\n\nfunction DumpMemorySnapshotComparedFile( file_1, file_2 )\n    MemoryRefInfo.m_cMethods.DumpMemorySnapshotComparedFile(\"./\", \"Compared\", -1, file_1, file_2)\nend\n\n"
  },
  {
    "path": "code/EVA/server/script/Robot.luaprj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<Project Name=\"Robot.luaprj\" Cmd=\"E:\\BaseService\\build\\bin\\Debug\\client_robot.exe\" Arg=\"\" Dir=\"E:\\BaseService\\code\\EVA\\server\" Toggle=\"true\" >\n    <Filter RelativePath=\".\\__Robot\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\_ClientRobotMain.lua\" />\n        <Filter RelativePath=\".\\RobotSub\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\RobotSubStart.lua\" />\n            <LuaFile RelativePath=\".\\FSMRobot.lua\" />\n            <LuaFile RelativePath=\".\\PublicRoomInfoMgr.lua\" />\n            <LuaFile RelativePath=\".\\Robot.lua\" />\n            <LuaFile RelativePath=\".\\RobotData.lua\" />\n            <LuaFile RelativePath=\".\\RobotGameBase.lua\" />\n            <LuaFile RelativePath=\".\\RobotMgr.lua\" />\n            <Filter RelativePath=\".\\GameDdz\" Toggle=\"false\" >\n                <LuaFile RelativePath=\".\\FSMDdz.lua\" />\n                <LuaFile RelativePath=\".\\RobotGameDdz.lua\" />\n            </Filter>\n            <LuaFile RelativePath=\".\\PublicRoomInfo.lua\" />\n        </Filter>\n        <LuaFile RelativePath=\".\\ThreadMgr.lua\" />\n        <Filter RelativePath=\".\\Test\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\CppTimerTest.lua\" />\n            <LuaFile RelativePath=\".\\CppTimerBase.lua\" />\n        </Filter>\n    </Filter>\n</Project>"
  },
  {
    "path": "code/EVA/server/script/SharedLib/Event/EventType.lua",
    "content": "--========================================================= \n-- 事件类型\n--=========================================================\n\nEventType = \n{\n\t-- 内部事件 格式:[EVENT_XXXXX]\n\tEVENT_LOGIN\t\t                        = \"EVENT_LOGIN\";\t\t\t            -- 执行登录状态切换\n\n}\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/SharedLib/InitSharedLib.lua",
    "content": "--========================================================= \n-- 初始化游戏内共享工具，游戏逻辑相关。\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = package.path .. BasePath .. \"Framework/?.lua;\";\n\nrequire(\"InitFramework\")\n\n\nrequire(\"StaticTableMgr\");\nrequire(\"Event/EventType\");\n\n\n\n\n\n-- 初始化单例\nfunction OnInitSharedLib()\n\t\n    StaticTableMgr:Init();\n    \nend\n\n\n\nOnInitSharedLib();\n\n\n"
  },
  {
    "path": "code/EVA/server/script/SharedLib/StaticTableMgr.lua",
    "content": "StaticTableMgr = {}\n\nfunction StaticTableMgr:Init()\n\t\n    local ConfigPath = Misc.GetBasePath() .. \"/script/DataTable/\";\n    \n    local json_text     = JsonUtil.file_load(ConfigPath..\"RoomConfig.json\")\n    self._RoomConfig    = Json.decode(json_text)\n\n    json_text           = JsonUtil.file_load(ConfigPath..\"RoomCreateCost.json\")\n    self._CreateCost    = Json.decode(json_text)\n    \n    json_text           = JsonUtil.file_load(ConfigPath..\"SpecialConfig.json\")\n    self._SpecialCfg    = Json.decode(json_text)\n    \n    \nend\n\n\nfunction StaticTableMgr:GetRoomConfig( room_type )\n    return self._RoomConfig[tostring(room_type)];\nend\n\nfunction StaticTableMgr:GetCreateCost( cost_id )\n    return self._CreateCost[tostring(cost_id)];\nend\n\nfunction StaticTableMgr:GetSpecialCfg( room_type )\n    return self._SpecialCfg[tostring(room_type)];\nend\n\nreturn StaticTableMgr;\n\n"
  },
  {
    "path": "code/EVA/server/script/_FES/Client/Client.lua",
    "content": "local Client = class(\"Client\")\n\n-- 构造函数;\nfunction Client:ctor()\n\tself.SockID     = nil;\n\tself.ConPLS     = nil;\n\tself.UID        = nil;\n\n    self._LastHeartbeat = TimerMgr:GetTime();\n    self._TimerHandle   = TimerMgr:AddTimer(7000, self, self.CheckTimeout);\nend\n\nfunction Client:ResetHeartbeat()\n    self._LastHeartbeat = TimerMgr:GetTime();\nend\n\nfunction Client:CheckTimeout()\n    if TimerMgr:GetTime() - self._LastHeartbeat > 1500000 then\n        ClientService:DisConnect(self.SockID);\n        -- nlinfo(\"CheckTimeout:DisConnect  \"..self.SockID);\n    else\n        self._TimerHandle = TimerMgr:AddTimer(7000, self, self.CheckTimeout);\n        nlinfo(\"CheckTimeout\");\n    end\nend\n\n-- 通知逻辑服务器，客户端网络断开。\nfunction Client:_NotifyClientOffline()\n    if  self.ConPLS ~= nil  then\n        local msg = CMessage(\"ClientOffline\");\n        msg:wint(self.UID)\n        BaseService:Send( self.ConPLS, msg )\n    end\nend\n\nfunction Client:Release()\n\n    nlinfo(\"Client:Release  UID:\" .. self.UID);\n    self:_NotifyClientOffline();\n    TimerMgr:RemoveTimer(self._TimerHandle);\nend\n\nreturn Client;\n"
  },
  {
    "path": "code/EVA/server/script/_FES/Client/ClientMgr.lua",
    "content": "ClientMgr = {}\n\n-- 初始化函数\nfunction ClientMgr:Init()\n\tself.ClientMap      = {};\n    self.SocketMap      = {};\nend\n\nfunction ClientMgr:GetClient( _uid )\n    return self.ClientMap[_uid];\nend\n\nfunction ClientMgr:SetClient( _uid, _sock_id )\n    if self.ClientMap[_uid] == nil then\n        local client    = Client:new();\n        client.SockID   = _sock_id;\n        client.UID      = _uid;\n\n        self.ClientMap[_uid] = client;\n        self.SocketMap[_sock_id] = client;\n    else\n        local client    = self.ClientMap[_uid];\n\n        self.SocketMap[client.SockID] = nil;\n        ClientService:RemoveClientData(_uid);\n        ClientService:DisConnect(client.SockID);\n        \n        client.ConPLS   = nil;\n        client.SockID   = _sock_id;\n        self.SocketMap[_sock_id] = client;\n    end\nend\n\n-- 客户端逻辑层心跳，刷新心跳时间。\nfunction ClientMgr:ResetHeartbeat( _uid )\n    local client = self.ClientMap[_uid];\n\n    if client ~= nil then\n        client:ResetHeartbeat();\n    end\nend\n\nfunction ClientMgr:RemoveClient( _uid )\n\tif self.ClientMap[_uid] ~= nil then\n        local old_client = self.ClientMap[_uid];\n        self.SocketMap[old_client.SockID] = nil;\n        self.ClientMap[_uid] = nil;\n        \n        ClientService:RemoveClientData(_uid);\n        old_client:Release();\n    end\nend\n\nfunction ClientMgr:RemoveSockID( _sockid )\n\tif self.SocketMap[_sockid] ~= nil then\n        local old_client = self.SocketMap[_sockid];\n        \n        nlinfo(\"ClientMgr:RemoveSockID:\".._sockid..\"   UID:\"..old_client.UID);\n\n        ClientService:RemoveClientData(old_client.UID);\n        self.ClientMap[old_client.UID] = nil;\n        self.SocketMap[_sockid] = nil;\n        old_client:Release();\n    end\nend\n\nreturn ClientMgr\n"
  },
  {
    "path": "code/EVA/server/script/_FES/FrontEndService.lua",
    "content": "FrontEndService = {}\n\nfunction FrontEndService:Init()\n\tself._EventRegister = EventRegister.new();\n\t\n\tself._EventRegister:RegisterEvent( \"FESCon\",            self, self.Connection );\n\tself._EventRegister:RegisterEvent( \"FESDis\",            self, self.DisConnection );\n    self._EventRegister:RegisterEvent( \"PLSCon\",            self, self.Connection );\n\tself._EventRegister:RegisterEvent( \"PLSDis\",            self, self.DisConnection );\n    \n    -- 注册其它服务器启动的回调\n    Net.SetConnectionCallback(\"FES\");\n    Net.SetDisConnectionCallback(\"FES\");\n    \n    Net.SetConnectionCallback(\"PLS\");\n    Net.SetDisConnectionCallback(\"PLS\");\n    \nend\n\n\nfunction FrontEndService:Connection( service_id, service_name )\n\tnlinfo(\"FrontEndService:Connection:\"..service_name..\" sid:\"..service_id);\nend\n\nfunction FrontEndService:DisConnection( service_id, service_name )\n\tnlinfo(\"FrontEndService:DisConnection\"..service_name..\" sid:\"..service_id);\nend\n\n--\t释放函数\nfunction FrontEndService:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\nreturn FrontEndService\n\n"
  },
  {
    "path": "code/EVA/server/script/_FES/Msg/MsgLogin.lua",
    "content": "MsgLogin = {}\n\nfunction MsgLogin:Init()\n\n\tself._EventRegister = EventRegister.new();\n\t\n\tself._EventRegister:RegisterEvent( ClientService.ConnectCallbackEvent,  \tself, self.Connect );\n\tself._EventRegister:RegisterEvent( ClientService.DisConnectCallbackEvent,   self, self.DisConnect );\n\t\n    --  客户端消息\n\tself._EventRegister:RegisterEvent( \"LOGIN\",     self, self.CBLogin );\n    self._EventRegister:RegisterEvent( \"HB\",        self, self.CBHeartBeat );\n    \n    --  服务器间消息\n    self._EventRegister:RegisterEvent( \"AuthOk\",    self, self.CBAuthOk );          -- 有客户端在其它FES上登录成功。RemoveClient\n    self._EventRegister:RegisterEvent( \"SyncData\",  self, self.CBLoginPLS );        -- 在PLS上登录成功。\n    \n\t\nend\n\nfunction MsgLogin:CBLogin( sock_id, msg_login )\n\n    local tbl_login = msg_login:rpb(\"PB.MsgLogin\");\n\tPrintTable(tbl_login);\n    \n    -- 验证签名\n\tlocal sign_str = tbl_login.UID .. tbl_login.Channel .. tbl_login.RoomType .. tbl_login.AppName;\n          sign_str = sign_str .. tbl_login.User .. tbl_login.NonceStr .. tbl_login.Timestamp;\n          sign_str = sign_str .. \"BLACKSHEEPWALL\";\n        \n\tlocal sign     = string.upper( md5(sign_str) );\n\n\n\tnlinfo(\"sign_str:\"..sign_str);\n\tnlinfo(\"sign:\"..sign);\n    \n    \n    \n    --------------  账号认证通过\n    local msg_authok = CMessage(\"AuthOk\");\n    msg_authok:wint64(tbl_login.UID);\n    BaseService:Broadcast( \"FES\", msg_authok )      -- 通知其它网关有玩家登录成功。\n    \n    msg_authok:wstring(tbl_login.RoomType);\n    BaseService:Broadcast( \"SCH\", msg_authok )      -- 玩家认证通过，请求发送数据。\n    \n    -- 保存客户端连接\n    ClientMgr:SetClient(tbl_login.UID, sock_id);\n\n\t--  通知客户端 账号认证通过.\n    ClientService:Send( sock_id, \"AuthOk\" );\n\nend\n\nfunction MsgLogin:CBHeartBeat( sock_id, msgin )\n\n    local uid = msgin:rint64();\n\tnlinfo(\"MsgLogin:CBHeartBeat\"..uid);\n    ClientMgr:ResetHeartbeat(uid);\n    \nend\n\n\n-- 有客户端在其它FES上登录成功。RemoveClient\nfunction MsgLogin:CBAuthOk( sock_id, msg_authok )\n\n    local uid = msg_authok:rint64();\n\tnlinfo(\"MsgLogin:AuthOk\"..uid);\n    ClientMgr:RemoveClient(uid);\n    \nend\n\nfunction MsgLogin:CBLoginPLS( pls_id, msg_sdata_2 )\n    \n\tlocal uid       = msg_sdata_2:rint64();\n    local client    = ClientMgr:GetClient(uid);\n    \n    if( client ~= nil ) then\n        client.ConPLS = pls_id;\n        \n        -- 设置UID相关信息，用于底层转发消息。   msg.xml  \n        ClientService:SetClientData( {client.UID, client.SockID, pls_id} );\n    end\nend\n\n\nfunction MsgLogin:Connect( sock_id )\n\tnlinfo(\"CallbackClient:Connect\"..sock_id);\nend\n\nfunction MsgLogin:DisConnect( sock_id )\n\tnlinfo(\"CallbackClient:DisConnect\"..sock_id);\n    ClientMgr:RemoveSockID(sock_id);\nend\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_FES/Player/PlayerInfo.lua",
    "content": "-- Player PLS Info\nlocal PlayerInfo = class(\"PlayerInfo\")\n\n-- 构造函数;\nfunction PlayerInfo:ctor()\n\tself.PLSID      = nil;\n\tself.UID        = nil;\nend\n\nreturn PlayerInfo;\n"
  },
  {
    "path": "code/EVA/server/script/_FES/Player/PlayerInfoMgr.lua",
    "content": "PlayerInfoMgr = {}\n\n-- 初始化函数\nfunction PlayerInfoMgr:Init()\n\tself.PlayerInfoMap      = Map:new();\nend\n\nfunction PlayerInfoMgr:GetPlayerInfo( _uid )\n    return self.PlayerInfoMap:Find(_uid);\nend\n\nfunction PlayerInfoMgr:SetPlayerInfo( _uid, _playerinfo )\n    if _uid ~= _playerinfo.UID then  assert()  end;\n    \n    self.PlayerInfoMap:Insert(_uid, _playerinfo);\nend\n\nfunction PlayerInfoMgr:RemovePlayerInfo( _uid )\n    self.PlayerInfoMap:Remove(_uid);\nend\n\nfunction PlayerInfoMgr:RemovePLS( pls_sid )\n    self.PlayerInfoMap:ForEachRemove(\"PLSID\", pls_sid);\nend\n\nreturn PlayerInfoMgr\n"
  },
  {
    "path": "code/EVA/server/script/_FES/_FESMain.lua",
    "content": "--========================================================= \n-- 加载常用模块\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"_FES/?.lua;\" .. BasePath .. \"SharedLib/?.lua;\";\n\nrequire(\"InitSharedLib\")\nrequire(\"FrontEndService\");\nrequire(\"Client/ClientMgr\");\nrequire(\"Msg/MsgLogin\");\n\n-- Class\nClient      = require(\"Client/Client\");\n\n\nClientService   = CallbackServer:new();\nRobotCallback   = CallbackServer:new();\n\n\n-- 主入口函数。从这里开始lua逻辑\nfunction ServiceInit()\n\t\n    nlinfo(\" =========FES Main Start============ \");\n\n    ClientMgr:Init();\n    FrontEndService:Init();\n    \n    ClientService:Init( \"ClientService\", \"tcp\" );\n    --ClientService:Init( \"ClientService\", \"ws\" );\n    \n    --ClientService:Init( \"ClientService\", \"wss\" );\n    \n    --ClientService:LoadSslCA(BasePath..\"DataTable/ssl/1_root_bundle.crt\");\n    --ClientService:LoadSslCrt(BasePath..\"DataTable/ssl/2_ssl.ranatune.com.crt\");\n    --ClientService:LoadSslPrivateKey(BasePath..\"DataTable/ssl/3_ssl.ranatune.com.key\");\n\n    ClientService:Listen( 9999 );\n\n    MsgLogin:Init();\n\n\nend\n\n-- 游戏循环\nfunction ServiceUpdate()\n    -- TimerMgr:Update( Misc.GetLocalTime() );\n    TimerMgr:Update(math.floor(os.clock() * 1000))\nend\n\nfunction ServiceRelease()\n    nlinfo(\"Lua Release.\");\nend\n\nfunction ServiceInfo()\n\n\nend\n\n--[[\n\n--bash_path = \"E:\\\\BaseService\\\\code\\\\EVA\\\\server\\\\script\\\\\";\n--package.path = bash_path .. \"Framework\\\\?.lua;\" .. bash_path .. \"Framework\\\\Net\\\\?.lua;\";\n\nnlinfo(package.path);\n\nlocal protobuf = require \"protobuf\"\n\naddr = io.open( bash_path..\"DataTable\\\\proto_msg.pb\", \"rb\")\nbuffer = addr:read \"*a\"  \naddr:close()  \n  \nprotobuf.register(buffer)  \n\nt = protobuf.decode(\"google.protobuf.FileDescriptorSet\", buffer) \n\nplayer_info = {  \n    name = \"Alice\",  \n    pid = 12345,  \n    view_player_list = {  \n        { pid = 17712345678, head_portrait = 1 },  \n        { pid = 17712345679, head_portrait = 2 },  \n    },  \n    level = 2\n}\n\n\ncode = protobuf.encode(\"MsgPlayerInfo\", player_info)\ndecode = protobuf.decode(\"MsgPlayerInfo\" , code)\n\nnlinfo(decode.name)\nnlinfo(decode.pid)\n\nfor _,v in ipairs(decode.view_player_list) do\n\tnlinfo(\"\\t\"..v.pid, v.head_portrait)\nend\n\n]]"
  },
  {
    "path": "code/EVA/server/script/_FES.luaprj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<Project Name=\"_FES.luaprj\" Cmd=\"E:\\BaseService\\build\\bin\\Debug\\frontend_service.exe\" Arg=\"\" Dir=\"E:\\BaseService\\code\\EVA\\server\" Toggle=\"false\" >\n    <Filter RelativePath=\".\\_FES\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\_FESMain.lua\" />\n        <LuaFile RelativePath=\".\\FrontEndService.lua\" />\n        <Filter RelativePath=\".\\Client\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\Client.lua\" />\n            <LuaFile RelativePath=\".\\ClientMgr.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Msg\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\MsgLogin.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Player\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\PlayerInfo.lua\" />\n            <LuaFile RelativePath=\".\\PlayerInfoMgr.lua\" />\n        </Filter>\n    </Filter>\n</Project>"
  },
  {
    "path": "code/EVA/server/script/_PLS/DB/DBMgr.lua",
    "content": "DBMgr = {}\n\n\nfunction DBMgr:Init()\n\n    self.ConnPlayerInfo = MysqlConn.NewInstance();\n    local conn_info = { \"localhost\", \"root\", \"\", \"d_mt_player\", 3306 };\n    self.ConnPlayerInfo:Connect( conn_info );\n\n\n    self.StmtGetPlayerInfo      = MysqlStmt.NewInstance(\"CALL _t_mt_select_playerinfo(?)\");\n    self.StmtCreatePlayer       = MysqlStmt.NewInstance(\"CALL _t_mt_insert_playerinfo(?)\");\n    \n    \n    self.MysqlResult = MysqlResult.NewInstance();\n    \n    \n    \n    self.ItemIDGen = IDGenerate.NewInstance(1020);\n    \nend\n\nfunction DBMgr:LoadPlayerInfo(_uid)\n\n    self.MysqlResult:Clear();\n    self.StmtGetPlayerInfo:Clear();\n\n\tself.StmtGetPlayerInfo:SetUint64(_uid);\n\t\n    if self.ConnPlayerInfo:Query( self.StmtGetPlayerInfo, self.MysqlResult ) > 0 then\n        \n        local tb_player_info    = PlayerDataHelper:new();\n        \n        tb_player_info.f_uid            = self.MysqlResult:GetUint64();\n        tb_player_info.f_nickname       = self.MysqlResult:GetString();\n        tb_player_info.f_portrait       = self.MysqlResult:GetUint32();\n        tb_player_info.f_money          = self.MysqlResult:GetUint64();\n        tb_player_info.f_rmb            = self.MysqlResult:GetUint64();\n        tb_player_info.f_main           = self.MysqlResult:GetUint32();\n        tb_player_info.f_flag_bit       = self.MysqlResult:GetUint64();\n\n        return tb_player_info;\n    end\n\n    return nil;\nend\n\nfunction DBMgr:CreatePlayer(_uid)\n\n    self.StmtCreatePlayer:Clear();\n\tself.StmtCreatePlayer:SetUint64(_uid);\n\t\n    if self.ConnPlayerInfo:Exec( self.StmtCreatePlayer ) > 0 then\n        return true;\n    end\n\n    return false;\nend\n\n\n--释放函数\nfunction DBMgr:Release()\n    \nend\n\n\nreturn DBMgr;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/DB/DBProc.lua",
    "content": "local DBProc = class(\"DBProc\")\n\n-- 构造函数;\nfunction DBProc:ctor( Data )\n\tself:Init();\nend\n\n\nfunction DBProc:LuaTest()\n\n\tnlinfo(\"DBProc LuaTest \");\n\t\n\tmsg_session = {  \n\t\tcheck = 13,  \n\t\tsession = 4611686020574871551,  \n\t\tindex = 21\n\t}\n\t\n\tPostSub( \"thd_player\", \"EVT_DB_SUB\", \"MsgSession\", msg_session, 0xffff );\n\nend\n\nfunction DBProc:LuaTestCB( from, proto_buf )\n\n\tlocal msg_session = protobuf.decode(\"MsgSession\" , proto_buf)\n\t\n\tnlinfo(\"Main Thread DBProc Callback \" .. from);\n\tnlinfo(msg_session.check);\n\tnlinfo(msg_session.session);\n\tnlinfo(msg_session.index);\n\t\n\tcode = protobuf.encode(\"MsgSession\", msg_session)\n\tlen  = string.len(code);\n\nend\n\nfunction DBProc:Init()\n\t\n\tself._EventRegister = EventRegister.new();\n\tself._EventRegister:RegisterEvent( \"EVT_DB_MAIN\",  self, self.LuaTestCB );\nend\n\n--释放函数\nfunction DBProc:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn DBProc;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/DB/DBSubProc.lua",
    "content": "local DBSubProc = class(\"DBSubProc\")\n\n-- 构造函数;\nfunction DBSubProc:ctor( Data )\n\tself:Init();\nend\n\nfunction DBSubProc:LuaTestCB( from, proto_buf )\n\n\tlocal msg_session = protobuf.decode(\"MsgSession\" , proto_buf)\n\t\n\tnlinfo(\"Sub Thread DBSubProc Callback \" .. from);\n\tnlinfo(msg_session.check);\n\tnlinfo(msg_session.session);\n\tnlinfo(msg_session.index);\n\t\n\tPostMain( \"thd_player\", \"EVT_DB_MAIN\", \"MsgSession\", msg_session, from );\n\t\nend\n\nfunction DBSubProc:Init()\n\t\n\tself._EventRegister = EventRegister.new();\n\tself._EventRegister:RegisterEvent( \"EVT_DB_SUB\",  self, self.LuaTestCB );\nend\n\n--释放函数\nfunction DBSubProc:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn DBSubProc;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/DB/DBSubStart.lua",
    "content": "local BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"_PLS/?.lua;\" .. BasePath .. \"Framework/?.lua;\";\n\n\nrequire(\"InitFramework\")\n\n\nnlinfo(\"-=======DBSubStart==========-\");\n\n\nDBSubProc = require(\"DBSubProc\");\nsub_proc = DBSubProc:new();\n\n\n--DBProc = require(\"DBProc\");\n--db_proc = DBProc:new();\n--db_proc:LuaTest();\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/Common/CardsAnalyseRes.lua",
    "content": "local CardsAnalyseRes = class(\"CardsAnalyseRes\")\n\n--[[\n        牌型分析结构，表示每张相同牌的信息。\n        Analyse必须是排序后的。\n--]]\n\nfunction CardsAnalyseRes:ctor()\n    self:Reset();\nend\n\nfunction CardsAnalyseRes:Reset()\n    self.CardCount      = { 0, 0, 0, 0 };\n    self.CardData       = { {}, {}, {}, {} };\nend\n\nfunction CardsAnalyseRes:GetCount( num )\n    if self.CardCount[num]~=nil then\n        return self.CardCount[num];\n    end\n    return 0;\nend\n\nfunction CardsAnalyseRes:GetDatas( num )\n    return self.CardData[num];\nend\n\n-- 牌的逻辑值是否是连续的\nfunction CardsAnalyseRes:IsLink( num )\n    local is_link   = false;\n    local cnt       = self:GetCount(num);\n\n    if cnt>=2 then\n        local val_1     = GetPokerLogicValue(self.CardData[num][1]);\n        \n        --  如果第一张牌不是2或王，继续判断。\n        if val_1<15 then\n            is_link = true;\n            \n            for i=2,cnt do\n                local val_next = GetPokerLogicValue(self.CardData[num][i])+i-1;\n                if val_1 ~= val_next then\n                    is_link = false;\n                    break;\n                end\n            end\n        end\n    end\n\n    return is_link;\nend\n\n-- 统计牌张数\nfunction CardsAnalyseRes:Analyse( hand_cards )\n\n    local hand_cnt = #hand_cards;\n    if hand_cnt==0 then return; end\n    \n    local i=1;\n    while i<=hand_cnt do\n\n        local card = hand_cards[i];\n        local same_cnt  = 1;\n        local logic_val = GetPokerLogicValue(card);\n        \n        -- 向后遍历同牌\n        for j=i+1,hand_cnt do\n            if( GetPokerLogicValue(hand_cards[j]) == logic_val ) then\n                same_cnt = same_cnt + 1;\n            else\n                break;\n            end\n        end\n\n        -- 保存结果\n        self.CardCount[same_cnt] = self.CardCount[same_cnt] + 1;\n        table.insert( self.CardData[same_cnt], logic_val );\n        \n        i = i+same_cnt;\n    end\n\nend\n\n\nreturn CardsAnalyseRes;\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/Common/CommonDef.lua",
    "content": "\n\n\nfunction CardColor( card )\n    return card & 0xF0;\nend\n\nfunction CardValue( card )\n    return card & 0x0F;\nend\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/Common/PokerDef.lua",
    "content": "\n\n\n\nConstCardsPoker = {\n        0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,   -- 方块;\n        0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,   -- 梅花;\n        0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,   -- 红桃;\n        0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,   -- 黑桃;\n        0x41,0x42,                                                          -- 大小王;\n}\n\n-- 获得牌的逻辑数值，牌值大小。\nfunction GetPokerLogicValue( card )\n    \n    local value = CardValue(card);\n    \n    -- 大小王\n    if card >= 0x40 then\n        return value+15;\n    end\n    \n    if value==1 then\n        return 14;\n    end\n    \n    if value==2 then\n        return 15;\n    end\n    \n    return value\nend\n\nfunction GetPokerCount( card_list, card )\n    local value = GetPokerLogicValue(card);\n    local count = 0;\n    \n    for _,v in ipairs(card_list) do\n        if value==GetPokerLogicValue(v) then\n            count = count + 1;\n        end\n    end\n    \n    return count;\nend\n\n\n-- 按牌的逻辑值从大到小排序\nfunction SortPokerLogicValue( cards )\n    \n    local cnt = #cards;\n    if cnt<=1 then  return; end\n\n    local logic_cards = {};\n\n    for i,card in ipairs(cards) do\n        logic_cards[i] = GetPokerLogicValue(card);\n    end\n\n    local is_sorted = false;\n    local last_n    = cnt - 1;\n\n    while ( not is_sorted ) do\n        is_sorted = true;\n\n        for i=1,last_n do\n            local ccurr = logic_cards[i];\n            local cnext = logic_cards[i+1];\n\n\t        if ( ccurr<cnext ) or ( ccurr==cnext and cards[i]<cards[i+1] ) then\n                logic_cards[i]          = cnext;\n                logic_cards[i+1]        = ccurr;\n                cards[i], cards[i+1]    = cards[i+1], cards[i]\n                is_sorted = false;\n            end\n        end\n\n        last_n = last_n - 1;\n    end\nend\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/DDZOutCardData.lua",
    "content": "local DdzOutCardData = class(\"DdzOutCardData\")\n\n-- 构造函数;\nfunction DdzOutCardData:ctor()\n    self:ClearData();\nend\n\nfunction DdzOutCardData:ClearData()\n    self.UID            = 0;\n    self.Type           = enum.CT_DDZ_ERROR;\n    self.Cards          = {};\n    self.CompVal        = 0;\nend\n\nfunction DdzOutCardData:GetCardCount()\n    return #self.Cards;\nend\n\nfunction DdzOutCardData:SetCards( cards )\n    self.Cards = {};\n    for i,v in ipairs(cards) do\n        self.Cards[i] = v;\n    end\nend\n\nfunction DdzOutCardData:Copy( out_data )\n    self.UID    = out_data.UID;\n    self.Type   = out_data.Type;\n    self:SetCards( out_data.Cards );\nend\n\nreturn DdzOutCardData;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/DdzCardTypes.lua",
    "content": "DdzCardtypes = {}\n\nfunction DdzCardtypes:Init()\n    self.TempAnalyse    = CardsAnalyseRes:new();\nend\n\n-- out_cards      Ҫж͵ơ\n-- first_type     жͣҪѡ͡\n-- return  type,comp_val(max)\nfunction DdzCardtypes:GetCardType( out_cards, first_type )\n\n    local out_cnt = #out_cards;\n\n    if out_cnt==0 then\n        -- \n        return enum.CT_DDZ_ERROR;\n    elseif out_cnt==1 then\n        -- \n        return enum.CT_DDZ_SINGLE, GetPokerLogicValue(out_cards[1]);\n    elseif out_cnt==2 then\n        local val_1 = GetPokerLogicValue(out_cards[1]);\n        \n        if out_cards[1]>0x40 and out_cards[2]>0x40 then\n            -- \n            return enum.CT_DDZ_HUOJIAN, val_1;\n        elseif val_1==GetPokerLogicValue(out_cards[2]) then\n            -- \n            return enum.CT_DDZ_DOUBLE, val_1;\n        end\n\n        return enum.CT_DDZ_ERROR;\n    end\n\n    -- Ʒ\n    local ddz_anly = self.TempAnalyse;\n    ddz_anly:Reset();\n    ddz_anly:Analyse( out_cards );\n\n    local cnt_4 = ddz_anly:GetCount(4);\n\n    if cnt_4>0 then\n        local anly_datas    = ddz_anly:GetDatas(4);\n        local first_val     = anly_datas[1];\n\n        if cnt_4==1 and out_cnt==4 then\n            -- ը\n            return enum.CT_DDZ_ZHADAN_SIZHANG, first_val;\n        elseif cnt_4==1 and out_cnt==6 then\n            -- Ĵ\n            return enum.CT_DDZ_FOUR_WITHDOUBLE, first_val;\n        elseif cnt_4==1 and out_cnt==8 and ddz_anly:GetCount(2)==2 then\n            -- Ĵ\n            return enum.CT_DDZ_FOUR_LIANGDUI, first_val;\n        elseif cnt_4==2 and out_cnt==8 then\n            \n            if first_type==enum.CT_DDZ_FOUR_LIANGDUI then\n                -- Ĵ\n                return enum.CT_DDZ_FOUR_LIANGDUI, first_val;\n            end\n\n            local second_val    = anly_datas[2];\n            if (first_val+1)==second_val then \n                -- ɻ\n                return enum.CT_DDZ_FEIJI_WITH_ONE, first_val;\n            end\n\n            return enum.CT_DDZ_FOUR_LIANGDUI, first_val;\n        end\n    end\n\n    local cnt_3 = ddz_anly:GetCount(3);\n    local cnt_2 = ddz_anly:GetCount(2);\n    local cnt_1 = ddz_anly:GetCount(1);\n\n    if cnt_3>0 then\n        local anly_datas    = ddz_anly:GetDatas(3);\n        local first_val     = anly_datas[1];\n        \n        if out_cnt==3 then\n            -- \n            return enum.CT_DDZ_THREE_TIAO, first_val;\n        elseif cnt_3==1 and out_cnt==4 then\n            -- һ\n            return enum.CT_DDZ_THREE_TIAO_WITH_ONE, first_val;\n        elseif cnt_3==1 and out_cnt==5 and cnt_2==1 then\n            -- \n            return enum.CT_DDZ_THREE_TIAO_WITH_YIDUI, first_val;\n        elseif cnt_3==2 then\n            -- ɻ\n            if out_cnt==6 then\n                -- ɻ\n                return enum.CT_DDZ_FEIJI_WITH_NULL, first_val;\n            else\n                if ddz_anly:IsLink(3) then\n                    if out_cnt==8 then\n                        if cnt_2==1 or cnt_1==2 then\n                            -- ɻ\n                            return enum.CT_DDZ_FEIJI_WITH_ONE, first_val;\n                        end\n                    elseif out_cnt==10 and cnt_2==2 then\n                        -- ɻ\n                        return enum.CT_DDZ_FEIJI_WITH_YIDUI, first_val;\n                    end\n                end\n            end\n        end\n    elseif cnt_2>=3 and cnt_2*2==out_cnt and ddz_anly:IsLink(2) then\n        -- \n        local anly_datas    = ddz_anly:GetDatas(2);\n        return enum.CT_DDZ_LIAN_DUI, anly_datas[1];\n    elseif cnt_1>=5 and cnt_1==out_cnt and ddz_anly:IsLink(1) then\n        -- ˳\n        local anly_datas    = ddz_anly:GetDatas(1);\n        return enum.CT_DDZ_SHUN_ZI, anly_datas[1];\n    end\n\n    return enum.CT_DDZ_ERROR;\nend\n\n\n\n--  curr_out 󣬷true\nfunction DdzCardtypes:CompareCards( curr_out, last_out )\n\n    if curr_out.Type==enum.CT_DDZ_HUOJIAN or last_out.Type==enum.CT_DDZ_ERROR or curr_out.UID==last_out.UID then\n        return true;\n    end\n\n    if curr_out.Type==enum.CT_DDZ_ERROR or last_out.Type==enum.CT_DDZ_HUOJIAN  then\n        return false; \n    end\n\n    -- Ƚը\n    if curr_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG or last_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG then\n\n        local curr_isbomb = curr_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG;\n        local last_isbomb = last_out.Type==enum.CT_DDZ_ZHADAN_SIZHANG;\n\n        if last_isbomb and not curr_isbomb then\n            -- ϼҳըԼĲը\n            return false;\n        elseif not last_isbomb and curr_isbomb then\n            -- ϼҳĲըԼը\n            return true;\n        elseif last_isbomb and curr_isbomb then\n            -- ըȽըС\n            return curr_out.CompVal > last_out.CompVal;\n        end\n    end\n    \n    -- ж:  1.Ͳͬʱֱӷش  2.Ƶͬ\n    if curr_out.Type ~= last_out.Type  or  #curr_out.Cards ~= #curr_out.Cards then\n        return false;\n    end\n\n    --[[\n    local ctype = curr_out.Type;\n\n    -- Ա\n    if ctype==enum.CT_DDZ_SINGLE or ctype==enum.CT_DDZ_DOUBLE or ctype==enum.CT_DDZ_LIAN_DUI or ctype==enum.CT_DDZ_SHUN_ZI then\n        return curr_out.CompVal > last_out.CompVal;\n    elseif ctype==enum.CT_DDZ_FEIJI_WITH_YIDUI or ctype==enum.CT_DDZ_FEIJI_WITH_ONE then\n\n    elseif ctype==enum.CT_DDZ_FEIJI_WITH_NULL then\n\n    elseif ctype==enum.CT_DDZ_FOUR_WITHDOUBLE or ctype==enum.CT_DDZ_FOUR_LIANGDUI then\n\n    elseif ctype==enum.CT_DDZ_THREE_TIAO or ctype==enum.CT_DDZ_THREE_TIAO_WITH_ONE or ctype==enum.CT_DDZ_THREE_TIAO_WITH_YIDUI then\n\n    end\n    ]]\n\n    return curr_out.CompVal > last_out.CompVal;\nend\n\n-- Ƿܴ last_out .\nfunction DdzCardtypes:CheckCanOutCards( last_out, hand_cards )\n\n    local lastype = last_out.Type;\n    \n    if last_out.CompVal==0 or lastype==enum.CT_DDZ_ERROR then\n        return true;\n    end\n    \n    if lastype==enum.CT_DDZ_SINGLE then\n        return self:__GetSingleCards(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_DOUBLE then\n        return self:__CheckHaveCards(last_out.CompVal, hand_cards, 2);\n    elseif lastype==enum.CT_DDZ_THREE_TIAO then\n        return self:__CheckHaveCards(last_out.CompVal, hand_cards, 3);\n    elseif lastype==enum.CT_DDZ_THREE_TIAO_WITH_ONE then\n        return self:__CheckHaveThreeOne(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_THREE_TIAO_WITH_YIDUI then\n        return self:__CheckHaveThreeDouble(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_LIAN_DUI then\n        return self:__CheckHaveDoubleLink(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_SHUN_ZI then\n        return self:__CheckHaveLinkCards(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_FEIJI_WITH_NULL then\n        return self:__CheckHaveFeiJiNull(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_FEIJI_WITH_ONE then\n        return self:__CheckHaveFeiJiOne(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_FEIJI_WITH_YIDUI then\n        return self:__CheckHaveFeiJiDouble(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_FOUR_WITHDOUBLE then\n        return self:__CheckHaveFourTwo(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_FOUR_LIANGDUI then\n        return self:__CheckHaveFourDouble(last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_ZHADAN_SIZHANG then\n        return self:__CheckCanOutBomb(lastype, last_out.CompVal, hand_cards);\n    elseif lastype==enum.CT_DDZ_HUOJIAN then\n        return false;\n    end\n\n    return false;\nend\n\nfunction DdzCardtypes:__CheckCanOutBomb( last_type, last_compval, hand_cards )\n   \n    if last_type==enum.CT_DDZ_HUOJIAN or #hand_cards<2 then\n        return false;\n    end\n\n    local group     = self:__GetCardValueGroup( hand_cards, 4 );\n    local has_hj    = self:__HasHuoJian(hand_cards);\n    \n    if #group<1 and not has_hj then\n        return false;\n    end\n    \n    -- ϼҳը\n    if last_type==enum.CT_DDZ_ZHADAN_SIZHANG and last_compval>0 then\n        \n        if group[1]>last_compval or has_hj then\n            return true;\n        end\n        return false;\n    end\n\n    return true;\nend\n\nfunction DdzCardtypes:__GetSingleCards( last_compval, hand_cards )\n    if #hand_cards >= 1 then\n        if GetPokerLogicValue(hand_cards[1]) > last_compval then\n            return true;    \n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveLinkCards( last_compval, hand_cards )\n\n    local hand_cnt = #hand_cards;\n\n    -- ˳\n    if hand_cnt>=5 then\n        \n        local first_val = GetPokerLogicValue(hand_cards[1]);\n        local group_1   = { first_val };\n        \n        for i=2,hand_cnt do\n            local curr = GetPokerLogicValue(hand_cards[i]);\n            if first_val ~= curr then\n                table.insert( group_1, curr );\n                first_val = curr;\n            end\n        end\n        \n        local max_val   = self:__CheckHaveLink( group_1, 5 );\n        if max_val>last_compval then\n            return true;\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveFeiJiNull( last_compval, hand_cards )\n    if #hand_cards>=6 then\n        local group_3   = self:__GetCardValueGroup( hand_cards, 3 );\n        local max_val   = self:__CheckHaveLink( group_3, 2 );\n        \n        if max_val>last_compval then\n            return true;\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveFeiJiOne( last_compval, hand_cards )\n    if #hand_cards>=8 then\n        local group_3   = self:__GetCardValueGroup( hand_cards, 3 );\n        local max_val   = self:__CheckHaveLink( group_3, 2 );\n        \n        if max_val>last_compval then\n            return true;\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveFeiJiDouble( last_compval, hand_cards )\n    if #hand_cards>=10 then\n        local group_3   = self:__GetCardValueGroup( hand_cards, 3 );\n        local max_val   = self:__CheckHaveLink( group_3, 2 );\n        \n        if max_val>last_compval then\n            local lk_group  = self:__GetLinkGroup( group_3, 2 );\n            local group_2   = self:__GetCardValueGroup( hand_cards, 2 );\n            local count     = 0;\n            \n            for _,gp in ipairs(lk_group) do     -- е 2\n                if gp[1]>last_compval then      -- ׸ֵϼҵķɻ\n                    local double_cnt = 0;\n                    \n                    for _,v2 in ipairs(group_2) do\n                        if gp[1]~=v2 and gp[2]~=v2 then\n                            double_cnt = double_cnt+1;\n                        end\n                    end\n                    \n                    if double_cnt>=2 then\n                        return true;\n                    end\n                end\n            end\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveThreeOne( last_compval, hand_cards )\n    if #hand_cards>=4 then\n        local group_3 = self:__GetCardValueGroup( hand_cards, 3 );\n        if #group_3>0 and group_3[1]>last_compval then\n            return true;\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveThreeDouble( last_compval, hand_cards )\n    if #hand_cards>=5 then\n        local group_3 = self:__GetCardValueGroup( hand_cards, 3 );\n        local group_2 = self:__GetCardValueGroup( hand_cards, 2 );\n        \n        if #group_3>0 and #group_2>0 then\n            for _,v3 in ipairs(group_3) do\n                if v3>last_compval then\n                    for _,v2 in ipairs(group_2) do\n                        if v3~=v2 then\n                            return true;\n                        end\n                    end\n                end\n            end\n        end\n    end\n\n    -- ûдģը\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\n-- Ĵ\nfunction DdzCardtypes:__CheckHaveFourTwo( last_compval, hand_cards )\n    if #hand_cards>=6 then\n        local group_4 = self:__GetCardValueGroup( hand_cards, 4 );\n        if #group_4>0 and group_4[1]>last_compval then\n            return true;\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\n-- Ĵ\nfunction DdzCardtypes:__CheckHaveFourDouble( last_compval, hand_cards )\n    if #hand_cards>=8 then\n        local group_4 = self:__GetCardValueGroup( hand_cards, 4 );\n        local group_2 = self:__GetCardValueGroup( hand_cards, 2 );\n        \n        if #group_4>0 and #group_2>0 then\n            for _,v4 in ipairs(group_4) do\n                if v4>last_compval then\n                    local double_cnt = 0;\n                    for _,v2 in ipairs(group_2) do\n                        if v4~=v2 then\n                            double_cnt = double_cnt+1;\n                        end\n                    end\n                    \n                    if double_cnt>=2 then\n                        return true;\n                    end\n                end\n            end\n        end\n    end\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\nfunction DdzCardtypes:__CheckHaveCards( last_compval, hand_cards, same_cnt )\n   \n    if #hand_cards < same_cnt then\n        return false;\n    end\n    \n    local group = self:__GetCardValueGroup( hand_cards, same_cnt );\n    \n    if #group>0 and group[1]>last_compval then\n        return true;\n    end\n    \n    -- ûдģը\n    return self:__CheckCanOutBomb( 0, last_cards, hand_cards );\nend\n\n-- cardsѴӴС,˳ӣ˳ӵ򷵻0.\nfunction DdzCardtypes:__CheckHaveLink( cvs, link_num )\n   \n    if #cvs < link_num then\n        return 0;\n    end\n    \n    local cont      = 1;    -- ͬͳ\n    local card_val  = cvs[1];\n    local max_val   = card_val;\n    \n    for i=2,#cvs do\n        local curr  = cvs[i];\n        \n        if curr+1==card_val then\n            cont = cont + 1;\n        end\n        \n        if cont==link_num then\n            return max_val;\n        end\n        \n        if curr+1~=card_val then\n            cont    = 1;\n            max_val = curr;\n        end\n        \n        card_val = curr;\n    end\n    \n    return 0;\nend\n\n-- ÷  local cvs={ 5, 3, 2, 1 }  __GetLinkGroup(cvs, 2)   => { {3,2}, {2,1} }\n-- card_vals ȥ list\nfunction DdzCardtypes:__GetLinkGroup( card_vals, link_num )\n\n    local res       = {};\n    local vals_len  = #card_vals;\n\n    if vals_len < link_num then\n        return res;\n    end\n\n\n    local x = 1;\n    local find = true;\n    \n    while find do\n        local cont      = 1;    -- ͬͳ\n        local card_val  = card_vals[x];\n        find            = false;\n\n        for i=x+1,vals_len do\n            local curr  = card_vals[i];\n            \n            if curr+1==card_val then\n                cont = cont + 1;\n            end\n            \n            if cont==link_num then\n                \n                local group = {};\n                for gi=i-link_num+1,i do\n                    table.insert( group, card_vals[gi] );\n                end\n                table.insert( res, group );\n\n                if i==vals_len then\n                    return res;\n                else\n                    x = i - link_num + 2;\n                    find = true;\n                    break;\n                end\n            end\n            \n            if curr+1~=card_val then\n                cont    = 1;\n            end\n            \n            card_val = curr;\n        end\n    end\n\n    return res;\nend\n\n-- tblȥ\nfunction DdzCardtypes:__UniqueList(tbl)\n    local res = {};\n    \n    if #tbl<1 then\n        return res;\n    end\n    \n    res[1] = tbl[1];\n    local value = tbl[1];\n    \n    for i=2,#tbl do\n        \n        if value~=tbl[i]then\n            table.insert(res, tbl[i])\n        end\n        \n        value = tbl[i];\n    end\n    \n    return res;\nend\n\n-- cards ѴӴС   ͳcardsͬ\n-- local cards={4,4,4,4,5,5} __GetCardValueGroup( cards, 2 )  => {4,4,5}\n-- local cards={4,4,4,4,5,5} __GetCardValueGroup( cards, 3 )  => {4}\nfunction DdzCardtypes:__GetCardValueGroup( cards, same_cnt )\n    \n    local res_group = {};\n    if #cards<1 then  return res_group;  end\n    \n    local cont      = 1;    -- ͬͳ\n    local card      = GetPokerLogicValue(cards[1]);\n    \n    for i=2,#cards do\n        local curr  = GetPokerLogicValue(cards[i]);\n        \n        if curr==card then\n            cont = cont + 1;\n        end\n        \n        if cont==same_cnt then\n            cont = 0;\n            table.insert(res_group, card)\n        end\n        \n        if curr~=card then\n            cont = 1;\n            card = curr;\n        end\n    end\n    \n    return res_group;\nend\n\nfunction DdzCardtypes:__HasHuoJian( cards )\n    if #cards<2 then  return false;  end\n    \n    local cont  = 0;    -- Сͳ\n    \n    for i=1,#cards do\n        if cards[i]>0x40 then\n            cont = cont + 1;\n            if cont == 2 then\n                return true;\n            end\n        end\n    end\n    \n    return false;\nend\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/DdzFSM.lua",
    "content": "local FSMDouDiZhu = class(\"FSMDouDiZhu\")\n\n--[[\n        ߼״̬\n--]]\n\nfunction FSMDouDiZhu:ctor()\n    self._GameFSM \t\t\t= StateMachine:new();\n    self._StateEnterTime    = 0;\n    self._CurrState         = \"TDDZStateWait\";\n    self.RoomDdz            = nil;\nend\n\nfunction FSMDouDiZhu:Init( room_ddz )\n    self._GameFSM:setup_state({\n        events = \n\t\t{\n            {name = \"TDDZStateWait\" \t\t\t        },  -- ȴʼ\n\t\t\t{name = \"TDDZStateCheckStartGame\"\t\t    },  -- ǷԿʼϷ\n\t\t\t{name = \"TDDZStateSelectMingCardStart\" \t    },  -- ѡƿʼ׶\n\t\t\t{name = \"TDDZStateStartGame\" \t\t\t    },  -- ʼϷ\n            {name = \"TDDZStateSendCard\" \t\t    \t},  -- \n            {name = \"TDDZStateQiangDiZhu\" \t\t    \t},  -- ׶\n            {name = \"TDDZStateSelectAddTimes\" \t\t    },  -- ѡӱ׶\n            {name = \"TDDZStateAction\" \t\t    \t    },  -- ɻ\n            {name = \"TDDZStateOutCard\" \t\t    \t    },  -- ״̬\n            {name = \"TDDZStateShowDown\" \t\t    \t},  -- Ϸ\n            {name = \"TDDZStateRelieveRoom\" \t\t    \t},  -- ɢ\n        },\n        callbacks =\n\t\t{\n\t\t\tonTDDZStateWait   \t\t        = handler(self, self.DoWait),\n\t\t\tonTDDZStateCheckStartGame  \t    = handler(self, self.DoCheckStartGame),\n            onTDDZStateSelectMingCardStart  = handler(self, self.DoSelectMingCardStart),\n            onTDDZStateStartGame  \t        = handler(self, self.DoStartGame),\n            onTDDZStateSendCard  \t        = handler(self, self.DoSendCard),\n            onTDDZStateQiangDiZhu  \t        = handler(self, self.DoQiangDiZhu),\n            onTDDZStateSelectAddTimes  \t    = handler(self, self.DoSelectAddTimes),\n            onTDDZStateAction  \t            = handler(self, self.DoAction),\n            onTDDZStateOutCard  \t        = handler(self, self.DoOutCard),\n            onTDDZStateShowDown  \t        = handler(self, self.DoShowDown),\n            onTDDZStateRelieveRoom  \t    = handler(self, self.DoRelieveRoom),\n\t\t}\n    })\n    \n    self.RoomDdz = room_ddz;\n    self:SwitchState( self._CurrState );\nend\n\n\nfunction FSMDouDiZhu:__GetRunStateTime()\n    return TimerMgr:GetTime() - self._StateEnterTime;\nend\n\nfunction FSMDouDiZhu:TickUpdate()\n    self._GameFSM:do_event( self._CurrState, false );\nend\n\nfunction FSMDouDiZhu:SwitchState( event, ... )\n    self._CurrState = event;\n    self._StateEnterTime = TimerMgr:GetTime();\n    self._GameFSM:do_event( event, true, ... );\nend\n\nfunction FSMDouDiZhu:GetState()\n\treturn self._CurrState;\nend\n\nfunction FSMDouDiZhu:IsState( state )\n    if self._CurrState == state then\n        return true;\n    end\n\treturn false;\nend\n\nfunction FSMDouDiZhu:DoWait( event )\n    if not event.args[1] then\n        -- ͨʼת״̬\n        if self.RoomDdz:GameStartWait() then\n            self:SwitchState(\"TDDZStateCheckStartGame\");\n        end\n    end\nend\n\n-- ǷԿʼ,ݲ飬ֱһ״̬\nfunction FSMDouDiZhu:DoCheckStartGame( event )\n    self:SwitchState(\"TDDZStateStartGame\");\nend\n\n-- ѡƿʼ\nfunction FSMDouDiZhu:DoSelectMingCardStart( event )\n    if event.args[1] then\n        self.RoomDdz:ResetGameData();\n        self.RoomDdz:BroadcastGameInfo();\n        self.RoomDdz:SendQiangDiZhuWik();\n    end\nend\n\nfunction FSMDouDiZhu:DoStartGame( event )\n    if event.args[1] then\n        self.RoomDdz.IsGameStart    = true;\n        self.RoomDdz:ResetGameData();\n        self.RoomDdz:BroadcastGameInfo();\n    else\n        \n        if self:__GetRunStateTime()<3000 then\n            return;\n        end\n        \n        -- self:SwitchState(\"TDDZStateSelectMingCardStart\");\n        self:SwitchState(\"TDDZStateSendCard\");\n    end\nend\n\nfunction FSMDouDiZhu:DoSendCard( event )\n    if event.args[1] then\n        self.RoomDdz:SendHandCard();\n        self.RoomDdz:BroadcastGameInfo();\n    else\n        if self:__GetRunStateTime()<3000 then\n            return;\n        end\n        \n        self:SwitchState(\"TDDZStateQiangDiZhu\");\n    end\nend\n\nfunction FSMDouDiZhu:DoQiangDiZhu( event )\n    if event.args[1] then\n        self.RoomDdz:SendQiangDiZhuWik();\n    end\nend\n\nfunction FSMDouDiZhu:DoSelectAddTimes( event )\n    --if self:__GetRunStateTime()<10000 then\n    --    return;\n    --end\nend\n\nfunction FSMDouDiZhu:DoAction( event )\n    if event.args[1] then\n        self.RoomDdz:BroadGameActionPlayer();\n    end\nend\n\nfunction FSMDouDiZhu:DoOutCard( event )\n    if self:__GetRunStateTime()>3000 then\n        self:SwitchState(\"TDDZStateAction\");\n    end\nend\n\nfunction FSMDouDiZhu:DoShowDown( event )\n    if event.args[1] then\n        self.RoomDdz:GameShowDown();\n        self.RoomDdz:BroadcastShowDownInfo();\n        self.RoomDdz:AfterShowDown();\n    else\n        if self:__GetRunStateTime() > 5000 then\n            self:SwitchState(\"TDDZStateWait\");\n        end\n    end\nend\n\nfunction FSMDouDiZhu:DoRelieveRoom( event )\n    nlinfo( \"FSMClass:DoRelieveRoom\" );\nend\n\nreturn FSMDouDiZhu;\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/DdzPlayerInfo.lua",
    "content": "local DdzPlayerInfo = class(\"DdzPlayerInfo\", RoomPlayerBase)\n\n--[[\n        \n--]]\n\nfunction DdzPlayerInfo:ctor()\n\n    self.super:ctor();\n    \n    self.QiangDiZhu     = 0;    -- ѡ     TDDZQiangDiZhu  TDDZJiaoFen\n    \n    self._TempCards     = {};\n\n    self._OutCount      = 0;    -- ҳƴʱʹ\n    self.Multi          = 1;\n    self.StartScore     = 0;    -- ÿֿʼʱҵϷ\n    \nend\n\nfunction DdzPlayerInfo:AddOutCount()\n    self._OutCount = self._OutCount + 1;\nend\n\nfunction DdzPlayerInfo:GetOutCount()\n    return self._OutCount;\nend\n\nfunction DdzPlayerInfo:AddHandCards( tbl, start_idx, end_idx )\n    if start_idx ~=nil then\n        for idx=start_idx, end_idx do\n            table.insert( self.HandCards, tbl[idx] );\n        end\n    else\n        for _,v in ipairs(tbl) do\n            table.insert( self.HandCards, v );\n        end\n    end\nend\n\nfunction DdzPlayerInfo:RemoveCards( cards )\n    \n    self._TempCards = {};\n    for i,c in ipairs(self.HandCards) do\n        self._TempCards[i] = c;\n    end\n\n    for i,c in ipairs(cards) do\n        for ih,ch in ipairs(self._TempCards) do\n            if ch==c then\n                table.remove(self._TempCards, ih);\n                break;\n            end\n        end\n    end\n    \n    if #self._TempCards + #cards == #self.HandCards then\n        self.HandCards = {};\n        for i,c in ipairs(self._TempCards) do\n            self.HandCards[i] = c;\n        end\n        return true;\n    end\n    \n    return false;\nend\n\n\n-- ÿʱ\nfunction DdzPlayerInfo:ClearOneGameData()\n    self:ClearOneGameState();\n    \n    self.StartScore = self._Score;\nend\n\nfunction DdzPlayerInfo:GetCardCount()\n    return #self.HandCards;\nend\n\n\n\n\n---------\n\n\nfunction DdzPlayerInfo:Auto()\n    \nend\n\n\n\nreturn DdzPlayerInfo;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/MsgRoomDdz.lua",
    "content": "MsgRoomDdz = {}\n\n--[[\n        斗地主消息处理。\n--]]\n\nfunction MsgRoomDdz:Init()\n\tself._EventRegister = EventRegister.new();\n    self._EventRegister:RegisterEvent( \"DDZ_SR\",            self, self.cbStartReady );              -- 斗地主开始准备\n    self._EventRegister:RegisterEvent( \"DDZ_CR\",            self, self.cbCancleReady );             -- 斗地主取消准备\n    self._EventRegister:RegisterEvent( \"DDZ_JB\",            self, self.cbDouDiZhuAddTimes );        -- 加倍选择\n    self._EventRegister:RegisterEvent( \"DDZ_QDZ\",           self, self.cbDouDiZhuQiangDiZhu );      -- 抢地主选择\n    self._EventRegister:RegisterEvent( \"DDZ_OC\",            self, self.cbDouDiZhuOutCard );         -- 斗地主出牌\n    self._EventRegister:RegisterEvent( \"DDZ_PS\",            self, self.cbDouDiZhuPassCards );       -- 斗地主过牌\n    self._EventRegister:RegisterEvent( \"DDZ_SMPS\",          self, self.cbPreStartMingPai );         -- 游戏开始前选择是否明牌\n    self._EventRegister:RegisterEvent( \"DDZ_DZMP\",          self, self.cbPreMingPai );              -- 出牌前地主选择是否明牌\nend\n\nfunction MsgRoomDdz:cbStartReady( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        room:UserStartReady(uid);\n    end\nend\n\nfunction MsgRoomDdz:cbCancleReady( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        room:UserCancelReady(uid);\n    end\nend\n\nfunction MsgRoomDdz:cbDouDiZhuAddTimes( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        local msg_jbr = msgin:rpb(\"PB.MsgJiaBeiResult\");\n        room:RefreshSelectJiaBei(uid, msg_jbr);\n    end\nend\n\nfunction MsgRoomDdz:cbDouDiZhuQiangDiZhu( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        local msg_qdz = msgin:rpb(\"PB.MsgQiangDiZhuResult\");\n        room:RefrshRoleQiangDiZhu(uid, msg_qdz);\n    end\nend\n\nfunction MsgRoomDdz:cbPreStartMingPai( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        \n        \n    end\nend\n\nfunction MsgRoomDdz:cbPreMingPai( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        \n        \n    end\nend\n\nfunction MsgRoomDdz:cbDouDiZhuOutCard( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        local msg_oc = msgin:rpb(\"PB.MsgDDZUserOutCard\");\n        room:UserOutCard( uid, msg_oc );\n    end\nend\n\nfunction MsgRoomDdz:cbDouDiZhuPassCards( fes_sid, msgin )\n    local uid       = msgin:rint64();\n    local room      = RoomMgr:GetRoomFromPID(uid);\n    \n    if room~=nil then\n        room:UserPassOutCard( uid );\n    end\nend\n\n--释放函数\nfunction MsgRoomDdz:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn MsgRoomDdz;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Games/PokerDdz/RoomDdz.lua",
    "content": "local RoomDdz = class(\"RoomDdz\", RoomBase)\n\nDdzFSM              = require(\"Games/PokerDdz/DdzFSM\")\nDdzPlayerInfo       = require(\"Games/PokerDdz/DdzPlayerInfo\")\nDdzOutCardData      = require(\"Games/PokerDdz/DDZOutCardData\")\n\n--[[\n        斗地主房间内游戏逻辑。\n--]]\n\nlocal tbinsert = table.insert\n\nfunction RoomDdz:ctor()\n\n    self.super:ctor();\n    \n    self.CFG_HAND_COUNT         = 17;       -- 每个玩家的初始手牌个数\n    self.CFG_TOTAL_CARD         = 54;       -- 牌池\n    self.CFG_BASE_SCORE         = 1;        -- 底分\n    self.CFG_DIPAI_COUNT        = 3;        -- 底牌个数\n    self.CFG_HANDCOUNT_MAX      = 20;       -- 手牌最大个数\n    self.CFG_TRUSTMAX           = 3;        -- 最大托管次数\n    self.CFG_FENGDING_16        = 16;       -- 16封顶\n    self.CFG_FENGDING_32        = 32;       -- 32封顶\n    self.CFG_FENGDING_64        = 64;       -- 64封顶\n    \n    self._GameCount             = 1;        -- 当前是第几局\n\n    self.Fsm                    = DdzFSM:new();\n    self.Fsm:Init(self);\n\n    self._LastOutCardData       = DdzOutCardData:new();\n    self._TempOutCardData       = DdzOutCardData:new();\n    \n    \n    -- 战绩回放\n    self._RecordNodeList        = {};       -- 战绩回放的节点\n    self._RecordGames           = {};       -- 记录房间中的每局战绩  list[_RecordNodeList]\n    \n    self:ResetGameData();\nend\n\n-- 每局清除数据\nfunction RoomDdz:ResetGameData()\n    \n    self._CardsPool             = {};\n\tself._CardsBottom           = {};       -- 剩下的三张底牌\n    self._ActionID              = 0;        -- 当前活动的玩家\n    self._ActionUserWik         = 0;        -- 当前活动玩家权限\n    self._Multiple              = 1;        -- 房间翻倍数\n    \n    self._QiangDiZhuWiki        = 0;        -- 抢地主权限\n    self._QiangDiZhu            = true;     -- 是否是叫地主抢地主模式\n    self._DiZhuID               = 0;        -- 地主 uid\n    self._CanOutCard            = {};       -- 当前可以出的牌，托管时使用\n    self.ShowDownEvent          = {};       -- 结算事件\n    \n    self._LastOutCardData:ClearData();\n    self._TempOutCardData:ClearData();\n    \n    -- 清空玩家临时数据\n    for _,v in ipairs(self.SeatPlayers) do\n        if v~=0 then\n            local room_player = self.RoomPlayerData:Find(v);\n            if room_player~=nil then\n                room_player:ClearOneGameData();\n            end\n        end\n    end\n    \n    -- 发牌洗牌\n    for i,v in pairs(ConstCardsPoker) do\n        self._CardsPool[i] = v;\n    end\n\n    shuffle(self._CardsPool);\nend\n\n-- 判断游戏是否可以开始\nfunction RoomDdz:GameStartWait()\n    --  人数是否足够\n    if self.RoomPlayerData:Count()<self.CFG_RM_MIN then\n        return false;\n    end\n    \n    -- 是否都点了准备\n    for _,v in pairs(self.RoomPlayerData.map) do\n        if not v:GetState( enum.STATE_DDZ_READY ) then\n            return false;\n        end\n    end\n    \n    return true;\nend\n\n-- 玩家加入房间\nfunction RoomDdz:JoinRoom( player )\n    local ddz_player = self.RoomPlayerData:Find(player.UID);\n\n    if ddz_player~=nil then\n        -- 返回房间\n        --ddz_player:SetState( enum.STATE_DDZ_NEWROLE );\n        self:BaseJoinRoom(player);\n        self:RefreshRoomInfo(player.UID);\n        return true;\n    else\n        \n        -- 如果房间已满，跳出。\n        if self.RoomPlayerData:Count() == self.CFG_RM_MIN then\n            return false\n        end\n        \n        -- 第一次进入房间\n        ddz_player = DdzPlayerInfo:new();\n        ddz_player:SetState( enum.STATE_DDZ_NEWROLE );\n\n        if player.UID == self.CreatorID then\n            --  设置是房主\n            ddz_player:SetState( enum.STATE_DDZ_ROOM_OWNER );\n        end\n\n        self.RoomPlayerData:Insert(player.UID, ddz_player);\n        \n        self:BaseJoinRoom(player);\n        self:BroadcastGameInfo();\n        return true;\n    end\nend\n\nfunction RoomDdz:TickUpdate()\n    self.Fsm:TickUpdate();\nend\n\nfunction RoomDdz:UserStartReady( uid )\n    local room_player = self.RoomPlayerData:Find(uid);\n    \n    if room_player~=nil then\n        room_player:SetState(enum.STATE_DDZ_READY);\n        local msg_int = { value=uid };\n        self:BroadcastMsg( \"DDZ_SR\", \"PB.MsgInt\", msg_int );\n    end\nend\n\nfunction RoomDdz:UserCancelReady( uid )\n    local room_player = self.RoomPlayerData:Find(uid);\n    \n    if room_player~=nil then\n        room_player:ClearState( enum.STATE_DDZ_READY );\n        local msg_int = { value=uid };\n        self:BroadcastMsg( \"DDZ_CR\", \"PB.MsgInt\", msg_int );\n    end\nend\n\nfunction RoomDdz:SendQiangDiZhuWik()\n    -- 随机一个玩家选择抢地主\n    local seat_idx  = math.random(1, #self.SeatPlayers);\n    self._ActionID  = self.SeatPlayers[seat_idx];\n    \n    self._QiangDiZhuWiki = 0;\n        \n    if _QiangDiZhu then\n        self._QiangDiZhuWiki = SetBits( self._QiangDiZhuWiki, {enum.DDZ_QDZ_BUJIAO, enum.DDZ_QDZ_JIAODIZHU} );\n    else\n        local qdz_wiks = { enum.DDZ_QDZ_BUJIAO, enum.DDZ_JF_JIAO_ONE, enum.DDZ_JF_JIAO_TWO, enum.DDZ_JF_JIAO_THREE };\n        self._QiangDiZhuWiki = SetBits( self._QiangDiZhuWiki, qdz_wiks );\n    end\n\n    self:__RefreshPlayerQDZState(self._ActionID);\n        \n    local msg_qdz = {\n        playid = self._ActionID;\n        qingdizhu_wiki = self._QiangDiZhuWiki;\n    }\n\n    local player    = PlayerMgr:GetPlayer(self._ActionID);\n    BaseService:SendToClient( player, \"DDZ_QDZ_QX\", \"PB.MsgQiangDiZhu\", msg_qdz );\n        \n    msg_qdz.qingdizhu_wiki = 0;\n    self:BroadcastMsg( \"DDZ_QDZ_QX\", \"PB.MsgQiangDiZhu\", msg_qdz, self._ActionID );\nend\n\n-- 刷新加倍的选择\nfunction RoomDdz:RefreshSelectJiaBei( uid, msg_jbr )\n    if self.Fsm:IsState(\"TDDZStateSelectAddTimes\") then\n        local room_player = self.RoomPlayerData:Find(uid);\n\n        if room_player~=nil then\n            room_player:SetState( enum.STATE_DDZ_SELECT_JIABEI );\n\n            if msg_jbr.result == enum.DDZ_AT_JIABIE then\n                room_player:SetState( enum.STATE_DDZ_JIABEI );\n            end\n            \n            msg_jbr.playid  = uid;\n            msg_jbr.state   = room_player:GetState();\n            \n            self:BroadcastMsg(\"DDZ_JB\", \"PB.MsgJiaBeiResult\", msg_jbr);\n\n            for _,v in pairs(self.RoomPlayerData.map) do\n                if not v:GetState(enum.STATE_DDZ_SELECT_JIABEI) then\n                    return;\n                end\n            end\n\n            -- 回放开始记录\n            self:__RecordGameStart();\n            \n            -- 如果所有玩家都选择过了，进入下一状态\n            self.Fsm:SwitchState(\"TDDZStateAction\");\n        end\n    end\nend\n\n-- 刷新抢地主\nfunction RoomDdz:RefrshRoleQiangDiZhu( uid, msg_qdz )\n\n    if not self.Fsm:IsState(\"TDDZStateQiangDiZhu\") then\n        return\n    end\n\n    local room_player = self.RoomPlayerData:Find(uid);\n        \n    if room_player~=nil then\n        --room_player:IsSelectJiaBei()\n            \n        local qdz_select = msg_qdz.result;\n        room_player.QiangDiZhu = qdz_select;\n            \n        if self._QiangDiZhu then\n                \n            if qdz_select==enum.DDZ_QDZ_QIANGDIZHU then\n                \n                self._Multiple = self._Multiple*3;\n                \n            end\n\n        end\n            \n        msg_qdz.playid      = uid;\n        msg_qdz.multiple    = self._Multiple;\n            \n        self:BroadcastMsg(\"DDZ_QDZ\", \"PB.MsgQiangDiZhuResult\", msg_qdz)\n\n\n        --  设置下一个玩家抢地主的操作\n        local next_uid = self:GetNextUID( uid );\n            \n        -- 如果都不叫，并且默认的地主叫了\n        if self._QiangDiZhu and qdz_select~=enum.DDZ_QDZ_BUJIAO then\n            while true do\n                local next_player = self:GetRoomPlayer(next_uid);\n                if next_player==nil then    return;  end\n                    \n                if next_uid==uid then\n                    self._ActionID = uid;\n                    self:SetDiZhuState(uid)\n                    return;\n                end\n                    \n                if next_player.QiangDiZhu == enum.DDZ_QDZ_BUJIAO then\n                    next_uid = self:GetNextUID( next_uid );\n                else\n                    break;\n                end\n            end\n        end\n            \n        local WIK   = 0;\n            \n        if self._QiangDiZhu then\n            if qdz_select==enum.DDZ_QDZ_BUJIAO then\n                    \n                if next_uid == self._ActionID then\n                    -- 没有人叫地主则系统随机的第一个人作为地主\n                    self:SetDiZhuState(next_uid);\n                    return;\n                end\n                    \n                -- 设置客户端可选择权限\n                WIK = SetBits( WIK, { enum.DDZ_QDZ_JIAODIZHU, enum.DDZ_QDZ_BUJIAO } );\n            else\n                if qdz_select == enum.DDZ_QDZ_JIAODIZHU then\n                    self._ActionID = uid;\n                elseif qdz_select == enum.DDZ_QDZ_QIANGDIZHU then\n                    -- 叫地主的玩家选择抢地主则完成抢地主\n                    self:__AddShowDownEvent(enum.EVENT_QIANGDIZHU, 1);\n                        \n                    if uid==self._ActionID then\n                        self:SetDiZhuState(next_uid);\n                        return;\n                    end\n                elseif qdz_select == enum.DDZ_QDZ_BUQIANG then\n                        \n                    if next_uid==self._ActionID then\n                            \n                            \n                        if not self:__CheckQiangDiDiZhu( next_uid ) then\n                            -- 如果下家叫地主，且都不抢，设置next_uid地主\n                            self:SetDiZhuState(next_uid);\n                            return;\n                        elseif uid==self._ActionID then\n                            -- 叫地主的玩家选择不抢地主后，选择最后一次抢地主的玩家做地主\n                            self._ActionID = self:__SelectDZ(next_uid);\n                            self:SetDiZhuState(self._ActionID);\n                            return;\n                        end\n                    end\n                end\n                    \n                -- 设置客户端可选择权限\n                WIK = SetBits( WIK, { enum.DDZ_QDZ_QIANGDIZHU, enum.DDZ_QDZ_BUQIANG } );\n            end\n        end\n            \n        self._QiangDiZhuWiki = WIK;\n        self:__RefreshPlayerQDZState(next_uid);\n            \n        local msg_qdz = {\n            playid          = next_uid,\n        };\n        self:BroadcastMsg(\"DDZ_QDZ_QX\", \"PB.MsgQiangDiZhu\", msg_qdz, next_uid)\n            \n        msg_qdz.qingdizhu_wiki = WIK;\n        local player = PlayerMgr:GetPlayer(next_uid);\n        BaseService:SendToClient( player, \"DDZ_QDZ_QX\", \"PB.MsgQiangDiZhu\", msg_qdz );\n    end\nend\n\n-- 设置地主和农民,抢地主完成\nfunction RoomDdz:SetDiZhuState( uid )\n    \n    local ply_dz = self.RoomPlayerData:Find(uid);\n    \n    if ply_dz~=nil then\n    \n        ply_dz:SetState( enum.STATE_DDZ_DIZHU );\n        ply_dz:AddHandCards( self._CardsBottom );\n        SortPokerLogicValue( ply_dz.HandCards );\n        \n        self._DiZhuID   = uid;\n        self._ActionID  = uid;\n        \n        \n        --- 底牌翻倍\n        \n    \n        -- 抢完地主清除玩家身上的抢地主状态\n        self:__RefreshPlayerQDZState(0);\n        \n        -- 填充抢地主最终结果(服务器广播的)\n        local MsgBRQiangDiZhuResult = {\n            multiple    = self._Multiple;\n            player_list = {};\n        }\n        \n        -- 暂时不加底牌翻倍\n        for u,v in pairs(self.RoomPlayerData.map) do\n            if u~=self._DiZhuID then\n                v:SetState( enum.STATE_DDZ_NONGMING )\n            \n            end\n            \n            local MsgQiangDiZhuResult = {\n                playid      = u;\n                state       = v:GetState();\n                cardcount   = v:GetCardCount();\n            }\n\n            -- 如果地主明牌了，增加地主手牌\n            if u==self._DiZhuID and ply_dz:GetState(enum.STATE_DDZ_MINGPAI) then\n                MsgQiangDiZhuResult[\"dizhu_cards\"] = ply_dz.HandCards;\n            end\n            \n            tbinsert(MsgBRQiangDiZhuResult.player_list, MsgQiangDiZhuResult);\n        end\n        \n        self:BroadcastMsg( \"DDZ_QDZ_F\", \"PB.MsgBRQiangDiZhuResult\", MsgBRQiangDiZhuResult, self._DiZhuID );\n        \n        -- 填充地主手牌，发给地主。\n        for _,v in pairs(MsgBRQiangDiZhuResult.player_list) do\n            if v.playid==self._DiZhuID then\n                if v.dizhu_cards==nil then\n                    v.dizhu_cards = ply_dz.HandCards;\n                end\n                break;\n            end\n        end\n        \n        local player = PlayerMgr:GetPlayer(uid);\n        BaseService:SendToClient(player, \"DDZ_QDZ_F\", \"PB.MsgBRQiangDiZhuResult\", MsgBRQiangDiZhuResult);\n        \n        -- 抢地主结束，切状态。\n        if self:CheckRoomSpecialKind(enum.TSK_DDZ_JIABEI) then\n            self.Fsm:SwitchState(\"TDDZStateSelectAddTimes\");\n        else\n            self.Fsm:SwitchState(\"TDDZStateSelectAddTimes\");\n        end\n        \n        -- 如果这里要切 TDDZStateAction  ，需要  self:__RecordGameStart();\n    end\nend\n\n-- 发牌\nfunction RoomDdz:SendHandCard()\n    local start_send    = 1;\n    local end_send      = self.CFG_HAND_COUNT;\n    \n    for _,v in ipairs(self.SeatPlayers) do\n        local room_player = self.RoomPlayerData:Find(v);\n        \n        if room_player~=nil then\n            \n            room_player:AddHandCards( self._CardsPool, start_send, end_send );\n            SortPokerLogicValue( room_player.HandCards );\n            \n            start_send  = start_send + self.CFG_HAND_COUNT;\n            end_send    = end_send + self.CFG_HAND_COUNT;\n        end\n    end\n\n    -- 发底牌\n    self._CardsBottom           = {};\n\n    for idx=start_send, self.CFG_TOTAL_CARD do\n        tbinsert( self._CardsBottom, self._CardsPool[idx] );\n    end\nend\n\n--  广播房间活动玩家\nfunction RoomDdz:BroadGameActionPlayer( )\n    self._ActionUserWik = self:__GetActionWik();\n    \n    local MsgDDZActon = {\n        new_actionid    = self._ActionID,\n        old_actionid    = self._LastOutCardData.UID,\n        last_out_type   = self._LastOutCardData.Type,\n        last_out_cards  = self._LastOutCardData.Cards,\n        wik             = self._ActionUserWik,\n        player_list     = {}\n    }\n    \n    for i,uid in ipairs(self.SeatPlayers) do\n        local ddz_player = self.RoomPlayerData:Find(uid);\n        if ddz_player~=nil then\n            local MsgDDZPlayer = {\n                seats       = i,\n                state       = ddz_player:GetState(),\n                hand_count  = ddz_player:GetCardCount(),\n                score       = ddz_player.Score,\n                player_base = { UID = uid }\n            }\n            \n            tbinsert( MsgDDZActon.player_list, MsgDDZPlayer );\n        end\n    end\n    \n    local player = PlayerMgr:GetPlayer(self._ActionID);\n    \n    if player~=nil then\n        BaseService:SendToClient(player, \"DDZ_RA\", \"PB.MsgDDZActon\", MsgDDZActon);\n    end\n    \n    self:__RecordGameActionState( MsgDDZActon );\n    \n    MsgDDZActon.wik     = enum.ASK_DDZ_NULL;\n    self:BroadcastMsg( \"DDZ_RA\", \"PB.MsgDDZActon\", MsgDDZActon, self._ActionID );\nend\n\nfunction RoomDdz:UserOutCard( uid, msg_oc )\n\n    if uid~=self._ActionID or not self:__GetFsmState(enum.TDDZStateAction) then\n        return false;\n    end\n\n    local room_player = self.RoomPlayerData:Find(uid);\n    \n    if room_player==nil then\n        return false;\n    end\n\n    -- 检查用户是否可以出牌\n    if not self:__UserOutCardLimit( room_player, msg_oc.out_cards ) then\n        return false;\n    end\n    \n    self._ActionUserWik = enum.ASK_DDZ_NULL;\n    \n    -- 检查手中是否还有牌。\n    if room_player:GetHandCount()>0 then\n        self.Fsm:SwitchState(\"TDDZStateOutCard\");\n        return true;\n    end\n    \n    -- 手牌数为零，已出完牌。\n    self._ActionID = uid;\n    self:__CheckIsChunTian();       -- 检查春天\n    \n    self.Fsm:SwitchState(\"TDDZStateShowDown\");  -- 跳结算\nend\n\n\nfunction RoomDdz:UserPassOutCard( uid, is_auto )\n    if self._ActionID~=uid or (not self:__GetFsmState(enum.TDDZStateAction)) or \n        (not GetBit(self._ActionUserWik, enum.ASK_DDZ_CHUPAI)) then\n        return;\n    end\n    \n    local room_player = self.RoomPlayerData:Find(uid);\n    \n    if room_player==nil then\n        return false;\n    end\n    \n    -- 客户端自动过牌时，检查下玩家手里有没有大于上家的牌\n    --if is_auto~=nil and is_auto then\n    --    if self:__CheckCanOutCards(room_player) then\n    --        return;\n    --    end\n    --end\n    \n    -- 查找下个玩家出牌\n    self._ActionID  = self:GetNextUID(self._ActionID);\n    \n    if self._ActionID > 0 then\n        -- 刷新过牌的玩家\n        self:__ClearPlayerState(enum.STATE_DDZ_GUOPAI);\n        room_player:SetState( enum.STATE_DDZ_GUOPAI );\n        self._ActionUserWik = enum.ASK_DDZ_NULL;\n        \n        local MsgDDZActon = {  old_actionid = uid  };\n        self:BroadcastMsg( \"DDZ_PS\", \"PB.MsgDDZActon\", MsgDDZActon );\n        self:__RecordGameShowCardPass( uid );\n        self.Fsm:SwitchState(\"TDDZStateOutCard\");\n    else\n        nlwarning(\"self._ActionID==0\");\n    end\nend\n\nfunction RoomDdz:BroadcastGameInfo( )\n    for _,v in ipairs(self.SeatPlayers) do\n        if v~=0 then\n            local msg_gameinfo = {};\n            self:SendGameInfo( v, \"DDZ_GI\", msg_gameinfo );\n        end\n    end\nend\n\nfunction RoomDdz:RefreshRoomInfo( uid )\n    local msg_gameinfo = {};\n    self:SendGameInfo( uid, \"DDZ_BLC\", msg_gameinfo );\nend\n\nfunction RoomDdz:SendGameInfo( uid, msg_name, msg_ddz_room )\n    msg_ddz_room.room_id = self.PrvRoomID;\n    self:__FillRoomInfoMsg(msg_ddz_room, uid);\n    \n    local cur_state = self:__GetFsmState();\n    if  uid==self._ActionID and \n        ( cur_state==enum.TDDZStateAction or \n          cur_state==enum.TDDZStateOutCard or \n          cur_state==enum.TDDZStateRelieveRoom ) \n    then\n        msg_ddz_room.wik = self._ActionUserWik;\n    else\n        msg_ddz_room.wik = enum.ASK_DDZ_NULL;\n    end\n\n\tlocal player = PlayerMgr:GetPlayer(uid);\n    BaseService:SendToClient( player, msg_name, \"PB.MsgDDZRoom\", msg_ddz_room )\nend\n\n-- 游戏结算\nfunction RoomDdz:GameShowDown()\n    self._GameCount     = self._GameCount + 1;\n    self:__AddShowDownEvent(enum.EVENT_DDZDIFEN, 1);\n    \n    local room_player = self.RoomPlayerData:Find( self._DiZhuID );\n    if room_player==nil then\n        return;\n    end\n\n    -- 计算玩家的翻倍数,设置地主翻倍数.\n    local dizhu_jb = room_player:GetState( enum.STATE_DDZ_JIABEI );\n    local total_multi, jiabei_cnt = self:__CalcJiaBei( dizhu_jb );\n    room_player.Mulit = total_multi;\n    \n    -- 封顶加减分\n    if self:CheckRoomSpecialKind(enum.TSK_DDZ_BFD) then\n        self:__NormalCalcScore(total_multi);\n    elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_16) then\n        self:__CalcScore( total_multi, 16, jiabei_cnt );\n    elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_32) then\n        self:__CalcScore( total_multi, 32, jiabei_cnt );\n    elseif self:CheckRoomSpecialKind(enum.TSK_DDZ_64) then\n        self:__CalcScore( total_multi, 64, jiabei_cnt );\n    else\n        self:__NormalCalcScore(total_multi);\n    end\nend\n\nfunction RoomDdz:AfterShowDown()\n    local COST_CFG = StaticTableMgr:GetCreateCost( self.CreateInfo.consume_id );\n    \n    if COST_CFG~=nil then\n        if self._GameCount > COST_CFG.game_cnt then\n            self.IsGameStart = false;\n            self:__GameOverRecordLog();\n            self:Release();\n        end\n    end\nend\n\nfunction RoomDdz:BroadcastShowDownInfo()\n    local COST_CFG = StaticTableMgr:GetCreateCost( self.CreateInfo.consume_id );\n    if COST_CFG==nil then   return;     end\n\n    local MsgDDZRoomShowDown = {\n        room_id     = self.PrvRoomID,\n        room_state  = enum[self:__GetFsmState()],\n        state_time  = 0,\n        game_count  = self._GameCount,\n        time        = os.time(),\n        game_over   = self._GameCount>=COST_CFG.game_cnt,\n        event_count = {},\n        player_list = {}\n    };\n    \n    for eid,cnt in pairs(self.ShowDownEvent) do\n        local MsgDDZShowDownEvent = { event_id=eid, count=cnt };\n        tbinsert( MsgDDZRoomShowDown.event_count, MsgDDZShowDownEvent );\n    end\n    \n    for uid,room_player in pairs(self.RoomPlayerData.map) do\n    \n        local MsgDDZPlayer = {\n            player_base     = { UID = uid },\n            \n        };\n        \n        self:__FillPlayerRoomInfoMsg( uid, MsgDDZPlayer, uid );\n        tbinsert( MsgDDZRoomShowDown.player_list, MsgDDZPlayer );\n    end\n    \n    if MsgDDZRoomShowDown.game_over then\n        -- 游戏结算积分\n        --self:__AddPlayerIntegral(  );\n    end\n    \n    self:BroadcastMsg( \"DDZ_SD\", \"PB.MsgDDZRoomShowDown\", MsgDDZRoomShowDown );\n    self:__RecordGameShowDown( MsgDDZRoomShowDown );\nend\n\n\nfunction RoomDdz:RelieveRequestRoom( uid, is_relieve )\n    \n    if is_relieve then\n        self:__AddPlayerState( enum.STATE_DDZ_RELIEVE, uid );\n    else\n        self:__ClearPlayerState( enum.STATE_DDZ_RELIEVE );\n    end\n    \n    --local relv_cnt = self:__GetPlayerState( enum.STATE_DDZ_RELIEVE );\n    \n    \n    -- 用户取消解散房间\n    --local MsgInt = { value = uid };\n    --self:__ClearPlayerState( enum.STATE_DDZ_RELIEVE );\n    --self:BroadcastMsg( \"DDZ_NRE\", \"PB.MsgInt\", MsgInt );\n    \n    if true then\n        self:RelieveAutoRoom()\n        return;\n    end\n    \n    local MsgRoleStateCount = {};\n    self:__RefreshPlayerState( MsgRoleStateCount );\n    self:BroadcastMsg( \"DDZ_ORE\", \"PB.MsgRoleStateCount\", MsgRoleStateCount );\n    \nend\n\nfunction RoomDdz:RelieveAutoRoom( )\n    self._GameCount = 9999;\n    --self.Fsm:SwitchState(\"TDDZStateShowDown\");  -- 跳结算\n    self:BroadcastShowDownInfo();\n    self:AfterShowDown();\nend\n\n-- 普通算分\nfunction RoomDdz:__NormalCalcScore( total_multi )\n    for uid,room_player in pairs(self.RoomPlayerData.map) do\n        if uid==self._DiZhuID then\n            room_player:ChangeScore( total_multi, self._ActionID==self._DiZhuID )\n        else\n            room_player:ChangeScore( room_player.Mulit, self._ActionID~=self._DiZhuID )\n        end\n    end\nend\n\n-- 计算玩家的积分\nfunction RoomDdz:__CalcScore( total_multi, limit_score, jiabei_cnt )\n\n    if total_multi>limit_score then\n        for uid,room_player in pairs(self.RoomPlayerData.map) do\n        \n            --  两个都没有加倍或者两个都加倍，在封顶时输赢的分相同\n            if jiabei_cnt==0 or jiabei_cnt==2 then\n                if uid==self._DiZhuID then\n                    room_player:ChangeScore( limit_score, self._ActionID==self._DiZhuID );\n                else\n                    room_player:ChangeScore( limit_score//2, self._ActionID~=self._DiZhuID );\n                end\n            else\n                -- 农民中一个加倍一个不加倍，封顶时要按照比例进行加减分\n                if uid~=self._DiZhuID then\n                    if room_player:GetState(enum.STATE_DDZ_JIABEI) then\n                        if limit_score==16 then\n                            room_player:ChangeScore( 11, self._ActionID~=self._DiZhuID );\n                        elseif limit_score==32 then\n                            room_player:ChangeScore( 22, self._ActionID~=self._DiZhuID );\n                        elseif limit_score==64 then\n                            room_player:ChangeScore( 43, self._ActionID~=self._DiZhuID );\n                        end\n                    else\n                        if limit_score==16 then\n                            room_player:ChangeScore( 5, self._ActionID~=self._DiZhuID );\n                        elseif limit_score==32 then\n                            room_player:ChangeScore( 10, self._ActionID~=self._DiZhuID );\n                        elseif limit_score==64 then\n                            room_player:ChangeScore( 21, self._ActionID~=self._DiZhuID );\n                        end\n                    end\n                else\n                    room_player:ChangeScore( limit_score, self._ActionID==self._DiZhuID );\n                end\n            end\n        end\n    else\n        self:__NormalCalcScore( total_multi );\n    end\nend\n\n-- 计算玩家加倍\nfunction RoomDdz:__CalcJiaBei( is_dizhu )\n    local total_multi   = 0;\n    local jiabei_cnt    = 0;\n    local add_times     = self:__GetSpecialCfg(\"add_times\");\n    \n    for uid,room_player in pairs(self.RoomPlayerData.map) do\n        \n        if uid~=self._DiZhuID then\n        \n            -- 如果没有加倍玩法，直接设置房间的加倍数\n            if not self:CheckRoomSpecialKind(enum.TSK_DDZ_JIABEI) then\n                room_player.Mulit = self._Multiple;\n                total_multi = total_multi + room_player.Mulit;\n            else\n                if room_player:GetState(enum.STATE_DDZ_JIABEI) then\n                    if is_dizhu then\n                        room_player.Mulit = self._Multiple * add_times * 2;\n                    else\n                        room_player.Mulit = self._Multiple * add_times;\n                    end\n                    \n                    jiabei_cnt = jiabei_cnt + 1;\n                else\n                    if is_dizhu then\n                        room_player.Mulit = self._Multiple * add_times;\n                    else\n                        room_player.Mulit = self._Multiple;\n                    end\n                end\n                \n                total_multi = total_multi + room_player.Mulit;\n            end\n        end\n    end\n    \n    return total_multi, jiabei_cnt;\nend\n\n-- 战绩保存\nfunction RoomDdz:__GameOverRecordLog()\n    nlinfo(\"=====     GameOverRecordLog \");\nend\n\nfunction RoomDdz:__FillRoomInfoMsg( msg_ddz_room, current_uid )\n\n    msg_ddz_room.room_id        = self.PrvRoomID;\n\n\tmsg_ddz_room.room_state     = self:__GetFsmState();\n    msg_ddz_room.state_time     = 0;                    -- 当前房间状态的运行时间\n    msg_ddz_room.action_id      = self._ActionID;\n    msg_ddz_room.game_count     = self._GameCount;\n    msg_ddz_room.multiple       = self._Multiple;       -- 房间的翻倍数\n\n\n    msg_ddz_room.bottom_cards   = self._CardsBottom;    -- 底牌\n\n\n    -- 上把牌信息\n    if self._LastOutCardData.UID>0 then\n        \n        msg_ddz_room.last_outcard = {\n            old_actionid    = self._LastOutCardData.UID,\n            out_type        = self._LastOutCardData.Type,\n            out_cards       = self._LastOutCardData.Cards\n        };\n    end\n    \n    -- 创建房间的信息\n    msg_ddz_room.private_room = self.CreateInfo;\n\n    for _,v in ipairs(self.SeatPlayers) do\n        if v>0 then\n            self:__FillPlayerBaseInfoMsg( v, msg_ddz_room, current_uid );\n        end\n    end\nend\n\n\nfunction RoomDdz:__FillPlayerBaseInfoMsg( uid, msg_ddz_room, current_uid )\n\n    local room_player = {};\n    \n    local player = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n    \n        room_player.player_base = {\n            UID         = uid,\n            Nickname    = player.PlayerDataHelper.f_nickname;\n            Portrait    = player.PlayerDataHelper.f_portrait;\n        }\n    end\n    \n    \n    \n    self:__FillPlayerRoomInfoMsg(uid, room_player, current_uid )\n    \n    if msg_ddz_room.player_list==nil then\n        msg_ddz_room.player_list = {};\n    end\n    \n    tbinsert( msg_ddz_room.player_list, room_player );\n  \nend\n\nfunction RoomDdz:__FillPlayerRoomInfoMsg( uid, msg_room_player, current_uid )\n    \n    local room_player = self.RoomPlayerData:Find(uid);\n    \n    if room_player~=nil then\n    \n        msg_room_player.state           = room_player:GetState();           -- 玩家的当前状态\n        msg_room_player.hand_count      = room_player:GetHandCount();       -- 玩家手中的牌数\n        msg_room_player.seats           = self:GetPlayerSeatIdx(uid);       -- 玩家的座位\n        msg_room_player.score           = room_player:GetScore();           -- 玩家当前的积分\n        msg_room_player.multiple        = room_player.Multi;\n        msg_room_player.show_down_score = room_player:GetScore() - room_player.StartScore;  -- 填充玩家的输赢积分\n        msg_room_player.qingdizhu_value = room_player.QiangDiZhu;\n\n        if self:__GetFsmState(enum.TDDZStateQiangDiZhu) and room_player:GetState(enum.STATE_DDZ_QIANGDIZHU) then\n            msg_room_player.qingdizhu_wiki = self._QiangDiZhuWiki;\n        end\n        \n        if uid==current_uid or room_player:GetState(enum.STATE_DDZ_MINGPAI) then\n            msg_room_player.card_list   = room_player.HandCards;\n        end\n    end\nend\n\nfunction RoomDdz:__CheckCanOutCards( room_player )\n    --self._CanOutCard    = {};\n\n    -- 上次出牌的玩家也是自己，或刚开局。\n    if  self._ActionID==self._LastOutCardData.UID or self._LastOutCardData:GetCardCount()==0  then\n        return true;\n    end\n\n    return DdzCardtypes:CheckCanOutCards( self._LastOutCardData, room_player.HandCards );\nend\n\n-- 检查除了uid外，有没有玩家抢过地主\nfunction RoomDdz:__CheckQiangDiDiZhu(uid)\n    for k,v in pairs(self.RoomPlayerData.map) do\n        if k~=uid and v.QiangDiZhu==enum.DDZ_QDZ_QIANGDIZHU then\n            return true;\n        end\n    end\n    return false;\nend\n\nfunction RoomDdz:__RefreshPlayerQDZState( uid )\n    self.RoomPlayerData:ForEach( function(k,v)\n        if k==uid then\n            v:SetState( enum.STATE_DDZ_QIANGDIZHU );\n        else\n            v:ClearState( enum.STATE_DDZ_QIANGDIZHU );\n        end\n    end )\nend\n\n-- 玩家状态数据\nfunction RoomDdz:__RefreshPlayerState( MsgRoleStateCount )\n    self.RoomPlayerData:ForEach( function(k,v)\n        local MsgRoleState = { role_id=k, state=v:GetState() };\n        tbinsert( MsgRoleStateCount, MsgRoleState );\n    end )\nend\n\n-- 叫地主的玩家选择不抢地主后，选择最后一次抢地主的玩家做地主\nfunction RoomDdz:__SelectDZ(uid)\n    for i=1,i<4 do\n        local next_uid = self:GetNextUID(uid);\n        \n        if next_uid~=self._ActionID then\n            local room_player = self:GetRoomPlayer(next_uid);\n            if room_player==nil then  return 0;  end\n            \n            if room_player.QiangDiZhu == enum.DDZ_QDZ_QIANGDIZHU then\n                return next_uid;\n            end\n        end\n        \n        uid = next_uid;\n    end\n    \n    return 0;\nend\n\n-- 获取当前活动玩家操作权限\nfunction RoomDdz:__GetActionWik()\n    self._CanOutCard        = {};\n    \n    local WIK               = enum.ASK_DDZ_NULL;\n    local room_player       = self.RoomPlayerData:Find(self._ActionID);\n    \n    if room_player==nil then\n        return WIK;\n    end\n    \n    -- 地主第一次出牌，没有选择明牌时可以有选择明牌的选项\n    if  self:CheckRoomSpecialKind(enum.TSK_DDZ_MINGPAI) and\n        self._ActionID==self._DiZhuID and\n        room_player:GetState(enum.STATE_DDZ_MINGPAI) and\n        room_player:GetHandCount()==self.CFG_HANDCOUNT_MAX\n    then\n        WIK = SetBit( WIK, enum.ASK_DDZ_DIZHU_MINGPAI );\n    end\n    \n    local is_can_out = self:__CheckCanOutCards(room_player);\n    \n    if is_can_out then\n        if self._ActionID==self._LastOutCardData.UID or self._LastOutCardData:GetCardCount()==0 then\n            WIK = SetBits( WIK, { enum.ASK_DDZ_TISHI, enum.ASK_DDZ_CHUPAI } );\n        else\n            WIK = SetBits( WIK, { enum.ASK_DDZ_TISHI, enum.ASK_DDZ_CHUPAI, enum.ASK_DDZ_BUCHU } );\n        end\n    else\n        WIK = SetBit( WIK, enum.ASK_DDZ_BUCHU );\n    end\n    \n    return WIK;\nend\n\n-- 检查用户可否出牌\nfunction RoomDdz:__UserOutCardLimit( room_player, out_cards )\n    \n    if not self:__GetFsmState(enum.TDDZStateAction) then\n        return false;\n    end\n    \n    -- 排序要出的牌,分析用。\n    SortPokerLogicValue(out_cards);\n    \n    -- 获取牌型\n    local card_type, comp_val = DdzCardtypes:GetCardType( out_cards, self._LastOutCardData.Type );\n    if card_type == enum.CT_DDZ_ERROR then\n        return false;\n    end\n    \n    -- \n    local temp_data     = self._TempOutCardData;\n    temp_data:SetCards(out_cards);\n    temp_data.Type      = card_type;\n    temp_data.UID       = self._ActionID;\n    temp_data.CompVal   = comp_val;\n    \n    -- 比较大小\n    if not DdzCardtypes:CompareCards( temp_data, self._LastOutCardData ) then\n        return false;\n    end\n\n    -- 检查手牌中是否有这些要出的牌，如果可以出牌，从手牌中删除玩家需要出的牌。\n    if not room_player:RemoveCards(temp_data.Cards) then\n        self:RefreshRoomInfo(self._ActionID);\n        return false;\n    end\n    \n    self._ActionID  = self:GetNextUID( self._ActionID );\n    self._LastOutCardData:Copy( temp_data );\n    \n    local MsgDDZUserOutCard = {\n        old_actionid    = temp_data.UID,\n        out_type        = card_type,\n        hand_count      = room_player:GetCardCount(),\n        hand_cards      = room_player.HandCards,\n        out_cards       = out_cards\n    }\n    \n    -- 出炸弹时需要瞬间翻倍，同步到客户端\n    if card_type==enum.CT_DDZ_ZHADAN_SIZHANG or card_type==enum.CT_DDZ_HUOJIAN then\n        local multi_boom = self:__GetSpecialCfg(\"multi_boom\");\n        if multi_boom~=nil then\n            self._Multiple = self._Multiple * multi_boom;\n            self:__AddShowDownEvent( enum.EVENT_ZHADAN, 1 );\n            MsgDDZUserOutCard.multiple = self._Multiple;\n        end\n    end\n    \n    -- 广播出牌信息\n    self:BroadcastMsg( \"DDZ_OC\", \"PB.MsgDDZUserOutCard\", MsgDDZUserOutCard );\n    \n    -- 添加玩家出牌次数，地主被春天时使用\n    room_player:AddOutCount();\n    \n    -- 记录出的牌\n    self:__RecordGameOutCard( MsgDDZUserOutCard );\n    \n    -- 清除上把的过牌状态\n    self:__ClearPlayerState(enum.STATE_DDZ_GUOPAI);\n    return true;\nend\n\n-- 添加玩家状态\nfunction RoomDdz:__AddPlayerState( state, uid )\n    for id,v in pairs(self.RoomPlayerData.map) do\n        if not (uid~=nil and id~=uid) then\n            v:SetState( state );\n        end\n    end\nend\n\n-- DelRoleState\nfunction RoomDdz:__ClearPlayerState( state, uid )\n    for id,v in pairs(self.RoomPlayerData.map) do\n        if not (uid~=nil and id~=uid) then\n            v:ClearState( state );\n        end\n    end\nend\n\nfunction RoomDdz:__GetFsmState( state )\n    if state~=nil then\n        if enum[self.Fsm:GetState()]==state then\n            return true;\n        end\n        return false;\n    else\n        return enum[self.Fsm:GetState()];\n    end\nend\n\nfunction RoomDdz:__CheckIsChunTian()\n    local is_ct = false;\n    \n    for uid,v in pairs(self.RoomPlayerData.map) do\n    \n        -- 检查地主有没有被春天\n        if uid==self._DiZhuID and self._DiZhuID~=self._ActionID and v:GetOutCount()==1 then\n            is_ct = true;\n            break;\n        end\n        \n        -- 地主获胜需要检查两个农民有没有被春天\n        if self._ActionID==self._DiZhuID and uid~=self._ActionID then\n        \n            if v:GetCardCount()==self.CFG_HAND_COUNT then\n                is_ct = true;\n            else\n                is_ct = false;\n                break;\n            end\n        end\n    end\n    \n    if is_ct then\n        local multi_ct = self:__GetSpecialCfg(\"multi_ct\");\n        if multi_ct~=nil then\n            self._Multiple = self._Multiple * multi_ct;\n            self:__AddShowDownEvent(enum.EVENT_CHUNTIAN, 1);\n        end\n    end\nend\n\n\n-- --------------------------  战绩回放  Start\n-- 记录游戏开始\nfunction RoomDdz:__RecordGameStart()\n\n    self._RecordNodeList = {\n        cmd_id      = enum.RC_ACTION_START_GAME,\n        \n        -- 房间数据\n        room_data   = { special_kind = self.CreateInfo.special_kind,\n                        banker       = self.CreateInfo.consume_id,\n                        bottom_cards = self._CardsBottom,\n                        game_count   = self._GameCount,\n                        score        = self._Multiple },\n                        \n        -- 玩家信息\n        role_data   = {},\n        next_node   = {}\n    };\n    \n    for i,uid in ipairs(self.SeatPlayers) do\n        local MsgRecordRoleInfo = { id = uid,  seat = i };\n        \n        local player = PlayerMgr:GetPlayer(uid);\n        if player~=nil then\n            MsgRecordRoleInfo.usename = player.PlayerDataHelper.f_username;\n            MsgRecordRoleInfo.nick_name = player.PlayerDataHelper.f_nickname;\n        end\n        \n        local room_player = self.RoomPlayerData:Find(uid);\n        if room_player~=nil then\n            MsgRecordRoleInfo.score = room_player:GetScore();\n            MsgRecordRoleInfo.team_type = room_player:GetState();\n            MsgRecordRoleInfo.hand_card = room_player.HandCards;\n        end\n        \n        tbinsert( self._RecordNodeList.role_data, MsgRecordRoleInfo );\n    end\nend\n\nfunction RoomDdz:__RecordGameOutCard( out_msg )\n    local MsgRecordNodeList = {\n        cmd_id      = enum.RC_ACTION_OUT_CARD,\n        target_id   = out_msg.old_actionid,\n        card_index  = out_msg.out_type,         -- 玩家出牌类型\n        action_id   = out_msg.hand_count,\n        card_value  = out_msg.out_cards,        -- 出牌列表\n        node_size   = out_msg.multiple,         -- 房间倍数\n        next_node   = {}\n    };\n\n    tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList );\nend\n\nfunction RoomDdz:__RecordGameActionState( MsgDDZActon )\n    local MsgRecordNodeList = {\n        cmd_id      = enum.RC_ACTION_OPERATE_RESULT,\n        action_id   = MsgDDZActon.new_actionid,\n        showdown_list = {},\n        next_node   = {}\n    };\n\n    for _,MsgDDZPlayer in pairs(MsgDDZActon.player_list) do\n        \n        local MsgRecordShowDown = {\n            id      = MsgDDZPlayer.seats,\n            score   = MsgDDZPlayer.score,\n            param1  = MsgDDZPlayer.hand_count,\n            param2  = MsgDDZPlayer.state\n        };\n        tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown );\n    end\n\n    tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList );\nend\n\nfunction RoomDdz:__RecordGameShowCardPass( uid )\n    local MsgRecordNodeList = {\n        cmd_id      = enum.RC_ACTION_OPERATE_CHOICE,\n        action_id   = uid,\n        next_node   = {}\n    };\n    tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList );\nend\n\nfunction RoomDdz:__RecordGameShowDown( MsgDDZRoomShowDown )\n    \n    local MsgRecordNodeList = {\n        cmd_id      = enum.RC_ACTION_SHOWDOWN,\n        showdown_list = {},\n        next_node   = {}\n    };\n    \n    local MsgRecordShowDown = { event = MsgDDZRoomShowDown.event_count };\n    tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown );\n\n\n    for _,MsgDDZPlayer in pairs(MsgDDZRoomShowDown.player_list) do\n        \n        local MsgRecordShowDown = {\n            id      = MsgDDZPlayer.seats,\n            play_id = MsgDDZPlayer.player_base.UID,\n            money   = MsgDDZPlayer.show_down_score,\n            score   = MsgDDZPlayer.score,\n            hucard  = MsgDDZPlayer.multiple,\n            param1  = MsgDDZPlayer.hand_count,\n            param2  = MsgDDZPlayer.state\n        };\n        tbinsert( MsgRecordNodeList.showdown_list, MsgRecordShowDown );\n    end\n\n    tbinsert( self._RecordNodeList.next_node, MsgRecordNodeList );\nend\n\nfunction RoomDdz:__RecordGameShowDownEvent( MsgRecordShowDown, MsgDDZRoomShowDown )\n    for _,evt in pairs(MsgDDZRoomShowDown.event_count) do\n        local MsgRecordEvent = { event_id = evt.event_id, count = evt.count };\n        tbinsert( MsgRecordShowDown.event, MsgRecordEvent );\n    end\n    -- MsgRecordShowDown.event = MsgDDZRoomShowDown.event_count;\nend\n\n-- --------------------------  战绩回放  End\n\n--释放函数\nfunction RoomDdz:Release()\n    self:BaseRelease();\nend\n\n\nreturn RoomDdz;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Msg/MsgLogin.lua",
    "content": "MsgLogin = {}\n\nfunction MsgLogin:Init()\n\tself._EventRegister = EventRegister.new();\n    self._EventRegister:RegisterEvent( \"SyncData\",          self, self.cbSyncData );\n    self._EventRegister:RegisterEvent( \"ClientOffline\",     self, self.cbClientOffline );\n    \nend\n\nfunction MsgLogin:cbSyncData( schid, msg_sdata_1 )\n\n    local uid           = msg_sdata_1:rint64();\n    local fesid         = msg_sdata_1:rint32();\n    \n    local player    = PlayerMgr:GetPlayer(uid);\n    \n    if player == nil then\n        player = PlayerMgr:LoadDBPlayer(uid);\n    end\n    \n    if player~=nil then\n        \n        player.ConFES = fesid;\n        PrintTable(player);\n        \n        -- 通知FES保存玩家在哪个PLS\n        msg_sdata_1:invert();\n        BaseService:Send( fesid, msg_sdata_1);\n        \n        -- 发送玩家数据给客户端\n        BaseService:SendToClient( player, \"SyncPlayerInfo\",\n                                  \"PB.MsgPlayerInfo\", player.PlayerDataHelper:ToMsg() )\n    end\n\t\nend\n\nfunction MsgLogin:cbClientOffline( fesid, msgin )\n\n    local uid       = msgin:rint();\n    local player    = PlayerMgr:GetPlayer(uid);\n\n    if player~=nil then\n        player:Offline();\n\t    nlinfo(\"MsgLogin:cbClientOffline UID:\"..uid);\n    end\nend\n\n--释放函数\nfunction MsgLogin:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn MsgLogin;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Msg/MsgRoom.lua",
    "content": "MsgRoom = {}\n\n-- 构造函数;\nfunction MsgRoom:Init()\n\tself._EventRegister = EventRegister.new();\n\n    self._EventRegister:RegisterEvent( \"ER\",                self, self.cbEnterRoom );\n    self._EventRegister:RegisterEvent( \"LR\",                self, self.cbLeaveRoom );\n    self._EventRegister:RegisterEvent( \"RRM\",               self, self.cbReleasePrvRoom );\n    self._EventRegister:RegisterEvent( \"DDZ_RE\",            self, self.cbDDZReliveRoom );\n    \n    \n    self._EventRegister:RegisterEvent( \"CPRM=>PLS\",         self, self.cbCreatePrivateRoom );\n    self._EventRegister:RegisterEvent( \"EPRM=>PLS\",         self, self.cbEnterPrivateRoom );\n\nend\n\nfunction MsgRoom:cbEnterRoom( fes_sid, msg_enter_room )\n\n\n    nlinfo(\"MsgRoom:cbEnterRoom\");\n\t\nend\n\nfunction MsgRoom:cbLeaveRoom( fes_sid, msgin )\n\n    local uid       = msgin:rint64();\n    local player    = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n        local room = RoomMgr:GetRoom(player.RoomID);\n        \n        if room~=nil then\n            room:LeaveRoom(uid);\n        end\n    end\n    nlinfo(\"MsgRoom:cbLeaveRoom\");\n\t\nend\n\nfunction MsgRoom:cbCreatePrivateRoom( sch_sid, msgin )\n    local uid           = msgin:rint();\n    local prv_room_id   = msgin:rint();\n    local pls_sid       = msgin:rint();\n    local msg_cpr       = msgin:rtable();\n--    local room_type     = msgin:rstring();\n\n    nlwarning(\"MsgRoom:cbCreatePrivateRoom\");\n    \n    nlinfo(uid);\n    nlinfo(prv_room_id);\n    nlinfo(pls_sid);\n    PrintTable(msg_cpr);\n\t\n    RoomMgr:CreatePrivateRoom(uid, prv_room_id, msg_cpr);\nend\n\nfunction MsgRoom:cbEnterPrivateRoom( sch_sid, msgin )\n    local uid           = msgin:rint();\n    local pls_sid       = msgin:rint();\n    local prv_room_id   = msgin:rint();\n    local room_type     = msgin:rstring();\n    \n    nlinfo(\"MsgRoom:cbEnterPrivateRoom\");\n    \n    nlinfo(uid);\n    nlinfo(prv_room_id);\n    nlinfo(pls_sid);\n    nlinfo(room_type);\n    \n    if GetServiceID()~=pls_sid then\n        nlwarning(\"GetServiceID()~=pls_sid\");\n        \n    else\n        RoomMgr:EnterPrivateRoom(uid, prv_room_id, room_type);\n    end\nend\n\nfunction MsgRoom:cbReleasePrvRoom( fes_sid, msgin )\n\n    local uid       = msgin:rint64();\n    local player    = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n        local room = RoomMgr:GetRoom(player.RoomID);\n        \n        if room~=nil then\n            room:RelieveForceRoom(uid);\n        end\n    end\nend\n\nfunction MsgRoom:cbDDZReliveRoom( fes_sid, msgin )\n\n    local uid       = msgin:rint64();\n    local player    = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n        local room = RoomMgr:GetRoom(player.RoomID);\n        \n        if room~=nil then\n            \n            local msg_bool = msgin:rpb(\"PB.MsgBool\");\n            room:RelieveRequestRoom(uid, msg_bool.value);\n        end\n    end\nend\n\n\n\n--释放函数\nfunction MsgRoom:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn MsgRoom;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Player/PlayerDataHelper.lua",
    "content": "local PlayerDataHelper = class(\"PlayerDataHelper\")\n\n-- 构造函数;\nfunction PlayerDataHelper:ctor()\n\n    self.f_uid          = nil;\n    self.f_username     = nil;\n    self.f_nickname     = nil;\n    self.f_portrait     = nil;\n    self.f_money        = nil;\n    self.f_rmb          = nil;\n    self.f_main         = nil;\n    self.f_flag_bit     = nil;\nend\n\nfunction PlayerDataHelper:ToMsg()\n    \n    local MsgPlayerInfo = {};\n    MsgPlayerInfo[\"UID\"]        = self.f_uid;\n    MsgPlayerInfo[\"Nickname\"]   = self.f_nickname;\n    MsgPlayerInfo[\"Portrait\"]   = self.f_portrait;\n    MsgPlayerInfo[\"Money\"]      = self.f_money;\n    MsgPlayerInfo[\"RMB\"]        = self.f_rmb;\n    MsgPlayerInfo[\"Main\"]       = self.f_main;\n    MsgPlayerInfo[\"FlagBit\"]    = self.f_flag_bit;\n    \n    return MsgPlayerInfo;\nend\n\nreturn PlayerDataHelper;"
  },
  {
    "path": "code/EVA/server/script/_PLS/Player/PlayerHelper.lua",
    "content": "local PlayerHelper = class(\"PlayerHelper\")\n\n-- 构造函数;\nfunction PlayerHelper:ctor()\n    \n    self.PlayerDataHelper      = nil;\n\n\n    self.UID                    = 0;\n    self.ConFES                 = nil;\n     \n    \n    self.IsRobot                = false;\n    \n    self.RoomID                 = 0;\n    self.JoinRoomTime           = 0;\n\n    self.OfflineTime            = 0;\n    self.LogoutTime             = nil;\n    self.PlayerState            = nil;\n        \n    self.LastUpdateTime         = TimerMgr:GetTime();\n    self._TimerHandle           = TimerMgr:AddTimer( 30000, self, self.TickUpdate );\nend\n\nfunction PlayerHelper:TickUpdate()\n\n    local curr_time     = TimerMgr:GetTime();\n\n    if curr_time - self.LastUpdateTime > 7*24*60*60*1000 then\n        self._TimerHandle = nil;    -- Release 时不再删除定时器\n        PlayerMgr:RemovePlayer(self.UID);\n    else\n        self._TimerHandle = TimerMgr:AddTimer( 10*60*1000, self, self.TickUpdate );\n    end\nend\n\n-- 从缓存中移除玩家,由PlayerMgr调用。\nfunction PlayerHelper:Release()\n\n    local msg = CMessage(\"RemovePlayer\");\n    msg:wint(self.UID);\n    BaseService:Broadcast(\"SCH\", msg);\n\n    if self._TimerHandle ~= nil then\n        TimerMgr:RemoveTimer(self._TimerHandle);\n    end\nend\n\nfunction PlayerHelper:Offline()\n    self.OfflineTime            = TimerMgr:GetTime();\n    self.ConFES                 = nil;\n    \n    if self.RoomID>0 then\n        local room = RoomMgr:GetRoom(self.RoomID);\n        \n\t\tif room~=nil then\n\t\t\troom:PlayerOffline( self.UID );\n\t\telse\n\t\t\tnlwarning(\"room==nil\");\n\t\tend\n    end\n\n    nlwarning(\"Offline================\");\nend\nfunction PlayerHelper:Online()\n    self.OfflineTime            = 0;\nend\n\n\n\nreturn PlayerHelper;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Player/PlayerMgr.lua",
    "content": "PlayerMgr = {}\n\n-- 初始化函数\nfunction PlayerMgr:Init()\n\tself.playerMap      = Map:new();\n\n    self.RobotPool      = {};\n    self.RobotIdx       = 1;\n    self.RobotMax       = 500;\n    self.RobotIDStart   = 1002;\n    self.RobotIDEnd     = 1003;\n    \n    for id=self.RobotIDStart,self.RobotIDEnd do\n    \n        local player_helper = self:LoadDBPlayer( id );\n        \n        \n    end\n    \n    \nend\n\n\nfunction PlayerMgr:Count()\n    return self.playerMap:Count();\nend\n\nfunction PlayerMgr:GetPlayer( _uid )\n\n    local player = self.playerMap:Find(_uid);\n    \n    if player~=nil then\n        player.LastUpdateTime = TimerMgr:GetTime();\n    end\n    \n    return player\nend\n\nfunction PlayerMgr:LoadDBPlayer( _uid )\n    \n    local tb_playerinfo = DBMgr:LoadPlayerInfo(_uid);\n    \n    if tb_playerinfo==nil then\n        if DBMgr:CreatePlayer(_uid)==true then\n            tb_playerinfo = DBMgr:LoadPlayerInfo(_uid);\n        end\n    end\n    \n    if tb_playerinfo~=nil then\n        local player_helper    = PlayerHelper:new();\n        \n        player_helper.UID               = _uid;\n        player_helper.PlayerDataHelper  = tb_playerinfo;\n        \n        self.playerMap:Insert(_uid, player_helper);\n        return player_helper;\n    end\n    \n    return nil;\nend\n\n-- 从缓存中移除玩家\nfunction PlayerMgr:RemovePlayer( _uid )\n    local player = self.playerMap:Find(_uid);\n    \n    if player~=nil then\n        if player.RoomID > 0 then\n            player:Release();\n            self.playerMap:Remove(_uid);\n        end\n    end\nend\n\nfunction PlayerMgr:MakeRobot()\n    \n    \n    \n    return nil;\nend\n\nreturn PlayerMgr\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/PlayerLogicService.lua",
    "content": "PlayerLogicService = {}\n\nfunction PlayerLogicService:Init()\n\n    -- 注册其它服务器启动的回调\n    Net.SetConnectionCallback(\"SCH\");\n    Net.SetDisConnectionCallback(\"SCH\");\n    \n    \n\tself._EventRegister = EventRegister.new();\n    self._EventRegister:RegisterEvent( \"SCHCon\",            self, self.SCHConnection );\n\tself._EventRegister:RegisterEvent( \"SCHDis\",            self, self.SCHDisConnection );\n    \n\n    self.TimerID    = 0;\n    self.sch_sid    = 0;\nend\n\nfunction PlayerLogicService:UpdatePLSInfo( service_id )\n    \n    local MsgServiceInfo = {};\n    MsgServiceInfo.MaxPlayer    = PlayerConfig.MaxPlayer;\n    MsgServiceInfo.CurrPlayer   = PlayerMgr:Count();\n    MsgServiceInfo.ServiceID    = Net.GetServiceID();\n    MsgServiceInfo.ServiceName  = Net.GetServiceName();\n    MsgServiceInfo.RoomList     = {};\n    \n    for k, v in pairs(PLSConfig.GameConfig) do  \n\n        local MsgRoomType   = {};\n        MsgRoomType.Type    = k;\n        MsgRoomType.Max     = v.Max;\n        MsgRoomType.Curr    = PlayerMgr:Count();\n        \n        table.insert( MsgServiceInfo.RoomList, MsgRoomType );\n    end\n    \n    BaseService:Send( service_id, \"SvrInfo\", \"PB.MsgServiceInfo\", MsgServiceInfo )\n\nend\n\n\nfunction PlayerLogicService:SCHConnection( service_id, service_name )\n\tnlinfo(\"PlayerLogicService:SCHConnection:\"..service_name..\" sid:\"..service_id);\n    \n    self.sch_sid = service_id;\n    self:UpdatePLSInfo(service_id);\n    self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer);\nend\n\nfunction PlayerLogicService:SCHDisConnection( service_id, service_name )\n\tnlinfo(\"PlayerLogicService:SCHDisConnection\"..service_name..\" sid:\"..service_id);\n    \n    self.sch_sid = nil;\n    TimerMgr:RemoveTimer(self.TimerID);\n    \nend\n\nfunction PlayerLogicService:UpdatePLSInfoTimer()\n    self:UpdatePLSInfo(self.sch_sid);\n    self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer);\nend\n\n--\t释放函数\nfunction PlayerLogicService:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\nreturn PlayerLogicService\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Room/RoomBase.lua",
    "content": "local RoomBase = class(\"RoomBase\")\n\n-- 构造函数;\nfunction RoomBase:ctor()\n    self.RoomID                 = RoomMgr:GenerateRoomID();\n    self.PrvRoomID              = 0;\n    self.RoomType               = \"\";\n\n    self.IsGameStart            = false;\n    self.CreatorID              = 0;                -- 房间归属\n    self.CreateInfo             = nil;              -- 创建房间选项信息。\n    self.RoomPlayerData         = Map:new();\n    self.SeatPlayers            = {};\n    self.ViewPlayers            = {};\n    self.ShowDownEvent          = {};\n    \n    self._TimerHandle           = 0;\n    self._TimerTick             = 1000;\n    self._CreateTime            = os.time();\n    \n    self.CFG_RM_MIN             = 9999;\n    self.CFG_LIMIT_TIME         = 28800;\nend\n\n\nfunction RoomBase:PrintInfo()\n    nlinfo(\"============== RoomID:\"..self.RoomID .. \"  PrvID:\"..self.PrvRoomID..\"  Creator:\"..self.CreatorID);\n    nlinfo(\"==>SeatPlayers:\")\n    PrintTable(self.SeatPlayers);\n    nlinfo(\"==>RoomPlayers:\")\n    PrintTable(self.RoomPlayerData.map);\nend\n\nfunction RoomBase:Init( room_type, update_tick )\n    \nend\n\nfunction RoomBase:BaseInit( room_type, update_tick )\n\n    if update_tick~=nil then\n        self._TimerTick = update_tick;\n    end\n    \n    local ROOM_CFG = StaticTableMgr:GetRoomConfig(room_type);\n    \n    if ROOM_CFG~=nil then\n        \n        self.RoomType               = room_type;\n        self.CFG_RM_MIN             = ROOM_CFG.room_min;\n        self.CFG_LIMIT_TIME         = ROOM_CFG.room_time;\n        \n        for i=1,ROOM_CFG.room_max do\n            table.insert(self.SeatPlayers, 0);\n        end\n        \n        self._TimerHandle = TimerMgr:AddTimer(self._TimerTick, self, self.BaseTickUpdate);\n        self:Init();\n    end\nend\n\nfunction RoomBase:TickUpdate()\n    nlinfo(\"RoomBase:TickUpdate  \"..self._TimerHandle);\nend\n\n\nfunction RoomBase:PlayerOffline(uid)\n    if not self.IsGameStart then\n        self:LeaveRoom(uid);\n    end\nend\n\nfunction RoomBase:BaseTickUpdate()\n    \n    if os.time()-self._CreateTime > self.CFG_LIMIT_TIME then\n        RoomMgr:ReleaseRoom( self.RoomID );\n        return;\n    end\n    \n    if self._TimerHandle > 0 then\n        -- BaseInit 之后才继续timer\n        self._TimerHandle = TimerMgr:AddTimer(self._TimerTick, self, self.BaseTickUpdate);\n    end\n    \n    self:TickUpdate();\nend\n\n\n-- 玩家加入房间\nfunction RoomBase:BaseJoinRoom( player )\n    player.RoomID   = self.RoomID;\n    self:__AddRoomPlayer(player.UID);\nend\n\n-- 玩家离开房间，子类可重写\nfunction RoomBase:LeaveRoom( uid )\n    self:BrLeaveRoom(uid);\n    \n    if not self.IsGameStart and uid~=self.CreatorID then\n        self:ReleaseRoomPlayer(uid);\n    end\nend\n\n-- 广播玩家离开房间\nfunction RoomBase:BrLeaveRoom( uid )\n    local msg_int = { value = uid };\n    self:BroadcastMsg( \"LR\", \"PB.MsgInt\", msg_int );\nend\n\nfunction RoomBase:ReleaseRoomPlayer( uid )\n    \n    -- 通知其它服务器离开房间\n    self:__NotifyOtherServiceLeave(uid);\n    \n    self:__RemoveSeatPlayer(uid);\n\n    local player = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n        player.RoomID = 0;\n    end\n    \n    self.RoomPlayerData:Remove(uid);\n    \n    if self:GetRoomPlayerNum()==0 then\n        RoomMgr:ReleaseRoom( self.RoomID );\n    end\nend\n\nfunction RoomBase:IsRoomPlayer( uid )\n    for _,v in ipairs(self.SeatPlayers) do\n        if v==uid then\n            return true;\n        end\n    end\n    return false;\nend\n\nfunction RoomBase:GetRoomPlayer( uid )\n    for _,v in ipairs(self.SeatPlayers) do\n        if v==uid then\n            return PlayerMgr:GetPlayer(uid);\n        end\n    end\n    return nil;\nend\n\nfunction RoomBase:GetPlayerSeatIdx( uid )\n    for k,v in ipairs(self.SeatPlayers) do\n        if v==uid then\n            return k;\n        end\n    end\n    return 0;\nend\n\nfunction RoomBase:GetRoomPlayerNum()\n    local count = 0;\n    for _,v in ipairs(self.SeatPlayers) do\n        if v~=0 then\n            count = count + 1;\n        end\n    end\n    return count;\nend\n\nfunction RoomBase:GetNextUID( curr_id )\n\n    local curr_seat = self:GetPlayerSeatIdx(curr_id);\n    \n    if curr_seat>0 then\n\n        -- 当前位置向后找\n        for i=curr_seat+1, #self.SeatPlayers do\n            local next_uid = self.SeatPlayers[i];\n            if next_uid>0 then\n                return next_uid;\n            end\n        end\n\n        -- 后面没有了，从头开始找\n        for i=1, #self.SeatPlayers do\n            local next_uid = self.SeatPlayers[i];\n            if next_uid>0 then\n                return next_uid;\n            end\n        end\n    end\n    \n    return 0;\nend\n\nfunction RoomBase:RelieveRequestRoom( uid, is_relieve )\n    \nend\n\nfunction RoomBase:RelieveAutoRoom()\n    \nend\n\nfunction RoomBase:RelieveForceRoom( uid )\n    if self.CreatorID == uid then\n        RoomMgr:ReleaseRoom( self.RoomID )\n    end\nend\n\n-- 新房间特殊玩法都用此方法判断\nfunction RoomBase:CheckRoomSpecialKind( special_kind )\n    if self.CreateInfo~=nil and self.CreateInfo.special_kind~=nil then\n        return GetBit(self.CreateInfo.special_kind, special_kind);\n    end\n    return false;\nend\n\nfunction RoomBase:IsFull()\n    local ROOM_CFG = StaticTableMgr:GetRoomConfig(self.RoomType);\n    \n    if ROOM_CFG~=nil then\n\n        if self:GetRoomPlayerNum()<ROOM_CFG.room_max then\n            return false;\n        end\n    end\n    \n    return true;\nend\n\nfunction RoomBase:Release()\n    self:BaseRelease();\nend\n\nfunction RoomBase:BaseRelease()\n    \n    if self.IsGameStart then\n        self:RelieveAutoRoom();\n    end\n\n    for _,uid in ipairs(self.SeatPlayers) do\n        if uid>0 then\n            self:ReleaseRoomPlayer(uid);\n        end\n    end\n    \n    self.Fsm = nil;\n    TimerMgr:RemoveTimer(self._TimerHandle);\nend\n\n\n--  广播消息给房间内桌上所有玩家  如有except_id，那么广播给除except_id的其它玩家。\nfunction RoomBase:BroadcastMsg( msg_name, proto_name, proto_stru, except_id )\n    \n    for _,v in ipairs(self.SeatPlayers) do\n        if v~=0 then\n            if except_id~=v then\n                local player = PlayerMgr:GetPlayer(v);\n                \n                if player~=nil then\n                    BaseService:SendToClient( player, msg_name, proto_name, proto_stru )\n                end\n            end\n        end\n    end\n    \nend     \n  \n--  广播消息给房间内观战所有玩家  如有except_id，那么广播给除except_id的其它玩家。\nfunction RoomBase:BroadcastViewer( msg_name, msg_stru, except_id )\n    \n    \n    \nend   \n\n-- 添加结算事件\nfunction RoomBase:__AddShowDownEvent( TShowDownEvent, count )\n    local event_cnt = self.ShowDownEvent[TShowDownEvent];\n    \n    if event_cnt==nil then\n        self.ShowDownEvent[TShowDownEvent] = count;\n    else\n        event_cnt = event_cnt + count;\n    end\nend\n\nfunction RoomBase:__GetSpecialCfg( field )\n    local ROOM_CFG  = StaticTableMgr:GetSpecialCfg(self.RoomType);\n    \n    if ROOM_CFG~=nil then\n        if field~=nil then\n            return ROOM_CFG[field];\n        end\n        return ROOM_CFG;\n    end\n    \n    return nil;\nend\n\nfunction RoomBase:__NotifyOtherServiceLeave( uid )\n\n    local msgout = CMessage(\"PLS=>LURT\");\n    msgout:wint(uid);\n    msgout:wstring(self.RoomType);\n    msgout:wint(self.PrvRoomID);\n\n    BaseService:Broadcast( \"SCH\", msgout );\nend\n\nfunction RoomBase:__AddRoomPlayer( uid )\n    local seat_idx = self:GetPlayerSeatIdx(uid);\n    \n    if seat_idx==0 then\n        \n        for k,v in ipairs(self.SeatPlayers) do\n            if v==0 then\n                self.SeatPlayers[k] = uid;\n                seat_idx = k;\n                break;\n            end\n        end\n    end\n    \n    return seat_idx;\nend\n\nfunction RoomBase:__RemoveSeatPlayer( uid )\n    for k,v in ipairs(self.SeatPlayers) do\n        if v==uid then\n            self.SeatPlayers[k] = 0;\n        end\n    end\nend\n\nfunction RoomBase:__GetViewPlayerNum()\n    return #self.ViewPlayers;\nend\n\nfunction RoomBase:__IsViewPlayer( playerid )\n    if self.ViewPlayers[playerid]~=nil then\n        return true;\n    end\n    return false;\nend\n\nreturn RoomBase;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Room/RoomFactory.lua",
    "content": "RoomFactory = {}\n\nfunction RoomFactory:Init()\n\t\n    self.RoomTypes                      = {};\n    self.RoomTypes[\"RM_DDZ\"]            = require(\"Games/PokerDdz/RoomDdz\");\n\nend\n\nfunction RoomFactory:CreateRoom( room_type )\n    local room_class = self.RoomTypes[room_type];\n    if room_class~=nil then\n        local room_ins = room_class:new(room_type);\n        room_ins:BaseInit(room_type, 1000);\n        return room_ins;\n    end\n    return nil;\nend\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Room/RoomMgr.lua",
    "content": "RoomMgr = {}\n\nfunction RoomMgr:Init()\n\t\n    self.GameRooms          = Map:new();               --  {roomid, room_ins}\n    --self.RoomTypes          = {};               --  {roomtype, {roomids, room_ins} }\n    self.PrvRoomTypes       = MapMap:new();               --  {roomtype, {prv_roomids, room_ins} }\n    \n    \n    self.RoomIDGen          = IDGenerate.NewInstance(1020);\nend\n\nfunction RoomMgr:PrintInfo()\n    nlinfo(\"==============  Rooms =============\");\n    self.GameRooms:ForEach( function(_,v) v:PrintInfo(); end );\nend\n\nfunction RoomMgr:CreatePrivateRoom( uid, prv_room_id, msg_cpr )\n\n    local room_type = msg_cpr.room_type;\n    local player    = PlayerMgr:GetPlayer(uid);\n    local ROOM_CFG  = StaticTableMgr:GetRoomConfig(room_type);\n    \n    if ROOM_CFG~=nil and player~=nil then\n        \n        if player.RoomID >0 then    -- 已经创建过房间了\n            nlwarning(\"already create room.  PlayerID:\".. uid..\"  RoomInfo:\");\n            \n            local room = self.GameRooms:Find(player.RoomID);\n            if room~=nil then\n                PrintTable(room);\n            end\n        else\n            local room_base = RoomFactory:CreateRoom(room_type);\n            \n            if room_base~=nil then\n                room_base.PrvRoomID     = prv_room_id;\n                room_base.CreatorID     = uid;\n                room_base.CreateInfo    = msg_cpr;\n\n                if room_base:JoinRoom(player) then\n                    self.GameRooms:Insert(room_base.RoomID, room_base);\n                    self.PrvRoomTypes:Insert(room_type, prv_room_id, room_base);\n                else\n                    room_base:Release();\n                    nlwarning(\"player join room fail.  uid:\"..uid)\n                end\n            end\n        end\n    end\n\n    return nil;\nend\n\nfunction RoomMgr:EnterPrivateRoom( uid, prv_room_id, room_type )\n\n    local player    = PlayerMgr:GetPlayer(uid);\n    local ROOM_CFG  = StaticTableMgr:GetRoomConfig(room_type);\n    \n    if ROOM_CFG~=nil and player~=nil then\n        \n        if player.RoomID >0 then\n            -- 已经在房间，自动返回\n            local room = self.GameRooms:Find(player.RoomID);\n            if room~=nil then\n                room:JoinRoom(player);\n            end\n        else\n            local room = self.PrvRoomTypes:Find(room_type, prv_room_id);\n\n            if room~=nil then\n                room:JoinRoom(player);\n            end\n        end\n    end\n\n    return nil;\nend\n\nfunction RoomMgr:GetRoom( room_id )\n    return self.GameRooms:Find(room_id);\nend\n\nfunction RoomMgr:ReleaseRoom( room_id )\n    local room = self.GameRooms:Find(room_id);\n    \n    if room~=nil then\n        \n        if room.PrvRoomID > 0 then\n            self.PrvRoomTypes:Remove( room.RoomType, room.PrvRoomID );\n        end\n        \n        self.GameRooms:Remove(room_id);\n        \n        room:Release();\n    end\nend\n\nfunction RoomMgr:GetRoomFromPID( uid )\n    local player    = PlayerMgr:GetPlayer(uid);\n    \n    if player~=nil then\n        return RoomMgr:GetRoom(player.RoomID);\n    end\n    \n    return nil;\nend\n\nfunction RoomMgr:GenerateRoomID()\n    return self.RoomIDGen:Generate();\nend\n\n\n--释放函数\nfunction RoomMgr:Release()\n    \nend\n\n\nreturn RoomMgr;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/Room/RoomPlayerBase.lua",
    "content": "local RoomPlayerBase = class(\"RoomPlayerBase\")\n\nfunction RoomPlayerBase:ctor()\n\n    self._State         = 0;\n    self._Score         = 0;            -- \n    \n    self.HandCards      = {};\nend\n\nfunction RoomPlayerBase:GetHandCount()\n    return #self.HandCards;\nend\n\nfunction RoomPlayerBase:ClearOneGameState()\n\n    local clear_states = { enum.STATE_DDZ_NEWROLE, enum.STATE_DDZ_RELIEVE, enum.STATE_DDZ_GUOPAI, enum.STATE_DDZ_NONGMING, enum.STATE_DDZ_DIZHU,\n    enum.STATE_DDZ_JIABEI, enum.STATE_DDZ_SELECT_JIABEI, enum.STATE_DDZ_MINGPAI,enum.STATE_DDZ_SELECT_MINGPAISTART, enum.STATE_DDZ_CONTINUE_GAME };\n    self._State = ClearBits( self._State, clear_states );\n    \n    self.HandCards = {};\nend\n\nfunction RoomPlayerBase:GetState( enum_val )\n    \n    if enum_val==nil then\n        return self._State;\n    end\n    \n    return GetBit(self._State, enum_val);\nend\n\nfunction RoomPlayerBase:SetState( enum_val )\n    self._State = SetBit( self._State, enum_val );\nend\n\nfunction RoomPlayerBase:ClearState( enum_val )\n    self._State = ClearBit(self._State, enum_val);\nend\n\nfunction RoomPlayerBase:AddHandCard( card )\n    table.insert(self.HandCards, card);\nend       \n        \nfunction RoomPlayerBase:RemoveHandCard( card )\n    for i,v in ipairs(self.HandCards) do\n        if v==card then\n            table.remove(self.HandCards, i);\n            return;\n        end\n    end\nend \n\nfunction RoomPlayerBase:GetHandCardMsgList( msg_cards )\n    for i,v in ipairs(self.HandCards) do\n        table.insert(msg_cards, v);\n    end\nend\n\nfunction RoomPlayerBase:SetScore( score )\n    self._Score = score;\nend\n\nfunction RoomPlayerBase:GetScore()\n    return self._Score;\nend\n\nfunction RoomPlayerBase:ChangeScore( score, is_add )\n    if is_add then\n        self._Score = self._Score + score;\n    else\n        self._Score = self._Score - score;\n    end\n    return self._Score;\nend\n\nfunction RoomPlayerBase:AddScore( score )\n    self._Score = self._Score + score;\n    return self._Score;\nend\n\nfunction RoomPlayerBase:SubScore( score )\n    self._Score = self._Score - score;\n    return self._Score;\nend\n\n\nreturn RoomPlayerBase;\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/_PLSConfig.lua",
    "content": "PLSConfig = {}\n\n\nPLSConfig[\"GameConfig\"] = {};\n\nPLSConfig.GameConfig[\"RM_DDZ\"] = { Max = 5000 };\n\n\n\n\n\n\n\nPlayerConfig = {\n    MaxPlayer           = 3000,             -- \n    DeleteTimeOut       = 8*60*60*1000,     -- ʱ䡣 λ\n    DeleteTimeCheck     = 10*60*1000,       --  ʱ\n}\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_PLS/_PLSMain.lua",
    "content": "--========================================================= \n-- 加载常用模块\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"_PLS/?.lua;\" .. BasePath .. \"SharedLib/?.lua;\";\n\n\nrequire(\"InitSharedLib\")\nrequire(\"_PLSConfig\")\nrequire(\"PlayerLogicService\")\nrequire(\"Player/PlayerMgr\")\nrequire(\"DB/DBMgr\")\nrequire(\"Room/RoomMgr\")\nrequire(\"Room/RoomFactory\")\n\n\nrequire(\"Msg/MsgLogin\")\nrequire(\"Msg/MsgRoom\")\nrequire(\"Games/PokerDdz/MsgRoomDdz\")\nrequire(\"Games/PokerDdz/DdzCardTypes\")\n\nrequire(\"Games/Common/PokerDef\");\nrequire(\"Games/Common/CommonDef\");\n\n\n\nPlayerDataHelper    = require(\"Player/PlayerDataHelper\");\nPlayerHelper        = require(\"Player/PlayerHelper\");\nRoomPlayerBase      = require(\"Room/RoomPlayerBase\")\nRoomBase            = require(\"Room/RoomBase\")\nCardsAnalyseRes     = require(\"Games/Common/CardsAnalyseRes\")\n\n\n-- 主入口函数。从这里开始lua逻辑\nfunction ServiceInit()\n\n    nlinfo(\"Lua PLSConfig:\");\n    PrintTable(PLSConfig)\n\n    MsgLogin:Init();\n    MsgRoom:Init();\n\n    MsgRoomDdz:Init();\n\n    \n    RoomFactory:Init();\n    RoomMgr:Init();\n    DBMgr:Init();\n    PlayerMgr:Init();\n    PlayerLogicService:Init();\n    \n    \n    DdzCardtypes:Init();\n    \n    --local room = RoomFactory:CreateRoom(\"RM_DDZ\");\n    \n --   local msg_ddz = {};\n    \n  --  room:__FillRoomInfoMsg(msg_ddz, 0);\n    \n    --PrintTable(msg_ddz);\n\n    \nend\n\n-- 游戏循环\nfunction ServiceUpdate()\n    local curr_tick = Misc.GetLocalTime();\n    TimerMgr:Update( curr_tick );\nend\n\nfunction ServiceRelease()\n    MsgLogin:Release();\n    MsgRoom:Release();\n    \n    RoomMgr:Release();\n    DBMgr:Release();\n    PlayerLogicService:Release();\n\n    nlinfo(\"Lua Release.\");\nend\n\nfunction ServiceInfo()\n    \n    nlinfo(\"PlayerNum:\"..PlayerMgr:Count());\n    \n    nlinfo(\"=========  Players =============\");\n    PrintTable(PlayerMgr.playerMap.map)\n    RoomMgr:PrintInfo();\n\n    \nend\n\n--[[\n\n\n\n\n--bash_path = \"E:\\\\BaseService\\\\code\\\\EVA\\\\server\\\\script\\\\\";\n--package.path = bash_path .. \"Framework\\\\?.lua;\" .. bash_path .. \"Framework\\\\Net\\\\?.lua;\";\n\nnlinfo(package.path);\n\nlocal protobuf = require \"protobuf\"\n\naddr = io.open( bash_path..\"DataTable\\\\proto_msg.pb\", \"rb\")\nbuffer = addr:read \"*a\"  \naddr:close()  \n  \nprotobuf.register(buffer)  \n\nt = protobuf.decode(\"google.protobuf.FileDescriptorSet\", buffer) \n\nplayer_info = {  \n    name = \"Alice\",  \n    pid = 12345,  \n    view_player_list = {  \n        { pid = 17712345678, head_portrait = 1 },  \n        { pid = 17712345679, head_portrait = 2 },  \n    },  \n    level = 2\n}\n\n\ncode = protobuf.encode(\"MsgPlayerInfo\", player_info)\ndecode = protobuf.decode(\"MsgPlayerInfo\" , code)\n\nnlinfo(decode.name)\nnlinfo(decode.pid)\n\nfor _,v in ipairs(decode.view_player_list) do\n\tnlinfo(\"\\t\"..v.pid, v.head_portrait)\nend\n\n]]"
  },
  {
    "path": "code/EVA/server/script/_PLS/hotfix_module_names.lua",
    "content": "-- Module names need hotfix.\n-- hotfix_helper.lua will reload this module in check().\n-- So it can be changed dynamically.\n\nlocal hotfix_module_names = {\n  \"Games/PokerDdz/RoomDdz\",\n}\n\nreturn hotfix_module_names\n"
  },
  {
    "path": "code/EVA/server/script/_PLS.luaprj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<Project Name=\"_PLS.luaprj\" Cmd=\"E:\\BaseService\\build\\bin\\Debug\\player_logic_service.exe\" Arg=\"\" Dir=\"E:\\BaseService\\code\\EVA\\server\" Toggle=\"false\" >\n    <Filter RelativePath=\".\\_PLS\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\_PLSMain.lua\" />\n        <LuaFile RelativePath=\".\\PlayerLogicService.lua\" />\n        <Filter RelativePath=\".\\DB\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\DBMgr.lua\" />\n            <LuaFile RelativePath=\".\\DBProc.lua\" />\n            <LuaFile RelativePath=\".\\DBSubProc.lua\" />\n            <LuaFile RelativePath=\".\\DBSubStart.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Msg\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\MsgLogin.lua\" />\n            <LuaFile RelativePath=\".\\MsgRoom.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Player\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\PlayerDataHelper.lua\" />\n            <LuaFile RelativePath=\".\\PlayerHelper.lua\" />\n            <LuaFile RelativePath=\".\\PlayerMgr.lua\" />\n        </Filter>\n        <LuaFile RelativePath=\".\\_PLSConfig.lua\" />\n        <Filter RelativePath=\".\\Room\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\RoomBase.lua\" />\n            <LuaFile RelativePath=\".\\RoomMgr.lua\" />\n            <LuaFile RelativePath=\".\\RoomFactory.lua\" />\n            <LuaFile RelativePath=\".\\RoomPlayerBase.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Games\" Toggle=\"false\" >\n            <Filter RelativePath=\".\\PokerDdz\" Toggle=\"false\" >\n                <LuaFile RelativePath=\".\\DdzFSM.lua\" />\n                <LuaFile RelativePath=\".\\DdzPlayerInfo.lua\" />\n                <LuaFile RelativePath=\".\\RoomDdz.lua\" />\n                <LuaFile RelativePath=\".\\MsgRoomDdz.lua\" />\n                <LuaFile RelativePath=\".\\DDZOutCardData.lua\" />\n                <LuaFile RelativePath=\".\\DdzCardTypes.lua\" />\n            </Filter>\n            <Filter RelativePath=\".\\Common\" Toggle=\"false\" >\n                <LuaFile RelativePath=\".\\PokerDef.lua\" />\n                <LuaFile RelativePath=\".\\CommonDef.lua\" />\n                <LuaFile RelativePath=\".\\CardsAnalyseRes.lua\" />\n            </Filter>\n        </Filter>\n    </Filter>\n</Project>"
  },
  {
    "path": "code/EVA/server/script/_SCH/Msg/MsgLogin.lua",
    "content": "--========================================================= \n-- SCH   负责分配到一个PLS\n--=========================================================\n\nMsgLogin = {}\n\nfunction MsgLogin:Init()\n\tself._EventRegister = EventRegister.new();\n\t\n    --  服务器间消息\n    self._EventRegister:RegisterEvent( \"AuthOk\",            self, self.DispatchPLS );\n\n    -- PLS 删除缓存中的玩家\n    self._EventRegister:RegisterEvent( \"RemovePlayer\",      self, self.cbRemovePlayer );\nend\n\n-- 分配PLS\nfunction MsgLogin:DispatchPLS( fes_id, msg_authok )\n\n    local uid       = msg_authok:rint64();\n    local room_type = msg_authok:rstring();\n    \n    local msg_sdata_0 = CMessage(\"SyncData\");\n    msg_sdata_0:wint64(uid);\n    msg_sdata_0:wint32(fes_id);\n\n    local player = PlayerInfoMgr:GetPlayerInfo(uid);\n    \n    if player~=nil then\n\n        player.ConFES = fes_id;\n        \n        if player.ConPLS~=nil then\n            BaseService:Send( player.ConPLS, msg_sdata_0 )\n        else\n            local pls_sid = PLSInfoMgr:AllocPLS(player.RoomType);\n            \n            if pls_sid~=nil then\n                player.ConPLS = pls_sid;\n                BaseService:Send( player.ConPLS, msg_sdata_0 )\n            else\n                nlwarning(player.RoomType..\" not in pls config.\");\n            end\n        end\n    else\n        local pls_sid = PLSInfoMgr:AllocPLS(room_type);\n\n        if pls_sid~=nil then\n            player = PlayerInfoMgr:CreatePlayerInfo(uid);\n            \n            player.ConFES   = fes_id;\n            player.ConPLS   = pls_sid;\n            player.RoomType = room_type;\n            \n            BaseService:Send( player.ConPLS, msg_sdata_0 )\n        else\n            nlwarning(room_type..\" not in pls config.\");\n        end\n    end\nend\n\nfunction MsgLogin:cbRemovePlayer( fesid, msgin )\n    local uid       = msgin:rint();\n\nend\n\n\nreturn MsgLogin;\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Msg/MsgRoom.lua",
    "content": "MsgRoom = {}\n\nfunction MsgRoom:Init()\n\tself._EventRegister = EventRegister.new();\n    self._EventRegister:RegisterEvent( \"CPRM\",          self, self.cbCreatePrivateRoom );\n    self._EventRegister:RegisterEvent( \"EPRM\",          self, self.cbEnterPrivateRoom );   \n    \n    self._EventRegister:RegisterEvent( \"PLS=>LURT\",     self, self.cbLeaveRoomType );   \n    \nend\n\n\nfunction MsgRoom:cbCreatePrivateRoom( sid, msgin )\n    local uid       = msgin:rint64();\n    local msg_cpr   = msgin:rpb(\"PB.MsgCreatePrivateRoom\");\n    RoomMgr:CreatePrivateRoom(uid, msg_cpr)\nend\n\nfunction MsgRoom:cbEnterPrivateRoom( sid, msgin )\n    local uid       = msgin:rint64();\n    local msg_epr   = msgin:rpb(\"PB.MsgEnterPrivateRoom\");\n    RoomMgr:EnterPrivateRoom(uid, msg_epr);\nend\n\nfunction MsgRoom:cbLeaveRoomType( sid, msgin )\n    local uid       = msgin:rint();\n    local prv_rmtp  = msgin:rstring();\n    local prv_rmid  = msgin:rint();\n    \n    RoomMgr:ResetPrivateRoom(uid, prv_rmtp, prv_rmid);\nend\n\n\n--释放函数\nfunction MsgRoom:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn MsgRoom;\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/PLSInfo/PLSGameInfo.lua",
    "content": "local PLSGameInfo = class(\"PLSGameInfo\")\n\n-- 构造函数;\nfunction PLSGameInfo:ctor()\n    self.Type       = \"\";\n\tself.Max        = 0;\n\tself.Curr       = 0;\nend\n\nfunction PLSGameInfo:IsFull()\n    if( self.Curr > self.Max ) then\n        return true;\n    end\n    return false;\nend\n\nreturn PLSGameInfo;\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/PLSInfo/PLSInfo.lua",
    "content": "local PLSInfo = class(\"PLSInfo\")\n\n-- 构造函数;\nfunction PLSInfo:ctor()\n\tself.ServiceID      = 0;\n    self.ServiceName    = \"\";\n    self.MaxPlayer      = 0;\n    self.CurrPlayer     = 0;\n    self.RoomList       = {};\nend\n\nfunction PLSInfo:LoadData( _service_info )\n    \n\tself.ServiceID      = _service_info.ServiceID;\n    self.ServiceName    = _service_info.ServiceName;\n    self.MaxPlayer      = _service_info.MaxPlayer;\n    self.CurrPlayer     = _service_info.CurrPlayer;\n    self.RoomList   = {};\n    \n    if _service_info.RoomList~=nil then\n    \n        for _,v in ipairs(_service_info.RoomList) do\n            \n            local game_info = PLSGameInfo:new();\n            game_info.Type  = v.Type;\n            game_info.Max   = v.Max;\n            game_info.Curr  = v.Curr;\n\n            self.RoomList[game_info.Type] = game_info;\n        end\n    end\n    \nend\n\nfunction PLSInfo:IsFull()\n    if( self.CurrPlayer > self.MaxPlayer ) then\n        return true;\n    end\n    return false;\nend\n\nreturn PLSInfo;\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/PLSInfo/PLSInfoMgr.lua",
    "content": "PLSInfoMgr = {}\n\n-- 初始化函数\nfunction PLSInfoMgr:Init()\n    self.PLSMap         = Map:new();\n    self._EventRegister = EventRegister.new();\n    \n    self._EventRegister:RegisterEvent( \"SvrInfo\",  self, self.SvrUpdateInfoCB );\n    \n    nlinfo(\"PLSInfoMgr:Init\");\nend\n\nfunction PLSInfoMgr:SvrUpdateInfoCB( msg_from, msg_svrinfo )\n    \n    local proto_buf = msg_svrinfo:rstring();\n    local pb_sinfo  = protobuf.decode(\"PB.MsgServiceInfo\" , proto_buf)\n    local pls_info  = PLSInfo:new();\n    pls_info:LoadData(pb_sinfo);\n    \n    if pb_sinfo.ServiceName==\"PLS\" then\n        self.PLSMap:Replace(pls_info.ServiceID, pls_info);\n    end\n\nend\n\nfunction PLSInfoMgr:AllocPLS( room_type )\n\n    for _,v in pairs(self.PLSMap.map) do\n        \n        if v.RoomList[room_type] ~= nil then\n            local game_info = v.RoomList[room_type];\n            \n            if not game_info:IsFull() then\n                game_info.Curr = game_info.Curr + 1;\n                return v.ServiceID;\n            end;\n        end;\n    end;\n    \n    return -1;\nend\n\nfunction PLSInfoMgr:IsInPLS( room_type, pls_sid )\n    local pls_info = self.PLSMap:Find(pls_sid);\n    \n    if pls_info~=nil then\n        if pls_info[room_type]~=nil then\n            return true;\n        end\n    end\n    \n    return false;\nend\n\n\n--释放函数\nfunction PLSInfoMgr:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\nreturn PLSInfoMgr\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Player/PlayerInfo.lua",
    "content": "-- Player SCH Info\nlocal PlayerInfo = class(\"PlayerInfo\")\n\n-- 构造函数;\nfunction PlayerInfo:ctor()\n\tself.ConPLS         = -1;\n    self.ConFES         = nil;\n\tself.UID            = nil;\n    --self.IsOffline      = false;\n    self.LogoutTime     = nil;\n    --self.TimerID        = nil;\n    self.RoomType       = \"\";\n    self.PrvRoomID      = 0;\nend\n\n\n\nfunction PlayerInfo:RemoveCachePlayerTimer()\n    \n    if self.LogoutTime then\n    \n        --self.TimerID = TimerMgr:AddTimer(7000, self, self.RemoveCachePlayerTimer);\n    else\n        --TimerMgr:RemoveTimer(self.TimerID);\n    end\n    \nend\n\nfunction PlayerInfo:Release()\n\n\nend\n\n--self.TimerID = TimerMgr:AddTimer(7000, self, self.UpdatePLSInfoTimer);\nreturn PlayerInfo;\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Player/PlayerInfoMgr.lua",
    "content": "PlayerInfoMgr = {}\n\n-- 初始化函数\nfunction PlayerInfoMgr:Init()\n\tself.PlayerInfoMap      = Map:new();\n    \n    nlinfo(\"PlayerInfoMgr:Init\");\nend\n\nfunction PlayerInfoMgr:GetPlayerInfo( _uid )\n    return self.PlayerInfoMap:Find(_uid);\nend\n\nfunction PlayerInfoMgr:CreatePlayerInfo( _uid )\n\n    local player = self.PlayerInfoMap:Find(_uid);\n    if player~= nil then\n        return player;\n    else\n        player = PlayerInfo:new();\n        player.UID = _uid;\n        self.PlayerInfoMap:Insert(_uid, player);\n    end\n\n    return player;\nend\n\nfunction PlayerInfoMgr:RemovePlayerInfo( _uid )\n    \n    local player = self.PlayerInfoMap:Find(_uid);\n    \n    if player ~= nil then\n        player:Release();\n        self.PlayerInfoMap:Remove(_uid);\n    end\nend\n\nfunction PlayerInfoMgr:RemovePLS( pls_sid )\n    self.PlayerInfoMap:ForEachRemove(\"ConPLS\", pls_sid);\n    \n    nlwarning(\"PlayerInfoMgr.RemovePLS:\"..pls_sid);\nend\n\nfunction PlayerInfoMgr:Release()\n    self.PlayerInfoMap:ForEach( function(_,v) v:Release(); end );\n    self.PlayerInfoMap = nil;\nend\n\nreturn PlayerInfoMgr\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Room/RoomIDAlloter.lua",
    "content": "local RoomIDAlloter = class(\"RoomIDAlloter\")\n\n-- 构造函数;\nfunction RoomIDAlloter:ctor()\n\tself.IDPool         = {};\n    self.RoomType       = \"\";\n    self.IDMax          = 999999; --999999;\n    self.__AllocIdx     = 1;\n\n    self:Init();\nend\n\nfunction RoomIDAlloter:Init()\n    \n    for i=1,self.IDMax do\n        self.IDPool[i] = i;\n    end\n    \n    for i=1,self.IDMax do\n        local ridx  = math.random(1, self.IDMax);\n        if i~=ridx then\n            local temp          = self.IDPool[i];\n            self.IDPool[i]      = self.IDPool[ridx];\n            self.IDPool[ridx]   = temp;\n        end\n    end\n    \nend\n\nfunction RoomIDAlloter:AllocID()\n    \n    if self.__AllocIdx == self.IDMax then\n        self.__AllocIdx = 1;\n    end\n\n    local newid = self.IDPool[self.__AllocIdx];\n    self.__AllocIdx = self.__AllocIdx + 1;\n    return newid;\nend\n\nreturn RoomIDAlloter;\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Room/RoomInfo.lua",
    "content": "local RoomInfo = class(\"RoomInfo\")\n\n-- 构造函数;\nfunction RoomInfo:ctor()\n    \n\tself.PLSID          = -1;\n    self.RoomType       = \"\";\n    self.PrvRoomID      = 0;\n    self.PlayerID       = 0;    -- 创建者ID\n\n\nend\n\n\n\nreturn RoomInfo;\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/Room/RoomMgr.lua",
    "content": "RoomMgr = {}\n\nfunction RoomMgr:Init()\n    \n    self._RoomIDPool            = {};\n    self._RoomsInfo             = MapMap:new();  -- { room_type, {prv_room_id, room_ins} }\n    \n    self:__InitRoomID();\n\nend\n\n\nfunction RoomMgr:CreatePrivateRoom( uid, msg_cpr )\n    \n    local player = PlayerInfoMgr:GetPlayerInfo(uid);\n    \n    if player~=nil then\n        if player.PrvRoomID==0 then\n            \n            local room_type     = msg_cpr.room_type;\n            local new_room_id   = self:__NewRoomID(room_type);\n            \n            if new_room_id>0 then\n                \n                local room_info = RoomInfo:new();\n                room_info.PlayerID      = uid;\n                room_info.PrvRoomID     = new_room_id;\n                room_info.RoomType      = room_type;\n\n                if PLSInfoMgr:IsInPLS(room_type, player.ConPLS) then\n                    room_info.PLSID = player.ConPLS;\n                else\n                    room_info.PLSID = PLSInfoMgr:AllocPLS(room_type);\n                end\n                \n                player.PrvRoomID    = new_room_id;\n                player.RoomType     = room_type;\n                \n                self._RoomsInfo:Insert(room_type, new_room_id, room_info);\n        \n                local msgout = CMessage(\"CPRM=>PLS\");\n                msgout:wint(uid);\n                msgout:wint(new_room_id);\n                msgout:wint(room_info.PLSID);\n                msgout:wtable(msg_cpr);\n                \n                BaseService:Send( player.ConPLS, msgout );\n            end\n        else\n            local msgout = CMessage(\"EPRM=>PLS\");\n            msgout:wint(uid);\n            msgout:wint(player.ConPLS);\n            msgout:wint(player.PrvRoomID);\n            msgout:wstring(player.RoomType);\n\n            BaseService:Send( player.ConPLS, msgout );\n        end\n    end\nend\n\nfunction RoomMgr:EnterPrivateRoom( uid, msg_epr )\n    \n    local player = PlayerInfoMgr:GetPlayerInfo(uid);\n    \n    if player~=nil then\n        if player.PrvRoomID==0 then\n            \n            local room_type     = msg_epr.room_type;\n            local room_id       = msg_epr.room_id;\n            local room = self._RoomsInfo:Find(room_type, room_id);\n            if room~=nil then\n                \n                player.PrvRoomID    = room_id;\n                player.RoomType     = room_type;\n                \n                local msgout = CMessage(\"EPRM=>PLS\");\n                msgout:wint(uid);\n                msgout:wint(room.PLSID);\n                msgout:wint(room_id);\n                msgout:wstring(room_type);\n\n                BaseService:Send( player.ConPLS, msgout );\n            end\n        else\n            local msgout = CMessage(\"EPRM=>PLS\");\n            msgout:wint(uid);\n            msgout:wint(player.ConPLS);\n            msgout:wint(player.PrvRoomID);\n            msgout:wstring(player.RoomType);\n\n            BaseService:Send( player.ConPLS, msgout );\n        end\n    end\nend\n\nfunction RoomMgr:ResetPrivateRoom( uid, prv_rmtp, prv_rmid )\n    local player = PlayerInfoMgr:GetPlayerInfo(uid);\n    \n    if player~=nil then\n        if player.PrvRoomID~=prv_rmid or player.RoomType~=prv_rmtp then\n            nlwarning(\" player.PrvRoomID~=prv_rmid or player.RoomType~=prv_rmtp \");\n            return;\n        end\n           \n        player.PrvRoomID    = 0;\n        player.RoomType     = \"\";\n    end\nend\n\nfunction RoomMgr:__NewRoomID( room_type )\n\n    local idpool = self._RoomIDPool[room_type];\n    local new_id = 0;\n    \n    if idpool~=nil then\n        new_id = idpool:AllocID();\n    end\n    \n    return new_id;\nend\n\nfunction RoomMgr:__InitRoomID()\n\n    for k, v in pairs(StaticTableMgr._RoomConfig) do  \n        if v.match == \"private\" then\n            self._RoomIDPool[k] = RoomIDAlloter.new();\n        end\n    end \n\nend\n\nreturn RoomMgr\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/ScheduleService.lua",
    "content": "ScheduleService = {}\n\nfunction ScheduleService:Init()\n\tself._EventRegister = EventRegister.new();\n\t\n\tself._EventRegister:RegisterEvent( \"FESCon\",            self, self.CbConnection );\n\tself._EventRegister:RegisterEvent( \"FESDis\",            self, self.CbFESDisConnection );\n    self._EventRegister:RegisterEvent( \"PLSCon\",            self, self.CbConnection );\n\tself._EventRegister:RegisterEvent( \"PLSDis\",            self, self.CbPLSDisConnection );\n    \n    -- 注册其它服务器启动的回调\n    Net.SetConnectionCallback(\"FES\");\n    Net.SetDisConnectionCallback(\"FES\");\n    \n    Net.SetConnectionCallback(\"PLS\");\n    Net.SetDisConnectionCallback(\"PLS\");\n    \n    nlinfo(\"ScheduleService:Init\");\nend\n\nfunction ScheduleService:CbConnection( service_id, service_name )\n\tnlinfo(\"ScheduleService:CbConnection:\"..service_name..\" sid:\"..service_id);\nend\n\nfunction ScheduleService:CbFESDisConnection( service_id, service_name )\n\tnlinfo(\"ScheduleService:CbFESDisConnection\"..service_name..\" sid:\"..service_id);\nend\n\nfunction ScheduleService:CbPLSDisConnection( service_id, service_name )\n    PlayerInfoMgr.RemovePLS(service_id);\nend\n\n--\t释放函数\nfunction ScheduleService:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\nreturn ScheduleService\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH/_SCHMain.lua",
    "content": "--========================================================= \n-- 加载常用模块\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"_SCH/?.lua;\" .. BasePath .. \"SharedLib/?.lua;\";\n\n\nrequire(\"InitSharedLib\")\nrequire(\"ScheduleService\")\nrequire(\"PLSInfo/PLSInfoMgr\")\nrequire(\"Player/PlayerInfoMgr\")\n\nMsgLogin            = require(\"Msg/MsgLogin\")\nMsgRoom             = require(\"Msg/MsgRoom\")\n\nPLSGameInfo         = require(\"PLSInfo/PLSGameInfo\")\nPLSInfo             = require(\"PLSInfo/PLSInfo\")\nPlayerInfo          = require(\"Player/PlayerInfo\")\n\nRoomInfo            = require(\"Room/RoomInfo\")\nRoomMgr             = require(\"Room/RoomMgr\")\nRoomIDAlloter       = require(\"Room/RoomIDAlloter\")\n\n\n--PHPService          = CallbackServer:new();\n\n\n\n-- 主入口函数。从这里开始lua逻辑\nfunction ServiceInit()\n\t\n    nlinfo(\"Lua Start.\");\n\n    MsgLogin:Init();\n    MsgRoom:Init();\n    \n    RoomMgr:Init();\n    PLSInfoMgr:Init();\n    PlayerInfoMgr:Init();\n    ScheduleService:Init();\n    \n    --PHPService:Init( \"PHP\", \"tcp\" );\n    --PHPService:Listen( 20458 );\n\nend\n\n-- 游戏循环\nfunction ServiceUpdate()\n    TimerMgr:Update( Misc.GetLocalTime() );\nend\n\nfunction ServiceRelease()\n    \n    PLSInfoMgr:Release();\n    PlayerInfoMgr:Release();\n    ScheduleService:Release();\n    nlinfo(\"Lua Release.\");\nend\n\n\nfunction ServiceInfo()\n    \n    PrintTable(PlayerInfoMgr.PlayerInfoMap.map);\nend\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/script/_SCH.luaprj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<Project Name=\"_SCH.luaprj\" Cmd=\"E:\\BaseService\\build\\bin\\Debug\\schedule_service.exe\" Arg=\"\" Dir=\"E:\\BaseService\\code\\EVA\\server\" Toggle=\"true\" >\n    <Filter RelativePath=\".\\_SCH\" Toggle=\"false\" >\n        <LuaFile RelativePath=\".\\_SCHMain.lua\" />\n        <LuaFile RelativePath=\".\\ScheduleService.lua\" />\n        <Filter RelativePath=\".\\Player\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\PlayerInfo.lua\" />\n            <LuaFile RelativePath=\".\\PlayerInfoMgr.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Msg\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\MsgLogin.lua\" />\n            <LuaFile RelativePath=\".\\MsgRoom.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\PLSInfo\" Toggle=\"true\" >\n            <LuaFile RelativePath=\".\\PLSGameInfo.lua\" />\n            <LuaFile RelativePath=\".\\PLSInfo.lua\" />\n            <LuaFile RelativePath=\".\\PLSInfoMgr.lua\" />\n        </Filter>\n        <Filter RelativePath=\".\\Room\" Toggle=\"false\" >\n            <LuaFile RelativePath=\".\\RoomMgr.lua\" />\n            <LuaFile RelativePath=\".\\RoomIDAlloter.lua\" />\n            <LuaFile RelativePath=\".\\RoomInfo.lua\" />\n        </Filter>\n    </Filter>\n</Project>"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/FSMRobot.lua",
    "content": "local FSMRobot = class(\"FSMRobot\")\n\n--[[\n        ߼״̬\n--]]\n\nfunction FSMRobot:ctor()\n    self._GameFSM \t\t\t= StateMachine:new();\n    self._StateEnterTime    = 0;\n    self._CurrState         = \"TIdle\";\n    self.Robot              = nil;\nend\n\nfunction FSMRobot:Init( robot )\n    self._GameFSM:setup_state({\n        events = \n\t\t{\n            {name = \"TIdle\" \t\t\t        },\n            {name = \"TLogin\" \t\t\t        },\n        },\n        callbacks =\n\t\t{\n            onTIdle   \t\t        = handler(self, self.DoIdle),\n\t\t\tonTLogin   \t\t        = handler(self, self.DoLogin),\n\t\t}\n    })\n    \n    self.Robot  = robot;\n    self:SwitchState( self._CurrState );\nend\n\n\nfunction FSMRobot:__GetRunStateTime()\n    return TimerMgr:GetTime() - self._StateEnterTime;\nend\n\nfunction FSMRobot:TickUpdate()\n    self._GameFSM:do_event( self._CurrState, false );\nend\n\nfunction FSMRobot:SwitchState( event, ... )\n    self._CurrState = event;\n    self._StateEnterTime = TimerMgr:GetTime();\n    self._GameFSM:do_event( event, true, ... );\nend\n\nfunction FSMRobot:GetState()\n\treturn self._CurrState;\nend\n\nfunction FSMRobot:IsState( state )\n    if self._CurrState == state then\n        return true;\n    end\n\treturn false;\nend\n\nfunction FSMRobot:DoIdle( event )\n    -- ǵһ֡һִ֡С\n    if not event.args[1] then\n        if not self.Robot:Connected() then\n            self:SwitchState(\"TLogin\");\n        end\n    end\nend\n\nfunction FSMRobot:DoLogin( event )\n    \n    --if event.args[1] then\n        --nlinfo( \"FSMClass:DoLogin SwitchState\" );\n    --else\n        --nlinfo( \"FSMClass:DoLogin TickUpdate\" );\n    --end\n    if not event.args[1] then\n        if self.Robot:Login() then\n            self.Robot:StartGameTest();\n            self:SwitchState(\"TIdle\");\n        end\n    end\nend\n\n\n\nreturn FSMRobot;\n\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/GameDdz/FSMDdz.lua",
    "content": "local FSMDdz = class(\"FSMDdz\")\n\n--[[\n        Ϸ߼״̬\n--]]\n\nfunction FSMDdz:ctor()\n    self._GameFSM \t\t\t= StateMachine:new();\n    self._StateEnterTime    = 0;\n    self._CurrState         = \"TIdle\";\n    self.Robot              = nil;\nend\n\nfunction FSMDdz:Init( robot )\n    self._GameFSM:setup_state({\n        events = \n\t\t{\n            {name = \"TIdle\" \t\t\t        },\n\t\t\t{name = \"TCreatePrvRoom\"\t\t    },\n\t\t\t{name = \"TJoinPrvRoom\" \t            },\n            {name = \"TInRoomIdlem\" \t            },\n            {name = \"TAction\" \t                },\n            {name = \"TShowDown\"                 },\n\n        },\n        callbacks =\n\t\t{\n            onTIdle   \t\t        = handler(self, self.DoIdle),\n\t\t\tonTCreatePrvRoom  \t    = handler(self, self.DoCreatePrvRoom),\n            onTJoinPrvRoom          = handler(self, self.DoJoinPrvRoom),\n            onTInRoomIdlem          = handler(self, self.DoInRoomIdlem),\n            onTAction               = handler(self, self.DoAction),\n            TShowDown               = handler(self, self.DoShowDown),\n\t\t}\n    })\n\n\n    self.Robot      = robot;\n    self.GameDdz    = robot.Game;\n    self:SwitchState( self._CurrState );\n\n    self.CreateRoomWait     = nil;\n\nend\n\n\nfunction FSMDdz:__GetRunStateTime()\n    return TimerMgr:GetTime() - self._StateEnterTime;\nend\n\nfunction FSMDdz:TickUpdate()\n    self._GameFSM:do_event( self._CurrState, false );\nend\n\nfunction FSMDdz:SwitchState( event, ... )\n    self._CurrState = event;\n    self._StateEnterTime = TimerMgr:GetTime();\n    self._GameFSM:do_event( event, true, ... );\nend\n\nfunction FSMDdz:GetState()\n\treturn self._CurrState;\nend\n\nfunction FSMDdz:IsState( state )\n    if self._CurrState == state then\n        return true;\n    end\n\treturn false;\nend\n\nfunction FSMDdz:DoIdle( event )\n    -- ǵһ֡һִ֡С\n    if not event.args[1] then\n        \n        if not (self.Robot.Data.UID > 0) then\n            return;\n        end\n\n        if self.Robot.Game.RoomInfo == nil then\n            local open_room = PublicRoomInfoMgr:GetOpenRoom(\"RM_DDZ\");\n\n            if open_room ~= nil  then\n                -- robotķ䣬롣\n                self:SwitchState(\"TJoinPrvRoom\", open_room);\n            else\n                -- ûйķ䣬һ\n                \n                if self.Robot.Data.UID==1007 then\n                    if self.CreateRoomWait == nil then\n                        self.CreateRoomWait = math.random(5000,10000);\n                    end\n                    \n                    if self:__GetRunStateTime() > self.CreateRoomWait then\n                        self.Robot:Print(\"request create room.   UID:\"..self.Robot.Data.UID .. \"  wait:\"..self.CreateRoomWait);\n                        self.CreateRoomWait = math.random(5000,60000);\n                        self:SwitchState(\"TCreatePrvRoom\");\n                    end\n                \n                end\n            end\n        end\n    end\nend\n\nfunction FSMDdz:DoCreatePrvRoom( event, open_room )\n    \n    if event.args[1] then\n        self.GameDdz:DoCreatePrvRoom()\n    else\n        if self:__GetRunStateTime() > 15*1000 then\n            -- 䳬ʱ\n            self:SwitchState(\"TIdle\");\n        end\n    end\nend\n\nfunction FSMDdz:DoJoinPrvRoom( event )\n    -- õִ֡\n    if event.args[1] then\n\n        self.Robot:Print(\"DoJoinPrvRoom\");\n        local open_room = event.args[2];\n\n        self.Robot:PrintTable(open_room);\n        self.GameDdz:DoJoinPrvRoom(open_room)\n\n    else\n        if self:__GetRunStateTime() > 15*1000 then\n            self:SwitchState(\"TIdle\");\n        end\n    end\nend\n\nfunction FSMDdz:DoInRoomIdlem( event )\n    \n    if not event.args[1] then\n        if not self.GameDdz:GetRobotState(enum.STATE_DDZ_READY) then\n            self.GameDdz:DoReady();\n        end\n    end\nend\n\nfunction FSMDdz:DoAction( event )\n    if not event.args[1] then\n        self.GameDdz:DoAction();\n    end\nend\n\nfunction FSMDdz:DoShowDown( event )\n\n\nend\n\n\nreturn FSMDdz;\n\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/GameDdz/RobotGameDdz.lua",
    "content": "local RobotGameDdz = class(\"RobotGameDdz\", RobotGameBase)\n\nfunction RobotGameDdz:ctor()\n    self.super:ctor();\n    self.Robot = nil;\n    self.RoomInfo   = nil;\n    self.SelfData   = nil;          --  player_listԼķ\n    self.HandCards  = {};\n    self.WIK        = 0;\nend\n\nfunction RobotGameDdz:GetFsmState()\n    return self.Robot.GameFsm:GetState();\nend\n\nfunction RobotGameDdz:GetRobotState( enum_idx )\n    return GetBit( self.SelfData.state, enum_idx );\nend\n\nfunction RobotGameDdz:__UID()\n    return self.Robot.Data.UID;\nend\n\nfunction RobotGameDdz:DoCreatePrvRoom()\n    local create_prvroom = { room_type=\"RM_DDZ\", consume_id=1001, special_kind=0x1c5 };\n    self.Robot:Send( \"CPRM\", \"PB.MsgCreatePrivateRoom\", create_prvroom );\nend\n\nfunction RobotGameDdz:DoJoinPrvRoom(open_room)\n    local join_prvroom = { room_id=open_room.RoomID, room_type=open_room.RoomType };\n    self.Robot:Send( \"EPRM\", \"PB.MsgEnterPrivateRoom\", join_prvroom );\nend\n\nfunction RobotGameDdz:DoReady()\n    self.Robot:Send( \"DDZ_SR\" );\nend\n\n-- ֵҳ\nfunction RobotGameDdz:DoAction()\n\n    if #self.HandCards>0 and self.WIK ~= enum.ASK_DDZ_NULL then\n        local flg_chupai    = 1 << enum.ASK_DDZ_CHUPAI;\n        local flg_buchu     = 1 << enum.ASK_DDZ_BUCHU;\n        local select_rnd    = math.random( 1, 15 );\n        \n        if self.WIK&flg_buchu and select_rnd==1 then\n            self.Robot:Send( \"DDZ_PS\" );\n        elseif self.WIK&flg_chupai then\n            local MsgDDZUserOutCard = {  out_cards = {}  };\n            local rnd_oc = math.random( 1, #self.HandCards );\n            table.insert( MsgDDZUserOutCard.out_cards, self.HandCards[rnd_oc] );\n            self.Robot:Send( \"DDZ_OC\", \"PB.MsgDDZUserOutCard\", MsgDDZUserOutCard );\n            self.Robot:Print( \"out card:\" .. self.HandCards[rnd_oc] );\n        end\n    end\nend\n\nfunction RobotGameDdz:cbDdzGameInfo( msgin )\n    \n    local ddz_gi = msgin:rpb(\"PB.MsgDDZRoom\");\n    \n    if ddz_gi==nil then\n        nlwarning(\"ddz_gi==nil !!!!!!!!!!!!\");\n        return\n    end\n\n    -- ˢ·\n    self.RoomInfo = ddz_gi;\n    \n    -- ˢԼ\n    for _,v in ipairs(ddz_gi.player_list) do\n        if v.player_base.UID == self.Robot.Data.UID then\n            self.SelfData   = v;\n            self.HandCards  = v.card_list;\n        end\n    end\n    \n    \n    self.Robot:PrintTable(ddz_gi);\n    self.Robot:Print(\"=======>  RobotGameDdz:cbDdzGameInfo  UID:\"..self.Robot.Data.UID);\n    \n    if self:GetFsmState()==\"TCreatePrvRoom\" then\n        \n        --if self:GetRobotState(enum.STATE_DDZ_ROOM_OWNER) then\n            -- ԼģصǴɹ\n        --    self.IsCreate = true;\n        --end\n        \n        \n        self.Robot:Print(\"=========>Create private room.   UID:\"..self.Robot.Data.UID);\n        -- room_id뵽бУ˼롣\n        \n        local pb_room_info = PublicRoomInfo:new();\n        pb_room_info.RoomType   = ddz_gi.private_room.room_type;\n        pb_room_info.RoomID     = ddz_gi.room_id;\n        pb_room_info.RoomRobots = ddz_gi.player_list;\n        \n        PublicRoomInfoMgr:PushOpenRoom(pb_room_info);\n        \n        self.Robot.GameFsm:SwitchState(\"TInRoomIdlem\");\n    elseif self:GetFsmState()==\"TJoinPrvRoom\" then\n        self.Robot:Print(\"=========>Join private room.   UID:\"..self.Robot.Data.UID);\n        self.Robot.GameFsm:SwitchState(\"TInRoomIdlem\");\n    else\n        \n        self.Robot:Print(\"=========>Refresh private room.   UID:\"..self.Robot.Data.UID);\n    end\nend\n\n-- ҵ׼Լ͸״̬\nfunction RobotGameDdz:cbDdzUserStartReady( msgin )\n    \n    local ready_uid = msgin:rpb(\"PB.MsgInt\");\n    \n    if self.Robot.Data.UID==ready_uid then\n        self.SelfData.state = SetBit( self.SelfData.state, enum.STATE_DDZ_READY );\n        self.Robot:Print(\"cbDdzUserStartReady\");\n    end\nend\n\nfunction RobotGameDdz:cbDDZ_QDZ_QX( msg_qdz )\n    self.Robot:Print(\"SELF:\"..self.Robot.Data.UID..\"    cbDDZ_QDZ_QX  UID:\"..msg_qdz.playid..\"  WIK:\"..msg_qdz.qingdizhu_wiki);\n    \n    if self.Robot.Data.UID==msg_qdz.playid then\n        \n        if msg_qdz.qingdizhu_wiki > 0 then\n            \n            local select_wki_list = {};\n            \n            for i=1,10 do\n                if GetBit( msg_qdz.qingdizhu_wiki, i ) then\n                    table.insert(select_wki_list, i);\n                end\n            end\n            \n            if #select_wki_list==0 then\n                nlwarning(\"#select_wki_list==0\");\n                return;\n            end\n            \n            local rnd           = math.random(#select_wki_list);\n            local select_wki    = select_wki_list[rnd];\n            \n            self.Robot:Print(\"Select WKI:\"..select_wki);\n            local MsgQiangDiZhuResult = { result=select_wki };\n            self.Robot:Send( \"DDZ_QDZ\", \"PB.MsgQiangDiZhuResult\", MsgQiangDiZhuResult );\n        end\n    end\nend\n\nfunction RobotGameDdz:cbDDZ_QDZ_F( msg_qdz_res )\n\n    -- ǵˢ\n    for _,v in ipairs(msg_qdz_res.player_list) do\n        if v.playid==self.Robot.Data.UID and #v.dizhu_cards>0 then\n            self.HandCards = v.dizhu_cards;\n            self.Robot:Print(\"Refresh DiZhu HandCards\");\n            break;\n        end\n    end\n    \n    local MsgJiaBeiResult = {\n        result = math.random(2)\n    };\n\n    self.Robot:Send( \"DDZ_JB\", \"PB.MsgJiaBeiResult\", MsgJiaBeiResult );\nend\n\n-- ֵҳ\nfunction RobotGameDdz:cbDDZ_RA( msg_ddz_act )\n    \n    self.Robot:PrintTable( msg_ddz_act );\n    \n    if msg_ddz_act.new_actionid == self:__UID() then\n        self.WIK      = msg_ddz_act.wik;\n    elseif msg_ddz_act.old_actionid == self:__UID() then\n\n        self.WIK      = msg_ddz_act.wik;\n        \n        -- ѳ\n        for i,v in ipairs(self.HandCards) do\n            if v==msg_ddz_act.last_out_cards[1] then\n                table.remove( self.HandCards, i );\n                break;\n            end\n        end\n    end\n    \n    if self:GetFsmState()~=\"TAction\" then\n        self.Robot.GameFsm:SwitchState(\"TAction\");\n    end\nend\n\nfunction RobotGameDdz:cbDDZ_SD( msg_ddz_sd )\n    self.Robot:PrintTable( msg_ddz_sd );\n    self.Robot.GameFsm:SwitchState(\"TShowDown\");\nend\n\n\nreturn RobotGameDdz;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/PublicRoomInfo.lua",
    "content": "local PublicRoomInfo = class(\"PublicRoomInfo\")\n\nfunction PublicRoomInfo:ctor()\n\t\n    self.RoomType       = \"\";\n    self.RoomID         = -1;\n\n    self.RoomRobots     = {};\nend\n\n\n\nreturn PublicRoomInfo;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/PublicRoomInfoMgr.lua",
    "content": "PublicRoomInfoMgr = {}\n\n-- Ϣrobot佻Ϣʹá\nfunction PublicRoomInfoMgr:Init()\n\t\n    self.Rooms      =   {};  -- room_tyype, {room_prvid,  room_ins}\nend\n\n\nfunction PublicRoomInfoMgr:PushOpenRoom( room_info )\n    \n    if self.Rooms[room_info.RoomType] == nil then\n        self.Rooms[room_info.RoomType] = {};\n    end\n    \n    self.Rooms[room_info.RoomType][room_info.RoomID] = room_info;\nend\n\nfunction PublicRoomInfoMgr:RemoveOpenRoom( room_type, room_prvid )\n\tself.Rooms[room_prvid] = nil;\nend\n\nfunction PublicRoomInfoMgr:GetOpenRoom( room_type )\n    local rooms = self.Rooms[room_type];\n    \n    if rooms~=nil then\n        for _,v in pairs(rooms) do\n            return v;\n        end    \n    end\n\n    return nil;\nend\n\nreturn PublicRoomInfoMgr;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/Robot.lua",
    "content": "local Robot = class(\"Robot\")\n\nfunction Robot:ctor()\n\t\n    self.Data               = RobotData:new();\n    self.Fsm                = FSMRobot:new();\n    self.Fsm:Init(self);\n    \n    self.Net        = bin_types.LuaCallbackClient.NewInstance(\"tcp\");\n\nend\n\nfunction Robot:Init( net_handle )\n    self.Net:SetHandle(net_handle);\nend\n\nfunction Robot:Update()\n    self.Net:Update();\n\n    self.Fsm:TickUpdate();\n\n    if self.GameFsm~=nil then\n        self.GameFsm:TickUpdate();\n        self.Game:Update();\n\n    end\nend\n\nfunction Robot:GetHandle()\n    return self.Net:GetHandle();\nend\n\nfunction Robot:Connected()\n    return self.Net:Connected();\nend\n\n-- ʼϷ߼\nfunction Robot:StartGameTest()\n    if self.Data.Game == \"RM_DDZ\"\tthen\n        self.Game                   = RobotGameDdz:new();\n        self.Game.Robot             = self;\n        self.GameFsm                = FSMDdz:new();\n        self.GameFsm:Init(self);\n    end\nend\n\nfunction Robot:PrintTable( tbl )\n    RobotMgr:PrintTable(tbl, self.Data.UID);\nend\n    \nfunction Robot:Print( str )\n    RobotMgr:Print(str, self.Data.UID);\nend\n\nfunction Robot:Login()\n    \n    local login_url     = \"http://127.0.0.1/www/login/login_test.php\";\n    local login_params  = \"?Channel=REG&GameType=\"..self.Data.Game..\"&User=\"..self.Data.User..\"&AppName=WX_5E8A\";\n    local http_res      = Net.HttpGet(login_url..login_params);\n    \n    if http_res==nil or #http_res<20 then\n        nlwarning(\"http login error\")\n        return\n    end\n    \n    local http_tb       = Json2Table(http_res);\n\n    self:PrintTable(http_tb)\n\n    self.Net:Connect(\"127.0.0.1:9999\");\n\n    if self.Net:Connected() then\n\n        local proto_msg = {\n            UID         = http_tb.UID,\n            Channel     = \"REG\",\n            RoomType    = \"RM_DDZ\",\n            AppName     = \"WX_5E8A\",\n            User        = self.Data.User,\n            NonceStr    = http_tb.NonceStr,\n            Timestamp   = http_tb.Timestamp,\n            Token       = http_tb.Token,\n        }\n\n        self:Send( \"LOGIN\", \"PB.MsgLogin\", proto_msg )\n\n        self:Print(\"Login :\"..self.Data.User);\n        return true;\n    else\n        nlwarning(\"Connect Error :\"..self.Data.User);\n    end\n\n    return false;\nend\n\nfunction Robot:HeartBeat()\n    local msgout    = CMessage(\"HB\");\n    self.Net:Send( msgout );\nend\n\nfunction Robot:Send( msgname, proto_type, proto_msg )\n    local msg   = CMessage(msgname);\n    if proto_type~=nil then\n        local code  = protobuf.encode(proto_type, proto_msg);\n        msg:wstring(code);\n    end\n    self.Net:Send( msg );\nend\n\n\n\nfunction Robot:cbSyncPlayerInfo( msgin )\n    local player_info = msgin:rpb(\"PB.MsgPlayerInfo\");\n\n    if player_info==nil then\n        nlwarning(\"player_info==nil !!!!!!!!!\");\n        return;\n    end\n    \n    self:Print(\"Robot:cbSyncPlayerInfo\");\n    self:PrintTable(player_info);\n    \n    self.Data.UID   = player_info.UID;\n    \n    \nend\n\n\nreturn Robot;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/RobotData.lua",
    "content": "local RobotData = class(\"RobotData\")\n\nfunction RobotData:ctor()\n\t\n    self.UID            = 0;\n    self.User           = \"\";\n    self._RoomState     = 0;\n    \n\n\n    -- robot \n    self.Game           = \"\";\nend\n\nfunction RobotData:ClearRoomState( enum_val )\n    if enum_val~=nil then\n        self._RoomState = ClearBit(self._RoomState, enum_val);\n    end\nend\n\nfunction RobotData:ClearRoomAllState()\n    self._RoomState = 0;\nend\n\nfunction RobotData:GetRoomState( enum_val )\n    \n    if enum_val==nil then\n        return self._RoomState;\n    end\n    \n    return GetBit(self._RoomState, enum_val);\nend\n\nfunction RobotData:SetRoomState( enum_val )\n    if enum_val~=nil then\n        self._RoomState = SetBit(self._RoomState, enum_val);\n    end\nend\n\nreturn RobotData;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/RobotGameBase.lua",
    "content": "local RobotGameBase = class(\"RobotGameBase\")\n\nfunction RobotGameBase:ctor()\n\t\n\n\n\nend\n\nfunction RobotGameBase:Update()\n    \n\nend\n\n\n\nreturn RobotGameBase;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/RobotMgr.lua",
    "content": "RobotMgr = {}\n\nfunction RobotMgr:Init()\n\t\n\tself._EventRegister = EventRegister.new();\n    -- ̼߳Ϣ\n\tself._EventRegister:RegisterEvent( \"TestSubProc\",  self, self.LuaTestCB );\n\n\n    -- Ϣ\n    self._EventRegister:RegisterEvent( \"AuthOk\",            self, self.cbAuthOk );\n    self._EventRegister:RegisterEvent( \"SyncPlayerInfo\",    self, self.cbSyncPlayerInfo );\n\n    -- Ϣ\n    self._EventRegister:RegisterEvent( \"DDZ_GI\",            self, self.cbDdzGameInfo );\n    self._EventRegister:RegisterEvent( \"DDZ_SR\",            self, self.cbDdzUserStartReady );\n    self._EventRegister:RegisterEvent( \"DDZ_QDZ_QX\",        self, self.cbDDZ_QDZ_QX );\n    self._EventRegister:RegisterEvent( \"DDZ_QDZ_F\",         self, self.cbDDZ_QDZ_F );\n    self._EventRegister:RegisterEvent( \"DDZ_RA\",            self, self.cbDDZ_RA );\n    self._EventRegister:RegisterEvent( \"DDZ_SD\",            self, self.cbDDZ_SD );\n    \n    \n    \n    \n    \n    \n\n    self.TotalRobot         = nil;\n    self.RobotList          = {};\n    self.PrintFilterWhite   = {};\n    \n    self.MsgNames           = {};\nend\n\nfunction RobotMgr:StartLogic( start_num, total_num )\n\t\n    --self.PrintFilterWhite[1007] = true;\n    \n    self.TotalRobot = total_num;\n\n    for i=1,total_num do\n        local robot                         = Robot:new();\n        robot.Data.User                     = \"test_\" .. start_num+i-1;\n        robot.Data.Game                     = \"RM_DDZ\";\n\n        robot:Init(i);\n        self.RobotList[robot:GetHandle()]   = robot;\n    end\nend\n\nfunction RobotMgr:RegisterMsg( msgname, callbackname )\n    if self.MsgNames[msgname]==nil then\n        self._EventRegister:RegisterEvent( msgname,            self, self.DispatchMsg );\n        self.MsgNames[msgname] = callbackname;\n    end\nend\n\nfunction RobotMgr:DispatchMsg( from, msgin )\n    \n    local robot = self.RobotList[from];\n    if robot~=nil then\n        --robot.Game:cbXXX(msgin);\n    end\nend\n\n\nfunction RobotMgr:Update()\n    for _,v in pairs(self.RobotList) do\n        v:Update();\n    end\nend\n\nfunction RobotMgr:Print( str, id )\n    if (#self.PrintFilterWhite)==0  then\n        nlinfo(\"UID:\"..id .. \"  \"..str);\n    else\n        if self.PrintFilterWhite[id]~=nil then\n            nlinfo(\"UID:\"..id .. \"  \"..str);\n        end\n    end\nend\n\nfunction RobotMgr:PrintTable( tbl, id )\n    if (#self.PrintFilterWhite)==0  then\n        local str = JsonUtil.serialise_value(tbl, indent, depth);\n        nlinfo(\"UID:\"..id .. \"  \"..str);\n    else\n        if self.PrintFilterWhite[id]~=nil then\n            local str = JsonUtil.serialise_value(tbl, indent, depth);\n            nlinfo(\"UID:\"..id .. \"  \"..str);\n        end\n    end\nend\n\nfunction RobotMgr:Release()\n    \nend\n\nfunction RobotMgr:LuaTestCB( from, msgin )\n\n\tlocal msgint  = msgin:rint();\n    local msgstr  = msgin:rstring();\n\t\n\tnlinfo(from);\n\tnlinfo(msgint);\n\tnlinfo(msgstr);\n    \n    \n    local msgout = CMessage(\"TestMainProc\");\n    msgout:wstring(\"TestMainProc\");\n\tMisc.PostMain( G_ThreadHandle, msgout );\nend\n\nfunction RobotMgr:cbAuthOk( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        nlinfo(\"RobotMgr:cbAuthOk\");\n    end\nend\n\nfunction RobotMgr:cbSyncPlayerInfo( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        robot:cbSyncPlayerInfo(msgin);\n    end\nend\n\nfunction RobotMgr:cbDdzGameInfo( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        robot.Game:cbDdzGameInfo(msgin);\n    end\nend\n\nfunction RobotMgr:cbDdzUserStartReady( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        robot.Game:cbDdzUserStartReady(msgin);\n    end\nend\n\nfunction RobotMgr:cbDDZ_QDZ_QX( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        local msg_qdz = msgin:rpb(\"PB.MsgQiangDiZhu\");\n        robot.Game:cbDDZ_QDZ_QX(msg_qdz);\n    end\nend\n\nfunction RobotMgr:cbDDZ_QDZ_F( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        local msg_qdz_res = msgin:rpb(\"PB.MsgBRQiangDiZhuResult\");\n        robot.Game:cbDDZ_QDZ_F(msg_qdz_res);\n    end\nend\n\nfunction RobotMgr:cbDDZ_RA( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        local msg_ddz_act = msgin:rpb(\"PB.MsgDDZActon\");\n        robot.Game:cbDDZ_RA(msg_ddz_act);\n    end\nend\n\nfunction RobotMgr:cbDDZ_SD( from, msgin )\n    local robot = self.RobotList[from];\n    if robot~=nil then\n        local msg_ddz_sd = msgin:rpb(\"PB.MsgDDZRoomShowDown\");\n        robot.Game:cbDDZ_SD(msg_ddz_sd);\n    end\nend\n\n\n\n\nreturn RobotMgr;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/RobotSub/RobotSubStart.lua",
    "content": "local BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"__Robot/RobotSub/?.lua;\" .. BasePath .. \"Framework/?.lua;\";\n\n\nrequire(\"InitFramework\")\nrequire(\"RobotMgr\")\nrequire(\"PublicRoomInfoMgr\")\n\nFSMRobot                = require(\"FSMRobot\")\nRobotGameBase           = require(\"RobotGameBase\")\nRobotData               = require(\"RobotData\")\nRobot                   = require(\"Robot\")\nPublicRoomInfo          = require(\"PublicRoomInfo\")\n\nFSMDdz                  = require(\"GameDdz/FSMDdz\")\nRobotGameDdz            = require(\"GameDdz/RobotGameDdz\")\n\nnlinfo(\"-=======DBSubStart==========-\");\n\n\nG_ThreadHandle = 999;\n\nfunction ThreadInit( thread_handle, params )\n\n    nlinfo(\"Lua ThreadInit:\".. thread_handle);\n\n    nlinfo(params);\n    \n    G_ThreadHandle = thread_handle;\n\n    PublicRoomInfoMgr:Init();\n    RobotMgr:Init();\n\n    RobotMgr:StartLogic(1, 3);\nend\n\n\n\nfunction ThreadUpdate()\n    TimerMgr:Update( Misc.GetLocalTime() );\n    RobotMgr:Update();\nend\n\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/Test/CppTimerBase.lua",
    "content": "\nlocal CppTimerBase = class(\"CppTimerBase\")\n\nfunction CppTimerBase:ctor()\n\tself.val = 0; \n    self._TimerHandle           = TimerMgr:AddTimer( 5000, self, self.TickUpdate);\n    \nend\n\nfunction CppTimerBase:TickUpdate()\n    --nlinfo(\"RoomBase:TickUpdate\");\n    self:BaseTickUpdate();\nend\n\nfunction CppTimerBase:BaseTickUpdate()\n    --nlinfo(\"RoomBase:BaseTickUpdate\");\n    self._TimerHandle = TimerMgr:AddTimer( 5000, self, self.TickUpdate);\n    \n    self.val = self.val+1;\n    print(\"======\"..self.val..\"   _TimerHandle:\"..self._TimerHandle);\n    \n    \nend\n\n--释放函数\nfunction CppTimerBase:Release()\n    self.Timer =  nil;\nend\n\n\nreturn CppTimerBase;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/Test/CppTimerTest.lua",
    "content": "\nlocal CppTimerTest = class(\"CppTimerTest\", CppTimerBase)\n\nfunction CppTimerTest:ctor()\n\tself.super:ctor();\nend\n\nreturn CppTimerTest;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/ThreadMgr.lua",
    "content": "ThreadMgr = {}\n\nfunction ThreadMgr:Init()\n\t\n\tself._EventRegister = EventRegister.new();\n\tself._EventRegister:RegisterEvent( \"TestMainProc\",  self, self.LuaTestCB );\n    \n    self._ThreadMap     = {};\n\nend\n\nfunction ThreadMgr:Strat()\n\t\n    \n    local RobotSubPath = Misc.GetBasePath() .. \"/script/__Robot/RobotSub/RobotSubStart.lua\";\n\n    for i=1003,1003 do\n        \n        local sub_thread    = bin_types.LuaThread.NewInstance(\"robot\", 1000);\n        local thread_handle = sub_thread:Start( RobotSubPath, Table2Json({uid=i, b=2}) );\n    \n        self._ThreadMap[thread_handle] = sub_thread;\n        \n        nlinfo(thread_handle);\n    end\n    \n    \n   \n    local msg = CMessage(\"TestSubProc\");\n    msg:wint(111222);\n    msg:wstring(\"string\");\n\n    self._ThreadMap[0]:Post(msg);\n    \nend\n\n\n\n\nfunction ThreadMgr:LuaTestCB( from, msgin )\n\n    local msgstr  = msgin:rstring();\n\t\n\tnlinfo(from);\n\tnlinfo(msgstr);\nend\n\n\nfunction ThreadMgr:LuaTestCB( from, msgin )\n\n    local msgstr  = msgin:rstring();\n\t\n\tnlinfo(from);\n\tnlinfo(msgstr);\nend\n\n--释放函数\nfunction ThreadMgr:Release()\n    self._EventRegister:UnRegisterAllEvent();\nend\n\n\nreturn ThreadMgr;\n"
  },
  {
    "path": "code/EVA/server/script/__Robot/_ClientRobotMain.lua",
    "content": "--========================================================= \n-- 加载常用模块\n--=========================================================\n\nlocal BasePath = Misc.GetBasePath() .. \"/script/\";\npackage.path = BasePath .. \"__Robot/?.lua;\" .. BasePath .. \"SharedLib/?.lua;\";\n\n\nrequire(\"InitSharedLib\")\nrequire(\"ThreadMgr\");\n\n--CppTimerBase = require(\"Test/CppTimerBase\");\n--CppTimerTest = require(\"Test/CppTimerTest\");\n\n\n-- 主入口函数。从这里开始lua逻辑\nfunction ServiceInit()\n\n    nlinfo(\"Lua Robot Init\");\n    \n    ThreadMgr:Init();\n\n    ThreadMgr:Strat();\n\n    \nend\n\n-- 主循环\nfunction ServiceUpdate()\n\n    local curr_tick = Misc.GetLocalTime();\n    TimerMgr:Update( curr_tick );\nend\n\nfunction ServiceRelease()\n\n    ThreadMgr:Release();\n    nlinfo(\"Lua Release.\");\nend\n\nfunction ServiceInfo()\n    \n\n    \nend\n\n"
  },
  {
    "path": "code/EVA/server/server_share/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.c *.cpp *.h)\nFILE(GLOB SRC_PROTO_MSG         msg_proto/*.h msg_proto/*.cc)\nFILE(GLOB SRC_LUA               lua/*.h lua/*.cpp)\nFILE(GLOB SRC_LUABIND           bin_luabind/*.h bin_luabind/*.cpp)\nFILE(GLOB SRC_LUACJson          cjson/*.h cjson/*.cpp)\nFILE(GLOB SRC_PBC               pbc/*.h pbc/*.cpp)\nFILE(GLOB SRC_LUAMySQL          lua_mysql/*.h lua_mysql/*.cpp)\nFILE(GLOB SRC_LUANET            lua_net/*.h lua_net/*.cpp)\n\nSOURCE_GROUP(\"MessageProto\"     FILES ${SRC_PROTO_MSG})\nSOURCE_GROUP(\"Lua\"              FILES ${SRC_LUA})\nSOURCE_GROUP(\"LuaBind\"          FILES ${SRC_LUABIND})\nSOURCE_GROUP(\"LuaCJson\"         FILES ${SRC_LUACJson})\nSOURCE_GROUP(\"LuaPBC\"           FILES ${SRC_PBC})\nSOURCE_GROUP(\"LuaMySQL\"         FILES ${SRC_LUAMySQL})\nSOURCE_GROUP(\"LuaNet\"           FILES ${SRC_LUANET})\n\nNL_TARGET_LIB(servershare ${SRC} ${SRC_PROTO_MSG} ${SRC_LUA} ${SRC_LUABIND} ${SRC_LUACJson} ${SRC_PBC}  ${SRC_LUAMySQL} ${SRC_LUANET})\n\nINCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/server/src/server_share ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${LUA_INCLUDE_DIR} ${PROTOBUF_INCLUDE_DIR} ${PBC_INCLUDE_DIR} ${CURL_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(  servershare\n\t\t\t\t\t\tnelmisc\n\t\t\t\t\t\tnelnet\n                        ${OPENSSL_LIBRARIES}\n                        ${CURL_LIBRARY}\n                        ${LIBXML2_LIBRARIES}\n\t\t\t\t\t\t${LUA_LIBRARIES}\n#\t\t\t\t\t\t${PBC_LIBRARY}\n\t\t\t\t\t\t${MYSQL_LIBRARIES}\n                        ${ZLIB_LIBRARIE_RELEASE}\n                        )\n\nNL_DEFAULT_PROPS(servershare \"Base, Library: Service Shared\")\nNL_ADD_RUNTIME_FLAGS(servershare)\nNL_ADD_LIB_SUFFIX(servershare)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH)\n  ADD_NATIVE_PRECOMPILED_HEADER(servershare ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.h ${CMAKE_CURRENT_SOURCE_DIR}/stdpch.cpp)\nENDIF(WITH_PCH)\n\n#INSTALL(TARGETS servershare LIBRARY DESTINATION ${EVA_LIB_PREFIX} ARCHIVE DESTINATION ${EVA_LIB_PREFIX} COMPONENT libraries)\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS servershare LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/base_object.h",
    "content": "#ifndef BASE_OBJECT_H\n#define BASE_OBJECT_H\n\n\nclass CBaseObject\n{\n\n};\n\n\n\n\n#endif\n\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/Public.h",
    "content": "#ifndef SERVER_SHARD_LUA_PUBLIC_H\n#define SERVER_SHARD_LUA_PUBLIC_H\n\n#ifndef LUA_COMPAT_MODULE\n#define LUA_COMPAT_MODULE\n#endif\n\n#include \"lua.hpp\"\n\n#include <cassert>\n#include <iostream>\n#include <string>\n\n#include <nel/misc/debug.h>\n\n#define     LOG_MESSAGE     nlwarning\n\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/Public.hpp",
    "content": "#pragma once\n\n#include \"ScriptBase.h\"\n#include \"ScriptHandle.h\"\n#include \"ScriptProxy.h\"\n#include \"ScriptExporter.h\"\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptBase.cpp",
    "content": "#ifndef NL_OS_WINDOWS\n#include \"ScriptBase.h\"\n#include \"ScriptExporter.h\"\n#include \"ScriptProxy.h\"\n\nnamespace bin\n{\n    /*\n    template <typename O>\t// If a object, must be a proxy\n    int TToLua<O*>::Make(O* o, lua_State* pL)\n    {\n        int nRet = 0;\n        if (o)\n        {\n            if (o->GetScriptObject().IsExported())\n            {\n                nRet = o->GetScriptObject().GetUserData(pL);\n            }\n            else\n            {\n                nRet = bin::ScriptExporterManager().AddScriptObject(o, pL);\n            }\n        }\n\n        if (!nRet)\n        {\n            lua_pushnil(pL);\n\n            nRet = 1;\n        }\n\n        return nRet;\n    }\n    \n\n    template <typename O>\t// If a object, must be a proxy\n    int TFmLua<O*>::Make(lua_State* pL, int nIdx, O*& o)\n    {\n        o = NULL;\n\n        if (!lua_isuserdata(pL, nIdx))\n        {\n            return 0;\n        }\n\n        void* pUd = lua_touserdata(pL, nIdx);\n        if (!pUd)\n        {\n            return 0;\n        }\n\n        SScriptProxy* pProxy = (SScriptProxy*)pUd;\n\n        if (!(pProxy->ePT&SScriptProxy::EPT_OBJECT))\n        {\n            return 0;\n        }\n\n        if (!pProxy->objRef.pObject)\n        {\n            return 0;\n        }\n\n        o = reinterpret_cast<O*>(pProxy->objRef.pObject->m_pThis);\n\n        return 1;\n    }\n    */\n};\n\n\n\n#endif // !NL_OS_WINDOWS\n\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptBase.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_BASE_H\n#define SERVER_SHARD_SCRIPT_BASE_H\n\n#include \"Public.h\"\n#include \"ScriptProxy.h\"\n\nnamespace bin\n{\n\tstatic const char* SCRIPT_OWN_OBJECTS\t= \"__bin_own_objects\";\n\tstatic const char* SCRIPT_USE_OBJECTS   = \"__bin_use_objects\";\n\tstatic const char* SCRIPT_REFS\t\t= \"__bin_refs\";\n\tstatic const char* SCRIPT_TYPES\t\t= \"__bin_types\";\n\n\t//extern void LOG_MESSAGE(const char* pszFmt, ...);\n\n\tclass INonCopyable \n\t{\n\tpublic:\n\t\tINonCopyable(){}\n\n\t\tINonCopyable(INonCopyable&);\n\t\tINonCopyable& operator = (INonCopyable&);\n\t};\n\n\tstruct SCheckLuaStack\n\t{\n\t\tlua_State*\t\tpLua;\n\t\tint\t\t\t\tnTop;\n\t\tSCheckLuaStack(lua_State* pL)\n\t\t\t: pLua(pL)\n\t\t\t, nTop(-1)\n\t\t{\n\t\t\tif(pLua)\n\t\t\t{\n\t\t\t\tnTop = lua_gettop(pLua);\n\t\t\t}\n\t\t}\n\n\t\t~SCheckLuaStack()\n\t\t{\n\t\t\tif(pLua)\n\t\t\t{\n\t\t\t\tlua_settop(pLua, nTop);\n\t\t\t\tpLua = NULL;\n\t\t\t\tnTop = -1;\n\t\t\t}\n\t\t}\n\t};\n\n#define CHECK_LUA_STACK(l)\tSCheckLuaStack __checkStack(l)\n\n\tstruct SGuardLuaGC\n\t{\n\t\tlua_State*\t\tpLua;\n\t\tSGuardLuaGC(lua_State* pL)\n\t\t\t: pLua(pL)\n\t\t{\n\t\t\tif(pLua)\n\t\t\t{\n\t\t\t\tlua_gc(pLua, LUA_GCSTOP, 0);\n\t\t\t}\n\t\t}\n\n\t\t~SGuardLuaGC()\n\t\t{\n\t\t\tif(pLua)\n\t\t\t{\n\t\t\t\tlua_gc(pLua, LUA_GCRESTART, 0);\n\n\t\t\t\tpLua = NULL;\n\t\t\t}\n\t\t}\n\t};\n#define GUARD_LUA_GC(l)\tSGuardLuaGC __guardGC(l)\n\n\tstruct SVoidType\n\t{\n\n\t};\n\n\tinline SVoidType __ret_void_tag() { return SVoidType();}\n#define RET_VOID bin::__ret_void_tag()\n\n\ttemplate <typename R>\n\tstruct TRetType\n\t{\n\t\ttypedef R return_type;\n\t};\n\n\ttemplate <>\n\tstruct TRetType<void>\n\t{\n\t\ttypedef SVoidType return_type;\n\t};\n\n\ttemplate <typename R>\n\tstruct TToLua;\n\n\ttemplate <>\n\tstruct TToLua<SVoidType>\n\t{\n\t\tstatic int Make(SVoidType v, lua_State* pL)\n\t\t{\n\t\t\tlua_pushnil(pL);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TToLua<bool>\n\t{\n\t\tstatic int Make(bool a, lua_State* pL)\n\t\t{\n\t\t\tlua_pushboolean(pL, a);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\t//template <>\n\t//struct TToLua<int>\n\t//{\n\t//\tstatic int Make(int a, lua_State* pL)\n\t//\t{\n\t//\t\tlua_pushinteger(pL, (LUA_INTEGER)a);\n\n\t//\t\treturn 1;\n\t//\t}\n\t//};\n\n\ttemplate <>\n\tstruct TToLua<double>\n\t{\n\t\tstatic int Make(double a, lua_State* pL)\n\t\t{\n\t\t\tlua_pushnumber(pL, a);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TToLua<sint64>\n\t{\n\t\tstatic int Make(sint64 a, lua_State* pL)\n\t\t{\n\t\t\tlua_pushinteger(pL, (LUA_INTEGER)a);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n    template <>\n    struct TToLua<sint32>\n    {\n        static int Make(sint32 a, lua_State* pL)\n        {\n            lua_pushinteger(pL, (LUA_INTEGER)a);\n\n            return 1;\n        }\n    };\n\n\ttemplate <>\n\tstruct TToLua<char*>\n\t{\n\t\tstatic int Make(char* a, lua_State* pL)\n\t\t{\n\t\t\tlua_pushstring(pL, a);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TToLua<const char*>\n\t{\n\t\tstatic int Make(const char* a, lua_State* pL)\n\t\t{\n\t\t\tlua_pushstring(pL, a);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TToLua<std::string>\n\t{\n\t\tstatic int Make(const std::string& a, lua_State* pL)\n\t\t{\n            lua_pushlstring(pL, a.c_str(), a.size());\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <typename O>\t// If a object, must be a proxy\n\tstruct TToLua<O*>\t\n\t{\n//#ifdef NL_OS_WINDOWS\n        static int Make(O* o, lua_State* pL)\n\t\t{\n\t\t\tint nRet = 0;\n\t\t\tif(o)\n\t\t\t{\n\t\t\t\tif(o->GetScriptObject().IsExported())\n\t\t\t\t{\n\t\t\t\t\tnRet = o->GetScriptObject().GetUserData(pL);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnRet = o->AddScriptObject(pL); //ScriptExporterManager().AddScriptObject(o, pL);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(!nRet)\n\t\t\t{\n\t\t\t\tlua_pushnil(pL);\n\n\t\t\t\tnRet = 1;\n\t\t\t}\n\n\t\t\treturn nRet;\n\t\t}\n//#else\n//        static int Make(O* o, lua_State* pL);\n//#endif\n\t};\n\n\ttemplate <typename A>\n\tstruct TFmLua;\n\n\ttemplate <>\n\tstruct TFmLua<SVoidType>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, SVoidType& v)\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<bool>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, bool& b)\n\t\t{\n\t\t\tif(!lua_isboolean(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tb = lua_toboolean(pL, nIdx)!=0;\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\t\n\ttemplate <>\n\tstruct TFmLua<sint32>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, sint32& a)\n\t\t{\n\t\t\tif(!lua_isnumber(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\ta = (sint32)lua_tointeger(pL, nIdx);\n\t\t\t\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<sint64>\t\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, sint64& a)\n\t\t{\n\t\t\tif(!lua_isnumber(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\ta = (sint64)lua_tointeger(pL, nIdx);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<double>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, double& d)\n\t\t{\n\t\t\tif(!lua_isnumber(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\td = lua_tonumber(pL, nIdx);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<std::string>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, std::string& str)\n\t\t{\n\t\t\tif(!lua_isstring(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tstr = lua_tostring(pL, nIdx);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<const char*>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, const char*& cstr)\n\t\t{\n\t\t\tif(!lua_isstring(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tcstr = lua_tostring(pL, nIdx);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n\n\t// Partial specialization Not support by function, use class instead\n\ttemplate <typename O>\t// If a object, must be a proxy\n\tstruct TFmLua<O*>\t\n\t{\n//#ifdef NL_OS_WINDOWS\n\t\tstatic int Make(lua_State* pL, int nIdx, O*& o)\n\t\t{\n\t\t\to = NULL;\n\n\t\t\tif(!lua_isuserdata(pL, nIdx))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\tvoid* pUd = lua_touserdata(pL, nIdx);\n\t\t\tif(!pUd)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tSScriptProxy* pProxy = (SScriptProxy*)pUd;\n\t\t\t\n\t\t\tif(!(pProxy->ePT&SScriptProxy::EPT_OBJECT))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n            if(!pProxy->objRef.pObject)\n            {\n                return 0;\n            }\n\n\t\t\t//o = reinterpret_cast<O*>(pProxy->objRef.pObject->m_pThis);\n            o = reinterpret_cast<O*>(pProxy->objRef.GetScriptObj());\n\n\t\t\treturn 1;\n\t\t}\n//#else\n//        static int Make(lua_State* pL, int nIdx, O*& o);\n//#endif\n\t};\n\n\ttemplate <typename T>\n\tstruct TArgumentType\n\t{\n\t\ttypedef T\t\t\tvalue_type;\n\t\ttypedef T&\t\t\targument_type;\n\t\ttypedef const T&\tc_argument_type;\n\t};\n\n\ttemplate <typename T>\n\tstruct TArgumentType<T&>\n\t{\n\t\ttypedef T\t\t\tvalue_type;\n\t\ttypedef T&\t\t\targument_type;\n\t\ttypedef const T&\tc_argument_type;\n\t};\n\n\ttemplate <typename T>\n\tstruct TArgumentType<const T&>\n\t{\n\t\ttypedef T\t\t\tvalue_type;\n\t\ttypedef T&\t\t\targument_type;\n\t\ttypedef const T&\tc_argument_type;\n\t};\n\n\ttemplate <typename T>\n\tstruct TArgumentType<T*>\n\t{\n\t\ttypedef T*\t\t\tvalue_type;\n\t\ttypedef T*\t\t\targument_type;\n\t\ttypedef T*\t\t\tc_argument_type;\n\t};\n\n\ttemplate <>\n\tstruct TArgumentType<void>\n\t{\n\t\ttypedef SVoidType\tvalue_type;\n\t\ttypedef SVoidType\targument_type;\n\t\ttypedef SVoidType\tc_argument_type;\n\t};\n\n\ttemplate <>\n\tstruct TArgumentType<int>\n\t{\n\t\ttypedef int\t\tvalue_type;\n\t\ttypedef int\t\targument_type;\n\t\ttypedef int\t\tc_argument_type;\n\t};\n\n\ttemplate <>\n\tstruct TArgumentType<bool>\n\t{\n\t\ttypedef bool\t\tvalue_type;\n\t\ttypedef bool\t\targument_type;\n\t\ttypedef bool\t\tc_argument_type;\n\t};\n\n\ttemplate <>\n\tstruct TArgumentType<double>\n\t{\n\t\ttypedef double\t\tvalue_type;\n\t\ttypedef double\t\targument_type;\n\t\ttypedef double\t\tc_argument_type;\n\t};\n\n\ttemplate <>\n\tstruct TArgumentType<long long>\n\t{\n\t\ttypedef long long\t\tvalue_type;\n\t\ttypedef long long\t\targument_type;\n\t\ttypedef long long\t\tc_argument_type;\n\t};\n\n\ttemplate <typename F, typename T>\n\tstruct TLuaFuncCaller;\n\n\ttemplate <typename F, typename R>\n\tstruct TLuaFuncCaller<F, R()>\n\t{\n\t\tF*\t\t\t\tpFun;\n\t\tlua_State*\t\tpLua;\n\n\t\tTLuaFuncCaller(lua_State* pL, F* pF)\n\t\t\t: pLua(pL), pFun(pF)\n\t\t{\n\t\t\tassert(pLua && pFun);\n\t\t}\n\n\t\tint MakeArgs()\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\n\t\tint MakeCArgs()\n\t\t{\n\t\t\tTFmLua<typename F::class_type*>::Make(pLua, 1, pFun->obj);\n\t\t\tif(!pFun->obj)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tint Call()\n\t\t{\n\t\t\treturn pFun->Exec();\n\t\t}\n\n\t\tint MakeRet()\n\t\t{\n\t\t\treturn TToLua<typename F::return_type>::Make(pFun->r, pLua);\n\t\t}\n\t};\n\n\ttemplate <typename F, typename R, typename A>\n\tstruct TLuaFuncCaller<F, R(A)>\n\t{\n\t\ttypedef typename TArgumentType<A>::value_type Arg; \n\t\tArg\t\t\t\t\t\t\t\ta;\n\t\tF*\t\t\t\t\t\t\t\tpFun;\n\t\tlua_State*\t\t\t\t\t\tpLua;\n\t\t\n\t\tTLuaFuncCaller(lua_State* pL, F* pF)\n\t\t\t: pLua(pL), pFun(pF)\n\t\t{\n\t\t\tassert(pLua && pFun);\n\t\t}\n\n\t\tint MakeArgs()\n\t\t{\n\t\t\tTFmLua<Arg>::Make(pLua, 1, a);\n\t\t\treturn 1;\n\t\t}\n\n\t\tint MakeCArgs()\n\t\t{\n\t\t\tTFmLua<typename F::class_type*>::Make(pLua, 1, pFun->obj);\n\t\t\tif(!pFun->obj)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tTFmLua<Arg>::Make(pLua, 2, a);\n\t\t\treturn 1;\n\t\t}\n\n\t\tint Call()\n\t\t{\n\t\t\treturn pFun->Exec(a);\n\t\t}\n\n\t\tint MakeRet()\n\t\t{\n\t\t\treturn TToLua<typename F::return_type>::Make(pFun->r, pLua);\n\t\t}\n\t};\n\n\ttemplate <typename F, typename R, typename A0, typename A1>\n\tstruct TLuaFuncCaller<F, R(A0, A1)>\n\t{\n\t\ttypedef typename TArgumentType<A0>::value_type Arg0;\n\t\ttypedef typename TArgumentType<A1>::value_type Arg1;\n\n\t\tArg0\t\t\t\t\t\t\ta0;\n\t\tArg1\t\t\t\t\t\t\ta1;\n\t\tF*\t\t\t\t\t\t\t\tpFun;\n\t\tlua_State*\t\t\t\t\t\tpLua;\n\n\t\tTLuaFuncCaller(lua_State* pL, F* pF)\n\t\t\t: pLua(pL), pFun(pF)\n\t\t{\n\t\t\tassert(pLua && pFun);\n\t\t}\n\n\t\tint MakeArgs()\n\t\t{\n\t\t\tTFmLua<Arg0>::Make(pLua, 1, a0);\n\t\t\tTFmLua<Arg1>::Make(pLua, 2, a1);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tint MakeCArgs()\n\t\t{\n\t\t\tTFmLua<typename F::class_type*>::Make(pLua, 1, pFun->obj);\n\t\t\tif(!pFun->obj)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\tTFmLua<Arg0>::Make(pLua, 2, a0);\n\t\t\tTFmLua<Arg1>::Make(pLua, 3, a1);\n\t\t\t\n\t\t\treturn 1;\n\t\t}\n\n\t\tint Call()\n\t\t{\n\t\t\treturn pFun->Exec(a0, a1);\n\t\t}\n\n\t\tint MakeRet()\n\t\t{\n\t\t\treturn TToLua<typename F::return_type>::Make(pFun->r, pLua);\n\t\t}\n\t};\n\n//! Define a script module(a lua table)\n//! \\param modName the name of table\n#define BEGIN_SCRIPT_MODULE(modName)\\\nnamespace __module_ ## modName\\\n{\\\n\tnamespace __module = __module_ ## modName;\\\n\tstatic const char* __pszName = #modName;\\\n\tstruct SModuleFunction_ ## modName;\\\n\ttypedef SModuleFunction_ ## modName __mf_LinkNode;\\\n\tstatic __mf_LinkNode* __pHead = NULL;\\\n\tstruct SModuleFunction_ ## modName : ModuleFunctionLinkNode\\\n\t{\\\n\t\tSModuleFunction_ ## modName(const char* pN, lua_CFunction pF)\\\n\t\t{\\\n\t\t\tpszName\t\t\t  = pN;\\\n\t\t\tpFunc\t\t\t  = pF;\\\n\t\t\tpNxt\t          = __module::__pHead;\\\n\t\t\t__module::__pHead = this;\\\n\t\t}\\\n\t};\n\t\n//! Define a module function(a function of the lua tabel)\n//! \\param name name of function\n//! \\param ret return type\n//! \\param args the arguments\n//! for example : \n//! DEFINE_MODULE_FUNCTION(func, std::string, (int a0, int a1))\n//! {\n//!     int v = a0+a1;\t\t\t\t// a0 and a1 comes from lua\n//!\t\tr = \"this is return value\";\t// The return value to lua\n//!     return 1;\t\t\t\t\t// return 1 means succeed, not the return value to lua\n//! }\n#define DEFINE_MODULE_FUNCTION(name, ret, args)\\\n\tstruct __mf_Impl_##name\\\n\t{\\\n\t\ttypedef TRetType< ret >::return_type return_type;\\\n\t\treturn_type\t r;\\\n\t\tbin::CScriptHandle lua;\\\n\t\tint Exec args;\\\n\t};\\\n\tstatic int __mf_lua_ ## name(lua_State* pL)\\\n\t{\\\n\t\t__mf_Impl_##name __mf_impl;\\\n\t\t__mf_impl.lua.Init(pL);\\\n\t\tTLuaFuncCaller<__mf_Impl_##name, ret args> caller(pL, &__mf_impl);\\\n\t\tif(!caller.MakeArgs() || !caller.Call() || !caller.MakeRet())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\treturn 1;\\\n\t}\\\n\tstatic __mf_LinkNode __mf_node_ ## name(#name, &__mf_lua_ ## name);\\\n\tint __mf_Impl_##name::Exec args\n\n//! End the definition of a module.\n#define END_SCRIPT_MODULE()\\\n\tstatic CModuleExporter __exporter(__module::__pszName, (ModuleFunctionLinkNode**)&__module::__pHead);\\\n};\n\n//! Define a script class.\n//! \\param clsName the name of this class.\n//! \\param cppName the c++ class name\n#define BEGIN_SCRIPT_CLASS(clsName, cppName)\\\nnamespace __class_ ## clsName\\\n{\\\n\tnamespace __class = __class_ ## clsName;\\\n\ttypedef cppName\tclass_type;\\\n\tconst char* __pszName = #clsName;\\\n\tconst char* __pszSuper = NULL;\\\n    struct SClassFunction_ ## clsName;\\\n    typedef SClassFunction_ ## clsName __cf_LinkNode;\\\n    static __cf_LinkNode* __pHead = NULL;\\\n    struct SClassFunction_ ## clsName : ClassFunctionLinkNode\\\n    {\\\n        SClassFunction_ ## clsName(const char* pN, lua_CFunction pF)\\\n        {\\\n            pszName\t\t\t  = pN;\\\n            pFunc\t\t\t  = pF;\\\n            pNxt\t          = __class::__pHead;\\\n            __class::__pHead = this;\\\n        }\\\n    };\n\n//! Indicates the super class name.\n//! \\param clsName the lua class name.\n//! \\param cppName the c++ class name.\n#define SUPER_CLASS(clsName, cppName)\\\n\tstruct SSetSuper_ ## clsName\\\n\t{\\\n\t\tSSetSuper_ ## clsName()\\\n\t\t{\\\n\t\t\t__class::__pszSuper = #clsName;\\\n\t\t}\\\n\t};\\\n\tSSetSuper_ ## clsName __setSuper;\n\n//! Define a class member function. you can access the c++ object by obj and return the value by set value to r.\n//! If the userdata is invalid, obj is null.\n#define DEFINE_CLASS_FUNCTION(name, ret, args)\\\n\tstruct __cf_Impl_##name\\\n\t{\\\n\ttypedef TRetType< ret >::return_type return_type;\\\n\ttypedef __class::class_type\t\t\t class_type;\\\n\tclass_type*  obj;\\\n\treturn_type\t r;\\\n\tint Exec args;\\\n\t};\\\n\tstatic int __cf_lua_ ## name(lua_State* pL)\\\n\t{\\\n\t\t__cf_Impl_##name __cf_impl;\\\n\t\tTLuaFuncCaller<__cf_Impl_##name, ret args> caller(pL, &__cf_impl);\\\n\t\tif(!caller.MakeCArgs() || !caller.Call() || !caller.MakeRet())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\treturn 1;\\\n\t}\\\n    static __cf_LinkNode __cf_node_ ## name(#name, &__cf_lua_ ## name);\\\n\tint __cf_Impl_##name::Exec args\n\n#define DEFINE_STATIC_FUNCTION(name, ret, args)\\\n\tstruct __cf_Impl_##name\\\n\t{\\\n\ttypedef TRetType< ret >::return_type return_type;\\\n\ttypedef __class::class_type\t\t\t class_type;\\\n\treturn_type\t r;\\\n\tint Exec args;\\\n\t};\\\n\tstatic int __cf_lua_ ## name(lua_State* pL)\\\n\t{\\\n\t\t__cf_Impl_##name __cf_impl;\\\n\t\tTLuaFuncCaller<__cf_Impl_##name, ret args> caller(pL, &__cf_impl);\\\n\t\tif(!caller.MakeArgs() || !caller.Call() || !caller.MakeRet())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\treturn 1;\\\n\t}\\\n    static __cf_LinkNode __cf_node_ ## name(#name, &__cf_lua_ ## name);\\\n\tint __cf_Impl_##name::Exec args\n\n//! End the definition of a class.\n#define END_SCRIPT_CLASS()\\\n\tstatic CClassExporter __exporter(__class::__pszSuper, __class::__pszName, (ClassFunctionLinkNode**)&__class::__pHead);\\\n    struct __cf_Record\\\n    {\\\n        __cf_Record()\\\n        {\\\n            __class::class_type::ClassExporter() = &__class::__exporter;\\\n        }\\\n    };\\\n    static __cf_Record __recorder;\\\n};\n\n//! Declare a class will be a script class. this declaration must be the base class, any sub-class of the class must be taged with DECLARE_SCRIPT_SUB_CLASS.\n#define DECLARE_SCRIPT_CLASS()\\\npublic:\\\n\tbin::SScriptObject           __m_scrObj;\\\n\tconst bin::SScriptObject& GetScriptObject() const\\\n\t{\\\n\t\treturn __m_scrObj;\\\n\t}\\\n\tbin::SScriptObject& GetScriptObject()\\\n\t{\\\n\t\treturn __m_scrObj;\\\n\t}\\\n    int AddScriptObject( lua_State* pL )\\\n\t{\\\n        return bin::ScriptExporterManager().AddScriptObject(this, pL);\\\n\t}\\\n\tbin::CScriptHandle& GetScriptHandle()\\\n\t{\\\n\t\treturn GetScriptObject().GetScriptHandle();\\\n\t}\\\n\tint GetScriptUserData(bin::CScriptUserData& scriptUserData)\\\n\t{\\\n\t\treturn GetScriptObject().GetUserData(scriptUserData);\\\n\t}\\\n\tbool IsExported()\\\n\t{\\\n\t\treturn GetScriptObject().IsExported();\\\n\t}\\\n\tvirtual bin::CClassExporter* GetExporter() const\\\n\t{\\\n\t\treturn ClassExporter();\\\n\t}\\\n\tstatic bin::CClassExporter*& ClassExporter()\\\n    {\\\n        static bin::CClassExporter* s_exporter = NULL;\\\n        return s_exporter;\\\n    }\\\nprivate:\n\n//! Taged a child class\n#define DECLARE_SCRIPT_SUB_CLASS(superCls)\\\n\tpublic:\\\n\ttypedef superCls Super;\\\n\tvirtual bin::CClassExporter* GetExporter() const\\\n\t{\\\n\t\treturn ClassExporter();\\\n\t}\\\n\tstatic bin::CClassExporter*& ClassExporter()\\\n\t{\\\n\t\tstatic bin::CClassExporter* s_exporter = NULL;\\\n\t\treturn s_exporter;\\\n\t}\\\n\tprivate:\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptExporter.cpp",
    "content": "//\n#include \"Public.h\"\n\n//\n#include \"ScriptExporter.h\"\n\n//\n#include \"ScriptBase.h\"\n\n//\n#include <fstream>\n\nnamespace bin\n{\n//\tvoid LOG_MESSAGE(const char* pszFmt, ...)\n//\t{\n//\t\tstatic char s_szBuffer[1024] = {0};\n//\n//\t\tva_list ls;\n//\t\tva_start(ls, pszFmt);\n//\n//\t\t_vsnprintf(s_szBuffer, 1024, pszFmt, ls);\n//\n//\t\tva_end(ls);\n//\n//\t\tstatic std::ofstream ofstr;\n//\t\tif(!ofstr.is_open())\n//\t\t{\n//\t\t\tofstr.open(\"bin_script.log\");\n//\t\t}\n//\n//\t\tofstr<< s_szBuffer<< std::endl;\n//#if defined _DEBUG\n//\t\t// To Console\n//\t\tstd::cout<< s_szBuffer<< std::endl;\n//#endif\n//\n//\t}\n\n\tint CScriptExporterManager::ExportClass(const char* pszName, lua_State* pL, const char* pszNameSpace /*= NULL*/)\n\t{\n\t\tExporterIterator pos = m_scriptExporters.find(pszName);\n\n\t\tif(pos != m_scriptExporters.end())\n\t\t{\n\t\t\tSExporterInfo info = pos->second->GetInfo();\n\t\t\tif(info.eET != SExporterInfo::EET_CLASS)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCClassExporter* pClsExp = (CClassExporter*)(pos->second);\n\t\t\treturn pClsExp->Export(pL, pszNameSpace);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tint CScriptExporterManager::ExportModule(const char* pszName, lua_State* pL)\n\t{\n\t\tExporterIterator pos = m_scriptExporters.find(pszName);\n\n\t\tif(pos != m_scriptExporters.end())\n\t\t{\n\t\t\tSExporterInfo info = pos->second->GetInfo();\n\t\t\tif(info.eET != SExporterInfo::EET_MODULE)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn pos->second->Export(pL);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tint CScriptExporterManager::ExportModuleTo(const char* pszName, lua_State* pL, CScriptTable& scriptTable)\n\t{\n\t\tassert(scriptTable.GetHandle() == pL);\n\n\t\tExporterIterator pos = m_scriptExporters.find(pszName);\n\n\t\tif(pos != m_scriptExporters.end())\n\t\t{\n\t\t\tSExporterInfo info = pos->second->GetInfo();\n\t\t\tif(info.eET != SExporterInfo::EET_MODULE)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCModuleExporter& exporter = (CModuleExporter&)*(pos->second);\n\t\t\treturn exporter.ExportTo(pL, scriptTable);\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tBEGIN_SCRIPT_MODULE(exporterManager)\n\t\tDEFINE_MODULE_FUNCTION(exportClass, bool, (const char* pszName, const std::string& strNameSpace))\n\t\t{\n\t\t\tif(strNameSpace.empty())\n\t\t\t{\n\t\t\t\tr = ScriptExporterManager().ExportClass(pszName, lua) != 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tr = ScriptExporterManager().ExportClass(pszName, lua, strNameSpace.c_str()) != 0;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tDEFINE_MODULE_FUNCTION(exportModule, bool, (const char* pszName, CScriptTable& tbl))\n\t\t{\n\t\t\tif(!tbl.IsReferd())\n\t\t\t{\n\t\t\t\tr = ScriptExporterManager().ExportModule(pszName, lua) != 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tr = ScriptExporterManager().ExportModuleTo(pszName, lua, tbl) != 0;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\tEND_SCRIPT_MODULE()\n};\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptExporter.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_EXPORTER_H\n#define SERVER_SHARD_SCRIPT_EXPORTER_H\n\n#include \"ScriptBase.h\"\n#include \"ScriptProxy.h\"\n#include \"ScriptObject.h\"\n\nnamespace bin\n{\n\tstruct SExporterInfo\n\t{\n\t\tenum EExporterType\n\t\t{\n\t\t\tEET_MODULE\t\t= 0,\t\t\t// A module, in lua just a table\n\t\t\tEET_FUNCTION,\t\t\t\t\t// Function\n\t\t\tEET_CLASS,\t\t\t\t\t\t// Class, in lua a userdata\n\t\t\tEET_SIZE,\n\t\t};\n\n\t\tconst char*\t\tpszName;\n\t\tEExporterType\teET;\n\t\tSExporterInfo()\n\t\t\t: pszName(NULL)\n\t\t\t, eET(EET_SIZE)\n\t\t{\n\n\t\t}\n\t};\n\t\t\n\tclass IScriptExporter\n\t{\n\tpublic:\n\t\tvirtual ~IScriptExporter(){}\n\t\tvirtual int Export(lua_State* pL) = 0;\n\t\tvirtual SExporterInfo GetInfo() const = 0;\n\t};\n\n\tclass CScriptExporterManager\n\t{\n\tpublic:\n\t\ttypedef CHashMap<std::string, IScriptExporter*>\t\t\tScriptExporters;\n\t\ttypedef ScriptExporters::const_iterator\t\t\t\t\tExporterIterator;\n\tpublic:\n\t\tCScriptExporterManager()\n\t\t{\n\n\t\t}\n\n\t\t// Internal used, the life of pExporter must be global\n\t\tint RegisterExporter(IScriptExporter* pExporter)\n\t\t{\n\t\t\tif(!pExporter)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tSExporterInfo info = pExporter->GetInfo();\n\t\t\tstd::pair<ExporterIterator, bool> ret = m_scriptExporters.insert(ScriptExporters::value_type(info.pszName, pExporter));\n\t\t\tassert(ret.second && \"ScriptBase.h [RegisterExporter] : Exporter conflict\");\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used, The user data is on the top of stack\n\t\ttemplate <typename T>\n\t\tint AddScriptObject(T* pObj, lua_State* pL)\n\t\t{\n#if defined _DEBUG\n\t\t\tint nOldTop = lua_gettop(pL);\n#endif\n\n\t\t\tSScriptProxy* pProxy = (SScriptProxy*)lua_newuserdata(pL, sizeof(SScriptProxy));\n\t\t\tif(!pProxy)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tnew(pProxy) SScriptProxy;\n\n\t\t\tpProxy->ePT                 = SScriptProxy::EPT_OBJECT;\n\t\t\tpProxy->objRef.pObject      = &pObj->GetScriptObject();\n\t\t\tpProxy->objRef.pLua         = pL;\n\t\t\t\n\t\t\t// Add property table for this object, this table will store the object field value\n\t\t\tlua_newtable(pL);\n\t\t\tlua_pushvalue(pL, -1);\n\t\t\tlua_setfield(pL, -2, \"__newindex\");\t\t// Assign support\n\t\t\tlua_pushvalue(pL, -1);\n\t\t\tlua_setfield(pL, -2, \"__index\");\t\t// Access support\n\t\t\tlua_pushstring(pL, \"object\");\n\t\t\tlua_setfield(pL, -2, \"type\");\n\n            {\n                lua_pushvalue(pL, -1);\n                lua_setfield(pL, -2, \"__bin_objtable\");    // Setup object table, so we can set a new type on this object\n            }\n\n\t\t\t// Set metatable to the new table, this metatable provides \"class member functions\"\n\t\t\t{\n\t\t\t\tSExporterInfo exporterInfo = pObj->GetExporter()->GetInfo();\n\t\t\t\tassert(exporterInfo.eET == SExporterInfo::EET_CLASS);\n\t\t\t\tluaL_getmetatable(pL, exporterInfo.pszName);\n\t\t\t\n\t\t\t\t// Set __gc, __gc will be called when the userdata(or table) is destroyed \n\t\t\t\tlua_getfield(pL, -1, \"__bin_gc\");\n\t\t\t\tlua_setfield(pL, -3, \"__gc\");\n\t\t\t\n\t\t\t\tlua_setmetatable(pL, -2);\n\t\t\t}\n\n\t\t\t// Set the new table as the metatable of this userdata, now the object is on the stack\n\t\t\t// This metatable provides \"class member fields and lua defined member functions\"\n\t\t\tlua_setmetatable(pL, -2);\n\n\t\t\t// Add the object to objects table, objects table is on the stack\n\t\t\tCheckObjectsTable(pL, pObj->GetScriptObject().IsWeaked());\n\t\t\tlua_pushvalue(pL, -2);\t// Set object to top\n\t\t\tpProxy->objRef.nRef = luaL_ref(pL, -2);\n\t\t\tlua_pop(pL, 1);\t\t\t// pop the objects table\n\n\t\t\t// Attach object to lua\n\t\t\tpObj->GetScriptObject().Attach(pObj, &pProxy->objRef);\n\n#if defined _DEBUG\n\t\t\tint nNewTop = lua_gettop(pL);\n\t\t\tassert(nNewTop == nOldTop+1);\n#endif\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used, The user data is on the top of stack\n\t\ttemplate <typename T>\n\t\tT* NewScriptObject(lua_State* pL, bool bDelByScr = true)\n\t\t{\n\t\t\tT* pObj = new T();\n\t\t\tpObj->GetScriptObject().SetDelByScr(bDelByScr);\n\n\t\t\tif(!AddScriptObject(pObj, pL))\n\t\t\t{\n\t\t\t\tdelete pObj;\n\t\t\t\tpObj = NULL;\n\t\t\t}\n\n\t\t\treturn pObj;\n\t\t}\n\n\t\t// Internal used, The user data is on the top of stack\n\t\ttemplate <typename T>\n\t\tint AddScriptObject(const char* pszName, T* pObj, lua_State* pL)\n\t\t{\n\t\t\tif(!AddScriptObject(pObj, pL))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\t\n\t\t\tlua_pushvalue(pL, -1);\n\t\t\tlua_setglobal(pL, pszName);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used\n\t\tint CheckObjectsTable(lua_State* pL, bool bWeaked)\n\t\t{\n\t\t\tconst char* pszName = bWeaked ? SCRIPT_OWN_OBJECTS : SCRIPT_USE_OBJECTS;\n\t\t\tlua_getfield(pL, LUA_REGISTRYINDEX, pszName);\n\t\t\tif(lua_isnil(pL, -1))\n\t\t\t{\n\t\t\t\tlua_pop(pL, 1);\t\t// Pop the nil value\n\n\t\t\t\tlua_newtable(pL);\n\t\t\t\t\n\t\t\t\t//Set objects table as value weak table\n\t\t\t\tif(bWeaked)\n\t\t\t\t{\n\t\t\t\t\tlua_newtable(pL);\n\t\t\t\t\tlua_pushstring(pL, \"v\");\n\t\t\t\t\tlua_setfield(pL, -2, \"__mode\");\n\t\t\t\t\tlua_setmetatable(pL, -2);\n\t\t\t\t}\n\n\t\t\t\tlua_pushvalue(pL, -1);\n\t\t\t\tlua_setfield(pL, LUA_REGISTRYINDEX, pszName);\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used\n\t\tint CheckRefsTable(lua_State* pL)\n\t\t{\n\t\t\tlua_getfield(pL, LUA_REGISTRYINDEX, SCRIPT_REFS);\n\t\t\tif(lua_isnil(pL, -1))\n\t\t\t{\n\t\t\t\tlua_pop(pL, 1);\n\n\t\t\t\tlua_newtable(pL);\n\n\t\t\t\tlua_pushvalue(pL, -1);\n\t\t\t\tlua_setfield(pL, LUA_REGISTRYINDEX, SCRIPT_REFS);\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used\n\t\tint CheckTypesTable(lua_State* pL)\n\t\t{\n\t\t\tlua_getfield(pL, LUA_REGISTRYINDEX, SCRIPT_TYPES);\n\t\t\tif(lua_isnil(pL, -1))\n\t\t\t{\n\t\t\t\tlua_pop(pL, 1);\n\n\t\t\t\tlua_newtable(pL);\n\n\t\t\t\tlua_pushvalue(pL, -1);\n\t\t\t\tlua_setfield(pL, LUA_REGISTRYINDEX, SCRIPT_TYPES);\n\n\t\t\t\tlua_pushvalue(pL, -1);\n\t\t\t\tlua_setglobal(pL, \"bin_types\");\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Internal used\n\t\tint ExportClass(const char* pszName, lua_State* pL, const char* pszNameSpace = NULL);\n\n\t\t// Internal used\n\t\tint ExportModule(const char* pszName, lua_State* pL);\n\n\t\t// Internal used\n\t\tint ExportModuleTo(const char* pszName, lua_State* pL, CScriptTable& scriptTable);\n\n\t\tint ExportClass(const char* pszName, CScriptHandle& scriptHandle, const char* pszNameSpace = NULL)\n\t\t{\n\t\t\tif(scriptHandle.IsNull())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn ExportClass(pszName, scriptHandle.GetHandle(), pszNameSpace);\n\t\t}\n\n\t\tint ExportModule(const char* pszName, CScriptHandle& scriptHandle)\n\t\t{\n\t\t\tif(scriptHandle.IsNull())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn ExportModule(pszName, scriptHandle.GetHandle());\n\t\t}\n\n\t\tint ExportModuleTo(const char* pszName, CScriptHandle& scriptHandle, const char* pszTableName)\n\t\t{\n\t\t\t// Get the table\n\t\t\tCScriptTable scriptTable;\n\t\t\tscriptHandle.Get(pszTableName, scriptTable);\n\t\t\t\n\t\t\tbool bNewed = !scriptTable.IsReferd();\n\t\t\tint ret = ExportModuleTo(pszName, scriptHandle, scriptTable);\n\t\t\tif(ret && bNewed)\t// The table is a new table ?\n\t\t\t{\n\t\t\t\tscriptHandle.Set(pszTableName, scriptTable);\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tint ExportModuleTo(const char* pszName, CScriptHandle& scriptHandle, CScriptTable& scriptTable)\n\t\t{\n\t\t\tif(scriptHandle.IsNull())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tbool bNeedUnref = false;\n\t\t\tif(!scriptTable.IsReferd())\n\t\t\t{\n\t\t\t\tscriptHandle.NewTable(scriptTable);\n\t\t\t\tbNeedUnref = true;\n\t\t\t}\n\n\t\t\tint ret = ExportModuleTo(pszName, scriptHandle.GetHandle(), scriptTable);\n\n\t\t\tif(!ret && bNeedUnref)\n\t\t\t{\n\t\t\t\tscriptTable.UnRef();\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\tprivate:\n\t\tScriptExporters\t\t\tm_scriptExporters;\n\t};\n\tinline CScriptExporterManager& ScriptExporterManager()\n\t{\n\t\tstatic CScriptExporterManager s_scriptExpoterManager;\n\n\t\treturn s_scriptExpoterManager;\n\t}\n\n\tstruct SModuleFunction\n\t{\n\t\tconst char*\t\t\tpszName;\n\t\tlua_CFunction\t\tpFunc;\n\t\tSModuleFunction(const char* pN = NULL, lua_CFunction pF = NULL)\n\t\t\t: pszName(pN), pFunc(pF)\n\t\t{\n\n\t\t}\n\t};\n\n\tstruct SClassFunction\n\t{\n\t\tconst char*\t\t\tpszName;\n\t\tlua_CFunction\t\tpFunc;\n\t\tSClassFunction(const char* pN = NULL, lua_CFunction pF = NULL)\n\t\t\t: pszName(pN), pFunc(pF)\n\t\t{\n\n\t\t}\n\t};\n\n\ttemplate <typename T>\n\tstruct TLinkNode : T\n\t{\n\t\tTLinkNode*\tpNxt;\n\t\tTLinkNode()\n\t\t\t: pNxt(NULL)\n\t\t{\n\n\t\t}\n\t};\n\n\ttypedef TLinkNode<SModuleFunction> ModuleFunctionLinkNode;\n\ttypedef TLinkNode<SClassFunction>  ClassFunctionLinkNode;\n\n\tclass CModuleExporter : public IScriptExporter\n\t{\n\tpublic:\n\t\tCModuleExporter(const char* pszName, ModuleFunctionLinkNode** ppHead)\n\t\t\t: m_pszModuleName(pszName)\n\t\t\t, m_ppHead(ppHead)\n\t\t{\n\t\t\tassert(m_pszModuleName && m_ppHead);\n\n\t\t\tScriptExporterManager().RegisterExporter(this);\n\t\t}\n\n\t\tvirtual int Export(lua_State* pL)\n\t\t{\n\t\t\tCHECK_LUA_STACK(pL);\n\n\t\t\tconst ModuleFunctionLinkNode* pNode = GetModuleFunctionList();\t// Empty module\n\t\t\tif(!pNode)\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tconst int SIZE_HINT = 10;\n\t\t\tluaL_pushmodule(pL, GetModuleName(), SIZE_HINT);\n\n\t\t\twhile(pNode)\n\t\t\t{\n\t\t\t\tlua_pushcfunction(pL, pNode->pFunc);\n\t\t\t\tlua_setfield(pL, -2, pNode->pszName);\n\n\t\t\t\tpNode = pNode->pNxt;\n\t\t\t}\n\n\t\t\tlua_pushstring(pL, GetModuleName());\n\t\t\tlua_setfield(pL, -2, \"name\");\n\n\t\t\tlua_pushstring(pL, \"module\");\n\t\t\tlua_setfield(pL, -2, \"type\");\n\n\t\t\tlua_pushcfunction(pL, &__Imported);\n\t\t\tlua_setfield(pL, -2, \"imported\");\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tint ExportTo(lua_State* pL, CScriptTable& scriptTable)\n\t\t{\n\t\t\tassert(scriptTable.GetHandle() == pL);\n\n\t\t\tCHECK_LUA_STACK(pL);\n\n\t\t\tconst ModuleFunctionLinkNode* pNode = GetModuleFunctionList();\t// Empty module\n\t\t\tif(!pNode)\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tscriptTable.PrepareStack();\t// table\n\n\t\t\twhile(pNode)\n\t\t\t{\n\t\t\t\tlua_pushcfunction(pL, pNode->pFunc);\t// table, func\n\t\t\t\tlua_setfield(pL, -2, pNode->pszName);\t// table\n\n\t\t\t\tpNode = pNode->pNxt;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tSExporterInfo GetInfo() const\n\t\t{\n\t\t\tSExporterInfo info;\n\n\t\t\tinfo.pszName = GetModuleName();\n\t\t\tinfo.eET     = SExporterInfo::EET_MODULE;\n\n\t\t\treturn info;\n\t\t}\n\n\t\tconst char* GetModuleName() const\n\t\t{\n\t\t\treturn m_pszModuleName;\n\t\t}\n\n\t\tconst ModuleFunctionLinkNode* GetModuleFunctionList() const\n\t\t{\n\t\t\treturn *m_ppHead;\n\t\t}\n\tprotected:\n\t\tstatic int __Imported(lua_State* pL)\n\t\t{\n\t\t\tlua_pushboolean(pL, true);\n\n\t\t\treturn 1;\n\t\t}\n\n\tprivate:\n\t\tconst char*\t\t\t\t\tm_pszModuleName;\n\t\tModuleFunctionLinkNode**\tm_ppHead;\n\t};\n\n\tclass CClassExporter : public IScriptExporter\n\t{\n\tpublic:\n\t\tCClassExporter(const char* pszSuper, const char* pszName, ClassFunctionLinkNode** ppHead)\n\t\t\t: m_pszSuperName(pszSuper)\n\t\t\t, m_pszClassName(pszName)\n\t\t\t, m_ppHead(ppHead)\n\t\t{\n\t\t\tassert(m_pszClassName && m_ppHead);\n\n\t\t\tScriptExporterManager().RegisterExporter(this);\n\t\t}\n\n\t\tint Export(lua_State* pL, const char* pszNameSpace)\n\t\t{\n\t\t\tCHECK_LUA_STACK(pL);\n\n\t\t\tif(luaL_newmetatable(pL, GetClassName()) != 0)\t// Has not been exported ?\n\t\t\t{\n\t\t\t\tlua_pushstring(pL, GetClassName());\n\t\t\t\tlua_setfield(pL, -2, \"name\");\n\n\t\t\t\tlua_pushstring(pL, \"class\");\n\t\t\t\tlua_setfield(pL, -2, \"type\");\n\n\t\t\t\tlua_pushvalue(pL, -1);\n\t\t\t\tlua_setfield(pL, -2, \"__index\");\n\n\t\t\t\tlua_pushcfunction(pL, &__GC);\n\t\t\t\tlua_setfield(pL, -2, \"__bin_gc\");\n\n\t\t\t\tlua_pushcfunction(pL, &__Imported);\n\t\t\t\tlua_setfield(pL, -2, \"imported\");\n\n\t\t\t\tif(m_pszSuperName)  // Export the super class\n\t\t\t\t{\n\t\t\t\t\tScriptExporterManager().ExportClass(m_pszClassName, pL, pszNameSpace);\n\n\t\t\t\t\tluaL_getmetatable(pL, m_pszSuperName);  // newClass, superClass\n                    lua_pushvalue(pL, -1);                  // newClass, superClass, superClass\n\n                    lua_setfield(pL, -3, \"super\");          // newClass, superClass\n                    lua_setmetatable(pL, -2);\n\t\t\t\t}\n\n\t\t\t\tconst ClassFunctionLinkNode* pNode = GetClassFunctionList();\t\n\t\t\t\twhile(pNode)\n\t\t\t\t{\n\t\t\t\t\tlua_pushcfunction(pL, pNode->pFunc);\n\t\t\t\t\tlua_setfield(pL, -2, pNode->pszName);\n\n\t\t\t\t\tpNode = pNode->pNxt;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Now type is on the stack\n\t\t\t{\n\t\t\t\tint nTypeIdx = -2;\n\t\t\t\tCHECK_LUA_STACK(pL);\n\n\t\t\t\tScriptExporterManager().CheckTypesTable(pL);\n\t\t\t\tif(pszNameSpace)\n\t\t\t\t{\n\t\t\t\t\tlua_getfield(pL, -1, pszNameSpace);\t// type, types, value\t\n\t\t\t\t\tif(lua_isnil(pL, -1))\n\t\t\t\t\t{\n\t\t\t\t\t\tlua_pop(pL, 1);\t\t\t\t\t// type, types\n\t\t\t\t\t\tlua_newtable(pL);\t\t\t\t// type, types, namespace \n\t\t\t\t\t\tlua_pushvalue(pL, -1);\t\t\t// type, types, namespace, namespace\n\n\t\t\t\t\t\tlua_setfield(pL, -3, pszNameSpace);// type, types, namespace\n\t\t\t\t\t}\n\t\t\t\t\telse if(!lua_istable(pL, -1))\n\t\t\t\t\t{\n\t\t\t\t\t\tluaL_error(pL, \"namespace[%s] must be a table\", pszNameSpace);\n\t\t\t\t\t}\n\n\t\t\t\t\tnTypeIdx = -3;\n\t\t\t\t}\n\n\t\t\t\t// Now the type table(or namespace) is on the stack\n\t\t\t\tlua_pushvalue(pL, nTypeIdx);\t\t\t\t// tbl, type\n\t\t\t\tlua_setfield(pL, -2, GetClassName());\t\t\t\n\t\t\t}\n\t\t\t\t\t\t\n\t\t\treturn 1;\n\t\t}\n\n\t\tvirtual int Export(lua_State* pL)\n\t\t{\n\t\t\treturn Export(pL, NULL);\n\t\t}\n\n\t\tSExporterInfo GetInfo() const\n\t\t{\n\t\t\tSExporterInfo info;\n\n\t\t\tinfo.pszName = GetClassName();\n\t\t\tinfo.eET     = SExporterInfo::EET_CLASS;\n\n\t\t\treturn info;\n\t\t}\n\n\t\tconst char* GetClassName() const\n\t\t{\n\t\t\treturn m_pszClassName;\n\t\t}\n\n\t\tconst ClassFunctionLinkNode* GetClassFunctionList() const\n\t\t{\n\t\t\treturn *m_ppHead;\n\t\t}\n\n\tprivate:\n\t\tconst char*\t\t\t\t\tm_pszSuperName;\n\t\tconst char*\t\t\t\t\tm_pszClassName;\n\t\tClassFunctionLinkNode**\t    m_ppHead;\n\n\t\t// Static\n\tprotected:\n\t\tstatic int __GC(lua_State* pL)\n\t\t{\n\t\t\tvoid* pUd = lua_touserdata(pL, 1);\n\t\t\tif(!pUd)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tSScriptProxy* pProxy = (SScriptProxy*)pUd;\n\n\t\t\tif(!(pProxy->ePT&SScriptProxy::EPT_OBJECT))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!pProxy->objRef.pObject)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(pProxy->objRef.pObject->GetDelByScr())\n\t\t\t{\n\t\t\t\tpProxy->objRef.pObject->ReleaseByScr();\t// Will call objRef.Unlink();\n\n\t\t\t\tassert(!pProxy->objRef.pObject);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpProxy->objRef.Unlink();\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Check whether this lua object still reference to a c++ object \n\t\tstatic int __Imported(lua_State* pL)\n\t\t{\n\t\t\tbool bRet = false;\n\t\t\tSScriptProxy* pProxy = (SScriptProxy*)lua_touserdata(pL, 1);\n\t\t\tif(pProxy && (pProxy->ePT&SScriptProxy::EPT_OBJECT) && pProxy->objRef.pObject)\n\t\t\t{\n\t\t\t\tbRet = true;\n\t\t\t}\n\t\t\tlua_pushboolean(pL, bRet);\n\n\t\t\treturn 1;\n\t\t}\n\t};\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptHandle.cpp",
    "content": "//\n#include \"Public.h\"\n\n//\n#include \"ScriptHandle.h\"\n\n//\n#include \"ScriptExporter.h\"\n\n//\n\nnamespace bin\n{\n\t//! Exec a lua file\n\t//! Initialize a CScriptHandle, NB. This CScriptHandle must be released state\n\tint CScriptHandle::Init()\n\t{\n\t\tassert(!m_pLua);\n\n\t\tm_pLua = luaL_newstate();\n\n\t\tif(!m_pLua)\n\t\t{\n\t\t\tgoto OPERATION_FAIL;\n\t\t}\n\n\t\tm_bOwn = true;\n\n\t\t{\n\t\t\tlua_State* L = m_pLua;\n\n\t\t\tconst luaL_Reg loadedlibs[] = \n\t\t\t{\n\t\t\t\t{\"_G\",\t\t\t\tluaopen_base},\n\t\t\t\t{LUA_LOADLIBNAME,\tluaopen_package},\n\t\t\t\t{LUA_COLIBNAME,\t\tluaopen_coroutine},\n\t\t\t\t{LUA_TABLIBNAME,\tluaopen_table},\n\t\t\t\t{LUA_IOLIBNAME,\t\tluaopen_io},\n\t\t\t\t{LUA_OSLIBNAME,\t\tluaopen_os},\n\t\t\t\t{LUA_STRLIBNAME,\tluaopen_string},\n\t\t\t\t{LUA_MATHLIBNAME,\tluaopen_math},\n#if defined _DEBUG\n\t\t\t\t{LUA_DBLIBNAME,\t\tluaopen_debug},\n#endif\n\t\t\t\t{NULL, NULL}\n\t\t\t};\n\n\t\t\tconst luaL_Reg* pos = loadedlibs;\n\t\t\tfor(; pos->name; ++pos) \n\t\t\t{\n\t\t\t\tluaL_requiref(L, pos->name, pos->func, 1);\n\t\t\t\tlua_pop(L, 1);\n\t\t\t}\n\t\t}\t\n\n\t\tScriptExporterManager().ExportModule(\"exporterManager\", *this);\n\n\t\treturn 1;\nOPERATION_FAIL:\n\n\t\tRelease();\n\n\t\treturn 0;\n\t}\n\n\tint CScriptHandle::Exec(const char* pszFileName,  CScriptTable& ret)\n\t{\n\t\tif(IsNull() || !pszFileName)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\tint nOldTop = lua_gettop(m_pLua);\n\n\t\tint nRet = luaL_dofile(m_pLua, pszFileName);\n\t\tif(nRet != LUA_OK)\t// Error, the error message is on the top\n\t\t{\n\t\t\tLOG_MESSAGE(\"[ERROR] Exec File[%s] : %s\", pszFileName, lua_tostring(m_pLua, -1));\n\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint nCnt = lua_gettop(m_pLua)-nOldTop;\n\t\t\tif(nCnt != 0)\n\t\t\t{\n\t\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\t\tif(!ret.IsReferd())\n\t\t\t\t{\n\t\t\t\t\tNewTable(ret);\n\t\t\t\t}\n\n\t\t\t\tassert(ret.GetHandle() == GetHandle());\n\n\t\t\t\tret.PrepareStack();\n\n\t\t\t\t// Set n\n\t\t\t\tlua_pushinteger(m_pLua, nCnt);\n\t\t\t\tlua_setfield(m_pLua, -2, \"n\");\n\n\t\t\t\tfor(int i=1; i<=nCnt; ++i)\n\t\t\t\t{\n\t\t\t\t\tlua_pushvalue(m_pLua, nOldTop+i);\n\t\t\t\t\tlua_rawseti(m_pLua, -2, i);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(ret.IsReferd())\n\t\t\t{\n\t\t\t\tret.Set(\"n\", nCnt);\n\t\t\t}\n\t\t}\n\n\t\treturn 1;\n\t}\n\t//! Exec a lua string, ret contains the return value from string\n\tint CScriptHandle::ExecString(const char* pszString, CScriptTable& ret)\n\t{\n\t\tif(IsNull() || !pszString)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\tint nOldTop = lua_gettop(m_pLua);\n\n\t\tint nRet = luaL_dostring(m_pLua, pszString);\n\t\tif(nRet != LUA_OK)\t// Error, the error message is on the top\n\t\t{\n\t\t\tLOG_MESSAGE(\"[ERROR] Exec String : %s\", lua_tostring(m_pLua, -1));\n\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint nCnt = lua_gettop(m_pLua)-nOldTop;\n\t\t\tif(nCnt != 0)\n\t\t\t{\n\t\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\t\tif(!ret.IsReferd())\n\t\t\t\t{\n\t\t\t\t\tNewTable(ret);\n\t\t\t\t}\n\n\t\t\t\tassert(ret.GetHandle() == GetHandle());\n\n\t\t\t\tret.PrepareStack();\n\n\t\t\t\t// Set n\n\t\t\t\tlua_pushinteger(m_pLua, nCnt);\n\t\t\t\tlua_setfield(m_pLua, -2, \"n\");\n\n\t\t\t\tfor(int i=1; i<=nCnt; ++i)\n\t\t\t\t{\n\t\t\t\t\tlua_pushvalue(m_pLua, nOldTop+i);\n\t\t\t\t\tlua_rawseti(m_pLua, -2, i);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if(ret.IsReferd())\n\t\t\t{\n\t\t\t\tret.Set(\"n\", nCnt);\n\t\t\t}\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tint CScriptHandle::Get(const char* pszName, CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptTable>(pszName, tbl), tbl);\n\t}\n\n\tint CScriptHandle::Get(const char* pszName, CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptUserData>(pszName, ud), ud);\n\t}\n\n\tint CScriptHandle::PostFmLua(int nFmLuaRet, CScriptTable& tbl)\n\t{\n\t\tif(nFmLuaRet)\n\t\t{\n\t\t\tCScriptTable::RefNode& ref = tbl.m_ref;\n\t\t\tref.LinkAfter(&m_head);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttbl.UnRef();\n\t\t}\n\n\t\treturn nFmLuaRet;\n\t}\n\n\tint CScriptHandle::PostFmLua(int nFmLuaRet, CScriptUserData& ud)\n\t{\n\t\tif(nFmLuaRet)\n\t\t{\n\t\t\tCScriptUserData::RefNode& ref = ud.m_ref;\n\t\t\tref.LinkAfter(&m_head);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tud.UnRef();\n\t\t}\n\n\t\treturn nFmLuaRet;\n\t}\n\n\tvoid CScriptHandle::InvlRetVal(CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\t}\n\n\tvoid CScriptHandle::InvlRetVal(CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\t}\n\n\tint CScriptHandle::NewTable(CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\n\t\tif(IsNull())\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\tlua_newtable(m_pLua);\n\n\t\treturn PostFmLua(TFmLua<CScriptTable>::Make(m_pLua, -1, tbl), tbl);\n\t}\n\n\tint CScriptHandle::NewTable(const char* pszName, CScriptTable& tbl)\n\t{\n\t\tif(!NewTable(tbl))\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tif(!Set(pszName, tbl))\n\t\t{\n\t\t\ttbl.UnRef();\n\t\t}\n\n\t\treturn tbl.IsReferd() ? 1 : 0;\n\t}\n\n\tint IScriptADBase::PrepareStack()\n\t{\n\t\tScriptExporterManager().CheckRefsTable(m_ref.pLua);\t\t// __bin_refs\n\n\t\tlua_rawgeti(m_ref.pLua, -1, m_ref.nRef);\t\t\t\t// __bin_refs this_table\n\n\t\treturn 1;\n\t}\n\n\tint IScriptADBase::PostFmLua(int nFmLuaRet, CScriptTable& tbl)\n\t{\n\t\tif(nFmLuaRet)\n\t\t{\n\t\t\tCScriptTable::RefNode& ref = tbl.m_ref;\n\t\t\tref.LinkAfter(&m_ref);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttbl.UnRef();\n\t\t}\n\n\t\treturn nFmLuaRet;\n\t}\n\n\tint IScriptADBase::PostFmLua(int nFmLuaRet, CScriptUserData& ud)\n\t{\n\t\tif(nFmLuaRet)\n\t\t{\n\t\t\tCScriptUserData::RefNode& ref = ud.m_ref;\n\t\t\tref.LinkAfter(&m_ref);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tud.UnRef();\n\t\t}\n\n\t\treturn nFmLuaRet;\n\t}\n\n\tvoid IScriptADBase::InvlRetVal(CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\t}\n\n\tvoid IScriptADBase::InvlRetVal(CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\t}\n\n\tint IScriptADBase::Get(const char* pszName, CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptTable>(pszName, tbl), tbl);\n\t}\n\n\tint IScriptADBase::Get(const char* pszName, CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptUserData>(pszName, ud), ud);\n\t}\n\n\tint IScriptADBase::Get(int nIdx, CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptTable>(nIdx, tbl), tbl);\n\t}\n\n\tint IScriptADBase::Get(int nIdx, CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\n\t\treturn PostFmLua(Get<CScriptUserData>(nIdx, ud), ud);\n\t}\n\n\t// Static\n\tvoid IScriptADBase::SRefNode::UnLinker(SScriptHandleRefNode* pT)\n\t{\n\t\tSRefNode* pThis = static_cast<SRefNode*>(pT);\n\n\t\tpThis->Unlink();\t// UnLink to ref list\n\n\t\tif(pThis->pLua && pThis->nRef!=LUA_NOREF)\n\t\t{\n\t\t\tCHECK_LUA_STACK(pThis->pLua);\n\n\t\t\tScriptExporterManager().CheckRefsTable(pThis->pLua);\t// Refs table is on the stack\n\t\t\tluaL_unref(pThis->pLua, -1, pThis->nRef);\n\t\t}\n\n\t\tpThis->pLua = NULL;\n\t\tpThis->nRef = LUA_NOREF;\n\t}\n\n\tint TFmLua<CScriptTable>::Make(lua_State* pL, int nIdx, CScriptTable& tbl)\n\t{\n\t\ttbl.UnRef();\n\n\t\tif(!lua_istable(pL, nIdx))\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tCHECK_LUA_STACK(pL);\n\n\t\tnIdx = lua_absindex(pL, nIdx);\t// To absolute index, avoid negative index\n\n\t\tCScriptTable::RefNode& ref = tbl.m_ref;\n\n\t\tScriptExporterManager().CheckRefsTable(pL);\n\t\tlua_pushvalue(pL, nIdx);\n\n\t\tref.pLua = pL;\n\t\tref.nRef = luaL_ref(pL, -2);\n\n\t\treturn 1;\n\t}\n\n\tint TFmLua<CScriptUserData>::Make(lua_State* pL, int nIdx, CScriptUserData& ud)\n\t{\n\t\tud.UnRef();\n\n\t\tif(!lua_isuserdata(pL, nIdx))\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tSScriptProxy* pProxy = (SScriptProxy*)lua_touserdata(pL, nIdx);\n\n\t\tif(!pProxy)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Check whether the proxy is associate with a valid object\n\t\tif(pProxy->ePT != SScriptProxy::EPT_OBJECT || !pProxy->objRef.pObject)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tCHECK_LUA_STACK(pL);\n\n\t\tnIdx = lua_absindex(pL, nIdx);\t// To absolute index, avoid negative index\n\n\t\tCScriptUserData::RefNode& ref = ud.m_ref;\n\n\t\tScriptExporterManager().CheckRefsTable(pL);\n\t\tlua_pushvalue(pL, nIdx);\n\n\t\tref.pLua = pL;\n\t\tref.nRef = luaL_ref(pL, -2);\n\n\t\treturn 1;\n\t}\n\n\tint TToLua<CScriptTable>::Make(CScriptTable& tbl, lua_State* pL)\n\t{\n\t\tif(!tbl.IsReferd())\n\t\t{\n\t\t\tlua_pushnil(pL);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tCScriptTable::RefNode& ref = tbl.m_ref;\n\t\tif(ref.pLua != pL)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tScriptExporterManager().CheckRefsTable(pL);\n\t\tlua_rawgeti(pL, -1, ref.nRef);\n\n\t\tlua_replace(pL, -2);\n\n\t\treturn 1;\n\t}\n\n\tint TToLua<CScriptUserData>::Make(CScriptUserData& ud, lua_State* pL)\n\t{\n\t\tif(!ud.IsReferd())\n\t\t{\n\t\t\tlua_pushnil(pL);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tCScriptUserData::RefNode& ref = ud.m_ref;\n\t\tif(ref.pLua != pL)\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tScriptExporterManager().CheckRefsTable(pL);\n\t\tlua_rawgeti(pL, -1, ref.nRef);\n\n\t\tlua_replace(pL, -2);\n\n\t\treturn 1;\n\t}\n}"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptHandle.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_HANDLE_H\n#define SERVER_SHARD_SCRIPT_HANDLE_H\n\n#include \"ScriptBase.h\"\n\nnamespace bin\n{\n\tstruct SDBLinkNode\n\t{\n\t\tSDBLinkNode*\tpPre;\n\t\tSDBLinkNode*\tpNxt;\n\n\t\tSDBLinkNode()\n\t\t\t: pPre(NULL)\n\t\t\t, pNxt(NULL)\n\t\t{\n\n\t\t}\n\n\t\tvoid LinkAfter(SDBLinkNode* pNode)\n\t\t{\n\t\t\tpNxt = pNode->pNxt;\n\t\t\tpPre = pNode;\n\n\t\t\tpPre->pNxt = this;\n\t\t\tif(pNxt)\n\t\t\t{\n\t\t\t\tpNxt->pPre = this;\n\t\t\t}\n\t\t}\n\n\t\tvoid LinkBefore(SDBLinkNode* pNode)\n\t\t{\n\t\t\tpNxt = pNode;\n\t\t\tpPre = pNode->pPre;\n\n\t\t\tpNxt->pPre = this;\n\t\t\tif(pPre)\n\t\t\t{\n\t\t\t\tpPre->pNxt = this;\n\t\t\t}\n\t\t}\n\n\t\tvoid Unlink()\n\t\t{\n\t\t\tif(pPre)\n\t\t\t{\n\t\t\t\tpPre->pNxt = pNxt;\n\t\t\t}\n\n\t\t\tif(pNxt)\n\t\t\t{\n\t\t\t\tpNxt->pPre = pPre;\t\n\t\t\t}\n\n\t\t\tpPre = NULL;\n\t\t\tpNxt = NULL;\n\t\t}\n\t};\n\n\tstruct SScriptHandleRefNode : SDBLinkNode\n\t{\n\t\ttypedef void (*UnLinker)(SScriptHandleRefNode*);\n\n\t\tUnLinker\t\tunLinker;\n\t\tSScriptHandleRefNode()\n\t\t\t: unLinker(NULL)\n\t\t{\n\n\t\t}\n\t};\n\n\tclass CScriptTable;\n\tclass CScriptUserData;\n\n\t//! Encapsulate a lua_State, provide global setting and reading interface\n\tclass CScriptHandle : INonCopyable\n\t{\n\tpublic:\n\t\tCScriptHandle()\n\t\t\t: m_bOwn(true)\n\t\t\t, m_pLua(NULL)\n\t\t{\n\n\t\t}\n\n\t\t~CScriptHandle()\n\t\t{\n\t\t\tRelease();\n\t\t}\n\t\t\n\t\t//! Initialize a CScriptHandle, NB. This CScriptHandle must be released state\n\t\tint Init();\n\n\t\t//! Initialize a CScriptHandle from file.\n\t\tint Init(const char* pszFileName)\n\t\t{\n\t\t\tif(!Init())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!Exec(pszFileName))\n\t\t\t{\n\t\t\t\tgoto OPERATION_FAIL;\n\t\t\t}\n\t\t\t\n\t\t\treturn 1;\nOPERATION_FAIL:\n\t\t\tRelease();\n\n\t\t\treturn 0;\n\t\t}\n\n\t\t//! Initialize a CScriptHandle from a exist lua_State.\n\t\t//! \\param bOwn  indicate whether CScriptHandle will own this pLua, if true, pLua will be closed while releasing this handle.\n\t\tint Init(lua_State* pLua, bool bOwn = false)\n\t\t{\n\t\t\tRelease();\n\n\t\t\tm_pLua = pLua;\n\t\t\tm_bOwn = bOwn; \n\n\t\t\treturn 1;\n\t\t}\n\n\t\t//! Init from a lua string.\n\t\tint InitFmString(const char* pszString)\n\t\t{\n\t\t\tif(!Init())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!ExecString(pszString))\n\t\t\t{\n\t\t\t\tgoto OPERATION_FAIL;\n\t\t\t}\n\n\t\t\treturn 1;\nOPERATION_FAIL:\n\t\t\tRelease();\n\n\t\t\treturn 0;\n\t\t}\n\n\t\t//! Release this handle, if this handle owns lua_State, lua_State will be closed.\n\t\t//! All the tables and userdatas got from this handle will be unlinked( IsReferd() is false) \n\t\tvoid Release()\n\t\t{\n\t\t\t// Unlink all relations\n\t\t\tSScriptHandleRefNode* pNode = &m_head;\n\t\t\tSScriptHandleRefNode* pNxt  = NULL;\n\t\t\twhile(pNode)\n\t\t\t{\n\t\t\t\tpNxt = (SScriptHandleRefNode*)pNode->pNxt;\n\t\t\t\tif(pNode->unLinker)\n\t\t\t\t{\n\t\t\t\t\tpNode->unLinker(pNode);\n\t\t\t\t}\n\n\t\t\t\tpNode = pNxt;\n\t\t\t}\n\n\t\t\tif(m_pLua)\n\t\t\t{\n\t\t\t\tif(m_bOwn)\n\t\t\t\t{\n\t\t\t\t\tlua_close(m_pLua);\n\t\t\t\t}\n\n\t\t\t\tm_pLua = NULL;\n\t\t\t}\n\n\t\t\tassert(!m_head.pNxt && !m_head.pPre && !m_head.unLinker);\n\t\t}\n\n\t\t//! Exec a lua file\n\t\tint Exec(const char* pszFileName)\n\t\t{\n\t\t\tif(IsNull() || !pszFileName)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\tint nRet = luaL_dofile(m_pLua, pszFileName);\n\t\t\tif(nRet != LUA_OK)\t// Error, the error message is on the top\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Exec File[%s] : %s\", pszFileName, lua_tostring(m_pLua, -1));\n\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t//! Exec a lua file\n\t\tint Exec(const char* pszFileName,  CScriptTable& ret);\n\n\t\t//! Exec a lua string\n\t\tint ExecString(const char* pszString)\n\t\t{\n\t\t\tif(IsNull() || !pszString)\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\tint nRet = luaL_dostring(m_pLua, pszString);\n\t\t\tif(nRet != LUA_OK)\t// Error, the error message is on the top\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Exec String : %s\", lua_tostring(m_pLua, -1));\n\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t//! Exec a lua string, ret contains the return value from string\n\t\tint ExecString(const char* pszString, CScriptTable& ret);\n\n\t\t//! Check if this handle is Null.\n\t\tbool IsNull() const\n\t\t{\n\t\t\treturn m_pLua == NULL;\n\t\t}\n\n\t\t//! Get the lua_State associated with this handle.\n\t\tlua_State* GetHandle() const\n\t\t{\n\t\t\treturn m_pLua;\n\t\t}\n\n\t\t//! Get any thing from the global table in this handle.\n\t\t//! \\param pszName the name of the variable.\n\t\t//! \\param v the out value.\n\t\t//! \\return 0-fail\n\t\ttemplate <typename T>\n\t\tint Get(const char* pszName, T& v)\n\t\t{\n\t\t\tif(IsNull())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\tlua_getglobal(m_pLua, pszName);\n\n\t\t\treturn TFmLua<typename TArgumentType<T>::value_type>::Make(m_pLua, -1, v);\n\t\t}\n\n\t\t//! Set anything in global table.\n\t\t//! \\param pszName name of the variable.\n\t\t//! \\param v input value.\n\t\t//! \\return 0-fail\n\t\ttemplate <typename T>\n\t\tint Set(const char* pszName, T v)\n\t\t{\n\t\t\tif(IsNull())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tCHECK_LUA_STACK(m_pLua);\n\n\t\t\tif(!TToLua<typename TArgumentType<T>::value_type>::Make(v, m_pLua))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_setglobal(m_pLua, pszName);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t//! Set a table, template function must pass variable in value, so pass tbl in reference here.\n\t\tint Set(const char* pszName, CScriptTable& tbl)\n\t\t{\n\t\t\treturn Set<CScriptTable&>(pszName, tbl);\n\t\t}\n\n\t\t//! See int Set(const char* pszName, CScriptTable& tbl)\n\t\tint Set(const char* pszName, CScriptUserData& ud)\n\t\t{\n\t\t\treturn Set<CScriptUserData&>(pszName, ud);\n\t\t}\n\n\t\t//! See int Set(const char* pszName, CScriptTable& tbl)\n\t\tint Set(const char* pszName, const std::string& str)\n\t\t{\n\t\t\treturn Set<const std::string&>(pszName, str);\n\t\t}\n\n\t\t//! Get a table from global table. if fail, tbl is invalid(IsRefered() is false).\n\t\t//! NB. tbl will be linked to this handle, so if handle is released, tbl will know this event.\n\t\tint Get(const char* pszName, CScriptTable& tbl);\n\n\t\t//! Get a userdata from global table. a userdata is a class you export to lua in fact.\n\t\tint Get(const char* pszName, CScriptUserData& ud);\n\n\t\t//! New a table, tbl will reference to it.\n\t\tint NewTable(CScriptTable& tbl);\n\n\t\t//! New a table, tbl will reference to it and this table will be set to global variable named pszName.\n\t\tint NewTable(const char* pszName, CScriptTable& tbl);\n\n#define ARGUMENT_TYPE(arg) typename TArgumentType<arg>::argument_type\n#define VALUE_TYPE(arg)    typename TArgumentType<arg>::value_type\n\n#define FUNC_PREWORK() \\\n\t\tInvlRetVal(r);\\\n\t\tif(IsNull())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\tCHECK_LUA_STACK(m_pLua);\\\n\t\tlua_getglobal(m_pLua, pszName);\\\n\t\tif(!lua_isfunction(m_pLua, -1))\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\n\n#define MAKE_ARG(type, vale)\\\n\t\tif(!TToLua<VALUE_TYPE(type)>::Make((vale), m_pLua))\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\n\n#define MAKE_RET()\\\n\tint __nFmRet = TFmLua<R>::Make(m_pLua, -1, r)\n\n#define FUNC_POSWORK()\\\n\treturn PostFmLua(__nFmRet, r);\n\n\t\t//! Call a global function named pszName, r is the returned value.\n\t\t//! \\return 0-fail.\n\t\ttemplate <typename R>\n\t\tint CallFunc(const char* pszName, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tif(lua_pcall(m_pLua, 0, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(m_pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n\t\t//! Call a global function named pszName, r is the returned value, a0 is the only argument.\n\t\t//! NB. you must indicate the argument type explicitly like CallFunc<Type>(name, arg, ret)\n\t\t//! NB. the return type will be interpreted by compiler, there is no need to indicate it's type.\n\t\t//! \\return 0-fail.\n\t\ttemplate <typename A0, typename R>\n\t\tint CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tMAKE_ARG(A0, a0);\n\n\t\t\tif(lua_pcall(m_pLua, 1, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(m_pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n\t\t//! Two args version, see One args version.\n\t\ttemplate <typename A0, typename A1, typename R>\n\t\tint CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tMAKE_ARG(A0, a0);\n\t\t\tMAKE_ARG(A1, a1);\n\n\t\t\tif(lua_pcall(m_pLua, 2, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(m_pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n        //! Three args version, see One args version.\n        template <typename A0, typename A1, typename A2, typename R>\n        int CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, ARGUMENT_TYPE(A2) a2, R& r)\n        {\n            FUNC_PREWORK();\n\n            MAKE_ARG(A0, a0);\n            MAKE_ARG(A1, a1);\n            MAKE_ARG(A2, a2);\n\n            if (lua_pcall(m_pLua, 3, 1, 0) != LUA_OK)\t// Error msg here\n            {\n                LOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(m_pLua, -1));\n                return 0;\n            }\n\n            MAKE_RET();\n\n            FUNC_POSWORK();\n        }\n#undef ARGUMENT_TYPE\n#undef VALUE_TYPE\n#undef FUNC_PREWORK\n#undef MAKE_THIS\n#undef MAKE_ARG\n#undef MAKE_RET\n#undef FUNC_POSWORK\n\t\n\tprotected:\n\t\ttemplate <typename T>\n\t\tint PostFmLua(int nFmLuaRet, T)\n\t\t{\n\t\t\treturn nFmLuaRet;\n\t\t}\n\n\t\tint PostFmLua(int nFmLuaRet, CScriptTable& tbl);\n\n\t\tint PostFmLua(int nFmLuaRet, CScriptUserData& ud);\n\n\t\ttemplate <typename T>\n\t\tvoid InvlRetVal(T& )\n\t\t{\n\n\t\t}\n\n\t\tvoid InvlRetVal(CScriptTable& tbl);\n\n\t\tvoid InvlRetVal(CScriptUserData& ud);\n\n\tprivate:\n\t\tbool\t\t\t\t\tm_bOwn;\n\t\tlua_State*\t\t\t\tm_pLua;\n\t\tSScriptHandleRefNode    m_head;\n\t};\n\n\t// Script abstract data base : abstract data means table and user data type\n\t// It's internal used, Never work with a table or userdata with this parent class \n\tclass IScriptADBase : INonCopyable\n\t{\n\tprotected:\n\t\tstruct SRefNode : SScriptHandleRefNode\n\t\t{\n\t\t\tSRefNode()\n\t\t\t\t: pLua(NULL)\n\t\t\t\t, nRef(LUA_NOREF)\n\t\t\t{\n\t\t\t\tunLinker = &UnLinker;\n\t\t\t}\n\n\t\t\tlua_State*\t\t\t\tpLua;\n\t\t\tint\t\t\t\t\t\tnRef;\n\n\t\t\tbool IsReferd() const\n\t\t\t{\n\t\t\t\treturn pLua && nRef != LUA_NOREF;\n\t\t\t}\n\n\t\t\tvoid UnRef() \n\t\t\t{\n\t\t\t\tif(unLinker)\n\t\t\t\t{\n\t\t\t\t\tunLinker(this);\n\t\t\t\t}\n\t\t\t}\n\n\t\tprotected:\n\t\t\t// Static\n\t\t\tstatic void UnLinker(SScriptHandleRefNode* pT);\n\t\t};\n\n\t\ttypedef SRefNode RefNode;\n\n\tpublic:\n\t\tIScriptADBase()\n\t\t{\n\n\t\t}\n\n\t\t~IScriptADBase()\n\t\t{\n\t\t\tUnRef();\n\t\t}\n\n\t\tbool IsReferd() const\n\t\t{\n\t\t\treturn m_ref.IsReferd();\n\t\t}\n\n\t\tvoid UnRef()\n\t\t{\n\t\t\tm_ref.UnRef();\n\t\t}\n\n\t\t//! Get value from the ad type(table or userdata)\n\t\ttemplate <typename T>\n\t\tint Get(const char* pszName, T& v)\n\t\t{\n\t\t\tif(!IsReferd())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_State* pLua = m_ref.pLua;\n\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tif(!PrepareStack()) // this_table is on the top\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_getfield(pLua, -1, pszName);\t\t\t\t// __bin_refs this_table value\n\n\t\t\treturn TFmLua<typename TArgumentType<T>::value_type>::Make(pLua, -1, v);\n\t\t}\n\n\t\ttemplate <typename T>\n\t\tint Set(const char* pszName, T v)\n\t\t{\n\t\t\tif(!IsReferd())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_State* pLua = m_ref.pLua;\n\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tif(!PrepareStack())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!TToLua<typename TArgumentType<T>::value_type>::Make(v, pLua))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_setfield(pLua, -2, pszName);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tint Set(const char* pszName, CScriptTable& tbl)\n\t\t{\n\t\t\treturn Set<CScriptTable&>(pszName, tbl);\n\t\t}\n\n\t\tint Set(const char* pszName, CScriptUserData& ud)\n\t\t{\n\t\t\treturn Set<CScriptUserData&>(pszName, ud);\n\t\t}\n\n\t\tint Set(const char* pszName, const std::string& str)\n\t\t{\n\t\t\treturn Set<const std::string&>(pszName, str);\n\t\t}\n\n\t\t//! Get value from ad type(Call this method means you treat ad type as a array).\n\t\t//! NB. Array starts at 1 not 0 in lua.\n\t\ttemplate <typename T>\n\t\tint Get(int nIdx, T& v)\n\t\t{\n\t\t\tif(!IsReferd())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_State* pLua = m_ref.pLua;\n\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tif(!PrepareStack())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_rawgeti(pLua, -1, nIdx);\n\n\t\t\treturn TFmLua<typename TArgumentType<T>::value_type>::Make(pLua, -1, v);\n\t\t}\n\n\t\t//! Set a array value.\n\t\ttemplate <typename T>\n\t\tint Set(int nIdx, T v)\n\t\t{\n\t\t\tif(!IsReferd())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_State* pLua = m_ref.pLua;\n\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tif(!PrepareStack())\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!TToLua<typename TArgumentType<T>::value_type>::Make(v, pLua))\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tlua_rawseti(pLua, -2, nIdx);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\tint Set(int nIdx, CScriptTable& tbl)\n\t\t{\n\t\t\treturn Set<CScriptTable&>(nIdx, tbl);\n\t\t}\n\n\t\tint Set(int nIdx, CScriptUserData& ud)\n\t\t{\n\t\t\treturn Set<CScriptUserData&>(nIdx, ud);\n\t\t}\n\n\t\tint Set(int nIdx, const std::string& str)\n\t\t{\n\t\t\treturn Set<const std::string&>(nIdx, str);\n\t\t}\n\n\t\tint Get(const char* pszName, CScriptTable& tbl);\n\n\t\tint Get(const char* pszName, CScriptUserData& ud);\n\n\t\tint Get(int nIdx, CScriptTable& tbl);\n\n\t\tint Get(int nIdx, CScriptUserData& ud);\n\n#define ARGUMENT_TYPE(arg) typename TArgumentType<arg>::argument_type\n\n#define VALUE_TYPE(arg)    typename TArgumentType<arg>::value_type\n\n#define MEM_FUNC_PREWORK() \\\n\tInvlRetVal(r);\\\n\tif(!IsReferd())\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\\\n\t\tlua_State* pLua = m_ref.pLua;\\\n\t\tCHECK_LUA_STACK(pLua);\\\n\t\tif(!PrepareStack())\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\\\n\t\tlua_getfield(pLua, -1, pszName);\\\n\t\tif(!lua_isfunction(pLua, -1))\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\n\n#define MAKE_THIS()\\\n\tlua_pushvalue(pLua, -2)\n\n#define MAKE_ARG(type, vale)\\\n\tif(!TToLua<VALUE_TYPE(type)>::Make((vale), pLua))\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\n\n#define MAKE_RET()\\\n\tint __nFmRet = TFmLua<R>::Make(pLua, -1, r)\n\n#define MEM_FUNC_POSWORK()\\\n\treturn PostFmLua(__nFmRet, r);\n\n\t\t//! Call a member function of this ad type.\n\t\t//! Member function means the first argument is this object(table or userdata)\n\t\t//! \\return 0-fail\n\t\ttemplate <typename R>\n\t\tint CallMemFunc(const char* pszName, R& r)\n\t\t{\n\t\t\tMEM_FUNC_PREWORK();\n\n\t\t\tMAKE_THIS();\n\n\t\t\tif(lua_pcall(pLua, 1, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call MemFunc[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tMEM_FUNC_POSWORK();\n\t\t}\n\n\t\t//! One argument version, See the 0 argument version.\n\t\ttemplate <typename A0, typename R>\n\t\tint CallMemFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r)\n\t\t{\n\t\t\tMEM_FUNC_PREWORK();\n\n\t\t\tMAKE_THIS();\n\t\t\tMAKE_ARG(A0, a0);\n\n\t\t\tif(lua_pcall(pLua, 2, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tMEM_FUNC_POSWORK();\n\t\t}\n\n\t\t//! Two arguments version, see 0 argument version.\n\t\ttemplate <typename A0, typename A1, typename R>\n\t\tint CallMemFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r)\n\t\t{\n\t\t\tMEM_FUNC_PREWORK();\n\n\t\t\tMAKE_THIS();\n\t\t\tMAKE_ARG(A0, a0);\n\t\t\tMAKE_ARG(A1, a1);\n\n\t\t\tif(lua_pcall(pLua, 3, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call MemFunc[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tMEM_FUNC_POSWORK();\n\t\t}\n#undef ARGUMENT_TYPE\n#undef VALUE_TYPE\n#undef MEM_FUNC_PREWORK\n#undef MAKE_THIS\n#undef MAKE_ARG\n#undef MAKE_RET\n#undef MEM_FUNC_POSWORK\n\t\n\t\tlua_State* GetHandle() const\n\t\t{\n\t\t\treturn m_ref.pLua;\n\t\t}\n\n\t\tint PrepareStack();\n\n\tprotected:\n\n\t\ttemplate <typename T>\n\t\tint PostFmLua(int nFmLuaRet, T)\n\t\t{\n\t\t\treturn nFmLuaRet;\n\t\t}\n\n\t\tint PostFmLua(int nFmLuaRet, CScriptTable& tbl);\n\n\t\tint PostFmLua(int nFmLuaRet, CScriptUserData& ud);\n\n\t\ttemplate <typename T>\n\t\tvoid InvlRetVal(T& )\n\t\t{\n\n\t\t}\n\n\t\tvoid InvlRetVal(CScriptTable& tbl);\n\n\t\tvoid InvlRetVal(CScriptUserData& ud);\n\n\t\tSRefNode\t\tm_ref;\n\n\t\tfriend class CScriptHandle;\n\t\tfriend class CScriptUserData;\n\t};\n\n\t//! Encapsulate a lua table.\n\tclass CScriptTable : public IScriptADBase\n\t{\n\tpublic:\n\t\tCScriptTable()\n\t\t{\n\n\t\t}\n\n\t\t~CScriptTable()\n\t\t{\n\t\t\t\n\t\t}\n\n#define ARGUMENT_TYPE(arg) typename TArgumentType<arg>::argument_type\n#define VALUE_TYPE(arg)    typename TArgumentType<arg>::value_type\n\n#define FUNC_PREWORK() \\\n\t\tInvlRetVal(r);\\\n\t\tif(!IsReferd())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\tlua_State* pLua = m_ref.pLua;\\\n\t\tCHECK_LUA_STACK(pLua);\\\n\t\tif(!PrepareStack())\\\n\t\t{\\\n\t\t\treturn 0;\\\n\t\t}\\\n\t\tlua_getfield(pLua, -1, pszName);\\\n\t\tif(!lua_isfunction(pLua, -1))\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\n\n#define MAKE_ARG(type, vale)\\\n\tif(!TToLua<VALUE_TYPE(type)>::Make((vale), pLua))\\\n\t\t{\\\n\t\treturn 0;\\\n\t\t}\n\n#define MAKE_RET()\\\n\tint __nFmRet = TFmLua<R>::Make(pLua, -1, r)\n\n#define FUNC_POSWORK()\\\n\treturn PostFmLua(__nFmRet, r);\n\n\t\ttemplate <typename R>\n\t\tint CallFunc(const char* pszName, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tif(lua_pcall(pLua, 0, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n\t\ttemplate <typename A0, typename R>\n\t\tint CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tMAKE_ARG(A0, a0);\n\n\t\t\tif(lua_pcall(pLua, 1, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n\t\ttemplate <typename A0, typename A1, typename R>\n\t\tint CallFunc(const char* pszName, ARGUMENT_TYPE(A0) a0, ARGUMENT_TYPE(A1) a1, R& r)\n\t\t{\n\t\t\tFUNC_PREWORK();\n\n\t\t\tMAKE_ARG(A0, a0);\n\t\t\tMAKE_ARG(A1, a1);\n\n\t\t\tif(lua_pcall(pLua, 2, 1, 0) != LUA_OK)\t// Error msg here\n\t\t\t{\n\t\t\t\tLOG_MESSAGE(\"[ERROR] Call Func[%s] : %s\", pszName, lua_tostring(pLua, -1));\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tMAKE_RET();\n\n\t\t\tFUNC_POSWORK();\n\t\t}\n\n#undef ARGUMENT_TYPE\n#undef VALUE_TYPE\n#undef FUNC_PREWORK\n#undef MAKE_THIS\n#undef MAKE_ARG\n#undef MAKE_RET\n#undef FUNC_POSWORK\n\n\t\ttemplate <typename A> friend struct TFmLua; \n\t\ttemplate <typename A> friend struct TToLua;\n\t\tfriend class CScriptHandle;\n\t\tfriend class CScriptUserData;\n\t};\n\n\t//! Encapsulate a lua userdata.\n\tclass CScriptUserData : public IScriptADBase\n\t{\n\tpublic:\n\t\tCScriptUserData()\n\t\t{\n\n\t\t}\n\n\t\t~CScriptUserData()\n\t\t{\n\n\t\t}\n\n\t\ttemplate <typename A> friend struct TFmLua;\n\t\ttemplate <typename A> friend struct TToLua;\n\t\tfriend class CScriptHandle;\n\t\tfriend class CScriptTable;\n\t};\n\n\t//! Utilities\n\ttemplate <>\n\tstruct TFmLua<CScriptTable>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, CScriptTable& tbl);\n\t};\n\n\ttemplate <>\n\tstruct TFmLua<CScriptUserData>\n\t{\n\t\tstatic int Make(lua_State* pL, int nIdx, CScriptUserData& ud);\n\t};\n\n\ttemplate <>\n\tstruct TToLua<CScriptTable>\n\t{\n\t\tstatic int Make(CScriptTable& tbl, lua_State* pL);\n\t};\n\n\ttemplate <>\n\tstruct TToLua<CScriptUserData>\n\t{\n\t\tstatic int Make(CScriptUserData& ud, lua_State* pL);\n\t};\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptObject.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_OBJECT_H\n#define SERVER_SHARD_SCRIPT_OBJECT_H\n\n#include \"ScriptHandle.h\"\n\nnamespace bin\n{\n\tstruct SScriptObject\n\t{\n\t\tSScriptObject()\n\t\t\t: m_pObjRef(NULL)\n\t\t\t, m_pThis(NULL)\n\t\t\t, m_pExporter(NULL)\n\t\t\t, m_bDelByScr(false)\n\t\t\t, m_pReleaser(NULL)\n\t\t{\n\n\t\t}\n\n\t\t~SScriptObject()\n\t\t{\n\t\t\tUnlink();\n\t\t}\n\n\t\t// Copy constructor and assign operator should do nothing \n\t\tSScriptObject(const SScriptObject& r)\n\t\t\t: m_pObjRef(NULL)\n\t\t\t, m_pThis(NULL)\n\t\t\t, m_pExporter(NULL)\n\t\t\t, m_bDelByScr(false)\t\t// Should use the r.m_bDelByScr ? \n\t\t\t, m_pReleaser(NULL)\n\t\t{\n\t\t\t\n\t\t}\n\n\t\tSScriptObject& operator = (const SScriptObject& r)\n\t\t{\n\t\t\t// Copy nothing about script part\n\t\t}\n\n\t\t// Internal used, Attach this object to lua object\n\t\ttemplate <typename T>\n\t\tvoid Attach(T* pThis, SScriptObjectRef* pObjRef)\n\t\t{\n\t\t\tassert(!m_pObjRef && !m_pThis);\n\n\t\t\tm_pObjRef   = pObjRef;\n\t\t\tm_pThis     = pThis;\n\t\t\tm_pExporter = pThis->GetExporter();\n\t\t\tassert(m_pExporter);\n\n\t\t\tm_pReleaser = &SScriptObject::ReleaseImpl<T>;\n\n\t\t\tInitScript();\n\t\t}\n\n\t\t// Internal used, unlink the reference to lua object, NB. lua object will still reference this c++ object\n\t\tvoid SideUnlink()\n\t\t{\n\t\t\tReleaseScript();\n\n\t\t\tm_pObjRef   = NULL;\n\t\t\tm_pThis     = NULL;\n\t\t\tm_pExporter = NULL;\n\t\t\tm_bDelByScr = false;\n\t\t}\n\n\t\t// Internal used, Unlink the connection between c++ object and lua object\n\t\tvoid Unlink()\n\t\t{\n\t\t\tif(m_pObjRef)\n\t\t\t{\n\t\t\t\tm_pObjRef->Unlink();\n\t\t\t}\n\n\t\t\tassert(!m_pObjRef);\n\t\t}\n\n\t\t// Internal used, Release api for lua proxy, NB. this object will be deleted after calling this method\n\t\tvoid ReleaseByScr()\n\t\t{\n\t\t\tif(GetDelByScr())\n\t\t\t{\n\t\t\t\t(this->*m_pReleaser)();\n\t\t\t}\n\t\t\t// Never touch anything later, the object has been destroyed.\n\t\t} \n\n\t\tbool IsExported() const\n\t\t{\n\t\t\treturn m_pObjRef != NULL;\n\t\t}\n\n\t\t// Internal used, Push userdata on top in pL's stack, nil if not exported\n\t\tint GetUserData(lua_State* pL) ;\n\n\t\t//! Get the lua_State handle. you can access lua machine from it.\n\t\tCScriptHandle& GetScriptHandle()\n\t\t{\n\t\t\treturn m_scriptHandle;\n\t\t}\n\n\t\t//! Get the userdata (lua representation of this class), you can access lua script part from it.\n\t\t//! GetUserData is not like GetScriptHandle to return what we want. If do it like that, lua gc can't get the chance to collect a userdata because the reference in ref table.\n\t\t//! NB. if you store scriptUserData for later using, scriptUserData will be invalid if the object has been destroyed automatically.\n\t\tint GetUserData(CScriptUserData& scriptUserData);\n\n\t\t//! Set if the lua deletes this object(Means lua manages the life of this object).\n\t\tvoid SetDelByScr(bool bDelByScr)\n\t\t{\n\t\t\tif(IsExported())\n\t\t\t{\n\t\t\t\tm_pObjRef->OnChangeWeakedTo(bDelByScr);\n\t\t\t}\n\n\t\t\tm_bDelByScr = bDelByScr;\n\t\t}\n\n\t\t//! Get the lua deleting tag.\n\t\tbool GetDelByScr() const\n\t\t{\n\t\t\treturn m_bDelByScr;\n\t\t}\n\n\t\tbool IsWeaked() const\n\t\t{\n\t\t\treturn GetDelByScr();\n\t\t}\n\n\tpublic:\n\t\t// Internal used, don't touch these things\n\t\tvoid*                   m_pThis;\n\t\tclass CClassExporter*   m_pExporter;\n\n\tprotected:\n\t\ttemplate <typename T>\n\t\tvoid ReleaseImpl()\n\t\t{\n\t\t\tT* pThis = reinterpret_cast<T*>(m_pThis);\n\n\t\t\tdelete pThis;\n\t\t}\n\t\t// Initialize script handle and script userdata\n\t\tint  InitScript();\n\t\t// Release script handle and script userdata\n\t\tvoid ReleaseScript();\n\tprotected:\n\t\tbool                    m_bDelByScr;\n\t\tSScriptObjectRef*\t    m_pObjRef;\n\t\ttypedef void (SScriptObject::* Releaser)();\n\t\tReleaser                m_pReleaser;\n\n\t\tCScriptHandle           m_scriptHandle;\n\t\t// NB : this reference will cause the gc can't clean the weak objects table if there is no reference in lua(except the ref table). \n\t\t//CScriptUserData\t\t\tm_scriptUserData;\n\t};\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptProxy.cpp",
    "content": "//\n#include \"Public.h\"\n\n//\n#include \"ScriptProxy.h\"\n#include \"ScriptObject.h\"\n\n//\n#include \"ScriptBase.h\"\n#include \"ScriptExporter.h\"\n\n//\n\nnamespace bin\n{\n    void* SScriptObjectRef::GetScriptObj()\n    {\n        return pObject->m_pThis;\n    }\n\n    void SScriptObjectRef::Unlink()\n    {\n\t\tSScriptObject* pObj = pObject;\n\t\t\n\t\t// Need pObj, So Unlink self first\n\t\tSideUnlink();\n        \n\t\t// Then obj\n\t\tif(pObj)\n        {\n            pObj->SideUnlink();\n        }\n    }\n\n\tvoid SScriptObjectRef::SideUnlink()\n\t{\n\t\t// Remove the object from objects table\n\t\tif(pLua && nRef!=LUA_NOREF)\n\t\t{\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tScriptExporterManager().CheckObjectsTable(pLua, pObject->IsWeaked());\n\n\t\t\t// Avoid re-entrance by CheckObjectsTable\n\t\t\tif(pLua && nRef!=LUA_NOREF)\n\t\t\t{\n\t\t\t\tluaL_unref(pLua, -1, nRef);\n\t\t\t}\n\t\t}\n\n\t\tpObject = NULL;\n\t\tpLua    = NULL;\n\t\tnRef    = LUA_NOREF;\n\t}\n\n\tvoid SScriptObjectRef::OnChangeWeakedTo(bool bWeaked)\n\t{\n\t\tif(pObject && pObject->IsWeaked() != bWeaked)\t// Weak property is changed\n\t\t{\n\t\t\tassert(pLua && nRef!=LUA_NOREF);\n\n\t\t\tCHECK_LUA_STACK(pLua);\n\n\t\t\tScriptExporterManager().CheckObjectsTable(pLua, pObject->IsWeaked());\t// oldTbl\n\t\t\tlua_rawgeti(pLua, -1, nRef);\t\t\t\t\t\t\t\t\t// oldTbl, obj\n\n\t\t\tScriptExporterManager().CheckObjectsTable(pLua, bWeaked);\t\t// oldTbl, obj, newTbl\n\t\t\tlua_pushvalue(pLua, -2);\t\t\t\t\t\t\t\t\t\t// oldTbl, obj, newTbl, obj\n\n\t\t\tint nNewRef = luaL_ref(pLua, -2);\t// oldTbl, obj, newTbl\n\t\t\tluaL_unref(pLua, -3, nRef);\n\n\t\t\tnRef = nNewRef;\n\t\t}\n\t}\n\n\t// Push userdata on top in pL's stack, nil if not exported\n\tint SScriptObject::GetUserData(lua_State* pL) \n\t{\n\t\tif(!IsExported() || m_pObjRef->pLua != pL)\n\t\t{\n\t\t\tlua_pushnil(pL);\n\n\t\t\treturn 1;\n\t\t}\n\n\t\t// Stop gc, because CheckObjectsTable may call gc\n\t\t//GUARD_LUA_GC(pL);\n\n\t\tScriptExporterManager().CheckObjectsTable(pL, IsWeaked());\n\t\tlua_rawgeti(pL, -1, m_pObjRef->nRef);\n\t\tlua_replace(pL, -2);\n\t\treturn 1;\n\t}\n\n\tint SScriptObject::GetUserData(CScriptUserData& scriptUserData)\n\t{\n\t\tscriptUserData.UnRef();\n\n\t\tif(m_scriptHandle.IsNull())\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tlua_State* pLua = m_pObjRef->pLua;\n\t\tCHECK_LUA_STACK(pLua);\n\n\t\t// Stop gc, because CheckObjectsTable may call gc\n\t\t//GUARD_LUA_GC(pLua);\n\n\t\tScriptExporterManager().CheckObjectsTable(pLua, IsWeaked());\n\t\tlua_rawgeti(pLua, -1, m_pObjRef->nRef);\n\n\t\tconst char* TEMP_REF = \"__bin_temp\";\n\t\tlua_setglobal(pLua, TEMP_REF);\n\n\t\tm_scriptHandle.Get(TEMP_REF, scriptUserData);\n\t\tlua_pushnil(pLua);\n\t\tlua_setglobal(pLua, TEMP_REF);\n\t\t\n\t\treturn 1;\n\t}\n\n\tint  SScriptObject::InitScript()\n\t{\n\t\tReleaseScript();\n\n\t\tlua_State* pLua = m_pObjRef->pLua;\n\t\tif(!m_scriptHandle.Init(pLua))\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tvoid SScriptObject::ReleaseScript()\n\t{\n\t\tm_scriptHandle.Release();\n\t}\n};"
  },
  {
    "path": "code/EVA/server/server_share/bin_luabind/ScriptProxy.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_PROXY_H\n#define SERVER_SHARD_SCRIPT_PROXY_H\n\nnamespace bin\n{\n    struct SScriptObject;\n\n\tstruct SScriptObjectRef\n\t{\n\t\tstruct SScriptObject*\tpObject;\n\t\tlua_State*\t\t\t\tpLua;\n\t\tint\t\t\t\t\t\tnRef;\n\n        // INonCopyable\n        SScriptObjectRef(SScriptObjectRef&);\n        SScriptObjectRef& operator = (SScriptObjectRef&);\n\n\t\tSScriptObjectRef()\n\t\t\t: pObject(NULL)\n\t\t\t, pLua(NULL)\n\t\t\t, nRef(LUA_NOREF)\n\t\t{\n\n\t\t}\n\n\t\t~SScriptObjectRef()\n\t\t{\n\t\t\tassert(!pObject);\n\t\t}\n\n        void* GetScriptObj();\n\n\t\t// Unlink the connection between c++ object and lua object\n\t\tvoid Unlink();\n\n\t\t// Unlink the lua object reference to c++ object, NB. The c++ object still reference to lua object\n\t\tvoid SideUnlink();\n\n\t\tvoid OnChangeWeakedTo(bool bWeaked);\n\t};\n\n\t//! a c++ proxy to lua. this is the only way lua accesses to a c++ object. \n\tstruct SScriptProxy\n\t{\n\t\tenum EProxyType\n\t\t{\n\t\t\tEPT_NULL    = 0,\n\t\t\tEPT_OBJECT,\n\t\t};\n\n\t\tEProxyType\t\t\t\tePT;\n\t\tSScriptObjectRef\t\tobjRef;\t\t\t// Valid only if Proxy takes a object\n\n\t\tSScriptProxy()\n\t\t\t: ePT(EPT_NULL)\n\t\t{\n\n\t\t}\n\t};\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/bit_set_ext2.h",
    "content": "#include <nel/misc/bit_set.h>\n#include <nel/misc/sstring.h>\n\nclass CBitSetExt2\n{\npublic:\n\n    bool SetValue( uint32 idx, uint8 value )\n    {\n        if ( idx!=0 && idx<MAX_INDEX && value < (1<<VALUE_USR_BIT) )\n        {\n            const uint bit_idx = idx << 1;\n\n            if ( m_BitSet.size() <= bit_idx )\n            {\n                m_BitSet.resizeNoReset(bit_idx+VALUE_USR_BIT);\n            }\n\n            m_BitSet.clear(bit_idx);\n            m_BitSet.clear(bit_idx+1);\n\n            if ( value&1 )   {  m_BitSet.set( bit_idx );  }\n            if ( value&2 )   {  m_BitSet.set( bit_idx+1 );  }\n\n\t\t\treturn true;\n        }\n\t\treturn false;\n    }\n\n    uint32 GetValue( uint32 idx )\n    {\n        uint32 val = INVALID_VAL;\n\n        if ( idx!=0 && idx<Size() )\n        {\n            const uint bit_idx = idx << 1;\n\n            val  = m_BitSet.get(bit_idx+1)<<1;\n            val |= (uint32)m_BitSet.get(bit_idx);\n        }\n\n        return val;\n    }\n\n    void InitBitmap( std::string& array_str )\n    {\n        m_BitSet.resize(array_str.size()*8);\n\n        if ( array_str.size()%sizeof(uint32) == 0 )\n        {\n            for ( uint i=0,j=0; i<array_str.size(); i+=sizeof(uint32) )\n            {\n                uint32 array_uint32 = *(uint32*)&array_str[i];\n                m_BitSet.setUint( array_uint32, j++ );\n            }\n        }\n        else\n        {\n            nlwarning( \"array_str.size()%sizeof(uint32)!=0\" );\n        }\n    }\n\n    std::string& GetArrayStr()\n    {\n        const std::vector<uint32>& bit_vct = m_BitSet.getVector();\n        m_ArrayStr.resize(bit_vct.size()*sizeof(uint32));\n\n        for ( uint i=0; i<bit_vct.size(); ++i )\n        {\n            *(uint32*)&m_ArrayStr[i*sizeof(uint32)] = bit_vct[i];\n        }\n        return m_ArrayStr;\n    }\n\n    uint32 Size()\n    {\n        return m_BitSet.size()>>1;\n    }\n\n    NLMISC::CSString toString()\n    {\n        NLMISC::CSString s;\n        for ( uint32 i=0; i!=Size(); ++i )\n        {\n            uint32 val = GetValue(i);\n\n            s << \"[\" << i <<\"]=\";\n            s << \"\" << val <<\"    \";\n\n            if ( i%5==0 )  {  s << \"\\n\";  }\n        }\n        s << \"\\n\";\n        return s;\n    }\n\n    enum \n    {\n        VALUE_USR_BIT = 2,\n        MAX_INDEX     = 512,\n        INVALID_VAL   = 0xff,\n    };\n\nprivate:\n    std::string         m_ArrayStr;\n    NLMISC::CBitSet     m_BitSet;\n};\n"
  },
  {
    "path": "code/EVA/server/server_share/buf_fifo2.h",
    "content": "#ifndef NL_BUF_FIFO_DOUBLE_H\n#define NL_BUF_FIFO_DOUBLE_H\n\n#include <nel/misc/types_nl.h>\n#include <vector>\n\nnamespace NLMISC {\n\ntemplate<class T>\nclass CBufFIFO2\n{\npublic:\n\tCBufFIFO2 ():_PosReadMax(0),_PosRead(0),_PosWrite(0),_pRead(NULL),_pWrite(NULL),_MaxSize(0){}\n\t~CBufFIFO2 (){}\n\n\tvoid init( uint32 size )\n\t{\n\t\t_MaxSize = size;\n\t\t_Data1.resize( _MaxSize );\n\t\t_Data2.resize( _MaxSize );\n\t\t_pRead = &_Data1;\n\t\t_pWrite = &_Data2;\n\t}\n\n\tbool push_back (T* data)\n\t{\n\t\t_WriteMutex.enter();\n\t\tif( _PosWrite < _MaxSize )\t\t//\tδ\n\t\t{\n\t\t\t(*_pWrite)[_PosWrite++] = data;\n\t\t\t_WriteMutex.leave();\n\t\t\treturn true;\n\t\t}\n\t\t_WriteMutex.leave();\n\t\treturn false;\n\t}\n\n    //   \n    void swap()\n    {\n        _ReadMutex.enter();\n        _WriteMutex.enter();\n\n        _PosReadMax = _PosWrite;\n        _PosWrite   = 0;\n        _PosRead    = 0;\n        std::vector<T*>* pTmp = _pRead;\n        _pRead  = _pWrite;\n        _pWrite = pTmp;\n\n        _WriteMutex.leave();\n        _ReadMutex.leave();\n    }\n\n\tT* pop_front()\n\t{\n\t\tT* pRet = NULL;\n\n\t\t_ReadMutex.enter();\n\t\tif( _PosRead < _PosReadMax )\n\t\t{\n\t\t\tpRet = (*_pRead)[_PosRead++];\n\t\t}\n\t\t_ReadMutex.leave();\n\n        if ( pRet==NULL )\n        {\n            swap();\n        }\n\t\treturn pRet;\n\t}\n\n\tuint32 size()\n\t{\n\t\treturn _PosWrite + _PosReadMax - _PosRead;\n\t}\n\nprivate:\n\n\tCMutex _WriteMutex;\n\tCMutex _ReadMutex;\n\tuint32 _PosRead;\n    uint32 _PosReadMax;\n\tuint32 _PosWrite;\n\tuint32 _MaxSize;\n\n\tstd::vector<T*>* _pRead;\n\tstd::vector<T*>* _pWrite;\n\tstd::vector<T*> _Data1;\n\tstd::vector<T*> _Data2;\n};\n\n\n} // NLMISC\n\n#endif // NL_BUF_FIFO_DOUBLE_H\n\n/* End of buf_fifo2.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/buf_fifo_ring.h",
    "content": "﻿#ifndef NL_BUF_FIFO_RING_H\n#define NL_BUF_FIFO_RING_H\n\n#include <nel/misc/types_nl.h>\n#include <vector>\n\nnamespace NLMISC {\n\ntemplate<class T>\nclass CBufFIFORing\n{\npublic:\n\n\tCBufFIFORing ():_PosRead(0),_PosWrite(0),_MaxSize(1)\n\t{\n\t\t_Data.resize(1);\n\t}\n\t~CBufFIFORing (){};\n\n\tuint32 init( uint32 size )\t//  扩展成2的倍数,<=2147483648。\n\t{\n\t\tif( size < 0x80000000 )\n\t\t{\n\t\t\tfor( uint32 ndx = 0; ndx < 32; ndx++ )\n\t\t\t{\n\t\t\t\t_MaxSize = ( _MaxSize << 1 );\n\t\t\t\tif( _MaxSize >= size )\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_MaxSize = 0x80000000;\n\t\t}\n\n\t\t_Mask = _MaxSize - 1;\n\t\t_Data.resize( _MaxSize );\n\t\treturn _MaxSize;\n\t}\n\n\tbool push_back (T* data)\n\t{\n\t\tbool res = false;\n\t\t\n\t\tif( _PosWrite - _PosRead < _MaxSize )\t\t//\t如果队列未满\n\t\t{\n\t\t\t_mutex.enter();\n\t\t\tuint32 write = _PosWrite++;\n\t\t\t_Data[write&_Mask] = data;\n\t\t\t_mutex.leave();\n\t\t\tres = true;\n\t\t}\n\t\t\n\t\treturn res;\n\t}\n\n\tT* pop_front()\n\t{\n\t\tT* res = NULL;\n\t\t\n\t\tif( _PosRead != _PosWrite )\t\t//\t如果队列不为空\n\t\t{\n\t\t\t_mutex.enter();\n\t\t\tuint32 read = _PosRead++;\n\t\t\tres = _Data[read&_Mask];\n\t\t\t_mutex.leave();\n\t\t}\n\t\t\n\t\treturn res;\n\t}\n\n\tuint32 size()\n\t{\n\t\treturn _PosWrite - _PosRead;\n\t}\n\n    bool empty( void )\n    {\n        return ( size() <= 0 );\n    }\n\n\tvoid clear()\n\t{\n\t\t_PosRead  = 0;\n\t\t_PosWrite = 0;\n\t}\n\nprivate:\n\tCMutex _mutex;\n\tvolatile uint32 _PosRead;\n\tvolatile uint32 _PosWrite;\n\tuint32  _MaxSize;\n\tuint32  _Mask;\n\n\tstd::vector<T*> _Data;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_BUF_FIFO_RING_H\n\n/* End of buf_fifo_ring.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/callback_adaptor.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef CALLBACK_ADAPTER_H\n#define CALLBACK_ADAPTER_H\n\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\n\nclass ICallbackServerAdaptor\n{\n\tvoid\t\t\t\t\t*_ContainerClass;\npublic:\n\tICallbackServerAdaptor(void *containerClass)\n\t\t:\t_ContainerClass(containerClass)\n\t{\n\t}\n\n\tvirtual ~ICallbackServerAdaptor()\n\t{\n\t}\n\n\tvoid *getContainerClass()\n\t{\n\t\treturn _ContainerClass;\n\t}\n\n\tvirtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) =0;\n\tvirtual void setConnectionCallback(NLNET::TNetCallback cb, void *arg) =0;\n\tvirtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) =0;\n\tvirtual void init(uint16 port) =0;\n\tvirtual void disconnect( NLNET::TSockId hostid) =0;\n\tvirtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid, bool log = true) =0;\n\tvirtual void update() =0;\n};\n\nclass ICallbackClientAdaptor\n{\n\tvoid\t\t\t\t\t*_ContainerClass;\npublic:\n\tICallbackClientAdaptor(void *containerClass)\n\t\t:\t_ContainerClass(containerClass)\n\t{\n\t}\n\n\tvirtual ~ICallbackClientAdaptor()\n\t{\n\t}\n\n\tvoid *getContainerClass()\n\t{\n\t\treturn _ContainerClass;\n\t}\n\tvirtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize) =0;\n\tvirtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg) =0;\n\tvirtual void connect( const NLNET::CInetAddress& addr ) =0;\n\tvirtual bool connected(  ) =0;\n\tvirtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid = NLNET::InvalidSockId, bool log = true) =0;\n\tvirtual void update() =0;\n};\n\n/** this is the default adaptor that make use of the NeL callback server\n */\nclass CNelCallbackServerAdaptor : public ICallbackServerAdaptor\n{\nprotected:\n\tNLNET::CCallbackServer\t_CallbackServer;\n\npublic:\n\tCNelCallbackServerAdaptor(void *containerClass)\n\t\t:\tICallbackServerAdaptor(containerClass)\n\t{\n\t\t_CallbackServer.setUserData(this);\n\t}\n\nprotected:\n\tvirtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize)\n\t{\n\t\t_CallbackServer.addCallbackArray(callbackarray, arraysize);\n\t}\n\tvirtual void setConnectionCallback(NLNET::TNetCallback cb, void *arg)\n\t{\n\t\t_CallbackServer.setConnectionCallback(cb, arg);\n\t}\n\tvirtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg)\n\t{\n\t\t_CallbackServer.setDisconnectionCallback(cb, arg);\n\t}\n\tvirtual void init(uint16 port)\n\t{\n\t\t_CallbackServer.init(port);\n\t}\n\tvirtual void disconnect( NLNET::TSockId hostid)\n\t{\n\t\t_CallbackServer.disconnect(hostid);\n\t}\n\n\tvirtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid, bool log = true)\n\t{\n\t\t_CallbackServer.send(buffer, hostid, log);\n\t}\n\tvirtual void update()\n\t{\n\t\t_CallbackServer.update();\n\t}\n};\n\n/** this is the default adaptor that make use of the NeL callback client\n */\nclass CNelCallbackClientAdaptor : public ICallbackClientAdaptor\n{\nprotected:\n\tNLNET::CCallbackClient\t_CallbackClient;\n\npublic:\n\tCNelCallbackClientAdaptor(void *containerClass)\n\t\t:\tICallbackClientAdaptor(containerClass)\n\t{\n\t\t_CallbackClient.setUserData(this);\n\t}\n\nprotected:\n\tvirtual void addCallbackArray(const NLNET::TCallbackItem *callbackarray, sint arraysize)\n\t{\n\t\t_CallbackClient.addCallbackArray(callbackarray, arraysize);\n\t}\n\tvirtual void setDisconnectionCallback(NLNET::TNetCallback cb, void *arg)\n\t{\n\t\t_CallbackClient.setDisconnectionCallback(cb, arg);\n\t}\n\tvirtual void connect( const NLNET::CInetAddress& addr )\n\t{\n\t\t_CallbackClient.connect(addr);\n\t}\n\tvirtual bool connected()\n\t{\n\t\treturn _CallbackClient.connected();\n\t}\n\n\tvirtual void send(const NLNET::CMessage &buffer, NLNET::TSockId hostid = NLNET::InvalidSockId, bool log = true)\n\t{\n\t\t_CallbackClient.send(buffer, hostid, log);\n\t}\n\tvirtual void update()\n\t{\n\t\t_CallbackClient.update();\n\t}\n};\n\n\n#endif // CALLBACK_ADAPTER_H\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/dtoa.cpp",
    "content": "/****************************************************************\n *\n * The author of this software is David M. Gay.\n *\n * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose without fee is hereby granted, provided that this entire notice\n * is included in all copies of any software which is or includes a copy\n * or modification of this software and in all copies of the supporting\n * documentation for such software.\n *\n * THIS SOFTWARE IS BEING PROVIDED \"AS IS\", WITHOUT ANY EXPRESS OR IMPLIED\n * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY\n * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY\n * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.\n *\n ***************************************************************/\n\n/* Please send bug reports to David M. Gay (dmg at acm dot org,\n * with \" at \" changed at \"@\" and \" dot \" changed to \".\").\t*/\n\n/* On a machine with IEEE extended-precision registers, it is\n * necessary to specify double-precision (53-bit) rounding precision\n * before invoking strtod or dtoa.  If the machine uses (the equivalent\n * of) Intel 80x87 arithmetic, the call\n *\t_control87(PC_53, MCW_PC);\n * does this with many compilers.  Whether this or another call is\n * appropriate depends on the compiler; for this to work, it may be\n * necessary to #include \"float.h\" or another system-dependent header\n * file.\n */\n\n/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.\n *\n * This strtod returns a nearest machine number to the input decimal\n * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are\n * broken by the IEEE round-even rule.  Otherwise ties are broken by\n * biased rounding (add half and chop).\n *\n * Inspired loosely by William D. Clinger's paper \"How to Read Floating\n * Point Numbers Accurately\" [Proc. ACM SIGPLAN '90, pp. 92-101].\n *\n * Modifications:\n *\n *\t1. We only require IEEE, IBM, or VAX double-precision\n *\t\tarithmetic (not IEEE double-extended).\n *\t2. We get by with floating-point arithmetic in a case that\n *\t\tClinger missed -- when we're computing d * 10^n\n *\t\tfor a small integer d and the integer n is not too\n *\t\tmuch larger than 22 (the maximum integer k for which\n *\t\twe can represent 10^k exactly), we may be able to\n *\t\tcompute (d*10^k) * 10^(e-k) with just one roundoff.\n *\t3. Rather than a bit-at-a-time adjustment of the binary\n *\t\tresult in the hard case, we use floating-point\n *\t\tarithmetic to determine the adjustment to within\n *\t\tone bit; only in really hard cases do we need to\n *\t\tcompute a second residual.\n *\t4. Because of 3., we don't need a large table of powers of 10\n *\t\tfor ten-to-e (just some small tables, e.g. of 10^k\n *\t\tfor 0 <= k <= 22).\n */\n\n/*\n * #define IEEE_8087 for IEEE-arithmetic machines where the least\n *\tsignificant byte has the lowest address.\n * #define IEEE_MC68k for IEEE-arithmetic machines where the most\n *\tsignificant byte has the lowest address.\n * #define Long int on machines with 32-bit ints and 64-bit longs.\n * #define IBM for IBM mainframe-style floating-point arithmetic.\n * #define VAX for VAX-style floating-point arithmetic (D_floating).\n * #define No_leftright to omit left-right logic in fast floating-point\n *\tcomputation of dtoa.  This will cause dtoa modes 4 and 5 to be\n *\ttreated the same as modes 2 and 3 for some inputs.\n * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3\n *\tand strtod and dtoa should round accordingly.  Unless Trust_FLT_ROUNDS\n *\tis also #defined, fegetround() will be queried for the rounding mode.\n *\tNote that both FLT_ROUNDS and fegetround() are specified by the C99\n *\tstandard (and are specified to be consistent, with fesetround()\n *\taffecting the value of FLT_ROUNDS), but that some (Linux) systems\n *\tdo not work correctly in this regard, so using fegetround() is more\n *\tportable than using FLT_ROUNDS directly.\n * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3\n *\tand Honor_FLT_ROUNDS is not #defined.\n * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines\n *\tthat use extended-precision instructions to compute rounded\n *\tproducts and quotients) with IBM.\n * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic\n *\tthat rounds toward +Infinity.\n * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased\n *\trounding when the underlying floating-point arithmetic uses\n *\tunbiased rounding.  This prevent using ordinary floating-point\n *\tarithmetic when the result could be computed with one rounding error.\n * #define Inaccurate_Divide for IEEE-format with correctly rounded\n *\tproducts but inaccurate quotients, e.g., for Intel i860.\n * #define NO_LONG_LONG on machines that do not have a \"long long\"\n *\tinteger type (of >= 64 bits).  On such machines, you can\n *\t#define Just_16 to store 16 bits per 32-bit Long when doing\n *\thigh-precision integer arithmetic.  Whether this speeds things\n *\tup or slows things down depends on the machine and the number\n *\tbeing converted.  If long long is available and the name is\n *\tsomething other than \"long long\", #define Llong to be the name,\n *\tand if \"unsigned Llong\" does not work as an unsigned version of\n *\tLlong, #define #ULLong to be the corresponding unsigned type.\n * #define KR_headers for old-style C function headers.\n * #define Bad_float_h if your system lacks a float.h or if it does not\n *\tdefine some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,\n *\tFLT_RADIX, FLT_ROUNDS, and DBL_MAX.\n * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)\n *\tif memory is available and otherwise does something you deem\n *\tappropriate.  If MALLOC is undefined, malloc will be invoked\n *\tdirectly -- and assumed always to succeed.  Similarly, if you\n *\twant something other than the system's free() to be called to\n *\trecycle memory acquired from MALLOC, #define FREE to be the\n *\tname of the alternate routine.  (FREE or free is only called in\n *\tpathological cases, e.g., in a dtoa call after a dtoa return in\n *\tmode 3 with thousands of digits requested.)\n * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making\n *\tmemory allocations from a private pool of memory when possible.\n *\tWhen used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,\n *\tunless #defined to be a different length.  This default length\n *\tsuffices to get rid of MALLOC calls except for unusual cases,\n *\tsuch as decimal-to-binary conversion of a very long string of\n *\tdigits.  The longest string dtoa can return is about 751 bytes\n *\tlong.  For conversions by strtod of strings of 800 digits and\n *\tall dtoa conversions in single-threaded executions with 8-byte\n *\tpointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte\n *\tpointers, PRIVATE_MEM >= 7112 appears adequate.\n * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK\n *\t#defined automatically on IEEE systems.  On such systems,\n *\twhen INFNAN_CHECK is #defined, strtod checks\n *\tfor Infinity and NaN (case insensitively).  On some systems\n *\t(e.g., some HP systems), it may be necessary to #define NAN_WORD0\n *\tappropriately -- to the most significant word of a quiet NaN.\n *\t(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)\n *\tWhen INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,\n *\tstrtod also accepts (case insensitively) strings of the form\n *\tNaN(x), where x is a string of hexadecimal digits and spaces;\n *\tif there is only one string of hexadecimal digits, it is taken\n *\tfor the 52 fraction bits of the resulting NaN; if there are two\n *\tor more strings of hex digits, the first is for the high 20 bits,\n *\tthe second and subsequent for the low 32 bits, with intervening\n *\twhite space ignored; but if this results in none of the 52\n *\tfraction bits being on (an IEEE Infinity symbol), then NAN_WORD0\n *\tand NAN_WORD1 are used instead.\n * #define MULTIPLE_THREADS if the system offers preemptively scheduled\n *\tmultiple threads.  In this case, you must provide (or suitably\n *\t#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed\n *\tby FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed\n *\tin pow5mult, ensures lazy evaluation of only one copy of high\n *\tpowers of 5; omitting this lock would introduce a small\n *\tprobability of wasting memory, but would otherwise be harmless.)\n *\tYou must also invoke freedtoa(s) to free the value s returned by\n *\tdtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.\n * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that\n *\tavoids underflows on inputs whose result does not underflow.\n *\tIf you #define NO_IEEE_Scale on a machine that uses IEEE-format\n *\tfloating-point numbers and flushes underflows to zero rather\n *\tthan implementing gradual underflow, then you must also #define\n *\tSudden_Underflow.\n * #define USE_LOCALE to use the current locale's decimal_point value.\n * #define SET_INEXACT if IEEE arithmetic is being used and extra\n *\tcomputation should be done to set the inexact flag when the\n *\tresult is inexact and avoid setting inexact when the result\n *\tis exact.  In this case, dtoa.c must be compiled in\n *\tan environment, perhaps provided by #include \"dtoa.c\" in a\n *\tsuitable wrapper, that defines two functions,\n *\t\tint get_inexact(void);\n *\t\tvoid clear_inexact(void);\n *\tsuch that get_inexact() returns a nonzero value if the\n *\tinexact bit is already set, and clear_inexact() sets the\n *\tinexact bit to 0.  When SET_INEXACT is #defined, strtod\n *\talso does extra computations to set the underflow and overflow\n *\tflags when appropriate (i.e., when the result is tiny and\n *\tinexact or when it is a numeric value rounded to +-infinity).\n * #define NO_ERRNO if strtod should not assign errno = ERANGE when\n *\tthe result overflows to +-Infinity or underflows to 0.\n * #define NO_HEX_FP to omit recognition of hexadecimal floating-point\n *\tvalues by strtod.\n * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now)\n *\tto disable logic for \"fast\" testing of very long input strings\n *\tto strtod.  This testing proceeds by initially truncating the\n *\tinput string, then if necessary comparing the whole string with\n *\ta decimal expansion to decide close cases. This logic is only\n *\tused for input more than STRTOD_DIGLIM digits long (default 40).\n */\n\n#include \"dtoa_config.h\"\n\n#ifndef Long\n#define Long long\n#endif\n#ifndef ULong\ntypedef unsigned Long ULong;\n#endif\n\n#ifdef DEBUG\n#include \"stdio.h\"\n#define Bug(x) {fprintf(stderr, \"%s\\n\", x); exit(1);}\n#endif\n\n#include \"stdlib.h\"\n#include \"string.h\"\n\n#ifdef USE_LOCALE\n#include \"locale.h\"\n#endif\n\n#ifdef Honor_FLT_ROUNDS\n#ifndef Trust_FLT_ROUNDS\n#include <fenv.h>\n#endif\n#endif\n\n#ifdef MALLOC\n#ifdef KR_headers\nextern char *MALLOC();\n#else\nextern void *MALLOC(size_t);\n#endif\n#else\n#define MALLOC malloc\n#endif\n\n#ifndef Omit_Private_Memory\n#ifndef PRIVATE_MEM\n#define PRIVATE_MEM 2304\n#endif\n#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))\nstatic double private_mem[PRIVATE_mem], *pmem_next = private_mem;\n#endif\n\n#undef IEEE_Arith\n#undef Avoid_Underflow\n#ifdef IEEE_MC68k\n#define IEEE_Arith\n#endif\n#ifdef IEEE_8087\n#define IEEE_Arith\n#endif\n\n#ifdef IEEE_Arith\n#ifndef NO_INFNAN_CHECK\n#undef INFNAN_CHECK\n#define INFNAN_CHECK\n#endif\n#else\n#undef INFNAN_CHECK\n#define NO_STRTOD_BIGCOMP\n#endif\n\n#include \"errno.h\"\n\n#ifdef Bad_float_h\n\n#ifdef IEEE_Arith\n#define DBL_DIG 15\n#define DBL_MAX_10_EXP 308\n#define DBL_MAX_EXP 1024\n#define FLT_RADIX 2\n#endif /*IEEE_Arith*/\n\n#ifdef IBM\n#define DBL_DIG 16\n#define DBL_MAX_10_EXP 75\n#define DBL_MAX_EXP 63\n#define FLT_RADIX 16\n#define DBL_MAX 7.2370055773322621e+75\n#endif\n\n#ifdef VAX\n#define DBL_DIG 16\n#define DBL_MAX_10_EXP 38\n#define DBL_MAX_EXP 127\n#define FLT_RADIX 2\n#define DBL_MAX 1.7014118346046923e+38\n#endif\n\n#ifndef LONG_MAX\n#define LONG_MAX 2147483647\n#endif\n\n#else /* ifndef Bad_float_h */\n#include \"float.h\"\n#endif /* Bad_float_h */\n\n#ifndef __MATH_H__\n#include \"math.h\"\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef CONST\n#ifdef KR_headers\n#define CONST /* blank */\n#else\n#define CONST const\n#endif\n#endif\n\n#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1\nExactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.\n#endif\n\ntypedef union { double d; ULong L[2]; } U;\n\n#ifdef IEEE_8087\n#define word0(x) (x)->L[1]\n#define word1(x) (x)->L[0]\n#else\n#define word0(x) (x)->L[0]\n#define word1(x) (x)->L[1]\n#endif\n#define dval(x) (x)->d\n\n#ifndef STRTOD_DIGLIM\n#define STRTOD_DIGLIM 40\n#endif\n\n#ifdef DIGLIM_DEBUG\nextern int strtod_diglim;\n#else\n#define strtod_diglim STRTOD_DIGLIM\n#endif\n\n/* The following definition of Storeinc is appropriate for MIPS processors.\n * An alternative that might be better on some machines is\n * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)\n */\n#if defined(IEEE_8087) + defined(VAX)\n#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \\\n((unsigned short *)a)[0] = (unsigned short)c, a++)\n#else\n#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \\\n((unsigned short *)a)[1] = (unsigned short)c, a++)\n#endif\n\n/* #define P DBL_MANT_DIG */\n/* Ten_pmax = floor(P*log(2)/log(5)) */\n/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */\n/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */\n/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */\n\n#ifdef IEEE_Arith\n#define Exp_shift  20\n#define Exp_shift1 20\n#define Exp_msk1    0x100000\n#define Exp_msk11   0x100000\n#define Exp_mask  0x7ff00000\n#define P 53\n#define Nbits 53\n#define Bias 1023\n#define Emax 1023\n#define Emin (-1022)\n#define Exp_1  0x3ff00000\n#define Exp_11 0x3ff00000\n#define Ebits 11\n#define Frac_mask  0xfffff\n#define Frac_mask1 0xfffff\n#define Ten_pmax 22\n#define Bletch 0x10\n#define Bndry_mask  0xfffff\n#define Bndry_mask1 0xfffff\n#define LSB 1\n#define Sign_bit 0x80000000\n#define Log2P 1\n#define Tiny0 0\n#define Tiny1 1\n#define Quick_max 14\n#define Int_max 14\n#ifndef NO_IEEE_Scale\n#define Avoid_Underflow\n#ifdef Flush_Denorm\t/* debugging option */\n#undef Sudden_Underflow\n#endif\n#endif\n\n#ifndef Flt_Rounds\n#ifdef FLT_ROUNDS\n#define Flt_Rounds FLT_ROUNDS\n#else\n#define Flt_Rounds 1\n#endif\n#endif /*Flt_Rounds*/\n\n#ifdef Honor_FLT_ROUNDS\n#undef Check_FLT_ROUNDS\n#define Check_FLT_ROUNDS\n#else\n#define Rounding Flt_Rounds\n#endif\n\n#else /* ifndef IEEE_Arith */\n#undef Check_FLT_ROUNDS\n#undef Honor_FLT_ROUNDS\n#undef SET_INEXACT\n#undef  Sudden_Underflow\n#define Sudden_Underflow\n#ifdef IBM\n#undef Flt_Rounds\n#define Flt_Rounds 0\n#define Exp_shift  24\n#define Exp_shift1 24\n#define Exp_msk1   0x1000000\n#define Exp_msk11  0x1000000\n#define Exp_mask  0x7f000000\n#define P 14\n#define Nbits 56\n#define Bias 65\n#define Emax 248\n#define Emin (-260)\n#define Exp_1  0x41000000\n#define Exp_11 0x41000000\n#define Ebits 8\t/* exponent has 7 bits, but 8 is the right value in b2d */\n#define Frac_mask  0xffffff\n#define Frac_mask1 0xffffff\n#define Bletch 4\n#define Ten_pmax 22\n#define Bndry_mask  0xefffff\n#define Bndry_mask1 0xffffff\n#define LSB 1\n#define Sign_bit 0x80000000\n#define Log2P 4\n#define Tiny0 0x100000\n#define Tiny1 0\n#define Quick_max 14\n#define Int_max 15\n#else /* VAX */\n#undef Flt_Rounds\n#define Flt_Rounds 1\n#define Exp_shift  23\n#define Exp_shift1 7\n#define Exp_msk1    0x80\n#define Exp_msk11   0x800000\n#define Exp_mask  0x7f80\n#define P 56\n#define Nbits 56\n#define Bias 129\n#define Emax 126\n#define Emin (-129)\n#define Exp_1  0x40800000\n#define Exp_11 0x4080\n#define Ebits 8\n#define Frac_mask  0x7fffff\n#define Frac_mask1 0xffff007f\n#define Ten_pmax 24\n#define Bletch 2\n#define Bndry_mask  0xffff007f\n#define Bndry_mask1 0xffff007f\n#define LSB 0x10000\n#define Sign_bit 0x8000\n#define Log2P 1\n#define Tiny0 0x80\n#define Tiny1 0\n#define Quick_max 15\n#define Int_max 15\n#endif /* IBM, VAX */\n#endif /* IEEE_Arith */\n\n#ifndef IEEE_Arith\n#define ROUND_BIASED\n#else\n#ifdef ROUND_BIASED_without_Round_Up\n#undef  ROUND_BIASED\n#define ROUND_BIASED\n#endif\n#endif\n\n#ifdef RND_PRODQUOT\n#define rounded_product(a,b) a = rnd_prod(a, b)\n#define rounded_quotient(a,b) a = rnd_quot(a, b)\n#ifdef KR_headers\nextern double rnd_prod(), rnd_quot();\n#else\nextern double rnd_prod(double, double), rnd_quot(double, double);\n#endif\n#else\n#define rounded_product(a,b) a *= b\n#define rounded_quotient(a,b) a /= b\n#endif\n\n#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))\n#define Big1 0xffffffff\n\n#ifndef Pack_32\n#define Pack_32\n#endif\n\ntypedef struct BCinfo BCinfo;\n struct\nBCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; };\n\n#ifdef KR_headers\n#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)\n#else\n#define FFFFFFFF 0xffffffffUL\n#endif\n\n#ifdef NO_LONG_LONG\n#undef ULLong\n#ifdef Just_16\n#undef Pack_32\n/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.\n * This makes some inner loops simpler and sometimes saves work\n * during multiplications, but it often seems to make things slightly\n * slower.  Hence the default is now to store 32 bits per Long.\n */\n#endif\n#else\t/* long long available */\n#ifndef Llong\n#define Llong long long\n#endif\n#ifndef ULLong\n#define ULLong unsigned Llong\n#endif\n#endif /* NO_LONG_LONG */\n\n#ifndef MULTIPLE_THREADS\n#define ACQUIRE_DTOA_LOCK(n)\t/*nothing*/\n#define FREE_DTOA_LOCK(n)\t/*nothing*/\n#endif\n\n#define Kmax 7\n\n#ifdef __cplusplus\nextern \"C\" double fpconv_strtod(const char *s00, char **se);\nextern \"C\" char *dtoa(double d, int mode, int ndigits,\n\t\t\tint *decpt, int *sign, char **rve);\n#endif\n\n struct\nBigint {\n\tstruct Bigint *next;\n\tint k, maxwds, sign, wds;\n\tULong x[1];\n\t};\n\n typedef struct Bigint Bigint;\n\n static Bigint *freelist[Kmax+1];\n\n static Bigint *\nBalloc\n#ifdef KR_headers\n\t(k) int k;\n#else\n\t(int k)\n#endif\n{\n\tint x;\n\tBigint *rv;\n#ifndef Omit_Private_Memory\n\tunsigned int len;\n#endif\n\n\tACQUIRE_DTOA_LOCK(0);\n\t/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */\n\t/* but this case seems very unlikely. */\n\tif (k <= Kmax && (rv = freelist[k]))\n\t\tfreelist[k] = rv->next;\n\telse {\n\t\tx = 1 << k;\n#ifdef Omit_Private_Memory\n\t\trv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));\n#else\n\t\tlen = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)\n\t\t\t/sizeof(double);\n\t\tif (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {\n\t\t\trv = (Bigint*)pmem_next;\n\t\t\tpmem_next += len;\n\t\t\t}\n\t\telse\n\t\t\trv = (Bigint*)MALLOC(len*sizeof(double));\n#endif\n\t\trv->k = k;\n\t\trv->maxwds = x;\n\t\t}\n\tFREE_DTOA_LOCK(0);\n\trv->sign = rv->wds = 0;\n\treturn rv;\n\t}\n\n static void\nBfree\n#ifdef KR_headers\n\t(v) Bigint *v;\n#else\n\t(Bigint *v)\n#endif\n{\n\tif (v) {\n\t\tif (v->k > Kmax)\n#ifdef FREE\n\t\t\tFREE((void*)v);\n#else\n\t\t\tfree((void*)v);\n#endif\n\t\telse {\n\t\t\tACQUIRE_DTOA_LOCK(0);\n\t\t\tv->next = freelist[v->k];\n\t\t\tfreelist[v->k] = v;\n\t\t\tFREE_DTOA_LOCK(0);\n\t\t\t}\n\t\t}\n\t}\n\n#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \\\ny->wds*sizeof(Long) + 2*sizeof(int))\n\n static Bigint *\nmultadd\n#ifdef KR_headers\n\t(b, m, a) Bigint *b; int m, a;\n#else\n\t(Bigint *b, int m, int a)\t/* multiply by m and add a */\n#endif\n{\n\tint i, wds;\n#ifdef ULLong\n\tULong *x;\n\tULLong carry, y;\n#else\n\tULong carry, *x, y;\n#ifdef Pack_32\n\tULong xi, z;\n#endif\n#endif\n\tBigint *b1;\n\n\twds = b->wds;\n\tx = b->x;\n\ti = 0;\n\tcarry = a;\n\tdo {\n#ifdef ULLong\n\t\ty = *x * (ULLong)m + carry;\n\t\tcarry = y >> 32;\n\t\t*x++ = y & FFFFFFFF;\n#else\n#ifdef Pack_32\n\t\txi = *x;\n\t\ty = (xi & 0xffff) * m + carry;\n\t\tz = (xi >> 16) * m + (y >> 16);\n\t\tcarry = z >> 16;\n\t\t*x++ = (z << 16) + (y & 0xffff);\n#else\n\t\ty = *x * m + carry;\n\t\tcarry = y >> 16;\n\t\t*x++ = y & 0xffff;\n#endif\n#endif\n\t\t}\n\t\twhile(++i < wds);\n\tif (carry) {\n\t\tif (wds >= b->maxwds) {\n\t\t\tb1 = Balloc(b->k+1);\n\t\t\tBcopy(b1, b);\n\t\t\tBfree(b);\n\t\t\tb = b1;\n\t\t\t}\n\t\tb->x[wds++] = carry;\n\t\tb->wds = wds;\n\t\t}\n\treturn b;\n\t}\n\n static Bigint *\ns2b\n#ifdef KR_headers\n\t(s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9;\n#else\n\t(const char *s, int nd0, int nd, ULong y9, int dplen)\n#endif\n{\n\tBigint *b;\n\tint i, k;\n\tLong x, y;\n\n\tx = (nd + 8) / 9;\n\tfor(k = 0, y = 1; x > y; y <<= 1, k++) ;\n#ifdef Pack_32\n\tb = Balloc(k);\n\tb->x[0] = y9;\n\tb->wds = 1;\n#else\n\tb = Balloc(k+1);\n\tb->x[0] = y9 & 0xffff;\n\tb->wds = (b->x[1] = y9 >> 16) ? 2 : 1;\n#endif\n\n\ti = 9;\n\tif (9 < nd0) {\n\t\ts += 9;\n\t\tdo b = multadd(b, 10, *s++ - '0');\n\t\t\twhile(++i < nd0);\n\t\ts += dplen;\n\t\t}\n\telse\n\t\ts += dplen + 9;\n\tfor(; i < nd; i++)\n\t\tb = multadd(b, 10, *s++ - '0');\n\treturn b;\n\t}\n\n static int\nhi0bits\n#ifdef KR_headers\n\t(x) ULong x;\n#else\n\t(ULong x)\n#endif\n{\n\tint k = 0;\n\n\tif (!(x & 0xffff0000)) {\n\t\tk = 16;\n\t\tx <<= 16;\n\t\t}\n\tif (!(x & 0xff000000)) {\n\t\tk += 8;\n\t\tx <<= 8;\n\t\t}\n\tif (!(x & 0xf0000000)) {\n\t\tk += 4;\n\t\tx <<= 4;\n\t\t}\n\tif (!(x & 0xc0000000)) {\n\t\tk += 2;\n\t\tx <<= 2;\n\t\t}\n\tif (!(x & 0x80000000)) {\n\t\tk++;\n\t\tif (!(x & 0x40000000))\n\t\t\treturn 32;\n\t\t}\n\treturn k;\n\t}\n\n static int\nlo0bits\n#ifdef KR_headers\n\t(y) ULong *y;\n#else\n\t(ULong *y)\n#endif\n{\n\tint k;\n\tULong x = *y;\n\n\tif (x & 7) {\n\t\tif (x & 1)\n\t\t\treturn 0;\n\t\tif (x & 2) {\n\t\t\t*y = x >> 1;\n\t\t\treturn 1;\n\t\t\t}\n\t\t*y = x >> 2;\n\t\treturn 2;\n\t\t}\n\tk = 0;\n\tif (!(x & 0xffff)) {\n\t\tk = 16;\n\t\tx >>= 16;\n\t\t}\n\tif (!(x & 0xff)) {\n\t\tk += 8;\n\t\tx >>= 8;\n\t\t}\n\tif (!(x & 0xf)) {\n\t\tk += 4;\n\t\tx >>= 4;\n\t\t}\n\tif (!(x & 0x3)) {\n\t\tk += 2;\n\t\tx >>= 2;\n\t\t}\n\tif (!(x & 1)) {\n\t\tk++;\n\t\tx >>= 1;\n\t\tif (!x)\n\t\t\treturn 32;\n\t\t}\n\t*y = x;\n\treturn k;\n\t}\n\n static Bigint *\ni2b\n#ifdef KR_headers\n\t(i) int i;\n#else\n\t(int i)\n#endif\n{\n\tBigint *b;\n\n\tb = Balloc(1);\n\tb->x[0] = i;\n\tb->wds = 1;\n\treturn b;\n\t}\n\n static Bigint *\nmult\n#ifdef KR_headers\n\t(a, b) Bigint *a, *b;\n#else\n\t(Bigint *a, Bigint *b)\n#endif\n{\n\tBigint *c;\n\tint k, wa, wb, wc;\n\tULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;\n\tULong y;\n#ifdef ULLong\n\tULLong carry, z;\n#else\n\tULong carry, z;\n#ifdef Pack_32\n\tULong z2;\n#endif\n#endif\n\n\tif (a->wds < b->wds) {\n\t\tc = a;\n\t\ta = b;\n\t\tb = c;\n\t\t}\n\tk = a->k;\n\twa = a->wds;\n\twb = b->wds;\n\twc = wa + wb;\n\tif (wc > a->maxwds)\n\t\tk++;\n\tc = Balloc(k);\n\tfor(x = c->x, xa = x + wc; x < xa; x++)\n\t\t*x = 0;\n\txa = a->x;\n\txae = xa + wa;\n\txb = b->x;\n\txbe = xb + wb;\n\txc0 = c->x;\n#ifdef ULLong\n\tfor(; xb < xbe; xc0++) {\n\t\tif ((y = *xb++)) {\n\t\t\tx = xa;\n\t\t\txc = xc0;\n\t\t\tcarry = 0;\n\t\t\tdo {\n\t\t\t\tz = *x++ * (ULLong)y + *xc + carry;\n\t\t\t\tcarry = z >> 32;\n\t\t\t\t*xc++ = z & FFFFFFFF;\n\t\t\t\t}\n\t\t\t\twhile(x < xae);\n\t\t\t*xc = carry;\n\t\t\t}\n\t\t}\n#else\n#ifdef Pack_32\n\tfor(; xb < xbe; xb++, xc0++) {\n\t\tif (y = *xb & 0xffff) {\n\t\t\tx = xa;\n\t\t\txc = xc0;\n\t\t\tcarry = 0;\n\t\t\tdo {\n\t\t\t\tz = (*x & 0xffff) * y + (*xc & 0xffff) + carry;\n\t\t\t\tcarry = z >> 16;\n\t\t\t\tz2 = (*x++ >> 16) * y + (*xc >> 16) + carry;\n\t\t\t\tcarry = z2 >> 16;\n\t\t\t\tStoreinc(xc, z2, z);\n\t\t\t\t}\n\t\t\t\twhile(x < xae);\n\t\t\t*xc = carry;\n\t\t\t}\n\t\tif (y = *xb >> 16) {\n\t\t\tx = xa;\n\t\t\txc = xc0;\n\t\t\tcarry = 0;\n\t\t\tz2 = *xc;\n\t\t\tdo {\n\t\t\t\tz = (*x & 0xffff) * y + (*xc >> 16) + carry;\n\t\t\t\tcarry = z >> 16;\n\t\t\t\tStoreinc(xc, z, z2);\n\t\t\t\tz2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;\n\t\t\t\tcarry = z2 >> 16;\n\t\t\t\t}\n\t\t\t\twhile(x < xae);\n\t\t\t*xc = z2;\n\t\t\t}\n\t\t}\n#else\n\tfor(; xb < xbe; xc0++) {\n\t\tif (y = *xb++) {\n\t\t\tx = xa;\n\t\t\txc = xc0;\n\t\t\tcarry = 0;\n\t\t\tdo {\n\t\t\t\tz = *x++ * y + *xc + carry;\n\t\t\t\tcarry = z >> 16;\n\t\t\t\t*xc++ = z & 0xffff;\n\t\t\t\t}\n\t\t\t\twhile(x < xae);\n\t\t\t*xc = carry;\n\t\t\t}\n\t\t}\n#endif\n#endif\n\tfor(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;\n\tc->wds = wc;\n\treturn c;\n\t}\n\n static Bigint *p5s;\n\n static Bigint *\npow5mult\n#ifdef KR_headers\n\t(b, k) Bigint *b; int k;\n#else\n\t(Bigint *b, int k)\n#endif\n{\n\tBigint *b1, *p5, *p51;\n\tint i;\n\tstatic int p05[3] = { 5, 25, 125 };\n\n\tif ((i = k & 3))\n\t\tb = multadd(b, p05[i-1], 0);\n\n\tif (!(k >>= 2))\n\t\treturn b;\n\tif (!(p5 = p5s)) {\n\t\t/* first time */\n#ifdef MULTIPLE_THREADS\n\t\tACQUIRE_DTOA_LOCK(1);\n\t\tif (!(p5 = p5s)) {\n\t\t\tp5 = p5s = i2b(625);\n\t\t\tp5->next = 0;\n\t\t\t}\n\t\tFREE_DTOA_LOCK(1);\n#else\n\t\tp5 = p5s = i2b(625);\n\t\tp5->next = 0;\n#endif\n\t\t}\n\tfor(;;) {\n\t\tif (k & 1) {\n\t\t\tb1 = mult(b, p5);\n\t\t\tBfree(b);\n\t\t\tb = b1;\n\t\t\t}\n\t\tif (!(k >>= 1))\n\t\t\tbreak;\n\t\tif (!(p51 = p5->next)) {\n#ifdef MULTIPLE_THREADS\n\t\t\tACQUIRE_DTOA_LOCK(1);\n\t\t\tif (!(p51 = p5->next)) {\n\t\t\t\tp51 = p5->next = mult(p5,p5);\n\t\t\t\tp51->next = 0;\n\t\t\t\t}\n\t\t\tFREE_DTOA_LOCK(1);\n#else\n\t\t\tp51 = p5->next = mult(p5,p5);\n\t\t\tp51->next = 0;\n#endif\n\t\t\t}\n\t\tp5 = p51;\n\t\t}\n\treturn b;\n\t}\n\n static Bigint *\nlshift\n#ifdef KR_headers\n\t(b, k) Bigint *b; int k;\n#else\n\t(Bigint *b, int k)\n#endif\n{\n\tint i, k1, n, n1;\n\tBigint *b1;\n\tULong *x, *x1, *xe, z;\n\n#ifdef Pack_32\n\tn = k >> 5;\n#else\n\tn = k >> 4;\n#endif\n\tk1 = b->k;\n\tn1 = n + b->wds + 1;\n\tfor(i = b->maxwds; n1 > i; i <<= 1)\n\t\tk1++;\n\tb1 = Balloc(k1);\n\tx1 = b1->x;\n\tfor(i = 0; i < n; i++)\n\t\t*x1++ = 0;\n\tx = b->x;\n\txe = x + b->wds;\n#ifdef Pack_32\n\tif (k &= 0x1f) {\n\t\tk1 = 32 - k;\n\t\tz = 0;\n\t\tdo {\n\t\t\t*x1++ = *x << k | z;\n\t\t\tz = *x++ >> k1;\n\t\t\t}\n\t\t\twhile(x < xe);\n\t\tif ((*x1 = z))\n\t\t\t++n1;\n\t\t}\n#else\n\tif (k &= 0xf) {\n\t\tk1 = 16 - k;\n\t\tz = 0;\n\t\tdo {\n\t\t\t*x1++ = *x << k  & 0xffff | z;\n\t\t\tz = *x++ >> k1;\n\t\t\t}\n\t\t\twhile(x < xe);\n\t\tif (*x1 = z)\n\t\t\t++n1;\n\t\t}\n#endif\n\telse do\n\t\t*x1++ = *x++;\n\t\twhile(x < xe);\n\tb1->wds = n1 - 1;\n\tBfree(b);\n\treturn b1;\n\t}\n\n static int\ncmp\n#ifdef KR_headers\n\t(a, b) Bigint *a, *b;\n#else\n\t(Bigint *a, Bigint *b)\n#endif\n{\n\tULong *xa, *xa0, *xb, *xb0;\n\tint i, j;\n\n\ti = a->wds;\n\tj = b->wds;\n#ifdef DEBUG\n\tif (i > 1 && !a->x[i-1])\n\t\tBug(\"cmp called with a->x[a->wds-1] == 0\");\n\tif (j > 1 && !b->x[j-1])\n\t\tBug(\"cmp called with b->x[b->wds-1] == 0\");\n#endif\n\tif (i -= j)\n\t\treturn i;\n\txa0 = a->x;\n\txa = xa0 + j;\n\txb0 = b->x;\n\txb = xb0 + j;\n\tfor(;;) {\n\t\tif (*--xa != *--xb)\n\t\t\treturn *xa < *xb ? -1 : 1;\n\t\tif (xa <= xa0)\n\t\t\tbreak;\n\t\t}\n\treturn 0;\n\t}\n\n static Bigint *\ndiff\n#ifdef KR_headers\n\t(a, b) Bigint *a, *b;\n#else\n\t(Bigint *a, Bigint *b)\n#endif\n{\n\tBigint *c;\n\tint i, wa, wb;\n\tULong *xa, *xae, *xb, *xbe, *xc;\n#ifdef ULLong\n\tULLong borrow, y;\n#else\n\tULong borrow, y;\n#ifdef Pack_32\n\tULong z;\n#endif\n#endif\n\n\ti = cmp(a,b);\n\tif (!i) {\n\t\tc = Balloc(0);\n\t\tc->wds = 1;\n\t\tc->x[0] = 0;\n\t\treturn c;\n\t\t}\n\tif (i < 0) {\n\t\tc = a;\n\t\ta = b;\n\t\tb = c;\n\t\ti = 1;\n\t\t}\n\telse\n\t\ti = 0;\n\tc = Balloc(a->k);\n\tc->sign = i;\n\twa = a->wds;\n\txa = a->x;\n\txae = xa + wa;\n\twb = b->wds;\n\txb = b->x;\n\txbe = xb + wb;\n\txc = c->x;\n\tborrow = 0;\n#ifdef ULLong\n\tdo {\n\t\ty = (ULLong)*xa++ - *xb++ - borrow;\n\t\tborrow = y >> 32 & (ULong)1;\n\t\t*xc++ = y & FFFFFFFF;\n\t\t}\n\t\twhile(xb < xbe);\n\twhile(xa < xae) {\n\t\ty = *xa++ - borrow;\n\t\tborrow = y >> 32 & (ULong)1;\n\t\t*xc++ = y & FFFFFFFF;\n\t\t}\n#else\n#ifdef Pack_32\n\tdo {\n\t\ty = (*xa & 0xffff) - (*xb & 0xffff) - borrow;\n\t\tborrow = (y & 0x10000) >> 16;\n\t\tz = (*xa++ >> 16) - (*xb++ >> 16) - borrow;\n\t\tborrow = (z & 0x10000) >> 16;\n\t\tStoreinc(xc, z, y);\n\t\t}\n\t\twhile(xb < xbe);\n\twhile(xa < xae) {\n\t\ty = (*xa & 0xffff) - borrow;\n\t\tborrow = (y & 0x10000) >> 16;\n\t\tz = (*xa++ >> 16) - borrow;\n\t\tborrow = (z & 0x10000) >> 16;\n\t\tStoreinc(xc, z, y);\n\t\t}\n#else\n\tdo {\n\t\ty = *xa++ - *xb++ - borrow;\n\t\tborrow = (y & 0x10000) >> 16;\n\t\t*xc++ = y & 0xffff;\n\t\t}\n\t\twhile(xb < xbe);\n\twhile(xa < xae) {\n\t\ty = *xa++ - borrow;\n\t\tborrow = (y & 0x10000) >> 16;\n\t\t*xc++ = y & 0xffff;\n\t\t}\n#endif\n#endif\n\twhile(!*--xc)\n\t\twa--;\n\tc->wds = wa;\n\treturn c;\n\t}\n\n static double\nulp\n#ifdef KR_headers\n\t(x) U *x;\n#else\n\t(U *x)\n#endif\n{\n\tLong L;\n\tU u;\n\n\tL = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;\n#ifndef Avoid_Underflow\n#ifndef Sudden_Underflow\n\tif (L > 0) {\n#endif\n#endif\n#ifdef IBM\n\t\tL |= Exp_msk1 >> 4;\n#endif\n\t\tword0(&u) = L;\n\t\tword1(&u) = 0;\n#ifndef Avoid_Underflow\n#ifndef Sudden_Underflow\n\t\t}\n\telse {\n\t\tL = -L >> Exp_shift;\n\t\tif (L < Exp_shift) {\n\t\t\tword0(&u) = 0x80000 >> L;\n\t\t\tword1(&u) = 0;\n\t\t\t}\n\t\telse {\n\t\t\tword0(&u) = 0;\n\t\t\tL -= Exp_shift;\n\t\t\tword1(&u) = L >= 31 ? 1 : 1 << 31 - L;\n\t\t\t}\n\t\t}\n#endif\n#endif\n\treturn dval(&u);\n\t}\n\n static double\nb2d\n#ifdef KR_headers\n\t(a, e) Bigint *a; int *e;\n#else\n\t(Bigint *a, int *e)\n#endif\n{\n\tULong *xa, *xa0, w, y, z;\n\tint k;\n\tU d;\n#ifdef VAX\n\tULong d0, d1;\n#else\n#define d0 word0(&d)\n#define d1 word1(&d)\n#endif\n\n\txa0 = a->x;\n\txa = xa0 + a->wds;\n\ty = *--xa;\n#ifdef DEBUG\n\tif (!y) Bug(\"zero y in b2d\");\n#endif\n\tk = hi0bits(y);\n\t*e = 32 - k;\n#ifdef Pack_32\n\tif (k < Ebits) {\n\t\td0 = Exp_1 | y >> (Ebits - k);\n\t\tw = xa > xa0 ? *--xa : 0;\n\t\td1 = y << ((32-Ebits) + k) | w >> (Ebits - k);\n\t\tgoto ret_d;\n\t\t}\n\tz = xa > xa0 ? *--xa : 0;\n\tif (k -= Ebits) {\n\t\td0 = Exp_1 | y << k | z >> (32 - k);\n\t\ty = xa > xa0 ? *--xa : 0;\n\t\td1 = z << k | y >> (32 - k);\n\t\t}\n\telse {\n\t\td0 = Exp_1 | y;\n\t\td1 = z;\n\t\t}\n#else\n\tif (k < Ebits + 16) {\n\t\tz = xa > xa0 ? *--xa : 0;\n\t\td0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;\n\t\tw = xa > xa0 ? *--xa : 0;\n\t\ty = xa > xa0 ? *--xa : 0;\n\t\td1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;\n\t\tgoto ret_d;\n\t\t}\n\tz = xa > xa0 ? *--xa : 0;\n\tw = xa > xa0 ? *--xa : 0;\n\tk -= Ebits + 16;\n\td0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;\n\ty = xa > xa0 ? *--xa : 0;\n\td1 = w << k + 16 | y << k;\n#endif\n ret_d:\n#ifdef VAX\n\tword0(&d) = d0 >> 16 | d0 << 16;\n\tword1(&d) = d1 >> 16 | d1 << 16;\n#else\n#undef d0\n#undef d1\n#endif\n\treturn dval(&d);\n\t}\n\n static Bigint *\nd2b\n#ifdef KR_headers\n\t(d, e, bits) U *d; int *e, *bits;\n#else\n\t(U *d, int *e, int *bits)\n#endif\n{\n\tBigint *b;\n\tint de, k;\n\tULong *x, y, z;\n#ifndef Sudden_Underflow\n\tint i;\n#endif\n#ifdef VAX\n\tULong d0, d1;\n\td0 = word0(d) >> 16 | word0(d) << 16;\n\td1 = word1(d) >> 16 | word1(d) << 16;\n#else\n#define d0 word0(d)\n#define d1 word1(d)\n#endif\n\n#ifdef Pack_32\n\tb = Balloc(1);\n#else\n\tb = Balloc(2);\n#endif\n\tx = b->x;\n\n\tz = d0 & Frac_mask;\n\td0 &= 0x7fffffff;\t/* clear sign bit, which we ignore */\n#ifdef Sudden_Underflow\n\tde = (int)(d0 >> Exp_shift);\n#ifndef IBM\n\tz |= Exp_msk11;\n#endif\n#else\n\tif ((de = (int)(d0 >> Exp_shift)))\n\t\tz |= Exp_msk1;\n#endif\n#ifdef Pack_32\n\tif ((y = d1)) {\n\t\tif ((k = lo0bits(&y))) {\n\t\t\tx[0] = y | z << (32 - k);\n\t\t\tz >>= k;\n\t\t\t}\n\t\telse\n\t\t\tx[0] = y;\n#ifndef Sudden_Underflow\n\t\ti =\n#endif\n\t\t    b->wds = (x[1] = z) ? 2 : 1;\n\t\t}\n\telse {\n\t\tk = lo0bits(&z);\n\t\tx[0] = z;\n#ifndef Sudden_Underflow\n\t\ti =\n#endif\n\t\t    b->wds = 1;\n\t\tk += 32;\n\t\t}\n#else\n\tif (y = d1) {\n\t\tif (k = lo0bits(&y))\n\t\t\tif (k >= 16) {\n\t\t\t\tx[0] = y | z << 32 - k & 0xffff;\n\t\t\t\tx[1] = z >> k - 16 & 0xffff;\n\t\t\t\tx[2] = z >> k;\n\t\t\t\ti = 2;\n\t\t\t\t}\n\t\t\telse {\n\t\t\t\tx[0] = y & 0xffff;\n\t\t\t\tx[1] = y >> 16 | z << 16 - k & 0xffff;\n\t\t\t\tx[2] = z >> k & 0xffff;\n\t\t\t\tx[3] = z >> k+16;\n\t\t\t\ti = 3;\n\t\t\t\t}\n\t\telse {\n\t\t\tx[0] = y & 0xffff;\n\t\t\tx[1] = y >> 16;\n\t\t\tx[2] = z & 0xffff;\n\t\t\tx[3] = z >> 16;\n\t\t\ti = 3;\n\t\t\t}\n\t\t}\n\telse {\n#ifdef DEBUG\n\t\tif (!z)\n\t\t\tBug(\"Zero passed to d2b\");\n#endif\n\t\tk = lo0bits(&z);\n\t\tif (k >= 16) {\n\t\t\tx[0] = z;\n\t\t\ti = 0;\n\t\t\t}\n\t\telse {\n\t\t\tx[0] = z & 0xffff;\n\t\t\tx[1] = z >> 16;\n\t\t\ti = 1;\n\t\t\t}\n\t\tk += 32;\n\t\t}\n\twhile(!x[i])\n\t\t--i;\n\tb->wds = i + 1;\n#endif\n#ifndef Sudden_Underflow\n\tif (de) {\n#endif\n#ifdef IBM\n\t\t*e = (de - Bias - (P-1) << 2) + k;\n\t\t*bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);\n#else\n\t\t*e = de - Bias - (P-1) + k;\n\t\t*bits = P - k;\n#endif\n#ifndef Sudden_Underflow\n\t\t}\n\telse {\n\t\t*e = de - Bias - (P-1) + 1 + k;\n#ifdef Pack_32\n\t\t*bits = 32*i - hi0bits(x[i-1]);\n#else\n\t\t*bits = (i+2)*16 - hi0bits(x[i]);\n#endif\n\t\t}\n#endif\n\treturn b;\n\t}\n#undef d0\n#undef d1\n\n static double\nratio\n#ifdef KR_headers\n\t(a, b) Bigint *a, *b;\n#else\n\t(Bigint *a, Bigint *b)\n#endif\n{\n\tU da, db;\n\tint k, ka, kb;\n\n\tdval(&da) = b2d(a, &ka);\n\tdval(&db) = b2d(b, &kb);\n#ifdef Pack_32\n\tk = ka - kb + 32*(a->wds - b->wds);\n#else\n\tk = ka - kb + 16*(a->wds - b->wds);\n#endif\n#ifdef IBM\n\tif (k > 0) {\n\t\tword0(&da) += (k >> 2)*Exp_msk1;\n\t\tif (k &= 3)\n\t\t\tdval(&da) *= 1 << k;\n\t\t}\n\telse {\n\t\tk = -k;\n\t\tword0(&db) += (k >> 2)*Exp_msk1;\n\t\tif (k &= 3)\n\t\t\tdval(&db) *= 1 << k;\n\t\t}\n#else\n\tif (k > 0)\n\t\tword0(&da) += k*Exp_msk1;\n\telse {\n\t\tk = -k;\n\t\tword0(&db) += k*Exp_msk1;\n\t\t}\n#endif\n\treturn dval(&da) / dval(&db);\n\t}\n\n static CONST double\ntens[] = {\n\t\t1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,\n\t\t1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,\n\t\t1e20, 1e21, 1e22\n#ifdef VAX\n\t\t, 1e23, 1e24\n#endif\n\t\t};\n\n static CONST double\n#ifdef IEEE_Arith\nbigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };\nstatic CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,\n#ifdef Avoid_Underflow\n\t\t9007199254740992.*9007199254740992.e-256\n\t\t/* = 2^106 * 1e-256 */\n#else\n\t\t1e-256\n#endif\n\t\t};\n/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */\n/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */\n#define Scale_Bit 0x10\n#define n_bigtens 5\n#else\n#ifdef IBM\nbigtens[] = { 1e16, 1e32, 1e64 };\nstatic CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };\n#define n_bigtens 3\n#else\nbigtens[] = { 1e16, 1e32 };\nstatic CONST double tinytens[] = { 1e-16, 1e-32 };\n#define n_bigtens 2\n#endif\n#endif\n\n#undef Need_Hexdig\n#ifdef INFNAN_CHECK\n#ifndef No_Hex_NaN\n#define Need_Hexdig\n#endif\n#endif\n\n#ifndef Need_Hexdig\n#ifndef NO_HEX_FP\n#define Need_Hexdig\n#endif\n#endif\n\n#ifdef Need_Hexdig /*{*/\nstatic unsigned char hexdig[256];\n\n static void\n#ifdef KR_headers\nhtinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;\n#else\nhtinit(unsigned char *h, unsigned char *s, int inc)\n#endif\n{\n\tint i, j;\n\tfor(i = 0; (j = s[i]) !=0; i++)\n\t\th[j] = i + inc;\n\t}\n\n static void\n#ifdef KR_headers\nhexdig_init()\n#else\nhexdig_init(void)\n#endif\n{\n#define USC (unsigned char *)\n\thtinit(hexdig, USC \"0123456789\", 0x10);\n\thtinit(hexdig, USC \"abcdef\", 0x10 + 10);\n\thtinit(hexdig, USC \"ABCDEF\", 0x10 + 10);\n\t}\n#endif /* } Need_Hexdig */\n\n#ifdef INFNAN_CHECK\n\n#ifndef NAN_WORD0\n#define NAN_WORD0 0x7ff80000\n#endif\n\n#ifndef NAN_WORD1\n#define NAN_WORD1 0\n#endif\n\n static int\nmatch\n#ifdef KR_headers\n\t(sp, t) char **sp, *t;\n#else\n\t(const char **sp, const char *t)\n#endif\n{\n\tint c, d;\n\tCONST char *s = *sp;\n\n\twhile((d = *t++)) {\n\t\tif ((c = *++s) >= 'A' && c <= 'Z')\n\t\t\tc += 'a' - 'A';\n\t\tif (c != d)\n\t\t\treturn 0;\n\t\t}\n\t*sp = s + 1;\n\treturn 1;\n\t}\n\n#ifndef No_Hex_NaN\n static void\nhexnan\n#ifdef KR_headers\n\t(rvp, sp) U *rvp; CONST char **sp;\n#else\n\t(U *rvp, const char **sp)\n#endif\n{\n\tULong c, x[2];\n\tCONST char *s;\n\tint c1, havedig, udx0, xshift;\n\n\tif (!hexdig['0'])\n\t\thexdig_init();\n\tx[0] = x[1] = 0;\n\thavedig = xshift = 0;\n\tudx0 = 1;\n\ts = *sp;\n\t/* allow optional initial 0x or 0X */\n\twhile((c = *(CONST unsigned char*)(s+1)) && c <= ' ')\n\t\t++s;\n\tif (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))\n\t\ts += 2;\n\twhile((c = *(CONST unsigned char*)++s)) {\n\t\tif ((c1 = hexdig[c]))\n\t\t\tc  = c1 & 0xf;\n\t\telse if (c <= ' ') {\n\t\t\tif (udx0 && havedig) {\n\t\t\t\tudx0 = 0;\n\t\t\t\txshift = 1;\n\t\t\t\t}\n\t\t\tcontinue;\n\t\t\t}\n#ifdef GDTOA_NON_PEDANTIC_NANCHECK\n\t\telse if (/*(*/ c == ')' && havedig) {\n\t\t\t*sp = s + 1;\n\t\t\tbreak;\n\t\t\t}\n\t\telse\n\t\t\treturn;\t/* invalid form: don't change *sp */\n#else\n\t\telse {\n\t\t\tdo {\n\t\t\t\tif (/*(*/ c == ')') {\n\t\t\t\t\t*sp = s + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} while((c = *++s));\n\t\t\tbreak;\n\t\t\t}\n#endif\n\t\thavedig = 1;\n\t\tif (xshift) {\n\t\t\txshift = 0;\n\t\t\tx[0] = x[1];\n\t\t\tx[1] = 0;\n\t\t\t}\n\t\tif (udx0)\n\t\t\tx[0] = (x[0] << 4) | (x[1] >> 28);\n\t\tx[1] = (x[1] << 4) | c;\n\t\t}\n\tif ((x[0] &= 0xfffff) || x[1]) {\n\t\tword0(rvp) = Exp_mask | x[0];\n\t\tword1(rvp) = x[1];\n\t\t}\n\t}\n#endif /*No_Hex_NaN*/\n#endif /* INFNAN_CHECK */\n\n#ifdef Pack_32\n#define ULbits 32\n#define kshift 5\n#define kmask 31\n#else\n#define ULbits 16\n#define kshift 4\n#define kmask 15\n#endif\n\n#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/\n static Bigint *\n#ifdef KR_headers\nincrement(b) Bigint *b;\n#else\nincrement(Bigint *b)\n#endif\n{\n\tULong *x, *xe;\n\tBigint *b1;\n\n\tx = b->x;\n\txe = x + b->wds;\n\tdo {\n\t\tif (*x < (ULong)0xffffffffL) {\n\t\t\t++*x;\n\t\t\treturn b;\n\t\t\t}\n\t\t*x++ = 0;\n\t\t} while(x < xe);\n\t{\n\t\tif (b->wds >= b->maxwds) {\n\t\t\tb1 = Balloc(b->k+1);\n\t\t\tBcopy(b1,b);\n\t\t\tBfree(b);\n\t\t\tb = b1;\n\t\t\t}\n\t\tb->x[b->wds++] = 1;\n\t\t}\n\treturn b;\n\t}\n\n#endif /*}*/\n\n#ifndef NO_HEX_FP /*{*/\n\n static void\n#ifdef KR_headers\nrshift(b, k) Bigint *b; int k;\n#else\nrshift(Bigint *b, int k)\n#endif\n{\n\tULong *x, *x1, *xe, y;\n\tint n;\n\n\tx = x1 = b->x;\n\tn = k >> kshift;\n\tif (n < b->wds) {\n\t\txe = x + b->wds;\n\t\tx += n;\n\t\tif (k &= kmask) {\n\t\t\tn = 32 - k;\n\t\t\ty = *x++ >> k;\n\t\t\twhile(x < xe) {\n\t\t\t\t*x1++ = (y | (*x << n)) & 0xffffffff;\n\t\t\t\ty = *x++ >> k;\n\t\t\t\t}\n\t\t\tif ((*x1 = y) !=0)\n\t\t\t\tx1++;\n\t\t\t}\n\t\telse\n\t\t\twhile(x < xe)\n\t\t\t\t*x1++ = *x++;\n\t\t}\n\tif ((b->wds = x1 - b->x) == 0)\n\t\tb->x[0] = 0;\n\t}\n\n static ULong\n#ifdef KR_headers\nany_on(b, k) Bigint *b; int k;\n#else\nany_on(Bigint *b, int k)\n#endif\n{\n\tint n, nwds;\n\tULong *x, *x0, x1, x2;\n\n\tx = b->x;\n\tnwds = b->wds;\n\tn = k >> kshift;\n\tif (n > nwds)\n\t\tn = nwds;\n\telse if (n < nwds && (k &= kmask)) {\n\t\tx1 = x2 = x[n];\n\t\tx1 >>= k;\n\t\tx1 <<= k;\n\t\tif (x1 != x2)\n\t\t\treturn 1;\n\t\t}\n\tx0 = x;\n\tx += n;\n\twhile(x > x0)\n\t\tif (*--x)\n\t\t\treturn 1;\n\treturn 0;\n\t}\n\nenum {\t/* rounding values: same as FLT_ROUNDS */\n\tRound_zero = 0,\n\tRound_near = 1,\n\tRound_up = 2,\n\tRound_down = 3\n\t};\n\n void\n#ifdef KR_headers\ngethex(sp, rvp, rounding, sign)\n\tCONST char **sp; U *rvp; int rounding, sign;\n#else\ngethex( CONST char **sp, U *rvp, int rounding, int sign)\n#endif\n{\n\tBigint *b;\n\tCONST unsigned char *decpt, *s0, *s, *s1;\n\tLong e, e1;\n\tULong L, lostbits, *x;\n\tint big, denorm, esign, havedig, k, n, nbits, up, zret;\n#ifdef IBM\n\tint j;\n#endif\n\tenum {\n#ifdef IEEE_Arith /*{{*/\n\t\temax = 0x7fe - Bias - P + 1,\n\t\temin = Emin - P + 1\n#else /*}{*/\n\t\temin = Emin - P,\n#ifdef VAX\n\t\temax = 0x7ff - Bias - P + 1\n#endif\n#ifdef IBM\n\t\temax = 0x7f - Bias - P\n#endif\n#endif /*}}*/\n\t\t};\n#ifdef USE_LOCALE\n\tint i;\n#ifdef NO_LOCALE_CACHE\n\tconst unsigned char *decimalpoint = (unsigned char*)\n\t\tlocaleconv()->decimal_point;\n#else\n\tconst unsigned char *decimalpoint;\n\tstatic unsigned char *decimalpoint_cache;\n\tif (!(s0 = decimalpoint_cache)) {\n\t\ts0 = (unsigned char*)localeconv()->decimal_point;\n\t\tif ((decimalpoint_cache = (unsigned char*)\n\t\t\t\tMALLOC(strlen((CONST char*)s0) + 1))) {\n\t\t\tstrcpy((char*)decimalpoint_cache, (CONST char*)s0);\n\t\t\ts0 = decimalpoint_cache;\n\t\t\t}\n\t\t}\n\tdecimalpoint = s0;\n#endif\n#endif\n\n\tif (!hexdig['0'])\n\t\thexdig_init();\n\thavedig = 0;\n\ts0 = *(CONST unsigned char **)sp + 2;\n\twhile(s0[havedig] == '0')\n\t\thavedig++;\n\ts0 += havedig;\n\ts = s0;\n\tdecpt = 0;\n\tzret = 0;\n\te = 0;\n\tif (hexdig[*s])\n\t\thavedig++;\n\telse {\n\t\tzret = 1;\n#ifdef USE_LOCALE\n\t\tfor(i = 0; decimalpoint[i]; ++i) {\n\t\t\tif (s[i] != decimalpoint[i])\n\t\t\t\tgoto pcheck;\n\t\t\t}\n\t\tdecpt = s += i;\n#else\n\t\tif (*s != '.')\n\t\t\tgoto pcheck;\n\t\tdecpt = ++s;\n#endif\n\t\tif (!hexdig[*s])\n\t\t\tgoto pcheck;\n\t\twhile(*s == '0')\n\t\t\ts++;\n\t\tif (hexdig[*s])\n\t\t\tzret = 0;\n\t\thavedig = 1;\n\t\ts0 = s;\n\t\t}\n\twhile(hexdig[*s])\n\t\ts++;\n#ifdef USE_LOCALE\n\tif (*s == *decimalpoint && !decpt) {\n\t\tfor(i = 1; decimalpoint[i]; ++i) {\n\t\t\tif (s[i] != decimalpoint[i])\n\t\t\t\tgoto pcheck;\n\t\t\t}\n\t\tdecpt = s += i;\n#else\n\tif (*s == '.' && !decpt) {\n\t\tdecpt = ++s;\n#endif\n\t\twhile(hexdig[*s])\n\t\t\ts++;\n\t\t}/*}*/\n\tif (decpt)\n\t\te = -(((Long)(s-decpt)) << 2);\n pcheck:\n\ts1 = s;\n\tbig = esign = 0;\n\tswitch(*s) {\n\t  case 'p':\n\t  case 'P':\n\t\tswitch(*++s) {\n\t\t  case '-':\n\t\t\tesign = 1;\n\t\t\t/* no break */\n\t\t  case '+':\n\t\t\ts++;\n\t\t  }\n\t\tif ((n = hexdig[*s]) == 0 || n > 0x19) {\n\t\t\ts = s1;\n\t\t\tbreak;\n\t\t\t}\n\t\te1 = n - 0x10;\n\t\twhile((n = hexdig[*++s]) !=0 && n <= 0x19) {\n\t\t\tif (e1 & 0xf8000000)\n\t\t\t\tbig = 1;\n\t\t\te1 = 10*e1 + n - 0x10;\n\t\t\t}\n\t\tif (esign)\n\t\t\te1 = -e1;\n\t\te += e1;\n\t  }\n\t*sp = (char*)s;\n\tif (!havedig)\n\t\t*sp = (char*)s0 - 1;\n\tif (zret)\n\t\tgoto retz1;\n\tif (big) {\n\t\tif (esign) {\n#ifdef IEEE_Arith\n\t\t\tswitch(rounding) {\n\t\t\t  case Round_up:\n\t\t\t\tif (sign)\n\t\t\t\t\tbreak;\n\t\t\t\tgoto ret_tiny;\n\t\t\t  case Round_down:\n\t\t\t\tif (!sign)\n\t\t\t\t\tbreak;\n\t\t\t\tgoto ret_tiny;\n\t\t\t  }\n#endif\n\t\t\tgoto retz;\n#ifdef IEEE_Arith\n ret_tiny:\n#ifndef NO_ERRNO\n\t\t\terrno = ERANGE;\n#endif\n\t\t\tword0(rvp) = 0;\n\t\t\tword1(rvp) = 1;\n\t\t\treturn;\n#endif /* IEEE_Arith */\n\t\t\t}\n\t\tswitch(rounding) {\n\t\t  case Round_near:\n\t\t\tgoto ovfl1;\n\t\t  case Round_up:\n\t\t\tif (!sign)\n\t\t\t\tgoto ovfl1;\n\t\t\tgoto ret_big;\n\t\t  case Round_down:\n\t\t\tif (sign)\n\t\t\t\tgoto ovfl1;\n\t\t\tgoto ret_big;\n\t\t  }\n ret_big:\n\t\tword0(rvp) = Big0;\n\t\tword1(rvp) = Big1;\n\t\treturn;\n\t\t}\n\tn = s1 - s0 - 1;\n\tfor(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)\n\t\tk++;\n\tb = Balloc(k);\n\tx = b->x;\n\tn = 0;\n\tL = 0;\n#ifdef USE_LOCALE\n\tfor(i = 0; decimalpoint[i+1]; ++i);\n#endif\n\twhile(s1 > s0) {\n#ifdef USE_LOCALE\n\t\tif (*--s1 == decimalpoint[i]) {\n\t\t\ts1 -= i;\n\t\t\tcontinue;\n\t\t\t}\n#else\n\t\tif (*--s1 == '.')\n\t\t\tcontinue;\n#endif\n\t\tif (n == ULbits) {\n\t\t\t*x++ = L;\n\t\t\tL = 0;\n\t\t\tn = 0;\n\t\t\t}\n\t\tL |= (hexdig[*s1] & 0x0f) << n;\n\t\tn += 4;\n\t\t}\n\t*x++ = L;\n\tb->wds = n = x - b->x;\n\tn = ULbits*n - hi0bits(L);\n\tnbits = Nbits;\n\tlostbits = 0;\n\tx = b->x;\n\tif (n > nbits) {\n\t\tn -= nbits;\n\t\tif (any_on(b,n)) {\n\t\t\tlostbits = 1;\n\t\t\tk = n - 1;\n\t\t\tif (x[k>>kshift] & 1 << (k & kmask)) {\n\t\t\t\tlostbits = 2;\n\t\t\t\tif (k > 0 && any_on(b,k))\n\t\t\t\t\tlostbits = 3;\n\t\t\t\t}\n\t\t\t}\n\t\trshift(b, n);\n\t\te += n;\n\t\t}\n\telse if (n < nbits) {\n\t\tn = nbits - n;\n\t\tb = lshift(b, n);\n\t\te -= n;\n\t\tx = b->x;\n\t\t}\n\tif (e > Emax) {\n ovfl:\n\t\tBfree(b);\n ovfl1:\n#ifndef NO_ERRNO\n\t\terrno = ERANGE;\n#endif\n\t\tword0(rvp) = Exp_mask;\n\t\tword1(rvp) = 0;\n\t\treturn;\n\t\t}\n\tdenorm = 0;\n\tif (e < emin) {\n\t\tdenorm = 1;\n\t\tn = emin - e;\n\t\tif (n >= nbits) {\n#ifdef IEEE_Arith /*{*/\n\t\t\tswitch (rounding) {\n\t\t\t  case Round_near:\n\t\t\t\tif (n == nbits && (n < 2 || any_on(b,n-1)))\n\t\t\t\t\tgoto ret_tiny;\n\t\t\t\tbreak;\n\t\t\t  case Round_up:\n\t\t\t\tif (!sign)\n\t\t\t\t\tgoto ret_tiny;\n\t\t\t\tbreak;\n\t\t\t  case Round_down:\n\t\t\t\tif (sign)\n\t\t\t\t\tgoto ret_tiny;\n\t\t\t  }\n#endif /* } IEEE_Arith */\n\t\t\tBfree(b);\n retz:\n#ifndef NO_ERRNO\n\t\t\terrno = ERANGE;\n#endif\n retz1:\n\t\t\trvp->d = 0.;\n\t\t\treturn;\n\t\t\t}\n\t\tk = n - 1;\n\t\tif (lostbits)\n\t\t\tlostbits = 1;\n\t\telse if (k > 0)\n\t\t\tlostbits = any_on(b,k);\n\t\tif (x[k>>kshift] & 1 << (k & kmask))\n\t\t\tlostbits |= 2;\n\t\tnbits -= n;\n\t\trshift(b,n);\n\t\te = emin;\n\t\t}\n\tif (lostbits) {\n\t\tup = 0;\n\t\tswitch(rounding) {\n\t\t  case Round_zero:\n\t\t\tbreak;\n\t\t  case Round_near:\n\t\t\tif (lostbits & 2\n\t\t\t && (lostbits & 1) | (x[0] & 1))\n\t\t\t\tup = 1;\n\t\t\tbreak;\n\t\t  case Round_up:\n\t\t\tup = 1 - sign;\n\t\t\tbreak;\n\t\t  case Round_down:\n\t\t\tup = sign;\n\t\t  }\n\t\tif (up) {\n\t\t\tk = b->wds;\n\t\t\tb = increment(b);\n\t\t\tx = b->x;\n\t\t\tif (denorm) {\n#if 0\n\t\t\t\tif (nbits == Nbits - 1\n\t\t\t\t && x[nbits >> kshift] & 1 << (nbits & kmask))\n\t\t\t\t\tdenorm = 0; /* not currently used */\n#endif\n\t\t\t\t}\n\t\t\telse if (b->wds > k\n\t\t\t || ((n = nbits & kmask) !=0\n\t\t\t     && hi0bits(x[k-1]) < 32-n)) {\n\t\t\t\trshift(b,1);\n\t\t\t\tif (++e > Emax)\n\t\t\t\t\tgoto ovfl;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#ifdef IEEE_Arith\n\tif (denorm)\n\t\tword0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0;\n\telse\n\t\tword0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20);\n\tword1(rvp) = b->x[0];\n#endif\n#ifdef IBM\n\tif ((j = e & 3)) {\n\t\tk = b->x[0] & ((1 << j) - 1);\n\t\trshift(b,j);\n\t\tif (k) {\n\t\t\tswitch(rounding) {\n\t\t\t  case Round_up:\n\t\t\t\tif (!sign)\n\t\t\t\t\tincrement(b);\n\t\t\t\tbreak;\n\t\t\t  case Round_down:\n\t\t\t\tif (sign)\n\t\t\t\t\tincrement(b);\n\t\t\t\tbreak;\n\t\t\t  case Round_near:\n\t\t\t\tj = 1 << (j-1);\n\t\t\t\tif (k & j && ((k & (j-1)) | lostbits))\n\t\t\t\t\tincrement(b);\n\t\t\t  }\n\t\t\t}\n\t\t}\n\te >>= 2;\n\tword0(rvp) = b->x[1] | ((e + 65 + 13) << 24);\n\tword1(rvp) = b->x[0];\n#endif\n#ifdef VAX\n\t/* The next two lines ignore swap of low- and high-order 2 bytes. */\n\t/* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */\n\t/* word1(rvp) = b->x[0]; */\n\tword0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16);\n\tword1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16);\n#endif\n\tBfree(b);\n\t}\n#endif /*!NO_HEX_FP}*/\n\n static int\n#ifdef KR_headers\ndshift(b, p2) Bigint *b; int p2;\n#else\ndshift(Bigint *b, int p2)\n#endif\n{\n\tint rv = hi0bits(b->x[b->wds-1]) - 4;\n\tif (p2 > 0)\n\t\trv -= p2;\n\treturn rv & kmask;\n\t}\n\n static int\nquorem\n#ifdef KR_headers\n\t(b, S) Bigint *b, *S;\n#else\n\t(Bigint *b, Bigint *S)\n#endif\n{\n\tint n;\n\tULong *bx, *bxe, q, *sx, *sxe;\n#ifdef ULLong\n\tULLong borrow, carry, y, ys;\n#else\n\tULong borrow, carry, y, ys;\n#ifdef Pack_32\n\tULong si, z, zs;\n#endif\n#endif\n\n\tn = S->wds;\n#ifdef DEBUG\n\t/*debug*/ if (b->wds > n)\n\t/*debug*/\tBug(\"oversize b in quorem\");\n#endif\n\tif (b->wds < n)\n\t\treturn 0;\n\tsx = S->x;\n\tsxe = sx + --n;\n\tbx = b->x;\n\tbxe = bx + n;\n\tq = *bxe / (*sxe + 1);\t/* ensure q <= true quotient */\n#ifdef DEBUG\n#ifdef NO_STRTOD_BIGCOMP\n\t/*debug*/ if (q > 9)\n#else\n\t/* An oversized q is possible when quorem is called from bigcomp and */\n\t/* the input is near, e.g., twice the smallest denormalized number. */\n\t/*debug*/ if (q > 15)\n#endif\n\t/*debug*/\tBug(\"oversized quotient in quorem\");\n#endif\n\tif (q) {\n\t\tborrow = 0;\n\t\tcarry = 0;\n\t\tdo {\n#ifdef ULLong\n\t\t\tys = *sx++ * (ULLong)q + carry;\n\t\t\tcarry = ys >> 32;\n\t\t\ty = *bx - (ys & FFFFFFFF) - borrow;\n\t\t\tborrow = y >> 32 & (ULong)1;\n\t\t\t*bx++ = y & FFFFFFFF;\n#else\n#ifdef Pack_32\n\t\t\tsi = *sx++;\n\t\t\tys = (si & 0xffff) * q + carry;\n\t\t\tzs = (si >> 16) * q + (ys >> 16);\n\t\t\tcarry = zs >> 16;\n\t\t\ty = (*bx & 0xffff) - (ys & 0xffff) - borrow;\n\t\t\tborrow = (y & 0x10000) >> 16;\n\t\t\tz = (*bx >> 16) - (zs & 0xffff) - borrow;\n\t\t\tborrow = (z & 0x10000) >> 16;\n\t\t\tStoreinc(bx, z, y);\n#else\n\t\t\tys = *sx++ * q + carry;\n\t\t\tcarry = ys >> 16;\n\t\t\ty = *bx - (ys & 0xffff) - borrow;\n\t\t\tborrow = (y & 0x10000) >> 16;\n\t\t\t*bx++ = y & 0xffff;\n#endif\n#endif\n\t\t\t}\n\t\t\twhile(sx <= sxe);\n\t\tif (!*bxe) {\n\t\t\tbx = b->x;\n\t\t\twhile(--bxe > bx && !*bxe)\n\t\t\t\t--n;\n\t\t\tb->wds = n;\n\t\t\t}\n\t\t}\n\tif (cmp(b, S) >= 0) {\n\t\tq++;\n\t\tborrow = 0;\n\t\tcarry = 0;\n\t\tbx = b->x;\n\t\tsx = S->x;\n\t\tdo {\n#ifdef ULLong\n\t\t\tys = *sx++ + carry;\n\t\t\tcarry = ys >> 32;\n\t\t\ty = *bx - (ys & FFFFFFFF) - borrow;\n\t\t\tborrow = y >> 32 & (ULong)1;\n\t\t\t*bx++ = y & FFFFFFFF;\n#else\n#ifdef Pack_32\n\t\t\tsi = *sx++;\n\t\t\tys = (si & 0xffff) + carry;\n\t\t\tzs = (si >> 16) + (ys >> 16);\n\t\t\tcarry = zs >> 16;\n\t\t\ty = (*bx & 0xffff) - (ys & 0xffff) - borrow;\n\t\t\tborrow = (y & 0x10000) >> 16;\n\t\t\tz = (*bx >> 16) - (zs & 0xffff) - borrow;\n\t\t\tborrow = (z & 0x10000) >> 16;\n\t\t\tStoreinc(bx, z, y);\n#else\n\t\t\tys = *sx++ + carry;\n\t\t\tcarry = ys >> 16;\n\t\t\ty = *bx - (ys & 0xffff) - borrow;\n\t\t\tborrow = (y & 0x10000) >> 16;\n\t\t\t*bx++ = y & 0xffff;\n#endif\n#endif\n\t\t\t}\n\t\t\twhile(sx <= sxe);\n\t\tbx = b->x;\n\t\tbxe = bx + n;\n\t\tif (!*bxe) {\n\t\t\twhile(--bxe > bx && !*bxe)\n\t\t\t\t--n;\n\t\t\tb->wds = n;\n\t\t\t}\n\t\t}\n\treturn q;\n\t}\n\n#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/\n static double\nsulp\n#ifdef KR_headers\n\t(x, bc) U *x; BCinfo *bc;\n#else\n\t(U *x, BCinfo *bc)\n#endif\n{\n\tU u;\n\tdouble rv;\n\tint i;\n\n\trv = ulp(x);\n\tif (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0)\n\t\treturn rv; /* Is there an example where i <= 0 ? */\n\tword0(&u) = Exp_1 + (i << Exp_shift);\n\tword1(&u) = 0;\n\treturn rv * u.d;\n\t}\n#endif /*}*/\n\n#ifndef NO_STRTOD_BIGCOMP\n static void\nbigcomp\n#ifdef KR_headers\n\t(rv, s0, bc)\n\tU *rv; CONST char *s0; BCinfo *bc;\n#else\n\t(U *rv, const char *s0, BCinfo *bc)\n#endif\n{\n\tBigint *b, *d;\n\tint b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase;\n\n\tdsign = bc->dsign;\n\tnd = bc->nd;\n\tnd0 = bc->nd0;\n\tp5 = nd + bc->e0 - 1;\n\tspeccase = 0;\n#ifndef Sudden_Underflow\n\tif (rv->d == 0.) {\t/* special case: value near underflow-to-zero */\n\t\t\t\t/* threshold was rounded to zero */\n\t\tb = i2b(1);\n\t\tp2 = Emin - P + 1;\n\t\tbbits = 1;\n#ifdef Avoid_Underflow\n\t\tword0(rv) = (P+2) << Exp_shift;\n#else\n\t\tword1(rv) = 1;\n#endif\n\t\ti = 0;\n#ifdef Honor_FLT_ROUNDS\n\t\tif (bc->rounding == 1)\n#endif\n\t\t\t{\n\t\t\tspeccase = 1;\n\t\t\t--p2;\n\t\t\tdsign = 0;\n\t\t\tgoto have_i;\n\t\t\t}\n\t\t}\n\telse\n#endif\n\t\tb = d2b(rv, &p2, &bbits);\n#ifdef Avoid_Underflow\n\tp2 -= bc->scale;\n#endif\n\t/* floor(log2(rv)) == bbits - 1 + p2 */\n\t/* Check for denormal case. */\n\ti = P - bbits;\n\tif (i > (j = P - Emin - 1 + p2)) {\n#ifdef Sudden_Underflow\n\t\tBfree(b);\n\t\tb = i2b(1);\n\t\tp2 = Emin;\n\t\ti = P - 1;\n#ifdef Avoid_Underflow\n\t\tword0(rv) = (1 + bc->scale) << Exp_shift;\n#else\n\t\tword0(rv) = Exp_msk1;\n#endif\n\t\tword1(rv) = 0;\n#else\n\t\ti = j;\n#endif\n\t\t}\n#ifdef Honor_FLT_ROUNDS\n\tif (bc->rounding != 1) {\n\t\tif (i > 0)\n\t\t\tb = lshift(b, i);\n\t\tif (dsign)\n\t\t\tb = increment(b);\n\t\t}\n\telse\n#endif\n\t\t{\n\t\tb = lshift(b, ++i);\n\t\tb->x[0] |= 1;\n\t\t}\n#ifndef Sudden_Underflow\n have_i:\n#endif\n\tp2 -= p5 + i;\n\td = i2b(1);\n\t/* Arrange for convenient computation of quotients:\n\t * shift left if necessary so divisor has 4 leading 0 bits.\n\t */\n\tif (p5 > 0)\n\t\td = pow5mult(d, p5);\n\telse if (p5 < 0)\n\t\tb = pow5mult(b, -p5);\n\tif (p2 > 0) {\n\t\tb2 = p2;\n\t\td2 = 0;\n\t\t}\n\telse {\n\t\tb2 = 0;\n\t\td2 = -p2;\n\t\t}\n\ti = dshift(d, d2);\n\tif ((b2 += i) > 0)\n\t\tb = lshift(b, b2);\n\tif ((d2 += i) > 0)\n\t\td = lshift(d, d2);\n\n\t/* Now b/d = exactly half-way between the two floating-point values */\n\t/* on either side of the input string.  Compute first digit of b/d. */\n\n\tif (!(dig = quorem(b,d))) {\n\t\tb = multadd(b, 10, 0);\t/* very unlikely */\n\t\tdig = quorem(b,d);\n\t\t}\n\n\t/* Compare b/d with s0 */\n\n\tfor(i = 0; i < nd0; ) {\n\t\tif ((dd = s0[i++] - '0' - dig))\n\t\t\tgoto ret;\n\t\tif (!b->x[0] && b->wds == 1) {\n\t\t\tif (i < nd)\n\t\t\t\tdd = 1;\n\t\t\tgoto ret;\n\t\t\t}\n\t\tb = multadd(b, 10, 0);\n\t\tdig = quorem(b,d);\n\t\t}\n\tfor(j = bc->dp1; i++ < nd;) {\n\t\tif ((dd = s0[j++] - '0' - dig))\n\t\t\tgoto ret;\n\t\tif (!b->x[0] && b->wds == 1) {\n\t\t\tif (i < nd)\n\t\t\t\tdd = 1;\n\t\t\tgoto ret;\n\t\t\t}\n\t\tb = multadd(b, 10, 0);\n\t\tdig = quorem(b,d);\n\t\t}\n\tif (b->x[0] || b->wds > 1)\n\t\tdd = -1;\n ret:\n\tBfree(b);\n\tBfree(d);\n#ifdef Honor_FLT_ROUNDS\n\tif (bc->rounding != 1) {\n\t\tif (dd < 0) {\n\t\t\tif (bc->rounding == 0) {\n\t\t\t\tif (!dsign)\n\t\t\t\t\tgoto retlow1;\n\t\t\t\t}\n\t\t\telse if (dsign)\n\t\t\t\tgoto rethi1;\n\t\t\t}\n\t\telse if (dd > 0) {\n\t\t\tif (bc->rounding == 0) {\n\t\t\t\tif (dsign)\n\t\t\t\t\tgoto rethi1;\n\t\t\t\tgoto ret1;\n\t\t\t\t}\n\t\t\tif (!dsign)\n\t\t\t\tgoto rethi1;\n\t\t\tdval(rv) += 2.*sulp(rv,bc);\n\t\t\t}\n\t\telse {\n\t\t\tbc->inexact = 0;\n\t\t\tif (dsign)\n\t\t\t\tgoto rethi1;\n\t\t\t}\n\t\t}\n\telse\n#endif\n\tif (speccase) {\n\t\tif (dd <= 0)\n\t\t\trv->d = 0.;\n\t\t}\n\telse if (dd < 0) {\n\t\tif (!dsign)\t/* does not happen for round-near */\nretlow1:\n\t\t\tdval(rv) -= sulp(rv,bc);\n\t\t}\n\telse if (dd > 0) {\n\t\tif (dsign) {\n rethi1:\n\t\t\tdval(rv) += sulp(rv,bc);\n\t\t\t}\n\t\t}\n\telse {\n\t\t/* Exact half-way case:  apply round-even rule. */\n\t\tif ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) {\n\t\t\ti = 1 - j;\n\t\t\tif (i <= 31) {\n\t\t\t\tif (word1(rv) & (0x1 << i))\n\t\t\t\t\tgoto odd;\n\t\t\t\t}\n\t\t\telse if (word0(rv) & (0x1 << (i-32)))\n\t\t\t\tgoto odd;\n\t\t\t}\n\t\telse if (word1(rv) & 1) {\n odd:\n\t\t\tif (dsign)\n\t\t\t\tgoto rethi1;\n\t\t\tgoto retlow1;\n\t\t\t}\n\t\t}\n\n#ifdef Honor_FLT_ROUNDS\n ret1:\n#endif\n\treturn;\n\t}\n#endif /* NO_STRTOD_BIGCOMP */\n\n double\nfpconv_strtod\n#ifdef KR_headers\n\t(s00, se) CONST char *s00; char **se;\n#else\n\t(const char *s00, char **se)\n#endif\n{\n\tint bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;\n\tint esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign;\n\tCONST char *s, *s0, *s1;\n\tdouble aadj, aadj1;\n\tLong L;\n\tU aadj2, adj, rv, rv0;\n\tULong y, z;\n\tBCinfo bc;\n\tBigint *bb, *bb1, *bd, *bd0, *bs, *delta;\n#ifdef Avoid_Underflow\n\tULong Lsb, Lsb1;\n#endif\n#ifdef SET_INEXACT\n\tint oldinexact;\n#endif\n#ifndef NO_STRTOD_BIGCOMP\n\tint req_bigcomp = 0;\n#endif\n#ifdef Honor_FLT_ROUNDS /*{*/\n#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */\n\tbc.rounding = Flt_Rounds;\n#else /*}{*/\n\tbc.rounding = 1;\n\tswitch(fegetround()) {\n\t  case FE_TOWARDZERO:\tbc.rounding = 0; break;\n\t  case FE_UPWARD:\tbc.rounding = 2; break;\n\t  case FE_DOWNWARD:\tbc.rounding = 3;\n\t  }\n#endif /*}}*/\n#endif /*}*/\n#ifdef USE_LOCALE\n\tCONST char *s2;\n#endif\n\n\tsign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0;\n\tdval(&rv) = 0.;\n\tfor(s = s00;;s++) switch(*s) {\n\t\tcase '-':\n\t\t\tsign = 1;\n\t\t\t/* no break */\n\t\tcase '+':\n\t\t\tif (*++s)\n\t\t\t\tgoto break2;\n\t\t\t/* no break */\n\t\tcase 0:\n\t\t\tgoto ret0;\n\t\tcase '\\t':\n\t\tcase '\\n':\n\t\tcase '\\v':\n\t\tcase '\\f':\n\t\tcase '\\r':\n\t\tcase ' ':\n\t\t\tcontinue;\n\t\tdefault:\n\t\t\tgoto break2;\n\t\t}\n break2:\n\tif (*s == '0') {\n#ifndef NO_HEX_FP /*{*/\n\t\tswitch(s[1]) {\n\t\t  case 'x':\n\t\t  case 'X':\n#ifdef Honor_FLT_ROUNDS\n\t\t\tgethex(&s, &rv, bc.rounding, sign);\n#else\n\t\t\tgethex(&s, &rv, 1, sign);\n#endif\n\t\t\tgoto ret;\n\t\t  }\n#endif /*}*/\n\t\tnz0 = 1;\n\t\twhile(*++s == '0') ;\n\t\tif (!*s)\n\t\t\tgoto ret;\n\t\t}\n\ts0 = s;\n\ty = z = 0;\n\tfor(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)\n\t\tif (nd < 9)\n\t\t\ty = 10*y + c - '0';\n\t\telse if (nd < 16)\n\t\t\tz = 10*z + c - '0';\n\tnd0 = nd;\n\tbc.dp0 = bc.dp1 = s - s0;\n\tfor(s1 = s; s1 > s0 && *--s1 == '0'; )\n\t\t++nz1;\n#ifdef USE_LOCALE\n\ts1 = localeconv()->decimal_point;\n\tif (c == *s1) {\n\t\tc = '.';\n\t\tif (*++s1) {\n\t\t\ts2 = s;\n\t\t\tfor(;;) {\n\t\t\t\tif (*++s2 != *s1) {\n\t\t\t\t\tc = 0;\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (!*++s1) {\n\t\t\t\t\ts = s2;\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#endif\n\tif (c == '.') {\n\t\tc = *++s;\n\t\tbc.dp1 = s - s0;\n\t\tbc.dplen = bc.dp1 - bc.dp0;\n\t\tif (!nd) {\n\t\t\tfor(; c == '0'; c = *++s)\n\t\t\t\tnz++;\n\t\t\tif (c > '0' && c <= '9') {\n\t\t\t\tbc.dp0 = s0 - s;\n\t\t\t\tbc.dp1 = bc.dp0 + bc.dplen;\n\t\t\t\ts0 = s;\n\t\t\t\tnf += nz;\n\t\t\t\tnz = 0;\n\t\t\t\tgoto have_dig;\n\t\t\t\t}\n\t\t\tgoto dig_done;\n\t\t\t}\n\t\tfor(; c >= '0' && c <= '9'; c = *++s) {\n have_dig:\n\t\t\tnz++;\n\t\t\tif (c -= '0') {\n\t\t\t\tnf += nz;\n\t\t\t\tfor(i = 1; i < nz; i++)\n\t\t\t\t\tif (nd++ < 9)\n\t\t\t\t\t\ty *= 10;\n\t\t\t\t\telse if (nd <= DBL_DIG + 1)\n\t\t\t\t\t\tz *= 10;\n\t\t\t\tif (nd++ < 9)\n\t\t\t\t\ty = 10*y + c;\n\t\t\t\telse if (nd <= DBL_DIG + 1)\n\t\t\t\t\tz = 10*z + c;\n\t\t\t\tnz = nz1 = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n dig_done:\n\te = 0;\n\tif (c == 'e' || c == 'E') {\n\t\tif (!nd && !nz && !nz0) {\n\t\t\tgoto ret0;\n\t\t\t}\n\t\ts00 = s;\n\t\tesign = 0;\n\t\tswitch(c = *++s) {\n\t\t\tcase '-':\n\t\t\t\tesign = 1;\n\t\t\tcase '+':\n\t\t\t\tc = *++s;\n\t\t\t}\n\t\tif (c >= '0' && c <= '9') {\n\t\t\twhile(c == '0')\n\t\t\t\tc = *++s;\n\t\t\tif (c > '0' && c <= '9') {\n\t\t\t\tL = c - '0';\n\t\t\t\ts1 = s;\n\t\t\t\twhile((c = *++s) >= '0' && c <= '9')\n\t\t\t\t\tL = 10*L + c - '0';\n\t\t\t\tif (s - s1 > 8 || L > 19999)\n\t\t\t\t\t/* Avoid confusion from exponents\n\t\t\t\t\t * so large that e might overflow.\n\t\t\t\t\t */\n\t\t\t\t\te = 19999; /* safe for 16 bit ints */\n\t\t\t\telse\n\t\t\t\t\te = (int)L;\n\t\t\t\tif (esign)\n\t\t\t\t\te = -e;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\te = 0;\n\t\t\t}\n\t\telse\n\t\t\ts = s00;\n\t\t}\n\tif (!nd) {\n\t\tif (!nz && !nz0) {\n#ifdef INFNAN_CHECK\n\t\t\t/* Check for Nan and Infinity */\n\t\t\tif (!bc.dplen)\n\t\t\t switch(c) {\n\t\t\t  case 'i':\n\t\t\t  case 'I':\n\t\t\t\tif (match(&s,\"nf\")) {\n\t\t\t\t\t--s;\n\t\t\t\t\tif (!match(&s,\"inity\"))\n\t\t\t\t\t\t++s;\n\t\t\t\t\tword0(&rv) = 0x7ff00000;\n\t\t\t\t\tword1(&rv) = 0;\n\t\t\t\t\tgoto ret;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t  case 'n':\n\t\t\t  case 'N':\n\t\t\t\tif (match(&s, \"an\")) {\n\t\t\t\t\tword0(&rv) = NAN_WORD0;\n\t\t\t\t\tword1(&rv) = NAN_WORD1;\n#ifndef No_Hex_NaN\n\t\t\t\t\tif (*s == '(') /*)*/\n\t\t\t\t\t\thexnan(&rv, &s);\n#endif\n\t\t\t\t\tgoto ret;\n\t\t\t\t\t}\n\t\t\t  }\n#endif /* INFNAN_CHECK */\n ret0:\n\t\t\ts = s00;\n\t\t\tsign = 0;\n\t\t\t}\n\t\tgoto ret;\n\t\t}\n\tbc.e0 = e1 = e -= nf;\n\n\t/* Now we have nd0 digits, starting at s0, followed by a\n\t * decimal point, followed by nd-nd0 digits.  The number we're\n\t * after is the integer represented by those digits times\n\t * 10**e */\n\n\tif (!nd0)\n\t\tnd0 = nd;\n\tk = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;\n\tdval(&rv) = y;\n\tif (k > 9) {\n#ifdef SET_INEXACT\n\t\tif (k > DBL_DIG)\n\t\t\toldinexact = get_inexact();\n#endif\n\t\tdval(&rv) = tens[k - 9] * dval(&rv) + z;\n\t\t}\n\tbd0 = 0;\n\tif (nd <= DBL_DIG\n#ifndef RND_PRODQUOT\n#ifndef Honor_FLT_ROUNDS\n\t\t&& Flt_Rounds == 1\n#endif\n#endif\n\t\t\t) {\n\t\tif (!e)\n\t\t\tgoto ret;\n#ifndef ROUND_BIASED_without_Round_Up\n\t\tif (e > 0) {\n\t\t\tif (e <= Ten_pmax) {\n#ifdef VAX\n\t\t\t\tgoto vax_ovfl_check;\n#else\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\t/* round correctly FLT_ROUNDS = 2 or 3 */\n\t\t\t\tif (sign) {\n\t\t\t\t\trv.d = -rv.d;\n\t\t\t\t\tsign = 0;\n\t\t\t\t\t}\n#endif\n\t\t\t\t/* rv = */ rounded_product(dval(&rv), tens[e]);\n\t\t\t\tgoto ret;\n#endif\n\t\t\t\t}\n\t\t\ti = DBL_DIG - nd;\n\t\t\tif (e <= Ten_pmax + i) {\n\t\t\t\t/* A fancier test would sometimes let us do\n\t\t\t\t * this for larger i values.\n\t\t\t\t */\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\t/* round correctly FLT_ROUNDS = 2 or 3 */\n\t\t\t\tif (sign) {\n\t\t\t\t\trv.d = -rv.d;\n\t\t\t\t\tsign = 0;\n\t\t\t\t\t}\n#endif\n\t\t\t\te -= i;\n\t\t\t\tdval(&rv) *= tens[i];\n#ifdef VAX\n\t\t\t\t/* VAX exponent range is so narrow we must\n\t\t\t\t * worry about overflow here...\n\t\t\t\t */\n vax_ovfl_check:\n\t\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\t\t/* rv = */ rounded_product(dval(&rv), tens[e]);\n\t\t\t\tif ((word0(&rv) & Exp_mask)\n\t\t\t\t > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))\n\t\t\t\t\tgoto ovfl;\n\t\t\t\tword0(&rv) += P*Exp_msk1;\n#else\n\t\t\t\t/* rv = */ rounded_product(dval(&rv), tens[e]);\n#endif\n\t\t\t\tgoto ret;\n\t\t\t\t}\n\t\t\t}\n#ifndef Inaccurate_Divide\n\t\telse if (e >= -Ten_pmax) {\n#ifdef Honor_FLT_ROUNDS\n\t\t\t/* round correctly FLT_ROUNDS = 2 or 3 */\n\t\t\tif (sign) {\n\t\t\t\trv.d = -rv.d;\n\t\t\t\tsign = 0;\n\t\t\t\t}\n#endif\n\t\t\t/* rv = */ rounded_quotient(dval(&rv), tens[-e]);\n\t\t\tgoto ret;\n\t\t\t}\n#endif\n#endif /* ROUND_BIASED_without_Round_Up */\n\t\t}\n\te1 += nd - k;\n\n#ifdef IEEE_Arith\n#ifdef SET_INEXACT\n\tbc.inexact = 1;\n\tif (k <= DBL_DIG)\n\t\toldinexact = get_inexact();\n#endif\n#ifdef Avoid_Underflow\n\tbc.scale = 0;\n#endif\n#ifdef Honor_FLT_ROUNDS\n\tif (bc.rounding >= 2) {\n\t\tif (sign)\n\t\t\tbc.rounding = bc.rounding == 2 ? 0 : 2;\n\t\telse\n\t\t\tif (bc.rounding != 2)\n\t\t\t\tbc.rounding = 0;\n\t\t}\n#endif\n#endif /*IEEE_Arith*/\n\n\t/* Get starting approximation = rv * 10**e1 */\n\n\tif (e1 > 0) {\n\t\tif ((i = e1 & 15))\n\t\t\tdval(&rv) *= tens[i];\n\t\tif (e1 &= ~15) {\n\t\t\tif (e1 > DBL_MAX_10_EXP) {\n ovfl:\n\t\t\t\t/* Can't trust HUGE_VAL */\n#ifdef IEEE_Arith\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\tswitch(bc.rounding) {\n\t\t\t\t  case 0: /* toward 0 */\n\t\t\t\t  case 3: /* toward -infinity */\n\t\t\t\t\tword0(&rv) = Big0;\n\t\t\t\t\tword1(&rv) = Big1;\n\t\t\t\t\tbreak;\n\t\t\t\t  default:\n\t\t\t\t\tword0(&rv) = Exp_mask;\n\t\t\t\t\tword1(&rv) = 0;\n\t\t\t\t  }\n#else /*Honor_FLT_ROUNDS*/\n\t\t\t\tword0(&rv) = Exp_mask;\n\t\t\t\tword1(&rv) = 0;\n#endif /*Honor_FLT_ROUNDS*/\n#ifdef SET_INEXACT\n\t\t\t\t/* set overflow bit */\n\t\t\t\tdval(&rv0) = 1e300;\n\t\t\t\tdval(&rv0) *= dval(&rv0);\n#endif\n#else /*IEEE_Arith*/\n\t\t\t\tword0(&rv) = Big0;\n\t\t\t\tword1(&rv) = Big1;\n#endif /*IEEE_Arith*/\n range_err:\n\t\t\t\tif (bd0) {\n\t\t\t\t\tBfree(bb);\n\t\t\t\t\tBfree(bd);\n\t\t\t\t\tBfree(bs);\n\t\t\t\t\tBfree(bd0);\n\t\t\t\t\tBfree(delta);\n\t\t\t\t\t}\n#ifndef NO_ERRNO\n\t\t\t\terrno = ERANGE;\n#endif\n\t\t\t\tgoto ret;\n\t\t\t\t}\n\t\t\te1 >>= 4;\n\t\t\tfor(j = 0; e1 > 1; j++, e1 >>= 1)\n\t\t\t\tif (e1 & 1)\n\t\t\t\t\tdval(&rv) *= bigtens[j];\n\t\t/* The last multiplication could overflow. */\n\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\tdval(&rv) *= bigtens[j];\n\t\t\tif ((z = word0(&rv) & Exp_mask)\n\t\t\t > Exp_msk1*(DBL_MAX_EXP+Bias-P))\n\t\t\t\tgoto ovfl;\n\t\t\tif (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {\n\t\t\t\t/* set to largest number */\n\t\t\t\t/* (Can't trust DBL_MAX) */\n\t\t\t\tword0(&rv) = Big0;\n\t\t\t\tword1(&rv) = Big1;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\tword0(&rv) += P*Exp_msk1;\n\t\t\t}\n\t\t}\n\telse if (e1 < 0) {\n\t\te1 = -e1;\n\t\tif ((i = e1 & 15))\n\t\t\tdval(&rv) /= tens[i];\n\t\tif (e1 >>= 4) {\n\t\t\tif (e1 >= 1 << n_bigtens)\n\t\t\t\tgoto undfl;\n#ifdef Avoid_Underflow\n\t\t\tif (e1 & Scale_Bit)\n\t\t\t\tbc.scale = 2*P;\n\t\t\tfor(j = 0; e1 > 0; j++, e1 >>= 1)\n\t\t\t\tif (e1 & 1)\n\t\t\t\t\tdval(&rv) *= tinytens[j];\n\t\t\tif (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)\n\t\t\t\t\t\t>> Exp_shift)) > 0) {\n\t\t\t\t/* scaled rv is denormal; clear j low bits */\n\t\t\t\tif (j >= 32) {\n\t\t\t\t\tif (j > 54)\n\t\t\t\t\t\tgoto undfl;\n\t\t\t\t\tword1(&rv) = 0;\n\t\t\t\t\tif (j >= 53)\n\t\t\t\t\t word0(&rv) = (P+2)*Exp_msk1;\n\t\t\t\t\telse\n\t\t\t\t\t word0(&rv) &= 0xffffffff << (j-32);\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tword1(&rv) &= 0xffffffff << j;\n\t\t\t\t}\n#else\n\t\t\tfor(j = 0; e1 > 1; j++, e1 >>= 1)\n\t\t\t\tif (e1 & 1)\n\t\t\t\t\tdval(&rv) *= tinytens[j];\n\t\t\t/* The last multiplication could underflow. */\n\t\t\tdval(&rv0) = dval(&rv);\n\t\t\tdval(&rv) *= tinytens[j];\n\t\t\tif (!dval(&rv)) {\n\t\t\t\tdval(&rv) = 2.*dval(&rv0);\n\t\t\t\tdval(&rv) *= tinytens[j];\n#endif\n\t\t\t\tif (!dval(&rv)) {\n undfl:\n\t\t\t\t\tdval(&rv) = 0.;\n\t\t\t\t\tgoto range_err;\n\t\t\t\t\t}\n#ifndef Avoid_Underflow\n\t\t\t\tword0(&rv) = Tiny0;\n\t\t\t\tword1(&rv) = Tiny1;\n\t\t\t\t/* The refinement below will clean\n\t\t\t\t * this approximation up.\n\t\t\t\t */\n\t\t\t\t}\n#endif\n\t\t\t}\n\t\t}\n\n\t/* Now the hard part -- adjusting rv to the correct value.*/\n\n\t/* Put digits into bd: true value = bd * 10^e */\n\n\tbc.nd = nd - nz1;\n#ifndef NO_STRTOD_BIGCOMP\n\tbc.nd0 = nd0;\t/* Only needed if nd > strtod_diglim, but done here */\n\t\t\t/* to silence an erroneous warning about bc.nd0 */\n\t\t\t/* possibly not being initialized. */\n\tif (nd > strtod_diglim) {\n\t\t/* ASSERT(strtod_diglim >= 18); 18 == one more than the */\n\t\t/* minimum number of decimal digits to distinguish double values */\n\t\t/* in IEEE arithmetic. */\n\t\ti = j = 18;\n\t\tif (i > nd0)\n\t\t\tj += bc.dplen;\n\t\tfor(;;) {\n\t\t\tif (--j < bc.dp1 && j >= bc.dp0)\n\t\t\t\tj = bc.dp0 - 1;\n\t\t\tif (s0[j] != '0')\n\t\t\t\tbreak;\n\t\t\t--i;\n\t\t\t}\n\t\te += nd - i;\n\t\tnd = i;\n\t\tif (nd0 > nd)\n\t\t\tnd0 = nd;\n\t\tif (nd < 9) { /* must recompute y */\n\t\t\ty = 0;\n\t\t\tfor(i = 0; i < nd0; ++i)\n\t\t\t\ty = 10*y + s0[i] - '0';\n\t\t\tfor(j = bc.dp1; i < nd; ++i)\n\t\t\t\ty = 10*y + s0[j++] - '0';\n\t\t\t}\n\t\t}\n#endif\n\tbd0 = s2b(s0, nd0, nd, y, bc.dplen);\n\n\tfor(;;) {\n\t\tbd = Balloc(bd0->k);\n\t\tBcopy(bd, bd0);\n\t\tbb = d2b(&rv, &bbe, &bbbits);\t/* rv = bb * 2^bbe */\n\t\tbs = i2b(1);\n\n\t\tif (e >= 0) {\n\t\t\tbb2 = bb5 = 0;\n\t\t\tbd2 = bd5 = e;\n\t\t\t}\n\t\telse {\n\t\t\tbb2 = bb5 = -e;\n\t\t\tbd2 = bd5 = 0;\n\t\t\t}\n\t\tif (bbe >= 0)\n\t\t\tbb2 += bbe;\n\t\telse\n\t\t\tbd2 -= bbe;\n\t\tbs2 = bb2;\n#ifdef Honor_FLT_ROUNDS\n\t\tif (bc.rounding != 1)\n\t\t\tbs2++;\n#endif\n#ifdef Avoid_Underflow\n\t\tLsb = LSB;\n\t\tLsb1 = 0;\n\t\tj = bbe - bc.scale;\n\t\ti = j + bbbits - 1;\t/* logb(rv) */\n\t\tj = P + 1 - bbbits;\n\t\tif (i < Emin) {\t/* denormal */\n\t\t\ti = Emin - i;\n\t\t\tj -= i;\n\t\t\tif (i < 32)\n\t\t\t\tLsb <<= i;\n\t\t\telse if (i < 52)\n\t\t\t\tLsb1 = Lsb << (i-32);\n\t\t\telse\n\t\t\t\tLsb1 = Exp_mask;\n\t\t\t}\n#else /*Avoid_Underflow*/\n#ifdef Sudden_Underflow\n#ifdef IBM\n\t\tj = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);\n#else\n\t\tj = P + 1 - bbbits;\n#endif\n#else /*Sudden_Underflow*/\n\t\tj = bbe;\n\t\ti = j + bbbits - 1;\t/* logb(rv) */\n\t\tif (i < Emin)\t/* denormal */\n\t\t\tj += P - Emin;\n\t\telse\n\t\t\tj = P + 1 - bbbits;\n#endif /*Sudden_Underflow*/\n#endif /*Avoid_Underflow*/\n\t\tbb2 += j;\n\t\tbd2 += j;\n#ifdef Avoid_Underflow\n\t\tbd2 += bc.scale;\n#endif\n\t\ti = bb2 < bd2 ? bb2 : bd2;\n\t\tif (i > bs2)\n\t\t\ti = bs2;\n\t\tif (i > 0) {\n\t\t\tbb2 -= i;\n\t\t\tbd2 -= i;\n\t\t\tbs2 -= i;\n\t\t\t}\n\t\tif (bb5 > 0) {\n\t\t\tbs = pow5mult(bs, bb5);\n\t\t\tbb1 = mult(bs, bb);\n\t\t\tBfree(bb);\n\t\t\tbb = bb1;\n\t\t\t}\n\t\tif (bb2 > 0)\n\t\t\tbb = lshift(bb, bb2);\n\t\tif (bd5 > 0)\n\t\t\tbd = pow5mult(bd, bd5);\n\t\tif (bd2 > 0)\n\t\t\tbd = lshift(bd, bd2);\n\t\tif (bs2 > 0)\n\t\t\tbs = lshift(bs, bs2);\n\t\tdelta = diff(bb, bd);\n\t\tbc.dsign = delta->sign;\n\t\tdelta->sign = 0;\n\t\ti = cmp(delta, bs);\n#ifndef NO_STRTOD_BIGCOMP /*{*/\n\t\tif (bc.nd > nd && i <= 0) {\n\t\t\tif (bc.dsign) {\n\t\t\t\t/* Must use bigcomp(). */\n\t\t\t\treq_bigcomp = 1;\n\t\t\t\tbreak;\n\t\t\t\t}\n#ifdef Honor_FLT_ROUNDS\n\t\t\tif (bc.rounding != 1) {\n\t\t\t\tif (i < 0) {\n\t\t\t\t\treq_bigcomp = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\telse\n#endif\n\t\t\t\ti = -1;\t/* Discarded digits make delta smaller. */\n\t\t\t}\n#endif /*}*/\n#ifdef Honor_FLT_ROUNDS /*{*/\n\t\tif (bc.rounding != 1) {\n\t\t\tif (i < 0) {\n\t\t\t\t/* Error is less than an ulp */\n\t\t\t\tif (!delta->x[0] && delta->wds <= 1) {\n\t\t\t\t\t/* exact */\n#ifdef SET_INEXACT\n\t\t\t\t\tbc.inexact = 0;\n#endif\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (bc.rounding) {\n\t\t\t\t\tif (bc.dsign) {\n\t\t\t\t\t\tadj.d = 1.;\n\t\t\t\t\t\tgoto apply_adj;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\telse if (!bc.dsign) {\n\t\t\t\t\tadj.d = -1.;\n\t\t\t\t\tif (!word1(&rv)\n\t\t\t\t\t && !(word0(&rv) & Frac_mask)) {\n\t\t\t\t\t\ty = word0(&rv) & Exp_mask;\n#ifdef Avoid_Underflow\n\t\t\t\t\t\tif (!bc.scale || y > 2*P*Exp_msk1)\n#else\n\t\t\t\t\t\tif (y)\n#endif\n\t\t\t\t\t\t  {\n\t\t\t\t\t\t  delta = lshift(delta,Log2P);\n\t\t\t\t\t\t  if (cmp(delta, bs) <= 0)\n\t\t\t\t\t\t\tadj.d = -0.5;\n\t\t\t\t\t\t  }\n\t\t\t\t\t\t}\n apply_adj:\n#ifdef Avoid_Underflow /*{*/\n\t\t\t\t\tif (bc.scale && (y = word0(&rv) & Exp_mask)\n\t\t\t\t\t\t<= 2*P*Exp_msk1)\n\t\t\t\t\t  word0(&adj) += (2*P+1)*Exp_msk1 - y;\n#else\n#ifdef Sudden_Underflow\n\t\t\t\t\tif ((word0(&rv) & Exp_mask) <=\n\t\t\t\t\t\t\tP*Exp_msk1) {\n\t\t\t\t\t\tword0(&rv) += P*Exp_msk1;\n\t\t\t\t\t\tdval(&rv) += adj.d*ulp(dval(&rv));\n\t\t\t\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\t\t\t\t}\n\t\t\t\t\telse\n#endif /*Sudden_Underflow*/\n#endif /*Avoid_Underflow}*/\n\t\t\t\t\tdval(&rv) += adj.d*ulp(&rv);\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tadj.d = ratio(delta, bs);\n\t\t\tif (adj.d < 1.)\n\t\t\t\tadj.d = 1.;\n\t\t\tif (adj.d <= 0x7ffffffe) {\n\t\t\t\t/* adj = rounding ? ceil(adj) : floor(adj); */\n\t\t\t\ty = adj.d;\n\t\t\t\tif (y != adj.d) {\n\t\t\t\t\tif (!((bc.rounding>>1) ^ bc.dsign))\n\t\t\t\t\t\ty++;\n\t\t\t\t\tadj.d = y;\n\t\t\t\t\t}\n\t\t\t\t}\n#ifdef Avoid_Underflow /*{*/\n\t\t\tif (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)\n\t\t\t\tword0(&adj) += (2*P+1)*Exp_msk1 - y;\n#else\n#ifdef Sudden_Underflow\n\t\t\tif ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {\n\t\t\t\tword0(&rv) += P*Exp_msk1;\n\t\t\t\tadj.d *= ulp(dval(&rv));\n\t\t\t\tif (bc.dsign)\n\t\t\t\t\tdval(&rv) += adj.d;\n\t\t\t\telse\n\t\t\t\t\tdval(&rv) -= adj.d;\n\t\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\t\tgoto cont;\n\t\t\t\t}\n#endif /*Sudden_Underflow*/\n#endif /*Avoid_Underflow}*/\n\t\t\tadj.d *= ulp(&rv);\n\t\t\tif (bc.dsign) {\n\t\t\t\tif (word0(&rv) == Big0 && word1(&rv) == Big1)\n\t\t\t\t\tgoto ovfl;\n\t\t\t\tdval(&rv) += adj.d;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\tdval(&rv) -= adj.d;\n\t\t\tgoto cont;\n\t\t\t}\n#endif /*}Honor_FLT_ROUNDS*/\n\n\t\tif (i < 0) {\n\t\t\t/* Error is less than half an ulp -- check for\n\t\t\t * special case of mantissa a power of two.\n\t\t\t */\n\t\t\tif (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask\n#ifdef IEEE_Arith /*{*/\n#ifdef Avoid_Underflow\n\t\t\t || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1\n#else\n\t\t\t || (word0(&rv) & Exp_mask) <= Exp_msk1\n#endif\n#endif /*}*/\n\t\t\t\t) {\n#ifdef SET_INEXACT\n\t\t\t\tif (!delta->x[0] && delta->wds <= 1)\n\t\t\t\t\tbc.inexact = 0;\n#endif\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (!delta->x[0] && delta->wds <= 1) {\n\t\t\t\t/* exact result */\n#ifdef SET_INEXACT\n\t\t\t\tbc.inexact = 0;\n#endif\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdelta = lshift(delta,Log2P);\n\t\t\tif (cmp(delta, bs) > 0)\n\t\t\t\tgoto drop_down;\n\t\t\tbreak;\n\t\t\t}\n\t\tif (i == 0) {\n\t\t\t/* exactly half-way between */\n\t\t\tif (bc.dsign) {\n\t\t\t\tif ((word0(&rv) & Bndry_mask1) == Bndry_mask1\n\t\t\t\t &&  word1(&rv) == (\n#ifdef Avoid_Underflow\n\t\t\t(bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)\n\t\t? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :\n#endif\n\t\t\t\t\t\t   0xffffffff)) {\n\t\t\t\t\t/*boundary case -- increment exponent*/\n\t\t\t\t\tif (word0(&rv) == Big0 && word1(&rv) == Big1)\n\t\t\t\t\t\tgoto ovfl;\n\t\t\t\t\tword0(&rv) = (word0(&rv) & Exp_mask)\n\t\t\t\t\t\t+ Exp_msk1\n#ifdef IBM\n\t\t\t\t\t\t| Exp_msk1 >> 4\n#endif\n\t\t\t\t\t\t;\n\t\t\t\t\tword1(&rv) = 0;\n#ifdef Avoid_Underflow\n\t\t\t\t\tbc.dsign = 0;\n#endif\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\telse if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {\n drop_down:\n\t\t\t\t/* boundary case -- decrement exponent */\n#ifdef Sudden_Underflow /*{{*/\n\t\t\t\tL = word0(&rv) & Exp_mask;\n#ifdef IBM\n\t\t\t\tif (L <  Exp_msk1)\n#else\n#ifdef Avoid_Underflow\n\t\t\t\tif (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1))\n#else\n\t\t\t\tif (L <= Exp_msk1)\n#endif /*Avoid_Underflow*/\n#endif /*IBM*/\n\t\t\t\t\t{\n\t\t\t\t\tif (bc.nd >nd) {\n\t\t\t\t\t\tbc.uflchk = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\tgoto undfl;\n\t\t\t\t\t}\n\t\t\t\tL -= Exp_msk1;\n#else /*Sudden_Underflow}{*/\n#ifdef Avoid_Underflow\n\t\t\t\tif (bc.scale) {\n\t\t\t\t\tL = word0(&rv) & Exp_mask;\n\t\t\t\t\tif (L <= (2*P+1)*Exp_msk1) {\n\t\t\t\t\t\tif (L > (P+2)*Exp_msk1)\n\t\t\t\t\t\t\t/* round even ==> */\n\t\t\t\t\t\t\t/* accept rv */\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t/* rv = smallest denormal */\n\t\t\t\t\t\tif (bc.nd >nd) {\n\t\t\t\t\t\t\tbc.uflchk = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto undfl;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n#endif /*Avoid_Underflow*/\n\t\t\t\tL = (word0(&rv) & Exp_mask) - Exp_msk1;\n#endif /*Sudden_Underflow}}*/\n\t\t\t\tword0(&rv) = L | Bndry_mask1;\n\t\t\t\tword1(&rv) = 0xffffffff;\n#ifdef IBM\n\t\t\t\tgoto cont;\n#else\n#ifndef NO_STRTOD_BIGCOMP\n\t\t\t\tif (bc.nd > nd)\n\t\t\t\t\tgoto cont;\n#endif\n\t\t\t\tbreak;\n#endif\n\t\t\t\t}\n#ifndef ROUND_BIASED\n#ifdef Avoid_Underflow\n\t\t\tif (Lsb1) {\n\t\t\t\tif (!(word0(&rv) & Lsb1))\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\telse if (!(word1(&rv) & Lsb))\n\t\t\t\tbreak;\n#else\n\t\t\tif (!(word1(&rv) & LSB))\n\t\t\t\tbreak;\n#endif\n#endif\n\t\t\tif (bc.dsign)\n#ifdef Avoid_Underflow\n\t\t\t\tdval(&rv) += sulp(&rv, &bc);\n#else\n\t\t\t\tdval(&rv) += ulp(&rv);\n#endif\n#ifndef ROUND_BIASED\n\t\t\telse {\n#ifdef Avoid_Underflow\n\t\t\t\tdval(&rv) -= sulp(&rv, &bc);\n#else\n\t\t\t\tdval(&rv) -= ulp(&rv);\n#endif\n#ifndef Sudden_Underflow\n\t\t\t\tif (!dval(&rv)) {\n\t\t\t\t\tif (bc.nd >nd) {\n\t\t\t\t\t\tbc.uflchk = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\tgoto undfl;\n\t\t\t\t\t}\n#endif\n\t\t\t\t}\n#ifdef Avoid_Underflow\n\t\t\tbc.dsign = 1 - bc.dsign;\n#endif\n#endif\n\t\t\tbreak;\n\t\t\t}\n\t\tif ((aadj = ratio(delta, bs)) <= 2.) {\n\t\t\tif (bc.dsign)\n\t\t\t\taadj = aadj1 = 1.;\n\t\t\telse if (word1(&rv) || word0(&rv) & Bndry_mask) {\n#ifndef Sudden_Underflow\n\t\t\t\tif (word1(&rv) == Tiny1 && !word0(&rv)) {\n\t\t\t\t\tif (bc.nd >nd) {\n\t\t\t\t\t\tbc.uflchk = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\tgoto undfl;\n\t\t\t\t\t}\n#endif\n\t\t\t\taadj = 1.;\n\t\t\t\taadj1 = -1.;\n\t\t\t\t}\n\t\t\telse {\n\t\t\t\t/* special case -- power of FLT_RADIX to be */\n\t\t\t\t/* rounded down... */\n\n\t\t\t\tif (aadj < 2./FLT_RADIX)\n\t\t\t\t\taadj = 1./FLT_RADIX;\n\t\t\t\telse\n\t\t\t\t\taadj *= 0.5;\n\t\t\t\taadj1 = -aadj;\n\t\t\t\t}\n\t\t\t}\n\t\telse {\n\t\t\taadj *= 0.5;\n\t\t\taadj1 = bc.dsign ? aadj : -aadj;\n#ifdef Check_FLT_ROUNDS\n\t\t\tswitch(bc.rounding) {\n\t\t\t\tcase 2: /* towards +infinity */\n\t\t\t\t\taadj1 -= 0.5;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 0: /* towards 0 */\n\t\t\t\tcase 3: /* towards -infinity */\n\t\t\t\t\taadj1 += 0.5;\n\t\t\t\t}\n#else\n\t\t\tif (Flt_Rounds == 0)\n\t\t\t\taadj1 += 0.5;\n#endif /*Check_FLT_ROUNDS*/\n\t\t\t}\n\t\ty = word0(&rv) & Exp_mask;\n\n\t\t/* Check for overflow */\n\n\t\tif (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {\n\t\t\tdval(&rv0) = dval(&rv);\n\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\tdval(&rv) += adj.d;\n\t\t\tif ((word0(&rv) & Exp_mask) >=\n\t\t\t\t\tExp_msk1*(DBL_MAX_EXP+Bias-P)) {\n\t\t\t\tif (word0(&rv0) == Big0 && word1(&rv0) == Big1)\n\t\t\t\t\tgoto ovfl;\n\t\t\t\tword0(&rv) = Big0;\n\t\t\t\tword1(&rv) = Big1;\n\t\t\t\tgoto cont;\n\t\t\t\t}\n\t\t\telse\n\t\t\t\tword0(&rv) += P*Exp_msk1;\n\t\t\t}\n\t\telse {\n#ifdef Avoid_Underflow\n\t\t\tif (bc.scale && y <= 2*P*Exp_msk1) {\n\t\t\t\tif (aadj <= 0x7fffffff) {\n\t\t\t\t\tif ((z = aadj) <= 0)\n\t\t\t\t\t\tz = 1;\n\t\t\t\t\taadj = z;\n\t\t\t\t\taadj1 = bc.dsign ? aadj : -aadj;\n\t\t\t\t\t}\n\t\t\t\tdval(&aadj2) = aadj1;\n\t\t\t\tword0(&aadj2) += (2*P+1)*Exp_msk1 - y;\n\t\t\t\taadj1 = dval(&aadj2);\n\t\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\t\tdval(&rv) += adj.d;\n\t\t\t\tif (rv.d == 0.)\n#ifdef NO_STRTOD_BIGCOMP\n\t\t\t\t\tgoto undfl;\n#else\n\t\t\t\t\t{\n\t\t\t\t\tif (bc.nd > nd)\n\t\t\t\t\t\tbc.dsign = 1;\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n#endif\n\t\t\t\t}\n\t\t\telse {\n\t\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\t\tdval(&rv) += adj.d;\n\t\t\t\t}\n#else\n#ifdef Sudden_Underflow\n\t\t\tif ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {\n\t\t\t\tdval(&rv0) = dval(&rv);\n\t\t\t\tword0(&rv) += P*Exp_msk1;\n\t\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\t\tdval(&rv) += adj.d;\n#ifdef IBM\n\t\t\t\tif ((word0(&rv) & Exp_mask) <  P*Exp_msk1)\n#else\n\t\t\t\tif ((word0(&rv) & Exp_mask) <= P*Exp_msk1)\n#endif\n\t\t\t\t\t{\n\t\t\t\t\tif (word0(&rv0) == Tiny0\n\t\t\t\t\t && word1(&rv0) == Tiny1) {\n\t\t\t\t\t\tif (bc.nd >nd) {\n\t\t\t\t\t\t\tbc.uflchk = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\tgoto undfl;\n\t\t\t\t\t\t}\n\t\t\t\t\tword0(&rv) = Tiny0;\n\t\t\t\t\tword1(&rv) = Tiny1;\n\t\t\t\t\tgoto cont;\n\t\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tword0(&rv) -= P*Exp_msk1;\n\t\t\t\t}\n\t\t\telse {\n\t\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\t\tdval(&rv) += adj.d;\n\t\t\t\t}\n#else /*Sudden_Underflow*/\n\t\t\t/* Compute adj so that the IEEE rounding rules will\n\t\t\t * correctly round rv + adj in some half-way cases.\n\t\t\t * If rv * ulp(rv) is denormalized (i.e.,\n\t\t\t * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid\n\t\t\t * trouble from bits lost to denormalization;\n\t\t\t * example: 1.2e-307 .\n\t\t\t */\n\t\t\tif (y <= (P-1)*Exp_msk1 && aadj > 1.) {\n\t\t\t\taadj1 = (double)(int)(aadj + 0.5);\n\t\t\t\tif (!bc.dsign)\n\t\t\t\t\taadj1 = -aadj1;\n\t\t\t\t}\n\t\t\tadj.d = aadj1 * ulp(&rv);\n\t\t\tdval(&rv) += adj.d;\n#endif /*Sudden_Underflow*/\n#endif /*Avoid_Underflow*/\n\t\t\t}\n\t\tz = word0(&rv) & Exp_mask;\n#ifndef SET_INEXACT\n\t\tif (bc.nd == nd) {\n#ifdef Avoid_Underflow\n\t\tif (!bc.scale)\n#endif\n\t\tif (y == z) {\n\t\t\t/* Can we stop now? */\n\t\t\tL = (Long)aadj;\n\t\t\taadj -= L;\n\t\t\t/* The tolerances below are conservative. */\n\t\t\tif (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) {\n\t\t\t\tif (aadj < .4999999 || aadj > .5000001)\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\telse if (aadj < .4999999/FLT_RADIX)\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n#endif\n cont:\n\t\tBfree(bb);\n\t\tBfree(bd);\n\t\tBfree(bs);\n\t\tBfree(delta);\n\t\t}\n\tBfree(bb);\n\tBfree(bd);\n\tBfree(bs);\n\tBfree(bd0);\n\tBfree(delta);\n#ifndef NO_STRTOD_BIGCOMP\n\tif (req_bigcomp) {\n\t\tbd0 = 0;\n\t\tbc.e0 += nz1;\n\t\tbigcomp(&rv, s0, &bc);\n\t\ty = word0(&rv) & Exp_mask;\n\t\tif (y == Exp_mask)\n\t\t\tgoto ovfl;\n\t\tif (y == 0 && rv.d == 0.)\n\t\t\tgoto undfl;\n\t\t}\n#endif\n#ifdef SET_INEXACT\n\tif (bc.inexact) {\n\t\tif (!oldinexact) {\n\t\t\tword0(&rv0) = Exp_1 + (70 << Exp_shift);\n\t\t\tword1(&rv0) = 0;\n\t\t\tdval(&rv0) += 1.;\n\t\t\t}\n\t\t}\n\telse if (!oldinexact)\n\t\tclear_inexact();\n#endif\n#ifdef Avoid_Underflow\n\tif (bc.scale) {\n\t\tword0(&rv0) = Exp_1 - 2*P*Exp_msk1;\n\t\tword1(&rv0) = 0;\n\t\tdval(&rv) *= dval(&rv0);\n#ifndef NO_ERRNO\n\t\t/* try to avoid the bug of testing an 8087 register value */\n#ifdef IEEE_Arith\n\t\tif (!(word0(&rv) & Exp_mask))\n#else\n\t\tif (word0(&rv) == 0 && word1(&rv) == 0)\n#endif\n\t\t\terrno = ERANGE;\n#endif\n\t\t}\n#endif /* Avoid_Underflow */\n#ifdef SET_INEXACT\n\tif (bc.inexact && !(word0(&rv) & Exp_mask)) {\n\t\t/* set underflow bit */\n\t\tdval(&rv0) = 1e-300;\n\t\tdval(&rv0) *= dval(&rv0);\n\t\t}\n#endif\n ret:\n\tif (se)\n\t\t*se = (char *)s;\n\treturn sign ? -dval(&rv) : dval(&rv);\n\t}\n\n#ifndef MULTIPLE_THREADS\n static char *dtoa_result;\n#endif\n\n static char *\n#ifdef KR_headers\nrv_alloc(i) int i;\n#else\nrv_alloc(int i)\n#endif\n{\n\tint j, k, *r;\n\n\tj = sizeof(ULong);\n\tfor(k = 0;\n\t\tsizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;\n\t\tj <<= 1)\n\t\t\tk++;\n\tr = (int*)Balloc(k);\n\t*r = k;\n\treturn\n#ifndef MULTIPLE_THREADS\n\tdtoa_result =\n#endif\n\t\t(char *)(r+1);\n\t}\n\n static char *\n#ifdef KR_headers\nnrv_alloc(s, rve, n) char *s, **rve; int n;\n#else\nnrv_alloc(const char *s, char **rve, int n)\n#endif\n{\n\tchar *rv, *t;\n\n\tt = rv = rv_alloc(n);\n\twhile((*t = *s++)) t++;\n\tif (rve)\n\t\t*rve = t;\n\treturn rv;\n\t}\n\n/* freedtoa(s) must be used to free values s returned by dtoa\n * when MULTIPLE_THREADS is #defined.  It should be used in all cases,\n * but for consistency with earlier versions of dtoa, it is optional\n * when MULTIPLE_THREADS is not defined.\n */\n\n void\n#ifdef KR_headers\nfreedtoa(s) char *s;\n#else\nfreedtoa(char *s)\n#endif\n{\n\tBigint *b = (Bigint *)((int *)s - 1);\n\tb->maxwds = 1 << (b->k = *(int*)b);\n\tBfree(b);\n#ifndef MULTIPLE_THREADS\n\tif (s == dtoa_result)\n\t\tdtoa_result = 0;\n#endif\n\t}\n\n/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.\n *\n * Inspired by \"How to Print Floating-Point Numbers Accurately\" by\n * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].\n *\n * Modifications:\n *\t1. Rather than iterating, we use a simple numeric overestimate\n *\t   to determine k = floor(log10(d)).  We scale relevant\n *\t   quantities using O(log2(k)) rather than O(k) multiplications.\n *\t2. For some modes > 2 (corresponding to ecvt and fcvt), we don't\n *\t   try to generate digits strictly left to right.  Instead, we\n *\t   compute with fewer bits and propagate the carry if necessary\n *\t   when rounding the final digit up.  This is often faster.\n *\t3. Under the assumption that input will be rounded nearest,\n *\t   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.\n *\t   That is, we allow equality in stopping tests when the\n *\t   round-nearest rule will give the same floating-point value\n *\t   as would satisfaction of the stopping test with strict\n *\t   inequality.\n *\t4. We remove common factors of powers of 2 from relevant\n *\t   quantities.\n *\t5. When converting floating-point integers less than 1e16,\n *\t   we use floating-point arithmetic rather than resorting\n *\t   to multiple-precision integers.\n *\t6. When asked to produce fewer than 15 digits, we first try\n *\t   to get by with floating-point arithmetic; we resort to\n *\t   multiple-precision integer arithmetic only if we cannot\n *\t   guarantee that the floating-point calculation has given\n *\t   the correctly rounded result.  For k requested digits and\n *\t   \"uniformly\" distributed input, the probability is\n *\t   something like 10^(k-15) that we must resort to the Long\n *\t   calculation.\n */\n\n char *\ndtoa\n#ifdef KR_headers\n\t(dd, mode, ndigits, decpt, sign, rve)\n\tdouble dd; int mode, ndigits, *decpt, *sign; char **rve;\n#else\n\t(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)\n#endif\n{\n /*\tArguments ndigits, decpt, sign are similar to those\n\tof ecvt and fcvt; trailing zeros are suppressed from\n\tthe returned string.  If not null, *rve is set to point\n\tto the end of the return value.  If d is +-Infinity or NaN,\n\tthen *decpt is set to 9999.\n\n\tmode:\n\t\t0 ==> shortest string that yields d when read in\n\t\t\tand rounded to nearest.\n\t\t1 ==> like 0, but with Steele & White stopping rule;\n\t\t\te.g. with IEEE P754 arithmetic , mode 0 gives\n\t\t\t1e23 whereas mode 1 gives 9.999999999999999e22.\n\t\t2 ==> max(1,ndigits) significant digits.  This gives a\n\t\t\treturn value similar to that of ecvt, except\n\t\t\tthat trailing zeros are suppressed.\n\t\t3 ==> through ndigits past the decimal point.  This\n\t\t\tgives a return value similar to that from fcvt,\n\t\t\texcept that trailing zeros are suppressed, and\n\t\t\tndigits can be negative.\n\t\t4,5 ==> similar to 2 and 3, respectively, but (in\n\t\t\tround-nearest mode) with the tests of mode 0 to\n\t\t\tpossibly return a shorter string that rounds to d.\n\t\t\tWith IEEE arithmetic and compilation with\n\t\t\t-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same\n\t\t\tas modes 2 and 3 when FLT_ROUNDS != 1.\n\t\t6-9 ==> Debugging modes similar to mode - 4:  don't try\n\t\t\tfast floating-point estimate (if applicable).\n\n\t\tValues of mode other than 0-9 are treated as mode 0.\n\n\t\tSufficient space is allocated to the return value\n\t\tto hold the suppressed trailing zeros.\n\t*/\n\n\tint bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,\n\t\tj, j1, k, k0, k_check, leftright, m2, m5, s2, s5,\n\t\tspec_case, try_quick;\n\tLong L;\n#ifndef Sudden_Underflow\n\tint denorm;\n\tULong x;\n#endif\n\tBigint *b, *b1, *delta, *mlo, *mhi, *S;\n\tU d2, eps, u;\n\tdouble ds;\n\tchar *s, *s0;\n#ifndef No_leftright\n#ifdef IEEE_Arith\n\tU eps1;\n#endif\n#endif\n#ifdef SET_INEXACT\n\tint inexact, oldinexact;\n#endif\n#ifdef Honor_FLT_ROUNDS /*{*/\n\tint Rounding;\n#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */\n\tRounding = Flt_Rounds;\n#else /*}{*/\n\tRounding = 1;\n\tswitch(fegetround()) {\n\t  case FE_TOWARDZERO:\tRounding = 0; break;\n\t  case FE_UPWARD:\tRounding = 2; break;\n\t  case FE_DOWNWARD:\tRounding = 3;\n\t  }\n#endif /*}}*/\n#endif /*}*/\n\n#ifndef MULTIPLE_THREADS\n\tif (dtoa_result) {\n\t\tfreedtoa(dtoa_result);\n\t\tdtoa_result = 0;\n\t\t}\n#endif\n\n\tu.d = dd;\n\tif (word0(&u) & Sign_bit) {\n\t\t/* set sign for everything, including 0's and NaNs */\n\t\t*sign = 1;\n\t\tword0(&u) &= ~Sign_bit;\t/* clear sign bit */\n\t\t}\n\telse\n\t\t*sign = 0;\n\n#if defined(IEEE_Arith) + defined(VAX)\n#ifdef IEEE_Arith\n\tif ((word0(&u) & Exp_mask) == Exp_mask)\n#else\n\tif (word0(&u)  == 0x8000)\n#endif\n\t\t{\n\t\t/* Infinity or NaN */\n\t\t*decpt = 9999;\n#ifdef IEEE_Arith\n\t\tif (!word1(&u) && !(word0(&u) & 0xfffff))\n\t\t\treturn nrv_alloc(\"Infinity\", rve, 8);\n#endif\n\t\treturn nrv_alloc(\"NaN\", rve, 3);\n\t\t}\n#endif\n#ifdef IBM\n\tdval(&u) += 0; /* normalize */\n#endif\n\tif (!dval(&u)) {\n\t\t*decpt = 1;\n\t\treturn nrv_alloc(\"0\", rve, 1);\n\t\t}\n\n#ifdef SET_INEXACT\n\ttry_quick = oldinexact = get_inexact();\n\tinexact = 1;\n#endif\n#ifdef Honor_FLT_ROUNDS\n\tif (Rounding >= 2) {\n\t\tif (*sign)\n\t\t\tRounding = Rounding == 2 ? 0 : 2;\n\t\telse\n\t\t\tif (Rounding != 2)\n\t\t\t\tRounding = 0;\n\t\t}\n#endif\n\n\tb = d2b(&u, &be, &bbits);\n#ifdef Sudden_Underflow\n\ti = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));\n#else\n\tif ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {\n#endif\n\t\tdval(&d2) = dval(&u);\n\t\tword0(&d2) &= Frac_mask1;\n\t\tword0(&d2) |= Exp_11;\n#ifdef IBM\n\t\tif (j = 11 - hi0bits(word0(&d2) & Frac_mask))\n\t\t\tdval(&d2) /= 1 << j;\n#endif\n\n\t\t/* log(x)\t~=~ log(1.5) + (x-1.5)/1.5\n\t\t * log10(x)\t =  log(x) / log(10)\n\t\t *\t\t~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))\n\t\t * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)\n\t\t *\n\t\t * This suggests computing an approximation k to log10(d) by\n\t\t *\n\t\t * k = (i - Bias)*0.301029995663981\n\t\t *\t+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );\n\t\t *\n\t\t * We want k to be too large rather than too small.\n\t\t * The error in the first-order Taylor series approximation\n\t\t * is in our favor, so we just round up the constant enough\n\t\t * to compensate for any error in the multiplication of\n\t\t * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,\n\t\t * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,\n\t\t * adding 1e-13 to the constant term more than suffices.\n\t\t * Hence we adjust the constant term to 0.1760912590558.\n\t\t * (We could get a more accurate k by invoking log10,\n\t\t *  but this is probably not worthwhile.)\n\t\t */\n\n\t\ti -= Bias;\n#ifdef IBM\n\t\ti <<= 2;\n\t\ti += j;\n#endif\n#ifndef Sudden_Underflow\n\t\tdenorm = 0;\n\t\t}\n\telse {\n\t\t/* d is denormalized */\n\n\t\ti = bbits + be + (Bias + (P-1) - 1);\n\t\tx = i > 32  ? word0(&u) << (64 - i) | word1(&u) >> (i - 32)\n\t\t\t    : word1(&u) << (32 - i);\n\t\tdval(&d2) = x;\n\t\tword0(&d2) -= 31*Exp_msk1; /* adjust exponent */\n\t\ti -= (Bias + (P-1) - 1) + 1;\n\t\tdenorm = 1;\n\t\t}\n#endif\n\tds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;\n\tk = (int)ds;\n\tif (ds < 0. && ds != k)\n\t\tk--;\t/* want k = floor(ds) */\n\tk_check = 1;\n\tif (k >= 0 && k <= Ten_pmax) {\n\t\tif (dval(&u) < tens[k])\n\t\t\tk--;\n\t\tk_check = 0;\n\t\t}\n\tj = bbits - i - 1;\n\tif (j >= 0) {\n\t\tb2 = 0;\n\t\ts2 = j;\n\t\t}\n\telse {\n\t\tb2 = -j;\n\t\ts2 = 0;\n\t\t}\n\tif (k >= 0) {\n\t\tb5 = 0;\n\t\ts5 = k;\n\t\ts2 += k;\n\t\t}\n\telse {\n\t\tb2 -= k;\n\t\tb5 = -k;\n\t\ts5 = 0;\n\t\t}\n\tif (mode < 0 || mode > 9)\n\t\tmode = 0;\n\n#ifndef SET_INEXACT\n#ifdef Check_FLT_ROUNDS\n\ttry_quick = Rounding == 1;\n#else\n\ttry_quick = 1;\n#endif\n#endif /*SET_INEXACT*/\n\n\tif (mode > 5) {\n\t\tmode -= 4;\n\t\ttry_quick = 0;\n\t\t}\n\tleftright = 1;\n\tilim = ilim1 = -1;\t/* Values for cases 0 and 1; done here to */\n\t\t\t\t/* silence erroneous \"gcc -Wall\" warning. */\n\tswitch(mode) {\n\t\tcase 0:\n\t\tcase 1:\n\t\t\ti = 18;\n\t\t\tndigits = 0;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tleftright = 0;\n\t\t\t/* no break */\n\t\tcase 4:\n\t\t\tif (ndigits <= 0)\n\t\t\t\tndigits = 1;\n\t\t\tilim = ilim1 = i = ndigits;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tleftright = 0;\n\t\t\t/* no break */\n\t\tcase 5:\n\t\t\ti = ndigits + k + 1;\n\t\t\tilim = i;\n\t\t\tilim1 = i - 1;\n\t\t\tif (i <= 0)\n\t\t\t\ti = 1;\n\t\t}\n\ts = s0 = rv_alloc(i);\n\n#ifdef Honor_FLT_ROUNDS\n\tif (mode > 1 && Rounding != 1)\n\t\tleftright = 0;\n#endif\n\n\tif (ilim >= 0 && ilim <= Quick_max && try_quick) {\n\n\t\t/* Try to get by with floating-point arithmetic. */\n\n\t\ti = 0;\n\t\tdval(&d2) = dval(&u);\n\t\tk0 = k;\n\t\tilim0 = ilim;\n\t\tieps = 2; /* conservative */\n\t\tif (k > 0) {\n\t\t\tds = tens[k&0xf];\n\t\t\tj = k >> 4;\n\t\t\tif (j & Bletch) {\n\t\t\t\t/* prevent overflows */\n\t\t\t\tj &= Bletch - 1;\n\t\t\t\tdval(&u) /= bigtens[n_bigtens-1];\n\t\t\t\tieps++;\n\t\t\t\t}\n\t\t\tfor(; j; j >>= 1, i++)\n\t\t\t\tif (j & 1) {\n\t\t\t\t\tieps++;\n\t\t\t\t\tds *= bigtens[i];\n\t\t\t\t\t}\n\t\t\tdval(&u) /= ds;\n\t\t\t}\n\t\telse if ((j1 = -k)) {\n\t\t\tdval(&u) *= tens[j1 & 0xf];\n\t\t\tfor(j = j1 >> 4; j; j >>= 1, i++)\n\t\t\t\tif (j & 1) {\n\t\t\t\t\tieps++;\n\t\t\t\t\tdval(&u) *= bigtens[i];\n\t\t\t\t\t}\n\t\t\t}\n\t\tif (k_check && dval(&u) < 1. && ilim > 0) {\n\t\t\tif (ilim1 <= 0)\n\t\t\t\tgoto fast_failed;\n\t\t\tilim = ilim1;\n\t\t\tk--;\n\t\t\tdval(&u) *= 10.;\n\t\t\tieps++;\n\t\t\t}\n\t\tdval(&eps) = ieps*dval(&u) + 7.;\n\t\tword0(&eps) -= (P-1)*Exp_msk1;\n\t\tif (ilim == 0) {\n\t\t\tS = mhi = 0;\n\t\t\tdval(&u) -= 5.;\n\t\t\tif (dval(&u) > dval(&eps))\n\t\t\t\tgoto one_digit;\n\t\t\tif (dval(&u) < -dval(&eps))\n\t\t\t\tgoto no_digits;\n\t\t\tgoto fast_failed;\n\t\t\t}\n#ifndef No_leftright\n\t\tif (leftright) {\n\t\t\t/* Use Steele & White method of only\n\t\t\t * generating digits needed.\n\t\t\t */\n\t\t\tdval(&eps) = 0.5/tens[ilim-1] - dval(&eps);\n#ifdef IEEE_Arith\n\t\t\tif (k0 < 0 && j1 >= 307) {\n\t\t\t\teps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */\n\t\t\t\tword0(&eps1) -= Exp_msk1 * (Bias+P-1);\n\t\t\t\tdval(&eps1) *= tens[j1 & 0xf];\n\t\t\t\tfor(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++)\n\t\t\t\t\tif (j & 1)\n\t\t\t\t\t\tdval(&eps1) *= bigtens[i];\n\t\t\t\tif (eps.d < eps1.d)\n\t\t\t\t\teps.d = eps1.d;\n\t\t\t\t}\n#endif\n\t\t\tfor(i = 0;;) {\n\t\t\t\tL = dval(&u);\n\t\t\t\tdval(&u) -= L;\n\t\t\t\t*s++ = '0' + (int)L;\n\t\t\t\tif (1. - dval(&u) < dval(&eps))\n\t\t\t\t\tgoto bump_up;\n\t\t\t\tif (dval(&u) < dval(&eps))\n\t\t\t\t\tgoto ret1;\n\t\t\t\tif (++i >= ilim)\n\t\t\t\t\tbreak;\n\t\t\t\tdval(&eps) *= 10.;\n\t\t\t\tdval(&u) *= 10.;\n\t\t\t\t}\n\t\t\t}\n\t\telse {\n#endif\n\t\t\t/* Generate ilim digits, then fix them up. */\n\t\t\tdval(&eps) *= tens[ilim-1];\n\t\t\tfor(i = 1;; i++, dval(&u) *= 10.) {\n\t\t\t\tL = (Long)(dval(&u));\n\t\t\t\tif (!(dval(&u) -= L))\n\t\t\t\t\tilim = i;\n\t\t\t\t*s++ = '0' + (int)L;\n\t\t\t\tif (i == ilim) {\n\t\t\t\t\tif (dval(&u) > 0.5 + dval(&eps))\n\t\t\t\t\t\tgoto bump_up;\n\t\t\t\t\telse if (dval(&u) < 0.5 - dval(&eps)) {\n\t\t\t\t\t\twhile(*--s == '0');\n\t\t\t\t\t\ts++;\n\t\t\t\t\t\tgoto ret1;\n\t\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n#ifndef No_leftright\n\t\t\t}\n#endif\n fast_failed:\n\t\ts = s0;\n\t\tdval(&u) = dval(&d2);\n\t\tk = k0;\n\t\tilim = ilim0;\n\t\t}\n\n\t/* Do we have a \"small\" integer? */\n\n\tif (be >= 0 && k <= Int_max) {\n\t\t/* Yes. */\n\t\tds = tens[k];\n\t\tif (ndigits < 0 && ilim <= 0) {\n\t\t\tS = mhi = 0;\n\t\t\tif (ilim < 0 || dval(&u) <= 5*ds)\n\t\t\t\tgoto no_digits;\n\t\t\tgoto one_digit;\n\t\t\t}\n\t\tfor(i = 1;; i++, dval(&u) *= 10.) {\n\t\t\tL = (Long)(dval(&u) / ds);\n\t\t\tdval(&u) -= L*ds;\n#ifdef Check_FLT_ROUNDS\n\t\t\t/* If FLT_ROUNDS == 2, L will usually be high by 1 */\n\t\t\tif (dval(&u) < 0) {\n\t\t\t\tL--;\n\t\t\t\tdval(&u) += ds;\n\t\t\t\t}\n#endif\n\t\t\t*s++ = '0' + (int)L;\n\t\t\tif (!dval(&u)) {\n#ifdef SET_INEXACT\n\t\t\t\tinexact = 0;\n#endif\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (i == ilim) {\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\tif (mode > 1)\n\t\t\t\tswitch(Rounding) {\n\t\t\t\t  case 0: goto ret1;\n\t\t\t\t  case 2: goto bump_up;\n\t\t\t\t  }\n#endif\n\t\t\t\tdval(&u) += dval(&u);\n#ifdef ROUND_BIASED\n\t\t\t\tif (dval(&u) >= ds)\n#else\n\t\t\t\tif (dval(&u) > ds || (dval(&u) == ds && L & 1))\n#endif\n\t\t\t\t\t{\n bump_up:\n\t\t\t\t\twhile(*--s == '9')\n\t\t\t\t\t\tif (s == s0) {\n\t\t\t\t\t\t\tk++;\n\t\t\t\t\t\t\t*s = '0';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t++*s++;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\tgoto ret1;\n\t\t}\n\n\tm2 = b2;\n\tm5 = b5;\n\tmhi = mlo = 0;\n\tif (leftright) {\n\t\ti =\n#ifndef Sudden_Underflow\n\t\t\tdenorm ? be + (Bias + (P-1) - 1 + 1) :\n#endif\n#ifdef IBM\n\t\t\t1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);\n#else\n\t\t\t1 + P - bbits;\n#endif\n\t\tb2 += i;\n\t\ts2 += i;\n\t\tmhi = i2b(1);\n\t\t}\n\tif (m2 > 0 && s2 > 0) {\n\t\ti = m2 < s2 ? m2 : s2;\n\t\tb2 -= i;\n\t\tm2 -= i;\n\t\ts2 -= i;\n\t\t}\n\tif (b5 > 0) {\n\t\tif (leftright) {\n\t\t\tif (m5 > 0) {\n\t\t\t\tmhi = pow5mult(mhi, m5);\n\t\t\t\tb1 = mult(mhi, b);\n\t\t\t\tBfree(b);\n\t\t\t\tb = b1;\n\t\t\t\t}\n\t\t\tif ((j = b5 - m5))\n\t\t\t\tb = pow5mult(b, j);\n\t\t\t}\n\t\telse\n\t\t\tb = pow5mult(b, b5);\n\t\t}\n\tS = i2b(1);\n\tif (s5 > 0)\n\t\tS = pow5mult(S, s5);\n\n\t/* Check for special case that d is a normalized power of 2. */\n\n\tspec_case = 0;\n\tif ((mode < 2 || leftright)\n#ifdef Honor_FLT_ROUNDS\n\t\t\t&& Rounding == 1\n#endif\n\t\t\t\t) {\n\t\tif (!word1(&u) && !(word0(&u) & Bndry_mask)\n#ifndef Sudden_Underflow\n\t\t && word0(&u) & (Exp_mask & ~Exp_msk1)\n#endif\n\t\t\t\t) {\n\t\t\t/* The special case */\n\t\t\tb2 += Log2P;\n\t\t\ts2 += Log2P;\n\t\t\tspec_case = 1;\n\t\t\t}\n\t\t}\n\n\t/* Arrange for convenient computation of quotients:\n\t * shift left if necessary so divisor has 4 leading 0 bits.\n\t *\n\t * Perhaps we should just compute leading 28 bits of S once\n\t * and for all and pass them and a shift to quorem, so it\n\t * can do shifts and ors to compute the numerator for q.\n\t */\n\ti = dshift(S, s2);\n\tb2 += i;\n\tm2 += i;\n\ts2 += i;\n\tif (b2 > 0)\n\t\tb = lshift(b, b2);\n\tif (s2 > 0)\n\t\tS = lshift(S, s2);\n\tif (k_check) {\n\t\tif (cmp(b,S) < 0) {\n\t\t\tk--;\n\t\t\tb = multadd(b, 10, 0);\t/* we botched the k estimate */\n\t\t\tif (leftright)\n\t\t\t\tmhi = multadd(mhi, 10, 0);\n\t\t\tilim = ilim1;\n\t\t\t}\n\t\t}\n\tif (ilim <= 0 && (mode == 3 || mode == 5)) {\n\t\tif (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {\n\t\t\t/* no digits, fcvt style */\n no_digits:\n\t\t\tk = -1 - ndigits;\n\t\t\tgoto ret;\n\t\t\t}\n one_digit:\n\t\t*s++ = '1';\n\t\tk++;\n\t\tgoto ret;\n\t\t}\n\tif (leftright) {\n\t\tif (m2 > 0)\n\t\t\tmhi = lshift(mhi, m2);\n\n\t\t/* Compute mlo -- check for special case\n\t\t * that d is a normalized power of 2.\n\t\t */\n\n\t\tmlo = mhi;\n\t\tif (spec_case) {\n\t\t\tmhi = Balloc(mhi->k);\n\t\t\tBcopy(mhi, mlo);\n\t\t\tmhi = lshift(mhi, Log2P);\n\t\t\t}\n\n\t\tfor(i = 1;;i++) {\n\t\t\tdig = quorem(b,S) + '0';\n\t\t\t/* Do we yet have the shortest decimal string\n\t\t\t * that will round to d?\n\t\t\t */\n\t\t\tj = cmp(b, mlo);\n\t\t\tdelta = diff(S, mhi);\n\t\t\tj1 = delta->sign ? 1 : cmp(b, delta);\n\t\t\tBfree(delta);\n#ifndef ROUND_BIASED\n\t\t\tif (j1 == 0 && mode != 1 && !(word1(&u) & 1)\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\t&& Rounding >= 1\n#endif\n\t\t\t\t\t\t\t\t   ) {\n\t\t\t\tif (dig == '9')\n\t\t\t\t\tgoto round_9_up;\n\t\t\t\tif (j > 0)\n\t\t\t\t\tdig++;\n#ifdef SET_INEXACT\n\t\t\t\telse if (!b->x[0] && b->wds <= 1)\n\t\t\t\t\tinexact = 0;\n#endif\n\t\t\t\t*s++ = dig;\n\t\t\t\tgoto ret;\n\t\t\t\t}\n#endif\n\t\t\tif (j < 0 || (j == 0 && mode != 1\n#ifndef ROUND_BIASED\n\t\t\t\t\t\t\t&& !(word1(&u) & 1)\n#endif\n\t\t\t\t\t)) {\n\t\t\t\tif (!b->x[0] && b->wds <= 1) {\n#ifdef SET_INEXACT\n\t\t\t\t\tinexact = 0;\n#endif\n\t\t\t\t\tgoto accept_dig;\n\t\t\t\t\t}\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\tif (mode > 1)\n\t\t\t\t switch(Rounding) {\n\t\t\t\t  case 0: goto accept_dig;\n\t\t\t\t  case 2: goto keep_dig;\n\t\t\t\t  }\n#endif /*Honor_FLT_ROUNDS*/\n\t\t\t\tif (j1 > 0) {\n\t\t\t\t\tb = lshift(b, 1);\n\t\t\t\t\tj1 = cmp(b, S);\n#ifdef ROUND_BIASED\n\t\t\t\t\tif (j1 >= 0 /*)*/\n#else\n\t\t\t\t\tif ((j1 > 0 || (j1 == 0 && dig & 1))\n#endif\n\t\t\t\t\t&& dig++ == '9')\n\t\t\t\t\t\tgoto round_9_up;\n\t\t\t\t\t}\n accept_dig:\n\t\t\t\t*s++ = dig;\n\t\t\t\tgoto ret;\n\t\t\t\t}\n\t\t\tif (j1 > 0) {\n#ifdef Honor_FLT_ROUNDS\n\t\t\t\tif (!Rounding)\n\t\t\t\t\tgoto accept_dig;\n#endif\n\t\t\t\tif (dig == '9') { /* possible if i == 1 */\n round_9_up:\n\t\t\t\t\t*s++ = '9';\n\t\t\t\t\tgoto roundoff;\n\t\t\t\t\t}\n\t\t\t\t*s++ = dig + 1;\n\t\t\t\tgoto ret;\n\t\t\t\t}\n#ifdef Honor_FLT_ROUNDS\n keep_dig:\n#endif\n\t\t\t*s++ = dig;\n\t\t\tif (i == ilim)\n\t\t\t\tbreak;\n\t\t\tb = multadd(b, 10, 0);\n\t\t\tif (mlo == mhi)\n\t\t\t\tmlo = mhi = multadd(mhi, 10, 0);\n\t\t\telse {\n\t\t\t\tmlo = multadd(mlo, 10, 0);\n\t\t\t\tmhi = multadd(mhi, 10, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\telse\n\t\tfor(i = 1;; i++) {\n\t\t\t*s++ = dig = quorem(b,S) + '0';\n\t\t\tif (!b->x[0] && b->wds <= 1) {\n#ifdef SET_INEXACT\n\t\t\t\tinexact = 0;\n#endif\n\t\t\t\tgoto ret;\n\t\t\t\t}\n\t\t\tif (i >= ilim)\n\t\t\t\tbreak;\n\t\t\tb = multadd(b, 10, 0);\n\t\t\t}\n\n\t/* Round off last digit */\n\n#ifdef Honor_FLT_ROUNDS\n\tswitch(Rounding) {\n\t  case 0: goto trimzeros;\n\t  case 2: goto roundoff;\n\t  }\n#endif\n\tb = lshift(b, 1);\n\tj = cmp(b, S);\n#ifdef ROUND_BIASED\n\tif (j >= 0)\n#else\n\tif (j > 0 || (j == 0 && dig & 1))\n#endif\n\t\t{\n roundoff:\n\t\twhile(*--s == '9')\n\t\t\tif (s == s0) {\n\t\t\t\tk++;\n\t\t\t\t*s++ = '1';\n\t\t\t\tgoto ret;\n\t\t\t\t}\n\t\t++*s++;\n\t\t}\n\telse {\n#ifdef Honor_FLT_ROUNDS\n trimzeros:\n#endif\n\t\twhile(*--s == '0');\n\t\ts++;\n\t\t}\n ret:\n\tBfree(S);\n\tif (mhi) {\n\t\tif (mlo && mlo != mhi)\n\t\t\tBfree(mlo);\n\t\tBfree(mhi);\n\t\t}\n ret1:\n#ifdef SET_INEXACT\n\tif (inexact) {\n\t\tif (!oldinexact) {\n\t\t\tword0(&u) = Exp_1 + (70 << Exp_shift);\n\t\t\tword1(&u) = 0;\n\t\t\tdval(&u) += 1.;\n\t\t\t}\n\t\t}\n\telse if (!oldinexact)\n\t\tclear_inexact();\n#endif\n\tBfree(b);\n\t*s = 0;\n\t*decpt = k + 1;\n\tif (rve)\n\t\t*rve = s;\n\treturn s0;\n\t}\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/dtoa_config.h",
    "content": "#ifndef _DTOA_CONFIG_H\n#define _DTOA_CONFIG_H\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n\n/* Ensure dtoa.c does not USE_LOCALE. Lua CJSON must not use locale\n * aware conversion routines. */\n#undef USE_LOCALE\n\n/* dtoa.c should not touch errno, Lua CJSON does not use it, and it\n * may not be threadsafe */\n#define NO_ERRNO\n\n#define Long    int32_t\n#define ULong   uint32_t\n#define Llong   int64_t\n#define ULLong  uint64_t\n\n#ifdef IEEE_BIG_ENDIAN\n#define IEEE_MC68k\n#else\n#define IEEE_8087\n#endif\n\n#define MALLOC(n)   xmalloc(n)\n\nstatic void *xmalloc(size_t size)\n{\n    void *p;\n\n    p = malloc(size);\n    if (!p) {\n        fprintf(stderr, \"Out of memory\");\n        abort();\n    }\n\n    return p;\n}\n\n#ifdef MULTIPLE_THREADS\n\n/* Enable locking to support multi-threaded applications */\n\n#include <pthread.h>\n\nstatic pthread_mutex_t private_dtoa_lock[2] = {\n    PTHREAD_MUTEX_INITIALIZER,\n    PTHREAD_MUTEX_INITIALIZER\n};\n\n#define ACQUIRE_DTOA_LOCK(n)    do {                                \\\n    int r = pthread_mutex_lock(&private_dtoa_lock[n]);              \\\n    if (r) {                                                        \\\n        fprintf(stderr, \"pthread_mutex_lock failed with %d\\n\", r);  \\\n        abort();                                                    \\\n    }                                                               \\\n} while (0)\n\n#define FREE_DTOA_LOCK(n)   do {                                    \\\n    int r = pthread_mutex_unlock(&private_dtoa_lock[n]);            \\\n    if (r) {                                                        \\\n        fprintf(stderr, \"pthread_mutex_unlock failed with %d\\n\", r);\\\n        abort();                                                    \\\n    }                                                               \\\n} while (0)\n\n#endif  /* MULTIPLE_THREADS */\n\n#endif  /* _DTOA_CONFIG_H */\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/fpconv.cpp",
    "content": "/* fpconv - Floating point conversion routines\n *\n * Copyright (c) 2011-2012  Mark Pulford <mark@kyne.com.au>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries\n * with locale support will break when the decimal separator is a comma.\n *\n * fpconv_* will around these issues with a translation buffer if required.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n\n#include \"fpconv.h\"\n#include \"nel/misc/string_common.h\"\n\n/* Lua CJSON assumes the locale is the same for all threads within a\n * process and doesn't change after initialisation.\n *\n * This avoids the need for per thread storage or expensive checks\n * for call. */\nstatic char locale_decimal_point = '.';\n\n/* In theory multibyte decimal_points are possible, but\n * Lua CJSON only supports UTF-8 and known locales only have\n * single byte decimal points ([.,]).\n *\n * localconv() may not be thread safe (=>crash), and nl_langinfo() is\n * not supported on some platforms. Use sprintf() instead - if the\n * locale does change, at least Lua CJSON won't crash. */\nstatic void fpconv_update_locale()\n{\n    char buf[8];\n\n    NLMISC::smprintf(buf, sizeof(buf), \"%g\", 0.5);\n    \n\n    /* Failing this test might imply the platform has a buggy dtoa\n     * implementation or wide characters */\n    if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {\n        fprintf(stderr, \"Error: wide characters found or printf() bug.\");\n        abort();\n    }\n\n    locale_decimal_point = buf[1];\n}\n\n/* Check for a valid number character: [-+0-9a-yA-Y.]\n * Eg: -0.6e+5, infinity, 0xF0.F0pF0\n *\n * Used to find the probable end of a number. It doesn't matter if\n * invalid characters are counted - strtod() will find the valid\n * number if it exists.  The risk is that slightly more memory might\n * be allocated before a parse error occurs. */\nstatic int valid_number_character(char ch)\n{\n    char lower_ch;\n\n    if ('0' <= ch && ch <= '9')\n        return 1;\n    if (ch == '-' || ch == '+' || ch == '.')\n        return 1;\n\n    /* Hex digits, exponent (e), base (p), \"infinity\",.. */\n    lower_ch = ch | 0x20;\n    if ('a' <= lower_ch && lower_ch <= 'y')\n        return 1;\n\n    return 0;\n}\n\n/* Calculate the size of the buffer required for a strtod locale\n * conversion. */\nstatic int strtod_buffer_size(const char *s)\n{\n    const char *p = s;\n\n    while (valid_number_character(*p))\n        p++;\n\n    return p - s;\n}\n\n/* Similar to strtod(), but must be passed the current locale's decimal point\n * character. Guaranteed to be called at the start of any valid number in a string */\ndouble fpconv_strtod(const char *nptr, char **endptr)\n{\n    char localbuf[FPCONV_G_FMT_BUFSIZE];\n    char *buf, *endbuf, *dp;\n    int buflen;\n    double value;\n\n    /* System strtod() is fine when decimal point is '.' */\n    if (locale_decimal_point == '.')\n        return strtod(nptr, endptr);\n\n    buflen = strtod_buffer_size(nptr);\n    if (!buflen) {\n        /* No valid characters found, standard strtod() return */\n        *endptr = (char *)nptr;\n        return 0;\n    }\n\n    /* Duplicate number into buffer */\n    if (buflen >= FPCONV_G_FMT_BUFSIZE) {\n        /* Handle unusually large numbers */\n        buf = (char*)malloc(buflen + 1);\n        if (!buf) {\n            fprintf(stderr, \"Out of memory\");\n            abort();\n        }\n    } else {\n        /* This is the common case.. */\n        buf = localbuf;\n    }\n    memcpy(buf, nptr, buflen);\n    buf[buflen] = 0;\n\n    /* Update decimal point character if found */\n    dp = strchr(buf, '.');\n    if (dp)\n        *dp = locale_decimal_point;\n\n    value = strtod(buf, &endbuf);\n    *endptr = (char *)&nptr[endbuf - buf];\n    if (buflen >= FPCONV_G_FMT_BUFSIZE)\n        free(buf);\n\n    return value;\n}\n\n/* \"fmt\" must point to a buffer of at least 6 characters */\nstatic void set_number_format(char *fmt, int precision)\n{\n    int d1, d2, i;\n\n    assert(1 <= precision && precision <= 14);\n\n    /* Create printf format (%.14g) from precision */\n    d1 = precision / 10;\n    d2 = precision % 10;\n    fmt[0] = '%';\n    fmt[1] = '.';\n    i = 2;\n    if (d1) {\n        fmt[i++] = '0' + d1;\n    }\n    fmt[i++] = '0' + d2;\n    fmt[i++] = 'g';\n    fmt[i] = 0;\n}\n\n/* Assumes there is always at least 32 characters available in the target buffer \nint fpconv_g_fmt(char *str, double num, int precision)\n{\n    char buf[FPCONV_G_FMT_BUFSIZE];\n    char fmt[6];\n    int len;\n    char *b;\n\n    set_number_format(fmt, precision);\n\n    // Pass through when decimal point character is dot.\n    if (locale_decimal_point == '.')\n        return NLMISC::smprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);\n\n    // snprintf() to a buffer then translate for other decimal point characters\n    len = NLMISC::smprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);\n\n    // Copy into target location. Translate decimal point if required\n    b = buf;\n    do {\n        *str++ = (*b == locale_decimal_point ? '.' : *b);\n    } while(*b++);\n\n    return len;\n}\n*/\n\nvoid fpconv_init()\n{\n    fpconv_update_locale();\n}\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/fpconv.h",
    "content": "/* Lua CJSON floating point conversion routines */\n\n/* Buffer required to store the largest string representation of a double.\n *\n * Longest double printed with %.14g is 21 characters long:\n * -1.7976931348623e+308 */\n# define FPCONV_G_FMT_BUFSIZE   32\n\n//#ifdef USE_INTERNAL_FPCONV\n//static void fpconv_init()\n//{\n//    /* Do nothing - not required */\n//}\n//#else\nextern void fpconv_init();\n//#endif\n\nextern int fpconv_g_fmt(char*, double, int);\nextern double fpconv_strtod(const char*, char**);\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/g_fmt.cpp",
    "content": "/****************************************************************\n *\n * The author of this software is David M. Gay.\n *\n * Copyright (c) 1991, 1996 by Lucent Technologies.\n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose without fee is hereby granted, provided that this entire notice\n * is included in all copies of any software which is or includes a copy\n * or modification of this software and in all copies of the supporting\n * documentation for such software.\n *\n * THIS SOFTWARE IS BEING PROVIDED \"AS IS\", WITHOUT ANY EXPRESS OR IMPLIED\n * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY\n * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY\n * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.\n *\n ***************************************************************/\n\n/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;\n * it suffices to declare buf\n *\tchar buf[32];\n */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n extern char *dtoa(double, int, int, int *, int *, char **);\n extern int g_fmt(char *, double, int);\n extern void freedtoa(char*);\n#ifdef __cplusplus\n\t}\n#endif\n\nint\nfpconv_g_fmt(char *b, double x, int precision)\n{\n\tregister int i, k;\n\tregister char *s;\n\tint decpt, j, sign;\n\tchar *b0, *s0, *se;\n\n\tb0 = b;\n#ifdef IGNORE_ZERO_SIGN\n\tif (!x) {\n\t\t*b++ = '0';\n\t\t*b = 0;\n\t\tgoto done;\n\t\t}\n#endif\n\ts = s0 = dtoa(x, 2, precision, &decpt, &sign, &se);\n\tif (sign)\n\t\t*b++ = '-';\n\tif (decpt == 9999) /* Infinity or Nan */ {\n\t\twhile((*b++ = *s++));\n\t\t/* \"b\" is used to calculate the return length. Decrement to exclude the\n\t\t * Null terminator from the length */\n\t\tb--;\n\t\tgoto done0;\n\t\t}\n\tif (decpt <= -4 || decpt > precision) {\n\t\t*b++ = *s++;\n\t\tif (*s) {\n\t\t\t*b++ = '.';\n\t\t\twhile((*b = *s++))\n\t\t\t\tb++;\n\t\t\t}\n\t\t*b++ = 'e';\n\t\t/* sprintf(b, \"%+.2d\", decpt - 1); */\n\t\tif (--decpt < 0) {\n\t\t\t*b++ = '-';\n\t\t\tdecpt = -decpt;\n\t\t\t}\n\t\telse\n\t\t\t*b++ = '+';\n\t\tfor(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);\n\t\tfor(;;) {\n\t\t\ti = decpt / k;\n\t\t\t*b++ = i + '0';\n\t\t\tif (--j <= 0)\n\t\t\t\tbreak;\n\t\t\tdecpt -= i*k;\n\t\t\tdecpt *= 10;\n\t\t\t}\n\t\t*b = 0;\n\t\t}\n\telse if (decpt <= 0) {\n\t\t*b++ = '0';\n\t\t*b++ = '.';\n\t\tfor(; decpt < 0; decpt++)\n\t\t\t*b++ = '0';\n\t\twhile((*b++ = *s++));\n\t\tb--;\n\t\t}\n\telse {\n\t\twhile((*b = *s++)) {\n\t\t\tb++;\n\t\t\tif (--decpt == 0 && *s)\n\t\t\t\t*b++ = '.';\n\t\t\t}\n\t\tfor(; decpt > 0; decpt--)\n\t\t\t*b++ = '0';\n\t\t*b = 0;\n\t\t}\n done0:\n\tfreedtoa(s0);\n#ifdef IGNORE_ZERO_SIGN\n done:\n#endif\n\treturn b - b0;\n\t}\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/lua_cjson.cpp",
    "content": "/* Lua CJSON - JSON support for Lua\n *\n * Copyright (c) 2010-2012  Mark Pulford <mark@kyne.com.au>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* Caveats:\n * - JSON \"null\" values are represented as lightuserdata since Lua\n *   tables cannot contain \"nil\". Compare with cjson.null.\n * - Invalid UTF-8 characters are not detected and will be passed\n *   untouched. If required, UTF-8 error checking should be done\n *   outside this library.\n * - Javascript comments are not part of the JSON spec, and are not\n *   currently supported.\n *\n * Note: Decoding is slower than encoding. Lua spends significant\n *       time (30%) managing tables when parsing JSON since it is\n *       difficult to know object/array sizes ahead of time.\n */\n\n#include <assert.h>\n#include <string.h>\n#include <math.h>\n#include <limits.h>\n#include <lua.hpp>\n\n#include \"strbuf.h\"\n#include \"fpconv.h\"\n\n#include <nel/misc/common.h>\n\n#ifndef CJSON_MODNAME\n#define CJSON_MODNAME   \"cjson\"\n#endif\n\n#ifndef CJSON_VERSION\n#define CJSON_VERSION   \"2.1devel\"\n#endif\n\n#ifdef NL_OS_WINDOWS\n     /* Workaround for Solaris platforms missing isinf() */\n    #if !defined(isinf) //&& (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF))\n    #define isinf(x) (!isnan(x) && isnan((x) - (x)))\n    #endif\n\n    #if !defined(isnan) //&& (defined(USE_INTERNAL_ISINF) || defined(MISSING_ISINF))\n    #define isnan _isnan\n    #endif\n\n#\tdefine strtoll _strtoi64\n#endif // NL_OS_WINDOWS\n\n\n#define DEFAULT_SPARSE_CONVERT 0\n#define DEFAULT_SPARSE_RATIO 2\n#define DEFAULT_SPARSE_SAFE 10\n#define DEFAULT_ENCODE_MAX_DEPTH 1000\n#define DEFAULT_DECODE_MAX_DEPTH 1000\n#define DEFAULT_ENCODE_INVALID_NUMBERS 0\n#define DEFAULT_DECODE_INVALID_NUMBERS 1\n#define DEFAULT_ENCODE_KEEP_BUFFER 1\n#define DEFAULT_ENCODE_NUMBER_PRECISION 14\n\n#ifdef DISABLE_INVALID_NUMBERS\n#undef DEFAULT_DECODE_INVALID_NUMBERS\n#define DEFAULT_DECODE_INVALID_NUMBERS 0\n#endif\n\ntypedef enum {\n    T_OBJ_BEGIN,\n    T_OBJ_END,\n    T_ARR_BEGIN,\n    T_ARR_END,\n    T_STRING,\n    T_NUMBER,\n    T_INTEGER,\n    T_BOOLEAN,\n    T_NULL,\n    T_COLON,\n    T_COMMA,\n    T_END,\n    T_WHITESPACE,\n    T_ERROR,\n    T_UNKNOWN\n} json_token_type_t;\n\nstatic const char *json_token_type_name[] = {\n    \"T_OBJ_BEGIN\",\n    \"T_OBJ_END\",\n    \"T_ARR_BEGIN\",\n    \"T_ARR_END\",\n    \"T_STRING\",\n    \"T_NUMBER\",\n    \"T_INTEGER\",\n    \"T_BOOLEAN\",\n    \"T_NULL\",\n    \"T_COLON\",\n    \"T_COMMA\",\n    \"T_END\",\n    \"T_WHITESPACE\",\n    \"T_ERROR\",\n    \"T_UNKNOWN\",\n    NULL\n};\n\ntypedef struct {\n    json_token_type_t ch2token[256];\n    char escape2char[256];  /* Decoding */\n\n    /* encode_buf is only allocated and used when\n     * encode_keep_buffer is set */\n    strbuf_t encode_buf;\n\n    int encode_sparse_convert;\n    int encode_sparse_ratio;\n    int encode_sparse_safe;\n    int encode_max_depth;\n    int encode_invalid_numbers;     /* 2 => Encode as \"null\" */\n    int encode_number_precision;\n    int encode_keep_buffer;\n\n    int decode_invalid_numbers;\n    int decode_max_depth;\n} json_config_t;\n\ntypedef struct {\n    const char *data;\n    const char *ptr;\n    strbuf_t *tmp;    /* Temporary storage for strings */\n    json_config_t *cfg;\n    int current_depth;\n} json_parse_t;\n\ntypedef struct {\n    json_token_type_t type;\n    int index;\n    union {\n        const char *string;\n        double number;\n        lua_Integer integer;\n        int boolean;\n    } value;\n    int string_len;\n} json_token_t;\n\nstatic const char *char2escape[256] = {\n    \"\\\\u0000\", \"\\\\u0001\", \"\\\\u0002\", \"\\\\u0003\",\n    \"\\\\u0004\", \"\\\\u0005\", \"\\\\u0006\", \"\\\\u0007\",\n    \"\\\\b\", \"\\\\t\", \"\\\\n\", \"\\\\u000b\",\n    \"\\\\f\", \"\\\\r\", \"\\\\u000e\", \"\\\\u000f\",\n    \"\\\\u0010\", \"\\\\u0011\", \"\\\\u0012\", \"\\\\u0013\",\n    \"\\\\u0014\", \"\\\\u0015\", \"\\\\u0016\", \"\\\\u0017\",\n    \"\\\\u0018\", \"\\\\u0019\", \"\\\\u001a\", \"\\\\u001b\",\n    \"\\\\u001c\", \"\\\\u001d\", \"\\\\u001e\", \"\\\\u001f\",\n    NULL, NULL, \"\\\\\\\"\", NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, \"\\\\/\",\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, \"\\\\\\\\\", NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, \"\\\\u007f\",\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n};\n\n/* ===== CONFIGURATION ===== */\n\nstatic json_config_t *json_fetch_config(lua_State *l)\n{\n    json_config_t *cfg;\n\n    cfg = (json_config_t *)lua_touserdata(l, lua_upvalueindex(1));\n    if (!cfg)\n        luaL_error(l, \"BUG: Unable to fetch CJSON configuration\");\n\n    return cfg;\n}\n\n/* Ensure the correct number of arguments have been provided.\n * Pad with nil to allow other functions to simply check arg[i]\n * to find whether an argument was provided */\nstatic json_config_t *json_arg_init(lua_State *l, int args)\n{\n    luaL_argcheck(l, lua_gettop(l) <= args, args + 1,\n                  \"found too many arguments\");\n\n    while (lua_gettop(l) < args)\n        lua_pushnil(l);\n\n    return json_fetch_config(l);\n}\n\n/* Process integer options for configuration functions */\nstatic int json_integer_option(lua_State *l, int optindex, int *setting,\n                               int min, int max)\n{\n    char errmsg[64];\n    int value;\n\n    if (!lua_isnil(l, optindex)) {\n        value = luaL_checkinteger(l, optindex);\n        NLMISC::smprintf(errmsg, sizeof(errmsg), \"expected integer between %d and %d\", min, max);\n        luaL_argcheck(l, min <= value && value <= max, 1, errmsg);\n        *setting = value;\n    }\n\n    lua_pushinteger(l, *setting);\n\n    return 1;\n}\n\n/* Process enumerated arguments for a configuration function */\nstatic int json_enum_option(lua_State *l, int optindex, int *setting,\n                            const char **options, int bool_true)\n{\n    static const char *bool_options[] = { \"off\", \"on\", NULL };\n\n    if (!options) {\n        options = bool_options;\n        bool_true = 1;\n    }\n\n    if (!lua_isnil(l, optindex)) {\n        if (bool_true && lua_isboolean(l, optindex))\n            *setting = lua_toboolean(l, optindex) * bool_true;\n        else\n            *setting = luaL_checkoption(l, optindex, NULL, options);\n    }\n\n    if (bool_true && (*setting == 0 || *setting == bool_true))\n        lua_pushboolean(l, *setting);\n    else\n        lua_pushstring(l, options[*setting]);\n\n    return 1;\n}\n\n/* Configures handling of extremely sparse arrays:\n * convert: Convert extremely sparse arrays into objects? Otherwise error.\n * ratio: 0: always allow sparse; 1: never allow sparse; >1: use ratio\n * safe: Always use an array when the max index <= safe */\nstatic int json_cfg_encode_sparse_array(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 3);\n\n    json_enum_option(l, 1, &cfg->encode_sparse_convert, NULL, 1);\n    json_integer_option(l, 2, &cfg->encode_sparse_ratio, 0, INT_MAX);\n    json_integer_option(l, 3, &cfg->encode_sparse_safe, 0, INT_MAX);\n\n    return 3;\n}\n\n/* Configures the maximum number of nested arrays/objects allowed when\n * encoding */\nstatic int json_cfg_encode_max_depth(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 1);\n\n    return json_integer_option(l, 1, &cfg->encode_max_depth, 1, INT_MAX);\n}\n\n/* Configures the maximum number of nested arrays/objects allowed when\n * encoding */\nstatic int json_cfg_decode_max_depth(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 1);\n\n    return json_integer_option(l, 1, &cfg->decode_max_depth, 1, INT_MAX);\n}\n\n/* Configures number precision when converting doubles to text */\nstatic int json_cfg_encode_number_precision(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 1);\n\n    return json_integer_option(l, 1, &cfg->encode_number_precision, 1, 14);\n}\n\n/* Configures JSON encoding buffer persistence */\nstatic int json_cfg_encode_keep_buffer(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 1);\n    int old_value;\n\n    old_value = cfg->encode_keep_buffer;\n\n    json_enum_option(l, 1, &cfg->encode_keep_buffer, NULL, 1);\n\n    /* Init / free the buffer if the setting has changed */\n    if (old_value ^ cfg->encode_keep_buffer) {\n        if (cfg->encode_keep_buffer)\n            strbuf_init(&cfg->encode_buf, 0);\n        else\n            strbuf_free(&cfg->encode_buf);\n    }\n\n    return 1;\n}\n\n#if defined(DISABLE_INVALID_NUMBERS) && !defined(USE_INTERNAL_FPCONV)\nvoid json_verify_invalid_number_setting(lua_State *l, int *setting)\n{\n    if (*setting == 1) {\n        *setting = 0;\n        luaL_error(l, \"Infinity, NaN, and/or hexadecimal numbers are not supported.\");\n    }\n}\n#else\n#define json_verify_invalid_number_setting(l, s)    do { } while(0)\n#endif\n\nstatic int json_cfg_encode_invalid_numbers(lua_State *l)\n{\n    static const char *options[] = { \"off\", \"on\", \"null\", NULL };\n    json_config_t *cfg = json_arg_init(l, 1);\n\n    json_enum_option(l, 1, &cfg->encode_invalid_numbers, options, 1);\n\n    json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);\n\n    return 1;\n}\n\nstatic int json_cfg_decode_invalid_numbers(lua_State *l)\n{\n    json_config_t *cfg = json_arg_init(l, 1);\n\n    json_enum_option(l, 1, &cfg->decode_invalid_numbers, NULL, 1);\n\n    json_verify_invalid_number_setting(l, &cfg->encode_invalid_numbers);\n\n    return 1;\n}\n\nstatic int json_destroy_config(lua_State *l)\n{\n    json_config_t *cfg;\n\n    cfg = (json_config_t *)lua_touserdata(l, 1);\n    if (cfg)\n        strbuf_free(&cfg->encode_buf);\n    cfg = NULL;\n\n    return 0;\n}\n\nstatic void json_create_config(lua_State *l)\n{\n    json_config_t *cfg;\n    int i;\n\n    cfg = (json_config_t *)lua_newuserdata(l, sizeof(*cfg));\n\n    /* Create GC method to clean up strbuf */\n    lua_newtable(l);\n    lua_pushcfunction(l, json_destroy_config);\n    lua_setfield(l, -2, \"__gc\");\n    lua_setmetatable(l, -2);\n\n    cfg->encode_sparse_convert = DEFAULT_SPARSE_CONVERT;\n    cfg->encode_sparse_ratio = DEFAULT_SPARSE_RATIO;\n    cfg->encode_sparse_safe = DEFAULT_SPARSE_SAFE;\n    cfg->encode_max_depth = DEFAULT_ENCODE_MAX_DEPTH;\n    cfg->decode_max_depth = DEFAULT_DECODE_MAX_DEPTH;\n    cfg->encode_invalid_numbers = DEFAULT_ENCODE_INVALID_NUMBERS;\n    cfg->decode_invalid_numbers = DEFAULT_DECODE_INVALID_NUMBERS;\n    cfg->encode_keep_buffer = DEFAULT_ENCODE_KEEP_BUFFER;\n    cfg->encode_number_precision = DEFAULT_ENCODE_NUMBER_PRECISION;\n\n#if DEFAULT_ENCODE_KEEP_BUFFER > 0\n    strbuf_init(&cfg->encode_buf, 0);\n#endif\n\n    /* Decoding init */\n\n    /* Tag all characters as an error */\n    for (i = 0; i < 256; i++)\n        cfg->ch2token[i] = T_ERROR;\n\n    /* Set tokens that require no further processing */\n    cfg->ch2token['{'] = T_OBJ_BEGIN;\n    cfg->ch2token['}'] = T_OBJ_END;\n    cfg->ch2token['['] = T_ARR_BEGIN;\n    cfg->ch2token[']'] = T_ARR_END;\n    cfg->ch2token[','] = T_COMMA;\n    cfg->ch2token[':'] = T_COLON;\n    cfg->ch2token['\\0'] = T_END;\n    cfg->ch2token[' '] = T_WHITESPACE;\n    cfg->ch2token['\\t'] = T_WHITESPACE;\n    cfg->ch2token['\\n'] = T_WHITESPACE;\n    cfg->ch2token['\\r'] = T_WHITESPACE;\n\n    /* Update characters that require further processing */\n    cfg->ch2token['f'] = T_UNKNOWN;     /* false? */\n    cfg->ch2token['i'] = T_UNKNOWN;     /* inf, ininity? */\n    cfg->ch2token['I'] = T_UNKNOWN;\n    cfg->ch2token['n'] = T_UNKNOWN;     /* null, nan? */\n    cfg->ch2token['N'] = T_UNKNOWN;\n    cfg->ch2token['t'] = T_UNKNOWN;     /* true? */\n    cfg->ch2token['\"'] = T_UNKNOWN;     /* string? */\n    cfg->ch2token['+'] = T_UNKNOWN;     /* number? */\n    cfg->ch2token['-'] = T_UNKNOWN;\n    for (i = 0; i < 10; i++)\n        cfg->ch2token['0' + i] = T_UNKNOWN;\n\n    /* Lookup table for parsing escape characters */\n    for (i = 0; i < 256; i++)\n        cfg->escape2char[i] = 0;          /* String error */\n    cfg->escape2char['\"'] = '\"';\n    cfg->escape2char['\\\\'] = '\\\\';\n    cfg->escape2char['/'] = '/';\n    cfg->escape2char['b'] = '\\b';\n    cfg->escape2char['t'] = '\\t';\n    cfg->escape2char['n'] = '\\n';\n    cfg->escape2char['f'] = '\\f';\n    cfg->escape2char['r'] = '\\r';\n    cfg->escape2char['u'] = 'u';          /* Unicode parsing required */\n}\n\n/* ===== ENCODING ===== */\n\nstatic void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex,\n                                  const char *reason)\n{\n    if (!cfg->encode_keep_buffer)\n        strbuf_free(json);\n    luaL_error(l, \"Cannot serialise %s: %s\",\n                  lua_typename(l, lua_type(l, lindex)), reason);\n}\n\n/* json_append_string args:\n * - lua_State\n * - JSON strbuf\n * - String (Lua stack index)\n *\n * Returns nothing. Doesn't remove string from Lua stack */\nstatic void json_append_string(lua_State *l, strbuf_t *json, int lindex)\n{\n    const char *escstr;\n    int i;\n    const char *str;\n    size_t len;\n\n    str = lua_tolstring(l, lindex, &len);\n\n    /* Worst case is len * 6 (all unicode escapes).\n     * This buffer is reused constantly for small strings\n     * If there are any excess pages, they won't be hit anyway.\n     * This gains ~5% speedup. */\n    strbuf_ensure_empty_length(json, len * 6 + 2);\n\n    strbuf_append_char_unsafe(json, '\\\"');\n    for (i = 0; i < len; i++) {\n        escstr = char2escape[(unsigned char)str[i]];\n        if (escstr)\n            strbuf_append_string(json, escstr);\n        else\n            strbuf_append_char_unsafe(json, str[i]);\n    }\n    strbuf_append_char_unsafe(json, '\\\"');\n}\n\n/* Find the size of the array on the top of the Lua stack\n * -1   object (not a pure array)\n * >=0  elements in array\n */\nstatic int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json)\n{\n    double k;\n    int max;\n    int items;\n\n    max = 0;\n    items = 0;\n\n    lua_pushnil(l);\n    /* table, startkey */\n    while (lua_next(l, -2) != 0) {\n        /* table, key, value */\n        if (lua_type(l, -2) == LUA_TNUMBER &&\n            (k = lua_tonumber(l, -2))) {\n            /* Integer >= 1 ? */\n            if (floor(k) == k && k >= 1) {\n                if (k > max)\n                    max = k;\n                items++;\n                lua_pop(l, 1);\n                continue;\n            }\n        }\n\n        /* Must not be an array (non integer key) */\n        lua_pop(l, 2);\n        return -1;\n    }\n\n    /* Encode excessively sparse arrays as objects (if enabled) */\n    if (cfg->encode_sparse_ratio > 0 &&\n        max > items * cfg->encode_sparse_ratio &&\n        max > cfg->encode_sparse_safe) {\n        if (!cfg->encode_sparse_convert)\n            json_encode_exception(l, cfg, json, -1, \"excessively sparse array\");\n\n        return -1;\n    }\n\n    return max;\n}\n\nstatic void json_check_encode_depth(lua_State *l, json_config_t *cfg,\n                                    int current_depth, strbuf_t *json)\n{\n    /* Ensure there are enough slots free to traverse a table (key,\n     * value) and push a string for a potential error message.\n     *\n     * Unlike \"decode\", the key and value are still on the stack when\n     * lua_checkstack() is called.  Hence an extra slot for luaL_error()\n     * below is required just in case the next check to lua_checkstack()\n     * fails.\n     *\n     * While this won't cause a crash due to the EXTRA_STACK reserve\n     * slots, it would still be an improper use of the API. */\n    if (current_depth <= cfg->encode_max_depth && lua_checkstack(l, 3))\n        return;\n\n    if (!cfg->encode_keep_buffer)\n        strbuf_free(json);\n\n    luaL_error(l, \"Cannot serialise, excessive nesting (%d)\",\n               current_depth);\n}\n\nstatic void json_append_data(lua_State *l, json_config_t *cfg,\n                             int current_depth, strbuf_t *json);\n\n/* json_append_array args:\n * - lua_State\n * - JSON strbuf\n * - Size of passwd Lua array (top of stack) */\nstatic void json_append_array(lua_State *l, json_config_t *cfg, int current_depth,\n                              strbuf_t *json, int array_length)\n{\n    int comma, i;\n\n    strbuf_append_char(json, '[');\n\n    comma = 0;\n    for (i = 1; i <= array_length; i++) {\n        if (comma)\n            strbuf_append_char(json, ',');\n        else\n            comma = 1;\n\n        lua_rawgeti(l, -1, i);\n        json_append_data(l, cfg, current_depth, json);\n        lua_pop(l, 1);\n    }\n\n    strbuf_append_char(json, ']');\n}\n\nstatic void json_append_number(lua_State *l, json_config_t *cfg,\n                               strbuf_t *json, int lindex)\n{\n    int len;\n#if LUA_VERSION_NUM >= 503\n    if (lua_isinteger(l, lindex)) {\n        lua_Integer num = lua_tointeger(l, lindex);\n        strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE); /* max length of int64 is 19 */\n        len = sprintf(strbuf_empty_ptr(json), LUA_INTEGER_FMT, num);\n        strbuf_extend_length(json, len);\n        return;\n    }\n#endif\n    double num = lua_tonumber(l, lindex);\n\n    if (cfg->encode_invalid_numbers == 0) {\n        /* Prevent encoding invalid numbers */\n        if (isinf(num) || isnan(num))\n            json_encode_exception(l, cfg, json, lindex,\n                                  \"must not be NaN or Infinity\");\n    } else if (cfg->encode_invalid_numbers == 1) {\n        /* Encode NaN/Infinity separately to ensure Javascript compatible\n         * values are used. */\n        if (isnan(num)) {\n            strbuf_append_mem(json, \"NaN\", 3);\n            return;\n        }\n        if (isinf(num)) {\n            if (num < 0)\n                strbuf_append_mem(json, \"-Infinity\", 9);\n            else\n                strbuf_append_mem(json, \"Infinity\", 8);\n            return;\n        }\n    } else {\n        /* Encode invalid numbers as \"null\" */\n        if (isinf(num) || isnan(num)) {\n            strbuf_append_mem(json, \"null\", 4);\n            return;\n        }\n    }\n\n    strbuf_ensure_empty_length(json, FPCONV_G_FMT_BUFSIZE);\n    len = fpconv_g_fmt(strbuf_empty_ptr(json), num, cfg->encode_number_precision);\n    strbuf_extend_length(json, len);\n}\n\nstatic void json_append_object(lua_State *l, json_config_t *cfg,\n                               int current_depth, strbuf_t *json)\n{\n    int comma, keytype;\n\n    /* Object */\n    strbuf_append_char(json, '{');\n\n    lua_pushnil(l);\n    /* table, startkey */\n    comma = 0;\n    while (lua_next(l, -2) != 0) {\n        if (comma)\n            strbuf_append_char(json, ',');\n        else\n            comma = 1;\n\n        /* table, key, value */\n        keytype = lua_type(l, -2);\n        if (keytype == LUA_TNUMBER) {\n            strbuf_append_char(json, '\"');\n            json_append_number(l, cfg, json, -2);\n            strbuf_append_mem(json, \"\\\":\", 2);\n        } else if (keytype == LUA_TSTRING) {\n            json_append_string(l, json, -2);\n            strbuf_append_char(json, ':');\n        } else {\n            json_encode_exception(l, cfg, json, -2,\n                                  \"table key must be a number or string\");\n            /* never returns */\n        }\n\n        /* table, key, value */\n        json_append_data(l, cfg, current_depth, json);\n        lua_pop(l, 1);\n        /* table, key */\n    }\n\n    strbuf_append_char(json, '}');\n}\n\n/* Serialise Lua data into JSON string. */\nstatic void json_append_data(lua_State *l, json_config_t *cfg,\n                             int current_depth, strbuf_t *json)\n{\n    int len;\n\n    switch (lua_type(l, -1)) {\n    case LUA_TSTRING:\n        json_append_string(l, json, -1);\n        break;\n    case LUA_TNUMBER:\n        json_append_number(l, cfg, json, -1);\n        break;\n    case LUA_TBOOLEAN:\n        if (lua_toboolean(l, -1))\n            strbuf_append_mem(json, \"true\", 4);\n        else\n            strbuf_append_mem(json, \"false\", 5);\n        break;\n    case LUA_TTABLE:\n        current_depth++;\n        json_check_encode_depth(l, cfg, current_depth, json);\n        len = lua_array_length(l, cfg, json);\n        if (len > 0)\n            json_append_array(l, cfg, current_depth, json, len);\n        else\n            json_append_object(l, cfg, current_depth, json);\n        break;\n    case LUA_TNIL:\n        strbuf_append_mem(json, \"null\", 4);\n        break;\n    case LUA_TLIGHTUSERDATA:\n        if (lua_touserdata(l, -1) == NULL) {\n            strbuf_append_mem(json, \"null\", 4);\n            break;\n        }\n    default:\n        /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD,\n         * and LUA_TLIGHTUSERDATA) cannot be serialised */\n        json_encode_exception(l, cfg, json, -1, \"type not supported\");\n        /* never returns */\n    }\n}\n\nstatic int json_encode(lua_State *l)\n{\n    json_config_t *cfg = json_fetch_config(l);\n    strbuf_t local_encode_buf;\n    strbuf_t *encode_buf;\n    char *json;\n    int len;\n\n    luaL_argcheck(l, lua_gettop(l) == 1, 1, \"expected 1 argument\");\n\n    if (!cfg->encode_keep_buffer) {\n        /* Use private buffer */\n        encode_buf = &local_encode_buf;\n        strbuf_init(encode_buf, 0);\n    } else {\n        /* Reuse existing buffer */\n        encode_buf = &cfg->encode_buf;\n        strbuf_reset(encode_buf);\n    }\n\n    json_append_data(l, cfg, 0, encode_buf);\n    json = strbuf_string(encode_buf, &len);\n\n    lua_pushlstring(l, json, len);\n\n    if (!cfg->encode_keep_buffer)\n        strbuf_free(encode_buf);\n\n    return 1;\n}\n\n/* ===== DECODING ===== */\n\nstatic void json_process_value(lua_State *l, json_parse_t *json,\n                               json_token_t *token);\n\nstatic int hexdigit2int(char hex)\n{\n    if ('0' <= hex  && hex <= '9')\n        return hex - '0';\n\n    /* Force lowercase */\n    hex |= 0x20;\n    if ('a' <= hex && hex <= 'f')\n        return 10 + hex - 'a';\n\n    return -1;\n}\n\nstatic int decode_hex4(const char *hex)\n{\n    int digit[4];\n    int i;\n\n    /* Convert ASCII hex digit to numeric digit\n     * Note: this returns an error for invalid hex digits, including\n     *       NULL */\n    for (i = 0; i < 4; i++) {\n        digit[i] = hexdigit2int(hex[i]);\n        if (digit[i] < 0) {\n            return -1;\n        }\n    }\n\n    return (digit[0] << 12) +\n           (digit[1] << 8) +\n           (digit[2] << 4) +\n            digit[3];\n}\n\n/* Converts a Unicode codepoint to UTF-8.\n * Returns UTF-8 string length, and up to 4 bytes in *utf8 */\nstatic int codepoint_to_utf8(char *utf8, int codepoint)\n{\n    /* 0xxxxxxx */\n    if (codepoint <= 0x7F) {\n        utf8[0] = codepoint;\n        return 1;\n    }\n\n    /* 110xxxxx 10xxxxxx */\n    if (codepoint <= 0x7FF) {\n        utf8[0] = (codepoint >> 6) | 0xC0;\n        utf8[1] = (codepoint & 0x3F) | 0x80;\n        return 2;\n    }\n\n    /* 1110xxxx 10xxxxxx 10xxxxxx */\n    if (codepoint <= 0xFFFF) {\n        utf8[0] = (codepoint >> 12) | 0xE0;\n        utf8[1] = ((codepoint >> 6) & 0x3F) | 0x80;\n        utf8[2] = (codepoint & 0x3F) | 0x80;\n        return 3;\n    }\n\n    /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */\n    if (codepoint <= 0x1FFFFF) {\n        utf8[0] = (codepoint >> 18) | 0xF0;\n        utf8[1] = ((codepoint >> 12) & 0x3F) | 0x80;\n        utf8[2] = ((codepoint >> 6) & 0x3F) | 0x80;\n        utf8[3] = (codepoint & 0x3F) | 0x80;\n        return 4;\n    }\n\n    return 0;\n}\n\n\n/* Called when index pointing to beginning of UTF-16 code escape: \\uXXXX\n * \\u is guaranteed to exist, but the remaining hex characters may be\n * missing.\n * Translate to UTF-8 and append to temporary token string.\n * Must advance index to the next character to be processed.\n * Returns: 0   success\n *          -1  error\n */\nstatic int json_append_unicode_escape(json_parse_t *json)\n{\n    char utf8[4];       /* Surrogate pairs require 4 UTF-8 bytes */\n    int codepoint;\n    int surrogate_low;\n    int len;\n    int escape_len = 6;\n\n    /* Fetch UTF-16 code unit */\n    codepoint = decode_hex4(json->ptr + 2);\n    if (codepoint < 0)\n        return -1;\n\n    /* UTF-16 surrogate pairs take the following 2 byte form:\n     *      11011 x yyyyyyyyyy\n     * When x = 0: y is the high 10 bits of the codepoint\n     *      x = 1: y is the low 10 bits of the codepoint\n     *\n     * Check for a surrogate pair (high or low) */\n    if ((codepoint & 0xF800) == 0xD800) {\n        /* Error if the 1st surrogate is not high */\n        if (codepoint & 0x400)\n            return -1;\n\n        /* Ensure the next code is a unicode escape */\n        if (*(json->ptr + escape_len) != '\\\\' ||\n            *(json->ptr + escape_len + 1) != 'u') {\n            return -1;\n        }\n\n        /* Fetch the next codepoint */\n        surrogate_low = decode_hex4(json->ptr + 2 + escape_len);\n        if (surrogate_low < 0)\n            return -1;\n\n        /* Error if the 2nd code is not a low surrogate */\n        if ((surrogate_low & 0xFC00) != 0xDC00)\n            return -1;\n\n        /* Calculate Unicode codepoint */\n        codepoint = (codepoint & 0x3FF) << 10;\n        surrogate_low &= 0x3FF;\n        codepoint = (codepoint | surrogate_low) + 0x10000;\n        escape_len = 12;\n    }\n\n    /* Convert codepoint to UTF-8 */\n    len = codepoint_to_utf8(utf8, codepoint);\n    if (!len)\n        return -1;\n\n    /* Append bytes and advance parse index */\n    strbuf_append_mem_unsafe(json->tmp, utf8, len);\n    json->ptr += escape_len;\n\n    return 0;\n}\n\nstatic void json_set_token_error(json_token_t *token, json_parse_t *json,\n                                 const char *errtype)\n{\n    token->type = T_ERROR;\n    token->index = json->ptr - json->data;\n    token->value.string = errtype;\n}\n\nstatic void json_next_string_token(json_parse_t *json, json_token_t *token)\n{\n    char *escape2char = json->cfg->escape2char;\n    char ch;\n\n    /* Caller must ensure a string is next */\n    assert(*json->ptr == '\"');\n\n    /* Skip \" */\n    json->ptr++;\n\n    /* json->tmp is the temporary strbuf used to accumulate the\n     * decoded string value.\n     * json->tmp is sized to handle JSON containing only a string value.\n     */\n    strbuf_reset(json->tmp);\n\n    while ((ch = *json->ptr) != '\"') {\n        if (!ch) {\n            /* Premature end of the string */\n            json_set_token_error(token, json, \"unexpected end of string\");\n            return;\n        }\n\n        /* Handle escapes */\n        if (ch == '\\\\') {\n            /* Fetch escape character */\n            ch = *(json->ptr + 1);\n\n            /* Translate escape code and append to tmp string */\n            ch = escape2char[(unsigned char)ch];\n            if (ch == 'u') {\n                if (json_append_unicode_escape(json) == 0)\n                    continue;\n\n                json_set_token_error(token, json,\n                                     \"invalid unicode escape code\");\n                return;\n            }\n            if (!ch) {\n                json_set_token_error(token, json, \"invalid escape code\");\n                return;\n            }\n\n            /* Skip '\\' */\n            json->ptr++;\n        }\n        /* Append normal character or translated single character\n         * Unicode escapes are handled above */\n        strbuf_append_char_unsafe(json->tmp, ch);\n        json->ptr++;\n    }\n    json->ptr++;    /* Eat final quote (\") */\n\n    strbuf_ensure_null(json->tmp);\n\n    token->type = T_STRING;\n    token->value.string = strbuf_string(json->tmp, &token->string_len);\n}\n\n/* JSON numbers should take the following form:\n *      -?(0|[1-9]|[1-9][0-9]+)(.[0-9]+)?([eE][-+]?[0-9]+)?\n *\n * json_next_number_token() uses strtod() which allows other forms:\n * - numbers starting with '+'\n * - NaN, -NaN, infinity, -infinity\n * - hexadecimal numbers\n * - numbers with leading zeros\n *\n * json_is_invalid_number() detects \"numbers\" which may pass strtod()'s\n * error checking, but should not be allowed with strict JSON.\n *\n * json_is_invalid_number() may pass numbers which cause strtod()\n * to generate an error.\n */\nstatic int json_is_invalid_number(json_parse_t *json)\n{\n    const char *p = json->ptr;\n\n    /* Reject numbers starting with + */\n    if (*p == '+')\n        return 1;\n\n    /* Skip minus sign if it exists */\n    if (*p == '-')\n        p++;\n\n    /* Reject numbers starting with 0x, or leading zeros */\n    if (*p == '0') {\n        int ch2 = *(p + 1);\n\n        if ((ch2 | 0x20) == 'x' ||          /* Hex */\n            ('0' <= ch2 && ch2 <= '9'))     /* Leading zero */\n            return 1;\n\n        return 0;\n    } else if (*p <= '9') {\n        return 0;                           /* Ordinary number */\n    }\n\n    /* Reject inf/nan */\n    if (!NLMISC::nlstricmp(p, \"inf\"))\n        return 1;\n    if (!NLMISC::nlstricmp(p, \"nan\"))\n        return 1;\n\n    /* Pass all other numbers which may still be invalid, but\n     * strtod() will catch them. */\n    return 0;\n}\n\nstatic void json_next_number_token(json_parse_t *json, json_token_t *token)\n{\n    char *endptr;\n    token->value.integer = strtoll(json->ptr, &endptr, 0);\n    if (json->ptr == endptr) {\n        json_set_token_error(token, json, \"invalid number\");\n        return;\n    }\n    if (*endptr == '.' || *endptr == 'e' || *endptr == 'E') {\n        token->type = T_NUMBER;\n        token->value.number = fpconv_strtod(json->ptr, &endptr);\n    } else {\n        token->type = T_INTEGER;\n    }\n    json->ptr = endptr;     /* Skip the processed number */\n\n    return;\n}\n\n/* Fills in the token struct.\n * T_STRING will return a pointer to the json_parse_t temporary string\n * T_ERROR will leave the json->ptr pointer at the error.\n */\nstatic void json_next_token(json_parse_t *json, json_token_t *token)\n{\n    const json_token_type_t *ch2token = json->cfg->ch2token;\n    int ch;\n\n    /* Eat whitespace. */\n    while (1) {\n        ch = (unsigned char)*(json->ptr);\n        token->type = ch2token[ch];\n        if (token->type != T_WHITESPACE)\n            break;\n        json->ptr++;\n    }\n\n    /* Store location of new token. Required when throwing errors\n     * for unexpected tokens (syntax errors). */\n    token->index = json->ptr - json->data;\n\n    /* Don't advance the pointer for an error or the end */\n    if (token->type == T_ERROR) {\n        json_set_token_error(token, json, \"invalid token\");\n        return;\n    }\n\n    if (token->type == T_END) {\n        return;\n    }\n\n    /* Found a known single character token, advance index and return */\n    if (token->type != T_UNKNOWN) {\n        json->ptr++;\n        return;\n    }\n\n    /* Process characters which triggered T_UNKNOWN\n     *\n     * Must use strncmp() to match the front of the JSON string.\n     * JSON identifier must be lowercase.\n     * When strict_numbers if disabled, either case is allowed for\n     * Infinity/NaN (since we are no longer following the spec..) */\n    if (ch == '\"') {\n        json_next_string_token(json, token);\n        return;\n    } else if (ch == '-' || ('0' <= ch && ch <= '9')) {\n        if (!json->cfg->decode_invalid_numbers && json_is_invalid_number(json)) {\n            json_set_token_error(token, json, \"invalid number\");\n            return;\n        }\n        json_next_number_token(json, token);\n        return;\n    } else if (!strncmp(json->ptr, \"true\", 4)) {\n        token->type = T_BOOLEAN;\n        token->value.boolean = 1;\n        json->ptr += 4;\n        return;\n    } else if (!strncmp(json->ptr, \"false\", 5)) {\n        token->type = T_BOOLEAN;\n        token->value.boolean = 0;\n        json->ptr += 5;\n        return;\n    } else if (!strncmp(json->ptr, \"null\", 4)) {\n        token->type = T_NULL;\n        json->ptr += 4;\n        return;\n    } else if (json->cfg->decode_invalid_numbers &&\n               json_is_invalid_number(json)) {\n        /* When decode_invalid_numbers is enabled, only attempt to process\n         * numbers we know are invalid JSON (Inf, NaN, hex)\n         * This is required to generate an appropriate token error,\n         * otherwise all bad tokens will register as \"invalid number\"\n         */\n        json_next_number_token(json, token);\n        return;\n    }\n\n    /* Token starts with t/f/n but isn't recognised above. */\n    json_set_token_error(token, json, \"invalid token\");\n}\n\n/* This function does not return.\n * DO NOT CALL WITH DYNAMIC MEMORY ALLOCATED.\n * The only supported exception is the temporary parser string\n * json->tmp struct.\n * json and token should exist on the stack somewhere.\n * luaL_error() will long_jmp and release the stack */\nstatic void json_throw_parse_error(lua_State *l, json_parse_t *json,\n                                   const char *exp, json_token_t *token)\n{\n    const char *found;\n\n    strbuf_free(json->tmp);\n\n    if (token->type == T_ERROR)\n        found = token->value.string;\n    else\n        found = json_token_type_name[token->type];\n\n    /* Note: token->index is 0 based, display starting from 1 */\n    luaL_error(l, \"Expected %s but found %s at character %d\",\n               exp, found, token->index + 1);\n}\n\nstatic inline void json_decode_ascend(json_parse_t *json)\n{\n    json->current_depth--;\n}\n\nstatic void json_decode_descend(lua_State *l, json_parse_t *json, int slots)\n{\n    json->current_depth++;\n\n    if (json->current_depth <= json->cfg->decode_max_depth &&\n        lua_checkstack(l, slots)) {\n        return;\n    }\n\n    strbuf_free(json->tmp);\n    luaL_error(l, \"Found too many nested data structures (%d) at character %d\",\n        json->current_depth, json->ptr - json->data);\n}\n\nstatic void json_parse_object_context(lua_State *l, json_parse_t *json)\n{\n    json_token_t token;\n\n    /* 3 slots required:\n     * .., table, key, value */\n    json_decode_descend(l, json, 3);\n\n    lua_newtable(l);\n\n    json_next_token(json, &token);\n\n    /* Handle empty objects */\n    if (token.type == T_OBJ_END) {\n        json_decode_ascend(json);\n        return;\n    }\n\n    while (1) {\n        if (token.type != T_STRING)\n            json_throw_parse_error(l, json, \"object key string\", &token);\n\n        /* Push key */\n        lua_pushlstring(l, token.value.string, token.string_len);\n\n        json_next_token(json, &token);\n        if (token.type != T_COLON)\n            json_throw_parse_error(l, json, \"colon\", &token);\n\n        /* Fetch value */\n        json_next_token(json, &token);\n        json_process_value(l, json, &token);\n\n        /* Set key = value */\n        lua_rawset(l, -3);\n\n        json_next_token(json, &token);\n\n        if (token.type == T_OBJ_END) {\n            json_decode_ascend(json);\n            return;\n        }\n\n        if (token.type != T_COMMA)\n            json_throw_parse_error(l, json, \"comma or object end\", &token);\n\n        json_next_token(json, &token);\n    }\n}\n\n/* Handle the array context */\nstatic void json_parse_array_context(lua_State *l, json_parse_t *json)\n{\n    json_token_t token;\n    int i;\n\n    /* 2 slots required:\n     * .., table, value */\n    json_decode_descend(l, json, 2);\n\n    lua_newtable(l);\n\n    json_next_token(json, &token);\n\n    /* Handle empty arrays */\n    if (token.type == T_ARR_END) {\n        json_decode_ascend(json);\n        return;\n    }\n\n    for (i = 1; ; i++) {\n        json_process_value(l, json, &token);\n        lua_rawseti(l, -2, i);            /* arr[i] = value */\n\n        json_next_token(json, &token);\n\n        if (token.type == T_ARR_END) {\n            json_decode_ascend(json);\n            return;\n        }\n\n        if (token.type != T_COMMA)\n            json_throw_parse_error(l, json, \"comma or array end\", &token);\n\n        json_next_token(json, &token);\n    }\n}\n\n/* Handle the \"value\" context */\nstatic void json_process_value(lua_State *l, json_parse_t *json,\n                               json_token_t *token)\n{\n    switch (token->type) {\n    case T_STRING:\n        lua_pushlstring(l, token->value.string, token->string_len);\n        break;;\n    case T_NUMBER:\n        lua_pushnumber(l, token->value.number);\n        break;;\n    case T_INTEGER:\n        lua_pushinteger(l, token->value.integer);\n        break;;\n    case T_BOOLEAN:\n        lua_pushboolean(l, token->value.boolean);\n        break;;\n    case T_OBJ_BEGIN:\n        json_parse_object_context(l, json);\n        break;;\n    case T_ARR_BEGIN:\n        json_parse_array_context(l, json);\n        break;;\n    case T_NULL:\n        /* In Lua, setting \"t[k] = nil\" will delete k from the table.\n         * Hence a NULL pointer lightuserdata object is used instead */\n        lua_pushlightuserdata(l, NULL);\n        break;;\n    default:\n        json_throw_parse_error(l, json, \"value\", token);\n    }\n}\n\nstatic int json_decode(lua_State *l)\n{\n    json_parse_t json;\n    json_token_t token;\n    size_t json_len;\n\n    luaL_argcheck(l, lua_gettop(l) == 1, 1, \"expected 1 argument\");\n\n    json.cfg = json_fetch_config(l);\n    json.data = luaL_checklstring(l, 1, &json_len);\n    json.current_depth = 0;\n    json.ptr = json.data;\n\n    /* Detect Unicode other than UTF-8 (see RFC 4627, Sec 3)\n     *\n     * CJSON can support any simple data type, hence only the first\n     * character is guaranteed to be ASCII (at worst: '\"'). This is\n     * still enough to detect whether the wrong encoding is in use. */\n    if (json_len >= 2 && (!json.data[0] || !json.data[1]))\n        luaL_error(l, \"JSON parser does not support UTF-16 or UTF-32\");\n\n    /* Ensure the temporary buffer can hold the entire string.\n     * This means we no longer need to do length checks since the decoded\n     * string must be smaller than the entire json string */\n    json.tmp = strbuf_new(json_len);\n\n    json_next_token(&json, &token);\n    json_process_value(l, &json, &token);\n\n    /* Ensure there is no more input left */\n    json_next_token(&json, &token);\n\n    if (token.type != T_END)\n        json_throw_parse_error(l, &json, \"the end\", &token);\n\n    strbuf_free(json.tmp);\n\n    return 1;\n}\n\n/* ===== INITIALISATION ===== */\n\n#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM < 502\n/* Compatibility for Lua 5.1.\n *\n * luaL_setfuncs() is used to create a module table where the functions have\n * json_config_t as their first upvalue. Code borrowed from Lua 5.2 source. */\nstatic void luaL_setfuncs (lua_State *l, const luaL_Reg *reg, int nup)\n{\n    int i;\n\n    luaL_checkstack(l, nup, \"too many upvalues\");\n    for (; reg->name != NULL; reg++) {  /* fill the table with given functions */\n        for (i = 0; i < nup; i++)  /* copy upvalues to the top */\n            lua_pushvalue(l, -nup);\n        lua_pushcclosure(l, reg->func, nup);  /* closure with those upvalues */\n        lua_setfield(l, -(nup + 2), reg->name);\n    }\n    lua_pop(l, nup);  /* remove upvalues */\n}\n#endif\n\n/* Call target function in protected mode with all supplied args.\n * Assumes target function only returns a single non-nil value.\n * Convert and return thrown errors as: nil, \"error message\" */\nstatic int json_protect_conversion(lua_State *l)\n{\n    int err;\n\n    /* Deliberately throw an error for invalid arguments */\n    luaL_argcheck(l, lua_gettop(l) == 1, 1, \"expected 1 argument\");\n\n    /* pcall() the function stored as upvalue(1) */\n    lua_pushvalue(l, lua_upvalueindex(1));\n    lua_insert(l, 1);\n    err = lua_pcall(l, 1, 1, 0);\n    if (!err)\n        return 1;\n\n    if (err == LUA_ERRRUN) {\n        lua_pushnil(l);\n        lua_insert(l, -2);\n        return 2;\n    }\n\n    /* Since we are not using a custom error handler, the only remaining\n     * errors are memory related */\n    return luaL_error(l, \"Memory allocation error in CJSON protected call\");\n}\n\n/* Return cjson module table */\nstatic int lua_cjson_new(lua_State *l)\n{\n    luaL_Reg reg[] = {\n        { \"encode\", json_encode },\n        { \"decode\", json_decode },\n        { \"encode_sparse_array\", json_cfg_encode_sparse_array },\n        { \"encode_max_depth\", json_cfg_encode_max_depth },\n        { \"decode_max_depth\", json_cfg_decode_max_depth },\n        { \"encode_number_precision\", json_cfg_encode_number_precision },\n        { \"encode_keep_buffer\", json_cfg_encode_keep_buffer },\n        { \"encode_invalid_numbers\", json_cfg_encode_invalid_numbers },\n        { \"decode_invalid_numbers\", json_cfg_decode_invalid_numbers },\n        { \"new\", lua_cjson_new },\n        { NULL, NULL }\n    };\n\n    /* Initialise number conversions */\n    fpconv_init();\n\n    /* cjson module table */\n    lua_newtable(l);\n\n    /* Register functions with config data as upvalue */\n    json_create_config(l);\n    luaL_setfuncs(l, reg, 1);\n\n    /* Set cjson.null */\n    lua_pushlightuserdata(l, NULL);\n    lua_setfield(l, -2, \"null\");\n\n    /* Set module name / version fields */\n    lua_pushliteral(l, CJSON_MODNAME);\n    lua_setfield(l, -2, \"_NAME\");\n    lua_pushliteral(l, CJSON_VERSION);\n    lua_setfield(l, -2, \"_VERSION\");\n\n    return 1;\n}\n\n/* Return cjson.safe module table */\nstatic int lua_cjson_safe_new(lua_State *l)\n{\n    const char *func[] = { \"decode\", \"encode\", NULL };\n    int i;\n\n    lua_cjson_new(l);\n\n    /* Fix new() method */\n    lua_pushcfunction(l, lua_cjson_safe_new);\n    lua_setfield(l, -2, \"new\");\n\n    for (i = 0; func[i]; i++) {\n        lua_getfield(l, -1, func[i]);\n        lua_pushcclosure(l, json_protect_conversion, 1);\n        lua_setfield(l, -2, func[i]);\n    }\n\n    return 1;\n}\n\nint luaopen_cjson(lua_State *l)\n{\n    lua_cjson_new(l);\n\n#ifdef ENABLE_CJSON_GLOBAL\n    /* Register a global \"cjson\" table. */\n    lua_pushvalue(l, -1);\n    lua_setglobal(l, CJSON_MODNAME);\n#endif\n\n    /* Return cjson table */\n    return 1;\n}\n\nint luaopen_cjson_safe(lua_State *l)\n{\n    lua_cjson_safe_new(l);\n\n    /* Return cjson.safe table */\n    return 1;\n}\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/strbuf.cpp",
    "content": "/* strbuf - String buffer routines\n *\n * Copyright (c) 2010-2012  Mark Pulford <mark@kyne.com.au>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n\n#include \"strbuf.h\"\n\nstatic void die(const char *fmt, ...)\n{\n    va_list arg;\n\n    va_start(arg, fmt);\n    vfprintf(stderr, fmt, arg);\n    va_end(arg);\n    fprintf(stderr, \"\\n\");\n\n    exit(-1);\n}\n\nvoid strbuf_init(strbuf_t *s, int len)\n{\n    int size;\n\n    if (len <= 0)\n        size = STRBUF_DEFAULT_SIZE;\n    else\n        size = len + 1;         /* \\0 terminator */\n\n    s->buf = NULL;\n    s->size = size;\n    s->length = 0;\n    s->increment = STRBUF_DEFAULT_INCREMENT;\n    s->dynamic = 0;\n    s->reallocs = 0;\n    s->debug = 0;\n\n    s->buf = (char*)malloc(size);\n    if (!s->buf)\n        die(\"Out of memory\");\n\n    strbuf_ensure_null(s);\n}\n\nstrbuf_t *strbuf_new(int len)\n{\n    strbuf_t *s;\n\n    s = (strbuf_t*)malloc(sizeof(strbuf_t));\n    if (!s)\n        die(\"Out of memory\");\n\n    strbuf_init(s, len);\n\n    /* Dynamic strbuf allocation / deallocation */\n    s->dynamic = 1;\n\n    return s;\n}\n\nvoid strbuf_set_increment(strbuf_t *s, int increment)\n{\n    /* Increment > 0:  Linear buffer growth rate\n     * Increment < -1: Exponential buffer growth rate */\n    if (increment == 0 || increment == -1)\n        die(\"BUG: Invalid string increment\");\n\n    s->increment = increment;\n}\n\nstatic inline void debug_stats(strbuf_t *s)\n{\n    if (s->debug) {\n        fprintf(stderr, \"strbuf(%lx) reallocs: %d, length: %d, size: %d\\n\",\n                (long)s, s->reallocs, s->length, s->size);\n    }\n}\n\n/* If strbuf_t has not been dynamically allocated, strbuf_free() can\n * be called any number of times strbuf_init() */\nvoid strbuf_free(strbuf_t *s)\n{\n    debug_stats(s);\n\n    if (s->buf) {\n        free(s->buf);\n        s->buf = NULL;\n    }\n    if (s->dynamic)\n        free(s);\n}\n\nchar *strbuf_free_to_string(strbuf_t *s, int *len)\n{\n    char *buf;\n\n    debug_stats(s);\n\n    strbuf_ensure_null(s);\n\n    buf = s->buf;\n    if (len)\n        *len = s->length;\n\n    if (s->dynamic)\n        free(s);\n\n    return buf;\n}\n\nstatic int calculate_new_size(strbuf_t *s, int len)\n{\n    int reqsize, newsize;\n\n    if (len <= 0)\n        die(\"BUG: Invalid strbuf length requested\");\n\n    /* Ensure there is room for optional NULL termination */\n    reqsize = len + 1;\n\n    /* If the user has requested to shrink the buffer, do it exactly */\n    if (s->size > reqsize)\n        return reqsize;\n\n    newsize = s->size;\n    if (s->increment < 0) {\n        /* Exponential sizing */\n        while (newsize < reqsize)\n            newsize *= -s->increment;\n    } else {\n        /* Linear sizing */\n        newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;\n    }\n\n    return newsize;\n}\n\n\n/* Ensure strbuf can handle a string length bytes long (ignoring NULL\n * optional termination). */\nvoid strbuf_resize(strbuf_t *s, int len)\n{\n    int newsize;\n\n    newsize = calculate_new_size(s, len);\n\n    if (s->debug > 1) {\n        fprintf(stderr, \"strbuf(%lx) resize: %d => %d\\n\",\n                (long)s, s->size, newsize);\n    }\n\n    s->size = newsize;\n    s->buf = (char*)realloc(s->buf, s->size);\n    if (!s->buf)\n        die(\"Out of memory\");\n    s->reallocs++;\n}\n\nvoid strbuf_append_string(strbuf_t *s, const char *str)\n{\n    int space, i;\n\n    space = strbuf_empty_length(s);\n\n    for (i = 0; str[i]; i++) {\n        if (space < 1) {\n            strbuf_resize(s, s->length + 1);\n            space = strbuf_empty_length(s);\n        }\n\n        s->buf[s->length] = str[i];\n        s->length++;\n        space--;\n    }\n}\n\n/* strbuf_append_fmt() should only be used when an upper bound\n * is known for the output string. */\nvoid strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)\n{\n    va_list arg;\n    int fmt_len;\n\n    strbuf_ensure_empty_length(s, len);\n\n    va_start(arg, fmt);\n    fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);\n    va_end(arg);\n\n    if (fmt_len < 0)\n        die(\"BUG: Unable to convert number\");  /* This should never happen.. */\n\n    s->length += fmt_len;\n}\n\n/* strbuf_append_fmt_retry() can be used when the there is no known\n * upper bound for the output string. */\nvoid strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)\n{\n    va_list arg;\n    int fmt_len;\n    int test;\n    int empty_len;\n\n    /* If the first attempt to append fails, resize the buffer appropriately\n     * and try again */\n    for (test = 0; ; test++) {\n        va_start(arg, fmt);\n        /* Append the new formatted string */\n        /* fmt_len is the length of the string required, excluding the\n         * trailing NULL */\n        empty_len = strbuf_empty_length(s);\n        /* Add 1 since there is also space to store the terminating NULL. */\n        fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);\n        va_end(arg);\n\n        if (fmt_len <= empty_len)\n            break;  /* SUCCESS */\n        if (test > 0)\n            die(\"BUG: length of formatted string changed\");\n\n        strbuf_resize(s, s->length + fmt_len);\n    }\n\n    s->length += fmt_len;\n}\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/cjson/strbuf.h",
    "content": "/* strbuf - String buffer routines\n *\n * Copyright (c) 2010-2012  Mark Pulford <mark@kyne.com.au>\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#include <stdlib.h>\n#include <stdarg.h>\n\n/* Size: Total bytes allocated to *buf\n * Length: String length, excluding optional NULL terminator.\n * Increment: Allocation increments when resizing the string buffer.\n * Dynamic: True if created via strbuf_new()\n */\n\ntypedef struct {\n    char *buf;\n    int size;\n    int length;\n    int increment;\n    int dynamic;\n    int reallocs;\n    int debug;\n} strbuf_t;\n\n#ifndef STRBUF_DEFAULT_SIZE\n#define STRBUF_DEFAULT_SIZE 1023\n#endif\n#ifndef STRBUF_DEFAULT_INCREMENT\n#define STRBUF_DEFAULT_INCREMENT -2\n#endif\n\n/* Initialise */\nextern strbuf_t *strbuf_new(int len);\nextern void strbuf_init(strbuf_t *s, int len);\nextern void strbuf_set_increment(strbuf_t *s, int increment);\n\n/* Release */\nextern void strbuf_free(strbuf_t *s);\nextern char *strbuf_free_to_string(strbuf_t *s, int *len);\n\n/* Management */\nextern void strbuf_resize(strbuf_t *s, int len);\nstatic int strbuf_empty_length(strbuf_t *s);\nstatic int strbuf_length(strbuf_t *s);\nstatic char *strbuf_string(strbuf_t *s, int *len);\nstatic void strbuf_ensure_empty_length(strbuf_t *s, int len);\nstatic char *strbuf_empty_ptr(strbuf_t *s);\nstatic void strbuf_extend_length(strbuf_t *s, int len);\n\n/* Update */\nextern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);\nextern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);\nstatic void strbuf_append_mem(strbuf_t *s, const char *c, int len);\nextern void strbuf_append_string(strbuf_t *s, const char *str);\nstatic void strbuf_append_char(strbuf_t *s, const char c);\nstatic void strbuf_ensure_null(strbuf_t *s);\n\n/* Reset string for before use */\nstatic inline void strbuf_reset(strbuf_t *s)\n{\n    s->length = 0;\n}\n\nstatic inline int strbuf_allocated(strbuf_t *s)\n{\n    return s->buf != NULL;\n}\n\n/* Return bytes remaining in the string buffer\n * Ensure there is space for a NULL terminator. */\nstatic inline int strbuf_empty_length(strbuf_t *s)\n{\n    return s->size - s->length - 1;\n}\n\nstatic inline void strbuf_ensure_empty_length(strbuf_t *s, int len)\n{\n    if (len > strbuf_empty_length(s))\n        strbuf_resize(s, s->length + len);\n}\n\nstatic inline char *strbuf_empty_ptr(strbuf_t *s)\n{\n    return s->buf + s->length;\n}\n\nstatic inline void strbuf_extend_length(strbuf_t *s, int len)\n{\n    s->length += len;\n}\n\nstatic inline int strbuf_length(strbuf_t *s)\n{\n    return s->length;\n}\n\nstatic inline void strbuf_append_char(strbuf_t *s, const char c)\n{\n    strbuf_ensure_empty_length(s, 1);\n    s->buf[s->length++] = c;\n}\n\nstatic inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)\n{\n    s->buf[s->length++] = c;\n}\n\nstatic inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)\n{\n    strbuf_ensure_empty_length(s, len);\n    memcpy(s->buf + s->length, c, len);\n    s->length += len;\n}\n\nstatic inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)\n{\n    memcpy(s->buf + s->length, c, len);\n    s->length += len;\n}\n\nstatic inline void strbuf_ensure_null(strbuf_t *s)\n{\n    s->buf[s->length] = 0;\n}\n\nstatic inline char *strbuf_string(strbuf_t *s, int *len)\n{\n    if (len)\n        *len = s->length;\n\n    return s->buf;\n}\n\n/* vi:ai et sw=4 ts=4:\n */\n"
  },
  {
    "path": "code/EVA/server/server_share/client_msg_desc.cpp",
    "content": "﻿#include \"client_msg_desc.h\"\n#include <nel/misc/file.h>\n#include <nel/misc/i_xml.h>\n#include <nel/net/callback_net_base.h>\n\n#include <google/protobuf/descriptor.h>  \n#include <google/protobuf/descriptor.pb.h>  \n#include <google/protobuf/dynamic_message.h>  \n#include <google/protobuf/compiler/importer.h>  \n\nusing namespace std;\nusing namespace NLMISC;\n\nvoid CMsgDesc::LoadMsgXml()\n{\n    bool res = false;\n    string path = NLMISC::CPath::lookup(\"msg.xml\");\n    CIFile file;\n\n    if (file.open (path))\n    {\n        CIXml xml;\n        if (xml.init (file))\n        {\n            xmlNodePtr rootPtr = xml.getRootNode();\n\n            if ( rootPtr != NULL )\n            {\n                xmlNodePtr proto_desc   = xml.getFirstChildNode (rootPtr, \"proto_src\");\n                std::string proto_path  = xml.getStringProperty(proto_desc, \"path\", \"\");\n\n                if ( !proto_path.empty() )\n                {\n                    m_DiskSourceTree->MapPath(\"\",proto_path);\n                }\n\n                xmlNodePtr proto_file   = xml.getFirstChildNode (proto_desc, \"file\");\n\n                for ( ; proto_file; proto_file=xml.getNextChildNode (proto_file, \"file\") )\n                {\n                    std::string proto_name  = xml.getStringProperty(proto_file, \"name\", \"\");\n                    m_Importer->Import(proto_name);\n                }\n            }\n\n            if ( rootPtr != NULL )\n            {\n                m_MsgDesc.clear();\n                xmlNodePtr record=xml.getFirstChildNode (rootPtr, \"leaf\");\n\n                for ( ; record; record=xml.getNextChildNode (record, \"leaf\") )\n                {\n                    MsgLeaf  msg_leaf;\n\n                    msg_leaf.msgname        = xml.getStringProperty(record, \"name\", \"\");\n                    msg_leaf.description    = xml.getStringProperty(record, \"description\", \"\");\n                    msg_leaf.is_log_event   = xml.getIntProperty(record, \"log_event\", 1) > 0 ? true: false;\n\n                    ///  解析转发到哪个服务器\n                    const CSString sendto   = xml.getStringProperty(record, \"sendto\", \"\");\n\n                    CVectorSString  vct_str;\n                    sendto.splitBySeparator(' ', vct_str);\n                    nlassert(vct_str.size()>0);\n\n                    for ( uint i=0; i<vct_str.size(); ++i )\n                    {\n                        msg_leaf.sendto.push_back(vct_str[i]);\n                    }\n\n                    /// 解析消息格式\n                    const CSString format = xml.getStringProperty(record, \"format\", \"\");\n\n                    vct_str.clear();\n                    format.splitBySeparator(' ', vct_str);\n\n                    for ( uint i=0; i<vct_str.size(); ++i )\n                    {\n                        MSG_FORMAT::TMsgFormat  msg_format = MSG_FORMAT::UNKNOWN;\n\n                        msg_format = MSG_FORMAT::toEnum(vct_str[i]);\n\n                        if ( msg_format==MSG_FORMAT::UNKNOWN )\n                        {\n                            const google::protobuf::Descriptor* descriptor = NULL;\n                            descriptor = m_Importer->pool()->FindMessageTypeByName(vct_str[i]);\n\n                            if (descriptor)\n                            {\n                                msg_leaf.format.push_back(MSG_FORMAT::ProtoMsg);\n                                msg_leaf.format_msg.push_back(vct_str[i]);\n                            }\n                            else\n                            {\n                                nlwarning(\"not define %s\", vct_str[i].c_str());\n                            }\n                        }\n                        else\n                        {\n                            msg_leaf.format.push_back(msg_format);\n                        }\n                    }\n\n                    ///    保存\n                    std::pair< TMsgDesc::iterator, bool > res;\n                    res = m_MsgDesc.insert( make_pair(msg_leaf.msgname, msg_leaf) );\n                    nlassert(res.second);\n                }\n                res = true;\n            }\n        }\n        file.close ();\n    }\n\n    nlassert(res);\n}\n\nMsgLeaf* CMsgDesc::GetMsgLeaf( std::string msg_name )\n{\n    MsgLeaf* pMsgLeaf = NULL;\n    TMsgDesc::iterator iter = m_MsgDesc.find(msg_name);\n\n    if ( iter != m_MsgDesc.end() )\n    {\n        pMsgLeaf = &iter->second;\n    }\n\n    return pMsgLeaf;\n}\n\nCMsgDesc::CMsgDesc()\n{\n    m_DiskSourceTree    = new google::protobuf::compiler::DiskSourceTree();\n    m_Importer          = new google::protobuf::compiler::Importer(m_DiskSourceTree, NULL);\n    m_Factory           = new google::protobuf::DynamicMessageFactory(m_Importer->pool());\n\n}\n\nCMsgDesc::~CMsgDesc()\n{\n    SAFE_DELETE(m_Factory);\n    SAFE_DELETE(m_Importer);\n    SAFE_DELETE(m_DiskSourceTree);\n}\n\ngoogle::protobuf::Message* CMsgDesc::CreateMessage( const std::string& typeName )\n{\n    google::protobuf::Message* pMsg = NULL;\n    const google::protobuf::Descriptor* pDescriptor = m_Importer->pool()->FindMessageTypeByName(typeName);\n\n    if (pDescriptor)\n    {\n        const google::protobuf::Message* pPrototype = m_Factory->GetPrototype(pDescriptor);\n\n        if (pPrototype)\n        {\n            pMsg = pPrototype->New();\n        }\n    }\n    return pMsg;\n}\n\n\n//TCallbackItem* CMsgDesc::GetTCPCallbackItem()\n//{\n//    return NULL;\n//}\n"
  },
  {
    "path": "code/EVA/server/server_share/client_msg_desc.h",
    "content": "#ifndef SERVER_SHARED_CLIENT_MSG_DESC_H\n#define SERVER_SHARED_CLIENT_MSG_DESC_H\n\n#include <nel/misc/singleton.h>\n#include <nel/misc/sstring.h>\n#include <nel/misc/i_xml.h>\n#include \"game_def.h\"\n#include \"msg_leaf.h\"\n\nnamespace google {\n    namespace protobuf {\n        class Message;\n        class DynamicMessageFactory;\n        namespace compiler {\n            class Importer;\n            class DiskSourceTree;\n        }\n    }\n}\n\nclass CMsgDesc : public NLMISC::CSingleton<CMsgDesc>\n{\npublic:\n\n    CMsgDesc();\n    ~CMsgDesc();\n\n    void LoadMsgXml();\n\n    MsgLeaf*  GetMsgLeaf( std::string msg_name );\n\n    google::protobuf::Message* CreateMessage(const std::string& typeName);\n//    TCallbackItem* GetTCPCallbackItem();\n\nprivate:\n\n    typedef std::map<std::string, MsgLeaf>  TMsgDesc;\n\n    TMsgDesc                                        m_MsgDesc;\n    google::protobuf::compiler::DiskSourceTree*     m_DiskSourceTree;\n    google::protobuf::compiler::Importer*           m_Importer;  \n    google::protobuf::DynamicMessageFactory*        m_Factory;\n};\n\n#define  MsgDesc  CMsgDesc::instance()\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/game_def.h",
    "content": "﻿#ifndef GAME_SHARD_GAME_DEF_H\n#define GAME_SHARD_GAME_DEF_H\n\n#include <nel/misc/types_nl.h>\n\nnamespace DEF {\n\n#ifndef FALSE\n#define FALSE               0\n#endif\n\n#ifndef TRUE\n#define TRUE                1\n#endif\n\ntypedef\tuint64   UID;\ntypedef\tuint32   RPC_SESSION;           ///  远程调用session\ntypedef uint64   CLIENT_SESSION;        ///  客户端身份\ntypedef uint32   TEMPLATE_ID;           ///  配置表使用的ID\ntypedef uint32   TEMPLATE_TYPE;         ///  \n\ntypedef uint32   CHECK_SUM;\ntypedef sint64   MONEY;\ntypedef uint32   EXP;\ntypedef sint64   RMB;\ntypedef uint32   ERROR_TYPE;\ntypedef uint32   SCRIPT_ID;\ntypedef uint32   EVENT_ID;\ntypedef uint32   ACK_IDX;\n\n\n#define RANDOM_SHOP_GRID_NUM        3\n#define PLAYERNAME_LENGTH           (24)                ///  玩家名字最大长度\n#define PLAYERNAME_LENGTH_MIN       (4)                 ///  玩家名字最小长度\n#define RPC_SESSION_TCP_FLAG        0x80000000          ///  rpc_session协议标识，用于区分 tcp 和 udp协议。\n#define FLOAT_RATE                  10000               ///  万分比\n#define FRIEND_FIGHT_NUM            5\n#define BAD_CHECK_SUM               DEF::CHECK_SUM(-1)\n\n#define NEW_PLAYER_FRIEND_LEVEL     5\n#define NEW_PLAYER_FIGHT_LEVEL      4\n\n#define ONE_YEAR 60*60*24*365\n#define ONE_DAY  60*60*24\n\n///   flag(1) session(24)  sid(7)\n///   flag   是tcp还是udp， 1:TCP  0:UDP\ninline bool IsTCPSession( RPC_SESSION rpc_session ) {  return rpc_session&RPC_SESSION_TCP_FLAG;  }\n\n#define PROPERTY( type , name )\\\n\tprivate:\\\n\t\ttype m_##name;\\\n\tpublic:\\\n\t\tinline void set_##name(type v){ \\\n\t\t\tm_##name = v;\\\n\t\t}\\\n\t\tinline type get_##name(){\\\n\t\t\treturn m_##name;\\\n\t\t}\\\n\n#define SAFE_DELETE( ptr ) do{ if( NULL != ptr ){ delete ptr ; ptr = NULL; } } while(0)\n#define SAFE_DELETE_ARRAY( ptr ) do{ if( NULL != ptr ){ delete[] ptr; ptr = NULL; } } while(0)\n\n#define GET_DBMSG(structname) \\\n    if( !data ) \\\n    return; \\\n    structname* db_msg = (structname*)( data ); \\\n    if( !db_msg ) \\\n    return ;\n\n#define GET_WORKER_AND_STMT(__THREAD,__DB,__STMT) \\\nnl::sql_worker* pWorker = SelectThread(__THREAD).get_worker( __DB );\\\nif ( NULL == pWorker ){  return ; }\\\nnl::sql_stmt*   pStmt = pWorker->get_stmt( __STMT );\\\nif( NULL == pStmt ){ return; }\n\n#define GET_WORKER_AND_STMT_MAIN(__THREAD,__DB,__STMT) \\\n    nl::sql_worker* pWorker = SelectThread(__THREAD).get_worker( __DB, true );\\\n    if ( NULL == pWorker ){  nlstop; }\\\n    nl::sql_stmt*   pStmt = pWorker->get_stmt( __STMT );\\\n    if( NULL == pStmt ){ nlstop; }\\\n    nl::sql_result* pResult = NULL;\n\n\n\n}\n\n#endif      //  GAME_SHARD_GAME_DEF_H\n"
  },
  {
    "path": "code/EVA/server/server_share/i18n_def.cpp",
    "content": "#include \"i18n_def.h\"\n#include \"nel/misc/string_conversion.h\"\n#include <cstdarg>\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace I18N\n{\n    NL_BEGIN_STRING_CONVERSION_TABLE (TI18N)\n        NL_STRING_CONVERSION_TABLE_ENTRY(LanguageName)\n//        NL_STRING_CONVERSION_TABLE_ENTRY(UID)\n    NL_END_STRING_CONVERSION_TABLE(TI18N, I18nConversion, UNKNOWN)\n\n    TI18N toEnum(const std::string &str)\n    {\n        return I18nConversion.fromString(str);\n    }\n\n    const std::string& toString(TI18N i18n_str)\n    {\n        return I18nConversion.toString(i18n_str);\n    }\n\n    \n    std::string\t_gstring;\n    const char* GetStr( const char* label )\n    {\n        _gstring = CI18N::get(label).toUtf8();\n        return _gstring.c_str();\n    }\n\n    #define GET_BUFFER_MAX 512\n    char _fstring[GET_BUFFER_MAX]={0};\n\n    const char* Format( const char* format_ptr, ... )\n    {\n        va_list _args;\n        va_start (_args, format_ptr);\n        int _res = vsnprintf (_fstring, GET_BUFFER_MAX-1, format_ptr, _args);\n        if (_res == -1 || _res == GET_BUFFER_MAX-1)\n        {\n            _fstring[GET_BUFFER_MAX-1] = '\\0';\n        }\n        va_end (_args);\n\n        return _fstring;\n    }\n\n}; // MSG_FORMAT\n\n"
  },
  {
    "path": "code/EVA/server/server_share/i18n_def.h",
    "content": "#ifndef SERVER_SHARED_I18N_DEF_H\n#define SERVER_SHARED_I18N_DEF_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/i18n.h\"\n\nnamespace I18N\n{\n    enum TI18N\n    {\n        LanguageName,\n        UNKNOWN\n    };\n\n    TI18N toEnum(const std::string &str);\n    const std::string& toString(TI18N i18n_str);\n\n    const char* GetStr( const char* label );\n    const char* Format( const char* format_ptr, ... );\n}; // I18N\n\n#define FORMAT_P0( __format )  I18N::GetStr(__format)\n\n#define FORMAT_P1( __format, __param )  I18N::Format( I18N::GetStr(__format)  , __param )\n\n\n\n#endif // SERVER_SHARED_I18N_DEF_H\n/* End of i18n_def.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/id_generate.cpp",
    "content": "#include \"id_generate.h\"\n#include <nel/misc/debug.h>\n#include <nel/net/service.h>\n\nCIDGenerate::CIDGenerate():m_CurrentID(0)\n{\n\n}\n\nvoid CIDGenerate::init( uint32 region_id, uint32 service_id, uint64 current_id )\n{\n    nlassert(region_id<=0x3ff);\n    nlassert(service_id<=0x3f);\n\n    if ( m_CurrentID < current_id )\n    {\n        m_CurrentID = current_id;\n    }\n    else\n    {\n        nlwarning(\"CIDGenerate::init   CurrID>InitID   (%lld)>(%lld)\", m_CurrentID, current_id);\n    }\n\n    m_BaseCode  =   region_id;\n    m_BaseCode  =   m_BaseCode << PlaceHolderService;\n    m_BaseCode  |=  service_id;\n    m_BaseCode  =   m_BaseCode << PlaceHolderIncreaseID;\n}\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( IDGenerate, CIDGenerate )\n\n    DEFINE_CLASS_FUNCTION( Generate, sint64, ())\n    {\n        r = obj->Generate();\n        return 1;\n    }\n\n    DEFINE_STATIC_FUNCTION(NewInstance, CIDGenerate*, (sint64 curr_id))\n    {\n        r = new CIDGenerate();\n\n        uint32 share_id = NLNET::IService::getInstance()->getShardId();\n        uint32 svr_id   = NLNET::IService::getInstance()->getServiceId().get();\n\n        r->init(share_id, svr_id, curr_id);\n        r->GetScriptObject().SetDelByScr(true);\n\n        return 1;\n    }\n\n    END_SCRIPT_CLASS()\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/id_generate.h",
    "content": "#ifndef SERVER_SHARED_ID_GENERATE_H\n#define SERVER_SHARED_ID_GENERATE_H\n\n#include <server_share/game_def.h>\n#include <server_share/bin_luabind/Public.hpp>\n\n/**\n *  ID  \n *    ȫGUID\n *\n *    0                   1                   2                   3\n *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9\n *   +-----------------------+---------------+---------------------------------------+\n *          region_id           service_id                  inc_id\n *           len(10)              len(6)                    len(48)\n *    \n *\n * \\author li9chuan@qq.com\n * \\date 2013\n */\n\nclass CIDGenerate\n{\n    DECLARE_SCRIPT_CLASS();\npublic:\n\n    CIDGenerate();\n\n    /**\n    *  IDɳʼ\n    *  @param region_id ϷID\n    *  @param service_id ID\n    *  @param current_id ǰѾﵽID ֻܱm_CurrentID֡\n    */\n\t///@{\n\tvoid init( uint32 region_id, uint32 service_id, uint64 current_id );\n    ///@}\n\n\tinline uint64 Generate()\n\t{\n\t\t++m_CurrentID;\n\t\treturn m_CurrentID | m_BaseCode;\n\t}\n\nprivate:\n\tuint64    m_BaseCode;\n\tuint64    m_CurrentID;\n\n    ///   10λID   6λID   48λID\n    enum TPlaceHolder\n    {\n        PlaceHolderService      = 6,\n        PlaceHolderRegion       = 10,\n        PlaceHolderIncreaseID   = 48, \n    };\n};\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_base_function.cpp",
    "content": "#include <server_share/server_def.h>\n#include <nel/misc/path.h>\n#include <nel/misc/md5.h>\n#include <string>\n#include \"lua_engine.h\"\n#include \"script_mgr.h\"\n#include <server_share/bin_luabind/Public.hpp>\n#include <server_share/lua/lua_thread.h>\n#include <zlib.h>\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace DEF;\n\nvoid forLuaBaseFunctionForceLink()\n{\n    ScriptMgr.ExecString( \"\" );\n}\n\nnamespace bin\n {\n    BEGIN_SCRIPT_MODULE(Misc)\n \n        DEFINE_MODULE_FUNCTION(GetBasePath, std::string, (void))\n        {\n            //nldebug(\"Calling func5 with (%s, %lld)\\n\", path.c_str(), a1);\n            r = NLMISC::CPath::getCurrentPath();\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(GetConfigInt, int, (std::string config_field))\n        {\n            CConfigFile::CVar *pVar = Config.getVarPtr (config_field);\n\n            if ( pVar!=NULL )\n            {\n                r = pVar->asInt();\n            }\n\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(MD5, std::string, (const char* buff, int len))\n        {\n            CHashKeyMD5 hash_key = getMD5( (const uint8*)buff, len );\n            r = hash_key.toString();\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(GetLocalTime, sint64, ())\n        {\n            r = NLMISC::CTime::getLocalTime();\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(PostMain, void, (sint32 threadHandle, CLuaMessage* pMsgIn))\n        {\n            CMessage* pMsg = new CMessage();\n            pMsg->swap(pMsgIn->m_Msg);\n\n            CLuaThread* pThread = LuaThreadMgr.GetLuaThread(threadHandle);\n\n            if (pThread != NULL)\n            {\n                pThread->PostMain(pMsg);\n            }\n\n            return 1;\n        }\n\n        //DEFINE_MODULE_FUNCTION(GetPath, string, (string& moudule_name))\n        //{\n        //    moudule_name.append(\".lua\");\n        //    string fullpath = CPath::lookup(moudule_name, false);\n\n        //    if (fullpath.size()>0)\n        //    {\n        //        r = NLMISC::CPath::getCurrentPath();\n        //        r.append(\"/\");\n        //        r.append(fullpath);\n        //    }\n        //    return 1;\n        //}\n\n        DEFINE_MODULE_FUNCTION(GetFileModificationDate, sint64, (string& script_full_path))\n        {\n            r = CFile::getFileModificationDate(script_full_path);\n            return 1;\n        }\n        \n        DEFINE_MODULE_FUNCTION(ZipCompress, std::string, (const char* buff, int len))\n        {\n            uLongf dest_len = compressBound(len);\n            r.resize(dest_len);\n\n            sint32 z_res = compress((Bytef *)&r[0], &dest_len, (Bytef *)buff, len);\n            if (z_res == Z_OK) {\n                r.resize(dest_len);\n            }\n            else {\n                r.resize(0);\n                nlwarning(\"ZipCompress Error:%d\", z_res);\n            }\n\n            return 1;\n        }\n\n    END_SCRIPT_MODULE()\n\n    BEGIN_SCRIPT_MODULE(Debug)\n\n        DEFINE_MODULE_FUNCTION(Warning, void, (const char* str, int stack_level))\n        {\n            lua_Debug ar;\n            lua_getstack(lua.GetHandle(),stack_level,&ar);\n            lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(str);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(Info, void, (const char* str, int stack_level))\n        {\n            lua_Debug ar;\n            lua_getstack(lua.GetHandle(),stack_level,&ar);\n            lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getInfoLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getInfoLog()->displayNL(str);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(Debug, void, (const char* str, int stack_level))\n        {\n            lua_Debug ar;\n            lua_getstack(lua.GetHandle(),stack_level,&ar);\n            lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getDebugLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getDebugLog()->displayNL(str);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(Stop, void, (const char* str, int stack_level))\n        {\n            lua_Debug ar;\n            lua_getstack(lua.GetHandle(),stack_level,&ar);\n            lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n            static bool ignoreNextTime = false; \n            if (!ignoreNextTime) \n            {\n                if(NLMISC::_assert_stop(ignoreNextTime, ar.currentline, ar.short_src, ar.name, NULL))\n                    NLMISC_BREAKPOINT; \n            }\n\n            return 1;\n        }\n\n    END_SCRIPT_MODULE()\n }\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_engine.cpp",
    "content": "#include \"lua_engine.h\"\n#include \"lua_param.h\"\n#include <nel/misc/displayer.h>\n#include <nel/misc/path.h>\n#include <server_share/pbc/pbc.h>\n#include \"server_share/bin_luabind/ScriptHandle.h\"\n#include \"server_share/bin_luabind/ScriptExporter.h\"\n\nextern int  luaopen_protobuf_c (lua_State* tolua_S);\nextern int  luaopen_cjson(lua_State *l);\n\n//void Lua_Trace(lua_State *L, lua_Debug *debug_msg)\n//{\n//\tchar tmp[6]={0};\n//\tchar * what = tmp;\n//\tstrcpy(what,\"nl\\0\\0\");\t\n//\tswitch(debug_msg->event)\n//\t{\n//\tcase LUA_HOOKCALL:\n//\t\twhat = strcat(what,\"uS\");\n//\t\tnlinfo(\"LUA_HOOKCALL  \");\n//\t\tbreak;\n//\tcase LUA_HOOKRET:\n//\t\twhat = strcat(what,\"u\");\n//\t\tnlinfo(\"LUA_HOOKRETURN  \");\n//\t\tbreak;\n//\tcase LUA_HOOKTAILRET:\n//\t\twhat = strcat(what,\"uS\");\n//\t\tnlinfo(\"LUA_HOOKTAILRETURN  \");\n//\t\tbreak;\n//\tcase LUA_HOOKLINE:\n//\t\twhat = strcat(what,\"uS\");\n//\t\tnlinfo(\"LUA_HOOKLINE  \");\n//\t\tbreak;\n//\tcase LUA_HOOKCOUNT:\n//\t\tbreak;\n//\tdefault:\n//\t\tbreak;\n//\t}\n//\t//printf(\"%s\",what);\n//\tif(debug_msg->currentline >0 )\t\n//\t\tnlinfo(\"curr line = \",debug_msg->currentline);\n//\n//\tif(lua_getinfo(L, what, debug_msg))\n//\t{\n//\t\t//printf(\"ʼ%dУ%dУʹⲿ%d\", debug_msg->linedefined,debug_msg->lastlinedefined,debug_msg->nups);\n//\t\tif(debug_msg->short_src != NULL) printf(debug_msg->short_src);\n//\t\tprintf(\"   \");\n//\t\tif(debug_msg->what != NULL) printf(debug_msg->what);\n//\t\tprintf(\"   \");\n//\t\tif(debug_msg->source != NULL) printf(debug_msg->source);\n//\t\tprintf(\"   \");\n//\t\tif(debug_msg->name != NULL) printf(debug_msg->name);\n//\t\tif(debug_msg->namewhat != NULL)printf(debug_msg->namewhat);\n//\t\tprintf(\"\\n\");\n//\t}\n//\tprintf(\"\\n\");\n//}\n//\n//static int Lua_Note(lua_State *L)\n//{\n//\n//\tint n = lua_gettop(L);  //Ĳ\n//\tint i;\n//\tlua_getglobal(L, \"tostring\"); //űtostringű⺯ѹջ\n//\tfor (i=1; i<=n; i++)\n//\t{\n//\t\tconst char *s;\n//\t\tlua_pushvalue(L, -1);  //ջıΪtostring ٴѹջ\n//\t\tlua_pushvalue(L, i);   //ҪӡֵҲǽűеʱĲѹջ\n//\t\tlua_call(L, 1, 1);     //ýűtostring\n//\t\ts = lua_tostring(L, -1);  //ֵջж\n//\n//\t\tif (s == NULL)\n//\t\t{\n//\t\t\treturn luaL_error(L, \"`tostring' must return a string to `print'\");\t\t\t\n//\t\t}\n//\n//\t\tif (i>1)\n//\t\t\tnldebug(\"\\t\");\n//\n//\t\tnldebug(\"%s\",s);\n//\t\tlua_pop(L, 1);  //ֵ\n//\t}\n//\n//\tnldebug(\"\\n\");\n//\treturn 0;\n//}\n\nvoid PrintLuaCallstack(lua_State *L, int stack_level = 0)\n{\n    lua_Debug debug_msg;\n    NLMISC::createDebug();\n\n    while (lua_getstack(L, stack_level, &debug_msg) == 1)\n    {\n        if (lua_getinfo(L, \"Slnu\", &debug_msg))\n        {\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition(debug_msg.currentline, debug_msg.short_src, debug_msg.name);\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"\");\n        }\n        ++stack_level;\n    }\n}\n\nCLuaEngine::CLuaEngine(void)\n{\n\tm_pLuaState = NULL;\n\n    m_ScriptHandle = new bin::CScriptHandle();\n\t//CreateLuaState();\n}\n\nCLuaEngine::~CLuaEngine(void)\n{\n}\n\nbool CLuaEngine::Init( std::string logpath )\n{\n    if(m_pLuaState!=NULL)\n        return true;\n\n    m_pLuaState = luaL_newstate();\t                /// һLua״̬ʵ\t\n\n    if(m_pLuaState==NULL)\n    {\n        nlerror( \"Lua State Create Fail.\" );\n        return false;\n    }\n\n\n    luaL_openlibs(m_pLuaState);                     /// LuaĻ\n\n    //if( !lua_checkstack(m_pLuaState, LUA_MINSTACK) )     ///  LuaĶջС\n    //{\n    //\tnlerror( \"set LuaState size fail(stacksize=1024).\" );\n    //\treturn false;\n    //}\n\n\n    //luaopen_protobuf_c(m_pLuaState);\n    luaL_requiref(m_pLuaState, \"protobuf.c\", luaopen_protobuf_c, 0);\n    luaL_requiref(m_pLuaState, \"cjson\", luaopen_cjson, 0);\n\n    m_ScriptHandle->Init(m_pLuaState);\n\n    \n\n    //tolua_auto_lua_callback_open(m_pLuaState);\n\n    //if( !lua_checkstack(m_pLuaState, stacksize) )     //LuaĶջСֹΪջС\n    //{\n    //\tnldebug( \"set LuaState size fail(stacksize=%d, top=%d, base=%d).\", stacksize, m_pLuaState->top, m_pLuaState->base );\n    //\treturn false;\n    //}\n\n    //#ifdef _DEBUG\n    //\tlua_sethook( m_pLuaState, Lua_Trace, LUA_MASKLINE , 0);\n    //#endif\n\n\n    //lua_register( m_pLuaState,\"note\",Lua_Note);\n\n    return true;\n}\n\nvoid CLuaEngine::Release()\n{\n\tif(m_pLuaState != NULL)\n\t{\n        m_ScriptHandle->Release();\n\t\tlua_close(m_pLuaState);\n\t}\n}\n\nlua_State *\tCLuaEngine::GetLuaState()\n{\n\treturn m_pLuaState;\n}\n\nconst char* CLuaEngine::GetLastError()\n{\n\treturn lua_tostring(m_pLuaState, -1);\n}\n\nbool CLuaEngine::LoadLuaFile(const char* fileName)\n{\n\treturn m_ScriptHandle->Exec(fileName);\n}\n\n\nbool CLuaEngine::RunMemoryLua(const char* pLuaData, int nDataLen)\n{\n\tif(pLuaData == NULL || nDataLen <= 0)\n\t{\n\t\treturn false;\n\t}\t\n\tint top = lua_gettop(m_pLuaState);\n\tif( !luaL_loadbuffer(m_pLuaState, pLuaData, nDataLen, pLuaData) )\n\t{\n\t\tif( !lua_pcall(m_pLuaState, 0, 0, 0) )\n\t\t{\n\t\t\tlua_settop(m_pLuaState, top);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tnlwarning(\"exec memory lua error, cause %s\", GetLastError());\n    PrintLuaCallstack(m_pLuaState, 1);\n\tlua_settop(m_pLuaState, top);\t\n\treturn false;\n}\n\nbool CLuaEngine::RunLuaFunction(const char* szFunName, const char* szTableName, const char* szSubTableName, \n\t\t\t\t\tLuaParams* pInParams, LuaParam * pOutParam, int nOutNum)\n{\n\tint top = lua_gettop(m_pLuaState);\n\tif(szTableName==NULL)\n\t{\n\t\tlua_getglobal(m_pLuaState, szFunName);\n\t}\n\telse if(szSubTableName==NULL)\n\t{\n\t\tlua_getglobal(m_pLuaState, szTableName);\n\t\tif(lua_istable(m_pLuaState, -1))\n\t\t{\n\t\t\tlua_getfield(m_pLuaState,-1,szFunName);\n\t\t}\n\t}\n\telse\n\t{\n\t\tlua_getglobal(m_pLuaState, szTableName);\n\t\tif(lua_istable(m_pLuaState, -1))\n\t\t{\n\t\t\tlua_getfield(m_pLuaState, -1,szSubTableName);\n\t\t\tif(lua_istable(m_pLuaState, -1))\n\t\t\t{\n\t\t\t\tlua_getfield(m_pLuaState,-1,szFunName);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif(!lua_isfunction(m_pLuaState, -1))\n\t{\n        nlwarning(\"call function(%s) fail, cause %s\", szFunName, GetLastError());\n        PrintLuaCallstack(m_pLuaState, 1);\n\t\tlua_settop(m_pLuaState, top);\n\t\treturn false;\n\t}\n\n    int inParamCnt = pInParams==NULL?0:pInParams->Count();\n\n\tfor(int i = 0; i < inParamCnt; i++)\n\t{\n\t\tswitch(pInParams->at(i).Type())\n\t\t{\n\t\t\tcase LUA_TNUMBER:\t\t\t\t\n\t\t\t\t//lua_pushnumber(m_pLuaState, pInParams->at(i).GetInt());\n                lua_pushinteger(m_pLuaState, pInParams->at(i).GetInt());\n\t\t\t\tbreak;\n\t\t\tcase LUA_TSTRING:\n\t\t\t\tlua_pushlstring(m_pLuaState, (char*)pInParams->at(i).Data(), pInParams->at(i).GetStringLen());\n\t\t\t\tbreak;\n\t\t\tcase LUA_TLIGHTUSERDATA:\n\t\t\t\tlua_pushlightuserdata(m_pLuaState, pInParams->at(i).Data());\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tnlwarning(\"call function(%s) fail, in param type error\", szFunName);\n                PrintLuaCallstack(m_pLuaState, 1);\n\t\t\t\tlua_settop(m_pLuaState, top);\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tif( !lua_pcall(m_pLuaState, inParamCnt, nOutNum, 0) )\n\t{\n\t\tfor(int n = 0; n < nOutNum; n++)\n\t\t{\n\t\t\tint nType = lua_type(m_pLuaState, -1);\n\t\t\tswitch(nType)\n\t\t\t{\n\t\t\t\tcase LUA_TNUMBER:\n\t\t\t\t\tpOutParam[n].SetInt( lua_tointeger(m_pLuaState, -1) );\n\t\t\t\t\tlua_pop(m_pLuaState, 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LUA_TBOOLEAN:\n\t\t\t\t\tpOutParam[n].SetInt( lua_toboolean(m_pLuaState, -1) );\n\t\t\t\t\tlua_pop(m_pLuaState, 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LUA_TSTRING:\n\n\t\t\t\t\t//pOutParam[n].SetString((char*)lua_tostring(m_pLuaState, -1));\n\t\t\t\t\tlua_pop(m_pLuaState, 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase LUA_TLIGHTUSERDATA:\n\t\t\t\t\tpOutParam[n].SetDataPointer((void*)lua_topointer(m_pLuaState, -1));\n\t\t\t\t\tlua_pop(m_pLuaState, 1);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tnlwarning(\"call function(%s) fail, out param type error = %s \", szFunName , lua_typename( m_pLuaState , -1 ) );\n                    PrintLuaCallstack(m_pLuaState, 1);\n\t\t\t\t\tlua_settop(m_pLuaState, top);\n\t\t\t\t\treturn false;\t\t\t\t\t\n\t\t\t}\n\t\t}\n\n\t\tlua_settop(m_pLuaState, top);   /// ָջΪδʱ״̬\n\t\treturn true;\n\t}\t\n\t\n\tnlwarning(\"call function(%s) fail, cause %s\", szFunName, GetLastError());\n    PrintLuaCallstack(m_pLuaState, 1);\n\tlua_settop(m_pLuaState, top);\n\treturn false;\n}\n\nvoid CLuaEngine::ExportModule( const char* pszName )\n{\n    bin::ScriptExporterManager().ExportModule( pszName, *m_ScriptHandle );\n}\n\nvoid CLuaEngine::ExportClass( const char* pszName )\n{\n    bin::ScriptExporterManager().ExportClass( pszName, *m_ScriptHandle );\n}\n\nvoid CLuaEngine::GcStep()\n{\n    H_AUTO(CLuaEngineGcStep);\n    lua_gc(m_pLuaState, LUA_GCSTEP, 0);\n}\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_engine.h",
    "content": "#ifndef SERVER_SHARD_LUA_ENGINE_H\n#define SERVER_SHARD_LUA_ENGINE_H\n\n#include \"lua_param.h\"\n\nnamespace bin{\n    class CScriptHandle;\n}\n\nclass CLuaEngine\n{\npublic:\n\tCLuaEngine(void);\n\tvirtual ~CLuaEngine(void);\n\npublic:\n\tbool\t\t\t            Init(std::string logpath=\"\");\n\n\tvoid\t\t\t            Release();\n\tlua_State *\t\t            GetLuaState();\n    bin::CScriptHandle*         GetScriptHandle()   { return m_ScriptHandle; }\n\tconst char*\t\t            GetLastError();\n    void                        GcStep();\n\n\tbool\t\t\t            LoadLuaFile(const char* szName);\n\tbool\t\t\t            RunMemoryLua(const char* pLuaData, int nDataLen);\n\tbool\t\t\t            RunLuaFunction(const char* szFunName, const char* szTableName = NULL,  const char* szSubTableName = NULL,LuaParams* pInParams=NULL, LuaParam * pOutParam = NULL, int nOutNum = 0);\n\n    void                        ExportModule( const char* pszName );\n    void                        ExportClass( const char* pszName );\n\nprivate:\n\tlua_State*\t\t            m_pLuaState;\n    bin::CScriptHandle*         m_ScriptHandle;\n};\n\n#endif\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_param.cpp",
    "content": "#include \"lua_param.h\"\n#include <nel/misc/debug.h>\n#include <nel/misc/displayer.h>\n\nstatic LuaParam  err;\n\nLuaParam& LuaParams::GetParam( uint index )\n{\n    if ( index<m_Count )\n    {\n        return m_Params[index];\n    }\n    else\n    {\n        nldebug(\"GetParam Error.\");\n\n        \n        return err;\n    }\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_param.h",
    "content": "#ifndef SERVER_SHARD_LUA_PARAM_H\n#define SERVER_SHARD_LUA_PARAM_H\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/log.h>\n#include <string>\n\n#include <lua.hpp>\n\nclass LuaParam\n{\npublic:\n\n    inline int Type()\n    {\n        return m_Type;\n    }\t\n\n    inline void SetInt(lua_Integer num)\n    {\n        m_Int = num;\n        m_Type = LUA_TNUMBER;\n    }\n\n    inline void SetString(const char* string, uint32 len)\n    {\n        m_DataHandle    = (void*)string;\n        m_Type          = LUA_TSTRING;\n        m_Int           = len;\n    }\n\n    inline uint32 GetStringLen() { return m_Int; }\n\n    inline void SetDataPointer(void* pointer)\n    {\n        m_DataHandle = pointer;\n        m_Type = LUA_TLIGHTUSERDATA;\n    }\n\n    inline void* Data()\n    {\n        if(m_Type == LUA_TNUMBER)\n            return &m_Int;\n        return (void*)m_DataHandle;\n    }\n\n    inline lua_Integer GetInt()\n    {\n        return m_Int;\n    }\n\n    LuaParam(void):m_Int(0),m_Type(LUA_TNUMBER),m_DataHandle(NULL) { }\n    LuaParam(void* pointer):m_Int(0),m_DataHandle(pointer),m_Type(LUA_TLIGHTUSERDATA) { }\n    LuaParam(lua_Integer luanumber):m_Int(luanumber),m_Type(LUA_TNUMBER),m_DataHandle(NULL) { }\n\n    virtual ~LuaParam(void){};\n\nprivate:\n    sint16\t\t\tm_Type;\n    void*\t\t\tm_DataHandle;\n    lua_Integer\t\tm_Int;\n};\n\nclass LuaParams\n{\npublic:\n    enum TParamsDefine\n    {\n        MAX_PARAMS = 3,\n    };\n\n    LuaParams():m_Count(0){}\n    ~LuaParams(){}\n\n    LuaParams( const lua_Number param1 ):\n        m_Count(1)\n    {\n        m_Params[0].SetInt(param1);\n    }\n\n    LuaParams( const lua_Number param1, const lua_Number param2 ):\n        m_Count(2)\n    {\n        m_Params[0].SetInt(param1);\n        m_Params[1].SetInt(param2);\n    }\n\n    LuaParams( const lua_Number param1, const std::string& param2 ) :\n        m_Count(2)\n    {\n        m_Params[0].SetInt(param1);\n        m_Params[1].SetString(param2.c_str(), param2.size());\n    }\n\n    LuaParams( const std::string& param1, const std::string& param2 ):\n        m_Count(2)\n    {\n        m_Params[0].SetString( param1.c_str(), param1.size() );\n        m_Params[1].SetString( param2.c_str(), param2.size() );\n    }\n\n    LuaParams( const lua_Integer param1, const std::string& param2, const std::string& param3 ):\n        m_Count(3)\n    {\n        m_Params[0].SetInt(param1);\n        m_Params[1].SetString( param2.c_str(), param2.size() );\n        m_Params[2].SetString( param3.c_str(), param3.size() );\n    }\n\n    //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 ):\n    //m_Count(4)\n    //{\n    //    m_Params[0].SetInt(param1);\n    //    m_Params[1].SetInt(param2);\n    //    m_Params[2].SetInt(param3);\n    //    m_Params[3].SetInt(param4);\n    //}\n\n    //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 ):\n    //m_Count(5)\n    //{\n    //    m_Params[0].SetInt(param1);\n    //    m_Params[1].SetInt(param2);\n    //    m_Params[2].SetInt(param3);\n    //    m_Params[3].SetInt(param4);\n    //    m_Params[4].SetInt(param5);\n    //}\n\n    //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 ):\n    //m_Count(6)\n    //{\n    //    m_Params[0].SetInt(param1);\n    //    m_Params[1].SetInt(param2);\n    //    m_Params[2].SetInt(param3);\n    //    m_Params[3].SetInt(param4);\n    //    m_Params[4].SetInt(param5);\n    //    m_Params[5].SetInt(param6);\n    //}\n\n    //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 , lua_Number param7 ):\n    //m_Count(7)\n    //{\n    //    m_Params[0].SetInt(param1);\n    //    m_Params[1].SetInt(param2);\n    //    m_Params[2].SetInt(param3);\n    //    m_Params[3].SetInt(param4);\n    //    m_Params[4].SetInt(param5);\n    //    m_Params[5].SetInt(param6);\n    //    m_Params[6].SetInt(param7);\n    //}\n\n    //LuaParams( lua_Number param1, lua_Number param2, lua_Number param3 , lua_Number param4 , lua_Number param5 , lua_Number param6 , lua_Number param7 , lua_Number param8 , lua_Number param9 , lua_Number param10 ):\n    //m_Count(10)\n    //{\n    //    m_Params[0].SetInt(param1);\n    //    m_Params[1].SetInt(param2);\n    //    m_Params[2].SetInt(param3);\n    //    m_Params[3].SetInt(param4);\n    //    m_Params[4].SetInt(param5);\n    //    m_Params[5].SetInt(param6);\n    //    m_Params[6].SetInt(param7);\n    //    m_Params[7].SetInt(param8);\n    //    m_Params[8].SetInt(param9);\n    //    m_Params[9].SetInt(param10);\n    //}\n\n    LuaParam&  GetParam( uint index );\n\n\n    //bool AddParam( lua_Number param1 )\n    //{\n    //    if ( m_Count+1<MAX_PARAMS )\n    //    {\n    //        m_Params[m_Count]=param1;\n    //        ++m_Count;\n    //        return true;\n    //    }\n    //    return false;\n    //}\n\n    bool AddParams( LuaParams other )\n    {\n        if ( other.Count()+m_Count < MAX_PARAMS )\n        {\n            for ( uint i=0; i<other.Count(); ++i )\n            {\n                m_Params[m_Count]=other.GetParam(i);\n                ++m_Count;\n            }\n            return true;\n        }\n        return false;\n    }\n    \n    LuaParam&   at( uint idx ) { return m_Params[idx]; }\n\n    LuaParam* GetParams()   { return m_Params; }\n    uint      Count()       { return m_Count;  }\n\n    void      resize( uint size )   { m_Count = size; }\nprivate:\n\n    uint        m_Count;\n    LuaParam    m_Params[MAX_PARAMS];\n\n    //std::vector<LuaParam>       m_Params;\n    \n    \n};\n\n\n\n#endif\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_thread.cpp",
    "content": "#include \"lua_thread.h\"\n#include <nel/misc/thread.h>\n#include \"script_mgr.h\"\n#include <server_share/server_def.h>\n#include <server_share/lua_net/lua_message.h>\n\nusing namespace NLMISC;\nusing namespace NLNET;\n\nvoid forLuaThreadForceLink()\n{\n    nlwarning(\"forLuaThreadForceLink\");\n}\n\nCLuaThread::CLuaThread( std::string name, sint32 update_tick ) : \n    m_ThreadHandle(NULL), m_ThreadName(name), m_AlreadyStarted(false),\n    m_RequireExit(false), m_LuaThreadHandle(-1), m_UpdateTick(0)\n{\n    if ( update_tick>0 && update_tick<0x7FFFFFFF )\n    {\n        m_UpdateTick = update_tick;\n    }\n}\n\nCLuaThread::~CLuaThread( void )\n{\n    Close();\n    LuaThreadMgr.RemoveLuaThread(m_LuaThreadHandle);\n}\n \nsint32 CLuaThread::Start( std::string lua_start, std::string params )\n{\n    m_ThreadHandle = NLMISC::IThread::create( this );\n\n    if ( m_ThreadHandle != NULL )\n    {\n        m_SubLuaEngine.Init();\n\n        m_SubLuaEngine.ExportModule(\"Misc\");\n        m_SubLuaEngine.ExportModule(\"Debug\");\n        m_SubLuaEngine.ExportModule(\"Net\");\n\n        m_SubLuaEngine.ExportClass(\"LuaMessage\");\n        m_SubLuaEngine.ExportClass(\"LuaThread\");\n        m_SubLuaEngine.ExportClass(\"LuaCallbackClient\");\n\n        m_SubLuaEngine.ExportClass(\"MysqlStmt\");\n        m_SubLuaEngine.ExportClass(\"MysqlConn\");\n        m_SubLuaEngine.ExportClass(\"MysqlResult\");\n\n        m_ToSubEvent.init(1024*1024);\n        m_ToMainEvent.init(1024*1024);\n\n        \n\n\n        //GetScriptObject().SetDelByScr(false);\n        //m_SubLuaEngine.GetScriptHandle()->Set( export_name.c_str(), this );\n\n        m_SubLuaEngine.GetScriptHandle()->Exec(lua_start.c_str());\n\n        m_LuaThreadHandle = LuaThreadMgr.RegisterLuaThread(this);\n\n        LuaParams _params(m_LuaThreadHandle, params);\n        m_SubLuaEngine.RunLuaFunction(\"ThreadInit\", NULL, NULL, &_params);\n\n        m_AlreadyStarted = true;\n\n        m_ThreadHandle->start();\n    }\n\n    return m_LuaThreadHandle;\n}\n\nvoid CLuaThread::Close( void )\n{\n    if ( NULL != m_ThreadHandle )\n    {\n        m_AlreadyStarted = false;\n        m_RequireExit = true;\n        m_ThreadHandle->wait();\n        m_ThreadHandle = NULL;\n    }\n}\n\nvoid CLuaThread::Update( void )\n{\n    if (m_AlreadyStarted)\n    {\n        CMessage* pMsg = NULL;\n        bin::CScriptTable    functbl;\n        ScriptMgr.GetScriptHandle()->Get(\"NetWorkHandler\", functbl);\n\n        while ((pMsg = m_ToMainEvent.pop_front()) != NULL)\n        {\n            sint32 nRet = 0;\n            m_LuaMainMsg.m_Msg.swap(*pMsg);\n            m_LuaMainMsg.m_Msg.invert();\n            functbl.CallFunc<sint32, CLuaMessage*, sint32>(\"OnMessage\", m_LuaThreadHandle, &m_LuaMainMsg, nRet);\n\n            SAFE_DELETE(pMsg);\n        }\n    }\n}\n\nvoid CLuaThread::run( void )\n{\n    bin::CScriptTable    functbl;\n    m_SubLuaEngine.GetScriptHandle()->Get(\"NetWorkHandler\", functbl);\n    NLMISC::TTime last_time = CTime::getLocalTime();\n\n    while ( !m_RequireExit )\n    {\n        CMessage* pMsg = m_ToSubEvent.pop_front();\n\n        if ( pMsg != NULL )\n        {\n            sint32 nRet = 0;\n            m_LuaSubMsg.m_Msg.swap(*pMsg);\n            m_LuaSubMsg.m_Msg.invert();\n            functbl.CallFunc<sint32, CLuaMessage*, sint32>(\"OnMessage\", m_LuaThreadHandle, &m_LuaSubMsg, nRet);\n\n            SAFE_DELETE(pMsg);\n        }\n        else\n        {\n            NLMISC::nlSleep( 3 );\n        }\n\n        if (m_UpdateTick > 0)\n        {\n            NLMISC::TTime curr_time = CTime::getLocalTime();\n            if (curr_time - last_time > m_UpdateTick)\n            {\n                m_SubLuaEngine.RunLuaFunction(\"ThreadUpdate\");\n                last_time = curr_time;\n            }\n        }\n    }\n}\n\nvoid CLuaThreadMgr::Init()\n{\n    //CConfigFile::CVar* pVar = Config.getVarPtr(\"LuaWorkThread\");\n\n    //if ( pVar != NULL )\n    //{\n    //    for (uint i = 0; i < pVar->size(); ++i)\n    //    {\n    //        NLMISC::CSString start_file = pVar->asString(i);\n    //        CVectorSString  res;\n    //        start_file.splitBySeparator( ' ', res );\n\n    //        if( res.size()!=2 ) { nlwarning( \"%s, config format error.\", start_file.c_str() ); continue; }\n\n    //        NLMISC::CSString script_full_path = CPath::lookup( res[1] );\n\n    //        if( !script_full_path.empty() )\n    //        {\n    //            CLuaThread* pLuaThread = new CLuaThread( res[0] );\n    //            pLuaThread->Start( script_full_path, res[0] );\n    //        }\n    //        else\n    //        {\n    //            nlwarning( \"%s, not found.\", script_full_path.c_str() );\n    //        }\n    //    }\n    //}\n}\n\nsint32 CLuaThreadMgr::RegisterLuaThread( CLuaThread* pThread )\n{\n    sint32 lua_handle = -1;\n\n    m_LuaThreadMutex.enter();\n    m_LuaThreadHandles.push_back(pThread);\n    lua_handle = m_LuaThreadHandles.size()-1;\n    m_LuaThreadMutex.leave();\n\n    return lua_handle;\n}\n\nvoid CLuaThreadMgr::Update()\n{\n    H_AUTO(CLuaThreadMgrUpdate);\n    m_LuaThreadMutex.enter();\n\n    for (uint i=0; i< m_LuaThreadHandles.size(); ++i)\n    {\n        m_LuaThreadHandles[i]->Update();\n    }\n\n    m_LuaThreadMutex.leave();\n}\n\nvoid CLuaThreadMgr::Release()\n{\n    m_LuaThreadMutex.enter();\n\n    for (uint i = 0; i< m_LuaThreadHandles.size(); ++i)\n    {\n        m_LuaThreadHandles[i]->Close();\n        delete m_LuaThreadHandles[i];\n    }\n\n    m_LuaThreadHandles.clear();\n    m_LuaThreadMutex.leave();\n}\n\nvoid CLuaThreadMgr::RemoveLuaThread( sint32 thread_handle )\n{\n    m_LuaThreadMutex.enter();\n    m_LuaThreadHandles[thread_handle] = NULL;\n    m_LuaThreadMutex.leave();\n}\n\nCLuaThread* CLuaThreadMgr::GetLuaThread( sint32 thread_handle )\n{\n    CLuaThread* pLuaThread = NULL;\n\n    m_LuaThreadMutex.enter();\n    pLuaThread = m_LuaThreadHandles[thread_handle];\n    m_LuaThreadMutex.leave();\n\n    return pLuaThread;\n}\n\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( LuaThread, CLuaThread )\n\n    DEFINE_CLASS_FUNCTION( Post, void, (CLuaMessage* pMsgIn))\n    {\n\t\tCMessage* pMsg = new CMessage();\n\t\tpMsg->swap(pMsgIn->m_Msg);\n\t\tobj->PostSub(pMsg);\n\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(Start, sint32, (std::string& lua_start, std::string& params))\n    {\n        r = obj->Start(lua_start, params);\n        return 1;\n    }\n\n    DEFINE_STATIC_FUNCTION(NewInstance, CLuaThread*, (std::string name, sint32 update_tick))\n    {\n        r = new CLuaThread(name, update_tick);\n        r->GetScriptObject().SetDelByScr(true);\n\n        return 1;\n    }\n\n    END_SCRIPT_CLASS()\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/lua_thread.h",
    "content": "#ifndef SERVER_SHARD_LUA_THREAD_H\n#define SERVER_SHARD_LUA_THREAD_H\n\n#include <nel/misc/singleton.h>\n#include <nel/misc/mutex.h>\n#include <server_share/buf_fifo2.h>\n#include <server_share/bin_luabind/Public.hpp>\n#include <server_share/lua/lua_engine.h>\n#include <server_share/lua_net/lua_message.h>\n#include <nel/net/message.h>\n\nnamespace bin{\n    class CScriptHandle;\n}\n\nclass CThreadEvent\n{\npublic:\n    uint64          m_From;\n    std::string     m_Data;\n    std::string     m_EventType;\n\n};\n\n\n\nclass CLuaThread : public NLMISC::IRunnable\n{\n    DECLARE_SCRIPT_CLASS();\n\npublic:\n\n    CLuaThread( std::string name, sint32 update_tick);\n    virtual ~CLuaThread(void);\n\n\n    /**\n    *  ߳\n    *  @param lua_start     ߳luaű·\n    *  @param params        ݲ\n    *  @return   lua_thread_handle\n    */\n    ///@{\n    sint32 Start(std::string lua_start, std::string params);\n    ///@}\n\n\n    // close;\n    void Close( void );\n\n\t// ̵߳ãȡ m_ToMainEvent\n    void Update( void );\n\n    void PostSub(NLNET::CMessage* pMsg)     { m_ToSubEvent.push_back(pMsg);  }\n    void PostMain(NLNET::CMessage* pMsg )   { m_ToMainEvent.push_back(pMsg); }\n\n    CLuaEngine&     GetLuaEngine() { return m_SubLuaEngine; }\nprotected:\n\n    // sub threads run;\n    void run( void );\n\nprivate:\n\n    NLMISC::IThread*            m_ThreadHandle;\n    CLuaEngine\t\t            m_SubLuaEngine;\n    std::string                 m_ThreadName;\n    sint32                      m_LuaThreadHandle;\n    bool                        m_AlreadyStarted;\n    sint32                      m_UpdateTick;\n\n    volatile bool               m_RequireExit;\n\n\n    NLMISC::CBufFIFO2< NLNET::CMessage >    m_ToSubEvent;\n    NLMISC::CBufFIFO2< NLNET::CMessage >    m_ToMainEvent;\n\n    CLuaMessage                 m_LuaMainMsg;\n    CLuaMessage                 m_LuaSubMsg;\n\n};\n\nclass CLuaThreadMgr : public NLMISC::CSingleton<CLuaThreadMgr>\n{\npublic:\n    CLuaThreadMgr() {}\n\n    sint32 RegisterLuaThread( CLuaThread* pThread );\n    void RemoveLuaThread( sint32 lua_handle );\n    CLuaThread* GetLuaThread( sint32 lua_handle);\n\n    void Init();\n\n    void Update();\n\n    void Release();\n\n\n\nprivate:\n\n    typedef std::vector<CLuaThread*>        TThreadHandles;\n\n    TThreadHandles      m_LuaThreadHandles;\n    NLMISC::CMutex      m_LuaThreadMutex;\n};\n\n#define  LuaThreadMgr  CLuaThreadMgr::instance()\n\n#endif\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/script_mgr.cpp",
    "content": "#include \"script_mgr.h\"\n#include <nel/misc/debug.h>\n#include <server_share/server_def.h>\n#include <string>\n#include \"lua_engine.h\"\n#include \"server_share/bin_luabind/Public.hpp\"\n#include <server_share/lua/lua_thread.h>\n#include <server_share/lua_mysql/mysql_conn.h>\n#include <server_share/id_generate.h>\n\nusing namespace std;\nusing namespace DEF;\nusing namespace NLMISC;\n\nextern void forLuaMysqlConnForceLink();\nextern void forLuaBaseFunctionForceLink();\nextern void forLuaMessageForceLink();\nextern void forLuaThreadForceLink();\nextern void forLuaCallbackClientForceLink();\n\nvoid luaexportforcelink()\n{\n    CIDGenerate idgen; \n\n    forLuaMysqlConnForceLink(); \n    forLuaBaseFunctionForceLink(); \n    forLuaMessageForceLink();\n    forLuaThreadForceLink();\n    forLuaCallbackClientForceLink();\n}\n\nbool CScriptMgr::init( LUA_OPEN pLuaOpen )\n{\n    m_IsInit = false;\n\t//UpdateServiceBootCount();\n\n    //string fn = IService::getInstance()->SaveFilesDirectory.toString();\n    string log_file = /*fn +*/ Config.getVar(\"LogDirectory\").asString();\n    string lua_log = log_file + \"lua_engine.log\";\n\n    m_LuaEngine.Release();\n    nlassert( m_LuaEngine.Init(lua_log) );\n\n    if ( pLuaOpen!=NULL )\n    {\n        pLuaOpen( m_LuaEngine.GetLuaState() );\n    }\n\n    ///  C++ӿ\n    Export();\n\n\n    CConfigFile::CVar* pVar = NULL;\n\n    if ((pVar = Config.getVarPtr(\"StartLuaScript\")) != NULL)\n    {\n        string script_full_path = CPath::lookup( pVar->asString() );\n        nlinfo(\"Loading %s.\", script_full_path.c_str());\n        m_IsInit = ScriptMgr.LoadScrpit(script_full_path.c_str());\n    }\n\n    return m_IsInit;\n}\n\nLuaParams CScriptMgr::run( std::string script_scope, std::string script_name, LuaParams lua_in, uint outnum )\n{\n    nlassert(outnum<=LuaParams::MAX_PARAMS);\n\n    LuaParams lua_out;\n    lua_out.resize(outnum);\n\n    bool run_ret = m_LuaEngine.RunLuaFunction( script_name.c_str(), script_scope.c_str(), NULL, \n                                                &lua_in, lua_out.GetParams(), lua_out.Count() );\n\n    //nlassert( run_ret );\n\n    if ( !run_ret )\n    {\n        lua_out.resize(0);\n    }\n\n    return lua_out;\n}\n\nlua_State * CScriptMgr::GetLuaState()\n{\n    return m_LuaEngine.GetLuaState();\n}\n\nvoid CScriptMgr::release()\n{\n    m_LuaEngine.RunLuaFunction( \"ServiceRelease\" );\n    m_LuaEngine.Release();\n}\n\nbool CScriptMgr::LoadScrpit( const char* szName )\n{\n    if( m_LuaEngine.LoadLuaFile(szName) )\n    {\n        return m_LuaEngine.RunLuaFunction( \"ServiceInit\" );\n    }\n\n    return false;\n}\n\nvoid CScriptMgr::update()\n{\n    H_AUTO(CScriptMgrUpdate);\n\n    if (m_IsInit)\n    {\n        m_LuaEngine.RunLuaFunction(\"ServiceUpdate\");\n        m_LuaEngine.GcStep();\n    }\n}\n\nvoid CScriptMgr::Export()\n{\n    m_LuaEngine.ExportModule(\"Misc\");\n    m_LuaEngine.ExportModule(\"Debug\");\n    m_LuaEngine.ExportModule(\"Net\");\n\n    m_LuaEngine.ExportClass(\"LuaCallbackServer\");\n    m_LuaEngine.ExportClass(\"LuaMessage\");\n    m_LuaEngine.ExportClass(\"IDGenerate\");\n    m_LuaEngine.ExportClass(\"LuaThread\");\n    m_LuaEngine.ExportClass(\"LuaCallbackClient\");\n    \n\n    m_LuaEngine.ExportClass(\"MysqlStmt\");\n    m_LuaEngine.ExportClass(\"MysqlConn\");\n    m_LuaEngine.ExportClass(\"MysqlResult\");\n}\n\nvoid CScriptMgr::ExecString( std::string exec_str )\n{\n    m_LuaEngine.GetScriptHandle()->ExecString( exec_str.c_str() );\n}\n\nvoid CScriptMgr::UpdateServiceBootCount()\n{\n    std::string cache_file = \".\";\n    cache_file.append( NLNET::IService::getInstance()->getServiceShortName() );\n    cache_file.append( \"-\" );\n    cache_file.append( NLMISC::toString(NLNET::IService::getInstance()->getServiceId().get()) );\n    cache_file.append( \".che\" );\n\n    if (!NLMISC::CFile::fileExists(cache_file))\n    {\n        NLMISC::CFile::createEmptyFile(cache_file);\n    }\n\n    CConfigFile cf;\n    cf.load(cache_file);\n\n    if ( !cf.exists(\"BootCnt\") )\n    {\n        CConfigFile::CVar var;\n        var.forceAsInt(1);\n        cf.insertVar(\"BootCnt\", var);\n    }\n    else\n    {\n        CConfigFile::CVar* pVar = cf.getVarPtr(\"BootCnt\");\n        uint32 boot_cnt = pVar->asInt();\n        ++boot_cnt;\n        pVar->setAsInt(boot_cnt);\n    }\n\n    cf.save();\n}\n\nNLMISC_COMMAND (lua, \"run lua string.\", \"lua\")\n{\n    if(args.size() != 1) return false;\n    ScriptMgr.ExecString( args[0] );\n    return true;\n}\n\nNLMISC_COMMAND(hotfix, \"lua module hotfix.\", \"\")\n{\n    if (args.size() != 0) return false;\n    ScriptMgr.ExecString(\"Hotfix:Update()\");\n    return true;\n}\n\nNLMISC_COMMAND(info, \"service information.\", \"\")\n{\n    if (args.size() != 0) return false;\n    ScriptMgr.ExecString(\"ServiceInfo()\");\n    return true;\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua/script_mgr.h",
    "content": "#ifndef SERVER_SHARD_SCRIPT_MGR_H\n#define SERVER_SHARD_SCRIPT_MGR_H\n\n#include <nel/misc/singleton.h>\n#include <server_share/game_def.h>\n#include <set>\n#include \"lua_engine.h\"\n\ntypedef int (*LUA_OPEN)(lua_State* tolua_S);\n\nnamespace bin{\n    class CScriptHandle;\n}\n\nclass CScriptMgr : public NLMISC::CSingleton<CScriptMgr>\n{\npublic:\n\n\tbool            init( LUA_OPEN pToluaOpen=NULL );\n    void            update();\n    void\t\t    release();\n\n    LuaParams       run( std::string script_scope, std::string script_name, LuaParams lua_in, uint outnum=0 );\n\n    void            ExecString( std::string );\n\n    bool                    LoadScrpit(const char* szName);\n    lua_State*              GetLuaState();\n    CLuaEngine&             GetLuaEngine()      { return m_LuaEngine; }\n    bin::CScriptHandle*     GetScriptHandle()   { return m_LuaEngine.GetScriptHandle(); }\n\nprivate:\n    void            UpdateServiceBootCount();\n    void            Export();\n    CLuaEngine      m_LuaEngine;\n    bool            m_IsInit;\n};\n\n#define  ScriptMgr  CScriptMgr::instance()\n#define  ScriptRun  ScriptMgr.run\n\n#endif\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_conn.cpp",
    "content": "﻿#include <errmsg.h>\n#include \"mysql_conn.h\"\n#include \"mysql_stmt.h\"\n#include \"mysql_result.h\"\n#include \"string\"\n\n#include <server_share/lua/script_mgr.h>\n\n#ifdef NL_OS_WINDOWS\nstatic const char* DB_NAMES = \"utf8\";\n#else\nstatic const char* DB_NAMES = \"utf8mb4\";\n#endif // NL_OS_WINDOWS\n\nCLuaMysqlConn::CLuaMysqlConn( void )\n    : m_mysql_( NULL ),\n      m_port_( 3306 ),\n      m_errno_( 0 ),\n      m_error_( \"\" )\n{\n}\n\nCLuaMysqlConn::~CLuaMysqlConn( void )\n{\n    close();\n}\n\n// connect.\nbool CLuaMysqlConn::connect( char const *host_,\n                        char const *user_,\n                        char const *pwd_,\n                        char const *db_,\n                        int         port_ )\n{\n    close();\n\n    m_mysql_ = mysql_init( NULL );\n\n    if ( NULL != m_mysql_ )\n    {\n        // set character.\n        mysql_options( m_mysql_, MYSQL_SET_CHARSET_NAME, DB_NAMES );\n\n        if ( NULL != mysql_real_connect( m_mysql_,\n                                         host_,\n                                         user_,\n                                         pwd_,\n                                         db_,\n                                         port_,\n                                         NULL,\n                                         0 ) )\n        {\n            m_host_.assign( host_ );\n            m_user_.assign( user_ );\n            m_pwd_.assign( pwd_ );\n            m_db_.assign( db_ );\n            m_port_ = port_;\n\n            // set autocommit.\n            mysql_autocommit( m_mysql_, 1 );\n            // set character set.\n            mysql_set_character_set( m_mysql_, DB_NAMES );\n\n            mysql_query(m_mysql_, \"SET character_set_client=binary\");\n\n            nlinfo( \"connect mysql server succeed!\" );\n            nlinfo( \"mysql client library : %s.\" , mysql_get_client_info() );\n            nlinfo( \"mysql server version: %s. \" , mysql_get_server_info( m_mysql_ ) );\n\n            return true;\n        }\n        else\n        {\n            m_errno_ = mysql_errno( m_mysql_ );\n            m_error_ = mysql_error( m_mysql_ );\n\n            nlwarning( \"connect mysql server failed, error = %d!\" , m_errno_ );\n        }\n    }\n    else\n    {\n        nlwarning( \" connect mysql server failed! \" );\n    }\n\n    return false;\n}\n\n// close.\nvoid CLuaMysqlConn::close( void )\n{\n    if ( NULL != m_mysql_ )\n    {\n        mysql_close( m_mysql_ );\n        m_mysql_ = NULL;\n    }\n}\n\n//CLuaMysqlStmt* CLuaMysqlConn::create_stmt( char const *sql_, size_t sz_ )\n//{\n//    CLuaMysqlStmt *_ret = NULL;\n//\n//    if ( NULL != m_mysql_ && NULL != sql_ && sz_ > 0 )\n//    {\n//        _ret = new (std::nothrow ) CLuaMysqlStmt ;\n//        if ( NULL!=_ret )\n//        {\n//            _ret->m_sql_.assign( sql_, sz_ );\n//        }\n//    }\n//\n//    return _ret;\n//}\n\n// execute.\nint CLuaMysqlConn::execute( CLuaMysqlStmt *stmt_ )\n{\n    int _ret = -1;\n\n    if ( NULL != m_mysql_ && NULL != stmt_ )\n    {\n        MYSQL_STMT *_stmt = mysql_stmt_init( m_mysql_ );\n\n        if ( NULL != _stmt )\n        {\n            if ( 0 == mysql_stmt_prepare( _stmt, stmt_->m_sql_.c_str(), stmt_->m_sql_.size() ) )\n            {\n                my_bool _bl = 1;\n\n                mysql_stmt_attr_set( _stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &_bl );\n                stmt_->_bind( mysql_stmt_param_count( _stmt ) );\n\n                if ( NULL != stmt_->m_bind_ )\n                {\n                    if ( 0 != mysql_stmt_bind_param( _stmt, stmt_->m_bind_ ) )\n                    {\n                        m_errno_ = mysql_errno( m_mysql_ );\n                        m_error_ = mysql_error( m_mysql_ );\n                        mysql_stmt_close( _stmt );\n                        _stmt = NULL;\n                        if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_bind_param\" ) )\n                        {\n                            _ret = execute( stmt_ );\n                        }\n                    }\n                }\n\n                if ( NULL != _stmt )\n                {\n                    if ( 0 == mysql_stmt_execute( _stmt ) )\n                    {\n                        _ret = (int)mysql_stmt_affected_rows( _stmt );\n\n                        /// 检查是否有结果集;\n                        MYSQL_RES *_res = mysql_stmt_result_metadata( _stmt );\n                        if ( NULL != _res )\n                        {\n                            unsigned int server_status = m_mysql_->server_status;\n\n                            if ( server_status & SERVER_PS_OUT_PARAMS )\n                            {\n                                nlwarning( \"此调用存储存在返回参数值，请检查sql语句和存储过程实现!\" );\n                                mysql_stmt_store_result( _stmt );\n                                mysql_free_result( _res );\n                                mysql_stmt_free_result( _stmt );\n                            }\n                            else\n                            {\n                                nlwarning( \"执行查询操作不应该返回任何结果集，请检查sql语句和存储过程实现!\" );\n                                mysql_stmt_store_result( _stmt );\n                                mysql_free_result( _res );\n                                mysql_stmt_free_result( _stmt );\n\n                                while ( 0 == mysql_stmt_next_result( _stmt ) )\n                                {\n                                    _res = mysql_stmt_result_metadata( _stmt );\n                                    if ( NULL != _res )\n                                    {\n                                        server_status = m_mysql_->server_status;\n                                        mysql_stmt_store_result( _stmt );\n                                        mysql_free_result( _res );\n                                        mysql_stmt_free_result( _stmt );\n                                        if ( server_status & SERVER_PS_OUT_PARAMS )\n                                        {\n                                            nlwarning( \" 此调用存储存在返回参数值，请检查sql语句和存储过程实现! \" );\n                                            break;\n                                        }\n                                        else\n                                        {\n                                            nlwarning( \" 执行查询操作不应该返回任何结果集，请检查sql语句和存储过程实现! \" );\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                        mysql_stmt_close( _stmt );\n                        _stmt = NULL;\n                        _res  = NULL;\n                    }\n                    else\n                    {\n                        m_errno_ = mysql_errno( m_mysql_ );\n                        m_error_ = mysql_error( m_mysql_ );\n                        mysql_stmt_close( _stmt );\n                        _stmt = NULL;\n                        if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_execute\" ) )\n                        {\n                            _ret = execute( stmt_ );\n                        }\n                    }\n                }\n            }\n            else\n            {\n                m_errno_ = mysql_errno( m_mysql_ );\n                m_error_ = mysql_error( m_mysql_ );\n                mysql_stmt_close( _stmt );\n                _stmt = NULL;\n                if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_prepare\" ) )\n                {\n                    _ret = execute( stmt_ );\n                }\n            }\n        }\n        else\n        {\n            m_errno_ = mysql_errno( m_mysql_ );\n            m_error_ = mysql_error( m_mysql_ );\n            if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_init\" ) )\n            {\n                _ret = execute( stmt_ );\n            }\n        }\n    }\n\n    return _ret;\n}\n\n// query.\nint CLuaMysqlConn::query( CLuaMysqlStmt *stmt_, CLuaMysqlResult **result_ )\n{\n    int _ret = -1;\n\n    if ( NULL != m_mysql_ && NULL != stmt_ && NULL != result_ )\n    {\n        MYSQL_STMT *_stmt = mysql_stmt_init( m_mysql_ );\n\n        //*result_ = NULL;\n        if ( NULL != _stmt )\n        {\n            if ( 0 == mysql_stmt_prepare( _stmt, stmt_->m_sql_.c_str(), stmt_->m_sql_.size() ) )\n            {\n                my_bool _bl = 1;\n\n                mysql_stmt_attr_set( _stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &_bl );\n                stmt_->_bind( mysql_stmt_param_count( _stmt ) );\n\n                if ( NULL != stmt_->m_bind_ )\n                {\n                    if ( 0 != mysql_stmt_bind_param( _stmt, stmt_->m_bind_ ) )\n                    {\n                        m_errno_ = mysql_errno( m_mysql_ );\n                        m_error_ = mysql_error( m_mysql_ );\n                        mysql_stmt_close( _stmt );\n                        _stmt = NULL;\n                        if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_bind_param\" ) )\n                        {\n                            _ret = query( stmt_, result_ );\n                        }\n                    }\n                }\n\n                if ( NULL != _stmt )\n                {\n                    if ( 0 == mysql_stmt_execute( _stmt ) )\n                    {\n                        _ret = (int)mysql_stmt_affected_rows( _stmt );\n                        MYSQL_RES *_res = mysql_stmt_result_metadata( _stmt );\n                        if ( NULL != _res )\n                        {\n                            unsigned int server_status = m_mysql_->server_status;\n\n                            if ( 0 == mysql_stmt_store_result( _stmt ) )\n                            {\n                                CLuaMysqlResult *_result = *result_;\n\n                                if ( *result_ == NULL )\n                                {\n                                    nlwarning(\"CLuaMysqlResult == NULL\");\n                                    _result = new( std::nothrow ) CLuaMysqlResult();\n                                    *result_ = _result;\n                                }\n\n                                if ( server_status & SERVER_PS_OUT_PARAMS )\n                                {\n                                    _ret = 0;\n                                    _result->_retval( _stmt, _res );\n                                    mysql_free_result( _res );\n                                    mysql_stmt_free_result( _stmt );\n                                }\n                                else\n                                {\n                                    _ret = (int)mysql_stmt_num_rows( _stmt );\n                                    _result->_init( _stmt, _res );\n                                    mysql_free_result( _res );\n                                    mysql_stmt_free_result( _stmt );\n\n                                    /// 检查是否还有结果集;\n                                    while ( 0 == mysql_stmt_next_result( _stmt ) )\n                                    {\n                                        _res = mysql_stmt_result_metadata( _stmt );\n                                        if ( NULL != _res )\n                                        {\n                                            server_status = m_mysql_->server_status;\n                                            if ( 0 == mysql_stmt_store_result( _stmt ) )\n                                            {\n                                                if ( server_status & SERVER_PS_OUT_PARAMS )\n                                                {\n                                                    _result->_retval( _stmt, _res );\n                                                    mysql_free_result( _res );\n                                                    mysql_stmt_free_result( _stmt );\n                                                    break;\n                                                }\n                                                else\n                                                {\n                                                    nlwarning( \"执行查询操作不应该返回任何结果集，请检查sql语句和存储过程实现!\" );\n                                                    mysql_stmt_store_result( _stmt );\n                                                    mysql_free_result( _res );\n                                                    mysql_stmt_free_result( _stmt );\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                                mysql_stmt_close( _stmt );\n                                _stmt = NULL;\n                            }\n                            else\n                            {\n                                m_errno_ = mysql_errno( m_mysql_ );\n                                m_error_ = mysql_error( m_mysql_ );\n                                mysql_stmt_close( _stmt );\n                                _stmt = NULL;\n                                if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_store_result\" ) )\n                                {\n                                    _ret = query( stmt_, result_ );\n                                }\n                                else\n                                {\n                                    _ret = -1;\n                                }\n                            }\n                        }\n                        else\n                        {\n                            mysql_stmt_close( _stmt );\n                            _stmt = NULL;\n                        }\n                    }\n                    else\n                    {\n                        m_errno_ = mysql_errno( m_mysql_ );\n                        m_error_ = mysql_error( m_mysql_ );\n                        mysql_stmt_close( _stmt );\n                        _stmt = NULL;\n                        if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_execute\" ) )\n                        {\n                            _ret = query( stmt_, result_ );\n                        }\n                    }\n                }\n            }\n            else\n            {\n                m_errno_ = mysql_errno( m_mysql_ );\n                m_error_ = mysql_error( m_mysql_ );\n                mysql_stmt_close( _stmt );\n                _stmt = NULL;\n                if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_prepare\" ) )\n                {\n                    _ret = query( stmt_, result_ );\n                }\n            }\n        }\n        else\n        {\n            m_errno_ = mysql_errno( m_mysql_ );\n            m_error_ = mysql_error( m_mysql_ );\n            if ( _procerror( stmt_->m_sql_.c_str(), \"mysql_stmt_init\" ) )\n            {\n                _ret = query( stmt_, result_ );\n            }\n        }\n    }\n\n    return _ret;\n}\n\n// reconnect.\nbool CLuaMysqlConn::_reconnect( void )\n{\n    if ( NULL != m_mysql_ && 0 == mysql_ping( m_mysql_ ) )\n    {\n        return true;\n    }\n    else\n    {\n        nlwarning( \"try to reconnect mysql server...\\n\" );\n        close();\n        m_mysql_ = mysql_init( NULL );\n        if ( NULL != m_mysql_ )\n        {\n            // set character.\n            mysql_options( m_mysql_, MYSQL_SET_CHARSET_NAME, \"utf8\" );\n            if ( NULL != mysql_real_connect( m_mysql_,\n                                             m_host_.c_str(),\n                                             m_user_.c_str(),\n                                             m_pwd_.c_str(),\n                                             m_db_.c_str(),\n                                             m_port_,\n                                             NULL,\n                                             0 ) )\n            {\n                // set autocommit.\n                mysql_autocommit( m_mysql_, 1 );\n                // set character set.\n                mysql_set_character_set( m_mysql_, \"utf8\" );\n\n                mysql_query(m_mysql_, \"SET character_set_client=binary\");\n\n                nlinfo( \"reconnect mysql server succeed!\" );\n                nlinfo( \"mysql client library: %s.\" , mysql_get_client_info() );\n                nlinfo( \"mysql server version: %s. \" , mysql_get_server_info( m_mysql_ ) );\n\n                return true;\n            }\n            else\n            {\n                nlwarning( \"reconnect mysql server failed, error = %d! \" , mysql_errno( m_mysql_ ) );\n            }\n        }\n        else\n        {\n            nlwarning( \" reconnect mysql server failed! \" );\n        }\n\n    }\n\n    return false;\n}\n\n// process error.\nbool CLuaMysqlConn::_procerror( char const *op_/* = NULL*/, char const *func_/* = NULL*/ )\n{\n    bool _ret = false;\n\n    if ( NULL != op_ && NULL != func_ )\n    {\n        nlinfo(\"op = %s, func = %s.\\n\" , op_ , func_ );\n    }\n    else if ( NULL != op_ )\n    {\n        nlinfo( \" op = %s. \" , op_ );\n    }\n\n    switch ( m_errno_ )\n    {\n    case CR_SERVER_GONE_ERROR:\n        {\n            nlwarning( \"mysql server has gone away, errno = %d!\"  , m_errno_ );\n\n            if ( _reconnect() )\n            {\n                _ret = true;\n            }\n            else\n            {\n                if ( NULL != m_mysql_ )\n                {\n                    m_errno_ = mysql_errno( m_mysql_ );\n                    m_error_ = mysql_error( m_mysql_ );\n                    //OSSleep( ERROR_SLEEP_TIME );\n                    _ret = _procerror( op_, __FUNCTION__ );\n                }\n            }\n        }\n        break;\n\n    case CR_SERVER_LOST:\n        {\n            nlwarning( \"lost the connection to mysql server, errno = %d!\\n\", m_errno_ );\n\n            if ( _reconnect() )\n            {\n                _ret = true;\n            }\n            else\n            {\n                if ( NULL != m_mysql_ )\n                {\n                    m_errno_ = mysql_errno( m_mysql_ );\n                    m_error_ = mysql_error( m_mysql_ );\n                    //OSSleep( ERROR_SLEEP_TIME );\n                    _ret = _procerror( op_, __FUNCTION__ );\n                }\n            }\n        }\n        break;\n\n    case CR_INVALID_CONN_HANDLE:\n        {\n            nlwarning( \"invalid connection handle, errno = %d!\\n\", m_errno_ );\n\n            if ( _reconnect() )\n            {\n                _ret = true;\n            }\n            else\n            {\n                if ( NULL != m_mysql_ )\n                {\n                    m_errno_ = mysql_errno( m_mysql_ );\n                    m_error_ = mysql_error( m_mysql_ );\n                    //OSSleep( ERROR_SLEEP_TIME );\n                    _ret = _procerror( op_, __FUNCTION__ );\n                }\n            }\n        }\n        break;\n\n    case CR_SERVER_LOST_EXTENDED:\n        {\n            nlwarning( \"lost the connection to mysql server error  = %d! \" , m_errno_ );\n\n            if ( _reconnect() )\n            {\n                _ret = true;\n            }\n            else\n            {\n                if ( NULL != m_mysql_ )\n                {\n                    m_errno_ = mysql_errno( m_mysql_ );\n                    m_error_ = mysql_error( m_mysql_ );\n                    //OSSleep( ERROR_SLEEP_TIME );\n                    _ret = _procerror( op_, __FUNCTION__ );\n                }\n            }\n        }\n        break;\n\n    default:\n        {\n            nlwarning( \"%s, error = %d! \" , m_error_.c_str(), m_errno_ );\n        }\n        break;\n    }\n\n    return _ret;\n}\n\n// errno.\nint CLuaMysqlConn::error( void ) const\n{\n    return m_errno_;\n}\n\nvoid forLuaMysqlConnForceLink()\n{\n    ScriptMgr.ExecString( \"\" );\n}\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( MysqlConn, CLuaMysqlConn )\n\n        DEFINE_CLASS_FUNCTION( Connect, bool, (CScriptTable& tb_msg))\n        {\n            if( tb_msg.IsReferd() )\n            {\n                std::string     myhost;\n                std::string     myuser;\n                std::string     mypwd;\n                std::string     mydb;\n                sint32          myport;\n\n                tb_msg.Get(1, myhost);\n                tb_msg.Get(2, myuser);\n                tb_msg.Get(3, mypwd);\n                tb_msg.Get(4, mydb);\n                tb_msg.Get(5, myport);\n\n                r = obj->connect( myhost.c_str(), myuser.c_str(), mypwd.c_str(), mydb.c_str(), myport );\n            }\n            else\n            {\n                r = false;\n            }\n\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Close, void, ())\n        {\n            obj->close();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Query, int, (CLuaMysqlStmt* pStmt, CLuaMysqlResult* pResult))\n        {\n            r = obj->query( pStmt, &pResult );\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Exec, int, (CLuaMysqlStmt* pStmt))\n        {\n            r = obj->execute( pStmt );\n            return 1;\n        }\n\n        DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlConn*, ())\n        {\n            r = new CLuaMysqlConn();\n            r->GetScriptObject().SetDelByScr(true);\n\n            return 1;\n        }\n\n    END_SCRIPT_CLASS()\n\n\n\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_conn.h",
    "content": "#ifndef LUA_MYSQL_CONN_H\n#define LUA_MYSQL_CONN_H\n\n#\tifdef _MSC_VER\n    #   if _MSC_VER < 1700\n        #include <my_global.h>\n    #endif\n#endif\n\n#include <mysql.h>\n#include <cstdio>\n#include <string>\n#include <server_share/bin_luabind/Public.hpp>\n\n#define ERROR_SLEEP_TIME 3000   /// ִSQLʱٴγִмʱ䣨룩\n\nclass CLuaMysqlStmt;\nclass CLuaMysqlResult;\n\nclass CLuaMysqlConn\n{\n    DECLARE_SCRIPT_CLASS();\npublic:\n    CLuaMysqlConn( void );\n    ~CLuaMysqlConn( void );\n\n    // connect.\n    bool connect( char const *host_,\n                  char const *user_,\n                  char const *pwd_,\n                  char const *db_,\n                  int         port_ );\n\n    // close.\n    void close( void );\n\n    // create statement.\n    //CLuaMysqlStmt* create_stmt( char const *sql_, size_t sz_ );\n\n    // execute.\n    int execute( CLuaMysqlStmt *stmt_ );\n\n    // query.\n    int query( CLuaMysqlStmt *stmt_, CLuaMysqlResult **result_ );\n\n    // errno.\n    int error( void ) const;\n\nprivate:\n    // reconnect.\n    bool _reconnect( void );\n\n    // process error.\n    bool _procerror( char const *op_ = NULL, char const *func_ = NULL );\n\nprivate:\n    MYSQL        *m_mysql_;\n    std::string   m_host_;\n    std::string   m_user_;\n    std::string   m_pwd_;\n    std::string   m_db_;\n    int           m_port_;\n    int           m_errno_;\n    std::string   m_error_;\n};\n\n\n#endif // LUA_MYSQL_CONN_H\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_result.cpp",
    "content": "#include \"mysql_result.h\"\n#include \"mysql_stmt.h\"\n#include <cstdio>\n\n\nCLuaMysqlResult::CLuaMysqlResult( void ):m_RowCount(0),m_CurrRow(-1),m_FieldCount(0),m_Idx(0)\n{\n    //m_cur_ = m_res_.end();\n}\n\nCLuaMysqlResult::~CLuaMysqlResult( void )\n{\n    //m_res_.clear();\n    //m_cur_ = m_res_.end();\n    //m_row_ = 0;\n}\n\n// close\nvoid CLuaMysqlResult::release( void )\n{\n    delete this;\n}\n\nvoid CLuaMysqlResult::clear()\n{\n    m_Result.clear();\n\n    m_RowCount      = 0;\n    m_CurrRow       = -1;\n    m_FieldCount    = 0;\n    m_Idx           = 0;\n}\n\nsize_t CLuaMysqlResult::count( void ) const\n{\n    return m_RowCount;\n}\n\nbool CLuaMysqlResult::next( void )\n{\n    bool _ret = false;\n\n    if ( m_CurrRow+1 < m_RowCount )\n    {\n        m_Idx = 0;\n        ++m_CurrRow;\n        _ret = true;\n    }\n    //if ( 0 == m_row_ &&\n    //     m_row_ < m_res_.size() &&\n    //     m_cur_ != m_res_.end() )\n    //{\n    //    ++ m_row_;\n    //    _ret = true;\n    //}\n    //else\n    //{\n    //    if ( m_cur_ != m_res_.end() )\n    //    {\n    //        ++ m_cur_;\n    //        if ( m_cur_ != m_res_.end() )\n    //        {\n    //            ++ m_row_;\n    //            _ret = true;\n    //        }\n    //    }\n    //}\n\n    return _ret;\n}\n\nmy_bool CLuaMysqlResult::get_bool()\n{\n    bool _ret = false;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = ( 0 != ( *(uint8*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = ( 0 != ( *(uint16*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = ( 0 != ( *(uint64*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = ( 0 != ( *(uint32*)_res.buf.c_str() ) );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = ( 0 != ( *(uint64*)_res.buf.c_str() ) );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nsint8 CLuaMysqlResult::get_int8()\n{\n    sint8 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (sint8)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (sint8)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (sint8)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (sint8)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (sint8)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (sint8)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (sint8)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nuint8 CLuaMysqlResult::get_uint8()\n{\n    uint8 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (uint8)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (uint8)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (uint8)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (uint8)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (uint8)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (uint8)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (uint8)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nsint16 CLuaMysqlResult::get_int16()\n{\n    sint16 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (sint16)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (sint16)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (sint16)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (sint16)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (sint16)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (sint16)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (sint16)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nuint16 CLuaMysqlResult::get_uint16()\n{\n    uint16 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (uint16)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (uint16)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (uint16)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (uint16)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (uint16)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (uint16)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (uint16)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nsint32 CLuaMysqlResult::get_int32()\n{\n    sint32 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (sint32)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (sint32)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (sint32)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (sint32)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (sint32)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (sint32)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (sint32)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n            ++m_Idx;\n\n        }\n    }\n\n    return _ret;\n}\n\nuint32 CLuaMysqlResult::get_uint32()\n{\n    uint32 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (uint32)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (uint32)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (uint32)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (uint32)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (uint32)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (uint32)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (uint32)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nsint64 CLuaMysqlResult::get_int64()\n{\n    sint64 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (sint64)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (sint64)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (sint64)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (sint64)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (sint64)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (sint64)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (sint64)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nuint64 CLuaMysqlResult::get_uint64()\n{\n    uint64 _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (uint64)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (uint64)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (uint64)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (uint64)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (uint64)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (uint64)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (uint64)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nfloat CLuaMysqlResult::get_float()\n{\n    float _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (float)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (float)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (float)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (float)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (float)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (float)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (float)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\ndouble CLuaMysqlResult::get_double()\n{\n    double _ret = 0;\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            switch ( _res.type )\n            {\n            case MYSQL_TYPE_TINY:\n                _ret = (double)( *(uint8*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_SHORT:\n                _ret = (double)( *(uint16*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_INT24:\n                _ret = (double)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONG:\n                _ret = (double)( *(uint32*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_LONGLONG:\n                _ret = (double)( *(uint64*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_FLOAT:\n                _ret = (double)( *(float*)_res.buf.c_str() );\n                break;\n            case MYSQL_TYPE_DOUBLE:\n                _ret = (double)( *(double*)_res.buf.c_str() );\n                break;\n            default:\n                break;\n            }\n\n            ++m_Idx;\n        }\n    }\n\n    return _ret;\n}\n\nstd::pair<size_t, char const*> CLuaMysqlResult::get_string()\n{\n    std::pair<size_t, char const*> _ret( 0, \"\" );\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && idx_ < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            if ( _res.size > 0 )\n            {\n                _ret.first  = _res.size;\n                _ret.second = _res.buf.c_str();\n                *(((char*)_ret.second) + _ret.first) = '\\0';\n            }\n        }\n\n        ++m_Idx;\n    }\n\n    return _ret;\n}\n\nstd::pair<size_t, void const*> CLuaMysqlResult::get_blob()\n{\n    std::pair<size_t, void const*> _ret( 0, \"\" );\n    uint32 curr_idx = row_offset()+m_Idx;\n\n    //if ( m_cur_ != m_res_.end() && m_Idx < m_cur_->size() )\n    {\n        result_t& _res = m_Result[curr_idx];\n\n        if ( !_res.is_null )\n        {\n            if ( _res.size > 0 )\n            {\n                _ret.first  = _res.size;\n                _ret.second = _res.buf.c_str();\n            }\n        }\n\n        ++m_Idx;\n    }\n\n    return _ret;\n}\n\nbool CLuaMysqlResult::_init( MYSQL_STMT *stmt_, MYSQL_RES *res_ )\n{\n    bool _ret = false;\n    m_RowCount = 0;\n    m_CurrRow = -1;\n\n    if ( NULL != stmt_ && NULL != res_ )\n    {\n        size_t _row = mysql_stmt_num_rows( stmt_ );\n\n        if ( _row > 0 )\n        {\n            size_t _count = 0;\n            MYSQL_BIND *_bind = NULL;\n\n            _count = mysql_stmt_field_count( stmt_ );\n            if ( _count > 0 )\n            {\n                m_FieldCount = _count;\n                _bind = (MYSQL_BIND*)malloc( _count * sizeof(MYSQL_BIND) );\n                memset( _bind, 0, _count * sizeof(MYSQL_BIND) );\n            }\n\n            if ( NULL != _bind )\n            {\n                //std::map<size_t, result_t> _result;\n                std::vector<result_t> _result;\n                _result.resize(_count);\n\n                size_t _idx = 0;\n                size_t _buff_max_len = 0;\n                MYSQL_FIELD *pField = mysql_fetch_field( res_ );\n\n                while ( NULL != pField )\n                {\n                    size_t    _sz  = 0;\n\n                    switch ( pField->type )\n                    {\n                    case MYSQL_TYPE_TINY:\n                        _sz = 1;\n                        break;\n                    case MYSQL_TYPE_SHORT:\n                        _sz = 2;\n                        break;\n                    case MYSQL_TYPE_INT24:\n                        _sz = 4;\n                        break;\n                    case MYSQL_TYPE_LONG:\n                        _sz = 4;\n                        break;\n                    case MYSQL_TYPE_LONGLONG:\n                        _sz = 8;\n                        break;\n                    case MYSQL_TYPE_FLOAT:\n                        _sz = 4;\n                        break;\n                    case MYSQL_TYPE_DOUBLE:\n                        _sz = 8;\n                        break;\n                    case MYSQL_TYPE_STRING:\n                    case MYSQL_TYPE_VAR_STRING:\n                    case MYSQL_TYPE_BLOB:\n                    case MYSQL_TYPE_TINY_BLOB:\n                    case MYSQL_TYPE_MEDIUM_BLOB:\n                    case MYSQL_TYPE_LONG_BLOB:\n                        _sz = pField->max_length;\n                        break;\n                    default:\n                        nlassert( false );\n                        break;\n                    }\n\n                    result_t& _res          = _result[_idx];\n                    _res.buf.assign( '\\0', _sz );\n                    _res.size              = _sz;\n                    _res.type              = pField->type;\n                    _res.is_null           = 0;\n\n                    _bind[_idx].buffer_type   = pField->type;\n                    _bind[_idx].buffer        = (void*)_res.buf.c_str();\n                    _bind[_idx].buffer_length = _res.size;\n                    _bind[_idx].length        = &_res.size;\n                    _bind[_idx].is_unsigned   = pField->flags & UNSIGNED_FLAG;\n                    _bind[_idx].is_null       = &_res.is_null;\n                    _buff_max_len            += _res.size;\n\n                    ++ _idx;\n                    pField = mysql_fetch_field( res_ );\n                }\n\n                if (  _buff_max_len > 0 && 0 == mysql_stmt_bind_result( stmt_, _bind ) )\n                {\n                    m_Result.resize( _row*_count );\n                    m_RowCount = _row;\n                    uint32 ret_idx = 0;\n\n                    //NLMISC::TTime  save_time = 0;\n                    //uint32         while_count = 0;\n\n                    while ( _row > 0 )\n                    {\n                        int _val = mysql_stmt_fetch( stmt_ );\n\n                        -- _row;\n                        if ( 0 == _val || MYSQL_DATA_TRUNCATED == _val )\n                        {\n                            uint32 row_offset = ret_idx*_count;\n\n                            \n                            for ( size_t _idx = 0; _idx < _count; ++ _idx )\n                            {\n                                result_t& src   = _result[_idx];\n                                result_t& dest  = m_Result[row_offset+_idx];\n\n                                //NLMISC::TTime sss = NLMISC::CTime::getLocalTime();\n                                dest.buf.assign( src.buf.c_str(), src.size );\n                                //save_time += NLMISC::CTime::getLocalTime() -  sss;\n                                //++while_count;\n\n                                //dest.buf     = src.buf;\n                                dest.size    = src.size;\n                                dest.type    = src.type;\n                                dest.is_null = src.is_null;\n                            }\n                            \n\n                            ++ret_idx;\n                        }\n                        else\n                        {\n                            m_RowCount = m_RowCount-_row;\n                            m_Result.resize( m_RowCount*m_FieldCount );\n                            _row = 0;\n                        }\n                    }\n\n                    //nlinfo(\"save itme : %lld  while_count:%d\",save_time,while_count);\n\n                    _ret   = true;\n                }\n\n                free( _bind );\n                _result.clear();\n            }\n        }\n    }\n\n    return _ret;\n}\n\nbool CLuaMysqlResult::_retval( MYSQL_STMT *stmt_, MYSQL_RES *res_ )\n{\n    bool _ret = false;\n\n    //if ( NULL != stmt_ && NULL != res_ )\n    //{\n    //    size_t _row = 0;\n\n    //    _row = mysql_stmt_num_rows( stmt_ );\n    //    if ( 1 == _row )    // صĽֻһ\n    //    {\n    //        size_t _count = 0;\n    //        MYSQL_BIND *_bind = NULL;\n\n    //        _count = mysql_stmt_field_count( stmt_ );\n    //        if ( _count > 0 )\n    //        {\n    //            _bind = (MYSQL_BIND*)malloc( _count * sizeof(MYSQL_BIND) );\n    //            memset( _bind, 0, _count * sizeof(MYSQL_BIND) );\n    //        }\n\n    //        if ( NULL != _bind )\n    //        {\n    //            std::map<size_t, result_t> _result;\n    //            size_t _idx = 0;\n    //            size_t _buff_max_len = 0;\n    //            MYSQL_FIELD *_field  = NULL;\n\n    //            _field = mysql_fetch_field( res_ );\n    //            while ( NULL != _field )\n    //            {\n    //                size_t    _sz  = 0;\n\n    //                switch ( _field->type )\n    //                {\n    //                case MYSQL_TYPE_TINY:\n    //                    _sz = 1;\n    //                    break;\n    //                case MYSQL_TYPE_SHORT:\n    //                    _sz = 2;\n    //                    break;\n    //                case MYSQL_TYPE_INT24:\n    //                    _sz = 4;\n    //                    break;\n    //                case MYSQL_TYPE_LONG:\n    //                    _sz = 4;\n    //                    break;\n    //                case MYSQL_TYPE_LONGLONG:\n    //                    _sz = 8;\n    //                    break;\n    //                case MYSQL_TYPE_FLOAT:\n    //                    _sz = 4;\n    //                    break;\n    //                case MYSQL_TYPE_DOUBLE:\n    //                    _sz = 8;\n    //                    break;\n    //                case MYSQL_TYPE_STRING:\n    //                case MYSQL_TYPE_VAR_STRING:\n    //                case MYSQL_TYPE_BLOB:\n    //                case MYSQL_TYPE_TINY_BLOB:\n    //                case MYSQL_TYPE_MEDIUM_BLOB:\n    //                case MYSQL_TYPE_LONG_BLOB:\n    //                    _sz = _field->max_length;\n    //                    break;\n    //                default:\n    //                    break;\n    //                }\n\n    //                result_t& _res          = _result[_idx];\n    //                _res.buf.assign( '\\0', _sz );\n    //                _res.size              = _sz;\n    //                _res.type              = _field->type;\n    //                _res.is_null           = 0;\n\n    //                _bind[_idx].buffer_type   = _field->type;\n    //                _bind[_idx].buffer        = (void*)_res.buf.c_str();\n    //                _bind[_idx].buffer_length = _res.size;\n    //                _bind[_idx].length        = &_res.size;\n    //                _bind[_idx].is_unsigned   = _field->flags & UNSIGNED_FLAG;\n    //                _bind[_idx].is_null       = &_res.is_null;\n    //                _buff_max_len            += _res.size;\n\n    //                ++ _idx;\n    //                _field = mysql_fetch_field( res_ );\n    //            }\n\n    //            if ( _buff_max_len > 0 && 0 == mysql_stmt_bind_result( stmt_, _bind ) )\n    //            {\n    //                int _val = mysql_stmt_fetch( stmt_ );\n    //                if ( 0 == _val || MYSQL_DATA_TRUNCATED == _val )\n    //                {\n    //                    result_t *_src = NULL;\n    //                    result_t *_dest = NULL;\n\n    //                    for ( size_t _idx = 0; _idx < _count; ++ _idx )\n    //                    {\n    //                        _src           = &_result[_idx];\n    //                        _dest          = &m_ret_[_idx];\n    //                        _dest->buf     = _src->buf;\n    //                        _dest->size    = _src->size;\n    //                        _dest->type    = _src->type;\n    //                        _dest->is_null = _src->is_null;\n    //                    }\n    //                }\n    //                _ret   = true;\n    //            }\n\n    //            free( _bind );\n    //            _result.clear();\n    //        }\n    //    }\n    //}\n\n    return _ret;\n}\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( MysqlResult, CLuaMysqlResult )\n\n        DEFINE_CLASS_FUNCTION( Next, bool, ())\n        {\n            r = obj->next();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Count, sint64, () )\n        {\n            r = obj->count();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Clear, void, () )\n        {\n            obj->clear();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetBool, bool, () )\n        {\n            r = obj->get_bool();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetInt8, sint64, () )\n        {\n            r = obj->get_int8();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetUint8, sint64, () )\n        {\n            r = obj->get_uint8();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetInt32, sint64, () )\n        {\n            r = obj->get_int32();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetUint32, sint64, () )\n        {\n            r = obj->get_uint32();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetInt64, sint64, () )\n        {\n            r = obj->get_int64();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetUint64, sint64, () )\n        {\n            r = obj->get_uint64();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetFloat, lua_Number, () )\n        {\n            r = obj->get_float();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetDouble, lua_Number, () )\n        {\n            r = obj->get_double();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetString,  std::string, () )\n        {\n            std::pair<size_t, char const*> pair = obj->get_string();\n            r.assign(pair.second, pair.first);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( GetBlob, std::string, () )\n        {\n            std::pair<size_t, void const*> pair = obj->get_blob();\n            r.assign((const char*)pair.second, pair.first);\n            //r.Set(1, (const char*)pair.second);\n            //r.Set(2, (int)pair.first);\n            return 1;\n        }\n\n\n        DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlResult*, ())\n        {\n            r = new CLuaMysqlResult();\n            r->GetScriptObject().SetDelByScr(true);\n\n            return 1;\n        }\n\n    END_SCRIPT_CLASS()\n\n}\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_result.h",
    "content": "#ifndef LUA_MYSQL_RESULT_H\n#define LUA_MYSQL_RESULT_H\n\n#include <nel/misc/types_nl.h>\n#include <vector>\n#include <mysql.h>\n\n#include \"mysql_string.h\"\n#include <server_share/bin_luabind/Public.hpp>\n\nclass CLuaMysqlResult\n{\n    DECLARE_SCRIPT_CLASS();\npublic:\n\n    friend class CLuaMysqlConn;\n\n    // close.\n    void release( void );\n\n    void clear();\n\n    // next.\n    bool next( void );\n\n    // count.\n    size_t count( void ) const;\n\n    // get bool value.\n    my_bool get_bool();\n\n    // get int8 value.\n    sint8 get_int8();\n\n    // get uint8 value.\n    uint8 get_uint8();\n\n    // get int16 value.\n    sint16 get_int16();\n\n    // get uint16 value.\n    uint16 get_uint16();\n\n    // get int32 value.\n    sint32 get_int32();\n\n    // get uint32 value.\n    uint32 get_uint32();\n\n    // get int64 value.\n    sint64 get_int64();\n\n    // get uint64 value.\n    uint64 get_uint64();\n\n    // get float value.\n    float get_float();\n\n    // get double value.\n    double get_double();\n\n    // get string.\n    std::pair<size_t, char const*> get_string();\n\n    // get blob.\n    std::pair<size_t, void const*> get_blob();\n\n\n    CLuaMysqlResult( void );\n    ~CLuaMysqlResult( void );\n\nprotected:\n\n    typedef struct _result\n    {\n        CLuaMysqlString   buf;\n        unsigned long     size;\n        enum_field_types  type;\n        my_bool           is_null;\n\n        _result( void )\n            : size( 0 ),\n              type( MYSQL_TYPE_NULL ),\n              is_null( 0 )\n        {}\n    } result_t;\n\n    // initialize.\n    bool _init( MYSQL_STMT *stmt_, MYSQL_RES *res_ );\n\n    // returned output parameters.\n    bool _retval( MYSQL_STMT *stmt_, MYSQL_RES *res_ );\n\n    uint32 row_offset() { return m_CurrRow<0?0:(m_CurrRow*m_FieldCount); }\n\nprivate:\n\n    typedef std::vector<_result>        TResult;\n    TResult             m_Result;\n\n    uint32              m_RowCount;\n    sint32              m_CurrRow;\n    uint32              m_FieldCount;\n\n    uint32              m_Idx;\n\n    //std::map<size_t, _result>                        m_ret_; // out parameters.\n};\n\n\n#endif // LUA_MYSQL_RESULT_H"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_stmt.cpp",
    "content": "#include \"mysql_stmt.h\"\n#include \"mysql_conn.h\"\n#include \"mysql_result.h\"\n#include <cstdio>\n#include <errmsg.h>\n\n\nCLuaMysqlStmt::CLuaMysqlStmt(  )\n    : m_bind_( NULL ),\n      m_count_( 0 ),\n      m_idx(0)\n{\n    m_Params.resize(64);\n}\n\nCLuaMysqlStmt::~CLuaMysqlStmt( void )\n{\n    if ( NULL != m_bind_ )\n    {\n        free( m_bind_ );\n        m_bind_  = NULL;\n        m_count_ = 0;\n        m_idx = 0;\n    }\n}\n\n// close.\nvoid CLuaMysqlStmt::release( void )\n{\n    delete this;\n}\n\nvoid CLuaMysqlStmt::clear()\n{\n    m_count_ = 0;\n    m_idx = 0;\n}\n\n// set bool value.\nvoid CLuaMysqlStmt::set_bool( my_bool bval_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char)bval_, 1 );\n    param.type = MYSQL_TYPE_TINY;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set int8 value.\nvoid CLuaMysqlStmt::set_int8( sint8 i8_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char)i8_, 1 );\n    param.type = MYSQL_TYPE_TINY;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set uint8 value.\nvoid CLuaMysqlStmt::set_uint8( uint8 ui8_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char)ui8_, 1 );\n    param.type = MYSQL_TYPE_TINY;\n    param.is_unsigned = UNSIGNED_FLAG;\n    ++m_idx;\n}\n\n// set int16 value.\nvoid CLuaMysqlStmt::set_int16( sint16 i16_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&i16_, 2 );\n    param.type = MYSQL_TYPE_SHORT;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set uint16 value.\nvoid CLuaMysqlStmt::set_uint16( uint16 ui16_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&ui16_, 2 );\n    param.type = MYSQL_TYPE_SHORT;\n    param.is_unsigned = UNSIGNED_FLAG;\n    ++m_idx;\n}\n\n// set int32 value.\nvoid CLuaMysqlStmt::set_int32( sint32 i32_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&i32_, 4 );\n    param.type = MYSQL_TYPE_LONG;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set uint32 value.\nvoid CLuaMysqlStmt::set_uint32( uint32 ui32_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&ui32_, 4 );\n    param.type = MYSQL_TYPE_LONG;\n    param.is_unsigned = UNSIGNED_FLAG;\n    ++m_idx;\n}\n\n// set int64 value.\nvoid CLuaMysqlStmt::set_int64( sint64 i64_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&i64_, 8 );\n    param.type = MYSQL_TYPE_LONGLONG;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set uint64 value.\nvoid CLuaMysqlStmt::set_uint64( uint64 ui64_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&ui64_, 8 );\n    param.type = MYSQL_TYPE_LONGLONG;\n    param.is_unsigned = UNSIGNED_FLAG;\n    ++m_idx;\n}\n\n// set float value.\nvoid CLuaMysqlStmt::set_float( float fval_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&fval_, 4 );\n    param.type = MYSQL_TYPE_FLOAT;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set double value.\nvoid CLuaMysqlStmt::set_double( double dval_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)&dval_, 8 );\n    param.type = MYSQL_TYPE_DOUBLE;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set string.\nvoid CLuaMysqlStmt::set_string( char const *str_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( str_ );\n    param.type = MYSQL_TYPE_STRING;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set string.\nvoid CLuaMysqlStmt::set_string( char const *str_, size_t sz_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( str_, sz_ );\n    param.type = MYSQL_TYPE_STRING;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// set blob.\nvoid CLuaMysqlStmt::set_blob( void const *ptr_, size_t sz_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)ptr_, sz_ );\n    param.type = MYSQL_TYPE_BLOB;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\nvoid CLuaMysqlStmt::set_tinyblob( void const *ptr_, size_t sz_ )\n{\n    param_t& param = m_Params[m_idx];\n\n    param.buf.assign( (char*)ptr_, sz_ );\n    param.type = MYSQL_TYPE_TINY_BLOB;\n    param.is_unsigned = 0;\n    ++m_idx;\n}\n\n// bind parameters.\nvoid CLuaMysqlStmt::_bind( size_t count_ )\n{\n    if ( m_count_ < count_ )\n    {\n        if ( NULL != m_bind_ )\n        {\n            free( m_bind_ );\n            m_bind_ = NULL;\n        }\n        m_bind_ = (MYSQL_BIND*)malloc( count_ * sizeof(MYSQL_BIND) );\n        m_count_ = count_;\n    }\n\n    if ( NULL != m_bind_ )\n    {\n        memset( m_bind_, 0, m_count_ * sizeof( MYSQL_BIND ) );\n\n        for ( size_t _idx = 0; _idx < count_; ++ _idx )\n        {\n            param_t& param = m_Params[_idx];\n\n            m_bind_[_idx].buffer        = (void*)param.buf.c_str();\n            m_bind_[_idx].buffer_length = param.buf.size();\n            m_bind_[_idx].buffer_type   = param.type;\n            m_bind_[_idx].is_unsigned   = param.is_unsigned;\n            m_bind_[_idx].is_null_value = param.is_null_val;\n        }\n    }\n}\n\n\n\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( MysqlStmt, CLuaMysqlStmt )\n\n        DEFINE_CLASS_FUNCTION( Clear, void, (void))\n        {\n            obj->clear();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetBool, void, (bool lua_bool))\n        {\n            obj->set_bool(lua_bool);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetInt8, void, (sint32 lua_val))\n        {\n            obj->set_int8(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetUint8, void, (sint32 lua_val))\n        {\n            obj->set_uint8(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetInt16, void, (sint32 lua_val))\n        {\n            obj->set_int16(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetUint16, void, (sint32 lua_val))\n        {\n            obj->set_uint16(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetInt32, void, (sint32 lua_val))\n        {\n            obj->set_int32(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetUint32, void, (sint32 lua_val))\n        {\n            obj->set_uint32(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetInt64, void, (sint64 lua_val))\n        {\n            obj->set_int64(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetUint64, void, (sint64 lua_int))\n        {\n            obj->set_uint64(lua_int);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetFloat, void, (lua_Number lua_val))\n        {\n            obj->set_float(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetDouble, void, (lua_Number lua_val))\n        {\n            obj->set_double(lua_val);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetString, void, (std::string lua_str))\n        {\n            obj->set_string(lua_str.c_str(), lua_str.size());\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetBlob, void, (const char* _buffer, int _len))\n        {\n            obj->set_blob(_buffer,_len);\n            return 1;\n        }\n\n        DEFINE_STATIC_FUNCTION(NewInstance, CLuaMysqlStmt*, (std::string sql))\n        {\n            CLuaMysqlStmt* pStmt = new (std::nothrow ) CLuaMysqlStmt;\n\n            if ( NULL!=pStmt )\n            {\n                pStmt->set_sql( sql );\n                r = pStmt;\n                r->GetScriptObject().SetDelByScr(true);\n            }\n\n            return 1;\n        }\n\n    END_SCRIPT_CLASS()\n\n\n\n\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_stmt.h",
    "content": "#ifndef LUA_MSQL_PSTMT_H\n#define LUA_MSQL_PSTMT_H\n\n#include \"mysql_result.h\"\n#include <server_share/bin_luabind/Public.hpp>\n\nclass CLuaMysqlStmt\n{\n    DECLARE_SCRIPT_CLASS();\npublic:\n    friend class CLuaMysqlConn;\n\n    // release.\n    void release( void );\n\n    void clear();\n\n    // set bool value.\n    void set_bool( my_bool bval_ );\n\n    // set int8 value.\n    void set_int8( sint8 i8_ );\n\n    // set uint8 value.\n    void set_uint8( uint8 ui8_ );\n\n    // set int16 value.\n    void set_int16( sint16 i16_ );\n\n    // set uint16 value.\n    void set_uint16( uint16 ui16_ );\n\n    // set int32 value.\n    void set_int32( sint32 i32_ );\n\n    // set uint32 value.\n    void set_uint32( uint32 ui32_ );\n\n    // set int64 value.\n    void set_int64( sint64 i64_ );\n\n    // set uint64 value.\n    void set_uint64( uint64 ui64_ );\n\n    // set float value.\n    void set_float( float fval_ );\n\n    // set double value.\n    void set_double( double dval_ );\n\n    // set string.\n    void set_string( char const *str_ );\n\n    // set string.\n    void set_string( char const *str_, size_t sz_ );\n\n    // set blob.\n    void set_blob( void const *ptr_, size_t sz_ );\n\n    void set_tinyblob( void const *ptr_, size_t sz_ );\n\n    void set_sql( std::string& sql ) { m_sql_.assign(sql.c_str(),sql.size()); }\n    \n//protected:\n    CLuaMysqlStmt( void );\n    ~CLuaMysqlStmt( void );\n\nprotected:\n    // bind parameters.\n    void _bind( size_t count_ );\n\nprivate:\n\n    typedef struct _param\n    {\n        CLuaMysqlString   buf;\n        enum_field_types type;\n        my_bool          is_unsigned;\n        my_bool          is_null_val;\n\n        _param( void )\n            : type( MYSQL_TYPE_NULL ),\n              is_unsigned( 0 ),\n              is_null_val( 0 )\n        {}\n\n        _param( enum_field_types in_type, my_bool in_unsigned )\n            : type( in_type ),\n            is_unsigned( in_unsigned ),\n            is_null_val( 0 )\n        {}\n\n    } param_t;\n\n    MYSQL_BIND                  *m_bind_;\n    size_t                      m_count_;   // count of MYSQL_BIND\n    std::vector<param_t>        m_Params;\n    std::string                 m_sql_;\n    uint32                      m_idx;\n};\n\n\n#endif // LUA_MSQL_PSTMT_H\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_string.cpp",
    "content": "#include \"mysql_stmt.h\"\n#include <string>\n\nCLuaMysqlString::CLuaMysqlString( void )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n}\n\nCLuaMysqlString::CLuaMysqlString( char const *str_ )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n    assign( str_ );\n}\n\nCLuaMysqlString::CLuaMysqlString( char const *str_, size_t sz_ )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n    assign( str_, sz_ );\n}\n\nCLuaMysqlString::CLuaMysqlString( CLuaMysqlString const &str_ )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n    assign( str_ );\n}\n\nCLuaMysqlString::CLuaMysqlString( char ch_, size_t sz_ )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n    assign( ch_, sz_ );\n}\n\nCLuaMysqlString::CLuaMysqlString( size_t sz_ )\n    : m_str_( 0 ),\n      m_off_( 0 ),\n      m_sz_( 0 )\n{\n    assign( '\\0', sz_ > 0 ? ( sz_ - 1 ) : sz_ );\n}\n\nCLuaMysqlString::~CLuaMysqlString( void )\n{\n    if ( 0 != m_str_ )      \n    {\n        delete[] m_str_;\n        m_str_ = 0;\n        m_off_ = 0;\n        m_sz_  = 0;\n    }\n}\n\n// to c-string.\nCLuaMysqlString::operator char const* ( void ) const\n{\n    return m_str_;\n}\n\n// operator [].\nchar& CLuaMysqlString::operator [] ( int idx )\n{\n    return m_str_[idx];\n}\n\n// operator =.\nCLuaMysqlString& CLuaMysqlString::operator = ( CLuaMysqlString const &str_ )\n{\n    return assign( str_ );\n}\n\n// operator =.\nCLuaMysqlString& CLuaMysqlString::operator = ( char const *str_ )\n{\n    return assign( str_ );\n}\n\n// operator =.\nCLuaMysqlString& CLuaMysqlString::operator = ( char ch_ )\n{\n    return assign( ch_, 1 );\n}\n\n// operator +=.\nCLuaMysqlString& CLuaMysqlString::operator += ( char ch_ )\n{\n    return append( ch_, 1 );\n}\n\n// operator ==.\nbool CLuaMysqlString::operator == ( CLuaMysqlString const &str_ ) const\n{\n    return ( 0 == compare( str_ ) );\n}\n\n// operator !=.\nbool CLuaMysqlString::operator == ( char const *str_ ) const\n{\n    return ( 0 == compare( str_ ) );\n}\n\n// operator !=.\nbool CLuaMysqlString::operator != ( CLuaMysqlString const &str_ ) const\n{\n    return ( 0 != compare( str_ ) );\n}\n\n// operator !=.\nbool CLuaMysqlString::operator != ( char const *str_ ) const\n{\n    return ( 0 != compare( str_ ) );\n}\n\n// operator <.\nbool CLuaMysqlString::operator < ( CLuaMysqlString const &str_ ) const\n{\n    return ( compare( str_ ) < 0 );\n}\n\n// operator <.\nbool CLuaMysqlString::operator < ( char const *str_ ) const\n{\n    return ( compare( str_ ) < 0 );\n}\n\n// operator <=.\nbool CLuaMysqlString::operator <= ( CLuaMysqlString const &str_ ) const\n{\n    return ( compare( str_ ) <= 0 );\n}\n\n// operator <=.\nbool CLuaMysqlString::operator <= ( char const *str_ ) const\n{\n    return ( compare( str_ ) <= 0 );\n}\n\n// operator >.\nbool CLuaMysqlString::operator > ( CLuaMysqlString const &str_ ) const\n{\n    return ( compare( str_ ) > 0 );\n}\n\n// operator >.\nbool CLuaMysqlString::operator > ( char const *str_ ) const\n{\n    return ( compare( str_ ) > 0 );\n}\n\n// operator >=.\nbool CLuaMysqlString::operator >= ( CLuaMysqlString const &str_ ) const\n{\n    return ( compare( str_ ) >= 0 );\n}\n\n// operator >=.\nbool CLuaMysqlString::operator >= ( char const *str_ ) const\n{\n    return ( compare( str_ ) >= 0 );\n}\n\nCLuaMysqlString& CLuaMysqlString::assign( CLuaMysqlString const &str_ )\n{\n    if ( this != &str_ )\n    {\n        if ( 0 != str_.m_str_ )\n        {\n            m_off_ = str_.m_off_;\n            if ( m_off_ >= m_sz_ )\n            {\n                if ( 0 != m_str_ )\n                {\n                    delete[] m_str_;\n                    m_str_ = 0;\n                }\n                m_sz_ = m_off_ + 1;\n                m_str_ = new( std::nothrow ) char[ m_sz_ ];\n            }\n\n            //memcpy( m_str_, str_.m_str_, m_off_ );\n            //m_str_[m_off_] = 0;\n            _strncpy( m_str_, str_.m_str_, m_off_ );\n        }\n        else if ( 0 != m_str_ )\n        {\n            *m_str_ = '\\0';\n            m_off_  = 0;\n        }\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::assign( char const *str_ )\n{\n    if ( 0 != str_ )\n    {\n        m_off_ = ::strlen( str_ );\n        if ( m_off_ >= m_sz_ )\n        {\n            if ( 0 != m_str_ )\n            {\n                delete[] m_str_;\n                m_str_ = 0;\n            }\n            m_sz_ = m_off_ + 1;\n            m_str_ = new( std::nothrow ) char[ m_sz_ ];\n        }\n\n        _strncpy( m_str_, str_, m_off_ );\n    }\n    else if ( 0 != m_str_ )\n    {\n        *m_str_ = '\\0';\n        m_off_  = 0;\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::assign( char const *str_, size_t sz_ )\n{\n    if ( 0 != str_ && sz_ > 0 )\n    {\n        m_off_ = sz_;\n        if ( m_off_ >= m_sz_ )\n        {\n            if ( 0 != m_str_ )\n            {\n                delete[] m_str_;\n                m_str_ = 0;\n            }\n            m_sz_ = sz_ + 1;\n            m_str_ = new( std::nothrow ) char[ m_sz_ ];\n        }\n\n        memcpy( m_str_, str_, sz_ );\n        m_str_[sz_] = 0;\n        //_strncpy( m_str_, str_, m_off_ );\n    }\n    else if ( 0 != m_str_ )\n    {\n        *m_str_ = '\\0';\n        m_off_  = 0;\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::assign( char ch_, size_t sz_ )\n{\n    m_off_ = sz_;\n    if ( m_off_ >= m_sz_ )\n    {\n        if ( 0 != m_str_ )\n        {\n            delete[] m_str_;\n            m_str_ = 0;\n        }\n        m_sz_ = sz_ + 1;\n        m_str_ = new( std::nothrow ) char[ m_sz_ ];\n    }\n\n    char *_str = m_str_;\n    while( sz_-- )\n        *_str++ = ch_;\n    *_str = '\\0';\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::append( CLuaMysqlString const &str_ )\n{\n    size_t _off, _sz;\n    char  *_str;\n\n    if ( this != &str_ )\n    {\n        if ( NULL != str_.m_str_ )\n        {\n            _off = m_off_ + str_.m_off_;\n            if ( _off >= m_sz_ )\n            {\n                _sz = _off + 1;\n                _str = new( std::nothrow ) char[ _sz ];\n\n                // copy\n                if ( NULL != m_str_ )\n                {\n                    _strncpy( _str, m_str_, m_off_ );\n                    delete[] m_str_;\n                }\n\n                m_str_ = _str;\n                m_sz_  = _sz;\n            }\n\n            _strncpy( m_str_ + m_off_, str_.m_str_, str_.m_off_ );\n            m_off_ = _off;\n        }\n    }\n    else if ( NULL != m_str_ )\n    {\n        _off = m_off_ << 1;\n        if ( _off >= m_sz_ )\n        {\n            _sz  = _off + 1;\n            _str = new( std::nothrow ) char[ _sz ];\n\n            // copy\n            _strncpy( _str, m_str_, m_off_ );\n            _strncpy( _str + m_off_, m_str_, m_off_ );\n\n            delete[] m_str_;\n            m_str_ = _str;\n            m_sz_  = _sz;\n            m_off_ = _off;\n        }\n        else\n        {\n            _strncpy( m_str_ + m_off_, m_str_, m_off_ );\n            m_off_ = _off;\n        }\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::append( char const *str_ )\n{\n    size_t _off, _sz;\n    char  *_str;\n\n    if ( NULL != str_ )\n    {\n        _off = m_off_ + ::strlen( str_ );\n        if ( _off >= m_sz_ )\n        {\n            _sz  = _off + 1;\n            _str = new( std::nothrow ) char[ _sz ];\n\n            // copy\n            if ( NULL != m_str_ )\n            {\n                _strncpy( _str, m_str_, m_off_ );\n                delete[] m_str_;\n            }\n\n            m_str_ = _str;\n            m_sz_  = _sz;\n        }\n\n        _strncpy( m_str_ + m_off_, str_, _off - m_off_ );\n        m_off_ = _off;\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::append( char const *str_, size_t sz_ )\n{\n    size_t _off, _sz;\n    char  *_str;\n\n    if ( NULL != str_ && sz_ > 0 )\n    {\n        _off = m_off_ + sz_;\n        if ( _off >= m_sz_ )\n        {\n            _sz  = _off + 1;\n            _str = new( std::nothrow ) char[ _sz ];\n            // copy\n            if ( NULL != m_str_ )\n            {\n                _strncpy( _str, m_str_, m_off_ );\n                delete[] m_str_;\n            }\n\n            m_str_ = _str;\n            m_sz_  = _sz;\n        }\n\n        _strncpy( m_str_ + m_off_, str_, sz_ );\n        m_off_ = _off;\n    }\n\n    return ( *this );\n}\n\nCLuaMysqlString& CLuaMysqlString::append( char ch_, size_t sz_ )\n{\n    size_t _off, _sz;\n    char  *_str;\n\n    _off = m_off_ + sz_;\n    if ( _off >= m_sz_ )\n    {\n        _sz  = _off + 1;\n        _str = new( std::nothrow ) char[ _sz ];\n\n        // copy\n        if ( NULL != m_str_ )\n        {\n            _strncpy( _str, m_str_, m_off_ );\n            delete[] m_str_;\n            m_str_ = 0;\n        }\n\n        m_str_ = _str;\n        m_sz_  = _sz;\n    }\n\n    _str = m_str_ + m_off_;\n    while ( sz_-- )\n        *_str++ = ch_;\n    *_str = '\\0';\n    m_off_ = _off;\n\n    return ( *this );\n}\n\nint CLuaMysqlString::compare( CLuaMysqlString const &str_ ) const\n{\n    if ( this == &str_ )\n    {\n        return 0;\n    }\n    else if ( 0 != m_str_ && 0 != str_.m_str_ )\n    {\n        int     _ret = 0;\n        size_t  _sz0 = m_off_;\n        size_t  _sz1 = str_.m_off_;\n        const char *_str0 = m_str_;\n        const char *_str1 = str_.m_str_;\n\n        while ( !( _ret = (int)( *_str0 - *_str1 ) )\n                && _sz0 && _sz1 )\n        {\n            ++ _str0;\n            ++ _str1;\n            -- _sz0;\n            -- _sz1;\n        }\n\n        if ( _ret < 0 )\n            _ret = -1;\n        else if ( _ret > 0 )\n            _ret = 1;\n        else if ( _sz0 )\n            _ret = 1;\n        else if ( _sz1 )\n            _ret = -1;\n\n        return _ret;\n    }\n    else if ( 0 != m_str_ )\n    {\n        return 1;\n    }\n    else if ( 0 != str_.m_str_ )\n    {\n        return -1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nint CLuaMysqlString::compare( const char *str_ ) const\n{\n    if ( 0 != m_str_ && 0 != str_ )\n    {\n        int    _ret = 0;\n        size_t _sz0 = m_off_;\n        const char *_str0 = m_str_;\n        const char *_str1 = str_;\n\n        while ( !( _ret = (int)( *_str0 - *_str1 ) )\n                && _sz0 && *_str1 )\n        {\n            ++ _str0;\n            ++ _str1;\n            -- _sz0;\n        }\n\n        if ( _ret < 0 )\n            _ret = -1;\n        else if ( _ret > 0 )\n            _ret = 1;\n        else if ( _sz0 )\n            _ret = 1;\n        else if ( *_str1 )\n            _ret = -1;\n\n        return _ret;\n    }\n    else if ( 0 != m_str_ )\n    {\n        return 1;\n    }\n    else if ( 0 != str_ )\n    {\n        return -1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nint CLuaMysqlString::compare( const char *str_, size_t sz_ ) const\n{\n    if ( 0 != m_str_ && 0 != str_ && sz_ > 0 )\n    {\n        int     _ret = 0;\n        size_t  _sz0 = m_off_;\n        size_t  _sz1 = sz_;\n        const char *_str0 = m_str_;\n        const char *_str1 = str_;\n\n        while ( !( _ret = (int)( *_str0 - *_str1 ) )\n                && _sz0 && _sz1 )\n        {\n            ++ _str0;\n            ++ _str1;\n            -- _sz0;\n            -- _sz1;\n        }\n\n        if ( _ret < 0 )\n            _ret = -1;\n        else if ( _ret > 0 )\n            _ret = 1;\n        else if ( _sz0 )\n            _ret = 1;\n        else if ( _sz1 )\n            _ret = -1;\n\n        return _ret;\n    }\n    else if ( 0 != m_str_ && sz_ > 0 )\n    {\n        return 1;\n    }\n    else if ( 0 != str_ && sz_ > 0 )\n    {\n        return -1;\n    }\n    else\n    {\n        return 0;\n    }\n}\n\nconst char* CLuaMysqlString::c_str( void ) const\n{\n    return m_str_;\n}\n\nsize_t CLuaMysqlString::size( void ) const\n{\n    return m_off_;\n}\n\nbool CLuaMysqlString::empty( void ) const\n{\n    return ( 0 == m_off_ );\n}\n\nvoid CLuaMysqlString::clear( void )\n{\n    if ( 0 != m_str_ )\n    {\n        m_str_[0] = '\\0';\n        m_off_    = 0;\n    }\n}\n\nchar* CLuaMysqlString::_strncpy( char *dst_, char const *src_, size_t sz_ )\n{\n    if ( 0 != dst_ && 0 != src_ )\n    {\n        char *_str = dst_;\n\n        while ( sz_-- )\n            *_str++ = *src_++;\n        *_str = '\\0';\n\n        return dst_;\n    }\n\n    return 0;\n}\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_mysql/mysql_string.h",
    "content": "#ifndef LUA_MYSQL_STRING_H\n#define LUA_MYSQL_STRING_H\n\nclass CLuaMysqlString\n{\npublic:\n    CLuaMysqlString( void );\n    CLuaMysqlString( char const *str_ );\n    CLuaMysqlString( char const *str_, size_t sz_ );\n    CLuaMysqlString( CLuaMysqlString const &str_ );\n    CLuaMysqlString( char ch_, size_t sz_ );\n    CLuaMysqlString( size_t sz_ );\n    ~CLuaMysqlString( void );\n\n    // to c-string.\n    operator char const* ( void ) const;\n\n    // operator [].\n    char& operator [] ( int idx );\n\n    // operator =.\n    CLuaMysqlString& operator = ( CLuaMysqlString const &str_ );\n\n    // operator =.\n    CLuaMysqlString& operator = ( char const *str_ );\n\n    // operator =.\n    CLuaMysqlString& operator = ( char ch_ );\n\n    // operator +=.\n    CLuaMysqlString& operator += ( CLuaMysqlString const &str_ );\n\n    // operator +=.\n    CLuaMysqlString& operator += ( char const *str_ );\n\n    // operator +=.\n    CLuaMysqlString& operator += ( char ch_ );\n\n    // operator ==.\n    bool operator == ( CLuaMysqlString const &str_ ) const;\n\n    // operator ==.\n    bool operator == ( char const *str_ ) const;\n\n    // operator !=.\n    bool operator != ( CLuaMysqlString const &str_ ) const;\n\n    // operator !=.\n    bool operator != ( char const *str_ ) const;\n\n    // operator <.\n    bool operator < ( CLuaMysqlString const &str_ ) const;\n\n    // operator <.\n    bool operator < ( char const *str_ ) const;\n\n    // operator <=.\n    bool operator <= ( CLuaMysqlString const &str_ ) const;\n\n    // operator <=.\n    bool operator <= ( char const *str_ ) const;\n\n    // operator >.\n    bool operator > ( CLuaMysqlString const &str_ ) const;\n\n    // operator >.\n    bool operator > ( char const *str_ ) const;\n\n    // operator >=.\n    bool operator >= ( CLuaMysqlString const &str_ ) const;\n\n    // operator >=.\n    bool operator >= ( char const *str_ ) const;\n\n    // assign.\n    CLuaMysqlString& assign( CLuaMysqlString const &str_ );\n\n    // assign.\n    CLuaMysqlString& assign( char const *str_ );\n\n    // assign.\n    CLuaMysqlString& assign( char const *str_, size_t sz_ );\n\n    // assign.\n    CLuaMysqlString& assign( char ch_, size_t sz_ );\n\n    // append.\n    CLuaMysqlString& append( CLuaMysqlString const &str_ );\n\n    // append.\n    CLuaMysqlString& append( char const *str_ );\n\n    // append.\n    CLuaMysqlString& append( char const *str_, size_t sz_ );\n\n    // assign.\n    CLuaMysqlString& append( char ch_, size_t sz_ );\n\n    // compare.\n    int compare( CLuaMysqlString const &str_ ) const;\n\n    // compare.\n    int compare( const char *str_ ) const;\n\n    // compare.\n    int compare( const char *str_, size_t sz_ ) const;\n\n    // c-string.\n    const char* c_str( void ) const;\n\n    // size.\n    size_t size( void ) const;\n\n    // empty.\n    bool empty( void ) const;\n\n    // clear.\n    void clear( void );\n\nprivate:\n    // strncpy.\n    char* _strncpy( char *dst_, char const *src_, size_t sz_ );\n\nprivate:\n    char  *m_str_;\n    size_t m_off_;\n    size_t m_sz_;\n};\n\n\n\n#endif // LUA_MYSQL_STRING_H"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_callback_client.cpp",
    "content": "#include \"lua_callback_client.h\"\n#include \"lua_message.h\"\n#include <server_share/lua/script_mgr.h>\n#include <nel/net/buf_client.h>\n#include <nel/net/callback_client.h>\n\nusing namespace bin;\nusing namespace NLNET;\n\nvoid forLuaCallbackClientForceLink()\n{\n    nlwarning(\"forLuaCallbackClientForceLink\");\n}\n\nvoid cbLuaClientMsg(CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n    CLuaCallbackClient* pClient = (CLuaCallbackClient*)netbase.getUserData();\n\n    CScriptTable    functbl;\n    pClient->GetScriptHandle().Get(\"NetWorkHandler\", functbl);\n\n    pClient->m_LuaTmpMsg->m_Msg.swap(msgin);\n    sint32 nRet = 0;\n    sint32 _hdl = pClient->GetHandle();\n\n    functbl.CallFunc<sint32, CLuaMessage*, sint32>(\"OnMessage\", _hdl, pClient->m_LuaTmpMsg, nRet);\n}\n\nCLuaCallbackClient::CLuaCallbackClient( std::string& protocal, sint32 thd_handle/*=-1*/)\n    : m_Protocal(protocal), m_MyHandle(0)\n{\n    if ( protocal==\"tcp\" )\n    {\n        CCallbackClient* pClient = new CCallbackClient();\n        //pClient->setConnectionCallback( cbLuaSvrConnect, this );\n        //pClient->setDisconnectionCallback( cbLuaSvrDisConnect, this );\n        pClient->setDefaultCallback(cbLuaClientMsg);\n\n        m_CallbackClientHandle = pClient;\n    }\n\n    m_LuaTmpMsg = new CLuaMessage();\n    m_CallbackClientHandle->setUserData(this);\n    nlassert(m_CallbackClientHandle !=NULL);\n}\n\nCLuaCallbackClient::~CLuaCallbackClient()\n{\n    delete m_CallbackClientHandle;\n    delete m_LuaTmpMsg;\n}\n\nvoid CLuaCallbackClient::Connect(std::string & url)\n{\n    CInetAddress addr(url);\n    CCallbackClient* pClient = (CCallbackClient*)m_CallbackClientHandle;\n    pClient->connect(addr);\n}\n\n///////////////////\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS(LuaCallbackClient, CLuaCallbackClient)\n\n    DEFINE_CLASS_FUNCTION(Send, void, (CLuaMessage* lua_msg))\n    {\n        obj->Send(lua_msg->m_Msg);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(DisConnect, void, ())\n    {\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(Connect, void, (std::string& url))\n    {\n        obj->Connect(url);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(SetHandle, void, (sint32 client_handle))\n    {\n        obj->SetHandle(client_handle);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(GetHandle, sint32, ())\n    {\n        r = obj->GetHandle();\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(Connected, bool, ())\n    {\n        r = obj->Connected();\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(Update, void, ())\n    {\n        obj->Update();\n        return 1;\n    }\n    \n\n    DEFINE_STATIC_FUNCTION(NewInstance, CLuaCallbackClient*, (std::string& protoc))\n    {\n        r = new CLuaCallbackClient(protoc);\n        r->GetScriptObject().SetDelByScr(true);\n        return 1;\n    }\n\n    END_SCRIPT_CLASS()\n\n\n}\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_callback_client.h",
    "content": "#ifndef SERVER_SHARD_LUA_CALLBACK_CLIENT_H\n#define SERVER_SHARD_LUA_CALLBACK_CLIENT_H\n\n#include <nel/misc/singleton.h>\n#include \"lua_network.h\"\n#include <server_share/game_def.h>\n#include <server_share/server_def.h>\n#include <server_share/bin_luabind/Public.hpp>\n\nnamespace bin {\n    class CScriptHandle;\n}\n\nclass CLuaMessage;\n\nclass CLuaCallbackClient\n{\n    DECLARE_SCRIPT_CLASS()\npublic:\n\n    CLuaCallbackClient( std::string& protocal, sint32 thd_handle=-1 );\n    ~CLuaCallbackClient();\n\n    void    Connect( std::string& url );\n\n\n    void    Update()\n    {\n        if(m_CallbackClientHandle->connected() )\n        {\n            m_CallbackClientHandle->update();\n        }\n    }\n\n    void    Send( const NLNET::CMessage &buffer )\n    {\n        if (m_CallbackClientHandle->connected())\n        {\n            m_CallbackClientHandle->send(buffer);\n        }\n    }\n\n    bool                Connected() { return m_CallbackClientHandle->connected(); }\n    uint32              GetHandle() { return m_MyHandle; }\n    void                SetHandle(uint32 handle) { m_MyHandle = handle; }\n\n    uint32              m_MyHandle;\n    CLuaMessage*        m_LuaTmpMsg;\n\nprivate:\n\n    std::string                                             m_Protocal;\n\n    NLNET::CCallbackNetBase*                                m_CallbackClientHandle;\n\n    std::string                                             m_StrBuffer;\n    std::string                                             m_SaveEventStr;\n};\n\n#endif          // SERVER_SHARD_LUA_CALLBACK_CLIENT_H\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_callback_server.cpp",
    "content": "#include \"lua_callback_server.h\"\n#include \"lua_message.h\"\n#include <server_share/lua/script_mgr.h>\n#include <nel/net/callback_server_websocket.h>\n#include <nel/net/callback_server_tcp.h>\n#include <server_share/client_msg_desc.h>\n\nusing namespace bin;\nusing namespace NLNET;\n\nNLMISC::CVariable<bool>\tVAR_MSG_COUNT(\"fes\", \"MsgCount\", \"memo\", false, 0, true);\nNLMISC::CVariable<bool>\tVAR_SAVE_EVENT(\"fes\", \"SaveEvent\", \"memo\", false, 0, true);\n\nvoid cbLuaServiceMsg ( CMessage &msgin, TSockId from, CCallbackNetBase &netbase )\n{\n    CLuaCallbackServer* pServer = (CLuaCallbackServer*)netbase.getUserData();\n    LuaNetworkMgr.IncReceiveMsgCount(msgin.getName());\n\n    MsgLeaf* pMsgLeaf = MsgDesc.GetMsgLeaf( msgin.getName() );\n\n    if ( pMsgLeaf!=NULL )\n    {\n        ClientData* pClient = pServer->GetClientData(from);\n\n        if ( pClient != NULL )\n        {\n            pServer->ForwardingMsg( pClient, msgin, pMsgLeaf );\n        }\n    }\n    else\n    {\n        CScriptTable    functbl;\n        ScriptMgr.GetScriptHandle()->Get(\"NetWorkHandler\", functbl);\n\n        pServer->m_LuaTmpMsg->m_Msg.swap(msgin);\n        sint32 nRet = 0;\n        sint64 _from = (sint64)from;\n\n        functbl.CallFunc<sint64, CLuaMessage*, sint32>(\"OnMessage\", _from, pServer->m_LuaTmpMsg, nRet);\n    }\n}\n\nCLuaCallbackServer::CLuaCallbackServer( std::string& name, std::string& protocal ) : m_NetName(name), m_Protocal(protocal)\n{\n    if( protocal==\"wss\" || protocal==\"ws\" )\n    {\n        CCallbackServerWebSocket* pServer = new CCallbackServerWebSocket();\n        pServer->setConnectionCallback( cbLuaSvrConnect, this );\n        pServer->setDisconnectionCallback( cbLuaSvrDisConnect, this );\n        pServer->setDefaultCallback(cbLuaServiceMsg);\n\n        m_CallbackServerHandle = pServer;\n    }\n    else if ( protocal==\"tcp\" )\n    {\n        CCallbackServerTcp* pServer = new CCallbackServerTcp();\n        pServer->setConnectionCallback( cbLuaSvrConnect, this );\n        pServer->setDisconnectionCallback( cbLuaSvrDisConnect, this );\n        pServer->setDefaultCallback(cbLuaServiceMsg);\n\n        m_CallbackServerHandle = pServer;\n    }\n\n    m_LuaTmpMsg = new CLuaMessage();\n    m_CallbackServerHandle->setUserData(this);\n\n    nlassert(m_CallbackServerHandle!=NULL);\n    LuaNetworkMgr.RegisterNetModule( name, this );\n}\n\nCLuaCallbackServer::~CLuaCallbackServer()\n{\n    LuaNetworkMgr.RemoveNetModule(m_NetName);\n    delete m_CallbackServerHandle; \n    delete m_LuaTmpMsg;\n}\n\nvoid CLuaCallbackServer::Listen( uint16 port )\n{\n    if ( m_Protocal==\"wss\" )\n    {\n        CCallbackServerWebSocket* pServer = (CCallbackServerWebSocket*)m_CallbackServerHandle;\n        pServer->setupSsl( m_SslCA, m_SslCrt, m_SslPrvKey );\n        pServer->init(port);\n    }\n    else if ( m_Protocal==\"ws\" )\n    {\n        ((CCallbackServerWebSocket*)m_CallbackServerHandle)->init(port);\n    }\n    else if( m_Protocal==\"tcp\" )\n    {\n        ((CCallbackServerTcp*)m_CallbackServerHandle)->init(port);\n    }\n}\n\nbool CLuaCallbackServer::ForwardingMsg( ClientData* pClient, NLNET::CMessage& msgin, MsgLeaf* pMsgLeaf )\n{\n    google::protobuf::Message* pMessage = NULL;\n\n    try\n    {\n        NLNET::CMessage  msgout( pMsgLeaf->msgname );\n        std::vector<MSG_FORMAT::TMsgFormat>& format = pMsgLeaf->format;\n        std::vector<std::string>& format_msg = pMsgLeaf->format_msg;\n        m_SaveEventStr.clear();\n        uint64  id = 0;\n\n        for ( uint i=0,j=0; i<format.size(); ++i )\n        {\n            switch (format[i])\n            {\n            case MSG_FORMAT::UID:\n                {\n                    msgout.serial(pClient->uid);\n                    id = pClient->uid;\n                    break;\n                }\n            case MSG_FORMAT::PLS:\n                {\n                    msgout.serial(pClient->pls_sid);\n                    break;\n                }\n            case MSG_FORMAT::JSON:\n                {\n                    msgin.serial(m_StrBuffer);\n                    // check json\n                    msgout.serial(m_StrBuffer);\n\n                    if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event )\n                    {\n                        m_SaveEventStr.append( \" \" );\n                        m_SaveEventStr.append( m_StrBuffer );\n                    }\n\n                    break;\n                }\n            case MSG_FORMAT::ProtoMsg:\n                {\n                    if ( j>=format_msg.size() )\n                    {\n                        return false;\n                    }\n\n                    pMessage = MsgDesc.CreateMessage(format_msg[j]);\n\n                    if ( pMessage!=NULL )\n                    {\n                        msgin.serial(pMessage);\n                        msgout.serial(pMessage);\n\n                        if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event )\n                        {\n                            m_SaveEventStr.append( \" \" );\n                            m_SaveEventStr.append( pMessage->ShortDebugString() );\n                        }\n\n                        SAFE_DELETE(pMessage);\n                    }\n                    else\n                    {\n                        nlwarning(\"msg:% define not found.\", format_msg[j].c_str());\n                        return false;\n                    }\n                    break;\n                }\n            case MSG_FORMAT::d:\n                {\n                    double   double_val;\n                    msgin.serial(double_val);\n                    msgout.serial(double_val);\n                    break;\n                }\n            case MSG_FORMAT::b:\n                {\n                    bool   bool_val;\n                    msgin.serial(bool_val);\n                    msgout.serial(bool_val);\n                    break;\n                }\n            case MSG_FORMAT::s:\n                {\n                    msgin.serial(m_StrBuffer);\n                    msgout.serial(m_StrBuffer);\n                    break;\n                }\n            case MSG_FORMAT::s8:\n                {\n                    sint8   sint8_val;\n                    msgin.serial(sint8_val);\n                    msgout.serial(sint8_val);\n                    break;\n                }\n            case MSG_FORMAT::s16:\n                {\n                    sint16   sint16_val;\n                    msgin.serial(sint16_val);\n                    msgout.serial(sint16_val);\n                    break;\n                }\n            case MSG_FORMAT::s32:\n                {\n                    sint32   sint32_val;\n                    msgin.serial(sint32_val);\n                    msgout.serial(sint32_val);\n                    break;\n                }\n            case MSG_FORMAT::s64:\n                {\n                    sint64   sint64_val;\n                    msgin.serial(sint64_val);\n                    msgout.serial(sint64_val);\n                    break;\n                }\n            case MSG_FORMAT::u8:\n                {\n                    uint8   uint8_val;\n                    msgin.serial(uint8_val);\n                    msgout.serial(uint8_val);\n                    break;\n                }\n            case MSG_FORMAT::u16:\n                {\n                    uint16   uint16_val;\n                    msgin.serial(uint16_val);\n                    msgout.serial(uint16_val);\n                    break;\n                }\n            case MSG_FORMAT::u32:\n                {\n                    uint32   uint32_val;\n                    msgin.serial(uint32_val);\n                    msgout.serial(uint32_val);\n                    break;\n                }\n            case MSG_FORMAT::u64:\n                {\n                    uint64   uint64_val;\n                    msgin.serial(uint64_val);\n                    msgout.serial(uint64_val);\n                    break;\n                }\n            default:\n                return false;\n            }\n        }\n\n        std::vector<std::string>& sendto = pMsgLeaf->sendto;\n        for ( uint i=0; i<sendto.size(); ++i )\n        {\n            if ( sendto[i] == LogicService )\n            {\n                if ( pClient->pls_sid != NLNET::TServiceId::InvalidId )\n                {\n                    NLNET::CMessage msgluasvr(\"_LS\");\n                    msgluasvr.serialMessage(msgout);\n                    Network->send( pClient->pls_sid, msgluasvr );\n                }\n            }\n            else\n            {\n                NLNET::CMessage msgluasvr(\"_LS\");\n                msgluasvr.serialMessage(msgout);\n                Network->send ( sendto[i], msgluasvr );\n            }\n        }\n\n        if ( VAR_SAVE_EVENT && pMsgLeaf->is_log_event )\n        {\n            //LogEvent( id, msgin.getName(), m_SaveEventStr.strip() );\n        }\n\n        return true;\n    }\n    catch (NLMISC::Exception &)\n    {\n        SAFE_DELETE(pMessage);\n        return false;\n    }\n\n    return false;\n}\n\nNLMISC_COMMAND (topmsg, \"\", \"\")\n{\n    if(args.size() != 0) return false;\n\n    CLuaNetworkMgr::TMsgCount::iterator iter,it_end;\n    iter    = LuaNetworkMgr.m_ReceiveMsgCount.begin();\n    it_end  = LuaNetworkMgr.m_ReceiveMsgCount.end();\n\n\n    std::multimap<uint64, std::string>  sortmap;\n\n    while ( iter!=it_end )\n    {\n        sortmap.insert( make_pair( iter->second, iter->first ) );\n        ++iter;\n    }\n\n    std::multimap<uint64, std::string>::reverse_iterator riter,rit_end;\n    riter    = sortmap.rbegin();\n    rit_end  = sortmap.rend();\n\n    while ( riter!=rit_end )\n    {\n        log.displayNL(\"Count: %\" NL_I64 \"u       Msg: %s\", riter->first, riter->second.c_str() );\n        ++riter;\n    }\n\n    return true;\n}\n\nNLMISC_COMMAND (loadmsg, \"\", \"\")\n{\n    if(args.size() != 0) return false;\n\n    MsgDesc.LoadMsgXml();\n    log.displayNL (\"ReLoadMsgXml Done.\");\n\n    return true;\n}\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_callback_server.h",
    "content": "#ifndef SERVER_SHARD_LUA_CALLBACK_SERVER_H\n#define SERVER_SHARD_LUA_CALLBACK_SERVER_H\n\n#include <nel/misc/singleton.h>\n#include \"lua_network.h\"\n#include <server_share/game_def.h>\n#include <server_share/server_def.h>\n#include <server_share/bin_luabind/Public.hpp>\n\nstruct  ClientData\n{\n    DEF::UID            uid;\n    NLNET::TSockId      sid;\n    NLNET::TServiceId   pls_sid;\n};\n\nstruct  MsgLeaf;\nclass   CLuaMessage;\n\nclass CLuaCallbackServer\n{\n    DECLARE_SCRIPT_CLASS()\npublic:\n\n    CLuaCallbackServer( std::string& name, std::string& protocal );\n    ~CLuaCallbackServer();\n\n    void    Listen( uint16 port );\n\n    void    LoadSslCA( std::string ssl_ca )             { m_SslCA       = ssl_ca;   }\n    void    LoadSslCrt( std::string ssl_crt )           { m_SslCrt      = ssl_crt;  }\n    void    LoadSslPrivateKey( std::string ssl_pk )     { m_SslPrvKey   = ssl_pk;   }\n\n    void    Update()\n    {\n        if( m_CallbackServerHandle->connected() )\n        {\n            m_CallbackServerHandle->update();\n        }\n    }\n\n    void    Send( NLNET::TSockId sock_id, const NLNET::CMessage &buffer )\n    {\n        m_CallbackServerHandle->send( buffer, sock_id );\n    }\n\n    bool    ForwardingMsg( ClientData* pClient, NLNET::CMessage& msgin, MsgLeaf* pMsgLeaf );\n\n    void    DisConnect(NLNET::TSockId sock_id)\n    {\n        m_CallbackServerHandle->disconnect(sock_id);\n    }\n\n    void    SetClientData( ClientData& client_data )\n    {\n        TClientMap::iterator iter = m_ClientMap.find( client_data.uid );\n\n        if ( iter != m_ClientMap.end() )\n        {\n            m_SockClient.erase(iter->second.sid);\n            m_SockClient[client_data.sid] = client_data;\n\n            iter->second.sid        = client_data.sid;\n            iter->second.pls_sid    = client_data.pls_sid;\n        }\n        else\n        {\n            m_ClientMap[client_data.uid]    = client_data;\n            m_SockClient[client_data.sid]   = client_data;\n        }\n    }\n    void    RemoveClientData( DEF::UID uid )\n    {\n        TClientMap::iterator iter = m_ClientMap.find( uid );\n\n        if ( iter != m_ClientMap.end() )\n        {\n            m_SockClient.erase(iter->second.sid);\n            m_ClientMap.erase(uid); \n        }\n    }\n\n    void    ClearClientData()\n    {\n        m_SockClient.clear();\n        m_ClientMap.clear(); \n    }\n\n    NLNET::TSockId     GetSockId( DEF::UID uid )           \n    {\n        TClientMap::iterator iter = m_ClientMap.find(uid);\n        if ( iter != m_ClientMap.end() )\n        {\n            return iter->second.sid;\n        }\n\n        return NLNET::InvalidSockId;\n    }\n\n    ClientData*         GetClientData( NLNET::TSockId sock_id )\n    {\n        ClientData* pClient = NULL;\n        TSockClient::iterator iter = m_SockClient.find(sock_id);\n\n        if ( iter != m_SockClient.end() )\n        {\n            pClient = &iter->second;\n        }\n\n        return pClient;\n    }\n\n    std::string         GetName()   { return m_NetName; }\n\n    CLuaMessage*        m_LuaTmpMsg;\n\nprivate:\n\n    std::string                                             m_NetName;\n    std::string                                             m_Protocal;\n\n    typedef     std::map<DEF::UID, ClientData>              TClientMap;\n    TClientMap                                              m_ClientMap;\n\n    typedef     std::map<NLNET::TSockId, ClientData>        TSockClient;\n    TSockClient                                             m_SockClient;\n\n    NLNET::CCallbackNetBase*                                m_CallbackServerHandle;\n\n    std::string                                             m_StrBuffer;\n    std::string                                             m_SaveEventStr;\n\n    std::string         m_SslCA;\n    std::string         m_SslCrt;\n    std::string         m_SslPrvKey;\n};\n\n#endif          // SERVER_SHARD_LUA_CALLBACK_SERVER_H\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_message.cpp",
    "content": "#include \"lua_message.h\"\n\nvoid forLuaMessageForceLink()\n{\n    nlwarning(\"forLuaMessageForceLink\");\n}\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( LuaMessage, CLuaMessage )\n\n    DEFINE_CLASS_FUNCTION( invert, void, ())\n    {\n        obj->m_Msg.invert();\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( name, std::string, ())\n    {\n        r = obj->m_Msg.getName();\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( clear, void, (std::string name))\n    {\n        obj->m_Msg.clear();\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wbuffer, void, (const char* buff, int len))\n    {\n        sint32  serial_val=len;\n        obj->m_Msg.serial(serial_val);\n        obj->m_Msg.serialBuffer((uint8*)buff, len);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wstring, void, (std::string& str))\n    {\n        obj->m_Msg.serial(str);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(wtable, void, (CScriptTable& tbl))\n    {\n        try\n        {\n            std::string json_str = \"\";\n            obj->GetScriptHandle().CallFunc<CScriptTable&, std::string>(\"Table2Json\", tbl, json_str);\n            obj->m_Msg.serial(json_str);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(), 1, &ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name);\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"wtable exception\");\n        }\n        return 1;\n    }\n\n\n    DEFINE_CLASS_FUNCTION( wbool, void, (bool in_val))\n    {\n        obj->m_Msg.serial(in_val);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wint, void, (sint64 in_val))\n    {\n        obj->m_Msg.serial(in_val);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wint32, void, (sint32 in_val))\n    {\n        obj->m_Msg.serial(in_val);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wint64, void, (sint64 in_val))\n    {\n        obj->m_Msg.serial(in_val);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( wuint32, void, (sint64 in_val))\n    {\n        uint32  serial_val=in_val;\n        obj->m_Msg.serial(serial_val);\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rbool, bool, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rbool is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rint32, sint32, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rint32 is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( ruint32, sint64, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            uint32  result=0;\n            obj->m_Msg.serial(result);\n            r = result;\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"ruint32 is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rint64, sint64, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rint64 is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rdouble, double, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rdouble is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rint, sint64, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rint is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rstring, std::string, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rstring is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION(rbuffer, std::string, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            obj->m_Msg.serial(r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(), 1, &ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name);\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rbuffer is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rtable, CScriptTable, ())\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            std::string json_str;\n            obj->m_Msg.serial(json_str);\n            obj->GetScriptHandle().NewTable(r);\n            obj->GetScriptHandle().CallFunc<std::string&, CScriptTable>( \"Json2Table\", json_str, r );\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rtable is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_CLASS_FUNCTION( rpb, CScriptTable, (std::string& pbstru))\n    {\n        nlassert(obj->m_Msg.isReading());\n        try\n        {\n            std::string pb_data;\n            obj->m_Msg.serial(pb_data);\n            obj->GetScriptHandle().NewTable(r);\n\n            CScriptTable    functbl;\n            obj->GetScriptHandle().Get(\"protobuf\", functbl);\n            functbl.CallFunc<std::string&, std::string&, CScriptTable>(\"decode\", pbstru, pb_data, r);\n        }\n        catch (const NLMISC::EStream&)\n        {\n            lua_Debug ar;\n            lua_getstack(obj->GetScriptHandle().GetHandle(),1,&ar);\n            lua_getinfo(obj->GetScriptHandle().GetHandle(), \"Sln\", &ar);\n\n            NLMISC::createDebug();\n            NLMISC::INelContext::getInstance().getWarningLog()->setPosition( ar.currentline, ar.short_src, ar.name );\n            NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"rpb is nil\");\n        }\n        return 1;\n    }\n\n    DEFINE_STATIC_FUNCTION(NewInstance, CLuaMessage*, (std::string name))\n    {\n        r = new CLuaMessage(name);\n        r->GetScriptObject().SetDelByScr(true);\n\n        return 1;\n    }\n\n    END_SCRIPT_CLASS()\n}\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_message.h",
    "content": "#ifndef SERVER_SHARD_LUA_NETWORK_MESSAGE_H\n#define SERVER_SHARD_LUA_NETWORK_MESSAGE_H\n\n#include <nel/net/message.h>\n#include \"server_share/bin_luabind/Public.hpp\"\n\nclass CLuaMessage\n{\n    DECLARE_SCRIPT_CLASS();\npublic:\n\n    CLuaMessage() {}\n\n    CLuaMessage( std::string& name )\n    {\n        m_Msg.setType(name);\n    }\n\n    NLNET::CMessage             m_Msg;\n};\n\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_network.cpp",
    "content": "#include \"lua_network.h\"\n#include \"lua_message.h\"\n#include \"lua_callback_server.h\"\n#include <server_share/lua/script_mgr.h>\n#include \"server_share/bin_luabind/Public.hpp\"\n#include \"curl/curl.h\"\n\nusing namespace NLMISC;\nusing namespace NLNET;\n\nstatic CLuaMessage* pUnifiedServiceMsg = new CLuaMessage();\n\nvoid cbLuaUnifiedServiceMsg ( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )\n{\n    uint32 subSize;\n    msgin.serial(subSize);\n    msgin.lockSubMessage(subSize);\n\n    pUnifiedServiceMsg->m_Msg.clear();\n    pUnifiedServiceMsg->m_Msg.assignFromSubMessage(msgin);\n\n    msgin.unlockSubMessage();\n\n\n    bin::CScriptTable    functbl;\n    ScriptMgr.GetScriptHandle()->Get(\"NetWorkHandler\", functbl);\n\n    sint32 nRet = 0;\n    sint32 _sid = serviceId.get();\n    functbl.CallFunc<sint32, CLuaMessage*, sint32>(\"OnMessage\", _sid, pUnifiedServiceMsg, nRet);\n}\n\n\n\n///  תͻ\nvoid cbLuaSendToClientMsg ( NLNET::CMessage& msgin, const std::string &serviceName, NLNET::TServiceId serviceId )\n{\n    DEF::UID        client_uid;\n    msgin.serial(client_uid);\n\n    uint32 subSize;\n    msgin.serial(subSize);\n    msgin.lockSubMessage(subSize);\n\n    pUnifiedServiceMsg->m_Msg.clear();\n    pUnifiedServiceMsg->m_Msg.assignFromSubMessage(msgin);\n\n    msgin.unlockSubMessage();\n\n    LuaNetworkMgr.SendToClient( client_uid, pUnifiedServiceMsg->m_Msg );\n}\n\nNLNET::TUnifiedCallbackItem LuaCallbackArray[] =\n{\n    { \"_LS\",                            cbLuaUnifiedServiceMsg          },\n    { \"_LSC\",                           cbLuaSendToClientMsg            },\n};\n\nvoid CLuaNetworkMgr::Init()\n{\n    NLNET::CUnifiedNetwork::getInstance()->addCallbackArray(LuaCallbackArray, sizeof(LuaCallbackArray)/sizeof(LuaCallbackArray[0]));\n}\n\nvoid CLuaNetworkMgr::RegisterNetModule( std::string name, CLuaCallbackServer* pNet )\n{\n    TNetHandle::iterator iter = m_LuaClientNetworkHandle.find(name);\n\n    if ( iter == m_LuaClientNetworkHandle.end() )\n    {\n        m_LuaClientNetworkHandle.insert( make_pair(name, pNet) ); \n    }\n    else\n    {\n        nlstop;\n    }\n}\n\nvoid CLuaNetworkMgr::RemoveNetModule( std::string name )\n{\n    m_LuaClientNetworkHandle.erase(name);\n}\n\nvoid CLuaNetworkMgr::Update()\n{\n    H_AUTO(CLuaNetworkMgrUpdate);\n    TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin();\n\n    while (iter!=m_LuaClientNetworkHandle.end())\n    {\n\n        iter->second->Update();\n        ++iter;\n    }\n}\n\nvoid CLuaNetworkMgr::Release()\n{\n    TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin();\n\n    while (iter!=m_LuaClientNetworkHandle.end())\n    {\n\n        delete iter->second;\n        ++iter;\n    }\n\n    m_LuaClientNetworkHandle.clear();\n}\n\nvoid CLuaNetworkMgr::SendToClient( uint64 uid, NLNET::CMessage& msgin )\n{\n    TNetHandle::iterator iter = m_LuaClientNetworkHandle.begin();\n\n    while ( iter != m_LuaClientNetworkHandle.end() )\n    {\n        TSockId sock_id = iter->second->GetSockId(uid);\n\n        if ( sock_id != InvalidSockId )\n        {\n            iter->second->Send( sock_id, msgin );\n        }\n\n        ++iter;\n    }\n}\n\nvoid CLuaNetworkMgr::IncReceiveMsgCount(std::string msg_name)\n{\n    TMsgCount::iterator iter = m_ReceiveMsgCount.find(msg_name);\n\n    if (iter != m_ReceiveMsgCount.end())\n    {\n        iter->second += 1;\n    }\n    else\n    {\n        m_ReceiveMsgCount.insert(make_pair(msg_name, 1));\n    }\n}\n\nvoid cbLuaSvrConnect( TSockId from, void *arg )\n{\n    CLuaCallbackServer* pLuaNetwork = (CLuaCallbackServer*)arg;\n\n    std::string lua_event = pLuaNetwork->GetName();\n    lua_event.append(\"Con\");\n\n    uint64          msg_from = (uint64)from;\n    std::string     msg_buff;\n\n    LuaParams lua_params( msg_from, lua_event, msg_buff );\n\n    ScriptMgr.run( \"NetWorkHandler\", \"OnNetEvent\", lua_params );\n}\n\nvoid cbLuaSvrDisConnect( TSockId from, void *arg )\n{\n    CLuaCallbackServer* pLuaNetwork = (CLuaCallbackServer*)arg;\n\n    std::string lua_event = pLuaNetwork->GetName();\n    lua_event.append(\"Dis\");\n\n    uint64          msg_from = (uint64)from;\n    std::string     msg_buff;\n\n\n    LuaParams lua_params( msg_from, lua_event, msg_buff );  \n    ScriptMgr.run( \"NetWorkHandler\", \"OnNetEvent\", lua_params );\n}\n\nvoid cbConnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg )\n{\n    std::string lua_event = serviceName;\n    lua_event.append(\"Con\");\n    LuaParams lua_params( (uint64)sid.get(), lua_event, serviceName );  \n    ScriptMgr.run( \"NetWorkHandler\", \"OnNetEvent\", lua_params );\n}\n\nvoid cbDisconnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg )\n{\n    std::string lua_event = serviceName;\n    lua_event.append(\"Dis\");\n    LuaParams lua_params( (uint64)sid.get(), lua_event, serviceName );  \n    ScriptMgr.run( \"NetWorkHandler\", \"OnNetEvent\", lua_params );\n}\n\nstatic size_t WriteDataFromCurl(char* buffer, size_t size, size_t nmemb, NLMISC::CSString* pWriterData)\n{\n    if (pWriterData == NULL)\n        return 0;\n\n    pWriterData->append(buffer, size*nmemb);\n    return size * nmemb;\n}\n\nstd::string HttpPost(std::string& url, std::string& params)\n{\n    std::string m_WriterData;\n\n    try\n    {\n        CURL* pCurl = curl_easy_init();\n\n        if (pCurl != NULL)\n        {\n            curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str());\n            curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L);\n\n            curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteDataFromCurl);\n            curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &m_WriterData);\n\n            /* Now specify the POST data */\n            curl_easy_setopt(pCurl, CURLOPT_POSTFIELDS, params.c_str());\n\n            /* Perform the request, res will get the return code */\n            CURLcode res = curl_easy_perform(pCurl);\n\n            curl_easy_cleanup(pCurl);\n            /* Check for errors */\n            if (res != CURLE_OK)\n            {\n                nlwarning(\"CLuaHttpRequest Post() failed: %s\\n\", curl_easy_strerror(res));\n            }\n        }\n    }\n    catch (...)\n    {\n\n    }\n\n    return m_WriterData;\n}\n\nstd::string HttpGet(std::string& url)\n{\n    std::string m_WriterData;\n\n    try\n    {\n        CURL* pCurl = curl_easy_init();\n\n        if (pCurl != NULL)\n        {\n            curl_easy_setopt(pCurl, CURLOPT_URL, url.c_str());\n            curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, 0L);\n\n            curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, WriteDataFromCurl);\n            curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, &m_WriterData);\n\n            /* Perform the request, res will get the return code */\n            CURLcode res = curl_easy_perform(pCurl);\n\n            curl_easy_cleanup(pCurl);\n            /* Check for errors */\n            if (res != CURLE_OK)\n            {\n                nlwarning(\"CLuaHttpRequest Get() failed: %s\\n\", curl_easy_strerror(res));\n            }\n        }\n    }\n    catch (...)\n    {\n\n    }\n\n    return m_WriterData;\n}\n\nnamespace bin\n{\n    BEGIN_SCRIPT_CLASS( LuaCallbackServer, CLuaCallbackServer )\n\n        DEFINE_CLASS_FUNCTION( Send, void, (sint64 sock_id, CLuaMessage* lua_msg))\n        {\n            obj->Send( (TSockId)sock_id, lua_msg->m_Msg );\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( SetClientData, void, (CScriptTable& uid_data))\n        {\n            if( uid_data.IsReferd() )\n            {\n                ClientData      cdata;\n                sint64          int64_val;\n\n                uid_data.Get(1, int64_val);         cdata.uid   = int64_val;\n                uid_data.Get(2, int64_val);         cdata.sid   = (NLNET::TSockId)int64_val;\n                uid_data.Get(3, int64_val);         cdata.pls_sid.set(int64_val);\n\n                obj->SetClientData( cdata );\n            }\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( DisConnect, void, (sint64 sock_id) )\n        {\n            obj->DisConnect((NLNET::TSockId)sock_id);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( RemoveClientData, void, (sint64 uid))\n        {\n            obj->RemoveClientData( uid );\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( ClearClientData, void, ())\n        {\n            obj->ClearClientData();\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( Listen, void, (sint32 port))\n        {\n            obj->Listen(port);\n            return 1;\n        }\n\n        DEFINE_CLASS_FUNCTION( LoadSslCA, void, (std::string& ssl_ca))\n        {\n            obj->LoadSslCA(ssl_ca);\n            return 1;\n        }\n        DEFINE_CLASS_FUNCTION( LoadSslCrt, void, (std::string& ssl_crt))\n        {\n            obj->LoadSslCrt(ssl_crt);\n            return 1;\n        }\n        DEFINE_CLASS_FUNCTION( LoadSslPrivateKey, void, (std::string& ssl_pk))\n        {\n            obj->LoadSslPrivateKey(ssl_pk);\n            return 1;\n        }\n\n        DEFINE_STATIC_FUNCTION(NewInstance, CLuaCallbackServer*, (std::string& svr_name, std::string& svr_protoc))\n        {\n            r = new CLuaCallbackServer(svr_name, svr_protoc);\n            r->GetScriptObject().SetDelByScr(true);\n            return 1;\n        }\n\n    END_SCRIPT_CLASS()\n\n\n    ///   \n    BEGIN_SCRIPT_MODULE(Net)\n\n        DEFINE_MODULE_FUNCTION(Broadcast, void, (const char* service_name, CLuaMessage* pMsg))\n        {\n            if( pMsg != NULL )\n            {\n                NLNET::CMessage msgout(\"_LS\");\n                msgout.serialMessage(pMsg->m_Msg);\n                Network->send(service_name, msgout, false);\n            }\n            else\n            {\n                lua_Debug ar;\n                lua_getstack(lua.GetHandle(), 2, &ar);\n                lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n                NLMISC::createDebug();\n                NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name);\n                NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"Broadcast %s  msg is NULL.\", service_name);\n            }\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(Send, void, (sint32 service_id, CLuaMessage* pMsg))\n        {\n            if (pMsg != NULL)\n            {\n                NLNET::CMessage msgout(\"_LS\");\n                msgout.serialMessage(pMsg->m_Msg);\n                Network->send( (NLNET::TServiceId)service_id, msgout );\n            }\n            else\n            {\n                lua_Debug ar;\n                lua_getstack(lua.GetHandle(), 2, &ar);\n                lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n                NLMISC::createDebug();\n                NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name);\n                NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"Send msg is NULL.\");\n            }\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(SendToClient, void, (CLuaMessage* pMsg, CScriptTable& tb_msg))\n        {\n            if( tb_msg.IsReferd() )\n            {\n                if (pMsg != NULL)\n                {\n                    int             sid;\n                    sint64          client_uid;\n\n                    tb_msg.Get(1, sid);\n                    tb_msg.Get(2, client_uid);\n\n                    CMessage msg_out(\"_LSC\");\n                    msg_out.serial(client_uid);\n                    msg_out.serialMessage(pMsg->m_Msg);\n\n                    Network->send((NLNET::TServiceId)sid, msg_out);\n                }\n                else\n                {\n                    lua_Debug ar;\n                    lua_getstack(lua.GetHandle(), 2, &ar);\n                    lua_getinfo(lua.GetHandle(), \"Sln\", &ar);\n\n                    NLMISC::createDebug();\n                    NLMISC::INelContext::getInstance().getWarningLog()->setPosition(ar.currentline, ar.short_src, ar.name);\n                    NLMISC::INelContext::getInstance().getWarningLog()->displayNL(\"SendToClient msg is NULL.\");\n                }\n            }\n\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(SetConnectionCallback, void, (std::string service_name))\n        {\n            CUnifiedNetwork::getInstance()->setServiceUpCallback(service_name, cbConnection);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(SetDisConnectionCallback, void, (std::string service_name))\n        {\n            CUnifiedNetwork::getInstance()->setServiceDownCallback(service_name, cbDisconnection);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(GetServiceID, int, ())\n        {\n            r = NLNET::IService::getInstance()->getServiceId().get();\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(GetServiceName, std::string, ())\n        {\n            r = NLNET::IService::getInstance()->getServiceShortName();;\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(HttpPost, std::string, (std::string& url, std::string& params))\n        {\n            r = HttpPost(url, params);\n            return 1;\n        }\n\n        DEFINE_MODULE_FUNCTION(HttpGet, std::string, (std::string& url))\n        {\n            r = HttpGet(url);\n            return 1;\n        }\n\n\n    END_SCRIPT_MODULE()\n\n\n}\n\n\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/lua_net/lua_network.h",
    "content": "#ifndef SERVER_SHARD_LUA_NETWORK_H\n#define SERVER_SHARD_LUA_NETWORK_H\n\n#include <nel/misc/singleton.h>\n#include <nel/net/unified_network.h>\n#include <nel/net/buf_net_base.h>\n\nclass CLuaCallbackServer; \n\nvoid cbLuaSvrConnect( NLNET::TSockId from, void *arg );\nvoid cbLuaSvrDisConnect( NLNET::TSockId from, void *arg );\nvoid cbConnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg );\nvoid cbDisconnection( const std::string &serviceName, NLNET::TServiceId sid, void *arg );\n\nclass CLuaNetworkMgr : public NLMISC::CSingleton<CLuaNetworkMgr>\n{\npublic:\n\n    void Init();\n\n    void RegisterNetModule( std::string name, CLuaCallbackServer* pNet );\n    void RemoveNetModule( std::string name );\n\n    void SendToClient( uint64 uid, NLNET::CMessage& msgin );\n    void IncReceiveMsgCount(std::string msg_name);\n\n    void Update();\n\n\n    void Release();\n\n    typedef std::map<std::string, uint64>                   TMsgCount;\n\n    TMsgCount                                               m_ReceiveMsgCount;\n    TMsgCount                                               m_SendMsgCount;\n\nprivate:\n\n    typedef std::map<std::string, CLuaCallbackServer*>    TNetHandle;\n    TNetHandle          m_LuaClientNetworkHandle;\n};\n\n#define  LuaNetworkMgr  CLuaNetworkMgr::instance()\n\n\n#endif  // SERVER_SHARD_LUA_NETWORK_H\n"
  },
  {
    "path": "code/EVA/server/server_share/msg_leaf.cpp",
    "content": "#include \"msg_leaf.h\"\n#include \"nel/misc/string_conversion.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace MSG_FORMAT\n{\n    NL_BEGIN_STRING_CONVERSION_TABLE (TMsgFormat)\n        NL_STRING_CONVERSION_TABLE_ENTRY(f)\n        NL_STRING_CONVERSION_TABLE_ENTRY(d)\n        NL_STRING_CONVERSION_TABLE_ENTRY(b)\n        NL_STRING_CONVERSION_TABLE_ENTRY(s)\n        NL_STRING_CONVERSION_TABLE_ENTRY(s8)\n        NL_STRING_CONVERSION_TABLE_ENTRY(s16)\n        NL_STRING_CONVERSION_TABLE_ENTRY(s32)\n        NL_STRING_CONVERSION_TABLE_ENTRY(s64)\n        NL_STRING_CONVERSION_TABLE_ENTRY(u8)\n        NL_STRING_CONVERSION_TABLE_ENTRY(u16)\n        NL_STRING_CONVERSION_TABLE_ENTRY(u32)\n        NL_STRING_CONVERSION_TABLE_ENTRY(u64)\n        NL_STRING_CONVERSION_TABLE_ENTRY(UID)\n        NL_STRING_CONVERSION_TABLE_ENTRY(PLS)\n        NL_STRING_CONVERSION_TABLE_ENTRY(JSON)\n    NL_END_STRING_CONVERSION_TABLE(TMsgFormat, MsgFormatConversion, UNKNOWN)\n\n    TMsgFormat toEnum(const std::string &str)\n    {\n        return MsgFormatConversion.fromString(str);\n    }\n\n    const std::string& toString(TMsgFormat format)\n    {\n        return MsgFormatConversion.toString(format);\n    }\n}; // MSG_FORMAT\n\n"
  },
  {
    "path": "code/EVA/server/server_share/msg_leaf.h",
    "content": "#ifndef SERVER_SHARED_MSG_LEAF_H\n#define SERVER_SHARED_MSG_LEAF_H\n\n#include \"nel/misc/types_nl.h\"\n#include <vector>\n#include <string>\n\nnamespace MSG_FORMAT\n{\n\tenum TMsgFormat\n\t{\n        f,\n        d,\n        b,\n        s,\n        s8,\n        s16,\n        s32,\n        s64,\n        u8,\n        u16,\n        u32,\n        u64,\n        UID,\n        PLS,\n        ProtoMsg,\n        JSON,\n\t\tUNKNOWN\n\t};\n\n\tTMsgFormat toEnum(const std::string &str);\n\tconst std::string& toString(TMsgFormat format);\n}; // MSG_FORMAT\n\nstruct MsgLeaf\n{\n    std::string  msgname;\n    std::vector<std::string>                    sendto;\n    std::vector<MSG_FORMAT::TMsgFormat>         format;\n    std::vector<std::string>                    format_msg;\n    std::string                                 description;\n    bool                                        is_log_event;\n};\n\n#endif // SERVER_SHARED_MSG_LEAF_H\n/* End of msg_leaf.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/object_pool.h",
    "content": "//\n//\tCObjectPool:\n\n\n#ifndef OBJECT_POOL_H\n#define OBJECT_POOL_H\n\n#include <string>\n#include <vector>\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/debug.h>\n#include \"buf_fifo2.h\"\n\n\nnamespace NLMISC {\n\ntemplate<class T>\nclass CObjectPool\n{\npublic:\n\tCObjectPool();\n\t~CObjectPool();\n\n\tinline bool\tinit( std::string name, sint32 max );\n\tinline T*\talloc();\n\tinline void\tfree( T *pMem );\n\tinline std::string report();\n\tinline uint32 use()\t{\treturn _fifo2.size();\t}\n\nprivate:\n\tstd::string\t\t_name;\t\t\t///\tصıʶ\n\tuint32\t\t\t_max;\t\t\t///\tصObj\n\tstd::vector<T>  _pool;\n\tCBufFIFO2<T>    _fifo2;\n};\n\ntemplate<class T>\nCObjectPool<T>::CObjectPool():\n_name(\"\"),_max(0)\n{}\n\ntemplate<class T>\nCObjectPool<T>::~CObjectPool()\n{}\n\ntemplate<class T>\ninline bool CObjectPool<T>::init(std::string name,sint32 max)\n{\n\t_name\t\t= name;\n\t_max\t\t= max;\n\n\t_pool.resize(_max);\n\t_fifo2.init(_max);\n\n\tfor( uint32 i=0; i<_max; ++i )\n\t{\n\t\t_fifo2.push_back(&(_pool[i]));\n\t}\n\n\treturn true;\n}\n\ntemplate<class T>\ninline T* CObjectPool<T>::alloc()\n{\n\treturn _fifo2.pop_front();\n}\n\ntemplate<class T>\ninline void CObjectPool<T>::free(T *pMem)\n{\n\tpMem->reset();\n\t_fifo2.push_back(pMem);\n}\n\ntemplate<class T>\ninline std::string CObjectPool<T>::report()\n{\n\tstd::string str_report = \"\";\t// use block : _fifo.size()/_max   ;   use memory : (_fifo.size()*sizeof(T))/(_max*sizeof(T))\n\treturn str_report;\n}\n\n}\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/alloc.cpp",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n\nstatic int _g = 0;\n\nvoid * _pbcM_malloc(size_t sz) {\n\t++ _g;\n\treturn malloc(sz);\n}\n\nvoid _pbcM_free(void *p) {\n\tif (p) {\n\t\t-- _g;\n\t\tfree(p);\n\t}\n}\n\nvoid* _pbcM_realloc(void *p, size_t sz) {\n\treturn realloc(p,sz);\n}\n\nvoid _pbcM_memory() {\n\tprintf(\"%d\\n\",_g);\t\n}\n\nstruct heap_page {\n\tstruct heap_page * next;\n};\n\nstruct heap {\n\tstruct heap_page *current;\n\tint size;\n\tint used;\n};\n\nstruct heap * \n_pbcH_new(int pagesize) {\n\tint cap = 1024;\n\twhile(cap < pagesize) {\n\t\tcap *= 2;\n\t}\n\tstruct heap * h = (struct heap *)_pbcM_malloc(sizeof(struct heap));\n\th->current = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + cap);\n\th->size = cap;\n\th->used = 0;\n\th->current->next = NULL;\n\treturn h;\n}\n\nvoid \n_pbcH_delete(struct heap *h) {\n\tstruct heap_page * p = h->current;\n\tstruct heap_page * next = p->next;\n\tfor(;;) {\n\t\t_pbcM_free(p);\n\t\tif (next == NULL)\n\t\t\tbreak;\n\t\tp = next;\n\t\tnext = p->next;\n\t}\n\t_pbcM_free(h);\n}\n\nvoid* \n_pbcH_alloc(struct heap *h, int size) {\n\tsize = (size + 3) & ~3;\n\tif (h->size - h->used < size) {\n\t\tstruct heap_page * p;\n\t\tif (size < h->size) {\n\t\t\tp = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + h->size);\n\t\t} else {\n\t\t\tp = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + size);\n\t\t}\n\t\tp->next = h->current;\n\t\th->current = p;\n\t\th->used = size;\n\t\treturn (p+1);\n\t} else {\n\t\tchar * buffer = (char *)(h->current + 1);\n\t\tbuffer += h->used;\n\t\th->used += size;\n\t\treturn buffer;\n\t}\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/alloc.h",
    "content": "#ifndef PROTOBUF_C_ALLOC_H\n#define PROTOBUF_C_ALLOC_H\n\n#include <stdlib.h>\n#include <string.h>\n\nvoid * _pbcM_malloc(size_t sz);\nvoid _pbcM_free(void *p);\nvoid * _pbcM_realloc(void *p, size_t sz);\nvoid _pbcM_memory();\n\nstruct heap;\n\nstruct heap * _pbcH_new(int pagesize);\nvoid _pbcH_delete(struct heap *);\nvoid* _pbcH_alloc(struct heap *, int size);\n\n#define HMALLOC(size) ((h) ? _pbcH_alloc(h, size) : _pbcM_malloc(size))\n\n#define pbc_malloc _pbcM_malloc\n#define pbc_free _pbcM_free\n#define pbc_realloc _pbcM_realloc\n#define pbc_memory _pbcM_memory\n\n#ifdef _WIN32\n\n#include <malloc.h>\n\n#endif\n\n#ifdef _MSC_VER\n\n#define alloca _alloca\n\n#endif\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/array.cpp",
    "content": "#include \"pbc.h\"\n#include \"array.h\"\n#include \"alloc.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nstruct array {\n\tint number;\n\tstruct heap *heap;\n\tunion _pbc_var * a;\n};\n\n#define INNER_FIELD ((PBC_ARRAY_CAP - sizeof(struct array)) / sizeof(pbc_var))\n\nvoid \n_pbcA_open(pbc_array _array) {\n\tstruct array * a = (struct array *)_array;\n\ta->number = 0;\n\ta->heap = NULL;\n\ta->a = (union _pbc_var *)(a+1);\n}\n\nvoid \n_pbcA_open_heap(pbc_array _array, struct heap *h) {\n\tstruct array * a = (struct array *)_array;\n\ta->number = 0;\n\ta->heap = h;\n\ta->a = (union _pbc_var *)(a+1);\n}\n\nvoid \n_pbcA_close(pbc_array _array) {\n\tstruct array * a = (struct array *)_array;\n\tif (a->heap == NULL && a->a != NULL && (union _pbc_var *)(a+1) != a->a) {\n\t\t_pbcM_free(a->a);\n\t\ta->a = NULL;\n\t}\n}\n\nvoid \n_pbcA_push(pbc_array _array, pbc_var var) {\n\tstruct array * a = (struct array *)_array;\n\tif (a->number == 0) {\n\t\ta->a = (union _pbc_var *)(a+1);\n\t} else if (a->number >= INNER_FIELD) {\n\t\tif (a->number == INNER_FIELD) {\n\t\t\tint cap = 1;\n\t\t\twhile (cap <= a->number + 1) \n\t\t\t\tcap *= 2;\n\t\t\tstruct heap * h = a->heap;\n\t\t\tunion _pbc_var * outer = (union _pbc_var *)HMALLOC(cap * sizeof(union _pbc_var));\n\t\t\tmemcpy(outer , a->a , INNER_FIELD * sizeof(pbc_var));\n\t\t\ta->a = outer;\n\t\t} else {\n\t\t\tint size=a->number;\n\t\t\tif (((size + 1) ^ size) > size) {\n\t\t\t\tstruct heap * h = a->heap;\n\t\t\t\tif (h) {\n\t\t\t\t\tvoid * old = a->a;\n\t\t\t\t\ta->a = (union _pbc_var *)_pbcH_alloc(h, sizeof(union _pbc_var) * (size+1) * 2);\n\t\t\t\t\tmemcpy(a->a, old, sizeof(union _pbc_var) * size);\n\t\t\t\t} else {\n\t\t\t\t\ta->a = (union _pbc_var *)_pbcM_realloc(a->a,sizeof(union _pbc_var) * (size+1) * 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\ta->a[a->number] = *var;\n\t++ a->number;\n}\n\nvoid \n_pbcA_index(pbc_array _array, int idx, pbc_var var)\n{\n\tstruct array * a = (struct array *)_array;\n\tvar[0] = a->a[idx];\n}\n\nvoid *\n_pbcA_index_p(pbc_array _array, int idx)\n{\n\tstruct array * a = (struct array *)_array;\n\treturn &(a->a[idx]);\n}\n\nint \npbc_array_size(pbc_array _array) {\n\tstruct array * a = (struct array *)_array;\n\treturn a->number;\n}\n\nuint32_t \npbc_array_integer(pbc_array array, int index, uint32_t *hi) {\n\tpbc_var var;\n\t_pbcA_index(array , index , var);\n\tif (hi) {\n\t\t*hi = var->integer.hi;\n\t}\n\treturn var->integer.low;\n}\n\ndouble \npbc_array_real(pbc_array array, int index) {\n\tpbc_var var;\n\t_pbcA_index(array , index , var);\n\treturn var->real;\n}\n\nstruct pbc_slice *\npbc_array_slice(pbc_array _array, int index) {\n\tstruct array * a = (struct array *)_array;\n\tif (index <0 || index > a->number) {\n\t\treturn NULL;\n\t}\n\treturn (struct pbc_slice *) &(a->a[index]);\n}\n\nvoid \npbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi) {\n\tpbc_var var;\n\tvar->integer.low = low;\n\tvar->integer.hi = hi;\n\t_pbcA_push(array,var);\n}\n\nvoid \npbc_array_push_slice(pbc_array array, struct pbc_slice *s) {\n\tpbc_var var;\n\tvar->m = *s;\n\t_pbcA_push(array,var);\n}\n\nvoid \npbc_array_push_real(pbc_array array, double v) {\n\tpbc_var var;\n\tvar->real = v;\n\t_pbcA_push(array,var);\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/array.h",
    "content": "#ifndef PROTOBUF_C_ARRAY_H\n#define PROTOBUF_C_ARRAY_H\n\n#include \"varint.h\"\n#include \"pbc.h\"\n#include \"alloc.h\"\n\ntypedef union _pbc_var {\n\tstruct longlong integer;\n\tdouble real;\n\tstruct {\n\t\tconst char * str;\n\t\tint len;\n\t} s;\n\tstruct {\n\t\tint id;\n\t\tconst char * name;\n\t} e;\n\tstruct pbc_slice m;\n\tvoid * p[2];\n} pbc_var[1];\n\nvoid _pbcA_open(pbc_array);\nvoid _pbcA_open_heap(pbc_array, struct heap *h);\nvoid _pbcA_close(pbc_array);\n\nvoid _pbcA_push(pbc_array, pbc_var var);\nvoid _pbcA_index(pbc_array , int idx, pbc_var var);\nvoid * _pbcA_index_p(pbc_array _array, int idx);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/bootstrap.cpp",
    "content": "#include \"pbc.h\"\n#include \"map.h\"\n#include \"context.h\"\n#include \"pattern.h\"\n#include \"proto.h\"\n#include \"alloc.h\"\n#include \"bootstrap.h\"\n#include \"stringpool.h\"\n#include \"array.h\"\n#include \"descriptor.pbc.h\"\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <stdint.h>\n\n/*\n\n// Descriptor\n\n// google.protobuf.Descriptor.proto encoded in descriptor.pbc.h with proto pbc.file .\n\npackage pbc;\n\nmessage field {\n\toptional string name = 1;\n\toptional int32 id = 2;\n\toptional int32 label = 3;\t// 0 optional 1 required 2 repeated \n\toptional int32 type = 4;\t// type_id\n\toptional string type_name = 5;\t\n\toptional int32 default_int = 6;\t \n\toptional string default_string = 7;\n\toptional double default_real = 8;\n}\n\nmessage file {\n\toptional string name = 1;\n\trepeated string dependency = 2;\n\n\trepeated string message_name = 3;\n\trepeated int32 message_size = 4;\n\trepeated field message_field = 5;\n\n\trepeated string enum_name = 6;\n\trepeated int32 enum_size = 7;\n\trepeated string enum_string = 8;\n\trepeated int32 enum_id = 9;\n}\n\n*/\n\nstruct field_t {\n\tstruct pbc_slice name;\n\tint32_t id;\n\tint32_t label;\n\tint32_t type;\n\tstruct pbc_slice type_name;\n\tint32_t default_integer;\n\tstruct pbc_slice default_string;\n\tdouble default_real;\n};\n\nstruct file_t {\n\tstruct pbc_slice name;\t// string\n\tpbc_array dependency;\t// string\n\tpbc_array message_name;\t// string\n\tpbc_array message_size;\t// int32\n\tpbc_array message_field;\t// field_t\n\tpbc_array enum_name;\t// string\n\tpbc_array enum_size;\t// int32\n\tpbc_array enum_string;\t// string\n\tpbc_array enum_id;\t// int32\n};\n\nstatic void\nset_enum_one(struct pbc_env *p, struct file_t *file, const char *name, int start, int sz) {\n\tstruct map_kv *table = (struct map_kv *)pbc_malloc(sz * sizeof(struct map_kv));\n\tint i;\n\tfor (i=0;i<sz;i++) {\n\t\tpbc_var id;\n\t\tpbc_var string;\n\t\t_pbcA_index(file->enum_id, start+i, id);\n\t\t_pbcA_index(file->enum_string, start+i, string);\n\t\ttable[i].id = (int)id->integer.low;\n\t\ttable[i].pointer = (void *)string->s.str;\n\t}\n\t_pbcP_push_enum(p,name,table,sz);\n\n\tpbc_free(table);\n}\n\nstatic void\nset_enums(struct pbc_env *p, struct file_t *file) {\n\tint n = pbc_array_size(file->enum_size);\n\tint i;\n\tint start = 0;\n\tfor (i=0;i<n;i++) {\n\t\tpbc_var name;\n\t\t_pbcA_index(file->enum_name,i,name);\n\t\tpbc_var var;\n\t\t_pbcA_index(file->enum_size,i,var);\n\t\tset_enum_one(p, file, name->s.str, start , (int)var->integer.low);\n\t\tstart += var->integer.low;\n\t}\n}\n\nstatic void\nset_default(struct _field *f, struct field_t *input) {\n\tswitch (f->type) {\n\tcase PTYPE_DOUBLE:\n\tcase PTYPE_FLOAT:\n\t\tf->default_v->real = input->default_real;\n\t\tbreak;\n\tcase PTYPE_STRING:\n\tcase PTYPE_ENUM:\n\t\tf->default_v->m = input->default_string;\n\t\tbreak;\n\tdefault:\n\t\tf->default_v->integer.low = input->default_integer;\n\t\tbreak;\n\t}\n}\n\nstatic void\nset_msg_one(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file, const char *name, int start, int sz , pbc_array queue) {\n\tint i;\n\tfor (i=0;i<sz;i++) {\n\t\tpbc_var _field;\n\t\t_pbcA_index(file->message_field, start+i, _field);\n\t\tstruct field_t field;\n\n\t\tint ret = pbc_pattern_unpack(FIELD_T, &_field->m, &field);\n\t\tif (ret != 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tstruct _field f;\n\t\tf.id = field.id;\n\t\tf.name = (const char *)field.name.buffer;\n\t\tf.type = field.type;\n\t\tf.label = field.label;\n\t\tf.type_name.n = (const char *)field.type_name.buffer;\n\t\tset_default(&f, &field);\n\n\t\t_pbcP_push_message(p,name, &f , queue);\n\n\t\t// don't need to close pattern since no array\n\t}\n\t_pbcP_init_message(p, name);\n}\n\nstatic void\nset_msgs(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file , pbc_array queue) {\n\tint n = pbc_array_size(file->message_size);\n\tint i;\n\tint start = 0;\n\tfor (i=0;i<n;i++) {\n\t\tpbc_var name;\n\t\t_pbcA_index(file->message_name,i,name);\n\t\tpbc_var sz;\n\t\t_pbcA_index(file->message_size,i,sz);\n\t\tset_msg_one(FIELD_T, p, file, name->s.str, start , (int)sz->integer.low , queue);\n\t\tstart += sz->integer.low;\n\t}\n}\n\nstatic void\nset_field_one(struct pbc_env *p, struct _field *f) {\n\tconst char * type_name = f->type_name.n;\n\tif (f->type == PTYPE_MESSAGE) {\n\t\tf->type_name.m  = (struct _message *)_pbcM_sp_query(p->msgs, type_name);\n//\t\tprintf(\"MESSAGE: %s %p\\n\",type_name, f->type_name.m);\n\t} else if (f->type == PTYPE_ENUM) {\n\t\tf->type_name.e = (struct _enum *)_pbcM_sp_query(p->enums, type_name);\n//\t\tprintf(\"ENUM: %s %p \",type_name, f->type_name.e);\n\t\tconst char * str = f->default_v->s.str;\n\t\tif (str && str[0]) {\n\t\t\tint err = _pbcM_si_query(f->type_name.e->name, str , &(f->default_v->e.id));\n\t\t\tif (err < 0)\n\t\t\t\tgoto _default;\n\t\t\tf->default_v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id, f->default_v->e.id);\n//\t\t\tprintf(\"[%s %d]\\n\",str,f->default_v->e.id);\n\t\t} else {\n_default:\n\t\t\tmemcpy(f->default_v, f->type_name.e->default_v, sizeof(pbc_var));\n//\t\t\tprintf(\"(%s %d)\\n\",f->default_v->e.name,f->default_v->e.id);\n\t\t}\n\t}\n}\n\nvoid\n_pbcB_register_fields(struct pbc_env *p, pbc_array queue) {\n\tint sz = pbc_array_size(queue);\n\tint i;\n\tfor (i=0;i<sz;i++) {\n\t\tpbc_var atom;\n\t\t_pbcA_index(queue,i,atom);\n\t\tstruct _field * f = (struct _field *)atom->m.buffer;\n\t\tset_field_one(p, f);\n\t}\n}\n\nstatic void\n_set_string(struct _pattern_field * f) {\n\tf->ptype = PTYPE_STRING;\n\tf->ctype = CTYPE_VAR;\n\tf->defv->s.str = \"\";\n\tf->defv->s.len = 0;\n}\n\nstatic void\n_set_int32(struct _pattern_field * f) {\n\tf->ptype = PTYPE_INT32;\n\tf->ctype = CTYPE_INT32;\n}\n\nstatic void\n_set_double(struct _pattern_field * f) {\n\tf->ptype = PTYPE_DOUBLE;\n\tf->ctype = CTYPE_DOUBLE;\n}\n\nstatic void\n_set_message_array(struct _pattern_field *f) {\n\tf->ptype = PTYPE_MESSAGE;\n\tf->ctype = CTYPE_ARRAY;\n}\n\nstatic void\n_set_string_array(struct _pattern_field * f) {\n\tf->ptype = PTYPE_STRING;\n\tf->ctype = CTYPE_ARRAY;\n}\n\nstatic void\n_set_int32_array(struct _pattern_field * f) {\n\tf->ptype = PTYPE_INT32;\n\tf->ctype = CTYPE_ARRAY;\n}\n\n#define SET_PATTERN(pat , idx , pat_type, field_name , type) \\\n\tpat->f[idx].id = idx+1 ; \\\n\tpat->f[idx].offset = offsetof(struct pat_type, field_name);\t\\\n\t_set_##type(&pat->f[idx]);\n\n#define F(idx,field_name,type) SET_PATTERN(FIELD_T, idx, field_t ,field_name, type)\n#define D(idx,field_name,type) SET_PATTERN(FILE_T, idx, file_t ,field_name, type)\n\nstatic int\nregister_internal(struct pbc_env * p, struct pbc_slice *slice) {\n\tstruct pbc_pattern * FIELD_T =  _pbcP_new(p,8);\n\tF(0,name,string);\n\tF(1,id,int32);\n\tF(2,label,int32);\n\tF(3,type,int32);\n\tF(4,type_name,string);\n\tF(5,default_integer,int32);\n\tF(6,default_string,string);\n\tF(7,default_real,double);\n\n\tstruct pbc_pattern * FILE_T =  _pbcP_new(p,10);\n\n\tD(0,name,string);\n\tD(1,dependency,string_array);\n\tD(2,message_name,string_array);\n\tD(3,message_size,int32_array);\n\tD(4,message_field,message_array);\n\tD(5,enum_name,string_array);\n\tD(6,enum_size,int32_array);\n\tD(7,enum_string,string_array);\n\tD(8,enum_id,int32_array);\n\n\tint ret = 0;\n\n\tstruct file_t file;\n\tint r = pbc_pattern_unpack(FILE_T, slice, &file);\n\tif (r != 0) {\n\t\tret = 1;\n\t\tgoto _return;\n\t}\n\n\t_pbcM_sp_insert(p->files , (const char *)file.name.buffer, NULL);\n\n\tpbc_array queue;\n\t_pbcA_open(queue);\n\n\tset_enums(p, &file);\n\tset_msgs(FIELD_T, p, &file, queue);\n\t_pbcB_register_fields(p, queue);\n\n\t_pbcA_close(queue);\n\tpbc_pattern_close_arrays(FILE_T, &file);\n\n_return:\n\tpbc_free(FIELD_T);\n\tpbc_free(FILE_T);\n\treturn ret;\n}\n\nvoid \n_pbcB_init(struct pbc_env * p) {\n\tstruct pbc_slice slice = { pbc_descriptor,sizeof(pbc_descriptor) };\n\tregister_internal(p,&slice);\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/bootstrap.h",
    "content": "#ifndef PROTOBUF_C_BOOTSTRAP_H\n#define PROTOBUF_C_BOOTSTRAP_H\n\n#include \"proto.h\"\n#include \"pbc.h\"\n\nvoid _pbcB_init(struct pbc_env *);\nvoid _pbcB_register_fields(struct pbc_env *, pbc_array queue);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/context.cpp",
    "content": "#include \"pbc.h\"\n#include \"alloc.h\"\n#include \"varint.h\"\n#include \"context.h\"\n\n#include <stdlib.h>\n#include <string.h>\n#include <stdint.h>\n#ifndef _MSC_VER\n#include <stdbool.h>\n#endif\n\n#define INNER_ATOM ((PBC_CONTEXT_CAP - sizeof(struct context)) / sizeof(struct atom))\n\nstatic char * \nwiretype_decode(uint8_t *buffer, int cap , struct atom *a , int start)\n{\n\tuint8_t temp[10];\n\tstruct longlong r;\n\tint len;\n\tif (cap >= 10) {\n\t\tlen = _pbcV_decode(buffer, &r);\n\t\tif (r.hi !=0)\n\t\t\treturn NULL;\n\t} else {\n\t\tmemcpy(temp, buffer , cap);\n\t\tlen = _pbcV_decode(temp, &r);\n\t\tif (len > cap || r.hi !=0)\n\t\t\treturn NULL;\n\t}\n\n\tint wiretype = r.low & 7;\n\ta->wire_id = r.low;\n\tbuffer += len;\n\tstart += len;\n\tcap -=len;\n\t\n\tswitch (wiretype) {\n\tcase WT_VARINT :\n\t\tif (cap >=10) {\n\t\t\tlen = _pbcV_decode(buffer, &a->v.i);\n\t\t} else {\n\t\t\tmemcpy(temp, buffer , cap);\n\t\t\tlen = _pbcV_decode(temp, &a->v.i);\n\t\t\tif (cap < len)\n\t\t\t\treturn NULL;\n\t\t}\n\t\treturn (char *)buffer+len;\n\tcase WT_BIT64 :\n\t\tif (cap < 8)\n\t\t\treturn NULL;\n\t\ta->v.i.low = buffer[0] |\n\t\t\tbuffer[1] << 8 |\n\t\t\tbuffer[2] << 16 |\n\t\t\tbuffer[3] << 24;\n\t\ta->v.i.hi = buffer[4] |\n\t\t\tbuffer[5] << 8 |\n\t\t\tbuffer[6] << 16 |\n\t\t\tbuffer[7] << 24;\n\t\treturn (char *)buffer + 8;\n\tcase WT_LEND :\n\t\tif (cap >=10) {\n\t\t\tlen = _pbcV_decode(buffer, &r);\n\t\t} else {\n\t\t\tmemcpy(temp, buffer , cap);\n\t\t\tlen = _pbcV_decode(temp, &r);\n\t\t}\n\t\tif (cap < len + r.low || r.hi !=0)\n\t\t\treturn NULL;\n\t\ta->v.s.start = start + len;\n\t\ta->v.s.end = start + len + r.low;\n\t\treturn (char *)buffer + len + r.low;\n\tcase WT_BIT32 :\n\t\tif (cap < 4)\n\t\t\treturn NULL;\n\t\ta->v.i.low = buffer[0] |\n\t\t\tbuffer[1] << 8 |\n\t\t\tbuffer[2] << 16 |\n\t\t\tbuffer[3] << 24;\n\t\ta->v.i.hi = 0;\n\t\treturn (char *)buffer + 4;\n\tdefault:\n\t\treturn NULL;\n\t}\n}\n\nstatic inline int\n_decode_varint(uint8_t * buffer, int size , struct atom * a) {\n\ta->wire_id = WT_VARINT;\n\tif (size < 10) {\n\t\tuint8_t temp[10];\n\t\tmemcpy(temp,buffer,size);\n\t\treturn _pbcV_decode(temp , &(a->v.i));\n\t} else {\n\t\treturn _pbcV_decode(buffer , &(a->v.i));\n\t}\n}\n\nstatic int\n_open_packed_varint(struct context * ctx , uint8_t * buffer, int size) {\n\tstruct atom * a = (struct atom *)(ctx + 1);\n\n\tint i;\n\n\tfor (i=0;i<INNER_ATOM;i++) {\n\t\tif (size == 0)\n\t\t\tbreak;\n\t\tint len = _decode_varint(buffer, size, &a[i]);\n\t\tbuffer += len;\n\t\tsize -= len;\n\t}\n\n\tif (size == 0) {\n\t\tctx->a = a;\n\t} else {\n\t\tint cap = 64;\n\t\tctx->a = (struct atom *)pbc_malloc(cap * sizeof(struct atom));\n\t\twhile (size > 0) {\n\t\t\tif (i >= cap) {\n\t\t\t\tcap = cap + 64;\n\t\t\t\tctx->a = (struct atom *)pbc_realloc(ctx->a, cap * sizeof(struct atom));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tint len = _decode_varint(buffer, size, &a[i]);\n\t\t\tbuffer += len;\n\t\t\tsize -= len;\n\n\t\t\t++i;\n\t\t}\n\t\tmemcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM);\n\t}\n\tctx->number = i;\n\n\treturn i;\n}\n\nint \n_pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size) {\n\tstruct context * ctx = (struct context *)_ctx;\n\tctx->buffer = (char *)buffer;\n\tctx->size = size;\n\tctx->number = 0;\n\tctx->a = NULL;\n\n\tif (buffer == NULL || size == 0) {\n\t\treturn 0;\n\t}\n\n\tint bits = 0;\n\n\tswitch (ptype) {\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_BOOL:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\n\tcase PTYPE_SINT32:\n\tcase PTYPE_SINT64:\n\t\treturn _open_packed_varint(ctx , (uint8_t *)buffer, size);\n\tcase PTYPE_DOUBLE:\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tctx->number = size / 8;\n\t\tbits = 64;\n\t\tbreak;\n\tcase PTYPE_FLOAT:\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tctx->number = size / 4;\n\t\tbits = 32;\n\t\tbreak;\n\tdefault:\n\t\treturn 0;\n\t}\n\n\tstruct atom * a = (struct atom *)(ctx + 1);\n\n\tif (ctx->number > INNER_ATOM) {\n\t\tctx->a = (struct atom *)pbc_malloc(ctx->number * sizeof(struct atom));\n\t\ta = ctx->a;\n\t} else {\n\t\tctx->a = a;\n\t}\n\n\tint i;\n\tif (bits == 64) {\n\t\tuint8_t * data = (uint8_t *)buffer;\n\t\tfor (i=0;i<ctx->number;i++) {\n\t\t\ta[i].wire_id = WT_BIT64;\n\t\t\ta[i].v.i.low = data[0] |\n\t\t\t\tdata[1] << 8 |\n\t\t\t\tdata[2] << 16 |\n\t\t\t\tdata[3] << 24;\n\t\t\ta[i].v.i.hi = data[4] |\n\t\t\t\tdata[5] << 8 |\n\t\t\t\tdata[6] << 16 |\n\t\t\t\tdata[7] << 24;\n\t\t\tdata += 8;\n\t\t}\n\t} else {\n\t\tuint8_t * data = (uint8_t *)buffer;\n\t\tfor (i=0;i<ctx->number;i++) {\n\t\t\ta[i].wire_id = WT_BIT32;\n\t\t\ta[i].v.i.low = data[0] |\n\t\t\t\tdata[1] << 8 |\n\t\t\t\tdata[2] << 16 |\n\t\t\t\tdata[3] << 24;\n\t\t\ta[i].v.i.hi = 0;\n\t\t\tdata += 4;\n\t\t}\n\t}\n\n\treturn ctx->number;\n}\n\nint \n_pbcC_open(pbc_ctx _ctx , void *buffer, int size) {\n\tstruct context * ctx = (struct context *)_ctx;\n\tctx->buffer = (char *)buffer;\n\tctx->size = size;\n\n\tif (buffer == NULL || size == 0) {\n\t\tctx->number = 0;\n\t\tctx->a = NULL;\n\t\treturn 0;\n\t}\n\n\tstruct atom * a = (struct atom *)(ctx + 1);\n\n\tint i;\n\tint start = 0;\n\n\tctx->a = a;\n\n\tfor (i=0;i<INNER_ATOM;i++) {\n\t\tif (size == 0)\n\t\t\tbreak;\n\t\tchar * next = wiretype_decode((uint8_t *)buffer, size , &a[i] , start);\n\t\tif (next == NULL)\n\t\t\treturn -i;\n\t\tstart += next - (char *)buffer;\n\t\tsize -= next - (char *)buffer;\n\t\tbuffer = next;\n\t}\n\n\tif (size > 0) {\n\t\tint cap = 64;\n\t\tctx->a = (struct atom *)pbc_malloc(cap * sizeof(struct atom));\n\t\twhile (size > 0) {\n\t\t\tif (i >= cap) {\n\t\t\t\tcap = cap + 64;\n\t\t\t\tctx->a = (struct atom *)pbc_realloc(ctx->a, cap * sizeof(struct atom));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tchar * next = wiretype_decode((uint8_t *)buffer, size , &ctx->a[i] , start);\n\t\t\tif (next == NULL) {\n\t\t\t\treturn -i;\n\t\t\t}\n\t\t\tstart += next - (char *)buffer;\n\t\t\tsize -= next - (char *)buffer;\n\t\t\tbuffer = next;\n\t\t\t++i;\n\t\t}\n\t\tmemcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM);\n\t}\n\tctx->number = i;\n\n\treturn i;\n}\n\n\nvoid \n_pbcC_close(pbc_ctx _ctx) {\n\tstruct context * ctx = (struct context *)_ctx;\n\tif (ctx->a != NULL && (struct atom *)(ctx+1) != ctx->a) {\n\t\tpbc_free(ctx->a);\n\t\tctx->a = NULL;\n\t}\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/context.h",
    "content": "#ifndef PROTOBUF_C_CONTEXT_H\n#define PROTOBUF_C_CONTEXT_H\n\n#include <stdint.h>\n\n#include \"array.h\"\n\n#define PBC_CONTEXT_CAP 256\n\n// wiretype\n\n#define WT_VARINT 0\n#define WT_BIT64 1\n#define WT_LEND 2\n#define WT_BIT32 5\n\n#define CTYPE_INT32 1\n#define CTYPE_INT64 2\n#define CTYPE_DOUBLE 3\n#define CTYPE_FLOAT 4\n#define CTYPE_POINTER 5\n#define CTYPE_BOOL 6\n#define CTYPE_INT8 7\n#define CTYPE_INT16 8\n#define CTYPE_ARRAY 9\n#define CTYPE_VAR 10\n#define CTYPE_PACKED 11\n\n#define PTYPE_DOUBLE   1\n#define PTYPE_FLOAT    2\n#define PTYPE_INT64    3   // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if negative values are likely.\n#define PTYPE_UINT64   4\n#define PTYPE_INT32    5   // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if negative values are likely.\n#define PTYPE_FIXED64  6\n#define PTYPE_FIXED32  7\n#define PTYPE_BOOL     8\n#define PTYPE_STRING   9\n#define PTYPE_GROUP    10  // Tag-delimited aggregate.\n#define PTYPE_MESSAGE  11  // Length-delimited aggregate.\n#define PTYPE_BYTES    12\n#define PTYPE_UINT32   13\n#define PTYPE_ENUM     14\n#define PTYPE_SFIXED32 15\n#define PTYPE_SFIXED64 16\n#define PTYPE_SINT32   17  // Uses ZigZag encoding.\n#define PTYPE_SINT64   18  // Uses ZigZag encoding.\n\nstruct slice {\n\tint start;\n\tint end;\n};\n\nstruct atom {\n\tint wire_id;\n\tunion {\n\t\tstruct slice s;\n\t\tstruct longlong i;\n\t} v;\n};\n\nstruct context {\n\tchar * buffer;\n\tint size;\n\tint number;\n\tstruct atom * a;\n};\n\ntypedef struct _pbc_ctx { char _data[PBC_CONTEXT_CAP]; } pbc_ctx[1];\n\nint _pbcC_open(pbc_ctx , void *buffer, int size);\t// <=0 failed\nint _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size);\nvoid _pbcC_close(pbc_ctx);\n\nstatic inline double\nread_double(struct atom * a) {\n\tunion {\n\t\tuint64_t i;\n\t\tdouble d;\n\t} u;\n\tu.i = (uint64_t) a->v.i.low | (uint64_t) a->v.i.hi << 32;\n\treturn u.d;\n}\n\nstatic inline float\nread_float(struct atom * a) {\n\tunion {\n\t\tuint32_t i;\n\t\tfloat f;\n\t} u;\n\tu.i = a->v.i.low;\n\treturn u.f;\n}\n\nstatic inline void\ndouble_encode(double v , uint8_t * buffer) {\n\tunion {\n\t\tdouble v;\n\t\tuint64_t e;\n\t} u;\n\tu.v = v;\n\tbuffer[0] = (uint8_t) (u.e & 0xff);\n\tbuffer[1] = (uint8_t) (u.e >> 8 & 0xff);\n\tbuffer[2] = (uint8_t) (u.e >> 16 & 0xff);\n\tbuffer[3] = (uint8_t) (u.e >> 24 & 0xff);\n\tbuffer[4] = (uint8_t) (u.e >> 32 & 0xff);\n\tbuffer[5] = (uint8_t) (u.e >> 40 & 0xff);\n\tbuffer[6] = (uint8_t) (u.e >> 48 & 0xff);\n\tbuffer[7] = (uint8_t) (u.e >> 56 & 0xff);\n}\n\nstatic inline void\nfloat_encode(float v , uint8_t * buffer) {\n\tunion {\n\t\tfloat v;\n\t\tuint32_t e;\n\t} u;\n\tu.v = v;\n\tbuffer[0] = (uint8_t) (u.e & 0xff);\n\tbuffer[1] = (uint8_t) (u.e >> 8 & 0xff);\n\tbuffer[2] = (uint8_t) (u.e >> 16 & 0xff);\n\tbuffer[3] = (uint8_t) (u.e >> 24 & 0xff);\n}\n\n#define CHECK_LEND(a,err) if ((a->wire_id & 7) != WT_LEND) return err;\n\n#if 0\n/* maybe we don't need check these wire type */\n#define CHECK_VARINT(a,err) if ((a->wire_id & 7) != WT_VARINT) return err;\n#define CHECK_BIT32(a,err) if ((a->wire_id & 7) != WT_BIT32) return err;\n#define CHECK_BIT64(a,err) if ((a->wire_id & 7) != WT_BIT64) return err;\n\n#else\n\n#define CHECK_VARINT(a,err)\n#define CHECK_BIT32(a,err)\n#define CHECK_BIT64(a,err)\n\n#endif\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/decode.cpp",
    "content": "#include \"pbc.h\"\n#include \"alloc.h\"\n#include \"context.h\"\n#include \"proto.h\"\n#include \"varint.h\"\n\n#include <assert.h>\n\nstatic const char * TYPENAME[] = {\n\t\"invalid\",\t// 0\n\t\"integer\",\t// 1\n\t\"real\",\t// 2\n\t\"boolean\",\t// 3\n\t\"enum\",\t// 4\n\t\"string\",\t// 5\n\t\"message\",\t// 6\n\t\"fixed64\",\t// 7\n\t\"fixed32\",\t// 8\n\t\"bytes\",\t// 9\n\t\"int64\",\t// 10\n\t\"uint\",\t// 11\n};\n\nstatic int\ncall_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) {\n\tunion pbc_value v;\n\tswitch (a->wire_id & 7) {\n\tcase WT_VARINT:\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\tf(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL);\n\t\tbreak;\n\tcase WT_BIT64:\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\tf(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL);\n\t\tbreak;\n\tcase WT_LEND:\n\t\tv.s.buffer = (char*)start + a->v.s.start;\n\t\tv.s.len = a->v.s.end - a->v.s.start;\n\t\tf(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL);\n\t\tbreak;\n\tcase WT_BIT32:\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = 0;\n\t\tf(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL);\n\t\tbreak;\n\tdefault:\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nstatic int\ncall_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) {\n\tunion pbc_value v;\n\tconst char * type_name = NULL;\n\tint type = _pbcP_type(f, &type_name);\n\tassert(type != 0);\n\tif (type_name == NULL) {\n\t\ttype_name = TYPENAME[type & ~PBC_REPEATED];\n\t}\n\tswitch (f->type) {\n\tcase PTYPE_DOUBLE:\n\t\tCHECK_BIT64(a, -1);\n\t\tv.f = read_double(a);\n\t\tbreak;\n\tcase PTYPE_FLOAT:\n\t\tCHECK_BIT32(a, -1);\n\t\tv.f = (double) read_float(a);\n\t\tbreak;\n\tcase PTYPE_ENUM:\n\t\tCHECK_VARINT(a, -1);\n\t\tv.e.id = a->v.i.low;\n\t\tv.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.e.id);\n\t\tbreak;\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\t\tCHECK_VARINT(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\tbreak;\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tCHECK_BIT64(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\tbreak;\n\tcase PTYPE_INT32:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_BOOL:\n\t\tCHECK_VARINT(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = 0;\n\t\tbreak;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tCHECK_BIT32(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = 0;\n\t\tbreak;\n\tcase PTYPE_SINT32: \n\t\tCHECK_VARINT(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\t_pbcV_dezigzag32((struct longlong *)&(v.i));\n\t\tbreak;\n\tcase PTYPE_SINT64:\n\t\tCHECK_VARINT(a, -1);\n\t\tv.i.low = a->v.i.low;\n\t\tv.i.hi = a->v.i.hi;\n\t\t_pbcV_dezigzag64((struct longlong *)&(v.i));\n\t\tbreak;\n\tcase PTYPE_STRING:\n\tcase PTYPE_BYTES:\n\tcase PTYPE_MESSAGE:\n\t\tCHECK_LEND(a, -1);\n\t\tv.s.buffer = start + a->v.s.start;\n\t\tv.s.len = a->v.s.end - a->v.s.start;\n\t\tbreak;\n\tdefault:\n\t\tassert(0);\n\t\tbreak;\n\t}\n\tpd(ud, type, type_name, &v, f->id, f->name);\n\treturn 0;\n}\n\nstatic int\ncall_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) {\n\tunion pbc_value v;\n\tconst char * type_name = NULL;\n\tint type = _pbcP_type(f, &type_name);\n\tassert(type != 0);\n\tif (type_name == NULL) {\n\t\ttype_name = TYPENAME[type & ~PBC_REPEATED];\n\t}\n\tv.i.hi = 0;\n\tint i;\n\tswitch(f->type) {\n\t\tcase PTYPE_DOUBLE:\n\t\t\tif (size % 8 != 0) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tfor (i=0;i<size;i+=8) {\n\t\t\t\tunion {\n\t\t\t\t\tdouble d;\n\t\t\t\t\tuint64_t i64;\n\t\t\t\t} u;\n\t\t\t\tu.i64 = (uint64_t)buffer[i] |\n\t\t\t\t\t(uint64_t)buffer[i+1] << 8 |\n\t\t\t\t\t(uint64_t)buffer[i+2] << 16 |\n\t\t\t\t\t(uint64_t)buffer[i+3] << 24 |\n\t\t\t\t\t(uint64_t)buffer[i+4] << 32 |\n\t\t\t\t\t(uint64_t)buffer[i+5] << 40 |\n\t\t\t\t\t(uint64_t)buffer[i+6] << 48 |\n\t\t\t\t\t(uint64_t)buffer[i+7] << 56;\n\t\t\t\tv.f = u.d;\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t}\n\t\t\treturn size/8;\n\t\tcase PTYPE_FLOAT:\n\t\t\tif (size % 4 != 0)\n\t\t\t\treturn -1;\n\t\t\tfor (i=0;i<size;i+=4) {\n\t\t\t\tunion {\n\t\t\t\t\tfloat f;\n\t\t\t\t\tuint32_t i32;\n\t\t\t\t} u;\n\t\t\t\tu.i32 = (uint32_t)buffer[i] |\n\t\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\t\tv.f = (double)u.f;\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t}\n\t\t\treturn size/4;\n\t\tcase PTYPE_FIXED32:\n\t\tcase PTYPE_SFIXED32:\n\t\t\tif (size % 4 != 0)\n\t\t\t\treturn -1;\n\t\t\tfor (i=0;i<size;i+=4) {\n\t\t\t\tv.i.low = (uint32_t)buffer[i] |\n\t\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t}\n\t\t\treturn size/4;\n\t\tcase PTYPE_FIXED64:\n\t\tcase PTYPE_SFIXED64:\n\t\t\tif (size % 8 != 0)\n\t\t\t\treturn -1;\n\t\t\tfor (i=0;i<size;i+=8) {\n\t\t\t\tv.i.low = (uint32_t)buffer[i] |\n\t\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\t\tv.i.hi = (uint32_t)buffer[i+4] |\n\t\t\t\t\t(uint32_t)buffer[i+5] << 8 |\n\t\t\t\t\t(uint32_t)buffer[i+6] << 16 |\n\t\t\t\t\t(uint32_t)buffer[i+7] << 24;\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t}\n\t\t\treturn size/8;\n\t\tcase PTYPE_INT64:\n\t\tcase PTYPE_UINT64:\n\t\tcase PTYPE_INT32:\n\t\tcase PTYPE_UINT32:\n\t\tcase PTYPE_BOOL: {\n\t\t\tint n = 0;\n\t\t\twhile (size > 0) {\n\t\t\t\tint len;\n\t\t\t\tif (size >= 10) {\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t} else {\n\t\t\t\t\tuint8_t temp[10];\n\t\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\tif (len > size)\n\t\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t\tbuffer += len;\n\t\t\t\tsize -= len;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\treturn n;\n\t\t}\n\t\tcase PTYPE_ENUM: {\n\t\t\tint n = 0;\n\t\t\twhile (size > 0) {\n\t\t\t\tint len;\n\t\t\t\tif (size >= 10) {\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t} else {\n\t\t\t\t\tuint8_t temp[10];\n\t\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\tif (len > size)\n\t\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\tv.e.id = v.i.low;\n\t\t\t\tv.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.i.low);\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t\tbuffer += len;\n\t\t\t\tsize -= len;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\treturn n;\n\t\t}\n\t\tcase PTYPE_SINT32: {\n\t\t\tint n = 0;\n\t\t\twhile (size > 0) {\n\t\t\t\tint len;\n\t\t\t\tif (size >= 10) {\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\t_pbcV_dezigzag32((struct longlong *)&(v.i));\n\t\t\t\t} else {\n\t\t\t\t\tuint8_t temp[10];\n\t\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\tif (len > size)\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t_pbcV_dezigzag32((struct longlong *)&(v.i));\n\t\t\t\t}\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t\tbuffer += len;\n\t\t\t\tsize -= len;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\treturn n;\n\t\t}\n\t\tcase PTYPE_SINT64: {\n\t\t\tint n = 0;\n\t\t\twhile (size > 0) {\n\t\t\t\tint len;\n\t\t\t\tif (size >= 10) {\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\t_pbcV_dezigzag64((struct longlong *)&(v.i));\n\t\t\t\t} else {\n\t\t\t\t\tuint8_t temp[10];\n\t\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\t\tlen = _pbcV_decode(buffer, (struct longlong *)&(v.i));\n\t\t\t\t\tif (len > size)\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t_pbcV_dezigzag64((struct longlong *)&(v.i));\n\t\t\t\t}\n\t\t\t\tpd(ud, type , type_name, &v, f->id, f->name);\n\t\t\t\tbuffer += len;\n\t\t\t\tsize -= len;\n\t\t\t\t++n;\n\t\t\t}\n\t\t\treturn n;\n\t\t}\n\t\tdefault:\n\t\t\treturn -1;\n\t}\n}\n\nint\npbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder pd, void *ud) {\n\tstruct _message * msg = _pbcP_get_message(env, type_name);\n\tif (msg == NULL) {\n\t\tenv->lasterror = \"Proto not found\";\n\t\treturn -1;\n\t}\n\tif (slice->len == 0) {\n\t\treturn 0;\n\t}\n\tpbc_ctx _ctx;\n\tint count = _pbcC_open(_ctx,slice->buffer,slice->len);\n\tif (count <= 0) {\n\t\tenv->lasterror = \"decode context error\";\n\t\t_pbcC_close(_ctx);\n\t\treturn count - 1;\n\t}\n\tstruct context * ctx = (struct context *)_ctx;\n\tuint8_t * start = (uint8_t *)slice->buffer;\n\n\tint i;\n\tfor (i=0;i<ctx->number;i++) {\n\t\tint id = ctx->a[i].wire_id >> 3;\n\t\tstruct _field * f = (struct _field *)_pbcM_ip_query(msg->id , id);\n\t\tif (f==NULL) {\n\t\t\tint err = call_unknown(pd,ud,id,&ctx->a[i],start);\n\t\t\tif (err) {\n\t\t\t\t_pbcC_close(_ctx);\n\t\t\t\treturn -i-1;\n\t\t\t}\n\t\t} else if (f->label == LABEL_PACKED) {\n\t\t\tstruct atom * a = &ctx->a[i];\n\t\t\tint n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start);\n\t\t\tif (n < 0) {\n\t\t\t\t_pbcC_close(_ctx);\n\t\t\t\treturn -i-1;\n\t\t\t}\n\t\t} else {\n\t\t\tif (call_type(pd,ud,f,&ctx->a[i],start) != 0) {\n\t\t\t\t_pbcC_close(_ctx);\n\t\t\t\treturn -i-1;\n\t\t\t}\n\t\t}\n\t}\n\n\t_pbcC_close(_ctx);\n\treturn ctx->number;\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/descriptor.pbc.h",
    "content": "static unsigned char pbc_descriptor[] = {\n72,1,72,2,72,3,72,4,72,5,72,6,72,7,72,8,\n72,9,72,10,72,11,72,12,72,13,72,14,72,15,72,16,\n72,17,72,18,72,1,72,2,72,3,72,1,72,2,72,3,\n72,0,72,1,72,2,50,42,103,111,111,103,108,101,46,112,\n114,111,116,111,98,117,102,46,70,105,101,108,100,68,101,115,\n99,114,105,112,116,111,114,80,114,111,116,111,46,84,121,112,\n101,0,50,43,103,111,111,103,108,101,46,112,114,111,116,111,\n98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,\n116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,50,\n41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,\n46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,116,\n105,109,105,122,101,77,111,100,101,0,50,35,103,111,111,103,\n108,101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,\n100,79,112,116,105,111,110,115,46,67,84,121,112,101,0,66,\n12,84,89,80,69,95,68,79,85,66,76,69,0,66,11,84,\n89,80,69,95,70,76,79,65,84,0,66,11,84,89,80,69,\n95,73,78,84,54,52,0,66,12,84,89,80,69,95,85,73,\n78,84,54,52,0,66,11,84,89,80,69,95,73,78,84,51,\n50,0,66,13,84,89,80,69,95,70,73,88,69,68,54,52,\n0,66,13,84,89,80,69,95,70,73,88,69,68,51,50,0,\n66,10,84,89,80,69,95,66,79,79,76,0,66,12,84,89,\n80,69,95,83,84,82,73,78,71,0,66,11,84,89,80,69,\n95,71,82,79,85,80,0,66,13,84,89,80,69,95,77,69,\n83,83,65,71,69,0,66,11,84,89,80,69,95,66,89,84,\n69,83,0,66,12,84,89,80,69,95,85,73,78,84,51,50,\n0,66,10,84,89,80,69,95,69,78,85,77,0,66,14,84,\n89,80,69,95,83,70,73,88,69,68,51,50,0,66,14,84,\n89,80,69,95,83,70,73,88,69,68,54,52,0,66,12,84,\n89,80,69,95,83,73,78,84,51,50,0,66,12,84,89,80,\n69,95,83,73,78,84,54,52,0,66,15,76,65,66,69,76,\n95,79,80,84,73,79,78,65,76,0,66,15,76,65,66,69,\n76,95,82,69,81,85,73,82,69,68,0,66,15,76,65,66,\n69,76,95,82,69,80,69,65,84,69,68,0,66,6,83,80,\n69,69,68,0,66,10,67,79,68,69,95,83,73,90,69,0,\n66,13,76,73,84,69,95,82,85,78,84,73,77,69,0,66,\n7,83,84,82,73,78,71,0,66,5,67,79,82,68,0,66,\n13,83,84,82,73,78,71,95,80,73,69,67,69,0,56,18,\n56,3,56,3,56,3,10,11,100,101,115,99,114,105,112,116,\n111,114,0,32,1,32,9,32,7,32,2,32,8,32,3,32,\n3,32,3,32,4,32,9,32,3,32,5,32,1,32,1,32,\n1,32,1,32,7,32,2,32,1,32,2,42,51,24,2,16,\n1,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116,\n111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,112,\n116,111,114,80,114,111,116,111,0,10,5,102,105,108,101,0,\n42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,42,\n16,32,9,24,0,10,8,112,97,99,107,97,103,101,0,16,\n2,42,19,32,9,24,2,10,11,100,101,112,101,110,100,101,\n110,99,121,0,16,3,42,55,24,2,16,4,32,11,42,32,\n103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,\n68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0,\n10,13,109,101,115,115,97,103,101,95,116,121,112,101,0,42,\n56,24,2,16,5,32,11,42,36,103,111,111,103,108,101,46,\n112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,115,\n99,114,105,112,116,111,114,80,114,111,116,111,0,10,10,101,\n110,117,109,95,116,121,112,101,0,42,57,24,2,16,6,32,\n11,42,39,103,111,111,103,108,101,46,112,114,111,116,111,98,\n117,102,46,83,101,114,118,105,99,101,68,101,115,99,114,105,\n112,116,111,114,80,114,111,116,111,0,10,8,115,101,114,118,\n105,99,101,0,42,57,24,2,16,7,32,11,42,37,103,111,\n111,103,108,101,46,112,114,111,116,111,98,117,102,46,70,105,\n101,108,100,68,101,115,99,114,105,112,116,111,114,80,114,111,\n116,111,0,10,10,101,120,116,101,110,115,105,111,110,0,42,\n46,24,0,16,8,32,11,42,28,103,111,111,103,108,101,46,\n112,114,111,116,111,98,117,102,46,70,105,108,101,79,112,116,\n105,111,110,115,0,10,8,111,112,116,105,111,110,115,0,42,\n58,24,0,16,9,32,11,42,31,103,111,111,103,108,101,46,\n112,114,111,116,111,98,117,102,46,83,111,117,114,99,101,67,\n111,100,101,73,110,102,111,0,10,17,115,111,117,114,99,101,\n95,99,111,100,101,95,105,110,102,111,0,42,13,32,9,24,\n0,10,5,110,97,109,101,0,16,1,42,53,24,2,16,2,\n32,11,42,37,103,111,111,103,108,101,46,112,114,111,116,111,\n98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,\n116,111,114,80,114,111,116,111,0,10,6,102,105,101,108,100,\n0,42,57,24,2,16,6,32,11,42,37,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,\n68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0,\n10,10,101,120,116,101,110,115,105,111,110,0,42,54,24,2,\n16,3,32,11,42,32,103,111,111,103,108,101,46,112,114,111,\n116,111,98,117,102,46,68,101,115,99,114,105,112,116,111,114,\n80,114,111,116,111,0,10,12,110,101,115,116,101,100,95,116,\n121,112,101,0,42,56,24,2,16,4,32,11,42,36,103,111,\n111,103,108,101,46,112,114,111,116,111,98,117,102,46,69,110,\n117,109,68,101,115,99,114,105,112,116,111,114,80,114,111,116,\n111,0,10,10,101,110,117,109,95,116,121,112,101,0,42,73,\n24,2,16,5,32,11,42,47,103,111,111,103,108,101,46,112,\n114,111,116,111,98,117,102,46,68,101,115,99,114,105,112,116,\n111,114,80,114,111,116,111,46,69,120,116,101,110,115,105,111,\n110,82,97,110,103,101,0,10,16,101,120,116,101,110,115,105,\n111,110,95,114,97,110,103,101,0,42,49,24,0,16,7,32,\n11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98,\n117,102,46,77,101,115,115,97,103,101,79,112,116,105,111,110,\n115,0,10,8,111,112,116,105,111,110,115,0,42,14,32,5,\n24,0,10,6,115,116,97,114,116,0,16,1,42,12,32,5,\n24,0,10,4,101,110,100,0,16,2,42,13,32,9,24,0,\n10,5,110,97,109,101,0,16,1,42,15,32,5,24,0,10,\n7,110,117,109,98,101,114,0,16,3,42,59,24,0,16,4,\n32,14,42,43,103,111,111,103,108,101,46,112,114,111,116,111,\n98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,\n116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,10,\n6,108,97,98,101,108,0,42,57,24,0,16,5,32,14,42,\n42,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,\n46,70,105,101,108,100,68,101,115,99,114,105,112,116,111,114,\n80,114,111,116,111,46,84,121,112,101,0,10,5,116,121,112,\n101,0,42,18,32,9,24,0,10,10,116,121,112,101,95,110,\n97,109,101,0,16,6,42,17,32,9,24,0,10,9,101,120,\n116,101,110,100,101,101,0,16,2,42,22,32,9,24,0,10,\n14,100,101,102,97,117,108,116,95,118,97,108,117,101,0,16,\n7,42,47,24,0,16,8,32,11,42,29,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,\n79,112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,\n115,0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,\n1,42,57,24,2,16,2,32,11,42,41,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,69,110,117,109,86,\n97,108,117,101,68,101,115,99,114,105,112,116,111,114,80,114,\n111,116,111,0,10,6,118,97,108,117,101,0,42,46,24,0,\n16,3,32,11,42,28,103,111,111,103,108,101,46,112,114,111,\n116,111,98,117,102,46,69,110,117,109,79,112,116,105,111,110,\n115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9,\n24,0,10,5,110,97,109,101,0,16,1,42,15,32,5,24,\n0,10,7,110,117,109,98,101,114,0,16,2,42,51,24,0,\n16,3,32,11,42,33,103,111,111,103,108,101,46,112,114,111,\n116,111,98,117,102,46,69,110,117,109,86,97,108,117,101,79,\n112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,115,\n0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,\n42,55,24,2,16,2,32,11,42,38,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,77,101,116,104,111,100,\n68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0,\n10,7,109,101,116,104,111,100,0,42,49,24,0,16,3,32,\n11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98,\n117,102,46,83,101,114,118,105,99,101,79,112,116,105,111,110,\n115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9,\n24,0,10,5,110,97,109,101,0,16,1,42,19,32,9,24,\n0,10,11,105,110,112,117,116,95,116,121,112,101,0,16,2,\n42,20,32,9,24,0,10,12,111,117,116,112,117,116,95,116,\n121,112,101,0,16,3,42,48,24,0,16,4,32,11,42,30,\n103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,\n77,101,116,104,111,100,79,112,116,105,111,110,115,0,10,8,\n111,112,116,105,111,110,115,0,42,21,32,9,24,0,10,13,\n106,97,118,97,95,112,97,99,107,97,103,101,0,16,1,42,\n29,32,9,24,0,10,21,106,97,118,97,95,111,117,116,101,\n114,95,99,108,97,115,115,110,97,109,101,0,16,8,42,30,\n24,0,16,10,32,8,10,20,106,97,118,97,95,109,117,108,\n116,105,112,108,101,95,102,105,108,101,115,0,48,0,42,40,\n24,0,16,20,32,8,10,30,106,97,118,97,95,103,101,110,\n101,114,97,116,101,95,101,113,117,97,108,115,95,97,110,100,\n95,104,97,115,104,0,48,0,42,72,24,0,16,9,32,14,\n42,41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,\n102,46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,\n116,105,109,105,122,101,77,111,100,101,0,10,13,111,112,116,\n105,109,105,122,101,95,102,111,114,0,58,6,83,80,69,69,\n68,0,42,30,24,0,16,16,32,8,10,20,99,99,95,103,\n101,110,101,114,105,99,95,115,101,114,118,105,99,101,115,0,\n48,0,42,32,24,0,16,17,32,8,10,22,106,97,118,97,\n95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101,\n115,0,48,0,42,30,24,0,16,18,32,8,10,20,112,121,\n95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101,\n115,0,48,0,42,68,24,2,16,231,7,32,11,42,36,103,\n111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,85,\n110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,105,\n111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,116,\n101,100,95,111,112,116,105,111,110,0,42,34,24,0,16,1,\n32,8,10,24,109,101,115,115,97,103,101,95,115,101,116,95,\n119,105,114,101,95,102,111,114,109,97,116,0,48,0,42,42,\n24,0,16,2,32,8,10,32,110,111,95,115,116,97,110,100,\n97,114,100,95,100,101,115,99,114,105,112,116,111,114,95,97,\n99,99,101,115,115,111,114,0,48,0,42,68,24,2,16,231,\n7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116,\n111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,116,\n101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,116,\n101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,0,\n42,60,24,0,16,1,32,14,42,35,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,79,\n112,116,105,111,110,115,46,67,84,121,112,101,0,10,6,99,\n116,121,112,101,0,58,7,83,84,82,73,78,71,0,42,15,\n32,8,24,0,10,7,112,97,99,107,101,100,0,16,2,42,\n21,24,0,16,3,32,8,10,11,100,101,112,114,101,99,97,\n116,101,100,0,48,0,42,29,32,9,24,0,10,21,101,120,\n112,101,114,105,109,101,110,116,97,108,95,109,97,112,95,107,\n101,121,0,16,9,42,68,24,2,16,231,7,32,11,42,36,\n103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,\n85,110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,\n105,111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,\n116,101,100,95,111,112,116,105,111,110,0,42,68,24,2,16,\n231,7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,\n116,111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,\n116,101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,\n116,101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,\n0,42,68,24,2,16,231,7,32,11,42,36,103,111,111,103,\n108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110,\n116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0,\n10,21,117,110,105,110,116,101,114,112,114,101,116,101,100,95,\n111,112,116,105,111,110,0,42,68,24,2,16,231,7,32,11,\n42,36,103,111,111,103,108,101,46,112,114,111,116,111,98,117,\n102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79,\n112,116,105,111,110,0,10,21,117,110,105,110,116,101,114,112,\n114,101,116,101,100,95,111,112,116,105,111,110,0,42,68,24,\n2,16,231,7,32,11,42,36,103,111,111,103,108,101,46,112,\n114,111,116,111,98,117,102,46,85,110,105,110,116,101,114,112,\n114,101,116,101,100,79,112,116,105,111,110,0,10,21,117,110,\n105,110,116,101,114,112,114,101,116,101,100,95,111,112,116,105,\n111,110,0,42,60,24,2,16,2,32,11,42,45,103,111,111,\n103,108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,\n110,116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,\n46,78,97,109,101,80,97,114,116,0,10,5,110,97,109,101,\n0,42,25,32,9,24,0,10,17,105,100,101,110,116,105,102,\n105,101,114,95,118,97,108,117,101,0,16,3,42,27,32,4,\n24,0,10,19,112,111,115,105,116,105,118,101,95,105,110,116,\n95,118,97,108,117,101,0,16,4,42,27,32,3,24,0,10,\n19,110,101,103,97,116,105,118,101,95,105,110,116,95,118,97,\n108,117,101,0,16,5,42,21,32,1,24,0,10,13,100,111,\n117,98,108,101,95,118,97,108,117,101,0,16,6,42,21,32,\n12,24,0,10,13,115,116,114,105,110,103,95,118,97,108,117,\n101,0,16,7,42,24,32,9,24,0,10,16,97,103,103,114,\n101,103,97,116,101,95,118,97,108,117,101,0,16,8,42,18,\n32,9,24,1,10,10,110,97,109,101,95,112,97,114,116,0,\n16,1,42,21,32,8,24,1,10,13,105,115,95,101,120,116,\n101,110,115,105,111,110,0,16,2,42,59,24,2,16,1,32,\n11,42,40,103,111,111,103,108,101,46,112,114,111,116,111,98,\n117,102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,\n111,46,76,111,99,97,116,105,111,110,0,10,9,108,111,99,\n97,116,105,111,110,0,42,13,32,5,24,2,10,5,112,97,\n116,104,0,16,1,42,13,32,5,24,2,10,5,115,112,97,\n110,0,16,2,26,34,103,111,111,103,108,101,46,112,114,111,\n116,111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,\n112,116,111,114,83,101,116,0,26,36,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,70,105,108,101,68,101,\n115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,32,\n103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,\n68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0,\n26,47,103,111,111,103,108,101,46,112,114,111,116,111,98,117,\n102,46,68,101,115,99,114,105,112,116,111,114,80,114,111,116,\n111,46,69,120,116,101,110,115,105,111,110,82,97,110,103,101,\n0,26,37,103,111,111,103,108,101,46,112,114,111,116,111,98,\n117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,116,\n111,114,80,114,111,116,111,0,26,36,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,\n115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,41,\n103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,\n69,110,117,109,86,97,108,117,101,68,101,115,99,114,105,112,\n116,111,114,80,114,111,116,111,0,26,39,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105,\n99,101,68,101,115,99,114,105,112,116,111,114,80,114,111,116,\n111,0,26,38,103,111,111,103,108,101,46,112,114,111,116,111,\n98,117,102,46,77,101,116,104,111,100,68,101,115,99,114,105,\n112,116,111,114,80,114,111,116,111,0,26,28,103,111,111,103,\n108,101,46,112,114,111,116,111,98,117,102,46,70,105,108,101,\n79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,77,101,115,115,97,103,\n101,79,112,116,105,111,110,115,0,26,29,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,\n79,112,116,105,111,110,115,0,26,28,103,111,111,103,108,101,\n46,112,114,111,116,111,98,117,102,46,69,110,117,109,79,112,\n116,105,111,110,115,0,26,33,103,111,111,103,108,101,46,112,\n114,111,116,111,98,117,102,46,69,110,117,109,86,97,108,117,\n101,79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,\n101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105,\n99,101,79,112,116,105,111,110,115,0,26,30,103,111,111,103,\n108,101,46,112,114,111,116,111,98,117,102,46,77,101,116,104,\n111,100,79,112,116,105,111,110,115,0,26,36,103,111,111,103,\n108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110,\n116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0,\n26,45,103,111,111,103,108,101,46,112,114,111,116,111,98,117,\n102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79,\n112,116,105,111,110,46,78,97,109,101,80,97,114,116,0,26,\n31,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,\n46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,0,\n26,40,103,111,111,103,108,101,46,112,114,111,116,111,98,117,\n102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,\n46,76,111,99,97,116,105,111,110,0,\n};"
  },
  {
    "path": "code/EVA/server/server_share/pbc/map.cpp",
    "content": "#include \"map.h\"\n#include \"alloc.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nstruct _pbcM_ip_slot {\n\tint id;\n\tvoid * pointer;\n\tint next;\n};\n\nstruct map_ip {\n\tsize_t array_size;\n\tvoid ** array;\n\tsize_t hash_size;\n\tstruct _pbcM_ip_slot * slot;\n};\n\nstruct _pbcM_si_slot {\n\tconst char *key;\n\tsize_t hash;\n\tint id;\n\tint next;\n};\n\nstruct map_si {\n\tsize_t size;\n\tstruct _pbcM_si_slot slot[1];\n};\n\nstatic size_t\ncalc_hash(const char *name)\n{\n\tsize_t len = strlen(name);\n\tsize_t h = len;\n\tsize_t step = (len>>5)+1;\n\tsize_t i;\n\tfor (i=len; i>=step; i-=step)\n\t    h = h ^ ((h<<5)+(h>>2)+(size_t)name[i-1]);\n\treturn h;\n}\n\nstruct map_si *\n_pbcM_si_new(struct map_kv * table, int size)\n{\n\tsize_t sz = sizeof(struct map_si) + (size-1) * sizeof(struct _pbcM_si_slot);\n\tstruct map_si * ret = (struct map_si *)pbc_malloc(sz);\n\tmemset(ret,0,sz);\n\n\tret->size = (size_t)size;\n\n\tint empty = 0;\n\tint i;\n\n\tfor (i=0;i<size;i++) {\n\t\tsize_t hash_full = calc_hash((const char *)table[i].pointer);\n\t\tsize_t hash = hash_full % size;\n\t\tstruct _pbcM_si_slot * slot = &ret->slot[hash];\n\t\tif (slot->key == NULL) {\n\t\t\tslot->key = (const char *)table[i].pointer;\n\t\t\tslot->id = table[i].id;\n\t\t\tslot->hash = hash_full;\n\t\t} else {\n\t\t\twhile(ret->slot[empty].key != NULL) {\n\t\t\t\t++empty;\n\t\t\t}\n\t\t\tstruct _pbcM_si_slot * empty_slot = &ret->slot[empty];\n\t\t\tempty_slot->next = slot->next;\n\t\t\tslot->next = empty + 1;\n\t\t\tempty_slot->id = table[i].id;\n\t\t\tempty_slot->key = (const char *)table[i].pointer;\n\t\t\tempty_slot->hash = hash_full;\n\t\t}\n\t}\n\n\treturn ret;\n}\n\nvoid \n_pbcM_si_delete(struct map_si *map)\n{\n\tpbc_free(map);\n}\n\nint\n_pbcM_si_query(struct map_si *map, const char *key, int *result) \n{\n\tsize_t hash_full = calc_hash(key);\n\tsize_t hash = hash_full % map->size;\n\n\tstruct _pbcM_si_slot * slot = &map->slot[hash];\n\tif (slot->key == NULL) {\n\t\treturn 1;\n\t}\n\tfor (;;) {\n\t\tif (slot->hash == hash_full && strcmp(slot->key, key) == 0) {\n\t\t\t*result = slot->id;\n\t\t\treturn 0;\n\t\t}\n\t\tif (slot->next == 0) {\n\t\t\treturn 1;\n\t\t}\n\t\tslot = &map->slot[slot->next-1];\n\t}\n}\n\nstatic struct map_ip *\n_pbcM_ip_new_hash(struct map_kv * table, int size)\n{\n\tstruct map_ip * ret = (struct map_ip *)pbc_malloc(sizeof(struct map_ip));\n\tret->array = NULL;\n\tret->array_size = 0;\n\tret->hash_size = (size_t)size;\n\tret->slot = (struct _pbcM_ip_slot *)pbc_malloc(sizeof(struct _pbcM_ip_slot) * size);\n\tmemset(ret->slot,0,sizeof(struct _pbcM_ip_slot) * size);\n\tint empty = 0;\n\tint i;\n\tfor (i=0;i<size;i++) {\n\t\tint hash = ((unsigned)table[i].id) % size;\n\t\tstruct _pbcM_ip_slot * slot = &ret->slot[hash];\n\t\tif (slot->pointer == NULL) {\n\t\t\tslot->pointer = table[i].pointer;\n\t\t\tslot->id = table[i].id;\n\t\t} else {\n\t\t\twhile(ret->slot[empty].pointer != NULL) {\n\t\t\t\t++empty;\n\t\t\t}\n\t\t\tstruct _pbcM_ip_slot * empty_slot = &ret->slot[empty];\n\t\t\tempty_slot->next = slot->next;\n\t\t\tslot->next = empty + 1;\n\t\t\tempty_slot->id = table[i].id;\n\t\t\tempty_slot->pointer = table[i].pointer;\n\t\t}\n\t}\n\treturn ret;\n}\n\nstruct map_ip *\n_pbcM_ip_new(struct map_kv * table, int size)\n{\n\tint i;\n\tint max = table[0].id;\n\tif (max > size * 2 || max < 0)\n\t\treturn _pbcM_ip_new_hash(table,size);\n\tfor (i=1;i<size;i++) {\n\t\tif (table[i].id < 0) {\n\t\t\treturn _pbcM_ip_new_hash(table,size);\n\t\t}\n\t\tif (table[i].id > max) {\n\t\t\tmax = table[i].id;\n\t\t\tif (max > size * 2)\n\t\t\t\treturn _pbcM_ip_new_hash(table,size);\n\t\t}\n\t}\n\tstruct map_ip * ret = (struct map_ip *)pbc_malloc(sizeof(struct map_ip));\n\tret->hash_size = size;\n\tret->slot = NULL;\n\tret->array_size = max + 1;\n\tret->array = (void **)pbc_malloc((max+1) * sizeof(void *));\n\tmemset(ret->array,0,(max+1) * sizeof(void *));\n\tfor (i=0;i<size;i++) {\n\t\tret->array[table[i].id] = table[i].pointer;\n\t}\n\treturn ret;\n}\n\nvoid\n_pbcM_ip_delete(struct map_ip * map)\n{\n\tif (map) {\n\t\tpbc_free(map->array);\n\t\tpbc_free(map->slot);\n\t\tpbc_free(map);\n\t}\n}\n\nstatic void\n_inject(struct map_kv * table, struct map_ip *map)\n{\n\tif (map->array) {\n\t\tint n = 0;\n\t\tint i;\n\t\tfor (i=0;i<(int)map->array_size;i++) {\n\t\t\tif (map->array[i]) {\n\t\t\t\ttable[n].id = i;\n\t\t\t\ttable[n].pointer = map->array[i];\n\t\t\t\t++ n;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tint i;\n\t\tfor (i=0;i<(int)map->hash_size;i++) {\n\t\t\ttable[i].id = map->slot[i].id;\n\t\t\ttable[i].pointer = map->slot[i].pointer;\n\t\t}\n\t}\n}\n\nstruct map_ip *\n_pbcM_ip_combine(struct map_ip *a, struct map_ip *b)\n{\n\tint sz = (int)(a->hash_size + b->hash_size);\n\tstruct map_kv * table = (struct map_kv *)pbc_malloc(sz * sizeof(struct map_kv));\n\tmemset(table , 0 , \tsz * sizeof(struct map_kv));\n\t_inject(table, a);\n\t_inject(table + a->hash_size, b);\n\tstruct map_ip * r = _pbcM_ip_new(table, sz);\n\tpbc_free(table);\n\treturn r;\n}\n\nvoid *\n_pbcM_ip_query(struct map_ip * map, int id)\n{\n\tif (map == NULL)\n\t\treturn NULL;\n\tif (map->array) {\n\t\tif (id>=0 && id<(int)map->array_size)\n\t\t\treturn map->array[id];\n\t\treturn NULL;\n\t}\n\tint hash = (unsigned)id % map->hash_size;\n\tstruct _pbcM_ip_slot * slot = &map->slot[hash];\n\tfor (;;) {\n\t\tif (slot->id == id) {\n\t\t\treturn slot->pointer;\n\t\t}\n\t\tif (slot->next == 0) {\n\t\t\treturn NULL;\n\t\t}\n\t\tslot = &map->slot[slot->next-1];\n\t}\n}\n\nstruct _pbcM_sp_slot {\n\tconst char *key;\n\tsize_t hash;\n\tvoid *pointer;\n\tint next;\n};\n\nstruct map_sp {\n\tsize_t cap;\n\tsize_t size;\n\tstruct heap *heap;\n\tstruct _pbcM_sp_slot * slot;\n};\n\nstruct map_sp *\n_pbcM_sp_new(int max , struct heap *h)\n{\n\tstruct map_sp * ret = (struct map_sp *)HMALLOC(sizeof(struct map_sp));\n\tint cap = 1;\n\twhile (cap < max) {\n\t\tcap *=2;\n\t}\n\tret->cap = cap;\n\tret->size = 0;\n\tret->slot = (struct _pbcM_sp_slot *)HMALLOC(ret->cap * sizeof(struct _pbcM_sp_slot));\n\tmemset(ret->slot,0,sizeof(struct _pbcM_sp_slot) * ret->cap);\n\tret->heap = h;\n\treturn ret;\n}\n\nvoid\n_pbcM_sp_delete(struct map_sp *map)\n{\n\tif (map && map->heap == NULL) {\n\t\t_pbcM_free(map->slot);\n\t\t_pbcM_free(map);\n\t}\n}\n\nstatic void _pbcM_sp_rehash(struct map_sp *map);\n\nstatic void\n_pbcM_sp_insert_hash(struct map_sp *map, const char *key, size_t hash_full, void * value)\n{\n\tif (map->cap > map->size) {\n\t\tsize_t hash = hash_full & (map->cap-1);\n\t\tstruct _pbcM_sp_slot * slot = &map->slot[hash];\n\t\tif (slot->key == NULL) {\n\t\t\tslot->key = key;\n\t\t\tslot->pointer = value;\n\t\t\tslot->hash = hash_full;\n\t\t} else {\n\t\t\tint empty = (hash + 1) & (map->cap-1);\n\t\t\twhile(map->slot[empty].key != NULL) {\n\t\t\t\tempty = (empty + 1) & (map->cap-1);\n\t\t\t}\n\t\t\tstruct _pbcM_sp_slot * empty_slot = &map->slot[empty];\n\t\t\tempty_slot->next = slot->next;\n\t\t\tslot->next = empty + 1;\n\t\t\tempty_slot->pointer = value;\n\t\t\tempty_slot->key = key;\n\t\t\tempty_slot->hash = hash_full;\n\t\t}\n\t\tmap->size++;\n\t\treturn;\n\t}\n\t_pbcM_sp_rehash(map);\n\t_pbcM_sp_insert_hash(map, key, hash_full, value);\n}\n\nstatic void\n_pbcM_sp_rehash(struct map_sp *map) {\n\tstruct heap * h = map->heap;\n\tstruct _pbcM_sp_slot * old_slot = map->slot;\n\tsize_t size = map->size;\n\tmap->size = 0;\n\tmap->cap *= 2;\n\tmap->slot = (struct _pbcM_sp_slot *)HMALLOC(sizeof(struct _pbcM_sp_slot)*map->cap);\n\tmemset(map->slot,0,sizeof(struct _pbcM_sp_slot)*map->cap);\n\tsize_t i;\n\tfor (i=0;i<size;i++) {\n\t\t_pbcM_sp_insert_hash(map, old_slot[i].key, old_slot[i].hash, old_slot[i].pointer);\n\t}\n\tif (h == NULL) {\n\t\t_pbcM_free(old_slot);\n\t}\n}\n\nstatic void **\n_pbcM_sp_query_insert_hash(struct map_sp *map, const char *key, size_t hash_full)\n{\n\tsize_t hash = hash_full & (map->cap-1);\n\tstruct _pbcM_sp_slot * slot = &map->slot[hash];\n\tif (slot->key == NULL) {\n\t\tif (map->cap <= map->size) \n\t\t\tgoto _rehash;\n\t\tslot->key = key;\n\t\tslot->hash = hash_full;\n\t\tmap->size++;\n\t\treturn &(slot->pointer);\n\t} else {\n\t\tfor (;;) {\n\t\t\tif (slot->hash == hash_full && strcmp(slot->key, key) == 0) \n\t\t\t\treturn &(slot->pointer);\n\t\t\tif (slot->next == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tslot = &map->slot[slot->next-1];\n\t\t}\n\t\tif (map->cap <= map->size) \n\t\t\tgoto _rehash;\n\n\t\tint empty = (hash + 1) & (map->cap-1);\n\t\twhile(map->slot[empty].key != NULL) {\n\t\t\tempty = (empty + 1) & (map->cap-1);\n\t\t}\n\t\tstruct _pbcM_sp_slot * empty_slot = &map->slot[empty];\n\t\tempty_slot->next = slot->next;\n\t\tslot->next = empty + 1;\n\t\tempty_slot->key = key;\n\t\tempty_slot->hash = hash_full;\n\n\t\tmap->size++;\n\n\t\treturn &(empty_slot->pointer);\n\t}\n_rehash:\n\t_pbcM_sp_rehash(map);\n\treturn _pbcM_sp_query_insert_hash(map, key, hash_full);\n}\n\nvoid\n_pbcM_sp_insert(struct map_sp *map, const char *key, void * value)\n{\n\t_pbcM_sp_insert_hash(map,key,calc_hash(key),value);\n}\n\nvoid **\n_pbcM_sp_query_insert(struct map_sp *map, const char *key)\n{\n\treturn _pbcM_sp_query_insert_hash(map,key,calc_hash(key));\n}\n\nvoid *\n_pbcM_sp_query(struct map_sp *map, const char *key)\n{\n\tif (map == NULL)\n\t\treturn NULL;\n\tsize_t hash_full = calc_hash(key);\n\tsize_t hash = hash_full & (map->cap -1);\n\n\tstruct _pbcM_sp_slot * slot = &map->slot[hash];\n\tif (slot->key == NULL)\n\t\treturn NULL;\n\tfor (;;) {\n\t\tif (slot->hash == hash_full && strcmp(slot->key, key) == 0) {\n\t\t\treturn slot->pointer;\n\t\t}\n\t\tif (slot->next == 0) {\n\t\t\treturn NULL;\n\t\t}\n\t\tslot = &map->slot[slot->next-1];\n\t}\n}\n\nvoid \n_pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p))\n{\n\tsize_t i;\n\tfor (i=0;i<map->cap;i++) {\n\t\tif (map->slot[i].pointer) {\n\t\t\tfunc(map->slot[i].pointer);\n\t\t}\n\t}\n}\n\nvoid \n_pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud)\n{\n\tsize_t i;\n\tfor (i=0;i<map->cap;i++) {\n\t\tif (map->slot[i].pointer) {\n\t\t\tfunc(map->slot[i].pointer,ud);\n\t\t}\n\t}\n}\n\nstatic int\n_find_first(struct map_sp *map)\n{\n\tsize_t i;\n\tfor (i=0;i<map->cap;i++) {\n\t\tif (map->slot[i].pointer) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\nstatic int\n_find_next(struct map_sp *map, const char *key)\n{\n\tsize_t hash_full = calc_hash(key);\n\tsize_t hash = hash_full & (map->cap -1);\n\n\tstruct _pbcM_sp_slot * slot = &map->slot[hash];\n\tif (slot->key == NULL)\n\t\treturn -1;\n\tfor (;;) {\n\t\tif (slot->hash == hash_full && strcmp(slot->key, key) == 0) {\n\t\t\tint i = slot - map->slot + 1;\n\t\t\twhile(i<map->cap) {\n\t\t\t\tif (map->slot[i].pointer) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t\t++i;\n\t\t\t}\n\t\t\treturn -1;\n\t\t}\n\t\tif (slot->next == 0) {\n\t\t\treturn -1;\n\t\t}\n\t\tslot = &map->slot[slot->next-1];\n\t}\n}\n\nvoid * \n_pbcM_sp_next(struct map_sp *map, const char ** key)\n{\n\tif (map == NULL) {\n\t\t*key = NULL;\n\t\treturn NULL;\n\t}\n\tint idx;\n\tif (*key == NULL) {\n\t\tidx = _find_first(map);\n\t} else {\n\t\tidx = _find_next(map, *key);\n\t}\n\tif (idx < 0) {\n\t\t*key = NULL;\n\t\treturn NULL;\n\t}\n\t*key = map->slot[idx].key;\n\treturn map->slot[idx].pointer;\n}\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/map.h",
    "content": "#ifndef PROTOBUF_C_MAP_H\n#define PROTOBUF_C_MAP_H\n\n#include \"alloc.h\"\n\nstruct map_ip;\nstruct map_si;\nstruct map_sp;\n\nstruct map_kv {\n\tint id;\n\tvoid *pointer;\n};\n\nstruct map_si * _pbcM_si_new(struct map_kv * table, int size);\nint _pbcM_si_query(struct map_si *map, const char *key, int *result);\nvoid _pbcM_si_delete(struct map_si *map);\n\nstruct map_ip * _pbcM_ip_new(struct map_kv * table, int size);\nstruct map_ip * _pbcM_ip_combine(struct map_ip * a, struct map_ip * b);\nvoid * _pbcM_ip_query(struct map_ip * map, int id);\nvoid _pbcM_ip_delete(struct map_ip *map);\n\nstruct map_sp * _pbcM_sp_new(int max, struct heap *h);\nvoid _pbcM_sp_insert(struct map_sp *map, const char *key, void * value);\nvoid * _pbcM_sp_query(struct map_sp *map, const char *key);\nvoid ** _pbcM_sp_query_insert(struct map_sp *map, const char *key);\nvoid _pbcM_sp_delete(struct map_sp *map);\nvoid _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p));\nvoid _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud);\nvoid * _pbcM_sp_next(struct map_sp *map, const char ** key);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/pattern.cpp",
    "content": "#include \"alloc.h\"\n#include \"context.h\"\n#include \"varint.h\"\n#include \"pattern.h\"\n#include \"array.h\"\n#include \"proto.h\"\n#include \"map.h\"\n\n#include <stdint.h>\n#ifndef _MSC_VER\n#include <stdbool.h>\n#endif\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <stdarg.h>\n\nstatic void\nset_default_v(void * output, int ctype, pbc_var defv) {\n\tswitch (ctype) {\n\tcase CTYPE_INT32:\n\t\t*(uint32_t *)output = defv->integer.low;\n\t\tbreak;\n\tcase CTYPE_INT64:\n\t\t*(uint64_t *)output = (uint64_t)defv->integer.low | (uint64_t)defv->integer.hi << 32;\n\t\tbreak;\n\tcase CTYPE_DOUBLE:\n\t\t*(double *)output = defv->real;\n\t\tbreak;\n\tcase CTYPE_FLOAT:\n\t\t*(float *)output = (float)defv->real;\n\t\tbreak;\n\tcase CTYPE_BOOL:\n\t\t*(bool *)output = (defv->integer.low != 0);\n\t\tbreak;\n\tcase CTYPE_INT8:\n\t\t*(uint8_t *)output = (uint8_t)defv->integer.low;\n\t\tbreak;\n\tcase CTYPE_INT16:\n\t\t*(uint16_t *)output = (uint16_t)defv->integer.low;\n\t\tbreak;\n\tcase CTYPE_VAR:\n\t\t*(union _pbc_var *)output = *defv;\n\t\tbreak;\n\t}\n}\n\nstatic void\n_pattern_set_default(struct _pattern_field *field, char *output) {\n\tif (field->ctype == CTYPE_ARRAY || field->ctype == CTYPE_PACKED) {\n\t\tstruct _pbc_array *array = (struct _pbc_array *)(output + field->offset);\n\t\t_pbcA_open(array);\n\t} else if (field->ptype == PTYPE_ENUM) {\n\t\tpbc_var defv;\n\t\tdefv->integer.low = field->defv->e.id;\n\t\tdefv->integer.hi = 0;\n\t\tset_default_v(output + field->offset, field->ctype, defv);\n\t}\n\tset_default_v(output + field->offset, field->ctype, field->defv);\n}\n\nvoid\npbc_pattern_set_default(struct pbc_pattern *pat, void *output) {\n\tint i;\n\tfor (i=0;i<pat->count;i++) {\n\t\t_pattern_set_default(&pat->f[i], (char *)output);\n\t}\n}\n\n// pattern unpack\n\nstatic struct _pattern_field *\nbsearch_pattern(struct pbc_pattern *pat, int id)\n{\n\tint begin = 0;\n\tint end = pat->count;\n\twhile (begin < end) {\n\t\tint mid = (begin + end)/2;\n\t\tstruct _pattern_field * f = &pat->f[mid];\n\t\tif (id == f->id) {\n\t\t\treturn f;\n\t\t}\n\t\tif (id < f->id) {\n\t\t\tend = mid;\n\t\t} else {\n\t\t\tbegin = mid + 1;\n\t\t}\n\t}\n\treturn NULL;\n}\n\nstatic inline int\nwrite_real(int ctype, double v, void *out) {\n\tswitch(ctype) {\n\tcase CTYPE_DOUBLE:\n\t\t*(double *)out = v;\n\t\treturn 0;\n\tcase CTYPE_FLOAT:\n\t\t*(float *)out = (float)v;\n\t\treturn 0;\n\tcase CTYPE_VAR:\n\t\t((union _pbc_var *)out)->real = v;\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\nstatic inline int\nwrite_longlong(int ctype, struct longlong *i, void *out) {\n\tswitch(ctype) {\n\tcase CTYPE_INT32:\n\t\t*(uint32_t *)out = i->low;\n\t\treturn 0;\n\tcase CTYPE_INT64:\n\t\t*(uint64_t *)out = (uint64_t)i->low | (uint64_t)i->hi << 32;\n\t\treturn 0;\n\tcase CTYPE_BOOL:\n\t\t*(bool *)out = (i->low !=0) ;\n\t\treturn 0;\n\tcase CTYPE_INT8:\n\t\t*(uint8_t *)out = (uint8_t)i->low;\n\t\treturn 0;\n\tcase CTYPE_INT16:\n\t\t*(uint8_t *)out = (uint16_t)i->low;\n\t\treturn 0;\n\tcase CTYPE_VAR:\n\t\t((union _pbc_var *)out)->integer = *i;\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\nstatic inline int\nwrite_integer(int ctype, struct atom *a, void *out) {\n\treturn write_longlong(ctype, &(a->v.i), out);\n}\n\nstatic int unpack_array(int ptype, char *buffer, struct atom *, pbc_array _array);\n\nint\n_pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array) {\n\tpbc_var var;\n\tvar->integer.hi = 0;\n\tint i;\n\tswitch(ptype) {\n\tcase PTYPE_DOUBLE:\n\t\tif (size % 8 != 0)\n\t\t\treturn -1;\n\t\tfor (i=0;i<size;i+=8) {\n\t\t\tunion {\n\t\t\t\tdouble d;\n\t\t\t\tuint64_t i64;\n\t\t\t} u;\n\t\t\tu.i64 = (uint64_t)buffer[i] |\n\t\t\t\t(uint64_t)buffer[i+1] << 8 |\n\t\t\t\t(uint64_t)buffer[i+2] << 16 |\n\t\t\t\t(uint64_t)buffer[i+3] << 24 |\n\t\t\t\t(uint64_t)buffer[i+4] << 32 |\n\t\t\t\t(uint64_t)buffer[i+5] << 40 |\n\t\t\t\t(uint64_t)buffer[i+6] << 48 |\n\t\t\t\t(uint64_t)buffer[i+7] << 56;\n\t\t\tvar->real = u.d;\n\t\t\t_pbcA_push(array, var);\n\t\t}\n\t\treturn size/8;\n\tcase PTYPE_FLOAT:\n\t\tif (size % 4 != 0)\n\t\t\treturn -1;\n\t\tfor (i=0;i<size;i+=4) {\n\t\t\tunion {\n\t\t\t\tfloat f;\n\t\t\t\tuint32_t i32;\n\t\t\t} u;\n\t\t\tu.i32 = (uint32_t)buffer[i] |\n\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\tvar->real = (double)u.f;\n\t\t\t_pbcA_push(array, var);\n\t\t}\n\t\treturn size/4;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tif (size % 4 != 0)\n\t\t\treturn -1;\n\t\tfor (i=0;i<size;i+=4) {\n\t\t\tvar->integer.low = (uint32_t)buffer[i] |\n\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\t_pbcA_push(array, var);\n\t\t}\n\t\treturn size/4;\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tif (size % 8 != 0)\n\t\t\treturn -1;\n\t\tfor (i=0;i<size;i+=8) {\n\t\t\tvar->integer.low = (uint32_t)buffer[i] |\n\t\t\t\t(uint32_t)buffer[i+1] << 8 |\n\t\t\t\t(uint32_t)buffer[i+2] << 16 |\n\t\t\t\t(uint32_t)buffer[i+3] << 24;\n\t\t\tvar->integer.hi = (uint32_t)buffer[i+4] |\n\t\t\t\t(uint32_t)buffer[i+5] << 8 |\n\t\t\t\t(uint32_t)buffer[i+6] << 16 |\n\t\t\t\t(uint32_t)buffer[i+7] << 24;\n\t\t\t_pbcA_push(array, var);\n\t\t}\n\t\treturn size/8;\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\t// enum must be integer type in pattern mode\n\tcase PTYPE_BOOL: {\n\t\tint n = 0;\n\t\twhile (size > 0) {\n\t\t\tint len;\n\t\t\tif (size >= 10) {\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t} else {\n\t\t\t\tuint8_t temp[10];\n\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t\tif (len > size)\n\t\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t_pbcA_push(array, var);\n\t\t\tbuffer += len;\n\t\t\tsize -= len;\n\t\t\t++n;\n\t\t}\n\t\treturn n;\n\t}\n\tcase PTYPE_SINT32: {\n\t\tint n = 0;\n\t\twhile (size > 0) {\n\t\t\tint len;\n\t\t\tif (size >= 10) {\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t\t_pbcV_dezigzag32(&(var->integer));\n\t\t\t} else {\n\t\t\t\tuint8_t temp[10];\n\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t\tif (len > size)\n\t\t\t\t\treturn -1;\n\t\t\t\t_pbcV_dezigzag32(&(var->integer));\n\t\t\t}\n\t\t\t_pbcA_push(array, var);\n\t\t\tbuffer += len;\n\t\t\tsize -= len;\n\t\t\t++n;\n\t\t}\n\t\treturn n;\n\t}\n\tcase PTYPE_SINT64: {\n\t\tint n = 0;\n\t\twhile (size > 0) {\n\t\t\tint len;\n\t\t\tif (size >= 10) {\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t\t_pbcV_dezigzag64(&(var->integer));\n\t\t\t} else {\n\t\t\t\tuint8_t temp[10];\n\t\t\t\tmemcpy(temp, buffer, size);\n\t\t\t\tlen = _pbcV_decode(buffer, &(var->integer));\n\t\t\t\tif (len > size)\n\t\t\t\t\treturn -1;\n\t\t\t\t_pbcV_dezigzag64(&(var->integer));\n\t\t\t}\n\t\t\t_pbcA_push(array, var);\n\t\t\tbuffer += len;\n\t\t\tsize -= len;\n\t\t\t++n;\n\t\t}\n\t\treturn n;\n\t}\n\t}\n\treturn -1;\n}\n\nstatic int\nunpack_field(int ctype, int ptype, char * buffer, struct atom * a, void *out) {\n\tif (ctype == CTYPE_ARRAY) {\n\t\treturn unpack_array(ptype, buffer, a , (struct _pbc_array *)out);\n\t}\n\tif (ctype == CTYPE_PACKED) {\n\t\treturn _pbcP_unpack_packed((uint8_t *)buffer + a->v.s.start, a->v.s.end - a->v.s.start,\tptype, (struct _pbc_array *)out);\n\t}\n\tswitch(ptype) {\n\tcase PTYPE_DOUBLE:\n\t\tCHECK_BIT64(a, -1);\n\t\treturn write_real(ctype, read_double(a), out);\n\tcase PTYPE_FLOAT:\n\t\tCHECK_BIT32(a, -1);\n\t\treturn write_real(ctype, read_float(a), out);\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\t// enum must be integer type in pattern mode\n\tcase PTYPE_BOOL:\n\t\tCHECK_VARINT(a, -1);\n\t\treturn write_integer(ctype, a , out);\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tCHECK_BIT32(a, -1);\n\t\treturn write_integer(ctype, a , out);\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tCHECK_BIT64(a, -1);\n\t\treturn write_integer(ctype, a , out);\n\tcase PTYPE_SINT32: {\n\t\tCHECK_VARINT(a, -1);\n\t\tstruct longlong temp = a->v.i;\n\t\t_pbcV_dezigzag32(&temp);\n\t\treturn write_longlong(ctype, &temp , out);\n\t}\n\tcase PTYPE_SINT64: {\n\t\tCHECK_LEND(a, -1);\n\t\tstruct longlong temp = a->v.i;\n\t\t_pbcV_dezigzag64(&temp);\n\t\treturn write_longlong(ctype, &temp , out);\n\t}\n\tcase PTYPE_MESSAGE: \n\t\tCHECK_LEND(a, -1);\n\t\t((union _pbc_var *)out)->m.buffer = buffer + a->v.s.start;\n\t\t((union _pbc_var *)out)->m.len = a->v.s.end - a->v.s.start;\n\t\treturn 0;\n\tcase PTYPE_STRING:\n\tcase PTYPE_BYTES:\n\t\tCHECK_LEND(a, -1);\n\t\t((struct pbc_slice *)out)->buffer = buffer + a->v.s.start;\n\t\t((struct pbc_slice *)out)->len = a->v.s.end - a->v.s.start;\n\t\treturn 0;\n\t}\n\treturn -1;\n}\n\nstatic int \nunpack_array(int ptype, char *buffer, struct atom * a, pbc_array _array) {\n\tpbc_var var;\n\tint r = unpack_field(CTYPE_VAR, ptype, buffer, a , var);\n\tif (r !=0 )\n\t\treturn r;\n\t_pbcA_push(_array , var);\n\n\treturn 0;\n}\n\nvoid \npbc_pattern_close_arrays(struct pbc_pattern *pat, void * data) {\n\tint i;\n\tfor (i=0;i<pat->count;i++) {\n\t\tif (pat->f[i].ctype == CTYPE_ARRAY || pat->f[i].ctype == CTYPE_PACKED) {\n\t\t\tvoid *array = (char *)data + pat->f[i].offset;\n\t\t\t_pbcA_close((struct _pbc_array *)array);\n\t\t}\n\t}\n}\n\nstatic inline int\n_pack_wiretype(uint32_t wt, struct pbc_slice *s) {\n\tint len;\n\tif (s->len < 10) {\n\t\tuint8_t temp[10];\n\t\tlen = _pbcV_encode32(wt, temp);\n\t\tif (len > s->len)\n\t\t\treturn -1;\n\t\tmemcpy(s->buffer, temp, len);\n\t} else {\n\t\tlen = _pbcV_encode32(wt, (uint8_t *)s->buffer);\n\t}\n\ts->buffer = (char *)s->buffer + len;\n\ts->len -= len;\n\treturn len;\n}\n\nstatic inline int\n_pack_varint64(uint64_t i64, struct pbc_slice *s) {\n\tint len;\n\tif (s->len < 10) {\n\t\tuint8_t temp[10];\n\t\tlen = _pbcV_encode(i64, temp);\n\t\tif (len > s->len)\n\t\t\treturn -1;\n\t\tmemcpy(s->buffer, temp, len);\n\t} else {\n\t\tlen = _pbcV_encode(i64, (uint8_t *)s->buffer);\n\t}\n\ts->buffer = (char *)s->buffer + len;\n\ts->len -= len;\n\treturn len;\n}\n\nstatic inline int\n_pack_sint32(uint32_t v, struct pbc_slice *s) {\n\tint len;\n\tif (s->len < 10) {\n\t\tuint8_t temp[10];\n\t\tlen = _pbcV_zigzag32(v, temp);\n\t\tif (len > s->len)\n\t\t\treturn -1;\n\t\tmemcpy(s->buffer, temp, len);\n\t} else {\n\t\tlen = _pbcV_zigzag32(v, (uint8_t *)s->buffer);\n\t}\n\ts->buffer = (char *)s->buffer + len;\n\ts->len -= len;\n\treturn len;\n}\n\nstatic inline int\n_pack_sint64(uint64_t v, struct pbc_slice *s) {\n\tint len;\n\tif (s->len < 10) {\n\t\tuint8_t temp[10];\n\t\tlen = _pbcV_zigzag(v, temp);\n\t\tif (len > s->len)\n\t\t\treturn -1;\n\t\tmemcpy(s->buffer, temp, len);\n\t} else {\n\t\tlen = _pbcV_zigzag(v, (uint8_t *)s->buffer);\n\t}\n\ts->buffer = (char *)s->buffer + len;\n\ts->len -= len;\n\treturn len;\n}\n\nstatic inline void\n_fix32_encode(uint32_t v , uint8_t *buffer) {\n\tbuffer[0] = (uint8_t) v;\n\tbuffer[1] = (uint8_t) (v >> 8);\n\tbuffer[2] = (uint8_t) (v >> 16);\n\tbuffer[3] = (uint8_t) (v >> 24);\n}\n\nstatic inline void\n_fix64_encode(struct longlong *v , uint8_t *buffer) {\n\t_fix32_encode(v->low , buffer);\n\t_fix32_encode(v->hi, buffer + 4);\n}\n\nstatic int\n_pack_number(int ptype , int ctype , struct pbc_slice *s, void *input) {\n\tpbc_var var;\n\tif (ctype == CTYPE_VAR) {\n\t\tmemcpy(var, input, sizeof(var));\n\t} else {\n\t\tswitch (ctype) {\n\t\tcase CTYPE_INT32:\n\t\t\tvar->integer.low = *(uint32_t *)input;\n\t\t\tvar->integer.hi = 0;\n\t\t\tbreak;\n\t\tcase CTYPE_INT64: {\n\t\t\tuint64_t v = *(uint64_t *)input;\n\t\t\tvar->integer.low = (uint32_t) (v & 0xffffffff);\n\t\t\tvar->integer.hi = (uint32_t) (v >> 32);\n\t\t\tbreak;\n\t\t}\n\t\tcase CTYPE_INT16:\n\t\t\tvar->integer.low = *(uint16_t *)input;\n\t\t\tvar->integer.hi = 0;\n\t\t\tbreak;\n\t\tcase CTYPE_INT8:\n\t\t\tvar->integer.low = *(uint8_t *)input;\n\t\t\tvar->integer.hi = 0;\n\t\t\tbreak;\n\t\tcase CTYPE_BOOL:\n\t\t\tvar->integer.low = *(bool *)input;\n\t\t\tvar->integer.hi = 0;\n\t\t\tbreak;\n\t\tcase CTYPE_DOUBLE:\n\t\t\tvar->real = *(double *)input;\n\t\t\tbreak;\n\t\tcase CTYPE_FLOAT:\n\t\t\tvar->real = *(float *)input;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tswitch(ptype) {\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tif (s->len < 8)\n\t\t\treturn -1;\n\t\t_fix64_encode(&(var->integer), (uint8_t *)s->buffer);\n\t\ts->buffer = (char *)s->buffer + 8;\n\t\ts->len -= 8;\n\t\treturn 8;\n\tcase PTYPE_DOUBLE:\n\t\tif (s->len < 8)\n\t\t\treturn -1;\n\t\tdouble_encode(var->real , (uint8_t *)s->buffer);\n\t\ts->buffer = (char *)s->buffer + 8;\n\t\ts->len -= 8;\n\t\treturn 8;\n\tcase PTYPE_FLOAT:\n\t\tif (s->len < 4)\n\t\t\treturn -1;\n\t\tfloat_encode((float)var->real , (uint8_t *)s->buffer);\n\t\ts->buffer = (char *)s->buffer + 4;\n\t\ts->len -= 4;\n\t\treturn 4;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tif (s->len < 4)\n\t\t\treturn -1;\n\t\t_fix32_encode(var->integer.low, (uint8_t *)s->buffer);\n\t\ts->buffer = (char *)s->buffer + 4;\n\t\ts->len -= 4;\n\t\treturn 4;\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT64:\n\tcase PTYPE_INT32:\n\t\treturn _pack_varint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32, s);\n\tcase PTYPE_UINT32:\n\tcase PTYPE_BOOL:\n\tcase PTYPE_ENUM:\n\t\treturn _pack_wiretype(var->integer.low , s);\n\tcase PTYPE_SINT32: \n\t\treturn _pack_sint32(var->integer.low , s);\n\tcase PTYPE_SINT64:\n\t\treturn _pack_sint64((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , s);\n\tdefault:\n\t\treturn -1;\n\t}\n}\n\nstatic int\n_pack_field(struct _pattern_field *pf , int ctype, struct pbc_slice *s, void *input) {\n\tint wiretype;\n\tint ret = 0;\n\tint len;\n\tstruct pbc_slice * input_slice;\n\tstruct pbc_slice string_slice;\n\n\tswitch(pf->ptype) {\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\tcase PTYPE_DOUBLE:\n\t\twiretype = WT_BIT64;\n\t\tgoto _number;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\tcase PTYPE_FLOAT:\n\t\twiretype = WT_BIT32;\n\t\tgoto _number;\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_BOOL:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\n\tcase PTYPE_SINT32:\n\tcase PTYPE_SINT64:\n\t\twiretype = WT_VARINT;\n\t\tgoto _number;\n\tcase PTYPE_STRING:\n\t\twiretype = WT_LEND;\n\t\tinput_slice = (struct pbc_slice *)input;\n\t\tif (input_slice->len >= 0)\n\t\t\tgoto _string;\n\t\tstring_slice.buffer = input_slice->buffer;\n\t\tstring_slice.len = strlen((const char *)string_slice.buffer) - input_slice->len;\n\t\tinput_slice = &string_slice;\n\t\n\t\tgoto _string;\n\tcase PTYPE_MESSAGE:\n\tcase PTYPE_BYTES:\n\t\twiretype = WT_LEND;\n\t\tgoto _bytes;\n\tdefault:\n\t\tbreak;\n\t}\n\n\treturn 0;\n_bytes:\n\tinput_slice = (struct pbc_slice *)input;\n_string:\n\tlen = _pack_wiretype(pf->id << 3 | WT_LEND , s);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tret += len;\n\tlen = _pack_wiretype(input_slice->len , s);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tret += len;\n\tif (input_slice->len > s->len)\n\t\treturn -1;\n\tmemcpy(s->buffer , input_slice->buffer, input_slice->len);\n\tret += input_slice->len;\n\ts->buffer = (char *)s->buffer + input_slice->len;\n\ts->len -= input_slice->len;\n\n\treturn ret;\n_number:\n\tlen = _pack_wiretype(pf->id << 3 | wiretype , s);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tret += len;\n\tlen = _pack_number(pf->ptype, ctype , s, input);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tret += len;\n\n\treturn ret;\n}\n\nstatic int \n_pack_repeated(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) {\n\tint n = pbc_array_size(array);\n\tint ret = 0;\n\tif (n>0) {\n\t\tint i;\n\t\tfor (i=0;i<n;i++) {\n\t\t\tint len = _pack_field(pf , CTYPE_VAR , s , _pbcA_index_p(array , i));\n\t\t\tif (len < 0)\n\t\t\t\treturn len;\n\t\t\tret += len;\n\t\t}\n\t}\n\treturn ret;\n}\n\nstatic int\n_pack_packed_fixed(struct _pattern_field *pf , int width, struct pbc_slice *s, pbc_array array) {\n\tint len;\n\tint n = pbc_array_size(array);\n\tlen = _pack_wiretype(n * width , s);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tif (s->len - len <  n * width)\n\t\treturn -1;\n\tint i;\n\tfor (i=0;i<n;i++) {\n\t\t_pack_number(pf->ptype, CTYPE_VAR , s, _pbcA_index_p(array, i));\n\t}\n\n\treturn len + n * width;\n}\n\nstatic int\n_pack_packed_varint(struct _pattern_field *pf , struct pbc_slice *slice, pbc_array array) {\n\tstruct pbc_slice s = * slice;\n\tint n = pbc_array_size(array);\n\tint estimate = n; \n\tint estimate_len = _pack_wiretype(estimate , &s);\n\tif (estimate_len < 0) {\n\t\treturn -1;\n\t}\n\tint i;\n\tint packed_len = 0;\n\tfor (i=0;i<n;i++) {\n\t\tint len\t= _pack_number(pf->ptype, CTYPE_VAR , &s, _pbcA_index_p(array, i));\n\t\tif (len < 0)\n\t\t\treturn -1;\n\t\tpacked_len += len;\n\t}\n\tif (packed_len == estimate) {\n\t\t*slice = s;\n\t\treturn packed_len + estimate_len;\n\t}\n\tuint8_t temp[10];\n\tstruct pbc_slice header_slice = { temp , 10 };\n\tint header_len = _pack_wiretype(packed_len , &header_slice);\n\tif (header_len == estimate_len) {\n\t\tmemcpy(slice->buffer , temp , header_len);\n\t\t*slice = s;\n\t\treturn packed_len + estimate_len;\n\t}\n\tif (header_len + packed_len > slice->len)\n\t\treturn -1;\n\tmemmove((char *)slice->buffer + header_len , (char *)slice->buffer + estimate_len, packed_len);\n\tmemcpy(slice->buffer , temp , header_len);\n\tslice->buffer = (char *)slice->buffer + packed_len + header_len;\n\tslice->len -= packed_len + header_len;\n\treturn packed_len + header_len;\n}\n\nstatic int \n_pack_packed(struct _pattern_field *pf , struct pbc_slice *s, pbc_array array) {\n\tint n = pbc_array_size(array);\n\tif (n == 0)\n\t\treturn 0;\n\n\tint ret = 0;\n\tint len;\n\tlen = _pack_wiretype(pf->id << 3 | WT_LEND , s);\n\tif (len < 0) {\n\t\treturn len;\n\t}\n\tret += len;\n\n\tswitch (pf->ptype) {\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\tcase PTYPE_DOUBLE:\n\t\tlen = _pack_packed_fixed(pf, 8, s , array);\n\t\tif (len < 0)\n\t\t\treturn len;\n\t\tbreak;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\tcase PTYPE_FLOAT:\n\t\tlen = _pack_packed_fixed(pf, 4, s , array);\n\t\tif (len < 0)\n\t\t\treturn len;\n\t\tbreak;\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_BOOL:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\n\tcase PTYPE_SINT32:\n\tcase PTYPE_SINT64:\n\t\tlen = _pack_packed_varint(pf, s, array);\n\t\tif (len < 0)\n\t\t\treturn len;\n\t\tbreak;\n\t}\n\tret += len;\n\n\treturn ret;\n}\n\nstatic bool\n_is_default(struct _pattern_field * pf, void * in) {\n\tswitch (pf->ctype) {\n\tcase CTYPE_INT64: {\n\t\tstruct longlong * d64 = &pf->defv->integer;\n\t\treturn ((uint64_t)d64->low | (uint64_t)d64->hi << 32) == *(uint64_t *)in;\n\t}\n\tcase CTYPE_DOUBLE: \n\t\treturn pf->defv->real == *(double *)in;\n\tcase CTYPE_FLOAT:\n\t\treturn (float)(pf->defv->real) == *(float *)in;\n\tcase CTYPE_INT32:\n\t\treturn pf->defv->integer.low == *(uint32_t *)in;\n\tcase CTYPE_INT16:\n\t\treturn (uint16_t)(pf->defv->integer.low) == *(uint16_t *)in;\n\tcase CTYPE_INT8:\n\t\treturn (uint8_t)(pf->defv->integer.low) == *(uint8_t *)in;\n\tcase CTYPE_BOOL:\n\t\tif (pf->defv->integer.low)\n\t\t\treturn *(bool *)in == true;\n\t\telse\n\t\t\treturn *(bool *)in == false;\n\t}\n\tif (pf->ptype == PTYPE_STRING) {\n\t\tstruct pbc_slice *slice = (struct pbc_slice *)in;\n\t\tif (slice->buffer == NULL) {\n\t\t\treturn pf->defv->s.str[0] == '\\0';\n\t\t}\n\t\tint len = slice->len;\n\t\tif (len <= 0) {\n\t\t\treturn strcmp(pf->defv->s.str, (const char *)slice->buffer) == 0;\n\t\t}\n\t\treturn len == pf->defv->s.len && memcmp(pf->defv->s.str, slice->buffer, len)==0;\n\t} else if (pf->ptype == PTYPE_BYTES) {\n\t\tstruct pbc_slice *slice = (struct pbc_slice *)in;\n\t\tif (slice->buffer == NULL)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nint \npbc_pattern_pack(struct pbc_pattern *pat, void *input, struct pbc_slice * s)\n{\n\tstruct pbc_slice slice = *s;\n\tint i;\n\tfor (i=0;i<pat->count;i++) {\n\t\tstruct _pattern_field * pf = &pat->f[i];\n\t\tvoid * in = (char *)input + pf->offset;\n\t\tint len = 0;\n\t\tswitch(pf->label) {\n\t\tcase LABEL_OPTIONAL:\n\t\t\tif (_is_default(pf , in)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase LABEL_REQUIRED:\n\t\t\tlen = _pack_field(pf, pf->ctype, &slice, in);\n\t\t\tbreak;\n\t\tcase LABEL_REPEATED:\n\t\t\tlen = _pack_repeated(pf, &slice , (struct _pbc_array *)in);\n\t\t\tbreak;\n\t\tcase LABEL_PACKED:\n\t\t\tlen = _pack_packed(pf, &slice , (struct _pbc_array *)in);\n\t\t\tbreak;\n\t\t}\n\t\tif (len < 0) {\n\t\t\treturn len;\n\t\t}\n\t}\n\tint len = (char *)slice.buffer - (char *)s->buffer;\n\tint ret = s->len - len;\n\ts->len = len;\n\treturn ret;\n}\n\nint \npbc_pattern_unpack(struct pbc_pattern *pat, struct pbc_slice *s, void * output) {\n\tif (s->len == 0) {\n\t\tpbc_pattern_set_default(pat, output);\n\t\treturn 0;\n\t}\n\tpbc_ctx _ctx;\n\tint r = _pbcC_open(_ctx, s->buffer, s->len);\n\tif (r <= 0) {\n\t\tpat->env->lasterror = \"Pattern unpack open context error\";\n\t\t_pbcC_close(_ctx);\n\t\treturn r-1;\n\t}\n\n\tstruct context * ctx = (struct context *)_ctx;\n\tbool * field = (bool *)alloca(pat->count * sizeof(bool));\n\tmemset(field, 0, pat->count * sizeof(bool));\n\n\tint i;\n\tint fc = 0;\n\n\tfor (i=0;i<ctx->number;i++) {\n\t\tstruct _pattern_field * f = bsearch_pattern(pat, ctx->a[i].wire_id >> 3);\n\t\tif (f) {\n\t\t\tint index = f - pat->f;\n\t\t\tif (field[index] == false) {\n\t\t\t\tfield[index] = true;\n\t\t\t\t++fc;\n\t\t\t\tif ((f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED)) {\n\t\t\t\t\tstruct _pbc_array *array = (struct _pbc_array *)((char *)output + f->offset);\n\t\t\t\t\t_pbcA_open(array);\n\t\t\t\t}\n\t\t\t}\n\t\t\tchar * out = (char *)output + f->offset;\n\t\t\tif (unpack_field(f->ctype , f->ptype , ctx->buffer , &ctx->a[i], out) < 0) {\n\t\t\t\tint j;\n\t\t\t\tfor (j=0;j<pat->count;j++) {\n\t\t\t\t\tif (field[j] == true && (pat->f[j].ctype == CTYPE_ARRAY || pat->f[j].ctype == CTYPE_PACKED)) {\n\t\t\t\t\t\tvoid *array = (char *)output + pat->f[j].offset;\n\t\t\t\t\t\t_pbcA_close((struct _pbc_array *)array);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t_pbcC_close(_ctx);\n\t\t\t\tpat->env->lasterror = \"Pattern unpack field error\";\n\t\t\t\treturn -i-1;\n\t\t\t}\n\t\t}\n\t}\n\t_pbcC_close(_ctx);\n\tif (fc != pat->count) {\n\t\tfor (i=0;i<pat->count;i++) {\n\t\t\tif (field[i] == false) {\n\t\t\t\t_pattern_set_default(&pat->f[i], (char *)output);\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n/* \n\tformat : key %type\n\t%f float\n\t%F double\n\t%d int32\n\t%D int64\n\t%b bool\n\t%h int16\n\t%c int8\n\t%s slice\n\t%a array\n*/\n\nstatic int\n_ctype(const char * ctype) {\n\tif (ctype[0]!='%')\n\t\treturn -1;\n\tswitch (ctype[1]) {\n\tcase 'f':\n\t\treturn CTYPE_FLOAT;\n\tcase 'F':\n\t\treturn CTYPE_DOUBLE;\n\tcase 'd':\n\t\treturn CTYPE_INT32;\n\tcase 'D':\n\t\treturn CTYPE_INT64;\n\tcase 'b':\n\t\treturn CTYPE_BOOL;\n\tcase 'h':\n\t\treturn CTYPE_INT16;\n\tcase 'c':\n\t\treturn CTYPE_INT8;\n\tcase 's':\n\t\treturn CTYPE_VAR;\n\tcase 'a':\n\t\treturn CTYPE_ARRAY;\n\tdefault:\n\t\treturn -1;\n\t}\n}\n\nstatic int\n_ctype_size(const char *ctype) {\n\tswitch (ctype[1]) {\n\tcase 'f':\n\t\treturn sizeof(float);\n\tcase 'F':\n\t\treturn sizeof(double);\n\tcase 'd':\n\t\treturn sizeof(int32_t);\n\tcase 'D':\n\t\treturn sizeof(int64_t);\n\tcase 'b':\n\t\treturn sizeof(bool);\n\tcase 'h':\n\t\treturn sizeof(int16_t);\n\tcase 'c':\n\t\treturn sizeof(int8_t);\n\tcase 's':\n\t\treturn sizeof(struct pbc_slice);\n\tcase 'a':\n\t\treturn sizeof(pbc_array);\n\tdefault:\n\t\treturn 0;\n\t}\n}\n\nstatic const char *\n_copy_string(const char *format , char ** temp) {\n\tchar * output = *temp;\n\twhile (*format == ' ' || *format == '\\t' || *format == '\\n' || *format == '\\r') {\n\t\t++format;\n\t}\n\twhile (*format != '\\0' &&\n\t\t*format != ' ' &&\n\t\t*format != '\\t' &&\n\t\t*format != '\\n' &&\n\t\t*format != '\\r') {\n\t\t*output = *format;\n\t\t++output;\n\t\t++format;\n\t}\n\t*output = '\\0';\n\t++output;\n\t*temp = output;\n\n\treturn format;\n}\n\nstatic int\n_scan_pattern(const char * format , char * temp) {\n\tint n = 0;\n\tfor(;;) {\n\t\tformat = _copy_string(format , &temp);\n\t\tif (format[0] == '\\0')\n\t\t\treturn 0;\n\t\t++n;\n\t\tformat = _copy_string(format , &temp);\n\t\tif (format[0] == '\\0')\n\t\t\treturn n;\n\t} \n}\n\nstatic int \n_comp_field(const void * a, const void * b) {\n\tconst struct _pattern_field * fa = (const struct _pattern_field *)a;\n\tconst struct _pattern_field * fb = (const struct _pattern_field *)b;\n\n\treturn fa->id - fb->id;\n}\n\nstruct pbc_pattern *\n_pbcP_new(struct pbc_env * env, int n) {\n\tsize_t sz = sizeof(struct pbc_pattern) + (sizeof(struct _pattern_field)) * (n-1);\n\tstruct pbc_pattern * ret = (struct pbc_pattern *)pbc_malloc(sz);\n\tmemset(ret, 0 , sz);\n\tret->count = n;\n\tret->env = env;\n\treturn ret;\n}\n\nstatic int\n_check_ctype(struct _field * field, struct _pattern_field *f) {\n\tif (field->label == LABEL_REPEATED) {\n\t\treturn f->ctype != CTYPE_ARRAY;\n\t} \n\tif (field->label == LABEL_PACKED) {\n\t\treturn f->ctype != CTYPE_PACKED;\n\t}\n\tif (field->type == PTYPE_STRING || field->type == PTYPE_MESSAGE || field->type == PTYPE_BYTES) {\n\t\treturn f->ctype != CTYPE_VAR;\n\t}\n\tif (field->type == PTYPE_FLOAT || field->type == PTYPE_DOUBLE) {\n\t\treturn !(f->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT);\n\t}\n\tif (field->type == PTYPE_ENUM) {\n\t\treturn !(f->ctype == CTYPE_INT8 || \n\t\t\tf->ctype == CTYPE_INT8 || \n\t\t\tf->ctype == CTYPE_INT16 ||\n\t\t\tf->ctype == CTYPE_INT32 ||\n\t\t\tf->ctype == CTYPE_INT64);\n\t}\n\n\treturn f->ctype == CTYPE_VAR || f->ctype == CTYPE_ARRAY || f->ctype == CTYPE_PACKED ||\n\t\tf->ctype == CTYPE_DOUBLE || f->ctype == CTYPE_FLOAT;\n}\n\nstruct pbc_pattern *\n_pattern_new(struct _message *m, const char *format) {\n\tint len = strlen(format);\n\tchar * temp = (char *)alloca(len+1);\n\tint n = _scan_pattern(format, temp);\n\tstruct pbc_pattern * pat = _pbcP_new(m->env, n);\n\tint i;\n\n\tconst char *ptr = temp;\n\n\tint offset = 0;\n\n\tfor (i=0;i<n;i++) {\n\t\tstruct _pattern_field * f = &(pat->f[i]);\n\t\tstruct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr);\n\t\tif (field == NULL) {\n\t\t\tm->env->lasterror = \"Pattern @new query none exist field\";\n\t\t\tgoto _error;\n\t\t}\n\t\tf->id = field->id;\n\t\tf->ptype = field->type;\n\t\t*f->defv = *field->default_v;\n\t\tf->offset = offset;\n\t\tf->label = field->label;\n\t\tptr += strlen(ptr) + 1;\n\t\tf->ctype = _ctype(ptr);\n\t\tif (f->ctype < 0) {\n\t\t\tm->env->lasterror = \"Pattern @new use an invalid ctype\";\n\t\t\tgoto _error;\n\t\t}\n\t\t\n\t\tif (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) {\n\t\t\tf->ctype = CTYPE_PACKED;\n\t\t}\n\t\tif (_check_ctype(field, f)) {\n\t\t\tm->env->lasterror = \"Pattern @new ctype check error\";\n\t\t\tgoto _error;\n\t\t}\n\n\t\toffset += _ctype_size(ptr);\n\t\tptr += strlen(ptr) + 1;\n\t}\n\n\tpat->count = n;\n\n\tqsort(pat->f , n , sizeof(struct _pattern_field), _comp_field);\n\treturn pat;\n_error:\n\tpbc_free(pat);\n\treturn NULL;\n}\n\nstruct pbc_pattern * \npbc_pattern_new(struct pbc_env * env , const char * message, const char * format, ... ) {\n\tstruct _message *m = _pbcP_get_message(env, message);\n\tif (m==NULL) {\n\t\tenv->lasterror = \"Pattern new can't find proto\";\n\t\treturn NULL;\n\t}\n\tif (format[0]=='@') {\n\t\treturn _pattern_new(m , format+1);\n\t}\n\n\tint len = strlen(format);\n\tchar * temp = (char *)alloca(len+1);\n\tint n = _scan_pattern(format, temp);\n\tstruct pbc_pattern * pat = _pbcP_new(env, n);\n\tint i;\n\tva_list ap;\n\tva_start(ap , format);\n\n\tconst char *ptr = temp;\n\n\tfor (i=0;i<n;i++) {\n\t\tstruct _pattern_field * f = &(pat->f[i]);\n\t\tstruct _field * field = (struct _field *)_pbcM_sp_query(m->name, ptr);\n\t\tif (field == NULL) {\n\t\t\tenv->lasterror = \"Pattern new query none exist field\";\n\t\t\tgoto _error;\n\t\t}\n\t\tf->id = field->id;\n\t\tf->ptype = field->type;\n\t\t*f->defv = *field->default_v;\n\t\tf->offset = va_arg(ap, int);\n\t\tf->label = field->label;\n\n\t\tptr += strlen(ptr) + 1;\n\n\t\tf->ctype = _ctype(ptr);\n\t\tif (f->ctype < 0) {\n\t\t\tenv->lasterror = \"Pattern new use an invalid ctype\";\n\t\t\tgoto _error;\n\t\t}\n\t\tif (f->ctype == CTYPE_ARRAY && field->label == LABEL_PACKED) {\n\t\t\tf->ctype = CTYPE_PACKED;\n\t\t}\n\t\tif (_check_ctype(field, f)) {\n\t\t\tenv->lasterror = \"Pattern new ctype check error\";\n\t\t\tgoto _error;\n\t\t}\n\n\t\tptr += strlen(ptr) + 1;\n\t}\n\n\tva_end(ap);\n\n\tpat->count = n;\n\n\tqsort(pat->f , n , sizeof(struct _pattern_field), _comp_field);\n\treturn pat;\n_error:\n\tpbc_free(pat);\n\treturn NULL;\n}\n\nvoid \npbc_pattern_delete(struct pbc_pattern * pat) {\n\tpbc_free(pat);\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/pattern.h",
    "content": "#ifndef PROTOBUF_C_PATTERN_H\n#define PROTOBUF_C_PATTERN_H\n\n#include \"pbc.h\"\n#include \"context.h\"\n#include \"array.h\"\n\nstruct _pattern_field {\n\tint id;\n\tint offset;\n\tint ptype;\n\tint ctype;\n\tint label;\n\tpbc_var defv;\n};\n\nstruct pbc_pattern {\n\tstruct pbc_env * env;\n\tint count;\n\tstruct _pattern_field f[1];\n};\n\nstruct pbc_pattern * _pbcP_new(struct pbc_env * env, int n);\nint _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/pbc-lua53.cpp",
    "content": "#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include \"lua.h\"\n#include \"lualib.h\"\n#include \"lauxlib.h\"\n#ifdef __cplusplus\n}\n#endif\n\n#if defined(__APPLE__)\n#include <malloc/malloc.h>\n#else\n#include <malloc.h>\n#endif\n\n#ifndef _MSC_VER\n#include <stdbool.h>\n#else\n#define alloca _alloca\n#endif\n\n#include <string.h>\n#include <stdlib.h>\n#include <stdint.h>\n\n#include \"pbc.h\"\n\nstatic inline void *\ncheckuserdata(lua_State *L, int index) {\n\tvoid * ud = lua_touserdata(L,index);\n\tif (ud == NULL) {\n\t\tluaL_error(L, \"userdata %d is nil\",index);\n\t}\n\treturn ud;\n}\n\nstatic int\n_env_new(lua_State *L) {\n\tstruct pbc_env * env = pbc_new();\n\tlua_pushlightuserdata(L, env);\n\treturn 1;\n}\n\nstatic int\n_env_register(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tsize_t sz = 0;\n\tconst char * buffer = luaL_checklstring(L, 2 , &sz);\n\tstruct pbc_slice slice;\n\tslice.buffer = (void *)buffer;\n\tslice.len = (int)sz;\n\tint ret = pbc_register(env, &slice);\n\n\tif (ret) {\n\t\treturn luaL_error(L, \"register fail\");\n\t}\n\treturn 0;\n}\n\nstatic int\n_env_enum_id(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tsize_t sz = 0;\n\tconst char* enum_type = luaL_checklstring(L, 2, &sz);\n\tconst char* enum_name = luaL_checklstring(L, 3, &sz);\n\tint32_t enum_id = pbc_enum_id(env, enum_type, enum_name);\n\tif (enum_id < 0)\n\t\treturn 0;\n\tlua_pushinteger(L, enum_id);\n\treturn 1;\n}\n\nstatic int\n_rmessage_new(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tconst char * type_name = luaL_checkstring(L,2);\n\tstruct pbc_slice slice;\n\tif (lua_isstring(L,3)) {\n\t\tsize_t sz = 0;\n\t\tslice.buffer = (void *)lua_tolstring(L,3,&sz);\n\t\tslice.len = (int)sz;\n\t} else {\n\t\tslice.buffer = lua_touserdata(L,3);\n\t\tslice.len = luaL_checkinteger(L,4);\n\t}\n\tstruct pbc_rmessage * m = pbc_rmessage_new(env, type_name, &slice);\n\tif (m==NULL)\n\t\treturn 0;\n\tlua_pushlightuserdata(L,m);\n\treturn 1;\n}\n\nstatic int\n_rmessage_delete(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tpbc_rmessage_delete(m);\n\n\treturn 0;\n}\n\nstatic int\n_rmessage_int(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tint index = luaL_checkinteger(L,3);\n\tuint32_t hi,low;\n\tlow = pbc_rmessage_integer(m, key, index, &hi);\n\tint64_t v = (int64_t)((uint64_t)hi << 32 | (uint64_t)low);\n\tlua_pushinteger(L,v);\n\n\treturn 1;\n}\n\nstatic int \n_rmessage_real(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tint index = luaL_checkinteger(L,3);\n\tdouble v = pbc_rmessage_real(m, key, index);\n\n\tlua_pushnumber(L,v);\n\n\treturn 1;\n}\n\nstatic int\n_rmessage_string(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tint index = lua_tointeger(L,3);\n\tint sz = 0;\n\tconst char * v = pbc_rmessage_string(m,key,index,&sz);\n\tlua_pushlstring(L,v,sz);\n\treturn 1;\n}\n\nstatic int\n_rmessage_message(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tint index = lua_tointeger(L,3);\n\tstruct pbc_rmessage * v = pbc_rmessage_message(m,key,index);\n\tlua_pushlightuserdata(L,v);\n\treturn 1;\n}\n\nstatic int\n_rmessage_size(lua_State *L) {\n\tstruct pbc_rmessage * m = (struct pbc_rmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\n\tint sz = pbc_rmessage_size(m, key);\n\n\tlua_pushinteger(L, sz);\n\n\treturn 1;\n}\n\nstatic int\n_env_type(lua_State *L) {\n\tlua_settop(L,3);\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tconst char * type_name = luaL_checkstring(L,2);\n\tif (lua_isnil(L,3)) {\n\t\tint ret = pbc_type(env, type_name, NULL, NULL);\n\t\tlua_pushboolean(L,ret);\n\t\treturn 1;\n\t}\n\tconst char * key = luaL_checkstring(L,3);\n\tconst char * type = NULL;\n\tint ret = pbc_type(env, type_name, key, &type);\n\tlua_pushinteger(L,ret);\n\tif (type == NULL) {\n\t\treturn 1;\n\t} {\n\t\tlua_pushstring(L, type);\n\t\treturn 2;\n\t}\n}\n\nstatic int\n_wmessage_new(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tconst char * type_name = luaL_checkstring(L,2);\n\tstruct pbc_wmessage * ret = pbc_wmessage_new(env, type_name);\n\tlua_pushlightuserdata(L,ret);\n\treturn 1;\n}\n\nstatic int\n_wmessage_delete(lua_State *L) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)lua_touserdata(L,1);\n\tpbc_wmessage_delete(m);\n\n\treturn 0;\n}\n\n\nstatic int\n_wmessage_real(lua_State *L) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tdouble number = luaL_checknumber(L,3);\n\tpbc_wmessage_real(m, key, number);\n\n\treturn 0;\n}\n\nstatic int\n_wmessage_string(lua_State *L) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tsize_t len = 0;\n\tconst char * v = luaL_checklstring(L,3,&len);\n\tint err = pbc_wmessage_string(m, key, v, (int)len);\n\tif (err) {\n\t\treturn luaL_error(L, \"Write string error : %s\", v);\n\t}\n\n\treturn 0;\n}\n\nstatic int\n_wmessage_message(lua_State *L) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tstruct pbc_wmessage * ret = pbc_wmessage_message(m, key);\n\tlua_pushlightuserdata(L, ret);\n\n\treturn 1;\n}\n\nstatic int\n_wmessage_int(lua_State *L) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tconst char * key = luaL_checkstring(L,2);\n\tint64_t number;\n\t// compat float for some historical reasons.\n\tif (lua_isinteger(L, 3)) {\n\t\tnumber = lua_tointeger(L,3);\n\t} else {\n\t\tnumber = (int64_t)lua_tonumber(L,3);\n\t}\n\tuint32_t hi = (uint32_t)(number >> 32);\n\tpbc_wmessage_integer(m, key, (uint32_t)number, hi);\n\n\treturn 0;\n}\n\nstatic int\n_wmessage_buffer(lua_State *L) {\n\tstruct pbc_slice slice;\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tpbc_wmessage_buffer(m , &slice);\n\tlua_pushlightuserdata(L, slice.buffer);\n\tlua_pushinteger(L, slice.len);\n\treturn 2;\n}\n\nstatic int\n_wmessage_buffer_string(lua_State *L) {\n\tstruct pbc_slice slice;\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)checkuserdata(L,1);\n\tpbc_wmessage_buffer(m , &slice);\n\tlua_pushlstring(L, (const char *)slice.buffer, slice.len);\n\treturn 1;\n}\n\n/*\n\tlightuserdata env\n */\nstatic int\n_last_error(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1);\n\tconst char * err = pbc_error(env);\n\tlua_pushstring(L,err);\n\treturn 1;\n}\n\n/*\n\tlightuserdata env\n\tstring message\n\tstring format\n */\nstatic int\n_pattern_new(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L, 1);\n\tconst char * message = luaL_checkstring(L,2);\n\tconst char * format = luaL_checkstring(L,3);\n\tstruct pbc_pattern * pat = pbc_pattern_new(env, message, format);\n\tif (pat == NULL) {\n\t\treturn luaL_error(L, \"create patten %s (%s) failed\", message , format);\n\t}\n\tlua_pushlightuserdata(L,pat);\n\n\treturn 1;\n}\n\nstatic int\n_pattern_delete(lua_State *L) {\n\tstruct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,1);\n\tpbc_pattern_delete(pat);\n\t\n\treturn 0;\n}\n\nstatic void *\n_push_value(lua_State *L, char * ptr, char type) {\n\tswitch(type) {\n\t\tcase 'd': {\n\t\t\tuint64_t v = *(uint64_t*)ptr;\n\t\t\tptr += 8;\n\t\t\tlua_pushinteger(L, v);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'i': {\n\t\t\tint32_t v = *(int32_t*)ptr;\n\t\t\tptr += 4;\n\t\t\tlua_pushinteger(L,v);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'b': {\n\t\t\tint32_t v = *(int32_t*)ptr;\n\t\t\tptr += 4;\n\t\t\tlua_pushboolean(L,v);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'r': {\n\t\t\tdouble v = *(double *)ptr;\n\t\t\tptr += 8;\n\t\t\tlua_pushnumber(L,v);\n\t\t\tbreak;\n\t\t}\n\t\tcase 's': {\n\t\t\tstruct pbc_slice * slice = (struct pbc_slice *)ptr;\n\t\t\tlua_pushlstring(L,(const char *)slice->buffer, slice->len);\n\t\t\tptr += sizeof(struct pbc_slice);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'm': {\n\t\t\tstruct pbc_slice * slice = (struct pbc_slice *)ptr;\n\t\t\tlua_createtable(L,2,0);\n\t\t\tlua_pushlightuserdata(L, slice->buffer);\n\t\t\tlua_rawseti(L,-2,1);\n\t\t\tlua_pushinteger(L,slice->len);\n\t\t\tlua_rawseti(L,-2,2);\n\t\t\tptr += sizeof(struct pbc_slice);\n\t\t\tbreak;\t\t\t\n\t\t}\n\t}\n\treturn ptr;\n}\n\nstatic void\n_push_array(lua_State *L, pbc_array array, char type, int index) {\n\tswitch (type) {\n\tcase 'I': {\n\t\tint v = pbc_array_integer(array, index, NULL);\n\t\tlua_pushinteger(L, v);\n\t\tbreak;\n\t}\n\tcase 'D': {\n\t\tuint32_t hi = 0;\n\t\tuint32_t low = pbc_array_integer(array, index, &hi);\n\t\tuint64_t v = (uint64_t)hi << 32 | (uint64_t)low;\n\t\tlua_pushinteger(L, v);\n\t\tbreak;\n\t}\n\tcase 'B': {\n\t\tint v = pbc_array_integer(array, index, NULL);\n\t\tlua_pushboolean(L, v);\n\t\tbreak;\n\t}\n\tcase 'X': {\n\t\tuint32_t hi = 0;\n\t\tuint32_t low = pbc_array_integer(array, index, &hi);\n\t\tuint64_t v = (uint64_t)low | (uint64_t)hi << 32;\n\t\tlua_pushlstring(L, (char *)&v, 8);\n\t\tbreak;\n\t}\n\tcase 'R': {\n\t\tdouble v = pbc_array_real(array, index);\n\t\tlua_pushnumber(L, v);\n\t\tbreak;\n\t}\n\tcase 'S': {\n\t\tstruct pbc_slice * slice = pbc_array_slice(array, index);\n\t\tlua_pushlstring(L, (const char *)slice->buffer,slice->len);\n\t\tbreak;\n\t}\n\tcase 'M': {\n\t\tstruct pbc_slice * slice = pbc_array_slice(array, index);\n\t\tlua_createtable(L,2,0);\n\t\tlua_pushlightuserdata(L,slice->buffer);\n\t\tlua_rawseti(L,-2,1);\n\t\tlua_pushinteger(L,slice->len);\n\t\tlua_rawseti(L,-2,2);\n\t\tbreak;\n\t}\n\t}\n\tlua_rawseti(L,-2,index+1);\n}\n\n/*\n\tlightuserdata pattern\n\tstring format \"ixrsmb\"\n\tinteger size\n\tlightuserdata buffer\n\tinteger buffer_len\n */\nstatic int\n_pattern_unpack(lua_State *L) {\n\tstruct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L, 1);\n\tif (pat == NULL) {\n\t\treturn luaL_error(L, \"unpack pattern is NULL\");\n\t}\n\tsize_t format_sz = 0;\n\tconst char * format = lua_tolstring(L,2,&format_sz);\n\tint size = lua_tointeger(L,3);\n\tstruct pbc_slice slice;\n\tif (lua_isstring(L,4)) {\n\t\tsize_t buffer_len = 0;\n\t\tconst char *buffer = luaL_checklstring(L,4,&buffer_len);\n\t\tslice.buffer = (void *)buffer;\n\t\tslice.len = buffer_len;\n\t} else {\n\t\tif (!lua_isuserdata(L,4)) {\n\t\t\treturn luaL_error(L, \"Need a userdata\");\n\t\t}\n\t\tslice.buffer = lua_touserdata(L,4);\n\t\tslice.len = luaL_checkinteger(L,5);\n\t}\n\t\n\tchar * temp = (char *)alloca(size);\n\tint ret = pbc_pattern_unpack(pat, &slice, temp);\n\tif (ret < 0) {\n\t\treturn 0;\n\t}\n\tlua_checkstack(L, format_sz + 3);\n\tint i;\n\tchar * ptr = temp;\n\tbool array = false;\n\tfor (i=0;i<format_sz;i++) {\n\t\tchar type = format[i];\n\t\tif (type >= 'a' && type <='z') {\n\t\t\tptr = (char *)_push_value(L,ptr,type);\n\t\t} else {\n\t\t\tarray = true;\n\t\t\tint n = pbc_array_size((struct _pbc_array *)ptr);\n\t\t\tlua_createtable(L,n,0);\n\t\t\tint j;\n\t\t\tfor (j=0;j<n;j++) {\n\t\t\t\t_push_array(L,(struct _pbc_array *)ptr, type, j);\n\t\t\t}\n\t\t\tptr += sizeof(pbc_array);\n\t\t}\n\t}\n\tif (array) {\n\t\tpbc_pattern_close_arrays(pat, temp);\n\t}\n\treturn format_sz;\n}\n\nstatic char *\n_get_value(lua_State *L, int index, char * ptr, char type) {\n\tswitch(type) {\n\t\tcase 'i': {\n\t\t\tint32_t v = luaL_checkinteger(L, index);\n\t\t\tmemcpy(ptr, &v, 4);\n\t\t\treturn ptr + 4;\n\t\t}\n\t\tcase 'd': {\n\t\t\tint64_t v = (int64_t)luaL_checkinteger(L, index);\n\t\t\tmemcpy(ptr, &v, 8);\n\t\t\treturn ptr + 8;\n\t\t}\n\t\tcase 'b': {\n\t\t\tint32_t v = lua_toboolean(L, index);\n\t\t\tmemcpy(ptr, &v, 4);\n\t\t\treturn ptr + 4;\n\t\t}\n\t\tcase 'r': {\n\t\t\tdouble v = luaL_checknumber(L, index);\n\t\t\tmemcpy(ptr, &v, 8);\n\t\t\treturn ptr + 8;\n\t\t}\n\t\tcase 's': {\n\t\t\tsize_t sz = 0;\n\t\t\tconst char * str = luaL_checklstring(L, index, &sz);\n\t\t\tstruct pbc_slice * slice = (struct pbc_slice *)ptr;\n\t\t\tslice->buffer = (void*)str;\n\t\t\tslice->len = sz;\n\t\t\treturn ptr + sizeof(struct pbc_slice);\n\t\t}\n\t\tcase 'm': {\n\t\t\tstruct pbc_slice * slice = (struct pbc_slice *)ptr;\n\t\t\tif (lua_istable(L,index)) {\n\t\t\t\tlua_rawgeti(L,index,1);\n\t\t\t\tslice->buffer = lua_touserdata(L,-1);\n\t\t\t\tlua_rawgeti(L,index,2);\n\t\t\t\tslice->len = lua_tointeger(L,-1);\n\t\t\t\tlua_pop(L,2);\n\t\t\t} else {\n\t\t\t\tsize_t sz = 0;\n\t\t\t\tconst char * buffer = luaL_checklstring(L, index, &sz);\n\t\t\t\tslice->buffer = (void *)buffer;\n\t\t\t\tslice->len = sz;\n\t\t\t}\n\t\t\treturn ptr + sizeof(struct pbc_slice);\n\t\t}\n\t\tdefault:\n\t\t\tluaL_error(L,\"unknown format %c\", type);\n\t\t\treturn ptr;\n\t}\n}\n\nstatic void\n_get_array_value(lua_State *L, pbc_array array, char type) {\n\tswitch(type) {\n\t\tcase 'I': {\n\t\t\tint32_t v = luaL_checkinteger(L, -1);\n\t\t\tuint32_t hi = 0;\n\t\t\tif (v<0) {\n\t\t\t\thi = ~0;\n\t\t\t}\n\t\t\tpbc_array_push_integer(array, v, hi);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'D' : {\n\t\t\tuint64_t v = (uint64_t)luaL_checknumber(L, -1);\n\t\t\tpbc_array_push_integer(array, (uint32_t)v, (uint32_t)(v >> 32));\n\t\t\tbreak;\n\t\t}\n\t\tcase 'B': {\n\t\t\tint32_t v = lua_toboolean(L, -1);\n\t\t\tpbc_array_push_integer(array, v ? 1: 0, 0);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'R': {\n\t\t\tdouble v = luaL_checknumber(L, -1);\n\t\t\tpbc_array_push_real(array, v);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'S': {\n\t\t\tsize_t sz = 0;\n\t\t\tconst char * str = luaL_checklstring(L, -1, &sz);\n\t\t\tstruct pbc_slice slice;\n\t\t\tslice.buffer = (void*)str;\n\t\t\tslice.len = sz;\n\t\t\tpbc_array_push_slice(array, &slice);\n\t\t\tbreak;\n\t\t}\n\t\tcase 'M': {\n\t\t\tstruct pbc_slice slice;\n\t\t\tif (lua_istable(L,-1)) {\n\t\t\t\tlua_rawgeti(L,-1,1);\n\t\t\t\tslice.buffer = lua_touserdata(L,-1);\n\t\t\t\tlua_rawgeti(L,-2,2);\n\t\t\t\tslice.len = lua_tointeger(L,-1);\n\t\t\t\tlua_pop(L,2);\n\t\t\t} else {\n\t\t\t\tsize_t sz = 0;\n\t\t\t\tconst char * buffer = luaL_checklstring(L, -1, &sz);\n\t\t\t\tslice.buffer = (void *)buffer;\n\t\t\t\tslice.len = sz;\n\t\t\t}\n\t\t\tpbc_array_push_slice(array, &slice);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n\tlightuserdata pattern\n\tstring format \"ixrsmbp\"\n\tinteger size\n */\nstatic int\n_pattern_pack(lua_State *L) {\n\tstruct pbc_pattern * pat = (struct pbc_pattern *)checkuserdata(L,1);\n\tif (pat == NULL) {\n\t\treturn luaL_error(L, \"pack pattern is NULL\");\n\t}\n\tsize_t format_sz = 0;\n\tconst char * format = lua_tolstring(L,2,&format_sz);\n\tint size = lua_tointeger(L,3);\n\n\tchar * data = (char *)alloca(size);\n//\tA trick , we don't need default value. zero buffer for array and message field.\n//\tpbc_pattern_set_default(pat, data);\n\tmemset(data, 0 , size);\n\n\tchar * ptr = data;\n\n\tint i;\n\n\tfor (i=0;i<format_sz;i++) {\n\t\tif (format[i] >= 'a' && format[i] <='z') {\n\t\t\tptr = _get_value(L, 4+i, ptr, format[i]);\n\t\t} else {\n\t\t\tif (!lua_istable(L,4+i)) {\n\t\t\t\tluaL_error(L,\"need table for array type\");\n\t\t\t}\n\t\t\tint j;\n\t\t\tint n = lua_rawlen(L,4+i);\n\t\t\tfor (j=0;j<n;j++) {\n\t\t\t\tlua_rawgeti(L,4+i,j+1);\n\t\t\t\t_get_array_value(L,(struct _pbc_array *)ptr,format[i]);\n\t\t\t\tlua_pop(L,1);\n\t\t\t}\n\t\t\tptr += sizeof(pbc_array);\n\t\t}\n\t}\n\n\tluaL_Buffer b;\n\tluaL_buffinit(L, &b);\n\n\tint cap = 128;\n\tfor (;;) {\n\t\tchar * temp = (char *)luaL_prepbuffsize(&b , cap);\n\n\t\tstruct pbc_slice slice;\n\t\tslice.buffer = temp;\n\t\tslice.len = cap;\n\n\t\tint ret = pbc_pattern_pack(pat, data, &slice);\n\n\t\tif (ret < 0) {\n\t\t\tcap = cap * 2;\n\t\t\tcontinue;\n\t\t}\n\n\t\tluaL_addsize(&b , slice.len);\n\t\tbreak;\n\t}\n\tluaL_pushresult(&b);\n\n\tpbc_pattern_close_arrays(pat, data);\n\treturn 1;\n}\n\nstatic int\n_pattern_size(lua_State *L) {\n\tsize_t sz =0;\n\tconst char *format = luaL_checklstring(L,1,&sz);\n\tint i;\n\tint size = 0;\n\tfor (i=0;i<sz;i++) {\n\t\tswitch(format[i]) {\n\t\tcase 'b': \n\t\tcase 'i':\n\t\t\tsize += 4;\n\t\t\tbreak;\n\t\tcase 'r':\n\t\tcase 'd':\n\t\t\tsize += 8;\n\t\t\tbreak;\n\t\tcase 's':\n\t\tcase 'm':\n\t\t\tsize += sizeof(struct pbc_slice);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tsize += sizeof(pbc_array);\n\t\t\tbreak;\n\t\t}\n\t}\n\tlua_pushinteger(L,size);\n\treturn 1;\n}\n\n/*\n\t-3 table key\n\t-2 table id\n\t-1 value\n */\nstatic void\nnew_array(lua_State *L, int id, const char *key) {\n\tlua_rawgeti(L, -2 , id);\n\tif (lua_isnil(L, -1)) {\n\t\tlua_pop(L,1);\n\t\tlua_newtable(L);  // table.key table.id value array\n\t\tlua_pushvalue(L,-1);\n\t\tlua_pushvalue(L,-1); // table.key table.id value array array array\n\t\tlua_setfield(L, -6 , key);\n\t\tlua_rawseti(L, -4, id);\n\t}\n}\n\nstatic void\npush_value(lua_State *L, int type, const char * type_name, union pbc_value *v) {\n\tswitch(type) {\n\tcase PBC_FIXED32:\n\tcase PBC_INT:\n\t\tlua_pushinteger(L, (int)v->i.low);\n\t\tbreak;\n\tcase PBC_REAL:\n\t\tlua_pushnumber(L, v->f);\n\t\tbreak;\n\tcase PBC_BOOL:\n\t\tlua_pushboolean(L, v->i.low);\n\t\tbreak;\n\tcase PBC_ENUM:\n\t\tlua_pushstring(L, v->e.name);\n\t\tbreak;\n\tcase PBC_BYTES:\n\tcase PBC_STRING:\n\t\tlua_pushlstring(L, (const char *)v->s.buffer , v->s.len);\n\t\tbreak;\n\tcase PBC_MESSAGE:\n\t\tlua_pushvalue(L, -3);\n\t\tlua_pushstring(L, type_name);\n\t\tlua_pushlstring(L, (const char *)v->s.buffer , v->s.len);\n\t\tlua_call(L, 2 , 1);\n\t\tbreak;\n\tcase PBC_FIXED64:\n\tcase PBC_UINT: \n\tcase PBC_INT64: {\n\t\tuint64_t v64 = (uint64_t)(v->i.hi) << 32 | (uint64_t)(v->i.low);\n\t\tlua_pushinteger(L,v64);\n\t\tbreak;\n\t}\n\tdefault:\n\t\tluaL_error(L, \"Unknown type %s\", type_name);\n\t\tbreak;\n\t}\n}\n\n/*\n\t-3: function decode\n\t-2: table key\n\t-1:\ttable id\n */\nstatic void\ndecode_cb(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key) {\n\tlua_State *L = (lua_State *)ud;\n\tif (key == NULL) {\n\t\t// undefined field\n\t\treturn;\n\t}\n\n\tif (type & PBC_REPEATED) {\n\t\tpush_value(L, type & ~PBC_REPEATED, type_name, v);\n\t\tnew_array(L, id , key);\t// func.decode table.key table.id value array\n\t\tint n = lua_rawlen(L,-1);\n\t\tlua_insert(L, -2);\t// func.decode table.key table.id array value\n\t\tlua_rawseti(L, -2 , n+1);\t// func.decode table.key table.id array\n\t\tlua_pop(L,1);\n\t} else {\n\t\tpush_value(L, type, type_name, v);\n\t\tlua_setfield(L, -3 , key);\n\t}\n}\n\n/*\n\t:1 lightuserdata env\n\t:2 function decode_message\n\t:3 table target\n\t:4 string type\n\t:5 string data\n\t:5 lightuserdata pointer\n\t:6 integer len\n\n\ttable\n */\nstatic int\n_decode(lua_State *L) {\n\tstruct pbc_env * env = (struct pbc_env *)checkuserdata(L,1);\n\tluaL_checktype(L, 2 , LUA_TFUNCTION);\n\tluaL_checktype(L, 3 , LUA_TTABLE);\n\tconst char * type = luaL_checkstring(L,4);\n\tstruct pbc_slice slice;\n\tif (lua_type(L,5) == LUA_TSTRING) {\n\t\tsize_t len;\n\t\tslice.buffer = (void *)luaL_checklstring(L,5,&len);\n\t\tslice.len = (int)len;\n\t} else {\n\t\tslice.buffer = checkuserdata(L,5);\n\t\tslice.len = luaL_checkinteger(L,6);\n\t}\n\tlua_pushvalue(L, 2);\n\tlua_pushvalue(L, 3);\n\tlua_newtable(L);\n\n\tint n = pbc_decode(env, type, &slice, decode_cb, L);\n\tif (n<0) {\n\t\tlua_pushboolean(L,0);\n\t} else {\n\t\tlua_pushboolean(L,1);\n\t}\n\treturn 1;\n}\n\nstruct gcobj {\n\tstruct pbc_env * env;\n\tint size_pat;\n\tint cap_pat;\n\tstruct pbc_pattern ** pat;\n\tint size_msg;\n\tint cap_msg;\n\tstruct pbc_rmessage ** msg;\n};\n\nstatic int\n_clear_gcobj(lua_State *L) {\n\tstruct gcobj * obj = (struct gcobj *)lua_touserdata(L,1);\n\tint i;\n\tfor (i=0;i<obj->size_pat;i++) {\n\t\tpbc_pattern_delete(obj->pat[i]);\n\t}\n\tfor (i=0;i<obj->size_msg;i++) {\n\t\tpbc_rmessage_delete(obj->msg[i]);\n\t}\n\tfree(obj->pat);\n\tfree(obj->msg);\n\tobj->pat = NULL;\n\tobj->msg = NULL;\n\tif (obj->env) {\n\t\tpbc_delete(obj->env);\n\t\tobj->env = NULL;\n\t}\n\n\treturn 0;\n}\n\nstatic int\n_gc(lua_State *L) {\n\tstruct gcobj * obj;\n\tlua_settop(L,1);\n\tobj\t= (struct gcobj *)lua_newuserdata(L,sizeof(*obj));\n\tobj->env = (struct pbc_env *)lua_touserdata(L,1);\n\tobj->size_pat = 0;\n\tobj->cap_pat = 4;\n\tobj->size_msg = 0;\n\tobj->cap_msg = 4;\n\tobj->pat = (struct pbc_pattern **)malloc(obj->cap_pat * sizeof(struct pbc_pattern *));\n\tobj->msg = (struct pbc_rmessage **)malloc(obj->cap_msg * sizeof(struct pbc_rmessage *));\n\n\tlua_createtable(L,0,1);\n\tlua_pushcfunction(L, _clear_gcobj);\n\tlua_setfield(L,-2,\"__gc\");\n\tlua_setmetatable(L,-2);\n\n\treturn 1;\n}\n\nstatic int\n_add_pattern(lua_State *L) {\n\tstruct gcobj * obj = (struct gcobj *)lua_touserdata(L,1);\n\tif (obj->size_pat >= obj->cap_pat) {\n\t\tobj->cap_pat *= 2;\n\t\tobj->pat = (struct pbc_pattern **)realloc(obj->pat, obj->cap_pat * sizeof(struct pbc_pattern *));\n\t}\n\tstruct pbc_pattern * pat = (struct pbc_pattern *)lua_touserdata(L,2);\n\tobj->pat[obj->size_pat++] = pat;\n\treturn 0;\n}\n\nstatic int\n_add_rmessage(lua_State *L) {\n\tstruct gcobj * obj = (struct gcobj *)lua_touserdata(L,1);\n\tif (obj->size_msg >= obj->cap_msg) {\n\t\tobj->cap_msg *= 2;\n\t\tobj->msg = (struct pbc_rmessage **)realloc(obj->msg, obj->cap_msg * sizeof(struct pbc_rmessage *));\n\t}\n\tstruct pbc_rmessage * msg = (struct pbc_rmessage *)lua_touserdata(L,2);\n\tobj->msg[obj->size_msg++] = msg;\n\treturn 0;\n}\n\nint\nluaopen_protobuf_c(lua_State *L) {\n\tluaL_Reg reg[] = {\n\t\t{\"_env_new\" , _env_new },\n\t\t{\"_env_register\" , _env_register },\n\t\t{\"_env_type\", _env_type },\n\t\t{\"_rmessage_new\" , _rmessage_new },\n\t\t{\"_rmessage_delete\" , _rmessage_delete },\n\t\t{\"_rmessage_int\", _rmessage_int },\n\t\t{\"_rmessage_real\" , _rmessage_real },\n\t\t{\"_rmessage_string\" , _rmessage_string },\n\t\t{\"_rmessage_message\" , _rmessage_message },\n\t\t{\"_rmessage_size\" , _rmessage_size },\n\t\t{\"_wmessage_new\", _wmessage_new },\n\t\t{\"_wmessage_delete\", _wmessage_delete },\n\t\t{\"_wmessage_real\", _wmessage_real },\n\t\t{\"_wmessage_string\", _wmessage_string },\n\t\t{\"_wmessage_message\", _wmessage_message },\n\t\t{\"_wmessage_int\", _wmessage_int },\n\t\t{\"_wmessage_buffer\", _wmessage_buffer },\n\t\t{\"_wmessage_buffer_string\", _wmessage_buffer_string },\n\t\t{\"_pattern_new\", _pattern_new },\n\t\t{\"_pattern_delete\", _pattern_delete },\n\t\t{\"_pattern_size\", _pattern_size },\n\t\t{\"_pattern_unpack\", _pattern_unpack },\n\t\t{\"_pattern_pack\", _pattern_pack },\n\t\t{\"_last_error\", _last_error },\n\t\t{\"_decode\", _decode },\n\t\t{\"_gc\", _gc },\n\t\t{\"_add_pattern\", _add_pattern },\n\t\t{\"_add_rmessage\", _add_rmessage },\n\t\t{\"_env_enum_id\", _env_enum_id},\n\t\t{NULL,NULL},\n\t};\n\n\tluaL_checkversion(L);\n\tluaL_newlib(L, reg);\n\n\treturn 1;\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/pbc.h",
    "content": "#ifndef PROTOBUF_C_H\n#define PROTOBUF_C_H\n\n#include <stdio.h>\n#include <stdint.h>\n\n#define PBC_ARRAY_CAP 64\n\n#define PBC_NOEXIST -1\n#define PBC_INT 1\n#define PBC_REAL 2\n#define PBC_BOOL 3\n#define PBC_ENUM 4\n#define PBC_STRING 5\n#define PBC_MESSAGE 6\n#define PBC_FIXED64 7\n#define PBC_FIXED32 8\n#define PBC_BYTES 9\n#define PBC_INT64 10\n#define PBC_UINT 11\n#define PBC_UNKNOWN 12\n#define PBC_REPEATED 128\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct _pbc_array { char _data[PBC_ARRAY_CAP]; } pbc_array[1];\n\nstruct pbc_slice {\n\tvoid *buffer;\n\tint len;\n};\n\nstruct pbc_pattern;\nstruct pbc_env;\nstruct pbc_rmessage;\nstruct pbc_wmessage;\n\nstruct pbc_env * pbc_new(void);\nvoid pbc_delete(struct pbc_env *);\nint pbc_register(struct pbc_env *, struct pbc_slice * slice);\nint pbc_type(struct pbc_env *, const char * type_name , const char * key , const char ** type);\nconst char * pbc_error(struct pbc_env *);\n\n// callback api\nunion pbc_value {\n\tstruct {\n\t\tuint32_t low;\n\t\tuint32_t hi;\n\t} i;\n\tdouble f;\n\tstruct pbc_slice s;\n\tstruct {\n\t\tint id;\n\t\tconst char * name;\n\t} e;\n};\n\ntypedef void (*pbc_decoder)(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key);\nint pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder f, void *ud);\n\n// message api\n\nstruct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice);\nvoid pbc_rmessage_delete(struct pbc_rmessage *);\n\nuint32_t pbc_rmessage_integer(struct pbc_rmessage * , const char *key , int index, uint32_t *hi);\ndouble pbc_rmessage_real(struct pbc_rmessage * , const char *key , int index);\nconst char * pbc_rmessage_string(struct pbc_rmessage * , const char *key , int index, int *sz);\nstruct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage *, const char *key, int index);\nint pbc_rmessage_size(struct pbc_rmessage *, const char *key);\nint pbc_rmessage_next(struct pbc_rmessage *, const char **key);\n\nstruct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name);\nvoid pbc_wmessage_delete(struct pbc_wmessage *);\n\n// for negative integer, pass -1 to hi\nint pbc_wmessage_integer(struct pbc_wmessage *, const char *key, uint32_t low, uint32_t hi);\nint pbc_wmessage_real(struct pbc_wmessage *, const char *key, double v);\nint pbc_wmessage_string(struct pbc_wmessage *, const char *key, const char * v, int len);\nstruct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *, const char *key);\nvoid * pbc_wmessage_buffer(struct pbc_wmessage *, struct pbc_slice * slice);\n\n// array api \n\nint pbc_array_size(pbc_array);\nuint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi);\ndouble pbc_array_real(pbc_array array, int index);\nstruct pbc_slice * pbc_array_slice(pbc_array array, int index);\n\nvoid pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi);\nvoid pbc_array_push_slice(pbc_array array, struct pbc_slice *);\nvoid pbc_array_push_real(pbc_array array, double v);\n\nstruct pbc_pattern * pbc_pattern_new(struct pbc_env * , const char * message, const char *format, ...);\nvoid pbc_pattern_delete(struct pbc_pattern *);\n\n// return unused bytes , -1 for error\nint pbc_pattern_pack(struct pbc_pattern *, void *input, struct pbc_slice * s);\n\n// <0 for error\nint pbc_pattern_unpack(struct pbc_pattern *, struct pbc_slice * s , void * output);\n\nvoid pbc_pattern_set_default(struct pbc_pattern * , void *data);\nvoid pbc_pattern_close_arrays(struct pbc_pattern *, void *data);\n\nint pbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/proto.cpp",
    "content": "#include \"pbc.h\"\n#include \"proto.h\"\n#include \"pattern.h\"\n#include \"map.h\"\n#include \"alloc.h\"\n#include \"stringpool.h\"\n#include \"bootstrap.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nconst char * \npbc_error(struct pbc_env * p) {\n\tconst char *err = p->lasterror;\n\tp->lasterror = \"\";\n\treturn err;\n}\n\nstruct _message * \n_pbcP_get_message(struct pbc_env * p , const char *name) {\n\treturn (struct _message *)_pbcM_sp_query(p->msgs, name);\n}\n\nstruct pbc_env * \npbc_new(void) {\n\tstruct pbc_env * p = (struct pbc_env *)pbc_malloc(sizeof(*p));\n\tp->files = _pbcM_sp_new(0 , NULL);\n\tp->enums = _pbcM_sp_new(0 , NULL);\n\tp->msgs = _pbcM_sp_new(0 , NULL);\n\tp->lasterror = \"\";\n\n\t_pbcB_init(p);\n\n\treturn p;\n}\n\nstatic void\nfree_enum(void *p) {\n\tstruct _enum * e = (struct _enum *)p;\n\t_pbcM_ip_delete(e->id);\n\t_pbcM_si_delete(e->name);\n\n\tpbc_free(p);\n}\n\nstatic void\nfree_stringpool(void *p) {\n\t_pbcS_delete((struct _stringpool *)p);\n}\n\nstatic void\nfree_msg(void *p) {\n\tstruct _message * m = (struct _message *)p;\n\tif (m->id)\n\t\t_pbcM_ip_delete(m->id);\n\tpbc_free(m->def);\n\t_pbcM_sp_foreach(m->name, pbc_free);\n\t_pbcM_sp_delete(m->name);\n\tpbc_free(p);\n}\n\nvoid \npbc_delete(struct pbc_env *p) {\n\t_pbcM_sp_foreach(p->enums, free_enum);\n\t_pbcM_sp_delete(p->enums);\n\n\t_pbcM_sp_foreach(p->msgs, free_msg);\n\t_pbcM_sp_delete(p->msgs);\n\n\t_pbcM_sp_foreach(p->files, free_stringpool);\n\t_pbcM_sp_delete(p->files);\n\n\tpbc_free(p);\n}\n\nstruct _enum *\n_pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) {\n\tvoid * check = _pbcM_sp_query(p->enums, name);\n\tif (check)\n\t\treturn NULL;\n\tstruct _enum * v = (struct _enum *)pbc_malloc(sizeof(*v));\n\tv->key = name;\n\tv->id = _pbcM_ip_new(table,sz);\n\tv->name = _pbcM_si_new(table,sz);\n\tv->default_v->e.id = table[0].id;\n\tv->default_v->e.name = (const char *)table[0].pointer;\n\n\t_pbcM_sp_insert(p->enums, name , v);\n\treturn v;\n}\n\nvoid \n_pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) {\n\tstruct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name);\n\tif (m==NULL) {\n\t\tm = (struct _message *)pbc_malloc(sizeof(*m));\n\t\tm->def = NULL;\n\t\tm->key = name;\n\t\tm->id = NULL;\n\t\tm->name = _pbcM_sp_new(0 , NULL);\n\t\tm->env = p;\n\t\t_pbcM_sp_insert(p->msgs, name, m);\n\t}\n\tstruct _field * field = (struct _field *)pbc_malloc(sizeof(*field));\n\tmemcpy(field,f,sizeof(*f));\n\t_pbcM_sp_insert(m->name, field->name, field); \n\tpbc_var atom;\n\tatom->m.buffer = field;\n\tif (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) {\n\t\t_pbcA_push(queue, atom);\n\t}\n}\n\nstruct _iter {\n\tint count;\n\tstruct map_kv * table;\n};\n\nstatic void\n_count(void *p, void *ud) {\n\tstruct _iter *iter = (struct _iter *)ud;\n\titer->count ++;\n}\n\nstatic void\n_set_table(void *p, void *ud) {\n\tstruct _field * field = (struct _field *)p;\n\tstruct _iter *iter = (struct _iter *)ud;\n\titer->table[iter->count].id = field->id;\n\titer->table[iter->count].pointer = field;\n\t++iter->count;\n}\n\nstruct _message * \n_pbcP_init_message(struct pbc_env * p, const char *name) {\n\tstruct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name);\n\tif (m == NULL) {\n\t\tm = (struct _message *)pbc_malloc(sizeof(*m));\n\t\tm->def = NULL;\n\t\tm->key = name;\n\t\tm->id = NULL;\n\t\tm->name = _pbcM_sp_new(0 , NULL);\n\t\tm->env = p;\n\t\t_pbcM_sp_insert(p->msgs, name, m);\n\n\t\treturn m;\n\t}\n\tif (m->id) {\n\t\t// extend message, delete old id map.\n\t\t_pbcM_ip_delete(m->id);\n\t}\n\tstruct _iter iter = { 0, NULL };\n\t_pbcM_sp_foreach_ud(m->name, _count, &iter);\n\titer.table = (struct map_kv *)pbc_malloc(iter.count * sizeof(struct map_kv));\n\titer.count = 0;\n\t_pbcM_sp_foreach_ud(m->name, _set_table, &iter);\n\n\tm->id = _pbcM_ip_new(iter.table , iter.count);\n\n\tpbc_free(iter.table);\n\n\treturn m;\n}\n\nint \n_pbcP_message_default(struct _message * m, const char * name, pbc_var defv) {\n\tstruct _field * f= (struct _field *)_pbcM_sp_query(m->name, name);\n\tif (f==NULL) {\n\t\t// invalid key\n\t\tdefv->p[0] = NULL;\n\t\tdefv->p[1] = NULL;\n\t\treturn -1;\n\t}\n\t*defv = *(f->default_v);\n\treturn f->type;\n}\n\nint \n_pbcP_type(struct _field * field, const char ** type) {\n\tif (field == NULL) {\n\t\treturn 0;\n\t}\n\tint ret = 0;\n\tswitch (field->type) {\n\tcase PTYPE_DOUBLE:\n\tcase PTYPE_FLOAT:\n\t\tret = PBC_REAL;\n\t\tbreak;\n\tcase PTYPE_INT64:\n\tcase PTYPE_SINT64:  \n\t\tret = PBC_INT64;\n\t\tbreak;\n\tcase PTYPE_INT32:\n\tcase PTYPE_SINT32:  \n\t\tret = PBC_INT;\n\t\tbreak;\n\tcase PTYPE_UINT32:\n\tcase PTYPE_UINT64:\n\t\tret = PBC_UINT;\n\t\tbreak;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tret = PBC_FIXED32;\n\t\tbreak;\n\tcase PTYPE_SFIXED64:\n\tcase PTYPE_FIXED64:\n\t\tret = PBC_FIXED64;\n\t\tbreak;\n\tcase PTYPE_BOOL:\n\t\tret = PBC_BOOL;\n\t\tbreak;\n\tcase PTYPE_STRING:\n\t\tret = PBC_STRING;\n\t\tbreak;\n\tcase PTYPE_BYTES:  \n\t\tret = PBC_BYTES;\n\t\tbreak;\n\tcase PTYPE_ENUM:\n\t\tret = PBC_ENUM;\n\t\tif (type) {\n\t\t\t*type = field->type_name.e->key;\n\t\t}\n\t\tbreak;\n\tcase PTYPE_MESSAGE:\n\t\tret = PBC_MESSAGE;\n\t\tif (type) {\n\t\t\t*type = field->type_name.m->key;\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\treturn 0;\n\t}\n\tif (field->label == LABEL_REPEATED ||\n\t\tfield->label == LABEL_PACKED) {\n\t\tret |= PBC_REPEATED;\n\t}\n\n\treturn ret;\n}\n\nint \npbc_type(struct pbc_env * p, const char * type_name , const char * key , const char ** type) {\n\tstruct _message *m = _pbcP_get_message(p, type_name);\n\tif (m==NULL) {\n\t\treturn 0;\n\t}\n\tif (key == NULL) {\n\t\treturn PBC_NOEXIST;\n\t}\n\tstruct _field * field = (struct _field *)_pbcM_sp_query(m->name, key);\n\treturn _pbcP_type(field, type);\n}\n\nint\npbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name) {\n\tstruct _enum *enum_map = (struct _enum *)_pbcM_sp_query(env->enums, enum_type);\n\tif(!enum_map) {\n\t\treturn -1;\n\t}\n\tint32_t enum_id = 0;\n\tint err = _pbcM_si_query(enum_map->name, enum_name, &enum_id);\n\tif(err) {\n\t\treturn -1;\n\t}\n\treturn enum_id;\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/proto.h",
    "content": "#ifndef PROTOBUFC_PROTO_H\n#define PROTOBUFC_PROTO_H\n\n#include \"pbc.h\"\n#include \"map.h\"\n#include \"array.h\"\n#ifndef _MSC_VER\n#include <stdbool.h>\n#endif\n#include <stddef.h>\n\nstruct map_ip;\nstruct map_si;\nstruct map_sp;\nstruct _message;\nstruct _enum;\n\n#define LABEL_OPTIONAL 0\n#define LABEL_REQUIRED 1\n#define LABEL_REPEATED 2\n#define LABEL_PACKED 3\n\nstruct _field {\n\tint id;\n\tconst char *name;\n\tint type;\n\tint label;\n\tpbc_var default_v;\n\tunion {\n\t\tconst char * n;\n\t\tstruct _message * m;\n\t\tstruct _enum * e;\n\t} type_name;\n};\n\nstruct _message {\n\tconst char * key;\n\tstruct map_ip * id;\t// id -> _field\n\tstruct map_sp * name;\t// string -> _field\n\tstruct pbc_rmessage * def;\t// default message\n\tstruct pbc_env * env;\n};\n\nstruct _enum {\n\tconst char * key;\n\tstruct map_ip * id;\n\tstruct map_si * name;\n\tpbc_var default_v;\n};\n\nstruct pbc_env {\n\tstruct map_sp * files;\t// string -> void *\n\tstruct map_sp * enums;\t// string -> _enum\n\tstruct map_sp * msgs;\t// string -> _message\n\tconst char * lasterror;\n};\n\nstruct _message * _pbcP_init_message(struct pbc_env * p, const char *name);\nvoid _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue);\nstruct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz );\nint _pbcP_message_default(struct _message * m, const char * name, pbc_var defv);\nstruct _message * _pbcP_get_message(struct pbc_env * p, const char *name);\nint _pbcP_type(struct _field * field, const char **type);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/register.cpp",
    "content": "#include \"pbc.h\"\n#include \"proto.h\"\n#include \"alloc.h\"\n#include \"map.h\"\n#include \"bootstrap.h\"\n#include \"context.h\"\n#include \"stringpool.h\"\n\n#include <string.h>\n#include <stdlib.h>\n\n#ifdef _MSC_VER\n#define strtoll _strtoi64\n#endif\n\nstatic const char *\n_concat_name(struct _stringpool *p , const char *prefix ,  int prefix_sz , const char *name , int name_sz, int *sz) {\n\tif (prefix_sz == 0) {\n\t\tif (sz) {\n\t\t\t*sz = name_sz;\n\t\t}\n\t\treturn _pbcS_build(p , name, name_sz);\n\t}\n\tchar * temp = (char *)alloca(name_sz + prefix_sz + 2);\n\tmemcpy(temp,prefix,prefix_sz);\n\ttemp[prefix_sz] = '.';\n\tmemcpy(temp+prefix_sz+1,name,name_sz);\n\ttemp[name_sz + prefix_sz + 1] = '\\0';\n\tif (sz) {\n\t\t*sz = name_sz + prefix_sz + 1;\n\t}\n\tconst char * ret = _pbcS_build(p , temp, name_sz + prefix_sz + 1);\n\treturn ret;\n}\n\nstatic void\n_register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) {\n\tint field_count = pbc_rmessage_size(enum_type, \"value\");\n\tstruct map_kv *table = (struct map_kv *)pbc_malloc(field_count * sizeof(struct map_kv));\n\tint i;\n\tfor (i=0;i<field_count;i++) {\n\t\tstruct pbc_rmessage * value = pbc_rmessage_message(enum_type, \"value\", i);\n\t\tint enum_name_sz;\n\t\tconst char *enum_name = pbc_rmessage_string(value , \"name\" , 0 , &enum_name_sz);\n\t\ttable[i].pointer = (void *)_pbcS_build(pool, enum_name , enum_name_sz);\n\t\ttable[i].id = pbc_rmessage_integer(value , \"number\", 0 , 0);\n\t}\n\tint name_sz;\n\tconst char * name = pbc_rmessage_string(enum_type, \"name\", 0 , &name_sz);\n\tconst char *temp = _concat_name(pool, prefix , prefix_sz , name , name_sz, NULL);\n\n\t_pbcP_push_enum(p,temp,table,field_count);\n\tpbc_free(table);\n}\n\nstatic void\n_set_default(struct _stringpool *pool, struct _field *f , int ptype, const char *value, int sz) {\n\tif (value == NULL || sz == 0) {\n\t\tif (f->type == PTYPE_STRING || f->type == PTYPE_BYTES) {\n\t\t\tf->default_v->s.str = \"\";\n\t\t\tf->default_v->s.len = 0;\n\t\t} else {\n\t\t\tf->default_v->integer.low = 0;\n\t\t\tf->default_v->integer.hi = 0;\n\t\t}\n\t\treturn;\n\t}\n\n\tswitch (f->type) {\n\tcase PTYPE_DOUBLE:\n\tcase PTYPE_FLOAT:\n\t\tf->default_v->real = strtod(value,NULL);\n\t\tbreak;\n\tcase PTYPE_STRING:\n\t\tf->default_v->s.str = _pbcS_build(pool, value , sz);\n\t\tf->default_v->s.len = sz;\n\t\tbreak;\n\tcase PTYPE_ENUM:\n\t\t// enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one()\n\t\tf->default_v->s.str = value;\n\t\tf->default_v->s.len = sz;\n\t\tbreak;\n\tcase PTYPE_BOOL:\n\t\tif (strcmp(value,\"true\") == 0) {\n\t\t\tf->default_v->integer.low = 1;\n\t\t} else {\n\t\t\tf->default_v->integer.low = 0;\n\t\t}\n\t\tf->default_v->integer.hi = 0;\n\t\tbreak;\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT64:\n\tcase PTYPE_SFIXED64:\n\tcase PTYPE_SINT64: {\n\t\tlong long v = strtoll(value, NULL, 10);\n\t\tf->default_v->integer.low = (long) v;\n\t\tf->default_v->integer.hi = (long)(v >> 32);\n\t\tbreak;\n\t\t}\n\tcase PTYPE_INT32:\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\tcase PTYPE_SINT32: {\n\t\tint low = strtol(value, NULL, 10);\n\t\tf->default_v->integer.low = low;\n\t\tif (low < 0) {\n\t\t\tf->default_v->integer.hi = -1;\n\t\t} else {\n\t\t\tf->default_v->integer.hi = 0;\n\t\t}\n\t\tbreak;\n\t}\n\tcase PTYPE_UINT32:\n\t\tf->default_v->integer.low = strtoul(value, NULL, 10);\n\t\tf->default_v->integer.hi = 0;\n\t\tbreak;\n\tcase PTYPE_BYTES:\n\tcase PTYPE_MESSAGE:\n\t\t// bytes and message types have no default value\n\t\tf->default_v->m.buffer = 0;\n\t\tf->default_v->m.len = 0;\n\t\tbreak;\n\tdefault:\n\t\tf->default_v->integer.low = 0;\n\t\tf->default_v->integer.hi = 0;\n\t\tbreak;\n\t}\n}\n\nstatic void\n_register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) {\n\tf->id = pbc_rmessage_integer(field, \"number\", 0 , 0);\n\tf->type = pbc_rmessage_integer(field, \"type\", 0 , 0);\t// enum\n\tf->label = pbc_rmessage_integer(field, \"label\", 0, 0) - 1; // LABEL_OPTIONAL = 0\n\tif (pbc_rmessage_size(field , \"options\") > 0) {\n\t\tstruct pbc_rmessage * options = pbc_rmessage_message(field, \"options\" , 0);\n\t\tint packed = pbc_rmessage_integer(options , \"packed\" , 0 , NULL);\n\t\tif (packed) {\n\t\t\tf->label = LABEL_PACKED;\n\t\t}\n\t}\n\tf->type_name.n = pbc_rmessage_string(field, \"type_name\", 0 , NULL) +1;\t// abandon prefix '.' \n\tint vsz;\n\tconst char * default_value = pbc_rmessage_string(field, \"default_value\", 0 , &vsz);\n\t_set_default(pool , f , f->type, default_value , vsz);\n}\n\nstatic void\n_register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) {\n\tint extension_count = pbc_rmessage_size(msg , \"extension\");\n\tif (extension_count <= 0) \n\t\treturn;\n\tint i;\n\n\tconst char * last = NULL;\n\n\tfor (i=0;i<extension_count;i++) {\n\t\tstruct pbc_rmessage * extension = pbc_rmessage_message(msg, \"extension\", i);\n\t\tint field_name_sz = 0;\n\t\tstruct _field f;\n\t\tconst char * field_name = pbc_rmessage_string(extension , \"name\" , 0, &field_name_sz);\n\t\tf.name =  _concat_name(pool, prefix, prefix_sz, field_name, field_name_sz, NULL);\n\n\t\t_register_field(extension, &f , pool);\n\n\t\tconst char * extendee = pbc_rmessage_string(extension , \"extendee\" , 0, NULL);\n\n\t\t_pbcP_push_message(p, extendee + 1 , &f , queue);\n\n\t\tif (last == NULL) {\n\t\t\tlast = extendee;\n\t\t} else if (strcmp(extendee,last) != 0) {\n\t\t\t_pbcP_init_message(p, last+1);\n\t\t\tlast = extendee;\n\t\t} \n\t}\n\t_pbcP_init_message(p, last+1);\n}\n\nstatic void\n_register_message(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * message_type, const char *prefix, int prefix_sz, pbc_array queue) {\n\tint name_sz;\n\tconst char * name = pbc_rmessage_string(message_type, \"name\", 0 , &name_sz);\n\tint sz = 0;\n\tconst char *temp = _concat_name(pool, prefix , prefix_sz , name , name_sz, &sz);\n\n\tint field_count = pbc_rmessage_size(message_type, \"field\");\n\tint i;\n\tfor (i=0;i<field_count;i++) {\n\t\tstruct pbc_rmessage * field = pbc_rmessage_message(message_type, \"field\" , i);\n\t\tstruct _field f;\n\t\tint field_name_sz;\n\t\tconst char * field_name = pbc_rmessage_string(field, \"name\", 0 , &field_name_sz);\n\t\tf.name = _pbcS_build(pool,field_name,field_name_sz);\n\n\t\t_register_field(field, &f , pool);\n\n\t\t_pbcP_push_message(p, temp , &f , queue);\n\t}\n\n\t_pbcP_init_message(p, temp);\n\n\t_register_extension(p, pool, temp, sz,message_type, queue);\n\n\t// nested enum\n\n\tint enum_count = pbc_rmessage_size(message_type, \"enum_type\");\n\n\tfor (i=0;i<enum_count;i++) {\n\t\tstruct pbc_rmessage * enum_type = pbc_rmessage_message(message_type, \"enum_type\", i);\n\t\t_register_enum(p, pool, enum_type, temp, sz);\n\t}\n\t\n\t// nested type\n\tint message_count = pbc_rmessage_size(message_type, \"nested_type\");\n\tfor (i=0;i<message_count;i++) {\n\t\tstruct pbc_rmessage * nested_type = pbc_rmessage_message(message_type, \"nested_type\", i);\n\t\t_register_message(p, pool, nested_type, temp, sz, queue);\n\t}\n}\n\nstatic void\n_register(struct pbc_env *p, struct pbc_rmessage * file, struct _stringpool *pool) {\n\tint package_sz;\n\tconst char *package = pbc_rmessage_string(file, \"package\", 0, &package_sz);\n\n\tpbc_array queue;\n\t_pbcA_open(queue);\n\n\tint enum_count = pbc_rmessage_size(file, \"enum_type\");\n\tint i;\n\n\tfor (i=0;i<enum_count;i++) {\n\t\tstruct pbc_rmessage * enum_type = pbc_rmessage_message(file, \"enum_type\", i);\n\t\t_register_enum(p,  pool , enum_type, package, package_sz);\n\t}\n\n\tint message_count = pbc_rmessage_size(file, \"message_type\");\n\tfor (i=0;i<message_count;i++) {\n\t\tstruct pbc_rmessage * message_type = pbc_rmessage_message(file, \"message_type\", i);\n\t\t_register_message(p, pool, message_type, package, package_sz, queue);\n\t}\n\n\t_register_extension(p, pool, package, package_sz, file , queue);\n\n\t_pbcB_register_fields(p, queue);\n\n\t_pbcA_close(queue);\n}\n\n#define CHECK_FILE_OK 0\n#define CHECK_FILE_EXIST 1\n#define CHECK_FILE_DEPENDENCY 2\n\nstatic int\n_check_file_name(struct pbc_env * p , struct pbc_rmessage * file, const char ** fname) {\n\tconst char * filename = pbc_rmessage_string(file, \"name\", 0, NULL);\n//\tprintf(\"reg :%s\\n\",filename);\n\tif (_pbcM_sp_query(p->files, filename)) {\n\t\treturn CHECK_FILE_EXIST;\n\t}\n\tint sz = pbc_rmessage_size(file, \"dependency\"); \n\tint i;\n\tfor (i=0;i<sz;i++) {\n\t\tconst char *dname = pbc_rmessage_string(file,\"dependency\",i,NULL);\n//\t\tprintf(\"dependency :%s\\n\",dname);\n\t\tif (_pbcM_sp_query(p->files, dname) == NULL) {\n\t\t\treturn CHECK_FILE_DEPENDENCY;\n\t\t}\n\t}\n\n\t*fname = filename;\n\n\treturn CHECK_FILE_OK;\n}\n\nstatic int\n_register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) {\n\tint r = 0;\n\tint i;\n\tfor (i=0;i<n;i++) {\n\t\tif (files[i] == NULL)\n\t\t\tcontinue;\n\t\tconst char *filename = NULL;\n\t\tint err = _check_file_name(p, files[i], &filename);\n\t\tswitch(err) {\n\t\tcase CHECK_FILE_EXIST:\n\t\t\tbreak;\n\t\tcase CHECK_FILE_DEPENDENCY:\n\t\t\t++r;\n\t\t\tbreak;\n\t\tcase CHECK_FILE_OK: {\n\t\t\tstruct _stringpool *pool = _pbcS_new();\n\t\t\tfilename = _pbcS_build(pool, filename , strlen(filename));\n\t\t\t_pbcM_sp_insert(p->files , filename, pool);\n\t\t\t_register(p,files[i],pool);\n\t\t\tfiles[i] = NULL;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn r;\n}\n\nint\npbc_register(struct pbc_env * p, struct pbc_slice *slice) {\n\tstruct pbc_rmessage * message = pbc_rmessage_new(p, \"google.protobuf.FileDescriptorSet\", slice);\n\tif (message == NULL) {\n\t\tp->lasterror = \"register open google.protobuf.FileDescriptorSet fail\";\n\t\treturn 1;\n\t}\n\tint n = pbc_rmessage_size(message, \"file\");\n\tstruct pbc_rmessage ** files = (struct pbc_rmessage **)alloca(n * sizeof(struct pbc_rmessage *));\n\tint i;\n\tif (n == 0) {\n\t\tp->lasterror = \"register empty\";\n        pbc_rmessage_delete(message);\n        return 1;\n\t}\n\tfor (i=0;i<n;i++) {\n\t\tfiles[i] = pbc_rmessage_message(message, \"file\", i);\n\t\tif (files[i] == NULL) {\n\t\t\tp->lasterror = \"register open fail\";\n            pbc_rmessage_delete(message);\n            return 1;\n\t\t}\n\t}\n\n\tint r = n;\n\tdo {\n\t\tint rr = _register_no_dependency(p,files , n);\n\t\tif (rr == r) {\n\t\t\tp->lasterror = \"register dependency error\";\n            pbc_rmessage_delete(message);\n            return 1;\n\t\t}\n\t\tr = rr;\n\t} while (r>0);\n\n\tpbc_rmessage_delete(message);\n\treturn 0;\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/rmessage.cpp",
    "content": "#include \"pbc.h\"\n#include \"alloc.h\"\n#include \"map.h\"\n#include \"context.h\"\n#include \"proto.h\"\n#include \"pattern.h\"\n#include \"varint.h\"\n\n#include <stddef.h>\n#include <string.h>\n\nstruct pbc_rmessage {\n\t\tstruct _message * msg;\n\t\tstruct map_sp * index;\t// key -> struct value *\n\t\tstruct heap * heap;\n};\n\nunion _var {\n\tpbc_var var;\n\tpbc_array array;\n\tstruct pbc_rmessage message;\n} ;\n\nstruct value {\n\tstruct _field * type;\n\tunion _var v;\n};\n\nint \npbc_rmessage_next(struct pbc_rmessage *m, const char **key) {\n\tstruct value * v = (struct value *)_pbcM_sp_next(m->index, key);\n\tif (*key == NULL) {\n\t\treturn 0;\n\t}\n\treturn _pbcP_type(v->type, NULL);\n}\n\n#define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var))\n#define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array))\n#define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage))\n\nstatic struct value *\nread_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) {\n\tconst char * temp = (const char *) (buffer + a->v.s.start);\n\tint len = a->v.s.end - a->v.s.start;\n\n\tif (len > 0 && temp[len-1] == '\\0') {\n\t\tstruct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->s.str = temp;\n\t\tv->v.var->s.len = len;\n\t\treturn v;\n\t} else {\n\t\tstruct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR + len + 1);\n\t\tmemcpy(((char *)v) + SIZE_VAR , temp, len);\n\t\t*(((char *)v) + SIZE_VAR + len) = '\\0';\n\t\tv->v.var->s.str = ((char *)v) + SIZE_VAR;\n\t\tv->v.var->s.len = len;\n\t\treturn v;\n\t}\n}\n\nstatic void\nread_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) {\n\tconst char * temp = (const char *) (buffer + a->v.s.start);\n\tint len = a->v.s.end - a->v.s.start;\n\tif (len == 0) {\n\t\tvar->s.str = \"\";\n\t\tvar->s.len = 0;\n\t}\n\telse if (temp[len-1] == '\\0') {\n\t\tvar->s.str = temp;\n\t\tvar->s.len = len;\n\t} else {\n\t\tchar * temp2 = (char *)_pbcH_alloc(h, len + 1);\n\t\tmemcpy(temp2, temp, len);\n\t\ttemp2[len]='\\0';\n\t\tvar->s.str = temp2;\n\t\tvar->s.len = -len;\n\t}\n}\n\nstatic void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type ,  void *buffer, int size, struct heap *h);\n\nstatic struct value *\nread_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) {\n\tstruct value * v;\n\n\tswitch (f->type) {\n\tcase PTYPE_DOUBLE:\n\t\tCHECK_BIT64(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->real = read_double(a);\n\t\tbreak;\n\tcase PTYPE_FLOAT:\n\t\tCHECK_BIT32(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->real = (double) read_float(a);\n\t\tbreak;\n\tcase PTYPE_ENUM:\n\t\tCHECK_VARINT(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->e.id = a->v.i.low;\n\t\tv->v.var->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low);\n\t\tbreak;\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_BOOL:\n\t\tCHECK_VARINT(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->integer = a->v.i;\n\t\tbreak;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tCHECK_BIT32(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->integer = a->v.i;\n\t\tbreak;\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tCHECK_BIT64(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->integer = a->v.i;\n\t\tbreak;\n\tcase PTYPE_SINT32: \n\t\tCHECK_VARINT(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->integer = a->v.i;\n\t\t_pbcV_dezigzag32(&(v->v.var->integer));\n\t\tbreak;\n\tcase PTYPE_SINT64:\n\t\tCHECK_VARINT(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->integer = a->v.i;\n\t\t_pbcV_dezigzag64(&(v->v.var->integer));\n\t\tbreak;\n\tcase PTYPE_STRING:\n\t\tCHECK_LEND(a,NULL);\n\t\tv = read_string(h,a,f,buffer);\n\t\tbreak;\n\tcase PTYPE_BYTES:\n\t\tCHECK_LEND(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_VAR);\n\t\tv->v.var->s.str = (const char *)(buffer + a->v.s.start);\n\t\tv->v.var->s.len = a->v.s.end - a->v.s.start;\n\t\tbreak;\n\tcase PTYPE_MESSAGE:\n\t\tCHECK_LEND(a,NULL);\n\t\tv = (struct value *)_pbcH_alloc(h, SIZE_MESSAGE);\n\t\t_pbc_rmessage_new(&(v->v.message), f->type_name.m , \n\t\t\tbuffer + a->v.s.start , \n\t\t\ta->v.s.end - a->v.s.start,h);\n\t\tbreak;\n\tdefault:\n\t\treturn NULL;\n\t}\n\tv->type = f;\n\treturn v;\n}\n\nstatic void\npush_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) {\n\tint n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start,\n\t\tf->type , array);\n\tif (n<=0) {\n\t\t// todo  : error\n\t\ttype->env->lasterror = \"Unpack packed field error\";\n\t\treturn;\n\t}\n\tif (f->type == PTYPE_ENUM) {\n\t\tint i;\n\t\tfor (i=0;i<n;i++) {\n\t\t\tunion _pbc_var * v = (union _pbc_var *)_pbcA_index_p(array, i);\n\t\t\tint id = v->integer.low;\n\t\t\tv->e.id = id;\n\t\t\tv->e.name = (const char*)_pbcM_ip_query(f->type_name.e->id , id);\n\t\t}\n\t}\n}\n\nstatic void\npush_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) {\n\tpbc_var v;\n\n\tswitch (f->type) {\n\tcase PTYPE_DOUBLE:\n\t\tv->real = read_double(a);\n\t\tbreak;\n\tcase PTYPE_FLOAT:\n\t\tv->real = (double) read_float(a);\n\t\tbreak;\n\tcase PTYPE_ENUM:\n\t\tv->e.id = a->v.i.low;\n\t\tv->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low);\n\t\tbreak;\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\tcase PTYPE_INT32:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED32:\n\tcase PTYPE_SFIXED64:\n\tcase PTYPE_BOOL:\n\t\tv->integer = a->v.i;\n\t\tbreak;\n\tcase PTYPE_SINT32: \n\t\tv->integer = a->v.i;\n\t\t_pbcV_dezigzag32(&(v->integer));\n\t\tbreak;\n\tcase PTYPE_SINT64:\n\t\tv->integer = a->v.i;\n\t\t_pbcV_dezigzag64(&(v->integer));\n\t\tbreak;\n\tcase PTYPE_STRING:\n\t\tCHECK_LEND(a, );\n\t\tread_string_var(h,v,a,f,buffer);\n\t\tbreak;\n\tcase PTYPE_BYTES:\n\t\tCHECK_LEND(a, );\n\t\tv->s.str = (const char *)(buffer + a->v.s.start);\n\t\tv->s.len = a->v.s.end - a->v.s.start;\n\t\tbreak;\n\tcase PTYPE_MESSAGE: {\n\t\tCHECK_LEND(a, );\n\t\tstruct pbc_rmessage message;\n\t\t_pbc_rmessage_new(&message, f->type_name.m , \n\t\t\tbuffer + a->v.s.start , \n\t\t\ta->v.s.end - a->v.s.start,h);\n\t\tif (message.msg == NULL) {\n\t\t\treturn;\n\t\t}\n\t\tv->p[0] = message.msg;\n\t\tv->p[1] = message.index;\n\t\tbreak;\n\t}\n\tdefault:\n\t\treturn;\n\t}\n\n\t_pbcA_push(array,v);\n}\n\nstatic void\n_pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) {\n\tif (size == 0) {\n\t\tret->msg = type;\n\t\tret->index = _pbcM_sp_new(0 , h);\n\t\tret->heap = h;\n\t\treturn;\n\t}\n\tpbc_ctx _ctx;\n\tint count = _pbcC_open(_ctx,buffer,size);\n\tif (count <= 0) {\n\t\ttype->env->lasterror = \"rmessage decode context error\";\n\t\tmemset(ret , 0, sizeof(*ret));\n\t\treturn;\n\t}\n\tstruct context * ctx = (struct context *)_ctx;\n\n\tret->msg = type;\n\tret->index = _pbcM_sp_new(count, h);\n\tret->heap = h;\n\n\tint i;\n\n\tfor (i=0;i<ctx->number;i++) {\n\t\tint id = ctx->a[i].wire_id >> 3;\n\t\tstruct _field * f = (struct _field *)_pbcM_ip_query(type->id , id);\n\t\tif (f) {\n\t\t\tif (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) {\n\t\t\t\tstruct value * v;\n\t\t\t\tvoid ** vv = _pbcM_sp_query_insert(ret->index, f->name);\n\t\t\t\tif (*vv == NULL) {\n\t\t\t\t\tv = (struct value *)_pbcH_alloc(h, SIZE_ARRAY);\n\t\t\t\t\tv->type = f;\n\t\t\t\t\t_pbcA_open_heap(v->v.array,ret->heap);\n\t\t\t\t\t*vv = v;\n\t\t\t\t} else {\n\t\t\t\t\tv= (struct value *)*vv;\n\t\t\t\t}\n\t\t\t\tif (f->label == LABEL_PACKED) {\n\t\t\t\t\tpush_value_packed(type, v->v.array , f , &(ctx->a[i]), (uint8_t *)buffer);\n\t\t\t\t\tif (pbc_array_size(v->v.array) == 0) {\n\t\t\t\t\t\ttype->env->lasterror = \"rmessage decode packed data error\";\n\t\t\t\t\t\t*vv = NULL;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpush_value_array(h,v->v.array , f, &(ctx->a[i]), (uint8_t *)buffer);\n\t\t\t\t\tif (pbc_array_size(v->v.array) == 0) {\n\t\t\t\t\t\ttype->env->lasterror = \"rmessage decode repeated data error\";\n\t\t\t\t\t\t*vv = NULL;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstruct value * v = read_value(h, f, &(ctx->a[i]), (uint8_t *)buffer);\n\t\t\t\tif (v) {\n\t\t\t\t\t_pbcM_sp_insert(ret->index, f->name, v);\n\t\t\t\t} else {\n\t\t\t\t\ttype->env->lasterror = \"rmessage decode data error\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t_pbcC_close(_ctx);\n}\n\nstruct pbc_rmessage * \npbc_rmessage_new(struct pbc_env * env, const char * type_name ,  struct pbc_slice * slice) {\n\tstruct _message * msg = _pbcP_get_message(env, type_name);\n\tif (msg == NULL) {\n\t\tenv->lasterror = \"Proto not found\";\n\t\treturn NULL;\n\t}\n\tstruct pbc_rmessage temp;\n\tstruct heap * h = _pbcH_new(slice->len);\n\t_pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h);\n\tif (temp.msg == NULL) {\n\t\t_pbcH_delete(h);\n\t\treturn NULL;\n\t}\n\n\tstruct pbc_rmessage *m = (struct pbc_rmessage *)_pbcH_alloc(temp.heap, sizeof(*m));\n\t*m = temp;\n\treturn m;\n}\n\nvoid \npbc_rmessage_delete(struct pbc_rmessage * m) {\n\tif (m) {\n\t\t_pbcH_delete(m->heap);\n\t}\n}\n\nconst char * \npbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) {\n\tstruct value * v = (struct value *)_pbcM_sp_query(m->index,key);\n\tint type = 0;\n\tpbc_var var;\n\tif (v == NULL) {\n\t\ttype = _pbcP_message_default(m->msg, key, var);\n\t} else {\n\t\tif (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {\n\t\t\t_pbcA_index(v->v.array, index, var);\n\t\t} else {\n\t\t\tvar[0] = v->v.var[0];\n\t\t}\n\t\ttype = v->type->type;\n\t}\n\n\tif (type == PTYPE_ENUM) {\n\t\tif (sz) {\n\t\t\t*sz = strlen(var->e.name);\n\t\t}\n\t\treturn var->e.name;\n\t}\n\n\tif (sz) {\n\t\tint len = var->s.len;\n\t\tif (len<0) {\n\t\t\tlen = - len;\n\t\t}\n\t\t*sz = len;\n\t}\n\treturn var->s.str;\n}\n\nuint32_t \npbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) {\n\tstruct value * v = (struct value *)_pbcM_sp_query(m->index,key);\n\tpbc_var var;\n\tint type = 0;\n\tif (v == NULL) {\n\t\ttype = _pbcP_message_default(m->msg, key, var);\n\t} else {\n\t\tif (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {\n\t\t\t_pbcA_index(v->v.array, index, var);\n\t\t} else {\n\t\t\tvar[0] = v->v.var[0];\n\t\t}\n\t\ttype = v->type->type;\n\t}\n\n\tif (type == PTYPE_ENUM) {\n\t\tif (hi) {\n\t\t\t*hi = 0;\n\t\t}\n\t\treturn var->e.id;\n\t}\n\n\tif (hi) {\n\t\t*hi = var->integer.hi;\n\t}\n\treturn var->integer.low;\n}\n\ndouble \npbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) {\n\tstruct value * v = (struct value *)_pbcM_sp_query(m->index,key);\n\tpbc_var var;\n\tif (v == NULL) {\n\t\t_pbcP_message_default(m->msg, key, var);\n\t} else {\n\t\tif (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {\n\t\t\t_pbcA_index(v->v.array, index, var);\n\t\t} else {\n\t\t\treturn v->v.var->real;\n\t\t}\n\t}\n\treturn var->real;\n}\n\n\nstruct pbc_rmessage * \npbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) {\n\tstruct value * v = (struct value *)_pbcM_sp_query(rm->index,key);\n\tif (v == NULL) {\n\t\tstruct _field * f = (struct _field *)_pbcM_sp_query(rm->msg->name, key);\n\t\tif (f == NULL) {\n\t\t\trm->msg->env->lasterror = \"Invalid key for sub-message\";\n\t\t\t// invalid key\n\t\t\treturn NULL;\n\t\t}\n\t\tstruct _message * m = f->type_name.m;\n\n\t\tif (m->def == NULL) {\n\t\t\t// m->def will be free at the end (pbc_delete).\n\t\t\tm->def = (struct pbc_rmessage *)pbc_malloc(sizeof(struct pbc_rmessage));\n\t\t\tm->def->msg = m;\n\t\t\tm->def->index = NULL;\n\t\t}\n\t\treturn m->def;\n\t} else {\n\t\tif (v->type->label == LABEL_REPEATED) {\n\t\t\treturn (struct pbc_rmessage *)_pbcA_index_p(v->v.array,index);\n\t\t} else {\n\t\t\treturn &(v->v.message);\n\t\t}\n\t}\n}\n\nint \npbc_rmessage_size(struct pbc_rmessage *m, const char *key) {\n\tstruct value * v = (struct value *)_pbcM_sp_query(m->index,key);\n\tif (v == NULL) {\n\t\treturn 0;\n\t}\n\tif (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) {\n\t\treturn pbc_array_size(v->v.array);\n\t} else {\n\t\treturn 1;\n\t}\n}"
  },
  {
    "path": "code/EVA/server/server_share/pbc/stringpool.cpp",
    "content": "#include \"alloc.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\n#define PAGE_SIZE 256\n\nstruct _stringpool {\n\tchar * buffer;\n\tsize_t len;\n\tstruct _stringpool *next;\n};\n\nstruct _stringpool * \n_pbcS_new(void) {\n\tstruct _stringpool * ret = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + PAGE_SIZE);\n\tret->buffer = (char *)(ret + 1);\n\tret->len = 0;\n\tret->next = NULL;\n\treturn ret;\n}\n\nvoid \n_pbcS_delete(struct _stringpool *pool) {\n\twhile(pool) {\n\t\tstruct _stringpool *next = pool->next;\n\t\tpbc_free(pool);\n\t\tpool = next;\n\t}\n}\n\nconst char *\n_pbcS_build(struct _stringpool *pool, const char * str , int sz) {\n\tsize_t s = sz + 1;\n\tif (s < PAGE_SIZE - pool->len) {\n\t\tchar * ret = pool->buffer + pool->len;\n\t\tmemcpy(pool->buffer + pool->len, str, s);\n\t\tpool->len += s;\n\t\treturn ret;\n\t}\n\tif (s > PAGE_SIZE) {\n\t\tstruct _stringpool * next = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + s);\n\t\tnext->buffer = (char *)(next + 1);\n\t\tmemcpy(next->buffer, str, s);\n\t\tnext->len = s;\n\t\tnext->next = pool->next;\n\t\tpool->next = next;\n\t\treturn next->buffer;\n\t}\n\tstruct _stringpool *next = (struct _stringpool *)pbc_malloc(sizeof(struct _stringpool) + PAGE_SIZE);\n\tnext->buffer = pool->buffer;\n\tnext->next = pool->next;\n\tnext->len = pool->len;\n\n\tpool->next = next;\n\tpool->buffer = (char *)(next + 1);\n\tmemcpy(pool->buffer, str, s);\n\tpool->len = s;\n\treturn pool->buffer;\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/stringpool.h",
    "content": "#ifndef PROTOBUF_C_STRINGPOOL_H\n#define PROTOBUF_C_STRINGPOOL_H\n\nstruct _stringpool;\n\nstruct _stringpool * _pbcS_new(void);\nvoid _pbcS_delete(struct _stringpool *pool);\nconst char * _pbcS_build(struct _stringpool *pool, const char * str , int sz);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/varint.cpp",
    "content": "#include \"varint.h\"\n\n#include \"pbc.h\"\n\n#include <stdint.h>\n\n//inline int\nint\n_pbcV_encode32(uint32_t number, uint8_t buffer[10])\n{\n\tif (number < 0x80) {\n\t\tbuffer[0] = (uint8_t) number ; \n\t\treturn 1;\n\t}\n\tbuffer[0] = (uint8_t) (number | 0x80 );\n\tif (number < 0x4000) {\n\t\tbuffer[1] = (uint8_t) (number >> 7 );\n\t\treturn 2;\n\t}\n\tbuffer[1] = (uint8_t) ((number >> 7) | 0x80 );\n\tif (number < 0x200000) {\n\t\tbuffer[2] = (uint8_t) (number >> 14);\n\t\treturn 3;\n\t}\n\tbuffer[2] = (uint8_t) ((number >> 14) | 0x80 );\n\tif (number < 0x10000000) {\n\t\tbuffer[3] = (uint8_t) (number >> 21);\n\t\treturn 4;\n\t}\n\tbuffer[3] = (uint8_t) ((number >> 21) | 0x80 );\n\tbuffer[4] = (uint8_t) (number >> 28);\n\treturn 5;\n}\n\nint\n_pbcV_encode(uint64_t number, uint8_t buffer[10]) \n{\n\tif ((number & 0xffffffff) == number) {\n\t\treturn _pbcV_encode32((uint32_t)number , buffer);\n\t}\n\tint i = 0;\n\tdo {\n\t\tbuffer[i] = (uint8_t)(number | 0x80);\n\t\tnumber >>= 7;\n\t\t++i;\n\t} while (number >= 0x80);\n\tbuffer[i] = (uint8_t)number;\n\treturn i+1;\n}\n\nint\n_pbcV_decode(uint8_t buffer[10], struct longlong *result) {\n\tif (!(buffer[0] & 0x80)) {\n\t\tresult->low = buffer[0];\n\t\tresult->hi = 0;\n\t\treturn 1;\n\t}\n\tuint32_t r = buffer[0] & 0x7f;\n\tint i;\n\tfor (i=1;i<4;i++) {\n\t\tr |= ((buffer[i]&0x7f) << (7*i));\n\t\tif (!(buffer[i] & 0x80)) {\n\t\t\tresult->low = r;\n\t\t\tresult->hi = 0;\n\t\t\treturn i+1;\n\t\t}\n\t}\n\tuint64_t lr = 0;\n\tfor (i=4;i<10;i++) {\n\t\tlr |= ((uint64_t)(buffer[i] & 0x7f) << (7*(i-4)));\n\t\tif (!(buffer[i] & 0x80)) {\n\t\t\tresult->hi = (uint32_t)(lr >> 4);\n\t\t\tresult->low = r | (((uint32_t)lr & 0xf) << 28);\n\t\t\treturn i+1;\n\t\t}\n\t}\n\n\tresult->low = 0;\n\tresult->hi = 0;\n\treturn 10;\n}\n\nint \n_pbcV_zigzag32(int32_t n, uint8_t buffer[10])\n{\n\tn = (n << 1) ^ (n >> 31);\n\treturn _pbcV_encode32(n,buffer);\n}\n\nint \n_pbcV_zigzag(int64_t n, uint8_t buffer[10])\n{\n\tn = (n << 1) ^ (n >> 63);\n\treturn _pbcV_encode(n,buffer);\n}\n\nvoid\n_pbcV_dezigzag64(struct longlong *r)\n{\n\tuint32_t low = r->low;\n\tr->low = ((low >> 1) | ((r->hi & 1) << 31)) ^ - (low & 1);\n\tr->hi = (r->hi >> 1) ^ - (low & 1);\n}\n\nvoid\n_pbcV_dezigzag32(struct longlong *r)\n{\n\tuint32_t low = r->low;\n\tr->low = (low >> 1) ^ - (low & 1);\n\tr->hi = -(low >> 31);\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/varint.h",
    "content": "#ifndef PROTOBUF_C_VARINT_H\n#define PROTOBUF_C_VARINT_H\n\n#include <stdint.h>\n\nstruct longlong {\n\tuint32_t low;\n\tuint32_t hi;\n};\n\nint _pbcV_encode32(uint32_t number, uint8_t buffer[10]);\nint _pbcV_encode(uint64_t number, uint8_t buffer[10]);\nint _pbcV_zigzag32(int32_t number, uint8_t buffer[10]);\nint _pbcV_zigzag(int64_t number, uint8_t buffer[10]);\n\nint _pbcV_decode(uint8_t buffer[10], struct longlong *result);\nvoid _pbcV_dezigzag64(struct longlong *r);\nvoid _pbcV_dezigzag32(struct longlong *r);\n\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/pbc/wmessage.cpp",
    "content": "#include \"pbc.h\"\n#include \"context.h\"\n#include \"alloc.h\"\n#include \"varint.h\"\n#include \"map.h\"\n#include \"proto.h\"\n\n#include <stdint.h>\n#include <string.h>\n#include <assert.h>\n\n#ifndef _MSC_VER\n#include <stdbool.h>\n#endif\n\n#define WMESSAGE_SIZE 64\n\nstruct pbc_wmessage {\n\tstruct _message *type;\n\tuint8_t * buffer;\n\tuint8_t * ptr;\n\tuint8_t * endptr;\n\tpbc_array sub;\n\tstruct map_sp *packed;\n\tstruct heap * heap;\n};\n\nstruct _packed {\n\tint id;\n\tint ptype;\n\tpbc_array data;\n};\n\nstatic struct pbc_wmessage *\n_wmessage_new(struct heap *h, struct _message *msg) {\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)_pbcH_alloc(h, sizeof(*m));\n\tm->type = msg;\n\tm->buffer = (uint8_t *)_pbcH_alloc(h, WMESSAGE_SIZE);\n\tm->ptr = m->buffer;\n\tm->endptr = m->buffer + WMESSAGE_SIZE;\n\t_pbcA_open_heap(m->sub, h);\n\tm->packed = NULL;\n\tm->heap = h;\n\n\treturn m;\n}\n\nstruct pbc_wmessage * \npbc_wmessage_new(struct pbc_env * env, const char *type_name) {\n\tstruct _message * msg = _pbcP_get_message(env, type_name);\n\tif (msg == NULL)\n\t\treturn NULL;\n\tstruct heap *h = _pbcH_new(0);\n\treturn _wmessage_new(h, msg);\n}\n\nvoid \npbc_wmessage_delete(struct pbc_wmessage *m) {\n\tif (m) {\n\t\t_pbcH_delete(m->heap);\n\t}\n}\n\nstatic void\n_expand_message(struct pbc_wmessage *m, int sz) {\n\tif (m->ptr + sz > m->endptr) {\n\t\tint cap = m->endptr - m->buffer;\n\t\tsz = m->ptr + sz - m->buffer;\n\t\tdo {\n\t\t\tcap = cap * 2;\n\t\t} while ( sz > cap ) ;\n\t\tint old_size = m->ptr - m->buffer;\n\t\tuint8_t * buffer = (uint8_t *)_pbcH_alloc(m->heap, cap);\n\t\tmemcpy(buffer, m->buffer, old_size);\n\t\tm->ptr = buffer + (m->ptr - m->buffer);\n\t\tm->endptr = buffer + cap;\n\t\tm->buffer = buffer;\n\t}\n}\n\nstatic struct _packed *\n_get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) {\n\tif (m->packed == NULL) {\n\t\tm->packed = _pbcM_sp_new(4, m->heap);\n\t}\n\tvoid ** v = _pbcM_sp_query_insert(m->packed , key);\n\tif (*v == NULL) {\n\t\t*v = _pbcH_alloc(m->heap, sizeof(struct _packed));\n\t\tstruct _packed *p = (struct _packed *)*v;\n\t\tp->id = f->id;\n\t\tp->ptype = f->type;\n\t\t_pbcA_open_heap(p->data, m->heap);\n\t\treturn p;\n\t}\n\treturn (struct _packed *)*v;\n}\n\nstatic void\n_packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) {\n\tstruct _packed * packed = _get_packed(m,f,key);\n\tpbc_var var;\n\tvar->integer.low = low;\n\tvar->integer.hi = hi;\n\t_pbcA_push(packed->data , var);\n}\n\nstatic void\n_packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) {\n\tstruct _packed * packed = _get_packed(m,f,key);\n\tpbc_var var;\n\tvar->real = v;\n\t_pbcA_push(packed->data , var);\n}\n\nstatic inline void\nint64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) {\n\tbuffer[0] = (uint8_t)(low & 0xff);\n\tbuffer[1] = (uint8_t)(low >> 8 & 0xff);\n\tbuffer[2] = (uint8_t)(low >> 16 & 0xff);\n\tbuffer[3] = (uint8_t)(low >> 24 & 0xff);\n\tbuffer[4] = (uint8_t)(hi & 0xff);\n\tbuffer[5] = (uint8_t)(hi >> 8 & 0xff);\n\tbuffer[6] = (uint8_t)(hi >> 16 & 0xff);\n\tbuffer[7] = (uint8_t)(hi >> 24 & 0xff);\n}\n\nstatic inline void\nint32_encode(uint32_t low, uint8_t * buffer) {\n\tbuffer[0] = (uint8_t)(low & 0xff);\n\tbuffer[1] = (uint8_t)(low >> 8 & 0xff);\n\tbuffer[2] = (uint8_t)(low >> 16 & 0xff);\n\tbuffer[3] = (uint8_t)(low >> 24 & 0xff);\n}\n\nint \npbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) {\n\tstruct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key);\n\tif (f==NULL) {\n\t\t// todo : error\n\t\tm->type->env->lasterror = \"wmessage_interger query key error\";\n\t\treturn -1;\n\t}\n\tif (f->label == LABEL_PACKED) {\n\t\t_packed_integer(m , f, key , low, hi);\n\t\treturn 0;\t\t\n\t}\n\tif (f->label == LABEL_OPTIONAL) {\n\t\tif (f->type == PTYPE_ENUM) {\n\t\t\tif (low == f->default_v->e.id)\n\t\t\t\treturn 0;\n\t\t} else {\n\t\t\tif (low == f->default_v->integer.low &&\n\t\t\t\thi == f->default_v->integer.hi) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\tint id = f->id << 3;\n\n\t_expand_message(m,20);\n\tswitch (f->type) {\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64: \n\tcase PTYPE_INT32:\n\t\tid |= WT_VARINT;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr);\n\t\tbreak;\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\n\tcase PTYPE_BOOL:\n\t\tid |= WT_VARINT;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_encode32(low, m->ptr);\n\t\tbreak;\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\tid |= WT_BIT64;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tint64_encode(low,hi,m->ptr);\n\t\tm->ptr += 8;\n\t\tbreak;\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\tid |= WT_BIT32;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tint32_encode(low,m->ptr);\n\t\tm->ptr += 4;\n\t\tbreak;\n\tcase PTYPE_SINT32:\n\t\tid |= WT_VARINT;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_zigzag32(low, m->ptr);\n\t\tbreak;\n\tcase PTYPE_SINT64:\n\t\tid |= WT_VARINT;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr);\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nint\npbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) {\n\tstruct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key);\n\tif (f == NULL) {\n\t\t// todo : error\n\t\tm->type->env->lasterror = \"wmessage_real query key error\";\n\t\treturn -1;\n\t}\n\tif (f->label == LABEL_PACKED) {\n\t\t_packed_real(m , f, key , v);\n\t\treturn 0;\t\t\n\t}\n\n\tif (f->label == LABEL_OPTIONAL) {\n\t\tif (v == f->default_v->real)\n\t\t\treturn 0;\n\t}\n\tint id = f->id << 3;\n\t_expand_message(m,18);\n\tswitch (f->type) {\n\tcase PTYPE_FLOAT: {\n\t\tid |= WT_BIT32;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tfloat_encode(v , m->ptr);\n\t\tm->ptr += 4;\n\t\tbreak;\n\t}\n\tcase PTYPE_DOUBLE:\n\t\tid |= WT_BIT64;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tdouble_encode(v , m->ptr);\n\t\tm->ptr += 8;\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nint\npbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) {\n\tstruct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key);\n\tif (f == NULL) {\n\t\t// todo : error\n\t\tm->type->env->lasterror = \"wmessage_string query key error\";\n\t\treturn -1;\n\t}\n\n\tbool varlen = false;\n\n\tif (len <=0) {\n\t\tvarlen = true;\n\t\t// -1 for add '\\0'\n\t\tlen = strlen(v) - len;\n\t}\n\tif (f->label == LABEL_PACKED) {\n\t\tif (f->type == PTYPE_ENUM) {\n\t\t\tchar * temp = (char *)alloca(len + 1);\n\t\t\tif (!varlen || v[len] != '\\0') {\n\t\t\t\tmemcpy(temp,v,len);\n\t\t\t\ttemp[len]='\\0';\n\t\t\t\tv = temp;\n\t\t\t}\n\t\t\tint enum_id = 0;\n\t\t\tint err = _pbcM_si_query(f->type_name.e->name, v , &enum_id);\n\t\t\tif (err) {\n\t\t\t\t// todo : error , invalid enum\n\t\t\t\tm->type->env->lasterror = \"wmessage_string packed invalid enum\";\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t_packed_integer(m , f, key , enum_id , 0);\n\t\t}\n\t\treturn 0;\t\n\t}\n\n\tif (f->label == LABEL_OPTIONAL) {\n\t\tif (f->type == PTYPE_ENUM) {\n\t\t\tif (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\\0') {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t} else if (f->type == PTYPE_STRING) {\n\t\t\tif (len == f->default_v->s.len &&\n\t\t\t\tstrcmp(v, f->default_v->s.str) == 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t} else if (f->type == PTYPE_BYTES) {\n\t\t\tif (len == 0) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\tint id = f->id << 3;\n\t_expand_message(m,20);\n\tswitch (f->type) {\n\tcase PTYPE_ENUM : {\n\t\tchar * temp = (char *)alloca(len+1);\n\t\tif (!varlen || v[len] != '\\0') {\n\t\t\tmemcpy(temp,v,len);\n\t\t\ttemp[len]='\\0';\n\t\t\tv = temp;\n\t\t}\n\t\tint enum_id = 0;\n\t\tint err = _pbcM_si_query(f->type_name.e->name, v, &enum_id);\n\t\tif (err) {\n\t\t\t// todo : error , enum invalid\n\t\t\tm->type->env->lasterror = \"wmessage_string invalid enum\";\n\t\t\treturn -1;\n\t\t}\n\t\tid |= WT_VARINT;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_encode32(enum_id, m->ptr);\n\t\tbreak;\n\t}\n\tcase PTYPE_STRING:\n\tcase PTYPE_BYTES:\n\t\tid |= WT_LEND;\n\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\tm->ptr += _pbcV_encode32(len, m->ptr);\n\t\t_expand_message(m,len);\n\t\tmemcpy(m->ptr , v , len);\n\t\tm->ptr += len;\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstruct pbc_wmessage * \npbc_wmessage_message(struct pbc_wmessage *m, const char *key) {\n\tstruct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key);\n\tif (f == NULL) {\n\t\t// todo : error\n\t\tm->type->env->lasterror = \"wmessage_message query key error\";\n\t\treturn NULL;\n\t}\n\tpbc_var var;\n\tvar->p[0] = _wmessage_new(m->heap, f->type_name.m);\n\tvar->p[1] = f;\n\t_pbcA_push(m->sub , var);\n\treturn (struct pbc_wmessage *)var->p[0];\n}\n\nstatic void\n_pack_packed_64(struct _packed *p,struct pbc_wmessage *m) {\n\tint n = pbc_array_size(p->data);\n\tint len = n * 8;\n\tint i;\n\tpbc_var var;\n\t_expand_message(m,10 + len);\n\tm->ptr += _pbcV_encode32(len, m->ptr);\n\tswitch (p->ptype) {\n\tcase PTYPE_DOUBLE:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\tdouble_encode(var->real , m->ptr + i * 8);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\tint64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8);\n\t\t}\n\t\tbreak;\n\t}\n\tm->ptr += len;\n}\n\nstatic void\n_pack_packed_32(struct _packed *p,struct pbc_wmessage *m) {\n\tint n = pbc_array_size(p->data);\n\tint len = n * 4;\n\tint i;\n\tpbc_var var;\n\t_expand_message(m,10 + len);\n\tm->ptr += _pbcV_encode32(len, m->ptr);\n\tswitch (p->ptype) {\n\tcase PTYPE_FLOAT:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\tfloat_encode(var->real , m->ptr + i * 8);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\tint32_encode(var->integer.low , m->ptr + i * 8);\n\t\t}\n\t\tbreak;\n\t}\n\tm->ptr += len;\n}\n\nstatic void\n_pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) {\n\tint n = pbc_array_size(p->data);\n\n\tint offset = m->ptr - m->buffer;\n\tint len = n * 2;\n\tif (p->ptype == PTYPE_BOOL) {\n\t\tlen = n;\n\t}\n\tint i;\n\tpbc_var var;\n\t_expand_message(m,10 + len);\n\tint len_len = _pbcV_encode32(len, m->ptr);\n\tm->ptr += len_len;\n\n\tswitch (p->ptype) {\n\tcase PTYPE_INT64:\n\tcase PTYPE_UINT64:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\t_expand_message(m,10);\n\t\t\tm->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr);\n\t\t}\n\t\tbreak;\n\tcase PTYPE_INT32:\n\tcase PTYPE_BOOL:\n\tcase PTYPE_UINT32:\n\tcase PTYPE_ENUM:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\t_expand_message(m,10);\n\t\t\tm->ptr += _pbcV_encode32(var->integer.low , m->ptr);\n\t\t}\n\t\tbreak;\n\tcase PTYPE_SINT32:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\t_expand_message(m,10);\n\t\t\tm->ptr += _pbcV_zigzag32(var->integer.low, m->ptr);\n\t\t}\n\t\tbreak;\n\tcase PTYPE_SINT64:\n\t\tfor (i=0;i<n;i++) {\n\t\t\t_pbcA_index(p->data, i, var);\n\t\t\t_expand_message(m,10);\n\t\t\tm->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr);\n\t\t}\n\t\tbreak;\n\tdefault:\n\t\t// error\n\t\tmemset(m->ptr , 0 , n);\n\t\tm->ptr += n;\n\t\tm->type->env->lasterror = \"wmessage type error when pack packed\";\n\t\tbreak;\n\t}\n\tint end_offset = m->ptr - m->buffer;\n\tint end_len = end_offset - (offset + len_len);\n\tif (end_len != len) {\n\t\tuint8_t temp[10];\n\t\tint end_len_len = _pbcV_encode32(end_len, temp);\n\t\tif (end_len_len != len_len) {\n\t\t\t_expand_message(m, end_len_len);\n\t\t\tmemmove(m->buffer + offset + end_len_len , \n\t\t\t\tm->buffer + offset + len_len , \n\t\t\t\tend_len);\n\t\t\tm->ptr +=  end_len_len - len_len;\n\t\t}\n\t\tmemcpy(m->buffer + offset , temp, end_len_len);\n\t}\n}\n\nstatic void\n_pack_packed(void *p, void *ud) {\n\tstruct _packed *packed = (struct _packed *)p;\n\tstruct pbc_wmessage * m = (struct pbc_wmessage *)ud;\n\tint id = packed->id << 3 | WT_LEND;\n\t_expand_message(m,10);\n\tm->ptr += _pbcV_encode32(id, m->ptr);\n\tswitch(packed->ptype) {\n\tcase PTYPE_DOUBLE:\n\tcase PTYPE_FIXED64:\n\tcase PTYPE_SFIXED64:\n\t\t_pack_packed_64(packed,m);\n\t\tbreak;\n\tcase PTYPE_FLOAT:\n\tcase PTYPE_FIXED32:\n\tcase PTYPE_SFIXED32:\n\t\t_pack_packed_32(packed,m);\n\t\tbreak;\n\tdefault:\n\t\t_pack_packed_varint(packed,m);\n\t\tbreak;\n\t}\n}\n\nvoid * \npbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) {\n\tif (m->packed) {\n\t\t_pbcM_sp_foreach_ud(m->packed , _pack_packed, m);\n\t}\n\tint i;\n\tint n = pbc_array_size(m->sub);\n\tfor (i=0;i<n;i++) {\n\t\tpbc_var var;\n\t\t_pbcA_index(m->sub, i , var);\n\t\tstruct pbc_slice s;\n\t\tpbc_wmessage_buffer((struct pbc_wmessage *)var->p[0] , &s);\n\t\tif (s.buffer) {\n\t\t\tstruct _field * f = (struct _field *)var->p[1];\n\t\t\tint id = f->id << 3 | WT_LEND;\n\t\t\t_expand_message(m,20+s.len);\n\t\t\tm->ptr += _pbcV_encode32(id, m->ptr);\n\t\t\tm->ptr += _pbcV_encode32(s.len, m->ptr);\n\t\t\tmemcpy(m->ptr, s.buffer, s.len);\n\t\t\tm->ptr += s.len;\n\t\t}\n\t}\n\tslice->buffer = m->buffer;\n\tslice->len = m->ptr - m->buffer;\n\n\treturn m->buffer;\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/ranking_change_near.h",
    "content": "﻿#ifndef GAME_SHARE_RANKING_CHANGE_NEAR_H\n#define GAME_SHARE_RANKING_CHANGE_NEAR_H\n\n#include <vector>\n#include <map>\n#include \"game_def.h\"\n\n/** 排名管理器\n *\t使用PID作为索引，SCORE作为排名依据，获取排名。\n *  每次SetScore() 分数或排名变动跨越的人数小于100时适用。\n *\n * \\author li9chuan\n * \\date 2013-1-14\n */\n\nclass CRankingChangeNear\n{\npublic:\n\tCRankingChangeNear ()\n\t{\n\t\t_vctScore.reserve(1024*128);\n\t\t_vctScore.resize(1);\t//\t占用第0位，排名从1开始\n\t}\n\t~CRankingChangeNear (){}\n\n\t/**\n\t*   设置玩家积分\n\t*\n\t*\t\\param  nID\n\t*\t\\param  nScore\n\t*\t\\return 排名从1开始，0表示异常\n\t*/\n\tDEF::RANKING SetScore( const DEF::PID nID, const DEF::SCORE nScore )\n\t{\n\t\tDEF::RANKING nRankingNew = GetIDRanking(nID);\n\n\t\tif ( nRankingNew == 0 )\n\t\t{\n\t\t\tDEF::RANKING nRanking = _addRankingBack( nID, nScore );\n\t\t\tnRankingNew = _upRanking( nRanking, nScore );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnRankingNew = _adjustRanking( nRankingNew, nScore );\n\t\t}\n\n\t\treturn nRankingNew;\n\t}\n\n\t/**\n\t*   获取排名\n\t*\n\t*\t\\param  nID\n\t*\t\\return 排名从1开始，0表示没有找到此ID\n\t*/\n\tDEF::RANKING GetRanking( const DEF::PID nID )\n\t{\n\t\treturn GetIDRanking(nID);\n\t}\n\n\tunsigned int GetMaxRow()\n\t{\n\t\treturn _vctScore.size();\n\t}\n\n\tuint32 GetPage( const DEF::PID nID, const uint32 nPageRow )\n\t{\n\t\tuint32 page = 0;\n\t\tDEF::RANKING ranking = GetRanking( nID );\n\t\tif ( ranking != 0 && nPageRow != 0 )\n\t\t{\n\t\t\tpage = ranking / nPageRow;\n\t\t\tif ( ranking % nPageRow != 0 )\n\t\t\t{\n\t\t\t\t++page;\n\t\t\t}\n\t\t}\n\t\treturn page;\n\t}\n\n\t/// 获得分页\n\tbool GetPage( const uint32 nPage, const uint32 nPageRow, std::vector<DEF::PID>& vct )\n\t{\n\t\tvct.clear();\n\t\tif ( nPage == 0 )\t{\treturn false;\t}\n\n\t\tuint32 pageStartIdx = (nPage-1)*nPageRow+1;\n\t\tuint32 pageEndIdx   = pageStartIdx + nPageRow;\n\n\t\tif ( pageEndIdx > _vctScore.size() )\n\t\t{\n\t\t\tpageEndIdx = (uint32)_vctScore.size();\n\t\t}\n\n\t\tif ( pageEndIdx >= pageStartIdx )\n\t\t{\n\t\t\tuint32 count = pageEndIdx-pageStartIdx;\n\n\t\t\tif ( count > 100 )\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tfor ( pageStartIdx; pageStartIdx<pageEndIdx; ++pageStartIdx )\n\t\t\t{\n\t\t\t\tvct.push_back(_vctScore[pageStartIdx].nID);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n    struct SPlayerInfo\n    {\n        DEF::SCORE      nScore;\n        DEF::PID        nID;\n    };\n\n    std::vector<SPlayerInfo>& GetRankingInfo()\n    {\n        return _vctScore;\n    }\n\nprivate:\n\n\t/**\n\t*   调整排名\n\t*       中间会改变多个玩家的名次。\n\t*\n\t*\t\\param  nRanking  调整前，玩家的排名\n\t*   \\param  nScore    玩家的分数\n\t*\t\\return 调整后，玩家的排名\n\t*/\n\tDEF::RANKING _adjustRanking( const DEF::RANKING nRanking, const DEF::SCORE nScore )\n\t{\n\t\tDEF::RANKING nNewRanking = nRanking;\n\n\t\tif ( nScore > _vctScore[nRanking].nScore )\t\t//\t如果积分增加了\n\t\t{\n\t\t\tnNewRanking = _upRanking( nRanking, nScore );\n\t\t} \n\t\telse if( nScore < _vctScore[nRanking].nScore )\t//\t如果积分降低了\n\t\t{\n\t\t\tnNewRanking = _downRanking( nRanking, nScore );\n\t\t}\n\n\t\treturn nNewRanking;\n\t}\n\n\t/**\n\t*   增加一条新的排名积分记录\n\t*       直接增加到尾部，最后一名。\n\t*\n\t*   \\param  nScore    玩家的分数\n\t*\t\\return 加入后，玩家的排名\n\t*/\n\tDEF::RANKING _addRankingBack( const DEF::PID nID, const DEF::SCORE nScore )\n\t{\n\t\tSPlayerInfo PlayerInfo;\n\t\tPlayerInfo.nScore   = nScore;\n\t\tPlayerInfo.nID      = nID;\n\n\t\t_vctScore.push_back(PlayerInfo);\n        return SetIDRanking( nID, _vctScore.size()-1 );\n\t}\n\n\tvoid _updateMapRanking( const DEF::RANKING nRanking )\n\t{\n        SetIDRanking( _vctScore[nRanking].nID, nRanking );\n\t}\n\n\tDEF::RANKING _upRanking( const DEF::RANKING nOldRanking, const DEF::SCORE nScore )\n\t{\n\t\tDEF::RANKING nNewRanking = nOldRanking;\n\n\t\t/// 缓存\n\t\tSPlayerInfo PlayerInfo;\n\t\tPlayerInfo.nID = _vctScore[nOldRanking].nID;\n\t\tPlayerInfo.nScore = nScore;\n\n\t\t/// 排名上移\n\t\tfor ( nNewRanking; nNewRanking>1; --nNewRanking )\n\t\t{\n\t\t\tif (_vctScore[nNewRanking-1].nScore<nScore )\n\t\t\t{\n\t\t\t\t_vctScore[nNewRanking] = _vctScore[nNewRanking-1];\n\t\t\t\t_updateMapRanking(nNewRanking);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_vctScore[nNewRanking] = PlayerInfo;\n\t\t\t\t_updateMapRanking(nNewRanking);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( nNewRanking == 1 )\n\t\t{\n\t\t\t_vctScore[nNewRanking] = PlayerInfo;\n\t\t\t_updateMapRanking(nNewRanking);\n\t\t}\n\n\t\treturn nNewRanking;\n\t}\n\n\tDEF::RANKING _downRanking( const DEF::RANKING nOldRanking, const DEF::SCORE nScore )\n\t{\n\t\tDEF::RANKING nNewRanking = nOldRanking;\n\n\t\t/// 缓存\n\t\tSPlayerInfo PlayerInfo;\n\t\tPlayerInfo.nID = _vctScore[nOldRanking].nID;\n\t\tPlayerInfo.nScore = nScore;\n\n\t\t/// 排名下移\n\t\tfor ( nNewRanking; nNewRanking<DEF::RANKING(_vctScore.size()-1); ++nNewRanking )\n\t\t{\n\t\t\tif (_vctScore[nNewRanking+1].nScore>nScore )\n\t\t\t{\n\t\t\t\t_vctScore[nNewRanking] = _vctScore[nNewRanking+1];\n\t\t\t\t_updateMapRanking(nNewRanking);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_vctScore[nNewRanking] = PlayerInfo;\n\t\t\t\t_updateMapRanking(nNewRanking);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif ( nNewRanking == _vctScore.size()-1 )\n\t\t{\n\t\t\t_vctScore[nNewRanking] = PlayerInfo;\n\t\t\t_updateMapRanking(nNewRanking);\n\t\t}\n\n\t\treturn nNewRanking;\n\t}\n\nprivate:\n\n    struct HashPIDRnk\n    {\n        DEF::PID        pid;\n        DEF::RANKING    ranking;\n\n        HashPIDRnk():pid(0)\n        { }\n    };\n\n\n\n    std::vector<SPlayerInfo>            _vctScore;\n\n    enum  _THashEnum\n    {\n        HashDepthMask = 0x1,\n        HashDepth     = HashDepthMask+1,\n\n        HashSpaceMask = 0xFFFFF,            //  100W\n        HashSpaceMax  = HashSpaceMask+1,\n    };\n\n    HashPIDRnk   _HashIDRanking[HashSpaceMax];                      ///  一级哈希空间\n\n    typedef std::map<DEF::PID, DEF::RANKING>     TIDRanking;\n    TIDRanking                              _HashRankingSecond;     ///  二级哈希空间\n\n    ///  return hash idx\n    inline uint HashFunctionPID( DEF::PID pid )\n    {\n        //return (pid>>10) & HashSpaceMask;\n        return (pid) & HashSpaceMask;\n    }\n\n    DEF::RANKING SetIDRanking( DEF::PID pid, DEF::RANKING ranking )\n    {\n        uint idx = HashFunctionPID(pid);\n\n        if ( _HashIDRanking[idx].pid==pid )\n        {\n            _HashIDRanking[idx].ranking = ranking;\n        }\n        else if ( _HashIDRanking[idx].pid==0 )\n        {\n            _HashIDRanking[idx].pid     = pid;\n            _HashIDRanking[idx].ranking = ranking;\n        }\n        else\n        {\n            TIDRanking::iterator iter = _HashRankingSecond.find(pid);\n\n            if ( iter!=_HashRankingSecond.end() )\n            {\n                iter->second = ranking;\n            }\n            else\n            {\n                _HashRankingSecond.insert( std::make_pair(pid, ranking) );\n            }\n        }\n\n        return ranking;\n    }\n\n    DEF::RANKING GetIDRanking( DEF::PID pid )\n    {\n        DEF::RANKING ranking = 0;\n        uint idx = HashFunctionPID(pid);\n\n        if ( _HashIDRanking[idx].pid==pid )\n        {\n            ranking = _HashIDRanking[idx].ranking;\n        }\n        else if ( _HashIDRanking[idx].pid==0 )\n        {\n        }\n        else\n        {\n            TIDRanking::iterator iter = _HashRankingSecond.find(pid);\n\n            if ( iter!=_HashRankingSecond.end() )\n            {\n                ranking = iter->second;\n            }\n        }\n\n        return ranking;\n    }\n};\n\n\n#endif // GAME_SHARE_RANKING_CHANGE_NEAR_H\n\n/* End of ranking_change_near.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/ranking_slot.h",
    "content": "﻿#ifndef GAME_SHARD_RANKING_SLOT_H\n#define GAME_SHARD_RANKING_SLOT_H\n\n#include <vector>\n#include <map>\n#include <set>\n#include <nel/misc/time_nl.h>\n#include \"game_def.h\"\n\n/** 排名槽管理器\n *\t使用PID作为索引，SCORE作为排名依据，获取排名。\n *  按积分槽排名。\n *  分数槽小于1W时效率较高:         UpdateRanking<2ms 。\n *  分数槽小于10W时(Release):      UpdateRanking<10ms 。\n *\n * \\author li9chuan\n * \\date 2015-1\n */\n\nclass CRankingSlot\n{\npublic:\n\n    typedef  std::set<DEF::PID>     _TPIDs;\n    typedef  std::vector<DEF::PID>  _TVctPIDs;\n\n    struct _Ranking\n    {\n        DEF::RANKING        Ranking;\n        _TPIDs              PIDs;\n\n        _Ranking():Ranking(0){}\n    };\n    typedef  std::map<DEF::PID, DEF::SCORE>     TMapScore;\n    typedef  std::map<DEF::SCORE, _Ranking>     TMapRanking;\n\n    CRankingSlot():_UpdateSeconds(0),_PreUpdateSecond1970(0),_FastSortMax(0){}\n\n\t/**\n\t*   初始化排行处理逻辑\n\t*\n\t*\t\\param  update_seconds  调用 UpdateRanking() 的最小间隔时间。\n\t*\t\\param  fast_sort_num   SetScore时，在fast_sort_num前的排名会即时更新。\n\t*/ \n    void InitRanking( uint32 update_seconds, uint32 fast_sort_num )\n    {\n        _UpdateSeconds  = update_seconds;\n        _FastSortMax    = fast_sort_num;\n    }\n\n\t/**\n\t*   设置玩家积分\n\t*\n\t*\t\\param  nID\n\t*\t\\param  nScore\n\t*/\n\tvoid SetScore( const DEF::PID pid, const DEF::SCORE score )\n\t{\n        DEF::RANKING nRankingNew = 0;\n\n        ///  移除玩家旧排名\n        TMapScore::iterator itscr = _MapScore.find( pid );\n\n        if ( itscr!=_MapScore.end() )\n        {\n            DEF::SCORE old_score = itscr->second;\n\n            if ( old_score==score )\n            {\n                return;\n            }\n\n            TMapRanking::iterator itrnk = _MapRanking.find( old_score );\n\n            if ( itrnk!=_MapRanking.end() )\n            {\n                itrnk->second.PIDs.erase(pid);\n\n                if ( itrnk->second.PIDs.empty() )\n                {\n                    _MapRanking.erase(itrnk);\n                }\n            }\n\n\t\t\titscr->second = score;\n        }\n        else\n        {\n            _MapScore.insert( std::make_pair(pid,score) );\n        }\n\n\n        /// 插入玩家新排名\n        TMapRanking::iterator itrnk = _MapRanking.find( score );\n\n        if ( itrnk!=_MapRanking.end() )\n        {\n            /// 如果已存在积分排名，插入对应积分槽内。\n            itrnk->second.PIDs.insert( pid );\n            nRankingNew = itrnk->second.Ranking;\n        }\n        else\n        {\n            /// 如果没有输入的积分，新插入一条\n            _Ranking  Rnk;\n            Rnk.PIDs.insert(pid);\n\n            std::pair<TMapRanking::iterator,bool> ret =  _MapRanking.insert( std::make_pair( score, Rnk ) );\n\t\t\t\n            if ( ret.first != _MapRanking.begin() )\n            {\n                TMapRanking::iterator it_cur = ret.first;\n                TMapRanking::iterator it_pre = --ret.first;\n\n                nRankingNew = it_pre->second.Ranking + it_pre->second.PIDs.size();\n                it_cur->second.Ranking = nRankingNew;\n            }\n            else\n            {\n                nRankingNew = 1;\n                ret.first->second.Ranking = nRankingNew;\n            }\n        }\n\n        ///    如果是前几名，那么即时排，不等update\n\n        if ( nRankingNew <= _FastSortMax )\n        {\n            _TopRnkPIDs.clear();\n\n            uint  rnk_idx = 0;\n            TMapRanking::reverse_iterator itrnk       = _MapRanking.rbegin();\n            TMapRanking::reverse_iterator itrnk_end   = _MapRanking.rend();\n\n            if ( itrnk!=itrnk_end )\n            {\n                itrnk->second.Ranking = 1;\n\n                _TPIDs::iterator  itpids     = itrnk->second.PIDs.begin();\n                _TPIDs::iterator  itpids_end = itrnk->second.PIDs.end();\n\n                while ( itpids!=itpids_end )\n                {\n                    _TopRnkPIDs.push_back( *itpids );\n\n                    ++rnk_idx;\n                    ++itpids;\n\n                    if ( rnk_idx>_FastSortMax )\n                    {\n                        return;\n                    }\n                }\n\n                ++itrnk;\n            }\n\n            while ( itrnk!=itrnk_end )\n            {\n                TMapRanking::reverse_iterator it_pre = itrnk;\n                --it_pre;\n                itrnk->second.Ranking = it_pre->second.Ranking + it_pre->second.PIDs.size();\n\n                _TPIDs::iterator  itpids     = itrnk->second.PIDs.begin();\n                _TPIDs::iterator  itpids_end = itrnk->second.PIDs.end();\n\n                while ( itpids!=itpids_end )\n                {\n                    _TopRnkPIDs.push_back( *itpids );\n\n                    ++rnk_idx;\n                    ++itpids;\n\n                    if ( rnk_idx>_FastSortMax )\n                    {\n                        return;\n                    }\n                }\n\n                ++itrnk;\n            }\n        }\n\t}\n\n\t/**\n\t*   获取排名\n\t*\n\t*\t\\param  nID\n\t*\t\\return 排名从1开始，0表示没有找到此ID\n\t*/\n\tDEF::RANKING GetRanking( const DEF::SCORE score )\n\t{\n        DEF::RANKING  rnk = 0;\n        TMapRanking::iterator iter = _MapRanking.find(score);\n\n        if ( iter!=_MapRanking.end() )\n        {\n            rnk = iter->second.Ranking;\n        }\n\n\t\treturn rnk;\n\t}\n\n    void UpdateRanking( )\n    {\n        uint32 curr_seconds = NLMISC::CTime::getSecondsSince1970();\n\n        if ( curr_seconds - _PreUpdateSecond1970 < _UpdateSeconds )\n        {\n            return;\n        }\n\n        _PreUpdateSecond1970 = curr_seconds;\n        _ResortRanking();\n    }\n\n    DEF::SCORE GetScore( DEF::PID unRoleID )\n    {\n        std::map<DEF::PID, DEF::SCORE> ::iterator it = _MapScore.find( unRoleID );\n        if ( it == _MapScore.end() ) {\n            return 0;\n        }\n\n        return it->second;\n    }\n\n    std::vector<DEF::PID>&  GetTopRanking()\n    {\n        return _TopRnkPIDs;\n    }\n\nprivate:\n\n    void    _ResortRanking()\n    {\n        TMapRanking::reverse_iterator itrnk       = _MapRanking.rbegin();\n        TMapRanking::reverse_iterator itrnk_end   = _MapRanking.rend();\n\n        if ( itrnk!=itrnk_end )\n        {\n            itrnk->second.Ranking = 1;\n            ++itrnk;\n        }\n\n        while ( itrnk!=itrnk_end )\n        {\n            TMapRanking::reverse_iterator it_pre = itrnk;\n            --it_pre;\n            itrnk->second.Ranking = it_pre->second.Ranking + it_pre->second.PIDs.size();\n            ++itrnk;\n        }\n    }\n\n\n    _TVctPIDs     _TopRnkPIDs;\n\n    TMapRanking     _MapRanking;\n    TMapScore       _MapScore;\n\n    uint32      _UpdateSeconds;\n    uint32      _PreUpdateSecond1970;\n    uint32      _FastSortMax;\n};\n\n\n#endif // GAME_SHARD_RANKING_SLOT_H\n\n/* End of ranking_solt.h */\n"
  },
  {
    "path": "code/EVA/server/server_share/server_def.cpp",
    "content": "#include \"server_def.h\"\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/server_def.h",
    "content": "#ifndef SERVICE_SHARED_SERVER_DEF_H\n#define SERVICE_SHARED_SERVER_DEF_H\n\n#include <nel/net/message.h>\n#include <nel/net/unified_network.h>\n#include <nel/net/callback_server.h>\n//#include <nel/misc/log.h>\n#include <nel/misc/debug.h>\n\n#include <google/protobuf/message.h>\n#include <google/protobuf/descriptor.h>\n\n#include \"game_def.h\"\n#include \"tools.h\"\n\n//NLMISC::CLog& Loger();\n\n#define     MaxUDPPacketSize   512\n\n//#ifdef NL_RELEASE\n//#\tif defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71\n//#\t\tdefine DebugLoger __noop\n//#\telse\n//#\t\tdefine DebugLoger 0&&\n//#\tendif\n//#else // NL_RELEASE\n//#\tdefine DebugLoger Loger().displayNL\n//#endif // NL_RELEASE\n\n#define  Network NLNET::CUnifiedNetwork::getInstance()\n#define  Config  NLNET::IService::getInstance()->ConfigFile\n\nconst std::string LogicService   = \"PLS\";\nconst std::string EntitiesServer = \"EGS\";\nconst std::string Persistent     = \"PDS\";\n\n/// msg name\nconst std::string T2C       = \"T2C\";\nconst std::string U2C       = \"U2C\";\nconst std::string ERR       = \"ERR\";\nconst std::string DB_PUT    = \"DB_PUT\";\nconst std::string DB_GET    = \"DB_GET\";\nconst std::string PLS2DB    = \"PLS2DB\";\nconst std::string DB2PLS    = \"DB2PLS\";\n\ninline void SendToClient( DEF::RPC_SESSION session, NLNET::CMessage& msgout, bool disconnect=true )\n{\n\tNLNET::CMessage _msgout(T2C);\n\t_msgout.serial(session);\n\t_msgout.serial(disconnect);\n\t_msgout.serialMessage(msgout);\n\n\tNetwork->send( NLNET::TServiceId(GetSID(session)), _msgout );\n}\n\ninline void SendToClient( DEF::RPC_SESSION session, std::string name, google::protobuf::Message* message, bool disconnect=true )\n{\n\tNLNET::CMessage msgout(name);\n\tmsgout.serial(message);\n\tSendToClient(session,msgout,disconnect);\n}\n\n/**\n*   @brief ͻ˼ʱ͵ϢͻUDP˿ڿʱЧ\n*   @param conFES ǰTServiceId\n*   @param uid ˺ID\n*   @param name Ϣ\n*   @param auto_resend ʧʱǷҪ㳢Զط\n*/\ninline void SendUDP( NLNET::TServiceId conFES, DEF::UID uid, std::string name, google::protobuf::Message* message, bool auto_resend )\n{\n    NLNET::CMessage msgsub(name);\n    msgsub.serial(message);\n    \n    NLNET::CMessage msgout(U2C);\n    msgout.serial(uid);\n    msgout.serial(auto_resend);\n    msgout.serialMessage(msgsub);\n\n    if ( NLNET::TServiceId::InvalidId == conFES || conFES.get()==0 )\n    {\n        nlwarning(\"------ %s  %d\",name.c_str(), conFES.get());\n        return;\n    }\n\n    Network->send( conFES, msgout );\n}\n\ninline void SendUDP( NLNET::TServiceId conFES, DEF::UID uid, NLNET::CMessage& msgout, bool auto_resend )\n{\n    NLNET::CMessage _msgout(U2C);\n    _msgout.serial(uid);\n    _msgout.serial(auto_resend);\n    _msgout.serialMessage(msgout);\n\n    if ( NLNET::TServiceId::InvalidId == conFES || conFES.get()==0 )\n    {\n        nlwarning(\"------ %s  %d\", msgout.getName().c_str(), conFES.get());\n        return;\n    }\n    Network->send( conFES, _msgout );\n}\n\ninline void AddToClientBuffer( NLNET::TServiceId conFES, DEF::UID uid, NLNET::CMessage& msgout )\n{\n\tNLNET::CMessage _msgout(\"ADD_MSG_BUF\");\n\t_msgout.serial(uid);\n\t_msgout.serialMessage(msgout);\n\n\tNetwork->send( conFES, _msgout );\n}\n\ninline void AddToClientBuffer( NLNET::TServiceId conFES, DEF::UID uid, std::string name, google::protobuf::Message* message )\n{\n\tNLNET::CMessage msgout(name);\n\tmsgout.serial(message);\n\tAddToClientBuffer(conFES,uid,msgout);\n}\n\n//inline google::protobuf::Message* CreateMessage(const std::string& typeName)\n//{\n//    google::protobuf::Message* message = NULL;\n//    const google::protobuf::Descriptor* descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(typeName);\n//    if (descriptor)\n//    {\n//        const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);\n//        if (prototype)\n//        {\n//            message = prototype->New();\n//        }\n//    }\n//    return message;\n//}\n\n#define  SaveToDB( opt, id, stru ) do {\\\n\tDB_OPT _opt = opt;\\\n\tDEF::PID _pid = id;\\\n\tNLNET::CMessage msg_pds( DB_PUT );\\\n\tmsg_pds.serial(_opt);\\\n\tmsg_pds.serial(_pid);\\\n\tmsg_pds.serial(stru);\\\n\tNetwork->send( Persistent, msg_pds ); \\\n\t} while(0)\n\n#define GetFromDB( opt , id , stru ) do{\\\n    DB_OPT _opt = opt;\\\n    DEF::PID _pid = id;\\\n    NLNET::CMessage msg_pds( DB_GET );\\\n    msg_pds.serial(_opt);\\\n    msg_pds.serial( _pid );\\\n    msg_pds.serial( stru );\\\n    Network->send( Persistent , msg_pds );\\\n    }while( 0 )\n\n\n\ninline void SendErrorToClient( DEF::ERROR_TYPE errNO, DEF::RPC_SESSION session )\n{\n    NLNET::CMessage msgsub(ERR);\n    msgsub.serial(errNO);\n\n    SendToClient( session, msgsub );\n}\n\ninline void SendErrorToClient( DEF::ERROR_TYPE errNO, DEF::RPC_SESSION session, sint64 param )\n{\n    NLNET::CMessage msgsub(ERR);\n    msgsub.serial(errNO);\n    msgsub.serial(param);\n\n    SendToClient( session, msgsub );\n}\n\ninline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO )\n{\n    NLNET::CMessage msgsub(ERR);\n    msgsub.serial(errNO);\n    SendUDP( conFES, uid, msgsub, true);\n}\n\ninline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO, sint64 param )\n{\n    NLNET::CMessage msgsub(ERR);\n    msgsub.serial(errNO);\n    msgsub.serial(param);\n    SendUDP( conFES, uid, msgsub, true);\n}\n\ninline void SendErrorToClient( NLNET::TServiceId conFES, DEF::UID uid, DEF::ERROR_TYPE errNO, sint64 param1 , sint64 param2)\n{\n    NLNET::CMessage msgsub(ERR);\n    msgsub.serial(errNO);\n    msgsub.serial(param1);\n    msgsub.serial(param2);\n    SendUDP( conFES, uid, msgsub, true);\n}\n\n\n\n#endif\n\n"
  },
  {
    "path": "code/EVA/server/server_share/sigslot.h",
    "content": "// sigslot.h: Signal/Slot classes\n//\n// Written by Sarah Thompson (sarah@telergy.com) 2002.\n//\n// License: Public domain. You are free to use this code however you like, with the proviso that\n//          the author takes on no responsibility or liability for any use.\n//\n// QUICK DOCUMENTATION\n//\n//\t\t\t\t(see also the full documentation at http://sigslot.sourceforge.net/)\n//\n//\t\t#define switches\n//\t\t\tSIGSLOT_PURE_ISO\t\t\t- Define this to force ISO C++ compliance. This also disables\n//\t\t\t\t\t\t\t\t\t\t  all of the thread safety support on platforms where it is\n//\t\t\t\t\t\t\t\t\t\t  available.\n//\n//\t\t\tSIGSLOT_USE_POSIX_THREADS\t- Force use of Posix threads when using a C++ compiler other than\n//\t\t\t\t\t\t\t\t\t\t  gcc on a platform that supports Posix threads. (When using gcc,\n//\t\t\t\t\t\t\t\t\t\t  this is the default - use SIGSLOT_PURE_ISO to disable this if\n//\t\t\t\t\t\t\t\t\t\t  necessary)\n//\n//\t\t\tSIGSLOT_DEFAULT_MT_POLICY\t- Where thread support is enabled, this defaults to multi_threaded_global.\n//\t\t\t\t\t\t\t\t\t\t  Otherwise, the default is single_threaded. #define this yourself to\n//\t\t\t\t\t\t\t\t\t\t  override the default. In pure ISO mode, anything other than\n//\t\t\t\t\t\t\t\t\t\t  single_threaded will cause a compiler error.\n//\n//\t\tPLATFORM NOTES\n//\n//\t\t\tWin32\t\t\t\t\t\t- On Win32, the WIN32 symbol must be #defined. Most mainstream\n//\t\t\t\t\t\t\t\t\t\t  compilers do this by default, but you may need to define it\n//\t\t\t\t\t\t\t\t\t\t  yourself if your build environment is less standard. This causes\n//\t\t\t\t\t\t\t\t\t\t  the Win32 thread support to be compiled in and used automatically.\n//\n//\t\t\tUnix/Linux/BSD, etc.\t\t- If you're using gcc, it is assumed that you have Posix threads\n//\t\t\t\t\t\t\t\t\t\t  available, so they are used automatically. You can override this\n//\t\t\t\t\t\t\t\t\t\t  (as under Windows) with the SIGSLOT_PURE_ISO switch. If you're using\n//\t\t\t\t\t\t\t\t\t\t  something other than gcc but still want to use Posix threads, you\n//\t\t\t\t\t\t\t\t\t\t  need to #define SIGSLOT_USE_POSIX_THREADS.\n//\n//\t\t\tISO C++\t\t\t\t\t\t- If none of the supported platforms are detected, or if\n//\t\t\t\t\t\t\t\t\t\t  SIGSLOT_PURE_ISO is defined, all multithreading support is turned off,\n//\t\t\t\t\t\t\t\t\t\t  along with any code that might cause a pure ISO C++ environment to\n//\t\t\t\t\t\t\t\t\t\t  complain. Before you ask, gcc -ansi -pedantic won't compile this\n//\t\t\t\t\t\t\t\t\t\t  library, but gcc -ansi is fine. Pedantic mode seems to throw a lot of\n//\t\t\t\t\t\t\t\t\t\t  errors that aren't really there. If you feel like investigating this,\n//\t\t\t\t\t\t\t\t\t\t  please contact the author.\n//\n//\n//\t\tTHREADING MODES\n//\n//\t\t\tsingle_threaded\t\t\t\t- Your program is assumed to be single threaded from the point of view\n//\t\t\t\t\t\t\t\t\t\t  of signal/slot usage (i.e. all objects using signals and slots are\n//\t\t\t\t\t\t\t\t\t\t  created and destroyed from a single thread). Behaviour if objects are\n//\t\t\t\t\t\t\t\t\t\t  destroyed concurrently is undefined (i.e. you'll get the occasional\n//\t\t\t\t\t\t\t\t\t\t  segmentation fault/memory exception).\n//\n//\t\t\tmulti_threaded_global\t\t- Your program is assumed to be multi threaded. Objects using signals and\n//\t\t\t\t\t\t\t\t\t\t  slots can be safely created and destroyed from any thread, even when\n//\t\t\t\t\t\t\t\t\t\t  connections exist. In multi_threaded_global mode, this is achieved by a\n//\t\t\t\t\t\t\t\t\t\t  single global mutex (actually a critical section on Windows because they\n//\t\t\t\t\t\t\t\t\t\t  are faster). This option uses less OS resources, but results in more\n//\t\t\t\t\t\t\t\t\t\t  opportunities for contention, possibly resulting in more context switches\n//\t\t\t\t\t\t\t\t\t\t  than are strictly necessary.\n//\n//\t\t\tmulti_threaded_local\t\t- Behaviour in this mode is essentially the same as multi_threaded_global,\n//\t\t\t\t\t\t\t\t\t\t  except that each signal, and each object that inherits has_slots, all\n//\t\t\t\t\t\t\t\t\t\t  have their own mutex/critical section. In practice, this means that\n//\t\t\t\t\t\t\t\t\t\t  mutex collisions (and hence context switches) only happen if they are\n//\t\t\t\t\t\t\t\t\t\t  absolutely essential. However, on some platforms, creating a lot of\n//\t\t\t\t\t\t\t\t\t\t  mutexes can slow down the whole OS, so use this option with care.\n//\n//\t\tUSING THE LIBRARY\n//\n//\t\t\tSee the full documentation at http://sigslot.sourceforge.net/\n//\n//\n// Libjingle specific:\n// This file has been modified such that has_slots and signalx do not have to be\n// using the same threading requirements. E.g. it is possible to connect a\n// has_slots<single_threaded> and signal0<multi_threaded_local> or\n// has_slots<multi_threaded_local> and signal0<single_threaded>.\n// If has_slots is single threaded the user must ensure that it is not trying\n// to connect or disconnect to signalx concurrently or data race may occur.\n// If signalx is single threaded the user must ensure that disconnect, connect\n// or signal is not happening concurrently or data race may occur.\n\n#ifndef WEBRTC_BASE_SIGSLOT_H__\n#define WEBRTC_BASE_SIGSLOT_H__\n\n#include <list>\n#include <set>\n#include <stdlib.h>\n\n// On our copy of sigslot.h, we set single threading as default.\n#define SIGSLOT_DEFAULT_MT_POLICY single_threaded\n\n#if defined(SIGSLOT_PURE_ISO) || (!defined(WIN32) && !defined(__GNUG__) && !defined(SIGSLOT_USE_POSIX_THREADS))\n#\tdefine _SIGSLOT_SINGLE_THREADED\n#elif defined(WIN32)\n#\tdefine _SIGSLOT_HAS_WIN32_THREADS\n#\tif !defined(WIN32_LEAN_AND_MEAN)\n#\t\tdefine WIN32_LEAN_AND_MEAN\n#\tendif\n#\tinclude <windows.h>\n#elif defined(__GNUG__) || defined(SIGSLOT_USE_POSIX_THREADS)\n#\tdefine _SIGSLOT_HAS_POSIX_THREADS\n#\tinclude <pthread.h>\n#else\n#\tdefine _SIGSLOT_SINGLE_THREADED\n#endif\n\n#ifndef SIGSLOT_DEFAULT_MT_POLICY\n#\tifdef _SIGSLOT_SINGLE_THREADED\n#\t\tdefine SIGSLOT_DEFAULT_MT_POLICY single_threaded\n#\telse\n#\t\tdefine SIGSLOT_DEFAULT_MT_POLICY multi_threaded_local\n#\tendif\n#endif\n\n// TODO: change this namespace to rtc?\nnamespace sigslot {\n\n\tclass single_threaded\n\t{\n\tpublic:\n\t\tsingle_threaded()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual ~single_threaded()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual void lock()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual void unlock()\n\t\t{\n\t\t\t;\n\t\t}\n\t};\n\n#ifdef _SIGSLOT_HAS_WIN32_THREADS\n\t// The multi threading policies only get compiled in if they are enabled.\n\tclass multi_threaded_global\n\t{\n\tpublic:\n\t\tmulti_threaded_global()\n\t\t{\n\t\t\tstatic bool isinitialised = false;\n\n\t\t\tif(!isinitialised)\n\t\t\t{\n\t\t\t\tInitializeCriticalSection(get_critsec());\n\t\t\t\tisinitialised = true;\n\t\t\t}\n\t\t}\n\n\t\tmulti_threaded_global(const multi_threaded_global&)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual ~multi_threaded_global()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual void lock()\n\t\t{\n\t\t\tEnterCriticalSection(get_critsec());\n\t\t}\n\n\t\tvirtual void unlock()\n\t\t{\n\t\t\tLeaveCriticalSection(get_critsec());\n\t\t}\n\n\tprivate:\n\t\tCRITICAL_SECTION* get_critsec()\n\t\t{\n\t\t\tstatic CRITICAL_SECTION g_critsec;\n\t\t\treturn &g_critsec;\n\t\t}\n\t};\n\n\tclass multi_threaded_local\n\t{\n\tpublic:\n\t\tmulti_threaded_local()\n\t\t{\n\t\t\tInitializeCriticalSection(&m_critsec);\n\t\t}\n\n\t\tmulti_threaded_local(const multi_threaded_local&)\n\t\t{\n\t\t\tInitializeCriticalSection(&m_critsec);\n\t\t}\n\n\t\tvirtual ~multi_threaded_local()\n\t\t{\n\t\t\tDeleteCriticalSection(&m_critsec);\n\t\t}\n\n\t\tvirtual void lock()\n\t\t{\n\t\t\tEnterCriticalSection(&m_critsec);\n\t\t}\n\n\t\tvirtual void unlock()\n\t\t{\n\t\t\tLeaveCriticalSection(&m_critsec);\n\t\t}\n\n\tprivate:\n\t\tCRITICAL_SECTION m_critsec;\n\t};\n#endif // _SIGSLOT_HAS_WIN32_THREADS\n\n#ifdef _SIGSLOT_HAS_POSIX_THREADS\n\t// The multi threading policies only get compiled in if they are enabled.\n\tclass multi_threaded_global\n\t{\n\tpublic:\n\t\tmulti_threaded_global()\n\t\t{\n\t\t\tpthread_mutex_init(get_mutex(), NULL);\n\t\t}\n\n\t\tmulti_threaded_global(const multi_threaded_global&)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual ~multi_threaded_global()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual void lock()\n\t\t{\n\t\t\tpthread_mutex_lock(get_mutex());\n\t\t}\n\n\t\tvirtual void unlock()\n\t\t{\n\t\t\tpthread_mutex_unlock(get_mutex());\n\t\t}\n\n\tprivate:\n\t\tpthread_mutex_t* get_mutex()\n\t\t{\n\t\t\tstatic pthread_mutex_t g_mutex;\n\t\t\treturn &g_mutex;\n\t\t}\n\t};\n\n\tclass multi_threaded_local\n\t{\n\tpublic:\n\t\tmulti_threaded_local()\n\t\t{\n\t\t\tpthread_mutex_init(&m_mutex, NULL);\n\t\t}\n\n\t\tmulti_threaded_local(const multi_threaded_local&)\n\t\t{\n\t\t\tpthread_mutex_init(&m_mutex, NULL);\n\t\t}\n\n\t\tvirtual ~multi_threaded_local()\n\t\t{\n\t\t\tpthread_mutex_destroy(&m_mutex);\n\t\t}\n\n\t\tvirtual void lock()\n\t\t{\n\t\t\tpthread_mutex_lock(&m_mutex);\n\t\t}\n\n\t\tvirtual void unlock()\n\t\t{\n\t\t\tpthread_mutex_unlock(&m_mutex);\n\t\t}\n\n\tprivate:\n\t\tpthread_mutex_t m_mutex;\n\t};\n#endif // _SIGSLOT_HAS_POSIX_THREADS\n\n\ttemplate<class mt_policy>\n\tclass lock_block\n\t{\n\tpublic:\n\t\tmt_policy *m_mutex;\n\n\t\tlock_block(mt_policy *mtx)\n\t\t\t: m_mutex(mtx)\n\t\t{\n\t\t\tm_mutex->lock();\n\t\t}\n\n\t\t~lock_block()\n\t\t{\n\t\t\tm_mutex->unlock();\n\t\t}\n\t};\n\n\tclass has_slots_interface;\n\n\ttemplate<class mt_policy>\n\tclass _connection_base0\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base0() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit() = 0;\n\t\tvirtual _connection_base0* clone() = 0;\n\t\tvirtual _connection_base0* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class mt_policy>\n\tclass _connection_base1\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base1() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type) = 0;\n\t\tvirtual _connection_base1<arg1_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class mt_policy>\n\tclass _connection_base2\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base2() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type) = 0;\n\t\tvirtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class mt_policy>\n\tclass _connection_base3\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base3() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type) = 0;\n\t\tvirtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>\n\tclass _connection_base4\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base4() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type, arg4_type) = 0;\n\t\tvirtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class mt_policy>\n\tclass _connection_base5\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base5() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type) = 0;\n\t\tvirtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class mt_policy>\n\tclass _connection_base6\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base6() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,\n\t\t\targ6_type) = 0;\n\t\tvirtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class mt_policy>\n\tclass _connection_base7\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base7() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,\n\t\t\targ6_type, arg7_type) = 0;\n\t\tvirtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>\n\tclass _connection_base8\n\t{\n\tpublic:\n\t\tvirtual ~_connection_base8() {}\n\t\tvirtual has_slots_interface* getdest() const = 0;\n\t\tvirtual void emit(arg1_type, arg2_type, arg3_type, arg4_type, arg5_type,\n\t\t\targ6_type, arg7_type, arg8_type) = 0;\n\t\tvirtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone() = 0;\n\t\tvirtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots_interface* pnewdest) = 0;\n\t};\n\n\tclass _signal_base_interface\n\t{\n\tpublic:\n\t\tvirtual void slot_disconnect(has_slots_interface* pslot) = 0;\n\t\tvirtual void slot_duplicate(const has_slots_interface* poldslot, has_slots_interface* pnewslot) = 0;\n\t};\n\n\ttemplate<class mt_policy>\n\tclass _signal_base : public _signal_base_interface, public mt_policy\n\t{\n\t};\n\n\tclass has_slots_interface\n\t{\n\tpublic:\n\t\thas_slots_interface()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tvirtual void signal_connect(_signal_base_interface* sender) = 0;\n\n\t\tvirtual void signal_disconnect(_signal_base_interface* sender) = 0;\n\n\t\tvirtual ~has_slots_interface()\n\t\t{\n\t\t}\n\n\t\tvirtual void disconnect_all() = 0;\n\t};\n\n\ttemplate<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass has_slots : public has_slots_interface, public mt_policy\n\t{\n\tprivate:\n\t\ttypedef std::set<_signal_base_interface*> sender_set;\n\t\ttypedef sender_set::const_iterator const_iterator;\n\n\tpublic:\n\t\thas_slots()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\thas_slots(const has_slots& hs)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\tconst_iterator it = hs.m_senders.begin();\n\t\t\tconst_iterator itEnd = hs.m_senders.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->slot_duplicate(&hs, this);\n\t\t\t\tm_senders.insert(*it);\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid signal_connect(_signal_base_interface* sender)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\tm_senders.insert(sender);\n\t\t}\n\n\t\tvoid signal_disconnect(_signal_base_interface* sender)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\tm_senders.erase(sender);\n\t\t}\n\n\t\tvirtual ~has_slots()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\tconst_iterator it = m_senders.begin();\n\t\t\tconst_iterator itEnd = m_senders.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->slot_disconnect(this);\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_senders.erase(m_senders.begin(), m_senders.end());\n\t\t}\n\n\tprivate:\n\t\tsender_set m_senders;\n\t};\n\n\ttemplate<class mt_policy>\n\tclass _signal_base0 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base0<mt_policy> *>  connections_list;\n\n\t\t_signal_base0()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base0(const _signal_base0& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base0()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class mt_policy>\n\tclass _signal_base1 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base1<arg1_type, mt_policy> *>  connections_list;\n\n\t\t_signal_base1()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base1(const _signal_base1<arg1_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base1()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class mt_policy>\n\tclass _signal_base2 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base2<arg1_type, arg2_type, mt_policy> *>\n\t\t\tconnections_list;\n\n\t\t_signal_base2()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base2(const _signal_base2<arg1_type, arg2_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base2()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class mt_policy>\n\tclass _signal_base3 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base3<arg1_type, arg2_type, arg3_type, mt_policy> *>\n\t\t\tconnections_list;\n\n\t\t_signal_base3()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base3(const _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base3()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy>\n\tclass _signal_base4 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base4<arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type, mt_policy> *>  connections_list;\n\n\t\t_signal_base4()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base4(const _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base4()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class mt_policy>\n\tclass _signal_base5 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base5<arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type, arg5_type, mt_policy> *>  connections_list;\n\n\t\t_signal_base5()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base5(const _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base5()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class mt_policy>\n\tclass _signal_base6 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base6<arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type, arg5_type, arg6_type, mt_policy> *>  connections_list;\n\n\t\t_signal_base6()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base6(const _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base6()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class mt_policy>\n\tclass _signal_base7 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base7<arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type, arg5_type, arg6_type, arg7_type, mt_policy> *>  connections_list;\n\n\t\t_signal_base7()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base7(const _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base7()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy>\n\tclass _signal_base8 : public _signal_base<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef std::list<_connection_base8<arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy> *>\n\t\t\tconnections_list;\n\n\t\t_signal_base8()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\t_signal_base8(const _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)\n\t\t\t: _signal_base<mt_policy>(s)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = s.m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = s.m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_connect(this);\n\t\t\t\tm_connected_slots.push_back((*it)->clone());\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_duplicate(const has_slots_interface* oldtarget, has_slots_interface* newtarget)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == oldtarget)\n\t\t\t\t{\n\t\t\t\t\tm_connected_slots.push_back((*it)->duplicate(newtarget));\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\t~_signal_base8()\n\t\t{\n\t\t\tdisconnect_all();\n\t\t}\n\n\t\tbool is_empty()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\treturn it == itEnd;\n\t\t}\n\n\t\tvoid disconnect_all()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\t(*it)->getdest()->signal_disconnect(this);\n\t\t\t\tdelete *it;\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tm_connected_slots.erase(m_connected_slots.begin(), m_connected_slots.end());\n\t\t}\n\n#ifdef _DEBUG\n\t\t\tbool connected(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\t\t\t\tif ((*it)->getdest() == pclass)\n\t\t\t\t\treturn true;\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n#endif\n\n\t\tvoid disconnect(has_slots_interface* pclass)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\tif((*it)->getdest() == pclass)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t\tpclass->signal_disconnect(this);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\t\t}\n\n\t\tvoid slot_disconnect(has_slots_interface* pslot)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::iterator it = m_connected_slots.begin();\n\t\t\ttypename connections_list::iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\ttypename connections_list::iterator itNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\tif((*it)->getdest() == pslot)\n\t\t\t\t{\n\t\t\t\t\tdelete *it;\n\t\t\t\t\tm_connected_slots.erase(it);\n\t\t\t\t}\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\tconnections_list m_connected_slots;\n\t};\n\n\n\ttemplate<class dest_type, class mt_policy>\n\tclass _connection0 : public _connection_base0<mt_policy>\n\t{\n\tpublic:\n\t\t_connection0()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection0(dest_type* pobject, void (dest_type::*pmemfun)())\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection0()\n\t\t{\n                }\n\n\t\tvirtual _connection_base0<mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection0<dest_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base0<mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection0<dest_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit()\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)();\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)();\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class mt_policy>\n\tclass _connection1 : public _connection_base1<arg1_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection1()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection1(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection1()\n\t\t{\n                }\n\n\t\tvirtual _connection_base1<arg1_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection1<dest_type, arg1_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base1<arg1_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection1<dest_type, arg1_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class mt_policy>\n\tclass _connection2 : public _connection_base2<arg1_type, arg2_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection2()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection2(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection2()\n\t\t{\n                }\n\n\t\tvirtual _connection_base2<arg1_type, arg2_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection2<dest_type, arg1_type, arg2_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base2<arg1_type, arg2_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection2<dest_type, arg1_type, arg2_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type, class mt_policy>\n\tclass _connection3 : public _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection3()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection3(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection3()\n\t\t{\n                }\n\n\t\tvirtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base3<arg1_type, arg2_type, arg3_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection3<dest_type, arg1_type, arg2_type, arg3_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type,\n\tclass arg4_type, class mt_policy>\n\tclass _connection4 : public _connection_base4<arg1_type, arg2_type,\n\t\targ3_type, arg4_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection4()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection4(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection4()\n\t\t{\n                }\n\n\t\tvirtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection4<dest_type, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3,\n\t\t\targ4_type a4)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3, a4);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type,\n\t\t\targ4_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type,\n\tclass arg4_type, class arg5_type, class mt_policy>\n\tclass _connection5 : public _connection_base5<arg1_type, arg2_type,\n\t\targ3_type, arg4_type, arg5_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection5()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection5(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection5()\n\t\t{\n                }\n\n\t\tvirtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection5<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type,\n\tclass arg4_type, class arg5_type, class arg6_type, class mt_policy>\n\tclass _connection6 : public _connection_base6<arg1_type, arg2_type,\n\t\targ3_type, arg4_type, arg5_type, arg6_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection6()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection6(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection6()\n\t\t{\n                }\n\n\t\tvirtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection6<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type,\n\tclass arg4_type, class arg5_type, class arg6_type, class arg7_type, class mt_policy>\n\tclass _connection7 : public _connection_base7<arg1_type, arg2_type,\n\t\targ3_type, arg4_type, arg5_type, arg6_type, arg7_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection7()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection7(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type, arg7_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection7()\n\t\t{\n                }\n\n\t\tvirtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection7<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type);\n\t};\n\n\ttemplate<class dest_type, class arg1_type, class arg2_type, class arg3_type,\n\tclass arg4_type, class arg5_type, class arg6_type, class arg7_type,\n\tclass arg8_type, class mt_policy>\n\tclass _connection8 : public _connection_base8<arg1_type, arg2_type,\n\t\targ3_type, arg4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>\n\t{\n\tpublic:\n\t\t_connection8()\n\t\t{\n\t\t\tm_pobject = NULL;\n\t\t\tm_pmemfun = NULL;\n\t\t}\n\n\t\t_connection8(dest_type* pobject, void (dest_type::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type,\n\t\t\targ7_type, arg8_type))\n\t\t{\n\t\t\tm_pobject = pobject;\n\t\t\tm_pmemfun = pmemfun;\n\t\t}\n\n\t\tvirtual ~_connection8()\n\t\t{\n                }\n\n\t\tvirtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>* clone()\n\t\t{\n\t\t\treturn new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>(*this);\n\t\t}\n\n\t\tvirtual _connection_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>* duplicate(has_slots_interface* pnewdest)\n\t\t{\n\t\t\treturn new _connection8<dest_type, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>((dest_type *)pnewdest, m_pmemfun);\n\t\t}\n\n\t\tvirtual void emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)\n\t\t{\n\t\t\t(m_pobject->*m_pmemfun)(a1, a2, a3, a4, a5, a6, a7, a8);\n\t\t}\n\n\t\tvirtual has_slots_interface* getdest() const\n\t\t{\n\t\t\treturn m_pobject;\n\t\t}\n\n\tprivate:\n\t\tdest_type* m_pobject;\n\t\tvoid (dest_type::* m_pmemfun)(arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type);\n\t};\n\n\ttemplate<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal0 : public _signal_base0<mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base0<mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal0()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal0(const signal0<mt_policy>& s)\n\t\t\t: _signal_base0<mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)())\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection0<desttype, mt_policy>* conn =\n\t\t\t\tnew _connection0<desttype, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit();\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()()\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit();\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal1 : public _signal_base1<arg1_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base1<arg1_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal1()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal1(const signal1<arg1_type, mt_policy>& s)\n\t\t\t: _signal_base1<arg1_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection1<desttype, arg1_type, mt_policy>* conn =\n\t\t\t\tnew _connection1<desttype, arg1_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal2 : public _signal_base2<arg1_type, arg2_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base2<arg1_type, arg2_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal2()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal2(const signal2<arg1_type, arg2_type, mt_policy>& s)\n\t\t\t: _signal_base2<arg1_type, arg2_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection2<desttype, arg1_type, arg2_type, mt_policy>* conn = new\n\t\t\t\t_connection2<desttype, arg1_type, arg2_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal3 : public _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal3()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal3(const signal3<arg1_type, arg2_type, arg3_type, mt_policy>& s)\n\t\t\t: _signal_base3<arg1_type, arg2_type, arg3_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>* conn =\n\t\t\t\tnew _connection3<desttype, arg1_type, arg2_type, arg3_type, mt_policy>(pclass,\n\t\t\t\tpmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal4 : public _signal_base4<arg1_type, arg2_type, arg3_type,\n\t\targ4_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal4()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal4(const signal4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>& s)\n\t\t\t: _signal_base4<arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection4<desttype, arg1_type, arg2_type, arg3_type, arg4_type, mt_policy>*\n\t\t\t\tconn = new _connection4<desttype, arg1_type, arg2_type, arg3_type,\n\t\t\t\targ4_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal5 : public _signal_base5<arg1_type, arg2_type, arg3_type,\n\t\targ4_type, arg5_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal5()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal5(const signal5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>& s)\n\t\t\t: _signal_base5<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection5<desttype, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, mt_policy>* conn = new _connection5<desttype, arg1_type, arg2_type,\n\t\t\t\targ3_type, arg4_type, arg5_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal6 : public _signal_base6<arg1_type, arg2_type, arg3_type,\n\t\targ4_type, arg5_type, arg6_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal6()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal6(const signal6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>& s)\n\t\t\t: _signal_base6<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection6<desttype, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, mt_policy>* conn =\n\t\t\t\tnew _connection6<desttype, arg1_type, arg2_type, arg3_type,\n\t\t\t\targ4_type, arg5_type, arg6_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal7 : public _signal_base7<arg1_type, arg2_type, arg3_type,\n\t\targ4_type, arg5_type, arg6_type, arg7_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal7()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal7(const signal7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>& s)\n\t\t\t: _signal_base7<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type,\n\t\t\targ7_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection7<desttype, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, mt_policy>* conn =\n\t\t\t\tnew _connection7<desttype, arg1_type, arg2_type, arg3_type,\n\t\t\t\targ4_type, arg5_type, arg6_type, arg7_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6, a7);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6, a7);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<class arg1_type, class arg2_type, class arg3_type, class arg4_type,\n\tclass arg5_type, class arg6_type, class arg7_type, class arg8_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>\n\tclass signal8 : public _signal_base8<arg1_type, arg2_type, arg3_type,\n\t\targ4_type, arg5_type, arg6_type, arg7_type, arg8_type, mt_policy>\n\t{\n\tpublic:\n\t\ttypedef _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy> base;\n\t\ttypedef typename base::connections_list connections_list;\n\t\tusing base::m_connected_slots;\n\n\t\tsignal8()\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\tsignal8(const signal8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>& s)\n\t\t\t: _signal_base8<arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>(s)\n\t\t{\n\t\t\t;\n\t\t}\n\n\t\ttemplate<class desttype>\n\t\t\tvoid connect(desttype* pclass, void (desttype::*pmemfun)(arg1_type,\n\t\t\targ2_type, arg3_type, arg4_type, arg5_type, arg6_type,\n\t\t\targ7_type, arg8_type))\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\t_connection8<desttype, arg1_type, arg2_type, arg3_type, arg4_type,\n\t\t\t\targ5_type, arg6_type, arg7_type, arg8_type, mt_policy>* conn =\n\t\t\t\tnew _connection8<desttype, arg1_type, arg2_type, arg3_type,\n\t\t\t\targ4_type, arg5_type, arg6_type, arg7_type,\n\t\t\t\targ8_type, mt_policy>(pclass, pmemfun);\n\t\t\tm_connected_slots.push_back(conn);\n\t\t\tpclass->signal_connect(this);\n\t\t}\n\n\t\tvoid emit(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\n\t\tvoid operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4,\n\t\t\targ5_type a5, arg6_type a6, arg7_type a7, arg8_type a8)\n\t\t{\n\t\t\tlock_block<mt_policy> lock(this);\n\t\t\ttypename connections_list::const_iterator itNext, it = m_connected_slots.begin();\n\t\t\ttypename connections_list::const_iterator itEnd = m_connected_slots.end();\n\n\t\t\twhile(it != itEnd)\n\t\t\t{\n\t\t\t\titNext = it;\n\t\t\t\t++itNext;\n\n\t\t\t\t(*it)->emit(a1, a2, a3, a4, a5, a6, a7, a8);\n\n\t\t\t\tit = itNext;\n\t\t\t}\n\t\t}\n\t};\n\n}; // namespace sigslot\n\n#endif // WEBRTC_BASE_SIGSLOT_H__\n"
  },
  {
    "path": "code/EVA/server/server_share/singleton_registry.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n\n  NOTE: The following extension would be intelligent:\n  ---------------------------------------------------\n  - add 'preInit', 'preServiceUpdate', 'preTickUpdate' and 'preRelease' methods\n  - add 'postInit', 'postServiceUpdate', 'postTickUpdate' and 'postRelease' methods\n  - call all 'preXXX' methods followed by all XXX methods followed by all postXXX methods\n  => This allows one to open log files etc in pre-init, start counters in pre-update, stop counters in post-update, etc...\n\n*/\n\n#ifndef SINGLETON_REGISTRY_H\n#define SINGLETON_REGISTRY_H\n\n\n//-------------------------------------------------------------------------------------------------\n// includes\n//-------------------------------------------------------------------------------------------------\n\n#include <set>\n\n//-------------------------------------------------------------------------------------------------\n// class IServiceSingleton\n//-------------------------------------------------------------------------------------------------\n\nclass IServiceSingleton\n{\npublic:\n\t// overloadable method called at service initialisation\n\tvirtual void init()\t\t\t\t{}\n\n\t// overloadable method called in the service update\n\tvirtual void serviceUpdate()\t{}\n\n\t// overloadable method called in the tick update\n\tvirtual void tickUpdate()\t\t{}\n\n\t// overloadable method called at service release\n\tvirtual void release()\t\t\t{}\n\nprotected:\n\t// protect from untrolled instantiation\n\t// this method registers the singleton with the singleton registry\n\tIServiceSingleton();\n\tvirtual ~IServiceSingleton() {}\n\nprivate:\n\t// prohibit copy\n\tIServiceSingleton(const IServiceSingleton&);\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// class CSingletonRegistry\n//-------------------------------------------------------------------------------------------------\n\nclass CSingletonRegistry\n{\npublic:\n\t// public interface for getting hold of the singleton instance\n\tstatic CSingletonRegistry* getInstance();\n\n\t// registration of an IServiceSingleton object with the singleton\n\tvoid registerSingleton(IServiceSingleton*);\n\n\t// methods called from the service loop\n\tvoid init();\n\tvoid serviceUpdate();\n\tvoid tickUpdate();\n\tvoid release();\n\nprivate:\n\t// prohibit uncontrolled instantiation\n\tCSingletonRegistry() {}\n\tCSingletonRegistry(const CSingletonRegistry&);\n\n\ttypedef std::set<IServiceSingleton*> TSingletons;\n\tTSingletons _Singletons;\n};\n\n#define SingletonRegistry CSingletonRegistry::getInstance()\n\n//-------------------------------------------------------------------------------------------------\n// inlines IServiceSingleton\n//-------------------------------------------------------------------------------------------------\n\ninline IServiceSingleton::IServiceSingleton()\n{\n\tCSingletonRegistry::getInstance()->registerSingleton(this);\n}\n\n\n//-------------------------------------------------------------------------------------------------\n// inlines CSingletonRegistry\n//-------------------------------------------------------------------------------------------------\n\ninline CSingletonRegistry* CSingletonRegistry::getInstance()\n{\n\tstatic CSingletonRegistry* instance= NULL;\n\tif (instance==NULL)\n\t{\n\t\tinstance=new CSingletonRegistry;\n\t}\n\treturn instance;\n}\n\ninline void CSingletonRegistry::registerSingleton(IServiceSingleton* singleton)\n{\n\t_Singletons.insert(singleton);\n}\n\ninline void CSingletonRegistry::init()\n{\n\tfor (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it)\n\t\t(*it)->init();\n}\n\ninline void CSingletonRegistry::tickUpdate()\n{\n\tfor (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it)\n\t\t(*it)->tickUpdate();\n}\n\ninline void CSingletonRegistry::serviceUpdate()\n{\n\tfor (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it)\n\t\t(*it)->serviceUpdate();\n}\n\ninline void CSingletonRegistry::release()\n{\n\tfor (TSingletons::iterator it=_Singletons.begin(); it!=_Singletons.end();++it)\n\t\t(*it)->release();\n}\n\n\n//-------------------------------------------------------------------------------------------------\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/stdpch.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdpch.h\"\n"
  },
  {
    "path": "code/EVA/server/server_share/stdpch.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"nel/misc/types_nl.h\"\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <stddef.h>\n#include <math.h>\n#include <time.h>\n#include <assert.h>\n\n#include <string>\n#include <vector>\n#include <list>\n#include <map>\n#include <set>\n#include <algorithm>\n#include <sstream>\n#include <exception>\n#include <utility>\n#include <deque>\n#include <limits>\n#include <queue>\n#include <memory>\n#include <functional>\n\n#include <nel/misc/common.h>\n#include <nel/misc/debug.h>\n\n#include <nel/misc/stream.h>\n#include <nel/misc/time_nl.h>\n#include <nel/misc/vector.h>\n#include <nel/misc/matrix.h>\n#include <nel/misc/rgba.h>\n#include <nel/misc/sheet_id.h>\n#include <nel/misc/command.h>\n#include <nel/misc/config_file.h>\n#include <nel/misc/variable.h>\n#include <nel/misc/shared_memory.h>\n#include <nel/misc/file.h>\n#include <nel/misc/path.h>\n#include <nel/misc/singleton.h>\n#include <nel/misc/string_common.h>\n#include <nel/misc/sstring.h>\n#include <nel/misc/bit_mem_stream.h>\n#include <nel/misc/o_xml.h>\n#include <nel/misc/i_xml.h>\n\n//#include <nel/net/udp_sock.h>\n#include <nel/net/unified_network.h>\n#include <nel/net/service.h>\n\n#ifndef _CLIENT_\n//#include <nel/georges/load_form.h>\n#endif\n\n#include <server_share/utils.h>\n"
  },
  {
    "path": "code/EVA/server/server_share/timer.cpp",
    "content": "﻿// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//-------------------------------------------------------------------------------------------------\n// includes\n//-------------------------------------------------------------------------------------------------\n\n#include \"stdpch.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/config_file.h\"\n#include <nel/net/service.h>\t// for config\n#include \"timer.h\"\n\nusing namespace NLMISC;\n\nNLMISC::CVariable<uint32> NbProcessedEventsInTimerManagerUpdate(\"timer\", \"NbProcessedEventInTimerManagerUpdate\", \"\", 0);\nNLMISC::CVariable<uint32> NbEventsToProcessInTimerManagerUpdate(\"timer\", \"NbEventsToProcessInTimerManagerUpdate\", \"\", 0);\n\nNL_INSTANCE_COUNTER_IMPL(CTimerEvent);\n\n////-------------------------------------------------------------------------------------------------\n////\tsyncTick()\n////-------------------------------------------------------------------------------------------------\n//void CTimerManager::syncTick()\n//{\n//\tuint32 delta= CTickEventHandler::getGameCycle()-_LastTick;\n//\n//\t// update the time values\n//\tfor (NLMISC::TGameCycle i=0;i<256;++i)\n//\t{\n//\t\tTEventVector& vect= getEventVector(i);\n//\t\tfor (uint32 j=0;j<vect.size();++j)\n//\t\t\tvect[j]->_Time+= delta;\n//\t}\n//\n//\t// re-locate the event vectors to line them back up with the time values that they represent\n//\tfor (NLMISC::TGameCycle i=0;i<256;++i)\n//\t{\n//\t\tTEventVector& vect= _EventVectors[i];\n//\t\twhile (!vect.empty() && ((uint8)vect[0]->_Time)!=i)\n//\t\t{\n//\t\t\tuint8 swapPos= (uint8)_EventVectors[i][0]->_Time;\n//\t\t\tstd::swap(_EventVectors[i],_EventVectors[swapPos]);\n//\t\t}\n//\t}\n//\n//\t_LastTick= CTickEventHandler::getGameCycle();\n//}\n\n\n\nvoid CTimerManager::init()\n{\n    CConfigFile::CVar *var;\n    if ((var = NLNET::IService::getInstance()->ConfigFile.getVarPtr(\"UpdateTimeout\")) != NULL)\n    {\n        _UpdateTimeout = var->asInt();\n    }\n\n    _BaseTime  = CTime::getLocalTime();\n    _LocalTime = _BaseTime;\n}\n\n\n//-------------------------------------------------------------------------------------------------\n//\ttickUpdate()\n//-------------------------------------------------------------------------------------------------\nvoid CTimerManager::tickUpdate()\n{\n\tH_AUTO(CTimerManagerUpdate);\n\n    NLMISC::TTime       NextTime = 0;\n\n    do \n    {\n\t    // update time\n\t    ++_CurrentTick;\n\t    _LocalTime = CTime::getLocalTime();\n\n\t    // select this game cycle's phrase event vector\n\t    TEventVector &vect= getInstance()->getEventVector(_CurrentTick);\n\n\t    // iterate through the vector processing its events\n\t    uint32 nextFreeSlot=0;\n\t    uint32 size=(uint32)vect.size();\n\t    for (uint32 i=0;i<size;++i)\n\t    {\n\t\t    NLMISC::CSmartPtr<CTimerEvent> eventPtr=vect[i];\n\n\t\t    // if the event is no longer valid then just skip it\n\t\t    if (eventPtr->getOwner()==NULL)\n\t\t\t    continue;\n\n\t\t    // if the event isn't valid yet then keep it for later\n\t\t    // BUG when event time is too high, like 0xffffffff which is used in special cases, so change the test\n\t\t    //if ((sint32)(eventPtr->getTime()-time)>0)\n\t\t    if (eventPtr->getTime() > _CurrentTick)\n\t\t    {\n\t\t\t    vect[nextFreeSlot]=eventPtr;\n\t\t\t    ++nextFreeSlot;\n\t\t\t    continue;\n\t\t    }\n\n\t\t    // process the event\n\t\t    eventPtr->processEvent();\n\t    }\n\t    if (!vect.empty())\n\t    {\n\t\t    //nlinfo(\"TimerManagerUpdate: Processed %d of %d events\",vect.size()-nextFreeSlot, vect.size());\n\t\t    NbEventsToProcessInTimerManagerUpdate = (uint32)vect.size();\n\t\t    NbProcessedEventsInTimerManagerUpdate = NbEventsToProcessInTimerManagerUpdate.get() - nextFreeSlot;\n\t    }\n\t    // resize the vector back down to keep only the events that we haven't dealt with yet\n\t    vect.resize(nextFreeSlot);\n\n        ///   check time\n        NextTime = _BaseTime + (_CurrentTick+1)*_UpdateTimeout;\n\n    } while (NextTime < _LocalTime);\n}\n\n"
  },
  {
    "path": "code/EVA/server/server_share/timer.h",
    "content": "﻿// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n  Intro:\n  ------\n  This file contains a complete timer system.\n  It is robust and can be used widely.\n  The user creates classes derived from CTimerEvent to represent their event handlers.\n  When the classes' set() or setRemaining() methods are called an entry is added to the event system provoking\n  a callback of the user's timerCallback() method at the given time.\n  If a CTimer object is destroyed its callback is automatically canceled.\n  A single timer may only have a single time set for it. Setting the time more than once will cancel\n  the previous time.\n  NOTE: The only requirement for the system is that the CTimerManager::tickUpdate() method is called every tick\n\n\n  Example 1: - a class containing a timer\n  ----------\n\tclass CMyClass\n\t{\n\tpublic:\n\t\tvoid startTimer()\n\t\t{\n\t\t\t// set the timer to trigger in 50 ticks\n\t\t\t_Timer.setRemaining(50);\n\t\t}\n\t\tvoid update()\n\t\t{\n\t\t\tif (_Timer.isActive())\n\t\t\t{\n\t\t\t\tnlinfo(\"time remaining: \",_Timer.getTimeRemaining());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// set the timer to trigger in 20 ticks\n\t\t\t\t_Timer.setRemaining(20);\n\t\t\t}\n\t\t}\n\tprivate:\n\t\tCTimer _Timer;\n\t};\n\n\n  Example 2: - a class using a timer and a custom event handler to trigger regular actions\n  ----------\n\tclass CMyClass;\n\tclass CMyTimerEvent;\n\n\tclass CMyTimerEvent: public CTimerEvent\n\t{\n\tpublic:\n\t\tCMyTimerEvent(CMyClass* parent);\n\t\tvoid timerCallback(CTimer* owner);\n\tprivate:\n\t\tCMyClass* _Parent;\n\t}\n\n\tclass CMyClass\n\t{\n\tpublic:\n\t\tvoid startTimer()\n\t\t{\n\t\t\t// set the timer to trigger in 50 ticks\n\t\t\t_Timer.setRemaining(50,new CMyTimerEvent(this));\n\t\t}\n\t\tvoid doSomething(CTimerEvent* event)\n\t\t{\n\t\t\tnlinfo(\"hello world\");\n\t\t\t// set the timer to trigger in 20 ticks with the same event handler\n\t\t\t_Timer.setRemaining(20,event);\n\t\t}\n\tprivate:\n\t\tCMyTimer _Timer;\n\t};\n\n\tvoid CMyTimerEvent::CMyTimerEvent(CMyClass* parent)\n\t{\n\t\t_Parent=parent;\n\t}\n\tvoid CMyTimerEvent::timerCallback(CTimer* owner)\n\t{\n\t\t_Parent->doSomething(this);\n\t}\n*/\n\n#ifndef TIMER_H\n#define TIMER_H\n\n//-------------------------------------------------------------------------------------------------\n// includes\n//-------------------------------------------------------------------------------------------------\n\n// stl\n#include <vector>\n// misc\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/smart_ptr.h\"\n// game share\n#include \"utils.h\"\n#include \"singleton_registry.h\"\n\n#include \"tools.h\"\n\n\n//-------------------------------------------------------------------------------------------------\n// forward class declarations\n//-------------------------------------------------------------------------------------------------\n\nclass CTimer;\nclass CTimerEvent;\nclass CTimerManager;\n\n//-------------------------------------------------------------------------------------------------\n// class CTimer\n//-------------------------------------------------------------------------------------------------\n// generic timer class\n\nclass CTimer\n{\npublic:\n\t// ctor and dtor\n\tCTimer();\n\tvirtual ~CTimer();\n\n\t// set the timer for a given target time & clear the custom event object\n\tvoid set(NLMISC::TTicks tick);\n\n\t// set the timer for somewhere between (time) and (time + variation)\n\t// also clear the custom event object\n\tvoid set(NLMISC::TTicks tick,uint32 variation);\n\n\t// set the timer for a given target time with given custom event handler object\n\tvoid set(NLMISC::TTicks tick,CTimerEvent* eventObject);\n\n\t// set the timer for somewhere between (time) and (time + variation)\n\t// also set given custom event handler object\n\tvoid set(NLMISC::TTicks tick,CTimerEvent* eventObject,uint32 variation);\n\n\t// set the timer for (current time + time) & clear the custom event object\n\tvoid setRemaining(NLMISC::TTicks tick);\n\n\t// set the timer for somewhere between (current time + time) and (current time + time + variation)\n\t// also clear the custom event object\n\tvoid setRemaining(NLMISC::TTicks tick,uint32 variation);\n\n\t// set the timer for (current time + time) with given custom event handler object\n\tvoid setRemaining(NLMISC::TTicks tick,CTimerEvent* eventObject);\n\n\t// set the timer for somewhere between (current time + time) and (current time + time + variation)\n\t// also set given custom event handler object\n\tvoid setRemaining(NLMISC::TTicks tick,CTimerEvent* eventObject,uint32 variation);\n\n    /**\n    *   @brief 在未来某一时刻触发。\n    *   @param SecondSince1970 触发的具体时间。\n    *   @param eventObject 定时器事件。\n    *   @param millisecond 可以散布在SecondSince1970之后的多少毫秒内触发（避免某一帧内的事件过多）。\n    */\n    bool setTime(NLMISC::TTime SecondSince1970,CTimerEvent* eventObject,uint32 millisecond=0);\n\n\t// test whether timer is running\n\tbool isActive() const;\n\n\t// reset the timer and clear the custom timer event\n\tvoid reset();\n\n\t// get the target time for the timer - return 0 if the event is not active\n\tNLMISC::TGameCycle getTime() const;\n\n\t// get the time remaining before the target time for the timer - return 0 if the event is not active\n\tNLMISC::TGameCycle getTimeRemaining() const;\n\n\t// get a pointer to the current custom event object\n\tCTimerEvent* getEvent();\n\nprivate:\n\t// prohibit copy\n\tCTimer(const CTimer&);\n\n\tCTimer& operator=(const CTimer&);\n\n\t// a smart pointer to the timer event - the event is reffed by a second smart ptr from the event system\n\tNLMISC::CSmartPtr<CTimerEvent> _Event;\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// class CTimerEvent\n//-------------------------------------------------------------------------------------------------\n// specialisable timer event class\n\nclass CTimerEvent: public NLMISC::CRefCount\n{\n\tNL_INSTANCE_COUNTER_DECL(CTimerEvent);\npublic:\n\t// callback to be specialised\n\tvirtual void timerCallback(CTimer* owner) {}\n\npublic:\n\t// ctor\n\tCTimerEvent();\n\n\t// dtor\n\tvirtual ~CTimerEvent();\n\n\t// read accessors\n\tNLMISC::TGameCycle getTime() const;\n\n\t// get hold of the object that created the event (or NULL if the object has been deleted)\n\tCTimer* getOwner() const;\n\n\t// return true if the event is active otherwise false\n\tbool isActive() const;\n\nprivate:\n\t// the following interface is reserved for use by the CTimer class\n\tfriend class CTimer;\n\n\t// setup the event\n\tvoid set(CTimer* owner,NLMISC::TGameCycle time);\n\n\t// setup the event, selecting a time between 'time' and 'time'+'variation'\n\tvoid set(CTimer* owner,NLMISC::TGameCycle time,uint32 variation);\n\n\t// clear the event - mark it for deletion\n\tvoid clear();\n\nprivate:\n\t// the following interface is reserved for use by the CTimerManager class\n\tfriend class CTimerManager;\n\n\t// method used by the event system to call the timer callback and kill off the event\n\tvoid processEvent();\n\nprivate:\n\t// the correct time for executing the event\n\tNLMISC::TTime _Time;\n\n\t// a pointer to the owner object - is NULL if owner object has been deleted or this event has been invalidated\n\tCTimer* _Owner;\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// class CTimerManager\n//-------------------------------------------------------------------------------------------------\n// singleton timer manager\n\nclass CTimerManager: public IServiceSingleton\n{\npublic:\n\n\tvirtual void init();\n\n\t// update called each tick in service update\n\t// updates events and cleans out event vectors\n\tvirtual void tickUpdate();\n\n    //serviceUpdate\n\n\t// get the singleton instance...\n\tstatic CTimerManager* getInstance();\n\n\t// callback called when the tick service connects - used to ajust time values of event objects\n\t//void syncTick();\n\tNLMISC::TGameCycle  getTick()            { return _CurrentTick; }\n\t//NLMISC::TTime       getTime()            { return _LocalTime; }\n\tNLMISC::TTime       getUpdateTimeout()   { return _UpdateTimeout; }\n\n    enum \n    {\n        TIMER_VECTOR_MASK = 0xffff,\n        TIMER_VECTOR_SIZE,\n    };\n\nprivate:\n\t// this is a singleton so prohibit construction\n\tCTimerManager();\n\n\t// the type of the event vector for a given time hash\n\ttypedef std::vector<NLMISC::CSmartPtr<CTimerEvent> > TEventVector;\n\n\t// the event vector is filled directly by CTimerEvent objects\n\tfriend class CTimerEvent;\n\n\t// singleton encapsulation of event vector set\n\tTEventVector& getEventVector(NLMISC::TGameCycle time);\n\n\t// data\n\t/// Select timeout value in milliseconds between to call of user update()\n\tNLMISC::TTime        _UpdateTimeout;\n\n\tNLMISC::TGameCycle   _CurrentTick;\n\tNLMISC::TGameCycle   _LastTick;\n\tNLMISC::TTime        _LocalTime;\n    NLMISC::TTime        _BaseTime;\n\n\tTEventVector _EventVectors[TIMER_VECTOR_SIZE];\n};\n\n#define TimerManager CTimerManager::getInstance()\n\n//-------------------------------------------------------------------------------------------------\n// class CTimer\n//-------------------------------------------------------------------------------------------------\n\ninline CTimer::CTimer()\n{\n}\n\ninline CTimer::~CTimer()\n{\n\treset();\n}\n\ninline void CTimer::set(NLMISC::TTime time)\n{\n    nlassertd(time>0);\n\tset(time,new CTimerEvent);\n}\n\ninline void CTimer::set(NLMISC::TTime time,uint32 variation)\n{\n    nlassertd(time>0);\n\tset(time,new CTimerEvent,variation);\n}\n\ninline void CTimer::set(NLMISC::TTime time,CTimerEvent* eventObject)\n{\n    nlassertd(time>0);\n\tif (_Event!=NULL)\n\t\t_Event->clear();\n\t_Event= eventObject;\n\n    NLMISC::TGameCycle add_cycle  = (time /*- TimerManager->getTime()*/)/TimerManager->getUpdateTimeout();\n    if ( add_cycle == 0 )    {    ++add_cycle;   }\n    NLMISC::TGameCycle game_cycle = TimerManager->getTick() + add_cycle;\n\n\teventObject->set(this,game_cycle);\n}\n\ninline void CTimer::set(NLMISC::TTime time,CTimerEvent* eventObject,uint32 variation)\n{\n    nlassertd(time>0);\n\tif (_Event!=NULL)\n\t\t_Event->clear();\n\t_Event= eventObject;\n\n\tNLMISC::TGameCycle add_cycle  = (time/* - TimerManager->getTime()*/)/TimerManager->getUpdateTimeout();\n    if ( add_cycle == 0 )    {    ++add_cycle;   }\n\tNLMISC::TGameCycle game_cycle = TimerManager->getTick() + add_cycle;\n\n\teventObject->set(this,game_cycle,variation);\n}\n\ninline void CTimer::setRemaining(NLMISC::TTime time)\n{\n\tset(/*TimerManager->getTime()+*/time);\n}\n\ninline void CTimer::setRemaining(NLMISC::TTime time,uint32 variation)\n{\n\tset(/*TimerManager->getTime()+*/time,variation);\n}\n\ninline void CTimer::setRemaining(NLMISC::TTime time,CTimerEvent* eventObject)\n{\n\tset(/*TimerManager->getTime()+*/time,eventObject);\n}\n\ninline void CTimer::setRemaining(NLMISC::TTime time,CTimerEvent* eventObject,uint32 variation)\n{\n\tset(/*TimerManager->getTime()+*/time,eventObject,variation);\n}\n\ninline bool CTimer::setTime( NLMISC::TTime SecondSince1970,CTimerEvent* eventObject,uint32 millisecond )\n{\n    NLMISC::TTicks ticks = SecondSince1970 - NLMISC::CTime::getSecondsSince1970();\n\n    if ( ticks <= 0 )\n    {\n        nlwarning(\"Set Timer Fail .  %s\", LocalTime.printtime( SecondSince1970 ));\n        //delete eventObject;\n        if (_Event!=NULL)\n            _Event->clear();\n        //_Event= eventObject;\n        return false;\n    }\n\n    ticks *= 1000;\n\n    if ( millisecond!=0 )\n    {\n        uint32 variation = millisecond/TimerManager->getUpdateTimeout();\n        if (variation==0)   {    variation = 1;    }\n        setRemaining( ticks, eventObject, variation );\n    }\n    else\n    {\n        setRemaining( ticks, eventObject );\n    }\n    return true;\n}\n\ninline void CTimer::reset()\n{\n\tif (_Event==NULL)\n\t\treturn;\n\t_Event->clear();\n\t_Event=NULL;\n}\n\ninline bool CTimer::isActive() const\n{\n\treturn (_Event!=NULL) && _Event->isActive();\n}\n\ninline NLMISC::TGameCycle CTimer::getTime() const\n{\n\tif (!isActive())\n\t\treturn 0;\n\treturn _Event->getTime();\n}\n\ninline NLMISC::TGameCycle CTimer::getTimeRemaining() const\n{\n\tif (!isActive())\n\t\treturn 0;\n\treturn getTime()/*-(TimerManager->getTime())*/;\n}\n\ninline CTimerEvent* CTimer::getEvent()\n{\n\treturn _Event;\n}\n\n//-------------------------------------------------------------------------------------------------\n// inlines CTimerEvent\n//-------------------------------------------------------------------------------------------------\n\ninline CTimerEvent::CTimerEvent()\n{\n\t_Owner\t= NULL;\n\t_Time\t= 0;\n}\n\ninline CTimerEvent::~CTimerEvent()\n{\n}\n\ninline void CTimerEvent::set(CTimer* owner,NLMISC::TGameCycle time)\n{\n\tBOMB_IF(owner==NULL,\"Impossible to set a timer with a NULL owner\",return);\n\tBOMB_IF(_Owner!=NULL && _Owner!=owner,\"Attempt to change owner of an active event\",return);\n\n\t_Owner\t= owner;\n\t_Time\t= time;\n\tCTimerManager::getInstance()->getEventVector(time).push_back(this);\n}\n\ninline void CTimerEvent::set(CTimer* owner,NLMISC::TGameCycle time,uint32 variation)\n{\n\tBOMB_IF(variation==0,\"shouldn't call this method with variation value of 0\", set(owner,time));\n\tBOMB_IF(variation>256,\"shouldn't call this method with variation value of >256\", variation=256);\n\n\tBOMB_IF(owner==NULL,\"Impossible to set a timer with a NULL owner\", return);\n\tBOMB_IF(_Owner!=NULL && _Owner!=owner,\"Attempt to change owner of an active event\", return);\n\t_Owner\t= owner;\n\n\tCTimerManager* mgr=CTimerManager::getInstance();\n\tCTimerManager::TEventVector *best=NULL;\n\tuint32 bestLength=~0u;\n\n\tfor (uint32 i=0;i<variation;++i)\n\t{\n\t\tCTimerManager::TEventVector& vect= mgr->getEventVector(time+i);\n\t\tuint32 length=(uint32)vect.size();\n\t\tif (length<=bestLength)\n\t\t{\n\t\t\tbestLength= length;\n\t\t\tbest=&vect;\n\t\t\t_Time = time + i;\n\t\t}\n\t}\n\tBOMB_IF(best==NULL,\"BUG: This can never happen!\",return)\n\tbest->push_back(this);\n}\n\ninline NLMISC::TGameCycle CTimerEvent::getTime() const\n{\n\treturn _Time;\n}\n\ninline CTimer* CTimerEvent::getOwner() const\n{\n\treturn _Owner;\n}\n\ninline bool CTimerEvent::isActive() const\n{\n\treturn _Owner!=NULL;\n}\n\ninline void CTimerEvent::clear()\n{\n\t_Owner=NULL;\n}\n\ninline void CTimerEvent::processEvent()\n{\n\tCTimer* owner=_Owner;\n\tBOMB_IF(owner==NULL,\"Attempt to process an event that no longer has a valid owner\",return)\n\n\t// mark the event as expired - the state may be chnaged during the timer callback...\n\t// NOTE: This operation results in '_Owner' being set to NULL\n\t_Owner->reset();\n\n\t// call the virtual callback\n\ttimerCallback(owner);\n}\n\n\n//-------------------------------------------------------------------------------------------------\n// inlines CTimerManager\n//-------------------------------------------------------------------------------------------------\n\ninline CTimerManager::CTimerManager()\n\t: _CurrentTick(0), _LastTick(0), _LocalTime(0), _UpdateTimeout(100)\n{}\n\ninline CTimerManager* CTimerManager::getInstance()\n{\n\tstatic CTimerManager* instance= NULL;\n\tif (instance==NULL)\n\t{\n\t\tinstance=new CTimerManager;\n\t}\n\treturn instance;\n}\n\ninline CTimerManager::TEventVector& CTimerManager::getEventVector(NLMISC::TGameCycle time)\n{\n\treturn _EventVectors[uint32(time&TIMER_VECTOR_MASK)];\n}\n\n//-------------------------------------------------------------------------------------------------\n#endif\n"
  },
  {
    "path": "code/EVA/server/server_share/tools.cpp",
    "content": "#include \"tools.h\"\n#include <ctime>\n\nusing namespace std;\nusing namespace NLMISC;\n\n//NLMISC::CMutex LocalTime.m_mutex(\"LocalTime.m_mutex\");\n//char LocalTime.m_cstime[LocalTime.TIME_STR_MAX];\n//NLMISC::TTime LocalTime.m_CurrTime;\n\n\nCLocalTime::CLocalTime():m_mutex(\"LocalTime.m_mutex\"),m_TimeZone(0)\n{\n    m_CurrTime = CTime::getLocalTime();\n    CalcTimeZone();\n}\n\n\ntm CLocalTime::gettime( const time_t time )\n{\n    struct tm timeinfo;\n\n#ifdef NL_OS_UNIX\n    localtime_r(&time, &timeinfo);\n#else\n    localtime_s(&timeinfo, &time);\n#endif // NL_OS_UNIX\n\n\t//m_mutex.enter();\n\t//tm *tms = std::localtime(&time);\n\t//timeinfo = *tms;\n\t//m_mutex.leave();\n\n\treturn timeinfo;\n}\n\ntm CLocalTime::gettime()\n{\n    //time_t t;\n    //time(&t);\n\treturn gettime(std::time(NULL));\n}\n\nuint32 CLocalTime::str2time(std::string strTime)\n{\n    tm CurTime = LocalTime.gettime(CTime::getSecondsSince1970());\n\n    // ;\n    std::string::size_type unOffsetA = strTime.find_first_of( '-' );\n\n    // ;\n    if ( unOffsetA != std::string::npos )\n    {\n        std::string year = strTime.substr( 0 , unOffsetA );\n        if ( year.empty() )\n            return 0;\n\n        CurTime.tm_year = atoi( year.c_str() )-1900;\n        strTime = strTime.substr( unOffsetA + 1 );\n\n        // ;\n        unOffsetA = strTime.find_first_of( '-' );\n        if ( unOffsetA != std::string::npos )\n        {\n            std::string mon = strTime.substr( 0 , unOffsetA );\n            if ( mon.empty() )\n                return -1;\n\n            CurTime.tm_mon = atoi( mon.c_str() )-1;\n            strTime = strTime.substr( unOffsetA + 1 );\n\n            // ;\n            unOffsetA = strTime.find_first_of(' ');\n            if ( unOffsetA != std::string::npos )\n            {\n                std::string day = strTime.substr( 0 , unOffsetA );\n                if ( day.empty() )\n                    return -1;\n\n                CurTime.tm_mday = atoi( day.c_str() );\n                strTime = strTime.substr( unOffsetA + 1 );\n            }\n        }\n    }\n\n\n    // ʱ;\n    unOffsetA = strTime.find_first_of( ':' );\n    if ( unOffsetA != std::string::npos )\n    {\n        std::string hour = strTime.substr( 0 , unOffsetA );\n        if ( hour.empty() )\n            return -1;\n\n        CurTime.tm_hour = atoi( hour.c_str() );\n        strTime = strTime.substr( unOffsetA + 1 );\n\n        // ;\n        unOffsetA = strTime.find_first_of( ':' );\n        if ( unOffsetA != std::string::npos )\n        {\n            std::string min = strTime.substr( 0 , unOffsetA );\n            if ( min.empty() )\n                return -1;\n\n            CurTime.tm_min = atoi( min.c_str() );\n            strTime = strTime.substr( unOffsetA + 1 );\n\n            // ;\n            if ( !strTime.empty() )\n            {\n                CurTime.tm_sec = atoi( strTime.c_str() );\n            }\n        }\n    }\n\n    return (uint32)std::mktime(&CurTime);\n}\n\nuint32 CLocalTime::mktime( const uint year, const uint month, const uint day, const uint hour, const uint minute, const uint second )\n{\n\ttm tms;\n\ttms.tm_year = year;\n\ttms.tm_mon  = month;\n\ttms.tm_mday = day;\n\ttms.tm_hour = hour;\n\ttms.tm_min  = minute;\n\ttms.tm_sec  = second;\n    tms.tm_isdst= 0;\n\n\treturn (uint32)std::mktime(&tms);\t\t//nl_mktime\n}\n\nuint32 CLocalTime::gettime( TTimeOperaion time_opt, sint32 time_val, uint32 base_time )\n{\n\tuint32 change_second = ( base_time > 0 ) ? base_time : CTime::getSecondsSince1970();\n\n    tm t = gettime( change_second );\n  \n    switch (time_opt)\n    {\n    case NEXT_DAY:\n        {\n            //  tm_mday [1-31]\n            if ( t.tm_mday > time_val )\n            {\n                // ǰڴҪڣ Ϊ¸µ\n                ++t.tm_mon;\n                t.tm_mday = time_val;\n            }\n            else\n            {\n                t.tm_mday = time_val;\n            }\n            change_second = std::mktime(&t);\n            break;\n        }\n    case NEXT_WEEK:\n        {\n            //  tm_mday [0-6]\n            if ( t.tm_wday > time_val )\n            {\n                // ǰڴҪڣ Ϊڵ\n                sint day = t.tm_wday - time_val;\n                change_second -= DAY_SECONDS * day;\n                change_second += WEEK_SECONDS;\n            }\n            else\n            {\n                sint day = time_val - t.tm_wday;\n                change_second += DAY_SECONDS * day;\n            }  \n            break;\n        }\n    case NEXT_HOUR:\n        {\n            //  tm_hour [0,23]\n            if ( t.tm_hour > time_val )\n            {\n                // ǰʱҪʱ䣬 Ϊڶʱ\n                sint hour = t.tm_hour - time_val;\n                change_second -= HOUR_SECONDS * hour;\n                change_second += DAY_SECONDS;\n            }\n            else\n            {\n                sint hour = time_val - t.tm_hour;\n                change_second += HOUR_SECONDS * hour;\n            }\n            break;\n        }\n    case ADD_HOUR:\n        {\n            sint32 day = time_val / DAY_HOURS;\n            if (day>0)\n            {\n                //ҪNext_Hourһ  tm_mdayϴڵ\n                t.tm_mday += day; \n            }\n            else\n            {\n                t.tm_hour += time_val;    \n            }\n            change_second = std::mktime(&t);\n            break;\n        }\n    default:\n        nlassertd(0);\n        break;\n    }\n\n    return change_second;\n}\n\nuint32  CLocalTime::gettime( vector<TimeOPT> vct_opt )\n{\n    uint32 change_second = CTime::getSecondsSince1970();\n\n    //for ( uint i=0; i<vct_opt.size(); ++i )\n    //{\n    //    //change_second = gettime( vct_opt[i].opt_type, vct_opt[i].value, change_second );\n    //}\n\n    return change_second;\n}\n\nconst char* CLocalTime::printtime( tm& tms )\n{\n    std::strftime (m_cstime, TIME_STR_MAX, \"%Y/%m/%d %H:%M:%S\", &tms);\n    return m_cstime;\n}\n\nconst char* CLocalTime::printtime( const uint32 time )\n{\n    tm t = gettime(time);\n    return printtime(t);\n}\n\nvoid CLocalTime::CalcTimeZone()\n{\n    time_t time_utc;  \n\n    // Get the UTC time  \n    time(&time_utc);  \n\n    tm tm_local = gettime(time_utc);\n\n    time_t time_local;  \n\n    // Change tm to time_t   \n    time_local = std::mktime(&tm_local);  \n\n    // Change it to GMT tm  \n    tm* tm_gmt = gmtime(&time_utc);\n\n    m_TimeZone = tm_local.tm_hour - tm_gmt->tm_hour;  \n}\n\n\n\n"
  },
  {
    "path": "code/EVA/server/server_share/tools.h",
    "content": "﻿#ifndef SWG_TOOLS_H\n#define SWG_TOOLS_H\n\n#include <nel/misc/singleton.h>\n#include <nel/net/unified_network.h>\n#include <nel/misc/mutex.h>\n#include <vector>\n#include \"game_def.h\"\n#include \"utils.h\"\n\n/// 基础小工具命名空间\n//namespace SWG\n\ninline uint64 get_id64( uint64 regionid, uint64 idx )\n{\n    regionid = regionid << 48;\n    uint64 id64 = regionid | idx;\n    return id64;\n}\n\n//inline NLNET::TServiceId GetSID( DEF::RPC_SESSION session )\n//{\n//    uint16 sid =  session & 0x7f;\n//    return NLNET::TServiceId(sid);\n//}\n\ninline uint16 GetSID( DEF::RPC_SESSION session )\n{\n    return session & 0x7f;\n}\n\nstruct BaseTime\n{\n    uint32     start_time;\n    uint32     base_year;\n    uint32     base_mon;\n    uint32     base_mday;\n    uint32     base_hour;\n    uint32     base_min;\n    uint32     base_sec;\n\n    BaseTime(uint32 _time, uint32 _year, uint32 _mon, uint32 _mday, uint32 _hour, uint32 _min, uint32 _sec)\n        : start_time( _time ),\n        base_year( _year ),\n        base_mon( _mon ),\n        base_mday( _mday ),\n        base_hour( _hour ),\n        base_min( _min ),\n        base_sec( _sec )\n    {}\n\n};\n\nenum TTimeOperaion\n{\n    NEXT_YEAR,\n    NEXT_MON,\n    NEXT_DAY,\n    NEXT_WEEK,\n    NEXT_HOUR,\n    ADD_HOUR,\n};\n\nstruct TimeOPT\n{\n    TTimeOperaion    opt_type;\n    sint32       value;\n\n    TimeOPT( TTimeOperaion _opt, sint _value )\n        :opt_type(_opt),value(_value)\n    {}\n};\n\nconst sint32 DAY_HOURS      = 24;\nconst sint32 MINUTE_SECONDS = 60;\nconst sint32 HOUR_SECONDS   = MINUTE_SECONDS * 60;\nconst sint32 DAY_SECONDS    = HOUR_SECONDS * 24;\nconst sint32 WEEK_SECONDS   = DAY_SECONDS * 7;\n\n//struct ADD_DAY : public TimeOPT\n//{\n//    ADD_DAY( sint day )\n//    :TimeOPT(TimeOPT::ADD_DAY,day){}\n//};\n//\n//TimeOPT TimeOPTArray[] =\n//{\n//    TimeOPT(TimeOPT::ADD_DAY, 1),\n//};\n\nclass CLocalTime : public NLMISC::CSingleton<CLocalTime>\n{\npublic:\n    CLocalTime();\n\n\ttm gettime(); \n\ttm gettime( const time_t time ); \n\n    ///  根据字符串获取时间   接受格式：2014-12-26 3:0:0\n    uint32 str2time(std::string strTime);\n\n    uint32 gettime( TTimeOperaion time_opt, sint32 time_val, uint32 _time=0/*, BaseTime base_time*/ );\n    uint32 gettime( std::vector<TimeOPT> vct_opt );\n\n\tuint32 mktime( const uint year, const uint month, const uint day, const uint hour, const uint minute, const uint second );\n\n    const char* printtime(tm& tms);\n    const char* printtime(const uint32 time);\n\n\tconst NLMISC::TTime  GetCurrTime()\t{ return m_CurrTime; }\n\tvoid SetCurrTime( NLMISC::TTime curr_time )\t{ m_CurrTime = curr_time; }\n\n    inline uint32 GetDay( uint32 time_seconds )\n    {\n        return (time_seconds+(HOUR_SECONDS*m_TimeZone))/DAY_SECONDS;\n    }\n\n    inline bool SameDay( uint32 time_seconds1, uint32 time_seconds2 )\n    {\n        return GetDay(time_seconds1)==GetDay(time_seconds2);\n    }\n\nprivate:\n\n    void  CalcTimeZone();\n\nprivate:\n\n    enum \n    {\n        TIME_STR_MAX = 25,\n    };\n\n\tNLMISC::CMutex      m_mutex;\n    char                m_cstime[TIME_STR_MAX];\n\tNLMISC::TTime       m_CurrTime;\n    uint32              m_TimeZone;\n};\n\n#define LocalTime CLocalTime::instance()\n\nconst uint32 Crc32Table[] =\n{\n    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,\n    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,\n    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,\n    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,\n    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,\n    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,\n    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,\n    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,\n    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,\n    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,\n    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,\n    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,\n    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,\n    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,\n    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,\n    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,\n    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,\n    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,\n    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,\n    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,\n    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,\n    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,\n    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,\n    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,\n    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,\n    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,\n    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,\n    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,\n    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,\n    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,\n    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,\n    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,\n    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d\n};\n\n\ninline uint32 crc32(uint32 crc, const uint8* buffer, uint length)\n{\n    crc = crc ^ 0xffffffffL;\n\n    for (uint i = 0; i < length; ++i)\n    {\n        crc = Crc32Table[(crc ^ buffer[i]) & 0xff] ^ (crc >> 8);\n    }\n\n    return (crc ^ 0xffffffffL);\n}\n\n\n\n#endif\n\n"
  },
  {
    "path": "code/EVA/server/server_share/utils.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//-------------------------------------------------------------------------------------------------\n// includes\n//-------------------------------------------------------------------------------------------------\n\n#include \"stdpch.h\"\n#include \"nel/misc/sstring.h\"\n\n\n//-------------------------------------------------------------------------------------------------\n// namespaces\n//-------------------------------------------------------------------------------------------------\n\nusing namespace NLMISC;\n\n\n//-----------------------------------------------------------------------------\n// cleanPath - convert a path to standardised format\n//-----------------------------------------------------------------------------\n\nCSString cleanPath(const CSString& path,bool addTrailingSlash)\n{\n\tCSString result;\n\n\t// split the path up into its component elements\n\tCVectorSString pathComponents;\n\tpath.unquoteIfQuoted().splitByOneOfSeparators(\"/\\\\\",pathComponents,false,false,true,false,true);\n\n\t// iterate over path components collapsing '.' and '..' entries\n\tfor (uint32 i=0;i<pathComponents.size();++i)\n\t{\n\t\t// skip \".\" entries\n\t\tif (pathComponents[i]==\".\")\n\t\t{\n\t\t\tpathComponents[i].clear();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// deal with \"..\"\n\t\tif (pathComponents[i]==\"..\")\n\t\t{\n\t\t\t// run back through our component list looking for an element to remove\n\t\t\tuint32 j;\n\t\t\tfor (j=i;j--;)\n\t\t\t{\n\t\t\t\tif (!pathComponents[j].empty())\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// if we found an element then remove it and the '..' as well\n\t\t\tif (j!=std::numeric_limits<uint32>::max())\n\t\t\t{\n\t\t\t\tpathComponents[j].clear();\n\t\t\t\tpathComponents[i].clear();\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\t// treat the special case where original path started with a '/' or '//'\n\tif (path.left(1)==\"/\" || path.left(1)==\"\\\\\")\n\t{\n\t\tresult= (path.left(2).right(1)==\"/\" || path.left(2).right(1)==\"\\\\\")? \"//\": \"/\";\n\t}\n\n\t// concatenate the path bits\n\tfor (uint32 i=0;i<pathComponents.size();++i)\n\t{\n\t\tif (!pathComponents[i].empty())\n\t\t{\n\t\t\tresult+= pathComponents[i];\n\t\t\tresult+= '/';\n\t\t}\n\t}\n\n\t// if we're not supposed to have a trailing slash then get rid of the one that's added by default\n\tif (addTrailingSlash==false && path.right(1)!='/' && path.right(1)!='\\\\')\n\t{\n\t\tresult.resize(result.size()-1);\n\t}\n\n\treturn result;\n}\n"
  },
  {
    "path": "code/EVA/server/server_share/utils.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef UTILS_H\n#define UTILS_H\n\n//-------------------------------------------------------------------------------------------------\n// includes\n//-------------------------------------------------------------------------------------------------\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/sstring.h\"\n\n#include <list>\n\n//-------------------------------------------------------------------------------------------------\n// UTILITY FUNCTIONS\n//-------------------------------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\ninline std::string capitalize(const std::string & s)\n{\n\tif ( s.empty() )\n\t\treturn s;\n\n\treturn NLMISC::toUpper( s.substr(0,1) ) + NLMISC::toLower( s.substr(1,std::string::npos) );\n}\n\ninline ucstring capitalize(const ucstring & s)\n{\n\tif ( s.empty() )\n\t\treturn s;\n\n\treturn NLMISC::toUpper( s.substr(0,1) ) + NLMISC::toLower( s.substr(1,std::string::npos) );\n}\n\n\n//-------------------------------------------------------------------------------------------------\n// HANDY MACROS - For forcing the pre-preprocessor to evaluate concatenation operations nicely\n//-------------------------------------------------------------------------------------------------\n\n// a Few examples:\n// ---------------\n//\n//\t#define TOTO TATA\n//\tMACRO_CONCAT(a,TOTO)\t\t=> aTOTO\n//\tMACRO_CONCAT2(a,TOTO)\t\t=> aTATA\n//\tMACRO_TOTXT(TOTO)\t\t\t=> \"TOTO\"\n//\tMACRO_TOTXT2(TOTO)\t\t\t=> \"TATA\"\n//\n///\tMACRO_CONCAT(a,__LINE__)\t=> a__LINE__\n//\tMACRO_CONCAT2(a,__LINE__)\t=> a123\n//\tMACRO_TOTXT(__LINE__)\t\t=> \"__LINE__\"\n//\tMACRO_TOTXT2(__LINE__)\t\t=> \"123\"\n//\n//\t__FILE_LINE__\t\t\t\t=> \"utils.h:123:\"\n\n#define MACRO_CONCAT(a,b) a##b\n#define MACRO_CONCAT2(a,b) CONCAT(a,b)\n#define MACRO_TOTXT(a) #a\n#define MACRO_TOTXT2(a) TOTXT(a)\n#define __FILE_LINE__ __FILE__ \":\" TOTXT2(__LINE__)\":\"\n\n\n//-------------------------------------------------------------------------------------------------\n// LOGGING / DEBUGGING MACROS\n//-------------------------------------------------------------------------------------------------\n\n#ifdef NL_DEBUG\n\t#define DEBUG_STOP nlstop;\n\t#define nlassertd(a) nlassert(a)\n#else\n\t#define DEBUG_STOP \\\n\t\tstd::string stack; \\\n\t\tNLMISC::getCallStack(stack); \\\n\t\tstd::vector<std::string> contexts;\\\n\t\tNLMISC::explode(stack, std::string(\"\\n\"), contexts);\\\n\t\tnldebug(\"Dumping callstack :\"); \\\n\t\tfor (uint i=0; i<contexts.size(); ++i) \\\n\t\t\tnldebug(\"  %3u : %s\", i, contexts[i].c_str());\n\t#define\tnlassertd(a) if (0) { } else { }\n#endif\n\n// the following set of definess can be undefined and re-defined to add user code to execute\n// systematically when GIVEUP, DROP or BOMB macros are triggered\n// eg #define ON_BOMB logError(__FILE__,__LINE__,msg);\n#define ON_GIVEUP\n#define ON_DROP\n#define ON_BOMB\n\n// info and warning macros\n#define INFO(msg) nlinfo((NLMISC::CSString()<<msg).c_str());\n#define WARN(msg) nlwarning((NLMISC::CSString()<<msg).c_str());\n\n// unconditional abort macros\n#define STOP(msg) { WARN(msg) DEBUG_STOP }\n#define GIVEUP(msg,action)\t{ INFO(msg) { ON_GIVEUP; } { action; } }\n#define DROP(msg,action)\t{ WARN(msg) { ON_DROP;   } { action; } }\n#define BOMB(msg,action)\t{ STOP(msg)\t{ ON_BOMB;   } { action; } }\n\n// conditional warn and abort macros\n#define GIVEUP_IF(condition,msg,action)\t\tif (!(condition));else GIVEUP(msg,action)\n#define WARN_IF(condition,msg)\t\t\t\tif (!(condition));else WARN(msg)\n#define DROP_IF(condition,msg,action)\t\tif (!(condition));else DROP(msg,action)\n#define BOMB_IF(condition,msg,action)\t\tif (!(condition));else BOMB(msg,action)\n#define STOP_IF(condition,msg)\t\t\t\tif (!(condition));else STOP(msg)\n\n// testing for variable value changes\n#define ON_CHANGE(type,var,code)\\\n\tclass __COnChange##var\\\n\t{\\\n\tpublic:\\\n\t\tconst type& _Var;\\\n\t\tconst type _OldVal;\\\n\t\t__COnChange##var(const type& var): _Var(var), _OldVal(var) {}\\\n\t\t~__COnChange##var() { if(_OldVal!=_Var) { code; } }\\\n\t}\\\n\t__onChange##__LINE__(var);\n\n#define ON_CHANGE_ASSERT(type,var) ON_CHANGE(type,var,nlerror(\"Variable \"#var\" changed from %s to %s\",NLMISC::toString(_OldVal).c_str(),NLMISC::toString(_Var).c_str()))\n\n\n//-------------------------------------------------------------------------------------------------\n// A handy 'nldebug', 'nlinfo' & 'nlwarning' override system\n//-------------------------------------------------------------------------------------------------\n//\n// The system includes a set of object classes\n// To override one or more of the standard NeL log channels one simply instantiates the appropriate class\n// with the new log channel as a parameter.\n// The log channel in question will revert to its previous value on destruction of the override object\n//\n// Usage Example:\n//\n//\tvoid doSomething()\n//\t{\n//\t\tnlinfo(\"bla\");\n//\t\tnlwarning(\"bla\");\n//\t}\n//\n//\tNLMISC_COMMAND(bla,\"bla\",\"bla\")\n//\t{\n//\t\tCNLLogOverride(&log);\n//\t\tdoSomething();\n//\t\treturn true;\n//\t}\n//\n\n//-------------------------------------------------------------------------------------------------\n\n//class CNLDebugOverride\n//{\n//public:\n//\tCNLDebugOverride(NLMISC::CLog *debugLog)\n//\t{\n//\t\tnlassert(debugLog!=NULL);\n//\t\t_OldValue=NLMISC::DebugLog;\n//\t\tnlassert(_OldValue!=NULL);\n//\t\tNLMISC::INelContext::getInstance().setDebugLog(debugLog);\n//\t}\n//\t~CNLDebugOverride()\n//\t{\n//\t\tNLMISC::INelContext::getInstance().setDebugLog(_OldValue);\n//\t}\n//private:\n//\t// prohibit copy\n//\tCNLDebugOverride(const CNLDebugOverride&);\n//\tNLMISC::CLog *_OldValue;\n//};\n//\n////-------------------------------------------------------------------------------------------------\n//\n//class CNLInfoOverride\n//{\n//public:\n//\tCNLInfoOverride(NLMISC::CLog *infoLog)\n//\t{\n//\t\tnlassert(infoLog!=NULL);\n//\t\t_OldValue=NLMISC::InfoLog;\n//\t\tnlassert(_OldValue!=NULL);\n//\t\tNLMISC::INelContext::getInstance().setInfoLog(infoLog);\n//\t}\n//\t~CNLInfoOverride()\n//\t{\n//\t\tNLMISC::INelContext::getInstance().setInfoLog(_OldValue);\n//\t}\n//private:\n//\t// prohibit copy\n//\tCNLInfoOverride(const CNLInfoOverride&);\n//\tNLMISC::CLog *_OldValue;\n//};\n//\n////-------------------------------------------------------------------------------------------------\n//\n//class CNLWarningOverride\n//{\n//public:\n//\tCNLWarningOverride(NLMISC::CLog *warningLog)\n//\t{\n//\t\tnlassert(warningLog!=NULL);\n//\t\t_OldValue=NLMISC::WarningLog;\n//\t\tnlassert(_OldValue!=NULL);\n//\t\tNLMISC::INelContext::getInstance().setWarningLog(warningLog);\n//\t}\n//\t~CNLWarningOverride()\n//\t{\n//\t\tNLMISC::INelContext::getInstance().setWarningLog(_OldValue);\n//\t}\n//private:\n//\t// prohibit copy\n//\tCNLWarningOverride(const CNLWarningOverride&);\n//\tNLMISC::CLog *_OldValue;\n//};\n//\n////-------------------------------------------------------------------------------------------------\n//\n//class CNLLogOverride\n//{\n//public:\n//\tCNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog)\t{}\n//\n//private:\n//\tCNLDebugOverride\t_DebugLog;\n//\tCNLInfoOverride\t\t_InfoLog;\n//\tCNLWarningOverride\t_WarningLog;\n//};\n//\n//\n////-------------------------------------------------------------------------------------------------\n//\n//class CNLSmartLogOverride\n//{\n//public:\n//\tCNLSmartLogOverride(NLMISC::CLog *commonLog):\n//\t\t_DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog),\n//\t\t_InfoLog(commonLog),\n//\t\t_WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog)\n//\t\t{}\n//\n//private:\n//\tCNLDebugOverride\t_DebugLog;\n//\tCNLInfoOverride\t\t_InfoLog;\n//\tCNLWarningOverride\t_WarningLog;\n//};\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system\n//-------------------------------------------------------------------------------------------------\n// example:\n// void traceTest2(int i)\n//\t{\n//\t\tCSTRACE;\n//\t\tif (i<2)\n//\t\t\ttraceTest2(++i);\n//\t\telse\n//\t\t\tSHOW_CALLSTACK;\n//\t}\n//\n//\tvoid traceTest()\n//\t{\n//\t\tCSTRACE_MSG(\"foo\");\n//\t\ttraceTest2(0);\n//\t\t{\n//\t\t\tint i=0;\n//\t\t\tCSTRACE_VAR(int,i);\n//\t\t\tCSTRACE_VAL(int,i);\n//\t\t\ti=1;\n//\t\t\tSHOW_CALLSTACK;\n//\t\t}\n//\t\tWARN_CALLSTACK;\n//\t}\n//\n// output:\n//\tINF 3980: >>test.cpp:21: Call Stack:\n//\tINF 3980: >>test.cpp:17\n//\tINF 3980: >>test.cpp:17\n//\tINF 3980: >>test.cpp:17\n//\tINF 3980: >>test.cpp:26: foo\n//\tINF 3980:\n//\tINF 3980: >>test.cpp:33: Call Stack:\n//\tINF 3980: >>test.cpp:31: i=[0]\n//\tINF 3980: >>test.cpp:30: i=>[1]\n//\tINF 3980: >>test.cpp:26: foo\n//\tINF 3980:\n//\tWRN 3980: >>test.cpp:35: Call Stack:\n//\tWRN 3980: >>test.cpp:26: foo\n//\tWRN 3980:\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system - MACROS\n//-------------------------------------------------------------------------------------------------\n// CSTRACE\t\t\t\t\t- displays source file and line number\n// CSTRACE_MSG(msg)\t\t\t- as with trace but with additional simple text message\teg TRACE_MSG(\"hello world\")\n// CSTRACE_VAL(type,name)\t- displays a value (calculated at the moment that the trace is created)\n// CSTRACE_VAR(type,name)\t- displays the value of the given variable at the moment that callstack is displayed\n// SHOW_CALLSTACK\t\t\t- displays the callstack using NLMISC::InfoLog\n// WARN_CALLSTACK\t\t\t- displays the callstack using NLMISC::WarningLog\n\n#define CSTRACE\\\n\tclass __CCallStackEntry##__LINE__: public ICallStackEntry\\\n\t{\\\n\tpublic:\\\n\t\tvirtual void displayEntry(NLMISC::CLog& log) const\\\n\t\t{\\\n\t\t\tlog.displayNL(\">>\"__FILE__\":%d\",__LINE__);\\\n\t\t}\\\n\t}\\\n\t__callStackEntry##__LINE__;\n\n#define CSTRACE_MSG(msg)\\\n\tclass __CCallStackEntry##__LINE__: public ICallStackEntry\\\n\t{\\\n\tpublic:\\\n\t\tvirtual void displayEntry(NLMISC::CLog& log) const\\\n\t\t{\\\n\t\t\tlog.displayNL(\">>\"__FILE__\":%d: %s\",__LINE__,msg);\\\n\t\t}\\\n\t}\\\n\t__callStackEntry##__LINE__;\n\n#define CSTRACE_VAL(type,var)\\\n\tclass __TraceVal_##var: public ICallStackEntry\\\n\t{\\\n\tpublic:\\\n\t\t__TraceVal_##var(const type& var): _Val(var) \\\n\t\t{\\\n\t\t}\\\n\t\tvirtual void displayEntry(NLMISC::CLog& log) const\\\n\t\t{\\\n\t\t\tlog.displayNL(\">>\"__FILE__\":%d: %s=[%s]\",__LINE__,#var,NLMISC::toString(_Val).c_str());\\\n\t\t}\\\n\t\tconst type _Val;\\\n\t}\\\n\t__traceVal_##var(var);\n\n#define CSTRACE_VAR(type,var)\\\n\tclass __TraceVar_##var: public ICallStackEntry\\\n\t{\\\n\tpublic:\\\n\t\t__TraceVar_##var(const type& var): _Var(var) \\\n\t\t{\\\n\t\t}\\\n\t\tvirtual void displayEntry(NLMISC::CLog& log) const\\\n\t\t{\\\n\t\t\tlog.displayNL(\">>\"__FILE__\":%d: %s=>[%s]\",__LINE__,#var,NLMISC::toString(_Var).c_str());\\\n\t\t}\\\n\t\tconst type& _Var;\\\n\t}\\\n\t__traceVar_##var(var);\n\n#define SHOW_CALLSTACK { CSTRACE_MSG(\"Call Stack:\"); CCallStackSingleton::display(NLMISC::InfoLog); }\n#define WARN_CALLSTACK { CSTRACE_MSG(\"Call Stack:\"); CCallStackSingleton::display(NLMISC::WarningLog); }\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system - Private stack entry base class\n//-------------------------------------------------------------------------------------------------\n\nclass ICallStackEntry\n{\npublic:\n\tICallStackEntry();\n\tvirtual ~ICallStackEntry();\n\tvoid displayStack(NLMISC::CLog& log) const;\n\n\tvirtual void displayEntry(NLMISC::CLog& log) const=0;\n\nprivate:\n\tICallStackEntry* _Next;\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system - Public Singleton Class\n//-------------------------------------------------------------------------------------------------\n\nclass CCallStackSingleton\n{\npublic:\n\tstatic ICallStackEntry* getTopStackEntry();\n\tstatic void setTopStackEntry(ICallStackEntry* newEntry);\n\tstatic void display(NLMISC::CLog *log=NLMISC::InfoLog);\n\nprivate:\n\t// this is a singleton so prohibit public construction\n\tCCallStackSingleton() {}\n\n\t// encapsulation of a variable to make it a singleton\n\tstatic ICallStackEntry*& topStackEntry();\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system - Public Singleton inlines\n//-------------------------------------------------------------------------------------------------\n\ninline ICallStackEntry* CCallStackSingleton::getTopStackEntry()\n{\n\treturn topStackEntry();\n}\n\ninline void CCallStackSingleton::setTopStackEntry(ICallStackEntry* newEntry)\n{\n\ttopStackEntry()= newEntry;\n}\n\ninline void CCallStackSingleton::display(NLMISC::CLog *log)\n{\n\tnlassert(log!=NULL);\n\tgetTopStackEntry()->displayStack(*log);\n\tlog->displayNL(\"\");\n}\n\ninline ICallStackEntry*& CCallStackSingleton::topStackEntry()\n{\n\tstatic ICallStackEntry* stackEntry=NULL;\n\treturn stackEntry;\n}\n\n\n//-------------------------------------------------------------------------------------------------\n// A Little CallStack system - Private stack entry base inlines\n//-------------------------------------------------------------------------------------------------\n\ninline ICallStackEntry::ICallStackEntry()\n{\n\t// add self to the call stack\n\t_Next=CCallStackSingleton::getTopStackEntry();\n\tCCallStackSingleton::setTopStackEntry(this);\n}\n\ninline ICallStackEntry::~ICallStackEntry()\n{\n\t// if this object is in the call stack then pop items off the top of the stack\n\t// until this object is no longer in the stack\n\twhile (_Next!=this)\n\t{\n\t\t// get a pointer to the top object on the call stack\n\t\tICallStackEntry* entry= CCallStackSingleton::getTopStackEntry();\n\t\tnlassertd(entry!=NULL);\n\n\t\t// pop the object off the callstack\n\t\tCCallStackSingleton::setTopStackEntry(entry->_Next);\n\n\t\t// mark object as no longer in callstack\n\t\tentry->_Next=entry;\n\t}\n}\n\ninline void ICallStackEntry::displayStack(NLMISC::CLog& log) const\n{\n\t// stop recursing when we reach a NULL object\n\t// (this is implemented in this way in order to ximplify call code)\n\tif (this==NULL)\n\t\treturn;\n\n\t// display this entry\n\tdisplayEntry(log);\n\n\t// recurse through call stack\n\t_Next->displayStack(log);\n}\n\n\n//-------------------------------------------------------------------------------------------------\n// HANDY Utility methods...\n//-------------------------------------------------------------------------------------------------\n\ninline NLMISC::CVectorSString& operator<<(NLMISC::CVectorSString& vect,const NLMISC::CSString s)\n{\n\tvect.push_back(s);\n\treturn vect;\n}\n\n\ntemplate<class T> inline T& vectAppend(std::vector<T>& vect)\n{\n\tvect.resize(vect.size()+1);\n\treturn vect.back();\n}\ntemplate<class T0,class T1> inline void vectInsert(std::vector<T0>& vect,const T1& value)\n{\n\tfor (uint32 i=0;i<vect.size();++i)\n\t\tif (vect[i]== value)\n\t\t\treturn;\n\n\tvect.push_back(value);\n}\n\ntemplate<class T> inline T& listAppend(std::list<T>& list)\n{\n\tlist.resize(list.size()+1);\n\treturn list.back();\n}\n\ninline NLMISC::CSString popString(NLMISC::IStream& stream)\n{\n\tstd::string s;\n\tstream.serial(s);\n\treturn s;\n}\n\ninline sint32 popSint(NLMISC::IStream& stream)\n{\n\tsint32 val;\n\tstream.serial(val);\n\treturn val;\n}\n\ninline uint32 popUint(NLMISC::IStream& stream)\n{\n\tuint32 val;\n\tstream.serial(val);\n\treturn val;\n}\n\ninline bool popBool(NLMISC::IStream& stream)\n{\n\tbool val;\n\tstream.serial(val);\n\treturn val;\n}\n\ntemplate<class T> inline void pushToStream(NLMISC::IStream& stream,const T& value)\n{\n\tstream.serial(const_cast<T&>(value));\n}\n\ninline void pushToStream(NLMISC::IStream& stream,const char* txt)\n{\n\tstd::string s(txt);\n\tstream.serial(s);\n}\n\n//-------------------------------------------------------------------------------------------------\n// HANDY IPtr and IConstPtr CLASSES\n//-------------------------------------------------------------------------------------------------\n// This class gives a base that can be specialised in order to make pointer encapsulation classes\n// it offers the basic standard methods that you have to define every time in the normal way...\n\ntemplate <class C>\nclass IPtr\n{\npublic:\n\tIPtr()\t\t\t\t\t\t\t\t\t\t{ _Ptr= NULL; }\n\tIPtr(C* p)\t\t\t\t\t\t\t\t\t{ operator=(p); }\n\tIPtr& operator=(C* p)\t\t\t\t\t\t{ _Ptr=p; return *this; }\n\tIPtr& operator=(IPtr& other)\t\t\t\t{ _Ptr=other._Ptr; return *this; }\n\tIPtr& operator++()\t\t\t\t\t\t\t{ ++_Ptr; return *this; }\n\tIPtr& operator--()\t\t\t\t\t\t\t{ --_Ptr; return *this; }\n\tconst C* operator->() const\t\t\t\t\t{ return _Ptr; }\n\tconst C& operator*() const\t\t\t\t\t{ return *_Ptr; }\n\toperator C const *() const\t\t\t\t\t{ return _Ptr; }\n\tC* operator->()\t\t\t\t\t\t\t\t{ return _Ptr; }\n\tC& operator*()\t\t\t\t\t\t\t\t{ return *_Ptr; }\n\toperator C*()\t\t\t\t\t\t\t\t{ return _Ptr; }\n\tbool operator==(const IPtr& other) const\t{ return _Ptr==other._Ptr; }\n\tbool operator!=(const IPtr& other) const\t{ return _Ptr!=other._Ptr; }\n\tbool operator==(const C* p) const\t\t\t{ return _Ptr==p; }\n\tbool operator!=(const C* p) const\t\t\t{ return _Ptr!=p; }\nprivate:\n\tC * _Ptr;\n};\n\n\ntemplate <class C>\nclass IConstPtr\n{\npublic:\n\tIConstPtr()\t\t\t\t\t\t\t\t\t\t{ _Ptr= NULL; }\n\tIConstPtr(const C* p)\t\t\t\t\t\t\t{ operator=(p); }\n\tIConstPtr& operator=(const C* p)\t\t\t\t{ _Ptr=p; return *this; }\n\tIConstPtr& operator=(const IConstPtr& other)\t{ _Ptr=other._Ptr; return *this; }\n\tIConstPtr& operator++()\t\t\t\t\t\t\t{ ++_Ptr; return *this; }\n\tIConstPtr& operator--()\t\t\t\t\t\t\t{ --_Ptr; return *this; }\n\tconst C* operator->() const\t\t\t\t\t\t{ return _Ptr; }\n\tconst C& operator*() const\t\t\t\t\t\t{ return *_Ptr; }\n\toperator C const *() const\t\t\t\t\t\t{ return _Ptr; }\n\tbool operator==(const IConstPtr& other) const\t{ return _Ptr==other._Ptr; }\n\tbool operator!=(const IConstPtr& other) const\t{ return _Ptr!=other._Ptr; }\n\tbool operator==(const C* p) const\t\t\t\t{ return _Ptr==p; }\n\tbool operator!=(const C* p) const\t\t\t\t{ return _Ptr!=p; }\nprivate:\n\tC const * _Ptr;\n};\n\n\n//-------------------------------------------------------------------------------------------------\n// HANDY cleanPath() method for cleaning file system paths\n//-------------------------------------------------------------------------------------------------\n\n// Clean a path performing the following operations:\n//\t- convert '\\\\' characters to '/'\n//\t- replace '//' strings in the middle of the path with '/'\n//\t- remove '.' directory entries\n//\t- colapse '..' directory entries (removing parent entries)\n//\t- append a final '/' (optionally)\n//\n// examples:\n//\t- a:/bcd/efg/\t\t=>\ta:/bcd/efg/ (no change)\n//\t- a:\\bcd\\efg\t\t=>\ta:/bcd/efg/\n//\t- \\bcd\\\\efg\t\t\t=>\t/bcd/efg/\n//\t- \\\\bcd\\efg\t\t\t=>\t//bcd/efg/\n//\t- \\bcd\\.\\efg\t\t=>\t/bcd/efg/\n//\t- \\bcd\\..\\efg\t\t=>\t/efg/\n//\t- bcd\\..\\efg\t\t=>\tefg/\n//\t- bcd\\..\\..\\efg\t\t=>\t../efg/\n//\t- \\bcd\\..\\..\\efg\t=>\t/efg/\t\t(NOTE: the redundant '..' entry is lost due to leading '\\')\n//\nNLMISC::CSString cleanPath(const NLMISC::CSString& path,bool addTrailingSlash);\n\n//\n//template <class T>\n//struct TTypeLimits\n//{\n//\tstatic T max();\n//\tstatic T min();\n//\tstatic T\tfloor(T value);\n//};\n//\n//template <>\n//struct TTypeLimits<uint8>\n//{\n//\tstatic uint8 max()\t\t\t{\t\treturn (uint8)0xff;\t}\n//\tstatic uint8 min()\t\t\t{\t\treturn 0;\t\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 0,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic uint8\tfloor(uint8 value)\t{\treturn value;\t\t}\n//};\n//template <>\n//struct TTypeLimits<uint16>\n//{\n//\tstatic uint16 max()\t\t\t{\t\treturn (uint16)0xffff;\t}\n//\tstatic uint16 min()\t\t\t{\t\treturn 0;\t\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 0,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic uint16\tfloor(uint16 value)\t{\treturn value;\t\t}\n//};\n//template <>\n//struct TTypeLimits<uint32>\n//{\n//\tstatic uint32 max()\t\t\t{\t\treturn 0xffffffffu;\t}\n//\tstatic uint32 min()\t\t\t{\t\treturn 0;\t\t\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 0,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic uint32\tfloor(uint32 value)\t{\treturn value;\t\t}\n//};\n///*\n//#ifdef NL_OS_WINDOWS\n//template <>\n//struct TTypeLimits<unsigned int> : public TTypeLimits<uint32>\n//{\n//};\n//#endif\n//*/\n//template <>\n//struct TTypeLimits<uint64>\n//{\n//\tstatic uint64 max()\t\t\t{\t\treturn UINT64_CONSTANT(0xffffffffffffffff);\t}\n//\tstatic uint64 min()\t\t\t{\t\treturn 0;\t\t\t\t\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 0,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic uint64\tfloor(uint64 value)\t{\treturn value;\t\t}\n//};\n//\n//template <>\n//struct TTypeLimits<sint8>\n//{\n//\tstatic sint8 max()\t\t{\t\treturn (sint8)0x7f;\t}\n//\tstatic sint8 min()\t\t{\t\treturn (sint8)0x80;\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic sint8\tfloor(sint8 value)\t{\treturn value;\t\t}\n//};\n//template <>\n//struct TTypeLimits<sint16>\n//{\n//\tstatic sint16 max()\t\t\t{\t\treturn (sint16)0x7fff;\t}\n//\tstatic sint16 min()\t\t\t{\t\treturn (sint16)0x8000;\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic sint16\tfloor(sint16 value)\t{\treturn value;\t\t}\n//};\n//template <>\n//struct TTypeLimits<sint32>\n//{\n//\tstatic sint32 max()\t\t\t{\t\treturn (sint32)0x7fffffff;\t}\n//\tstatic sint32 min()\t\t\t{\t\treturn (sint32)0x80000000;\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic sint32\tfloor(sint32 value)\t{\treturn value;\t\t}\n//};\n///*#ifdef NL_OS_WINDOWS\n//template <>\n//struct TTypeLimits<int> : public TTypeLimits<sint32>\n//{\n//};\n//#endif*/\n//template <>\n//struct TTypeLimits<sint64>\n//{\n//\tstatic sint64 max()\t\t\t{\t\treturn SINT64_CONSTANT(0x7fffffffffffffff);\t}\n//\tstatic sint64 min()\t\t\t{\t\treturn SINT64_CONSTANT(0x8000000000000000);\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 1,\n//\t};\n//\tstatic sint64\tfloor(sint64 value)\t{\treturn value;\t\t}\n//};\n//\n//template <>\n//struct TTypeLimits<float>\n//{\n//\tstatic float max()\t\t\t{\t\treturn FLT_MAX;\t}\n//\tstatic float min()\t\t\t{\t\treturn FLT_MIN;\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 0,\n//\t};\n//\tstatic float\tfloor(float f)\t{ return f < 0 ? (float)::ceil(f) : (float)::floor(f);\t}\n//};\n//template <>\n//struct TTypeLimits<double>\n//{\n//\tstatic double max()\t\t\t{\t\treturn DBL_MAX;\t}\n//\tstatic double min()\t\t\t{\t\treturn DBL_MIN;\t}\n//\tenum\n//\t{\n//\t\tIsSigned = 1,\n//\t\tIsInteger = 0,\n//\t};\n//\tstatic double\tfloor(double d)\t{ return d < 0 ? ::ceil(d) : ::floor(d);\t}\n//};\n//\n//\n//\n//template <class T, class U>\n//inline T checkedCast(U val)\n//{\n//\ttypedef TTypeLimits<U>\tTLimitIn;\n//\ttypedef TTypeLimits<T>\tTLimitOut;\n//\n//\t// Only allow checked cast to integer type !\n//\tnlctassert(TLimitOut::IsInteger);\n//\n//\tT dest = (T) val;\n//\tU check = (U) dest;\n//\n//\tif (val < 0)\n//\t{\n//\t\tBOMB_IF(check != TLimitIn::floor(val), \"checkedCast : Value \"<<val<<\" exceed the negative capacity of \"<<typeid(T).name()<<\" clamping at min value\", return TLimitOut::min());\n//\t}\n//\telse\n//\t{\n//\t\tBOMB_IF(check != TLimitIn::floor(val), \"checkedCast : Value \"<<val<<\" exceed the positive capacity of \"<<typeid(T).name()<<\" clamping at max value\", return TLimitOut::max());\n//\t}\n//\n//\treturn T(dest);\n//}\n\n\n//-------------------------------------------------------------------------------------------------\n#endif\n"
  },
  {
    "path": "code/EVA/server/shard.screen.rc",
    "content": "# ------------------------------------------------------------------------------\n# SCREEN KEYBINDINGS\n# ------------------------------------------------------------------------------\n\n# Set default encoding using utf8\ndefutf8 on\n\n## 解决中文乱码,这个要按需配置\ndefencoding utf8\nencoding utf8 utf8\n\n# 屏幕缓冲区行数\ndefscrollback 10000\n \n# 下标签设置\nhardstatus on\ncaption always '%{gk}[%{G}%H%{g}][%= %{wk}%?%-Lw%?%{=b kR}(%{W}%n*%f %t%?(%u)%?%{=b kR})%{= kw}%?%+Lw%?%?%= %{g}]%{=b C}[%m/%d/%y %C %A]%{W}'\n \n#关闭闪屏\nvbell off\n \n#Keboard binding\n# bind Alt+z to move to previous window\nbindkey ^[z prev\n# bind Alt+x to move to next window\nbindkey ^[x next\n\n# bind Alt`~= to screen0~12\nbindkey \"^[`\" select 0\nbindkey \"^[1\" select 1\nbindkey \"^[2\" select 2\nbindkey \"^[3\" select 3\nbindkey \"^[4\" select 4\nbindkey \"^[5\" select 5\nbindkey \"^[6\" select 6\nbindkey \"^[7\" select 7\nbindkey \"^[8\" select 8\nbindkey \"^[9\" select 9\nbindkey \"^[0\" select 10\nbindkey \"^[-\" select 11\nbindkey \"^[=\" select 12\n\n# Remove some stupid / dangerous key bindings\nbind ^k\n#bind L\nbind ^\\\n# Make them better\nbind \\\\ quit\nbind K kill\nbind I login on\nbind O login off\n\nchdir $MT_PATH/server\n\n# aes\n#screen -t aes /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh aes valgrind --leak-check=full admin_service -A. -C. --fulladminname=admin_executor_service --shortadminname=AES --nobreak --writepid\n#screen -t aes /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh aes admin_service -A. -C. --fulladminname=admin_executor_service --shortadminname=AES --nobreak --nolog\n\n# rns\nscreen -t rns /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh rns naming_service -A. -C. -W. --nobreak --nolog\n\n# lgs\n#screen -t lgs /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh lgs logger_service -A. -C. --nobreak --nolog\n\n# fes_0\nscreen -t fes_0 /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh fes_0 frontend_service -A. -C. --nobreak --nolog\n\n# sch\nscreen -t sch /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh sch schedule_service -A. -C. --nobreak --nolog\n\n# pds\n#screen -t pds /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh pds persistant_data_service -A. -C. --nobreak --nolog\n\n# lgc_0\nscreen -t lgc_0 /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh lgc_0 player_logic_service -A. -C. --nobreak --nolog\n\n# mail\n#screen -t mail /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh mail mail_service -A. -C. --nobreak --nolog\n\n# ras\n#screen -t ras /bin/sh $MT_PATH/tools/scripts/linux/service_launcher.sh ras admin_service -A. -C. --fulladminname=admin_service --shortadminname=AS --nobreak --nolog\n\n\n\n\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/clean_log.sh",
    "content": "rm $MT_PATH/server/*.log\nrm $MT_PATH/server/core*\nrm $MT_PATH/server/*core\nrm $MT_PATH/server/v*_core.*\nrm $MT_PATH/server/core*\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/generate_packed_sheets.sh",
    "content": "\ncd ~/MT/code/EVA/server\n\nshard stop\n\nclean_log.sh\n\nrm src/*/*.packed_sheets\n\nmake\n\nshard batchstart\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/loop_aes.sh",
    "content": "#!/bin/sh -\n\nDOMAIN=$(pwd |sed \"s%/home/nevrax/%%\")\n\nwhile(true)\ndo\n  echo AESAliasName= \\\"aes_$(hostname -s)\\\"\\; > ./aes_alias_name.cfg\n\n  if [ $(grep \"AESPort[ \\t]*=\" */*cfg | grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u | wc -l) -gt 1 ] ; then\n      echo - FIXME: services don\\'t agree on AESPort ; read\n  fi\n  if [ $(grep \"AESPort[ \\t]*=\" */*cfg | grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u | wc -l) -eq 1 ] ; then\n      echo AESPort=$(grep \"AESPort[ \\t]*=\" */*cfg| grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u) >> ./aes_alias_name.cfg\n  fi\n\n  if [ $(grep \"ASPort[ \\t]*=\" */*cfg | grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u | wc -l) -gt 1 ] ; then\n      echo - FIXME: services don\\'t agree on ASPort ; read\n  fi\n  if [ $(grep \"ASPort[ \\t]*=\" */*cfg | grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u | wc -l) -eq 1 ] ; then\n      echo ASPort=$(grep \"ASPort[ \\t]*=\" */*cfg| grep -v debug | sed \"s/.*=[ \\t]*//\" | sort -u) >> ./aes_alias_name.cfg\n  fi\n\n  ./live/service_ryzom_admin_service/ryzom_admin_service -A. -C. -L. --nobreak --fulladminname=admin_executor_service --shortadminname=AES\n  sleep 2\ndone\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/mt_domain_screen_wrapper.sh",
    "content": "#!/bin/sh\n\nCMD=$1\n#DOMAIN=$(pwd|sed s%/home/nevrax/%%)\nDOMAIN=shard\n\nif [ \"$CMD\" = \"\" ]\nthen\n    echo\n    echo Screen sessions currently running:\n    screen -list\n    echo\n    echo \"Commands:\"\n    echo \"  'start' to start the shard\"\n    echo \"  'stop'  to stop the ${DOMAIN}\"\n    echo \"  'join'  to join the ${DOMAIN}'s screen session\"\n    echo \"  'share' to join the screen session in shared mode\"\n    echo \"  'state' to view state information for the ${DOMAIN}\"\n    echo\n    printf \"Enter a command: \"\n    read CMD\nfi\n\nif [ \"$CMD\" = \"stop\" ]\nthen\n    if [ $(screen -list | grep \\\\\\.${DOMAIN} | wc -l) != 1 ]\n    then\n        echo Cannot stop domain \\'${DOMAIN}\\' because no screen by that name appears to be running\n        screen -list\n    else\n        screen -d -r $(screen -list | grep \\\\\\.${DOMAIN}| sed 's/(.*)//') -X quit> /dev/null\n        rm -v */*.state\n        rm -v */*launch_ctrl ./global.launch_ctrl\n    fi\nfi\n\nSTARTARGS=\nif [ \"$CMD\" = \"batchstart\" ]\nthen\n    STARTARGS='-d -m'\n    CMD='start'\nfi\n\nif [ \"$CMD\" = \"start\" ]\nthen\n    ulimit -c unlimited\n    screen -wipe > /dev/null\n    if [ $( screen -list | grep \\\\\\.${DOMAIN} | wc -w ) != 0 ]\n    then\n        echo Cannot start domain \\'${DOMAIN}\\' because this domain is already started\n        screen -list | grep $DOMAIN\n    else\n        screen $STARTARGS -S ${DOMAIN} -c ${DOMAIN}.screen.rc\n    fi\n\n    if [ \"$STARTARGS\" != \"\" ]\n    then\n        # on \"batchstart\", AES needs to be launched and AES will then launch other services\n        printf LAUNCH > aes/aes.launch_ctrl\n    fi\nfi\n\nif [ \"$CMD\" = \"join\" ]\nthen\n    if [ $(screen -list | grep \\\\\\.${DOMAIN} | wc -l) != 1 ]\n    then\n        echo Cannot join domain \\'${DOMAIN}\\' because no screen by that name appears to be running\n        screen -list\n    else\n        screen -r $(screen -list | grep \\\\\\.${DOMAIN}| sed 's/(.*)//')\n    fi\nfi\n\nif [ \"$CMD\" = \"share\" ]\nthen\n    if [ $(screen -list | grep \\\\\\.${DOMAIN} | wc -l) != 1 ]\n    then\n        echo Cannot join domain \\'${DOMAIN}\\' because no screen by that name appears to be running\n        screen -list\n    else\n        screen -r -x $(screen -list | grep \\\\\\.${DOMAIN}| sed 's/(.*)//')\n    fi\nfi\n\nif [ \"$CMD\" = \"state\" ]\nthen\n    echo State of domain ${DOMAIN}:\n    if [ \"$(echo */*.state)\" = \"*/*.state\" ]\n    then\n        echo - No state files found\n    else\n        grep RUNNING */*state\n    fi\nfi\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/service_launcher.sh",
    "content": "#!/bin/sh\n\n# the object is to make a launcher script that works with a command file to determine when to launch the application that it is responsible for\n\n#DOMAIN=$(pwd |sed \"s%/home/nevrax/%%\" | sed \"s%/.*%%\")\nDOMAIN=shard\n#NAME_BASE=$(pwd | sed 's/\\/home\\/nevrax\\///' | sed 's/^.*\\///')\n\nNAME_BASE=\"$1/$1\"\nmkdir $1\nshift\n\n#if [ _$DOMAIN == _pre_live ]\n#\tthen\n\tCTRL_FILE=${NAME_BASE}.launch_ctrl\n\tNEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl\n#elif [ _$DOMAIN == _pre_pre_live ]\n#\tthen\n#\tCTRL_FILE=${NAME_BASE}.launch_ctrl\n#\tNEXT_CTRL_FILE=${NAME_BASE}.deferred_launch_ctrl\n#else\n#\tCTRL_FILE=${NAME_BASE}_immediate.launch_ctrl\n#\tNEXT_CTRL_FILE=${NAME_BASE}_waiting.launch_ctrl\n#fi\nSTATE_FILE=${NAME_BASE}.state\nSTART_COUNTER_FILE=${NAME_BASE}.start_count\nCTRL_CMDLINE=$*\n\necho\necho ---------------------------------------------------------------------------------\necho Starting service launcher\necho ---------------------------------------------------------------------------------\nprintf \"%-16s = \" CMDLINE         ; echo $CTRL_CMDLINE\nprintf \"%-16s = \" CTRL_FILE       ; echo $CTRL_FILE\nprintf \"%-16s = \" NEXT_CTRL_FILE  ; echo $NEXT_CTRL_FILE\nprintf \"%-16s = \" STATE_FILE      ; echo $STATE_FILE\necho ---------------------------------------------------------------------------------\necho\n\n# reinit the start counter\necho 0 > $START_COUNTER_FILE\nSTART_COUNTER=0\n\necho Press ENTER to launch program\nwhile true\ndo\n\n  # see if the conditions are right to launch the app\n  if [ -e $CTRL_FILE ]\n      then\n\n      # a control file exists so read it's contents\n      CTRL_COMMAND=_$(cat $CTRL_FILE)_\n\n      # do we have a 'launch' command?\n      if [ $CTRL_COMMAND = _LAUNCH_ ]\n          then\n\n\t\t  # update the start counter\n\t\t  START_COUNTER=$(( $START_COUNTER + 1 ))\n\t\t  echo $START_COUNTER > $START_COUNTER_FILE\n\n\t\t  # big nasty hack to deal with the special cases of ryzom_naming_service and ryzom_admin_service who have badly names cfg files\n\t\t  #for f in ryzom_*cfg\n\t\t  #  do\n\t\t  #  cp $f $(echo $f | sed \"s/ryzom_//\")\n\t\t  #done\n\n\t\t  # we have a launch command so prepare, launch, wait for exit and do the housekeeping\n\t\t  echo -----------------------------------------------------------------------\n\t\t  echo Launching ...\n\t\t  echo\n\t\t  printf RUNNING > $STATE_FILE\n\n          $CTRL_CMDLINE\n\n\t\t  echo -----------------------------------------------------------------------\n\t\t  printf STOPPED > $STATE_FILE\n\n\t\t  # consume (remove) the control file to allow start once\n\t\t  rm -f $CTRL_FILE\n\n\t\t  echo Press ENTER to relaunch\n       fi\n  fi\n\n  # either we haven't launched the app yet or we have launched and it has exitted\n  if [ -e $NEXT_CTRL_FILE ]\n  then\n      # we have some kind of relaunch directive lined up so deal with it\n      mv $NEXT_CTRL_FILE $CTRL_FILE\n  else\n      # give the terminal user a chance to press enter to provoke a re-launch when auto-relaunch in AES is disabled\n      HOLD=`sh -ic '{ read a; echo \"ENTER\" 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null`\n      if [ \"${HOLD}\" = \"ENTER\" ]\n      then\n          printf LAUNCH > $CTRL_FILE\n      fi\n  fi\n\ndone\n\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/shard",
    "content": "#!/bin/sh\nif [ -z \"${MT_PATH+xxx}\" ]; \nthen \n\techo \"ERROR: The variable MT_PATH must be set! (e.g. /home/username/mt/code/mt)\";\n\texit 1;\nfi\ncd $MT_PATH/server\n/bin/sh $MT_PATH/tools/scripts/linux/mt_domain_screen_wrapper.sh $*\n"
  },
  {
    "path": "code/EVA/tools/scripts/linux/utilities",
    "content": "#!/bin/sh -\n\nSSH_AGENT_FILE=\"$HOME/ssh_agent_file\"\n\nBASENAME=`basename $0`\nLOG_INFO=\"$MT_PATH/log/${BASENAME}_info.log\"\nLOG_ERROR=\"$MT_PATH/log/${BASENAME}_error.log\"\n\n# first param is the subject line\n# others params are email\nsend_mail()\n{\n\tSUBJECT=$1\n\tshift\n\techo Send mail to $* with log $LOG_ERROR in body and subject $SUBJECT\n\tcat $LOG_ERROR | mail -s \"$SUBJECT on `hostname`\" $*\n}\n\nprint_success()\n{\n\techo \"*********************** $* SUCCESS !\"\n\techo\n}\n\nprint_failure()\n{\n\techo \"***************************************************\"\n\techo \"***************************************************\"\n\techo \"*********************** $* FAILED\"\n\techo \"***************************************************\"\n\techo \"***************************************************\"\n}\n\n\n# failed fill the log and send email if necessary\n# argument are the error message\nfailed()\n{\n\tprint_failure $*\n\tif [ \"X$LOG_INFO\" != \"X\" ]\n\t\tthen\n\t\tprint_failure $* >> $LOG_INFO\n\tfi\n\tif [ \"X$LOG_ERROR\" != \"X\" ]\n\t\tthen\n\t\tprint_failure $* >> $LOG_ERROR\n\tfi\n\n\tif [ \"X$MAIL_ERROR\" != \"X\" ]\n\t\tthen\n\t\tsend_mail \"$* FAILED\" $MAIL_ERROR\n\t\telse\n\t\techo \"No email to send the error mail\" >> $LOG_ERROR\n\tfi\n\n\techo \"exiting...\"\n\texit\n}\n\n# useful function to avoid continuing if something goes wrong\n# first param is $? and second is the string that will display\nverify()\n{\n\tif [ $1 -eq 0 ]\n\t\tthen\n\t\tshift\n\t\tprint_success $*\n\t\tif [ \"X$LOG_INFO\" != \"X\" ]\n\t\t\tthen\n\t\t\tprint_success $* >> $LOG_INFO\n\t\tfi\n\t\tif [ \"X$LOG_ERROR\" != \"X\" ]\n\t\t\tthen\n\t\t\tprint_success $* >> $LOG_ERROR\n\t\tfi\n\telse\n\t\tshift\n\t\tfailed $*\n\tfi\n}\n\n# step_failed() fills the log and increments $STEPS_FAILURES\nstep_failed()\n{\n\tprint_failure $*\n\tif [ \"X$LOG_INFO\" != \"X\" ]\n\t\tthen\n\t\tprint_failure $* >> $LOG_INFO\n\tfi\n\tif [ \"X$LOG_ERROR\" != \"X\" ]\n\t\tthen\n\t\tprint_failure $* >> $LOG_ERROR\n\tfi\n\n\tif [ \"X$STEPS_FAILURES\" = \"X\" ]\n\t\tthen\n\t\tSTEPS_FAILURES=0\n\t\telse\n\t\tSTEPS_FAILURES=`expr $STEPS_FAILURES + 1`\n\tfi\n}\n\n# call init_steps() before you use step()\n# it takes a label for following steps as parameter\ninit_steps()\n{\n\tSTEPS_LABEL=\"$*\"\n\tSTEPS_FAILURES=0\n}\n\n# like verify() but will continue even if step failed until verify_steps() is called\n# first param is $? and second is the string that will display\nstep()\n{\n\tif [ $1 -eq 0 ]\n\t\tthen\n\t\tshift\n\t\tprint_success $*\n\t\tif [ \"X$LOG_INFO\" != \"X\" ]\n\t\t\tthen\n\t\t\tprint_success $* >> $LOG_INFO\n\t\tfi\n\t\tif [ \"X$LOG_ERROR\" != \"X\" ]\n\t\t\tthen\n\t\t\tprint_success $* >> $LOG_ERROR\n\t\tfi\n\telse\n\t\tshift\n\t\tstep_failed $*\n\tfi\n}\n\n# call verify_steps() when you want to stop if error(s) occured in previous steps\nverify_steps()\n{\n    if [ $STEPS_FAILURES -eq 0 ]\n        then\n        print_success $STEPS_LABEL\n        if [ \"X$LOG_INFO\" != \"X\" ]\n            then\n            print_success $STEPS_LABEL >> $LOG_INFO\n        fi\n        if [ \"X$LOG_ERROR\" != \"X\" ]\n            then\n            print_success $STEPS_LABEL >> $LOG_ERROR\n        fi\n    else\n\t\tif [ $STEPS_FAILURES -eq 1 ]\n\t\t\tthen\n\t\t\tfailed \"1 step failed: $STEPS_LABEL\"\n\t\telse\n\t\t\tfailed \"$STEPS_FAILURES steps failed: $STEPS_LABEL\"\n\t\tfi\n    fi\n}\n\nask_confirmation()\n{\n\techo \"Using this script will destroy the current version, type 'yes' if you really want to do that\"\n\tread CONF\n\tif [ \"X$CONF\" != \"Xyes\" ]; then\n\t\tfailed \"You didn't answer 'yes', I stop the script!\"\n\tfi\n}\n\ncheck_host()\n{\n\tHOST=`hostname -s`\n\tif [ \"X$HOST\" != \"X$1\" ]; then\n\t\tfailed \"You can execute this script only on '$1' and not on '$HOST'\"\n\tfi\n}\n\n# useful function to initialize the default log for all scripts\ninit()\n{\n\tif [ \"X$LOG_INFO\" != \"X\" ]\n\t\tthen\n\t\ttest -d `dirname $LOG_INFO` || mkdir -p `dirname $LOG_INFO`\n\t\ttest ! -f $LOG_INFO || rm $LOG_INFO\n\t\ttouch $LOG_INFO\n\t\t# display all ulimit in the log\n\t\tulimit -a >>$LOG_INFO\n\tfi\n\n\tif [ \"X$LOG_ERROR\" != \"X\" ]\n\t\tthen\n\t\ttest -d `dirname $LOG_ERROR` || mkdir -p `dirname $LOG_ERROR`\n\t\ttest ! -f $LOG_ERROR || rm $LOG_ERROR\n\t\ttouch $LOG_ERROR\n\tfi\n}\n\ninit_ssh()\n{\n\tif [ ! -f $SSH_AGENT_FILE ]\n\t\tthen\n\t\tfailed \"the file $SSH_AGENT_FILE not exist, you must call create_ssh_agent_file first\"\n\tfi\n\n\teval `cat $SSH_AGENT_FILE`\n}\n"
  },
  {
    "path": "code/README",
    "content": ""
  },
  {
    "path": "code/changelog.template",
    "content": "# To generate ChangeLog files use these commands :\n# hg log -M --style ./changelog.template nel > nel/ChangeLog\n# hg log -M --style ./changelog.template ryzom > ryzom/ChangeLog\n\nheader = '\\n{date|shortdate}  {author}\\n\\n'\nchangeset = '\\t* {desc|fill68|tabindent|strip} [r{rev}]\\n'\n"
  },
  {
    "path": "code/config.h.cmake",
    "content": "#ifndef CONFIG_H\n#define CONFIG_H\n\n#cmakedefine HAVE_DL_H 1\n#cmakedefine HAVE_EXECINFO_H 1\n#cmakedefine HAVE_ICONV 1\n#cmakedefine HAVE_INTTYPES_H 1\n#cmakedefine HAVE_LANGINFO_CODESET 1\n#cmakedefine HAVE_LIMITS_H 1\n#cmakedefine HAVE_MALLOC_H 1\n#cmakedefine HAVE_PAM_MISC_H 1\n#cmakedefine HAVE_PAM_PAM_APPL_H 1\n#cmakedefine HAVE_PTHREAD 1\n#cmakedefine HAVE_SECURITY_PAM_APPL_H 1\n#cmakedefine HAVE_SECURITY_PAM_MISC_H 1\n#cmakedefine HAVE_STDINT_H 1\n#cmakedefine HAVE_SYS_MOUNT_H 1\n#cmakedefine HAVE_SYS_PARAM_H 1\n#cmakedefine HAVE_SYS_STATVFS_H 1\n#cmakedefine HAVE_SYS_TYPES_H 1\n#cmakedefine HAVE_UNISTD_H 1\n#cmakedefine HAVE_UTIME_H 1\n#cmakedefine HAVE_WCHAR_H 1\n\n#cmakedefine HAVE_BACKTRACE 1\n#cmakedefine HAVE_INET_NTOA 1\n#cmakedefine HAVE_INET_NTOP 1\n#cmakedefine HAVE_INET_PTON 1\n#cmakedefine HAVE_STRERROR 1\n#cmakedefine HAVE_STRLCAT 1\n#cmakedefine HAVE_STRPTIME 1\n#cmakedefine HAVE_STRTOK_R 1\n#cmakedefine HAVE_STRTOULL 1\n#cmakedefine HAVE_STATVFS 1\n#cmakedefine HAVE_STAT64 1\n\n#cmakedefine NL_OPENGL_AVAILABLE ${NL_OPENGL_AVAILABLE}\n#cmakedefine NL_OPENGLES_AVAILABLE ${NL_OPENGLES_AVAILABLE}\n#cmakedefine NL_DIRECT3D_AVAILABLE ${NL_DIRECT3D_AVAILABLE}\n\n#cmakedefine NL_FMOD_AVAILABLE ${NL_FMOD_AVAILABLE}\n#cmakedefine NL_OPENAL_AVAILABLE ${NL_OPENAL_AVAILABLE}\n#cmakedefine NL_DSOUND_AVAILABLE ${NL_DSOUND_AVAILABLE}\n#cmakedefine NL_XAUDIO2_AVAILABLE ${NL_XAUDIO2_AVAILABLE}\n\n#cmakedefine NL_BIN_PREFIX \"${NL_BIN_ABSOLUTE_PREFIX}\"\n#cmakedefine NL_ETC_PREFIX \"${NL_ETC_ABSOLUTE_PREFIX}\"\n#cmakedefine NL_SHARE_PREFIX \"${NL_SHARE_ABSOLUTE_PREFIX}\"\n#cmakedefine NL_LIB_PREFIX \"${NL_LIB_ABSOLUTE_PREFIX}\"\n#cmakedefine NL_DRIVER_PREFIX \"${NL_DRIVER_ABSOLUTE_PREFIX}\"\n\n#cmakedefine RYZOM_BIN_PREFIX \"${RYZOM_BIN_ABSOLUTE_PREFIX}\"\n#cmakedefine RYZOM_ETC_PREFIX \"${RYZOM_ETC_ABSOLUTE_PREFIX}\"\n#cmakedefine RYZOM_SHARE_PREFIX \"${RYZOM_SHARE_ABSOLUTE_PREFIX}\"\n\n#endif // CONFIG_H\n"
  },
  {
    "path": "code/nel/AUTHORS",
    "content": "Please check www.nevrax.org for more information"
  },
  {
    "path": "code/nel/CMakeLists.txt",
    "content": "PROJECT(NeL CXX C)\n\nIF(WITH_STATIC_DRIVERS)\n  ADD_DEFINITIONS(-DNL_STATIC)\nENDIF(WITH_STATIC_DRIVERS)\n\n# On Windows we need to find DirectInput for NLMISC.\n# This is how we get events.\nIF(WIN32)\n#  FIND_PACKAGE(DirectXSDK REQUIRED)\n\n  # On Win32 we can also build the MAX plugins.\n  IF(WITH_NEL_MAXPLUGIN)\n    FIND_PACKAGE(3dsMaxSDK)\n  ENDIF(WITH_NEL_MAXPLUGIN)\nENDIF(WIN32)\n\nIF(WITH_3D)\n  FIND_PACKAGE(FreeType)\n\n  IF(WITH_NEL_CEGUI)\n    FIND_PACKAGE(CEGUI)\n  ENDIF(WITH_NEL_CEGUI)\n\nENDIF(WITH_3D)\n\nIF(WITH_SOUND)\n  FIND_PACKAGE(Ogg)\n  FIND_PACKAGE(Vorbis)\n\n  IF(WITH_DRIVER_OPENAL)\n    FIND_PACKAGE(OpenAL)\n  ENDIF(WITH_DRIVER_OPENAL)\n\n  IF(WITH_DRIVER_FMOD)\n    FIND_PACKAGE(FMOD)\n  ENDIF(WITH_DRIVER_FMOD)\nENDIF(WITH_SOUND)\n\nIF(WITH_GTK)\n  FIND_PACKAGE(GTK2)\nENDIF(WITH_GTK)\n\nIF(WITH_INSTALL_LIBRARIES)\n  IF(UNIX)\n    SET(prefix ${CMAKE_INSTALL_PREFIX})\n    SET(exec_prefix ${NL_BIN_ABSOLUTE_PREFIX})\n    SET(libdir ${NL_LIB_ABSOLUTE_PREFIX})\n    SET(includedir ${CMAKE_INSTALL_PREFIX}/include)\n    SET(enable_ligo ${WITH_LIGO})\n    SET(enable_logic ${WITH_LOGIC})\n    SET(enable_georges ${WITH_GEORGES})\n    SET(enable_net ${WITH_NET})\n    SET(enable_3d ${WITH_3D})\n    SET(enable_pacs ${WITH_PACS})\n    SET(enable_sound ${WITH_SOUND})\n    CONFIGURE_FILE(nel-config.in ${CMAKE_CURRENT_BINARY_DIR}/nel-config)\n\n    INSTALL(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/nel-config DESTINATION ${NL_BIN_PREFIX})\n  ENDIF(UNIX)\n\n  ADD_SUBDIRECTORY(include)\nENDIF(WITH_INSTALL_LIBRARIES)\n\nADD_SUBDIRECTORY(src)\n\nIF(WITH_NEL_SAMPLES)\n  ADD_SUBDIRECTORY(samples)\nENDIF(WITH_NEL_SAMPLES)\n\n# Allow to compile only max plugins without other tools.\nIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN)\n  IF(WITH_NEL_TOOLS)\n    FIND_PACKAGE(Squish)\n  ENDIF(WITH_NEL_TOOLS)\n  ADD_SUBDIRECTORY(tools)\nENDIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN)\n\n"
  },
  {
    "path": "code/nel/COPYING",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "code/nel/ChangeLog",
    "content": "Please check http://dev.ryzom.com/projects/nel/roadmap for more information.\n"
  },
  {
    "path": "code/nel/INSTALL",
    "content": "\nPlease check www.nevrax.org for more information\n"
  },
  {
    "path": "code/nel/NEWS",
    "content": "Please check www.nevrax.org for more information"
  },
  {
    "path": "code/nel/README",
    "content": "Introduction\n------------\n\nNeL is a software platform for creating and running massively multi-user\nentertainment in a 3D environment over the Internet.\n\nThe NeL library is further divided into specific modules: network, ai, 3d\nand misc. If you want to use any of these, you also need to use the misc\npart of the library, but ai, 3d and network are totally independant from\neach other so you can use only the parts you really need in your project.\n\nIf you want know more about the library content and functionalities, you\nshould take a look on the documents present in the doc directory.\n\nNeL is currently developped and tested under GNU/Linux and Windows\nenvironments. \n\n\nLicense\n-------\n\nNeL is a Free Software project under the GNU Affero General Public License,\nwhich means all its code is available for everyone to download, examine,\nuse, modify, and distribute, subject to the usual restrictions attached\nto any GPL software. If you are not familiar with the AGPL, see the COPYING\nfile for for more details on license terms and other legal issues.\n\n\nInstallation\n------------\n\nPlease check the dev.ryzom.com for more information"
  },
  {
    "path": "code/nel/include/CMakeLists.txt",
    "content": "SUBDIRS(nel)\n\n"
  },
  {
    "path": "code/nel/include/nel/CMakeLists.txt",
    "content": "SUBDIRS(misc)\n\nIF(WITH_3D)\n  SUBDIRS(3d)\nENDIF(WITH_3D)\n\nIF(WITH_GUI)\n  ADD_SUBDIRECTORY(gui)\nENDIF(WITH_GUI)\n\nIF(WITH_GEORGES)\n  SUBDIRS(georges)\nENDIF(WITH_GEORGES)\n\nIF(WITH_LIGO)\n  SUBDIRS(ligo)\nENDIF(WITH_LIGO)\n\nIF(WITH_LOGIC)\n  SUBDIRS(logic)\nENDIF(WITH_LOGIC)\n\nIF(WITH_NET)\n  SUBDIRS(net)\nENDIF(WITH_NET)\n\nIF(WITH_SOUND)\n  SUBDIRS(sound)\nENDIF(WITH_SOUND)\n\nIF(WITH_PACS)\n  SUBDIRS(pacs)\nENDIF(WITH_PACS)\n\nIF(WITH_NEL_CEGUI)\n  SUBDIRS(cegui)\nENDIF(WITH_NEL_CEGUI)\n"
  },
  {
    "path": "code/nel/include/nel/georges/CMakeLists.txt",
    "content": "FILE(GLOB HEADERS *.h)\n\nINSTALL(FILES ${HEADERS} DESTINATION include/nel/georges COMPONENT headers)\n"
  },
  {
    "path": "code/nel/include/nel/georges/form.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FORM_H\n#define NL_FORM_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/georges/u_form.h\"\n#include \"form_elm.h\"\n#include \"header.h\"\n\nextern bool convertFormFile (const char *oldFileName, const char *newFileName);\n\nnamespace NLGEORGES\n{\n\nclass UFormElm;\n\n/**\n  * This class implement a georges form.\n  */\nclass CForm : public UForm\n{\n\tfriend class CFormLoader;\n\tfriend bool convertFormFile (const char *oldFileName, const char *newFileName);\npublic:\n\n\tenum { HeldElementCount = 4 };\n\n\t// From UForm\n\tUFormElm&\t\tgetRootNode ();\n\tconst UFormElm& getRootNode () const;\n\tconst std::string &getComment () const;\n\tvoid\t\t\twrite (class NLMISC::IStream &stream);\n\tvoid\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\tuint\t\t\tgetNumParent () const;\n\tUForm\t\t\t*getParentForm (uint parent) const;\n\n#ifdef NL_OS_WINDOWS\n#  pragma warning (disable : 4355)\n#endif\n\tCForm ();\n\t~CForm ();\n\n\t// Clean the form. Erase parents.\n\tvoid\t\t\t\tclean ();\n\n\t// ** Types\n\n\t// ** Header\n\tCFileHeader\t\t\tHeader;\n\n\t// ** Body\n\n\t/// Vector of CFormElm*\n\tCFormElmStruct\t\tElements;\n\n\t/// Backup slots\n\tCFormElmStruct\t\t*HeldElements[HeldElementCount];\n\n\t// ** IO functions\n\t// Set the filename before saving the form\n\tvoid\t\t\t\twrite (xmlDocPtr doc, const char *filename);\n\n\t// ** Parent access\n\n\t// Insert parent before parent indexed \"before\".\n\tbool\t\t\t\tinsertParent (uint before, const char *filename, CForm *parent);\n\n\t// Remove a parent from parent list\n\tvoid\t\t\t\tremoveParent (uint parent);\n\n\t// Get a parent\n\tCForm *\t\t\t\tgetParent (uint parent) const;\n\tconst std::string\t&getParentFilename (uint parent) const;\n\n\t// Get parent count\n\tuint\t\t\t\tgetParentCount () const;\n\n\t// Clear parents\n\tvoid\t\t\t\tclearParents ();\n\n\t// Get the form filename with extension\n\tconst std::string\t&getFilename () const;\n\n\t// Error handling\n\tvoid\t\t\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n\nprivate:\n\n\t// A parent structure\n\tclass CParent\n\t{\n\tpublic:\n\t\tstd::string\t\t\t\t\tParentFilename;\n\t\tNLMISC::CSmartPtr<CForm>\tParent;\n\t};\n\n\t/// Pointer on the parent\n\tstd::vector<CParent>\t\t\tParentList;\n\n\t// CFormLoader call it\n\t// Set the filename before reading the form\n\tvoid\t\t\t\tread (xmlNodePtr node, CFormLoader &loader, CFormDfn *dfn, const char *filename);\n\n\t// Called by read\n\tvoid\t\t\t\treadParent (const char *parent, CFormLoader &loader);\n\n\t// The form filename\n\tstd::string\t\t\t_Filename;\n};\n\n} // NLGEORGES\n\n#endif // NL_FORM_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/form_dfn.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FORM_DFN_H\n#define NL_FORM_DFN_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/smart_ptr.h\"\n#include \"nel/georges/u_form_dfn.h\"\n#include \"nel/georges/u_form_elm.h\"\n#include \"header.h\"\n#include \"type.h\"\n\nbool convertDfnFile (const char *oldFileName, const char *newFileName);\n\nnamespace NLGEORGES\n{\n\nclass CFormLoader;\n\n/**\n  * This class is the defnition for a family of forms.\n  */\nclass CFormDfn : public UFormDfn\n{\n\tfriend class CForm;\n\tfriend class CType;\n\tfriend class CFormElm;\n\tfriend class CFormLoader;\n\tfriend class CFormElmStruct;\n\tfriend bool convertDfnFile (const char *oldFileName, const char *newFileName);\npublic:\n\n\t// Default cstr\n\tCFormDfn ()\n\t{\n\t\tRound = 0xffffffff;\n\t}\n\n\tvirtual ~CFormDfn () { }\n\n\t// A form definition entry\n\tclass CEntry\n\t{\n\t\tfriend class CType;\n\t\tfriend class CForm;\n\t\tfriend class CFormElm;\n\t\tfriend class CFormDfn;\n\t\tfriend class CFormElmStruct;\n\t\tfriend bool convertDfnFile (const char *oldFileName, const char *newFileName);\n\tpublic:\n\n\t\tCEntry ()\n\t\t{\n\t\t\tTypeElement = EntryType;\n\t\t\tFilenameExt = \"*.*\";\n\t\t}\n\n\t\t// Get the type\n\t\tclass CType\t\t\t\t\t*getTypePtr ();\n\n\t\t// Get the type\n\t\tconst CType\t\t\t\t\t*getTypePtr () const;\n\n\t\t// Get the dfn\n\t\tCFormDfn\t\t\t\t\t*getDfnPtr ();\n\n\t\t// Get the dfn\n\t\tconst CFormDfn\t\t\t\t*getDfnPtr () const;\n\n\t\t// Get type flag\n\t\tTEntryType\t\t\t\t\tgetType () const;\n\n\t\t// Set as a type\n\t\tvoid\t\t\t\t\t\tsetType (CFormLoader &loader, const char *filename);\n\n\t\tvoid\t\t\t\t\t\tsetType (TEntryType type);\n\n\t\t// Set as a dfn\n\t\tvoid\t\t\t\t\t\tsetDfn (CFormLoader &loader, const char *filename);\n\n\t\t// Set as a dfn pointer\n\t\tvoid\t\t\t\t\t\tsetDfnPointer ();\n\n\t\t// Get element Name\n\t\tconst std::string\t\t\t&getName () const;\n\n\t\t// Set element Name\n\t\tvoid\t\t\t\t\t\tsetName (const char *name);\n\n\t\t// Get the filename\n\t\tconst std::string\t\t\t&getFilename() const;\n\n\t\t// Get the filename extension\n\t\tconst std::string\t\t\t&getFilenameExt() const;\n\n\t\t// Set the filename\n\t\tvoid\t\t\t\t\t\tsetFilename (const char *def);\n\n\t\t// Set the filename extension\n\t\tvoid\t\t\t\t\t\tsetFilenameExt (const char *ext);\n\n\t\t// Get default value\n\t\tconst std::string\t\t\t&getDefault () const;\n\n\t\t// Set default value\n\t\tvoid\t\t\t\t\t\tsetDefault (const char *def);\n\n\t\t// Set array flag\n\t\tvoid\t\t\t\t\t\tsetArrayFlag (bool flag);\n\n\t\t// Get array flag\n\t\tbool\t\t\t\t\t\tgetArrayFlag () const;\n\n\tprivate:\n\t\t// Entry name\n\t\tstd::string\t\t\t\t\tName;\n\n\t\t// What is the type of the element ?\n\t\tTEntryType\t\t\t\t\tTypeElement;\n\n\t\t// Is an array of this type ?\n\t\tbool\t\t\t\t\t\tArray;\n\n\t\t// The filename\n\t\tstd::string\t\t\t\t\tFilename;\n\n\t\t// The default value for atom\n\t\tstd::string\t\t\t\t\tDefault;\n\n\t\t// The filename\n\t\tstd::string\t\t\t\t\tFilenameExt;\n\n\t\t// Smart ptr on the type or the dfn\n\t\tNLMISC::CSmartPtr<CType>\tType;\n\n\t\t// Smart ptr on the type or the dfn\n\t\tNLMISC::CSmartPtr<CFormDfn>\tDfn;\n\t};\n\n\t// Parent DFN\n\tclass CParent\n\t{\n\tpublic:\n\t\t// The parent filename\n\t\tstd::string\t\t\t\t\t\tParentFilename;\n\n\t\t// The parent smart\n\t\tNLMISC::CSmartPtr<CFormDfn>\tParent;\n\t};\n\n\tvoid\t\t\t\t\t\t\taddEntry( const std::string &name );\n\n\tvoid\t\t\t\t\t\t\tremoveEntry( uint idx );\n\n\t// ** IO functions\n\tvoid\t\t\t\t\t\t\twrite (xmlDocPtr root, const char *filename);\n\n\t// Count parent DFN\n\tuint\t\t\t\t\t\t\tcountParentDfn (uint32 round=0) const;\n\n\t// Get parent DFN\n\tvoid\t\t\t\t\t\t\tgetParentDfn (std::vector<CFormDfn*> &array, uint32 round=0);\n\n\t// Get parent DFN\n\tvoid\t\t\t\t\t\t\tgetParentDfn (std::vector<const CFormDfn*> &array, uint32 round=0) const;\n\n\t// Get num parent\n\tuint\t\t\t\t\t\t\tgetNumParent () const;\n\n\t// Get parent count\n\tvoid\t\t\t\t\t\t\tsetNumParent (uint size);\n\n\t// Set a parent\n\tvoid\t\t\t\t\t\t\tsetParent (uint parent, CFormLoader &loader, const char *filename);\n\n\t// Get a parent\n\tCFormDfn\t\t\t\t\t\t*getParent (uint parent) const;\n\n\t// Get a parent string\n\tconst std::string\t\t\t\t&getParentFilename (uint parent) const;\n\n\t// Get num entry\n\tuint\t\t\t\t\t\t\tgetNumEntry () const;\n\n\t// Set num entry\n\tvoid\t\t\t\t\t\t\tsetNumEntry (uint size);\n\n\t// Get an entry\n\tconst CEntry\t\t\t\t\t&getEntry (uint entry) const;\n\n\t// Get an entry\n\tCEntry\t\t\t\t\t\t\t&getEntry (uint entry);\n\n\t// Form UFormDfn\n\tbool\t\t\t\t\t\t\tgetEntryType (uint entry, TEntryType &type, bool &array) const;\n\tbool\t\t\t\t\t\t\tgetEntryName (uint entry, std::string &name) const;\n\tbool\t\t\t\t\t\t\tgetEntryIndexByName (uint &entry, const\tstd::string &name) const;\n\tbool\t\t\t\t\t\t\tgetEntryDfn (uint entry, UFormDfn **dfn);\n\n\tbool\t\t\t\t\t\t\tgetEntryByName\t\t\t(const std::string &name, CFormDfn::CEntry **entry);\n\tbool\t\t\t\t\t\t\tgetEntryDfnByName\t\t(const std::string &name, UFormDfn **dfn);\n\tbool\t\t\t\t\t\t\tisAnArrayEntryByName\t(const std::string &name)\tconst;\n\n\tbool\t\t\t\t\t\t\tgetEntryType (uint entry, UType **type);\n\tuint\t\t\t\t\t\t\tgetNumParents () const;\n\tbool\t\t\t\t\t\t\tgetParent (uint parent, UFormDfn **parentRet);\n\tconst std::string\t\t\t\t&getComment () const;\n\tbool\t\t\t\t\t\t\tgetEntryFilename (uint entry, std::string& filename) const;\n\tbool\t\t\t\t\t\t\tgetEntryFilenameExt (uint entry, std::string& filename) const;\n\tbool\t\t\t\t\t\t\tgetParentFilename (uint parent, std::string &filename) const;\n\tvoid\t\t\t\t\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\n\t// Get the sub dfn of a dfn\n\tCFormDfn\t\t\t\t\t\t*getSubDfn (uint index, uint &dfnIndex);\n\tconst CFormDfn\t\t\t\t\t*getSubDfn (uint index, uint &dfnIndex) const;\n\n\t// Header\n\tCFileHeader\t\t\t\t\t\tHeader;\n\n\t// Error handling\n\tvoid\t\t\t\t\t\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n\nprivate:\n\t// The parents array\n\tstd::vector<CParent>\t\t\tParents;\n\n\t// A vector of entries\n\tstd::vector<CEntry>\t\t\t\tEntries;\n\n\t// Recursive call count\n\tmutable uint32\t\t\t\t\tRound;\n\n\t// The form DFN filename\n\tstd::string\t\t\t\t\t\t_Filename;\n\nprivate:\n\t// Read method called by the form loader\n\tvoid\t\t\t\t\t\t\tread (xmlNodePtr doc, CFormLoader &loader, bool forceLoad, const char *filename);\n};\n\n} // NLGEORGES\n\n#endif // NL_FORM_DFN_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/form_elm.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FORM_ELM_H\n#define NL_FORM_ELM_H\n\n#include \"nel/georges/u_form_elm.h\"\n#include \"nel/misc/smart_ptr.h\"\n#include \"nel/misc/rgba.h\"\n\n#include \"form_dfn.h\"\n\n#define NLGEORGES_FIRST_ROUND 0\n#define NLGEORGES_MAX_RECURSION 100\n\nnamespace NLGEORGES\n{\n\nclass CType;\nclass CFormDfn;\nclass CForm;\n\n/**\n  * Base class of form elements\n  */\nclass CFormElm : public UFormElm\n{\n\tfriend class CForm;\n\tfriend class CType;\n\tfriend class CFormDfn;\npublic:\n\n\t// Contructor\n\tCFormElm (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex);\n\n\t// Destructor\n\tvirtual ~CFormElm ();\n\n\t/// Reset contents\n\tvirtual void\tclean() {}\n\n\t// Get the form pointer\n\tCForm\t\t\t*getForm () const;\n\n\t// Is the element used by this form ?\n\tvirtual bool\tisUsed (const CForm *form) const;\n\n\t// Get the form name of the element\n\tvirtual void\tgetFormName (std::string &result, const CFormElm *child=NULL) const = 0;\n\n\t// From UFormElm\n\tvirtual bool\tgetNodeByName (const UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round=0) const;\n\tvirtual bool\tgetNodeByName (UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round=0);\n\tvirtual bool\tgetValueByName (std::string &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (sint8 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (uint8 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (sint16 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (uint16 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (sint32 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (uint32 &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (float &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (double &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (bool &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tgetValueByName (NLMISC::CRGBA &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round=0) const;\n\tvirtual bool\tsetValueByName (const char *value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (sint8 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (uint8 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (sint16 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (uint16 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (sint32 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (uint32 value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (float value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (double value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (bool value, const char *name, bool *created);\n\tvirtual bool\tsetValueByName (NLMISC::CRGBA value, const char *name, bool *created);\n\tvirtual UFormElm\t*getParent () const;\n\tvirtual const CType *getType ();\n\tvirtual bool\tisArray () const;\n\tvirtual bool\tgetArraySize (uint &size) const;\n\tvirtual bool\tgetArrayNode (const UFormElm **result, uint arrayIndex) const;\n\tvirtual bool\tgetArrayNode (UFormElm **result, uint arrayIndex);\n\tvirtual bool\tgetArrayNodeName (std::string &result, uint arrayIndex) const;\n\tvirtual bool\tgetArrayValue (std::string &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (sint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (uint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (sint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (uint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (sint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (uint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (float &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (double &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (bool &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tgetArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tvirtual bool\tisStruct () const;\n\tvirtual bool\tisVirtualStruct () const;\n\tvirtual bool\tgetDfnName (std::string &dfnName ) const;\n\tvirtual bool\tgetStructSize (uint &size) const;\n\tvirtual bool\tgetStructNodeName (uint element, std::string &result) const;\n\tvirtual bool\tgetStructNode (uint element, const UFormElm **result) const;\n\tvirtual bool\tgetStructNode (uint element, UFormElm **result);\n\tvirtual bool\tisAtom () const;\n\tvirtual bool\tgetValue (std::string &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (sint8 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (uint8 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (sint16 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (uint16 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (sint32 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (uint32 &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (float &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (double &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (bool &resultname, TEval evaluate) const;\n\tvirtual bool\tgetValue (NLMISC::CRGBA &resultname, TEval evaluate) const;\n\tvirtual UFormDfn\t*getStructDfn () { return NULL; }\n\n\t// ** Convert functions\n\n\tinline bool\t\tconvertValue (sint8 &result, const char *value) const;\n\tinline bool\t\tconvertValue (uint8 &result, const char *value) const;\n\tinline bool\t\tconvertValue (sint16 &result,\tconst char *value) const;\n\tinline bool\t\tconvertValue (uint16 &result,\tconst char *value) const;\n\tinline bool\t\tconvertValue (sint32 &result,\tconst char *value) const;\n\tinline bool\t\tconvertValue (uint32 &result,\tconst char *value) const;\n\tinline bool\t\tconvertValue (float &result, const char *value) const;\n\tinline bool\t\tconvertValue (double &result, const char *value) const;\n\tinline bool\t\tconvertValue (bool &result, const char *value) const;\n\tinline bool\t\tconvertValue (NLMISC::CRGBA &result, const char *value) const;\n\n\t// ** Get dependencies\n\tvirtual void\tgetDependencies (std::set<std::string> &dependencies) const = 0;\n\n\t// ** Internal node access\n\n\t// Create a node by name. If the node already exists, return it\n\tbool\tcreateNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array, bool &created);\n\n\t/**\n\t  * Delete a node by name. If the node already exists, return it\n\t  *Delete its parent if not used\n\t  */\n\tbool\tdeleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array);\n\n\t// Search for a node by name\n\tbool\tgetNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array, bool &parentVDfnArray, bool verbose, uint32 round) const;\n\n\t/**\n\t  * Insert an array node by name\n\t  * The index asked must be < the size of the array.\n\t  */\n\tbool\tarrayInsertNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array, bool verbose, uint arrayIndex) const;\n\n\t/**\n\t  * Delete an array node by name\n\t  * The index asked must be < the size of the array.\n\t  */\n\tbool\tarrayDeleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array, bool verbose, uint arrayIndex) const;\nprotected:\n\n\t// Action to perform\n\tenum TNodeAction\n\t{\n\t\tReturn,\n\t\tCreate,\n\t\tDelete,\n\t};\n\n\t/**\n\t  * Is createNode == Create, (*node)->Form must be == to the form argument.\n\t  * Is createNode == Return, form argument is not used, can be undefined.\n\t  *\n\t  * Only form, name, and action, must be defined.\n\t  * Then, else (*parentDfn / indexDfn ) or *node must be defined.\n\t  * Other values are for result only.\n\t  */\n\tstatic bool\tgetInternalNodeByName (CForm *form, const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\t\tbool &array, TNodeAction action, bool &created, bool &parentVDfnArray, bool verbose, uint32 round);\n\n\t/**\n\t  * Unlink a child\n\t  */\n\tvirtual void unlink (CFormElm *child);\n\npublic:\n\n\t// Get next token, return NULL if last token\n\tstatic const char* tokenize (const char *name, std::string &str, uint &errorIndex, uint &code);\n\n\t// ** IO functions\n\tvirtual xmlNodePtr\twrite (xmlNodePtr node, const CForm *form, const char *structName = NULL, bool forceWrite = false) const = 0;\n\nprotected:\n\n\t// The form of this node\n\tCForm\t\t\t\t*Form;\n\n\t// The parent node of this node\n\tCFormElm\t\t\t*ParentNode;\n\n\t// The parent DFN of this node\n\tconst CFormDfn\t\t*ParentDfn;\n\n\t// The index in the parent DFN for this node\n\tuint\t\t\t\tParentIndex;\n\n\t// Recurce Tag\n\tuint32\t\t\t\tRound;\n\n\t// Error handling\n\tstatic void\t\t\twarning (bool exception, const char *formName, const char *formFileName, const char *function, const char *format, ... );\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n\nprivate:\n\t// Tokens\n\tenum TToken\n\t{\n\t\tTokenString = 0,\n\t\tTokenPoint,\n\t\tTokenArrayBegin,\n\t\tTokenArrayEnd,\n\t};\n};\n\n/**\n  * Define a structure of elements\n  *\n  * This structure has pointers on named sub structures in Elements.\n  * If a sub structure is empty, its pointer is NULL.\n  */\nclass CFormElmStruct : public CFormElm\n{\npublic:\n\t// Default constructor\n\tCFormElmStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex);\n\tvirtual ~CFormElmStruct ();\n\n\t// Clear sub elements\n\tvoid clean ();\n\n\t// Smart pointer on the form definition for this structure\n\tNLMISC::CSmartPtr<CFormDfn>\tFormDfn;\n\n\t// Pointer on the parent element\n\t//CFormElmStruct\t\t\t\t\t*Parent;\n\n\t// A struct element\n\tclass CFormElmStructElm\n\t{\n\tpublic:\n\t\tCFormElmStructElm ()\n\t\t{\n\t\t\tElement = NULL;\n\t\t}\n\n\t\tstd::string\t\tName;\n\t\tCFormElm*\t\tElement;\n\t};\n\n\n\t// Build form a DFN\n\tvoid\t\t\t\tbuild (const CFormDfn *dfn);\n\n\t// From UFormElm\n\tbool\t\t\t\tisStruct () const;\n\tbool\t\t\t\tgetStructSize (uint &size) const;\n\tbool\t\t\t\tgetStructNodeName (uint element, std::string &result) const;\n\tbool\t\t\t\tgetStructNode (uint element, const UFormElm **result) const;\n\tbool\t\t\t\tgetStructNode (uint element, UFormElm **result);\n\tUFormDfn\t\t\t*getStructDfn ();\n\n\t// From CFormElm\n\tbool\t\t\t\tisUsed (const CForm *form) const;\n\txmlNodePtr\t\t\twrite (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const;\n\tvoid\t\t\t\tunlink (CFormElm *child);\n\tvoid\t\t\t\tgetFormName (std::string &result, const CFormElm *child) const;\n\tvoid\t\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\n\t// Call by CFormLoader\n\tvoid\t\t\t\tread (xmlNodePtr node, CFormLoader &loader, const CFormDfn *dfn, CForm *form);\n\n\t// Sub Elements\n\tstd::vector<CFormElmStructElm>\t\tElements;\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n};\n\n/**\n  * Define an array of elements\n  */\nclass CFormElmVirtualStruct : public CFormElmStruct\n{\npublic:\n\n\tCFormElmVirtualStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex);\n\tvirtual ~CFormElmVirtualStruct() { }\n\n\t// The Dfn filename used by this struct\n\tstd::string\t\t\tDfnFilename;\n\n\t// From UFormElm\n\tbool\t\t\t\tisVirtualStruct () const;\n\tbool\t\t\t\tgetDfnName (std::string &dfnName ) const;\n\n\t// From CFormElm\n\tbool\t\t\t\tisUsed (const CForm *form) const;\n\txmlNodePtr\t\t\twrite (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const;\n\n\t// Call by CFormLoader\n\tvoid\t\t\t\tread (xmlNodePtr node, CFormLoader &loader, CForm *form);\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n};\n\n/**\n  * Define an array of elements\n  */\nclass CFormElmArray : public CFormElm\n{\npublic:\n\t// Default constructor\n\tCFormElmArray (CForm *form, const CFormDfn *formDfn, const CType *type, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex);\n\tvirtual ~CFormElmArray ();\n\tvoid clean ();\n\n\t// Smart pointer on the form definition for this structure\n\tNLMISC::CSmartPtr<CFormDfn>\tFormDfn;\n\n\t// Pointer on the type (the smart pointer in hold by CFormDfn)\n\tconst CType\t\t\t*Type;\n\n\t// From UFormElm\n\tbool\t\t\t\tisArray () const;\n\tbool\t\t\t\tgetArraySize (uint &size) const;\n\tbool\t\t\t\tgetArrayNode (const UFormElm **result, uint arrayIndex) const;\n\tbool\t\t\t\tgetArrayNode (UFormElm **result, uint arrayIndex);\n\tbool\t\t\t\tgetArrayNodeName (std::string &result, uint arrayIndex) const;\n\tbool\t\t\t\tgetArrayValue (std::string &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (sint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (uint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (sint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (uint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (sint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (uint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (float &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (double &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (bool &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\tbool\t\t\t\tgetArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const;\n\n\t// From CFormElm\n\txmlNodePtr\t\t\twrite (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const;\n\tbool\t\t\t\tsetParent (CFormElm *parent);\n\tvoid\t\t\t\tunlink (CFormElm *child);\n\tbool\t\t\t\tisUsed (const CForm *form) const;\n\tvoid\t\t\t\tgetFormName (std::string &result, const CFormElm *child) const;\n\tvoid\t\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\n\t// Call by CFormLoader\n\n\t// Read an array\n\tvoid\t\t\t\tread (xmlNodePtr node, CFormLoader &loader, CForm *form);\n\n\t// A struct element\n\tclass CElement\n\t{\n\tpublic:\n\t\tCElement ()\n\t\t{\n\t\t\tElement = NULL;\n\t\t}\n\n\t\tstd::string\t\tName;\n\t\tCFormElm*\t\tElement;\n\t};\n\n\t// Array of elements\n\tstd::vector<CElement>\t\tElements;\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n};\n\n/**\n  * Signed integer element\n  */\nclass CFormElmAtom : public CFormElm\n{\n\tfriend class CForm;\n\tfriend class CFormElm;\n\tfriend class CType;\npublic:\n\t// Default constructor\n\tCFormElmAtom (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex);\n\tvirtual ~CFormElmAtom() { }\n\n\t// Pointer on the parent element\n\t//CFormElmAtom\t\t\t\t*Parent;\n\n\t// Pointer on the type (the smart pointer in hold by CFormDfn)\n\tconst CType\t\t\t\t\t*Type;\n\n\t// From CFormElm\n\txmlNodePtr\t\t\t\t\twrite (xmlNodePtr node, const CForm *form, const char *structName, bool forceWrite = false) const;\n\tbool\t\t\t\t\t\tsetParent (CFormElm *parent);\n\tvoid\t\t\t\t\t\tgetFormName (std::string &result, const CFormElm *child) const;\n\tvoid\t\t\t\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\tconst CType*                      getType ();\n\n\t// Call by CFormLoader\n\tvoid\t\t\t\t\t\tread (xmlNodePtr node, CFormLoader &loader, const CType *type, CForm *form);\n\n\t// From UFormElm\n\tbool\t\t\t\t\t\tisAtom () const;\n\tbool\t\t\t\t\t\tgetValue (std::string &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (sint8 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (uint8 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (sint16 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (uint16 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (sint32 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (uint32 &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (float &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (double &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (bool &result, TEval evaluate) const;\n\tbool\t\t\t\t\t\tgetValue (NLMISC::CRGBA &result, TEval evaluate) const;\n\n\t// Set the value, the elt been used\n\tvoid\t\t\t\t\t\tsetValue (const char *value);\n\n\t// Get the raw value. Does not care about any parent or default values\n\tvoid\t\t\t\t\t\tgetValue (std::string &result) const;\n\nprivate:\n\t// The value\n\tstd::string\t\t\t\t\tValue;\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n};\n\n// ***************************************************************************\n// CFormElm inlines\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (sint8 &result, const char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, -128.f, 127.f);\n\t\tresult = (sint8)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in sint8.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (uint8 &result, const char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, 0.f, 255.f);\n\t\tresult = (uint8)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in uint8.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (sint16 &result,\tconst char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, -32768.f, 32767.f);\n\t\tresult = (sint16)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in sint16.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (uint16 &result,\tconst char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, 0.f, 65535.f);\n\t\tresult = (uint16)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in uint16.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (sint32 &result,\tconst char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, -2147483648.f, 2147483647.f);\n\t\tresult = (sint32)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in sint32.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (uint32 &result,\tconst char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tNLMISC::clamp (tmp, 0.f, 4294967295.f);\n\t\tresult = (sint32)tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in uint32.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (float &result, const char *value) const\n{\n\tif (NLMISC::fromString(value, result))\n\t{\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in float.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (double &result, const char *value) const\n{\n\tfloat tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tresult = tmp;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in double.\", value);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (bool &result, const char *value) const\n{\n\tint tmp;\n\tif (NLMISC::fromString(value, tmp))\n\t{\n\t\tresult = tmp != 0;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tstd::string temp = NLMISC::toLower(std::string(value));\n\t\tif (strcmp (temp.c_str (), \"true\") == 0)\n\t\t{\n\t\t\tresult  = true;\n\t\t\treturn true;\n\t\t}\n\t\tif (strcmp (temp.c_str (), \"false\") == 0)\n\t\t{\n\t\t\tresult  = false;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Error message\n\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in boolean.\", value);\n\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CFormElm::convertValue (NLMISC::CRGBA &result, const char *value) const\n{\n\tfloat r, g, b;\n\tif (sscanf (value, \"%f,%f,%f\", &r, &g, &b) == 3)\n\t{\n\t\tNLMISC::clamp (r, 0.f, 255.f);\n\t\tNLMISC::clamp (g, 0.f, 255.f);\n\t\tNLMISC::clamp (b, 0.f, 255.f);\n\t\tresult.R = (uint8)r;\n\t\tresult.G = (uint8)g;\n\t\tresult.B = (uint8)b;\n\t\treturn true;\n\t}\n\n\t// Error message\n\twarning (false, \"convertValue\", \"Can't convert the string \\\"%s\\\" in RGB color.\", value);\n\n\treturn false;\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n\n#endif // NL_FORM_ELM_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/form_loader.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FORM_LOADER_H\n#define NL_FORM_LOADER_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/smart_ptr.h\"\n#include \"nel/georges/u_form_loader.h\"\n\n\nnamespace NLGEORGES\n{\n\nclass UForm;\nclass CType;\nclass CFormDfn;\nclass CForm;\n\n/**\n * Georges form loader implementation\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass CFormLoader : public UFormLoader\n{\npublic:\n\tvirtual ~CFormLoader();\n\t// From UFormLoader\n\tUForm\t\t*loadForm (const char *filename);\n\tUFormDfn\t*loadFormDfn (const char *filename);\n\tUType\t\t*loadFormType (const char *filename);\n\n\t// Load type and formDfn\n\tCType\t\t*loadType (const char *filename);\n\tCFormDfn\t*loadFormDfn (const char *filename, bool forceLoad);\n\nprivate:\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n\n\ttypedef std::map<std::string, NLMISC::CRefPtr<CType> >\t\tTTypeMap;\n\ttypedef std::map<std::string, NLMISC::CRefPtr<CFormDfn> >\tTFormDfnMap;\n\ttypedef std::map<std::string, NLMISC::CRefPtr<CForm> >\t\tTFormMap;\n\n\t// Map of filename / CRefPtr<CType>\n\tTTypeMap\t\t_MapType;\n\n\t// Map of filename / CRefPtr<CFormDfnCFormDfn>\n\tTFormDfnMap\t\t_MapFormDfn;\n\n\t// Map of form / CRefPtr<CForm>\n\tTFormMap\t\t_MapForm;\n};\n\n\n} // NLGEORGES\n\n\n#endif // NL_FORM_LOADER_H\n\n/* End of form_loader.h */\n"
  },
  {
    "path": "code/nel/include/nel/georges/header.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_HEADER_H\n#define NL_HEADER_H\n\n#include \"nel/misc/types_nl.h\"\n\n// Include from libxml2\n#include <libxml/parser.h>\n\nnamespace NLGEORGES\n{\n\nclass CFileHeader\n{\npublic:\n\t/// Default constructor\n\tCFileHeader ();\n\n\t// Form states\n\tenum TState\n\t{\n\t\tModified =0,\n\t\tChecked,\n\t\tStateCount,\n\t};\n\n\t/// Add a log\n\tvoid\t\t\t\taddLog (const char *log);\n\n\t/// Set the comment\n\tvoid\t\t\t\tsetComments (const char *comments);\n\n\t/// Major version number\n\tuint32\t\t\t\tMajorVersion;\n\n\t/// Minor version number\n\tuint32\t\t\t\tMinorVersion;\n\n\t/// State of the form\n\tTState\t\t\t\tState;\n\n\t/// Comments of the form\n\tstd::string\t\t\tComments;\n\n\t/// Log of the form\n\tstd::string\t\t\tLog;\n\n\t/// ** IO functions\n\tvoid\t\t\t\tread (xmlNodePtr root);\n\tvoid\t\t\t\twrite (xmlNodePtr node) const;\n\n\t// Get state string\n\tstatic const char\t*getStateString (TState state);\n\n\t// Error handling\n\tvoid\t\t\t\twarning (bool exception, const char *function, const char *format, ... ) const;\n};\n\n} // NLGEORGES\n\n#endif // NL_HEADER_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/load_form.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LOAD_FORM_H\n#define NL_LOAD_FORM_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"nel/misc/path.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/sheet_id.h\"\n#include \"nel/misc/algo.h\"\n\n#include \"u_form_loader.h\"\n#include \"u_form.h\"\n\n/** This function is used to load values from georges sheet in a quick way.\n * The first time it loads the sheet and parse it with the readGeorges function\n * provided by the user to read the value he wants. It'll generate a packed file\n * that contains this values (using serialCont). The next launch, the function will\n * only load the packed file and if some sheet have changed, it'll automatically regenerate\n * the packed file.\n *\n * To use the loadForm(), you first have to create a class that will contains values for one sheet.\n * This class must also implements 2 functions (readGeorges() and serial()) and 1 static function (getVersion())\n *\n * Extension file name for the packedFilename must be \".packed_sheets\"\n *\n * Classical use (copy/paste this in your code):\n\n\t// For each sheet in the packed sheet, an instance of this class\n\t// is created and stored into an stl container.\n\t// This class must be default and copy constructable.\n\tclass CContainerEntry\n\t{\n\tpublic:\n\t\tCContainerEntry () : WalkSpeed(1.3f), RunSpeed(6.0f) {}\n\n\t\tfloat WalkSpeed, RunSpeed;\n\n\t\t// load the values using the george sheet\n\t\tvoid readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId)\n\t\t{\n\t\t\t// the form was found so read the true values from George\n\t\t\tform->getRootNode ().getValueByName (WalkSpeed, \"Basics.MovementSpeeds.WalkSpeed\");\n\t\t\tform->getRootNode ().getValueByName (RunSpeed, \"Basics.MovementSpeeds.RunSpeed\");\n\t\t}\n\n\t\t// load/save the values using the serial system\n\t\tvoid serial (NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial (WalkSpeed, RunSpeed);\n\t\t}\n\n\t\t// Event to implement any action when the sheet no longer exist.\n\t\t// This method is called when a sheet have been read from the packed sheet\n\t\t// and the associated sheet file no more exist in the directories.\n\t\tvoid removed()\n\t\t{\n\t\t\t// any action that is needed if the sheet no more exist.\n\t\t}\n\n\t\t// return the version of this class, increments this value when the content of this class changed\n\t\tstatic uint getVersion () { return 1; }\n\t};\n\n\t// this structure is filled by the loadForm() function and will contain all you need\n\tstd::map<NLMISC::CSheetId,CContainerEntry> Container;\n\n\tvoid init ()\n\t{\n\t\t// load the values using the george sheet or packed file and fill the container\n\t\tloadForm(\".creature\", \"test.packed_sheets\", Container);\n\t}\n\n * Now you can access the Container (using the CSheedId) to know the WalkSpeed and RunSpeed of all creatures.\n *\n */\n\n\n/// Dictionnary entry for dependency information.\n/*\nstruct TLoadFormDicoEntry\n{\n\tstd::string\t\tFilename;\n\tuint32\t\t\tModificationDate;\n\n\tvoid serial(NLMISC::IStream &s)\n\t{\n\t\ts.serial(Filename);\n\t\ts.serial(ModificationDate);\n\t}\n};\n*/\nconst uint32\t\tPACKED_SHEET_HEADER = NELID(\"PKSH\");\nconst uint32\t\tPACKED_SHEET_VERSION = 5;\n// This Version may be used if you want to use the serialVersion() system in loadForm()\nconst uint32\t\tPACKED_SHEET_VERSION_COMPATIBLE = 0;\n\n// ***************************************************************************\n/** This function is used to load values from georges sheet in a quick way.\n * \\param sheetFilter a vector of string to filter the sheet in the case you need more than one filter\n * \\param packedFilename the name of the file that this function will generate (extension must be \"packed_sheets\")\n * \\param container the map that will be filled by this function\n */\ntemplate <class T>\nvoid loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string>\t\t\t\t\t\tdictionnary;\n\tstd::map<std::string, uint>\t\t\t\t\t\tdictionnaryIndex;\n\tstd::map<NLMISC::CSheetId, std::vector<uint32> >\tdependencies;\n\tstd::vector<uint32>\t\t\t\t\t\t\t\tdependencyDates;\n\n\t// check the extension (i know that file like \"foo.packed_sheetsbar\" will be accepted but this check is enough...)\n\tnlassert (packedFilename.find (\".packed_sheets\") != std::string::npos);\n\n\tstd::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);\n\tif (packedFilenamePath.empty())\n\t{\n\t\tpackedFilenamePath = packedFilename;\n\t}\n\n\t// make sure the CSheetId singleton has been properly initialised\n\tNLMISC::CSheetId::init(updatePackedSheet);\n\n\t// load the packed sheet if exists\n\ttry\n\t{\n\t\tNLMISC::CIFile ifile;\n\t\tifile.setCacheFileOnOpen(true);\n\t\tif (!ifile.open (packedFilenamePath))\n\t\t{\n\t\t\tthrow\tNLMISC::Exception(\"can't open PackedSheet %s\", packedFilenamePath.c_str());\n\t\t}\n\t\t// an exception will be launch if the file is not the good version or if the file is not found\n\n\t\t//nlinfo (\"loadForm(): Loading packed file '%s'\", packedFilename.c_str());\n\n\t\t// read the header\n\t\tifile.serialCheck(PACKED_SHEET_HEADER);\n\t\tifile.serialCheck(PACKED_SHEET_VERSION);\n\t\tifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t// Read depend block size\n\t\tuint32\tdependBlockSize;\n\t\tifile.serial(dependBlockSize);\n\n\t\t// Read the dependencies only if update packed sheet\n\t\tif(updatePackedSheet)\n\t\t{\n\t\t\t// read the dictionnary\n\t\t\t{\n\t\t\t\tifile.serialCont(dictionnary);\n\t\t\t}\n\t\t\t// read the dependency data\n\t\t\t{\n\t\t\t\tuint32 depSize;\n\t\t\t\tifile.serial(depSize);\n\t\t\t\tfor (uint i=0; i<depSize; ++i)\n\t\t\t\t{\n\t\t\t\t\tNLMISC::CSheetId sheetId;\n\n\t\t\t\t\t// Avoid copy, use []\n\t\t\t\t\tifile.serial(sheetId);\n\t\t\t\t\tifile.serialCont(dependencies[sheetId]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// else dummy read one big block => no heavy reallocation / free\n\t\telse if(dependBlockSize>0)\n\t\t{\n\t\t\tstd::vector<uint8>\tbigBlock;\n\t\t\tbigBlock.resize(dependBlockSize);\n\t\t\tifile.serialBuffer(&bigBlock[0], dependBlockSize);\n\t\t}\n\n\t\t// read the packed sheet data\n\t\tuint32\tnbEntries;\n\t\tuint32\tver;\n\t\tifile.serial (nbEntries);\n\t\tifile.serial (ver);\n\t\tif(ver != T::getVersion ())\n\t\t\tthrow NLMISC::Exception(\"The packed sheet version in stream is different of the code\");\n\t\tifile.serialCont (container);\n\t\tifile.close ();\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\t// clear the container because it can contains partially loaded sheet so we must clean it before continue\n\t\tcontainer.clear ();\n\t\tif (!updatePackedSheet)\n\t\t{\n\t\t\tif (errorIfPackedSheetNotGood)\n\t\t\t\tnlerror (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\t\t\telse\n\t\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)\", e.what());\n\t\t}\n\t}\n\n\t// if we don't want to update packed sheet, we have nothing more to do\n\tif (!updatePackedSheet)\n\t{\n\t\t//nlinfo (\"Don't update the packed sheet with real sheet\");\n\t\treturn;\n\t}\n\n\t// retreive the date of all dependency file\n\t{\n\t\tfor (uint i=0; i<dictionnary.size(); ++i)\n\t\t{\n\t\t\tstd::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);\n\t\t\tif (!p.empty())\n\t\t\t{\n\t\t\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\t\t\t\tdependencyDates.push_back(d);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// file not found !\n\t\t\t\t// write a future date to invalidate any file dependent on it\n\t\t\t\tnldebug(\"Can't find dependent file %s !\", dictionnary[i].c_str());\n\t\t\t\tdependencyDates.push_back(0xffffffff);\n\t\t\t}\n\t\t}\n\t}\n\n\t// build a vector of the sheetFilters sheet ids (ie: \"item\")\n\tstd::vector<NLMISC::CSheetId> sheetIds;\n\tstd::vector<std::string> filenames;\n\tfor (uint i = 0; i < sheetFilters.size(); i++)\n\t\tNLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);\n\n\t// if there's no file, nothing to do\n\tif (sheetIds.empty())\n\t\treturn;\n\n\t// set up the current sheet in container to remove sheet that are in the container and not in the directory anymore\n\tstd::map<NLMISC::CSheetId, bool> sheetToRemove;\n\tfor (typename std::map<NLMISC::CSheetId, T>::iterator it = container.begin(); it != container.end(); it++)\n\t{\n\t\tsheetToRemove.insert (std::make_pair((*it).first, true));\n\t}\n\n\t// check if we need to create a new .pitems or just read it\n\tuint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);\n\n\tbool containerChanged = false;\n\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\n\tstd::vector<uint> NeededToRecompute;\n\n\tfor (uint k = 0; k < filenames.size(); k++)\n\t{\n\t\tstd::string p = NLMISC::CPath::lookup (filenames[k], false, false);\n\t\tif (p.empty()) continue;\n\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\n\t\t// no need to remove this sheet\n\t\tsheetToRemove[sheetIds[k]] = false;\n\n\t\tif( d > packedFiledate || container.find (sheetIds[k]) == container.end())\n\t\t{\n\t\t\tNeededToRecompute.push_back(k);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check the date of each parent\n\t\t\tnlassert(dependencies.find(sheetIds[k]) != dependencies.end());\n\t\t\tstd::vector<uint32> &depends = dependencies[sheetIds[k]];\n\n\t\t\tfor (uint i=0; i<depends.size(); ++i)\n\t\t\t{\n\t\t\t\tif (dependencyDates[depends[i]] > packedFiledate)\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"Dependency on %s for %s not up to date !\",\n\t\t\t\t\t\tdictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());\n\t\t\t\t\tNeededToRecompute.push_back(k);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tnlinfo (\"%d sheets checked, %d need to be recomputed\", filenames.size(), NeededToRecompute.size());\n\n\tNLMISC::TTime last = NLMISC::CTime::getLocalTime ();\n\tNLMISC::TTime start = NLMISC::CTime::getLocalTime ();\n\n\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\tstd::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >\tcacheFormList;\n\n\tfor (uint j = 0; j < NeededToRecompute.size(); j++)\n\t{\n\t\tif(NLMISC::CTime::getLocalTime () > last + 5000)\n\t\t{\n\t\t\tlast = NLMISC::CTime::getLocalTime ();\n\t\t\tif(j>0)\n\t\t\t\tnlinfo (\"%.0f%% completed (%d/%d), %d seconds remaining\", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);\n\t\t}\n\n\t\t// create the georges loader if necessary\n\t\tif (formLoader == NULL)\n\t\t{\n\t\t\tNLMISC::WarningLog->addNegativeFilter(\"CFormLoader: Can't open the form file\");\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader ();\n\t\t}\n\n\t\t//\tcache used to retain information (to optimize time).\n\t\tif (form)\n\t\t\tcacheFormList.push_back\t(form);\n\n\t\t// Load the form with given sheet id\n\t\tform = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());\n\t\tif (form)\n\t\t{\n\t\t\t// build the dependency data\n\t\t\t{\n\t\t\t\tstd::vector<uint32>\t\tdepends;\n\t\t\t\tstd::set<std::string>\tdependFiles;\n\t\t\t\tform->getDependencies (dependFiles);\n\t\t\t\tnlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());\n\t\t\t\t// remove the sheet itself from the container\n\t\t\t\tdependFiles.erase(sheetIds[NeededToRecompute[j]].toString());\n\n\t\t\t\tstd::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tconst\tstd::string filename = NLMISC::CFile::getFilename(*first);\n\t\t\t\t\tstd::map<std::string,uint>::iterator\tfindDicIt=dictionnaryIndex.find(filename);\n\n\t\t\t\t\tif\t(findDicIt!=dictionnaryIndex.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tdepends.push_back(findDicIt->second);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::string p = NLMISC::CPath::lookup (*first, false, false);\n\t\t\t\t\tif\t(!p.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tuint dicIndex;\n\t\t\t\t\t\t// add a new dictionnary entry\n\t\t\t\t\t\tdicIndex = (uint)dictionnary.size();\n\t\t\t\t\t\tdictionnaryIndex.insert(std::make_pair(filename, (uint)dictionnary.size()));\n\t\t\t\t\t\tdictionnary.push_back(filename);\n\n\t\t\t\t\t\t// add the dependecy index\n\t\t\t\t\t\tdepends.push_back(dicIndex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// store the dependency list with the sheet ID\n\t\t\t\tdependencies[sheetIds[NeededToRecompute[j]]] = depends;\n\t\t\t}\n\n\t\t\t// add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one\n\t\t\ttypedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;\n            typedef typename std::pair<TType1, bool> TType2;\n\t\t\tTType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));\n\n\t\t\t(*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);\n\t\t\tcontainerChanged = true;\n\t\t}\n\t}\n\n\tif(NeededToRecompute.size() > 0)\n\t\tnlinfo (\"%d seconds to recompute %d sheets\", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());\n\n\t// free the georges loader if necessary\n\tif (formLoader != NULL)\n\t{\n\t\tNLGEORGES::UFormLoader::releaseLoader (formLoader);\n\t\tNLMISC::WarningLog->removeFilter (\"CFormLoader: Can't open the form file\");\n\t}\n\n\t// we have now to remove sheets that are in the container and not exist anymore in the sheet directories\n\tfor (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)\n\t{\n\t\tif((*it2).second)\n\t\t{\n\t\t\tnlinfo (\"the sheet '%s' is not in the directory, remove it from container\", (*it2).first.toString().c_str());\n\t\t\tcontainer.find((*it2).first)->second.removed();\n\t\t\tcontainer.erase((*it2).first);\n\t\t\tcontainerChanged = true;\n\t\t\tdependencies.erase((*it2).first);\n\t\t}\n\t}\n\n\t// now, save the new container in the packedfile\n\ttry\n\t{\n\t\tif(containerChanged)\n\t\t{\n\t\t\tNLMISC::COFile ofile;\n\t\t\tofile.open(packedFilenamePath);\n\n\t\t\t// write the header.\n\t\t\tofile.serialCheck(PACKED_SHEET_HEADER);\n\t\t\tofile.serialCheck(PACKED_SHEET_VERSION);\n\t\t\tofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t\t// Write a dummy block size for now\n\t\t\tsint32\tposBlockSize= ofile.getPos();\n\t\t\tuint32\tdependBlockSize= 0;\n\t\t\tofile.serial(dependBlockSize);\n\n\t\t\t// write the dictionnary\n\t\t\tofile.serialCont(dictionnary);\n\n\t\t\t// write the dependencies data\n\t\t\tuint32 depSize = (uint32)dependencies.size();\n\t\t\tofile.serial(depSize);\n\t\t\tstd::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNLMISC::CSheetId si = first->first;\n\t\t\t\tofile.serial(si);\n\t\t\t\tofile.serialCont(first->second);\n\t\t\t}\n\n\t\t\t// Then get the dictionary + dependencies size, and write it back to posBlockSize\n\t\t\tsint32\tendBlockSize= ofile.getPos();\n\t\t\tdependBlockSize= (endBlockSize - posBlockSize) - 4;\n\t\t\tofile.seek(posBlockSize, NLMISC::IStream::begin);\n\t\t\tofile.serial(dependBlockSize);\n\t\t\tofile.seek(endBlockSize, NLMISC::IStream::begin);\n\n\t\t\t// write the sheet data\n\t\t\tuint32 nbEntries = (uint32)sheetIds.size();\n\t\t\tuint32 ver = T::getVersion ();\n\t\t\tofile.serial (nbEntries);\n\t\t\tofile.serial (ver);\n\t\t\tofile.serialCont(container);\n\t\t\tofile.close ();\n\t\t}\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\tnlinfo (\"loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)\", e.what());\n\t}\n\n\t// housekeeping\n\tsheetIds.clear ();\n\tfilenames.clear ();\n}\n\n// ***************************************************************************\n/** This function is used to load values from georges sheet in a quick way.\n * \\param sheetFilter a string to filter the sheet (ie: \".item\")\n * \\param packedFilename the name of the file that this function will generate (extension must be \"packed_sheets\")\n * \\param container the map that will be filled by this function\n */\ntemplate <class T>\nvoid loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string> vs;\n\tvs.push_back(sheetFilter);\n\tloadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);\n}\n\n\n// ***************************************************************************\n// variant with smart pointers, maintain with function above\ntemplate <class T>\nvoid loadForm2(const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string>\t\t\t\t\t\tdictionnary;\n\tstd::map<std::string, uint>\t\t\t\t\t\tdictionnaryIndex;\n\tstd::map<NLMISC::CSheetId, std::vector<uint32> >\tdependencies;\n\tstd::vector<uint32>\t\t\t\t\t\t\t\tdependencyDates;\n\n\t// check the extension (i know that file like \"foo.packed_sheetsbar\" will be accepted but this check is enough...)\n\tnlassert (packedFilename.find (\".packed_sheets\") != std::string::npos);\n\n\tstd::string packedFilenamePath = NLMISC::CPath::lookup(NLMISC::CFile::getFilename(packedFilename), false, false);\n\tif (packedFilenamePath.empty())\n\t{\n\t\tpackedFilenamePath = packedFilename;\n\t}\n\n\t// make sure the CSheetId singleton has been properly initialised\n\tNLMISC::CSheetId::init(updatePackedSheet);\n\n\t// load the packed sheet if exists\n\ttry\n\t{\n\t\tNLMISC::CIFile ifile;\n\t\tifile.setCacheFileOnOpen(true);\n\t\tif (!ifile.open (packedFilenamePath))\n\t\t{\n\t\t\tthrow\tNLMISC::Exception(\"can't open PackedSheet %s\", packedFilenamePath.c_str());\n\t\t}\n\t\t// an exception will be launch if the file is not the good version or if the file is not found\n\n\t\tnlinfo (\"loadForm(): Loading packed file '%s'\", packedFilename.c_str());\n\n\t\t// read the header\n\t\tifile.serialCheck(PACKED_SHEET_HEADER);\n\t\tifile.serialCheck(PACKED_SHEET_VERSION);\n\t\tsint\tloadFormVersion= ifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t// Read depend block size\n\t\tuint32\tdependBlockSize;\n\t\tifile.serial(dependBlockSize);\n\n\t\t// Read the dependencies only if update packed sheet\n\t\tif(updatePackedSheet)\n\t\t{\n\t\t\t// read the dictionnary\n\t\t\t{\n\t\t\t\tifile.serialCont(dictionnary);\n\t\t\t}\n\t\t\t// read the dependency data\n\t\t\t{\n\t\t\t\tuint32 depSize;\n\t\t\t\tifile.serial(depSize);\n\t\t\t\tfor (uint i=0; i<depSize; ++i)\n\t\t\t\t{\n\t\t\t\t\tNLMISC::CSheetId sheetId;\n\n\t\t\t\t\t// Avoid copy, use []\n\t\t\t\t\tifile.serial(sheetId);\n\t\t\t\t\tifile.serialCont(dependencies[sheetId]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// else dummy read one big block => no heavy reallocation / free\n\t\telse if(dependBlockSize>0)\n\t\t{\n\t\t\tstd::vector<uint8>\tbigBlock;\n\t\t\tbigBlock.resize(dependBlockSize);\n\t\t\tifile.serialBuffer(&bigBlock[0], dependBlockSize);\n\t\t}\n\n\t\t// read the packed sheet data\n\t\tuint32\tnbEntries;\n\t\tuint32\tver;\n\t\tifile.serial (nbEntries);\n\t\tifile.serial (ver);\n\t\tif(ver != T::getVersion ())\n\t\t\tthrow NLMISC::Exception(\"The packed sheet version in stream is different of the code\");\n\t\tifile.serialPtrCont (container);\n\t\tifile.close ();\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\t// clear the container because it can contains partially loaded sheet so we must clean it before continue\n\t\tcontainer.clear ();\n\t\tif (!updatePackedSheet)\n\t\t{\n\t\t\tif (errorIfPackedSheetNotGood)\n\t\t\t\tnlerror (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\t\t\telse\n\t\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)\", e.what());\n\t\t}\n\t}\n\n\t// if we don't want to update packed sheet, we have nothing more to do\n\tif (!updatePackedSheet)\n\t{\n\t\tnlinfo (\"Don't update the packed sheet with real sheet\");\n\t\treturn;\n\t}\n\n\t// retreive the date of all dependency file\n\t{\n\t\tfor (uint i=0; i<dictionnary.size(); ++i)\n\t\t{\n\t\t\tstd::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);\n\t\t\tif (!p.empty())\n\t\t\t{\n\t\t\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\t\t\t\tdependencyDates.push_back(d);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// file not found !\n\t\t\t\t// write a future date to invalidate any file dependent on it\n\t\t\t\tnldebug(\"Can't find dependent file %s !\", dictionnary[i].c_str());\n\t\t\t\tdependencyDates.push_back(0xffffffff);\n\t\t\t}\n\t\t}\n\t}\n\n\t// build a vector of the sheetFilters sheet ids (ie: \"item\")\n\tstd::vector<NLMISC::CSheetId> sheetIds;\n\tstd::vector<std::string> filenames;\n\tfor (uint i = 0; i < sheetFilters.size(); i++)\n\t\tNLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);\n\n\t// if there's no file, nothing to do\n\tif (sheetIds.empty())\n\t\treturn;\n\n\t// set up the current sheet in container to remove sheets that are in the container and not in the directory anymore\n\tstd::map<NLMISC::CSheetId, bool> sheetToRemove;\n\tfor (typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator it = container.begin(); it != container.end(); it++)\n\t{\n\t\tsheetToRemove.insert (std::make_pair((*it).first, true));\n\t}\n\n\t// check if we need to create a new .pitems or just read it\n\tuint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);\n\n\tbool containerChanged = false;\n\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\n\tstd::vector<uint> NeededToRecompute;\n\n\tfor (uint k = 0; k < filenames.size(); k++)\n\t{\n\t\tstd::string p = NLMISC::CPath::lookup (filenames[k], false, false);\n\t\tif (p.empty()) continue;\n\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\n\t\t// no need to remove this sheet\n\t\tsheetToRemove[sheetIds[k]] = false;\n\n\t\tif( d > packedFiledate || container.find (sheetIds[k]) == container.end())\n\t\t{\n\t\t\tNeededToRecompute.push_back(k);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check the date of each parent\n\t\t\tnlassert(dependencies.find(sheetIds[k]) != dependencies.end());\n\t\t\tstd::vector<uint32> &depends = dependencies[sheetIds[k]];\n\n\t\t\tfor (uint i=0; i<depends.size(); ++i)\n\t\t\t{\n\t\t\t\tif (dependencyDates[depends[i]] > packedFiledate)\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"Dependency on %s for %s not up to date !\",\n\t\t\t\t\t\tdictionnary[depends[i]].c_str(), sheetIds[k].toString().c_str());\n\t\t\t\t\tNeededToRecompute.push_back(k);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tnlinfo (\"%d sheets checked, %d need to be recomputed\", filenames.size(), NeededToRecompute.size());\n\n\tNLMISC::TTime last = NLMISC::CTime::getLocalTime ();\n\tNLMISC::TTime start = NLMISC::CTime::getLocalTime ();\n\n\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\tstd::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >\tcacheFormList;\n\n\tfor (uint j = 0; j < NeededToRecompute.size(); j++)\n\t{\n\t\tif(NLMISC::CTime::getLocalTime () > last + 5000)\n\t\t{\n\t\t\tlast = NLMISC::CTime::getLocalTime ();\n\t\t\tif(j>0)\n\t\t\t\tnlinfo (\"%.0f%% completed (%d/%d), %d seconds remaining\", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);\n\t\t}\n\n\t\t// create the georges loader if necessary\n\t\tif (formLoader == NULL)\n\t\t{\n\t\t\tNLMISC::WarningLog->addNegativeFilter(\"CFormLoader: Can't open the form file\");\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader ();\n\t\t}\n\n\t\t//\tcache used to retain information (to optimize time).\n\t\tif (form)\n\t\t\tcacheFormList.push_back\t(form);\n\n\t\t// Load the form with given sheet id\n\t\tform = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());\n\t\tif (form)\n\t\t{\n\t\t\t// build the dependency data\n\t\t\t{\n\t\t\t\tstd::vector<uint32>\t\tdepends;\n\t\t\t\tstd::set<std::string>\tdependFiles;\n\t\t\t\tform->getDependencies (dependFiles);\n\t\t\t\tnlassert(dependFiles.find(sheetIds[NeededToRecompute[j]].toString()) != dependFiles.end());\n\t\t\t\t// remove the sheet itself from the container\n\t\t\t\tdependFiles.erase(sheetIds[NeededToRecompute[j]].toString());\n\n\t\t\t\tstd::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tconst\tstd::string filename = NLMISC::CFile::getFilename(*first);\n\t\t\t\t\tstd::map<std::string,uint>::iterator\tfindDicIt=dictionnaryIndex.find(filename);\n\n\t\t\t\t\tif\t(findDicIt!=dictionnaryIndex.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tdepends.push_back(findDicIt->second);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::string p = NLMISC::CPath::lookup (*first, false, false);\n\t\t\t\t\tif\t(!p.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tuint dicIndex;\n\t\t\t\t\t\t// add a new dictionnary entry\n\t\t\t\t\t\tdicIndex = (uint)dictionnary.size();\n\t\t\t\t\t\tdictionnaryIndex.insert(std::make_pair(filename, (NLMISC::TSStringId)dictionnary.size()));\n\t\t\t\t\t\tdictionnary.push_back(filename);\n\n\t\t\t\t\t\t// add the dependency index\n\t\t\t\t\t\tdepends.push_back(dicIndex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// store the dependency list with the sheet ID\n\t\t\t\tdependencies[sheetIds[NeededToRecompute[j]]] = depends;\n\t\t\t}\n\n\t\t\t// add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one\n\t\t\ttypedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;\n            typedef typename std::pair<TType1, bool> TType2;\n\t\t\tTType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));\n\n\t\t\t(*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);\n\t\t\tcontainerChanged = true;\n\t\t}\n\t}\n\n\tif(NeededToRecompute.size() > 0)\n\t\tnlinfo (\"%d seconds to recompute %d sheets\", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());\n\n\t// free the georges loader if necessary\n\tif (formLoader != NULL)\n\t{\n\t\tNLGEORGES::UFormLoader::releaseLoader (formLoader);\n\t\tNLMISC::WarningLog->removeFilter (\"CFormLoader: Can't open the form file\");\n\t}\n\n\t// we have now to remove sheets that are in the container and not exist anymore in the sheet directories\n\tfor (std::map<NLMISC::CSheetId, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)\n\t{\n\t\tif((*it2).second)\n\t\t{\n\t\t\tnlinfo (\"the sheet '%s' is not in the directory, remove it from container\", (*it2).first.toString().c_str());\n\t\t\tcontainer.find((*it2).first)->second->removed();\n\t\t\tcontainer.erase((*it2).first);\n\t\t\tcontainerChanged = true;\n\t\t\tdependencies.erase((*it2).first);\n\t\t}\n\t}\n\n\t// now, save the new container in the packedfile\n\ttry\n\t{\n\t\tif(containerChanged)\n\t\t{\n\t\t\tNLMISC::COFile ofile;\n\t\t\tofile.open(packedFilenamePath);\n\n\t\t\t// write the header.\n\t\t\tofile.serialCheck(PACKED_SHEET_HEADER);\n\t\t\tofile.serialCheck(PACKED_SHEET_VERSION);\n\t\t\tofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t\t// Write a dummy block size for now\n\t\t\tsint32\tposBlockSize= ofile.getPos();\n\t\t\tuint32\tdependBlockSize= 0;\n\t\t\tofile.serial(dependBlockSize);\n\n\t\t\t// write the dictionnary\n\t\t\tofile.serialCont(dictionnary);\n\n\t\t\t// write the dependencies data\n\t\t\tuint32 depSize = (uint32)dependencies.size();\n\t\t\tofile.serial(depSize);\n\t\t\tstd::map<NLMISC::CSheetId, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNLMISC::CSheetId si = first->first;\n\t\t\t\tofile.serial(si);\n\t\t\t\tofile.serialCont(first->second);\n\t\t\t}\n\n\t\t\t// Then get the dicionary + dependencies size, and write it back to posBlockSize\n\t\t\tsint32\tendBlockSize= ofile.getPos();\n\t\t\tdependBlockSize= (endBlockSize - posBlockSize) - 4;\n\t\t\tofile.seek(posBlockSize, NLMISC::IStream::begin);\n\t\t\tofile.serial(dependBlockSize);\n\t\t\tofile.seek(endBlockSize, NLMISC::IStream::begin);\n\n\t\t\t// write the sheet data\n\t\t\tuint32 nbEntries = (uint32)sheetIds.size();\n\t\t\tuint32 ver = T::getVersion ();\n\t\t\tofile.serial (nbEntries);\n\t\t\tofile.serial (ver);\n\t\t\tofile.serialPtrCont(container);\n\t\t\tofile.close ();\n\t\t}\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\tnlinfo (\"loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)\", e.what());\n\t}\n\n\t// housekeeping\n\tsheetIds.clear ();\n\tfilenames.clear ();\n}\n\n// ***************************************************************************\n// variant with smart pointers, maintain with function above\ntemplate <class T>\nvoid loadForm2(const std::string &sheetFilter, const std::string &packedFilename, std::map<NLMISC::CSheetId, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string> vs;\n\tvs.push_back(sheetFilter);\n\tloadForm2(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);\n}\n\n\n\n// ***************************************************************************\n/** This function is used to load values from georges sheet in a quick way.\n * \\param sheetFilter a vector of string to filter the sheet in the case you need more than one filter\n * \\param packedFilename the name of the file that this function will generate (extension must be \"packed_sheets\")\n * \\param container the map that will be filled by this function\n */\ntemplate <class T>\nvoid loadForm (const std::vector<std::string> &sheetFilters, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string>\t\t\t\t\t\tdictionnary;\n\tstd::map<std::string, uint>\t\t\t\t\t\tdictionnaryIndex;\n\tstd::map<std::string, std::vector<uint32> >\t\tdependencies;\n\tstd::vector<uint32>\t\t\t\t\t\t\t\tdependencyDates;\n\n\t// check the extension (i know that file like \"foo.packed_sheetsbar\" will be accepted but this check is enough...)\n\tnlassert (packedFilename.find (\".packed_sheets\") != std::string::npos);\n\n\tstd::string packedFilenamePath = NLMISC::CPath::lookup(packedFilename, false, false);\n\tif (packedFilenamePath.empty())\n\t{\n\t\tpackedFilenamePath = packedFilename;\n\t}\n\n\t// make sure the CSheetId singleton has been properly initialised\n//\tNLMISC::CSheetId::init(updatePackedSheet);\n\n\t// load the packed sheet if exists\n\ttry\n\t{\n\t\tNLMISC::CIFile ifile;\n\t\tifile.setCacheFileOnOpen(true);\n\t\tifile.open (packedFilenamePath);\n\t\t// an exception will be launch if the file is not the good version or if the file is not found\n\n\t\tnlinfo (\"loadForm(): Loading packed file '%s'\", packedFilename.c_str());\n\n\t\t// read the header\n\t\tifile.serialCheck(PACKED_SHEET_HEADER);\n\t\tifile.serialCheck(PACKED_SHEET_VERSION);\n\t\tifile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t// Read depend block size\n\t\tuint32\tdependBlockSize;\n\t\tifile.serial(dependBlockSize);\n\n\t\t// Read the dependencies only if update packed sheet\n\t\tif(updatePackedSheet)\n\t\t{\n\t\t\t// read the dictionnary\n\t\t\t{\n\t\t\t\tifile.serialCont(dictionnary);\n\t\t\t}\n\t\t\t// read the dependency data\n\t\t\t{\n\t\t\t\tuint32 depSize;\n\t\t\t\tifile.serial(depSize);\n\t\t\t\tfor (uint i=0; i<depSize; ++i)\n\t\t\t\t{\n\t\t\t\t\tstd::string sheetName;\n\n\t\t\t\t\t// Avoid copy, use []\n\t\t\t\t\tifile.serial(sheetName);\n\t\t\t\t\tifile.serialCont(dependencies[sheetName]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// else dummy read one big block => no heavy reallocation / free\n\t\telse if(dependBlockSize>0)\n\t\t{\n\t\t\tstd::vector<uint8>\tbigBlock;\n\t\t\tbigBlock.resize(dependBlockSize);\n\t\t\tifile.serialBuffer(&bigBlock[0], dependBlockSize);\n\t\t}\n\n\t\t// read the packed sheet data\n\t\tuint32\tnbEntries;\n\t\tuint32\tver;\n\t\tifile.serial (nbEntries);\n\t\tifile.serial (ver);\n\t\tif(ver != T::getVersion ())\n\t\t\tthrow NLMISC::Exception(\"The packed sheet version in stream is different of the code\");\n\t\tifile.serialCont (container);\n\t\tifile.close ();\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\t// clear the container because it can contains partially loaded sheet so we must clean it before continue\n\t\tcontainer.clear ();\n\t\tif (!updatePackedSheet)\n\t\t{\n\t\t\tif (errorIfPackedSheetNotGood)\n\t\t\t\tnlerror (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\t\t\telse\n\t\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file and can't reconstruct them (%s)\", e.what());\n\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo (\"loadForm(): Exception during reading the packed file, I'll reconstruct it (%s)\", e.what());\n\t\t}\n\t}\n\n\t// if we don't want to update packed sheet, we have nothing more to do\n\tif (!updatePackedSheet)\n\t{\n\t\tnlinfo (\"Don't update the packed sheet with real sheet\");\n\t\treturn;\n\t}\n\n\t// retreive the date of all dependency file\n\t{\n\t\tfor (uint i=0; i<dictionnary.size(); ++i)\n\t\t{\n\t\t\tstd::string p = NLMISC::CPath::lookup (dictionnary[i], false, false);\n\t\t\tif (!p.empty())\n\t\t\t{\n\t\t\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\t\t\t\tdependencyDates.push_back(d);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// file not found !\n\t\t\t\t// write a future date to invalidate any file dependent on it\n\t\t\t\tnldebug(\"Can't find dependent file %s !\", dictionnary[i].c_str());\n\t\t\t\tdependencyDates.push_back(0xffffffff);\n\t\t\t}\n\t\t}\n\t}\n\n\t// build a vector of the sheetFilters sheet ids (ie: \"item\")\n\tstd::vector<std::string> sheetNames;\n\t{\n\t\tstd::vector<std::string>::const_iterator first(sheetFilters.begin()), last(sheetFilters.end());\n\t\tfor (; first != last; ++first)\n\t\t\tNLMISC::CPath::getFileList(*first, sheetNames);\n\n\t}\n\n\t// if there's no file, nothing to do\n\tif (sheetNames.empty())\n\t\treturn;\n\n\t// set up the current sheet in container to remove sheet that are in the container and not in the directory anymore\n\tstd::map<std::string, bool> sheetToRemove;\n\t{\n\t\ttypename std::map<std::string, T>::iterator first(container.begin()), last(container.end());\n\t\tfor(; first != last; ++first)\n\t\t\tsheetToRemove.insert (make_pair(first->first, true));\n\t}\n\n\t// check if we need to create a new .pitems or just read it\n\tuint32 packedFiledate = NLMISC::CFile::getFileModificationDate(packedFilenamePath);\n\n\tbool containerChanged = false;\n\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\n\tstd::vector<uint> NeededToRecompute;\n\n\tfor (uint k = 0; k < sheetNames.size(); k++)\n\t{\n\t\tstd::string p = NLMISC::CPath::lookup (sheetNames[k], false, false);\n\t\tif (p.empty())\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tuint32 d = NLMISC::CFile::getFileModificationDate(p);\n\n\t\t// no need to remove this sheet\n\t\tsheetToRemove[sheetNames[k]] = false;\n\n\t\tif( d > packedFiledate || container.find (sheetNames[k]) == container.end())\n\t\t{\n\t\t\tNeededToRecompute.push_back(k);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check the date of each parent\n\t\t\tnlassert(dependencies.find(sheetNames[k]) != dependencies.end());\n\t\t\tstd::vector<uint32> &depends = dependencies[sheetNames[k]];\n\n\t\t\tfor (uint i=0; i<depends.size(); ++i)\n\t\t\t{\n\t\t\t\tif (dependencyDates[depends[i]] > packedFiledate)\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"Dependency on %s for %s not up to date !\",\n\t\t\t\t\t\tdictionnary[depends[i]].c_str(), sheetNames[k].c_str());\n\t\t\t\t\tNeededToRecompute.push_back(k);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tnlinfo (\"%d sheets checked, %d need to be recomputed\", sheetNames.size(), NeededToRecompute.size());\n\n\tNLMISC::TTime lastTime = NLMISC::CTime::getLocalTime ();\n\tNLMISC::TTime start = NLMISC::CTime::getLocalTime ();\n\n\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\n\tfor (uint j = 0; j < NeededToRecompute.size(); j++)\n\t{\n\t\tif(NLMISC::CTime::getLocalTime () > lastTime + 5000)\n\t\t{\n\t\t\tlastTime = NLMISC::CTime::getLocalTime ();\n\t\t\tif(j>0)\n\t\t\t\tnlinfo (\"%.0f%% completed (%d/%d), %d seconds remaining\", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(lastTime-start)/j/1000);\n\t\t}\n\n\t\t// create the georges loader if necessary\n\t\tif (formLoader == NULL)\n\t\t{\n\t\t\tNLMISC::WarningLog->addNegativeFilter(\"CFormLoader: Can't open the form file\");\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader ();\n\t\t}\n\n\t\t// Load the form with given sheet id\n\t\tform = formLoader->loadForm (sheetNames[NeededToRecompute[j]].c_str ());\n\t\tif (form)\n\t\t{\n\t\t\t// build the dependency data\n\t\t\t{\n\t\t\t\tstd::vector<uint32>\t\tdepends;\n\t\t\t\tstd::set<std::string>\tdependFiles;\n\t\t\t\tform->getDependencies (dependFiles);\n\t\t\t\tnlassert(dependFiles.find(sheetNames[NeededToRecompute[j]]) != dependFiles.end());\n\t\t\t\t// remove the sheet itself from the container\n\t\t\t\tdependFiles.erase(sheetNames[NeededToRecompute[j]]);\n\n\t\t\t\tstd::set<std::string>::iterator first(dependFiles.begin()), last(dependFiles.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tstd::string p = NLMISC::CPath::lookup (*first, false, false);\n\t\t\t\t\tif (!p.empty())\n\t\t\t\t\t{\n//\t\t\t\t\t\tuint32 date = NLMISC::CFile::getFileModificationDate(p);\n\n\t\t\t\t\t\tuint dicIndex;\n\t\t\t\t\t\tstd::string filename = NLMISC::CFile::getFilename(p);\n\n\t\t\t\t\t\tif (dictionnaryIndex.find(filename) == dictionnaryIndex.end())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// add a new dictionnary entry\n\t\t\t\t\t\t\tdicIndex = (uint)dictionnary.size();\n\t\t\t\t\t\t\tdictionnaryIndex.insert(std::make_pair(filename, (uint)dictionnary.size()));\n\t\t\t\t\t\t\tdictionnary.push_back(filename);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdicIndex = dictionnaryIndex.find(filename)->second;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// add the dependecy index\n\t\t\t\t\t\tdepends.push_back(dicIndex);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// store the dependency list with the sheet ID\n\t\t\t\tdependencies[sheetNames[NeededToRecompute[j]]] = depends;\n\t\t\t}\n\n\t\t\t// add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one\n\t\t\ttypedef typename std::map<std::string, T>::iterator TType1;\n            typedef typename std::pair<TType1, bool> TType2;\n\t\t\tTType2 res = container.insert(std::make_pair(sheetNames[NeededToRecompute[j]],T()));\n\n\t\t\t(*res.first).second.readGeorges (form, sheetNames[NeededToRecompute[j]]);\n\t\t\tcontainerChanged = true;\n\t\t}\n\t}\n\n\tnlinfo (\"%d seconds to recompute %d sheets\", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());\n\n\t// free the georges loader if necessary\n\tif (formLoader != NULL)\n\t{\n\t\tNLGEORGES::UFormLoader::releaseLoader (formLoader);\n\t\tNLMISC::WarningLog->removeFilter (\"CFormLoader: Can't open the form file\");\n\t}\n\n\t// we have now to remove sheet that are in the container and not exist anymore in the sheet directories\n\tfor (std::map<std::string, bool>::iterator it2 = sheetToRemove.begin(); it2 != sheetToRemove.end(); it2++)\n\t{\n\t\tif(it2->second)\n\t\t{\n\t\t\t// inform the contained object that it is no more needed.\n\t\t\tcontainer.find(it2->first)->second.removed();\n\t\t\tcontainer.erase(it2->first);\n\t\t\tcontainerChanged = true;\n\t\t\tdependencies.erase((*it2).first);\n\t\t}\n\t}\n\n\t// now, save the new container in the packedfile\n\ttry\n\t{\n\t\tif(containerChanged)\n\t\t{\n\t\t\tNLMISC::COFile ofile;\n\t\t\tofile.open(packedFilenamePath);\n\n\t\t\t// write the header.\n\t\t\tofile.serialCheck(PACKED_SHEET_HEADER);\n\t\t\tofile.serialCheck(PACKED_SHEET_VERSION);\n\t\t\tofile.serialVersion(PACKED_SHEET_VERSION_COMPATIBLE);\n\n\t\t\t// Write a dummy block size for now\n\t\t\tsint32\tposBlockSize= ofile.getPos();\n\t\t\tuint32\tdependBlockSize= 0;\n\t\t\tofile.serial(dependBlockSize);\n\n\t\t\t// write the dictionnary\n\t\t\tofile.serialCont(dictionnary);\n\n\t\t\t// write the dependencies data\n\t\t\tuint32 depSize = (uint32)dependencies.size();\n\t\t\tofile.serial(depSize);\n\t\t\tstd::map<std::string, std::vector<uint32> >::iterator first(dependencies.begin()), last(dependencies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tstd::string  sheetName = first->first;\n\t\t\t\tofile.serial(sheetName);\n\t\t\t\tofile.serialCont(first->second);\n\t\t\t}\n\n\t\t\t// Then get the dicionary + dependencies size, and write it back to posBlockSize\n\t\t\tsint32\tendBlockSize= ofile.getPos();\n\t\t\tdependBlockSize= (endBlockSize - posBlockSize) - 4;\n\t\t\tofile.seek(posBlockSize, NLMISC::IStream::begin);\n\t\t\tofile.serial(dependBlockSize);\n\t\t\tofile.seek(endBlockSize, NLMISC::IStream::begin);\n\n\t\t\t// write the sheet data\n\t\t\tuint32 nbEntries = (uint32)sheetNames.size();\n\t\t\tuint32 ver = T::getVersion ();\n\t\t\tofile.serial (nbEntries);\n\t\t\tofile.serial (ver);\n\t\t\tofile.serialCont(container);\n\t\t\tofile.close ();\n\t\t}\n\t}\n\tcatch (const NLMISC::Exception &e)\n\t{\n\t\tnlinfo (\"loadForm(): Exception during saving the packed file, it will be recreated next launch (%s)\", e.what());\n\t}\n\n\t// housekeeping\n\tsheetNames.clear ();\n}\n\n// ***************************************************************************\n/** This function is used to load values from georges sheet in a quick way.\n * \\param sheetFilter a string to filter the sheet (ie: \".item\")\n * \\param packedFilename the name of the file that this function will generate (extension must be \"packed_sheets\")\n * \\param container the map that will be filled by this function\n */\ntemplate <class T>\nvoid loadForm (const std::string &sheetFilter, const std::string &packedFilename, std::map<std::string, T> &container, bool updatePackedSheet=true, bool errorIfPackedSheetNotGood=true)\n{\n\tstd::vector<std::string> vs;\n\tvs.push_back(sheetFilter);\n\tloadForm(vs, packedFilename, container, updatePackedSheet, errorIfPackedSheetNotGood);\n}\n\n// ***************************************************************************\ntemplate <class T>\nvoid loadFormNoPackedSheet (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)\n{\n\tstd::vector<std::string> vs;\n\tvs.push_back(sheetFilter);\n\tloadFormNoPackedSheet(vs, container, wildcardFilter);\n}\n\n// ***************************************************************************\n// variant with smart pointers, maintain with function above\ntemplate <class T>\nvoid loadFormNoPackedSheet2 (const std::string &sheetFilter, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)\n{\n\tstd::vector<std::string> vs;\n\tvs.push_back(sheetFilter);\n\tloadFormNoPackedSheet2(vs, container, wildcardFilter);\n}\n\n// ***************************************************************************\n/** This function is used to load values from georges sheet in a quick way.\n *\tNB: no packedsheet is given for load/write\n * \\param sheetFilters a vector of string to filter the sheet (by extension) in the case you need more than one filter\n * \\param wildcardFilter an additional by sheet filter (must include the extension)\n * \\param container the map that will be filled by this function\n */\ntemplate <class T>\nvoid loadFormNoPackedSheet (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, T> &container, const std::string &wildcardFilter)\n{\n\t// make sure the CSheetId singleton has been properly initialised\n\tNLMISC::CSheetId::init(false);\n\n\t// build a vector of the sheetFilters sheet ids (ie: \"item\")\n\tstd::vector<NLMISC::CSheetId> sheetIds;\n\tstd::vector<std::string> filenames;\n\tfor (uint i = 0; i < sheetFilters.size(); i++)\n\t\tNLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);\n\n\n\t// if there's no file, nothing to do\n\tif (sheetIds.empty())\n\t\treturn;\n\n\n\t// compute sheets that needs to be recomputed\n\tstd::vector<uint> NeededToRecompute;\n\tfor (uint k = 0; k < filenames.size(); k++)\n\t{\n\t\tstd::string p = NLMISC::CPath::lookup (filenames[k], false, false);\n\t\tif (p.empty()) continue;\n\t\t// check if wildcardok\n\t\tif(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;\n\n\t\tNeededToRecompute.push_back(k);\n\t}\n\tnlinfo (\"%d sheets checked, %d need to be recomputed\", filenames.size(), NeededToRecompute.size());\n\n\n\tNLMISC::TTime last = NLMISC::CTime::getLocalTime ();\n\tNLMISC::TTime start = NLMISC::CTime::getLocalTime ();\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\tstd::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >\tcacheFormList;\n\n\t// For all sheets need to recompute\n\tfor (uint j = 0; j < NeededToRecompute.size(); j++)\n\t{\n\t\tif(NLMISC::CTime::getLocalTime () > last + 5000)\n\t\t{\n\t\t\tlast = NLMISC::CTime::getLocalTime ();\n\t\t\tif(j>0)\n\t\t\t\tnlinfo (\"%.0f%% completed (%d/%d), %d seconds remaining\", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);\n\t\t}\n\n\t\t// create the georges loader if necessary\n\t\tif (formLoader == NULL)\n\t\t{\n\t\t\tNLMISC::WarningLog->addNegativeFilter(\"CFormLoader: Can't open the form file\");\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader ();\n\t\t}\n\n\t\t//\tcache used to retain information (to optimize time).\n\t\tif (form)\n\t\t\tcacheFormList.push_back\t(form);\n\n\t\t// Load the form with given sheet id\n\t\tform = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());\n\t\tif (form)\n\t\t{\n\t\t\t// add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one\n\t\t\ttypedef typename std::map<NLMISC::CSheetId, T>::iterator TType1;\n            typedef typename std::pair<TType1, bool> TType2;\n\t\t\tTType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]],T()));\n\n\t\t\t(*res.first).second.readGeorges (form, sheetIds[NeededToRecompute[j]]);\n\t\t}\n\t}\n\n\tif(NeededToRecompute.size() > 0)\n\t\tnlinfo (\"%d seconds to recompute %d sheets\", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());\n\n\t// free the georges loader if necessary\n\tif (formLoader != NULL)\n\t{\n\t\tNLGEORGES::UFormLoader::releaseLoader (formLoader);\n\t\tNLMISC::WarningLog->removeFilter (\"CFormLoader: Can't open the form file\");\n\t}\n\n\t// housekeeping\n\tsheetIds.clear ();\n\tfilenames.clear ();\n}\n\n// ***************************************************************************\n// variant with smart pointers, maintain with function above\ntemplate <class T>\nvoid loadFormNoPackedSheet2 (const std::vector<std::string> &sheetFilters, std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> > &container, const std::string &wildcardFilter)\n{\n\t// make sure the CSheetId singleton has been properly initialised\n\tNLMISC::CSheetId::init(false);\n\n\t// build a vector of the sheetFilters sheet ids (ie: \"item\")\n\tstd::vector<NLMISC::CSheetId> sheetIds;\n\tstd::vector<std::string> filenames;\n\tfor (uint i = 0; i < sheetFilters.size(); i++)\n\t\tNLMISC::CSheetId::buildIdVector(sheetIds, filenames, sheetFilters[i]);\n\n\n\t// if there's no file, nothing to do\n\tif (sheetIds.empty())\n\t\treturn;\n\n\n\t// compute sheets that needs to be recomputed\n\tstd::vector<uint> NeededToRecompute;\n\tfor (uint k = 0; k < filenames.size(); k++)\n\t{\n\t\tstd::string p = NLMISC::CPath::lookup (filenames[k], false, false);\n\t\tif (p.empty()) continue;\n\t\t// check if wildcardok\n\t\tif(!wildcardFilter.empty() && !NLMISC::testWildCard(p,wildcardFilter)) continue;\n\n\t\tNeededToRecompute.push_back(k);\n\t}\n\tnlinfo (\"%d sheets checked, %d need to be recomputed\", filenames.size(), NeededToRecompute.size());\n\n\n\tNLMISC::TTime last = NLMISC::CTime::getLocalTime ();\n\tNLMISC::TTime start = NLMISC::CTime::getLocalTime ();\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\tstd::vector<NLMISC::CSmartPtr<NLGEORGES::UForm> >\tcacheFormList;\n\n\t// For all sheets need to recompute\n\tfor (uint j = 0; j < NeededToRecompute.size(); j++)\n\t{\n\t\tif(NLMISC::CTime::getLocalTime () > last + 5000)\n\t\t{\n\t\t\tlast = NLMISC::CTime::getLocalTime ();\n\t\t\tif(j>0)\n\t\t\t\tnlinfo (\"%.0f%% completed (%d/%d), %d seconds remaining\", (float)j*100.0/NeededToRecompute.size(),j,NeededToRecompute.size(), (NeededToRecompute.size()-j)*(last-start)/j/1000);\n\t\t}\n\n\t\t// create the georges loader if necessary\n\t\tif (formLoader == NULL)\n\t\t{\n\t\t\tNLMISC::WarningLog->addNegativeFilter(\"CFormLoader: Can't open the form file\");\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader ();\n\t\t}\n\n\t\t//\tcache used to retain information (to optimize time).\n\t\tif (form)\n\t\t\tcacheFormList.push_back\t(form);\n\n\t\t// Load the form with given sheet id\n\t\tform = formLoader->loadForm (sheetIds[NeededToRecompute[j]].toString().c_str ());\n\t\tif (form)\n\t\t{\n\t\t\t// add the new creature, it could be already loaded by the packed sheets but will be overwritten with the new one\n\t\t\ttypedef typename std::map<NLMISC::CSheetId, NLMISC::CSmartPtr<T> >::iterator TType1;\n            typedef typename std::pair<TType1, bool> TType2;\n\t\t\tTType2 res = container.insert(std::make_pair(sheetIds[NeededToRecompute[j]], NLMISC::CSmartPtr<T>(new T())));\n\n\t\t\t(*res.first).second->readGeorges (form, sheetIds[NeededToRecompute[j]]);\n\t\t}\n\t}\n\n\tif(NeededToRecompute.size() > 0)\n\t\tnlinfo (\"%d seconds to recompute %d sheets\", (uint32)(NLMISC::CTime::getLocalTime()-start)/1000, NeededToRecompute.size());\n\n\t// free the georges loader if necessary\n\tif (formLoader != NULL)\n\t{\n\t\tNLGEORGES::UFormLoader::releaseLoader (formLoader);\n\t\tNLMISC::WarningLog->removeFilter (\"CFormLoader: Can't open the form file\");\n\t}\n\n\t// housekeeping\n\tsheetIds.clear ();\n\tfilenames.clear ();\n}\n\n#endif // NL_LOAD_FORM_H\n\n/* End of load_form.h */\n"
  },
  {
    "path": "code/nel/include/nel/georges/type.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TYPE_H\n#define NL_TYPE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/georges/u_type.h\"\n#include \"nel/georges/u_form_elm.h\"\n#include \"header.h\"\n\nnamespace NLGEORGES\n{\n\nclass UFormElm;\n\n/**\n  * This class is a basic type used by atomic form element.\n  */\nclass CType : public UType\n{\n\tfriend class CFormLoader;\npublic:\n\n\tCType ();\n\tvirtual ~CType ();\n\n\t// ** UI\n\tenum TUI\n\t{\n\t\tEdit,\t\t\t\t// Default, for all types\n\t\tEditSpin,\t\t\t// For number types\n\t\tNonEditableCombo,\t// For all types\n\t\tFileBrowser,\t\t// Browse file\n\t\tBigEdit,\t\t\t// Edit a huge text\n\t\tColorEdit,\t\t\t// Edit a color\n\t\tIconWidget,\t\t\t// Draw an icon\n\t\tUITypeCount\n\t};\n\n\t// Is a UI compatible with a type ?\n\tstatic bool uiCompatible (TType type, TUI ui);\n\n\t// ** IO functions\n\tvoid\t\t\t\twrite (xmlDocPtr doc) const;\n\n\t// Header\n\tCFileHeader\t\t\tHeader;\n\n\t// Type of the type\n\tUType::TType\t\tType;\n\n\t// Type fo user interface\n\tTUI\t\t\t\t\tUIType;\n\n\t// Default value\n\tstd::string\t\t\tDefault;\n\n\t// Min value\n\tstd::string\t\t\tMin;\n\n\t// Max value\n\tstd::string\t\t\tMax;\n\n\t// Increment step value\n\tstd::string\t\t\tIncrement;\n\n\t// Evaluate a node\n\tbool\t\t\t\tgetValue (std::string &result, const class CForm *form, const class CFormElmAtom *node, const class CFormDfn &parentDfn,\n\t\t\t\t\t\t\t\t\tuint parentIndex, UFormElm::TEval evaluate, uint32 *where, uint32 round, const char *formName) const;\n\n\t// Definitions\n\tclass CDefinition\n\t{\n\tpublic:\n\t\t// Label of the definition\n\t\tstd::string\t\tLabel;\n\n\t\t// Value of the definition\n\t\tstd::string\t\tValue;\n\t};\n\n\t// Array of definition\n\tstd::vector<CDefinition>\tDefinitions;\n\n\t// Get the type names\n\tstatic const char *getTypeName (UType::TType type);\n\tstatic const char *getUIName (TUI type);\n\n\t// From UType\n\tvirtual TType\t\t\t\tgetType () const;\n\tvirtual const std::string\t&getDefault () const;\n\tvirtual const std::string\t&getMin () const;\n\tvirtual const std::string\t&getMax () const;\n\tvirtual const std::string\t&getIncrement () const;\n\tvirtual uint\t\t\t\tgetNumDefinition () const;\n\tvirtual bool\t\t\t\tgetDefinition (uint index, std::string &label, std::string &value) const;\n\tvirtual const std::string\t&getComment () const;\n\tvirtual\tvoid\t\t\t\tgetDependencies (std::set<std::string> &dependencies) const;\n\nprivate:\n\n\t// Error handling\n\tvirtual void\t\twarning (bool exception, const char *formName, const char *formFilename, const char *function, const char *format, ... ) const;\n\tvirtual void\t\twarning2 (bool exception, const char *function, const char *format, ... ) const;\n\n\t// Type names\n\tstatic const char\t*TypeNames[];\n\tstatic const char\t*UITypeNames[];\n\n\t// CFormLoader call it\n\tvoid\t\t\t\tread (xmlNodePtr root);\n\n};\n\n} // NLGEORGES\n\n#endif // NL_TYPE_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/u_form.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_U_FORM_H\n#define NL_U_FORM_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/smart_ptr.h\"\n#include <set>\n\nnamespace NLMISC\n{\nclass IStream;\n}\n\nnamespace NLGEORGES\n{\n\nclass UFormElm;\n\n/**\n  * This class provide an interface to access Georges form\n  */\nclass UForm : public NLMISC::CRefCount\n{\npublic:\n\n\tvirtual ~UForm ();\n\n\t/**\n\t  * Access form nodes\n\t  */\n\n\t/// Get a mutable pointer on the root element of the form. It is a struct node.\n\tvirtual UFormElm&\t\tgetRootNode () = 0;\n\n\t/// Get a const pointer on the root element of the form. It is a struct node.\n\tvirtual const UFormElm& getRootNode () const = 0;\n\n\t/** Write the form in a stream.\n\t  *\n\t  * \\param stream is the stream used to write the form\n\t  */\n\tvirtual void\t\t\twrite (NLMISC::IStream &stream) = 0;\n\n\t/**\n\t  * Access form parents\n\t  */\n\n\t/// Get a mutable pointer on the root element of the form. It is a struct node.\n\tvirtual uint\t\t\tgetNumParent () const = 0;\n\n\t/// Get a mutable pointer on the root element of the form. It is a struct node.\n\tvirtual UForm\t\t\t*getParentForm (uint parent) const = 0;\n\n\t// Get the form filename with extension\n\tvirtual const std::string &getFilename () const = 0;\n\n\t/**\n\t  * Get the comment\n\t  */\n\tvirtual const std::string &getComment () const = 0;\n\n\t/**\n\t  * Get dependency files\n\t  */\n\tvirtual void\tgetDependencies (std::set<std::string> &dependencies) const = 0;\n};\n\n\n} // NLGEORGES\n\n#endif // NL_U_FORM_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/u_form_dfn.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_U_FORM_DFN_H\n#define NL_U_FORM_DFN_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"u_form_elm.h\"\n#include \"nel/misc/smart_ptr.h\"\n\nnamespace NLGEORGES\n{\n\nclass UType;\n\n/**\n  * Georges DFN ifle interface\n  *\n  * \\author Cyril 'Hulud' Corvazier\n  * \\author Nevrax France\n  * \\date 2002\n  */\nclass UFormDfn : public NLMISC::CRefCount // Deprecated , public UFormElm\n{\npublic:\n\n  virtual ~UFormDfn() { }\n\n\n\t// ** Common methods\n\n\n\t// Type of dfn entry\n\tenum TEntryType\n\t{\n\t\tEntryType,\n\t\tEntryDfn,\n\t\tEntryVirtualDfn,\n\t};\n\n\t/**\n\t  * Return the number of entry in this DFN\n\t  */\n\tvirtual uint getNumEntry () const = 0;\n\n\t/**\n\t  * Return the entry type.\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the type.\n\t  * \\param type will be filled with the entry type.\n\t  * \\param array is true if the entry is an array, else false.\n\t  * \\return true if successed, false if the entry doesn't exist.\n\t  */\n\tvirtual bool getEntryType (uint entry, TEntryType &type, bool &array) const = 0;\n\n\t/**\n\t  * Return the entry name\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param name will be filled with the entry name.\n\t  * \\return true if successed, false if the entry doesn't exist.\n\t  */\n\tvirtual bool\tgetEntryName (uint entry, std::string &name) const = 0;\n\n\tvirtual\tbool\tgetEntryIndexByName (uint &entry, const\tstd::string &name) const = 0;\n\n\t/**\n\t  * Return the filename of the type or the DFN.\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param name will be filled with the entry filename.\n\t  * \\return true if successed, false if the entry doesn't exist or is a virtual DFN.\n\t  */\n\tvirtual bool getEntryFilename (uint entry, std::string &name) const = 0;\n\n\t/**\n\t  * Return the filename extension used by the DFN entry.\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param name will be filled with the entry filename.\n\t  * \\return true if successed, false if the entry doesn't exist or is a virtual DFN.\n\t  */\n\tvirtual bool getEntryFilenameExt (uint entry, std::string &name) const = 0;\n\n\t/**\n\t  * Return the entry DFN pointer\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param dfn will be filled with the DFN pointer.\n\t  * \\return true if successed, false if the entry doesn't exist or is not a DFN.\n\t  */\n\tvirtual bool getEntryDfn (uint entry, UFormDfn **dfn) = 0;\n\n\t/**\n\t  * Return the entry DFN pointer\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param name is the supposed name of the dfn.\n\t  * \\param dfn will be filled with the DFN pointer.\n\t  * \\return true if successed, false if the entry doesn't exist or is not a DFN.\n\t  */\n\tvirtual bool\tgetEntryDfnByName\t\t(const std::string &name, UFormDfn **dfn) = 0;\n\tvirtual bool\tisAnArrayEntryByName\t(const std::string &name)\tconst = 0;\n\n\t/**\n\t  * Return the entry Type pointer\n\t  * Doesn't look in parents DFN.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param type will be filled with the TYPE pointer.\n\t  * \\return true if successed, false if the entry doesn't exist or is not a Type.\n\t  */\n\tvirtual bool getEntryType (uint entry, UType **type) = 0;\n\n\t/**\n\t  * Get the number of parent DFN.\n\t  * Doesn't look in parents DFN for parents.\n\t  */\n\tvirtual uint getNumParents () const = 0;\n\n\t/**\n\t  * Get a parent.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param parent will be filled with the parent pointer.\n\t  * \\return true if successed, false if the parent doesn't exist.\n\t  */\n\tvirtual bool getParent (uint parent, UFormDfn **parentRet) = 0;\n\n\t/**\n\t  * Get a parent filename.\n\t  *\n\t  * \\param entry is the entry id to get the dfn pointer.\n\t  * \\param parent will be filled with the parent pointer.\n\t  * \\return true if successed, false if the parent doesn't exist.\n\t  */\n\tvirtual bool getParentFilename (uint parent, std::string &filename) const = 0;\n\n\t/**\n\t  * Get the comment\n\t  */\n\tvirtual const std::string &getComment () const = 0;\n\n\t/**\n\t  * Get dependency files\n\t  */\n\tvirtual void\tgetDependencies (std::set<std::string> &dependencies) const = 0;\n};\n\n} // NLGEORGES\n\n#endif // NL_U_FORM_DFN_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/u_form_elm.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_U_FORM_ELM_H\n#define NL_U_FORM_ELM_H\n\n#include \"nel/misc/types_nl.h\"\n\nnamespace NLMISC\n{\n\tclass CRGBA;\n}\n\nnamespace NLGEORGES\n{\n\nclass UFormElm\n{\npublic:\n\t// dtor\n\tvirtual ~UFormElm() {}\n\n\t// ** Common methods\n\n\t/// Value evalution\n\tenum TEval\n\t{\n\t\tNoEval,\t\t\t\t/// The value will not be evaluated at all, the litteral value will be returned\n\t\tFormula,\t\t\t/// Eval the enumeration value, but don't evaluate the formula nor the value references\n\t\tEval,\t\t\t\t/// Full evaluation of the value\n\t};\n\n\t/// Where a node has been found\n\tenum TWhereIsNode\n\t{\n\t\tNodeForm,\t\t\t/// The node has been found in the form\n\t\tNodeParentForm,\t\t/// The node has been found in the parent form\n\t\tNodeDfn,\t\t\t/// The node is a DFN\n\t\tNodeType,\t\t\t/// The node is a Type\n\t};\n\n\t/**\n\t  * Return a node pointer with its name.\n\t  *\n\t  * \\param result will be filled with the node pointer. Can be NULL if the node doesn't exist.\n\t  * \\param name is the form node name\n\t  * \\param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with\n\t  * the position where the node has been found. If result is NULL, where is undefined.\n\t  * \\return true if the result has been filled, false if the node is not referenced.\n\t  *\n\t  * About the node existance\n\t  *\n\t  * An atom node exist if its value is defined.\n\t  * A struct node exist if one of its children exist.\n\t  * An array node exist if one of its children exist.\n\t  * If the node doesn't exist, you can't have a pointer on it with getNodeByName(). It returns NULL.\n\t  * But, you can evaluate the value of non-existant atom nodes with getValueByName().\n\t  *\n\t  * About the form name:\n\t  *\n\t  * Struct elements name must be separated by '.'\n\t  * Struct indexes must be between '[' and ']'\n\t  *\n\t  * Exemple:\n\t  * \"position.x\"\t\t\t:\tget the element named x in the struct named position\n\t  * \"entities[2].color\"\t\t:\tget the node named color in the second element of the entities array\n\t  */\n\tvirtual bool\tgetNodeByName (const UFormElm **result, const char *name, TWhereIsNode *where = NULL, bool reserved=true, uint32 round=0) const = 0;\n\tvirtual bool\tgetNodeByName (UFormElm **result, const char *name, TWhereIsNode *where = NULL, bool reserved=true, uint32 round=0) = 0;\n\n\n\t/// Where a value has been found\n\tenum TWhereIsValue\n\t{\n\t\tValueForm,\t\t\t\t/// The value has been found in the form\n\t\tValueParentForm,\t\t/// The value has been found in the parent form\n\t\tValueDefaultDfn,\t\t/// The value has been found in the DFN default value\n\t\tValueDefaultType,\t\t/// The value has been found in the TYPE default value\n\t\tDummy = 0xffffffff\t\t/// Be sure the size == sizeof(uint32)\n\t};\n\n\t/**\n\t  * Get a form value with its name.\n\t  * The numbers are clamped to the type limit values.\n\t  *\n\t  * \\param result is a reference on the value to fill with the result.\n\t  * \\param name is the form name of the value to found.\n\t  * \\param evaluate must be true if you want to have an evaluated value, false if you want the formula value.\n\t  * \\param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with\n\t  * the position where the value has been found.\n\t  * \\return true if the result has been filled, false if the value has not been found or the cast has failed or the evaluation has failed.\n\t  * \\see getNodeByName ()\n\t  */\n\tvirtual bool\tgetValueByName (std::string &result, const char *namename, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (sint8 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (uint8 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (sint16 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (uint16 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (sint32 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (uint32 &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (float &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (double &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\tvirtual bool\tgetValueByName (bool &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\n\t/// Warning, only R, G and B members are filled, not A.\n\tvirtual bool\tgetValueByName (NLMISC::CRGBA &result, const char *name, TEval evaluate = Eval, TWhereIsValue *where = NULL, uint32 round=0) const = 0;\n\n\t/**\n\t  * Set a form value with its name. If the node doesn't exist, it is created.\n\t  *\n\t  * \\param value is a reference on the value to set in the form.\n\t  * \\param name is the form name of the value to set or create.\n\t  * \\param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with\n\t  * the position where the value has been found.\n\t  * \\param created is a pointer on the creatation flag. If created is not NULL, it is filled with\n\t  * true if the value has been created, false it the value has been filled.\n\t  * \\return true if the value has been set, false if the value has not been found or hasn't been created.\n\t  */\n\tvirtual bool\tsetValueByName (const char *value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (sint8 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (uint8 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (sint16 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (uint16 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (sint32 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (uint32 value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (float value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (double value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (bool value, const char *name, bool *created = NULL) = 0;\n\tvirtual bool\tsetValueByName (NLMISC::CRGBA value, const char *name, bool *created = NULL) = 0;\n\n\n\t// ** Array element methods\n\n\n\t/// Return true if the element is an array\n\tvirtual bool\tisArray () const = 0;\n\n\t/// Return true if the element is an array and fill size with the array size\n\tvirtual bool\tgetArraySize (uint &size) const = 0;\n\n\t/**\n\t  * Get a array sub element const pointer.\n\t  * If return true, fill result with the arrayIndex cell's element\n\t  * Can be NULL if the node doesn't exist.\n\t  */\n\tvirtual bool\tgetArrayNode (const UFormElm **result, uint arrayIndex) const = 0;\n\n\t/**\n\t  * Get a array sub element mutable pointer.\n\t  * If return true, fill result with the arrayIndex cell's element pointer.\n\t  * Can be NULL if the node doesn't exist.\n\t  */\n\tvirtual bool\tgetArrayNode (UFormElm **result, uint arrayIndex) = 0;\n\n\n\t/**\n\t  * Get an array value. The node must be an array of atom element.\n\t  *\n\t  * \\param result is a reference on the value to fill with the result.\n\t  * \\param arrayIndex is the array index to evaluate.\n\t  * \\param evaluate must be true if you want to have an evaluated value, false if you want the formula value.\n\t  * \\param where is a pointer on the information flag of the value. If Where is not NULL, it is filled with\n\t  * the position where the value has been found.\n\t  * \\return true if the result has been filled, false if the value has not been found or the cast has failed or the evaluation has failed.\n\t  */\n\tvirtual bool\tgetArrayValue (std::string &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (sint8 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (uint8 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (sint16 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (uint16 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (sint32 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (uint32 &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (float &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (double &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\tvirtual bool\tgetArrayValue (bool &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\n\t/// Warning, only R, G and B members are filled, not A.\n\tvirtual bool\tgetArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate = Eval, TWhereIsValue *where = NULL) const = 0;\n\n\t/// Return the name of a table element.\n\tvirtual bool\tgetArrayNodeName (std::string &result, uint arrayIndex) const = 0;\n\n\n\t// ** Struct element methods\n\n\n\t/// Return true if the element is a struct or a virtual struct\n\tvirtual bool\tisStruct () const = 0;\n\n\t/// Return true if the element is a virtual struct\n\tvirtual bool\tisVirtualStruct () const = 0;\n\n\t/// Get the dfn filename for this virtual struct. Must be a virtual struct node.\n\tvirtual bool\tgetDfnName (std::string &dfnName ) const = 0;\n\n\t/// Return the struct size\n\tvirtual bool\tgetStructSize (uint &size) const = 0;\n\n\t/// Return the element name\n\tvirtual bool\tgetStructNodeName (uint element, std::string &result) const = 0;\n\n\t/// Return a const element pointer. Can be NULL if the node doesn't exist.\n\tvirtual bool\tgetStructNode (uint element, const UFormElm **result) const = 0;\n\n\t/// Return a mutable element pointer. Can be NULL if the node doesn't exist.\n\tvirtual bool\tgetStructNode (uint element, UFormElm **result) = 0;\n\n\t/// Return the struct dfn\n\tvirtual class UFormDfn\t*getStructDfn () = 0;\n\n\t// ** Atom element methods\n\n\n\t/// Returns the type of the atom. NULL otherwise.\n\tvirtual const class UType     *getType () = 0;\n\n\t/// Return true if the element is an atom\n\tvirtual bool\tisAtom () const = 0;\n\n\t/**\n\t  * Return the atom value.\n\t  * The numbers are clamped to the type limit values.\n\t  *\n\t  * \\param result is the reference on the value to fill with result\n\t  * \\param evaluate must be true if you want to have an evaluated value, false if you want the formula value.\n\t  */\n\tvirtual bool\tgetValue (std::string &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (sint8 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (uint8 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (sint16 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (uint16 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (sint32 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (uint32 &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (float &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (double &result, TEval evaluate = Eval) const = 0;\n\tvirtual bool\tgetValue (bool &result, TEval evaluate = Eval) const = 0;\n\n\t/// Warning, only R, G and B members are filled, not A.\n\tvirtual bool\tgetValue (NLMISC::CRGBA &result, TEval evaluate = Eval) const = 0;\n};\n\n} // NLGEORGES\n\n#endif // NL_U_FORM_ELM_H\n"
  },
  {
    "path": "code/nel/include/nel/georges/u_form_loader.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_U_FORM_LOADER_H\n#define NL_U_FORM_LOADER_H\n\n#include \"nel/misc/types_nl.h\"\n\n\nnamespace NLGEORGES\n{\n\nclass UType;\nclass UForm;\nclass UFormDfn;\n\n/**\n * Georges form loader interface\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass UFormLoader\n{\npublic:\n\tvirtual ~UFormLoader() {}\n\n\t/** Load a form, use NMISC::CPath to find the file.\n\t  *\n\t  * The pointer on the form must be held in a CSmartPtr<UForm>. Returns NULL if the form can't be loaded.\n\t  */\n\tvirtual UForm *loadForm (const char *filename) = 0;\n\n\t/** Load a DFN, use NMISC::CPath to find the file.\n\t  *\n\t  * The pointer on the form must be held in a CSmartPtr<UFormDfn>. Returns NULL if the DFN can't be loaded.\n\t  */\n\tvirtual UFormDfn *loadFormDfn (const char *filename) = 0;\n\n\t/** Load a type, use NMISC::CPath to find the file.\n\t  *\n\t  * The pointer on the form must be held in a CSmartPtr<UType>. Returns NULL if the type can't be loaded.\n\t  */\n\tvirtual UType *loadFormType (const char *filename) = 0;\n\n\t/// Create a form loader\n\tstatic UFormLoader *createLoader ();\n\n\t/// Create a form loader\n\tstatic void releaseLoader (UFormLoader *loader);\n};\n\n\n} // NLGEORGES\n\n\n#endif // NL_U_FORM_LOADER_H\n\n/* End of u_form_loader.h */\n"
  },
  {
    "path": "code/nel/include/nel/georges/u_type.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_U_TYPE_H\n#define NL_U_TYPE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/smart_ptr.h\"\n\nnamespace NLGEORGES\n{\n\n/**\n * Georges type interface\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass UType : public NLMISC::CRefCount\n{\npublic:\n\n  virtual ~UType() { }\n\n\t// ** Type\n\tenum TType\n\t{\n\t\tUnsignedInt=0,\n\t\tSignedInt,\n\t\tDouble,\n\t\tString,\n\t\tColor,\n\t\tTypeCount\n\t};\n\n\t/**\n\t  * Get the type of this type.\n\t  */\n\tvirtual TType\t\t\t\tgetType () const = 0;\n\n\t/**\n\t  * Get the default value of this type.\n\t  */\n\tvirtual const std::string\t&getDefault () const = 0;\n\n\t/**\n\t  * Get the min value of this type.\n\t  */\n\tvirtual const std::string\t&getMin () const = 0;\n\n\t/**\n\t  * Get the max value of this type.\n\t  */\n\tvirtual const std::string\t&getMax () const = 0;\n\n\t/**\n\t  * Get the increment value of this type.\n\t  */\n\tvirtual const std::string\t&getIncrement () const = 0;\n\n\t/**\n\t  * Get the definition count for this type.\n\t  */\n\tvirtual uint\t\t\t\tgetNumDefinition () const = 0;\n\n\t/**\n\t  * Get a definition for this type.\n\t  *\n\t  * index is the index of the defnition you want to get.\n\t  * If the method returns true, label will be filled with\n\t  * the definition label and value will be filled with the\n\t  * defnition value.\n\t  * The method returns false if the index is invalid. In this\n\t  * case, label and value are not changed.\n\t  */\n\tvirtual bool\t\t\t\tgetDefinition (uint index, std::string &label, std::string &value) const = 0;\n\n\t/**\n\t  * Get the comments of type.\n\t  */\n\tvirtual const std::string\t&getComment () const = 0;\n\n\t/**\n\t  * Get dependency files\n\t  */\n\tvirtual void\tgetDependencies (std::set<std::string> &dependencies) const = 0;\n};\n\n\n} // NLGEORGES\n\n\n#endif // NL_U_TYPE_H\n\n/* End of u_type.h */\n"
  },
  {
    "path": "code/nel/include/nel/ligo/CMakeLists.txt",
    "content": "FILE(GLOB HEADERS *.h)\n\nINSTALL(FILES ${HEADERS} DESTINATION include/nel/ligo COMPONENT headers)\n"
  },
  {
    "path": "code/nel/include/nel/ligo/ligo_config.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LIGO_CONFIG_H\n#define NL_LIGO_CONFIG_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"primitive_class.h\"\n#include \"primitive_configuration.h\"\n\n#define DEFAULT_PRIMITIVE_COLOR (CRGBA (128, 0, 0, 128))\n\nnamespace NLLIGO\n{\n\nclass IPrimitive;\nclass CPrimitive;\n\n/**\n *  Ligo config file\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLigoConfig\n{\npublic:\n\n\tCLigoConfig();\n\n\tvirtual ~CLigoConfig() { }\n\n\t/** Load the config file. Can throw some exceptions if file doesn't exist or is malformed.\n\t  *\n\t  * This file will try to open the file ligo class description file (XML) using the LigoClass as file name.\n\t  * It will try first to load directly the file and then to lookup the file in NLMISC::CPath.\n\t  */\n\tbool readConfigFile (const char *fileName, bool parsePrimitiveComboContent);\n\n\t/**\n\t  * This file will read the file ligo class description file (XML) using the LigoClass as file name.\n\t  * It will try first to load directly the file and then to lookup the file in NLMISC::CPath.\n\t  */\n\tbool readPrimitiveClass (const char *fileName, bool parsePrimitiveComboContent);\n\n\tbool reloadIndexFile(const std::string &indexFileName = std::string());\n\n\n\t/// Reset the primitive configurations\n\tvoid resetPrimitiveConfiguration ();\n\n\t/// \\name Public value\n\n\t/// Size of a cell of the ligoscape in meter\n\tfloat\tCellSize;\n\n\t/// Snap precision for vertex position checking in meter\n\tfloat\tSnap;\n\n\t/// Zone snap shot resolution\n\tuint\tZoneSnapShotRes;\n\n\t/// The ligo class file\n\tstd::string\tPrimitiveClassFilename;\n\n\t/// \\name Primitive class accessors\n\n\t/// Get the dynamic bit size for alias\n\tuint32\t\t\t\tgetDynamicAliasSize() const;\n\t/// Get the dynamic bit mask for alias\n\tuint32\t\t\t\tgetDynamicAliasMask() const;\n\t/// Get the static bit size for alias\n\tuint32\t\t\t\tgetStaticAliasSize() const;\n\t/// Get the static bit mask for alias\n\tuint32\t\t\t\tgetStaticAliasMask() const;\n\t/// Build an alias given a static and dynamic part\n\tuint32\t\t\t\tbuildAlias(uint32 staticPart, uint32 dynamicPart, bool warnIfOverload = true) const;\n\t/// register filename to static alias translation\n\tvoid\t\t\t\tregisterFileToStaticAliasTranslation(const std::string &fileName, uint32 staticPart);\n\t/// get the static alias mapping (or 0 if no mapping defined)\n\tvirtual uint32\t\t\t\tgetFileStaticAliasMapping(const std::string &fileName) const;\n\t/// get the filename for a static alias (or empty string for 0)\n\tconst std::string\t&getFileNameForStaticAlias(uint32 staticAlias) const;\n\t/// Check if a file is already mapped\n\tbool\t\t\t\tisFileStaticAliasMapped(const std::string &fileName) const;\n\t/// Build a standard human readable alias string\n\tstd::string\t\t\taliasToString(uint32 fullAlias);\n\t/// Read a standard human readable alias string\n\tuint32\t\t\t\taliasFromString(std::string fullAlias);\n\n\n\t// Get a primitive class\n\tconst CPrimitiveClass\t\t*getPrimitiveClass (const NLLIGO::IPrimitive &primitive) const;\n\n\t// Get a primitive class\n\tconst CPrimitiveClass\t\t*getPrimitiveClass (const char *className) const;\n\n\t// Get the primitive color\n\tNLMISC::CRGBA\t\t\t\tgetPrimitiveColor (const NLLIGO::IPrimitive &primitive);\n\n\t// Is the primitive deletable ?\n\tbool isStaticChild (const NLLIGO::IPrimitive &primitive);\n\n\t// Is the primitive linked to its brother primitive ?\n\tbool isPrimitiveLinked (const NLLIGO::IPrimitive &primitive);\n\n\t// Return the next primitive linked to 'primitive', or NULL\n\tconst NLLIGO::IPrimitive *getLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const;\n\n\t// Return the previous primitive linked to 'primitive', or NULL\n\tconst NLLIGO::IPrimitive *getPreviousLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const;\n\n\t// Is the primitive deletable ?\n\tbool isPrimitiveDeletable (const NLLIGO::IPrimitive &primitive);\n\n\t// Is the child primitive can be a child of the parent primitive ?\n\tbool canBeChild (const NLLIGO::IPrimitive &child, const NLLIGO::IPrimitive &parent);\n\n\t// Is the primitive a root primitive ?\n\tbool canBeRoot (const NLLIGO::IPrimitive &primitive);\n\n\t// Read a property from an XML file\n\tbool getPropertyString (std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName);\n\n\t// Output error message\n\tvoid syntaxError (const char *filename, xmlNodePtr xmlNode, const char *format, ...);\n\tvirtual void errorMessage (const char *format, ... );\n\n\t// Access to the config string\n\tconst std::vector<std::string> &getContextString () const;\n\n\t// Access the primitive configuration\n\tconst std::vector<CPrimitiveConfigurations> &getPrimitiveConfiguration() const\n\t{\n\t\treturn _PrimitiveConfigurations;\n\t}\n\n\t// Update the DynamicAlias bit count that was previously defined in the config file.\n\t// The _StaticAliasFileMapping is updated in order that full alias stay the same.\n\t// All previous DynamicAlias must fit in the new DynamicAliasBitCount\n\tvoid updateDynamicAliasBitCount(uint32 newDynamicAliasBitCount);\n\nprivate:\n\n\t// Init primitive class manager\n\tbool\t\tinitPrimitiveClass (const char *filename);\n\n\t// The primitive class manager\n\tstd::map<std::string, CPrimitiveClass>\t_PrimitiveClasses;\n\n\t// The context strings\n\tstd::vector<std::string>\t_Contexts;\n\n\t// The file context look up\n\tstd::map<std::string, std::string>\t_ContextFilesLookup;\n\n\t// The primitive configurations\n\tstd::vector<CPrimitiveConfigurations>\t_PrimitiveConfigurations;\n\n\t// Dynamic alias bit count\n\tuint32\t\t\t\t_DynamicAliasBitCount;\n\n\t/// Name of the index file\n\tstd::string\t\t\t_IndexFileName;\n\t// Static alias part file mapping : filename -> staticAliasPart\n\tstd::map<std::string, uint32>\t\t_StaticAliasFileMapping;\n};\n\n}\n\n#endif // NL_LIGO_CONFIG_H\n\n/* End of ligo_config.h */\n"
  },
  {
    "path": "code/nel/include/nel/ligo/primitive.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef __PRIMITIVE_H__\n#define __PRIMITIVE_H__\n\n#include \"nel/misc/vector.h\"\n#include \"nel/misc/rgba.h\"\n\n// Include from libxml2\n#include <libxml/parser.h>\n\n#include <vector>\n\nnamespace NLLIGO\n{\n\n#ifdef NL_DEBUG\n#\tdefine NLLIGO_DEBUG\n#endif\n\n\n/**\n  * Ligo primitives are used to add logical geometrical gameplay information.\n  * Ligo primitives are NODES, POINTS, PATHES or ZONES.\n  * Ligo primitives have a CLASS.\n  *\n  * The primitive class defines the properties attached to the primitive\n  * The primitive class are defined in the XML file specified in the LigoClass field of the CLigoConfig class.\n  */\n\nclass CPrimitives;\nclass CLigoConfig;\n\n// ***************************************************************************\n\nvoid Register ();\n\n// ***************************************************************************\n\n/*\n * This class is a property class for ligo primitive.\n */\nclass IProperty : public NLMISC::IStreamable\n{\npublic:\n\tIProperty ()\n\t{\n\t\tDefault = false;\n\t}\n\n\t// This property is set to default\n\tbool Default;\n\t// Force class to be polymorphic\n\tvirtual void foo () const = 0;\n};\n\n// ***************************************************************************\n\n/*\n * This class is a property class for ligo primitive.\n * This is a simple string\n */\nclass CPropertyString : public IProperty\n{\npublic:\n\tCPropertyString () {}\n\tCPropertyString (const char *str);\n\tCPropertyString (const std::string &str);\n\tCPropertyString (const char *str, bool _default);\n\tvirtual ~CPropertyString () {}\n\tstd::string\t\t\tString;\n\n\tNLMISC_DECLARE_CLASS (CPropertyString)\n\n\tvirtual void serial(NLMISC::IStream &f)\n\t{\n\t\tf.serial(Default);\n\t\tf.serial(String);\n\t}\n\n\t// Force class to be polymorphic\n\tvirtual void foo () const {}\n};\n\n// ***************************************************************************\n\n/*\n * This class is a property class for ligo primitive.\n * This is a string array\n */\nclass CPropertyStringArray : public IProperty\n{\npublic:\n\tCPropertyStringArray () {}\n\tvirtual ~CPropertyStringArray () {}\n\tCPropertyStringArray (const std::vector<std::string> &stringArray);\n\tCPropertyStringArray (const std::vector<std::string> &stringArray, bool _default);\n\tstd::vector<std::string>\tStringArray;\n\n\tNLMISC_DECLARE_CLASS (CPropertyStringArray)\n\n\tvirtual void serial(NLMISC::IStream &f)\n\t{\n\t\tf.serial(Default);\n\t\tf.serialCont(StringArray);\n\t}\n\t// Force class to be polymorphic\n\tvirtual void foo () const {}\n};\n\n// ***************************************************************************\n\n/*\n * This class is a property class for ligo primitive.\n * This is a string array\n */\nclass CPropertyColor : public IProperty\n{\npublic:\n\tNLMISC::CRGBA\t\tColor;\n\n\tNLMISC_DECLARE_CLASS (CPropertyColor)\n\n\tvirtual void serial(NLMISC::IStream &f)\n\t{\n\t\tf.serial(Default);\n\t\tf.serial(Color);\n\t}\n\t// Force class to be polymorphic\n\tvirtual void foo () const {}\n\n\t// ctors\n\tCPropertyColor() {}\n\tCPropertyColor(NLMISC::CRGBA col) : Color(col) {}\n};\n\n// ***************************************************************************\n\nclass CPrimVector : public NLMISC::CVector\n{\npublic:\n\tCPrimVector ()\n\t{\n\t\tSelected = false;\n\t}\n\tCPrimVector (const NLMISC::CVector &v)\n\t{\n\t\tCVector::operator= (v);\n\t\tSelected = false;\n\t}\n\n\tvoid serial(NLMISC::IStream &f)\n\t{\n\t\tCVector::serial(f);\n\t\tf.serial(Selected);\n\t}\n\n\tbool\tSelected;\n};\n\n// ***************************************************************************\n\n/*\n * This class is the base class for ligo primitive.\n *\n * Provide access to common properties.\n * Provide access to the primitive hierachy\n */\nclass IPrimitive : public NLMISC::IStreamable\n{\n\tfriend class CPrimitives;\npublic:\n\n\t// Deprecated\n//\tstd::string\t\t\t\t\t\tLayer;\n\t// Deprecated\n//\tstd::string\t\t\t\t\t\tName;\n\n\t// Expended in the tree view\n//\tbool\t\t\t\t\t\t\tExpanded;\n\n\tenum\n\t{\n\t\tNotAnArray,\n\t\tAtTheEnd = 0xffffffff,\n\t};\n\n\t/// \\name Hierarchy\n\tIPrimitive ();\n\n\tvirtual ~IPrimitive ();\n\n\tIPrimitive (const IPrimitive &node);\n\n\tvirtual void operator= (const IPrimitive &node);\n\n\t/** Get the children primitive count */\n\tuint\t\t\t\tgetNumChildren () const\n\t{\n\t\treturn (uint)_Children.size ();\n\t}\n\n\t/** Get a child primitive */\n\tbool\t\t\t\tgetChild (const IPrimitive *&result, uint childId) const;\n\n\t/** Get a child primitive */\n\tbool\t\t\t\tgetChild (IPrimitive *&result, uint childId);\n\n\t/** Get the parent primitive */\n\tIPrimitive\t\t\t*getParent ()\n\t{\n\t\treturn _Parent;\n\t}\n\tconst IPrimitive\t*getParent () const\n\t{\n\t\treturn _Parent;\n\t}\n\n\t/**\tGet the primitive relative to this and the given path\t */\n\tconst\tIPrimitive\t*getPrimitive\t(const\tstd::string\t&absoluteOrRelativePath)\tconst;\n\n\t/** Get the id of the child, return 0xffffffff if not found */\n\tbool\t\t\t\tgetChildId (uint &childId, const IPrimitive *child) const;\n\n\t/** Remove and delete a child primitive */\n\tbool\t\t\t\tremoveChild (IPrimitive *child);\n\n\t/** Remove and delete a child primitive */\n\tbool\t\t\t\tremoveChild (uint childId);\n\n\t/// Remove the child primitive from the children list, don't delete it\n\tbool\t\t\t\tunlinkChild(IPrimitive *child);\n\n\t/** Remove and delete all children primitives */\n\tvoid\t\t\t\tremoveChildren ();\n\n\t/**\n\t  * Insert a child primitive before the index.\n\t  * The pointer will be deleted by the parent primitive using the ::delete operator.\n\t  * return false if the index is invalid\n\t  */\n\tbool\t\t\t\tinsertChild (IPrimitive *primitive, uint index = AtTheEnd);\n\n\t/// \\name Properties\n\n\t/**\n\t  * Get a num properties\n\t  **/\n\tuint\t\t\t\tgetNumProperty () const;\n\n\t/**\n\t  * Get a properties by its index\n\t  * This method (iterate a list) is slower than getPropertyByName (look up in a map).\n\t  **/\n\tbool\t\t\t\tgetProperty (uint index, std::string &property_name, const IProperty *&result) const;\n\n\t/**\n\t  * Get a properties by its index\n\t  * This method (iterate a list) is slower than getPropertyByName (look up in a map).\n\t  **/\n\tbool\t\t\t\tgetProperty (uint index, std::string &property_name, IProperty *&result);\n\n\t/** Check the existence of a named property */\n\tbool\t\t\t\tcheckProperty(const std::string &property_name) const;\n\n\t/**\n\t  * Add a property\n\t  * If the property already exist, the method does nothing and returns false.\n\t  * The pointer will be deleted by the primitive using the ::delete operator.\n\t  **/\n\tbool\t\t\t\taddPropertyByName (const char *property_name, IProperty *result);\n\n\t/**\n\t  * Get a property with its name\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, const IProperty *&result) const;\n\n\t/**\n\t  * Get a property with its name\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, IProperty *&result) const;\n\n\t/**\n\t  * Get a string property with its name. Return false if the property is not found or is not a string property.\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, std::string *&result) const;\n\n\t/**\n\t  * Get a string array property with its name. Return false if the property is not found or is not a string array property.\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, std::vector<std::string> *&result) const;\n\n\t/**\n\t  * Get a string property with its name. Return false if the property is not found or is not a string property.\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, std::string &result) const;\n\n\t/**\n\t  * Get a string array property with its name. Return false if the property is not found or is not a string array property.\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, const std::vector<std::string> *&result) const;\n\n\t/**\n\t  * Get a color property with its name. Return false if the property is not found or is not a string array property.\n\t  **/\n\tbool\t\t\t\tgetPropertyByName (const char *property_name, NLMISC::CRGBA &result) const;\n\n\t/**\n\t  * Remove a property\n\t  * This is method (iterate a list) is slower than removePropertyByName (look up in a map).\n\t  **/\n\tbool\t\t\t\tremoveProperty (uint index);\n\n\t/**\n\t  * Remove a property by its name\n\t  **/\n\tbool\t\t\t\tremovePropertyByName (const char *property_name);\n\n\t/**\n\t  * Remove all the properties\n\t  **/\n\tvoid\t\t\t\tremoveProperties ();\n\n\t/* Init default primitive's parameters\n\t *\n\t * This method will add all the properties declared in the primitive class and create default properties.\n\t */\n\tvoid\t\t\t\tinitDefaultValues (CLigoConfig &config);\n\n\t// Read the primitive, calls initDefaultValue (CLigoConfig &config)\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\n\t// Write the primitive\n\tvirtual void write (xmlNodePtr xmlNode, const char *filename) const;\n\n\t// Get the vertices\n\tvirtual uint\t\t\t\tgetNumVector () const = 0;\n\tvirtual const CPrimVector\t*getPrimVector () const = 0;\n\tvirtual CPrimVector\t\t\t*getPrimVector () = 0;\n\n\t// Make a copy\n\tvirtual IPrimitive *copy () const = 0;\n\n\t// used for fast binary save/load (exploitation mode)\n\tvoid serial(NLMISC::IStream &f);\n\n\t// shortcut to getPropertyByName(\"name\", ret); return ret;\n\tstd::string\t\t\t\t\tgetName() const;\n\n\tconst std::string\t\t\t&getUnparsedProperties() const;\n\tvoid\t\t\t\t\t\tsetUnparsedProperties(const std::string &unparsedProperties) const;\n\nprivate:\n\n\t// callback called just after the node is attach under a parent\n\tvirtual void onLinkToParent() {}\n\t// callback called just before the node is removed from it's parent\n\tvirtual void onUnlinkFromParent() {}\n\n\t/// Callback called just after an ancestor is linked\n\tvirtual void onBranchLink() {}\n\t/// Callback called just before an ancestor is unlinked\n\tvirtual void onBranchUnlink() {}\n\n\t/// Callback called when the primitive is updated, giving a chance to track the primitive's modifications during the loading\n\tvirtual void onModifyPrimitive(CPrimitives &/* primitives */) const {}\n\n\t// internal recusive call\n\tvoid branchLink();\n\tvoid branchUnlink();\n\n\t// Update child Id\n\tvoid updateChildId (uint index);\n\n\t// Child id\n\tuint32\t\t\t\t\t\t\t\t\t_ChildId;\n\n\t// Parent\n\tIPrimitive\t\t\t\t\t\t\t\t*_Parent;\n\n\t// Children\n\tstd::vector<IPrimitive*>\t\t\t\t_Children;\n\n\t// Single properties\n\tstd::map<std::string, IProperty*>\t\t_Properties;\n\n\t// Editor specific properties (unparsed)\n\tmutable std::string\t\t\t\t\t\t_UnparsedProperties;\n\n\n#ifdef NLLIGO_DEBUG\n\tstd::string\t\t\t\t\t\t\t\t_DebugClassName;\n\tstd::string\t\t\t\t\t\t\t\t_DebugPrimitiveName;\n#endif\n\n\n};\n\n// ***************************************************************************\n\n// Simple primitive node\nclass CPrimNode : public IPrimitive\n{\npublic:\n\t// \\name From IClassable\n\tNLMISC_DECLARE_CLASS (CPrimNode)\n\nprotected:\n\n\t// void operator= (const CPrimNode &node);\n\n\n\t// Get the vertices\n\tvirtual uint\t\t\t\tgetNumVector () const;\n\tvirtual const CPrimVector\t*getPrimVector () const;\n\tvirtual CPrimVector\t\t\t*getPrimVector ();\n\n\t// Read the primitive\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\n\t// \\name From IPrimitive\n\tvirtual IPrimitive *copy () const;\n};\n\n// ***************************************************************************\n\nclass CPrimPoint : public IPrimitive\n{\n\npublic:\n\n\tCPrimPoint ()\n\t{\n\t\tAngle = 0;\n\t}\n\n\n\tCPrimVector\t\t\t\tPoint;\n\tfloat\t\t\t\t\tAngle;\t// Angle on OZ, CCW\n\npublic:\n\n\tvoid serial (NLMISC::IStream &f);\n\n\t// void operator= (const CPrimPoint &node);\n\n\t// \\name From IClassable\n\tNLMISC_DECLARE_CLASS (CPrimPoint);\n\nprotected:\n\n\t// Get the vertices\n\tvirtual uint\t\t\t\tgetNumVector () const;\n\tvirtual const CPrimVector\t*getPrimVector () const;\n\tvirtual CPrimVector\t\t\t*getPrimVector ();\n\n\t// Read the primitive\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\n\t// Write the primitive\n\tvirtual void write (xmlNodePtr xmlNode, const char *filename) const;\n\n\t// \\name From IPrimitive\n\tvirtual IPrimitive *copy () const;\n};\n\n\n// ***************************************************************************\nclass CPrimPath : public IPrimitive\n{\n\npublic:\n\n\tstd::vector<CPrimVector>\tVPoints;\n\npublic:\n\n\tvoid serial (NLMISC::IStream &f);\n\n\t// void operator= (const CPrimPath &node);\n\n\t// \\name From IClassable\n\tNLMISC_DECLARE_CLASS (CPrimPath);\n\nprotected:\n\n\t// Get the vertices\n\tvirtual uint\t\t\t\tgetNumVector () const;\n\tvirtual const CPrimVector\t*getPrimVector () const;\n\tvirtual CPrimVector\t\t\t*getPrimVector ();\n\n\t// Read the primitive\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\n\t// Write the primitive\n\tvirtual void write (xmlNodePtr xmlNode, const char *filename) const;\n\n\t// \\name From IPrimitive\n\tvirtual IPrimitive *copy () const;\n};\n\n\n// ***************************************************************************\n\nclass CPrimZone : public IPrimitive\n{\n\npublic:\n\n\tstd::vector<CPrimVector>\tVPoints;\n\n\tstatic float getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos);\n\npublic:\n\n\tbool contains (const NLMISC::CVector &v) const { return CPrimZone::contains(v, VPoints); }\n\tbool contains(const NLMISC::CVector &v, float &distance, NLMISC::CVector &nearPos, bool isPath) const { return CPrimZone::contains(v, VPoints, distance, nearPos, isPath); }\n\n\t// void operator= (const CPrimZone &node);\n\n\tvoid serial (NLMISC::IStream &f);\n\n\t// Returns true if the vector v is inside of the patatoid\n\tstatic bool contains (const NLMISC::CVector &v, const std::vector<NLMISC::CVector> &points);\n\t// Returns true if the vector v is inside of the patatoid and set the distance of the nearest segment and the position of the nearest point.\n\tstatic bool contains (const NLMISC::CVector &v, const std::vector<NLMISC::CVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath);\n\t// Returns true if the vector v is inside of the patatoid\n\tstatic bool contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points);\n\t// Returns true if the vector v is inside of the patatoid and set the distance of the nearest segment and the position of the nearest point.\n\tstatic bool contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath);\n\n\t/// Returns the barycenter of the zone (warning, it may be outside of the zone if it is not convex). Returns CVector::Null if there is no vertex.\n\tNLMISC::CVector\t\tgetBarycentre() const;\n\n\t/// Returns the smallest axis-aligned box containing the zone (z is always set to 0)\n\tvoid\t\t\t\tgetAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const;\n\n\t/// Return the area of the axis-aligned box containing the zone\n\tfloat\t\t\t\tgetAreaOfAABox() const;\n\n\t// \\name From IClassable\n\tNLMISC_DECLARE_CLASS (CPrimZone);\n\nprotected:\n\n\t// Get the vertices\n\tvirtual uint\t\t\t\tgetNumVector () const;\n\tvirtual const CPrimVector\t*getPrimVector () const;\n\tvirtual CPrimVector\t\t\t*getPrimVector ();\n\n\t// Read the primitive\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\n\t// Write the primitive\n\tvirtual void write (xmlNodePtr xmlNode, const char *filename) const;\n\n\t// \\name From IPrimitive\n\tvirtual IPrimitive *copy () const;\n};\n\n\n// ***************************************************************************\n\n/** This primitive type is used to handle unique alias across a primitive file.\n *\tUsage of this primitive imply the setting of the appropriate 'ligo context'\n *\tbefore reading or copy/pasting alias.\n*/\nclass CPrimAlias : public IPrimitive\n{\n\tfriend class CPrimitives;\n\n\t/// The 'dynamic' part of the alias\n\tuint32\t\t\t\t_Alias;\n\t/// The primitive container\n\tclass CPrimitives\t*_Container;\n\n\t// Needed overloads (not used)\n\tvirtual uint\t\t\t\tgetNumVector () const\n\t{\n\t\treturn 0;\n\t};\n\tvirtual const CPrimVector\t*getPrimVector () const\n\t{\n\t\treturn NULL;\n\t}\n\tvirtual CPrimVector\t\t\t*getPrimVector ()\n\t{\n\t\treturn NULL;\n\t}\n\n\n\tvirtual void onBranchLink();\n\t// callback called just before the node is removed from it's parent\n\tvirtual void onBranchUnlink();\n\n\tvoid regenAlias();\n\npublic:\n\t// \\name From IClassable\n\tNLMISC_DECLARE_CLASS (CPrimAlias);\n\n\t// private default constructor\n\tCPrimAlias();\n\t// copy constructor needed\n\tCPrimAlias(const CPrimAlias &other);\n\n\t~CPrimAlias();\n\n\t// return the dynamic part of the alias\n\tuint32\tgetAlias() const;\n\n\t// Return the full alias, merge of the static and dynamic part\n\tuint32\tgetFullAlias() const;\n\n\t// Read the primitive\n\tvirtual bool read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config);\n\t// Write the primitive\n\tvirtual void write (xmlNodePtr xmlNode, const char *filename) const;\n\t// Create a copy of this primitive\n\tvirtual IPrimitive *copy () const;\n\t// serial for binary save\n\tvirtual void serial (NLMISC::IStream &f);\n\n};\n\n// ***************************************************************************\n\n/*\nThis class is deprecated.\n*/\nclass CPrimRegion\n{\n\npublic:\n\n\tstd::string\t\t\t\tName;\n\tstd::vector<CPrimPoint> VPoints;\n\tstd::vector<CPrimZone>\tVZones;\n\tstd::vector<CPrimPath>\tVPaths;\n\n\tstd::vector<bool>\t\tVHidePoints;\n\tstd::vector<bool>\t\tVHideZones;\n\tstd::vector<bool>\t\tVHidePaths;\n\npublic:\n\n\tvoid serial (NLMISC::IStream &f);\n};\n\n// ***************************************************************************\n\n/**\n  * This class is a ligo primitives set\n  */\nclass CPrimitives\n{\npublic:\n\n\tCPrimitives ();\n\tCPrimitives (const CPrimitives &other);\n\t~CPrimitives ();\n\n\t// Operator copy\n\tCPrimitives&\toperator= (const CPrimitives &other);\n\n\t// Convert from old format to the new one\n\tvoid\t\t\tconvert (const CPrimRegion &region);\n\n\t// Read the primitive\n\tbool\t\t\tread (xmlNodePtr xmlNode, const char *filename, CLigoConfig &config);\n\n\t// Write the primitive\n\tvoid\t\t\twrite (xmlDocPtr xmlNode, const char *filename) const;\n\n\t// Write the primitive\n\tvoid\t\t\twrite (xmlNodePtr root, const char *filename) const;\n\n\t// serial the primitive. Used for binary files.\n\tvoid\t\t\tserial(NLMISC::IStream &f);\n\n\t// Root primitive hierarchy\n\tCPrimNode\t\t*RootNode;\n\n\t// get the static alias part for this primitive\n\tuint32\t\t\tgetAliasStaticPart();\n\n\t// set the static alias part for this primitive\n\tvoid\t\t\tsetAliasStaticPart(uint32 staticPart);\n\n\t// Build an alias by combining the static and dynamic part\n\tuint32\t\t\tbuildFullAlias(uint32 dynamicPart);\n\n\t// Generate a new unique alias (dynamic part only)\n\tuint32\t\t\tgenAlias(IPrimitive *prim, uint32 preferedAlias = 0);\n\t// Reserve an alias and store it in the used alias list (dynamic part only)\n//\tvoid\t\t\treserveAlias(uint32 dynamicAlias);\n\t// Remove an alias from the list of alias in use (dynamic part only)\n\tvoid\t\t\treleaseAlias(IPrimitive *prim, uint32 dynamicAlias);\n\n\t// Force the assignation of the specified alias to the primitive. If another primitive\n\t// already hold the alias, this other primitive is assigned a new alias.\n\tvoid\t\t\tforceAlias(CPrimAlias *prim, uint32 alias);\n\n\t// get the last generated alias value (for debug only)\n\tuint32\t\t\tgetLastGeneratedAlias();\n\n\t// Return the primitive indexed by the given alias (ie, it doesn't return the alias primitive, but its first parent)\n\tIPrimitive\t\t*getPrimitiveByAlias(uint32 primAlias);\n\n\t// Build the complete list of indexed primitive (ie all primitive that have a primalias child)\n\tvoid\t\t\tbuildPrimitiveWithAliasList(std::map<uint32, IPrimitive*> &result);\n\n\nprivate:\n\t// Conversion internal methods\n\tvoid\t\t\tconvertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden);\n\tvoid\t\t\tconvertPrimitive (const IPrimitive *prim, bool hidden);\n\n\t/// Optional context information\n\tCLigoConfig\t\t\t*_LigoConfig;\n\t/// Static part alias mapping (can be 0 if no mapping is defined)\n\tuint32\t\t\t\t_AliasStaticPart;\n\t/// Last generated Alias, used to compute the next alias\n\tuint32\t\t\t\t_LastGeneratedAlias;\n\t/// List of alias in use in the primitive (dynamic part only)\n\tstd::map<uint32, IPrimitive*>\t_AliasInUse;\n\t// Store the filename\n\t// This allows to retrieve the static alias when reloading from binary file\n\tstd::string\t\t\t_Filename;\n};\n\n// ***************************************************************************\n\n/** Singleton to manage special loading feature related to\n *\tunique alias assignment\n */\nclass CPrimitiveContext\n{\n\tstatic CPrimitiveContext\t*_Instance;\n\n\t// private ctor\n\tCPrimitiveContext();\npublic:\n\n\t// get the singleton reference\n\tstatic CPrimitiveContext\t&instance()\n\t{\n\t\tif (!_Instance)\n\t\t{\n\t\t\t_Instance = new CPrimitiveContext;\n\t\t}\n\n\t\treturn *_Instance;\n\t}\n\n\t/// The current ligo configuration file.\n\tCLigoConfig\t\t*CurrentLigoConfig;\n\t/// The current primitives container.\n\tCPrimitives\t\t*CurrentPrimitive;\n\n};\n\n\n} // namespace NLLIGO\n\n#endif // __PRIMITIVE_H__\n\n"
  },
  {
    "path": "code/nel/include/nel/ligo/primitive_class.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PRIMITIVE_CLASS_H\n#define NL_PRIMITIVE_CLASS_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/rgba.h\"\n#include <map>\n#include <set>\n\n// Include from libxml2\n#include <libxml/parser.h>\n\nnamespace NLLIGO\n{\n\nclass IPrimitive;\nclass IProperty;\nclass CLigoConfig;\n\n/**\n * Class of primitive\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass CPrimitiveClass\n{\npublic:\n\n\t// Type of the primitive\n\tenum TType\n\t{\n\t\tNode,\n\t\tPoint,\n\t\tPath,\n\t\tBitmap,\n\t\tZone,\n\t\tAlias\n\t}\t\t\t\t\t\tType;\n\n\t/// Constructor\n\tCPrimitiveClass ();\n\n\t/// Class name\n\tstd::string\t\t\t\tName;\n\n\t/// Filename extension (for type File)\n\tstd::string\t\t\t\tFileExtension;\n\n\t/// File type (for type File)\n\tstd::string\t\t\t\tFileType;\n\n\t/// Color\n\tNLMISC::CRGBA\t\t\tColor;\n\n\t/// Auto init ?\n\tbool\t\t\t\t\tAutoInit;\n\n\t/// Deletable ?\n\tbool\t\t\t\t\tDeletable;\n\n\t/// Collision ?\n\tbool\t\t\t\t\tCollision;\n\n\t/// Link children ?\n\tbool\t\t\t\t\tLinkBrothers;\n\n\t/// Show arrow ?\n\tbool\t\t\t\t\tShowArrow;\n\n\t/// Numberize on copy ?\n\tbool\t\t\t\t\tNumberize;\n\n\t/// Is primitive visible ?\n\tbool\t\t\t\t\tVisible;\n\n\t/// Init parameters\n\tclass CInitParameters\n\t{\n\t\t// A default value\n\t\tclass CDefaultValue\n\t\t{\n\t\tpublic:\n\t\t\tstd::string\t\tName;\n\t\t\tbool\t\t\tGenID;\n\n\t\t\tbool\t\t\toperator== (const CDefaultValue &other) const\n\t\t\t{\n\t\t\t\treturn (Name == other.Name) && (GenID == other.GenID);\n\t\t\t}\n\n\t\t\tbool\t\t\toperator< (const CDefaultValue &other) const\n\t\t\t{\n\t\t\t\tif (Name < other.Name)\n\t\t\t\t\treturn true;\n\t\t\t\telse if (Name == other.Name)\n\t\t\t\t{\n\t\t\t\t\treturn (GenID < other.GenID);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\tpublic:\n\t\t/// Parameter name\n\t\tstd::string\t\t\t\t\tName;\n\n\t\t/// Default value\n\t\tstd::vector<CDefaultValue>\tDefaultValue;\n\t};\n\n\t// Parameter description\n\tclass CParameter : public CInitParameters\n\t{\n\tpublic:\n\t\tCParameter () {}\n\t\tCParameter (const NLLIGO::IProperty &property, const char *propertyName);\n\t\tbool operator== (const CParameter &other) const;\n\t\tbool operator< (const CParameter &other) const;\n\n\t\t// Type\n\t\tenum TType\n\t\t{\n\t\t\tBoolean,\n\t\t\tConstString,\n\t\t\tString,\n\t\t\tStringArray,\n\t\t\tConstStringArray,\n\t\t}\t\t\tType;\n\n\t\t/// Is parameter visible ?\n\t\tbool\t\tVisible;\n\n\t\t// Is a filename\n\t\tbool\t\tFilename;\n\n\t\t// Make a look up ?\n\t\tbool\t\tLookup;\n\n\t\t/// Is parameter read only ?\n\t\tbool\t\tReadOnly;\n\n\t\t// File extension\n\t\tstd::string\tFileExtension;\n\n\t\t// Autonaming\n\t\tstd::string\tAutoname;\n\n\t\t// Folder\n\t\tstd::string\tFolder;\n\n\t\t// Size of multi line view\n\t\tuint\t\tWidgetHeight;\n\n\t\t// Sort entry in combo box\n\t\tbool\t\tSortEntries;\n\n\t\t// Editable\n\t\tbool\t\tEditable;\n\n\t\t// Display horizontal slider in multiline edit box\n\t\tbool\t\tDisplayHS;\n\n\t\t// Combobox value\n\t\tclass CConstStringValue\n\t\t{\n\t\tpublic:\n\t\t\tbool operator== (const CConstStringValue &other) const;\n\t\t\tbool operator< (const CConstStringValue &other) const;\n\t\t\tstd::vector<std::string>\tValues;\n\t\t\tstd::vector<std::string>\tPrimitivePath;\n\t\t\tvoid\tappendFilePath\t\t\t\t(std::vector<std::string> &pathList)\tconst;\n\t\t\tvoid\tappendPrimPath\t\t\t\t(std::vector<std::string> &pathList, const\tstd::vector<const IPrimitive*>\t&relativePrimPaths)\tconst;\n\t\t\tvoid\tgetPrimitivesForPrimPath\t(std::vector<const IPrimitive*>\t&relativePrimPaths, const\tstd::vector<const IPrimitive*>\t&startPrimPath)\tconst;\n\t\t};\n\n\t\t// Map of combobox value per context\n\t\tstd::map<std::string, CConstStringValue>\tComboValues;\n\n\t\t/// Get the autoname translation\n\t\tbool\ttranslateAutoname (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass) const;\n\n\t\t// Get a default value\n\t\tbool\tgetDefaultValue (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string *fromWhere = NULL) const;\n\t\tbool\tgetDefaultValue (std::vector<std::string> &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string *fromWhere = NULL) const;\n\t};\n\n\t/// Parameters\n\tstd::vector<CParameter>\tParameters;\n\n\t// Child\n\tclass CChild\n\t{\n\tpublic:\n\t\t/// Static child name\n\t\tstd::string\tName;\n\n\t\t/// Child class name\n\t\tstd::string\tClassName;\n\n\t\t/// Init parameters\n\t\tstd::vector<CInitParameters>\tParameters;\n\t};\n\n\t// Static Children\n\tstd::vector<CChild>\t\t\tStaticChildren;\n\n\t// Dynamic Children\n\tstd::vector<CChild>\t\t\tDynamicChildren;\n\n\t// Generated Children\n\tstd::vector<CChild>\t\t\tGeneratedChildren;\n\n\t// Read\n\tbool\tread (xmlNodePtr primitiveNode,\n\t\t\t\t\tconst char *filename,\n\t\t\t\t\tconst char *className,\n\t\t\t\t\tstd::set<std::string> &contextStrings,\n\t\t\t\t\tstd::map<std::string, std::string> &contextFilesLookup,\n\t\t\t\t\tNLLIGO::CLigoConfig &config,\n\t\t\t\t\tbool parsePrimitiveComboContent);\n};\n\n} // NLLIGO\n\n#endif // NL_PRIMITIVE_CLASS_H\n\n/* End of primitive_class.h */\n"
  },
  {
    "path": "code/nel/include/nel/ligo/primitive_configuration.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PRIMITIVE_CONFIGURATION_H\n#define NL_PRIMITIVE_CONFIGURATION_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/rgba.h\"\n#include <vector>\n\n// Include from libxml2\n#include <libxml/parser.h>\n\nnamespace NLLIGO\n{\n\nclass CLigoConfig;\nclass IPrimitive;\n\n/**\n * Ligo primitive configuration description.\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CPrimitiveConfigurations\n{\npublic:\n\n\t// The name of the matching values\n\tstd::string\tName;\n\n\t// The configuration color\n\tNLMISC::CRGBA\tColor;\n\n\t// Matching pairs\n\tclass CMatchGroup\n\t{\n\tpublic:\n\t\tstd::vector<std::pair<std::string, std::string>\t>\tPairs;\n\t};\n\n\t// The pair of name / value parameter to match\n\tstd::vector<CMatchGroup>\tMatchPairs;\n\n\t// Read from a xml tree\n\tbool\tread (xmlNodePtr configurationNode, const char *filename, const char *name, class CLigoConfig &config);\n\n\t// Test if this primitive belong this configuration\n\tbool\tbelong (const IPrimitive &primitive) const;\n};\n\n}\n\n#endif // NL_PRIMITIVE_CONFIGURATION_H\n\n/* End of ligo_config.h */\n"
  },
  {
    "path": "code/nel/include/nel/ligo/primitive_utils.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n\n#ifndef PRIMITIVE_UTIL_H\n#define PRIMITIVE_UTIL_H\n\n#include \"primitive.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n#include <limits>\n#include <vector>\n#include <string>\n\nnamespace NLLIGO\n{\n\ntypedef std::vector<IPrimitive*>\tTPrimitiveSet;\n\n/** Default predicate for primitive enumerator.\n *\tThis predicate test the class name of each primitive against a\n *\tgiven class name.\n */\nstruct TPrimitiveClassPredicate : public std::unary_function<IPrimitive*, bool>\n{\n\tTPrimitiveClassPredicate(const std::string &className)\n\t\t:\tClassName(className)\n\t{}\n\n\tbool operator () (const IPrimitive *prim) const\n\t{\n\t\tstd::string *s;\n\t\tif (prim->getPropertyByName(\"class\", s) && *s == ClassName)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\t/// The primitive class name to check\n\tconst std::string\t\tClassName;\n};\n\n/** Predicate for primitive enumerator.\n *\tThis predicate test the name of each primitive against a\n *\tgiven name.\n */\nstruct TPrimitiveNamePredicate\n{\n\tTPrimitiveNamePredicate(const std::string &name)\n\t\t:\tName(name)\n\t{}\n\n\tbool operator () (const IPrimitive *prim) const\n\t{\n\t\tstd::string *s;\n\t\tif (prim->getPropertyByName(\"name\", s) && *s == Name)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\t/// The primitive name to check\n\tconst std::string\t\tName;\n};\n\n/** Predicate for primitive enumerator.\n *\tThis predicate test the class name and name of the primitive.\n */\nstruct TPrimitiveClassAndNamePredicate\n{\n\tTPrimitiveClassAndNamePredicate(const std::string &className, const std::string &name)\n\t\t:\tClassName(className),\n\t\tName(name)\n\t{}\n\n\tbool operator () (const IPrimitive *prim) const\n\t{\n\t\tstd::string *s;\n\t\tif (prim->getPropertyByName(\"class\", s) && *s == ClassName)\n\t\t{\n\t\t\tif (prim->getPropertyByName(\"name\", s) && *s == Name)\n\t\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/// The primitive class name to check\n\tconst std::string\t\tClassName;\n\t/// The primitive name to check\n\tconst std::string\t\tName;\n};\n\n/** Predicate for primitive enumerator.\n *\tThis predicate test the string value of a given property\n */\nstruct TPrimitivePropertyPredicate\n{\n\tTPrimitivePropertyPredicate(const std::string &propName, const std::string &value)\n\t\t:\tPropName(propName), PropValue(value)\n\t{}\n\n\tbool operator () (const IPrimitive *prim) const\n\t{\n\t\tstd::string *s;\n\t\tif (prim->getPropertyByName(PropName.c_str(), s) && *s == PropValue)\n\t\t\treturn true;\n\t\treturn false;\n\t}\n\n\t/// The property name\n\tconst std::string\t\tPropName;\n\t/// The property value\n\tconst std::string\t\tPropValue;\n};\n\n/** The primitive enumerator class is used to iterate over primitive node that\n *\tmatch a given predicate.\n *\tThe primitive are tested recursively starting at an arbitrary node in the\n *\tprimitive tree.\n *\tApplication code just need to call getNextMatch until it return NULL indicating\n *\tthere is no more node that match the predicate.\n */\ntemplate <class Pred = TPrimitiveClassPredicate>\nclass CPrimitiveEnumerator\n{\npublic:\n\t/** Construct a primitive enumerator.\n\t *\tstartPrim is the primitive where the enumeration start. Even if the startPrimitive\n\t *\tis not at the root of the primitive tree, the enumerator will not\n\t *\ttry to parse the parent of startPrim.\n\t *\tpredicate is the functor predicate. Each node is tested against the bool operator()(IPrimitive *)\n\t *\tmethod of the predicate. If the predicate return true, then the node is returned by getNextMatch.\n\t */\n\tCPrimitiveEnumerator(IPrimitive *startPrim, Pred &predicate)\n\t\t: _StartPrim(startPrim),\n\t\t_Predicate(predicate),\n\t\t_CurrentPrim(startPrim)\n\t{\n\t\t// mark the root node as non checked\n\t\t_IndexStack.push_back(std::numeric_limits<uint>::max());\n\t}\n\n\t/** Each call to this method will return a primitive pointer that match\n\t *\tthe predicate functor.\n\t *\tReturn NULL when there is no more primitive matching the predicate.\n\t */\n\tIPrimitive *getNextMatch()\n\t{\n\t\twhile (!_IndexStack.empty())\n\t\t{\n\t\t\tif (_IndexStack.back() == std::numeric_limits<uint>::max())\n\t\t\t{\n\t\t\t\t_IndexStack.back() = 0;\n\t\t\t\t// we need to check the current node.\n\t\t\t\tif (_Predicate(_CurrentPrim))\n\t\t\t\t{\n\t\t\t\t\t// this one match !\n\t\t\t\t\treturn _CurrentPrim;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (_IndexStack.back() < _CurrentPrim->getNumChildren())\n\t\t\t{\n\t\t\t\tIPrimitive *child;\n\t\t\t\tif (_CurrentPrim->getChild(child, _IndexStack.back()++))\n\t\t\t\t{\n\t\t\t\t\t// go down into this node\n\t\t\t\t\t_IndexStack.push_back(std::numeric_limits<uint>::max());\n\t\t\t\t\t_CurrentPrim = child;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// no more child to test, pop one level\n\t\t\t\t_IndexStack.pop_back();\n\t\t\t\t_CurrentPrim = _CurrentPrim->getParent();\n\t\t\t}\n\t\t}\n\t\t// no more match\n\t\treturn NULL;\n\t}\n\n\nprivate:\n\n\t/// The root primitive for enumeration\n\tIPrimitive\t*_StartPrim;\n\t/// The predicate functor\n\tPred\t\t_Predicate;\n\t/// The current primitive\n\tIPrimitive\t*_CurrentPrim;\n\t/// for each recursion level, keep the index of the currently explored child.\n\tstd::vector<uint>\t_IndexStack;\n};\n\n/** Build a primitive set that match the predicate\n *\tThis class makes use of the CPrimitiveEnumerator class to iterate\n *\ton each valid node and fill the result primitive set.\n*/\ntemplate <class Pred>\nclass CPrimitiveSet\n{\npublic:\n\n\tvoid buildSet(IPrimitive *startPrimitive, Pred &predicate, TPrimitiveSet &result)\n\t{\n\t\tCPrimitiveEnumerator<Pred>\tenumerator(startPrimitive, predicate);\n\n\t\tIPrimitive *p;\n\t\twhile ((p = enumerator.getNextMatch()) != NULL)\n\t\t\tresult.push_back(p);\n\t}\n};\n\n/** Filter a primitive set against a predicate.\n *\tUseful to refine a primitive set with another predicate.\n */\ntemplate <class Pred>\nclass CPrimitiveSetFilter\n{\npublic:\n\n\tvoid filterSet(const std::vector<IPrimitive*> &source, Pred &predicate, TPrimitiveSet &result)\n\t{\n\t\tstd::vector<IPrimitive*>::const_iterator first(source.begin()), last(source.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\n\t\t\tif (predicate(*first))\n\t\t\t\tresult.push_back(*first);\n\t\t}\n\t}\n};\n\n/** Utility function that load an xml primitive file into a CPrimitives object.\n *\tThis function deal with file IO and XML parsing call.\n *\tReturn false if the loading fail for some reason, true otherwise.\n */\ninline bool loadXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName, CLigoConfig &ligoConfig)\n{\n\ttry\n\t{\n\t\tNLMISC::CIFile\tfileIn(fileName);\n\t\tNLMISC::CIXml xmlIn;\n\t\txmlIn.init (fileIn);\n\n\t\t// Read it\n\t\treturn primDoc.read (xmlIn.getRootNode (), NLMISC::CFile::getFilename(fileName).c_str(), ligoConfig);\n\t}\n\tcatch(const NLMISC::Exception &e)\n\t{\n\t\tnlwarning(\"Error reading input file '%s': '%s'\", fileName.c_str(), e.what());\n\t\treturn false;\n\t}\n}\n\n/** Utility function that save a CPrimitives object into an xml file.\n *\tThis function deal with file IO and XML parsing call.\n *\tReturn false if the saving fail for some reason, true otherwise.\n */\ninline bool saveXmlPrimitiveFile(CPrimitives &primDoc, const std::string &fileName)\n{\n\ttry\n\t{\n\t\tNLMISC::COFile\tfileOut(fileName);\n//\t\txmlDocPtr\txmlDoc = xmlNewDoc((xmlChar*)(\"1.0\"));;\n\t\tNLMISC::COXml xmlOut;\n\t\txmlOut.init (&fileOut);\n//\t\tNLMISC::CIXml xmlOut;\n//\t\txmlOut.init (fileOut);\n\n\t\t// Read it\n\t\tprimDoc.write(xmlOut.getDocument(), fileName.c_str());\n\n\t\txmlOut.flush ();\n\n\t\tfileOut.close();\n\n\t\treturn true;\n\n//\t\treturn xmlSaveFile(fileName.c_str(), xmlDoc) != -1;\n\t}\n\tcatch(const NLMISC::Exception &e)\n\t{\n\t\tnlwarning(\"Error writing output file '%s': '%s'\", fileName.c_str(), e.what());\n\t\treturn false;\n\t}\n}\n\n/** Utility function to look for the first child of a primitive node that\n *\tmatch the predicate.\n *\tReturn NULL if none of the child match the predicate.\n *\tThere is no way to get the next matching child using this function,\n *\tyou must use filterPrimitiveChilds to do this.\n */\ntemplate <class Pred>\nIPrimitive *getPrimitiveChild(IPrimitive *parent, Pred &predicate)\n{\n\tfor (uint i=0; i<parent->getNumChildren(); ++i)\n\t{\n\t\tIPrimitive *child;\n\t\tif (parent->getChild(child, i) && predicate(child))\n\t\t{\n\t\t\treturn child;\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n/** Utility function to look for the first parent of a primitive node that\n *\tmatch the predicate.\n *\tReturn NULL if none of the parent match the predicate.\n */\ntemplate <class Pred>\nIPrimitive *getPrimitiveParent(IPrimitive *prim, Pred &predicate)\n{\n\tIPrimitive *parent = prim->getParent();\n\twhile (parent)\n\t{\n\t\tif (predicate(parent))\n\t\t\treturn parent;\n\n\t\tparent = parent->getParent();\n\t}\n\n\treturn NULL;\n}\n\n/** Utility function that fill a primitive set with all the child nodes\n *\tthat match the predicate.\n */\ntemplate <class Pred>\nvoid filterPrimitiveChilds(IPrimitive *parent, Pred &predicate, TPrimitiveSet &result)\n{\n\tfor (uint i=0; i<parent->getNumChildren(); ++i)\n\t{\n\t\tIPrimitive *child;\n\t\tif (parent->getChild(child, i) && predicate(child))\n\t\t\tresult.push_back(child);\n\t}\n}\n\n\n/** Build a string that represent the path to a node\n *\tNote that the reverse operation does not guaranty to\n *\treturn a unique node because there is no name\n *\tuniqueness constraint in the primitive system.\n */\nstd::string buildPrimPath(const IPrimitive *prim);\n\n/** Return a set of primitive that match a given path*/\nvoid selectPrimByPath(IPrimitive *rootNode, const std::string &path, TPrimitiveSet &result);\n\n} // namespace NLLIGO\n\n\n#endif // #define PRIMITIVE_UTIL_H\n"
  },
  {
    "path": "code/nel/include/nel/ligo/zone_bank.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ZONE_BANK_H\n#define NL_ZONE_BANK_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include <string>\n#include <vector>\n\nnamespace NLLIGO\n{\n\n// Categories that MUST exist\n// (zone)\n// (size)\n// (material) or (transname + transtype + transnum)\n\n// All categories are string but some categories are particular string:\n// zone is any string\n// size is two number separated by a 'x'\n// material is any string\n// transname is two string (of materials separated by a '-')\n// transnum is a number\n// transtype is a string among (flat, cornera, cornerb)\n\n// ***************************************************************************\n\n/// No category of the type given found\n#define STRING_NO_CAT_TYPE\t\"< NOCATTYPE >\"\n\n// ***************************************************************************\n\nclass CZoneBankElement\n{\n\n\t// Category stuff\n\t// The key is the Type of the category\t(Ex: \"material\", \"size\", ...)\n\t// The second element is the value\t\t(Ex: \"Grass\", \"2x2\", ...)\n\tstd::map<std::string, std::string>\t_CategoriesMap;\n\n\t// In this list the category type and value must be unique and 2 categories MUST\n\t// appears : \"zone\" (The zone name) and \"size\" (*x* (ex:4x4 3x1 etc...))\n\t// Some categories used in WorldEditor : \"material\", \"transition\"\n\tuint8\t\t\t\t\t_SizeX, _SizeY;\n\tstd::vector<bool>\t\t_Mask;\n\n\tstatic std::string\t\t_NoCatTypeFound; // = STRING_NO_CAT_TYPE\n\npublic:\n\n\tCZoneBankElement ();\n\n\t// Set the mask of the zone bank element\n\tvoid setMask (const std::vector<bool> &mask, uint8 sizeX, uint8 sizeY);\n\n\tvoid addCategory (const std::string &CatType, const std::string &CatValue);\n\tconst std::string &getName (); // Return the value of the \"zone\" category\n\tconst std::string &getSize ();\n\tuint8 getSizeX () { return _SizeX; }\n\tuint8 getSizeY () { return _SizeY; }\n\tconst std::vector<bool> &getMask () { return _Mask; }\n\n\t/// Return the CatValue or STRING_NO_CAT_TYPE if no category of that type found\n\tconst std::string &getCategory(const std::string &CatType);\n\n\t/// Convert size in the categories to _SizeX, _SizeY\n\tvoid convertSize ();\n\tvoid serial (NLMISC::IStream &f);\n\n\tfriend class CZoneBank;\n};\n\n// ***************************************************************************\n\nclass CZoneBank\n{\n\n\tstd::map<std::string,CZoneBankElement>\t_ElementsMap;\n\n\tstd::vector<CZoneBankElement*>\t_Selection;\n\npublic:\n\n\t// Debug stuff beg\n\t// ---------------\n\tvoid debugInit(const std::string &sPath);\n\tvoid debugSaveInit(CZoneBankElement &zbeTmp, const std::string &fileName);\n\t// ---------------\n\t// Debug stuff end\n\n\tvoid reset ();\n\t/// Initialize the zone bank with all files present in the path given (note pathName must not end with '\\\\')\n\tbool initFromPath (const std::string &pathName, std::string &error);\n\t/// Load an element in the current directory\n\tbool addElement (const std::string &elementName, std::string &error);\n\n\tvoid getCategoriesType (std::vector<std::string> &CategoriesType);\n\tvoid getCategoryValues (const std::string &CategoryType, std::vector<std::string> &CategoryValues);\n\tCZoneBankElement *getElementByZoneName (const std::string &ZoneName);\n\n\t// Selection\n\tvoid resetSelection ();\n\tvoid addOrSwitch (const std::string &CategoryType, const std::string &CategoryValue);\n\tvoid addAndSwitch (const std::string &CategoryType, const std::string &CategoryValue);\n\tvoid getSelection (std::vector<CZoneBankElement*> &SelectedElements);\n\n};\n\n// ***************************************************************************\n\n} // namespace NLLIGO\n\n// ***************************************************************************\n\n#endif // NL_ZONE_BANK_H\n\n/* End of zone_bank.h */\n"
  },
  {
    "path": "code/nel/include/nel/ligo/zone_region.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef __ZONE_REGION_H__\n#define __ZONE_REGION_H__\n\n// ***************************************************************************\n\n#include \"nel/misc/stream.h\"\n#include <vector>\n#include <string>\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n\n#define STRING_OUT_OF_BOUND \"< OOB >\"\n#define STRING_UNUSED\t\t\"< UNUSED >\"\n\n// ***************************************************************************\n\nstruct SPiece\n{\n\tsint32\t\t\t\tw, h;\t\t\t// Max 255x255\n\tstd::vector<uint8>\tTab;\n\n\tvoid\t\t\trotFlip (uint8 rot, uint8 flip);\n};\n\n// ***************************************************************************\n\nclass CZoneRegion\n{\n\npublic:\n\n\tCZoneRegion ();\n\n\tvoid\t\t\t\tserial (NLMISC::IStream &f);\n\tvoid\t\t\t\tresize (sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY);\n\tvoid\t\t\t\tbasicSet (sint32 x, sint32 y, sint32 PosX, sint32 PosY,  const std::string &ZoneName);\n\n\n\t// Accessors\n\tconst std::string\t&getName (sint32 x, sint32 y) const;\n\tuint8\t\t\t\tgetPosX (sint32 x, sint32 y) const;\n\tuint8\t\t\t\tgetPosY (sint32 x, sint32 y) const;\n\tuint8\t\t\t\tgetRot (sint32 x, sint32 y) const;\n\tuint8\t\t\t\tgetFlip (sint32 x, sint32 y) const;\n\tuint8\t\t\t\tgetCutEdge (sint32 x, sint32 y, uint8 pos) const; // pos==0 -> getUpCE, pos==1 -> getDownCE, ...\n\tuint32\t\t\t\tgetDate (sint32 x, sint32 y, uint8 lowOrHigh) const; // lowOrHigh == 0 -> low\n\tstd::string\t\t\tgetSharingMatNames (sint32 x, sint32 y, uint edge);\n\tuint8\t\t\t\tgetSharingCutEdges (sint32 x, sint32 y, uint edge);\n\n\t// Accessors\n\tbool\t\t\t\tsetName (sint32 x, sint32 y, const std::string &newValue);\n\tbool\t\t\t\tsetPosX (sint32 x, sint32 y, uint8 newValue);\n\tbool\t\t\t\tsetPosY (sint32 x, sint32 y, uint8 newValue);\n\tbool\t\t\t\tsetRot (sint32 x, sint32 y, uint8 newValue);\n\tbool\t\t\t\tsetFlip (sint32 x, sint32 y, uint8 newValue);\n\tbool\t\t\t\tsetSharingMatNames (sint32 x, sint32 y, uint edge, const std::string &newValue);\n\tbool\t\t\t\tsetSharingCutEdges (sint32 x, sint32 y, uint edge, uint8 newValue);\n\n\tsint32\t\t\t\tgetMinX () const { return _MinX; };\n\tsint32\t\t\t\tgetMaxX () const { return _MaxX; };\n\tsint32\t\t\t\tgetMinY () const { return _MinY; };\n\tsint32\t\t\t\tgetMaxY () const { return _MaxY; };\n\n\tvoid\t\t\t\tsetMinX (sint32 newValue) { _MinX = newValue; };\n\tvoid\t\t\t\tsetMaxX (sint32 newValue) { _MaxX = newValue; };\n\tvoid\t\t\t\tsetMinY (sint32 newValue) { _MinY = newValue; };\n\tvoid\t\t\t\tsetMaxY (sint32 newValue) { _MaxY = newValue; };\n\nprotected:\n\n\t// An element of the grid\n\tstruct SZoneUnit\n\t{\n\t\tstd::string\t\t\tZoneName;\n\t\tuint8\t\t\t\tPosX, PosY; // Position in a large piece\n\t\tuint8\t\t\t\tRot, Flip; // Rot 0-0deg, 1-90deg, 2-180deg, 3-270deg, Flip 0-false, 1-true\n\n\t\t// Work Data : For transition\t\t\t\t[2 3]\n\t\tstd::string\t\t\tSharingMatNames[4];\t//  [0 1]\n\t\tuint8\t\t\t\tSharingCutEdges[4]; // 0-Up, 1-Down, 2-Left, 3-Right (value [0-2])\n\n\t\tSZoneUnit ();\n\t\tvoid\t\t\tserial (NLMISC::IStream &f);\n\t\tconst SZoneUnit&operator= (const SZoneUnit&zu);\n\t};\n\n\tstruct SZoneUnit2 : public SZoneUnit\n\t{\n\t\tuint32\t\t\t\tDateLow;\n\t\tuint32\t\t\t\tDateHigh;\n\n\t\tSZoneUnit2 ();\n\t\tvoid\t\t\tserial (NLMISC::IStream &f);\n\t\tconst SZoneUnit2&operator= (const SZoneUnit2&zu);\n\t\tconst SZoneUnit2&operator= (const SZoneUnit&zu);\n\t};\n\n\tstatic std::string\t\t\t_StringOutOfBound;\n\nprotected:\n\n\tstd::vector<SZoneUnit2>\t\t_Zones;\n\tsint32\t\t\t\t\t\t_MinX, _MinY;\n\tsint32\t\t\t\t\t\t_MaxX, _MaxY;\n\n};\n\n\n} // namespace NLLIGO\n\n#endif // __ZONE_REGION_H__\n"
  },
  {
    "path": "code/nel/include/nel/logic/CMakeLists.txt",
    "content": "FILE(GLOB HEADERS *.h)\n\nINSTALL(FILES ${HEADERS} DESTINATION include/nel/logic COMPONENT headers)\n"
  },
  {
    "path": "code/nel/include/nel/logic/logic_condition.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef LOGIC_CONDITION_H\n#define LOGIC_CONDITION_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\nnamespace NLLOGIC\n{\n\nclass CLogicStateMachine;\nclass CLogicConditionNode;\n\n/**\n * CLogicComparisonBlock\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicComparisonBlock\n{\n\t/// state machine managing this comparison block\n\tCLogicStateMachine * _LogicStateMachine;\n\npublic:\n\n\t/// variable name\n\tstd::string VariableName;\n\n\t/// comparison operator\n\tstd::string Operator;\n\n\t/// comparand\n\tsint64 Comparand;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicComparisonBlock()\n\t{\n\t\t_LogicStateMachine = 0;\n\t\tVariableName = \"no_name\";\n\t\tOperator = \">\";\n\t\tComparand = 0;\n\t}\n\n\t/**\n\t *\tSet the logic state machine\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t *\tTest the condition\n\t *\n\t * \\return true if this condition is fulfiled, false else\n\t */\n\tbool testLogic();\n\n\t/**\n\t * serial\n\t */\n\t//void serial(class NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n\n\n\n\n/**\n * CLogicConditionLogicBlock\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicConditionLogicBlock\n{\n\t/// state machine managing this logic block\n\tCLogicStateMachine * _LogicStateMachine;\n\npublic:\n\n\t/// all condition logic block types\n\tenum TLogicConditionLogicBlockType\n\t{\n\t\tNOT = 0,\n\t\tCOMPARISON,\n\t\tSUB_CONDITION,\n\t};\n\n\t/// type of this condition block\n\tTLogicConditionLogicBlockType Type;\n\n\t/// name of the sub-condition\n\tstd::string SubCondition;\n\n\t/// comparison block\n\tCLogicComparisonBlock ComparisonBlock;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicConditionLogicBlock()\n\t{\n\t\tType = SUB_CONDITION;\n\t\tSubCondition = \"no_condition\";\n\t}\n\n\t/**\n\t *\tReturn info about the type of the block\n\t *\n\t * \\return true if this block is a NOT block\n\t */\n\tbool isNotBlock() const { return (Type == NOT); }\n\n\t/**\n\t *\tSet the logic state machine\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t *\tTest the condition\n\t *\n\t * \\return true if this condition is fulfiled, false else\n\t */\n\tbool testLogic();\n\n\t/**\n\t *\tFill a set with all the variables name referenced by this condition\n\t *\n\t * \\param condVars a set to store the variable names\n\t */\n\tvoid fillVarSet( std::set<std::string>& condVars );\n\n\t/**\n\t * serial\n\t */\n\t//void serial(class NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n\n\n/**\n * CLogicConditionNode\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicConditionNode\n{\n\t/// state machine managing this logic block\n\tCLogicStateMachine * _LogicStateMachine;\n\npublic:\n\n\t/// all condition node types\n\tenum TConditionNodeType\n\t{\n\t\tTERMINATOR = 0,\n\t\tLOGIC_NODE\n\t};\n\n\t/// type of this condition node\n\tTConditionNodeType Type;\n\n\t// if this node is a logical node :\n\t/// condition logic node\n\tCLogicConditionLogicBlock LogicBlock;\n\n\t/// condition nodes\n\tstd::vector<CLogicConditionNode *> _Nodes;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicConditionNode()\n\t{\n\t\t_LogicStateMachine = 0;\n\t\tType = TERMINATOR;\n\t}\n\n\t/**\n\t *\tSet the logic state machine\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t * add a node in the subtree\n\t *\n\t * \\param node is the new node to add\n\t */\n\tvoid addNode( CLogicConditionNode * node );\n\n\t/**\n\t *\tTest the condition\n\t *\n\t * \\return true if this condition is fulfiled, false else\n\t */\n\tbool testLogic();\n\n\t/**\n\t *\tFill a set with all the variables name referenced by this condition\n\t *\n\t * \\param condVars is a set to store the variable names\n\t */\n\tvoid fillVarSet( std::set<std::string>& condVars );\n\n\t/**\n\t * serial\n\t */\n\t//void serial(class NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\t/**\n\t * Destructor\n\t */\n\t~CLogicConditionNode();\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n\n\n\n/**\n * CLogicCondition\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicCondition\n{\n\t/// condition name\n\tstd::string _ConditionName;\n\npublic:\n\n\t/// condition tree\n\tstd::vector<CLogicConditionNode> Nodes;\n\n\t/**\n\t *\tCLogicCondition\n\t */\n\tCLogicCondition()\n\t{\n\t\t_ConditionName = \"no_condition\";\n\t}\n\n\t/**\n\t *\tSet the logic state machine\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t *\tSet the condition's name\n\t *\n\t * \\param name is the condition's name\n\t */\n\tvoid setName( std::string name ) { _ConditionName = name; }\n\n\t/**\n\t *\tGet the condition's name\n\t *\n\t * \\return the condition's name\n\t */\n\tstd::string getName() const {\treturn _ConditionName; }\n\n\t/**\n\t *\tAdd a condition node\n\t *\n\t * \\param node is the new node to add\n\t */\n\tvoid addNode( CLogicConditionNode node ) { Nodes.push_back( node ); }\n\n\t/**\n\t *\tTest the condition\n\t *\n\t * \\return true if this condition is fulfiled, false else\n\t */\n\tbool testLogic();\n\n\t/**\n\t *\tFill a set with all the variables name referenced by this condition\n\t *\n\t * \\param condVars is a set to store the variable names\n\t */\n\tvoid fillVarSet( std::set<std::string>& condVars );\n\n\t/**\n\t * serial\n\t */\n\t//void serial(class NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n} // NLLOGIC\n\n#endif //LOGIC_CONDITION\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/logic/logic_event.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef LOGIC_EVENT_H\n#define LOGIC_EVENT_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\n//#include \"game_share/sid.h\"\n\n\nnamespace NLLOGIC\n{\n\nclass CLogicStateMachine;\n\n\n/**\n * CLogicEventMessage\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicEventMessage\n{\npublic:\n\n\t/// true if the message has to be sent\n\tbool ToSend;\n\n\t/// true if the message has been sent\n\tbool Sent;\n\n\t/// message destination\n\tstd::string Destination;\n\n\t/// message destination id\n\tNLMISC::CEntityId DestinationId;\n\n\t/// message id\n\tstd::string MessageId;\n\n\t/// message arguments\n\tstd::string Arguments;\n\n\t/**\n\t *\tDefault constructor\n\t */\n\tCLogicEventMessage()\n\t{\n\t\tToSend = false;\n\t\tSent = false;\n\t\tDestination = \"no_destination\";\n\t\tMessageId = \"no_id\";\n\t\tDestinationId.setType( 0xfe );\n\t\tDestinationId.setCreatorId( 0 );\n\t\tDestinationId.setDynamicId( 0 );\n\t\tArguments = \"no_arguments\";\n\t}\n\n\t/**\n\t * serial\n\t */\n\t//void serial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node, const char *subName = \"\") const;\n\tvoid read (xmlNodePtr node, const char *subName = \"\");\n};\n\n\n/**\n * CLogicEventAction\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicEventAction\n{\npublic:\n\n\t/// true if this action consist in a state change, false if it's a message\n\tbool IsStateChange;\n\n\t/// state name for state change\n\tstd::string StateChange;\n\n\t/// event message\n\tCLogicEventMessage EventMessage;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicEventAction()\n\t{\n\t\tIsStateChange = false;\n\t}\n\n\t/**\n\t * This message will be sent as soon as the dest id will be given\n\t */\n\tvoid enableSendMessage();\n\n\t/**\n\t * serial\n\t */\n\t//void serial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n\n\n/**\n * CLogicEvent\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicEvent\n{\n\t/// state machine managing this event\n\tCLogicStateMachine * _LogicStateMachine;\n\npublic:\n\n\t/// condition name\n\tstd::string ConditionName;\n\n\t/// event action\n\tCLogicEventAction EventAction;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicEvent()\n\t{\n\t\t_LogicStateMachine = 0;\n\t\tConditionName = \"no_condition\";\n\t}\n\n\t/**\n\t *\tReset this event\n\t */\n\tvoid reset();\n\n\t/**\n\t *\tSet the logic state machine\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t * Test the condition\n\t *\n\t * \\return true if condition is fulfiled\n\t */\n\tbool testCondition();\n\n\t/**\n\t * serial\n\t */\n\t//void serial(class NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n} // NLLOGIC\n\n#endif //LOGIC_EVENT\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/logic/logic_state.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef LOGIC_STATE_H\n#define LOGIC_STATE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\n#include \"nel/net/service.h\"\n\n//#include \"game_share/sid.h\"\n\n#include \"logic_event.h\"\n\nnamespace NLLOGIC\n{\n\nclass CLogicStateMachine;\n\n/// map destination names to destination sid\ntypedef std::map<std::string, NLMISC::CEntityId> TSIdMap;\n\n/**\n * CLogicState\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicState\n{\npublic:\n\n\t/// state name\n\tstd::string _StateName;\n\n\t/// entry messages\n\tstd::vector<CLogicEventMessage> _EntryMessages;\n\n\t/// exit messages\n\tstd::vector<CLogicEventMessage> _ExitMessages;\n\n\t/// logic\n\tstd::vector<CLogicEvent> _Events;\n\n\t/// state machine containing this state\n\tCLogicStateMachine * _LogicStateMachine;\n\n\t/// messages to send by the service\n\tstd::multimap<NLMISC::CEntityId, NLNET::CMessage> _MessagesToSend;\n\npublic:\n\n\t/**\n\t *\tDefault constructor\n\t */\n\tCLogicState();\n\n\t/**\n\t * Set the state machine which contains this state\n\t *\n\t * \\param logicStateMachine is the state machine containing this block\n\t */\n\tvoid setLogicStateMachine( CLogicStateMachine * logicStateMachine );\n\n\t/**\n\t * set the state name\n\t *\n\t * \\param name is the new state's name\n\t */\n\tvoid setName( std::string name ) { _StateName = name; }\n\n\t/**\n\t * get the state name\n\t *\n\t * \\return the state's name\n\t */\n\tstd::string getName() { return _StateName; }\n\n\t/**\n\t * Add an event\n\t *\n\t * \\param event is the event to add\n\t */\n\tvoid addEvent( CLogicEvent event );\n\n\t/**\n\t * Associate message destination name with sid\n\t *\n\t * \\param sIdMap is the map associating destination name with a destination id\n\t */\n\tvoid addSIdMap( const TSIdMap& sIdMap );\n\n\t/**\n\t * Test the conditions of this state\n\t */\n\tvoid processLogic();\n\n\t/**\n\t *\tGet the messages to send\n\t *\n\t  * \\param msgs is the map associating all the message to send with their destination id\n\t */\n\tvoid getMessagesToSend( std::multimap<NLMISC::CEntityId,NLNET::CMessage>& msgs );\n\n\t/**\n\t * send the entry messages\n\t */\n\tvoid enterState();\n\n\t/**\n\t * send the exit messages\n\t */\n\tvoid exitState();\n\n\t/**\n\t *\tTry to send the entry messages\n\t */\n\tvoid trySendEntryMessages();\n\n\t/**\n\t *\tTry to send the event messages\n\t */\n\tvoid trySendEventMessages();\n\n\t/**\n\t * Fill a map associating all the referenced var in the state with the id of service managing them\n\t * (debug purpose)\n\t */\n\tvoid fillVarMap( std::multimap<NLMISC::CEntityId,std::string >& stateMachineVariables );\n\n\t/**\n\t * serial\n\t */\n\t//void serial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvoid write (xmlNodePtr node) const;\n\tvoid read (xmlNodePtr node);\n};\n\n\n} // NLLOGIC\n\n#endif //LOGIC_STATE\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/logic/logic_state_machine.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef LOGIC_STATE_MACHINE_H\n#define LOGIC_STATE_MACHINE_H\n\n#include \"logic_state.h\"\n#include \"logic_variable.h\"\n#include \"logic_condition.h\"\n\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\n#include \"nel/net/service.h\"\n\n#include <vector>\n#include <map>\n#include <string>\n\n\nnamespace NLLOGIC\n{\n\nvoid xmlCheckNodeName (xmlNodePtr &node, const char *nodeName);\nstd::string getXMLProp (xmlNodePtr node, const char *propName);\n\n/**\n * CLogicStateMachine\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicStateMachine\n{\n\t/// variables\n\tstd::map<std::string, CLogicVariable> _Variables;\n\n\t/// counters\n\tstd::map<std::string, CLogicCounter> _Counters;\n\n\t/// conditions used in this state machine\n\tstd::map<std::string, CLogicCondition> _Conditions;\n\n\t/// states\n\tstd::map<std::string, CLogicState> _States;\n\n\t/// name of the current state\n\tstd::string _CurrentState;\n\n\t/// name of this sate machine\n\tstd::string _Name;\n\npublic:\n\n\tconst std::map<std::string, CLogicVariable> &getVariables () { return _Variables; }\n\tconst std::map<std::string, CLogicCounter> &getCounters () { return _Counters; }\n\tconst std::map<std::string, CLogicCondition> &getConditions () { return _Conditions; }\n\tconst std::map<std::string, CLogicState> &getStates () { return _States; }\n\n\n\t/**\n\t *\tDefault constructor\n\t */\n\tCLogicStateMachine() { _Name = \"no_name\"; }\n\n\t/**\n\t * Set the state machine name\n\t *\n\t * \\param name is the name of state machine\n\t */\n\tvoid setName( const std::string& name ) { _Name = name; }\n\n\t/**\n\t * Get the state machine name\n\t *\n\t * \\return the name of this state machine\n\t */\n\tstd::string getName() const { return _Name; }\n\n\t/**\n\t *\tSet the current state\n\t *\n\t * \\param stateName is the name of the state to give focus to\n\t */\n\tvoid setCurrentState( std::string stateName );\n\n\t/**\n\t * call the addSIdMap() method for each sate machines\n\t *\n\t * \\param sIdMap is the map associating destination name with a destination id\n\t */\n\tvoid addSIdMap( const TSIdMap& sIdMap );\n\n\t/**\n\t * call the processLogic method for each sate machines\n\t */\n\tvoid processLogic();\n\n\t/**\n\t * Get the self-addressed message\n\t *\n\t * \\param msgs is the list used to store the self-addressed messages\n\t */\n\tvoid getSelfAddressedMessages( std::list<NLNET::CMessage>& msgs );\n\n\t/**\n\t * Add a variable in the state machine\n\t *\n\t * \\param var is the new variable to add in this state machine\n\t */\n\tvoid addVariable( CLogicVariable var ) { _Variables.insert( std::make_pair(var.getName(),var) ); }\n\n\t/**\n\t *\tGet the variable\n\t *\n\t * \\param varName is the name of the variable to get\n\t * \\param var is the variable to get\n\t * \\return true if the variable has been found, false if not\n\t */\n\tbool getVariable( std::string& varName, CLogicVariable& var );\n\n\t/**\n\t * Add a counter in the state machine\n\t *\n\t * \\param counter is the new counter to add in this state machine\n\t */\n\tvoid addCounter( CLogicCounter counter ) { _Counters.insert( std::make_pair(counter.getName(),counter) ); }\n\n\t/**\n\t * Add a condition in the state machine\n\t *\n\t * \\param condition is the new condition to add in this state machine\n\t */\n\tvoid addCondition( CLogicCondition condition );\n\n\t/**\n\t *\tGet the condition\n\t *\n\t * \\param condName is the name of the condition to get\n\t * \\param cond is the condition to get\n\t * \\return true if the condition has been found, false if not\n\t */\n\tbool getCondition( const std::string& condName, CLogicCondition& cond );\n\n\t/**\n\t *\tGet the messages to send\n\t *\n\t * \\param msgs is the list used to store the messages to send\n\t */\n\tvoid getMessagesToSend( std::multimap<NLMISC::CEntityId,NLNET::CMessage>& msgs );\n\n\t/**\n\t * Add a state to the state machine\n\t *\n\t * \\param state is the new state to add in this state machine\n\t */\n\tvoid addState( CLogicState logicState );\n\n\t/**\n\t *\tmodify a variable\n\t *\n\t * \\param varName is the name of the variable to modify\n\t * \\param modifOperator can be one of these operators :\"SET\"(\"set\"),\"ADD\"(\"add\"),\"SUB\"(\"sub\"),\"MUL\"(\"mul\"),\"DIV\"(\"div\")\n\t * \\param value is the value to use along with the modificator\n\t */\n\tvoid modifyVariable( std::string varName, std::string modifOperator, sint64 value );\n\n\t/**\n\t * serial\n\t */\n\t//void serial( NLMISC::IStream &f ) throw(NLMISC::EStream);\n\n\t/**\n\t *\tDisplay the variables\n\t */\n\tvoid displayVariables();\n\n\t/**\n\t *\tDisplay the states\n\t */\n\tvoid displayStates();\n\n\t/**\n\t *\tSet the verbose mode for a variable\n\t *\n\t * \\param varName is the name of the variable\n\t * \\param b is true to activate the verbose mode, false else\n\t */\n\tvoid setVerbose( std::string varName, bool b );\n\n\tvoid write (xmlDocPtr doc) const;\n\tvoid read (xmlNodePtr node);\n};\n\n} // NLLOGIC\n\n#endif //LOGIC_SYSTEM\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/logic/logic_variable.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef LOGIC_VARIABLE_H\n#define LOGIC_VARIABLE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\nnamespace NLLOGIC\n{\n\n/**\n * CLogicVariable\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicVariable\n{\nprotected:\n\n\t/// variable value\n\tsint64 _Value;\n\n\t/// variable name\n\tstd::string _Name;\n\n\t/// true if verbose mode is active\n\tbool _Verbose;\n\npublic:\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicVariable();\n\n\t/**\n\t * Set the variable name\n\t *\n\t * \\param name is the name of the variable\n\t */\n\tvoid setName( std::string name ) { _Name = name; }\n\n\t/**\n\t * Get the variable name\n\t *\n\t * \\return the name of the variable\n\t */\n\tstd::string getName() const { return _Name; }\n\n\t/**\n\t * Set the variable value\n\t *\n\t * \\param value is the new value of the variable\n\t */\n\tvoid setValue( sint64 value );\n\n\t/**\n\t * Get the variable value\n\t *\n\t * \\return the variable's value\n\t */\n\tsint64 getValue() const { return _Value; }\n\n\t/**\n\t *\tSet the verbose mode active or inactive\n\t *\n\t * \\param varName is the name of the variable\n\t * \\param b is true to activate the verbose mode, false else\n\t */\n\tvoid setVerbose( bool b ) { _Verbose = b; }\n\n\t/**\n\t * Apply modifications on a variable\n\t *\n\t * \\param op can be one of these operators :\"SET\"(\"set\"),\"ADD\"(\"add\"),\"SUB\"(\"sub\"),\"MUL\"(\"mul\"),\"DIV\"(\"div\")\n\t * \\param value is the value to use along with the modificator\n\t */\n\tvoid applyModification( std::string op, sint64 value );\n\n\t/**\n\t * update the variable\n\t */\n\tvirtual void processLogic();\n\n\t/**\n\t * serial\n\t */\n\t//virtual void serial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvirtual void write (xmlNodePtr node) const;\n\tvirtual void read (xmlNodePtr node);\n};\n\n\n\n\n/**\n * CLogicCounter\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLogicCounter : public CLogicVariable\n{\n\tuint _TickCount;\n\npublic:\n\n\t/// counter running mode\n\tenum TLogicCounterRule\n\t{\n\t\tSTOP_AT_LIMIT = 0,\n\t\tLOOP,\n\t\tSHUTTLE,\n\t\tDOWN_UP, // bounce at low end, stop at high end\n\t\tUP_DOWN, // bounce at high end, stop at low end\n\t};\n\n\t/// counter running state\n\tenum TLogicCounterRunningMode\n\t{\n\t\tSTOPPED = 0,\n\t\tRUN,\n\t\tREWIND,\n\t\tFAST_FORWARD,\n\t};\n\n\n\t/// period between inc( measured in game ticks )\n\tCLogicVariable Period;\n\n\t/// time offset to apply with period\n\tCLogicVariable Phase;\n\n\t/// regular increment value( normally 1 or -1 )\n\tCLogicVariable Step;\n\n\t/// lower limit for counter\n\tCLogicVariable LowLimit;\n\n\t/// higher limit for counter\n\tCLogicVariable HighLimit;\n\n\n\t/// running mode\n\tCLogicVariable Mode;\n\n\t/// running state\n\tCLogicVariable Control;\n\n\t/**\n\t * Default constructor\n\t */\n\tCLogicCounter();\n\n\t/**\n\t * update the counter\n\t */\n\tvoid update();\n\n\t/**\n\t *\tcheck the counter value according to the running mode\n\t */\n\tvoid manageRunningMode();\n\n\t/**\n\t * serial\n\t */\n\t//void serial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\tvirtual void write (xmlNodePtr node) const;\n\tvirtual void read (xmlNodePtr node);\n};\n\n} // NLLOGIC\n\n#endif //LOGIC_VARIABLE\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/CMakeLists.txt",
    "content": "FILE(GLOB HEADERS *.h)\n\nINSTALL(FILES ${HEADERS} DESTINATION include/nel/misc COMPONENT headers)\n"
  },
  {
    "path": "code/nel/include/nel/misc/aabbox.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_AABBOX_H\n#define NL_AABBOX_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n#include \"plane.h\"\n#include \"common.h\"\n#include \"stream.h\"\n#include \"bsphere.h\"\n\n\nnamespace NLMISC\n{\n\nclass CMatrix;\n\n// ***************************************************************************\n/**\n * An Axis Aligned Bounding Box.\n * Note: Center/HalfSize set to private, to have same manipulation for CAABBox and CAABBoxExt.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CAABBox\n{\nprotected:\n\t/// The center of the bbox.\n\tCVector\t\t\tCenter;\n\t/// The size/2 of the bbox.\n\tCVector\t\t\tHalfSize;\n\npublic:\n\n\t/// Empty bbox Constructor.  (for AABBoxExt::getRadius() correctness).\n\tCAABBox() : Center(0,0,0), HalfSize(0,0,0) {}\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\n\t/// \\name Builds.\n\t// @{\n\tvoid\t\t\tsetCenter(const CVector &center) {Center= center;}\n\tvoid\t\t\tsetHalfSize(const CVector &hs) {HalfSize= hs;}\n\t/// Set the size of the bbox (ie 2* the halfSize).\n\tvoid\t\t\tsetSize(const CVector &s) {HalfSize= s/2;}\n\t/// Build the bbox, with a min/max style bbox.\n\tvoid\t\t\tsetMinMax(const CVector &bmin, const CVector &bmax)\n\t{\n\t\tCenter= (bmin+bmax)/2;\n\t\tHalfSize= bmax-Center;\n\t}\n\t/** extend the bbox so it contains v.\n\t * Warning!! By default, a bbox is the vector 0,0,0. So set the first vertex with setCenter() or else the bbox will\n\t * be the extension of v and (0,0,0)...\n\t */\n\tvoid\t\t\textend(const CVector &v);\n\t//@}\n\n\n\t/// \\name Gets.\n\t// @{\n\tCVector\t\t\tgetMin() const {return Center-HalfSize;}\n\tCVector\t\t\tgetMax() const {return Center+HalfSize;}\n\tvoid\t\t\tgetMin(CVector &ret) const {ret= Center-HalfSize;}\n\tvoid\t\t\tgetMax(CVector &ret) const {ret= Center+HalfSize;}\n\tconst CVector\t&getCenter() const {return Center;}\n\tconst CVector\t&getHalfSize() const {return HalfSize;}\n\t/// Return the size of the bbox.\n\tCVector\t\t\tgetSize() const {return HalfSize*2;}\n\tvoid\t\t\tgetSize(CVector &ret) const {ret= HalfSize*2;}\n\t/// Return the radius of the bbox.\n\tfloat\t\t\tgetRadius() const {return HalfSize.norm();}\n\t// @}\n\n\t/// \\name Clip\n\t// @{\n\t/// Is the bbox partially in front of the plane??\n\tbool\t\t\tclipFront(const CPlane &p) const;\n\t/// Is the bbox partially in back of the plane??\n\tbool\t\t\tclipBack(const CPlane &p) const;\n\t/// Does the bbox include this point.\n\tbool\t\t\tinclude(const CVector &a) const;\n\t/// Does the bbox include entirely this bbox.\n\tbool\t\t\tinclude(const CAABBox &box) const;\n\t/// Does the bbox intersect the bbox box.\n\tbool\t\t\tintersect(const CAABBox &box) const;\n\t/// Does the bbox intersect the triangle ABC.\n\tbool\t\t\tintersect(const CVector &a, const CVector &b, const CVector &c) const;\n\t/// Does the bbox instersect the sphere s\n\tbool\t\t\tintersect(const CBSphere &s) const;\n\t/// Does the bbox instersect the segment AB\n\tbool\t\t\tintersect(const CVector &a, const CVector &b) const;\n\t/// clip the segment by the bbox. return false if don't intersect. a and b are modified.\n\tbool\t\t\tclipSegment(CVector &a, CVector &b) const;\n\t// @}\n\n\t/// \\name Misc\n\t// @{\n\t/// Build the equivalent polytope of planes.\n\tvoid\t\t\tmakePyramid(CPlane\tplanes[6]) const;\n\n\t/**\n\t* Compute the union of 2 bboxs, that is the aabbox that contains the 2 others.\n\t* Should end up in NLMISC\n\t*/\n\n\tstatic CAABBox\tcomputeAABBoxUnion(const CAABBox &b1, const CAABBox &b2);\n\n\t/**\n\t* Compute the intersection of 2 bboxs.\n\t*\tNB: this methods suppose the intersection exist, and doesn't check it (use intersect() to check).\n\t*\tIf !intersect, *this is still modified and the result bbox is big shit.\n\t*/\n\tvoid\t\t\tcomputeIntersection(const CAABBox &b1, const CAABBox &b2);\n\n\n\t/** Apply a matrix on an aabbox\n\t *  \\return an aabbox, bigger or equal to parameter, after the matrix multiplication\n\t */\n\tstatic CAABBox transformAABBox(const CMatrix &mat, const CAABBox &box);\n\n\t// @}\n\n\tvoid\t\t\tserial(NLMISC::IStream &f);\n};\n\n\n// ***************************************************************************\n/**\n * An Extended Axis Aligned Bouding Box.  Sphere Min/Max Radius is stored for improved clip test.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCAABBoxExt : private CAABBox\n{\nprotected:\n\tfloat\t\t\tRadiusMin, RadiusMax;\n\n\tvoid\t\t\tupdateRadius()\n\t{\n\t\t// The bounding sphere.\n\t\tRadiusMax= CAABBox::getRadius();\n\t\t// The including sphere.\n\t\tRadiusMin= NLMISC::minof((float)fabs(HalfSize.x), (float)fabs(HalfSize.y), (float)fabs(HalfSize.z));\n\t}\n\npublic:\n\t/// Empty bbox Constructor\n\tCAABBoxExt() {RadiusMin= RadiusMax=0;}\n\t/// Constructor from a normal BBox.\n\tCAABBoxExt(const CAABBox &o) {RadiusMin= RadiusMax=0; *this=o;}\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\n\t/// \\name Builds.\n\t// @{\n\tvoid\t\t\tsetCenter(const CVector &center) {Center= center;}\n\tvoid\t\t\tsetHalfSize(const CVector &hs) {HalfSize= hs; updateRadius();}\n\tvoid\t\t\tsetSize(const CVector &s) {HalfSize= s/2;  updateRadius();}\n\t/// Build the bbox, with a min/max style bbox.\n\tvoid\t\t\tsetMinMax(const CVector &bmin, const CVector &bmax)\n\t{\n\t\tCenter= (bmin+bmax)/2;\n\t\tHalfSize= bmax-Center;\n\t\tupdateRadius();\n\t}\n\tCAABBoxExt\t\t&operator=(const CAABBox &o) {Center= o.getCenter(); HalfSize= o.getHalfSize(); updateRadius(); return (*this);}\n\t//@}\n\n\n\t/// \\name Gets.\n\t// @{\n\tCVector\t\t\tgetMin() const {return CAABBox::getMin();}\n\tCVector\t\t\tgetMax() const {return CAABBox::getMax();}\n\tconst CVector\t&getCenter() const {return Center;}\n\tconst CVector\t&getHalfSize() const {return HalfSize;}\n\t/// Return the size of the bbox.\n\tCVector\t\t\tgetSize() const {return HalfSize*2;}\n\t/// Return the (stored!!) radius of the bbox.\n\tfloat\t\t\tgetRadius() const {return RadiusMax;}\n\t/// Return a simple Axis Aligned Bounding Box (no radius inside)\n\tCAABBox\t\t\tgetAABBox() const { CAABBox box; box.setCenter(getCenter()); box.setHalfSize(getHalfSize()); return box; }\n\t// @}\n\n\t/// \\name Clip\n\t// @{\n\t/// Is the bbox partially in front of the plane?? p MUST be normalized.\n\tbool\t\t\tclipFront(const CPlane &p) const;\n\t/// Is the bbox partially in back of the plane?? p MUST be normalized.\n\tbool\t\t\tclipBack(const CPlane &p) const;\n\t/// Does the bbox intersect the bbox box.\n\tbool\t\t\tintersect(const CAABBoxExt &box) const\n\t\t{return CAABBox::intersect(box);}\n\t/// Does the bbox intersect the triangle ABC.\n\tbool\t\t\tintersect(const CVector &a, const CVector &b, const CVector &c) const\n\t\t{return CAABBox::intersect(a,b,c);}\n\t// @}\n\n\tvoid\t\t\tserial(NLMISC::IStream &f);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_AABBOX_H\n\n/* End of aabbox.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/algo.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ALGO_H\n#define NL_ALGO_H\n\n#include \"types_nl.h\"\n#include <vector>\n#include <string>\n#include \"ucstring.h\"\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n// blend between 2 values\n// NB: like 'toString' or 'swap', this function is intended to be specialised for other types (CRGBA ...)\ntemplate <class T, class U>\nT blend(const T &v0, const T &v1, const U &blendFactor)\n{\n\treturn blendFactor * v1 + ((U) 1 - blendFactor) * v0;\n}\n\n\n// ***************************************************************************\n// add a delta to a value until it reaches the wanted target. Value is clamped to the target\ninline void incrementalBlend(float &value, float target, float absDelta)\n{\n\tnlassert(absDelta >= 0.f);\n\tif (value < target)\n\t{\n\t\tvalue += absDelta;\n\t\tif (value > target) value = target;\n\t}\n\telse if (target < value)\n\t{\n\t\tvalue -= absDelta;\n\t\tif (value < target) value = target;\n\t}\n}\n\n// ***************************************************************************\n/** bilinear of 4 values\n  *  v3    v2\n  *  +-----+\n  *  |     |\n  *  |     |\n  *  +-----+\n  *  v0    v1\n  *\n  *\n  *  T\n  *  ^\n  *  |\n  *  |\n  *  +---> S\n  */\ntemplate <class T, class U>\nT computeBilinear(const T &v0, const T &v1, const T &v2, const T &v3, const U &s, const U &t)\n{\n\tT h0 = t * v3 + ((U) 1 - t) * v0;\n\tT h1 = t * v2 + ((U) 1 - t) * v1;\n\treturn s * h1 + ((U) 1 - s) * h0;\n}\n\n// ***************************************************************************\n/** Select all points crossed by the line [(x0,y0) ; (x1,y1)]\n *  Not the same than brensenham\n */\nvoid drawFullLine (float x0, float y0, float x1, float y1, std::vector<std::pair<sint, sint> > &result);\n\n// ***************************************************************************\n/** Select points on the line [(x0,y0) ; (x1,y1)]\n */\nvoid drawLine (float x0, float y0, float x1, float y1, std::vector<std::pair<sint, sint> > &result);\n\n\n// ***************************************************************************\n/**\tSearch the lower_bound in a sorted array of Value, in growing order (0, 1, 2....).\n *\toperator<= is used to perform the comparison.\n *\tIt return the first element such that array[id]<=key\n *\tIf not possible, 0 is returned\n *\tNB: but 0 may still be a good value, so you must check whether or not 0 means \"Not found\", or \"Id 0\".\n */\ntemplate<class T>\nuint\t\tsearchLowerBound(const T *array, uint arraySize, const T &key)\n{\n\tuint\tstart=0;\n\tuint\tend= arraySize;\n\t// find lower_bound by dichotomy\n\twhile(end-1>start)\n\t{\n\t\tuint\tpivot= (end+start)/2;\n\t\t// return the lower_bound, ie return first start with array[pivot]<=key\n\t\tif(array[pivot] <= key)\n\t\t\tstart= pivot;\n\t\telse\n\t\t\tend= pivot;\n\t}\n\n\treturn start;\n}\n\n\n// ***************************************************************************\n/**\tSearch the lower_bound in a sorted array of Value, in growing order (0, 1, 2....).\n *\toperator<= is used to perform the comparison.\n *\tIt returns the first element such that array[id]<=key\n *\tIf not possible, 0 is returned\n *\tNB: but 0 may still be a good value, so you must check whether or not 0 means \"Not found\", or \"Id 0\".\n */\ntemplate<class T>\nuint\t\tsearchLowerBound(const std::vector<T> &array, const T &key)\n{\n\tuint\tsize= (uint)array.size();\n\tif(size==0)\n\t\treturn 0;\n\telse\n\t\treturn searchLowerBound(&array[0], size, key);\n}\n\n\n// ***************************************************************************\n/** Clamp a sint in 0..255. Avoid cond jump.\n */\nstatic inline\tvoid fastClamp8(sint &v)\n{\n#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)\n\t// clamp v in 0..255 (no cond jmp)\n\t__asm\n\t{\n\t\tmov\t\tesi, v\n\t\tmov\t\teax, [esi]\n\t\tmov\t\tebx, eax\n\t\t// clamp to 0.\n\t\tadd\t\teax, 0x80000000\n\t\tsbb\t\tecx, ecx\n\t\tnot\t\tecx\n\t\tand\t\tebx, ecx\n\t\t// clamp to 255.\n\t\tadd\t\teax, 0x7FFFFF00\n\t\tsbb\t\tecx, ecx\n\t\tor\t\tebx, ecx\n\t\tand\t\tebx, 255\n\t\t// store\n\t\tmov\t\t[esi], ebx\n\t}\n#else\n\tclamp(v, 0, 255);\n#endif\n}\n\n\n// ***************************************************************************\n/** return true if the string strIn verify the wildcard string wildCard.\n *\teg:\n *\t\ttestWildCard(\"azert\", \"*\")== true\n *\t\ttestWildCard(\"azert\", \"??er*\")== true\n *\t\ttestWildCard(\"azert\", \"*er*\")== true\n *\t\ttestWildCard(\"azert\", \"azert*\")== true\n *\tUndefined result if s has some '*',\n *\treturn false if wildcard has some \"**\" or \"*?\"\n *\tNB: case-sensitive\n */\nbool\t\ttestWildCard(const char *strIn, const char *wildCard);\n\nbool\t\ttestWildCard(const std::string &strIn, const std::string &wildCard);\n\n\n// ***************************************************************************\n/** From a string with some separators, build a vector of string.\n *\teg: splitString(\"hello|bye|||bee\", \"|\", list) return 3 string into list: \"hello\", \"bye\" and \"bee\".\n */\nvoid\t\tsplitString(const std::string &str, const std::string &separator, std::vector<std::string> &retList);\n\nvoid\t\tsplitUCString(const ucstring &ucstr, const ucstring &separator, std::vector<ucstring> &retList);\n\n// ***************************************************************************\n/// In a string or ucstring, find a substr and replace it with another. return true if replaced\ntemplate<class T, class U>\nbool\t\tstrFindReplace(T &str, const T &strFind, const U &strReplace)\n{\n\ttypename T::size_type pos= str.find(strFind);\n\tif(pos != T::npos)\n\t{\n\t\tstr.replace(pos, strFind.size(), T(strReplace) );\n\t\treturn true;\n\t}\n\telse return false;\n}\n\ntemplate<class T, class U>\nbool\t\tstrFindReplace(T &str, const char *strFind, const U &strReplace)\n{\n\tT\ttempStr(strFind);\n\treturn strFindReplace(str, tempStr, strReplace);\n}\n\n// set flags in a bit set\ntemplate <class T, class U>\ninline void setFlags(T &dest, U mask, bool on)\n{\n\tif (on)\n\t{\n\t\tdest = (T) (dest | (T) mask);\n\t}\n\telse\n\t{\n\t\tdest = (T) (dest & ~((T) mask));\n\t}\n}\n\n//DoubleRound(1.234,2) = 1.23\n//DoubleRound(1.234,0) = 1.0\n//DoubleRound(123.4,-1) = 120.0\ninline double DoubleRound(double dVal, short iPlaces)\n{\n    double dRetval;\n    double dMod = 0.0000001;\n\n    if (dVal<0.0) dMod=-0.0000001;\n\n    dRetval=dVal;\n    dRetval+=(5.0/pow(10.0,iPlaces+1.0));\n    dRetval*=pow(10.0,iPlaces);\n    dRetval=floor(dRetval+dMod);\n    dRetval/=pow(10.0,iPlaces);\n\n    return (dRetval);\n}\n\n} // NLMISC\n\n\n#endif // NL_ALGO_H\n\n/* End of algo.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/app_context.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef APP_CONTEXT_H\n#define APP_CONTEXT_H\n\n#include \"nel/misc/types_nl.h\"\n#include <map>\n\nnamespace NLMISC\n{\n\tclass CLog;\n\tclass CMemDisplayer;\n\tclass CMsgBoxDisplayer;\n\n\n\t/** Interface definition for nel context.\n\t *\tAny application wide data can be accessed thru this interface.\n\t *\n\t *\tThe NeL context is a mean to allow dynamic library loading in NeL.\n\t *\tIn order to make all NeL application safe, it is mandatory to declare\n\t *\ta NeL context at startup of any application (first instruction of the\n\t *\tmain() or WinMain() is good practice).\n\t *\tNote that for NLNET::IService oriented application, service framwork\n\t *\talready provide the application context.\n\t *\n\t *\t\\author Boris 'SoniX' Boucher\n\t *  \\date 2005\n\t */\n\tclass INelContext\n\t{\n\t\tstatic INelContext ** _getInstance();\n\tpublic:\n\n\t\t/// Access to the context singleton\n\t\tstatic INelContext &getInstance();\n\n\t\tstatic bool isContextInitialised();\n\n\t\tvirtual ~INelContext();\n\n\t\t//@name Singleton registry\n\t\t//@{\n\t\t/** Return the pointer associated to a given singleton name\n\t\t *\tIf the name is not present, return NULL.\n\t\t */\n\t\tvirtual void *getSingletonPointer(const std::string &singletonName) =0;\n\t\t/** Register a singleton pointer.\n\t\t*/\n\t\tvirtual void setSingletonPointer(const std::string &singletonName, void *ptr) =0;\n\t\t/** Release a singleton pointer */\n\t\tvirtual void releaseSingletonPointer(const std::string &singletonName, void *ptr) =0;\n\t\t//@}\n\n\t\t//@name Global debugging object\n\t\t//@{\n\t\tvirtual CLog *getErrorLog() =0;\n\t\tvirtual void setErrorLog(CLog *errorLog) =0;\n\t\tvirtual CLog *getWarningLog() =0;\n\t\tvirtual void setWarningLog(CLog *warningLog) =0;\n\t\tvirtual CLog *getInfoLog() =0;\n\t\tvirtual void setInfoLog(CLog *infoLog) =0;\n\t\tvirtual CLog *getDebugLog() =0;\n\t\tvirtual void setDebugLog(CLog *debugLog) =0;\n\t\tvirtual CLog *getAssertLog() =0;\n\t\tvirtual void setAssertLog(CLog *assertLog) =0;\n\t\tvirtual CMemDisplayer *getDefaultMemDisplayer() =0;\n\t\tvirtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer) =0;\n\t\tvirtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer() =0;\n\t\tvirtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer) =0;\n\t\tvirtual bool getDebugNeedAssert() =0;\n\t\tvirtual void setDebugNeedAssert(bool needAssert) =0;\n\t\tvirtual bool getNoAssert() =0;\n\t\tvirtual void setNoAssert(bool noAssert) =0;\n\t\tvirtual bool getAlreadyCreateSharedAmongThreads() =0;\n\t\tvirtual void setAlreadyCreateSharedAmongThreads(bool b) =0;\n\t\tvirtual bool isWindowedApplication() = 0;\n\t\tvirtual void setWindowedApplication(bool b = true) = 0;\n\t\t//@}\n\tprotected:\n\t\t/// Called by derived class to finalize initialisation of context\n\t\tvoid\tcontextReady();\n\n\t\tstatic INelContext *_NelContext;\n\n\t};\n\n\t/** This class implement the context interface for the application module\n\t *\tThat means that this class will really hold the data.\n\t *\t\\author Boris 'SoniX' Boucher\n\t *  \\date 2005\n\t */\n\tclass CApplicationContext : public INelContext\n\t{\n\tpublic:\n\t\tCApplicationContext();\n\n\t\tvirtual void *getSingletonPointer(const std::string &singletonName);\n\t\tvirtual void setSingletonPointer(const std::string &singletonName, void *ptr);\n\t\tvirtual void releaseSingletonPointer(const std::string &singletonName, void *ptr);\n\n\t\tvirtual CLog *getErrorLog();\n\t\tvirtual void setErrorLog(CLog *errorLog);\n\t\tvirtual CLog *getWarningLog();\n\t\tvirtual void setWarningLog(CLog *warningLog);\n\t\tvirtual CLog *getInfoLog();\n\t\tvirtual void setInfoLog(CLog *infoLog);\n\t\tvirtual CLog *getDebugLog();\n\t\tvirtual void setDebugLog(CLog *debugLog);\n\t\tvirtual CLog *getAssertLog();\n\t\tvirtual void setAssertLog(CLog *assertLog);\n\t\tvirtual CMemDisplayer *getDefaultMemDisplayer();\n\t\tvirtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer);\n\t\tvirtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer();\n\t\tvirtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer);\n\t\tvirtual bool getDebugNeedAssert();\n\t\tvirtual void setDebugNeedAssert(bool needAssert);\n\t\tvirtual bool getNoAssert();\n\t\tvirtual void setNoAssert(bool noAssert);\n\t\tvirtual bool getAlreadyCreateSharedAmongThreads();\n\t\tvirtual void setAlreadyCreateSharedAmongThreads(bool b);\n\t\tvirtual bool isWindowedApplication();\n\t\tvirtual void setWindowedApplication(bool b);\n\n\tprivate:\n\t\t/// Singleton registry\n\t\ttypedef std::map<std::string, void*>\tTSingletonRegistry;\n\t\tTSingletonRegistry\t\t_SingletonRegistry;\n\n\t\tCLog *ErrorLog;\n\t\tCLog *WarningLog;\n\t\tCLog *InfoLog;\n\t\tCLog *DebugLog;\n\t\tCLog *AssertLog;\n\t\tCMemDisplayer *DefaultMemDisplayer;\n\t\tCMsgBoxDisplayer *DefaultMsgBoxDisplayer;\n\t\tbool DebugNeedAssert;\n\t\tbool NoAssert;\n\t\tbool AlreadyCreateSharedAmongThreads;\n\t\tbool WindowedApplication;\n\t};\n\n\t/** This class implements the context interface for the a library module.\n\t *\tAll it contains is forward call to the application context instance.\n\t *\t\\author Boris 'SoniX' Boucher\n\t *  \\date 2005\n\t */\n\tclass CLibraryContext : public INelContext\n\t{\n\tpublic:\n\t\tCLibraryContext (INelContext &applicationContext);\n\n\t\tvirtual void *getSingletonPointer(const std::string &singletonName);\n\t\tvirtual void setSingletonPointer(const std::string &singletonName, void *ptr);\n\t\tvirtual void releaseSingletonPointer(const std::string &singletonName, void *ptr);\n\n\t\tvirtual CLog *getErrorLog();\n\t\tvirtual void setErrorLog(CLog *errorLog);\n\t\tvirtual CLog *getWarningLog();\n\t\tvirtual void setWarningLog(CLog *warningLog);\n\t\tvirtual CLog *getInfoLog();\n\t\tvirtual void setInfoLog(CLog *infoLog);\n\t\tvirtual CLog *getDebugLog();\n\t\tvirtual void setDebugLog(CLog *debugLog);\n\t\tvirtual CLog *getAssertLog();\n\t\tvirtual void setAssertLog(CLog *assertLog);\n\t\tvirtual CMemDisplayer *getDefaultMemDisplayer();\n\t\tvirtual void setDefaultMemDisplayer(CMemDisplayer *memDisplayer);\n\t\tvirtual CMsgBoxDisplayer *getDefaultMsgBoxDisplayer();\n\t\tvirtual void setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer);\n\t\tvirtual bool getDebugNeedAssert();\n\t\tvirtual void setDebugNeedAssert(bool needAssert);\n\t\tvirtual bool getNoAssert();\n\t\tvirtual void setNoAssert(bool noAssert);\n\t\tvirtual bool getAlreadyCreateSharedAmongThreads();\n\t\tvirtual void setAlreadyCreateSharedAmongThreads(bool b);\n\t\tvirtual bool isWindowedApplication();\n\t\tvirtual void setWindowedApplication(bool b);\n\n\tprivate:\n\t\t/// Pointer to the application context.\n\t\tINelContext\t\t*_ApplicationContext;\n\t};\n\n\n\t//@name Singleton utility\n\t//@{\n\t/** Some utility macro to build singleton compatible with\n\t *\tthe dynamic loading of library\n\t *\tThis macro must be put inside the singleton class\n\t *\tdefinition.\n\t *\tWarning : this macro change the current access right, it end up with\n\t *\tprivate access right.\n\t */\n#define NLMISC_SAFE_SINGLETON_DECL(className) \\\n\tprivate:\\\n\t\t/* declare private constructors*/ \\\n\t\t/*className () {}*/\\\n\t\tclassName (const className &) {}\\\n\t\t/* the local static pointer to the singleton instance */ \\\n\t\tstatic className\t*_Instance; \\\n\tpublic:\\\n\t\tstatic className &getInstance() \\\n\t\t{ \\\n\t\t\tif (_Instance == NULL) \\\n\t\t\t{ \\\n\t\t\t\t/* the nel context MUST be initialised */ \\\n\t\t\t\tnlassertex(NLMISC::INelContext::isContextInitialised(), (\"You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.\")); \\\n\t\t\t\tvoid *ptr = NLMISC::INelContext::getInstance().getSingletonPointer(#className); \\\n\t\t\t\tif (ptr == NULL) \\\n\t\t\t\t{ \\\n\t\t\t\t\t/* allocate the singleton and register it */ \\\n\t\t\t\t\t_Instance = new className; \\\n\t\t\t\t\tNLMISC::INelContext::getInstance().setSingletonPointer(#className, _Instance); \\\n\t\t\t\t} \\\n\t\t\t\telse \\\n\t\t\t\t{ \\\n\t\t\t\t\t_Instance = reinterpret_cast<className*>(ptr); \\\n\t\t\t\t} \\\n\t\t\t} \\\n\t\t\treturn *_Instance; \\\n\t\t} \\\n\tprivate:\n\n\t/** The same as above, but generate a getInstance method that\n\t *\treturn a pointer instead of a reference\n\t */\n#define NLMISC_SAFE_SINGLETON_DECL_PTR(className) \\\n\tprivate:\\\n\t\t/* declare private constructors*/ \\\n\t\t/*className () {}*/\\\n\t\tclassName (const className &) {}\\\n\t\t/* the local static pointer to the singleton instance */ \\\n\t\tstatic className\t*_Instance; \\\n\tpublic:\\\n\t\tstatic className *getInstance() \\\n\t\t{ \\\n\t\t\tif (_Instance == NULL) \\\n\t\t\t{ \\\n\t\t\t\t/* the nel context MUST be initialised */ \\\n\t\t\t\tnlassertex(NLMISC::INelContext::isContextInitialised(), (\"You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.\")); \\\n\t\t\t\tvoid *ptr = NLMISC::INelContext::getInstance().getSingletonPointer(#className); \\\n\t\t\t\tif (ptr == NULL) \\\n\t\t\t\t{ \\\n\t\t\t\t\t/* allocate the singleton and register it */ \\\n\t\t\t\t\t_Instance = new className; \\\n\t\t\t\t\tNLMISC::INelContext::getInstance().setSingletonPointer(#className, _Instance); \\\n\t\t\t\t} \\\n\t\t\t\telse \\\n\t\t\t\t{ \\\n\t\t\t\t\t_Instance = reinterpret_cast<className*>(ptr); \\\n\t\t\t\t} \\\n\t\t\t} \\\n\t\t\treturn _Instance; \\\n\t\t} \\\n\tprivate:\n\n\t /** This macro is the complement of the previous one.\n\t *\tIt must be put in a cpp file to implement the static\n\t *\tproperty of the singleton.\n\t */\n#define NLMISC_SAFE_SINGLETON_IMPL(className) className *className::_Instance = NULL;\n\n/// Function type for library entry point\ntypedef void (*TInitLibraryFunc)(INelContext &applicationContext);\n\n/** An helper macro to build the dll entry point easily.\n */\n#define NLMISC_LIBRARY_ENTRY\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tvoid libraryEntryImp(NLMISC::INelContext &applicationContext)\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tnlassert(!NLMISC::INelContext::isContextInitialised() || &applicationContext == &(NLMISC::INelContext::getInstance()));\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tif (!NLMISC::INelContext::isContextInitialised())\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\tnew CLibraryContext(applicationContext);\t\t\t\t\t\t\t\t\\\n\t\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\textern \"C\"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tNLMISC_LIB_EXPORT TInitLibraryFunc libraryEntry = libraryEntryImp;\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\n\nclass CLibrary;\n/// helper function to init newly loaded nel library\nvoid initNelLibrary(CLibrary &lib);\n\n\n} // namespace NLMISC\n\n\n#endif //APP_CONTEXT_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/array_2d.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ARRAY_2D_H\n#define NL_ARRAY_2D_H\n\n#include \"nel/misc/rect.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/traits_nl.h\"\n\nnamespace NLMISC\n{\n\n/** A simple 2D array.\n  *\n  * Access is done using the () operator\n  *\n  * Example :\n  *\n  * CArray2D<uint> myArray;\n  * myArray.init(10, 10, 0); // fill with zero's\n  * myArray(5, 5) = 1;\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2005\n  */\ntemplate <class T> class CArray2D\n{\npublic:\n\ttypedef typename std::vector<T> TArrayContainer;\n\ttypedef typename TArrayContainer::iterator iterator;\n\ttypedef typename TArrayContainer::const_iterator const_iterator;\n\tCArray2D() : _Width(0), _Height(0) {}\n\tvoid init(uint width, uint height);\n\tvoid init(uint width, uint height, const T &defaultValue);\n\tbool empty() const { return _Array.empty(); }\n\tvoid clear();\n\titerator begin() { return _Array.begin(); }\n\titerator end() { return _Array.end(); }\n\tconst_iterator begin() const { return _Array.begin(); }\n\tconst_iterator end() const { return _Array.end(); }\n\n\tbool isIn(sint x, sint y) const { return x >= 0 && y >= 0 && x < (sint) _Width && y < (sint) _Height; }\n\n\t// access element by column/row\n\tT &operator()(uint x, uint y)\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\tnlassert(x < _Width);\n\t\t\tnlassert(y < _Height);\n\t\t#endif\n\t\treturn _Array[x + y * _Width];\n\t}\n\t// access element by column/row (const version)\n\tconst T &operator()(uint x, uint y) const\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\tnlassert(x < _Width);\n\t\t\tnlassert(y < _Height);\n\t\t#endif\n\t\treturn _Array[x + y * _Width];\n\t}\n\t// Return width of array\n\tuint getWidth() const { return _Width; }\n\t// Return height of array\n\tuint getHeight() const { return _Height; }\n\t/** Move array content of the given offset. No wrapping is applied\n\t  * Example : move(1, 0) will move the array of one column to the left. The latest column is lost. The first column remains unchanged\n\t  */\n\tvoid move(sint offsetX, sint offsetY);\n\t// Move a part of the array. Values are clamped as necessary\n\tvoid moveSubArray(sint dstX, sint dstY, sint srcX, sint srcY, sint width, sint height);\n\t// Blit content from another array\n\tvoid blit(const CArray2D<T> &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint dstX, sint dstY);\n\t// get an iterator to the start of a row\n\titerator beginRow(uint row)\n\t{\n\t\tnlassert(row < _Height);\n\t\treturn _Array.begin() + row * _Width;\n\t}\n\tconst_iterator beginRow(uint row) const\n\t{\n\t\tnlassert(row < _Height);\n\t\treturn _Array.begin() + row * _Width;\n\t}\n\titerator endRow(uint row)\n\t{\n\t\tnlassert(row < _Height);\n\t\treturn _Array.begin() + (row + 1) * _Width;\n\t}\n\tconst_iterator endRow(uint row) const\n\t{\n\t\tnlassert(row < _Height);\n\t\treturn _Array.begin() + (row + 1) * _Width;\n\t}\n\t// get an iterator at the given position\n\titerator getIteratorAt(uint x, uint y)\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\tnlassert(x < _Width);\n\t\t\tnlassert(y < _Height);\n\t\t#endif\n\t\treturn _Array.begin() + x + (y * _Width);\n\t}\n\t// Get a const iterator at the given position\n\tconst_iterator getIteratorAt(uint x, uint y) const\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\tnlassert(x < _Width);\n\t\t\tnlassert(y < _Height);\n\t\t#endif\n\t\treturn _Array.begin() + x + (y * _Width);\n\t}\n\t/** See which part of array should be updated after its content has been displaced by the given offset (by a call to move for example).\n\t  * Example: getUpdateRects(0, 1, result) will result the first row as a result\n\t  */\n\tvoid getUpdateRects(sint moveOffsetX, sint moveOffsetY, std::vector<NLMISC::CRect> &rectsToUpdate);\n\t// See which parts of array will be discarded if the array is displaced by the given offset\n\tvoid getDiscardRects(sint moveOffsetX, sint moveOffsetY, std::vector<NLMISC::CRect> &discardedRects);\n\t//\n\tvoid serial(NLMISC::IStream &f) throw(NLMISC::EStream);\nprivate:\n\tTArrayContainer _Array;\n\tuint _Width;\n\tuint _Height;\nprivate:\n\tinline void checkRect(const NLMISC::CRect &r) const\n\t{\n\t\tnlassert(r.X >= 0 && r.X < (sint32) _Width);\n\t\tnlassert(r.Y >= 0 && r.Y < (sint32) _Height);\n\t\tnlassert(r.X + r.Width >= 0 && r.X + (sint32)  r.Width <= (sint32) _Width);\n\t\tnlassert(r.Y + r.Height >= 0 && r.Y + (sint32) r.Height <= (sint32) _Height);\n\t}\n};\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::clear()\n{\n\t_Array.clear();\n\t_Width = _Height = 0;\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::serial(NLMISC::IStream &f) throw(NLMISC::EStream)\n{\n\tf.serialCont(_Array);\n\tuint32 width = _Width;\n\tuint32 height = _Height;\n\tf.serial(width);\n\tf.serial(height);\n\t_Width = width;\n\t_Height = height;\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::getUpdateRects(sint moveOffsetX, sint moveOffsetY, std::vector<NLMISC::CRect> &rectsToUpdate)\n{\n\trectsToUpdate.clear();\n\tif (moveOffsetX < 0) // moved right ?\n\t{\n\t\t// the width to update\n\t\tuint width = std::min((uint) moveOffsetX, _Width);\n\t\t// the grid moved top or bottom, exclude this part\n\t\tsint height = _Height - abs(moveOffsetY);\n\t\tif (height > 0)\n\t\t{\n\t\t\t// complete column on the right\n\t\t\trectsToUpdate.push_back(NLMISC::CRect((sint32) (_Width - width), (sint32) (std::max(- moveOffsetY, 0)), (uint32) width, (uint32) height));\n\t\t\t#ifdef NL_DEBUG\n\t\t\t\tcheckRect(rectsToUpdate.back());\n\t\t\t#endif\n\t\t}\n\t}\n\telse if (moveOffsetX > 0) // moved left ?\n\t{\n\t\t// the width to update\n\t\tuint width = std::min((uint) (- moveOffsetX), _Width);\n\t\t// the grid moved top or bottom.\n\t\tsint height = _Height - abs(moveOffsetY);\n\t\tif (height > 0)\n\t\t{\n\t\t\t// complete column on the right\n\t\t\trectsToUpdate.push_back(NLMISC::CRect(0, (sint32) std::max(- moveOffsetY, 0), (uint32) width, (uint32) height));\n\t\t\t#ifdef NL_DEBUG\n\t\t\t\tcheckRect(rectsToUpdate.back());\n\t\t\t#endif\n\t\t}\n\t}\n\t// update top or bottom part\n\tif (moveOffsetY < 0)\n\t{\n\t\tsint height = std::min((uint) moveOffsetY, _Height);\n\t\trectsToUpdate.push_back(NLMISC::CRect(0, _Height - height, _Width, height));\n\t\t#ifdef NL_DEBUG\n\t\t\tcheckRect(rectsToUpdate.back());\n\t\t#endif\n\t}\n\telse\n\tif (moveOffsetY > 0)\n\t{\n\t\tsint height = std::min((uint) (- moveOffsetY), _Height);\n\t\trectsToUpdate.push_back(NLMISC::CRect(0, 0, _Width, height));\n\t\t#ifdef NL_DEBUG\n\t\t\tcheckRect(rectsToUpdate.back());\n\t\t#endif\n\t}\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::getDiscardRects(sint moveOffsetX, sint moveOffsetY,std::vector<NLMISC::CRect> &discardedRects)\n{\n\tgetUpdateRects(- moveOffsetX, - moveOffsetY, discardedRects);\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::moveSubArray(sint dstX, sint dstY, sint srcX, sint srcY, sint width, sint height)\n{\n\tif (srcX >= (sint) getWidth()) return;\n\tif (srcY >= (sint) getHeight()) return;\n\tif (dstX >= (sint) getWidth()) return;\n\tif (dstY >= (sint) getHeight()) return;\n\tif (srcX < 0)\n\t{\n\t\twidth += srcX;\n\t\tif (width <= 0) return;\n\t\tsrcX = 0;\n\t}\n\tif (srcY < 0)\n\t{\n\t\theight += srcY;\n\t\tif (height <= 0) return;\n\t\tsrcY = 0;\n\t}\n\tif (srcX + width > (sint) getWidth())\n\t{\n\t\twidth = getWidth() - srcX;\n\t}\n\tif (srcY + height > (sint) getHeight())\n\t{\n\t\theight = getHeight() - srcY;\n\t}\n\tif (dstX < 0)\n\t{\n\t\twidth += dstX;\n\t\tif (width < 0) return;\n\t\tsrcX -= dstX;\n\t\tdstX = 0;\n\t}\n\tif (dstY < 0)\n\t{\n\t\theight += dstY;\n\t\tif (height < 0) return;\n\t\tsrcY -= dstY;\n\t\tdstY = 0;\n\t}\n\tif (dstX + width > (sint) getWidth())\n\t{\n\t\twidth =  getWidth() - dstX;\n\t}\n\tif (dstY + height > (sint) getHeight())\n\t{\n\t\theight =  getHeight() - dstY;\n\t}\n\t#ifdef NL_DEBUG\n\t\tnlassert(width > 0);\n\t\tnlassert(height > 0);\n\t\tnlassert(srcX >= 0 && srcX < (sint) getWidth());\n\t\tnlassert(srcY >= 0 && srcY < (sint) getHeight());\n\t#endif\n\tif (dstY < srcY)\n\t{\n\t\tconst_iterator src = getIteratorAt(srcX, srcY);\n\t\titerator dst = getIteratorAt(dstX, dstY);\n\t\tdo\n\t\t{\n\t\t\tif (CTraits<T>::SupportRawCopy)\n\t\t\t{\n\t\t\t\t// type support fast copy\n\t\t\t\t::memcpy(&(*dst), &(*src), sizeof(T) * width);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::copy(src, src + width, dst);\n\t\t\t}\n\t\t\tsrc += _Width;\n\t\t\tdst += _Width;\n\t\t}\n\t\twhile(--height);\n\t}\n\telse if (dstY > srcY)\n\t{\n\t\t// copy from top to bottom\n\t\tconst_iterator src = getIteratorAt(srcX, srcY + height - 1);\n\t\titerator dst = getIteratorAt(dstX, dstY + height - 1);\n\t\tdo\n\t\t{\n\t\t\tif (CTraits<T>::SupportRawCopy)\n\t\t\t{\n\t\t\t\t// type support fast copy\n\t\t\t\t::memcpy(&(*dst), &(*src), sizeof(T) * width);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::copy(src, src + width, dst);\n\t\t\t}\n\t\t\tsrc -= _Width;\n\t\t\tdst -= _Width;\n\t\t}\n\t\twhile(--height);\n\t}\n\telse\n\t{\n\t\tconst_iterator src = getIteratorAt(srcX, srcY);\n\t\titerator dst = getIteratorAt(dstX, dstY);\n\t\tif (dstX < srcX)\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (CTraits<T>::SupportRawCopy)\n\t\t\t\t{\n\t\t\t\t\t// type support fast copy\n\t\t\t\t\t::memmove(&(*dst), &(*src), sizeof(T) * width);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstd::reverse_copy(src, src + width, dst);\n\t\t\t\t}\n\t\t\t\tsrc += _Width;\n\t\t\t\tdst += _Width;\n\t\t\t}\n\t\t\twhile(--height);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (CTraits<T>::SupportRawCopy)\n\t\t\t\t{\n\t\t\t\t\t// type support fast copy\n\t\t\t\t\t::memcpy(&(*dst), &(*src), sizeof(T) * width);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstd::copy(src, src + width, dst);\n\t\t\t\t}\n\t\t\t\tsrc += _Width;\n\t\t\t\tdst += _Width;\n\t\t\t}\n\t\t\twhile(--height);\n\t\t}\n\t}\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::blit(const CArray2D<T> &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint dstX, sint dstY)\n{\n\tif (&src == this)\n\t{\n\t\tmoveSubArray(dstX, dstY, srcX, srcY, srcWidth, srcHeight);\n\t\treturn;\n\t}\n\t// clip x\n\tif (srcX < 0)\n\t{\n\t\tsrcWidth += srcX;\n\t\tif (srcWidth <= 0) return;\n\t\tdstX -= srcX;\n\t\tsrcX = 0;\n\t}\n\tif (srcX + srcWidth > (sint) src.getWidth())\n\t{\n\t\tsrcWidth = src.getWidth() - srcX;\n\t\tif (srcWidth <= 0) return;\n\t}\n\tif (dstX < 0)\n\t{\n\t\tsrcWidth += dstX;\n\t\tif (srcWidth <= 0) return;\n\t\tsrcX -= dstX;\n\t\tdstX = 0;\n\t}\n\tif (dstX + srcWidth > (sint) getWidth())\n\t{\n\t\tsrcWidth = getWidth() - dstX;\n\t\tif (srcWidth <= 0) return;\n\t}\n\t// clip y\n\tif (srcY < 0)\n\t{\n\t\tsrcHeight += srcY;\n\t\tif (srcHeight <= 0) return;\n\t\tdstY -= srcY;\n\t\tsrcY = 0;\n\t}\n\tif (srcY + srcHeight > (sint) src.getHeight())\n\t{\n\t\tsrcHeight = src.getHeight() - srcY;\n\t\tif (srcHeight <= 0) return;\n\t}\n\tif (dstY < 0)\n\t{\n\t\tsrcHeight += dstY;\n\t\tif (srcHeight <= 0) return;\n\t\tsrcY -= dstY;\n\t\tdstY = 0;\n\t}\n\tif (dstY + srcHeight > (sint) getHeight())\n\t{\n\t\tsrcHeight = getHeight() - dstY;\n\t\tif (srcHeight <= 0) return;\n\t}\n\tconst T *srcBase = (const T *) &src._Array[0];\n\tconst T *srcPtr = &(srcBase[srcX + srcY * src.getWidth()]);\n\tconst T *srcEndPtr = srcPtr + srcHeight * src.getWidth();\n\tT *destBase = (T *) &_Array[0];\n\tT *destPtr = \t&(destBase[dstX + dstY * getWidth()]);\n\twhile (srcPtr != srcEndPtr)\n\t{\n\t\tif (CTraits<T>::SupportRawCopy)\n\t\t{\n\t\t\tmemcpy(destPtr, srcPtr, sizeof(T) * srcWidth);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstd::copy(srcPtr, srcPtr + srcWidth, destPtr);\n\t\t}\n\t\tsrcPtr += src.getWidth();\n\t\tdestPtr += getWidth();\n\t}\n\n}\n\n\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::move(sint offsetX, sint offsetY)\n{\n\tmoveSubArray(offsetX, offsetY, 0, 0, _Width, _Height);\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::init(uint width, uint height)\n{\n\t_Array.resize(width * height);\n\t_Width = width;\n\t_Height = height;\n}\n\n//*********************************************************************************\ntemplate <class T>\nvoid CArray2D<T>::init(uint width,uint height, const T &defaultValue)\n{\n\t_Array.resize(width * height, defaultValue);\n\t_Width = width;\n\t_Height = height;\n}\n\n} // NLMISC\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/async_file_manager.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_ASYNC_FILE_MANAGER_H\n#define NL_ASYNC_FILE_MANAGER_H\n\n#include \"types_nl.h\"\n#include \"task_manager.h\"\n\n\nnamespace NLMISC\n{\n\n/**\n * CAsyncFileManager is a class that manage file loading in a seperate thread\n * \\author Matthieu Besson\n * \\author Nevrax France\n * \\date 2002\n */\nclass CAsyncFileManager : public CTaskManager\n{\n\tNLMISC_SAFE_SINGLETON_DECL(CAsyncFileManager);\n\tCAsyncFileManager() {}\npublic:\n\n\t// Must be called instead of constructing the object\n//\tstatic CAsyncFileManager &getInstance ();\n\t// NB: release the singleton, but assert if there is any pending loading tasks.\n\t// Each system that use the async file manager should ensure it has no more pending task in it\n\tstatic void terminate ();\n\n\t// Do not use these methods with the bigfile manager\n\tvoid loadFile (const std::string &fileName, uint8 **pPtr);\n\tvoid loadFiles (const std::vector<std::string> &vFileNames, const std::vector<uint8**> &vPtrs);\n\n\n\tvoid signal (bool *pSgn); // Signal a end of loading for a group of \"mesh or file\" added\n\tvoid cancelSignal (bool *pSgn);\n\n\t/**\n\t *\tCCancelCallback is an interface that is used in call to CAsyncFileManager::cancelLoad.\n\t *\tThis class contains one method that is called for each task in the async file loader.\n\t *\tIf the method returns true, then the task is removed and cancelLoad return.\n\t *\t\\author Boris Boucher\n\t *\t\\author Nevrax France\n\t *\t\\date 10/2002\n\t */\n\tclass ICancelCallback\n\t{\n\tpublic:\n\t\tvirtual ~ICancelCallback() {}\n\t\tvirtual bool callback(const IRunnable *prunnable) const =0;\n\t};\n\n\t/// Add a load task in the CAsyncFileManager task list.\n\tvoid addLoadTask(IRunnable *ploadTask);\n\t/** Call this method to cancel a programmed load.\n\t *\t\\return False if the task either already ended or running.\n\t */\n\tbool cancelLoadTask(const ICancelCallback &cancelCallBack);\n\nprivate:\n\n//\tCAsyncFileManager (); // Singleton mode -> access it with the getInstance function\n\n//\tstatic CAsyncFileManager *_Singleton;\n\n\t// All the tasks\n\t// -------------\n\n\t// Load a file\n\tclass CFileLoad : public IRunnable\n\t{\n\t\tstd::string _FileName;\n\t\tuint8 **_ppFile;\n\tpublic:\n\t\tCFileLoad (const std::string& sFileName, uint8 **ppFile);\n\t\tvoid run (void);\n\t\tvoid getName (std::string &result) const;\n\t};\n\n\t// Load multiple files\n\tclass CMultipleFileLoad : public IRunnable\n\t{\n\t\tstd::vector<std::string> _FileNames;\n\t\tstd::vector<uint8**> _Ptrs;\n\tpublic:\n\t\tCMultipleFileLoad (const std::vector<std::string> &vFileNames, const std::vector<uint8**> &vPtrs);\n\t\tvoid run (void);\n\t\tvoid getName (std::string &result) const;\n\t};\n\n\t// Signal\n\tclass CSignal  : public IRunnable\n\t{\n\tpublic:\n\t\tbool *Sgn;\n\tpublic:\n\t\tCSignal (bool *pSgn);\n\t\tvoid run (void);\n\t\tvoid getName (std::string &result) const;\n\t};\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_ASYNC_FILE_MANAGER_H\n\n/* End of async_file_manager.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/base64.h",
    "content": "#ifndef NL_BASE64_H\n#define NL_BASE64_H\n\n#include \"types_nl.h\"\n\n#include <string>\n\nnamespace NLMISC\n{\n\nstd::string base64_encode( std::string const& );\nstd::string base64_decode( std::string const& );\n\n}; // namespace NLMISC\n\n#endif // NL_BASE64_H\n\n/* End of base64.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/big_file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BIG_FILE_H\n#define NL_BIG_FILE_H\n\n#include \"types_nl.h\"\n#include \"tds.h\"\n#include \"singleton.h\"\n\n\nnamespace NLMISC {\n\n/**\n * Big file management\n * \\author Matthieu Besson\n * \\author Nevrax France\n * \\date 2002\n */\n\nconst uint32 BF_ALWAYS_OPENED\t\t=\t0x00000001;\nconst uint32 BF_CACHE_FILE_ON_OPEN\t=\t0x00000002;\n\n// ***************************************************************************\nclass CBigFile\n{\n\tNLMISC_SAFE_SINGLETON_DECL(CBigFile);\n\n\tCBigFile() {}\n\t~CBigFile() {}\n\npublic:\n\t// release memory\n\tstatic void releaseInstance();\n\n\t// Retrieve the global instance\n//\tstatic CBigFile &getInstance ();\n\n\t// Add a big file to the manager\n\tbool add (const std::string &sBigFileName, uint32 nOptions);\n\n\t// get path of all added bigfiles\n\tvoid getBigFilePaths(std::vector<std::string> &bigFilePaths);\n\n\t// Remove a big file from the manager\n\tvoid remove (const std::string &sBigFileName);\n\n\t// true if a bigFile is added\n\tbool isBigFileAdded(const std::string &sBigFileName) const;\n\n\t// return name of Big File\n\tstd::string getBigFileName(const std::string &sBigFileName) const;\n\n\t// List all files in a bigfile\n\tvoid list (const std::string &sBigFileName, std::vector<std::string> &vAllFiles);\n\n\t// Remove all big files added\n\tvoid removeAll ();\n\n\t/** Signal that the current thread has ended : all file handles \"permanently\" allocated for that thread\n\t  * can be released then, preventing them from accumulating.\n\t  */\n\tvoid currentThreadFinished();\n\n\n\t// Used by CIFile to get information about the files within the big file\n\tFILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rBigFileOffset,\n\t\t\t\t\tbool &rCacheFileOnOpen, bool &rAlwaysOpened);\n\n\t// Used by Sound to get information for async loading of mp3 in .bnp. Return false if file not found in registered bnps\n\tbool getFileInfo (const std::string &sFileName, uint32 &rFileSize, uint32 &rBigFileOffset);\n\n\t// Used for CPath only for the moment !\n\tchar *getFileNamePtr(const std::string &sFileName, const std::string &sBigFileName);\n\n// ***************\nprivate:\n\tclass\tCThreadFileArray;\n\tfriend class\tCThreadFileArray;\n\n\t// A ptr to a file.\n\tstruct\tCHandleFile\n\t{\n\t\tFILE\t\t*File;\n\t\tCHandleFile() : File(NULL) { }\n\t};\n\n\t// A class which return a FILE * handle per Thread.\n\tclass\tCThreadFileArray\n\t{\n\tpublic:\n\t\tCThreadFileArray();\n\n\t\t// Allocate a FileId for a BNP.\n\t\tuint32\t\t\tallocate();\n\t\t// Given a BNP File Id, return its FILE* handle for the current thread.\n\t\tCHandleFile\t\t&get(uint32 index);\n\n\t\tvoid currentThreadFinished();\n\n\tprivate:\n\t\t// Do it this way because a few limited TDS is possible (64 on NT4)\n\t\tCTDS\t\t_TDS;\n\t\t// The array is grow only!!\n\t\tuint32\t\t_CurrentId;\n\t};\n\n\t// A BNPFile header\n\tstruct BNPFile\n\t{\n\t\tBNPFile() : Name(NULL), Size(0), Pos(0) { }\n\t\tchar\t\t*Name;\n\t\tuint32\t\tSize;\n\t\tuint32\t\tPos;\n\t};\n\n\tstruct CBNPFileComp\n\t{\n\t\tbool operator()(const BNPFile &f, const BNPFile &s )\n\t\t{\n\t\t\treturn strcmp( f.Name, s.Name ) < 0;\n\t\t}\n\t};\n\n\t// A BNP structure\n\tstruct BNP\n\t{\n\t\tBNP() : FileNames(NULL) { }\n\n\t\t// FileName of the BNP. important to open it in getFile() (for other threads or if not always opened).\n\t\tstd::string\t\t\t\t\t\tBigFileName;\n\t\t// map of files in the BNP.\n\t\tchar\t\t\t\t\t\t\t*FileNames;\n\t\tstd::vector<BNPFile>\t\t\tFiles;\n\t\t// Since many seek may be done on a FILE*, each thread should have its own FILE opened.\n\t\tuint32\t\t\t\t\t\t\tThreadFileId;\n\t\tbool\t\t\t\t\t\t\tCacheFileOnOpen;\n\t\tbool\t\t\t\t\t\t\tAlwaysOpened;\n\t};\nprivate:\n\n//\tCBigFile(); // Singleton mode -> access it with the getInstance function\n\n//\tstatic CBigFile\t\t\t\t*_Singleton;\n\n\t// This is an array of CHandleFile, unique to each thread\n\tCThreadFileArray\t\t\t_ThreadFileArray;\n\n\tstd::map<std::string, BNP> _BNPs;\n\n\t// common for getFile and getFileInfo\n\tbool getFileInternal (const std::string &sFileName, BNP *&zeBnp, BNPFile *&zeBnpFile);\n};\n\n} // NLMISC\n\n\n#endif // NL_BIG_FILE_H\n\n/* End of big_file.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/bit_mem_stream.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BIT_MEM_STREAM_H\n#define NL_BIT_MEM_STREAM_H\n\n#include \"types_nl.h\"\n#include \"mem_stream.h\"\n\n\nnamespace NLMISC {\n\n\n/* In debugging stage, should be defined. In stable stage, undefine it!\n * Works along with the verboseAllTraffic command\n */\n#ifndef NL_NO_DEBUG\n#\tifdef NL_OS_WINDOWS\n#\t\tdefine LOG_ALL_TRAFFIC\n#\telse\n#\t\tundef LOG_ALL_TRAFFIC\n#\tendif\n#endif\n\n#ifdef LOG_ALL_TRAFFIC\n\nextern bool VerboseAllTraffic;\n\n#define serialAndLog1( v ) \\\n\t_serialAndLog( #v, v );\n\n#define serialAndLog2( v, s ) \\\n\t_serialAndLog( #v, v, s );\n\n#define serialBitAndLog( v ) \\\n\t_serialBitAndLog( #v, v );\n\n#define\tserialAdaptAndLog( argstr, b, type ) \\\n\tuint32 ub=0; \\\n\tif ( isReading() ) \\\n\t{ \\\n\t\t_serialAndLog( argstr, ub, sizeof(type)*8 ); \\\n\t\tb = (type)ub; \\\n\t} \\\n\telse \\\n\t{ \\\n\t\tub = (uint32)b; \\\n\t\t_serialAndLog( argstr, ub, sizeof(type)*8 ); \\\n\t}\n\n#ifdef NL_LITTLE_ENDIAN\n\n#define\tserialAdapt64AndLog( argstr, b ) \\\n\t_serialAndLog( argstr, *((uint32*)(&b)), 32 ); \\\n\t_serialAndLog( argstr, *((uint32*)(&b)+1), 32 );\n\n#else\n\n#define\tserialAdapt64AndLog( argstr, b ) \\\n\tserialAndLog( argstr, *((uint32*)(&b)+1), 32); \\\n\tserialAndLog( argstr, *((uint32*)(&b)), 32);\n\n#endif\n\n\n#else\n\n#define serialAndLog1 serial\n#define serialAndLog2 serial\n#define serialBitAndLog serialBit\n\n\n#endif\n\n#define\tserialAdapt( b, type ) \\\n\tuint32 ub=0; \\\n\tif ( isReading() ) \\\n\t{ \\\n\t\tserial( ub, sizeof(type)*8 ); \\\n\t\tb = (type)ub; \\\n\t} \\\n\telse \\\n\t{ \\\n\t\tub = (uint32)b; \\\n\t\tserial( ub, sizeof(type)*8 ); \\\n\t}\n\n#ifdef NL_LITTLE_ENDIAN\n\n#define\tserialAdapt64( b ) \\\n\tserial( *((uint32*)(&b)), 32); \\\n\tserial( *((uint32*)(&b)+1), 32);\n\n#else\n\n#define\tserialAdapt64( b ) \\\n\tserial( *((uint32*)(&b)+1), 32); \\\n\tserial( *((uint32*)(&b)), 32);\n\n#endif\n\n\nclass CBitSet;\n\n\n/*\n * Item of CBMSDbgInfo\n */\nstruct TBMSSerialInfo\n{\n\tenum TSerialType { B, U, U64, F, BF, Buffer, NbSerialTypes };\n\n\tTBMSSerialInfo( uint32 bitpos, uint32 bitsize, TSerialType type, const char *symbol )\n\t{\n\t\tnlassert( bitpos < 800000 );\n\t\tBitPos = bitpos;\n\t\tBitSize = bitsize;\n\t\tType = type;\n\t\tSymbol = symbol;\n\t}\n\n\tuint32\t\tBitPos;\n\tuint32\t\tBitSize;\n\tTSerialType\tType;\n\tconst char\t*Symbol;\n};\n\nextern const char * SerialTypeToCStr [ TBMSSerialInfo::NbSerialTypes ];\n\n\ntypedef std::vector< TBMSSerialInfo > TBMSSerialInfoList;\n\n\n/*\n * Data members struct for CBMSDbgInfo\n */\nstruct TBMSDbgInfoData\n{\n\t/// Constructor\n\tTBMSDbgInfoData() : List(), CurrentBrowsedItem(0), NextSymbol(NULL), AddEventIsEnabled(true) {}\n\n\t/// Vector of serial items\n\tTBMSSerialInfoList\t\t\t\tList;\n\n\t/// Current browsed item in the list (valid only from beginEventBrowsing() until clear() or addSerial()/addPoke())\n\tuint32\t\t\t\t\t\t\tCurrentBrowsedItem;\n\n\t/// Symbol of next event\n\tconst char\t\t\t\t\t\t*NextSymbol;\n\n\t/// Flag to enable/disable addSerial() and addPoke() (because CBitMemStream::getSerialItem() must not add events in the list)\n\tbool\t\t\t\t\t\t\tAddEventIsEnabled;\n};\n\nclass CBitMemStream;\n\n/*\n * Debug details about what was serialised (sizeof is only one pointer if not explicitely initialised)\n */\nclass CBMSDbgInfo\n{\npublic:\n\n#ifdef NL_DEBUG\n\t/// Constructor\n\tCBMSDbgInfo() : _DbgData(NULL) { init(); }\n#else\n\t/// Constructor\n\tCBMSDbgInfo() {}\n#endif\n\n#ifdef NL_DEBUG\n\t/// Copy constructor\n\tCBMSDbgInfo( const CBMSDbgInfo& src ) : _DbgData(NULL)\n\t{\n\t\tinit();\n\t\toperator=( src );\n\t}\n\n\t/// Operator=\n\tCBMSDbgInfo&\toperator=( const CBMSDbgInfo& src )\n\t{\n\t\t*_DbgData = *src._DbgData;\n\t\treturn *this;\n\t}\n\n\t/// Destructor\n\t~CBMSDbgInfo()\n\t{\n\t\tdelete _DbgData;\n\t\t_DbgData = NULL;\n\t}\n\n#endif\n\tvoid swap(CBMSDbgInfo &other)\n\t{\n#ifdef NL_DEBUG\n\t\tstd::swap(_DbgData, other._DbgData);\n#else\n\t\tnlunreferenced(other);\n#endif\n\t}\n\n\t/// Add a serial event at the end\n\tvoid\taddSerial( uint32 bitpos, uint32 size, TBMSSerialInfo::TSerialType type )\n\t{\n#ifdef NL_DEBUG\n\t\tif ( ! _DbgData->AddEventIsEnabled )\n\t\t{\n\t\t\t_DbgData->NextSymbol = NULL;\n\t\t\treturn;\n\t\t}\n\n\t\tTBMSSerialInfo serialItem( bitpos, size, type, _DbgData->NextSymbol );\n\t\t_DbgData->List.push_back( serialItem );\n\t\t_DbgData->NextSymbol = NULL;\n#else\n\t\tnlunreferenced(bitpos);\n\t\tnlunreferenced(size);\n\t\tnlunreferenced(type);\n#endif\n\t}\n\n\t/// Add a serial event in the middle\n\tvoid\taddPoke( uint32 bitpos, uint32 size, TBMSSerialInfo::TSerialType type )\n\t{\n#ifdef NL_DEBUG\n\t\tif ( ! _DbgData->AddEventIsEnabled )\n\t\t{\n\t\t\t_DbgData->NextSymbol = NULL;\n\t\t\treturn;\n\t\t}\n\n\t\tTBMSSerialInfo serialItem( bitpos, size, type, _DbgData->NextSymbol );\n\n\t\t/// Find where to add it\n\t\tbool found = false;\n\t\tTBMSSerialInfoList::iterator itl;\n\t\tfor ( itl=_DbgData->List.begin(); itl!=_DbgData->List.end(); ++itl )\n\t\t{\n\t\t\tif ( (*itl).BitPos == bitpos )\n\t\t\t{\n\t\t\t\t// Found, replace reserved by poked\n\t\t\t\t(*itl) = serialItem;\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif ( ! found )\n\t\t{\n\t\t\tnlwarning( \"Missing reserve() corresponding to poke()\" );\n\t\t}\n\t\t_DbgData->NextSymbol = NULL;\n#else\n\t\tnlunreferenced(bitpos);\n\t\tnlunreferenced(size);\n\t\tnlunreferenced(type);\n#endif\n\t}\n\n\t/// Set the symbol for the next event that will be added (optional)\n\tvoid\tsetSymbolOfNextSerialEvent( const char *symbol )\n\t{\n#ifdef NL_DEBUG\n\t\t_DbgData->NextSymbol = symbol;\n#else\n\t\tnlunreferenced(symbol);\n#endif\n\t}\n\n\t/// Clear\n\tvoid\tclear()\n\t{\n#ifdef NL_DEBUG\n\t\t_DbgData->List.clear();\n#endif\n\t}\n\n\t/// Begin a browsing session of serial events, addSerial()/addPoke() is now disabled\n\tvoid\t\tbeginEventBrowsing()\n\t{\n#ifdef NL_DEBUG\n\t\t_DbgData->CurrentBrowsedItem = 0;\n\t\t_DbgData->AddEventIsEnabled = false;\n#endif\n\t}\n\n\t/// End a browsing session of serial events, and reenable addSerial()/addPoke()\n\tvoid\t\tendEventBrowsing()\n\t{\n#ifdef NL_DEBUG\n\t\t_DbgData->AddEventIsEnabled = true;\n#endif\n\t}\n\n\t/// Return an eventId of serial event, or \"\" (and eventId -1) if nothing found at the specified bitpos\n\tstd::string\tgetEventIdAtBitPos( uint32 bitpos, sint32 *eventId )\n\t{\n#ifdef NL_DEBUG\n\t\tif ( _DbgData->CurrentBrowsedItem < _DbgData->List.size() )\n\t\t{\n\t\t\tif ( bitpos == _DbgData->List[_DbgData->CurrentBrowsedItem].BitPos ) // works only with a vector!\n\t\t\t{\n\t\t\t\t*eventId = (sint32)_DbgData->CurrentBrowsedItem;\n\t\t\t\t++_DbgData->CurrentBrowsedItem;\n\t\t\t\treturn toString( \"(%u)\", _DbgData->CurrentBrowsedItem - 1 );\n\t\t\t}\n\t\t\t//nlassert( bitpos < (*_List)[_CurrentBrowsedItem].BitPos ); // occurs if stream overflow\n\t\t}\n#else\n\t\tnlunreferenced(bitpos);\n#endif\n\t\t*eventId = -1;\n\t\treturn std::string();\n\t}\n\n\t/// Return full info about a serial event, or \"\" if eventId is -1\n\tstd::string getEventLegendAtBitPos( CBitMemStream& bms, sint32 eventId );\n\nprivate:\n\n#ifdef NL_DEBUG\n\t/// Explicit init\n\tvoid\tinit()\n\t{\n\t\t_DbgData = new TBMSDbgInfoData();\n\t}\n\n\t/// List of serials\n\tTBMSDbgInfoData\t\t\t*_DbgData;\n#endif\n};\n\n\n/**\n * Bit-oriented memory stream\n *\n * How output mode works:\n * In CMemStream, _BufPos points to the end of the stream, where to write new data.\n * In CBitMemStream, _BufPos points to the last byte of the stream, where to write new data.\n * Then _FreeBits tells the number of bits not used in this byte (i.e. (8-_FreeBits) is the\n * number of bits already filled inside this byte).\n * The minimum buffer size is 1: when nothing has been written yet, the position is at beginning\n * and _FreeBits is 8.\n *\n * How input mode works:\n * Same as in CMemStream, but some bits may be free in the last byte (the information about\n * how many is not stored in the CBitMemStream object, the reader needs to know the format of\n * the data it reads).\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001, 2003\n */\nclass CBitMemStream : public CMemStream\n{\npublic:\n\n\t/// Constructor\n\tCBitMemStream( bool inputStream=false, uint32 defaultcapacity=32 );\n\n\t/// Copy constructor\n\tCBitMemStream( const CBitMemStream& other );\n\n\t/// Assignment operator\n\tCBitMemStream&\toperator=( const CBitMemStream& other )\n\t{\n\t\tCMemStream::operator=( other );\n\t\t_FreeBits = other._FreeBits;\n\t\t_DbgInfo = other._DbgInfo;\n\t\treturn *this;\n\t}\n\n\t// Echange status and memory data\n\tvoid swap(CBitMemStream &other);\n\n\t/**\n\t * Set the position at the beginning. In output mode, the method ensures the buffer\n\t * contains at least one blank byte to write to.\n\t *\n\t * If you are using the stream only in output mode, you can use this method as a faster version\n\t * of clear() *if you don't serialize pointers*.\n\t */\n\tvirtual void\t\tresetBufPos()\n\t{\n\t\t// This is ensured in CMemStream::CMemStream() and CMemStream::clear()\n\t\t//if ( (!isReading()) && _Buffer.empty() )\n\t\t///\t_Buffer.resize( 8 ); // at least 8 bytes\n\t\tnlassert( ! ((!isReading()) && _Buffer.getBuffer().empty()) );\n\n\t\tCMemStream::resetBufPos();\n\t\tif ( !isReading() )\n//\t\t\t*_BufPos = 0; // partial prepareNextByte()\n\t\t\t*(_Buffer.getBufferWrite().getPtr()+_Buffer.Pos) = 0;\n\t\t_FreeBits = 8;\n\t\t_DbgInfo.clear();\n\t}\n\n\t/** Returns the length (size) of the message, in bytes.\n\t * If isReading(), it is the number of bytes that can be read,\n\t * otherwise it is the number of bytes that have been written\n\t * (the last byte may not be full, it may have free bits, see\n\t * also getPosInBit()).\n\t */\n\tvirtual uint32\tlength() const\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treturn lengthR();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( _FreeBits == 8 )\n\t\t\t\treturn lengthS();\n\t\t\telse\n\t\t\t\treturn lengthS() + 1;\n\t\t}\n\t}\n\n\t/// Transforms the message from input to output or from output to input\n\tvirtual void\tinvert()\n\t{\n\t\tif ( ! isReading() )\n\t\t{\n//\t\t\t++_BufPos; // write->read: extend to keep the last byte inside the payload\n\t\t\t++_Buffer.Pos; // write->read: extend to keep the last byte inside the payload\n\t\t}\n\t\tCMemStream::invert();\n\t\tif ( ! isReading() )\n\t\t{\n#ifdef NL_DEBUG\n//\t\t\tnlassert( _BufPos == _Buffer.getPtr()+_Buffer.size() );\n\t\t\tnlassert( _Buffer.Pos == _Buffer.getBuffer().size() );\n#endif\n//\t\t\t--_BufPos; // read->write: set the position on the last byte, not at the end as in CMemStream::invert()\n\t\t\t--(_Buffer.Pos); // read->write: set the position on the last byte, not at the end as in CMemStream::invert()\n\t\t}\n\t\t// Keep the same _FreeBits\n\t}\n\n\t/// Clears the message\n\tvirtual void\tclear()\n\t{\n\t\tCMemStream::clear();\n\t\tresetBufPos();\n\t}\n\n\t/// Returns the number of bit from the beginning of the buffer (in bit)\n\tsint32\tgetPosInBit() const\n\t{\n//\t\treturn (_BufPos - _Buffer.getPtr() + 1)*8 - _FreeBits;\n\t\treturn (_Buffer.Pos + 1)*8 - _FreeBits;\n\t}\n\n\t/// Returns the stream as a string with 0 and 1.\n\tvoid\t\t\tdisplayStream( const char *title=\"\", CLog *log = NLMISC::DebugLog );\n\n\t/// See doc in CMemStream::fill()\n\tvoid\t\t\tfill( const uint8 *srcbuf, uint32 len )\n\t{\n\t\t_FreeBits = 8;\n\t\t_DbgInfo.clear();\n\t\tCMemStream::fill( srcbuf, len );\n\t}\n\n\t/// See doc in CMemStream::bufferToFill()\n\tvirtual uint8\t\t*bufferToFill( uint32 msgsize )\n\t{\n\t\t_FreeBits = 8;\n\t\t_DbgInfo.clear();\n\t\treturn CMemStream::bufferToFill( msgsize );\n\t}\n\n\t/// Append the contents of a bitmemstream at the end of our bitmemstream (precondition: !isReading())\n\tvoid\t\t\tappend( const CBitMemStream& newBits );\n\n\t/// Serialize a buffer\n\tvirtual void\tserialBuffer(uint8 *buf, uint len);\n\n\t/// Serialize one bit\n\tvirtual void\tserialBit( bool& bit );\n\n#ifdef LOG_ALL_TRAFFIC\n\tvoid\t\t\t_serialAndLog( const char *argstr, uint32& value, uint nbits );\n\tvoid\t\t\t_serialAndLog( const char *argstr, uint64& value, uint nbits );\n\tvoid\t\t\t_serialBitAndLog( const char *argstr, bool& bit );\n#endif\n\n\t/**\n\t * Serialize only the nbits lower bits of value (nbits range: [1..32])\n\t * When using this method, always leave resetvalue to true.\n\t */\n\tvoid\t\t\tserial( uint32& value, uint nbits, bool resetvalue=true )\n\t{\n\t\t_DbgInfo.addSerial( getPosInBit(), nbits, TBMSSerialInfo::U );\n\t\tinternalSerial( value, nbits, resetvalue );\n\t}\n\n\t/**\n\t * Serialize only the nbits lower bits of 64-bit value (nbits range: [1..64])\n\t */\n\tvoid\t\t\tserial( uint64& value, uint nbits )\n\t{\n\t\t_DbgInfo.addSerial( getPosInBit(), nbits, TBMSSerialInfo::U64 );\n\t\tinternalSerial( value, nbits );\n\t}\n\n\t/**\n\t * Same as CMemStream::reserve(). Warning, the return value is a byte pos (not bitpos)!\n\t * Consider using reserveBits() instead.\n\t */\n\tsint32\t\t\treserve( uint byteLen );\n\n\t/**\n\t * In a output bit stream, serialize nbits bits (no matter their value).\n\t * Works even if the number of bits to add is larger than 64. See also poke() and pokeBits().\n\t */\n\tvoid\t\t\treserveBits( uint nbits );\n\n\t/*\n\t * Rewrite the nbbits lowest bits of a value at the specified position bitpos of the current output bit stream.\n\t *\n\t * Preconditions:\n\t * - bitpos+nbbits <= the current length in bit of the stream.\n\t * - The bits poked must have been reserved by reserveBits() (i.e. set to 0)\n\t */\n\tvoid\t\t\tpoke( uint32 value, uint bitpos, uint nbits );\n\n\t/**\n\t * Rewrite the bitfield at the specified position bitpos of the current output bit stream.\n\t * The size of the bitfield is *not* written into the stream (unlike serialCont()).\n\t * Precondition: bitpos+bitfield.size() <= the current length in bit of the stream. See also reserveBits().\n\t */\n\tvoid\t\t\tpokeBits( const NLMISC::CBitSet& bitfield, uint bitpos );\n\n\t/**\n\t * Read bitfield.size() bits from the input stream to fill the bitfield.\n\t * It means you have to know the size and to resize the bitfield yourself.\n\t */\n\tvoid\t\t\treadBits( NLMISC::CBitSet& bitfield );\n\n\t/// Display the bits of the stream just before the specified bitpos (or current pos if -1)\n\tvoid\t\t\tdisplayLastBits( sint nbits, sint bitpos=-1, NLMISC::CLog *log=NLMISC::DebugLog );\n\n\t/// Return a string showing the serial item\n\tstd::string\t\tgetSerialItem( const TBMSSerialInfo& serialItem );\n\n\t/// Template serialisation (should take the one from IStream)\n    template<class T>\n\tvoid\t\t\tserial(T &obj)\t\t\t\t\t\t\t{ obj.serial(*this); }\n\n\t// CMemStream::serialCont() will call CBitMemStream's virtual serialBuffer()\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::vector<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::list<T> &cont) \t\t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::deque<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::set<T> &cont) \t\t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::multiset<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::map<K, T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::multimap<K, T> &cont) \t{CMemStream::serialCont(cont);}\n\n\t/*template<class T0,class T1>\n\tvoid\t\t\tserial(T0 &a, T1 &b)\n\t{ serial(a); serial(b);}\n\ttemplate<class T0,class T1,class T2>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c)\n\t{ serial(a); serial(b); serial(c);}\n\ttemplate<class T0,class T1,class T2,class T3>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d)\n\t{ serial(a); serial(b); serial(c); serial(d);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4,class T5>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}*/\n\n\t/** \\name Base type serialisation.\n\t * Those method are a specialisation of template method \"void serial(T&)\".\n\t */\n\t//@{\n\n\n/*\n#define\tserialAdapt64( b, type ) \\\n\tuint32 ubl=0, ubh=0; \\\n\tif ( isReading() ) \\\n\t{ \\\n\t\tserial( ubh, sizeof(uint32)*8 ); \\\n\t\tserial( ubl, sizeof(uint32)*8 ); \\\n\t\tb = (((type)ubh)<<32)+ubl; \\\n\t} \\\n\telse \\\n\t{ \\\n\t\tubh = (uint32)(b>>32); \\\n\t\tubl = (uint32)(b); \\\n\t\tserial( ubh, sizeof(uint32)*8 ); \\\n\t\tserial( ubl, sizeof(uint32)*8 ); \\\n\t}\n*/\n\n#ifdef LOG_ALL_TRAFFIC\n\tvoid\t\t\t_serialAndLog(const char *argstr, uint8 &b) { serialAdaptAndLog( argstr, b, uint8 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, sint8 &b) { serialAdaptAndLog( argstr, b, sint8 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, uint16 &b) { serialAdaptAndLog( argstr, b, uint16 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, sint16 &b) { serialAdaptAndLog( argstr, b, sint16 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, uint32 &b) { serialAdaptAndLog( argstr, b, uint32 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, sint32 &b) { serialAdaptAndLog( argstr, b, sint32 ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, uint64 &b) { serialAdapt64AndLog( argstr, b ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, sint64 &b) { serialAdapt64AndLog( argstr, b ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, float &b);\n\tvoid\t\t\t_serialAndLog(const char *argstr, double &b) { serialAdapt64AndLog( argstr, b ); }\n\tvoid\t\t\t_serialAndLog(const char *argstr, bool &b) { _serialBitAndLog( argstr, b ); }\n#ifndef NL_OS_CYGWIN\n\tvirtual void\t_serialAndLog(const char *argstr, char &b) { serialAdaptAndLog( argstr, b, char ); }\n#endif\n#endif\n\n\tvirtual void\tserial(uint8 &b) { serialAdapt( b, uint8 ); }\n\tvirtual void\tserial(sint8 &b) { serialAdapt( b, sint8 ); }\n\tvirtual void\tserial(uint16 &b) { serialAdapt( b, uint16 ); }\n\tvirtual void\tserial(sint16 &b) { serialAdapt( b, sint16 ); }\n\tvirtual void\tserial(uint32 &b) { serialAdapt( b, uint32 ); }\n\tvirtual void\tserial(sint32 &b) { serialAdapt( b, sint32 ); }\n\tvirtual void\tserial(uint64 &b) { serialAdapt64( b ); }\n\tvirtual void\tserial(sint64 &b) { serialAdapt64( b ); }\n\tvirtual void\tserial(float &b);\n\tvirtual void\tserial(double &b) { serialAdapt64( b ); }\n\tvirtual void\tserial(bool &b) { serialBit( b ); }\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b) { serialAdapt( b, char ); }\n#endif\n\n\tvirtual void\tserial(std::string &b);\n\tvirtual void\tserial(ucstring &b);\n\n\tvirtual void\tserial(CBitMemStream &b) { serialMemStream(b); }\n\tvirtual void\tserialMemStream(CMemStream &b);\n\n\n\t//@}\n\n\t/// Specialisation of serialCont() for vector<uint8>\n\tvirtual void\t\t\tserialCont(std::vector<uint8> &cont) { serialVector(cont); }\n\t/// Specialisation of serialCont() for vector<sint8>\n\tvirtual void\t\t\tserialCont(std::vector<sint8> &cont) { serialVector(cont); }\n\t/// Specialisation of serialCont() for vector<bool>\n\tvirtual void\t\t\tserialCont(std::vector<bool> &cont);\n\nprotected:\n\n\t/**\n\t * Helper for serial(uint32,uint)\n\t */\n\tvoid\t\t\tinternalSerial( uint32& value, uint nbits, bool resetvalue=true );\n\n\t/**\n\t * Helper for serial(uint64,uint)\n\t */\n\tvoid\t\t\tinternalSerial( uint64& value, uint nbits )\n\t{\n\t\tif ( nbits > 32 )\n\t\t{\n\t\t\tif ( isReading() )\n\t\t\t{\n\t\t\t\t// Reset and read MSD\n\t\t\t\tuint32 msd = 0;\n\t\t\t\tinternalSerial( msd, nbits-32 );\n\t\t\t\tvalue = (uint64)msd << 32;\n\t\t\t\t// Reset and read LSD\n\t\t\t\tinternalSerial( (uint32&)value, 32 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Write MSD\n\t\t\t\tuint32 msd = (uint32)(value >> 32);\n\t\t\t\tinternalSerial( msd, nbits-32 );\n\t\t\t\t// Write LSD\n\t\t\t\tinternalSerial( (uint32&)value, 32 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( isReading() )\n\t\t\t{\n\t\t\t\t// Reset MSB (=0 is faster than value&=0xFFFFFFFF)\n\t\t\t\tvalue = 0;\n\t\t\t}\n\t\t\t// Read or write LSB\n\t\t\tinternalSerial( (uint32&)value, nbits );\n\t\t}\n\t}\n\n\t/**\n\t * Prepare next byte for writing.\n\t *\n\t * Preconditions:\n\t * - See the preconditions of increaseBufferIfNecessary() and pointNextByte()\n\t *\n\t * Postconditions:\n\t * - See the postconditions of increaseBufferIfNecessary() and pointNextByte()\n\t * - The new pointed byte is 0\n\t */\n\tvoid\t\t\tprepareNextByte()\n\t{\n\t\tpointNextByte();\n\t\tincreaseBufferIfNecessary();\n//\t\t*_BufPos = 0;\n\t\t*(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = 0;\n\t}\n\n\t/**\n\t * Point the beginning of the byte after _BufPos\n\t *\n\t * Preconditions\n\t * - The last written byte, at pos _BufPos, is fully written (but _FreeBits may not be updated yet)\n\t *\n\t * Postconditions\n \t * - The pos was incremented by 1, _FreeBits is 8\n\t */\n\tvoid\t\t\tpointNextByte()\n\t{\n#ifdef NL_DEBUG\n\t\tnlassert( !isReading() );\n#endif\n\t\t_FreeBits = 8;\n//\t\t++_BufPos;\n\t\t++_Buffer.Pos;\n\t}\n\n\t/**\n\t * Increase the size of the buffer if necessary (outpout bit stream)\n\t *\n\t * Preconditions:\n\t * - The stream is in output mode (!isReading())\n\t * - resetBufPos() must have been called since construction\n\t * - getPos() <= _Buffer.size()\n\t *\n\t * Postconditions:\n\t * - getPos() < _Buffer.size()\n\t */\n\tvoid\t\t\tincreaseBufferIfNecessary()\n\t{\n#ifdef NL_DEBUG\n//\t\tnlassert( (!isReading()) && (!_Buffer.empty()) );\n\t\tnlassert( (!isReading()) && (!_Buffer.getBuffer().empty()) );\n//\t\tnlassert( _BufPos <= _Buffer.getPtr() + _Buffer.size() );\n\t\tnlassert( _Buffer.Pos <= _Buffer.getBuffer().size() );\n#endif\n//\t\tuint32 bytepos = _BufPos - _Buffer.getPtr();\n//\t\tuint32 bytepos = _BufPos;\n//\t\tif ( bytepos == _Buffer.size() )\n\t\tif ( _Buffer.Pos == _Buffer.getBuffer().size() )\n\t\t{\n//\t\t\t_Buffer.resize( bytepos * 2 );\n\t\t\t_Buffer.getBufferWrite().resize( _Buffer.Pos * 2 );\n//\t\t\t_BufPos = _Buffer.getPtr() + bytepos; // don't change the pos but update pointer (needed because the buffer may have moved when reallocating)\n\t\t}\n\t}\n\n\t/**\n\t* Helper for poke(), to write a value inside an output stream (works because reserveBits sets to 0)\n\t* Warning: if _FreeBits == 8, increments _BufPos.\n\t*/\n\tvoid\t\t\tserialPoke( uint32 value, uint nbits );\n\n\t/// Number of bits unused at the current pos. If 8, means the current pos if full and we need to increment the pos!\n\tuint\t\t\t_FreeBits; // From 8 downto 1\n\n\t/// Debug details about what was serialised\n\tCBMSDbgInfo\t\t_DbgInfo;\n};\n\n\n/// Display a part of a bitmemstream\nvoid\tdisplayBitStream( const CBitMemStream& msg, sint beginbitpos, sint endbitpos, NLMISC::CLog *log=NLMISC::DebugLog );\n\n\n/*\n * Return full info about a serial event, or \"\" if eventId is -1\n */\ninline std::string CBMSDbgInfo::getEventLegendAtBitPos( CBitMemStream& bms, sint32 eventId )\n{\n#ifdef NL_DEBUG\n\tif ( eventId != -1 )\n\t{\n\t\tnlassert( eventId < (sint32)_DbgData->List.size() );\n\t\tTBMSSerialInfo& serialItem = _DbgData->List[eventId]; // works only with a vector!\n\t\treturn toString( \"(%d) BitPos %3u Type %s BitSize %2u Value %s %s\\n\",\n\t\t\t\t\teventId, serialItem.BitPos, SerialTypeToCStr[serialItem.Type], serialItem.BitSize,\n\t\t\t\t\tbms.getSerialItem( serialItem ).c_str(), (serialItem.Symbol!=NULL)?serialItem.Symbol:\"\" );\n\t}\n#else\n\tnlunreferenced(bms);\n\tnlunreferenced(eventId);\n#endif\n\n\treturn std::string();\n}\n\n\n} // NLMISC\n\n\n#endif // NL_BIT_MEM_STREAM_H\n\n/* End of bit_mem_stream.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/bit_set.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BIT_SET_H\n#define NL_BIT_SET_H\n\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n\n\nnamespace\tNLMISC\n{\n\n// Size in bit of base word.\n#define\tNL_BITLEN\t\t\t(4*8)\n#define\tNL_BITLEN_SHIFT\t\t5\n\n// ***************************************************************************\n/**\n * A BitSet, to test / set flags quickly.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCBitSet\n{\npublic:\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\t/// \\name Object.\n\t//@{\n\tCBitSet();\n\tCBitSet(uint numBits);\n\tCBitSet(const CBitSet &bs);\n\t~CBitSet();\n\tCBitSet\t&operator=(const CBitSet &bs);\n\t//@}\n\n\t/// \\name Basics.\n\t//@{\n\t/// Resize the bit array. All Bits are reseted.\n\tvoid\tresize (uint numBits);\n\t/// Resize the bit array. Bits are not reseted. New bits are set with value.\n\tvoid\tresizeNoReset (uint numBits, bool value=false);\n\t/// Clear the bitarray so size() return 0.\n\tvoid\tclear();\n\t/// Return size of the bit array.\n\tuint\tsize() const\n\t{\n\t\treturn NumBits;\n\t}\n\t/// Set a bit to 0 or 1.\n\tvoid\tset(sint bitNumber, bool value)\n\t{\n\t\tnlassert(bitNumber>=0 && bitNumber<NumBits);\n\n\t\tuint\tmask= bitNumber&(NL_BITLEN-1);\n\t\tmask= 1<<mask;\n\t\tif(value)\n\t\t\tArray[bitNumber >> NL_BITLEN_SHIFT]|= mask ;\n\t\telse\n\t\t\tArray[bitNumber >> NL_BITLEN_SHIFT]&= ~mask;\n\t}\n\t/// Get the value of a bit.\n\tbool\tget(sint bitNumber) const\n\t{\n\t\tnlassert(bitNumber>=0 && bitNumber<NumBits);\n\n\t\tuint\tmask= bitNumber&(NL_BITLEN-1);\n\t\tmask= 1<<mask;\n\t\treturn (Array[bitNumber >> NL_BITLEN_SHIFT] & mask) != 0;\n\t}\n\t/// Get the value of a bit.\n\tbool\toperator[](sint bitNumber) const\n\t{\n\t\treturn get(bitNumber);\n\t}\n\t/// Set a bit to 1.\n\tvoid\tset(sint bitNumber) {set(bitNumber, true);}\n\t/// Set a bit to 0.\n\tvoid\tclear(sint bitNumber) {set(bitNumber, false);}\n\t/// Set all bits to 1.\n\tvoid\tsetAll();\n\t/// Set all bits to 0.\n\tvoid\tclearAll();\n\t//@}\n\n\n\t/// \\name Bit operations.\n\t//@{\n\t/// Return The bitarray NOTed.\n\tCBitSet\toperator~() const;\n\t/**\n\t * Return this ANDed with bs.\n\t * The result BitSet is of size of \\c *this. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\toperator&(const CBitSet &bs) const;\n\t/**\n\t * Return this ORed with bs.\n\t * The result BitSet is of size of \\c *this. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\toperator|(const CBitSet &bs) const;\n\t/**\n\t * Return this XORed with bs.\n\t * The result BitSet is of size of \\c *this. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\toperator^(const CBitSet &bs) const;\n\n\t/// NOT the BitArray.\n\tvoid\tflip();\n\t/**\n\t * AND the bitArray with bs.\n\t * The bitset size is not changed. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\t&operator&=(const CBitSet &bs);\n\t/**\n\t * OR the bitArray with bs.\n\t * The bitset size is not changed. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\t&operator|=(const CBitSet &bs);\n\t/**\n\t * XOR the bitArray with bs.\n\t * The bitset size is not changed. Any missing bits into bs will be considered as 0.\n\t */\n\tCBitSet\t&operator^=(const CBitSet &bs);\n\t//@}\n\n\n\t/// \\name Bit comparisons.\n\t//@{\n\t/**\n\t * Compare two BitSet not necessarely of same size. The comparison is done on N bits, where N=min(this->size(), bs.size())\n\t * \\return true if the N common bits of this and bs are the same. false otherwise.\n\t */\n\tbool\tcompareRestrict(const CBitSet &bs) const;\n\t/// Compare two BitSet. If not of same size, return false.\n\tbool\toperator==(const CBitSet &bs) const;\n\t/// operator!=.\n\tbool\toperator!=(const CBitSet &bs) const;\n\t/// Return true if all bits are set. false if size()==0.\n\tbool\tallSet();\n\t/// Return true if all bits are cleared. false if size()==0.\n\tbool\tallCleared();\n\t//@}\n\n\n\t/// Serialize\n\tvoid\tserial(NLMISC::IStream &f);\n\n\t/// Return the raw vector\n\tconst std::vector<uint32>& getVector() const { return Array; }\n\n\t/// Write an uint32 into the bit set (use with caution, no check)\n\tvoid\tsetUint( uint32 srcValue, uint i ) { Array[i] = srcValue; }\n\n\t/// Return a string representing the bitfield with 1 and 0 (from left to right)\n\tstd::string\ttoString() const;\n\nprivate:\n\tstd::vector<uint32>\tArray;\n\tsint\t\t\t\tNumBits;\n\tuint32\t\t\t\tMaskLast;\t// Mask for the last uint32.\n};\n\n\n}\n\n\n\n#endif // NL_BIT_SET_H\n\n/* End of bit_set.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/bitmap.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_BITMAP_H\n#define NL_BITMAP_H\n\n\n#include \"types_nl.h\"\n#include \"rgba.h\"\n#include \"debug.h\"\n#include <vector>\n#include \"object_vector.h\"\n\n\nnamespace NLMISC\n{\n\n\nclass IStream;\n\n//------------------ DDS STUFFS --------------------\n\n#ifndef NL_MAKEFOURCC\n    #define NL_MAKEFOURCC(ch0, ch1, ch2, ch3)                              \\\n                ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) |   \\\n                ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 ))\n#endif\n\nconst uint32\tDDS_HEADER = NL_MAKEFOURCC('D', 'D', 'S', ' ');\nconst uint32\tDXT_HEADER = NL_MAKEFOURCC('D', 'X', 'T', '\\0');\nconst uint32\tPNG_HEADER = NL_MAKEFOURCC(0x89, 'P', 'N', 'G');\nconst uint32\tJPG_HEADER = NL_MAKEFOURCC(0xff, 0xd8, 0xff, 0xe0);\n\n\n// dwLinearSize is valid\n#define DDSD_LINEARSIZE         0x00080000l\n\n\n//---------------- END OF DDS STUFFS ------------------\n\n\nconst uint8\tMAX_MIPMAP = 16;\n\n\n\n\n/**\n * Class Bitmap\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2000\n */\n/* *** IMPORTANT ********************\n * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL\n * **********************************\n */\nclass CBitmap\n{\nprotected :\n\tCObjectVector<uint8> _Data[MAX_MIPMAP];\n\n\t// The number of mipmaps. base image IS a mipmap. 1 means a base image with no mipmaping.\n\tuint8\t_MipMapCount;\n\tbool\t_LoadGrayscaleAsAlpha;\n\tuint32\t_Width;\n\tuint32\t_Height;\n\n\t// don't forget to update operator=() and swap() if adding a data member\n\nprivate :\n\n\n\t/**\n\t * blend 2 integers between 0 and 255 .\n\t * \\param n0 first integer\n\t * \\param n1 second integer\n\t * \\param coef coefficient for the first integer (must be in [0,256])\n\t */\n\tuint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);\n\n\n\t/**\n\t * Read a DDS from an IStream.\n\t * The bitmap is readen as a set of bytes and stocked compressed.\n\t * Width and Height are multiple of 4.\n\t * \\param IStream The stream must be in reading mode.\n\t * \\return image depth\n\t * \\throw EDDSBadHeader : surface is header is not valid.\n\t */\n\tuint8 readDDS(NLMISC::IStream &f, uint mipMapSkip);\n\n\n\t/**\n\t * Read a TGA from an IStream.\n\t * TGA pictures can be in 24 or 32 bits, RLE or uncompressed\n\t * \\param f IStream (must be a reading stream)\n\t * \\return image depth if succeed, 0 else\n\t */\n\tuint8 readTGA(\tNLMISC::IStream &f);\n\n\n\t/**\n\t * Read a PNG from an IStream.\n\t * PNG pictures can be in 24 or 32 bits\n\t * \\param f IStream (must be a reading stream)\n\t * \\return image depth if succeed, 0 else\n\t */\n\tuint8 readPNG( NLMISC::IStream &f );\n\n\n\t/**\n\t * Read a JPG from an IStream.\n\t * JPG pictures can be in 24\n\t * \\param f IStream (must be a reading stream)\n\t * \\return image depth if succeed, 0 else\n\t */\n\tuint8 readJPG( NLMISC::IStream &f );\n\n\n\t/**\n\t * Change bitmap format\n\t *\n\t * about DXTC1 to DXTC5 :\n\t * Does nothing if the format is not DXTC1\n\t * about alpha encoding :\n\t *\t\talpha0 == alpha1\n\t *\t\tcode(x,y) == 7 for every (x,y)\n\t *\n\t * about luminance to alpha and alpha to luminance :\n\t *      the buffer keeps unchanged\n\t *\n\t */\n\t///@{\n\tbool convertToDXTC5();\n\n\tbool convertToRGBA();\n\tbool luminanceToRGBA();\n\tbool alphaToRGBA();\n\tbool alphaLuminanceToRGBA();\n\n\tbool convertToLuminance();\n\tbool rgbaToLuminance();\n\tbool alphaToLuminance();\n\tbool alphaLuminanceToLuminance();\n\n\tbool convertToAlpha();\n\tbool rgbaToAlpha();\n\tbool luminanceToAlpha();\n\tbool alphaLuminanceToAlpha();\n\n\tbool convertToAlphaLuminance();\n\tbool rgbaToAlphaLuminance();\n\tbool luminanceToAlphaLuminance();\n\tbool alphaToAlphaLuminance();\n\n\t///@}\n\n\t/**\n\t * Decompress bitmap compressed with S3TC DXT1 algorithm.\n\t * \\param alpha if alpha is true there's alpha.\n\t */\n\tbool decompressDXT1(bool alpha);\n\n\t/**\n\t * Decompress bitmap compressed with S3TC DXT3 algorithm.\n\t * \\throw EAllocationFailure : can't allocate memory.\n\t */\n\tbool decompressDXT3();\n\n\n\t/**\n\t * Decompress bitmap compressed with S3TC DXT3 algorithm.\n\t * \\throw EAllocationFailure : can't allocate memory.\n\t */\n\tbool decompressDXT5();\n\n\n\t/**\n\t * Extracting RGBA infos from a 16bits word. (used by S3TC decompression)\n\t * \\param color a 16bits integer\n\t * \\param r a CRGBA\n\t */\n\tstatic void uncompress(uint16 color, NLMISC::CRGBA &);\n\n\n\t/**\n\t * The resample function\n\t * \\param pSrc CRGBA array\n\t * \\param pDest CRGBA array for storing resampled texture\n\t * \\param nSrcWidth original width\n\t * \\param nSrcHeight original height\n\t * \\param nDestWidth width after resample\n\t * \\param nDestHeight height after resample\n\t */\n\tvoid resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,\n\t\t\t\t\t\t\t sint32 nSrcWidth, sint32 nSrcHeight,\n\t\t\t\t\t\t\t sint32 nDestWidth, sint32 nDestHeight);\n\n\t/**\n\t * The FAST resample function : works only when reducing the size by two\n\t * and when the image is square\n\t * \\param pSrc CRGBA array\n\t * \\param pDest CRGBA array for storing resampled texture\n\t * \\param nSrcWidth original width\n\t * \\param nSrcHeight original height\n\t * \\param nDestWidth width after resample\n\t * \\param nDestHeight height after resample\n\t */\n\tvoid resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,\n\t\t\t\t\t\t\t\tsint32 nSrcWidth, sint32 nSrcHeight,\n\t\t\t\t\t\t\t\tsint32 nDestWidth, sint32 nDestHeight);\n\n\n\t/**\n\t * Quadratic interpolator\n\t * \\return the interpolation in (x,y) of the values (xy**)\n\t */\n\tfloat getColorInterp (float x, float y, float xy00, float xy01, float xy10, float xy11) const;\n\n\n\t/// name  DXTC single texel read\n\t//@{\n\t\tstatic CRGBA getDXTCColorFromBlock(const uint8 *block, sint x, sint y);\n\t\tCRGBA getDXTC1Texel(sint x, sint y, uint32 numMipMap) const;\n\t\tCRGBA getDXTC3Texel(sint x, sint y, uint32 numMipMap) const;\n\t\tCRGBA getDXTC5Texel(sint x, sint y, uint32 numMipMap) const;\n\t//@}\n\n\n\tCRGBA getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const;\n\n\n\t// Make a dummy from a bitfield\n\tvoid\tmakeDummyFromBitField(const uint8\tbitmap[1024]);\n\n\t// Flip DXTC\n\tvoid\tflipHDXTCBlockColor(uint8 *bitColor, uint32 w);\n\tvoid\tflipVDXTCBlockColor(uint8 *bitColor, uint32 h);\n\tvoid\tflipHDXTCBlockAlpha3(uint8 *bitColor, uint32 w);\n\tvoid\tflipVDXTCBlockAlpha3(uint8 *bitColor, uint32 h);\n\tvoid\tflipHDXTCBlockAlpha5(uint8 *bitColor, uint32 w);\n\tvoid\tflipVDXTCBlockAlpha5(uint8 *bitColor, uint32 h);\n\tvoid\tflipDXTC(bool vertical);\n\tvoid\tflipDXTCMipMap(bool vertical, uint mm, uint type);\n\npublic:\n\n\tenum TType\n\t{\n\t\tRGBA=0,\n\t\tLuminance,\n\t\tAlpha,\n\t\tAlphaLuminance,\n\t\tDXTC1,\n\t\tDXTC1Alpha,\n\t\tDXTC3,\n\t\tDXTC5,\n\t\tDsDt,\n\t\tModeCount,\n\t\tDonTKnow=0xffffffff\n\t} PixelFormat;\n\n\tstatic const uint32 bitPerPixels[ModeCount];\n\tstatic const uint32 DXTC1HEADER;\n\tstatic const uint32 DXTC3HEADER;\n\tstatic const uint32 DXTC5HEADER;\n\n\t// don't forget to update operator=() and swap() if adding a data member\n\n\tCBitmap()\n\t{\n\t\t_MipMapCount = 1;\n\t\t_Width = 0;\n\t\t_Height = 0;\n\t\tPixelFormat = RGBA;\n\t\t_LoadGrayscaleAsAlpha = true;\n\t}\n\n\tvirtual ~CBitmap() { }\n\n\t// swap 2 bitmaps contents\n\tvoid\tswap(CBitmap &other);\n\n\t/**\n\t * Read a bitmap(TGA, JPEG, PNG or DDS) from an IStream.\n\t * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5), PNG, JPEG and\n\t * uncompressed TGA (24 and 32 bits).\n\t * \\param IStream The stream must be in reading mode.\n\t * \\param mipMapSkip if the file is a DDS with mipMap. N=mipMapSkip mipmaps are skipped.\n\t * \\return image depth (24 or 32), or 0 if load failed\n\t * \\throw ESeekFailed : seek has failed\n\t */\n\tuint8\tload(NLMISC::IStream &f, uint mipMapSkip=0);\n\n\n\t/**\n\t * Determinate the bitmap size from a bitmap(TGA or DDS) from an IStream. load just header of the file.\n\t * Bitmap supported are DDS (DXTC1, DXTC1 with Alpha, DXTC3, DXTC5), PNG, JPEG and\n\t * uncompressed TGA (24 and 32 bits).\n\t * NB: at the end, f is seeked to begin.\n\t * \\param IStream The stream must be in reading mode.\n\t * \\param width the width of the image. 0 if fails.\n\t * \\param height the height of the image. 0 if fails.\n\t * \\throw ESeekFailed : seek has failed\n\t */\n\tstatic void\t\tloadSize(NLMISC::IStream &f, uint32 &width, uint32 &height);\n\n\n\t/** same than other loadSize(), but with a pathName.\n\t * \\see loadSize()\n\t */\n\tstatic void\t\tloadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight);\n\n\n\t/**\n\t * Make a dummy \"?\" texture. Useful for file not found. Mode is rgba.\n\t */\n\tvoid\tmakeDummy();\n\n\n\t/**\n\t * Make a dummy \"2\" texture. Useful for file not power of 2. Mode is rgba.\n\t */\n\tvoid\tmakeNonPowerOf2Dummy();\n\n\t/**\n\t * Return the pixels buffer of the image, or of one of its mipmap.\n\t * Return a reference of an array in pixel format get with getPixelFormat().\n\t * \\return CObjectVector<uint8>& RGBA pixels\n\t */\n\t///@{\n\tCObjectVector<uint8>& getPixels(uint32 numMipMap = 0)\n\t{\n\t\t//nlassert (numMipMap<=_MipMapCount);\n\t\treturn _Data[numMipMap];\n\t}\n\tconst CObjectVector<uint8>& getPixels(uint32 numMipMap = 0) const\n\t{\n\t\t//nlassert (numMipMap<=_MipMapCount);\n\t\treturn _Data[numMipMap];\n\t}\n\t/** Gain ownership of this texture datas. As a result, the bitmap is reseted (put in the same state than when ctor is called, e.g a single mipmap with null size)\n\t  * The CObjectVector objects that contains the bitmap (one per mipmap) datas are 'swapped' with those in the array  provided by the caller.\n\t  * NB : The user must provide at least min(getMipMapCount(), maxMipMapCount) entries in the array\n\t  * \\param mipmapArray Array of mipmap that receive the bitmap datas\n\t  * \\param maxMipMapCount Max number of mipmap to be copied in the destination array.\n\t  */\n\tvoid unattachPixels(CObjectVector<uint8> *mipmapDestArray, uint maxMipMapCount = MAX_MIPMAP);\n\n\t///@}\n\n\n\t/**\n\t * Convert bitmap to another type\n\t * conversion to rgba always work. No-op if already rgba.\n\t * \\param type new type for the bitmap\n\t * \\return true if conversion succeeded, false else\n\t */\n\tbool convertToType (TType type);\n\n\n\n\t/**\n\t * Return the format of pixels stored at the present time in the object buffer.\n\t * \\return Pixel format (rgba luminance alpha alphaLuminance dxtc1 dxtc1Alpha dxtc3 dxtc5)\n\t */\n\tTType getPixelFormat() const\n\t{\n\t\treturn PixelFormat;\n\t}\n\n\n\t/**\n\t * Return the image width, or a mipmap width.\n\t * \\param mipMap mipmap level\n\t * \\return image width (0 if mipmap not found)\n\t */\n\tvirtual uint32 getWidth(uint32 numMipMap = 0) const;\n\n\n\t/**\n\t * Return the image height, or a mipmap height.\n\t * \\param mipMap mipmap level\n\t * \\return image height (0 if mipmap not found)\n\t */\n\tvirtual uint32 getHeight(uint32 numMipMap = 0) const;\n\n\n\t/**\n\t * Return the size (in pixels) of the image: <=> getHeight()*getWidth().\n\t * \\param mipMap mipmap level\n\t * \\return image size (0 if mipmap not found)\n\t */\n\tuint32 getSize(uint32 numMipMap = 0) const;\n\n\n\t/**\n\t * Return the number of mipmaps. Level0 is a mipmap...\n\t * \\return number of mipmaps. 0 if no image at all. 1 if no mipmaping (for the base level).\n\t */\n\tuint32 getMipMapCount() const\n\t{\n\t\treturn _MipMapCount;\n\t}\n\n\t// Compute the number of mipmap needed for that bitmap (independently from the current number of mipmaps that have been set)\n\tuint32 computeNeededMipMapCount() const;\n\n\t/**\n\t * Rotate a bitmap in CCW mode.\n\t *\n\t * \\see releaseMipMaps().\n\t */\n\tvoid rotateCCW();\n\n\t/**\n\t * Build the mipmaps of the bitmap if they don't exist.\n\t * Work only in RGBA mode...\n\t * \\see releaseMipMaps().\n\t */\n\tvoid buildMipMaps();\n\n\t/**\n\t * Release the mipmaps of the bitmap if they exist.\n\t * Work for any mode.\n\t * \\see buildMipMaps().\n\t */\n\tvoid releaseMipMaps();\n\n\t/**\n\t * Reset the buffer. Mipmaps are deleted and bitmap is not valid anymore.\n\t *\n\t * \\param type is the new type used for this texture\n\t */\n\tvoid reset(TType type=RGBA);\n\n\n\t/**\n\t * Resample the bitmap. If mipmaps exist they are deleted, then rebuilt\n\t * after resampling.\n\t * \\param nNewWidth width after resample\n\t * \\param nNewHeight height after resample\n\t */\n\tvoid resample (sint32 nNewWidth, sint32 nNewHeight);\n\n\n\t/**\n\t * Resize the bitmap. If mipmaps exist they are deleted and not rebuilt.\n\t * This is not a crop. Pixels are lost after resize.\n\t *\n\t * \\param nNewWidth width after resize\n\t * \\param nNewHeight height after resize\n\t * \\param newType is the new type of the bitmap. If don_t_know, keep the same pixel format that before.\n\t * \\param resetTo0 by default the vector are filled by 0. set false to gain performances.\n\t */\n\tvoid resize (sint32 nNewWidth, sint32 nNewHeight, TType newType=DonTKnow, bool resetTo0= true);\n\n\n\t/**  ADVANCED USE\n\t * Resize a single mipmap level. resize() should have been called before.\n\t * This is not a crop. Pixels are lost after resize.\n\t *\tNo validity check is made. It is the user responsabitility fo setup correct mipmap size.\n\t *\n\t * \\param numMipMap id of the mipmap\n\t * \\param nNewWidth width after resize\n\t * \\param nNewHeight height after resize\n\t * \\param resetTo0 by default the vector are filled by 0. set false to gain performances.\n\t */\n\tvoid resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0= true);\n\n\n\t/**  ADVANCED USE\n\t *\tTo use in conjunction with resizeMipMap. Setup the correct total number of mipmap\n\t *\tNo validity check is made. It is the user responsabitility fo setup correct mipmap count.\n\t */\n\tvoid setMipMapCount(uint32 mmc);\n\n\n\t/**\n\t * Write a TGA (24 or 32 bits) from the object pixels buffer.\n\t * If the current pixel format is not rgba then the method does nothing\n\t * If the pixel format is Alpha then we save in 8 bpp\n\t * \\param f IStream (must be a reading stream)\n\t * \\param d depth : 8 or 16 or 24 or 32 (0 for automatic)\n\t * \\param upsideDown if true, the bitmap will be saved with the upside down\n\t * \\return true if succeed, false else\n\t */\n\tbool writeTGA(NLMISC::IStream &f, uint32 d=0, bool upsideDown = false);\n\n\t/**\n\t * Write a PNG (24 or 32 bits) from the object pixels buffer.\n\t * If the current pixel format is not rgba then the method does nothing\n\t * If the pixel format is Alpha then we save in 8 bpp\n\t * \\param f IStream (must be a reading stream)\n\t * \\param d depth : 8 or 16 or 24 or 32 (0 for automatic)\n\t * \\return true if succeed, false else\n\t */\n\tbool writePNG(NLMISC::IStream &f, uint32 d=0);\n\n\t/**\n\t * Write a JPG from the object pixels buffer.\n\t * If the current pixel format is not rgba then the method does nothing\n\t * If the pixel format is Alpha then we save in 8 bpp\n\t * \\param f IStream (must be a reading stream)\n\t * \\param quality 0=very bad quality 100=best quality\n\t * \\return true if succeed, false else\n\t */\n\tbool writeJPG(NLMISC::IStream &f, uint8 quality = 80);\n\n\t/**\n\t * Tell the bitmap to load grayscale bitmap as alpha or luminance format.\n\t *\n\t * \\param loadAsAlpha is true to load grayscale bitmaps as alpha. false to load grayscale bitmaps as luminance.\n\t * default value is true.\n\t */\n\tvoid loadGrayscaleAsAlpha (bool loadAsAlpha)\n\t{\n\t\t_LoadGrayscaleAsAlpha=loadAsAlpha;\n\t}\n\n\n\t/**\n\t * Tell if the bitmap loads grayscale bitmap as alpha or luminance format.\n\t *\n\t * \\return true if the bitmap loads grayscale bitmaps as alpha, false if it loads grayscale bitmaps as luminance.\n\t */\n\tbool isGrayscaleAsAlpha () const\n\t{\n\t\treturn _LoadGrayscaleAsAlpha;\n\t}\n\n\n\t/**\n\t * Perform a simple blit from the source to this bitmap at the (x, y) pos\n\t * The dimension of the original bitmap are preserved\n\t * For now, this texture and the source must have the same format\n\t * With DXTC format, the dest coordinates must be a multiple of 4\n\t * mipmap are not rebuild when present\n\t * IMPORTANT : copy to self is not handled correctly\n\t * \\return true if the params were corrects and if the blit occurs. In debug build there's an assertion\n\t */\n\tbool blit(const CBitmap *src, sint32 x, sint32 y) ;\n\t/**\n\t * Extended version of blit. The destinaion of the blit is 'this' bitmap\n\t * Source and dest rect are clamped as necessary.\n\t * For now, only RGBA is uspported (an asertion occurs otherwise)\n\t * mipmap are not updated.\n\t * IMPORTANT : copy to self is not handled correctly\n\t */\n\tvoid blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY);\n\n\n\t/**\n\t * Get the color in the bitmap for the first mipmap\n\t * The mipmaps must be built. If not just return the bilinear at the given point.\n\t * NB: coordinates are clamped.\n\t * \\param tiled If false coordinate are clamped, else the bitmap is considered to tile\n\t */\n\tCRGBAF getColor (float x, float y) const;\n\t// Get Color with optional tiling on axis\n\tCRGBAF getColor (float x, float y, bool tileU, bool tileV) const;\n\n\n\n\n\n\t/** Get the pixel at the given coorrdinate.\n\t  * Works in RGBA and DXTC modes.\n\t  * Outside of the bitmap it returns Black (or if mipmap is not found)\n\t  */\n\tCRGBA  getPixelColor(sint x, sint y, uint32 numMipMap = 0) const;\n\t/**\n\t * Horizontal flip (all the columns are flipped)\n\t * Works only with RGBA, and DXTC formats (only if w/h is a power of 2)\n\t */\n\tvoid flipH();\n\n\n\t/**\n\t * Vertical flip (all the rows are flipped)\n\t * Works only with RGBA, and DXTC formats (only if w/h is a power of 2)\n\t */\n\tvoid flipV();\n\n\t/**\n\t * Rotation of the bitmap of 90 degree in clockwise\n\t */\n\tvoid rot90CW();\n\n\t/**\n\t * Rotation of the bitmap of 90 degree in counter clockwise\n\t */\n\tvoid rot90CCW();\n\n\t/** Set this bitmap as the result of the blend bewteen 2 bitmap\n\t  * REQUIRE : - Bm0 and Bm1 should have the same size.\n\t  *           - Both bitmap should be convertible to RGBA pixel format.\n\t  * The result is a RGBA bitmap.\n\t  * NB: this just works with the first mipmaps\n\t  * \\param factor The blend factor. 0 means the result is equal to Bm0, 256 means the result is equal to Bm1\n\t  * \\param inputBitmapIsMutable when true, bitmap can be converted in place when needed (no copy done)\n\t  */\n\tvoid blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable = false);\n\n\tvoid getData(uint8*& extractData);\n\n\tvoid getDibData(uint8*& extractData);\n\n\tCBitmap& operator= (const CBitmap& from)\n\t{\n\t\tif (&from == this)\n\t\t\treturn *this;\n\t\tfor (uint i=0; i!=MAX_MIPMAP; ++i)\n\t\t{\n\t\t\t_Data[i] = from._Data[i]; // requires more than a surface copy\n\t\t}\n\t\t_MipMapCount = from._MipMapCount;\n\t\t_LoadGrayscaleAsAlpha = from._LoadGrayscaleAsAlpha;\n\t\t_Width = from._Width;\n\t\t_Height = from._Height;\n\t\tPixelFormat = from.PixelFormat;\n\t\treturn *this;\n\t}\n};\n\n} // NLMISC\n\n\n#endif // NL_BITMAP_H\n\n/* End of bitmap.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/block_memory.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BLOCK_MEMORY_H\n#define NL_BLOCK_MEMORY_H\n\n#include \"types_nl.h\"\n#include <list>\n#include <vector>\n#include \"debug.h\"\n#include \"mutex.h\"\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/// See CBlockMemory::Purge\nextern\tbool\t\tNL3D_BlockMemoryAssertOnPurge;\t// =true.\n\n\n// ***************************************************************************\n/**\n * Block memory allocation\n *\n * This memory manager is a fast memory allocator, doing same thing as new/delete. It works by blocks. Blocks are always\n * allocated, never deleted.  Allocation/free are in O(1).\n *\n * Elements with sizeof(T)<sizeof(void*) should not be used with this allocator, because\n * sizeEltInMemory= max(sizeof(T),sizeof(void*)).\n *\n * free() check invalid ptr in debug only, for extra cost of 8 octets per element.\n *\n * NB: if template parameter __ctor_dtor__ is false, then ctor and dtor are not called when an element is allocate()-ed\n *\tor deallocate()-ed.\n *\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate<class T, bool __ctor_dtor__= true >\nclass CBlockMemory\n{\npublic:\n\n\t/// Constructor\n\tCBlockMemory(uint blockSize= 16)\n\t{\n\t\tnlassert(blockSize);\n\t\t_BlockSize= blockSize;\n\t\t_EltSize= std::max((uint)sizeof(T), (uint)sizeof(void*));\n\t\t_NextFreeElt= NULL;\n\t\t_NAllocatedElts= 0;\n\t}\n\t// just copy setup from other blockMemory, don't copy data!\n\tCBlockMemory(const CBlockMemory<T, __ctor_dtor__> &other)\n\t{\n\t\t_BlockSize= other._BlockSize;\n\t\t// if other block is rebinded, don't copy its rebinded size.\n\t\t_EltSize= (uint)std::max(sizeof(T), sizeof(void*));\n\t\t// No elts allocated\n\t\t_NextFreeElt= NULL;\n\t\t_NAllocatedElts= 0;\n\t}\n\t/** purge()\n\t */\n\t~CBlockMemory()\n\t{\n\t\tpurge();\n\t}\n\n\n\t/// allocate an element. ctor is called.\n\tT*\t\t\t\tallocate()\n\t{\n\t\t_Mutex.enter();\n\n\t\t// if not enough memory, aloc a block.\n\t\tif(!_NextFreeElt)\n\t\t{\n\t\t\t_Blocks.push_front(CBlock());\n\t\t\tbuildBlock(*_Blocks.begin());\n\t\t\t// new free elt points to the beginning of this block.\n\t\t\t_NextFreeElt= (*_Blocks.begin()).Data;\n#ifdef NL_DEBUG\n\t\t\t// if debug, must decal for begin check.\n\t\t\t_NextFreeElt= (uint32*)_NextFreeElt + 1;\n#endif\n\t\t}\n\n\t\t// choose next free elt.\n\t\tnlassert(_NextFreeElt);\n\t\tT*\t\tret= (T*)_NextFreeElt;\n\n\t\t// update _NextFreeElt, so it points to the next free element.\n\t\t_NextFreeElt= *(void**)_NextFreeElt;\n\n\t\t// construct the allocated element.\n\t\tif( __ctor_dtor__ )\n\t\t\tnew (ret) T;\n\n\t\t// some simple Check.\n#ifdef NL_DEBUG\n\t\tuint32\t*checkStart= (uint32*)(void*)ret-1;\n\t\tuint32\t*checkEnd  = (uint32*)((uint8*)(void*)ret+_EltSize);\n\t\tnlassert( *checkStart == CheckDeletedIdent);\n\t\tnlassert( *checkEnd   == CheckDeletedIdent);\n\t\t// if ok, mark this element as allocated.\n\t\t*checkStart= CheckAllocatedIdent;\n\t\t*checkEnd  = CheckAllocatedIdent;\n#endif\n\n\t\t_NAllocatedElts++;\n\n\t\t_Mutex.leave();\n\n\t\treturn ret;\n\t}\n\n\t/// delete an element allocated with this manager. dtor is called. NULL is tested.\n\tvoid\t\t\tfree(T* ptr)\n\t{\n\t\tif(!ptr)\n\t\t\treturn;\n\n\t\t_Mutex.enter();\n\n\t\t// some simple Check.\n\t\tnlassert(_NAllocatedElts>0);\n#ifdef NL_DEBUG\n\t\tuint32\t*checkStart= (uint32*)(void*)ptr-1;\n\t\tuint32\t*checkEnd  = (uint32*)((uint8*)(void*)ptr+_EltSize);\n\t\tnlassert( *checkStart == CheckAllocatedIdent);\n\t\tnlassert( *checkEnd   == CheckAllocatedIdent);\n\t\t// if ok, mark this element as deleted.\n\t\t*checkStart = *checkEnd = uint32(CheckDeletedIdent);\n#endif\n\n\t\t// destruct the element.\n\t\tif( __ctor_dtor__ )\n\t\t\tptr->~T();\n\n\t\t// just append this freed element to the list.\n\t\t*(void**)ptr= _NextFreeElt;\n\t\t_NextFreeElt= (void*) ptr;\n\n\t\t_NAllocatedElts--;\n\n\t\t_Mutex.leave();\n\t}\n\n\n\t/** delete all blocks, freeing all memory. It is an error to purge() or delete a CBlockMemory, while elements\n\t * still remains!! You must free your elements with free().\n\t *\tNB: you can disable this assert if you set NL3D_BlockMemoryAssertOnPurge to false\n\t *\t(good to quit a program quickly without uninitialize).\n\t */\n\tvoid\tpurge ()\n\t{\n\t\t_Mutex.enter();\n\n\t\tif(NL3D_BlockMemoryAssertOnPurge)\n\t\t{\n\t\t\tnlassert(_NAllocatedElts==0);\n\t\t}\n\n\t\twhile(_Blocks.begin()!=_Blocks.end())\n\t\t{\n\t\t\treleaseBlock(*_Blocks.begin());\n\t\t\t_Blocks.erase(_Blocks.begin());\n\t\t}\n\n\t\t_NextFreeElt= NULL;\n\t\t_NAllocatedElts= 0;\n\n\t\t_Mutex.leave();\n\t}\n\n\n// ********************\npublic:\n\n\t// This is to be used with CSTLBlockAllocator only!!! It changes the size of an element!!\n\tvoid\t\t__stl_alloc_changeEltSize(uint eltSize)\n\t{\n\t\t_Mutex.enter();\n\n\t\t// must not be used with object ctor/dtor behavior.\n\t\tnlassert(__ctor_dtor__ == false);\n\t\t// format size.\n\t\teltSize= std::max((uint)eltSize, (uint)sizeof(void*));\n\t\t// if not the same size as before\n\t\tif(_EltSize!= eltSize)\n\t\t{\n\t\t\t// verify that rebind is made before any allocation!!\n\t\t\tnlassert(_Blocks.empty());\n\t\t\t// change the size.\n\t\t\t_EltSize= eltSize;\n\t\t}\n\n\t\t_Mutex.leave();\n\t};\n\t// This is to be used with CSTLBlockAllocator only!!!\n\tuint\t\t__stl_alloc_getEltSize() const\n\t{\n\t\treturn _EltSize;\n\t}\n\n\nprivate:\n\t/// size of a block.\n\tuint\t\t_BlockSize;\n\t/// size of an element in the block.\n\tuint\t\t_EltSize;\n\t/// number of elements allocated.\n\tsint\t\t_NAllocatedElts;\n\t/// next free element.\n\tvoid\t\t*_NextFreeElt;\n\t/// Must be ThreadSafe (eg: important for 3D PointLight and list of transform)\n\tCFastMutex\t_Mutex;\n\n\n\t/// a block.\n\tstruct\tCBlock\n\t{\n\t\t/// The data allocated.\n\t\tvoid\t\t*Data;\n\t};\n\n\t/// list of blocks.\n\tstd::list<CBlock>\t_Blocks;\n\n\n\t/// For debug only, check ident.\n\tenum  TCheckIdent\t{ CheckAllocatedIdent= 0x01234567, CheckDeletedIdent= 0x89ABCDEF };\n\n\nprivate:\n\tvoid\t\tbuildBlock(CBlock &block)\n\t{\n\t\tuint\ti;\n\t\tuint32\tnodeSize= _EltSize;\n#ifdef NL_DEBUG\n\t\t// must allocate more size for mem checks in debug.\n\t\tnodeSize+= 2*sizeof(uint32);\n#endif\n\n\t\t// allocate.\n\t\tblock.Data = (void*)new uint8 [_BlockSize * nodeSize];\n\n\t\t// by default, all elements are not allocated, build the list of free elements.\n\t\tvoid\t*ptr= block.Data;\n#ifdef NL_DEBUG\n\t\t// if debug, must decal for begin check.\n\t\tptr= (uint32*)ptr + 1;\n#endif\n\t\tfor(i=0; i<_BlockSize-1; i++)\n\t\t{\n\t\t\t// next elt.\n\t\t\tvoid\t*next= (uint8*)ptr + nodeSize;\n\t\t\t// points to the next element in this array.\n\t\t\t*(void**)ptr= next;\n\t\t\t// next.\n\t\t\tptr= next;\n\t\t}\n\t\t// last element points to NULL.\n\t\t*(void**)ptr= NULL;\n\n\n\t\t// If debug, must init all check values to CheckDeletedIdent.\n#ifdef NL_DEBUG\n\t\tptr= block.Data;\n\t\t// must decal for begin check.\n\t\tptr= (uint32*)ptr + 1;\n\t\t// fill all nodes.\n\t\tfor(i=0; i<_BlockSize; i++)\n\t\t{\n\t\t\tuint32\t*checkStart= (uint32*)ptr-1;\n\t\t\tuint32\t*checkEnd  = (uint32*)((uint8*)ptr+_EltSize);\n\t\t\t// mark this element as deleted.\n\t\t\t*checkStart = *checkEnd = uint32(CheckDeletedIdent);\n\n\t\t\t// next elt.\n\t\t\tptr= (uint8*)ptr + nodeSize;\n\t\t}\n#endif\n\n\t}\n\tvoid\t\treleaseBlock(CBlock &block)\n\t{\n\t\tdelete [] ((uint8*)block.Data);\n\t}\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_BLOCK_MEMORY_H\n\n/* End of block_memory.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/bsphere.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BSPHERE_H\n#define NL_BSPHERE_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n#include \"plane.h\"\n#include \"matrix.h\"\n\n\nnamespace NLMISC\n{\n\n\n/**\n * A bounding Sphere.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CBSphere\n{\npublic:\n\tCVector\t\t\tCenter;\n\tfloat\t\t\tRadius;\n\n\t/// Empty Constructor.\n\tCBSphere() {}\n\t/// Constructor.\n\tCBSphere(const CVector & center, float radius) : Center(center), Radius(radius) {}\n\n\n\t/// \\name transform\n\t// @{\n\n\t/** compute res= mat * this. NB: radius is maximized, taking max of the 3 axis of the matrix.\n\t * NB: this may be false if the matrix is not orthogonal...\n\t */\n\tvoid\tapplyTransform(const CMatrix &mat, CBSphere &res);\n\n\t// @}\n\n\t/// \\name Clip\n\t// @{\n\t/// Is the bbox partially in front of the plane??  p MUST be normalized.\n\tbool\tclipFront(const CPlane &p) const;\n\t/// Is the bbox partially in back of the plane??  p MUST be normalized.\n\tbool\tclipBack(const CPlane &p) const;\n\t// @}\n\n\t/// Does the sphere include this point?\n\tbool\tinclude(const CVector &p) const;\n\t/// Does the sphere include TOTALY this sphere?\n\tbool\tinclude(const CBSphere &s) const;\n\t/// Does the sphere intersect the other?\n\tbool\tintersect(const CBSphere &s) const;\n\n\t/// Build the union of the 2 sphere ans set to *this. work if this==s1 || this==s2.\n\tvoid\tsetUnion(const CBSphere &sa, const CBSphere &sb);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_BSPHERE_H\n\n/* End of bsphere.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/buf_fifo.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_FIFO_H\n#define NL_BUF_FIFO_H\n\n#include \"types_nl.h\"\n\n#include <vector>\n\n#include \"time_nl.h\"\n#include \"mem_stream.h\"\n#include \"command.h\"\n\n\nnamespace NLMISC {\n\n#undef BUFFIFO_TRACK_ALL_BUFFERS\n\n\n/**\n * This class is a dynamic size FIFO that contains variable size uint8 buffer.\n * It's used in the layer1 network for storing temporary messages.\n * You can resize the internal FIFO buffer if you know the average size\n * of data you'll put in it. It have the same behavior as STL so if the\n * buffer is full the size will be automatically increase by 2.\n *\n * TODO: Add a method getMsgNb() that will return the number of messages in queue.\n * For acceptable performance, it would need to store the current number instead\n * of browsing the blocks.\n *\n * \\code\n \tCBufFIFO fifo;\n\tfifo.resize(10000);\n\tvector<uint8> vec;\n\tvec.resize(rand()%256);\n\tmemset (&(vec[0]), '-', vec.size());\n\t// push the vector\n\tfifo.push(vec);\n\t// display the fifo\n\tfifo.display();\n\tvector<uint8> vec2;\n\t// get the vector\n\tfifo.pop(vec2);\n * \\endcode\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CBufFIFO\n{\npublic:\n\n\tCBufFIFO ();\n\t~CBufFIFO ();\n\n\t/// Push 'buffer' in the head of the FIFO\n\tvoid\t push (const std::vector<uint8> &buffer) { push (&buffer[0], (uint32)buffer.size()); }\n\n\tvoid\t push (const NLMISC::CMemStream &buffer) { push (buffer.buffer(), buffer.length()); }\n\n\tvoid\t push (const uint8 *buffer, uint32 size);\n\n\t/// Concate and push 'buffer1' and buffer2 in the head of the FIFO. The goal is to avoid a copy\n\tvoid\t push (const std::vector<uint8> &buffer1, const std::vector<uint8> &buffer2);\n\n\t/// Get the buffer in the tail of the FIFO and put it in 'buffer'\n\tvoid\t front (std::vector<uint8> &buffer);\n\n\tvoid\t front (NLMISC::CMemStream &buffer);\n\n\tvoid\t front (uint8 *&buffer, uint32 &size);\n\n\t/// This function returns the last byte of the front message\n\t/// It is used by the network to know a value quickly without doing front()\n\tuint8\t frontLast ();\n\n\n\t/// Pop the buffer in the tail of the FIFO\n\tvoid\t pop ();\n\n\t/// Set the size of the FIFO buffer in byte\n\tvoid\t resize (uint32 size);\n\n\t/// Return true if the FIFO is empty\n\tbool\t empty () { return _Empty; }\n\n\n\t/// Erase the FIFO\n\tvoid\t clear ();\n\n\t/// Returns the size of the FIFO\n\tuint32\t size ();\n\n\t/// display the FIFO to stdout (used to debug the FIFO)\n\tvoid\t display ();\n\n\t/// display the FIFO statistics (speed, nbcall, etc...) to stdout\n\tvoid\t displayStats (CLog *log = InfoLog);\n\nprivate:\n\n\ttypedef uint32 TFifoSize;\n\n\t// pointer to the big buffer\n\tuint8\t*_Buffer;\n\t// size of the big buffer\n\tuint32\t _BufferSize;\n\n\t// true if the bufffer is empty\n\tbool\t _Empty;\n\n\t// head of the FIFO\n\tuint8\t*_Head;\n\t// tail of the FIFO\n\tuint8\t*_Tail;\n\t// pointer to the rewinder of the FIFO\n\tuint8\t*_Rewinder;\n\n\t// return true if we can put size bytes on the buffer\n\t// return false if we have to resize\n\tbool\t canFit (uint32 size);\n\n\n\t// statistics of the FIFO\n\tuint32 _BiggestBlock;\n\tuint32 _SmallestBlock;\n\tuint32 _BiggestBuffer;\n\tuint32 _SmallestBuffer;\n\tuint32 _Pushed ;\n\tuint32 _Fronted;\n\tuint32 _Resized;\n\tTTicks _PushedTime;\n\tTTicks _FrontedTime;\n\tTTicks _ResizedTime;\n\n#ifdef BUFFIFO_TRACK_ALL_BUFFERS\n\ttypedef std::set<CBufFIFO*> TAllBuffers;\n\t// All the buffer for debug output\n\tstatic TAllBuffers\t\t_AllBuffers; // WARNING: not mutexed, can produce some crashes!\n#endif\n\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(misc, dumpAllBuffers);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_BUF_FIFO_H\n\n/* End of buf_fifo.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/callback.h",
    "content": "/*\n\nCopyright (c) 2009-2014, Jan BOON\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n*/\n\n#ifndef NLMISC_CALLBACK_H\n#define NLMISC_CALLBACK_H\n#include <nel/misc/types_nl.h>\n\n// STL includes\n\n// NeL includes\n#include <nel/misc/debug.h>\n\n// Project includes\n\nnamespace NLMISC {\n\n#define NLMISC_CALLBACK_TEMPLATE \\\n/** \\\n * \\brief NLMISC_CALLBACK_ARGS_CLASS \\\n * \\date 2009-03-03 18:09GMT \\\n * \\author Jan BOON \\\n * Callback template \\\n */ \\\ntemplate<typename TReturn NLMISC_CALLBACK_ARGS_TYPENAME> \\\nclass NLMISC_CALLBACK_ARGS_CLASS \\\n{ \\\n\t/* Very simple reference counting callback base */ \\\n\tclass CCallbackBase \\\n\t{ \\\n\tpublic: \\\n\t\tCCallbackBase() : m_RefCount(0) \\\n\t\t{ \\\n\t\t\t \\\n\t\t} \\\n\t\t \\\n\t\tvirtual ~CCallbackBase() \\\n\t\t{ \\\n\t\t\tnlassert(!m_RefCount); \\\n\t\t} \\\n\t\t \\\n\t\tvoid refAdd() \\\n\t\t{ \\\n\t\t\t++m_RefCount; \\\n\t\t} \\\n\t\t \\\n\t\tvoid refRemove() \\\n\t\t{ \\\n\t\t\t--m_RefCount; \\\n\t\t\tif (!m_RefCount) \\\n\t\t\t\tdelete this; \\\n\t\t} \\\n\t\t \\\n\t\tvirtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) = 0; \\\n\t\t \\\n\t\tvirtual bool equals(const CCallbackBase *callbackBase) = 0; \\\n\t\t \\\n\t\t/* disable copy */ \\\n\t\tCCallbackBase(const CCallbackBase &); \\\n\t\tCCallbackBase &operator=(const CCallbackBase &); \\\n\t\t \\\n\tprivate: \\\n\t\tuint m_RefCount; \\\n\t}; \\\n\t \\\n\ttypedef TReturn TCallbackFunction(NLMISC_CALLBACK_ARGS_DECL); \\\n\tclass CCallbackFunction : public CCallbackBase \\\n\t{ \\\n\tpublic: \\\n\t\tCCallbackFunction(TCallbackFunction *callbackFunction) : m_CallbackFunction(callbackFunction) \\\n\t\t{ \\\n\t\t\tnlassert(m_CallbackFunction); \\\n\t\t} \\\n\t\t \\\n\t\tvirtual ~CCallbackFunction() \\\n\t\t{ \\\n\t\t\tm_CallbackFunction = NULL; \\\n\t\t} \\\n\t\t \\\n\t\tvirtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \\\n\t\t{ \\\n\t\t\treturn m_CallbackFunction(NLMISC_CALLBACK_ARGS_IMPL); \\\n\t\t} \\\n\t\t \\\n\t\tvirtual bool equals(const CCallbackBase *callbackBase) \\\n\t\t{ \\\n\t\t\tconst CCallbackFunction *callbackFunction = \\\n\t\t\t\tdynamic_cast<const CCallbackFunction *>(callbackBase); \\\n\t\t\tif (!callbackFunction) return false; \\\n\t\t\treturn m_CallbackFunction == callbackFunction->m_CallbackFunction; \\\n\t\t} \\\n\t\t \\\n\tprivate: \\\n\t\tTCallbackFunction *m_CallbackFunction; \\\n\t}; \\\n\t \\\n\ttemplate<typename TClass> \\\n\tclass CCallbackMethod : public CCallbackBase \\\n\t{ \\\n\t\ttypedef TReturn (TClass::*TCallbackMethod)(NLMISC_CALLBACK_ARGS_DECL); \\\n\tpublic: \\\n\t\tCCallbackMethod(TClass *callbackObject, TCallbackMethod callbackMethod) : m_CallbackObject(callbackObject), m_CallbackMethod(callbackMethod) \\\n\t\t{ \\\n\t\t\tnlassert(m_CallbackObject); \\\n\t\t\tnlassert(m_CallbackMethod); \\\n\t\t} \\\n\t\t \\\n\t\tvirtual ~CCallbackMethod() \\\n\t\t{ \\\n\t\t\tm_CallbackObject = NULL; \\\n\t\t\tm_CallbackMethod = NULL; \\\n\t\t} \\\n\t\t \\\n\t\tvirtual TReturn callback(NLMISC_CALLBACK_ARGS_DECL) \\\n\t\t{ \\\n\t\t\treturn (m_CallbackObject->*m_CallbackMethod)(NLMISC_CALLBACK_ARGS_IMPL); \\\n\t\t} \\\n\t\t \\\n\t\tvirtual bool equals(const CCallbackBase *callbackBase) \\\n\t\t{ \\\n\t\t\tconst CCallbackMethod *callbackMethod = \\\n\t\t\t\tdynamic_cast<const CCallbackMethod *>(callbackBase); \\\n\t\t\tif (!callbackMethod) return false; \\\n\t\t\treturn m_CallbackObject == callbackMethod->m_CallbackObject \\\n\t\t\t\t&& m_CallbackMethod == callbackMethod->m_CallbackMethod; \\\n\t\t} \\\n\t\t \\\n\tprivate: \\\n\t\tTClass *m_CallbackObject; \\\n\t\tTCallbackMethod m_CallbackMethod; \\\n\t}; \\\n\t \\\npublic: \\\n\tCCallback() : m_CallbackBase(NULL) \\\n\t{ \\\n\t\t \\\n\t} \\\n\t \\\n\tCCallback(TCallbackFunction *callbackFunction) : m_CallbackBase(new CCallbackFunction(callbackFunction)) \\\n\t{ \\\n\t\tnlassert(m_CallbackBase); \\\n\t\tm_CallbackBase->refAdd(); \\\n\t} \\\n\t \\\n\ttemplate<typename TClass> \\\n\tCCallback(TClass *callbackObject, TReturn (TClass::*callbackMethod)(NLMISC_CALLBACK_ARGS_DECL)) : m_CallbackBase(new CCallbackMethod<TClass>(callbackObject, callbackMethod)) \\\n\t{ \\\n\t\tnlassert(m_CallbackBase); \\\n\t\tm_CallbackBase->refAdd(); \\\n\t} \\\n\t \\\n\tCCallback(const CCallback &callback) \\\n\t{ \\\n\t\tm_CallbackBase = callback.m_CallbackBase; \\\n\t\tif (m_CallbackBase) \\\n\t\t\tm_CallbackBase->refAdd(); \\\n\t} \\\n\t \\\n\tCCallback &operator=(const CCallback &callback) \\\n\t{ \\\n\t\tif (m_CallbackBase != callback.m_CallbackBase) \\\n\t\t{ \\\n\t\t\tif (m_CallbackBase) \\\n\t\t\t\tm_CallbackBase->refRemove(); \\\n\t\t\tm_CallbackBase = callback.m_CallbackBase; \\\n\t\t\tif (m_CallbackBase) \\\n\t\t\t\tm_CallbackBase->refAdd(); \\\n\t\t} \\\n\t\treturn *this; \\\n\t} \\\n\t \\\n\t~CCallback() \\\n\t{ \\\n\t\tif (m_CallbackBase) \\\n\t\t{ \\\n\t\t\tm_CallbackBase->refRemove(); \\\n\t\t\tm_CallbackBase = NULL; \\\n\t\t} \\\n\t} \\\n\t \\\n\tTReturn callback(NLMISC_CALLBACK_ARGS_DECL) \\\n\t{ \\\n\t\tnlassert(m_CallbackBase); \\\n\t\treturn m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \\\n\t} \\\n\t \\\n\tTReturn operator()(NLMISC_CALLBACK_ARGS_DECL) \\\n\t{ \\\n\t\tnlassert(m_CallbackBase); \\\n\t\treturn m_CallbackBase->callback(NLMISC_CALLBACK_ARGS_IMPL); \\\n\t} \\\n\t \\\n\tbool valid() const \\\n\t{ \\\n\t\treturn m_CallbackBase != NULL; \\\n\t} \\\n\t \\\n\toperator bool() const \\\n\t{ \\\n\t\treturn m_CallbackBase != NULL; \\\n\t} \\\n\t \\\n\tbool operator==(const CCallback &callback) \\\n\t{ \\\n\t\treturn m_CallbackBase->equals(callback.m_CallbackBase); \\\n\t} \\\n\t \\\nprivate: \\\n\tCCallbackBase *m_CallbackBase; \\\n\t \\\n}; /* class CCallback */ \\\n\ntemplate<typename TReturn, typename TArgsA = void, typename TArgsB = void, typename TArgsC = void, typename TArgsD = void, typename TArgsE = void, typename TArgsF = void, typename TArgsG = void, typename TDummy = void>\nclass CCallback;\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, void, void, void, void, void, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME \n#define NLMISC_CALLBACK_ARGS_DECL \n#define NLMISC_CALLBACK_ARGS_IMPL \nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, void, void, void, void, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA\n#define NLMISC_CALLBACK_ARGS_IMPL argsA\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, void, void, void, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, TArgsC, void, void, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, TArgsC, TArgsD, void, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, TArgsC, TArgsD, TArgsE, void, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, TArgsC, TArgsD, TArgsE, TArgsF, void, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n\n#define NLMISC_CALLBACK_ARGS_CLASS CCallback<TReturn, TArgsA, TArgsB, TArgsC, TArgsD, TArgsE, TArgsF, TArgsG, void>\n#define NLMISC_CALLBACK_ARGS_TYPENAME , typename TArgsA, typename TArgsB, typename TArgsC, typename TArgsD, typename TArgsE, typename TArgsF, typename TArgsG\n#define NLMISC_CALLBACK_ARGS_DECL TArgsA argsA, TArgsB argsB, TArgsC argsC, TArgsD argsD, TArgsE argsE, TArgsF argsF, TArgsG argsG\n#define NLMISC_CALLBACK_ARGS_IMPL argsA, argsB, argsC, argsD, argsE, argsF, argsG\nNLMISC_CALLBACK_TEMPLATE\n#undef NLMISC_CALLBACK_ARGS_CLASS\n#undef NLMISC_CALLBACK_ARGS_TYPENAME\n#undef NLMISC_CALLBACK_ARGS_DECL\n#undef NLMISC_CALLBACK_ARGS_IMPL\n#undef NLMISC_CALLBACK_ARGS_CLASSNAME\n\n#undef NLMISC_CALLBACK_TEMPLATE\n\n} /* namespace NLMISC */\n\n#endif /* #ifndef NLMISC_CALLBACK_H */\n\n/* end of file */\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n#ifndef CDB_H\n#define CDB_H\n\n// misc\n#include \"types_nl.h\"\n#include \"smart_ptr.h\"\n#include \"string_mapper.h\"\n#include \"sstring.h\"\n\n#include <libxml/parser.h>\n\nnamespace NLMISC\n{\nclass IProgressCallback;\nclass CBitMemStream;\nclass CCDBNodeLeaf;\nclass CCDBNodeBranch;\nclass CCDBBankHandler;\n\n/**\n * Interface to manage a database node, can contain a unique property or a set of property\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2002\n */\n\nclass ICDBNode : public CRefCount\n{\n\t//-----------------------------------------------------------------------\n\t// end of IDBNode interface\n\t// start of CDB sub-class definitions\n\npublic:\n\tenum EPropType\n\t{\n\t\tUNKNOWN = 0,\n\t\t// Unsigned\n\t\tI1,  I2,  I3,  I4,  I5,  I6,  I7,  I8,  I9,  I10, I11, I12, I13, I14, I15, I16,\n\t\tI17, I18, I19, I20, I21, I22, I23, I24, I25, I26, I27, I28, I29, I30, I31, I32,\n\t\tI33, I34, I35, I36, I37, I38, I39, I40, I41, I42, I43, I44, I45, I46, I47, I48,\n\t\tI49, I50, I51, I52, I53, I54, I55, I56, I57, I58, I59, I60, I61, I62, I63, I64,\n\t\t// Signed\n\t\tS1,  S2,  S3,  S4,  S5,  S6,  S7,  S8,  S9,  S10, S11, S12, S13, S14, S15, S16,\n\t\tS17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31, S32,\n\t\tS33, S34, S35, S36, S37, S38, S39, S40, S41, S42, S43, S44, S45, S46, S47, S48,\n\t\tS49, S50, S51, S52, S53, S54, S55, S56, S57, S58, S59, S60, S61, S62, S63, S64,\n\t\tTEXT, Nb_Prop_Type\n\t};\n\n\n\t/**\n\t * observer interface to a database property\n\t * \\author Nicolas Brigand\n\t * \\author Nevrax France\n\t * \\date 2002\n\t */\n\tclass IPropertyObserver : public CRefCount\n\t{\n\tpublic :\n\t\tvirtual ~IPropertyObserver()\t{}\n\t\tvirtual void update(ICDBNode* node ) = 0;\n\t};\n\n\n\n\t/**\n\t * Text id\n\t * \\author Stephane Coutelas\n\t * \\author Nevrax France\n\t * \\date 2002\n\t */\n\tclass CTextId\n\t{\n\tpublic:\n\t\t/**\n\t\t *\tDefault constructor\n\t\t */\n\t\tCTextId(): _Idx(0) {}\n\n\t\t/**\n\t\t * Init this text id from a string\n\t\t */\n\t\texplicit CTextId( const std::string& str ): _Idx(0)\n\t\t{\n\t\t\tconst std::string &s = str;\n\t\t\tuint32 i, j;\n\t\t\tfor (i=0,j=0; i+j<s.size(); j++)\n\t\t\t\tif (s[i+j]==':')\n\t\t\t\t{\n\t\t\t\t\t_Ids.push_back(s.substr(i,j));\n\t\t\t\t\ti+=j+1;\t// +1 to skip the ':'\n\t\t\t\t\tj=0;\n\t\t\t\t}\n\t\t\t// deal with the last id in the string (terminated by a '\\x0' and not a ':')\n\t\t\t_Ids.push_back(s.substr(i,j));\n\t\t}\n\n\t\t/**\n\t\t *\tBuild a string from this text id\n\t\t */\n\t\tstd::string toString() const\n\t\t{\n\t\t\tif (_Ids.size()==0) return std::string(\"\");\n\t\t\tstd::string str=_Ids[0];\n\t\t\tfor (unsigned i=1; i<_Ids.size(); i++)\n\t\t\t\tstr +=std::string(\":\")+ _Ids[i];\n\t\t\treturn str;\n\t\t}\n\n\t\t/**\n\t\t * Push back a sub name id to this id\n\t\t */\n\t\tvoid push( const std::string &str ) {\t_Ids.push_back( str ); }\n\n\t\t/**\n\t\t * Remove the last sub name id to this id\n\t\t */\n\t\tvoid pop() { _Ids.pop_back(); }\n\n\t\t/**\n\t\t * Return the next sub id\n\t\t */\n\t\tconst std::string &readNext() const\n\t\t{\n\t\t\tnlassert( _Idx < _Ids.size() );\n\t\t\treturn _Ids[_Idx++];\n\t\t}\n\n\t\t/** return true if a call to readNext can be performed\n\t\t  */\n\t\tbool hasElements() const { return _Idx < _Ids.size(); }\n\n\t\t/**\n\t\t * Get the current index in Id\n\t\t */\n\t\tuint getCurrentIndex() const { return _Idx; }\n\n\t\t/**\n\t\t *\tReturn the count of strings composing this id\n\t\t */\n\t\tuint size() const { return (uint)_Ids.size(); }\n\n\t\t/** Return an element. empty if bad index\n\t\t */\n\t\tconst std::string &getElement(uint idx)\n\t\t{\n\t\t\tstatic std::string empty;\n\t\t\tif(idx>=size())\n\t\t\t\treturn empty;\n\t\t\telse\n\t\t\t\treturn _Ids[idx];\n\t\t}\n\n\tprivate:\n\t\tstd::vector<std::string> _Ids;\n\t\tmutable uint _Idx;\n\t};\n\n//-----------------------------------------------------------------------\n// end of CDB sub-class definitions\n\n\n//-----------------------------------------------------------------------\n// IDBNode interface definition\n\npublic :\n\n\t/**\n\t *\tdestructor\n\t */\n\tvirtual ~ICDBNode() {}\n\n\t/**\n\t *\tBuild the structure of the database from a file\n\t * \\param f is the stream\n\t */\n\tvirtual void init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL ) = 0;\n\n\t/**\n\t * Save a backup of the database\n\t * \\param id is the text id of the property/grp\n\t * \\param f is the stream\n\t */\n\tvirtual void write( CTextId& id, FILE * f) = 0;\n\n\t/**\n\t * Update the database from a stream coming from the FE\n\t * \\param gc the server gameCycle of this update. Any outdated update are aborted\n\t * \\param f : the stream.\n\t */\n\tvirtual void readDelta( TGameCycle gc, CBitMemStream & f ) = 0;\n\n\t/**\n\t * Get a node . Create it if it does not exist yet\n\t * \\param id : the CTextId identifying the node\n\t */\n\tvirtual ICDBNode * getNode( const CTextId& id, bool bCreate = true )=0 ;\n\n\t/**\n\t * Get a node\n\t * \\param idx is the node index\n\t */\n\tvirtual ICDBNode * getNode( uint16 idx ) = 0;\n\n\t/**\n\t * Get a node index\n\t * \\param node is a pointer to the node\n\t * \\param index is a reference that receive the result\n\t * \\return true if the node was found\n\t */\n\tvirtual bool getNodeIndex( ICDBNode* node , uint & index) = 0;\n\n\t/**\n\t * Return the value of a property (the update flag is set to false)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\return the value of the property\n\t */\n\tvirtual sint64 getProp( CTextId& id ) = 0;\n\n\t/**\n\t * Set the value of a property (the update flag is set to true)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\param value is the value of the property\n\t * \\return bool : 'true' if property found.\n\t */\n\tvirtual bool setProp( CTextId& id, sint64 value ) = 0;\n\n\t/// Reset all leaf data from this point\n\tvirtual void resetData(TGameCycle gc, bool forceReset=false) = 0;\n\n\t/**\n\t * Clear the node and his children\n\t */\n\tvirtual void clear() = 0;\n\n\t/**\n\t* add an observer to a property\n\t* \\param observer : pointer to an observer\n\t* \\param id text id identifying the property\n\t* \\return false if the node doesn't exist\n\t*/\n\tvirtual bool addObserver(IPropertyObserver* observer, CTextId& id) = 0;\n\n\t/** remove an obsever\n\t * \\param observer : pointer to an observer\n\t * \\param id text id identifying the property\n\t * \\return false if the node or observer doesn t exist\n\t */\n\tvirtual bool removeObserver(IPropertyObserver* observer, CTextId& id) = 0;\n\n\t/**\n\t * Inform a node of its parenthood\n\t */\n\tvirtual void setParent(CCDBNodeBranch * /* parent */) { nlassertex(0,(\"setParent() not overloaded for given node type!\")); }\n\n\t/**\n\t * get the parent of a node\n\t */\n\tvirtual CCDBNodeBranch* getParent() { nlassertex(0,(\"getParent() not overloaded for given node type!\")); return NULL; }\n\n\t/**\n\t * get the name of this node\n\t */\n\tconst std::string * getName() const { return &_DBSM->localUnmap(_Name); }\n\n\t/**\n\t * get the full name of this node separator is ':' (ie UI:INTERFACE:REDSTUFF)\n\t * This will not return the fullname with the ROOT !\n\t */\n\tstd::string getFullName();\n\n\t/// Count the leaves\n\tvirtual uint\t\t\tcountLeaves() const = 0;\n\n\t/// Find the leaf which count is specified (if found, the returned value is non-null and count is 0)\n\tvirtual CCDBNodeLeaf\t*findLeafAtCount( uint& count ) = 0;\n\n\t/// Set the atomic branch flag (when all the modified nodes of a branch should be tranmitted at the same time)\n\tvoid\t\t\t\t\tsetAtomic( bool atomicBranch ) { _AtomicFlag = atomicBranch; }\n\n\t/// Return true if the branch has the atomic flag\n\tbool\t\t\t\t\tisAtomic() const { return _AtomicFlag; }\n\n\t// test if the node is a leaf\n\tvirtual bool\t\t\tisLeaf() const = 0;\n\n\t/// Debug purpose\n\tvirtual void display (const std::string &/* prefix */){}\n\n\t/// Return the string id corresponding to the argument\n\tstatic TStringId getStringId(const std::string& nodeName)\n\t{\n\t\tif (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper();\n\t\treturn _DBSM->localMap(nodeName);\n\t}\n\n\t/// Return a pointer to the string corresponding to the argument\n\tstatic const std::string *getStringFromId(TStringId nodeStringId)\n\t{\n\t\tif (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper();\n\t\treturn &_DBSM->localUnmap(nodeStringId);\n\t}\n\n\t/// release string mapper\n\tstatic void releaseStringMapper();\n\n\tstatic bool isDatabaseVerbose(){ return verboseDatabase; }\n\tstatic void setVerboseDatabase( bool b ){ verboseDatabase = b; }\n\nprotected:\n\n\t/// Constructor\n\tICDBNode() : _AtomicFlag(false)\n\t{\n\t\tif (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper();\n\t\t_Name = CStringMapper::emptyId();\n\t}\n\n\t/// Constructor\n\tICDBNode (const std::string &name) : _AtomicFlag(false)\n\t{\n\t\tif (_DBSM == NULL) _DBSM = CStringMapper::createLocalMapper();\n\t\t_Name = _DBSM->localMap(name);\n\t\t//_NameDbg = name;\n\t}\n\n\t// utility to build full name efficiently (without reallocating the string at each parent level)\n\tvoid _buildFullName(CSString &fullName);\n\n\t/// Atomic flag: is the branch an atomic group, or is the leaf a member of an atomic group\n\tbool\t\t\t_AtomicFlag\t\t: 1;\n\n\t/// Name of the node\n\tTStringId\t_Name;\n\t//std::string _NameDbg;\n\n\tstatic CStringMapper *_DBSM;\n\n\tstatic bool verboseDatabase;\n\n};\n\n\n}\n\n\n#endif // CDB_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_bank_handler.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef CDB_BANK_HANDLER\n#define CDB_BANK_HANDLER\n\n#include <vector>\n#include \"nel/misc/types_nl.h\"\n\nnamespace NLMISC{\n\n/**\n @brief Manages the bank names and mappings of the CDB it's associated with\n\n Banks are numeric identifiers for the top-level branches of the CDB.\n They are used for saving bandwidth, because the local CDBs are updated with deltas,\n that identify the updatable top-level branch with this id.\n The CCDBBankHandler manages the mapping of banks to their names, unified (node) index,\n and the other way around.\n\n */\nclass CCDBBankHandler{\npublic:\n\t/**\n\t @brief The class' constructor\n\t @param maxbanks the maximum number of banks we need to handle\n\t*/\n\tCCDBBankHandler( uint maxbanks );\n\n\t/// Very surprisingly this is the destructor\n\t~CCDBBankHandler(){}\n\n\t/**\n\t @brief   Returns the unified (node) index for the specified bank Id.\n\t @param   bank The bank whose uid we need.\n\t @return  Returns an uid or static_cast< uint >( -1 ) on failure.\n\t*/\n\tuint getUIDForBank( uint bank ) const;\n\n\t/**\n\t @brief   Returns the bank Id for the specified unified (node) index.\n\t @param   uid The unified (node) index we need to translate to bank Id.\n\t @return  Returns a bank Id.\n\t*/\n\tuint getBankForUID( uint uid ) const{ return _UnifiedIndexToBank[ uid ]; }\n\n\t/// Returns the last unified (node) index we mapped.\n\tuint getLastUnifiedIndex() const{ return _CDBLastUnifiedIndex; }\n\n\t/**\n\t @brief   Returns the number of bits used to store the number of nodes that belong to this bank.\n\t @param   bank The banks whose id bits we need.\n\t @return  Returns the number of bits used to store the number of nodes that belong to this bank.\n\t*/\n\tuint getFirstLevelIdBits( uint bank ) const{ return _FirstLevelIdBitsByBank[ bank ]; }\n\n\t/**\n\t @brief   Returns the name of the specified bank.\n\t @param   bank The id of the bank we need the name of.\n\t @return  Returns the name of the specified bank.\n\t*/\n\tstd::string getBankName( uint bank ) const{ return _CDBBankNames[ bank ]; }\n\n\t/**\n\t @brief   Looks up the bank Id of the bank name specified.\n\t @param   name The name of the bank whose Id we need.\n\t @return  Returns the id of the bank, or static_cast< uint >( -1 ) on fail.\n\t*/\n\tuint getBankByName( const std::string &name ) const;\n\n\t/**\n\t @brief   Maps the specified bank name to a unified (node) index and vica versa.\n\t @param   bankName Name of the bank to map.\n\t*/\n\tvoid mapNodeByBank( const std::string &bankName );\n\n\t/**\n\t @brief   Loads the known bank names from an array ( the order decides the bank Id ).\n\t @param   strings The array of the banks names.\n\t @param   size    The size of the array.\n\t*/\n\tvoid fillBankNames( const char **strings, uint size );\n\n\t/// Resets the node to bank mapping vector\n\tvoid resetNodeBankMapping(){ _UnifiedIndexToBank.clear(); }\n\n\t/// Resets all maps, and sets _CDBLastUnifiedIndex to 0.\n\tvoid reset();\n\n\tuint getUnifiedIndexToBankSize() const{ return _UnifiedIndexToBank.size(); }\n\n\t/// Calculates the number of bits used to store the number of nodes that belong to the banks.\n\tvoid calcIdBitsByBank();\n\n\t/**\n\t @brief   Looks up the unified (node) index of a bank node.\n\t @param   bank  The bank id of the node we are looking up.\n\t @param   index The index of the node within the bank.\n\t @return  Returns the unified (node) index of the specified bank node.\n\t*/\n\tuint getServerToClientUIDMapping( uint bank, uint index ) const{ return _CDBBankToUnifiedIndexMapping[ bank ][ index ]; }\n\n\t/**\n\t @brief Resizes the bank holders. WARNING: Resets data contained.\n\t @param newSize - The new maximum number of banks.\n\t */\n\tvoid resize( uint newSize );\n\nprivate:\n\t/// Mapping from server database index to client database index (first-level nodes)\n\tstd::vector< std::vector< uint > > _CDBBankToUnifiedIndexMapping;\n\t\n\t/// Mapping from client database index to bank IDs (first-level nodes)\n\tstd::vector< uint > _UnifiedIndexToBank;\n\t\n\t/// Last index mapped\n\tuint _CDBLastUnifiedIndex;\n\t\n\t/// Number of bits for first-level branches, by bank\n\tstd::vector< uint > _FirstLevelIdBitsByBank;\n\n\t/// Names of the CDB banks\n\tstd::vector< std::string > _CDBBankNames;\n\n\t/// The number of banks used\n\tuint maxBanks;\n};\n\n}\n\n#endif\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_branch.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n#ifndef CDB_BRANCH_H\n#define CDB_BRANCH_H\n\n#include \"cdb.h\"\n\n#define NL_CDB_OPTIMIZE_PREDICT 1\n\nnamespace NLMISC{\n\n/**\n * Database Node which contains a set of properties\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2002\n */\nclass CCDBNodeBranch : public ICDBNode\n{\npublic:\n\n\tclass ICDBDBBranchObserverHandle\n\t{\n\tpublic:\n\t\tvirtual ~ICDBDBBranchObserverHandle(){}\n\n\t\tvirtual ICDBNode* owner()                                 = 0;\n\t\tvirtual IPropertyObserver* observer()                     = 0;\n\t\tvirtual bool observesLeaf( const std::string &leafName )  = 0;\n\t\tvirtual bool inList( uint list )                          = 0;\n\t\tvirtual void addToFlushableList()                         = 0;\n\t\tvirtual void removeFromFlushableList( uint list )         = 0;\n\t\tvirtual void removeFromFlushableList()                    = 0;\n\n\t};\n\n\t// default constructor\n\tCCDBNodeBranch(const std::string &name) : ICDBNode(name)\n\t{\n\t\t_Parent = NULL;\n\t\t_IdBits = 0;\n\t\t_Sorted = false;\n\t}\n\n\t/**\n\t *\tBuild the structure of the database from a file\n\t * \\param f is the stream\n\t */\n\tvoid init( xmlNodePtr node, class IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL );\n\n\t/**\n\t * Add a new sub node\n\t * \\param node is the new subnode\n\t * \\param nodeName is the name of the node\n\t */\n\tvoid attachChild( ICDBNode * node, std::string nodeName );\n\n\t/**\n\t * Get a node . Create it if it does not exist yet\n\t * \\param id : the CTextId identifying the node\n\t */\n\tICDBNode * getNode (const CTextId& id, bool bCreate=true);\n\n\t/**\n\t * Get a node. Return NULL if out of bounds (no warning)\n\t * \\param idx is the node index\n\t */\n\tICDBNode * getNode( uint16 idx );\n\n\t/**\n\t * Get a node index\n\t * \\param node is a pointer to the node\n\t */\n\tvirtual bool getNodeIndex( ICDBNode* node , uint& index)\n\t{\n\t\tindex=0;\n\t\tfor ( std::vector<ICDBNode*>::const_iterator it = _Nodes.begin(); it != _Nodes.end(); it++)\n\t\t{\n\t\t\tif (*it == node)\n\t\t\t\treturn true;\n\t\t\tindex++;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// return the child with the given node id, creating it if requested\n\tCCDBNodeLeaf *getLeaf( const char *id, bool bCreate );\n\tCCDBNodeLeaf *getLeaf( const std::string &id, bool bCreate ) { return getLeaf(id.c_str(), bCreate); }\n\n\t/**\n\t * Save a backup of the database\n\t * \\param id is the text id of the property/grp\n\t * \\param f is the stream\n\t */\n\tvoid write( CTextId& id, FILE * f);\n\n\t/// Update the database from the delta, but map the first level with the bank mapping (see _CDBBankToUnifiedIndexMapping)\n\tvoid readAndMapDelta( TGameCycle gc, CBitMemStream& s, uint bank, CCDBBankHandler *bankHandler );\n\n\t/// Update the database from a stream coming from the FE\n\tvoid readDelta( TGameCycle gc, CBitMemStream & f );\n\n\t/**\n\t * Return the value of a property (the update flag is set to false)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\return the value of the property\n\t */\n\tsint64 getProp( CTextId& id );\n\n\t/**\n\t * Set the value of a property (the update flag is set to true)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\param value is the value of the property\n\t * \\return bool : 'true' if property found.\n\t */\n\tbool setProp( CTextId& id, sint64 value );\n\n\t/// Clear the node and his children\n\tvoid clear();\n\n\tvoid resetNode( TGameCycle gc, uint node )\n\t{\n\t\tif( node > _Nodes.size() )\n\t\t\treturn;\n\t\t\n\t\t_Nodes[ node ]->resetData( gc );\n\t}\n\n\t/// Reset all leaf data from this point\n\tvoid resetData(TGameCycle gc, bool forceReset=false)\n\t{\n\t\tfor ( uint i=0; i!=_Nodes.size(); ++i )\n\t\t{\n\t\t\t_Nodes[i]->resetData(gc, forceReset);\n\t\t}\n\t}\n\n\t/**\n\t *\tDestructor\n\t */\n\tvirtual ~CCDBNodeBranch() { clear(); }\n\n\t// the parent node for a branch (NULL by default)\n\tvirtual void setParent(CCDBNodeBranch *parent) { _Parent=parent; }\n\n\tvirtual CCDBNodeBranch*  getParent()\n\t{\n\t\treturn _Parent;\n\t}\n\n\t//get the number of nodes\n\tuint16 getNbNodes()\n\t{\n\t\treturn (uint16)_Nodes.size();\n\t}\n\n\t/// Count the leaves\n\tvirtual uint\tcountLeaves() const;\n\n\t/// Find the leaf which count is specified (if found, the returned value is non-null and count is 0)\n\tvirtual CCDBNodeLeaf\t*findLeafAtCount( uint& count );\n\n\tvirtual void display (const std::string &prefix);\n\n\tvoid removeNode (const CTextId& id);\n\n\t/**\n\t* add an observer to a property\n\t* \\param observer : pointer to an observer\n\t* \\param id text id identifying the property\n\t* \\return false if the node doen t exist\n\t*/\n\tvirtual bool addObserver(IPropertyObserver* observer, CTextId& id);\n\n\t/** remove an obsever\n\t * \\param observer : pointer to an observer\n\t * \\return false if the node or observer doesn t exist\n\t */\n\tvirtual bool removeObserver(IPropertyObserver* observer, CTextId& id);\n\n\t// Add an observer to this branch. It will be notified of any change in the sub-leaves\n\n\t/**\n\t * Add observer to all sub-leaves, except if a positive filter is set:\n\t * If positiveLeafNameFilter is non-empty, only changes to leaves having names found in it\n\t * will be notified (this is equivalent to creating a sub-branch containing only the specified leaves\n\t * and setting a branch observer on it, except you don't need to change your database paths\n\t * and update large amounts of code!).\n\t */\n\tvoid addBranchObserver( ICDBDBBranchObserverHandle* handle, const std::vector<std::string>& positiveLeafNameFilter=std::vector<std::string>());\n\n\t/**\n\t * Easy version of addBranchObserver() (see above).\n\t * Examples of dbPathFromThisNode:\n\t * \"\" -> this node\n\t * \"FOO:BAR\" ->  sub-branch \"BAR\" of \"FOO\" which is a sub-branch of this node\n\t */\n\tvoid addBranchObserver( ICDBDBBranchObserverHandle *handle, const char *dbPathFromThisNode, const char **positiveLeafNameFilter=NULL, uint positiveLeafNameFilterSize=0);\n\n\t// Remove observer from all sub-leaves\n\tbool removeBranchObserver(IPropertyObserver* observer);\n\n\t/// Easy version of removeBranchObserver() (see above and see easy version of addBranchObserver())\n\tvoid removeBranchObserver(const char *dbPathFromThisNode, ICDBNode::IPropertyObserver& observer);\n\n\tvirtual bool isLeaf() const { return false; }\n\n\t// mark this branch and parent branch as 'modified'. This is usually called by sub-leaves\n\tvoid onLeafChanged( TStringId leafName );\n\n\t/// Find a subnode at this level\n\tICDBNode * find (const std::string &nodeName);\n\nprotected:\n\ttypedef std::list< ICDBDBBranchObserverHandle* > TObserverHandleList;\n\n\tCCDBNodeBranch\t\t\t*_Parent;\n\n\t/// database subnodes not sorted\n\tstd::vector<ICDBNode*>\t_Nodes;\n\n\t/// subnodes sorted by name\n\tstd::vector<ICDBNode*>\t_NodesByName;\n\n\t// number of bits required to stock my children's ids\n\tuint8\t\t\t\t\t_IdBits : 7;\n\tbool\t\t\t\t\t_Sorted : 1;\n\n\t// observers for this node or branch\n\tTObserverHandleList\t\tobserverHandles;\n\n\t/// called by clear\n\tvoid\t\t\tremoveAllBranchObserver();\n\n#if NL_CDB_OPTIMIZE_PREDICT\n\tCRefPtr<ICDBNode>\t\t_PredictNode;\n#endif\n};\n\n}\n\n#endif // CDB_BRANCH_H\n\n\n\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_branch_observing_handler.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef CDB_BRANCH_OBS_HNDLR\n#define CDB_BRANCH_OBS_HNDLR\n\n#include \"nel/misc/cdb_branch.h\"\n\nnamespace NLMISC{\n\n\t/**\n\t @brief Manages the CDB branch observers.\n\n\t When a leaf's data changes, it notifies the branch, which then marks the observers as notifiable.\n\t The marked observers can then be notified and flushed on request.\n\n\t */\n\tclass CCDBBranchObservingHandler{\n\n\t\tenum{\n\t\t\tMAX_OBS_LST  = 2\n\t\t};\n\n\tpublic:\n\t\tCCDBBranchObservingHandler();\n\n\t\t~CCDBBranchObservingHandler();\n\n\t\t/// Notifies the observers, and flushes the list\n\t\tvoid flushObserverCalls();\n\n\t\tvoid reset();\n\n\t\tvoid addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter );\n\n\t\tvoid addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize );\n\n\t\tvoid removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer );\n\n\t\tvoid removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer );\n\t\t\n\t\t\n\t\t///Observer for branch observer flush events.\n\t\tclass IBranchObserverCallFlushObserver : public CRefCount{\n\t\tpublic:\n\t\t\tvirtual ~IBranchObserverCallFlushObserver(){}\n\t\t\tvirtual void onObserverCallFlush() = 0;\n\t\t};\n\t\n\tprivate:\n\t\tvoid triggerFlushObservers();\n\t\n\tpublic:\n\t\tvoid addFlushObserver( IBranchObserverCallFlushObserver *observer );\n\t\tvoid removeFlushObserver( IBranchObserverCallFlushObserver *observer );\n\t\n\tprivate:\n\n\t\t/**\n\t\t @brief Handle to a branch observer.\n\n\t\t The handle stores the owner branch, the observer and remembers if it's marked for notifying the observer.\n\t\t Also it manages adding/removing itself to/from the marked observer handles list, which is handled by CCDBBranchObservingHandler.\n\n\t\t */\n\t\tclass CCDBDBBranchObserverHandle : public CCDBNodeBranch::ICDBDBBranchObserverHandle{\n\n\t\tpublic:\n\n\t\t\tCCDBDBBranchObserverHandle( ICDBNode::IPropertyObserver *observer, CCDBNodeBranch *owner, CCDBBranchObservingHandler *handler );\n\n\t\t\t~CCDBDBBranchObserverHandle();\n\n\t\t\tICDBNode* owner(){ return _owner; }\n\n\t\t\tICDBNode::IPropertyObserver* observer(){ return _observer; }\n\n\t\t\tbool observesLeaf( const std::string &leafName );\n\n\t\t\tbool inList( uint list );\n\n\t\t\tvoid addToFlushableList();\n\n\t\t\tvoid removeFromFlushableList( uint list );\n\n\t\t\tvoid removeFromFlushableList();\n\n\t\tprivate:\n\n\t\t\tbool _inList[ MAX_OBS_LST ];\n\n\t\t\tstd::vector< std::string > _observedLeaves;\n\n\t\t\tCCDBNodeBranch *_owner;\n\n\t\t\tNLMISC::CRefPtr< ICDBNode::IPropertyObserver > _observer;\n\n\t\t\tCCDBBranchObservingHandler *_handler;\n\n\t\t};\n\n\t\tstd::list< CCDBNodeBranch::ICDBDBBranchObserverHandle* > flushableObservers[ MAX_OBS_LST ];\n\n\t\tCCDBNodeBranch::ICDBDBBranchObserverHandle *currentHandle;\n\n\t\tuint currentList;\n\n\t\tstd::vector< IBranchObserverCallFlushObserver* > flushObservers;\n\n\t};\n}\n\n#endif\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_check_sum.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n#ifndef NL_CDB_CHECK_SUM_H\n#define NL_CDB_CHECK_SUM_H\n\n#include \"types_nl.h\"\n\n#include <vector>\n\nnamespace NLMISC{\n\n/**\n * class implementing check sum for the client database\n * these check sum can be used to ensure that linked properties have all been modified\n * \\author Nicolas Brigand\n * \\author Nevrax France\n * \\date 2002\n */\nclass CCDBCheckSum\n{\npublic:\n\t///constructor\n\tCCDBCheckSum();\n\n\t//clear the sum\n\tvoid clear()\n\t{\n\t\t_Sum = 0;\n\t};\n\n\t///add an uint8 to the sum\n\tvoid add(uint8 el);\n\n\t///add a value to the check sum\n\ttemplate <class T>\n\tvoid add(const T & el)\n\t{\n\t\tT value = el;\n\t\tfor (uint8 i=0; i< sizeof(T); i++)\n\t\t{\n\t\t\tuint8 tmp = (uint8)(value & 0xFF);\n\t\t\tadd(tmp);\n\t\t\tvalue >>=8;\n\t\t}\n\t}\n\n\t///add a vector to the sum\n\ttemplate <class T>\n\tvoid addVector(const std::vector<T> &  vect)\n\t{\n\t\tfor (typename std::vector<T>::const_iterator it = vect.begin(); it != vect.end(); it++)\n\t\t\tadd(*it);\n\t}\n\n\tuint32 getSum()\n\t{\n\t\treturn _Sum;\n\t}\nprivate:\n\t///the checsum result\n\tuint32 _Sum;\n\n\t///the following values are used in the check algorithm\n\tuint32 _Factor;\n    uint32 _Const1;\n    uint32 _Const2;\n\n};\n\n\n}\n\n#endif // NL_CDB_CHECK_SUM_H\n\n/* End of cdb_check_sum.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_leaf.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n#ifndef CDB_LEAF_H\n#define CDB_LEAF_H\n\n#include \"cdb.h\"\n#include \"cdb_branch.h\"\n#include \"time_nl.h\"\n#include \"rgba.h\"\n\nnamespace NLMISC{\n\n/**\n * Database node which contains a unique property\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2002\n */\nclass CCDBNodeLeaf : public ICDBNode\n{\npublic:\n\t// flush all observers calls for modified nodes\n\tstatic void flushObserversCalls();\n\n\n\t/// Return the value of the property.\n\tinline sint64 getValue64() { return _Property; }\n\n\t/// Set the value of the property (set '_Changed' flag with 'true').\n\tvoid setValue64 (sint64 prop);\n\n\tinline sint32 getValue32() { return *((sint32*)&_Property); }\n\tvoid setValue32 (sint32 prop);\n\tinline sint16 getValue16() { return *((sint16*)&_Property); }\n\tvoid setValue16 (sint16 prop);\n\tinline sint8 getValue8() { return *((sint8*)&_Property); }\n\tvoid setValue8 (sint8 prop);\n\tinline bool getValueBool() { return (_Property!=(sint64)0 ); }\n\tvoid setValueBool (bool prop);\n\tinline CRGBA getValueRGBA()\n\t{\n\t\tCRGBA col;\n\t\tcol.R = (uint8)(_Property&0xff);\n\t\tcol.G = (uint8)((_Property>>8)&0xff);\n\t\tcol.B = (uint8)((_Property>>16)&0xff);\n\t\tcol.A = (uint8)((_Property>>24)&0xff);\n\t\treturn col;\n\t}\n\tvoid setValueRGBA (const CRGBA &color);\n\n\t/// Return the value of the property before the database change\n\tinline sint64 getOldValue64() { return _oldProperty; }\n\tinline sint32 getOldValue32() { return *((sint32*)&_oldProperty); }\n\tinline sint16 getOldValue16() { return *((sint16*)&_oldProperty); }\n\tinline sint8 getOldValue8() { return *((sint8*)&_oldProperty); }\n\tinline bool getOldValueBool() { return (_oldProperty!=(sint64)0 ); }\n\n\n\t/// Return the type of the property.\n\tinline const EPropType &type() const {return _Type;}\n\n\t/// Set the property Type.\n\tinline void type(const EPropType &t) {_Type = t;}\n\n\t/// Return 'true' if the property changed since last call.\n\tinline const bool &changed() const {return _Changed;}\n\n\t/// Set the property flag to known if the property changed since last call.\n\tinline void changed(const bool &c) {_Changed = c;}\n\n\t/**\n\t * Default constructor\n\t */\n\tCCDBNodeLeaf(const std::string &name) : ICDBNode(name)\n\t{\n\t\t_Parent=0;\n\t\t_Property = 0;\n\t\t_oldProperty = 0;\n\t\t_Type = UNKNOWN;\n\t\t_Changed = false;\n\t\t_LastChangeGC = 0;\n\t}\n\n\t/**\n\t *\tBuild the structure of the database from a file\n\t * \\param f is the stream\n\t */\n\tvoid init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks=false, CCDBBankHandler *bankHandler = NULL );\n\n\t/**\n\t * Get a node\n\t * \\param idx is the node index\n\t */\n\tICDBNode * getNode( uint16 idx );\n\n\t/**\n\t * Get a node . Create it if it does not exist yet\n\t * \\param id : the CTextId identifying the node\n\t */\n\tICDBNode * getNode (const CTextId& id, bool bCreate);\n\n\t/**\n\t * Get a node index\n\t * \\param node is a pointer to the node\n\t */\n\tvirtual bool getNodeIndex( ICDBNode* /* node */, uint& /* index */)\n\t{\n\t\treturn false;\n\t}\n\n\t/**\n\t * Save a backup of the database\n\t * \\param id is the text id of the property/grp\n\t * \\param f is the stream\n\t */\n\tvoid write( CTextId& id, FILE * f);\n\n\t/**\n\t * Update the database from a stream coming from the FE\n\t * \\param f : the stream.\n\t */\n\tvoid readDelta(TGameCycle gc, CBitMemStream & f );\n\n\t/**\n\t * Return the value of a property (the update flag is set to false)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\return the structure of the property\n\t */\n\tsint64 getProp( CTextId& id );\n\n\t/**\n\t * Set the value of a property (the update flag is set to true)\n\t * \\param id is the text id of the property/grp\n\t * \\param name is the name of the property\n\t * \\param value is the value of the property\n\t * \\return bool : 'false' if id is too long.\n\t */\n\tbool setProp( CTextId& id, sint64 value );\n\n\t/**\n\t * Set the value of a property, only if gc>=_LastChangeGC\n\t */\n\tbool setPropCheckGC(TGameCycle gc, sint64 value);\n\n\t/// Reset all leaf data from this point\n\tvoid resetData(TGameCycle gc, bool forceReset=false);\n\n\t/**\n\t * Clear the node and his children\n\t */\n\tvoid clear();\n\n\n\t// the parent node for a branch (NULL by default)\n\tvirtual void setParent(CCDBNodeBranch* parent) { _Parent=parent; }\n\n\t//get the node parent\n\tvirtual CCDBNodeBranch\t*getParent()\n\t{\n\t\treturn _Parent;\n\t}\n\n\t/// Count the leaves\n\tvirtual uint\t\t\tcountLeaves() const\n\t{\n\t\treturn 1;\n\t}\n\n\t/// Find the leaf which count is specified (if found, the returned value is non-null and count is 0)\n\tvirtual CCDBNodeLeaf\t*findLeafAtCount( uint& count )\n\t{\n\t\tif ( count == 0 )\n\t\t\treturn this;\n\t\telse\n\t\t{\n\t\t\t--count;\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\t/// Debug purpose\n\tvirtual void display(const std::string &prefix);\n\n\n\tvirtual bool isLeaf() const { return true; }\n\n\t/**\n\t* add an observer to a property\n\t* \\param observer : pointer to an observer\n\t* \\param id text id identifying the property\n\t* \\return false if the node doen t exist\n\t*/\n\tvirtual bool addObserver(IPropertyObserver* observer, CTextId& id);\n\n\t/** remove an obsever\n\t * \\param observer : pointer to an observer\n\t * \\param id text id identifying the property\n\t * \\return false if the node or observer doesn t exist\n\t */\n\tvirtual bool removeObserver(IPropertyObserver* observer, CTextId& id);\n\n\n\t/// get the last change GameCycle (server tick) for this value\n\tTGameCycle\tgetLastChangeGC() const {return _LastChangeGC;}\n\n\nprivate:\n\n\tCCDBNodeBranch *\t_Parent;\n\n\t/// property value\n\tsint64\t\t\t\t_Property;\n\tsint64\t\t\t\t_oldProperty;\n\n\t/// property type\n\tEPropType\t\t\t_Type;\n\n\t/// true if this value has changed\n\tbool\t\t\t\t_Changed;\n\n\t/// gamecycle (servertick) of the last change for this value.\n\t/// change are made in readDelta only for change >= _LastChangeGC\n\tTGameCycle\t_LastChangeGC;\n\n\t/// observers to call when the value really change\n\tstd::vector<IPropertyObserver*> _Observers;\n\nprivate:\n\tvoid notifyObservers();\n\n};\n\n////////////////////\n// INLINE MEMBERS //\n////////////////////\n\n\n}\n\n\n#endif // CDB_LEAF_H\n\n\n\n\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/cdb_manager.h",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef CDB_MANAGER_H\n#define CDB_MANAGER_H\n\n#include \"nel/misc/cdb_branch.h\"\n#include \"nel/misc/cdb_leaf.h\"\n#include \"nel/misc/cdb_bank_handler.h\"\n#include \"nel/misc/cdb_branch_observing_handler.h\"\n\nnamespace NLMISC{\n\n\t/// Class that encapsulates the separate CDB components\n\tclass CCDBManager{\n\t\n\tpublic:\n\t\t/**\n\t\t The constructor\n\t\t @param maxBanks  -  The maximum number of banks to be used\n\n\t\t */\n\t\tCCDBManager( const char *rootNodeName, uint maxBanks );\n\n\t\t~CCDBManager();\n\n\n\t\t/**\n\t\t Returns the specified leaf node from the database.\n\t\t @param name The name of the leaf node.\n\t\t @param create Specifies if the node should be created if it doesn't exist yet.\n\n\t\t */\n\t\tCCDBNodeLeaf* getDbLeaf( const std::string &name, bool create = true );\n\n\n\n\t\t/**\n\t\t Returns the specified branch node from the database.\n\t\t @param name The name of the branch.\n\n\t\t */\n\t\tCCDBNodeBranch* getDbBranch( const std::string &name );\n\n\n\t\t/**\n\t\t Deletes the specified database node.\n\t\t @param name The name of the database node.\n\n\t\t */\n\t\tvoid delDbNode( const std::string &name );\n\t\t\n\t\t/**\n\t\t Adds an observer to a branch of the database.\n\t\t @param branchName The name of the branch we want to observe\n\t\t @param observer   The observer we want to add\n\t\t @param positiveLeafNameFilter A vector of strings containing the names of the leaves we want to observe\n\n\t\t */\n\t\tvoid addBranchObserver( const char *branchName, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter = std::vector< std::string >() );\n\n\t\t/**\n\t\t Adds an observer to a branch of the database.\n\t\t @param branch  The branch we want to observe\n\t\t @param observer   The observer we want to add\n\t\t @param positiveLeafNameFilter A vector of strings containing the names of the leaves we want to observe\n\n\t\t */\n\t\tvoid addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter = std::vector< std::string >() );\n\n\n\t\t/**\n\t\t Adds an observer to a branch of the database.\n\t\t @param branchName The name of the branch we start from\n\t\t @param dbPathFromThisNode The path to the branch we want to observe\n\t\t @param observer   The observer we want to add\n\t\t @param positiveLeafNameFilter An array of strings containing the names of the leaves we want to observe\n\t\t @param positiveLeafNameFilterSize The size of the array\n\n\t\t */\n\t\tvoid addBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter = NULL, uint positiveLeafNameFilterSize = 0 );\n\n\t\t\n\t\t/**\n\t\t Adds an observer to a branch of the database.\n\t\t @param branch The branch we start from\n\t\t @param dbPathFromThisNode The path to the branch we want to observe\n\t\t @param observer   The observer we want to add\n\t\t @param positiveLeafNameFilter An array of strings containing the names of the leaves we want to observe\n\t\t @param positiveLeafNameFilterSize The size of the array\n\n\t\t */\n\t\tvoid addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize );\n\n\n\t\t/**\n\t\t Removes an observer from a branch in the database.\n\t\t @param branchName The name of the branch\n\t\t @param observer The observer we want to remove\n\n\t\t */\n\t\tvoid removeBranchObserver( const char *branchName, ICDBNode::IPropertyObserver* observer );\n\n\n\t\t/**\n\t\t Removes an observer from a branch in the database.\n\t\t @param branch The branch\n\t\t @param observer The observer we want to remove\n\n\t\t */\n\t\tvoid removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer );\n\n\n\t\t/**\n\t\t Removes an observer from a branch in the database.\n\t\t @param branchName The name of the branch we start from\n\t\t @param dbPathFromThisNode The path to the branch we want to observe from the starting branch\n\t\t @param observer The observer we want to remove\n\n\t\t */\n\t\tvoid removeBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer );\n\n\n\t\t/**\n\t\t Removes an observer from a branch in the database.\n\t\t @param branchName The name of the branch we start from\n\t\t @param dbPathFromThisNode The path to the branch we want to observe from the starting branch\n\t\t @param observer The observer we want to remove\n\n\t\t */\n\t\tvoid removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer );\n\n\n\t\t/**\n\t\t Adds a branch observer call flush observer. ( These are notified after the branch observers are notified )\n\t\t @param observer The observer\n\n\t\t */\n\t\tvoid addFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer );\n\n\n\t\t/**\n\t\t Removes a branch observer call flush observer.\n\t\t @param observer The observer\n\t\t */\n\t\tvoid removeFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer );\n\n\t\t/**\n\t\t Notifies the observers whose observed branches were updated.\n\t\t */\n\t\tvoid flushObserverCalls();\n\n\t\t/**\n\t\t Resets the specified bank.\n\t\t @param gc GameCycle ( no idea what it is exactly, probably some time value )\n\t\t @param bank The banks we want to reset\n\n\t\t */\n\t\tvoid resetBank( uint gc, uint bank );\n\t\t\n\t\t/**\n\t\t @brief Resizes the bank holders. WARNING: Resets data contained.\n\t\t @param newSize - The new maximum number of banks.\n\t\t */\n\t\tvoid resizeBanks( uint newSize );\n\t\n\tprotected:\n\t\tCCDBBankHandler bankHandler;\n\t\tCCDBBranchObservingHandler branchObservingHandler;\n\t\tCRefPtr< CCDBNodeBranch > _Database;\n\t};\n\n}\n\n#endif\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/check_fpu.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_CHECK_FPU_H\n#define NL_CHECK_FPU_H\n\n\nnamespace NLMISC\n{\n\nclass CFpuChecker\n{\nprivate:\n\tstatic int\t_RefFpuCtrl;\n\tvoid check();\n\tvoid dumpFpu(int value);\npublic:\n\tCFpuChecker();\n\t~CFpuChecker();\n};\n\n}\n\n\n// Enable define. Normal State is 0, to save CPU speed.\n#define NL_CHECK_FPU_CONTROL_WORD 0\n\n// Use those Macros\n#if NL_CHECK_FPU_CONTROL_WORD\n#define FPU_CHECKER NLMISC::CFpuChecker __fpc__;\n#define FPU_CHECKER_ONCE { NLMISC::CFpuChecker __fpc__; }\n#else\n#define FPU_CHECKER\n#define FPU_CHECKER_ONCE\n#endif\n\n\n#endif\t// NL_CHECK_FPU_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/class_id.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CLASS_ID_H\n#define NL_CLASS_ID_H\n\n\n#include \"types_nl.h\"\n\n\nnamespace\tNLMISC\n{\n\n// ***************************************************************************\n/**\n * A unique id to specify Object by a uint64.\n * The Deriver should use a Max-like Id generator, to identify his own object.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCClassId\n{\n\tuint64\tUid;\n\npublic:\n\tstatic const\tCClassId\tNull;\n\npublic:\n\tCClassId() {Uid=0;}\n\tCClassId(uint32 a, uint32 b) {Uid= ((uint64)a<<32) | b;}\n\tCClassId(uint64 a) {Uid=a;}\n\tbool\toperator==(const CClassId &o) const {return Uid==o.Uid;}\n\tbool\toperator!=(const CClassId &o) const {return Uid!=o.Uid;}\n\tbool\toperator<=(const CClassId &o) const {return Uid<=o.Uid;}\n\tbool\toperator>=(const CClassId &o) const {return Uid>=o.Uid;}\n\tbool\toperator<(const CClassId &o) const {return Uid<o.Uid;}\n\tbool\toperator>(const CClassId &o) const {return Uid>o.Uid;}\n\t//CClassId& operator=(const CClassId &o) { Uid = o.Uid; return *this;}\n\toperator uint64() const {return Uid;}\n\n};\n\n/**\n * Class to be used as a hash traits for a hash_map accessed by CClassId\n * Ex: CHashMap< CClassId, CMyData, CClassIdHashMapTraits> _MyHashMap;\n */\nclass CClassIdHashMapTraits\n{\npublic:\n\tenum { bucket_size = 4, min_buckets = 8, };\n\tinline size_t operator() ( const CClassId& classId ) const\n\t{\n\t\treturn ((((uint64)classId >> 32)|0xFFFFFFFF) ^ (((uint64)classId|0xFFFFFFFF) & 0xFFFFFFFF));\n\t}\n\tbool operator() (const CClassId &classId1, const CClassId &classId2) const\n\t{\n\t\treturn classId1 < classId2;\n\t}\n};\n\n}\n\n\n#endif // NL_CLASS_ID_H\n\n/* End of class_id.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/class_registry.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CLASS_REGISTRY_H\n#define NL_CLASS_REGISTRY_H\n\n#include\t\"types_nl.h\"\n#include\t\"common.h\"\n#include\t<typeinfo>\n#include\t<string>\n#include\t<set>\n\n\nnamespace\tNLMISC\n{\n\n\n// ======================================================================================================\n/**\n * Class Registry Exception.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nstruct ERegistry : public Exception\n{\n\tERegistry() : Exception( \"Registry error\" ) {}\n\n\tERegistry( const std::string& str ) : Exception( str ) {}\n};\n\nstruct ERegisteredClass : public ERegistry\n{\n\tERegisteredClass() : ERegistry( \"Class already registered\" ) {}\n};\n\nstruct EUnregisteredClass : public ERegistry\n{\n\tEUnregisteredClass() : ERegistry( \"Class not registered\" ) {}\n\tEUnregisteredClass(const std::string &className) : ERegistry( std::string(\"Class not registered : \") + className ) {}\n};\n\n\n// ======================================================================================================\n/**\n * An Object Streamable interface.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass IClassable\n{\npublic:\n\tvirtual std::string\t\tgetClassName() =0;\n\tvirtual ~IClassable() {}\n};\n\n\n// ======================================================================================================\n/**\n * The Class registry where we can instanciate IClassable objects from their names.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CClassRegistry\n{\npublic:\n\t/// Inits the ClassRegistry (especially RegistredClasses)\n\tstatic void\t\t\tinit();\n\n\t/// release memory\n\tstatic void\t\t\trelease();\n\n\t///\tRegister your class for future Instanciation.\n\tstatic\tvoid\t\tregisterClass(const std::string &className, IClassable* (*creator)(), const std::string &typeidCheck) throw(ERegistry);\n\n\t/// Create an object from his class name.\n\tstatic\tIClassable\t*create(const std::string &className) throw(ERegistry);\n\n\t/// check if the object has been correctly registered. Must be used for debug only, and Must compile with RTTI.\n\tstatic\tbool\t\tcheckObject(IClassable* obj);\n\n\nprivate:\n\tstruct\tCClassNode\n\t{\n\t\tstd::string\t\t\tTypeIdCheck;\n\t\tIClassable*\t(*Creator)();\n\t};\n\ttypedef CHashMap<std::string, CClassNode> TClassMap;\n\tstatic\tTClassMap\t*RegistredClasses;\n\n};\n\n\n/// Useful Macros.\n#define\tNLMISC_DECLARE_CLASS(_class_)\t\t\t\t\t\\\n\tvirtual std::string\tgetClassName() {return #_class_;}\t\t\\\n\tstatic\tNLMISC::IClassable\t*creator() {return new _class_;}\n#define\tNLMISC_REGISTER_CLASS(_class_) NLMISC::CClassRegistry::registerClass(#_class_, _class_::creator, typeid(_class_).name());\n\n\n\n}\t// namespace NLMISC.\n\n\n#endif // NL_STREAM_H\n\n/* End of stream.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/cmd_args.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CMD_ARGS_H\n#define NL_CMD_ARGS_H\n\n//\n// Includes\n//\n#include <string>\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/sstring.h\"\n\nnamespace NLMISC\n{\n\nclass CCmdArgs\n{\npublic:\n\t/// Sets the command line and init _Args variable. You must call this before calling main()\n\tvoid setArgs (int argc, const char **argv);\n\n\t/// Sets the command line and init _Args variable. You must call this before calling main()\n\tvoid setArgs (const char *args);\n\n\t/// Returns arguments of the program pass from the user to the program using parameters (ie: \"myprog param1 param2\")\n\tconst NLMISC::CVectorSString    &getArgs () const { return _Args; }\n\n\t/// Returns true if the argument if present in the command line (ie: haveArg('p') will return true if -p is in the command line)\n\tbool                                                    haveArg (char argName) const;\n\n\t/** Returns the parameter linked to an option\n\t * getArg('p') will return toto if -ptoto is in the command line\n\t * getArg('p') will return C:\\Documents and Settings\\toto.tmp if -p\"C:\\Documents and Settings\\toto.tmp\" is in the command line\n\t * It'll thrown an Exception if the argName is not found\n\t */\n\tstd::string                                             getArg (char argName) const;\n\n\t/// return true if named long arg is present on the commandline\n\t/// eg haveLongArg(\"toto\") returns true if \"--toto\" or \"--toto=xxx\" can be found on commandline\n\tbool                                                    haveLongArg (const char* argName) const;\n\n\t/// returns the value associated with the given named argument\n\t/// both \"--toto=xxx\" and \"--toto xxx\" are acceptable\n\t/// quotes round arguments are stripped\n\tstd::string                                             getLongArg (const char* argName) const;\nprotected:\n\t/// Array of arguments pass from the command line\n\tNLMISC::CVectorSString                          _Args;\n}; // class CCmdArgs\n\n}; // NAMESPACE NLMISC\n\n#endif // NL_CMD_ARGS_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/co_task.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CO_TASK_H\n#define NL_CO_TASK_H\n\n#include \"types_nl.h\"\n//#include <vector>\n\nnamespace NLMISC\n{\n#if defined (NL_OS_WINDOWS)\n# define NL_WIN_CALLBACK CALLBACK\n#elif defined (NL_OS_UNIX)\n# define NL_WIN_CALLBACK\n#endif\n\n\t// Default to 8KB stack for tasks\n\tconst unsigned int\tNL_TASK_STACK_SIZE = 8*1024;\n\n\t// forward def for platform specific data\n\tstruct TCoTaskData;\n\n\t/** The coroutine task class encapsulate the coroutines detail and provide\n\t *\tan easy to use simple master/slave coroutine model.\n\t *\tThe concept is that the main thread is the 'master' (or parent) coroutine\n\t *\tand that the task is run by a slave coroutine.\n\t *\tTherefore, you can 'start' the task, 'yield' the focus from the task to it's\n\t *\tparent, 'resume' the task from the parent, check for termination of the task,\n\t *\tand/or wait for it.\n\t *\n\t *\tNote that for safety reasons, the CCoTask do not provide mean to for\n\t *\tthe termination of the task. Like for threads, 'killing' a task while\n\t *\tdestroy the task stack without calling destructor of any object create\n\t *\ton the stack. This can lead to memory leaks or atomic destruction of\n\t *\tearth (if used inside an ICBM control program).\n\t *\tSo, as a rule of thumb, (valid for thread as well), you should always\n\t *\tdesign your code so your coroutines are cleanly terminated before\n\t *\tyour program end.\n\t *\n\t *\tIf you don't know about coroutines, a short description follow :\n\t *\t\t* Coroutines are some sort of multi-threading\n\t *\t\t* Coroutines are not preemptive, it's the application code that choose\n\t *\t\t\ttask swapping point\n\t *\t\t* thus, coroutines don't need heavy synchronization (like mutex)\n\t *\t\t* coroutines are said to be lighter than thread during context switch\n\t *\t\t* coroutines don't replace preemptives threads, they have their own application domain\n\t *\n\t *\n\t *\tPlease note that this class is really simple (compared to what can be done with coroutines)\n\t *\tbut match the need for a very simple mean to have two task running side by side with\n\t *\tpredefined sync point.\n\t *\tYou can build the same think using thread and mutex, but it will be a lot more complex\n\t *\tto build and debug.\n\t *\n\t *  A simple sample :\n\t *\tCMyTask : public CCoTask\n\t *\t{\n\t *\tpublic:\n\t *\t\tvoid run()\n\t *\t\t{\n\t *\t\t\tfor (uint i=0; i<7; ++i)\n\t *\t\t\t{\n\t *\t\t\t\tprintf(\"CoTask : %i\\n\", i)\n\t *\t\t\t\t// leave control to parent task\n\t *\t\t\t\tyield();\n\t *\t\t\t}\n\t *\t\t}\n\t *\t};\n\t *\n\t *\tuint main()\n\t *\t{\n\t *\t\tCMyTask task;\n\t *\t\t// start the task, block until task terminate or call 'yield'\n\t *\t\ttask.resume();\n\t *\n\t *\t\tfor (uint i=0; i<5; ++i)\n\t *\t\t{\n\t *\t\t\tprintf(\"Main : %i\\n\", i);\n\t *\t\t\t// let the task run a bit\n\t *\t\t\ttask.resume();\n\t *\t\t}\n\t *\n\t *\t\t// wait for task completion\n\t *\t\ttask.wait();\n\t *\t}\n\t *\n\t *\tThis little proggy will output the following :\n\t *\t*********** Output *************\n\t *\tCoTask : 1\n\t *\tMain : 1\n\t *\tCoTask : 2\n\t *\tMain : 2\n\t *\tCoTask : 3\n\t *\tMain : 3\n\t *\tCoTask : 4\n\t *\tMain : 4\n\t *\tCoTask : 5\n\t *\tCoTask : 6\n\t *\t*********** End of output ********\n\t *\n\t *\n\t */\n\tclass CCoTask\n\t{\n\t\t/// Flag stating if the task is started or not\n\t\tbool\t_Started;\n\t\t/// Flag statig if the task should terminate as soon as possible\n\t\tbool\t_TerminationRequested;\n\t\t/// Flag stating if the task is finished (run() have returned)\n\t\tbool\t_Finished;\n\n\t\t/// Pointer on internal platform specific data\n\t\tTCoTaskData\t*_PImpl;\n\n\t\tfriend struct TCoTaskData;\n\n\t\t/// Coroutine bootstrap function\n\t\tvoid start();\n\tpublic:\n\n\t\t/** Get the current task object.\n\t\t *\tReturn NULL if the current thread context is not in a CCoTask coroutine\n\t\t */\n\t\tstatic CCoTask *getCurrentTask();\n\n\t\t/** Constructor with stack size for the task.\n\t\t *\tThe default stack size is 8 KB because it sound cool and because\n\t\t *\tI found many coroutine code that use a 8 KB stack.\n\t\t *\tIf you need to start many (more than some 10th) tasks with very\n\t\t *\tlittle stack usage, you could reduce you coroutine memory overhead\n\t\t *\tby lowering the stack size.\n\t\t */\n\t\tCCoTask(uint stackSize = NL_TASK_STACK_SIZE);\n\t\t/** Destructor. If the task is running, set the termination requested flag\n\t\t *\tand resume the task until it terminate.\n\t\t *\tIf you task is badly designed, your destructor will never return, waiting\n\t\t *\tindefinitely for the task to terminate.\n\t\t */\n\t\tvirtual ~CCoTask();\n\n\t\t/* Start or resume task execution.\n\t\t * If called from the current task context, do nothing (execution continue in the\n\t\t * current task)\n\t\t */\n\t\tvoid resume();\n\n\t\t/// to call from the task, yield execution focus to parent task\n\t\tvoid yield();\n\n\t\t/** Check if task is started.\n\t\t *\tA task is not started until you call resume().\n\t\t */\n\t\tbool isStarted()\n\t\t{\n\t\t\treturn _Started;\n\t\t}\n\t\t/// check for task completion\n\t\tbool isFinished()\n\t\t{\n\t\t\treturn _Finished;\n\t\t}\n\n\t\t/// parent task ask for task ending (run function should check this and terminate asap)\n\t\tvoid requestTerminate();\n\n\t\t/** check if termination request have been called (mainly used by task user code\n\t\t *\tto check for terminating the task on request).\n\t\t */\n\t\tbool isTerminationRequested()\n\t\t{\n\t\t\treturn _TerminationRequested;\n\t\t}\n\n\t\t/** Called by parent task, wait until the task terminate. Note obviously that this call can lead to an\n\t\t *\tinfinite wait if the task function is not willing to terminate itself.\n\t\t */\n\t\tvoid wait();\n\n\t\t/** the run method to implement by the derived class. This is where\n\t\t *\tyou put the co routine code.\n\t\t *\tCoroutine terminate when this method return.\n\t\t */\n\t\tvirtual void run() =0;\n\n\t\t/** Wait (using 'yield') until some amount of time (in milliseconds) has ellapsed, or until termination is requested.\n\t\t *  This should be called inside this task 'run()', else an assertion is raised\n\t\t */\n\t\tvoid sleep(uint milliseconds);\n\n\n\t};\n\n\n} // namespace NLMISC\n\n#endif // NL_CO_TASK_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/command.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_COMMAND_H\n#define NL_COMMAND_H\n\n#include \"types_nl.h\"\n#include \"twin_map.h\"\n\n#include <string>\n#include <map>\n#include <set>\n#include <vector>\n//#include <sstream>\n#include <istream>\n\n#include \"stream.h\"\n#include \"config_file.h\"\n#include \"log.h\"\n\n\nnamespace NLMISC {\n\n/** WARNING:\n *   This is standard Unix linker behavior: object files\n *   that are not referenced from outside are discarded. The\n *   file in which you run your constructor is thus simply\n *   thrown away by the linker, which explains why the constructor\n *   is not run.\n */\n\n/**\n * Create a function that can be call in realtime.\n *\n * Example:\n * \\code\n\t// I want to create a function that computes the square of the parameter and display the result\n\tNLMISC_COMMAND(square,\"display the square of the parameter\",\"<value>\")\n\t{\n\t\t// check args, if there s not the right number of parameter, return bad\n\t\tif(args.size() != 1) return false;\n\t\t// get the value\n\t\tuint32 val;\n\t\tfromString(args[0], val);\n\t\t// display the result on the displayer\n\t\tlog.displayNL(\"The square of %d is %d\", val, val*val);\n\t\treturn true;\n\t}\n * \\endcode\n *\n * Please use the same casing than for the function (first letter in lower case and after each word first letter in upper case)\n * ie: myFunction, step, orderByName, lookAtThis\n *\n * System extended by Sadge July 2004\n *  - NLMISC_CATEGORISED_COMMAND now takes a 4th 'category' parameter which is used by 'help' system to organise cmmands\n *  - All default commands added by NeL are categorised as \"nel\"\n *  - All commands created using the NLMISC_COMMAND macro are are categorised as \"commands\"\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\n#define NLMISC_COMMAND(__name,__help,__args) NLMISC_CATEGORISED_COMMAND(commands,__name,__help,__args)\n#define NLMISC_CATEGORISED_COMMAND(__category,__name,__help,__args) \\\nstruct __category##_##__name##Class: public NLMISC::ICommand \\\n{ \\\n\t__category##_##__name##Class() : NLMISC::ICommand(#__category,#__name,__help,__args) { } \\\n\tvirtual bool execute(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human); \\\n}; \\\n__category##_##__name##Class __category##_##__name##Instance; \\\nbool __category##_##__name##Class::execute(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\n/** Helper to declare a command as friend of a class.\n *\tUseful when you want to declare debug command that access private class method or data.\n*/\n#define NLMISC_COMMAND_FRIEND(__name) friend struct commands_##__name##Class\n#define NLMISC_CATEGORISED_COMMAND_FRIEND(__category,__name) friend struct __category##_##__name##Class\n\n/**\n * Create a function that can be call in realtime. Don't use this class directly but use the macro NLMISC_COMMAND\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass ICommand\n{\npublic:\n\n\t/// Constructor\n\tICommand(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs);\n\n\tvirtual ~ICommand();\n\n\t// quiet means that we don't display anything else than the value\n\t// human means that we want the value in a human readable if possible\n\tvirtual bool execute(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human = true) = 0;\n\n\tstd::string CategoryName;\n\tstd::string HelpString;\n\tstd::string CommandArgs;\n\n\t// is it a variable or a classic command?\n\tenum TType { Unknown, Command, Variable };\n\tTType Type;\n\n\t// static members\n\n\ttypedef std::map<std::string, ICommand *> TCommand;\n//\ttypedef std::set<std::string> TCategorySet;\n\n\tstatic TCommand\t\t*LocalCommands;\n//\tstatic TCategorySet\t*LocalCategories;\n//\tstatic TCommand\t\t*LocalCommands;\n\tstatic bool\t\t\tLocalCommandsInit;\n\n\t/// Executes the command and display output to the log\n\t/// \\param quiet true if you don't want to display the \"executing the command ...\"\n\tstatic bool execute (const std::string &commandWithArgs, NLMISC::CLog &log, bool quiet = false, bool human = true);\n\n\t/** Command name completion.\n\t * Case-sensitive. Displays the list after two calls with the same non-unique completion.\n     * Completes commands used with prefixes (such as \"help \" for example) as well.\n\t */\n\tstatic void\texpand (std::string &commandName, NLMISC::CLog &log=*InfoLog);\n\n\tstatic void serialCommands (IStream &f);\n\n\t/// returns true if the command exists\n\tstatic bool exists (std::string const &commandName);\n\n\t/// if the string begin with an upper case, it s a variable, otherwise, it s a command\n\tstatic bool isCommand (const std::string &str);\n\n\t/// Retrieve the interface over command object for the given command name.\n\tstatic ICommand *getCommand(const std::string &commandName);\n\n\tconst std::string &getName () const { return _CommandName; }\n\n\t/** declare a command to \"enable control char\". By default all commands \"enable control char\"\n\t *\n\t *\teg: if enableControlCharForCommand(\"region\", false) is called, then the command:\n\t *\n\t *\tregion hello; \"i am busy\" \\never disturb me please\n\t *\n\t *\twon't treat '\"', '\\' and ';' as special control character.\n\t *\tThus the final list of args will be (separated by '/' here for clarity):\n\t *\n\t *\thello;/\"i/am/busy\"/\\never/disturb/me/please\n\t */\n\tstatic void\tenableControlCharForCommand(const std::string &commandName, bool state);\n\n\t/// see enableControlCharForCommand()\n\tstatic bool\tisControlCharForCommandEnabled(const std::string &commandName);\n\nprotected:\n\n\tstd::string _CommandName;\n\n};\n\n\n/** Struct to host data for one object command\n * \\author Boris 'SoniX' Boucher\n * \\author Nevrax France\n * \\date 2005\n */\nstruct TCommandHandlerInfo\n{\n\t/// The help string of the command\n\tstd::string\t\tCommandHelp;\n\t/// The argument required for the command\n\tstd::string\t\tCommandArgs;\n\n\t/// A comparison operator need for STL container storage\n\tbool operator ==(const TCommandHandlerInfo &other) const\n\t{\n\t\treturn (CommandHelp == other.CommandHelp) && (CommandArgs == other.CommandArgs);\n\t}\n};\n\n/** Struct to host data for all the commands of an object class\n * \\author Boris 'SoniX' Boucher\n * \\author Nevrax France\n * \\date 2005\n */\nstruct TCommandHandlerClassInfo\n{\n\t/// Number of instance of object of this class\n\tuint32\t\t\tInstanceCount;\n\n\t/// The list of command available on this class of object.\n\ttypedef std::map<std::string, TCommandHandlerInfo>\tTCommandsInfo;\n\tTCommandsInfo\t_Commands;\n\n\t/// Constructor.\n\tTCommandHandlerClassInfo()\n\t\t: InstanceCount(0)\n\t{}\n};\n\n\n/** Base class for command handler.\n *\tCommand handler are a mean to build object that support NeL commands\n *\t_Commands are associated to object class and invoked to named instance.\n *\tEach named instance must have a unique name (whatever it's class).\n *\tUnlike NeL global commands, object commands are invoked in the context\n *\tof the object instance.\n *\n *\tIn order to write an object that support commands, you must devive from\n *\ttemplate<class MyClass> CCommandsHandler. The class ICommandsHandler\n *\tis used by the command registry to handle any type of object.\n *\n * \\author Boris 'SoniX' Boucher\n * \\author Nevrax France\n * \\date 2005\n */\nclass ICommandsHandler\n{\n\t/// Store the class name after handler registration\n\tconst std::string\t\t*_ClassName;\npublic:\n\n\tICommandsHandler();\n\n\t/** The derived class call this method to register the instance in\n\t *\tthe command registry.\n\t *\tBefore calling this method, the object is not available for\n\t *\tcommands invocation.\n\t */\n\tvoid registerCommandsHandler();\n\t/** The derived class call this method to unregister the instance in\n\t *\tthe command registry.\n\t *\tAfter this call, the object is no more liste in named object\n\t *\tlist nor it can receive command invocation.\n\t *\tYou can later re-register the object.\n\t */\n\tvoid unregisterCommandsHandler();\n\n\tvirtual const std::string &getCommandHandlerClassName() const =0;\n\n\t/** This methods implemented by CCommandHandler is used by the\n\t *\tcommand registry to retrieve the name of the object instance.\n\t */\n\tvirtual const std::string &getCommandHandlerName() const =0;\n\n\t/** This methods implemented by CCommandHandler is used by the\n\t *\tcommand registry to build the list of available commands\n\t *\ton the object class.\n\t */\n\tvirtual void fillCommandsHandlerList(TCommandHandlerClassInfo::TCommandsInfo &commandList) =0;\n\n\t/** Virtual destructor to unregister the object instance.\n\t *\tWhen all the instance of a given class are deleted,\n\t *\tthe associated command an class information are\n\t *\tremoved from the command registry.\n\t */\n\tvirtual ~ICommandsHandler();\n\n\t/** This methods implemented by CCommandHandler is used by the\n\t *\tcommand registry to start a command execution.\n\t */\n\tvirtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human = true) =0;\n};\n\ntemplate <class T>\nstruct TCommandHandler : public TCommandHandlerInfo\n{\n\ttypedef bool (T::*TCommand)(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human);\n\n\tTCommand\tCommandHandler;\n};\n\n\n/** Template class used as base for derivation of object that support commands.\n *\tTo declare your object supporting commands, you must\n *\tderive from this class with your class type as template parameter.\n *\n *\te.g :\n *\tclass CMyClass : public CCommandsHandler<CMyClass>\n *\t{\n *\t};\n *\n *\tTo easily generate the command table, NeL provide some macros :\n *\n *\tclass CMyClass : public CCommandsHandler<CMyClass>\n *\t{\n *\tpublic:\n *\n *\t\tNLMISC_COMMAND_HANDLER_TABLE_BEGIN(CMyClass)\n *\t\t\tNLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand1, \"help\", \"args\")\n *\t\t\tNLMISC_COMMAND_HANDLER_ADD(CMyClass, theCommand2, \"other help\", \"other args\")\n *\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n *\n *\t\tNLMISC_CLASS_COMMAND_DECL(theCommand1)\n *\t\t{\n *\t\t\t// put yout code here\n *\t\t}\n *\n *\t\tNLMISC_CLASS_COMMAND_DECL(theCommand2)\n *\t\t{\n *\t\t\t// put yout code here\n *\t\t}\n *\t};\n *\n *\tYou can also derive a class and add some more commands in the\n *\tderived class by using NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN:\n *\n *\tclass CMyDerivedClass : public CMyClass\n *\t{\n *\t\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CMyClass)\n *\t\t\tNLMISC_COMMAND_HANDLER_ADD(CMyClass, addedCommand, \"help\", \"args\")\n *\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n *\n *\t\tNLMISC_CLASS_COMMAND_DECL(addedCommand)\n *\t\t{\n *\t\t\t// put yout code here\n *\t\t}\n *\t};\n *\n * \\author Boris 'SoniX' Boucher\n * \\author Nevrax France\n * \\date 2005\n */\n//template <class T>\n//class CCommandsHandler : public ICommandsHandler\n//{\n//public:\n//\t/** Constructor, used to initialise the class name in the interface class */\n////\tCCommandsHandler()\n////\t\t: ICommandsHandler(T::getCommandHandlerClassName())\n////\t{\n////\t}\n////\n//\t/** Virtual pure method used by execute to retrieve the method pointer.\n//\t *\tThis method will be automatically implemented by the NLMISC_COMMAND_HANDLER_TABLE_BEGIN\n//\t *\tmacro utility.\n//\t */\n////\tvirtual TCommand getCommandHandler(const std::string &commandName) =0;\n//\n//\t/** Execute a command.\n//\t *\tReturn false if no command of the name exist.\n//\t */\n////\tbool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human = true)\n////\t{\n////\t\tTCommand cmd = getCommandHandler(commandName);\n////\t\tif (cmd != NULL)\n////\t\t{\n////\t\t\tT* tp = static_cast<T*>(this);\n////\t\t\treturn (tp->*cmd)(rawCommandString, args, log, quiet, human);\n////\t\t}\n////\t\telse\n////\t\t{\n////\t\t\tlog.displayNL(\"Command on object '%s' : unknow command '%s'\",\n////\t\t\t\tgetCommandHandlerName().c_str(),\n////\t\t\t\tcommandName.c_str());\n////\t\t\treturn false;\n////\t\t}\n////\t}\n//};\n\n/** Macro to start a command handler table.\n *\tUse it inside the class declaration.\n */\n#define NLMISC_COMMAND_HANDLER_TABLE_BEGIN(className)\t\\\n\t/* Typedef a method pointer on the template class.\t\t*/\t\\\n\t/*\tThis type is the type of the command handler method.*/\t\\\n\t/*\tIt have the same signature as global NeL commands.\t*/\t\\\n\ttypedef bool (className::*TCommand)(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human);\t\\\n\t\\\n\t/** Typedef for a container for command handler table. */\t\\\n\ttypedef std::map<std::string, NLMISC::TCommandHandler<className> >\tTCommandsTable;\t\\\n\t\\\n\tvirtual const std::string &getCommandHandlerClassName()\tconst\\\n\t{\t\\\n\t\tstatic std::string className(#className);\t\\\n\t\treturn className;\t\\\n\t}\t\\\n\tTCommand className##_getCommandHandler(const std::string &commandName)\t\\\n\t{\t\\\n\t\tTCommandsTable\tcommandTable = className##_getCommandsHandlerTable();\t\\\n\t\tTCommandsTable::iterator it = commandTable.find(commandName);\t\\\n\t\t\\\n\t\tif (it != commandTable.end())\t\\\n\t\t{\t\\\n\t\t\t/** ok, we have the command handler*/\t\\\n\t\t\treturn it->second.CommandHandler;\t\\\n\t\t}\t\\\n\t\telse\t\\\n\t\t\treturn NULL;\t\\\n\t}\t\\\n\tvirtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human) \\\n\t{ \\\n\t\tTCommand cmd = className##_getCommandHandler(commandName); \\\n\t\tif (cmd != NULL) \\\n\t\t{ \\\n\t\t\tif (!quiet)\\\n\t\t\t\tlog.displayNL(\"Execute command: %s\", rawCommandString.c_str()); \\\n\t\t\treturn (this->*cmd)(rawCommandString, args, log, quiet, human); \\\n\t\t} \\\n\t\telse \\\n\t\t{ \\\n\t\t\tlog.displayNL(\"Command on object '%s' : unknow command '%s'\", \\\n\t\t\t\tgetCommandHandlerName().c_str(), \\\n\t\t\t\tcommandName.c_str()); \\\n\t\t\treturn false; \\\n\t\t} \\\n\t} \\\n\tvirtual void fillCommandsHandlerList(NLMISC::TCommandHandlerClassInfo::TCommandsInfo &commandList)\t\\\n\t{\t\\\n\t\tconst TCommandsTable\t&commandTable = className##_getCommandsHandlerTable();\t\\\n\t\tTCommandsTable::const_iterator first(commandTable.begin()), last(commandTable.end());\t\\\n\t\tfor (; first != last; ++first)\t\\\n\t\t{\t\\\n\t\t\tcommandList.insert(std::make_pair(first->first, first->second));\t\\\n\t\t}\t\\\n\t}\t\\\n\t\\\n\tconst TCommandsTable &className##_getCommandsHandlerTable()\t\\\n\t{\t\\\n\t\tstatic bool initialized = false;\t\\\n\t\tstatic TCommandsTable\tcommandsTable;\t\\\n\t\\\n\t\tif (!initialized)\t\\\n\t\t{\t\\\n\t\t\tinitialized = true; \\\n\n\n/** Macro to add a handler in the handler table.\n *\tUse this macro between NLMISC_COMMAND_HANDLER_TABLE_BEGIN and\n *\tNLMISC_COMMAND_HANDLER_TABLE_END macros.\n *\n *\tThe command name must match a method of the class with\n *\ta command signature.\n *\tYou can easily declare command method using the macro\n *\tNLMISC_CLASS_COMMAND_DECL\n *\n */\n#define NLMISC_COMMAND_HANDLER_ADD(className, theCommandName, theCommandHelp, theCommandArgs) \\\n\t\t\t{\t\\\n\t\t\t\tNLMISC::TCommandHandler<className> ch;\t\\\n\t\t\t\tch.CommandArgs = theCommandArgs;\t\\\n\t\t\t\tch.CommandHelp = theCommandHelp;\t\\\n\t\t\t\tch.CommandHandler = &className::cmdHandler_##theCommandName; \\\n\t\t\t\tcommandsTable.insert(std::make_pair(std::string(#theCommandName), ch));\t\\\n\t\t\t}\t\\\n\n/** Macro to end the command handler table.\n *\tMust be put after the last command handler adding.\n */\n#define NLMISC_COMMAND_HANDLER_TABLE_END\t\\\n\t\t}\t\\\n\t\treturn commandsTable; \\\n\t}\t\\\n\n/** Macro to add commands in a class that derive from a class\n *\tthat already declare a command handler table.\n *\tthe most derivative class will override base class commands\n *\tif they have the same name.\n */\n#define NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(className, baseClassName)\t\\\n\ttypedef bool (className::*TCommand)(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human);\t\\\n\ttypedef std::map<std::string, NLMISC::TCommandHandler<className> >\tTCommandsTable;\t\\\n\tvirtual const std::string &getCommandHandlerClassName()\tconst\\\n\t{\t\\\n\t\tstatic std::string className(#className);\t\\\n\t\treturn className;\t\\\n\t}\t\\\n\tTCommand className##_getCommandHandler(const std::string &commandName)\t\\\n\t{\t\\\n\t\tTCommandsTable\tcommandTable = className##_getCommandsHandlerTable();\t\\\n\t\tTCommandsTable::iterator it = commandTable.find(commandName);\t\\\n\t\t\\\n\t\tif (it != commandTable.end())\t\\\n\t\t{\t\\\n\t\t\t/* ok, we have the command handler*/\t\\\n\t\t\treturn it->second.CommandHandler;\t\\\n\t\t}\t\\\n\t\telse\t\\\n\t\t{ \\\n\t\t\treturn NULL;\\\n\t\t} \\\n\t}\t\\\n\tvirtual bool execute(const std::string &rawCommandString, const std::string &commandName, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human) \\\n\t{ \\\n\t\tTCommand cmd = className##_getCommandHandler(commandName); \\\n\t\tif (cmd != NULL) \\\n\t\t{ \\\n\t\t\treturn (this->*cmd)(rawCommandString, args, log, quiet, human); \\\n\t\t} \\\n\t\telse \\\n\t\t{ \\\n\t\t\t/* try with the base class */ \\\n\t\t\treturn baseClassName::execute(rawCommandString, commandName, args, log, quiet, human);\\\n\t\t} \\\n\t} \\\n\tvirtual void fillCommandsHandlerList(NLMISC::TCommandHandlerClassInfo::TCommandsInfo &commandList)\t\\\n\t{\t\\\n\t\tconst TCommandsTable\t&commandTable = className##_getCommandsHandlerTable();\t\\\n\t\tTCommandsTable::const_iterator first(commandTable.begin()), last(commandTable.end());\t\\\n\t\tfor (; first != last; ++first)\t\\\n\t\t{\t\\\n\t\t\tcommandList.insert(std::make_pair(first->first, first->second));\t\\\n\t\t}\t\\\n\t\t/* call base class to complete the command table */ \\\n\t\tbaseClassName::fillCommandsHandlerList(commandList); \\\n\t}\t\\\n\t\\\n\tconst TCommandsTable &className##_getCommandsHandlerTable()\t\\\n\t{\t\\\n\t\tstatic bool initialized = false;\t\\\n\t\tstatic TCommandsTable\tcommandsTable;\t\\\n\t\\\n\t\tif (!initialized)\t\\\n\t\t{\t\\\n\t\t\tinitialized = true; \\\n\n\n// A macro to declare or implement inline the command method\n#define NLMISC_CLASS_COMMAND_DECL(commandName) \\\n\tbool cmdHandler_##commandName(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\n// A macro to implement the command method in a cpp (you still need to declare it in the class scope using the previous macro)\n#define NLMISC_CLASS_COMMAND_IMPL(className, commandName) \\\n\tbool className::cmdHandler_##commandName(const std::string &rawCommandString, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\n// A macro to recall a base class command implementation\n#define NLMISC_CLASS_COMMAND_CALL_BASE(baseClassName, commandName)\\\n\tbaseClassName::cmdHandler_##commandName(rawCommandString, args, log, quiet, human)\n\n/** The command registry is a singleton that hold all available\n *\tcommands.\n *\tIt bridge the legacy global commands and variable with\n *\tthe object commands.\n *\n *\tAll the legacy static call made on ICommand are now forwarded\n *\tdirectly to this class (e.g. IService::execute)\n *\n *\tThis class is modeled after the safe singlton pattern,\n *\tso it is safe to use in a dynamicaly loaded library\n *\tprogram.\n *\n * \\author Boris 'SoniX' Boucher\n * \\author Nevrax France\n * \\date 2005\n */\nclass CCommandRegistry\n{\n\t// this class is a safe singleton (dll friendly)\n\tNLMISC_SAFE_SINGLETON_DECL(CCommandRegistry);\n\tCCommandRegistry() {}\n\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(nel, help);\n\n\tfriend void cbVarChanged (CConfigFile::CVar &var);\n\tfriend class ICommand;\n\tfriend class ICommandsHandler;\n\tfriend class INelContext;\n\n\ttypedef std::map<std::string, ICommand *>\tTCommand;\n\ttypedef std::set<std::string>\t\t\t\tTCategorySet;\n\n\t/// List of commands categories\n\tTCategorySet\t_Categories;\n\t/// List of available command\n\tTCommand\t\t_Commands;\n\n\ttypedef CTwinMap<std::string, ICommandsHandler *>\tTCommandsHandlers;\n\t/// Registry for commands handlers named instance\n\tTCommandsHandlers\t\t\t_CommandsHandlers;\n\n\ttypedef std::map<std::string, TCommandHandlerClassInfo >\tTCommandsHandlersClass;\n\t/// Registry for commands name and handler class\n\tTCommandsHandlersClass\t\t_CommandsHandlersClass;\n\n\tstd::set<std::string>\t\t_CommandsDisablingControlChar;\n\n\t/// Used by ICommand to register themselves\n\tvoid registerCommand(ICommand *command);\n\t/// Used by ICommand to unregister themselves\n\tvoid unregisterCommand(ICommand *command);\n\n\npublic:\n\n\t/// Called by command handlers to register themselves.\n\tvoid registerNamedCommandHandler(ICommandsHandler *handler, const std::string &className);\n\t/// Called by command handlers to unregister themselves.\n\tvoid unregisterNamedCommandHandler(ICommandsHandler *handler, const std::string &className);\n\n\t/// Executes the command and display output to the log\n\t/// \\param quiet true if you don't want to display the \"executing the command ...\"\n\tbool execute (const std::string &commandWithArgs, NLMISC::CLog &log, bool quiet = false, bool human = true);\n\n\t/** Command name completion.\n\t * Case-sensitive. Displays the list after two calls with the same non-unique completion.\n     * Completes commands used with prefixes (such as \"help \" for example) as well.\n\t */\n\tvoid expand (std::string &commandName, NLMISC::CLog &log=*InfoLog);\n\n\tvoid serialCommands (IStream &f);\n\n\t/// returns true if the command exists\n\tbool exists (std::string const &commandName);\n\n\t/// Return true if a named command handler with that name is registered\n\tbool isNamedCommandHandler(const std::string &handlerName);\n\n\t/// if the string begin with an upper case, it s a variable, otherwise, it s a command\n\tbool isCommand (const std::string &str);\n\n\t/// Retrieve the interface over command object for the given command name.\n\tICommand *getCommand(const std::string &commandName);\n\n\t/** declare a command to \"enable control char\". By default all commands \"enable control char\"\n\t *\n\t *\teg: if enableControlCharForCommand(\"region\", false) is called, then the command:\n\t *\n\t *\tregion hello; \"i am busy\" \\never disturb me please\n\t *\n\t *\twon't treat '\"', '\\' and ';' as special control character.\n\t *\tThus the final list of args will be (separated by '/' here for clarity):\n\t *\n\t *\thello;/\"i/am/busy\"/\\never/disturb/me/please\n\t */\n\tvoid\tenableControlCharForCommand(const std::string &commandName, bool state);\n\n\t/// see enableControlCharForCommand()\n\tbool\tisControlCharForCommandEnabled(const std::string &commandName);\n\n\t// initialisation for IVariable management (variable are an extension of commands)\n\tvoid initVariables(NLMISC::CConfigFile &configFile);\n\n};\n\n/** This class is only used to serialize easily a command for the admin service for example */\nstruct CSerialCommand\n{\n\tCSerialCommand () : Name (\"<Unknown>\"), Type(ICommand::Unknown) { }\n\tCSerialCommand (std::string n, ICommand::TType t) : Name (n), Type(t) { }\n\n\tstd::string Name;\n\tICommand::TType Type;\n\n\tvoid serial (IStream &f)\n\t{\n\t\tf.serial (Name);\n\t\tf.serialEnum (Type);\n\t}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_COMMAND_H\n\n/* End of command.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/common.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef\tNL_COMMON_H\n#define\tNL_COMMON_H\n\n#include \"types_nl.h\"\n\n#include <cctype>\n#include <cstdio>\n#include <cmath>\n#include <cstring>\n#include <string>\n#include <vector>\n#include <cfloat>\n#include <cstdarg>\n#include <cstdlib>\n#include <algorithm>\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <process.h>\n#\tinclude <intrin.h>\n#else\n#\tinclude <unistd.h>\n#\tinclude <sys/types.h>\n#endif\n\n#include \"string_common.h\"\n\n#ifdef NL_OS_WINDOWS\n\tstruct nameHWND__;\n\ttypedef struct HWND__ *HWND;\n\ttypedef HWND nlWindow;\n\t#define EmptyWindow NULL\n#elif defined(NL_OS_MAC)\n\t// TODO This should be NSView*, but then we would need to include Cocoa.h\n\t//   and compile with \"-x objective-c++\" ... everything including this file.\n\ttypedef void* nlWindow;\n\t#define EmptyWindow NULL\n#elif defined(NL_OS_UNIX)\n\ttypedef int nlWindow;\n\t#define EmptyWindow 0\n#endif\n\n/// This namespace contains all miscellaneous classes used by other modules\nnamespace\tNLMISC\n{\n\n/** Read the time stamp counter. Supports only Intel architectures for now\n  */\n#ifdef NL_CPU_INTEL\n\ninline uint64 rdtsc()\n{\n\tuint64 ticks;\n#\tifdef NL_OS_WINDOWS\n#\tifdef NL_NO_ASM\n\t\tticks = uint64(__rdtsc());\n#\telse\n\t\t// We should use the intrinsic code now. ticks = uint64(__rdtsc());\n\t\t__asm\trdtsc\n\t\t__asm\tmov\t\tDWORD PTR [ticks], eax\n\t\t__asm\tmov\t\tDWORD PTR [ticks + 4], edx\n#\tendif // NL_NO_ASM\n#\telse\n\t\t__asm__ volatile(\".byte 0x0f, 0x31\" : \"=a\" (ticks.low), \"=d\" (ticks.high));\n#\tendif // NL_OS_WINDOWS\n\treturn ticks;\n}\n\n#endif\t// NL_CPU_INTEL\n\n\n/** breakable statement, used to allow break call inside parenthesis.\n */\n#define\t\tbreakable\t\\\n\tswitch(1) case 1: default:\n\n\n/** Pi constant in double format.\n */\nconst double Pi = 3.1415926535897932384626433832795;\n\n\n// retrieve size of a static array\n#define sizeofarray(v) (sizeof(v) / sizeof((v)[0]))\n\n/** Return a float random inside the interval [0,mod]\n */\ninline float frand(float mod)\n{\n\tdouble\tr = (double) rand();\n\tr/= (double) RAND_MAX;\n\treturn (float)(r * mod);\n}\n\n\n/** Return -1 if f<0, 0 if f==0, 1 if f>1\n */\ninline sint fsgn(double f)\n{\n\tif(f<0)\n\t\treturn -1;\n\telse if(f>0)\n\t\treturn 1;\n\telse\n\t\treturn 0;\n}\n\n\n/** Return the square of a number\n */\ntemplate<class T>\tinline T sqr(const T &v)\n{\n\treturn v * v;\n}\n\n\n/** Force v to be inside the interval [min,max]. Warning: implicit cast are made if T,U or V are different.\n */\ntemplate<class T, class U, class V>\tinline void clamp(T &v, const U &min, const V &max)\n{\n\tv = (v < min) ? min : v;\n\tv = (v > max) ? max : v;\n}\n\n\n/** MIN/MAX extended functions.\n */\ntemplate<class T>\tinline T minof(const T& a,  const T& b,  const T& c)\n\t{return std::min(std::min(a,b),c);}\ntemplate<class T>\tinline T minof(const T& a,  const T& b,  const T& c,  const T& d)\n\t{return std::min(minof(a,b,c),d);}\ntemplate<class T>\tinline T minof(const T& a,  const T& b,  const T& c,  const T& d,  const T& e)\n\t{return std::min(minof(a,b,c,d),e);}\ntemplate<class T>\tinline T maxof(const T& a,  const T& b,  const T& c)\n\t{return std::max(std::max(a,b),c);}\ntemplate<class T>\tinline T maxof(const T& a,  const T& b,  const T& c,  const T& d)\n\t{return std::max(maxof(a,b,c),d);}\ntemplate<class T>\tinline T maxof(const T& a,  const T& b,  const T& c,  const T& d,  const T& e)\n\t{return std::max(maxof(a,b,c,d),e);}\n\n/** \\c contReset take a container like std::vector or std::deque and put his size to 0 like \\c clear() but free all buffers.\n * This function is useful because \\c resize(), \\c clear(), \\c erase() or \\c reserve() methods never realloc when the array size come down.\n * \\param a is the container to reset.\n */\ntemplate<class T>\tinline void contReset (T& a)\n{\n\ta.~T();\n\tnew (&a) T;\n}\n\n/** Return the value maximized to the next power of 2 of v.\n * Example:\n *   raiseToNextPowerOf2(8) is 8\n *   raiseToNextPowerOf2(5) is 8\n */\nuint\t\t\traiseToNextPowerOf2 (uint v);\n\n/** Return the power of 2 of v.\n * Example:\n *   getPowerOf2(8) is 3\n *   getPowerOf2(5) is 3\n */\nuint\t\t\tgetPowerOf2 (uint v);\n\n/** Return \\c true if the value is a power of 2.\n */\nbool\t\t\tisPowerOf2 (sint32 v);\n\n\n/** Converts from degrees to radians\n */\ninline float\tdegToRad( float deg )\n{\n\treturn deg * (float)Pi / 180.0f;\n}\n\n\n/** Converts from radians to degrees\n */\ninline float\tradToDeg( float rad )\n{\n\treturn rad * 180.0f / (float)Pi;\n}\n\n\n/** Return true if double is a valid value (not inf nor nan)\n */\ninline double\tisValidDouble (double v)\n{\n#ifdef NL_OS_WINDOWS\n\treturn _finite(v) && !_isnan(v);\n#else\n#ifdef _STLPORT_VERSION\n\treturn !isnan(v) && !isinf(v);\n#else\n\treturn !std::isnan(v) && !std::isinf(v);\n#endif\n#endif\n}\n\n\n/** Convert a string in lower case.\n * \\param str a string to transform to lower case\n */\n\nstd::string\ttoLower ( const std::string &str );\nvoid\t\ttoLower ( char *str );\nchar\t\ttoLower ( const char ch );\t// convert only one character\n\n/** Convert a string in upper case.\n * \\param a string to transform to upper case\n */\n\nstd::string\ttoUpper ( const std::string &str);\nvoid\t\ttoUpper ( char *str);\n\n// Remove all the characters <= 32 (tab, space, new line, return, vertical tab etc..) at the beginning and at the end of a string\ntemplate <class T> T trim (const T &str)\n{\n\ttypename T::size_type start = 0;\n\tconst typename T::size_type size = str.size();\n\twhile (start < size && str[start] <= 32)\n\t\tstart++;\n\ttypename T::size_type end = size;\n\twhile (end > start && str[end-1] <= 32)\n\t\tend--;\n\treturn str.substr (start, end-start);\n}\n\n// remove spaces at the end of the string\ntemplate <class T> T trimRightWhiteSpaces (const T &str)\n{\n\ttypename T::size_type end = str.size();\n\twhile (end > 0 && str[end-1] == ' ')\n\t\tend--;\n\treturn str.substr (0, end);\n}\n\n//////////////////////////////////////////////////////////////////////////\n// ****  DEPRECATED *****: PLEASE DON'T USE THESE METHODS BUT FUNCTIONS ABOVE toLower() and toUpper()\n//////////////////////////////////////////////////////////////////////////\ninline std::string\t\t&strlwr ( std::string &str )\t\t{ str = toLower(str); return str; }\ninline std::string\t\t strlwr ( const std::string &str )\t{ return toLower(str); }\ninline char\t\t\t*strlwr ( char *str )\t\t\t\t{ toLower(str); return str; }\ninline std::string\t\t&strupr ( std::string &str )\t\t{ str = toUpper(str); return str; }\ninline std::string\t\t strupr ( const std::string &str )\t{ return toUpper(str); }\ninline char\t\t\t*strupr ( char *str )\t\t\t\t{ toUpper(str); return str; }\n\n\n/** Compare 2 C-Style strings without regard to case\n  * \\return 0 if strings are equal, < 0 if lhs < rhs, > 0 if lhs > rhs\n  *\n  * On Windows,   use stricmp\n  * On GNU/Linux, create stricmp using strcasecmp and use stricmp\n  */\n#ifndef NL_OS_WINDOWS\ninline int stricmp(const char *lhs, const char *rhs) { return strcasecmp(lhs, rhs); }\ninline int strnicmp(const char *lhs, const char *rhs, size_t n) { return strncasecmp(lhs, rhs, n); }\n#endif\n\ninline sint nlstricmp(const char *lhs, const char *rhs) { return stricmp(lhs, rhs); }\ninline sint nlstricmp(const std::string &lhs, const std::string &rhs) { return stricmp(lhs.c_str(), rhs.c_str()); }\ninline sint nlstricmp(const std::string &lhs, const char *rhs) { return stricmp(lhs.c_str(),rhs); }\ninline sint nlstricmp(const char *lhs, const std::string &rhs) { return stricmp(lhs,rhs.c_str()); }\n\n/** Signed 64 bit fseek. Same interface as fseek\n  */\nint\t\tnlfseek64( FILE *stream, sint64 offset, int origin );\n\n// Retrieve position in a file, same interface as ftell\nsint64  nlftell64(FILE *stream);\n\n/**\n * Base class for all NeL exception.\n * It enables to construct simple string at the ctor.\n */\nclass Exception : public std::exception\n{\nprotected:\n\tstd::string\t_Reason;\npublic:\n\tException();\n\tException(const std::string &reason);\n\tException(const char *format, ...);\n\tvirtual ~Exception() throw() {}\n\tvirtual const char\t*what() const throw();\n};\n\n\n/**\n * Portable Sleep() function that suspends the execution of the calling thread for a number of milliseconds.\n * Note: the resolution of the timer is system-dependant and may be more than 1 millisecond.\n */\nvoid nlSleep( uint32 ms );\n\n\n/// Returns Process Id (note: on Linux, Process Id is the same as the Thread Id)\n#ifdef NL_OS_WINDOWS\n#\tdefine getpid _getpid\n#endif\n\n/// Returns Thread Id (note: on Linux, Process Id is the same as the Thread Id)\nsize_t getThreadId();\n\n/// Returns a readable string from a vector of bytes. unprintable char are replaced by '?'\nstd::string stringFromVector( const std::vector<uint8>& v, bool limited = true );\n\n\n/// Convert a string into an sint64 (same as atoi() function but for 64 bits intergers)\nsint64 atoiInt64 (const char *ident, sint64 base = 10);\n\n/// Convert an sint64 into a string (same as itoa() function but for 64 bits intergers)\nchar* itoaInt64 (sint64 number, char *str, sint64 base = 10);\n\n\n/// Convert a number in bytes into a string that is easily readable by an human, for example 105123 -> \"102kb\"\nstd::string bytesToHumanReadable (const std::string &bytes);\nstd::string bytesToHumanReadable (uint64 bytes);\n\n/// Convert a human readable into a bytes,  for example \"102kb\" -> 105123\nuint32 humanReadableToBytes (const std::string &str);\n\n/// Convert a time into a string that is easily readable by an human, for example 3600 -> \"1h\"\nstd::string secondsToHumanReadable (uint32 time);\n\n\n/// Get a bytes or time in string format and convert it in seconds or bytes\nuint32 fromHumanReadable (const std::string &str);\n\n/// Add digit grouping seperator to if value >= 10 000. Assumes input is numerical string.\nstd::string formatThousands(const std::string& s);\n\n/// This function executes a program in the background and returns instantly (used for example to launch services in AES).\n/// The program will be launched in the current directory\nbool launchProgram (const std::string &programName, const std::string &arguments);\n\n/// This function kills a program using his pid (on unix, it uses the kill() POSIX function)\nbool killProgram(uint32 pid);\n\n/// This function kills a program using his pid with abort signal (on unix, it uses the kill() POSIX function)\nbool abortProgram(uint32 pid);\n\n/** Returns a string corresponding to the class T in string format.\n * Example:\n *  string num = toString (1234); // num = \"1234\";\n */\n/*acetemplate<class T> std::string toString (const T &t)\n{\n\tstd::stringstream ss;\n\tss << t;\n\treturn ss.str();\n}\n*/\n\n/** Returns a string corresponding to the format and parameter (like printf).\n * Example:\n *  string hexnum = toString (\"%x\", 255); // hexnum = \"ff\";\n */\n/*#ifdef NL_OS_WINDOWS\ninline std::string _toString (const char *format, ...)\n#else\ninline std::string toString (const char *format, ...)\n#endif\n{\n\tstd::string Result;\n\tNLMISC_CONVERT_VARGS (Result, format, NLMISC::MaxCStringSize);\n\treturn Result;\n}\n\n#ifdef NL_OS_WINDOWS\nCHECK_TYPES(std::string toString, return _toString)\n#endif // NL_OS_WINDOWS\n\n\n\n#ifdef NL_OS_UNIX\ninline std::string toString (const uint8 &t)\n{\n\tstd::stringstream ss;\n\tss << (unsigned int)t;\n\treturn ss.str();\n}\n\ninline std::string toString (const sint8 &t)\n{\n\tstd::stringstream ss;\n\tss << (unsigned int)t;\n\treturn ss.str();\n}\n#endif // NL_OS_UNIX\n*/\n\n/** Explode a string (or ucstring) into a vector of string with *sep* as separator. If sep can be more than 1 char, in this case,\n * we find the entire sep to separator (it s not a set of possible separator)\n *\n * \\param skipEmpty if true, we don't put in the res vector empty string\n */\ntemplate <class T> void explode (const T &src, const T &sep, std::vector<T> &res, bool skipEmpty = false)\n{\n\tstd::string::size_type oldpos = 0, pos;\n\n\tres.clear ();\n\n\tdo\n\t{\n\t\tpos = src.find (sep, oldpos);\n\t\tT s;\n\t\tif(pos == std::string::npos)\n\t\t\ts = src.substr (oldpos);\n\t\telse\n\t\t\ts = src.substr (oldpos, (pos-oldpos));\n\n\t\tif (!skipEmpty || !s.empty())\n\t\t\tres.push_back (s);\n\n\t\toldpos = pos+sep.size();\n\t}\n\twhile(pos != std::string::npos);\n}\n\n\n/* All the code above is used to add our types (uint8, ...) in the stringstream (used by the toString() function).\n * So we can use stringstream operator << and >> with all NeL simple types (except for ucchar and ucstring)\n */\n/*\n#ifdef NL_OS_WINDOWS\n\n#if _MSC_VER < 1300\t// visual or older (on visual .NET, we don't need to do that)\n\n#define NLMISC_ADD_BASIC_ISTREAM_OPERATOR(__type,__casttype) \\\ntemplate <class _CharT, class _Traits> \\\nstd::basic_istream<_CharT, _Traits>& __cdecl \\\noperator>>(std::basic_istream<_CharT, _Traits>& __is, __type& __z) \\\n{ \\\n\t__casttype __z2 = (__casttype) __z; \\\n\t__is.operator>>(__z2); \\\n\t__z = (__type) __z2; \\\n\treturn __is; \\\n} \\\n \\\ntemplate <class _CharT, class _Traits> \\\nstd::basic_ostream<_CharT, _Traits>& __cdecl \\\noperator<<(std::basic_ostream<_CharT, _Traits>& __os, const __type& __z) \\\n{ \\\n\tstd::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp; \\\n\t__tmp << (__casttype) __z; \\\n\treturn __os << __tmp.str(); \\\n}\n\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint8, unsigned int);\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint8, signed int);\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint16, unsigned int);\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint16, signed int);\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(uint32, unsigned int);\nNLMISC_ADD_BASIC_ISTREAM_OPERATOR(sint32, signed int);\n\n#endif // _MSC_VER < 1300\n\n\ntemplate <class _CharT, class _Traits>\nstd::basic_istream<_CharT, _Traits>& __cdecl\noperator>>(std::basic_istream<_CharT, _Traits>& __is, uint64& __z)\n{\n\t__z = 0;\n\tbool neg = false;\n\tchar c;\n\tdo\n\t{\n\t\t__is >> c;\n\t}\n\twhile (isspace(c));\n\n\tif (c == '-')\n\t{\n\t\tneg = true;\n\t\t__is >> c;\n\t}\n\n\twhile (isdigit(c))\n\t{\n\t\t__z *= 10;\n\t\t__z += c-'0';\n\t\t__is >> c;\n\t\tif (__is.fail())\n\t\t\tbreak;\n\t}\n\n\tif (neg) __z = 0;\n\n\treturn __is;\n}\n\ntemplate <class _CharT, class _Traits>\nstd::basic_ostream<_CharT, _Traits>& __cdecl\noperator<<(std::basic_ostream<_CharT, _Traits>& __os, const uint64& __z)\n{\n\tstd::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res;\n\n\tif (__z == 0)\n\t{\n\t\t__res << '0';\n\t}\n\telse\n\t{\n\t\tstd::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp;\n\t\tuint64\t__z2 = __z;\n\t\twhile (__z2 != 0)\n\t\t{\n\t\t\t__tmp << (char)((__z2%10)+'0');\n\t\t\t__z2 /= 10;\n\t\t}\n\n\t\tuint __s = __tmp.str().size();\n\t\tfor (uint i = 0; i < __s; i++)\n\t\t\t__res << __tmp.str()[__s - 1 - i];\n\t}\n\treturn __os << __res.str();\n}\n\ntemplate <class _CharT, class _Traits>\nstd::basic_istream<_CharT, _Traits>& __cdecl\noperator>>(std::basic_istream<_CharT, _Traits>& __is, sint64& __z)\n{\n\t__z = 0;\n\tbool neg = false;\n\tchar c;\n\tdo\n\t{\n\t\t__is >> c;\n\t}\n\twhile (isspace(c));\n\n\tif (c == '-')\n\t{\n\t\tneg = true;\n\t\t__is >> c;\n\t}\n\n\twhile (isdigit(c))\n\t{\n\t\t__z *= 10;\n\t\t__z += c-'0';\n\t\t__is >> c;\n\t\tif (__is.fail())\n\t\t\tbreak;\n\t}\n\n\tif (neg) __z = -__z;\n\n\treturn __is;\n}\n\ntemplate <class _CharT, class _Traits>\nstd::basic_ostream<_CharT, _Traits>& __cdecl\noperator<<(std::basic_ostream<_CharT, _Traits>& __os, const sint64& __z)\n{\n\tstd::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __res;\n\n\tif (__z == 0)\n\t{\n\t\t__res << '0';\n\t}\n\telse\n\t{\n\t\tsint64\t__z2 = __z;\n\n\t\tif (__z2 < 0)\n\t\t{\n\t\t\t__res << '-';\n\t\t}\n\n\t\tstd::basic_ostringstream<_CharT, _Traits, std::allocator<_CharT> > __tmp;\n\t\twhile (__z2 != 0)\n\t\t{\n\t\t\tif (__z2 < 0)\n\t\t\t{\n\t\t\t\t__tmp << (char)((-(__z2%10))+'0');\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__tmp << (char)((__z2%10)+'0');\n\t\t\t}\n\t\t\t__z2 /= 10;\n\t\t}\n\n\t\tuint __s = __tmp.str().size();\n\t\tfor (uint i = 0; i < __s; i++)\n\t\t\t__res << __tmp.str()[__s - 1 - i];\n\t}\n\treturn __os << __res.str();\n}\n\n#endif // NL_OS_WINDOWS\n*/\n\nclass CLog;\n\n/// Display the bits (with 0 and 1) composing a byte (from right to left)\nvoid displayByteBits( uint8 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log );\n\n/// Display the bits (with 0 and 1) composing a number (uint32) (from right to left)\nvoid displayDwordBits( uint32 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log );\n\n/// this wrapping is due to a visual bug when calling isprint with big value\n/// example of crash with VC6 SP4:\tint a = isprint(0x40e208);\n#ifdef NL_OS_WINDOWS\ninline int nlisprint(int c)\n{\n\tif(c>255||c<0) return 0;\n\treturn isprint(c);\n}\n#else\n#define nlisprint isprint\n#endif\n\n// Open an url in a browser\nbool openURL (const char *url);\n\n// Open a document\nbool openDoc (const char *document);\n\n// AntiBug method that return an epsilon if x==0, else x\ninline float\tfavoid0(float x)\n{\n\tif(x==0)\treturn 0.00001f;\n\treturn x;\n}\ninline double\tdavoid0(double x)\n{\n\tif(x==0)\treturn 0.00001;\n\treturn x;\n}\n// AntiBug method that return 1 if x==0, else x\ntemplate<class T>\ninline T\t\tiavoid0(T x)\n{\n\tif(x==0)\treturn 1;\n\treturn x;\n}\n\n\n} // NLMISC\n\n#endif\t// NL_COMMON_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/config_file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CONFIG_FILE_H\n#define NL_CONFIG_FILE_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n#include \"debug.h\"\n#include \"log.h\"\n\n#include <vector>\n#include <string>\n#include <cstdio>\n\nnamespace NLMISC\n{\n\n/**\n * CConfigFile class. Useful when you want to have a configuration file with variables.\n * It manages integers, real (double), and string basic types. A variable can be an array of\n * basic type. In this case, all elements of the array must have the same type.\n *\n * If you setup the global callback before loading, it'll be called after the load() function.\n *\n * Example:\n *\\code\n * try\n * {\n * \tCConfigFile cf;\n *\n * \t// Load and parse \"test.txt\" file\n *  cf.load (\"test.txt\");\n *\n *\t// Attach a callback to the var1 variable. When the var1 will change, this cvar1cb function will be called\n *\tcf.setCallback (\"var1\", var1cb);\n *\n *\t// Get the foo variable (suppose it's a string variable)\n *\tCConfigFile::CVar &foo = cf.getVar (\"foo\");\n *\n *\t// Display the content of the variable\n *\tprintf (\"foo = %s\\n\", foo.asString ().c_str ());\n *\n * \t// Get the bar variable (suppose it's an array of int)\n * \tCConfigFile::CVar &bar = cf.getVar (\"bar\");\n *\n * \t// Display the content of all the elements of the bar variable\n * \tprintf (\"bar have %d elements : \\n\", bar.size ());\n * \tfor (int i = 0; i < bar.size (); i++)\n * \t\tprintf (\"%d \", bar.asInt (i));\n * \tprintf(\"\\n\");\n * }\n * catch (const EConfigFile &e)\n * {\n *\t// Something goes wrong... catch that\n * \tprintf (\"%s\\n\", e.what ());\n * }\n *\\endcode\n *\n * Example of config file:\n *\\code\n * // one line comment\n * / * big comment\n *     on more than one line * /\n *\n * var1 = 123;                           // var1  type:int,         value:123\n * var2 = \"456.25\";                      // var2  type:string,      value:\"456.25\"\n * var3 = 123.123;                       // var3  type:real,        value:123.123\n *\n * // the resulting type is type of the first left value\n * var4 = 123.123 + 2;                   // var4  type:real,        value:125.123\n * var5 = 123 + 2.1;                     // var5  type:int,         value:125\n *\n * var6 = (-112+1) * 3 - 14;             // var6  type:int,         value:-347\n *\n * var7 = var1 + 1;                      // var7  type:int,         value:124\n *\n * var8 = var2 + 10;                     // var8  type:string,      value:456.2510 (convert 10 into a string and concat it)\n * var9 = 10.15 + var2;                  // var9  type:real,        value:466.4 (convert var2 into a real and add it)\n *\n * var10 = { 10.0, 51.1 };               // var10 type:realarray,   value:{10.0,51.1}\n * var11 = { \"str1\", \"str2\", \"str3\" };   // var11 type:stringarray, value:{\"str1\", \"str2\", \"str3\"}\n *\n * var12 = { 10+var1, var1-var7 };       // var12 type:intarray,    value:{133,-1}\n *\\endcode\n *\n * Operators are '+', '-', '*', '/'.\n * You can't use operators on a array variable, for example, you can't do \\cvar13=var12+1.\n * If you have 2 variables with the same name, the first value will be remplaced by the second one.\n *\n * \\bug if you terminate the config file with a comment without carriage returns it'll generate an exception, add a carriage returns\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CConfigFile\n{\npublic:\n\n\t/**\n\t * CVar class. Used by CConfigFile. A CVar is returned when you want to have a variable.\n\t *\n\t * Example: see the CConfigFile example\n\t *\n\t * \\author Vianney Lecroart\n\t * \\author Nevrax France\n\t * \\date 2000\n\t */\n\tstruct CVar\n\t{\n\tpublic:\n\n\t\tCVar () : Type(T_UNKNOWN), Root(false), Comp(false), FromLocalFile(true), SaveWrap(6) {}\n\n\t\t/// \\name Access to the variable content.\n\t\t//@{\n\t\t/// Get the content of the variable as an integer\n\t\tint\t\t\t\t\tasInt\t\t(int index=0) const;\n\t\t/// Get\tthe content of the variable as a double\n\t\tdouble\t\t\t\tasDouble\t(int index=0) const;\n\t\t/// Get the content of the variable as a float\n\t\tfloat\t\t\t\tasFloat\t\t(int index=0) const;\n\t\t/// Get the content of the variable as a STL string\n\t\tstd::string\t\t\tasString\t(int index=0) const;\n\t\t/// Get the content of the variable as a boolean\n\t\tbool\t\t\t\tasBool\t\t(int index=0) const;\n\t\t//@}\n\n\t\t/// \\name Set the variable content.\n\t\t/// If the index is the size of the array, the value will be append at the end.\n\t\t//@{\n\t\t/// Set the content of the variable as an integer\n\t\tvoid\t\t\t\tsetAsInt\t(int val, int index=0);\n\t\t/// Set\tthe content of the variable as a double\n\t\tvoid\t\t\t\tsetAsDouble\t(double val, int index=0);\n\t\t/// Set the content of the variable as a float\n\t\tvoid\t\t\t\tsetAsFloat\t(float val, int index=0);\n\t\t/// Set the content of the variable as a STL string\n\t\tvoid\t\t\t\tsetAsString\t(const std::string &val, int index=0);\n\n\t\t/// Force the content of the variable to be a single integer\n\t\tvoid\t\t\t\tforceAsInt\t(int val);\n\t\t/// Force the content of the variable to be a single double\n\t\tvoid\t\t\t\tforceAsDouble\t(double val);\n\t\t/// Force the content of the variable to be a single string\n\t\tvoid\t\t\t\tforceAsString\t(const std::string &val);\n\n\t\t/// Set the content of the aray variable as an integer\n\t\tvoid\t\t\t\tsetAsInt\t(const std::vector<int> &vals);\n\t\t/// Set the content of the aray variable as a double\n\t\tvoid\t\t\t\tsetAsDouble\t(const std::vector<double> &vals);\n\t\t/// Set the content of the aray variable as a float\n\t\tvoid\t\t\t\tsetAsFloat\t(const std::vector<float> &vals);\n\t\t/// Set the content of the aray variable as a string\n\t\tvoid\t\t\t\tsetAsString\t(const std::vector<std::string> &vals);\n\n\t\t//@}\n\n\t\tbool\t\toperator==\t(const CVar& var) const;\n\t\tbool\t\toperator!=\t(const CVar& var) const;\n\n\t\t// add this variable with var\n\t\tvoid\t\tadd (const CVar &var);\n\n\t\t// Get the size of the variable. It's the number of element of the array or 1 if it's not an array.\n\t\tuint\t\tsize () const;\n\n\t\t/// \\name Internal use\n\t\t//@{\n\t\tstatic const char *TypeName[];\n\n\t\tenum TVarType { T_UNKNOWN, T_INT, T_STRING, T_REAL, T_BOOL };\n\n\t\tstd::string\t\t\t\t\tName;\n\t\tTVarType\t\t\t\t\tType;\n\t\tbool\t\t\t\t\t\tRoot;\t\t// true if this var comes from the root document. false else.\n\t\tbool\t\t\t\t\t\tComp;\t\t// true if the parser found a 'complex' var (ie an array)\n\t\tbool\t\t\t\t\t\tFromLocalFile;\t// Used during cfg parsing. True if the var has been created from the currently parsed cfg\n\t\tstd::vector<int>\t\t\tIntValues;\n\t\tstd::vector<double>\t\t\tRealValues;\n\t\tstd::vector<std::string>\tStrValues;\n\n\t\tint\t\t\t\t\t\t\tSaveWrap;\n\n\t\tvoid\t\t\t\t\t\t(*Callback)(CVar &var);\n\t\t//@}\n\t};\n\n\tCConfigFile() : _Callback(NULL) {}\n\n\tvirtual ~CConfigFile ();\n\n\t/// Get a variable with the variable name\n\tCVar &getVar (const std::string &varName);\n\n\t/// Get a variable pointer with the variable name, without throwing exception. Return NULL if not found.\n\tCVar *getVarPtr (const std::string &varName);\n\n\t/// Get the variable count.\n\tuint\tgetNumVar () const;\n\n\t/// Get a variable.\n\tCVar\t*getVar (uint varId);\n\n\t/// Add a variable. If the variable already exists, return it.\n\tCVar\t*insertVar (const std::string &varName, const CVar &varToCopy);\n\n\t/// Return true if the variable exists, false otherwise\n\tbool exists (const std::string &varName);\n\n\t/// load and parse the file\n\tvoid load (const std::string &fileName, bool lookupPaths = false);\n\n\t/// save the config file\n\tvoid save () const;\n\n\t/// Clear all the variable array (including information on variable callback etc)\n\tvoid clear ();\n\n\t/// set to 0 or \"\" all variable in the array (but not destroy them)\n\tvoid clearVars ();\n\n\t/// Returns true if the file has been loaded\n\tbool loaded();\n\n\t/// Returns the number of variables in the configuration\n\tuint32 getVarCount();\n\n\t/// reload and reparse the file\n\tvoid reparse (bool lookupPaths = false);\n\n\t/// display all variables with nlinfo (debug use)\n\tvoid display () const;\n\n\t/// display all variables with nlinfo (debug use)\n\tvoid display (CLog *log) const;\n\n\t/// set a callback function that is called when the config file is modified\n\tvoid setCallback (void (*cb)());\n\n\t/// set a callback function to a variable, it will be called when this variable is modified\n\tvoid setCallback (const std::string &VarName, void (*cb)(CConfigFile::CVar &var));\n\n\t/// contains the variable names that getVar() and getVarPtr() tried to access but not present in the cfg\n\tstd::vector<std::string> UnknownVariables;\n\n\t/// returns the config file name\n\tstd::string getFilename () const { return FileNames[0]; }\n\n\t/// set the time between 2 file checking (default value is 1 second)\n\t/// \\param timeout time in millisecond, if timeout=0, the check will be made each \"frame\"\n\tstatic void setTimeout (uint32 timeout);\n\n\t/// Internal use only\n\tstatic void checkConfigFiles ();\n\nprivate:\n\n\t/// Internal use only\n\tvoid (*_Callback)();\n\n\t/// Internal use only\n\tstd::vector<CVar>\t_Vars;\n\n\t// contains the configfilename (0) and roots configfilenames\n//\tstd::string\t_FileName;\n//\tstd::vector<uint32>\t\t\t_LastModified;\n\n\t// contains the configfilename (0) and roots configfilenames\n\tstd::vector<std::string>\tFileNames;\n\tstd::vector<uint32>\t\t\tLastModified;\n\n\tstatic uint32\t_Timeout;\n\n\tstatic std::vector<CConfigFile *> *_ConfigFiles;\n};\n\nstruct EConfigFile : public Exception\n{\n\tEConfigFile() { _Reason = \"Unknown Config File Exception\";}\n};\n\nstruct EBadType : public EConfigFile\n{\n\tEBadType (const std::string &varName, int varType, int wantedType)\n\t{\n\t\tstatic char str[NLMISC::MaxCStringSize];\n\t\tsmprintf (str, NLMISC::MaxCStringSize, \"Bad variable type, variable \\\"%s\\\" is a %s and not a %s\", varName.c_str (), CConfigFile::CVar::TypeName[varType], CConfigFile::CVar::TypeName[wantedType]);\n\t\t_Reason = str;\n\t\tnlinfo(\"CF: Exception will be launched: %s\", _Reason.c_str());\n\t}\n};\n\nstruct EBadSize : public EConfigFile\n{\n\tEBadSize (const std::string &varName, int varSize, int varIndex)\n\t{\n\t\tstatic char str[NLMISC::MaxCStringSize];\n\t\tsmprintf (str, NLMISC::MaxCStringSize, \"Trying to access to the index %d but the variable \\\"%s\\\" size is %d\", varIndex, varName.c_str (), varSize);\n\t\t_Reason = str;\n\t\tnlinfo(\"CF: Exception will be launched: %s\", _Reason.c_str());\n\t}\n};\n\nstruct EUnknownVar : public EConfigFile\n{\n\tEUnknownVar (const std::string &filename, const std::string &varName)\n\t{\n\t\tstatic char str[NLMISC::MaxCStringSize];\n\t\tsmprintf (str, NLMISC::MaxCStringSize, \"variable \\\"%s\\\" not found in file \\\"%s\\\"\", varName.c_str (), filename.c_str());\n\t\t_Reason = str;\n\t\tnlinfo(\"CF: Exception will be launched: %s\", _Reason.c_str());\n\t}\n};\n\nstruct EParseError : public EConfigFile\n{\n\tEParseError (const std::string &fileName, int currentLine)\n\t{\n\t\tstatic char str[NLMISC::MaxCStringSize];\n\t\tsmprintf (str, NLMISC::MaxCStringSize, \"Parse error on the \\\"%s\\\" file, line %d\", fileName.c_str (), currentLine);\n\t\t_Reason = str;\n\t\tnlinfo(\"CF: Exception will be launched: %s\", _Reason.c_str());\n\t}\n};\n\nstruct EFileNotFound : public EConfigFile\n{\n\tEFileNotFound (const std::string &fileName)\n\t{\n\t\tstatic char str[NLMISC::MaxCStringSize];\n\t\tsmprintf (str, NLMISC::MaxCStringSize, \"File \\\"%s\\\" not found\", fileName.c_str ());\n\t\t_Reason = str;\n\t}\n};\n\n} // NLMISC\n\n#endif // NL_CONFIG_FILE_H\n\n/* End of config_file.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/contiguous_block_allocator.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CONTIGUOUS_BLOCK_ALLOCATOR_H\n#define NL_CONTIGUOUS_BLOCK_ALLOCATOR_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\n/** One of the simplest scheme of allocation around, but very useful in some situations.\n  * This allocator is just provided with a single block of memory at start (possibly of size 0). Each alloc get a new block in that big block, by\n  * simply advancing a pointer. When not enough space is available, the default stl allocator is used.\n  * When a block is deallocated, nothing happens, unless the block was allocated using the default stl allocator is used, in which case deallocate() is called.\n  *\n  * The typical use is when an object makes a lot of allocations at init, but in a predictable way, and if it doesn't make alloc / realloc\n  * later. In this case the caller can measure the amount of memory needed to create the object, and can create this allocator with the good amount of\n  * memory. Subsequent allocations will then be very fast even for very differently sized blocks, with no fragmentation inside the allocated block\n  * and no memory overhead per allocated bloc.\n  *\n  * Obviously, if the quantity of memory to be allocated can't be predicted (or if no max bytes can be forseen), then other allocators may\n  * be best suited.\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  *\n  */\nclass CContiguousBlockAllocator\n{\npublic:\n\t// ctor\n\tCContiguousBlockAllocator();\n\t// dtor\n\t~CContiguousBlockAllocator();\n\t// Init the allocator with the given size. Previous allocations become invalid, so when calling init again, the user must have\n    // freed all memory he allocated\n\tvoid init(uint numBytes = 0);\n\t// synonymous to init(0)\n\tvoid release() { init(0); }\n\t// allocated a block of n bytes\n\tvoid *alloc(uint numBytes);\n\t// deallocate a block\n\tvoid free(void *block, uint numBytes);\n\t// compute the total number of bytes allocated since init\n\t// NB : freed block are not subtracted from that total !!\n\tuint getNumAllocatedBytes() const { return _NumAllocatedBytes; }\n\t#ifdef NL_DEBUG\n\t    // get number of calls to alloc since last init\n\t\tuint getNumAlloc() const { return _NumAlloc; }\n\t\t// get number of calls to free since last init\n\t\tuint getNumFree() const { return _NumFree; }\n\t#endif\nprivate:\n\tuint8\t\t\t\t\t*_BlockStart;\n\tuint8\t\t\t\t\t*_BlockEnd;\n\tuint8\t\t\t\t\t*_NextAvailablePos;\n\tuint\t\t\t\t\t _NumAllocatedBytes;\n\tstd::allocator<uint8>    _DefaultAlloc;\n\n\t#ifdef NL_DEBUG\n\t\tuint _NumAlloc;\n\t\tuint _NumFree;\n\t#endif\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/cpu_time_stat.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CPU_TIME_STAT_H\n#define NL_CPU_TIME_STAT_H\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/time_nl.h>\n\n#include <deque>\n\nnamespace NLMISC\n{\n\n/**\n * Utility class to read cpu time information from /proc/stat and /cpu/pid/stat\n * Allows accurate timing measures for both cpu and process (at least at OS timing accuracy)\n * Call peekMeasures() once in a while (once a second, for instance, to avoid to much load)\n * then call each getCPU... and getProcess... methods to get instant CPU or Process load.\n *\n * \\author Benjamin Legros\n * \\author Nevrax France\n * \\date 2004\n */\nclass CCPUTimeStat\n{\npublic:\n\n\tCCPUTimeStat();\n\n\t/**\n\t * Get absolute ticks value for the whole cpu set\n\t * e.g. a foursome of cpu will all tell their ticks through these numbers\n\t */\n\tstatic bool\t\tgetCPUTicks(uint64& user, uint64& nice, uint64& system, uint64& idle, uint64& iowait);\n\n\t/// Get absolute ticks values for a specific pid\n\tstatic bool\t\tgetPIDTicks(uint64& utime, uint64& stime, uint64& cutime, uint64& cstime, uint pid);\n\n\n\n\t/// \\name Measure peeking and reading\n\t// @{\n\n\t/// Peek measure\n\tvoid\t\t\tpeekMeasures();\n\n\tenum TMeasureType\n\t{\n\t\tInstant,\n\t\tMean,\n\t\tPeak\n\t};\n\n\t/**\n\t * Get Overall CPU Load\n\t * Call this method to know the overall server CPU usage (0=min, 1=max)\n\t * All processes running on the same machine will return approximately\n\t * the same value\n\t */\n\tfloat\t\t\tgetCPULoad(TMeasureType type = Instant) const\t\t\t\t{ return _CPUUser.get(type)+_CPUSystem.get(type)+_CPUNice.get(type)+_CPUIOWait.get(type); }\n\n\t/**\n\t * Get overall load for this process (children excluded)\n\t * Call this method to know the CPU usage for this process (0=min, 1=max)\n\t * Please note that quadriprocessor machines will show maximum of 0.25 per process\n\t * (0.5 for a biprocessor).\n\t * Children of a process are processes that have been launched from this process\n\t * (that is, this process is marked as parent of the child process, see ppid, fork() and/or exec())\n\t * Unused but by the AES (all launched services are children of the AES)\n\t */\n\tfloat\t\t\tgetProcessLoad(TMeasureType type = Instant) const\t\t\t{ return _PIDUTime.get(type)+_PIDSTime.get(type); }\n\n\t// @}\n\n\n\n\t/** \\name Detailed measures\n\t * These methods allow you to check precisely what consumes cpu power,\n\t * (user processes/kernel/nice processes...)\n\t */\n\t// @{\n\n\t/// Get User Load\n\tfloat\t\t\tgetCPUUserLoad(TMeasureType type = Instant) const\t\t\t{ return _CPUUser.get(type); }\n\t/// Get System Load\n\tfloat\t\t\tgetCPUSystemLoad(TMeasureType type = Instant) const\t\t\t{ return _CPUSystem.get(type); }\n\t/// Get Nice Load\n\tfloat\t\t\tgetCPUNiceLoad(TMeasureType type = Instant) const\t\t\t{ return _CPUNice.get(type); }\n\t/// Get Nice Load\n\tfloat\t\t\tgetCPUIOWaitLoad(TMeasureType type = Instant) const\t\t\t{ return _CPUIOWait.get(type); }\n\n\t/// Get User load for this process (children excluded)\n\tfloat\t\t\tgetProcessUserLoad(TMeasureType type = Instant) const\t\t{ return _PIDUTime.get(type); }\n\t/// Get Sytem load for this process (children excluded)\n\tfloat\t\t\tgetProcessSystemLoad(TMeasureType type = Instant) const\t\t{ return _PIDSTime.get(type); }\n\t/// Get User load for this process (children included)\n\tfloat\t\t\tgetProcessCUserLoad(TMeasureType type = Instant) const\t\t{ return _PIDCUTime.get(type); }\n\t/// Get Sytem load for this process (children included)\n\tfloat\t\t\tgetProcessCSystemLoad(TMeasureType type = Instant) const\t{ return _PIDCSTime.get(type); }\n\t/// Get overall load for this process (children included)\n\tfloat\t\t\tgetProcessCLoad(TMeasureType type = Instant) const\t\t\t{ return _PIDCUTime.get(type)+_PIDCSTime.get(type); }\n\n\n\n\t// @}\n\n\nprivate:\n\n\tstruct CTickStat\n\t{\n\t\tCTickStat() : Tick(0), Diff(0), Load(0.0f)\t{ }\n\t\tuint64\t\tTick;\n\t\tuint32\t\tDiff;\n\t\tfloat\t\tLoad;\n\n\t\ttypedef std::deque<std::pair<NLMISC::TTime, float> >\tTLoadQueue;\n\t\tTLoadQueue\tLoadQueue;\n\n\t\tvoid\tcomputeDiff(uint64 newTick)\n\t\t{\n\t\t\tDiff = (uint32)(newTick-Tick);\n\t\t\tTick = newTick;\n\t\t}\n\n\t\tvoid\tcomputeLoad(uint32 total, const NLMISC::TTime& ctime)\n\t\t{\n\t\t\tLoad = (float)Diff / (float)total;\n\n\t\t\twhile (!LoadQueue.empty() && ctime-LoadQueue.front().first > 60000)\n\t\t\t\tLoadQueue.pop_front();\n\t\t\tLoadQueue.push_back(std::make_pair(ctime, Load));\n\t\t}\n\n\t\tfloat\tget(TMeasureType type) const\n\t\t{\n\t\t\tif (type == Peak)\n\t\t\t\treturn getPeakLoad();\n\t\t\telse if (type == Mean)\n\t\t\t\treturn getMeanLoad();\n\t\t\telse\n\t\t\t\treturn Load;\n\t\t}\n\n\t\tfloat\tgetPeakLoad() const\n\t\t{\n\t\t\tfloat\tpeak = 0.0f;\n\t\t\tuint\ti;\n\t\t\tfor (i=0; i<LoadQueue.size(); ++i)\n\t\t\t\tif (LoadQueue[i].second > peak)\n\t\t\t\t\tpeak = LoadQueue[i].second;\n\t\t\treturn peak;\n\t\t}\n\n\t\tfloat\tgetMeanLoad() const\n\t\t{\n\t\t\tif (LoadQueue.empty())\n\t\t\t\treturn 0.0f;\n\t\t\tfloat\tt = 0.0f;\n\t\t\tuint\ti;\n\t\t\tfor (i=0; i<LoadQueue.size(); ++i)\n\t\t\t\tt += LoadQueue[i].second;\n\t\t\treturn t/i;\n\t\t}\n\t};\n\n\tuint32\t\t\t_PID;\n\tbool\t\t\t_FirstTime;\n\n\tuint64\t\t\t_LastCPUTicks;\n\tCTickStat\t\t_CPUUser;\n\tCTickStat\t\t_CPUNice;\n\tCTickStat\t\t_CPUSystem;\n\tCTickStat\t\t_CPUIdle;\n\tCTickStat\t\t_CPUIOWait;\n\n\tuint64\t\t\t_LastPIDTicks;\n\tCTickStat\t\t_PIDUTime;\n\tCTickStat\t\t_PIDSTime;\n\tCTickStat\t\t_PIDCUTime;\n\tCTickStat\t\t_PIDCSTime;\n};\n\n}\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/debug.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DEBUG_H\n#define NL_DEBUG_H\n\n#include \"common.h\"\n#include \"log.h\"\n#include \"mutex.h\"\n#include \"mem_displayer.h\"\n#include \"displayer.h\"\n#include \"app_context.h\"\n\n#include <cstdio>\n#include <set>\n\nnamespace NLMISC\n{\n\n#ifdef ASSERT_THROW_EXCEPTION\n#define ASSERT_THROW_EXCEPTION_CODE(exp) ASSERT_THROW_EXCEPTION_CODE_EX(exp, #exp)\n#define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str) if(!(exp)) throw NLMISC::Exception(str\" returns false\");\n#else\n#define ASSERT_THROW_EXCEPTION_CODE(exp)\n#define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str)\n#endif\n\n/** Imposter class to wrap all global access to the nel context for backward compatibility\n *\tYoyo note: This was a template before, hence with inline.\n *\tWe removed the inline because there was a hard compilation bug\n *\tin plugin max under some compiler which caused operator-> to crash.... (don't understand why grrrr)\n *\tBtw the method is optimized like this (1 call instead of 3 (and one with virtual)) because we added a local cache (_Log)\n *\tThus it is much better like this.\n */\nclass CImposterLog\n{\nprivate:\n\ttypedef CLog *(INelContext::*TAccessor)();\n\n\t// Method to access the Log\n\tTAccessor\t_Accessor;\npublic:\n\tCImposterLog(TAccessor accessor);\n\tCLog* operator -> ();\n\toperator CLog*();\n\tCLog &operator ()();\n};\n\n\n//\n// Externals\n//\n\n// NOTE: The following are all NULL until createDebug() has been called at least once\n// NOTE2: You must not use this class before the main() (not inside a static class ctor)\nextern CImposterLog\t\tErrorLog;\nextern CImposterLog\t\tWarningLog;\nextern CImposterLog\t\tInfoLog;\nextern CImposterLog\t\tDebugLog;\nextern CImposterLog\t\tAssertLog;\n\nextern CMemDisplayer *DefaultMemDisplayer;\nextern CMsgBoxDisplayer *DefaultMsgBoxDisplayer;\n\n\n//\n// Functions\n//\n\n// internal use only\nvoid createDebug (const char *logPath = NULL, bool logInFile = true, bool eraseLastLog = false);\n\n/// Do not call this, unless you know what you're trying to do (it kills debug)!\nvoid destroyDebug();\n\n// call this if you want to change the dir of the log.log file\nvoid changeLogDirectory(const std::string &dir);\n\n// call this if you want to get the dir of the log.log file\nstd::string getLogDirectory();\n\n// internal breakpoint window\nvoid enterBreakpoint (const char *message);\n\n// if true, the assert generates an assert\n// if false, the assert just displays a warning and continue\nvoid setAssert (bool assert);\n\n// Beep (Windows only, no effect elsewhere)\nvoid beep( uint freq, uint duration );\n\n\ntypedef std::string (*TCrashCallback)();\n\n// this function enables user application to add information in the log when a crash occurs\nvoid setCrashCallback(TCrashCallback crashCallback);\n\n// For Crash report window. allow to know if a crash has already raised in the application\nbool\tisCrashAlreadyReported();\nvoid\tsetCrashAlreadyReported(bool state);\n\n\n// This very amazing macro __FUNCTION__ doesn't exist on VC6, map it to NULL\n#ifdef NL_COMP_VC6\n#\tdefine __FUNCTION__ NULL\n#endif\n\n\n// Macros\n\n/// Utility macro used by NL_MACRO_TO_STR to concatenate macro in text message.\n#define NL_MACRO_TO_STR_SUBPART(x) #x\n\n/** Use this macro to concatenate macro such\n *\tYou can use this macro to build '#pragma message' friendly macro\n *\tor to make macro definition into string\n *\teg : #define M1 foo\n *\t\t #define MESSAGE \"the message is \"NL_MACRO_TO_STR(M1)\n *\t\t #pragma message(MESSAGE)\n *\t\t printf(NL_MACRO_TO_STR(M1));\n */\n#define NL_MACRO_TO_STR(x) NL_MACRO_TO_STR_SUBPART(x)\n\n/** the two following macros help to build compiler message using #pragma message\n *\ton visual C++.\n *\tThe macro generate a message formated like the visual C++ compiler message.\n *\tNL_LOC_MSG generate informative message and\n *\tNL_LOC_WRN generate warning message not differentiable to genuine Visual C++ warning.\n *\tThe two message allow automatic source access with F4 or double click in\n *\toutput window.\n *\n *  usage : #pragma message( NL_LOC_MGS \"your message\" )\n *\n *  Note : If you want to concatenate another macro to your message, you\n *\t\t\tcan append using the NL_MACRO_TO_STR macro like in\n *\t\t\t#define CLASS_NAME TheClassName\n *\t\t\t#pragma message( NL_LOC_MGS \"The class name is \" NL_MACRO_TO_STR(CLASS_NAME))\n *  Note 2 : To show a warning under GCC, use #warning \"Your warning here\",\n *           see nel/net/net_manager.h for an example on how to use these correctly.\n */\n#define NL_LOC_MSG __FILE__\"(\" NL_MACRO_TO_STR(__LINE__) \") : Message: \"\n#define NL_LOC_WRN __FILE__\"(\" NL_MACRO_TO_STR(__LINE__) \") : Warning Msg: \"\n\n\n/**\n * \\def nldebug(exp)\n * Log a debug string. You don't have to put the final new line. It will be automatically append at the end of the string.\n *\n * Example:\n *\\code\n\tvoid function(sint type)\n\t{\n\t\t// display the type value.\n\t\tnldebug(\"type is %d\", type);\n\t}\n *\\endcode\n */\n#ifdef NL_NO_DEBUG\n#\tif defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71\n#\t\tdefine nldebug __noop\n#\telse\n#\t\tdefine nldebug 0&&\n#\tendif\n#else // NL_NO_DEBUG\n\textern bool DisableNLDebug;\n#\tdefine nldebug if (NLMISC::DisableNLDebug) {} else (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getDebugLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getDebugLog())->displayNL\n#endif // NL_NO_DEBUG\n\n/**\n * \\def nlinfo(exp)\n * Same as nldebug but it will be display in debug and in release mode.\n */\n#ifdef NL_NO_DEBUG\n#\tif defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71\n#\t\tdefine nlinfo __noop\n#\telse\n#\t\tdefine nlinfo 0&&\n#\tendif\n#else // NL_NO_DEBUG\n#\tdefine nlinfo (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getInfoLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getInfoLog())->displayNL\n#endif // NL_NO_DEBUG\n\n/**\n * \\def nlwarning(exp)\n * Same as nlinfo but you have to call this macro when something goes wrong but it's not a fatal error, the program could continue.\n *\n * Example:\n *\\code\n\tvoid function(char *str)\n\t{\n\t\t// display the type value.\n\t\tif (str==NULL)\n\t\t{\n\t\t\tnlwarning(\"in function(), str should not be NULL, assume it's an empty string\");\n\t\t\tstr=\"\";\n\t\t}\n\t}\n *\\endcode\n */\n\n#ifdef NL_NO_DEBUG\n#\tif defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 71\n#\t\tdefine nlwarning __noop\n#\telse\n#\t\tdefine nlwarning 0&&\n#\tendif\n#else // NL_NO_DEBUG\n#\tdefine nlwarning (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getWarningLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getWarningLog())->displayNL\n#endif // NL_NO_DEBUG\n\n/**\n * \\def nlerror(exp)\n * Same as nlinfo but you have to call it when you have a fatal error, this macro display the text and \\b exit the application\n * automatically. nlerror must be in a try/catch because it generates an EFatalError exception to exit the application.\n *\n *\\code\n\tvoid function(char *filename)\n\t{\n\t\tFILE *fp = fopen (filename, \"r\");\n\t\tif (fp==NULL)\n\t\t{\n\t\t\tnlerror(\"file not found\");\n\t\t}\n\t}\n *\\endcode\n */\n#define nlerror (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlFatalError)\n\n\n/**\n * \\def nlerrornoex(exp)\n * Same as nlerror but it doesn't generate any exceptions. It's used only in very specific case, for example, when you\n * call a nlerror in a catch block (look the service.cpp)\n */\n#define nlerrornoex (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlError)\n\n\n/**\n * \\def nlassert(exp)\n * Try the assertion of \\c exp. In release mode, nlassert do \\b *nothing*. In debug mode, If \\c exp is true, nothing happen,\n * otherwise, the program stop on the assertion line.\n *\n * Example:\n *\\code\n\tvoid function(char *string)\n\t{\n\t\t// the string must not be NULL.\n\t\tnlassert(string!=NULL);\n\t}\n *\\endcode\n */\n\n/**\n * \\def nlassertonce(exp)\n * Same behaviour as nlassert but the assertion will be test on time only. It's useful when you are under an inner loop and\n * you don't want to flood log file for example.\n *\n * Example:\n *\\code\n\tfor (int i = 0; i < Vect.size(); i++)\n\t{\n\t\t// all string must not be NULL, but if it's happen, log only the first time.\n\t\tnlassertonce(Vect[i].string!=NULL);\n\t}\n *\\endcode\n */\n\n/**\n * \\def nlassertex(exp,str)\n * Same behaviour as nlassert but add a user defined \\c str variables args string that will be display with the assert message.\n * Very useful when you can't debug directly on your computer.\n *\n * Example:\n *\\code\n\tvoid function(sint type)\n\t{\n\t\t// the \\c type must be between 0 and 15.\n\t\tnlassertex(type>=0&&type<=16, (\"type was %d\", type));\n\t\t// it'll display something like \"assertion failed line 10 of test.cpp: type>=&&type<=16, type was 423555463\"\n\t}\n *\\endcode\n */\n\n/**\n * \\def nlverify(exp)\n * Same behaviour as nlassert but the \\c exp will be executed in release mode too (but not tested).\n *\n * Example:\n *\\code\n\t// Load a file and assert if the load failed. This example will work \\b only in debug mode because in release mode,\n\t// nlassert do nothing, the load function will not be called...\n\tnlassert(load(\"test.tga\"));\n\n\t// If you want to do that anyway, you could call nlverify. In release mode, the assertion will not be tested but\n\t// the \\c load function will be called.\n\tnlverify(load(\"test.tga\"));\n\n\t// You can also do this:\n\tbool res = load (\"test.tga\"));\n\tassert(res);\n\n *\\endcode\n */\n\n/**\n * \\def nlverifyonce(exp)\n * Same behaviour as nlassertonce but it will execute \\c exp in debug and release mode.\n */\n\n/**\n * \\def nlverifyex(exp,str)\n * Same behaviour as nlassertex but it will execute \\c exp in debug and release mode.\n */\n\n/**\n * \\def nlstop\n * It stop the application at this point. It's exactly the same thing as \"nlassert(false)\".\n * Example:\n *\\code\n\tswitch(type)\n\t{\n\tcase 1: ... break;\n\tcase 2: ... break;\n\tdefault: nlstop;\t// it should never happen...\n\t}\n *\\endcode\n */\n\n/**\n * \\def nlstoponce\n * Same as nlassertonce(false);\n */\n\n/**\n * \\def nlstopex(exp)\n * Same as nlassertex(false,exp);\n */\n\n// removed because we always check assert (even in release mode) #if defined (NL_OS_WINDOWS) && defined (NL_DEBUG)\n#if defined (NL_OS_WINDOWS)\n#define NLMISC_BREAKPOINT __debugbreak();\n#else\n#define NLMISC_BREAKPOINT abort()\n#endif\n\n// Internal, don't use it (make smaller assert code)\nextern bool _assert_stop(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp);\nextern void _assertex_stop_0(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp);\nextern bool _assertex_stop_1(bool &ignoreNextTime);\n\n// removed because we always check assert (even in release mode) #if defined(NL_DEBUG)\n\n#ifdef NL_NO_DEBUG\n#\tdefine nlassert(exp) if(false)\n#\tdefine nlassertonce(exp) if(false)\n#\tdefine nlassertex(exp, str) if(false)\n#\tdefine nlverify(exp) { exp; }\n#\tdefine nlverifyonce(exp) { exp; }\n#\tdefine nlverifyex(exp, str) { exp; }\n#else // NL_NO_DEBUG\n\n#\tifdef NL_OS_UNIX\n\n// Linux set of asserts is reduced due to that there is no message box displayer\n\n#define nlassert(exp) \\\ndo { \\\n\tif (!(exp)) { \\\n\t\tNLMISC::createDebug (); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayNL (\"\\\"%s\\\" \", #exp); \\\n\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n#define nlassertonce(exp) nlassert(exp)\n\n#define nlassertex(exp, str) \\\ndo { \\\n\tif (!(exp)) { \\\n\t\tNLMISC::createDebug (); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayNL (\"\\\"%s\\\" \", #exp); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \\\n\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n#define nlverify(exp) nlassert(exp)\n#define nlverifyonce(exp) nlassert(exp)\n#define nlverifyex(exp, str) nlassertex(exp, str)\n\n#\telse // NL_OS_UNIX\n\n#define nlassert(exp) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tbool _expResult_ = (exp) ? true : false; \\\n\tif (!ignoreNextTime && !_expResult_) { \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n\tASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \\\n} while(0)\n\n#define nlassertonce(exp) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tif (!ignoreNextTime && !(exp)) { \\\n\t\tignoreNextTime = true; \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n#define nlassertex(exp, str) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tbool _expResult_ = (exp) ? true : false; \\\n\tif (!ignoreNextTime && !_expResult_) { \\\n\t\tNLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \\\n\t\tif(NLMISC::_assertex_stop_1(ignoreNextTime)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n\tASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \\\n} while(0)\n\n#define nlverify(exp) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tbool _expResult_ = (exp) ? true : false; \\\n\tif (!_expResult_ && !ignoreNextTime) { \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n\tASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \\\n} while(0)\n\n#define nlverifyonce(exp) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tbool _expResult_ = (exp) ? true : false; \\\n\tif (!_expResult_ && !ignoreNextTime) { \\\n\t\tignoreNextTime = true; \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n#define nlverifyex(exp, str) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tbool _expResult_ = (exp) ? true : false; \\\n\tif (!_expResult_ && !ignoreNextTime) { \\\n\t\tNLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \\\n\t\tif(NLMISC::_assertex_stop_1(ignoreNextTime)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n\tASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \\\n} while(0)\n\n#\tendif // NL_OS_UNIX\n\n#endif // NL_NO_DEBUG\n\n#define nlunreferenced(identifier) (void)identifier\n\n#define nlstop \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tif (!ignoreNextTime) { \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n\tASSERT_THROW_EXCEPTION_CODE(false) \\\n} while(0)\n\n#define nlstoponce \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tif (!ignoreNextTime) { \\\n\t\tignoreNextTime = true; \\\n\t\tif(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n\n#define nlstopex(str) \\\ndo { \\\n\tstatic bool ignoreNextTime = false; \\\n\tif (!ignoreNextTime) { \\\n\t\tNLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL); \\\n\t\tNLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \\\n\t\tif(NLMISC::_assertex_stop_1(ignoreNextTime)) \\\n\t\t\tNLMISC_BREAKPOINT; \\\n\t} \\\n} while(0)\n\n\nstruct EFatalError : public Exception\n{\n\tEFatalError() : Exception( \"nlerror() called\" ) {}\n};\n\nclass ETrapDebug : public Exception\n{\n};\n\n// undef default assert to force people to use nlassert() instead of assert()\n// if NL_MAP_ASSERT is set we map assert to nlassert instead of removing it\n// this makes it compatible with zeroc's ICE network library\n\n#ifdef NL_MAP_ASSERT\n#\tifdef assert\n#\t\tundef assert\n#\t\tdefine assert nlassert\n#\tendif\n#else\n#\tifdef assert\n#\t\tundef assert\n#\t\tdefine assert(a) you_must_not_use_assert___use_nl_assert___read_debug_h_file\n#\tendif\n#endif\n\n\n/// Get the call stack and set it with result\nvoid getCallStack(std::string &result, sint skipNFirst = 0);\n\n/// Get the call stack and the logs and set it with result\nvoid getCallStackAndLog (std::string &result, sint skipNFirst = 0);\n\n/**\n * safe_cast<>: this is a function which nlassert() a dynamic_cast in Debug, and just do a static_cast in release.\n * So slow check is made in debug, but only fast cast is made in release.\n */\ntemplate<class T, class U>\tinline T\tsafe_cast(U o)\n{\n\t// NB: must check debug because assert may still be here in release\n#ifdef NL_DEBUG\n\tnlassert(dynamic_cast<T>(o));\n#endif\n\treturn static_cast<T>(o);\n}\n\n/**\n * type_cast<>: this is a function which nlassert() a dynamic_cast in Debug, and just do a static_cast in release.\n * So slow check is made in debug, but only fast cast is made in release.\n * Differs from safe_cast by allowinf NULL objets. (ask Stephane LE DORZE for more explanations).\n */\ntemplate<class T, class U>\tinline T\ttype_cast(U o)\n{\n\t// NB: must check debug because assert may still be here in release\n#ifdef NL_DEBUG\n\tif (o)\n\t\tnlassert(dynamic_cast<T>(o));\n#endif\n\t//\toptimization made to check pointer validity before address translation. (hope it works on linux).\n\tif ((size_t)(static_cast<T>((U)0x0400)) == (size_t)((U)0x0400))\n\t{\n\t\treturn static_cast<T>(o);\n\t}\n\telse\n\t{\n\t\treturn (o==0)?0:static_cast<T>(o);\n\t}\n}\n\n/** Compile time assertion\n  */\n#ifdef NL_ISO_CPP0X_AVAILABLE\n#\tdefine nlctassert(cond) static_assert(cond, \"Compile time assert in \"#cond)\n#else\n#\tdefine nlctassert(cond) (void)sizeof(uint[(cond) ? 1 : 0])\n#endif\n\n/**\n*\tAllow to verify an object was accessed before its destructor call.\n*\tFor instance, it could be used to check if the user take care of method call return.\n*\tex:\n*\t\tCMustConsume<TErrorCode>\tfoo()\n*\t\t{\n*\t\t\t...\n*\t\t\treturn\tErrorInvalidateType;\t\t//\tpart of TErrorCode enum.\n*\t\t}\n*\tExclusive implementation samples:\n*\t\tTerrorCode code=foo().consumeValue();\t//\tGood!\n*\t\tfoo().consume();\t\t\t\t\t\t//\tGood!\n*\t\tTerrorCode code=foo();\t\t\t\t\t//\tMistake!\n*\t\tfoo();\t\t\t\t\t\t\t\t\t//\tWill cause an assert at next ending brace during execution time.\n*\t\tTerrorCode code=foo().Value();\t\t\t//\tWill cause an assert at next ending brace during execution time.\n*\t(ask Stephane LE DORZE for more explanations).\n*/\n\n// Need a breakpoint in the assert / verify macro\nextern bool DebugNeedAssert;\n\n// Internal process, don't use it\nextern bool NoAssert;\n\n\ntemplate<class T>\nclass CMustConsume\n{\npublic:\n\tCMustConsume(const T &val) : Value(val)\n#if !FINAL_VERSION\n\t, Consumed(false)\n#endif\n\t{\n\t}\n\n\t~CMustConsume()\n\t{\n#if !FINAL_VERSION\n\t\tnlassert(Consumed == true);\n#endif\n\t}\n\n\t//\tGet the value without validating the access.\n\tconst T &value() const\n\t{\n\t\treturn Value;\n\t}\n\n\toperator const T &() const\n\t{\n#if !FINAL_VERSION\n\t\tConsumed = true;\n#endif\n\t\treturn Value;\n\t}\n\n\t//\tGet the value and validate the access.\n\tconst T &consumeValue() const\n\t{\n#if !FINAL_VERSION\n\t\tConsumed = true;\n#endif\n\t\treturn Value;\n\t}\n\t//\tOnly consume the access.\n\tvoid consume() const\n\t{\n#if !FINAL_VERSION\n\t\tConsumed = true;\n#endif\n\t}\n\nprivate:\n\tT\t\t\t\tValue;\n#if !FINAL_VERSION\n\tmutable\tbool\tConsumed;\n#endif\n};\n\n/// Data for instance counting\nstruct TInstanceCounterData\n{\n\tsint32\t\t_InstanceCounter;\n\tsint32\t\t_DeltaCounter;\n\tconst char\t*_ClassName;\n\tbool\t\t_Touched;\n\n\tTInstanceCounterData(const char *className);\n\n\t~TInstanceCounterData();\n};\n\n// forward declaration for members of CInstanceCounterManager\nclass CInstanceCounterLocalManager;\n\n// The singleton used to display the instance counter\nclass CInstanceCounterManager\n{\n//\tNLMISC_SAFE_SINGLETON_DECL(CInstanceCounterManager);\n\tprivate:\n\t\t/* declare private constructors*/\n\t\tCInstanceCounterManager () {}\n\t\tCInstanceCounterManager (const CInstanceCounterManager &) {}\n\t\t/* the local static pointer to the singleton instance */\n\t\tstatic CInstanceCounterManager\t*_Instance;\n\tpublic:\n\t\tstatic CInstanceCounterManager &getInstance()\n\t\t{\n\t\t\tif (_Instance == NULL)\n\t\t\t{\n\t\t\t\t/* the nel context MUST be initialised */\n//\t\t\t\tnlassert(NLMISC::NelContext != NULL);\n\t\t\t\tvoid *ptr = NLMISC::INelContext::getInstance().getSingletonPointer(\"CInstanceCounterManager\");\n\t\t\t\tif (ptr == NULL)\n\t\t\t\t{\n\t\t\t\t\t/* allocate the singleton and register it */\n\t\t\t\t\t_Instance = new CInstanceCounterManager;\n\t\t\t\t\tNLMISC::INelContext::getInstance().setSingletonPointer(\"CInstanceCounterManager\", _Instance);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_Instance = reinterpret_cast<CInstanceCounterManager*>(ptr);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn *_Instance;\n\t\t}\n\tprivate:\npublic:\n\n\tstd::string displayCounters() const;\n\n\tvoid resetDeltaCounter();\n\n\tuint32 getInstanceCounter(const std::string &className) const;\n\tsint32 getInstanceCounterDelta(const std::string &className) const;\n\nprivate:\n\n\tfriend class CInstanceCounterLocalManager;\n\n\tvoid registerInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr);\n\tvoid unregisterInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr);\n\n//\tstatic CInstanceCounterManager\t\t*_Instance;\n\tstd::set<CInstanceCounterLocalManager*>\t_InstanceCounterMgrs;\n};\n\n//\n// Local instance counter\n//\nclass CInstanceCounterLocalManager\n{\npublic:\n\tstatic CInstanceCounterLocalManager &getInstance()\n\t{\n\t\tif (_Instance == NULL)\n\t\t{\n\t\t\t_Instance = new CInstanceCounterLocalManager;\n\t\t}\n\t\treturn *_Instance;\n\t}\n\n\tstatic void releaseInstance()\n\t{\n\t\tif (_Instance != NULL)\n\t\t{\n\t\t\tdelete _Instance;\n\t\t\t_Instance = NULL;\n\t\t}\n\t}\n\n\tvoid registerInstanceCounter(TInstanceCounterData *counter)\n\t{\n\t\t_InstanceCounters.insert(counter);\n\t}\n\n\tvoid unregisterInstanceCounter(TInstanceCounterData *counter);\n\n\t~CInstanceCounterLocalManager()\n\t{\n\t\tCInstanceCounterManager::getInstance().unregisterInstaceCounterLocalManager(this);\n\t}\n\nprivate:\n\tfriend class CInstanceCounterManager;\n\tfriend class INelContext;\n\n\tCInstanceCounterLocalManager()\n\t{\n\t}\n\n\tvoid registerLocalManager()\n\t{\n\t\tCInstanceCounterManager::getInstance().registerInstaceCounterLocalManager(this);\n\t}\n\n\tstatic CInstanceCounterLocalManager\t\t*_Instance;\n\tstd::set<TInstanceCounterData*>\t\t\t_InstanceCounters;\n};\n\n\n/** Utility to count instance of class.\n *\tThis class is designed to be lightweight and to trace\n *\tthe number of instance of 'tagged' class.\n *\tCommands are provided to display the actual number\n *\tof object of each class and to compute delta\n *\tbetween two call of the displayer.\n *\tUsage is simple, you just have to put a macro\n *\tinside the class definition to trace it's allocation\n *\tand a macro in the implementation file.\n *\tThe macro only add a compiler minimum size for member\n *\tstruct of 0 octets (witch can be 0 or 1 octet, compiler\n *\tdependent).\n *\tusage :\n *\n *\tIn the header :\n *\tclass foo\t// This is the class we want to count instance\n *\t{\n *\t\tNL_INSTANCE_COUNTER_DECL(foo);\n *\t}\n *\tIn the cpp :\n *\tNL_INSTANCE_COUNTER_IMPL(foo);\n */\n#define NL_INSTANCE_COUNTER_DECL(className) \\\npublic: \\\n\tstruct className##InstanceCounter \\\n\t{ \\\n\t\tclassName##InstanceCounter() \\\n\t\t{ \\\n\t\t\t_InstanceCounterData._InstanceCounter++; \\\n\t\t\t_InstanceCounterData._Touched = true; \\\n\t\t} \\\n\t\tclassName##InstanceCounter(const className##InstanceCounter &/* other */) \\\n\t\t{ \\\n\t\t\t_InstanceCounterData._InstanceCounter++; \\\n\t\t\t_InstanceCounterData._Touched = true; \\\n\t\t} \\\n\t\t\\\n\t\t~className##InstanceCounter()\\\n\t\t{ \\\n\t\t\t_InstanceCounterData._InstanceCounter--; \\\n\t\t} \\\n\t\tstatic sint32 getInstanceCounter() \\\n\t\t{ \\\n\t\t\treturn _InstanceCounterData._InstanceCounter; \\\n\t\t} \\\n\t\tstatic sint32 getInstanceCounterDelta() \\\n\t\t{ \\\n\t\t\treturn _InstanceCounterData._InstanceCounter - _InstanceCounterData._DeltaCounter; \\\n\t\t} \\\n\t\tstatic NLMISC::TInstanceCounterData\t_InstanceCounterData; \\\n\t}; \\\n\t \\\n\tclassName##InstanceCounter\t_##className##InstanceCounter; \\\nprivate:\n\n/// The macro to make the implementation of the counter\n#define NL_INSTANCE_COUNTER_IMPL(className) NLMISC::TInstanceCounterData className::className##InstanceCounter::_InstanceCounterData(#className);\n\n/// An utility macro to get the instance counter for a class\n#define NL_GET_LOCAL_INSTANCE_COUNTER(className) className::className##InstanceCounter::getInstanceCounter()\n#define NL_GET_INSTANCE_COUNTER(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounter(#className)\n\n/// An utility macro to get the delta since the last counter reset.\n#define NL_GET_LOCAL_INSTANCE_COUNTER_DELTA(className) className::className##InstanceCounter::getInstanceCounterDelta()\n#define NL_GET_INSTANCE_COUNTER_DELTA(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounterDelta(#className)\n\n//\n// Following are internal functions, you should never use them\n//\n\n/// Never use this function (internal use only)\nvoid nlFatalError (const char *format, ...);\n\n/// Never use this function but call the nlerror macro (internal use only)\nvoid nlError (const char *format, ...);\n\n#define NL_CRASH_DUMP_FILE \"nel_debug.dmp\"\n\n// Standard API to retrieve error code and test for windows or unix platform\n\n/// Return the last error code generated by a system call\nint getLastError();\n\n/// Return a readable text according to the error code submited\nstd::string formatErrorMessage(int errorCode);\n\n\n//-------------------------------------------------------------------------------------------------\n// A handy 'nldebug', 'nlinfo' & 'nlwarning' override system\n//-------------------------------------------------------------------------------------------------\n//\n// The system includes a set of object classes\n// To override one or more of the standard NeL log channels one simply instantiates the appropriate class\n// with the new log channel as a parameter.\n// The log channel in question will revert to its previous value on destruction of the override object\n//\n// Usage Example:\n//\n//\tvoid doSomething()\n//\t{\n//\t\tnlinfo(\"bla\");\n//\t\tnlwarning(\"bla\");\n//\t}\n//\n//\tNLMISC_COMMAND(bla,\"bla\",\"bla\")\n//\t{\n//\t\tCNLLogOverride(&log);\n//\t\tdoSomething();\n//\t\treturn true;\n//\t}\n//\n\n//-------------------------------------------------------------------------------------------------\n\nclass CNLDebugOverride\n{\npublic:\n\tCNLDebugOverride(NLMISC::CLog *debugLog)\n\t{\n\t\tnlassert(debugLog!=NULL);\n\t\t_OldValue=NLMISC::DebugLog;\n\t\tnlassert(_OldValue!=NULL);\n\t\tNLMISC::INelContext::getInstance().setDebugLog(debugLog);\n\t}\n\t~CNLDebugOverride()\n\t{\n\t\tNLMISC::INelContext::getInstance().setDebugLog(_OldValue);\n\t}\nprivate:\n\t// prohibit copy\n\tCNLDebugOverride(const CNLDebugOverride&);\n\tNLMISC::CLog *_OldValue;\n};\n\n//-------------------------------------------------------------------------------------------------\n\nclass CNLInfoOverride\n{\npublic:\n\tCNLInfoOverride(NLMISC::CLog *infoLog)\n\t{\n\t\tnlassert(infoLog!=NULL);\n\t\t_OldValue=NLMISC::InfoLog;\n\t\tnlassert(_OldValue!=NULL);\n\t\tNLMISC::INelContext::getInstance().setInfoLog(infoLog);\n\t}\n\t~CNLInfoOverride()\n\t{\n\t\tNLMISC::INelContext::getInstance().setInfoLog(_OldValue);\n\t}\nprivate:\n\t// prohibit copy\n\tCNLInfoOverride(const CNLInfoOverride&);\n\tNLMISC::CLog *_OldValue;\n};\n\n//-------------------------------------------------------------------------------------------------\n\nclass CNLWarningOverride\n{\npublic:\n\tCNLWarningOverride(NLMISC::CLog *warningLog)\n\t{\n\t\tnlassert(warningLog!=NULL);\n\t\t_OldValue=NLMISC::WarningLog;\n\t\tnlassert(_OldValue!=NULL);\n\t\tNLMISC::INelContext::getInstance().setWarningLog(warningLog);\n\t}\n\t~CNLWarningOverride()\n\t{\n\t\tNLMISC::INelContext::getInstance().setWarningLog(_OldValue);\n\t}\nprivate:\n\t// prohibit copy\n\tCNLWarningOverride(const CNLWarningOverride&);\n\tNLMISC::CLog *_OldValue;\n};\n\n//-------------------------------------------------------------------------------------------------\n\nclass CNLLogOverride\n{\npublic:\n\tCNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog)\t{}\n\nprivate:\n\tCNLDebugOverride\t_DebugLog;\n\tCNLInfoOverride\t\t_InfoLog;\n\tCNLWarningOverride\t_WarningLog;\n};\n\n\n//-------------------------------------------------------------------------------------------------\n\nclass CNLSmartLogOverride\n{\npublic:\n\tCNLSmartLogOverride(NLMISC::CLog *commonLog):\n\t\t_DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog),\n\t\t_InfoLog(commonLog),\n\t\t_WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog)\n\t\t{}\n\nprivate:\n\tCNLDebugOverride\t_DebugLog;\n\tCNLInfoOverride\t\t_InfoLog;\n\tCNLWarningOverride\t_WarningLog;\n};\n\n\n\n\n} // NLMISC\n\n#endif // NL_DEBUG_H\n\n/* End of debug.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/di_event_emitter.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DI_EVENT_EMITTER_H\n#define NL_DI_EVENT_EMITTER_H\n\n\n\n#include \"types_nl.h\"\n\n\n#ifdef NL_OS_WINDOWS\n\n\n#define DIRECTINPUT_VERSION 0x0800\n\n#include \"input_device_server.h\"\n#include \"input_device_manager.h\"\n#include \"event_emitter.h\"\n#include \"smart_ptr.h\"\n#include \"events.h\"\n#include \"rect.h\"\n#include \"game_device.h\"\n#define NOMINMAX\n#include <windows.h>\n#include <dinput.h>\n\n\n\nnamespace NLMISC\n{\n\n\nclass CWinEventEmitter;\nclass CDIKeyboard;\nclass CDIMouse;\nstruct IMouseDevice;\nstruct IKeyboardDevice;\n\n//\nstruct EDirectInput : public EInputDevice\n{\n\tEDirectInput(const char *reason) : EInputDevice(reason) {}\n};\n//\nstruct EDirectInputLibNotFound : public  EDirectInput\n{\n\tEDirectInputLibNotFound() : EDirectInput(\"can't found the direct input dll\") {}\n};\n//\nstruct EDirectInputInitFailed : public  EDirectInput\n{\n\tEDirectInputInitFailed() : EDirectInput(\"Direct input initialization failed\") {}\n};\n//\nstruct EDirectInputCooperativeLevelFailed : public  EDirectInput\n{\n\tEDirectInputCooperativeLevelFailed() : EDirectInput(\"Direct Input Device Cooperative level couldn't be set\") {}\n};\n\n\n// Class to represent Direct Inputs events\nstruct CDIEvent : public IInputDeviceEvent\n{\n\tvirtual bool\toperator < (const IInputDeviceEvent &ide) const\n\t{\n\t\t// just compare the dates\n\t\treturn Datas.dwTimeStamp < (safe_cast<const CDIEvent *>(&ide))->Datas.dwTimeStamp;\n\t}\n\tDIDEVICEOBJECTDATA\tDatas;\n};\n\n/**\n * This manage events by using DirectInput8.\n * This should be polled regularly.\n * This can be mixed with a CWinEmitter (for example, you may have mouse using direct input, and keyboard using standard messages)\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 2002\n */\nclass CDIEventEmitter : public IEventEmitter, public IInputDeviceManager\n{\npublic:\n\t/** Build a Direct Input Event Emitter object. An exception containing the reason is thrown if the initialization failed.\n\t  * The obtained object must be released by deleting it.\n\t  * \\param hinst the instance of the application.\n\t  * \\param hwnd  the main window of the application.\n\t  * \\param we A windows eventsemitter. Can be NULL. Needed if you want to mix WIN32 events and Direct Input events\n\t  *\t\t\t  (for example, a Direct Input Mouse and a Win32 Keyboard)\n\t  */\n\tstatic CDIEventEmitter *create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we);\n\t~CDIEventEmitter();\npublic:\n\n\t/// This poll the direct input state, directly storing the result in the given server, or keeping the result in internal server if NULL.\n\tvoid\t\t\t\t\tpoll(CEventServer *server = NULL);\n\n\t///\\name From IDeviceManager, access to devices\n\t//@{\n\t\t// Test if a mouse has been created (by a call to getMouseDeivce)\n\t\tvirtual\tbool\t\t\tisMouseCreated() { return _Mouse != NULL; }\n\t\t/** Create the mouse device if needed (one active at a time for that object, repeated calls returns the same pointer) and get an interface on it. An exception if thrown if it couldn't be obtained.\n\t\t  * If this object has a pointer on a win32 emiter, Win32 mouse messages are replaced by this mouse messages.\n\t\t  */\n\t\tvirtual IMouseDevice\t*getMouseDevice(bool hardware) throw(EInputDevice);\n\t\t/// remove the direct input mouse\n\t\tvirtual void\treleaseMouse();\n\t\t/** Create the keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer)  and get an interface on it.\n\t\t  * If this object has a pointer on a win32 emiter, Win32 keyboard messages are replaced by this keyboard messages.\n\t\t  * NB: A direct input has no notion of localization or key combinations. See keyboard_device.h for more infos\n\t\t  */\n\t\tvirtual IKeyboardDevice\t*getKeyboardDevice() throw(EInputDevice);\n\t\t/// remove the direct input keyboard\n\t\tvirtual void\treleaseKeyboard();\n\t\t// Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector\n\t\tvirtual void\tenumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice);\n\t\t// Create the given game device from its instance name. It also means that it will begin to sends inputs\n\t\tvirtual IGameDevice\t*createGameDevice(const std::string &instanceName) throw(EInputDevice);\n\t\t// Release the given game device\n\t\tvirtual void\t\t releaseGameDevice(IGameDevice\t*);\n\t//@}\n\n\t/// from IEventEmitter\n\tvirtual void\t\t\tsubmitEvents(CEventServer &server, bool allWindows);\n\tvirtual void\t\t\temulateMouseRawMode(bool enable);\n\n\t// Build a TMouseButton value from the current buttons state\n\tTMouseButton\tbuildButtonsFlags() const;\n\t// Build a TMouseButton value (but with no mouse values)\n\tTMouseButton\tbuildKeyboardButtonFlags() const\n\t{\n\t\treturn (TMouseButton) (buildButtonsFlags() & (ctrlButton|shiftButton|altButton));\n\t}\n\n//================================================================\n//================================================================\n//================================================================\nprivate:\n\ttypedef HRESULT (WINAPI * TPDirectInput8Create) (HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID* ppvOut, LPUNKNOWN punkOuter);\n\t// Private internal server message, used to stored all messages internally before to dispatch them, when no server is supplied to poll(...\n\tclass CDIEventServer : CEventServer\n\t{\n\t\tfriend class CDIEventEmitter;\n\tpublic:\n\t\tvoid setServer (CEventServer *server)\n\t\t{\n\t\t\t_Server = server;\n\t\t}\n\tprivate:\n\t\tbool pumpEvent(CEvent *event)\n\t\t{\n\t\t\tCEventServer::pumpEvent(event);\n\t\t\t_Server->postEvent (event);\n\t\t\treturn false;\n\t\t}\n\tprivate:\n\t\tCEventServer *_Server;\n\t};\nprivate:\n\tHWND\t\t\t\t\t\t\t\t_hWnd;\n\tTMouseButton\t\t\t\t\t\t_ButtonsFlags;\n\tNLMISC::CRefPtr<CWinEventEmitter>\t_WE;\n\tstatic HMODULE\t\t\t\t_DirectInputLibHandle;\n\tstatic TPDirectInput8Create _PDirectInput8Create;\n\tstatic uint\t\t\t\t\t_NumCreatedInterfaces;\nprivate:\n\tstatic bool loadLib();\n\tstatic void unloadLib();\n//====\nprivate:\n\tCDIEventServer\t\t\t\t\t\t\t_InternalServer;\n\tCInputDeviceServer\t\t\t\t\t\t_DeviceServer;\n\tIDirectInput8\t\t\t\t\t\t\t*_DInput8;\n\tCDIMouse\t\t\t\t\t\t\t\t*_Mouse;\n\tCDIKeyboard\t\t\t\t\t\t\t\t*_Keyboard;\nprivate:\n\tCDIEventEmitter(HWND hwnd, CWinEventEmitter *we);\n};\n\n\n\n} // NLMISC\n\n#endif // NL_WINDOWS\n\n\n#endif // NL_DX_EVENT_EMITTER_H\n\n/* End of dx_event_emitter.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/diff_tool.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef DIFF_TOOL_H\n#define DIFF_TOOL_H\n\n#include \"i18n.h\"\n\nnamespace STRING_MANAGER\n{\n\tconst ucstring\t\tnl(\"\\r\\n\");\n\n\n\tstruct TStringInfo\n\t{\n\t\tstd::string\t\t\tIdentifier;\n\t\tucstring\t\t\tText;\n\t\tucstring\t\t\tText2;\n\t\tmutable ucstring\tComments;\n\t\tuint64\t\t\t\tHashValue;\n\t};\n\n\tstruct TStringDiffContext\n\t{\n\t\ttypedef std::vector<TStringInfo>::iterator\titerator;\n\t\tconst std::vector<TStringInfo>\t&Addition;\n\t\tstd::vector<TStringInfo>\t\t&Reference;\n\t\tstd::vector<TStringInfo>\t\t&Diff;\n\n\t\tTStringDiffContext(const std::vector<TStringInfo> &addition, std::vector<TStringInfo> &reference, std::vector<TStringInfo> &diff)\n\t\t\t: Addition(addition),\n\t\t\tReference(reference),\n\t\t\tDiff(diff)\n\t\t{\n\t\t}\n\t};\n\n\tstruct TClause\n\t{\n\t\tstd::string\tIdentifier;\n\t\tucstring\tConditions;\n\t\tucstring\tText;\n\t\tucstring\tComments;\n\t\tuint64\t\tHashValue;\n\t};\n\n\tstruct TPhrase\n\t{\n\t\tstd::string\t\t\t\tIdentifier;\n\t\tucstring\t\t\t\tParameters;\n\t\tmutable ucstring\t\tComments;\n\t\tstd::vector<TClause>\tClauses;\n\t\tuint64\t\t\t\t\tHashValue;\n\t};\n\n\tstruct TPhraseDiffContext\n\t{\n\t\ttypedef\tstd::vector<TPhrase>::iterator iterator;\n\t\tconst std::vector<TPhrase>\t&Addition;\n\t\tstd::vector<TPhrase>\t\t\t&Reference;\n\t\tstd::vector<TPhrase>\t\t\t&Diff;\n\n\t\tTPhraseDiffContext(const std::vector<TPhrase> &addition, std::vector<TPhrase> &reference, std::vector<TPhrase> &diff)\n\t\t\t: Addition(addition),\n\t\t\tReference(reference),\n\t\t\tDiff(diff)\n\t\t{\n\t\t}\n\t};\n\n\tstruct TWorksheet\n\t{\n\t\ttypedef std::vector<ucstring>\tTRow;\n\t\ttypedef std::vector<TRow>\t\tTData;\n\t\tTData\tData;\n\t\tuint\tColCount;\n\n\t\tTWorksheet()\n\t\t\t: ColCount(0)\n\t\t{\n\t\t}\n\n\t\tstd::vector<TRow>::iterator\t\tbegin()\n\t\t{\n\t\t\treturn Data.begin();\n\t\t}\n\n\t\tstd::vector<TRow>::iterator\t\tend()\n\t\t{\n\t\t\treturn Data.end();\n\t\t}\n\n\t\tstd::vector<TRow>::const_iterator\t\tbegin() const\n\t\t{\n\t\t\treturn Data.begin();\n\t\t}\n\n\t\tstd::vector<TRow>::const_iterator\t\tend() const\n\t\t{\n\t\t\treturn Data.end();\n\t\t}\n\n\t\tvoid push_back(const TRow &row)\n\t\t{\n\t\t\tData.push_back(row);\n\t\t}\n\n\t\tstd::vector<TRow>::iterator insert(std::vector<TRow>::iterator pos, const TRow &value)\n\t\t{\n\t\t\treturn Data.insert(pos, value);\n\t\t}\n\n\t\tstd::vector<TRow>::iterator erase(std::vector<TRow>::iterator it)\n\t\t{\n\t\t\treturn Data.erase(it);\n\t\t}\n\n\t\tTRow &back()\n\t\t{\n\t\t\treturn Data.back();\n\t\t}\n\n\t\tTRow &operator [] (uint index)\n\t\t{\n\t\t\treturn Data[index];\n\t\t}\n\n\t\tconst TRow &operator [] (uint index) const\n\t\t{\n\t\t\treturn Data[index];\n\t\t}\n\n\t\tuint size() const\n\t\t{\n\t\t\treturn (uint)Data.size();\n\t\t}\n\n\t\tvoid insertColumn(uint colIndex)\n\t\t{\n\t\t\tnlassert(colIndex <= ColCount);\n\n\t\t\tfor (uint i=0; i<Data.size(); ++i)\n\t\t\t{\n\t\t\t\t// insert a default value.\n\t\t\t\tData[i].insert(Data[i].begin()+colIndex, ucstring());\n\t\t\t}\n\t\t\tColCount++;\n\t\t}\n\n\t\tvoid copyColumn(uint srcColIndex, uint dstColIndex)\n\t\t{\n\t\t\tnlassert(srcColIndex < ColCount);\n\t\t\tnlassert(dstColIndex < ColCount);\n\n\t\t\tfor (uint i=0; i<Data.size(); ++i)\n\t\t\t{\n\t\t\t\tData[i][dstColIndex] = Data[i][srcColIndex];\n\t\t\t}\n\t\t}\n\n\t\tvoid eraseColumn(uint colIndex)\n\t\t{\n\t\t\tnlassertex(colIndex < ColCount, (\"TWorksheet::eraseColumn : bad column index: colIndex(%u) is not less than ColCount(%u)\", colIndex, ColCount));\n\n\t\t\tfor (uint i=0; i<Data.size(); ++i)\n\t\t\t{\n\t\t\t\t// insert a default value.\n\t\t\t\tData[i].erase(Data[i].begin()+colIndex);\n\t\t\t}\n\t\t\tColCount--;\n\t\t}\n\n\t\tvoid moveColumn(uint oldColIndex, uint newColIndex)\n\t\t{\n\t\t\tnlassert(oldColIndex < ColCount);\n\t\t\tnlassert(newColIndex < ColCount);\n\n\t\t\tif (oldColIndex == newColIndex)\n\t\t\t\treturn;\n\n\t\t\tif (newColIndex > oldColIndex)\n\t\t\t{\n\t\t\t\t// the dst is after the src, no problem with index\n\t\t\t\tinsertColumn(newColIndex);\n\t\t\t\tcopyColumn(oldColIndex, newColIndex);\n\t\t\t\teraseColumn(oldColIndex);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the dst is before the src, need to take the column insertion into account\n\t\t\t\tinsertColumn(newColIndex);\n\t\t\t\tcopyColumn(oldColIndex+1, newColIndex);\n\t\t\t\teraseColumn(oldColIndex+1);\n\t\t\t}\n\t\t}\n\n\t\tvoid setColCount(uint count)\n\t\t{\n\t\t\tif (count != ColCount)\n\t\t\t{\n\t\t\t\tfor (uint i=0; i<Data.size(); ++i)\n\t\t\t\t\tData[i].resize(count);\n\t\t\t}\n\t\t\tColCount = count;\n\t\t}\n\n\t\tbool findId(uint& colIndex)\n\t\t{\n\t\t\tif (Data.empty())\n\t\t\t\treturn false;\n\n\t\t\tfor (TWorksheet::TRow::iterator it=Data[0].begin(); it!=Data[0].end(); ++it)\n\t\t\t{\n\t\t\t\tstd::string columnTitle = (*it).toString();\n\t\t\t\tif ( ! columnTitle.empty() )\n\t\t\t\t{\n\t\t\t\t\t// Return the first column for which the title does not begin with '*'\n\t\t\t\t\tif ( columnTitle[0] != '*' )\n\t\t\t\t\t{\n\t\t\t\t\t\tcolIndex = (uint)(it - Data[0].begin());\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tbool findCol(const ucstring &colName, uint &colIndex)\n\t\t{\n\t\t\tif (Data.empty())\n\t\t\t\treturn false;\n\t\t\tTWorksheet::TRow::iterator it = std::find(Data[0].begin(), Data[0].end(), colName);\n\t\t\tif (it == Data[0].end())\n\t\t\t\treturn false;\n\n\t\t\tcolIndex = (uint)(it - Data[0].begin());\n\t\t\treturn true;\n\t\t}\n\n\t\tvoid insertRow(uint rowIndex, const TRow &row)\n\t\t{\n\t\t\tnlassertex(rowIndex <= Data.size(), (\"TWorksheet::insertRow: bad row index: rowIndex(%u) is out of range (max=%u)\", rowIndex, Data.size()-1));\n\t\t\tnlassertex(row.size() == ColCount, (\"TWorksheet::insertRow: bad column count : inserted row size(%u) is invalid (must be %u) at rowIndex(%u)\", row.size(), ColCount, rowIndex));\n\n\t\t\tData.insert(Data.begin()+rowIndex, row);\n\t\t}\n\n\t\t// resize the rows\n\t\tvoid resize(uint numRows)\n\t\t{\n\t\t\tuint\toldSize= (uint)Data.size();\n\t\t\tData.resize(numRows);\n\t\t\t// alloc good Column count for new lines\n\t\t\tfor(uint i= oldSize;i<Data.size();i++)\n\t\t\t\tData[i].resize(ColCount);\n\t\t}\n\n\t\tbool findRow(uint colIndex, const ucstring &colValue, uint &rowIndex)\n\t\t{\n\t\t\tnlassertex(colIndex < ColCount, (\"TWorksheet::findRow: bad column index: colIndex(%u) is not less than ColCount(%u)\", colIndex, ColCount));\n\n\t\t\tTData::iterator first(Data.begin()), last(Data.end());\n\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (first->operator[](colIndex) == colValue)\n\t\t\t\t{\n\t\t\t\t\trowIndex = (uint)(first - Data.begin());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\tvoid setData(uint rowIndex, uint colIndex, const ucstring &value)\n\t\t{\n\t\t\tnlassertex(rowIndex < Data.size(), (\"TWorksheet::setData: bad row index: rowIndex(%u) is out of range (max=%u)\", rowIndex, Data.size()));\n\t\t\tnlassertex(colIndex < ColCount, (\"TWorksheet::setData: bad column index: colIndex(%u) is not less than ColCount(%u) ar rowIndex(%u)\", colIndex, ColCount, rowIndex));\n\n\t\t\tData[rowIndex][colIndex] = value;\n\t\t}\n\n\t\tconst ucstring &getData(uint rowIndex, uint colIndex) const\n\t\t{\n\t\t\tnlassertex(rowIndex < Data.size(), (\"TWorksheet::getData: bad row index: rowIndex(%u) is out of range (max=%u)\", rowIndex, Data.size()));\n\t\t\tnlassertex(colIndex < ColCount, (\"TWorksheet::getData: bad column index: colIndex(%u) is not less than ColCount(%u) at rowIndex(%u)\", colIndex, ColCount, rowIndex));\n\n\t\t\treturn Data[rowIndex][colIndex];\n\t\t}\n\n\t\tvoid setData(uint rowIndex, const ucstring &colName, const ucstring &value)\n\t\t{\n\t\t\tnlassertex(rowIndex > 0, (\"TWorksheet::setData: rowIndex(%u) must be greater then 0 !\", rowIndex));\n\t\t\tnlassertex(rowIndex < Data.size(), (\"TWorksheet::setData: rowIndex(%u) is out of range (max=%u)\", rowIndex, Data.size()));\n\t\t\tTWorksheet::TRow::iterator it = std::find(Data[0].begin(), Data[0].end(), ucstring(colName));\n\t\t\tnlassertex(it != Data[0].end(), (\"TWorksheet::setData: invalid colName: can't find the column named '%s' at row %u\", colName.toString().c_str(), rowIndex));\n\n\t\t\tData[rowIndex][it - Data[0].begin()] = value;\n\t\t}\n\t\tconst ucstring &getData(uint rowIndex, const ucstring &colName) const\n\t\t{\n\t\t\tnlassertex(rowIndex > 0, (\"TWorksheet::getData: bad row index: rowIndex(%u) must be greater then 0 !\", rowIndex));\n\t\t\tnlassertex(rowIndex < Data.size(), (\"TWorksheet::getData: bad row index: rowIndex(%u) is out of range (max=%u)\", rowIndex, Data.size()));\n\t\t\tTWorksheet::TRow::const_iterator it = std::find(Data[0].begin(), Data[0].end(), ucstring(colName));\n\t\t\tnlassertex(it != Data[0].end(), (\"TWorksheet::getData: invalid colName: can't find the column named '%s' at row %u\", colName.toString().c_str(), rowIndex));\n\n\t\t\treturn Data[rowIndex][it - Data[0].begin()];\n\t\t}\n\t};\n\n\n\tstruct TGetWorksheetIdentifier\n\t{\n\t\tstd::string operator()(const TWorksheet &container, uint index) const\n\t\t{\n\t\t\treturn container.getData(index, 1).toString();\n\t\t}\n\t};\n\n\tstruct TGetWorksheetHashValue\n\t{\n\t\tuint64 operator()(const TWorksheet &container, uint index) const\n\t\t{\n\t\t\treturn NLMISC::CI18N::stringToHash(container.getData(index, ucstring(\"*HASH_VALUE\")).toString());\n\t\t}\n\t};\n\n\tstruct TTestWorksheetItem : public std::unary_function<TWorksheet::TRow, bool>\n\t{\n\t\tucstring\tIdentifier;\n\t\tTTestWorksheetItem(const std::string &identifier)\n\t\t\t: Identifier(identifier)\n\t\t{}\n\t\tbool operator () (const TWorksheet::TRow &row) const\n\t\t{\n\t\t\treturn row[1] == Identifier;\n\t\t}\n\t};\n\n\n\tstruct TWordsDiffContext\n\t{\n\t\ttypedef\tTWorksheet::TData::iterator iterator;\n\t\tconst TWorksheet\t&Addition;\n\t\tTWorksheet\t\t\t&Reference;\n\t\tTWorksheet\t\t\t&Diff;\n\n\t\tTWordsDiffContext(const TWorksheet &addition, TWorksheet &reference, TWorksheet &diff)\n\t\t\t: Addition(addition),\n\t\t\tReference(reference),\n\t\t\tDiff(diff)\n\t\t{\n\t\t}\n\t};\n\n\ttemplate<class ItemType>\n\tstruct TGetIdentifier\n\t{\n\t\tstd::string operator()(const std::vector<ItemType> &container, uint index) const\n\t\t{\n\t\t\treturn container[index].Identifier;\n\t\t}\n\t};\n\n\ttemplate<class ItemType>\n\tstruct TGetHashValue\n\t{\n\t\tuint64 operator()(const std::vector<ItemType> &container, uint index) const\n\t\t{\n\t\t\treturn container[index].HashValue;\n\t\t}\n\t};\n\n\ttemplate<class ItemType>\n\tstruct TTestItem : public std::unary_function<ItemType, bool>\n\t{\n\t\tstd::string\tIdentifier;\n\t\tTTestItem(const std::string &identifier)\n\t\t\t: Identifier(identifier)\n\t\t{}\n\t\tbool operator () (const ItemType &item) const\n\t\t{\n\t\t\treturn item.Identifier == Identifier;\n\t\t}\n\t};\n\n\t/**\n\t*\tItemType must have a property named Identifier that uniquely\n\t*\tidentify each item.\n\t*\tItemType must have a property named HashValue that is used\n\t*\tto determine the change between context.Addition and context.Reference vector.\n\t*/\n\ttemplate <class ItemType, class Context, class GetIdentifier = TGetIdentifier<ItemType>, class GetHashValue = TGetHashValue<ItemType>, class TestItem = TTestItem<ItemType> >\n\tclass CMakeDiff\n\t{\n\tpublic:\n\t\tstruct IDiffCallback\n\t\t{\n\t\t\tvirtual void onEquivalent(uint addIndex, uint refIndex, Context &context) = 0;\n\t\t\tvirtual void onAdd(uint addIndex, uint refIndex, Context &context) = 0;\n\t\t\tvirtual void onRemove(uint addIndex, uint refIndex, Context &context) = 0;\n\t\t\tvirtual void onChanged(uint addIndex, uint refIndex, Context &context) = 0;\n\t\t\tvirtual void onSwap(uint newIndex, uint refIndex, Context &context) = 0;\n\n\t\t};\n\n\t\tvoid makeDiff(IDiffCallback *callback, Context &context, bool skipFirstRecord = false)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\t// compile time checking\n//\t\t\tContext::iterator testIt;\n#endif\n\t\t\tGetIdentifier\tgetIdentifier;\n\t\t\tGetHashValue\tgetHashValue;\n\t\t\t// compare the context.Reference an context.Addition file, remove any equivalent strings.\n\t\t\tuint addCount, refCount;\n\t\t\tif (skipFirstRecord)\n\t\t\t{\n\t\t\t\taddCount = 1;\n\t\t\t\trefCount = 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taddCount = 0;\n\t\t\t\trefCount=0;\n\t\t\t}\n\n\t\t\twhile (addCount < context.Addition.size() || refCount < context.Reference.size())\n\t\t\t{\n\t\t\t\tbool equal = true;\n\t\t\t\tif (addCount != context.Addition.size() && refCount != context.Reference.size())\n\t\t\t\t{\n\t\t\t\t\tequal = getHashValue(context.Addition, addCount) == getHashValue(context.Reference, refCount);\n\t\t\t\t}\n\n//\t\t\t\tvector<ItemType>::iterator it;\n\n\t\t\t\tif (addCount == context.Addition.size()\n\t\t\t\t\t||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\t!equal\n\t\t\t\t\t\t&&\tfind_if(context.Addition.begin(), context.Addition.end(), TestItem(getIdentifier(context.Reference, refCount))) == context.Addition.end()\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\t// this can only be removal\n\t\t\t\t\tcallback->onRemove(addCount, refCount, context);\n\t\t\t\t\tcontext.Reference.erase(context.Reference.begin()+refCount);\n//\t\t\t\t\t++refCount;\n\t\t\t\t}\n\t\t\t\telse if (refCount == context.Reference.size()\n\t\t\t\t\t||\n\t\t\t\t\t\t(\n\t\t\t\t\t\t\t!equal\n\t\t\t\t\t\t&&\tfind_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))) == context.Reference.end()\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\t// this can only be context.Addition\n\t\t\t\t\tcallback->onAdd(addCount, refCount, context);\n\t\t\t\t\tcontext.Reference.insert(context.Reference.begin()+refCount, context.Addition[addCount]);\n\t\t\t\t\t++refCount;\n\t\t\t\t\t++addCount;\n\t\t\t\t}\n\t\t\t\telse if (getIdentifier(context.Addition, addCount) != getIdentifier(context.Reference, refCount))\n\t\t\t\t{\n\t\t\t\t\t// swap two element.\n//\t\t\t\t\tContext::iterator it = find_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount)));\n//\t\t\t\t\tif (it == context.Reference.end())\n\n\t\t\t\t\tif (find_if(\n\t\t\t\t\t\t\tcontext.Reference.begin(),\n\t\t\t\t\t\t\tcontext.Reference.end(),\n\t\t\t\t\t\t\tTestItem(getIdentifier(context.Addition, addCount)))\n\t\t\t\t\t\t\t== context.Reference.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// context.Addition\n\t\t\t\t\t\tcallback->onAdd(addCount, refCount, context);\n\t\t\t\t\t\tcontext.Reference.insert(context.Reference.begin()+refCount, context.Addition[addCount]);\n\t\t\t\t\t\t++refCount;\n\t\t\t\t\t\t++addCount;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n//\t\t\t\t\t\tnlassert(it != context.Reference.begin()+refCount);\n\t\t\t\t\t\tuint index = (uint)(find_if(context.Reference.begin(), context.Reference.end(), TestItem(getIdentifier(context.Addition, addCount))) - context.Reference.begin());\n\n//\t\t\t\t\t\tcallback->onSwap(it - context.Reference.begin(), refCount, context);\n\t\t\t\t\t\tcallback->onSwap(index, refCount, context);\n//\t\t\t\t\t\tstd::swap(*it, context.Reference[refCount]);\n\t\t\t\t\t\tstd::swap(context.Reference[index], context.Reference[refCount]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (getHashValue(context.Addition, addCount) != getHashValue(context.Reference, refCount))\n\t\t\t\t{\n\t\t\t\t\t// changed element\n\t\t\t\t\tcallback->onChanged(addCount, refCount, context);\n\t\t\t\t\t++refCount;\n\t\t\t\t\t++addCount;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// same entry\n\t\t\t\t\tcallback->onEquivalent(addCount, refCount, context);\n\t\t\t\t\taddCount++;\n\t\t\t\t\trefCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\ttypedef CMakeDiff<TStringInfo, TStringDiffContext>\t\tTStringDiff;\n\ttypedef CMakeDiff<TPhrase, TPhraseDiffContext>\t\t\tTPhraseDiff;\n\ttypedef CMakeDiff<TWorksheet::TRow, TWordsDiffContext, TGetWorksheetIdentifier, TGetWorksheetHashValue, TTestWorksheetItem>\tTWorkSheetDiff;\n\n\n\tuint64\t\tmakePhraseHash(const TPhrase &phrase);\n\tbool\t\tparseHashFromComment(const ucstring &comments, uint64 &hashValue);\n\n\tbool\t\tloadStringFile(const std::string filename, std::vector<TStringInfo> &stringInfos, bool forceRehash, ucchar openMark = '[', ucchar closeMark = ']', bool specialCase = false);\n\tucstring\tprepareStringFile(const std::vector<TStringInfo> &strings, bool removeDiffComments, bool noDiffInfo = false);\n\n\tbool\t\treadPhraseFile(const std::string &filename, std::vector<TPhrase> &phrases, bool forceRehash);\n\tbool\t\treadPhraseFileFromString(ucstring const& doc, const std::string &filename, std::vector<TPhrase> &phrases, bool forceRehash);\n\tucstring\ttabLines(uint nbTab, const ucstring &str);\n\tucstring\tpreparePhraseFile(const std::vector<TPhrase> &phrases, bool removeDiffComments);\n\n\tbool\t\tloadExcelSheet(const std::string filename, TWorksheet &worksheet, bool checkUnique = true);\n\tbool\t\treadExcelSheet(const ucstring &text, TWorksheet &worksheet, bool checkUnique = true);\n\tvoid\t\tmakeHashCode(TWorksheet &sheet, bool forceRehash);\n\tucstring\tprepareExcelSheet(const TWorksheet &worksheet);\n\n}\t// namespace STRING_MANAGER\n\n#endif // DIFF_TOOL_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DISPLAYER_H\n#define NL_DISPLAYER_H\n\n#include \"types_nl.h\"\n\n#include <string>\n\n#include \"log.h\"\n\nnamespace NLMISC\n{\n\n\nclass CMutex;\n\n\n/**\n * Displayer interface. Used to specialize a displayer to display a string.\n * \\ref log_howto\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass IDisplayer\n{\npublic:\n\n\t/// Constructor\n\tIDisplayer(const char *displayerName = \"\");\n\n\t/// Destructor\n\tvirtual ~IDisplayer();\n\n\t/// Display the string where it does.\n\tvoid display( const CLog::TDisplayInfo& args, const char *message );\n\n\t/// This is the identifier for a displayer, it is used to find or remove a displayer\n\tstd::string DisplayerName;\n\nprotected:\n\n\t/// Method to implement in the derived class\n\tvirtual void doDisplay( const CLog::TDisplayInfo& args, const char *message) = 0;\n\n\n\t// Return the header string with date (for the first line of the log)\n\tstatic const char *HeaderString ();\n\npublic:\n\n\t/// Convert log type to string\n\tstatic const char *logTypeToString (CLog::TLogType logType, bool longFormat = false);\n\n\t/// Convert the current date to human string\n\tstatic const char *dateToHumanString ();\n\n\t/// Convert date to \"2000/01/14 10:05:17\" string\n\tstatic const char *dateToHumanString (time_t date);\n\n\t/// Convert date to \"784551148\" string (time in second from 1975)\n\tstatic const char *dateToComputerString (time_t date);\n\nprivate:\n\n\tCMutex\t*_Mutex;\n};\n\n\n\n/**\n * Std displayer. Put string to stdout.\n * \\ref log_howto\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CStdDisplayer : virtual public IDisplayer\n{\npublic:\n\tCStdDisplayer (const char *displayerName = \"\") : IDisplayer (displayerName) {}\n\nprotected:\n\n\t/// Display the string to stdout and OutputDebugString on Windows\n\tvirtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message );\n\n};\n\n\n/**\n * File displayer. Put string into a file.\n * \\ref log_howto\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CFileDisplayer : virtual public IDisplayer\n{\npublic:\n\n\t/// Constructor\n\tCFileDisplayer (const std::string &filename, bool eraseLastLog = false, const char *displayerName = \"\", bool raw = false);\n\n\tCFileDisplayer ();\n\n\t~CFileDisplayer ();\n\n\t/// Set Parameter of the displayer if not set at the ctor time\n\tvoid setParam (const std::string &filename, bool eraseLastLog = false);\n\nprotected:\n\t/// Put the string into the file.\n    virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message );\n\nprivate:\n\tstd::string _FileName;\n\n\tFILE\t\t*_FilePointer;\n\n\tbool\t\t_NeedHeader;\n\n\tuint\t\t_LastLogSizeChecked;\n\n\tbool\t\t_Raw;\n};\n\n/**\n * Message Box displayer. Put string into a message box.\n * \\ref log_howto\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CMsgBoxDisplayer : virtual public IDisplayer\n{\npublic:\n\tCMsgBoxDisplayer (const char *displayerName = \"\") : IDisplayer (displayerName), IgnoreNextTime(false) {}\n\n\tbool IgnoreNextTime;\n\nprotected:\n\t/// Put the string into the file.\n    virtual void doDisplay ( const CLog::TDisplayInfo& args, const char *message );\n};\n\n\n}\n\n#endif // NL_DISPLAYER_H\n\n/* End of displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/dummy_window.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DUMMY_WINDOW_H\n#define NL_DUMMY_WINDOW_H\n\n\n#include \"nel/misc/types_nl.h\"\n\n#ifdef NL_OS_WINDOWS // for win32 os only\n\n#ifndef WIN32_LEAN_AND_MEAN\n#\tdefine WIN32_LEAN_AND_MEAN\n#endif\n#ifndef _WIN32_WINDOWS\n#\tdefine _WIN32_WINDOWS 0x0410\n#endif\n#ifndef _WIN32_WINNT\n#\tdefine _WIN32_WINNT 0x0400\n#endif\n#ifndef WINVER\n#\tdefine WINVER 0x0400\n#endif\n#ifndef NOMINMAX\n#\tdefine NOMINMAX\n#endif\n#include <windows.h>\n\n\nnamespace NLMISC\n{\n\n/** A simple invisible win32 window, with an optional message handling function.\n  * Possible uses include :\n  * - Creating an icon in the tray (require a window to be passed)\n  * - Creating a message queue (in order to use an IPC mechanism such as WM_COPYDATA)\n  * - etc.\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2007\n  */\nclass CDummyWindow\n{\npublic:\n\tCDummyWindow();\n\t/** Init a dummy window, with an optional message handling procedure\n\t  * \\return true on success\n\t  */\n\tbool init(HINSTANCE hInstance, WNDPROC winProc = NULL);\n\t// release this window\n\tvoid release();\n\t~CDummyWindow();\n\t// Get this window handle\n\tHWND getWnd() const { return _HWnd; }\nprivate:\n\tHWND _HWnd;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_OS_WINDOWS\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/dynloadlib.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DYNLIBLOAD_H\n#define NL_DYNLIBLOAD_H\n\n#include \"types_nl.h\"\n#include <string>\n#include <vector>\n\n#ifdef NL_OS_WINDOWS\nstruct HINSTANCE__;\ntypedef struct HINSTANCE__ *HINSTANCE;\ntypedef HINSTANCE HMODULE;      /* HMODULEs can be used in place of HINSTANCEs */\n#else\n#\tinclude <dlfcn.h>\n#endif\n\nnamespace NLMISC\n{\n\n/// Define the os specific type for dynamic library module handler\n#if defined (NL_OS_WINDOWS)\ntypedef HMODULE\t\tNL_LIB_HANDLE;\n#elif defined (NL_OS_UNIX)\ntypedef void*\t\tNL_LIB_HANDLE;\n#else\n# error \"You must define the module type on this platform\"\n#endif\n\n#ifdef NL_OS_WINDOWS\n// MSCV need explicit tag to export or import symbol for a code module\n#define NL_LIB_EXPORT\t__declspec(dllexport)\n#define NL_LIB_IMPORT\t__declspec(dllimport)\n#else\n// other systems don't bother with this kind of detail, they export any 'extern' symbol (almost all functions)\n#define NL_LIB_EXPORT\n#define NL_LIB_IMPORT\n#endif\n\n/// Generic dynamic library loading function.\nNL_LIB_HANDLE\tnlLoadLibrary(const std::string &libName);\n/// Generic dynamic library unloading function.\nbool\t\t\tnlFreeLibrary(NL_LIB_HANDLE libHandle);\n/// Generic dynamic library symbol address lookup function.\nvoid\t\t\t*nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &symbolName);\n\n// Compilation mode specific suffixes\n#ifdef NL_OS_WINDOWS\n#\tifdef NL_DEBUG_INSTRUMENT\nconst std::string nlLibSuffix(\"_di\");\n#\telif defined(NL_DEBUG)\nconst std::string nlLibSuffix(\"_d\");\n#\telif defined(NL_RELEASE)\nconst std::string nlLibSuffix(\"_r\");\n#\telse\n#\t\terror \"Unknown compilation mode, can't build suffix\"\n#\tendif\n#elif defined (NL_OS_UNIX)\nconst std::string nlLibSuffix; // empty\n#else\n#\terror \"You must define the lib suffix for your platform\"\n#endif\n\n\n// Utility macro to export a module entry point as a C pointer to a C++ class or function\n#define NL_LIB_EXPORT_SYMBOL(symbolName, classOrFunctionName, instancePointer) \\\nextern \"C\" \\\n{ \\\n\tNL_LIB_EXPORT classOrFunctionName\t*symbolName = (classOrFunctionName*)instancePointer; \\\n};\n\n/*\n *\n * \\author Boris Boucher\n * \\author Nevrax France\n * \\date 2004\n */\nclass CLibrary\n{\n\t/// Dynamic library handle\n\tNL_LIB_HANDLE\t_LibHandle;\n\t/// Loaded library name\n\tstd::string\t\t_LibFileName;\n\n\t/** When a module handle is assigned to the instance, this\n\t *\tflag state whether the CLibrary will free the library or not\n\t *\twhen it is deleted.\n\t */\n\tbool\t\t\t_Ownership;\n\t/** This points to the 'pure' nel library interface.\n\t *\tThis means that the library export an entry point called\n\t *\t'NeLLibraryEntry' that points to a INelLibrary interface.\n\t *\tThis interface is used by the CLibrary class to\n\t *\tmanage efficiently the library and to give\n\t *\tlibrary implementors some hooks on library management.\n\t */\n\tclass INelLibrary\t\t*_PureNelLibrary;\n\n\t/// Lib paths\n\tstatic std::vector<std::string>\t_LibPaths;\n\n\t/// Private copy constructor, not authorized\n\tCLibrary (const CLibrary &other);\n\n\t// Private assignment operator\n\tCLibrary &operator =(const CLibrary &other);\n\npublic:\n\tCLibrary();\n\t/** Assign a existing module handler to a new dynamic library instance\n\t *\tNote that you cannot use 'pure nel library' this way.\n\t */\n\tCLibrary(NL_LIB_HANDLE libHandle, bool ownership);\n\t/// Load the specified library and take ownership by default\n\tCLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership = true);\n\t/// Destructor, free the library if the object have ownership\n\tvirtual ~CLibrary();\n\n\t/** Load the specified library.\n\t*\tThe method assert if a module is already assigned or loaded\n\t*\tIf addNelDecoration is true, the standard Nel suffix and library extention or prefix are\n\t*\tadded to the lib name (with is just a base name).\n\t*\tIf tryLibPath is true, then the method will try to find the required\n\t*\tlibrary in the added library files (in order of addition).\n\t*\tReturn true if the library load ok.\n\t*/\n\tbool loadLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership = true);\n\n\t/** Unload (free) the assigned/loaded library.\n\t*\tThe object must have ownership over the library or the call will assert.\n\t*\tAfter this call, you can recall loadLibrary.\n\t*/\n\tvoid freeLibrary();\n\n\t/** Get the address a the specified procedure in the library\n\t*\tReturn NULL is the proc is not found,\n\t*\tAssert if the library is not load or assigned.\n\t*/\n\tvoid *getSymbolAddress(const std::string &symbolName);\n\n\t/// Get the name of the loaded library\n\tstd::string getLibFileName()\n\t{\n\t\treturn _LibFileName;\n\t}\n\n\t/// Check whether a library is effectively loaded\n\tbool isLibraryLoaded();\n\n\t/** Check if the loaded library is a pure library\n\t *\tReturn false if the library is not pure\n\t *\tor if the library is not loaded.\n\t */\n\tbool isLibraryPure();\n\n\t/** Return the pointer on the pure nel library interface.\n\t *\tReturn NULL if isLibraryPure() is false.\n\t */\n\tclass INelLibrary *getNelLibraryInterface();\n\n\t/** Build a NeL standard library name according to platform and compilation mode setting.\n\t *\taka : adding decoration one base lib name.\n\t *\te.g : 'mylib' become\t'mylib_rd.dll' on Windows ReleaseDebug mode or\n\t *\t\t\t\t\t\t\t'libmylib.so' on unix system.\n\t */\n\tstatic std::string makeLibName(const std::string &baseName);\n\t/** Remove NeL standard library name decoration according to platform and compilation mode setting.\n\t *\te.g : 'mylib_rd.dll' on windows ReleaseDebug mode become 'mylib'\n\t */\n\tstatic std::string cleanLibName(const std::string &decoratedName);\n\t/** Add a list of library path\n\t *\t@see loadLibrary for a discusion about lib path\n\t */\n\tstatic void addLibPaths(const std::vector<std::string> &paths);\n\t/** Add a library path\n\t *\t@see loadLibrary for a discusion about lib path\n\t */\n\tstatic void addLibPath(const std::string &path);\n\n};\n\n/** Interface class for 'pure Nel' library module.\n *\tThis interface is used to expose a standard\n *\tentry point for dynamically loaded library\n *\tand to add some hooks for library implementor\n *\tover library loading/unloading.\n */\nclass INelLibrary\n{\n\tfriend class CLibrary;\n\n\t/// this counter keep tracks of how many time the library have been loaded in the same process.\n\tuint32\t\t\t\t\t\t_LoadingCounter;\n\t/// The library context\n\tclass CLibraryContext\t\t*_LibContext;\n\n\t/** Called by CLibrary after a successful loadLibrary\n\t *\tNote : this methods MUST be virtual to ensure\n\t *\tthat the code executed is the one from\n\t *\tthe loaded library.\n\t */\n\tvirtual void _onLibraryLoaded(class INelContext &nelContext);\n\t/** Called by the CLibrary class before unloading the library.\n\t *\tNote : this methods MUST be virtual to ensure\n\t *\tthat the code executed is the one from\n\t *\tthe loaded library.\n\t */\n\tvirtual void _onLibraryUnloaded();\npublic:\n\n\tINelLibrary()\n\t\t: _LoadingCounter(0),\n\t\t_LibContext(NULL)\n\t{}\n\n\tvirtual ~INelLibrary();\n\n\t/// Return the loading counter value\n\tuint32\tgetLoadingCounter();\n\n\t/** Called after each loading of the library.\n\t *\tfirstTime is true if this is the first time that\n\t *\tthis library is loaded in the current process.\n\t *\tIf the process load more than once the same\n\t *\tlibrary, subsequent call to this method will\n\t *\thave firstTime false.\n\t *\tImplement this method to initialize think or whatever.\n\t */\n\tvirtual void onLibraryLoaded(bool firstTime) =0;\n\t/** Called after before each unloading of the library.\n\t *\tlastTime is true if the library will be effectively\n\t *\tunmapped from the process memory.\n\t *\tIf the library have been loaded more than once,\n\t *\tthen lastTime is false, indicating that the\n\t *\tlibrary will still be in the process memory\n\t *\tspace after the call.\n\t */\n\tvirtual void onLibraryUnloaded(bool lastTime) =0;\n};\n\n#define NLMISC_PURE_LIB_ENTRY_POINT\tNelLibraryEntry\n\n#define NLMISC_DECL_PURE_LIB(className) \\\n\tclassName\t_PureLibraryEntryInstance; \\\n\tNL_LIB_EXPORT_SYMBOL( NLMISC_PURE_LIB_ENTRY_POINT, NLMISC::INelLibrary, &_PureLibraryEntryInstance)\n\n} // NLMISC\n\n#endif // NL_DYNLIBLOAD_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/eid_translator.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef\tNL_EID_TRANSLATOR_H\n#define\tNL_EID_TRANSLATOR_H\n\n#include <string>\n#include <vector>\n#include <map>\n#include <limits>\n\n#include \"types_nl.h\"\n#include \"entity_id.h\"\n#include \"ucstring.h\"\n#include \"command.h\"\n\nnamespace\tNLMISC\n{\n\nclass CEntityIdTranslator\n{\n\tNLMISC_SAFE_SINGLETON_DECL_PTR(CEntityIdTranslator);\npublic:\n\n\t/** Descriptor for an entity in the translator */\n\tstruct CEntity\n\t{\n\t\tCEntity ()\n\t\t\t:\tEntityNameStringId(0),\n\t\t\t\tEntitySlot(-1),\n\t\t\t\tShardId(0),\n\t\t\t\tUId(std::numeric_limits<uint32>::max()),\n\t\t\t\tOnline(false)\n\t\t{ }\n\n\t\tCEntity (const ucstring &entityName, uint32 uid, const std::string &userName, sint8 entitySlot, uint32 shardId =0)\n\t\t\t:\tEntityName(entityName),\n\t\t\t\tEntityNameStringId(0),\n\t\t\t\tEntitySlot(entitySlot),\n\t\t\t\tShardId(shardId),\n\t\t\t\tUId(uid),\n\t\t\t\tUserName(userName),\n\t\t\t\tOnline(false)\n\t\t{ }\n\n\t\t/// The display name of the entity\n\t\tucstring\tEntityName;\n\t\t/// The mapped name of the entity (used to store IOS generated string id)\n\t\tuint32\t\tEntityNameStringId;\n\t\t/// the character slot\n\t\tsint8\t\tEntitySlot;\n\t\t/// Shard id of the entity (for multi shard systems)\n\t\tuint32\t\tShardId;\n\n\t\t/// User id the character owner (aka account id)\n\t\tuint32\t\tUId;\n\t\t/// User name of the character owner (aka account name)\n\t\tstd::string UserName;\n\n\t\t/// A flag stating if the character is online\n\t\tbool\t\tOnline;\n\n\t\tvoid serial (NLMISC::IStream &s);\n\t};\n\n\ttypedef std::map<NLMISC::CEntityId, CEntity>\tTEntityCont;\n\n\t/// clear all the registered entities from the translator.\n\tvoid\t\t\t\tclear();\n\t// performs all check on a name ( name validity + uniqueness )\n\tbool\t\t\t\tcheckEntityName (const ucstring &entityName);\n\t/// return true if a name already exists\n\tbool\t\t\t\tentityNameExists(const ucstring &entityName);\n\t// register an entity in this manager\n\tvoid\t\t\t\tregisterEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const std::string &userName, uint32 shardId =0);\n\t// register or update an entity in this manager\n\tvoid\t\t\t\tupdateEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const std::string &userName, uint32 shardId =0);\n\t// unregister an entity from this manager\n\tvoid\t\t\t\tunregisterEntity (const CEntityId &eid);\n\t// Check if an entity is registered\n\tbool\t\t\t\tisEntityRegistered(const CEntityId &eid);\n\t// set an association entityName / entityStringId, return true if association has been set\n\tbool\t\t\t\tsetEntityNameStringId(const ucstring &entityName, uint32 stringId);\n\t// set an association entityId / entityStringId, return true if association has been set\n\tbool\t\t\t\tsetEntityNameStringId(const CEntityId &eid, uint32 stringId);\n\t// get string id for entityId\n\tuint32\t\t\t\tgetEntityNameStringId(const CEntityId &eid);\n\t// get the shard id of an entity\n\tuint32\t\t\t\tgetEntityShardId(const CEntityId &eid);\n\n\t// set an eid to online or not\n\tvoid\t\t\t\tsetEntityOnline (const CEntityId &eid, bool online);\n\n\t// is an entity in online\n\tbool\t\t\t\tisEntityOnline (const CEntityId &eid);\n\n\t// check if parameters are coherent with the content of the class, if not, set with the parameters and warn\n\tvoid\t\t\t\tcheckEntity (const CEntityId &eid, const ucstring &entityName, uint32 uid, const std::string &userName);\n\n\t// the first param is the file where are all entities information, the second is a text file (one line per pattern using * and ?) with invalid entity name\n\tvoid\t\t\t\tload (const std::string &fileName, const std::string &invalidEntityNamesFilename);\n\n\t// you must call this function to save the data into the hard drive\n\tvoid\t\t\t\tsave ();\n\n\t// get eid using the entity name\n\tCEntityId\t\t\tgetByEntity (const ucstring &entityName);\n\n\t// get entity name using the eid\n\tconst ucstring\t\t&getByEntity (const NLMISC::CEntityId &eid);\n\n\tvoid\t\t\t\tgetEntityIdInfo (const CEntityId &eid, ucstring &entityName, sint8 &entitySlot, uint32 &uid, std::string &userName, bool &online, std::string* additional = NULL);\n\n\t// transform a username ucstring into a string that can be compared with registered string\n\tstd::string\t\t\tgetRegisterableString( const ucstring & entityName);\n\n\t/// return a vector of invalid names\n\tconst std::vector<std::string> & getInvalidNames(){ return InvalidEntityNames; }\n\n\n\tconst TEntityCont\t&getRegisteredEntities () { return RegisteredEntities; }\n\n\tstatic const uint Version;\n\n\tuint FileVersion;\n\n\t/**\n\t * Callback called when getEntityIdInfo called, so service may add additional info\n\t * Format MUST be [InfoName InfoValue]* (e.g. a list of 2 strings, first being name for\n\t * the retrieved info, and second being the value of the info\n\t */\n\ttypedef std::string\t(*TAdditionalInfoCb)(const CEntityId &eid);\n\n\tTAdditionalInfoCb\tEntityInfoCallback;\n\n\tstatic void removeShardFromName(ucstring& name);\n\nprivate:\n\t// get all eid for a user using the user name or the user id\n\tvoid\t\t\t\tgetByUser (uint32 uid, std::vector<NLMISC::CEntityId> &res);\n\tvoid\t\t\t\tgetByUser (const std::string &userName, std::vector<NLMISC::CEntityId> &res, bool exact=true);\n\n\tvoid\t\t\t\tgetByEntity (const ucstring &entityName, std::vector<NLMISC::CEntityId> &res, bool exact);\n\n\t// return the user id and 0 if not found\n\tuint32\t\t\t\tgetUId (const std::string &userName);\n\tstd::string\t\t\tgetUserName (uint32 uid);\n\n\t// Returns true if the username is valid.\n\t// It means that there only alphabetic and numerical character and the name is at least 3 characters long.\n\tbool isValidEntityName (const ucstring &entityName, NLMISC::CLog *log = NLMISC::InfoLog );\n\n\n\t/// The container for all entity in the translator\n\tTEntityCont\t\t\tRegisteredEntities;\n\n\ttypedef std::map<ucstring, NLMISC::CEntityId>\tTNameIndexCont;\n\t/// the reverse index to retreive entity by name\n\tTNameIndexCont\tNameIndex;\n\n\t// Singleton, no ctor access\n\tCEntityIdTranslator() { EntityInfoCallback = NULL; }\n\n\tstd::string FileName;\n\n\tstd::vector<std::string> InvalidEntityNames;\n\n\tfriend void cbInvalidEntityNamesFilename(const std::string &filename);\n\tfriend struct entityNameValidClass;\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(nel,findEIdByUser);\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(nel,findEIdByEntity);\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(nel,entityNameValid);\n\tNLMISC_CATEGORISED_COMMAND_FRIEND(nel,playerInfo);\n};\n\n}\n\n#endif // NL_EID_TRANSLATOR_H\n\n/* End of eid_translator.h */\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/entity_id.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ENTITY_ID_H\n#define NL_ENTITY_ID_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n#include \"common.h\"\n#include \"stream.h\"\n\nnamespace NLMISC {\n\n/**\n * Entity identifier\n * \\author Sameh Chafik, Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nstruct CEntityId\n{\n\t// pseudo constants\n\tenum\n\t{\n\t\tDYNAMIC_ID_SIZE = 8,\n\t\tCREATOR_ID_SIZE = 8,\n\t\tTYPE_SIZE = 8,\n\t\tID_SIZE = 40,\n\t\tUNKNOWN_TYPE = (1 << TYPE_SIZE)-1\n\t};\n\nprotected:\n\n\t// ---------------------------------------------------------------------------------\n\t// instantiated data\n\n\tunion\n\t{\n\t\tstruct\n\t\t{\n\t\t/// Id of the service where the entity is (variable routing info).\n\t\tuint64\tDynamicId   :  DYNAMIC_ID_SIZE;\n\t\t/// Id of the service who created the entity (persistent).\n\t\tuint64\tCreatorId   :  CREATOR_ID_SIZE;\n\t\t/// Type of the entity (persistent).\n\t\tuint64\tType :\t\t\tTYPE_SIZE;\n\t\t/// Local entity number (persistent).\n\t\tuint64\tId :\t\t\tID_SIZE;\n\t\t} DetailedId;\n\n\t\tuint64 FullId;\n\t};\n\n\t// ---------------------------------------------------------------------------------\n\t// static data\n\n\t/// Counter for generation of unique entity ids\n\tstatic NLMISC::CEntityId\t_NextEntityId;\n\n\t///The local num service id of the local machin.\n\tstatic uint8\t\t\t\t_ServerId;\n\npublic:\n\n\t// ---------------------------------------------------------------------------------\n\t// static data\n\n\t///The maximum number that we could generate without generate an overtaking exception.\n\tstatic const uint64\t\t\tMaxEntityId;\n\n\t/// Unknown CEntityId is similar as a NULL pointer.\n\tstatic const CEntityId\t\tUnknown;\n\n\n\t// ---------------------------------------------------------------------------------\n\t// generation of new unique entity ids\n\n\t/// Set the service id for the generator\n\tstatic void\t\t\t\t\tsetServiceId( uint8 sid )\n\t{\n\t\t_NextEntityId.setDynamicId( sid );\n\t\t_NextEntityId.setCreatorId( sid );\n\t\t_ServerId = sid;\n\t}\n\n\t/// Generator of entity ids\n\tstatic CEntityId\t\t\tgetNewEntityId( uint8 type )\n\t{\n\t\tnlassert(_NextEntityId != Unknown ); // type may be Unknown, so isUnknownId() would return true\n\t\tNLMISC::CEntityId id = _NextEntityId++;\n\t\tid.setType( type );\n\t\treturn id;\n\t}\n\n\t// ---------------------------------------------------------------------------------\n\t// constructors\n\n\t///\\name Constructor\n\t//@{\n\n\tCEntityId ()\n\t{\n\t\tFullId = 0;\n\t\tDetailedId.Type = UNKNOWN_TYPE;\n\n\t\t/*\n\t\tDynamicId = 0;\n\t\tCreatorId = 0;\n\t\tType = 127;\n\t\tId = 0;\n\t\t*/\n\t}\n\n\tCEntityId (uint8 type, uint64 id, uint8 creator, uint8 dynamic)\n\t{\n\t\tDetailedId.DynamicId = dynamic;\n\t\tDetailedId.CreatorId = creator;\n\t\tDetailedId.Type = type;\n\t\tDetailedId.Id = id;\n\t}\n\n\tCEntityId (uint8 type, uint64 id)\n\t{\n\t\tDetailedId.Type = type;\n\t\tDetailedId.Id = id;\n\t\tDetailedId.CreatorId = _ServerId;\n\t\tDetailedId.DynamicId = _ServerId;\n\t}\n\n\texplicit CEntityId (uint64 p)\n\t{\n\t\tFullId = p;\n\t\t/*\n\t\tDynamicId = (p & 0xff);\n\t\tp >>= 8;\n\t\tCreatorId = (p & 0xff);\n\t\tp >>= 8;\n\t\tType = (p & 0xff);\n\t\tp >>= 8;\n\t\tId = (p);\n\t\t*/\n\t}\n\n\tCEntityId (const CEntityId &a)\n\t{\n\t\tFullId = a.FullId;\n\t\t/*\n\t\tDynamicId = a.DynamicId;\n\t\tCreatorId = a.CreatorId;\n\t\tType = a.Type;\n\t\tId = a.Id;\n\t\t*/\n\t}\n\n\t///fill from read stream.\n\tCEntityId (NLMISC::IStream &is)\n\t{\n\t\tis.serial(FullId);\n\t\t/*\n\t\tuint64 p;\n\t\tis.serial(p);\n\n\t\tDynamicId = (p & 0xff);\n\t\tp >>= 8;\n\t\tCreatorId = (p & 0xff);\n\t\tp >>= 8;\n\t\tType = (p & 0xff);\n\t\tp >>= 8;\n\t\tId = p;\n\t\t*/\n\t}\n\n\texplicit CEntityId (const std::string &str)\n\t{\n\t\tfromString(str.c_str());\n\t}\n\n\texplicit CEntityId (const char *str)\n\t{\n\t\tCEntityId ();\n\t\tfromString(str);\n\t}\n\t//@}\n\n\n\t// ---------------------------------------------------------------------------------\n\t// accessors\n\n\t/// Get the full id\n\tuint64 getRawId() const\n\t{\n\t\treturn FullId;\n\t\t/*\n\t\treturn (uint64)*this;\n\t\t*/\n\t}\n\n\t/// Get the local entity number\n\tuint64 getShortId() const\n\t{\n\t\treturn DetailedId.Id;\n\t}\n\n\t/// Set the local entity number\n\tvoid setShortId( uint64 shortId )\n\t{\n\t\tDetailedId.Id = shortId;\n\t}\n\n\t/// Get the variable routing info\n\tuint8 getDynamicId() const\n\t{\n\t\treturn DetailedId.DynamicId;\n\t}\n\n\t/// Set the variable routing info\n\tvoid setDynamicId( uint8 dynId )\n\t{\n\t\tDetailedId.DynamicId = dynId;\n\t}\n\n\t/// Get the persistent creator id\n\tuint8 getCreatorId() const\n\t{\n\t\treturn DetailedId.CreatorId;\n\t}\n\n\t/// Set the persistent creator id\n\tvoid setCreatorId( uint8 creatorId )\n\t{\n\t\tDetailedId.CreatorId = creatorId;\n\t}\n\n\t/// Get the entity type\n\tuint8 getType() const\n\t{\n\t\treturn (uint8)DetailedId.Type;\n\t}\n\n\t/// Set the entity type\n\tvoid setType( uint8 type )\n\t{\n\t\tDetailedId.Type = type;\n\t}\n\n\t/// Get the persistent part of the entity id (the dynamic part in the returned id is 0)\n\tuint64 getUniqueId() const\n\t{\n\t\tCEntityId id;\n\t\tid.FullId = FullId;\n\t\tid.DetailedId.DynamicId = 0;\n\t\treturn id.FullId;\n\t}\n\n\t/// Test if the entity id is Unknown\n\tbool isUnknownId() const\n\t{\n\t\treturn DetailedId.Type == UNKNOWN_TYPE;\n\t}\n\n\n\t// ---------------------------------------------------------------------------------\n\t// operators\n\n\t///\\name comparison of two CEntityId.\n\t//@{\n\tbool operator == (const CEntityId &a) const\n//\tvirtual bool operator == (const CEntityId &a) const\n\t{\n\n\t\tCEntityId testId ( FullId ^ a.FullId );\n\t\ttestId.DetailedId.DynamicId = 0;\n\t\treturn testId.FullId == 0;\n\n\t\t/*\n\t\treturn (Id == a.DetailedId.Id && DetailedId.CreatorId == a.DetailedId.CreatorId && DetailedId.Type == a.DetailedId.Type);\n\t\t*/\n\t}\n\tbool operator != (const CEntityId &a) const\n\t{\n\t\treturn !((*this) == a);\n\t}\n\n\tbool operator < (const CEntityId &a) const\n//\tvirtual bool operator < (const CEntityId &a) const\n\t{\n\t\treturn getUniqueId() < a.getUniqueId();\n\n\t\t/*\n\t\tif (Type < a.Type)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse if (Type == a.Type)\n\t\t{\n\t\t\tif (Id < a.Id)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if (Id == a.Id)\n\t\t\t{\n\t\t\t\treturn (CreatorId < a.CreatorId);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t\t*/\n\t}\n\n\tbool operator > (const CEntityId &a) const\n//\tvirtual bool operator > (const CEntityId &a) const\n\t{\n\t\treturn getUniqueId() > a.getUniqueId();\n\n\t\t/*\n\t\tif (Type > a.Type)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse if (Type == a.Type)\n\t\t{\n\t\t\tif (Id > a.Id)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if (Id == a.Id)\n\t\t\t{\n\t\t\t\treturn (CreatorId > a.CreatorId);\n\t\t\t}\n\t\t}\n\t\t// lesser\n\t\treturn false;\n\t\t*/\n\t}\n\t//@}\n\n\tconst CEntityId &operator ++(int)\n\t{\n\t\tif(DetailedId.Id < MaxEntityId)\n\t\t{\n\t\t\tDetailedId.Id ++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror (\"CEntityId looped (max was %\" NL_I64 \"d\", MaxEntityId);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tconst CEntityId &operator = (const CEntityId &a)\n\t{\n\t\tFullId = a.FullId;\n\t\t/*\n\t\tDynamicId = a.DynamicId;\n\t\tCreatorId = a.CreatorId;\n\t\tType = a.Type;\n\t\tId = a.Id;\n\t\t*/\n\t\treturn *this;\n\t}\n\n\tconst CEntityId &operator = (uint64 p)\n\t{\n\t\tFullId = p;\n\t\t/*\n\t\tDynamicId = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tCreatorId = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tType = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tId = (uint64)(p);\n\t\t*/\n\t\treturn *this;\n\t}\n\n\n\t// ---------------------------------------------------------------------------------\n\t// other methods...\n\tuint64 asUint64()const\n\t{\n\t\treturn FullId;\n\t}\n\n/*\toperator uint64 () const\n\t{\n\t\treturn FullId;\n\n\t\tuint64 p = Id;\n\t\tp <<= 8;\n\t\tp |= (uint64)Type;\n\t\tp <<= 8;\n\t\tp |= (uint64)CreatorId;\n\t\tp <<= 8;\n\t\tp |= (uint64)DynamicId;\n\n\t\treturn p;\n\t}\n*/\n\n\t// ---------------------------------------------------------------------------------\n\t// loading, saving, serialising...\n\n\t/// Save the Id into an output stream.\n\tvoid save(NLMISC::IStream &os)\n//\tvirtual void save(NLMISC::IStream &os)\n\t{\n\t\tos.serial(FullId);\n\t\t/*\n\t\tuint64 p = Id;\n\t\tp <<= 8;\n\t\tp |= (uint64)Type;\n\t\tp <<= 8;\n\t\tp |= (uint64)CreatorId;\n\t\tp <<= 8;\n\t\tp |= (uint64)DynamicId;\n\t\tos.serial(p);\n\t\t*/\n\t}\n\n\t/// Load the number from an input stream.\n\tvoid load(NLMISC::IStream &is)\n//\tvirtual void load(NLMISC::IStream &is)\n\t{\n\t\tis.serial(FullId);\n\t\t/*\n\t\tuint64 p;\n\t\tis.serial(p);\n\n\t\tDynamicId = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tCreatorId = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tType = (uint64)(p & 0xff);\n\t\tp >>= 8;\n\t\tId = (uint64)(p);\n\t\t*/\n\t}\n\n\n\tvoid serial (NLMISC::IStream &f) throw (NLMISC::EStream)\n//\tvirtual void serial (NLMISC::IStream &f) throw (NLMISC::EStream)\n\t{\n\t\tif (f.isReading ())\n\t\t{\n\t\t\tload (f);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsave (f);\n\t\t}\n\t}\n\n\n\t// ---------------------------------------------------------------------------------\n\t// string convertions\n\n\t/// return a string in form \"(a:b:c:d)\" where a,b,c,d are components of entity id.\n\tstd::string toString() const\n\t{\n\t\tstd::string ident;\n\t\tident.reserve(25);\n\t\tident+='(';\n\t\tgetDebugString (ident);\n\t\tident+=')';\n\t\treturn ident;\n\t}\n\n\t/// Read from a debug string, use the same format as toString() (id:type:creator:dynamic) in hexadecimal\n\tvoid\tfromString(const char *str)\n//\tvirtual void\tfromString(const char *str)\n\t{\n\t\tuint64\t\tid;\n\t\tuint\t\ttype;\n\t\tuint\t\tcreatorId;\n\t\tuint\t\tdynamicId;\n\n\t\tif (sscanf(str, \"(%\" NL_I64 \"x:%x:%x:%x)\", &id, &type, &creatorId, &dynamicId) != 4)\n\t\t{\n\t\t\t*this = Unknown;\n\t\t\treturn;\n\t\t}\n\n\t\tDetailedId.Id = id;\n\t\tDetailedId.Type = type;\n\t\tDetailedId.CreatorId = creatorId;\n\t\tDetailedId.DynamicId = dynamicId;\n\t}\n\n\t/// Have a debug string.\n\tvoid getDebugString(std::string &str) const\n//\tvirtual void getDebugString(std::string &str) const\n\t{\n\t\tstr.reserve(str.size()+24);\n\t\tchar b[256];\n\t\tmemset(b,0,255);\n\t\tmemset(b,'0',19);\n\t\tsint n;\n\n\t\tuint64 x = DetailedId.Id;\n\t\tchar baseTable[] = \"0123456789abcdef\";\n\t\tfor(n = 10; n < 20; n ++)\n\t\t{\n\t\t\tb[19 - n] = baseTable[(x & 15)];\n\t\t\tx >>= 4;\n\t\t}\n\t\tb[19 - 9] = ':';\n\n\t\tx = DetailedId.Type;\n\t\tfor(n = 7; n < 9; n ++)\n\t\t{\n\t\t\tb[19 - n] = baseTable[(x & 15)];\n\t\t\tx >>= 4;\n\t\t}\n\t\tb[19 - 6] = ':';\n\n\t\tx = DetailedId.CreatorId;\n\t\tfor(n = 4; n < 6; n ++)\n\t\t{\n\t\t\tb[19 - n] = baseTable[(x & 15)];\n\t\t\tx >>= 4;\n\t\t}\n\t\tb[19 - 3] = ':';\n\n\t\tx = DetailedId.DynamicId;\n\t\tfor(n = 1; n < 3; n ++)\n\t\t{\n\t\t\tb[19 - n] = baseTable[(x & 15)];\n\t\t\tx >>= 4;\n\t\t}\n\t\tstr += \"0x\";\n\t\tstr += b;\n\t}\n/*\n\t/// \\name NLMISC::IStreamable method.\n\t//@{\n\tstd::string\tgetClassName ()\n//\tvirtual std::string\tgetClassName ()\n\t{\n\t\treturn std::string (\"<CEntityId>\");\n\t}\n\n\t//@}\n*/\n\n//\tfriend std::stringstream &operator << (std::stringstream &__os, const CEntityId &__t);\n};\n\n/**\n * a generic hasher for entities\n */\n/*class CEidHash\n{\npublic:\n\tsize_t\toperator () ( const NLMISC::CEntityId & id ) const\n\t{\n\t\tuint64 hash64 = id.getUniqueId();\n\t\treturn size_t(hash64) ^ size_t( hash64 >> 32 );\n\t\treturn (uint32)id.getShortId();\n\t}\n};*/\n\n// Traits for hash_map using CEntityId\nstruct CEntityIdHashMapTraits\n{\n\tenum { bucket_size = 4, min_buckets = 8, };\n\tCEntityIdHashMapTraits() { }\n\tsize_t operator() (const NLMISC::CEntityId &id ) const\n\t{\n\t\tuint64 hash64 = id.getUniqueId();\n\t\treturn size_t(hash64) ^ size_t( hash64 >> 32 );\n\t\t//return size_t(id.getShortId());\n\t}\n\tbool operator() (const NLMISC::CEntityId &id1, const NLMISC::CEntityId &id2) const\n\t{\n\t\treturn id1.getShortId() < id2.getShortId();\n\t}\n};\n\n\n/*inline std::stringstream &operator << (std::stringstream &__os, const CEntityId &__t)\n{\n\t__os << __t.toString ();\n\treturn __os;\n}*/\n\n} // NLMISC\n\n#endif // NL_ENTITY_ID_H\n\n/* End of entity_id.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/enum_bitset.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_ENUM_BIYSET_H\n#define NL_ENUM_BIYSET_H\n\n#include \"types_nl.h\"\n#include \"sstring.h\"\n\nnamespace NLMISC\n{\n\ttemplate <class EnumType, typename BitsetType>\n\tstruct TSimpleEnum\n\t{\n\t\tstatic BitsetType getValue (EnumType value)\n\t\t{\n\t\t\treturn BitsetType(value);\n\t\t}\n\t};\n\n\ttemplate <class EnumType, typename BitsetType>\n\tstruct TContainedEnum\n\t{\n\t\tstatic BitsetType getValue (EnumType value)\n\t\t{\n\t\t\treturn BitsetType(value.getValue());\n\t\t}\n\t};\n\n\n\t/** Utility to build 'ored' bit set from a 2 powered enum.\n\t *\tThe class give to user a conprehensive interface for\n\t *\tdealing with 'ored' enum value.\n\t *\n\t *\tThe class not strictly check that the enum only contains\n\t *\tpower of 2 values because the enum can eventualy\n\t *\tcontains pre 'ored' values.\n\t *\tFor each access, the size in bit of the enumerated value\n\t *\tpassed to the class is checked to not oversize the\n\t *\tBitsetType capacity.\n\t *\tBy default, the BitsetType is set to 32 bits, but you\n\t *\tcan provide your own type to narrow or expand the\n\t *\tcapacity.\n\t *\n\t *\tYou can add an additional checking by setting the maxValue to\n\t *\tthe max value of the enumerated type.\n\t *\n\t *\tFor from/to string convertion, you can also provide a delimiter\n\t *\tchar (that is comma by default).\n\t *\n\t *\n\t *\tusage:\n\t *\tenum foo\n\t *\t{\n\t *\t\tvalue1 = 1,\n\t *\t\tvalue2 = 2,\n\t *\t\tvalue3 = 4,\n\t *\t\tvalue4 = 8,\n\t *\t\tmaxFoo\n\t *\t};\n\t *\n\t *\t// Create the enum bit set, using enum foo, coded on an uint32 and limited\n\t *\t// to the value maxFoo in order to check for invalid values.\n\t *\tCEnumBitSet<foo, uint32, maxFoo>\tmyset;\n\t *\tmyset.setEnumValue(value1);\n\t *\tmyset.setEnumValue(value4);\n\t *\tmyset.clearEnumValue(value4);\n\t *\n\t *\tmyset.checkEnumValue(value1);\t// return true\n\t *\tmyset.checkEnumValue(value2);\t// return false\n\t *\tmyset.checkEnumValue(value4);\t// return false\n\t */\n\ttemplate <class EnumType,\n\t\t\t\ttypename BitsetType = uint32,\n\t\t\t\tBitsetType maxValue = UINT_MAX,\n\t\t\t\tchar Delimiter=',',\n\t\t\t\tclass EnumAccessor = TSimpleEnum<EnumType, BitsetType>,\n\t\t\t\tclass SimpleEnumType = EnumType\n\t\t\t\t>\n\tstruct CEnumBitset\n\t{\n\t\t// Default constructor with no flag set\n\t\tCEnumBitset()\n\t\t\t: Bitset(0)\n\t\t{\n\t\t}\n\n\t\t// Constructor with one flag set\n\t\tCEnumBitset(EnumType value)\n\t\t\t: Bitset(0)\n\t\t{\n\t\t\tsetEnumValue(value);\n\t\t}\n\n\t\t// Constructor with a enumerated string\n\t\tCEnumBitset(const std::string &valueList)\n\t\t\t: Bitset(0)\n\t\t{\n\t\t\tfromString(valueList);\n\t\t}\n\n\t\t/// Add a bit\n\t\tvoid addEnumValue(EnumType value)\n\t\t{\n\t\t\tnlwarning(\"Deprecated, please use setEnumValue\");\n\t\t\tsetEnumValue(value);\n\t//\t\tnlassert(value < maxValue);\n\t//\t\tBitset |= value;\n\t\t}\n\n\t\t/// set a bit\n\t\tvoid setEnumValue(EnumType value)\n\t\t{\n\t\t\tnlassert(EnumAccessor::getValue(value) < maxValue);\n\t\t\tBitset |= EnumAccessor::getValue(value);\n\t\t}\n\n\t\t/// clear a bit\n\t\tvoid clearEnumValue(EnumType value)\n\t\t{\n\t\t\tnlassert(EnumAccessor::getValue(value) < maxValue);\n\t\t\tBitset &= ~(EnumAccessor::getValue(value));\n\t\t}\n\n\t\tbool checkEnumValue(EnumType value)\n\t\t{\n\t\t\treturn (Bitset & EnumAccessor::getValue(value)) == EnumAccessor::getValue(value);\n\t\t}\n\n\t\tstd::string toString() const\n\t\t{\n\t\t\tCSString result;\n\n\t\t\tstd::string delim;\n\t\t\tdelim += Delimiter;\n\n\t\t\t// count up to 64 bits\n\t\t\tBitsetType value=1;\n\t\t\tuint i=0;\n\t\t\tfor (; i<64; value <<= 1, ++i)\n\t\t\t{\n\t\t\t\tif (Bitset & value)\n\t\t\t\t{\n\t\t\t\t\tif (!result.empty())\n\t\t\t\t\t\tresult << delim;\n\t\t\t\t\t// this bit is set, add a string\n\t\t\t\t\tresult << EnumType::toString(SimpleEnumType(value));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tbool fromString(const std::string &valueList)\n\t\t{\n\t\t\tstd::vector<std::string> values;\n\n\t\t\tstd::string delim;\n\t\t\tdelim += Delimiter;\n\n\t\t\tNLMISC::explode(valueList, delim, values, true);\n\n\t\t\tfor( uint i=0; i<values.size(); ++i)\n\t\t\t{\n\t\t\t\tsetEnumValue(EnumType(values[i]));\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tbool operator == (const CEnumBitset &other) const\n\t\t{\n\t\t\treturn Bitset == other.Bitset;\n\t\t}\n\n\t\tbool operator != (const CEnumBitset &other) const\n\t\t{\n\t\t\treturn ! operator == (other);\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(Bitset);\n\t\t}\n\n\t\tBitsetType\t\tBitset;\n\t};\n\n} // namespace NLMISC\n\n\n#endif // NL_ENUM_BIYSET_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/eval_num_expr.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVAL_NUM_EXPR_H\n#define NL_EVAL_NUM_EXPR_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\n/**\n  * This class performs numerical expression parsing.\n  */\nclass CEvalNumExpr\n{\npublic:\n\tvirtual ~CEvalNumExpr() {}\n\t/// Eval return error.\n\tenum TReturnState\n\t{\n\t\tNoError,\t\t\t// No error\n\t\tUnknownValue,\t\t// Unknown value has been parsed\n\t\tValueError,\t\t\t// Error during user defined value evaluation\n\t\tUnknownFunction,\t// Unknown function has been parsed\n\t\tFunctionError,\t\t// Error during user defined function evaluation\n\t\tNumberSyntaxError,\t// Syntax error in a number expression\n\t\tUnknownOperator,\t// Unknown operator\n\t\tMustBeOpen,\t\t\t// Should be a open parenthesis\n\t\tMustBeClose,\t\t// Should be a close parenthesis\n\t\tMustBeComa,\t\t\t// Should be a coma character\n\t\tMustBeExpression,\t// Should be an expression\n\t\tNotUnaryOperator,\t// Should not be an unary operator\n\t\tMustBeEnd,\t\t\t// Should be the end\n\t\tMustBeDoubleQuote,\t// Should be a double quote\n\t\tDividByZero,\t\t// Divide by zero\n\t\tReturnValueCount\n\t};\n\n\t/**\n\t  * Evaluate a numerical expression.\n\t  *\n\t  * Doesn't allocate heap memory for common complexity expression.\n\t  *\n\t  * \\param expression is an expression string. See the expression grammar.\n\t  * \\param result is filled with the result if the function returns \"NoError\".\n\t  * \\param errorIndex is a pointer on an integer value filled with the index\n\t  * of the parsing error in the input string if function doesn't return \"NoError\".\n\t  * This value can be NULL.\n\t  * \\param userData is a user data used by user eval function\n\t  *\t\\return NoError if the expression has been parsed. Result is filled with the evaluated value.\n\t  *\n\t  * This expression must follow the following grammar with the following evaluation priority:\n\t  *\n\t  * expression:\t'-' expression\n\t  *\t\t\t\t| '!' expression\t\t// Returns true if a equal false, else false (logical not)\n\t  *\t\t\t\t| '~' expression\t\t// Returns ~ round(a) (bitwise not)\n\t  *\t\t\t\t| '(' expression ')'\n\t  *\t\t\t\t| expression operator expression\n\t  *\t\t\t\t| function1 '(' expression ')'\n\t  *\t\t\t\t| function2 '(' expression ',' expression ')'\n\t  *\t\t\t\t| number\n\t  *\t\t\t\t| constant\n\t  *\t\t\t\t| string\t// User defined value, evaluated by the evalValue() callback\n\t  *\n\t  * operator:\t'*'\t\t// Calculates (a * b)\n\t  *\t\t\t\t| '/'\t\t// Calculates (a / b)\n\t  *\t\t\t\t| '%'\t\t// Calculates the remainder of (a / b)\n\t  *\t\t\t\t| '+'\t\t// Calculates (a + b)\n\t  *\t\t\t\t| '-'\t\t// Calculates (a - b)\n\t  *\t\t\t\t| '<<'\t\t// Returns round(a) left 32 bits unsigned shift by round(b)\n\t  *\t\t\t\t| '>>'\t\t// Returns round(a) right 32 bits unsigned shift by round(b)\n\t  *\t\t\t\t| '<-'\t\t// Returns round(a) left 32 bits signed shift by round(b)\n\t  *\t\t\t\t| '->'\t\t// Returns round(a) right 32 bits signed shift by round(b)\n\t  *\t\t\t\t| '<'\t\t// Returns true if a is strictly smaller than b\n\t  *\t\t\t\t| '<='\t\t// Returns true if a is smaller or equal than b\n\t  *\t\t\t\t| '>'\t\t// Returns true if a is strictly bigger than b\n\t  *\t\t\t\t| '>='\t\t// Returns true if a is bigger or equal than b\n\t  *\t\t\t\t| '=='\t\t// Returns true if a equal b, else returns false (warning, performs a floating point comparison)\n\t  *\t\t\t\t| '!='\t\t// Returns false if a equal b, else returns true (warning, performs a floating point comparison)\n\t  *\t\t\t\t| '&'\t\t// Returns round(a) & round(b) over 32 bits\n\t  *\t\t\t\t| '|'\t\t// Returns round(a) | round(b) over 32 bits\n\t  *\t\t\t\t| '^'\t\t// Returns round(a) ^ round(b) over 32 bits\n\t  *\t\t\t\t| '&&'\t\t// Returns true if a equal true and b equal true else returns false\n\t  *\t\t\t\t| '||'\t\t// Returns true if a equal true or b equal true else returns false\n\t  *\t\t\t\t| '^^'\t\t// Returns true if a equal true and b equal false, or, a equal false and b equal 1.0, else returns false\n\t  *\n\t  * function1:\tabs\t\t\t// Calculates the absolute value\n\t  *\t\t\t\t| acos\t\t// Calculates the arccosine\n\t  *\t\t\t\t| asin\t\t// Calculates the arcsine\n\t  *\t\t\t\t| atan\t\t// Calculates the arctangent\n\t  *\t\t\t\t| ceil\t\t// Calculates the ceiling of a value ( ceil(-1.1) = -1, ceil(1.1) = 2 )\n\t  *\t\t\t\t| cos\t\t// Calculates the cosine\n\t  *\t\t\t\t| cosh\t\t// Calculates the hyperbolic cosine\n\t  *\t\t\t\t| exp\t\t// Calculates the exponential\n\t  *\t\t\t\t| exponent\t// Calculates the exponent of a floating point value\n\t  *\t\t\t\t| floor\t\t// Calculates the floor of a value ( floor(-1.1) = -2, floor(1.1) = 1 )\n\t  *\t\t\t\t| int\t\t// Calculates the C style integer value ( int(-1.6) = -1, int(1.6) = 1 )\n\t  *\t\t\t\t| log\t\t// Calculates logarithms\n\t  *\t\t\t\t| log10\t\t// Calculates base-10 logarithms\n\t  *\t\t\t\t| mantissa\t// Calculates the mantissa of a floating point value\n\t  *\t\t\t\t| round\t\t// Calculates the nearest integer value ( round(-1.6) = -2, round(1.1) = 1 )\n\t  *\t\t\t\t| sin\t\t// Calculate sines\n\t  *\t\t\t\t| sinh\t\t// Calculate hyperbolic sines\n\t  *\t\t\t\t| sq\t\t// Calculates the square\n\t  *\t\t\t\t| sqrt\t\t// Calculates the square root\n\t  *\t\t\t\t| tan\t\t// Calculates the tangent\n\t  *\t\t\t\t| tanh\t\t// Calculates the hyperbolic tangent\n\t  *\t\t\t\t| string\t// User defined one arg function, evaluated by the evalfunction() callback\n\t  *\n\t  * function2:\tmax\t\t\t// Returns the larger of two values\n\t  *\t\t\t\t| min\t\t// Returns the smaller of two values\n\t  *\t\t\t\t| atan2\t\t// Calculates the arctangent of arg0/arg1\n\t  *\t\t\t\t| pow\t\t// Calculates a raised at the power of b\n\t  *\t\t\t\t| rand\t\t// Calculates a pseudo random value (arg0 <= randomValue < arg1)\n\t  *\t\t\t\t| string\t// User defined two args function, evaluated by the evalfunction() callback\n\t  *\n\t  * number:\t\t[0-9]+\t\t\t\t\t\t\t\t// Unsigned decimal integer\n\t  *\t\t\t\t| \"0x\"[0-9a-fA-F]+\t\t\t\t\t// Unsigned hexadecimal integer\n\t  *\t\t\t\t| \"0\"[0-7]+\t\t\t\t\t\t\t// Unsigned octal integer\n\t  *\t\t\t\t| [0-9]*.[0-9]+\t\t\t\t\t\t// Unsigned floating point value\n\t  *\t\t\t\t| [0-9]*.[0-9]+[eE]-?[0-9]*.[0-9]+\t// Unsigned floating point value with signed exponent\n\t  *\n\t  * constant:\te\t\t\t// 2.7182818284590452353602874713527\n\t  *\t\t\t\t| pi\t\t// 3.1415926535897932384626433832795\n\t  *\n\t  * string:\t\t[^ 0-9\\t\\n/\\*-+=<>&|\\^!%~\\(\\)\\.,\\\"][^ \\t\\n/\\*-+=<>&|\\^!%~\\(\\)\\.,\\\"]*\t// Labels ($foo, #foo01, _001)\n\t  *\t\t\t\t| \\\"[]+\\\"\t\t// All kind of labels between double quotes \"123456\" \"foo.foo[12]\"\n\t  *\n\t  * Operator precedence:\n\t  *\n\t  *  0 - unary operator (-, ~, !)\n\t  *  1 - *, /, %\n\t  *\t 2 - +, -,\n\t  *  3 - <<, >>, <-, ->\n\t  *  4 - <, <=, >, >=\n\t  *\t 5 - ==, !=\n\t  *  6 - &\n\t  *\t 7 - |\n\t  *\t 8 - ^\n\t  *\t 9 - &&\n\t  *\t10 - ||\n\t  *\t11 - ^^\n\t  *\n\t  */\n\tTReturnState evalExpression (const char *expression, double &result, int *errorIndex, uint32 userData = 0);\n\n\t/// Get error string\n\tconst char* getErrorString (TReturnState state) const;\n\nprotected:\n\n\t/// Overridable functions\n\n\t/**\n\t  * Eval a user defined value. Default implementation returns UnknownValue.\n\t  * The user can parse the value and fill the result double and return NoError, UnknownValue or\n\t  * ValueError.\n\t  *\n\t  * \\param value is the value to parse.\n\t  * \\param result is the result to fill if the value has been successfully parsed.\n\t  * \\param userData is a user data used by user eval function.\n\t  * \\return UnknownValue if the value is not known, ValueError is the value evaluation failed or NoError\n\t  * if it has been parsed.\n\t  */\n\tvirtual TReturnState evalValue (const char *value, double &result, uint32 userData);\n\n\t/**\n\t  * Eval a user defined function. Default implementation returns UnknownFunction.\n\t  * The user can parse the function name and fill the result double and return NoError, UnknownFunction\n\t  * or FunctionError.\n\t  *\n\t  * To convert double argu in boolean argu, use (round (value) != 0.0) ? true : false\n\t  *\n\t  * \\param funcName is the name of the function to evaluate.\n\t  * \\param arg0 is the first parameter passed to the function.\n\t  * \\param arg1 is the second parameter passed to the function.\n\t  * \\param result is the result to fill if the value has been successfully parsed.\n\t  * \\return UnknownFunction if the function doesn't exist, FunctionError if the function evaluation\n\t  * failed, NoError if it has been parsed.\n\t  */\n\tvirtual TReturnState evalFunction (const char *funcName, double arg0, double &result);\n\tvirtual TReturnState evalFunction (const char *funcName, double arg0, double arg1, double &result);\n\nprivate:\n\n\t/// Implementation\n\n\t/// Expression tokens\n\tenum TToken\n\t{\n\t\tNumber,\t\t// This is a number\n\t\tFunction1,\t// This is a function with one argu\n\t\tFunction2,\t// This is a function with two argu\n\t\tString,\t\t// This is a user string\n\t\tOperator,\t// This is an operator\n\t\tOpen,\t\t// (\n\t\tClose,\t\t// )\n\t\tComa,\t\t// ,\n\t\tEnd,\t\t// End of string\n\t};\n\n\t// Operators\n\tenum TOperator\n\t{\n\t\tNot = 0,\t\t// !\n\t\tTilde,\t\t\t// ~\n\t\tMul,\t\t\t// *\n\t\tDiv,\t\t\t// /\n\t\tRemainder,\t\t// %\n\t\tPlus,\t\t\t// +\n\t\tMinus,\t\t\t// -\n\t\tULeftShift,\t\t// <<\n\t\tURightShift,\t// >>\n\t\tSLeftShift,\t\t// <-\n\t\tSRightShift,\t// ->\n\t\tInferior,\t\t// <\n\t\tInferiorEqual,\t// <=\n\t\tSuperior,\t\t// >\n\t\tSuperiorEqual,\t// >=\n\t\tEqual,\t\t\t// ==\n\t\tNotEqual,\t\t// !=\n\t\tAnd,\t\t\t// &\n\t\tOr,\t\t\t\t// |\n\t\tXor,\t\t\t// ^\n\t\tLogicalAnd,\t\t// &&\n\t\tLogicalOr,\t\t// ||\n\t\tLogicalXor,\t\t// ^^\n\t\tOperatorCount,\t//\n\t\tNotOperator, // This is not an operator\n\t\tExtOperator, // This is a 2 characters operator\n\t};\n\n\t// Functions\n\tenum TReservedWord\n\t{\n\t\tAbs = 0,\n\t\tAcos,\n\t\tAsin,\n\t\tAtan,\n\t\tAtan2,\n\t\tCeil,\n\t\tCos,\n\t\tCosh,\n\t\tExp,\n\t\tExponent,\n\t\tFloor,\n\t\tInt,\n\t\tLog,\n\t\tLog10,\n\t\tMantissa,\n\t\tMax,\n\t\tMin,\n\t\tPow,\n\t\tRand,\n\t\tRound,\n\t\tSin,\n\t\tSinh,\n\t\tSq,\n\t\tSqrt,\n\t\tTan,\n\t\tTanh,\n\t\tReservedWordCount,\n\t};\n\n\t// Some constant\n\tenum\n\t{\n\t\tInternalStringLen = 32,\n\t\tInternalOperator = 4,\n\t};\n\n\t/// Members\n\tTReturnState\t_State;\t\t// Current state\n\tconst char\t\t*_ExprPtr;\t// Current pointer on the expression\n\n\t/// Read a decimal double\n\tTReturnState readDecimal (double &value);\n\n\t/// Read an integer\n\tvoid readIntegerNumberDecimal (double &value);\n\n\t/// Internal functions\n\n\t/// Get the next token\n\tTReturnState\tgetNextToken (TToken &token);\n\n\t/// Evaluate an expression\n\tTReturnState\tevalExpression (double &result, TToken &nextToken, uint32 userData);\n\n\t/// Reserved word\n\tTReservedWord\t_ReservedWordFound;\n\n\t/// Current string\n\tchar\t\t\t_InternalString[InternalStringLen];\n\tstd::string\t\t_InternalStlString;\n\tconst char\t\t*_InternalStringPtr;\n\n\t/// Current value\n\tdouble\t\t\t_Value;\n\n\t/// Current operator\n\tTOperator\t\t_Op;\n\n\t/// Static values\n\n\t/// Char to operator array\n\tstatic const TToken\t\t_ReservedWordToken[ReservedWordCount];\n\tstatic const char\t\t*_ReservedWord[ReservedWordCount];\n\tstatic const TOperator\t_OperatorArray[128];\n\tstatic const bool\t\t_StringChar[128];\n\tstatic const char\t\t*_ErrorString[ReturnValueCount];\n\tstatic const int\t\t_OperatorPrecedence[];\n\npublic:\n\n\tbool internalCheck ();\n};\n\n}\n\n#endif // NL_EVAL_NUM_EXPR_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/event_emitter.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVENT_EMITTER_H\n#define NL_EVENT_EMITTER_H\n\n#include \"types_nl.h\"\n#include \"event_server.h\"\n#include \"smart_ptr.h\"\n\n\n\nnamespace NLMISC {\n\n/*===================================================================*/\n\nclass CEventServer;\n\n/**\n * CEventEmitter\n * Send events to the event server\n *\n */\n/* *** IMPORTANT ********************\n * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL\n * **********************************\n */\nclass IEventEmitter\t: public NLMISC::CRefCount\n{\npublic:\n\t/// dtor\n\tvirtual ~IEventEmitter() {}\n\t/**\n\t * sends all events to server\n\t * (should call CEventServer method postEvent() )\n\t * \\param server\n\t */\n\tvirtual void submitEvents(CEventServer & server, bool allWindows) = 0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_EVENT_EMITTER_H\n\n/* End of event_emitter.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/event_emitter_multi.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVENT_EMITTER_MULTI_H\n#define NL_EVENT_EMITTER_MULTI_H\n\n#include \"types_nl.h\"\n#include \"event_emitter.h\"\n#include <vector>\n\n\nnamespace NLMISC {\n\n\n/** The composite pattern applied to events emmitters.\n * This is useful when you don't have the opportunity to register more than\n * one event emitter to an event server.\n */\nclass CEventEmitterMulti : public IEventEmitter\n{\npublic:\n\t/// dtor\n\tvirtual ~CEventEmitterMulti();\n\t/// add an emitter\n\tvoid\taddEmitter(IEventEmitter *e, bool mustDelete);\n\t/// remove an emitter (and delete it if necessary)\n\tvoid\tremoveEmitter(IEventEmitter *e);\n\t/// test whether e is in the emitter list\n\tbool\tisEmitter(IEventEmitter *e) const;\n\t// Get the number of registered emitters\n\tuint\tgetNumEmitters() const { return (uint)_Emitters.size(); }\n\t// Get an emitter\n\tIEventEmitter *getEmitter(uint index);\n\tconst IEventEmitter *getEmitter(uint index) const;\n\t/// From IEventEmitter. This call submitEvents on all the emitters\n\tvirtual void submitEvents(CEventServer &server, bool allWindows);\n\n\tvirtual bool copyTextToClipboard(const ucstring &text);\n\tvirtual bool pasteTextFromClipboard(ucstring &text);\n\nprivate:\n\ttypedef std::vector<std::pair<IEventEmitter *, bool> > TEmitterCont;\n\tTEmitterCont\t_Emitters;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_EVENT_EMITTER_MULTI_H\n\n/* End of event_emitter_multi.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/event_listener.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVENT_LISTENER_H\n#define NL_EVENT_LISTENER_H\n\n#include \"types_nl.h\"\n#include \"events.h\"\n#include \"bit_set.h\"\n\n\nnamespace NLMISC {\n\nclass CEvent;\nclass CEventServer;\n\n/**\n * Interface for event listener. A listener provides a callback.\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2000\n */\nclass IEventListener\n{\npublic:\n\n\t/// Constructor\n\tIEventListener();\n\t/// Destructor\n\tvirtual ~IEventListener() {}\n\n\t/** Called by CServer::pumpEvent(). The default calls the () operator, unless a hook has been set.\n\t  * In this case processEvent is called on the hook instead (the hook can forward the call to that listener afterwards).\n\t  */\n\tvirtual void process(const CEvent& event)\n\t{\n\t\tif (_Hook)\n\t\t{\n\t\t\t_Hook->process(event);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t(*this)(event);\n\t\t}\n\t}\n\n\t/**\n\t  * Call back of the listener.\n\t  * \\param event is the event send to the listener\n\t  */\n\tvirtual void operator ()(const CEvent& event)=0;\n\n\t// Set a hook which can intercept msgs.\n    void\t\t\tsetHook(IEventListener *hook) { _Hook = hook; }\n\tIEventListener *getHook() const  { return _Hook; }\nprivate:\n\tIEventListener *_Hook;\n};\n\n\n/**\n * CEventListenerAsync\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2000\n */\nclass CEventListenerAsync: public IEventListener\n{\npublic:\n\n\t/// Constructor\n\tCEventListenerAsync();\n\tvirtual ~CEventListenerAsync() {}\n\n\t/**\n\t  * Register the listener to the server.\n\t  */\n\tvoid addToServer (CEventServer& server);\n\n\t/**\n\t  * Unregister the listener to the server.\n\t  */\n\tvoid removeFromServer (CEventServer& server);\n\n\t/**\n\t  * Get a key down instant state.\n\t  * \\param key is the key to check.\n\t  */\n\tbool isKeyDown(TKey key) const;\n\n\t/**\n\t  * Get if a the state of key has pushed since the last call of isKeyPushed with release=true.\n\t  * \\param key is the key to check.\n\t  * \\param release if true, the pushed state of the key is released (force to be false).\n\t  *\t\tIt will return to true next time only if key is released and then re-pushed.\n\t  * \\see reset()\n\t  */\n\tbool isKeyPushed (TKey key, bool release=true);\n\n\n\t/**\n\t  * Clear all the Down states to false. Useful sometimes when you don't bother what has been pushed before.\n\t  * e.g.: your app listen/test to the key 'A' and 'B' for a certain long period. Then, it test 'C' and 'D' later.\n\t  * If the user has pressed (by mistake) the key 'C' during the first period, this API has record it, and then, at the\n\t  * second period, isKeyDown(KeyC) will return true the first time the key is tested, unless if you do a\n\t  * reset() at the beggining of the second period.\n\t  * Clear all the pushed states to false too.\n\t  * \\see isKeyDown()\n\t  */\n\tvoid reset ();\n\n\nprotected:\n\t/*\n\t * Call back of the listener.\n\t * \\param event is the event send to the listener\n\t */\n\tvirtual void operator ()(const CEvent& event);\n\tCBitSet _KeyArray;\n\t// Must have 2 arrays because of key repetition...\n\tCBitSet _KeyDownArray, _KeyReleaseArray;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_EVENT_LISTENER_H\n\n/* End of event_listener.h */\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/event_server.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVENT_SERVER_H\n#define NL_EVENT_SERVER_H\n\n#include \"types_nl.h\"\n#include \"class_id.h\"\n#include <map>\n#include <list>\n\n\nnamespace NLMISC {\n\nclass IEventEmitter;\nclass IEventListener;\nclass CEvent;\n\n/*===================================================================*/\n\ntypedef std::multimap<CClassId, IEventListener*, CClassIdHashMapTraits> mapListener;\n\n\n/**\n * CEventServer\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2000\n */\nclass CEventServer\n{\n\tmapListener _Listeners;\n\tstd::list<IEventEmitter*> _Emitters;\n\tstd::list<CEvent*> _Events;\n\tbool\t\t_Pumping;\n\npublic:\n\tCEventServer();\n\tvirtual ~CEventServer();\n\n\t/**\n\t * add event to the list\n\t * \\param event\n\t */\n\tvoid postEvent(CEvent * event);\n\n\t/**\n\t * get call every callbacks associated with event id\n\t * \\param allWindows is true : pump the messages of all windows, not only the driver window.\n\t */\n\tvoid pump(bool allWindows = false);\n\n\t/**\n\t * Add a callback (associated with an id)\n\t * \\param id of the CEvent class to hook\n\t * \\param listener to use with this event\n\t */\n\tvoid addListener(CClassId id, IEventListener* listener );\n\n\t/**\n\t * Remove a callback\n\t * \\param id of event's callback\n\t * \\param listener to be removed\n\t */\n\tvoid removeListener(CClassId id, IEventListener* listener );\n\n\t/**\n\t * Add an Emitter to the server\n\t * \\param emitter\n\t */\n\tvoid addEmitter(IEventEmitter * emitter);\n\n\t/**\n\t * Remove an Emitter from the server\n\t * \\param emitter\n\t */\n\tvoid removeEmitter(IEventEmitter * emitter);\n\nprotected:\n\t/**\n\t * call every callbacks associated with event id\n\t * \\param event\n\t * \\return true if the pointer must be delete, false if it not. (post to another message queue...)\n\t */\n\tvirtual bool pumpEvent(CEvent* event);\n};\n\n\n/*===================================================================*/\n\n} // NLMISC\n\n\n#endif // NL_EVENT_SERVER_H\n\n/* End of event_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/events.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EVENTS_H\n#define NL_EVENTS_H\n\n#include \"types_nl.h\"\n#include \"class_id.h\"\n#include \"ucstring.h\"\n#include <map>\n#include <list>\n\nnamespace NLMISC {\n\n/*===================================================================*/\n\nclass IEventEmitter;\n\n/**\n * CEvent. System event.\n * \\date 2000\n */\nclass CEvent : public CClassId\n{\npublic:\n\t/// Emitter of the event. Can be NULL if the event is posted directly to the CEventServer.\n\tIEventEmitter* Emitter;\n\n\t// duplicate the object\n\tvirtual\tCEvent\t\t*clone() const =0;\n\n\tvirtual ~CEvent() {}\n\nprotected:\n\t/** Constructor.\n\t  * \\param emitter is the emitter of the event. Can be NULL if the event is posted directly to the CEventServer.\n\t  * \\param classId is the classId of the event. Should be unique for each event.\n\t  */\n\tCEvent (IEventEmitter* emitter, const CClassId& classId) : CClassId (classId)\n\t{\n\t\tEmitter=emitter;\n\t}\n};\n\n// Key events\nconst CClassId EventKeyDownId (0x3c2643da, 0x43f802a1);\nconst CClassId EventKeyUpId (0x1e62e85, 0x68a35d46);\nconst CClassId EventCharId (0x552255fe, 0x75a2373f);\nconst CClassId EventStringId (0x49b5af8f, 0x7f52cd26);\n\n// Window events\nconst CClassId EventActivateId (0x7da66b0a, 0x1ef74519);\nconst CClassId EventSetFocusId (0x17650fac, 0x19f85dde);\nconst CClassId EventDestroyWindowId (0x69be73fe, 0x4b07603b);\nconst CClassId EventCloseWindowId (0xb5cb1333, 0xd092e63a);\n\n// Mouse events\nconst CClassId EventMouseMoveId (0x3dd12fdb, 0x472f548b);\nconst CClassId EventMouseDownId (0x35b7878, 0x5d4a0f86);\nconst CClassId EventMouseUpId (0xcce1f7e, 0x7ed344d7);\nconst CClassId EventMouseDblClkId (0x55a94cb3, 0x3e641517);\nconst CClassId EventMouseWheelId (0x73ac4321, 0x4c273150);\n\n// Misc events\nconst CClassId EventDisplayChangeId(0x1751559, 0x25b52b3c);\n\n// Input Mehod Editor (IME) events\nconst CClassId EventIME (0x261f1ede, 0x1b0a6c3a);\n\n\nenum TKey\n{\n\tKeyNOKEY          =0x00,\n\tKey0              ='0',\n\tKey1              ='1',\n\tKey2              ='2',\n\tKey3              ='3',\n\tKey4              ='4',\n\tKey5              ='5',\n\tKey6              ='6',\n\tKey7              ='7',\n\tKey8              ='8',\n\tKey9              ='9',\n\tKeyA              ='A',\n\tKeyB              ='B',\n\tKeyC              ='C',\n\tKeyD              ='D',\n\tKeyE              ='E',\n\tKeyF              ='F',\n\tKeyG              ='G',\n\tKeyH              ='H',\n\tKeyI              ='I',\n\tKeyJ              ='J',\n\tKeyK              ='K',\n\tKeyL              ='L',\n\tKeyM              ='M',\n\tKeyN              ='N',\n\tKeyO              ='O',\n\tKeyP              ='P',\n\tKeyQ              ='Q',\n\tKeyR              ='R',\n\tKeyS              ='S',\n\tKeyT              ='T',\n\tKeyU              ='U',\n\tKeyV              ='V',\n\tKeyW              ='W',\n\tKeyX              ='X',\n\tKeyY              ='Y',\n\tKeyZ              ='Z',\n\tKeyLBUTTON        =0x01,\n\tKeyRBUTTON        =0x02,\n\tKeyCANCEL         =0x03,\n\tKeyMBUTTON        =0x04,\n\tKeyBACK           =0x08,\n\tKeyTAB            =0x09,\n\tKeyCLEAR          =0x0C,\n\tKeyRETURN         =0x0D,\n\tKeySHIFT          =0x10,\n\tKeyCONTROL        =0x11,\n\tKeyMENU           =0x12,\n\tKeyPAUSE          =0x13,\n\tKeyCAPITAL        =0x14,\n\tKeyKANA           =0x15,\n\tKeyHANGEUL        =0x15,\n\tKeyHANGUL         =0x15,\n\tKeyJUNJA          =0x17,\n\tKeyFINAL          =0x18,\n\tKeyHANJA          =0x19,\n\tKeyKANJI          =0x19,\n\tKeyESCAPE         =0x1B,\n\tKeyCONVERT        =0x1C,\n\tKeyNONCONVERT     =0x1D,\n\tKeyACCEPT         =0x1E,\n\tKeyMODECHANGE     =0x1F,\n\tKeySPACE          =0x20,\n\tKeyPRIOR          =0x21,\n\tKeyNEXT           =0x22,\n\tKeyEND            =0x23,\n\tKeyHOME           =0x24,\n\tKeyLEFT           =0x25,\n\tKeyUP             =0x26,\n\tKeyRIGHT          =0x27,\n\tKeyDOWN           =0x28,\n\tKeySELECT         =0x29,\n\tKeyPRINT          =0x2A,\n\tKeyEXECUTE        =0x2B,\n\tKeySNAPSHOT       =0x2C,\n\tKeyINSERT         =0x2D,\n\tKeyDELETE         =0x2E,\n\tKeyHELP           =0x2F,\n\tKeyLWIN           =0x5B,\n\tKeyRWIN           =0x5C,\n\tKeyAPPS           =0x5D,\n\tKeyNUMPAD0        =0x60,\n\tKeyNUMPAD1        =0x61,\n\tKeyNUMPAD2        =0x62,\n\tKeyNUMPAD3        =0x63,\n\tKeyNUMPAD4        =0x64,\n\tKeyNUMPAD5        =0x65,\n\tKeyNUMPAD6        =0x66,\n\tKeyNUMPAD7        =0x67,\n\tKeyNUMPAD8        =0x68,\n\tKeyNUMPAD9        =0x69,\n\tKeyMULTIPLY       =0x6A,\n\tKeyADD            =0x6B,\n\tKeySEPARATOR      =0x6C,\n\tKeySUBTRACT       =0x6D,\n\tKeyDECIMAL        =0x6E,\n\tKeyDIVIDE         =0x6F,\n\tKeyF1             =0x70,\n\tKeyF2             =0x71,\n\tKeyF3             =0x72,\n\tKeyF4             =0x73,\n\tKeyF5             =0x74,\n\tKeyF6             =0x75,\n\tKeyF7             =0x76,\n\tKeyF8             =0x77,\n\tKeyF9             =0x78,\n\tKeyF10            =0x79,\n\tKeyF11            =0x7A,\n\tKeyF12            =0x7B,\n\tKeyF13            =0x7C,\n\tKeyF14            =0x7D,\n\tKeyF15            =0x7E,\n\tKeyF16            =0x7F,\n\tKeyF17            =0x80,\n\tKeyF18            =0x81,\n\tKeyF19            =0x82,\n\tKeyF20            =0x83,\n\tKeyF21            =0x84,\n\tKeyF22            =0x85,\n\tKeyF23            =0x86,\n\tKeyF24            =0x87,\n\tKeyNUMLOCK        =0x90,\n\tKeySCROLL         =0x91,\n\tKeyLSHIFT         =0xA0,\n\tKeyRSHIFT         =0xA1,\n\tKeyLCONTROL       =0xA2,\n\tKeyRCONTROL       =0xA3,\n\tKeyLMENU          =0xA4,\n\tKeyRMENU          =0xA5,\n\tKeySEMICOLON      =0xBA,\n\tKeyEQUALS         =0xBB,\n\tKeyCOMMA          =0xBC,\n\tKeyDASH           =0xBD,\n\tKeyPERIOD         =0xBE,\n\tKeySLASH          =0xBF,\n\tKeyTILDE          =0xC0,\n\tKeyLBRACKET       =0xDB,\n\tKeyBACKSLASH      =0xDC,\n\tKeyRBRACKET       =0xDD,\n\tKeyAPOSTROPHE     =0xDE,\n\tKeyPARAGRAPH      =0xDF,\n\tKeyOEM_102        =0xE2,\n\tKeyPROCESSKEY     =0xE5,\n\tKeyATTN           =0xF6,\n\tKeyCRSEL          =0xF7,\n\tKeyEXSEL          =0xF8,\n\tKeyEREOF          =0xF9,\n\tKeyPLAY           =0xFA,\n\tKeyZOOM           =0xFB,\n\tKeyNONAME         =0xFC,\n\tKeyPA1            =0xFD,\n\tKeyOEM_CLEAR      =0xFE,\n\tKeyCount          =0xFF\n};\n\nenum TMouseButton\n{\n\tnoButton      =0x0,\n\tleftButton    =0x1,\n\tmiddleButton  =0x2,\n\trightButton   =0x4,\n\tctrlButton    =0x8,\n\tshiftButton   =0x10,\n\taltButton     =0x20\n};\n\nenum TKeyButton\n{\n\tnoKeyButton     =0x0,\n\tctrlKeyButton   =0x8,\n\tshiftKeyButton  =0x10,\n\taltKeyButton    =0x20\n};\n\n/**\n * CEventKey\n */\nclass CEventKey : public CEvent\n{\npublic:\n\tCEventKey (TKeyButton button, IEventEmitter* emitter, const CClassId& classId) : CEvent (emitter, classId)\n\t{\n\t\tButton=button;\n\t}\n\tTKeyButton Button;\n\npublic:\n\t// return a TKey for its associated String (eg KeyA for \"KeyA\")\n\tstatic\tTKey\t\t\t\tgetKeyFromString(const std::string &str);\n\t// return the string equivalent to the TKey (eg \"KeyA\" for KeyA)\n\tstatic\tconst std::string\t&getStringFromKey(TKey k);\n};\n\n/**\n * CEventKeyDown\n * Send when a key is push down. The key type is Key and FirstTime is true if the previous key state wasn't pushed.\n */\nclass CEventKeyDown : public CEventKey\n{\npublic:\n\tCEventKeyDown (TKey key, TKeyButton button, bool bFirstTime, IEventEmitter* emitter) : CEventKey (button, emitter, EventKeyDownId)\n\t{\n\t\tKey=key;\n\t\tFirstTime=bFirstTime;\n\t}\n\tTKey Key;\n\tbool FirstTime;\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventKeyDown(*this);}\n};\n\n/**\n * CEventKeyUp\n */\nclass CEventKeyUp : public CEventKey\n{\npublic:\n\tCEventKeyUp (TKey key, TKeyButton button, IEventEmitter* emitter) : CEventKey (button, emitter, EventKeyUpId)\n\t{\n\t\tKey=key;\n\t}\n\tTKey Key;\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventKeyUp(*this);}\n};\n\n/**\n * CEventChar\n */\nclass CEventChar : public CEventKey\n{\npublic:\n\tCEventChar (ucchar c, TKeyButton button, IEventEmitter* emitter) : CEventKey (button, emitter, EventCharId), _Raw(true)\n\t{\n\t\tChar=c;\n\t}\n\tucchar Char;\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventChar(*this);}\n\tvoid\t\t\t\t\tsetRaw( bool raw ) { _Raw = raw; }\n\tbool\t\t\t\t\tisRaw() const { return _Raw; }\n\nprivate:\n\tbool\t_Raw; // true if raw, false if composed by an IME\n\n};\n\n/**\n * CEventString\n */\nclass CEventString : public CEventKey\n{\npublic:\n\tCEventString (const ucstring &str, IEventEmitter* emitter) : CEventKey (noKeyButton, emitter, EventStringId)\n\t{\n\t\tString = str;\n\t}\n\tucstring String;\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventString(*this);}\n};\n\n/**\n * CEventMouse.\n * Base for mouse events.\n */\nclass CEventMouse : public CEvent\n{\npublic:\n\tfloat X,Y;\n\tTMouseButton Button;\n\n\tCEventMouse (float x, float y, TMouseButton button, IEventEmitter* emitter, const CClassId& classId) : CEvent (emitter, classId)\n\t{\n\t\tX = x;\n\t\tY = y;\n\t\tButton = button;\n\t}\n};\n\n\n/**\n * CEventMouseDown\n * Send when a single mouse button is pushed down. The Button value should have only ONE flag set between leftButton, rightButton and middleButton.\n * X and Y have the new mouse position in window coordinate system.\n */\nclass CEventMouseDown : public CEventMouse\n{\npublic:\n\tCEventMouseDown (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseDownId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventMouseDown(*this);}\n};\n\n\n/**\n * CEventMouseUp\n * Send when a single mouse button is pushed down. The Button value should have only ONE flag set between leftButton, rightButton and middleButton.\n * X and Y have the new mouse position in window coordinate system.\n */\nclass CEventMouseUp : public CEventMouse\n{\npublic:\n\tCEventMouseUp (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseUpId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventMouseUp(*this);}\n};\n\n\n/**\n * CEventMouseMove\n * Button have the state of the three mouse and SHIFT CTRL and ALT system keys. When the flag is set, the button is pushed.\n * X and Y have the new mouse position in window coordinate system.\n */\nclass CEventMouseMove : public CEventMouse\n{\npublic:\n\tCEventMouseMove (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseMoveId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventMouseMove(*this);}\n};\n\n\n/**\n * CEventMouseDblClk\n * Send when a single mouse button is double clicked. The Button value should have only ONE flag set between leftButton, rightButton and middleButton.\n * X and Y have the new mouse position in window coordinate system.\n */\nclass CEventMouseDblClk : public CEventMouse\n{\npublic:\n\tCEventMouseDblClk (float x, float y, TMouseButton button, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseDblClkId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventMouseDblClk(*this);}\n};\n\n\n/**\n * CEventMouseWheel\n * Send when the mouse wheel is actioned.\n * Button have the state of the three mouse and SHIFT CTRL and ALT system keys. When the flag is set, the button is pushed.\n * X and Y have the new mouse position in window coordinate system.\n * If Direction is true, the wheel was moved forward and if it is false, backward.\n */\nclass CEventMouseWheel : public CEventMouse\n{\npublic:\n\tbool\tDirection;\n\tCEventMouseWheel (float x, float y, TMouseButton button, bool direction, IEventEmitter* emitter) : CEventMouse (x, y, button, emitter, EventMouseWheelId)\n\t{\n\t\tDirection=direction;\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventMouseWheel(*this);}\n};\n\n\n/**\n * CEventActivate. Called when window is actived / disactived.\n */\nclass CEventActivate : public CEvent\n{\npublic:\n\t/**\n\t  * True if window is actived, false if it is disactived.\n\t  */\n\tbool Activate;\n\n\t/**\n\t  * Create an activate event. Notify the activation disactivation of a window.\n\t  * \\param activate is True if window is actived, false if it is disactived.\n\t  */\n\tCEventActivate (bool activate, IEventEmitter* emitter) : CEvent (emitter, EventActivateId)\n\t{\n\t\tActivate = activate;\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventActivate(*this);}\n};\n\n\n/**\n * CEventSetFocus. Called when window lost / get keyboard focus.\n */\nclass CEventSetFocus : public CEvent\n{\npublic:\n\t/**\n\t  * True if window get the focus, false if it lost it.\n\t  */\n\tbool Get;\n\n\t/**\n\t  * Create focus event. Notify get and lost of the keyboard focus of a window.\n\t  * \\param activate is True if window get the focus, false if it lost it.\n\t  */\n\tCEventSetFocus (bool get, IEventEmitter* emitter) : CEvent (emitter, EventSetFocusId)\n\t{\n\t\tGet = get;\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventSetFocus(*this);}\n};\n\n\n/**\n * CEventDestroyWindow\n */\nclass CEventDestroyWindow : public CEvent\n{\npublic:\n\tCEventDestroyWindow (IEventEmitter* emitter) : CEvent (emitter, EventDestroyWindowId)\n\t{\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventDestroyWindow(*this);}\n};\n\n/**\n * CEventCloseWindow\n */\nclass CEventCloseWindow : public CEvent\n{\npublic:\n\tCEventCloseWindow (IEventEmitter* emitter) : CEvent (emitter, EventCloseWindowId)\n\t{\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventCloseWindow(*this);}\n};\n\n/**\n * CEventIME\n */\nclass CEventIME : public CEvent\n{\npublic:\n\tCEventIME (uint32 msg, uint32 wParam, uint32 lParam, IEventEmitter* emitter) : CEvent (emitter, EventIME), EventMessage(msg), WParam(wParam), LParam(lParam)\n\t{}\n\n\tuint32\tEventMessage;\n\tuint32\tWParam, LParam;\n\n\tvirtual CEvent\t\t\t*clone() const {return new CEventIME(*this);}\n};\n\n/**\n * CEventDisplayChange : Called user has changed the desktop resolution\n */\nclass CEventDisplayChange : public CEvent\n{\npublic:\n\tuint Width;\n\tuint Height;\n\tuint BitDepth;\n\n\t/**\n\t  * Create focus event. Notify get and lost of the keyboard focus of a window.\n\t  * \\param activate is True if window get the focus, false if it lost it.\n\t  */\n\tCEventDisplayChange(uint width, uint height, uint bitDepth, IEventEmitter* emitter) : CEvent (emitter, EventDisplayChangeId)\n\t{\n\t\tWidth    = width;\n\t\tHeight   = height;\n\t\tBitDepth = bitDepth;\n\t}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CEventDisplayChange(*this);}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_EVENTS_H\n\n/* End of events.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/factory.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n\n\n\n\n#ifndef FACTORY_H\n#define FACTORY_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n#include <map>\n\nnamespace NLMISC\n{\n\n/** Interface class for object registered in the factory.\n *\tThis is for factory internal use, you should not need to use this class directly.\n */\ntemplate <class BaseClass>\nclass IFactoryRegister\n{\npublic:\n\tvirtual ~IFactoryRegister() {}\n\t/// This method is called to create an instance of the factored object.\n\tvirtual BaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam) = 0;\n};\n\n\n/** Factory implementation class.\n *\tthe class take 2 template argument :\n *\t\t* BaseClass : the common base class for all factored object of one factory.\n *\t\t* KeyType : the type of the key that identify the factorable object (string by default).\n *\n *\tThe factory conforms to singleton design pattern.\n *\n *\tBaseClass must provide a typedef for TCTorParam corresponding to the parameter\n *\trequired by the constructor of factored object.\n */\ntemplate <class BaseClass, class KeyType = std::string>\nclass CFactory\n{\n\ttypedef std::map<KeyType, IFactoryRegister<BaseClass>*> TRegisterCont;\n\npublic:\n\n\t/// Get the singleton instance reference.\n\tstatic CFactory &instance()\n\t{\n\t\t// Singleton instance pointer.\n\t\tstatic CFactory\t*instance = NULL;\n\t\tif (!instance)\n\t\t{\n\t\t\tinstance = new CFactory();\n\t\t}\n\t\treturn *instance;\n\t}\n\n\t/** Register a factorable object in the factory.\n\t *\tThe method receive the key for this factorable object and\n\t *\ta pointer on the interface of a factory register object.\n\t */\n\tvoid registerClass(const KeyType &key, IFactoryRegister<BaseClass> *factoryRegister)\n\t{\n\t\tnlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end());\n\t\t_FactoryRegisters.insert(std::make_pair(key, factoryRegister));\n\t}\n\n\t/** Create a new instance of a factorable object.\n\t *\t\\param key the identifier of the object to create.\n\t *\t\\param ctorParam the parameter for the constructor.\n\t *\t\\return\ta pointer on the newly created object.\n\t */\n\tBaseClass *createObject(const KeyType &key, const typename BaseClass::TCtorParam &ctorParam)\n\t{\n\t\ttypename TRegisterCont::iterator it (_FactoryRegisters.find(key));\n\t\tif (it == _FactoryRegisters.end())\n\t\t\treturn NULL;\n\t\telse\n\t\t\treturn it->second->createObject(ctorParam);\n\t}\n\n\t// Add some introspection\n\tvoid fillFactoryList(std::vector<KeyType> &classList)\n\t{\n\t\ttypename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tclassList.push_back(first->first);\n\t\t}\n\t}\nprotected:\n\t/// Singleton instance pointer.\n//\tstatic CFactory\t*_Instance;\n\n\t/// Container of all registered factorable object.\n\tTRegisterCont\t_FactoryRegisters;\n};\n\n/** This class is responsible for creating the factorable object and to register\n *\tthem in the factory instance.\n *\tYou must declare an instance of this class for each factorable object.\n **/\ntemplate <class FactoryClass, class BaseClass, class FactoredClass, class KeyType>\nclass CFactoryRegister : public IFactoryRegister<BaseClass>\n{\npublic:\n\t/** Constructor.\n\t *\tRegister the factorable object in the factory.\n\t *\t/param key The identifier for this factorable object.\n\t */\n\tCFactoryRegister(const KeyType &key)\n\t{\n\t\tFactoryClass::instance().registerClass(key, this);\n\t}\n\n\t/** Create an instance of the factorable class.\n\t *\tImplements IFactoryRegister::createObject\n\t */\n\tBaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam)\n\t{\n\t\treturn new FactoredClass(ctorParam);\n\t}\n};\n\n/** Macro to declare a factory.\n *\tPlace this macro in an appropriate cpp file to declare a factory implementation.\n *\tYou just need to specify the base class type and key type.\n */\n//#define NLMISC_IMPLEMENT_FACTORY(baseClass, keyType)\tNLMISC::CFactory<baseClass, keyType>\t*NLMISC::CFactory<baseClass, keyType>::_Instance = NULL\n\n/** Macro to declare a factorable object.\n *\tPlace this macro in a cpp file after your factorable class declaration.\n */\n#define NLMISC_REGISTER_OBJECT(baseClass, factoredClass, keyType, keyValue)\tNLMISC::CFactoryRegister<NLMISC::CFactory<baseClass, keyType>, baseClass, factoredClass, keyType>\tRegister##factoredClass(keyValue)\n\n#define NLMISC_GET_FACTORY(baseClass, keyType) NLMISC::CFactory<baseClass, keyType>::instance()\n\n\n/** Interface class for object registered in the indirect factory.\n *\tThis is for indirect factory internal use, you should not need to use this class directly.\n */\ntemplate <class BaseFactoryClass>\nclass IFactoryIndirectRegister\n{\npublic:\n\tvirtual ~IFactoryIndirectRegister() {}\n\t/** Return the factory implementation.*/\n\tvirtual BaseFactoryClass *getFactory() = 0;\n};\n\n\n\n/** Indirect factory implementation class.\n *\tthe class take 2 template argument :\n *\t\t* BaseFactoryClass : the common base class for all factory object of one indirect factory.\n *\t\t* KeyType : the type of the key that identify the factorable object (string by default).\n *\n *\tThe indirect factory conforms to singleton design pattern.\n *\n *\tIn indirect factory, the object returned by the factory are not instance of factored object\n *\tbut instance of 'sub' factory that do the real job.\n *\tThis can be useful in some case, like adapting existing code into a factory\n *\tor having a complex constructor (or more than one constructor).\n */\ntemplate <class BaseFactoryClass, class KeyType = std::string>\nclass CFactoryIndirect\n{\n\ttypedef std::map<KeyType, IFactoryIndirectRegister<BaseFactoryClass>*> TRegisterCont;\n\npublic:\n\t/// Get the singleton instance reference.\n\tstatic CFactoryIndirect &instance()\n\t{\n\t\tstatic CFactoryIndirect\t*instance = NULL;\n\t\tif (!instance)\n\t\t{\n\t\t\tinstance = new CFactoryIndirect();\n\t\t}\n\t\treturn *instance;\n\t}\n\n\tvoid registerClass(const KeyType &key, IFactoryIndirectRegister<BaseFactoryClass> *factoryRegister)\n\t{\n\t\tnlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end());\n\t\t_FactoryRegisters.insert(std::make_pair(key, factoryRegister));\n\t}\n\n\tBaseFactoryClass *getFactory(const KeyType &key)\n\t{\n\t\ttypename TRegisterCont::const_iterator it (_FactoryRegisters.find(key));\n\t\tif (it == _FactoryRegisters.end())\n\t\t\treturn NULL;\n\t\telse\n\t\t\treturn it->second->getFactory();\n\t}\n\t// Add some introspection\n\tvoid fillFactoryList(std::vector<KeyType> &classList)\n\t{\n\t\ttypename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tclassList.push_back(first->first);\n\t\t}\n\t}\nprotected:\n//\tstatic CFactoryIndirect\t*_Instance;\n\n\tTRegisterCont\t_FactoryRegisters;\n};\n\n\ntemplate <class IndirectFactoryClass, class BaseFactoryClass, class SpecializedFactoryClass, class KeyType>\nclass CFactoryIndirectRegister : public IFactoryIndirectRegister<BaseFactoryClass>\n{\n\tSpecializedFactoryClass\t_FactoryClass;\npublic:\n\tCFactoryIndirectRegister(const KeyType &key)\n\t{\n\t\tIndirectFactoryClass::instance().registerClass(key, this);\n\t}\n\n\tBaseFactoryClass *getFactory()\n\t{\n\t\treturn &_FactoryClass;\n\t}\n};\n\n//#define NLMISC_IMPLEMENT_FACTORY_INDIRECT(baseFactoryClass, keyType)\tNLMISC::CFactoryIndirect<baseFactoryClass, keyType>\t*NLMISC::CFactoryIndirect<baseFactoryClass, keyType>::_Instance = NULL\n\n#define NLMISC_GET_FACTORY_INDIRECT_REGISTRY(baseFactoryClass, keyType)\tNLMISC::CFactoryIndirect<baseFactoryClass, keyType>::getInstance()\n#define NLMISC_REGISTER_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType, keyValue)\tNLMISC::CFactoryIndirectRegister<NLMISC::CFactoryIndirect<baseFactoryClass, keyType>, baseFactoryClass, specializedFactoryClass, keyType>\tRegisterIndirect##specializedFactoryClass(keyValue)\n#define NLMISC_DECLARE_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType)\textern NLMISC::CFactoryIndirectRegister<NLMISC::CFactoryIndirect<baseFactoryClass, keyType>, baseFactoryClass, specializedFactoryClass, keyType>\tRegisterIndirect##specializedFactoryClass\n\n#define NLMISC_GET_FACTORY_INDIRECT(specializedFactoryClass) RegisterIndirect##specializedFactoryClass.getFactory()\n\n} // namespace NLMISC\n\n#endif // FACTORY_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/fast_floor.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FAST_FLOOR_H\n#define NL_FAST_FLOOR_H\n\n#include \"types_nl.h\"\n#include <cmath>\n#include <nel/misc/debug.h>\n\nnamespace NLMISC\n{\n\nconst uint\t\tOptFastFloorCWStackSize = 10;\nextern int      OptFastFloorCWStack[OptFastFloorCWStackSize];\nextern int      *OptFastFloorCWStackPtr;\nextern int      *OptFastFloorCWStackEnd;\n\n// fastFloor function.\n#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR)\n\n#include <cfloat>\n\n// The magic constant value. support both positive and negative numbers.\nextern double\tOptFastFloorMagicConst ;\n\ninline void OptFastFloorPushCW(int ctrl)\n{\n\tnlassert(OptFastFloorCWStackPtr < OptFastFloorCWStackEnd);\n\t*OptFastFloorCWStackPtr++ = _controlfp(0, 0);\n\t_controlfp( ctrl, _MCW_RC|_MCW_PC );\n}\n\ninline void OptFastFloorPopCW()\n{\n\tnlassert(OptFastFloorCWStackPtr >=  OptFastFloorCWStack);\n\t_controlfp(*(--OptFastFloorCWStackPtr), _MCW_RC|_MCW_PC);\n}\n\n\n// init float CW.\ninline void  OptFastFloorBegin()\n{\n\tOptFastFloorPushCW(_RC_DOWN|_PC_53);\n}\n\n// reset float CW.\ninline void  OptFastFloorEnd()\n{\n\tOptFastFloorPopCW();\n}\n\n// Force __stdcall to not pass parameters in registers.\ninline sint32 __stdcall OptFastFloor(float x)\n{\n\tstatic __int64\tres;\n\t__asm\n\t{\n\t\tfld\t\tx\n\t\tfadd\tqword ptr OptFastFloorMagicConst\n\t\tfstp\tqword ptr res\n\t}\n\n\treturn (sint32) (res&0xFFFFFFFF);\n}\n\n\n// Force __stdcall to not pass parameters in registers.\n// Only used by particles system\ninline float __stdcall OptFastFractionnalPart(float x)\n{\n\tstatic double res;\n\t__asm\n\t{\n\t\tfld\t\tx\n\t\tfld     st(0)\n\t\tfadd\tqword ptr OptFastFloorMagicConst\n\t\tfstp\tqword ptr res\n\t\tfisub   dword ptr res\n\t\tfstp    dword ptr res\n\t}\n\n\treturn * (float *) &res;\n}\n\n\n// The magic constant value, for 24 bits precision support positive numbers only\nextern float\tOptFastFloorMagicConst24 ;\n// init float CW. Init with float 24 bits precision, for faster float operation.\ninline void  OptFastFloorBegin24()\n{\n\tOptFastFloorPushCW(_RC_DOWN|_PC_24);\n}\n\n// reset float CW.\ninline void  OptFastFloorEnd24()\n{\n\tOptFastFloorPopCW();\n}\n\n// Force __stdcall to not pass parameters in registers.\n/// Same method as OptFastFloor, but result are always positive and should never be bigger than 2^23-1\n/// Only used for float to byte color attributes conversions\ninline uint32 __stdcall OptFastFloor24(float x)\n{\n\tstatic uint32\tres;\n\t__asm\n\t{\n\t\tfld\t\tx\n\t\tfadd\tdword ptr OptFastFloorMagicConst24\n\t\tfstp\tdword ptr res\n\t}\n\n\treturn res;\n}\n\n\n\n#else\n\n#ifdef __SSE__\n\n// SSE intrinsics header\n#include <xmmintrin.h>\n\ninline void OptFastFloorPushCW(int ctrl)\n{\n\tnlassert(OptFastFloorCWStackPtr < OptFastFloorCWStackEnd);\n\t*OptFastFloorCWStackPtr++ = _MM_GET_ROUNDING_MODE();\n\t_MM_SET_ROUNDING_MODE(ctrl);\n}\n\ninline void OptFastFloorPopCW()\n{\n\tnlassert(OptFastFloorCWStackPtr >=  OptFastFloorCWStack);\n\t_MM_SET_ROUNDING_MODE(*(--OptFastFloorCWStackPtr));\n}\n\n#endif\n\ninline void  OptFastFloorBegin()\n{\n#ifdef __SSE__\n\tOptFastFloorPushCW(_MM_ROUND_DOWN);\n#endif\n}\n\ninline void  OptFastFloorEnd()\n{\n#ifdef __SSE__\n\tOptFastFloorPopCW();\n#endif\n}\n\ninline sint  OptFastFloor(float x)\n{\n#ifdef __SSE__\n\treturn _mm_cvtss_si32(_mm_set_ss(x));\n#else\n\treturn (sint)floor(x);\n#endif\n}\n\ninline float  OptFastFractionnalPart(float x)\n{\n#ifdef __SSE__\n\tstatic __m128 a, b;\n\ta = _mm_set_ss(x);\n\tb = _mm_cvtsi32_ss(b, _mm_cvttss_si32(a));\n\treturn _mm_cvtss_f32(_mm_comilt_ss(a, b) ? _mm_sub_ss(b, a):_mm_sub_ss(a, b));\n#else\n\treturn x < 0.f ? (sint)x - x:x - (sint)x;\n#endif\n}\n\n\ninline void  OptFastFloorBegin24()\n{\n#ifdef __SSE__\n\tOptFastFloorPushCW(_MM_ROUND_DOWN);\n#endif\n}\n\ninline void  OptFastFloorEnd24()\n{\n#ifdef __SSE__\n\tOptFastFloorPopCW();\n#endif\n}\n\ninline uint32 OptFastFloor24(float x)\n{\n#ifdef __SSE__\n\treturn (uint32)_mm_cvtss_si32(_mm_set_ss(x));\n#else\n\treturn (uint32)floor(x);\n#endif\n}\n\n\n#endif\n\n\n\n} // NLMISC\n\n\n#endif // NL_FAST_FLOOR_H\n\n/* End of fast_floor.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/fast_id_map.h",
    "content": "/**\n * \\file fast_id_map.h\n * \\brief CFastIdMap\n * \\date 2012-04-10 19:28GMT\n * \\author Jan Boon (Kaetemi)\n * CFastIdMap\n */\n\n/* \n * Copyright (C) 2012  by authors\n * \n * This file is part of RYZOM CORE.\n * RYZOM CORE is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n * \n * RYZOM CORE is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Affero General Public License for more details.\n * \n * You should have received a copy of the GNU Affero General Public\n * License along with RYZOM CORE.  If not, see\n * <http://www.gnu.org/licenses/>.\n */\n\n#ifndef NLMISC_FAST_ID_MAP_H\n#define NLMISC_FAST_ID_MAP_H\n#include <nel/misc/types_nl.h>\n\n// STL includes\n\n// NeL includes\n#include <nel/misc/debug.h>\n\n// Project includes\n\nnamespace NLMISC {\n\n/**\n * \\brief CFastIdMap\n * \\date 2012-04-10 19:28GMT\n * \\author Jan Boon (Kaetemi)\n * This template allows for assigning unique uint32 identifiers to pointers.\n * Useful when externally only exposing an identifier, when pointers may have been deleted.\n * The identifier is made from two uint16's, one being the direct index in the identifier vector, \n * and the other being a verification value that is increased when the identifier index is re-used.\n * TId must be a typedef of uint32.\n * TValue should be a pointer.\n */\ntemplate<typename TId, class TValue>\nclass CFastIdMap\n{\nprotected:\n\tstruct CIdInfo\n\t{\n\t\tCIdInfo() { }\n\t\tCIdInfo(uint16 verification, uint16 next, TValue value) : \n\t\t\tVerification(verification), Next(next), Value(value) { }\n\t\tuint16 Verification;\n\t\tuint16 Next;\n\t\tTValue Value;\n\t};\n\t/// ID memory\n\tstd::vector<CIdInfo> m_Ids;\n\t/// Nb of assigned IDs\n\tuint m_Size;\n\t/// Assigned IDs\n\tuint16 m_Next;\n\npublic:\n\tCFastIdMap(TValue defaultValue) : m_Size(0), m_Next(0)\n\t{\n\t\t// Id 0 will contain the last available unused id, and be 0 if no more unused id's are available\n\t\t// defaultValue will be returned when the ID is not found\n\t\tm_Ids.push_back(CIdInfo(0, 0, defaultValue));\n\t}\n\n\tvirtual ~CFastIdMap() { }\n\n\tvoid clear()\n\t{\n\t\tm_Ids.resize(1);\n\t\tm_Ids[0].Next = 0;\n\t}\n\n\tTId insert(TValue value)\n\t{\n\t\t// get next unused index\n\t\tuint16 idx = m_Ids[0].Next;\n\t\tif (idx == 0)\n\t\t{\n\t\t\t// size of used elements must be equal to the vector size minus one, when everything is allocated\n\t\t\tnlassert((m_Ids.size() - 1) == m_Size);\n\t\t\t\n\t\t\tidx = (uint16)m_Ids.size();\n\t\t\tuint16 verification = rand();\n\t\t\tm_Ids.push_back(CIdInfo(verification, m_Next, value));\n\t\t\tm_Next = idx;\n\t\t\treturn (TId)(((uint32)verification) << 16) & idx;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_Ids[0].Next = m_Ids[idx].Next; // restore the last unused id\n\t\t\tm_Ids[idx].Value = value;\n\t\t\treturn (TId)(((uint32)m_Ids[idx].Verification) << 16) & idx;\n\t\t}\n\t}\n\n\tvoid erase(TId id)\n\t{\n\t\tuint32 idx = ((uint32)id) & 0xFFFF;\n\t\tuint16 verification = (uint16)(((uint32)id) >> 16);\n\t\tif (m_Ids[idx].Verification == verification)\n\t\t{\n\t\t\tm_Ids[idx].Value = m_Ids[0].Value; // clean value for safety\n\t\t\tm_Ids[idx].Verification = (uint16)(((uint32)m_Ids[idx].Verification + 1) & 0xFFFF); // change verification value, allow overflow :)\n\t\t\tm_Ids[idx].Next = m_Ids[0].Next; // store the last unused id\n\t\t\tm_Ids[0].Next = (uint16)idx; // set this as last unused id\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"Invalid ID\");\n\t\t}\n\t}\n\n\tTValue get(TId id)\n\t{\n\t\tuint32 idx = ((uint32)id) & 0xFFFF;\n\t\tuint16 verification = (uint16)(((uint32)id) >> 16);\n\t\tif (m_Ids[idx].Verification == verification)\n\t\t{\n\t\t\treturn m_Ids[idx].Value;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnldebug(\"Invalid ID\");\n\t\t\treturn m_Ids[0].Value;\n\t\t}\n\t}\n\n\tinline uint size() { return m_Size; }\n\n}; /* class CFastIdMap */\n\n} /* namespace NLMISC */\n\n#endif /* #ifndef NLMISC_FAST_ID_MAP_H */\n\n/* end of file */\n"
  },
  {
    "path": "code/nel/include/nel/misc/fast_mem.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FAST_MEM_H\n#define NL_FAST_MEM_H\n\n#include \"types_nl.h\"\n\n\nnamespace NLMISC\n{\n\n//typedef void  *memcpyptr(void *dts, const void *src, size_t nbytes);\n\n/**\n * Functions for Fast Memory manipulation with Pentium-class processors.\n * From http://www.sgi.com/developers/technology/irix/resources/asc_cpu.html\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2002\n */\nclass CFastMem\n{\npublic:\n\n\t/**\n\t *\tThis is a function pointer that points on the best memcpy function available depending of the OS and proc.\n\t *  In the best case, it will use memcpySSE(), and in worst case, it'll use the libc memcpy()\n\t *  Simply use it this way: CFastMem::memcpy(dst, src, size);\n\t */\n\tstatic void  *(*memcpy)(void *dts, const void *src, size_t nbytes);\n\n\t/**\n\t *\tFast precaching of memory in L1 cache using SSE or MMX where available\n\t *\t(NB: others methods don't do the test)\n\t *\tnbytes should not override 4K\n\t */\n\tstatic void\t\tprecache(const void *src, uint nbytes);\n\n\t/////////////////////////////////////////////\n\n\t/**\n\t *\tFast memcpy using SSE instructions: prefetchnta and movntq. Can be called only if SSE and MMX is supported\n\t *\tNB: Copy per block of 4K through L1 cache\n\t *\tResult is typically 420 Mo/s instead of 150 Mo/s.\n\t */\n\tstatic void\t\t*memcpySSE(void *dst, const void *src, size_t nbytes);\n\n\t/**\n\t *\tFast precaching of memory in L1 cache using MMX/SSE instructions: movq and prefetchnta\n\t *\tResult is typically 880 Mo/s (surely slower because of overhead).\n\t *\tnbytes should not override 4K\n\t */\n\tstatic void\t\tprecacheSSE(const void *src, uint nbytes);\n\n\t/**\n\t *\tFast precaching of memory in L1 cache using MMX instructions only: movq\n\t *\tResult is typically 720 Mo/s (surely slower because of overhead).\n\t *\tHence prefer precacheSSE() when available.\n\t *\tnbytes should not override 4K\n\t */\n\tstatic void\t\tprecacheMMX(const void *src, uint nbytes);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_FAST_MEM_H\n\n/* End of fast_mem.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FILE_H\n#define NL_FILE_H\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n\n\n\nnamespace NLMISC\n{\n\n// ======================================================================================================\n/**\n * File Exception.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nstruct EFile : public EStream\n{\n\tEFile () : EStream( \"Unknown file error\" ) {}\n\tEFile (const std::string& filename) : EStream( \"Unknown file error in '\"+filename+\"'\" ), Filename(filename) {}\n\tEFile (const std::string& filename, const std::string& text, bool ) : EStream( text ), Filename(filename) {}\n\n\tvirtual ~EFile() throw() {}\n\n\tstd::string Filename;\n};\n\nstruct EFileNotOpened : public EFile\n{\n\tEFileNotOpened( const std::string& filename ) : EFile( filename, \"File '\"+filename+\"' not opened\", true ) {}\n};\n\nstruct EReadError : public EFile\n{\n\tEReadError( const std::string& filename ) : EFile( filename, \"Read error in file '\" +filename+\"' (End of file?)\", true ) {}\n};\n\nstruct EWriteError : public EFile\n{\n\tEWriteError( const std::string& filename ) : EFile( filename, \"Write Error in file '\" +filename+\"'\", true ) {}\n};\n\nstruct EDiskFullError : public EWriteError\n{\n\tEDiskFullError( const std::string& filename ) : EWriteError(filename) {}\n};\n\nstruct ERenameError : public EFile\n{\n\tERenameError( const std::string& dest, const std::string& src ) : EFile( dest, \"Rename Error from the file '\" +src+\"' to the file '\" +dest+\"'\", true ) {}\n};\n\n\n// ======================================================================================================\n/**\n * Input File.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n * ***********************************************\n *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n *\tIt can be loaded/called through CAsyncFileManager for instance\n * ***********************************************\n */\nclass CIFile : public IStream\n{\npublic:\t\t// Basic Usage.\n\t/// Object. NB: destructor close() the stream.\n\tCIFile();\n\tCIFile(const std::string &path, bool text=false);\n\t~CIFile();\n\n\t/// Open a file for reading. false if failed. close() if a file was opened.\n\tbool\topen (const std::string &path, bool text=false);\n\n\t/// Set the cache file on open option (default behaviour is false (file is not cached at opening)\n\tvoid\tsetCacheFileOnOpen (bool newState);\n\n\t/** If the file is opened with a big file, CacheFileOnOpen is replaced with big file option. Except if\n\t *\tallowBNPCacheFileOnOpen(false) is called. true is default.\n\t */\n\tvoid\tallowBNPCacheFileOnOpen(bool newState);\n\n\t/// Set the async loading state (to go to sleep 5 ms after 100 Ko serialized)\n\tvoid\tsetAsyncLoading (bool newState);\n\npublic:\t\t// Advanced Usage.\n\t/// Explicit close.\n\tvoid\tclose();\n\t/// flush the file.\n\tvoid\tflush();\n\t/// Seek the file\n\tbool\tseek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream);\n\t/// Get the location of the file pointer\n\tsint32\tgetPos () const throw(EStream);\n\n\t// Imp the Name of the stream as the name of the file.\n\tvirtual std::string\t\tgetStreamName() const;\n\n\t// same function that in ifstream\n\t// return a string separated by \\n or eof, used to parsing text file\n\tvoid getline (char *buffer, uint32 bufferSize);\n\n\t// return the size of the file\n\tuint32 getFileSize () const { return _FileSize; }\n\n\t// return true if there's nothing more to read (same as ifstream)\n\tbool eof ();\n\n\tvirtual void\t\tserialBuffer(uint8 *buf, uint len)throw(EReadError);\n\n\t/// \\name Statistics\n\n\t/// Get the number of file open from the beginning of the application. Files can be in a big file.\n\tstatic uint32\tgetNumFileOpen() {return _FileOpened;}\n\n\t/// Get the number of read acces to a file.\n\tstatic uint32\tgetNumFileRead() {return _FileRead;}\n\n\t/// Get the number of byte read from the file system since the application start.\n\tstatic uint32\tgetReadFromFile() {return _ReadFromFile;}\n\n\t/// Get the number of byte being reading from the file system at the moment.\n\tstatic uint32\tgetReadingFromFile() {return _ReadingFromFile;}\n\n\t/// Get the last 40 files opened. The files can be in a big file.\n\tstatic void\t\tdump (std::vector<std::string> &result);\n\n\t/// clear the dump of the last 40 files opened\n\tstatic void\t\tclearDump ();\n\nprotected:\n\tvirtual void\t\tserialBit(bool &bit) throw(EReadError);\n\n\tvirtual uint\t\tgetDbgStreamSize() const;\n\n\nprivate:\n\tFILE\t\t*_F;\n\tstd::string _FileName;\n\n\t// Async\n\tstatic uint32 _NbBytesSerialized;\n\tstatic uint32 _NbBytesLoaded;\n\n\t// Stats\n\tstatic uint32 _FileOpened;\n\tstatic uint32 _FileRead;\n\tstatic uint32 _ReadFromFile;\n\tstatic uint32 _ReadingFromFile;\n\tstatic CSynchronized<std::deque<std::string> > _OpenedFiles;\n\n\tbool _IsAsyncLoading;\n\n\t// Cache\n\tbool\t\t\t_CacheFileOnOpen;\n\tbool\t\t\t_AllowBNPCacheFileOnOpen;\n\tuint8\t\t\t*_Cache;\n\tmutable sint32\t_ReadPos;\n\tuint32\t\t\t_FileSize;\n\n\t// Big file & xml pack\n\tbool\t_AlwaysOpened;\n\t/// Flag true if file is in a big file\n\tbool\t_IsInBigFile;\n\t/// Flag true if file is in an xml pack\n\tbool\t_IsInXMLPackFile;\n\t//// Offset in bnp or xml pack\n\tuint32\t_BigFileOffset;\n\n\t// Load async if needed in the cache.\n\tvoid\tloadIntoCache();\n};\n\n\n// ======================================================================================================\n/**\n * Output File.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass COFile : public IStream\n{\npublic:\t\t// Basic Usage.\n\t/// Object. NB: destructor close() the stream.\n\tCOFile();\n\tCOFile(const std::string &path, bool append=false, bool text=false, bool useTempFile=false);\n\t~COFile();\n\n\t/** Open a file for writing. false if failed. close() if a file was opened.\n\t*\tIf you open the file with the flag useTempFile, you MUST close explicitly the file\n\t*\twith close() if the writing as been successed.\n\t*/\n\tbool\topen(const std::string &path, bool append=false, bool text=false, bool useTempFile=false);\n\n\tbool\tisOpen\t()\tconst\n\t{\n\t\treturn\t_F!=NULL;\n\t}\n\npublic:\t\t// Advanced Usage.\n\t/// Explicit close.\n\tvoid\tclose();\n\t/// flush the file.\n\tvoid\tflush();\n\t/// Seek the file\n\tbool\tseek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream);\n\t/// Get the location of the file pointer\n\tsint32\tgetPos () const throw(EStream);\n\n\t// Imp the Name of the stream as the name of the file.\n\tvirtual std::string\t\tgetStreamName() const;\n\n\t// very useful to serialize string in text mode (without the size)\n\tvirtual void\t\tserialBuffer(uint8 *buf, uint len) throw(EWriteError);\n\nprotected:\n\t/// Internal close.\n\tvoid\tinternalClose(bool success);\n\tvirtual void\t\tserialBit(bool &bit) throw(EWriteError);\n\nprivate:\n\tFILE\t*_F;\n\tstd::string _FileName;\n\tstd::string _TempFileName;\n};\n\n\n}\n\n\n#endif // NL_FILE_H\n\n/* End of file.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/fixed_size_allocator.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_FIXED_SIZE_ALLOCATOR_H\n#define NL_FIXED_SIZE_ALLOCATOR_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\n/** An allocator that can allocate and deallocate blocks of fixed size in O(1)\n  * Blocks are managed by chunks. Any number of blocks can be allocated, but once\n  * a block is allocated, a whole chunk need to be.\n  * With 32 bits pointers, there may be a 4 - 12 bytes overhead per object\n  * NB: Unlike CBlockManager, when a chunk contains no allocated blocks, it will be freed.\n  *     If only one chunk remains, it isn't deleted, however.\n  *     Another motivation for that class is that it can be used for a memory arena style allocator, because\n  *     size isn't a fixed parameter of template. A fixed size allocator implemented as a template for type T can be layered on this implementation.\n  *\n  * NB : number of blocks per chunks must be at least 3\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  */\nclass CFixedSizeAllocator\n{\npublic:\n\tCFixedSizeAllocator(uint numBytesPerBlock, uint numBlockPerChunk);\n\t~CFixedSizeAllocator();\n\t/// alloc a block\n\tvoid *alloc();\n\t/// destroy and dealloc a block\n\tvoid free(void *block);\n\t//\n\tuint getNumBytesPerBlock() const { return _NumBytesPerBlock; }\n\tuint getNumBlockPerChunk() const { return _NumBlockPerChunk; }\n\t//\n\tuint getNumAllocatedBlocks() const { return _NumAlloc; }\nprivate:\n\tclass CChunk;\n\t\n\tclass NL_ALIGN(NL_DEFAULT_MEMORY_ALIGNMENT) CNode\n\t{\n\tpublic:\n\t\tCChunk *Chunk; // the Chunk this node belongs to.\n\t\t// NB: blocks starts here in memory when node is allocated\n\t\tCNode  *Next;  // points the next free block. Valid only if node is not allocated, otherwise, block datas overlap tht field.\n\t\tCNode  **Prev; // points the previous node 'Next' field. Valid only if node is not allocated, otherwise, block datas overlap that field.\n\t\t// Unlink this node from the chunk it is in\n\t\t// Then it is considered allocated\n\tpublic:\n\t\tvoid *unlink();\n\t\t// Link back this node to the chunk it belongs to.\n\t\t// Then, it is added as a free node in the chunk and in the allocator\n\t\t// If all node of a chunk are unused, and it is not the last chunk of the allocator, it\n\t\t// is removed.\n\t\tvoid link();\n\t};\n\tclass CChunk\n\t{\n\tpublic:\n\t\tuint\t\t\t\t\t\tNumFreeObjs;\n\t\tCFixedSizeAllocator\t\t\t*Allocator;\n\t\tuint8\t\t\t\t\t\t*Mem;\n\tpublic:\n\t\t// ctor\n\t\tCChunk();\n\t\t// dtor\n\t\t~CChunk();\n\t\t// init & allocate memory\n\t\tvoid init(CFixedSizeAllocator *fsa);\n\t\t// access to a node\n\t\tCNode &getNode(uint index);\n\t\t// get the block size in bytes (header included)\n\t\tuint  getBlockSizeWithOverhead() const;\n\t\t/// a chunk has been given back\n\t\tinline void add();\n\t\t/// a chunk has been taken\n\t\tinline void grab();\n\t};\n\tfriend class CChunk;\n\tfriend class CNode;\n\t//\n\tCNode\t*_FreeSpace;\n\tuint     _NumChunks; // The number of created chunks. Once one of them is created, we manage\n\t\t\t\t\t\t // to keep it alive in order to avoid chunk creation / destructions\n\t\t\t\t\t\t // if only a few blocks are used\n\tuint\t_NumBytesPerBlock;\n\tuint\t_NumBlockPerChunk;\n\t//\n\tuint\t_NumAlloc;\n};\n\n} // NLMISC\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/game_device.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_GAME_DEVICE_H\n#define NL_GAME_DEVICE_H\n\n#include \"types_nl.h\"\n#include \"input_device.h\"\n#include <string>\n#include <vector>\n\n\nnamespace NLMISC\n{\n\n/// Describe a game device\nstruct CGameDeviceDesc\n{\n\t// type of the device\n\tenum TDevType { GamePad, Joystick, DontKnow, DevTypeLast }\t\tDevType;\n\t// Friendly name for the instance. For example, \"Joystick 1.\"\n\tstd::string\tInstanceName;\n\t// Friendly name for the product\n\tstd::string\tProductName;\n\t// Tells whether this device is connected\n\tbool\t\tConnected;\n};\n\n// a list of game device description\ntypedef std::vector<CGameDeviceDesc> TDeviceDescVect;\n\n/// for devices comparison. The 'Connected' field is ignored.\ninline bool operator == (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs)\n{\n\treturn lhs.InstanceName == rhs.InstanceName && lhs.ProductName == rhs.ProductName;\n}\n//\ninline bool operator != (const CGameDeviceDesc &lhs, const CGameDeviceDesc &rhs)\n{\n\treturn !(lhs == rhs);\n}\n\n\n/**\n * This abstract a joystick or gamepad\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 2002\n */\nstruct IGameDevice : public IInputDevice\n{\n\tenum TAxis { XAxis = 0, YAxis, ZAxis, /* translation */\n\t\t\t\t RXAxis, RYAxis, RZAxis,   /* rotations */\n\t\t\t\t MaxNumAxis\n\t\t\t\t};\n\n\t/// Get a general description of this device\n\tvirtual const CGameDeviceDesc &getDescription()  const = 0;\n\n\t///\\name Controls presence\n\t//@{\n\t\t// returns the number of buttons available on this game device\n\t\tvirtual\tuint  getNumButtons()  const = 0;\n\t\t/** Check if the given axe is present on this game device\n\t\t  * NB : only absolute axis are managed\n\t\t  */\n\t\tvirtual bool\t\thasAxis(TAxis axis)  const = 0;\n\t\t// Check the number of sliders presents on this game device\n\t\tvirtual uint\t\tgetNumSliders()  const = 0;\n\t\t// Check the number of point of views controls present on this game device\n\t\tvirtual\tuint\t\tgetNumPOV()  const = 0;\n\t//@}\n\n\t///\\name Controls names. Must ensure that controls are present before calling these methods.\n\t//@{\n\t\tvirtual const char *getButtonName(uint index)  const = 0;\n\t\tvirtual const char *getAxisName(TAxis axis)  const = 0;\n\t\tvirtual const char *getSliderName(uint index)  const = 0;\n\t\tvirtual const char *getPOVName(uint index)  const = 0;\n\t//@}\n\n\t///\\name Controls state. Must ensure that controls are present before calling these methods.\n\t//@{\n\t\t// Return true if the given button is pushed.\n\t\tvirtual bool\t\tgetButtonState(uint index) const = 0;\n\t\t// Return a value in [-1, 1] for a translation axis, or an orientation.\n\t\tvirtual float\t\tgetAxisValue(TAxis axis) const = 0;\n\t\t// Return a value in [0, 1]\n\t\tvirtual float\t\tgetSliderPos(uint index) const = 0;\n\t\t// Return a CCW angle in degrees\n\t\tvirtual float\t\tgetPOVAngle(uint index) const = 0;\n\t//@}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_GAME_DEVICE_H\n\n/* End of GAME_device.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/game_device_events.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_GAME_DEVICE_EVENT_H\n#define NL_GAME_DEVICE_EVENT_H\n\n#include \"types_nl.h\"\n#include \"events.h\"\n#include \"game_device.h\"\n\n\n\n\nnamespace NLMISC\n{\n\nstruct IMouseDevice;\nstruct IGameDevice;\n\nconst CClassId  EventGDMouseMove(0x12142bc4, 0x43c73e74);\nconst CClassId  EventGDButtonDownId(0x57141957, 0x3efb143a);\nconst CClassId  EventGDButtonUpId(0x16105e06, 0x302536b2);\nconst CClassId  EventGDAxisMovedId(0x073306, 0x41173626);\nconst CClassId  EventGDSliderMovedId(0x68776586, 0x394a6916);\nconst CClassId  EventGDPOVChanged(0x362851b9, 0x395c4d61);\n\n\n//==========================================================================================\n/// A raw mouse move message, expressed in mickeys (relative values)\nclass  CGDMouseMove : public CEvent\n{\npublic:\n\tIMouseDevice *MD;\n\tsint X, Y;\npublic:\n\tCGDMouseMove(IEventEmitter *emitter, IMouseDevice *md, sint x, sint y) : CEvent(emitter, EventGDMouseMove), MD(md), X(x), Y(y)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDMouseMove(*this);}\n};\n\n\n//==========================================================================================\n/**\n * An event from a game device (joystick, joypad ...)\n */\nclass CGameDeviceEvent : public CEvent\n{\npublic:\n\t/// the game device this event come from\n\tIGameDevice *GameDevice;\npublic:\n\tCGameDeviceEvent(\n\t\t\t\t\t IGameDevice *gameDevice,\n\t\t\t\t\t IEventEmitter *emitter,\n\t\t\t\t\t const CClassId &classId\n\t\t\t\t\t)\n\t\t\t\t\t: CEvent(emitter, classId),\n\t\t\t\t\t  GameDevice(gameDevice)\n\t{}\n};\n\n\n//==========================================================================================\n/** A button state has changed\n  */\nclass CGDButton : public CGameDeviceEvent\n{\npublic:\n\t// index of the buttons that has been pushed\n\tuint ButtonIndex;\n\tbool Pushed;\npublic:\n\t///\n\tCGDButton(\n\t\t\t  uint buttonIndex,\n\t\t\t  bool pushed,\n\t\t\t  IGameDevice *gameDevice,\n\t\t\t  IEventEmitter *emitter,\n\t\t\t  const CClassId &classId\n\t\t\t )\n\t\t\t : CGameDeviceEvent(gameDevice, emitter, classId),\n\t\t\t   ButtonIndex(buttonIndex),\n\t\t\t   Pushed(pushed)\n\t{}\n};\n\n\n//==========================================================================================\n/** A button has been pushed\n  */\nclass CGDButtonDown : public CGDButton\n{\npublic:\n\t///\n\tCGDButtonDown(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter)\n\t\t\t\t : CGDButton(buttonIndex, true, gameDevice, emitter, EventGDButtonDownId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDButtonDown(*this);}\n};\n\n//==========================================================================================\n/** A button has been released\n  */\nclass CGDButtonUp : public CGDButton\n{\npublic:\n\t///\n\tCGDButtonUp(uint buttonIndex, IGameDevice *gameDevice, IEventEmitter *emitter)\n\t\t\t\t : CGDButton(buttonIndex, false, gameDevice, emitter, EventGDButtonUpId)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDButtonUp(*this);}\n};\n\n//==========================================================================================\n/// An axis has moved\nclass CGDAxisMoved : public CGameDeviceEvent\n{\npublic:\n\tIGameDevice::TAxis\tAxis;\n\t// current position of the axis, ranges from -1.f to 1.f\n\tfloat\t\t\t\tValue;\npublic:\n\tCGDAxisMoved(\n\t\t\t\t  IGameDevice::TAxis axis,\n\t\t\t\t  float\tvalue,\n\t\t\t\t  IGameDevice *gameDevice,\n\t\t\t\t  IEventEmitter *emitter\n\t\t\t\t )\n\t\t\t\t : CGameDeviceEvent(gameDevice, emitter, EventGDAxisMovedId),\n\t\t\t\t   Axis(axis),\n\t\t\t\t   Value(value)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDAxisMoved(*this);}\n};\n\n\n//==========================================================================================\n/// A slider position has changed\nclass CGDSliderMoved : public CGameDeviceEvent\n{\npublic:\n\tuint SliderIndex;\n\t// current position of the slider, ranges from 0.f to 1.f\n\tfloat SliderPos;\npublic:\n\tCGDSliderMoved(\n\t\t\t\t  float\tsliderPos,\n\t\t\t\t  uint sliderIndex,\n\t\t\t\t  IGameDevice *gameDevice,\n\t\t\t\t  IEventEmitter *emitter\n\t\t\t\t )\n\t\t\t\t : CGameDeviceEvent(gameDevice, emitter, EventGDSliderMovedId),\n\t\t\t\t   SliderIndex(sliderIndex),\n\t\t\t\t   SliderPos(sliderPos)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDSliderMoved(*this);}\n};\n\n//==========================================================================================\n/// A point of view control changed\nclass CGDPOVChanged : public CGameDeviceEvent\n{\npublic:\n\tuint  POVIndex;\n\tbool  Centered;\n\t// The POV angle, in degrees (CW)\n\tfloat POVAngle;\npublic:\n\tCGDPOVChanged(\n\t\t\t\t  bool  centered,\n\t\t\t\t  float\tpovAngle,\n\t\t\t\t  uint\tpovIndex,\n\t\t\t\t  IGameDevice *gameDevice,\n\t\t\t\t  IEventEmitter *emitter\n\t\t\t\t )\n\t\t\t\t : CGameDeviceEvent(gameDevice, emitter, EventGDPOVChanged),\n\t\t\t\t   POVIndex(povIndex),\n\t\t\t\t   Centered(centered),\n\t\t\t\t   POVAngle(povAngle)\n\t{}\n\n\tvirtual\tCEvent\t\t\t*clone() const {return new CGDPOVChanged(*this);}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_GAME_DEVICE_EVENT_H\n\n/* End of game_device_event.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/geom_ext.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TRIANGLE_EXT_H\n#define NL_TRIANGLE_EXT_H\n\n#include \"types_nl.h\"\n#include \"line.h\"\n#include \"triangle.h\"\n#include \"quad.h\"\n#include \"uv.h\"\n#include \"rgba.h\"\n\n\nnamespace NLMISC\n{\n\n// ***************************************************************************\n// ***************************************************************************\n// Lines.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\n/**\n * A line with 2 colors.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CLineColor : public CLine\n{\npublic:\n\tCRGBA\tColor0, Color1;\n\npublic:\n\n\t/// Constructor\n\tCLineColor() {}\n\n\tCLineColor\t\t&operator=(const CLine &line)\n\t{\n\t\t*((CLine*)this)= line;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A line with 2 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CLineUV : public CLine\n{\npublic:\n\tCUV\t\tUv0, Uv1;\n\npublic:\n\n\t/// Constructor\n\tCLineUV() {}\n\n\tCLineUV\t\t&operator=(const CLine &line)\n\t{\n\t\t*((CLine*)this)= line;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A line with 2 colors and 2 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CLineColorUV : public CLine\n{\npublic:\n\tCRGBA\tColor0, Color1;\n\tCUV\t\tUv0, Uv1;\n\npublic:\n\n\t/// Constructor\n\tCLineColorUV() {}\n\n\tCLineColorUV\t\t&operator=(const CLine &line)\n\t{\n\t\t*((CLine*)this)= line;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n// ***************************************************************************\n// Triangles.\n// ***************************************************************************\n// ***************************************************************************\n\n\n\n// ***************************************************************************\n/**\n * A triangle with 3 colors.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CTriangleColor : public CTriangle\n{\npublic:\n\tCRGBA\tColor0, Color1, Color2;\n\npublic:\n\n\t/// Constructor\n\tCTriangleColor() {}\n\n\tCTriangleColor\t\t&operator=(const CTriangle &tri)\n\t{\n\t\t*((CTriangle*)this)= tri;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A triangle with 3 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CTriangleUV : public CTriangle\n{\npublic:\n\tCUV\t\tUv0, Uv1, Uv2;\n\npublic:\n\n\t/// Constructor\n\tCTriangleUV() {}\n\n\tCTriangleUV\t\t&operator=(const CTriangle &tri)\n\t{\n\t\t*((CTriangle*)this)= tri;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A triangle with 3 colors and 3 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CTriangleColorUV : public CTriangle\n{\npublic:\n\tCRGBA\tColor0, Color1, Color2;\n\tCUV\t\tUv0, Uv1, Uv2;\n\npublic:\n\n\t/// Constructor\n\tCTriangleColorUV() {}\n\n\tCTriangleColorUV\t\t&operator=(const CTriangle &tri)\n\t{\n\t\t*((CTriangle*)this)= tri;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n// ***************************************************************************\n// Quads.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\n/**\n * A quad with 4 colors.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CQuadColor : public CQuad\n{\npublic:\n\tCRGBA\tColor0, Color1, Color2, Color3;\n\npublic:\n\n\t/// Constructor\n\tCQuadColor() {}\n\n\tCQuadColor\t\t&operator=(const CQuad &quad)\n\t{\n\t\t*((CQuad*)this)= quad;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A quad with 4 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CQuadUV : public CQuad\n{\npublic:\n\tCUV\t\tUv0, Uv1, Uv2, Uv3;\n\npublic:\n\n\t/// Constructor\n\tCQuadUV() {}\n\n\tCQuadUV\t\t&operator=(const CQuad &quad)\n\t{\n\t\t*((CQuad*)this)= quad;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A quad with 4 colors and 4 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CQuadColorUV : public CQuad\n{\npublic:\n\tCRGBA\tColor0, Color1, Color2, Color3;\n\tCUV\t\tUv0, Uv1, Uv2, Uv3;\n\npublic:\n\n\t/// Constructor\n\tCQuadColorUV() {}\n\n\tCQuadColorUV\t\t&operator=(const CQuad &quad)\n\t{\n\t\t*((CQuad*)this)= quad;\n\t\treturn *this;\n\t}\n\n};\n\n\n// ***************************************************************************\n/**\n * A quad with 4 colors and 8 uvs.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CQuadColorUV2 : public CQuadColorUV\n{\npublic:\n\tCUV\t\tUv02, Uv12, Uv22, Uv32;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_TRIANGLE_EXT_H\n\n/* End of triangle_ext.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/grid_traversal.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef _GRID_TRAVERSAL_H\n#define _GRID_TRAVERSAL_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\nclass CVector2f;\n\n/** Utility class for incremental grid traversal\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2005\n  */\nclass CGridTraversal\n{\npublic:\n\t/** begin to traverse a grid along the given segments\n\t  * \\return first location in the grid\n\t  */\n\tstatic void startTraverse(const NLMISC::CVector2f &start, sint &nextX, sint &nextY);\n\t/** continue grid traversal from the given position\n\t  * If there are remaingind cells to traverse then true is returned, x & y are updated\n\t  */\n\tstatic bool traverse(const NLMISC::CVector2f &start, const NLMISC::CVector2f &dir, sint &x, sint &y);\n};\n\n\n} // NLMISC\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/gtk_displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_GTK_DISPLAYER_H\n#define NL_GTK_DISPLAYER_H\n\n#ifdef NL_USE_GTK\n\n#include \"types_nl.h\"\n\n#include \"displayer.h\"\n#include \"reader_writer.h\"\n\n#include \"window_displayer.h\"\n\n#include <gtk/gtk.h>\n\nnamespace NLMISC {\n\n\n/**\n * this displayer displays on a gtk windows.\n * MT = Main Thread, DT = Display Thread\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CGtkDisplayer : public NLMISC::CWindowDisplayer\n{\npublic:\n\n\tCGtkDisplayer (const char *displayerName = \"\");\n\n\tvirtual ~CGtkDisplayer ();\n\nprivate:\n\n\t// called by DT only\n\tvoid\tresizeLabels ();\n\t// called by DT only\n\tvoid\tupdateLabels ();\n\n\t// called by DT only\n\tvoid\topen (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log);\n\t// called by DT only\n\tvoid\tclear ();\n\t// called by DT only\n\tvoid\tdisplay_main ();\n\n\tvirtual void\tsetTitleBar (const std::string &titleBar);\n\n\tvirtual void\tgetWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h);\n\n\t// all these variables above are used only by the DT\n\n\tfriend gint updateInterf (gpointer data);\n\tfriend gint ButtonClicked(GtkWidget *Widget, gpointer *Data);\n\n\t// the MT must set the value to true to exit the thread\n\tbool Exit;\n};\n\n} // NLMISC\n\n#endif // NL_USE_GTK\n\n#endif // NL_GTK_DISPLAYER_H\n\n/* End of gtk_displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/heap_memory.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_HEAP_MEMORY_H\n#define NL_HEAP_MEMORY_H\n\n#include \"types_nl.h\"\n#include <map>\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * A Heap manager. Work with any kind of memory.\n *\tThis heap manager is not designed for speed (because it stills use standard heap allocation), but for\n *\tuse with special memory or special cases where malloc/new cannot be used.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CHeapMemory\n{\npublic:\n\n\t/// Constructor\n\tCHeapMemory();\n\t~CHeapMemory();\n\n\t/// reset the entire container. NB: no free() is made on the heap.\n\tvoid\t\t\treset();\n\t/** init the heap. this reset() the heap. heap ptr is stored in this class, but no CHeapMemory methods\n\t * write or read into. They use standard heap instead (new / delete).\n\t *\t\\param heap the heap ptr. heap should be at least N-bytes aligned, where N is the alignment you need (see\n\t *\tparam align, 4 by default).\n\t *\t\\param align Any size given to allocate() will be rounded to match this alignement.\n\t *\tValid values are 4,8,16, or 32. 4 by default.\n\t */\n\tvoid\t\t\tinitHeap(void *heap, uint size, uint align=4);\n\n\n\t/// return the size passed in setHeap().\n\tuint\t\t\tgetHeapSize() const {return _HeapSize;}\n\t/// return the heap size allocated.\n\tuint\t\t\tgetHeapSizeUsed() const {return _HeapSizeUsed;}\n\n\n\t/** allocate a block of size bytes. return NULL if not enough space or if size==0.\n\t *\tNB: for alignements consideration, allocation are aligned to 4 bytes.\n\t */\n\tvoid\t\t\t*allocate(uint size);\n\t/// free a block allocated with alloate(). no-op if NULL. nlstop() if don't find this block.\n\tvoid\t\t\tfree(void *ptr);\n\n\n// *********************\nprivate:\n\n\t// The map size -> EmptySpace.\n\ttypedef\tstd::multimap<uint, uint8*>\t\tTEmptySpaceSizeMap;\n\ttypedef\tTEmptySpaceSizeMap::iterator\tItEmptySpaceSizeMap;\n\n\n\tstruct\tCEmptySpace\n\t{\n\t\t// The adress of this empty space, in the heap\n\t\tuint8\t\t*Ptr;\n\t\t// The size of this empty space.\n\t\tuint\t\tSize;\n\t\t// An iterator of his place in the  TEmptySpaceMap.\n\t\tItEmptySpaceSizeMap\t\tSizeIt;\n\t};\n\n\n\t// The map ptr -> EmptySpace.\n\ttypedef\tstd::map<uint8*, CEmptySpace>\tTEmptySpacePtrMap;\n\ttypedef\tTEmptySpacePtrMap::iterator\t\tItEmptySpacePtrMap;\n\n\n\t// The map ptr -> size: AllocatedSpace;\n\ttypedef\tstd::map<uint8*, uint>\t\t\tTAllocatedSpaceMap;\n\ttypedef\tTAllocatedSpaceMap::iterator\tItAllocatedSpaceMap;\n\n\nprivate:\n\tuint8\t\t\t*_HeapPtr;\n\tuint\t\t\t_HeapSize;\n\tuint\t\t\t_HeapSizeUsed;\n\tuint\t\t\t_Alignment;\n\n\t/// The array of empty spaces.\n\tTEmptySpacePtrMap\t\t_EmptySpaces;\n\t/// for allocate method, the size -> empty space map.\n\tTEmptySpaceSizeMap\t\t_EmptySpaceMap;\n\t// The map of allocated blocks.\n\tTAllocatedSpaceMap\t\t_AllocatedSpaceMap;\n\n\n\tvoid\t\tremoveEmptySpace(CEmptySpace &space);\n\tvoid\t\taddEmptySpace(CEmptySpace &space);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_HEAP_MEMORY_H\n\n/* End of heap_memory.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/hierarchical_timer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_HIERARCHICAL_TIMER_H\n#define NL_HIERARCHICAL_TIMER_H\n\n#include <string>\n#include <vector>\n#include <algorithm>\n\n#include \"types_nl.h\"\n#include \"time_nl.h\"\n#include \"debug.h\"\n\n#ifndef NL_NO_DEBUG\n#\tdefine ALLOW_TIMING_MEASURES\n#endif // NL_NO_DEBUG\n\n\n#ifdef ALLOW_TIMING_MEASURES\n\n// You should need only this macro, bench the local scope\n#\tdefine H_AUTO(__name)\t\tstatic NLMISC::CHTimer\t__name##_timer(#__name); NLMISC::CAutoTimer\t__name##_auto(&__name##_timer);\n\n// Same as H_AUTO but you don't have to give a name, it uses the function/line\n#\tdefine H_AUTO2\t\t\t\tstatic std::string __str_##__LINE__(NLMISC::toString(\"%s:%d\", __FUNCTION__, __LINE__)); static NLMISC::CHTimer __timer_##__LINE__(__str_##__LINE__.c_str()); NLMISC::CAutoTimer __auto_##__LINE__(&__timer_##__LINE__);\n\n// If you want to bench a specific part of the code\n#\tdefine H_BEFORE(__name)\t\tstatic NLMISC::CHTimer\t__name##_timer(#__name); __name##_timer.before();\n#\tdefine H_AFTER(__name)\t\t__name##_timer.after();\n\n// Display the timer info after each loop call\n#\tdefine H_AUTO_INST(__name)\tstatic NLMISC::CHTimer\t__name##_timer(#__name); NLMISC::CAutoTimerInst\t__name##_auto(&__name##_timer);\n\n// H_AUTO split in 2. The declaration of the static timer, and a CAutoTimer instance.\n// Useful to group same timer bench in different functions for example\n#\tdefine H_AUTO_DECL(__name)\tstatic NLMISC::CHTimer\t__name##_timer(#__name);\n#\tdefine H_AUTO_USE(__name)\tNLMISC::CAutoTimer\t__name##_auto(&__name##_timer);\n\n//\n#\tdefine H_TIME(__name,__inst) \\\n\t{ \\\n\tstatic NLMISC::CHTimer\tnl_h_timer(#__name); \\\n\tnl_h_timer.before(); \\\n\t__inst \\\n\tnl_h_timer.after(); \\\n\t}\n\n#else\n// void macros\n#\tdefine H_TIME(__name,__inst) __inst\n#\tdefine H_BEFORE(__name)\n#\tdefine H_AFTER(__name)\n#\tdefine H_AUTO(__name)\n#\tdefine H_AUTO2\n#\tdefine H_AUTO_INST(__name)\n#\tdefine H_AUTO_DECL(__name)\n#\tdefine H_AUTO_USE(__name)\n#endif\n\nnamespace NLMISC\n{\n\n#ifdef NL_COMP_VC\n// Visual C++ warning : ebp maybe modified\n#\tpragma warning(disable:4731)\n#endif\n\n\n/**  A simple clock to measure ticks.\n  *  \\warning On Intel platform, processor cycles are counted, on other platforms, CTime::getPerformanceTime is used instead.\n  *\n  * \\sa CStopWatch\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2002\n  */\nclass CSimpleClock\n{\npublic:\n\tCSimpleClock() : _NumTicks(0)\n\t{\n#ifdef NL_DEBUG\n\t\t\t_Started = false;\n#endif\n\t}\n\t// start measure\n\tvoid start()\n\t{\n#ifdef NL_DEBUG\n\t\t\tnlassert(!_Started);\n\t\t\t_Started = true;\n#endif\n#ifdef NL_CPU_INTEL\n\t\t_StartTick = rdtsc();\n#else\n\t\t_StartTick = CTime::getPerformanceTime();\n#endif\n\t}\n\t// end measure\n\tvoid stop()\n\t{\n#ifdef  NL_DEBUG\n\t\t\tnlassert(_Started);\n\t\t\t_Started = false;\n#endif\n#ifdef NL_CPU_INTEL\n\t\t_NumTicks = rdtsc() - _StartTick;\n#else\n\t\t_NumTicks = CTime::getPerformanceTime() - _StartTick;\n#endif\n\t}\n\t// get measure\n\tuint64\tgetNumTicks() const\n\t{\n#ifdef NL_DEBUG\n\t\tnlassert(!_Started);\n#endif\n\t\tnlassert(_NumTicks != 0);\n\t\treturn _NumTicks;\n\t}\n\t// This compute the duration of start and stop (in cycles).\n\tstatic void init();\n\t/** Get the number of ticks needed to perform start().\n\t  * Should have called init() before calling this.\n\t  */\n\tstatic uint64 getStartStopNumTicks()\n\t{\n\t\treturn _StartStopNumTicks;\n\t}\nprivate:\n\tuint64  _StartTick;\n\tuint64\t_NumTicks;\n#ifdef  NL_DEBUG\n\tbool\t_Started;\n#endif\n\tstatic bool\t\t_InitDone;\n\tstatic uint64\t_StartStopNumTicks;\n};\n\n\n/**\n * Hierarchical timing system. Allows to accurately measure performance of routines, and displays results hierarchically.\n * To time a piece of code, just declare a static CHTimer object and encapsulate code between calls to before() and after() methods.\n * ex:\n *\\code\n void myFunction()\n {\n\tstatic CHTimer\tmyTimer(\"myFunction\");\n\tmyTimer.before();\n\t// some code here\n\tmyTimer.after();\n }\n *\\endcode\n * Don't forget to call after() to avoid timing wrongness or assertion crashes !\n *\n * \\warning Supports only single-threaded applications.\n * \\warning Supports only Intel processors.\n *\n * \\author Benjamin Legros\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 2001, 2002\n */\nclass CHTimer\n{\npublic:\n\t// this enum is used to sort displayed results\n\tenum TSortCriterion { NoSort,\n\t\t\t\t\t\t  TotalTime,\n\t\t\t\t\t\t  TotalTimeWithoutSons,\n\t\t\t\t\t\t  MeanTime,\n\t\t\t\t\t\t  NumVisits,\n\t\t\t\t\t\t  MaxTime,\n\t\t\t\t\t\t  MinTime,\n\t\t\t\t\t\t  MaxSession,\n\t\t\t\t\t\t  SortCriterionsLast\n\t\t\t\t\t\t};\npublic:\n\t/// ctor\n\tCHTimer() : _Name(NULL), _Parent(NULL), _IsRoot(false) {}\n\tCHTimer(const char *name, bool isRoot = false) : _Name(name), _Parent(NULL), _IsRoot(isRoot) {}\n\t/// Starts a measuring session\n\tvoid\t\t\tbefore()\n\t{\n\t\tif (_Benching)\n\t\t\tdoBefore();\n\t}\n\t// Ends a measuring session\n\tvoid\t\t\tafter()\n\t{\n\t\tif (_Benching)\n\t\t\tdoAfter(false);\n\t}\n\tvoid\t\t\tafter(bool displayAfter)\n\t{\n\t\tif (_Benching)\n\t\t\tdoAfter(displayAfter);\n\t}\n\t// Get this node name\n\tconst char\t\t*getName() const { return _Name; }\n\tvoid\t\t\tsetName(const char *name) { _Name = name; }\n\t/** Starts a bench session\n\t  * \\param wantStandardDeviation When true, benchmarks will report the standard deviation of values. This require more memory, however, because each samples must be kept.\n\t  * \\param quick if true, quick compute the frequency of the processor\n\t  */\n\tstatic void\t\tstartBench(bool wantStandardDeviation = false, bool quick = false, bool reset = true);\n\t/** For backward compatibility\n\t  */\n\tstatic void\t\tbench() { startBench(); }\n\t/** For backward compatibility\n\t  */\n\tstatic void\t\tadjust() {}\n\t/// Ends a bench session\n\tstatic void\t\tendBench();\n\n\tstatic bool\t\tbenching () { return _Benching; }\n\n\t/** Display results\n\t  * \\param displayEx true to display more detailed infos\n\t  */\n\tstatic void\t\tdisplay(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool displayEx = true);\n\t/** Display results by execution paths\n\t  * \\param displayInline true to display each result on a single line.\n\t  * \\param alignPaths    true to display all execution paths aligned.\n\t  * \\param displayEx\t true to display more detailed infos.\n\t  */\n\tstatic void\t\tdisplayByExecutionPath(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayInline = true, bool alignPaths = true, bool displayEx = true);\n\n\t/** Hierarchical display, no sorting is done\n\t  * \\param displayEx\t true to display more detailed infos.\n\t  * \\param labelNumChar\n\t  */\n\tstatic void\t\tdisplayHierarchical(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);\n\n\t/** Hierarchical display, no sorting is done\n\t  * \\param displayEx\t true to display more detailed infos.\n\t  * \\param labelNumChar\n\t  */\n\tstatic void\t\tdisplayHierarchicalByExecutionPath(CLog *log= InfoLog, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);\n\n\t/** Hierarchical display, sorting is done in branches\n\t  * \\param displayEx\t true to display more detailed infos.\n\t  * \\param labelNumChar\n\t  */\n\tstatic void\t\tdisplayHierarchicalByExecutionPathSorted(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2);\n\n\t/** Hierarchical display, sorting is done in branches\n\t  * \\param displayEx\t true to display more detailed infos.\n\t  * \\param labelNumChar\n\t  */\n\tstatic void\t\tdisplaySummary(CLog *log= InfoLog, TSortCriterion criterion = TotalTime, bool displayEx = true, uint labelNumChar = 32, uint indentationStep = 2, uint maxDepth = 3);\n\n\t/// Clears stats, and re initializes all timer structure\n\tstatic void\t\tclear();\n\n\t/// Clears SessionMax current stats (only current value)\n\tstatic void\t\tclearSessionCurrent();\n\n\t/// Clears all SessionMax stats (max and current values)\n\tstatic void\t\tclearSessionStats();\n\n\t/// Update session stats\n\tstatic void\t\tupdateSessionStats();\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\nprivate:\n\tstruct CNode;\n\ttypedef std::vector<CNode *>   TNodeVect;\n\ttypedef std::vector<CHTimer *> TTimerVect;\n\t//\n\t/// a node in an execution path\n\tstruct CNode\n\t{\n\t\ttypedef std::vector<double> TTimeVect;\n\t\t//\n\t\tCNode\t\t\t\t\t*Parent;\n\t\tTNodeVect\t\t\t\tSons;\n\t\tCHTimer\t\t\t\t\t*Owner;\t   // the hierarchical timer this node is associated with\n\t\tuint64\t\t\t\t\tTotalTime; // the total time spent in that node, including sons\n\t\tuint64\t\t\t\t\tLastSonsTotalTime;\n\t\tuint64\t\t\t\t\tSonsTotalTime; // maybe different from LastSonsTotalTime while benching the sons and if the display is called in a benched node\n\t\tTTimeVect\t\t\t\tMeasures;  // All time measures. Used only when standard deviation is wanted\n\t\tuint64\t\t\t\t\tMinTime;   // the minimum time spent in that node\n\t\tuint64\t\t\t\t\tMaxTime;   // the maximum time spent in that node\n\t\tuint64\t\t\t\t\tNumVisits; // the number of time the execution has gone through this node\n\t\t// session max measure\n\t\tuint64\t\t\t\t\tSessionCurrent;\n\t\tuint64\t\t\t\t\tSessionMax;\n\t\t//\n\t\tuint64\t\t\t\t\tSonsPreambule; // preamble time for the sons\n\t\tCSimpleClock\t\t\tClock;         // a clock to do the measures at this node\n\t\t// ctor\n\t  CNode(CHTimer\t*owner = NULL, CNode\t*parent = NULL) : Parent(parent), Owner(owner)\n\t\t{\n\t\t\treset();\n\t\t}\n\t\t// dtor\n\t\t~CNode();\n\t\t// Get the number of nodes in the tree starting at this node\n\t\tuint  getNumNodes() const;\n\t\t// release the sons, should not be benching when calling this\n\t\tvoid\treleaseSons();\n\t\t// reset this node measures\n\t\tvoid\treset()\n\t\t{\n\t\t\tSonsTotalTime\t\t = 0;\n\t\t\tTotalTime\t\t\t = 0;\n\t\t\tMaxTime\t\t\t\t = 0;\n\t\t\tMinTime\t\t\t\t = (uint64) -1;\n\t\t\tNumVisits\t\t\t = 0;\n\t\t\tSonsPreambule\t     = 0;\n\t\t\tLastSonsTotalTime    = 0;\n\t\t\tSessionCurrent       = 0;\n\t\t\tSessionMax           = 0;\n\t\t\tNLMISC::contReset(Measures);\n\t\t}\n\t\t//\n\t\t// Display this node path\n\t\tvoid\tdisplayPath(CLog *log) const;\n\t\t// Get this node path\n\t\tvoid    getPath(std::string &dest) const;\n\n\t\t// reset session current\n\t\tvoid\tresetSessionCurrent()\n\t\t{\n\t\t\tSessionCurrent = 0;\n\t\t\tfor (uint i=0; i<Sons.size(); ++i)\n\t\t\t\tSons[i]->resetSessionCurrent();\n\t\t}\n\t\t// reset all session stats\n\t\tvoid\tresetSessionStats()\n\t\t{\n\t\t\tSessionCurrent = 0;\n\t\t\tSessionMax = 0;\n\t\t\tfor (uint i=0; i<Sons.size(); ++i)\n\t\t\t\tSons[i]->resetSessionStats();\n\t\t}\n\t\t// spread session value through the while node tree\n\t\tvoid\tspreadSession()\n\t\t{\n\t\t\tSessionMax = SessionCurrent;\n\t\t\tfor (uint i=0; i<Sons.size(); ++i)\n\t\t\t\tSons[i]->spreadSession();\n\t\t}\n\t};\n\n\t/** Some statistics\n\t  * They can be build from a set of nodes\n\t  */\n\tstruct CStats\n\t{\n\t\tdouble  TimeStandardDeviation;\n\t\tdouble\tTotalTime;\n\t\tdouble\tTotalTimeWithoutSons;\n\t\tdouble\tMeanTime;\n\t\tuint64\tNumVisits;\n\t\tdouble\tMinTime;\n\t\tdouble\tMaxTime;\n\t\tdouble\tSessionMaxTime;\n\n\t\t// build stats from a single node\n\t\tvoid buildFromNode(CNode *node, double msPerTick);\n\n\t\t// build stats from a vector of nodes\n\t\tvoid buildFromNodes(CNode **firstNode, uint numNodes, double msPerTick);\n\n\t\t// display stats\n\t\tvoid display(CLog *log, bool displayEx = false, bool wantStandardDeviation = false);\n\n\t\t/** Get a string for stats (all stats on the same line)\n\t\t  * \\param statEx display extended stats\n\t\t  */\n\t\tvoid getStats(std::string &dest, bool statEx, double rootTotalTime, bool wantStandardDeviation = false);\n\t};\n\t// Stats and the associated timer\n\tstruct CTimerStat : public CStats\n\t{\n\t\tCHTimer *Timer;\n\t};\n\t// Stats and the associated node\n\tstruct CNodeStat : public CStats\n\t{\n\t\tCNode *Node;\n\t};\n\n\t/** A statistics sorter, based on some criterion.\n\t  * It works on pointers on CStats objects\n\t  */\n\tstruct CStatSorter\n\t{\n\t\tCStatSorter(TSortCriterion criterion = TotalTime) : Criterion(criterion)\n\t\t{}\n\t\tTSortCriterion Criterion;\n\t\t// Less operator\n\t\tbool operator()(const CStats *lhs, const CStats *rhs);\n\t};\n\n\n\t/** For Hierarchical + sorted display. displayHierarchicalByExecutionPath()\n\t *\n\t */\n\tstruct\tCExamStackEntry\n\t{\n\t\t// The node.\n\t\tCNode\t\t\t\t*Node;\n\t\t// The current child to process.\n\t\tuint\t\t\t\tCurrentChild;\n\t\t// The childes, sorted by specific criterion.\n\t\tstd::vector<CNode*>\tChildren;\n\t\t// The depth of the entry\n\t\tuint\t\t\t\tDepth;\n\n\t\texplicit\tCExamStackEntry(CNode *node)\n\t\t{\n\t\t\tNode= node;\n\t\t\tCurrentChild= 0;\n\t\t\tDepth = 0;\n\t\t}\n\n\t\texplicit\tCExamStackEntry(CNode *node, uint depth)\n\t\t{\n\t\t\tNode= node;\n\t\t\tCurrentChild= 0;\n\t\t\tDepth = depth;\n\t\t}\n\t};\n\n\t// Real Job.\n\tvoid\t\t\tdoBefore();\n\tvoid\t\t\tdoAfter(bool displayAfter = false);\n\n\tstatic void\t\testimateAfterStopTime();\n\nprivate:\n\t// walk the tree to current execution node, creating it if necessary\n\tvoid\t\t\twalkTreeToCurrent();\nprivate:\n\t// node name\n\tconst  char\t\t\t\t\t\t*_Name;\n\t// the parent timer\n\tCHTimer\t\t\t\t\t\t\t*_Parent;\n\t// the sons timers\n\tTTimerVect\t\t\t\t\t\t_Sons;\n\t// Tells if this is a root node\n\tbool\t\t\t\t\t\t\t_IsRoot;\nprivate:\n\t// root node of the hierarchy\n\tstatic CNode\t\t\t\t\t_RootNode;\n\t// the current node of the execution\n\tstatic CNode\t\t\t\t\t*_CurrNode;\n\t// the root timer\n\tstatic CHTimer\t\t\t\t\t _RootTimer;\n\t/** This clock is used to measure the preamble of methods such as CHTimer::before()\n\t  * This is static, but the Hierarchical Timer doesn't support multi threading anyway..\n      */\n\tstatic CSimpleClock\t\t\t\t_PreambuleClock;\n\t//\n\tstatic double\t\t\t\t\t_MsPerTick;\n\t//\n\tstatic bool\t\t\t\t\t\t_Benching;\n\t//\n\tstatic bool\t\t\t\t\t\t_BenchStartedOnce;\n\t//\n\tstatic bool\t\t\t\t\t\t_WantStandardDeviation;\n\t//\n\tstatic CHTimer\t\t\t\t   *_CurrTimer;\n\t//\n\tstatic sint64\t\t\t\t\t_AfterStopEstimateTime;\n\tstatic bool\t\t\t\t\t\t_AfterStopEstimateTimeDone;\n};\n\n/**\n * An automatic measuring timer. Encapsulates calls to CHTimer, and avoids missuses of before() and after().\n * ex:\n *\\code\n void myFunction()\n {\n\tstatic CHTimer\tmyTimer(\"myFunction\");\n\tCAutoTimer\t\tmyAuto(myTimer);\n\t// some code here\n }\n *\\endcode\n * Don't forget to call after() to avoid timing wrongness or assertion crashes !\n * \\author Benjamin Legros\n * \\author Nevrax France\n * \\date 2001\n */\nclass CAutoTimer\n{\nprivate:\n\tCHTimer *_HTimer;\npublic:\n\tCAutoTimer(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); }\n\t~CAutoTimer() { _HTimer->after(); }\n};\n\n\n/**\n *\tSame but display result at end.\n */\nclass CAutoTimerInst\n{\nprivate:\n\tCHTimer *_HTimer;\npublic:\n\tCAutoTimerInst(CHTimer *timer) : _HTimer(timer) { _HTimer->before(); }\n\t~CAutoTimerInst() { _HTimer->after(true); }\n};\n\n\n} // NLMISC\n\n#endif // NL_HIERARCHICAL_TIMER_H\n\n/* End of hierarchical_timer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/historic.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_HISTORIC_H\n#define NL_HISTORIC_H\n\n#include \"nel/misc/types_nl.h\"\n#include <deque>\n\nnamespace NLMISC\n{\n\n/** An historic with user defined size.\n  * An historic is just a fifo with constraint on size\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  */\ntemplate <class T>\nclass CHistoric\n{\npublic:\n\tCHistoric(uint maxSize = 0) : _MaxSize(maxSize) {}\n\t// Add a value at end of historic. If historic is full then the oldest entry is removed\n\tinline void\t\tpush(const T &value);\n\t// Pop the value at the end of jistoric\n\tinline void\t\tpop();\n\t// Return true is there are no values in the historics.\n\tbool\t\t\tempty() const { return _Historic.empty(); }\n\t// Get max number of entries in the historic.\n\tuint\t\t\tgetMaxSize() const { return _MaxSize; }\n\t// Set number of entries in the historic. Oldest entries are removed\n\tinline void\t\tsetMaxSize(uint maxSize);\n\t// Get current size of historic\n\tuint\t\t\tgetSize() const { return (uint)_Historic.size(); }\n\t// Access to an element in history, 0 being the oldest, size - 1 being the lastest added element\n\tconst T\t\t   &operator[](uint index) const { return _Historic[index]; /* let STL do out of range check */ }\n\t// Clear historic\n\tvoid\t\t\tclear() { _Historic.clear(); }\nprivate:\n\tstd::deque<T> _Historic;\n\tuint\t\t  _MaxSize;\n};\n\n\n////////////////////\n// IMPLEMENTATION //\n////////////////////\n\n// ****************************************************************************************************\ntemplate <class T>\ninline void\tCHistoric<T>::push(const T &value)\n{\n\tnlassert(_Historic.size() <= _MaxSize);\n\tif (_MaxSize == 0) return;\n\tif (getSize() == _MaxSize)\n\t{\n\t\t_Historic.pop_front();\n\t}\n\t_Historic.push_back(value);\n}\n\n// ****************************************************************************************************\ntemplate <class T>\ninline void\tCHistoric<T>::pop()\n{\n\tnlassert(!_Historic.empty());\n\t_Historic.pop_back();\n}\n\n// ****************************************************************************************************\ntemplate <class T>\ninline void\tCHistoric<T>::setMaxSize(uint maxSize)\n{\n\tif (maxSize < getSize())\n\t{\n\t\tuint toRemove = std::min(getSize() - maxSize, getSize());\n\t\t_Historic.erase(_Historic.begin(), _Historic.begin() + toRemove);\n\t}\n\t_MaxSize = maxSize;\n}\n\n}\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/i18n.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_I18N_H\n#define NL_I18N_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n#include \"file.h\"\n\n#include <string>\n#include <map>\n#include <algorithm>\n\n\nnamespace NLMISC {\n\n\n/**\n * Class for the internationalization. It's a singleton pattern.\n *\n * This class provide an easy way to localize all string.\n * First you load the language file with \\c load().\n * Now, you can get a localized string with its association with \\c get().\n *\n *\\code\n\t// load the language French\n\tCI18N::load (\"fr\");\n\t// display \"Salut\" that is the \"hi\" string in the selected language (French).\n\tnlinfo (CI18N::get(\"Hi\").c_str ());\n\t// display \"rms est un master\", the French version of the string\n\tnlinfo (\"rms\"+CI18N::get(\"Master\").c_str ());\n *\\endcode\n *\n *\tUpdate 26-02-2002 Boris Boucher\n *\n *\tLanguages are now preferably handled via official language code.\n *\tWe use the ISO 639-1 code for language.\n *\tOptionally, we can append a country code (ISO 3066) to differentiate\n *\tbetween language flavor (eg Chinese is ISO 639-1 zh, but come in\n *\ttraditional or simplified form. So we append the country code :\n *\tzh-CN (china) for simplified, zh for traditional).\n *\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\n\nclass CI18N\n{\npublic:\n\n\t/// Control over text loading\n\tenum TLineFormat\n\t{\n\t\t// the text file is just loaded, no conversion or checks done on line delimiters\n\t\tLINE_FMT_NO_CARE,\n\t\t// the line delimiters are forced to LF (\\n, code 0x0a)\n\t\tLINE_FMT_LF,\n\t\t// the line delimiters are forced to CRLF (\\r\\n , code 0x0d 0x0a)\n\t\tLINE_FMT_CRLF\n\t};\n\n\t/** Proxy interface for loading string file.\n\t *\tImplement this interface in client code and set it inside I18N\n\t *\tin order to be able to do any work on string file before they\n\t *\tare read by CI18N.\n\t *\tThis is used by Ryzom to merge the working string file with\n\t *\tthe exploitation one when they are more recent.\n\t */\n\tstruct ILoadProxy\n\t{\n\t\tvirtual ~ILoadProxy() {}\n\t\tvirtual void loadStringFile(const std::string &filename, ucstring &text) =0;\n\t};\n\n\t/// Set the load proxy class. Proxy can be NULL to unregister.\n\tstatic void setLoadProxy(ILoadProxy *loadProxy);\n\n\t// Get the current load proxy\n\tstatic ILoadProxy *getLoadProxy() { return _LoadProxy; }\n\n\t/// Return a vector with all language available. The vector contains the name of the language.\n\t/// The index in the vector is used in \\c load() function\n\tstatic const std::vector<ucstring> &getLanguageNames();\n\n\t/** Return a vector with all language code available.\n\t *\tCode are ISO 639-2 compliant.\n\t *\tAs in getLanguageNames(), the index in the vector can be used to call load()\n\t */\n\tstatic const std::vector<std::string> &getLanguageCodes();\n \n\t/// Load a language file depending of the language code(\"en\", \"fr\", ...). Code are ISO 639-2 compliant.\n\tstatic void load (const std::string &languageCode, const std::string &fallbackLanguageCode=\"\");\n\n\t/** Load a language file from its filename\n\t  * \\param filename name of the language file to load, with its extension\n\t  * \\param reload The file is being reloaded so error message won't be issued for strings that are overwritten\n\t  */\n\tstatic void loadFromFilename (const std::string &filename, bool reload);\n\n\t/// Returns the name of the language in the language name (English, Francais, ...)\n\tstatic ucstring getCurrentLanguageName ();\n\n\t/// Returns the code of the language (\"fr\", \"en\", ...)\n\tstatic std::string getCurrentLanguageCode ();\n\n\t/// Find a string in the selected language and return his association.\n\tstatic const ucstring &get (const std::string &label);\n\n\t// Test if a string has a translation in the selected language.\n\t// NB : The empty string is considered to have a translation\n\tstatic bool\t\t\t   hasTranslation(const std::string &label);\n\n\t/** Read the content of a file as a Unicode text.\n\t *\tThe method support 16 bits or 8bits utf-8 tagged files.\n\t *\t8 bits UTF-8 encoding can be recognized by a non official header :\n\t *\tEF,BB, BF.\n\t *\t16 bits encoding can be recognized by the official header :\n\t *\tFF, FE, witch can be reversed if the data are MSB first.\n\t *\n\t *\tOptionally, you can force the reader to consider the file as\n\t *\tUTF-8 encoded.\n\t *\tOptionally, you can ask the reader to interpret #include commands.\n\t */\n\tstatic void readTextFile(const std::string &filename,\n\t\t\t\t\t\t\t\tucstring &result, bool forceUtf8 = false,\n\t\t\t\t\t\t\t\tbool fileLookup = true,\n\t\t\t\t\t\t\t\tbool preprocess = false,\n\t\t\t\t\t\t\t\tTLineFormat lineFmt = LINE_FMT_NO_CARE,\n\t\t\t\t\t\t\t    bool warnIfIncludesNotFound = true);\n\n\t/** Read the content of a buffer as a Unicode text.\n\t *\tThis is to read preloaded Unicode files.\n\t *\tThe method support 16 bits or 8bits utf-8 tagged buffer.\n\t *\t8 bits UTF-8 encoding can be recognized by a non official header :\n\t *\tEF,BB, BF.\n\t *\t16 bits encoding can be recognized by the official header :\n\t *\tFF, FE, witch can be reversed if the data are MSB first.\n\t *\n\t *\tOptionally, you can force the reader to consider the file as\n\t *\tUTF-8 encoded.\n\t */\n\tstatic void readTextBuffer(uint8 *buffer, uint size, ucstring &result, bool forceUtf8 = false);\n\n\t/** Remove any C style comment from the passed string.\n\t */\n\tstatic void removeCComment(ucstring &commentedString);\n\n\t/** Encode a Unicode string into a string using UTF-8 encoding.\n\t*/\n\tstatic std::string encodeUTF8(const ucstring &str);\n\n\t/** Write a Unicode text file using Unicode 16 or UTF-8 encoding.\n\t */\n\tstatic void writeTextFile(const std::string filename, const ucstring &content, bool utf8 = true);\n\n\tstatic ucstring makeMarkedString(ucchar openMark, ucchar closeMark, const ucstring &text);\n\n\t//@{\n\t//\\name Parsing utility\n\t/** Skip the white space.\n\t *\tYou can optionally pass a ucstring pointer to receive any comments string that build the\n\t *\twhite space.\n\t *\tThis is useful if you want to keep the comments.\n\t *\tNB : comments are appended to the comments string.\n\t */\n\tstatic void\t\tskipWhiteSpace\t\t(ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring *storeComments = NULL, bool newLineAsWhiteSpace = true);\n\t/// Parse a label\n\tstatic bool\t\tparseLabel\t\t\t(ucstring::const_iterator &it, ucstring::const_iterator &last, std::string &label);\n\t/// Parse a marked string. NB : usually, we use [ and ] as string delimiters in translation files.\n\tstatic bool\t\tparseMarkedString\t(ucchar openMark, ucchar closeMark, ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring &result, uint32 *lineCounter = NULL, bool allowNewline = true);\n\t/** Try to read a given token at current position.\n\t *\tThe function will first skip any white space then try to read the token\n\t *\tIf found, the function return true and 'it' is advanced after the matched token,\n\t *\tOtherwise, the function return false and 'it' is unchanged.\n\t */\n\tstatic bool\t\tmatchToken(const char* token, ucstring::const_iterator &it, ucstring::const_iterator end);\n\t/// Advance iterator to the start of next line or to the end of string\n\tstatic void\t\tskipLine(ucstring::const_iterator &it, ucstring::const_iterator end, uint32 &lineCounter);\n\t//@}\n\n\t//@{\n\t//\\name Hash code tools.\n\t// Generate a hash value for a given string\n\tstatic uint64\tmakeHash(const ucstring &str);\n\t// convert a hash value to a readable string\n\tstatic std::string hashToString(uint64 hash);\n\t// convert a readable string into a hash value.\n\tstatic uint64 stringToHash(const std::string &str);\n\t// fast convert a hash value to a ucstring\n\tstatic void\thashToUCString(uint64 hash, ucstring &dst);\n\t//@}\n\n\tstatic void setNoResolution( bool b ){ noResolution = b; }\n\nprivate:\n\n\ttypedef std::map<std::string, ucstring>\t\t\t\t\t\tStrMapContainer;\n\n\tstatic ILoadProxy\t\t\t\t\t\t\t\t\t\t\t*_LoadProxy;\n\n\tstatic StrMapContainer\t\t\t\t\t\t\t\t\t\t_StrMap;\n\tstatic bool\t\t\t\t\t\t\t\t\t\t\t\t\t_StrMapLoaded;\n\n\t// the alternative language that will be used if the sentence is not found in the original language\n\tstatic StrMapContainer\t\t\t\t\t\t\t\t\t\t_StrMapFallback;\n\n\tstatic std::vector<std::string>\t\t\t\t\t\t\t\t_LanguageCodes;\n\tstatic std::vector<ucstring>\t\t\t\t\t\t\t\t_LanguageNames;\n\n\tstatic bool\t\t\t\t\t\t\t\t\t\t\t\t\t_LanguagesNamesLoaded;\n\n\tstatic std::string\t\t\t\t\t\t\t\t\t\t\t_SelectedLanguageCode;\n\tstatic const ucstring\t\t\t\t\t\t\t\t\t\t_NotTranslatedValue;\n\n\t/** Structure to hold contextual info during\n\t *\tread of preprocessed file\n\t */\n\tstruct TReadContext\n\t{\n\t\t/// The defined symbols\n\t\tstd::set<std::string>\t\tDefines;\n\n\t\t/// The if stack (push true until a bad test is found, push false for\n\t\t/// all subsequent if imbrication)\n\t\tstd::vector<bool>\t\t\tIfStack;\n\t};\n\nprivate:\n\n\t/// Init _LanguageCodes and _LanguageNames\n\tstatic void initLanguages();\n\n\tstatic bool loadFileIntoMap(const std::string &filename, StrMapContainer &dest);\n\n\t/// The internal read function, it does the real job of readTextFile\n\tstatic void _readTextFile(const std::string &filename,\n\t\t\t\t\t\t\t\tucstring &result, bool forceUtf8,\n\t\t\t\t\t\t\t\tbool fileLookup,\n\t\t\t\t\t\t\t\tbool preprocess,\n\t\t\t\t\t\t\t\tTLineFormat lineFmt,\n\t\t\t\t\t\t\t    bool warnIfIncludesNotFound,\n\t\t\t\t\t\t\t\tTReadContext &readContext);\n\n\t// Don't resolve labels\n\tstatic bool noResolution;\n};\n\n} // NLMISC\n\n\n#endif // NL_I18N_H\n\n/* End of i18n.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/i_xml.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_I_XML_H\n#define NL_I_XML_H\n\n//#define NL_DONT_USE_EXTERNAL_CODE\n#undef NL_DONT_USE_EXTERNAL_CODE\n\n#ifndef NL_DONT_USE_EXTERNAL_CODE\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n\n// Include from libxml2\n#include <libxml/parser.h>\n\nnamespace NLMISC {\n\n\nstruct EXmlParsingError : public EStream\n{\n\tEXmlParsingError ( const std::string& str ) : EStream( str ) {}\n};\n\n/**\n * Input xml stream\n *\n * This class is an xml formated input stream.\n *\n * This stream use an internal stream to input source xml code.\n * Use setStream to initialise it.\n \\code\n\t// Check exceptions\n\ttry\n\t{\n\t\t// File stream\n\t\tCIFile file;\n\n\t\t// open the file\n\t\tif (file.open (\"input.xml\"))\n\t\t{\n\t\t\t// XMl stream\n\t\t\tCIXml input;\n\n\t\t\t// Init, read all the input file...\n\t\t\tif (input.init (file))\n\t\t\t{\n\t\t\t\t// Serial the class\n\t\t\t\tmyClass.serial (input);\n\t\t\t}\n\n\t\t\t// Close the file\n\t\t\tfile.close ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// File not found\n\t\t}\n\t}\n\tcatch (const Exception &e)\n\t{\n\t\t// Something wrong appends\n\t}\n \\endcode\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CIXml : public IStream\n{\n\tfriend void xmlGenericErrorFuncRead (void *ctx, const char *msg, ...);\npublic:\n\n\t/** Default ctor\n\t  */\n\tCIXml ();\n\n\t// If tryBinaryMode is true, try to open the stream in both, XML and Binary if XML doesn't work.\n\t// In tryBinaryMode, the stream keep a pointer on the input stream passed to init();\n\tCIXml (bool tryBinaryMode);\n\n\t/** Dtor. Call release().\n\t  */\n\tvirtual ~CIXml ();\n\n\t/** Stream initialisation. The stream must be an input stream.\n\t  * init() will load the XML tree. So init() can raise read error exceptions.\n\t  *\n\t  * \\param stream is the stream the class will use to input xml code.\n\t  * this pointer is not held by the class. This stream must support end seek functions (as files).\n\t  * \\return true if init success, false if stream is not an input stream.\n\t  */\n\tbool\t\t\tinit (IStream &stream);\n\n\t/** Release the resources used by the stream.\n\t  */\n\tvoid\t\t\trelease ();\n\n\t/** Get the root node pointer\n\t  */\n\txmlNodePtr\t\tgetRootNode () const;\n\n\t/** Get the first child node pointer named childName. NULL if no node named childName.\n\t  */\n\tstatic xmlNodePtr getFirstChildNode (xmlNodePtr parent, const char *childName);\n\n\t/** Get the next child node pointer name childName, brother of previous. NULL if no node named childName.\n\t  */\n\tstatic xmlNodePtr getNextChildNode (xmlNodePtr last, const char *childName);\n\n\t/** Get the first child node pointer of type. NULL if no node of type.\n\t  */\n\tstatic xmlNodePtr getFirstChildNode (xmlNodePtr parent, xmlElementType type);\n\n\t/** Get the next child node pointer of type. NULL if no node of type.\n\t  */\n\tstatic xmlNodePtr getNextChildNode (xmlNodePtr last, xmlElementType type);\n\n\t/** Count number of sub node named with a given name for a given node.\n\t  */\n\tstatic uint\t\tcountChildren (xmlNodePtr node, const char *childName);\n\n\t/** Count number of sub node of type for a given node.\n\t  */\n\tstatic uint\t\tcountChildren (xmlNodePtr node, xmlElementType type);\n\n\t/**\n\t  * Read a property string\n\t  *\n\t  * Returns true and the result if the property has been found, else false.\n\t  */\n\tstatic bool\t\tgetPropertyString (std::string &result, xmlNodePtr node, const char *property);\n\n\t/**\n\t  *\tRead an integer property - if the property is not found the default value is returned\n\t  */\n\tstatic int\t\tgetIntProperty(xmlNodePtr node, const char *property, int defaultValue);\n\n\t/**\n\t  *\tRead a floating point property - if the property is not found the default value is returned\n\t  */\n\tstatic double\tgetFloatProperty(xmlNodePtr node, const char *property, float defaultValue);\n\n\t/**\n\t  *\tRead a string property - if the property is not found the default value is returned\n\t  */\n\tstatic std::string getStringProperty(xmlNodePtr node, const char *property, const std::string& defaultValue);\n\n\t/**\n\t  * Read the content of the node as a string\n\t  *\n\t  * Returns true and the result if some text has been found, else false.\n\t  */\n\tstatic bool\t\tgetContentString (std::string &result, xmlNodePtr node);\n\nprivate:\n\n\t/// From IStream\n\tvirtual void\tserial(uint8 &b);\n\tvirtual void\tserial(sint8 &b);\n\tvirtual void\tserial(uint16 &b);\n\tvirtual void\tserial(sint16 &b);\n\tvirtual void\tserial(uint32 &b);\n\tvirtual void\tserial(sint32 &b);\n\tvirtual void\tserial(uint64 &b);\n\tvirtual void\tserial(sint64 &b);\n\tvirtual void\tserial(float &b);\n\tvirtual void\tserial(double &b);\n\tvirtual void\tserial(bool &b);\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b);\n#endif\n\tvirtual void\tserial(std::string &b);\n\tvirtual void\tserial(ucstring &b);\n\tvirtual void\tserialBuffer(uint8 *buf, uint len);\n\tvirtual void\tserialBit(bool &bit);\n\n\tvirtual bool\txmlPushBeginInternal (const char *nodeName);\n\tvirtual bool\txmlPushEndInternal ();\n\tvirtual bool\txmlPopInternal ();\n\tvirtual bool\txmlSetAttribInternal (const char *attribName);\n\tvirtual bool\txmlBreakLineInternal ();\n\tvirtual bool\txmlCommentInternal (const char *comment);\n\n\t// Internal functions\n\tvoid\t\t\tserialSeparatedBufferIn ( std::string &value, bool checkSeparator = true );\n\tinline void\t\tflushContentString ();\n\n\t// Push has began\n\tbool\t\t\t_PushBegin;\n\n\t// Attribute present\n\tbool\t\t\t_AttribPresent;\n\n\t// Attribute name\n\tstd::string\t\t_AttribName;\n\n\t// Current libxml node\n\txmlNodePtr\t\t_CurrentNode;\n\n\t// Current libxml header node opened\n\txmlNodePtr\t\t_CurrentElement;\n\n\t// Parser pointer\n\txmlParserCtxtPtr\t_Parser;\n\n\t// Current node text\n\tstd::string\t\t_ContentString;\n\n\t// Current index in the node string\n\tuint\t\t\t_ContentStringIndex;\n\n\t// Error message\n\tstd::string\t\t_ErrorString;\n\n\t// Try binary mode\n\tbool\t\t\t_TryBinaryMode;\n\n\t// If not NULL, binary mode detected, use this stream in serials\n\tIStream\t\t\t*_BinaryStream;\n\n\t// System dependant structure for locale\n\tvoid*\t\t\t_Locale;\n};\n\n\n} // NLMISC\n\n#endif // NL_DONT_USE_EXTERNAL_CODE\n\n#endif // NL_I_XML_H\n\n/* End of o_xml.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/input_device.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_INPUT_DEVICE_H\n#define NL_INPUT_DEVICE_H\n\n#include \"types_nl.h\"\n\n\nnamespace NLMISC\n{\n\n\nclass  CEventServer;\nclass  CInputDeviceServer;\nstruct IInputDeviceEvent;\n\n\n/**\n * Base class that wrap to a device\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 2002\n */\n\nstruct IInputDevice\n{\n\t/** Set the buffer size for this device (the number of samples it can retains).\n\t  * This return true if the size could be set\n\t  */\n\tvirtual bool setBufferSize(uint size) = 0;\n\t/// Get the buffer size for this device\n\tvirtual uint getBufferSize() const = 0;\n\n\t///\\name Device server specifics. You usually don't want to call these\n\t//@{\n\t\t/** For device server usage :\n\t\t  * Called at the beginning of each events retrieval.\n\t\t  * If a device doesn't support buffered datas, the state changes can be directly send to the event server.\n\t\t  * The default does nothing.\n\t\t  */\n\t\tvirtual void begin(CEventServer * /* server */) {}\n\n\t\t/**\tFor device server usage :\n\t\t  * Poll all events from that device, and notify them to the given device server, so that they can be sorted between devices.\n\t\t  * This retrieves messages, but do not process them.\n\t\t  */\n\t\tvirtual void poll(CInputDeviceServer *dev) = 0;\n\t\t/** For device server usage :\n\t\t  * Process an event (eventually update this device state), and translate the message to a IEventServerMessage\n\t\t  */\n\t\tvirtual void submit(IInputDeviceEvent *deviceEvent, CEventServer *server) = 0;\n\t\t/** For device server usage :\n\t\t  * Says that the next message is for another device, or that it is the last message that will be received.\n\t\t  * This allow to pack several messages in one (for example, to sum up mouse moves until a click occurs)\n\t\t  * The default does nothing.\n\t\t  * The next message can be used to get a time stamp for example. It may be NULL is no next message is available\n\t\t  */\n\t\tvirtual void transitionOccured(CEventServer * /* server */, const IInputDeviceEvent * /* nextMessage */) {}\n\t//@}\n\n\t// dtor\n\tvirtual ~IInputDevice() {}\n};\n\n} // NLMISC\n\n\n#endif // NL_INPUT_DEVICE_H\n\n/* End of input_device.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/input_device_manager.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_INPUT_DEVICE_MANAGER_H\n#define NL_INPUT_DEVICE_MANAGER_H\n\n#include \"types_nl.h\"\n#include \"game_device.h\"\n#include \"common.h\"\n\nnamespace NLMISC\n{\n\n\nstruct IMouseDevice;\nstruct IKeyboardDevice;\n\n\n\nstruct EInputDevice : public Exception\n{\n\tEInputDevice(const char *reason) : Exception(reason) {}\n};\n\n\n/** Interface for objects that give low level access to devices (mouse, keyboard, joypads and joysticks).\n  * Generally an object implementing this interface will send the appropriate events when a device is 'created'.\n  * (Example of implementation : a direct input event emitter)\n  */\nstruct IInputDeviceManager\n{\n\t// Test if a mouse has been created (by a call to getMouseDeivce)\n\tvirtual\tbool\t\t\tisMouseCreated() = 0;\n\t/// Create the low level mouse device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained.\n\tvirtual IMouseDevice\t*getMouseDevice(bool hardware) throw(EInputDevice) = 0;\n\t/// remove the low level mouse\n\tvirtual void\t\t\treleaseMouse() = 0;\n\t/// Create the low level keyboard device if needed (one active at a time for that object, repeated calls returns the same pointer). An exception if thrown if it couldn't be obtained.\n\tvirtual IKeyboardDevice\t*getKeyboardDevice() throw(EInputDevice) = 0;\n\t/// remove the low level keyboard\n\tvirtual void\t\t\treleaseKeyboard() = 0;\n\t// Enumerates current game devices (gamepads, joystick etc.). The result is stored in the given vector\n\tvirtual void\t\t\tenumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice) = 0;\n\t// Create the given game device interface from its instance name. It also means that it will begin to sends events.\n\tvirtual IGameDevice\t\t*createGameDevice(const std::string &instanceName) throw(EInputDevice) = 0;\n\t// Release the given game device.\n\tvirtual void\t\t\treleaseGameDevice(IGameDevice *gd) = 0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_INPUT_DEVICE_MANAGER_H\n\n/* End of device_manager.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/input_device_server.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_INPUT_DEVICE_SERVER_H\n#define NL_INPUT_DEVICE_SERVER_H\n\n#include \"types_nl.h\"\n#include <vector>\n\n\nnamespace NLMISC\n{\n\nclass CEventServer;\nstruct IInputDevice;\nstruct IInputDeviceEvent;\n\n\n/** Base class for an input device server. Unlike an event server, it manages several devices, and can sort their events (by date for example).\n  * It keeps a list of active devices.\n  * It can poll datas from every active device.\n  * It can sort devices messages to submit them in correct order to a CEventServer.\n  */\n\nclass CInputDeviceServer\n{\npublic:\n\t/// register a device into this device server.\n\tvoid\tregisterDevice(IInputDevice *device);\n\t/// remove a device from this server (but does not delete it).\n\tvoid\tremoveDevice(IInputDevice *device);\n\t// returns the number of registered devices\n\tuint\tgetNumDevices() const { return (uint)_Devices.size(); }\n\t// return a device\n\tIInputDevice *getDevice(uint index) { return _Devices[index]; }\n\t/// Test whether the given device is handled by this server.\n\tbool\tisDevice(IInputDevice *device) const;\n\t/// Retrieve datas from the devices, and submit them to the given CEventServer.\n\tvoid\tpoll(CEventServer *server);\n\t/// Allow an input device to register an event. The event will then be deleted by this server\n\tvoid\tsubmitEvent(IInputDeviceEvent *deviceEvent);\n\t// dtor\n\tvirtual ~CInputDeviceServer() {}\nprivate:\n\ttypedef\tstd::vector<IInputDevice *>\t\t TDeviceCont;\n\ttypedef\tstd::vector<IInputDeviceEvent *> TEventCont;\nprivate:\n\tTDeviceCont\t_Devices;\n\tTEventCont  _Events;\n};\n\n\n\n\n/** An event from an input device.\n  */\nstruct IInputDeviceEvent\n{\n\tIInputDevice    *Emitter;\t// the input device that emitted that event\n\t// Used to sort events by time stamp.\n\tvirtual bool\toperator < (const IInputDeviceEvent &IInputDeviceEvent) const = 0;\n\tvirtual ~IInputDeviceEvent() {}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_INPUT_DEVICE_SERVER_H\n\n/* End of input_device_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/inter_window_msg_queue.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef RY_INTER_WINDOW_MSG_QUEUE_H\n#define RY_INTER_WINDOW_MSG_QUEUE_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/mutex.h\"\n#include \"nel/misc/shared_memory.h\"\n#include \"nel/misc/mem_stream.h\"\n#include \"nel/misc/dummy_window.h\"\n\n#ifndef WIN32_LEAN_AND_MEAN\n#\tdefine WIN32_LEAN_AND_MEAN\n#endif\n#ifndef _WIN32_WINDOWS\n#\tdefine _WIN32_WINDOWS 0x0410\n#endif\n#ifndef _WIN32_WINNT\n#\tdefine _WIN32_WINNT 0x0400\n#endif\n#ifndef WINVER\n#\tdefine WINVER 0x0400\n#endif\n#ifndef NOMINMAX\n#\tdefine NOMINMAX\n#endif\n#include <windows.h>\n\nnamespace NLMISC\n{\n\n// **************************************************************************************************\n/** IPC Utility class to enable easy window-window communication\n  *\n  * This enable 2-ways non blocking communication between 2 windows on the same machine (windows\n  * may belong to different processes)\n  *\n  * Only works on microsoft windows os for now\n  *\n  * The implementation relies on the WM_COPYDATA message to enable communication, but create a separate thread\n  * to enable non blocking exchange. (The WM_COPYDATA message require the use of SendMessage, which is blocking until the\n  * target window receive the message and respond)\n  *\n  * Identifier should be agreed on for the 2 windows that are to communicate (windows handles are transparently\n  * exchanged through shared memory based on this name)\n  *\n  * When initializing the queue for a specific window, this window message proc will be subclassed\n  * to enable interception of the WM_COPYDATA for that window.\n  *\n  * 'release' should be called before the hooked window is destroyed, to avoid dangling reference to it\n  * in this object. As one can expect 'release' is also automatically called when this object is destroyed\n  *\n  * Additionnaly, an internal, invisible window will be create if no one is given (second form of 'init'). This avoid having to worry\n  * about order of init / release of subclassing.\n  *\n  * FIXME : In fact, creating an invisible, internal window (that is required to have a message queue), should be the default,\n  * this would hide the internal communication mean, and we simply would have something called like 'CInterProcessMsgQueue'.\n  * Alternatives have been considered, but this one seemed simpler at first because of the facility offered by WM_COPYDATA\n  * Other possible implementations include shared memory (would require additionnal synchronisation & possible splitting of messages then), sockets (would make the firewall complain then ...) etc.\n  * .\n  */\n\nclass CInterWindowMsgQueue\n{\npublic:\n\tCInterWindowMsgQueue();\n\t~CInterWindowMsgQueue();\n\t/** Create a 2-way inter process message queue.\n\t  * Each ownerWindow / localId / foreignId triplet should be unique, repeated call with the same value will return false\n\t  * as long as the message queue created from them is alive\n\t  * IMPORTANT: 'ownerWindow' will be subclassed to handle the messages. If multiple subclassing are done on that window,\n\t  * they must be undone in reverse order, or an assertion will be raised. The simplest thing is use the second form of init,\n\t  * which will create an internal invisible window, thusavoiding this concern.\n\t  */\n\tbool init(HINSTANCE hInstance, uint32 localId, uint32 foreignId);\n\t/** Create a 2-way message queue between 2 windows.\n\t  * Each ownerWindow / localId / foreignId triplet should be unique, repeated call with the same value will return false\n\t  * as long as the message queue created from them is alive\n\t  * IMPORTANT: 'ownerWindow' will be subclassed to handle the messages. If multiple subclassing are done on that window,\n\t  * they must be undone in reverse order, or an assertion will be raised. The simplest thing is use the second form of init,\n\t  * which will create an internal invisible window, thusavoiding this concern.\n\t  *\n\t  * return true on success\n\t  */\n\tbool init(HWND ownerWindow, uint32 localId, uint32 foreignId);\n\t/** Release the msg queue\n\t  * This will unhook the window, restoring its previous message procedure\n\t  * Note than if the window was hooked by someone else, an assert will be raised\n\t  * Hooks on windows msg proc should thus be 'unhooked' in reverse order\n\t  */\n\tvoid release();\n\t/** Send a new message\n\t  * The msg is guaranteed to be received by the other window as long as it remains alive\n\t  */\n\tvoid sendMessage(CMemStream &msg);\n\t// See if a message has arrived from foreign window, return true if so\n\tbool pumpMessage(CMemStream &dest);\n\t// Test if other window is present\n\tbool connected() const;\n\t//\n\tuint getSendQueueSize() const;\n\tuint getReceiveQueueSize() const;\n\n\n// **************************************************************************************************\nprivate:\n\tstruct CMsg\n\t{\n\t\tstd::vector<uint8> Msg;\n\t\tvoid serial(NLMISC::IStream &f)\n\t\t{\n\t\t\tf.serialVersion(0);\n\t\t\tf.serialCont(Msg);\n\t\t}\n\t};\n\n\ttypedef std::list<CMsg> TMsgList;\n\tCSynchronized<TMsgList> _OutMessageQueue; // outgoing messages : filled by main thread, pumped by\n\t\t\t\t\t\t\t\t\t\t\t\t\t  // this 'CInterWindowMsgQueue' internal thread to hide latency of SendMessage\n\t\t\t\t\t\t\t\t\t\t\t\t\t  // to the main thread\n\n\tTMsgList\t\t\t\t\t\t_InMessageQueue;  // Incoming messages : not synchronised here, because the wnd\n\t\t\t\t\t\t\t\t\t\t\t\t      // message proc that receive foreign window messages (through WM_COPYDATA)\n\t\t\t\t\t\t\t\t\t\t\t\t\t  // belong to the same thread than the reader (that calls 'pumpMessage')\n\n\tCDummyWindow\t\t\t\t\t_DummyWindow;\n\n\n\t// internal send thread\n\tclass CSendTask : public IRunnable\n\t{\n\tpublic:\n\t\tCSendTask(CInterWindowMsgQueue *parent);\n\t\t// from IRunnable\n\t\tvirtual void run();\n\t\t// parent should call this to ask the thread to terminate\n\t\tvoid stop();\n\tprivate:\n\t\tCInterWindowMsgQueue *_Parent;\n\t\tbool\t\t\t\t  _StopAsked;\n\t};\n\n\tfriend class CSendTask;\n\n\t/** One protagonist in the communication. May be the 'local' of 'foreign' window\n\t  * The responsbility of this class is to allow to set / retrieve the window handle\n\t  * of local / foreign window.\n\t  * Window handle is needed by the send thread when it need to call SendMessage\n\t  */\n\tclass CProtagonist\n\t{\n\tpublic:\n\t\tCProtagonist();\n\t\t~CProtagonist();\n\t\tvoid release();\n\t\t// init this 'protagonist'\n\t\tbool init(uint32 id);\n\t\t// set handle for foreign window\n\t\tvoid setWnd(HWND wnd);\n\t\t// get local or foreign window handle\n\t\tHWND getWnd();\n\t\tuint32 getId() const { return _Id; }\n\tprivate:\n\t\tuint32\t\t\t\t\t_Id;\n\t\tHWND\t\t\t\t\t_Wnd;\n\t\tHANDLE\t\t\t\t\t_SharedMemMutex;\t\t\t// system-wide mutex for access to window handle in shared memory\n\t\tvoid\t\t\t\t\t*_SharedWndHandle; // no need for mutex here as the value will be written atomically (a single memory word)\n\tprivate:\n\t\t// shared memory mutex\n\t\tvoid acquireSMMutex();\n\t\tvoid releaseSMMutex();\n\t};\n\t//\n\tCProtagonist\t\t_LocalWindow;\n\tCProtagonist\t\t_ForeignWindow;\n\tCSendTask\t\t\t*_SendTask;\n\tIThread\t\t\t\t*_SendThread;\n\tstatic const uint   _CurrentVersion; // for messages serialisation\n\n\n\n\n\t// Unique identifier for a 2-way message queue (that is, a CInterWindowMsgQueue object after it has been\n\t// initialized)\n\t// This is required since the window message proc 'ListenerProc' is static so we must be\n\t// retrieve the associated 'CInterWindowMsgQueue' object from the (local id, foreign id) pair\n\tclass CMsgQueueIdent\n\t{\n\tpublic:\n\t\tHWND Wnd;\n\t\tuint32 LocalId;\n\t\tuint32 ForeignId;\n\tpublic:\n\t\tCMsgQueueIdent(HWND wnd, uint32 localId, uint32 foreignId)\n\t\t\t\t\t : Wnd(wnd), LocalId(localId), ForeignId(foreignId) {}\n\t\tbool operator < (const CMsgQueueIdent &other) const\n\t\t{\n\t\t\tif (Wnd != other.Wnd) return Wnd < other.Wnd;\n\t\t\tif (LocalId != other.LocalId) return LocalId < other.LocalId;\n\t\t\treturn LocalId < other.LocalId;\n\t\t}\n\t};\n\ttypedef std::map<CMsgQueueIdent, CInterWindowMsgQueue *> TMessageQueueMap;\n\tstatic CSynchronized<TMessageQueueMap> _MessageQueueMap;\n\n\t// map window handle to old message queue\n\tclass COldMsgProc\n\t{\n\tpublic:\n\t\tWNDPROC OldWinProc;\n\t\tuint\tRefCount;\n\tpublic:\n\t\tCOldMsgProc() : OldWinProc(NULL), RefCount(0) {}\n\t};\n\n\ttypedef std::map<HWND, COldMsgProc> TOldWinProcMap;\n\n\tstatic TOldWinProcMap _OldWinProcMap;\n\n\tbool initInternal(HINSTANCE hInstance, HWND ownerWindow, uint32 localId, uint32 foreignId = 0);\n\nprivate:\n\tstatic\tLRESULT CALLBACK listenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\n\tstatic\tLRESULT CALLBACK invisibleWindowListenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\n\tstatic  LRESULT\t\t\t handleWMCopyData(HWND hwnd, COPYDATASTRUCT *cds);\n\tvoid updateTargetWindow();\n\tvoid clearOutQueue();\n};\n\n\n} // NLMISC\n\n#endif\n\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/keyboard_device.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_KEYBOARD_DEVICE_H\n#define NL_KEYBOARD_DEVICE_H\n\n#include \"types_nl.h\"\n#include \"events.h\"\n#include \"input_device.h\"\n\n\n\nnamespace NLMISC\n{\n\n/** Gives access to low level keyboard parameters\n  * - 'Shift' messages are replaced by RShift and LShift msg.\n  * - 'Control' messages are replaced by 'RControl' and 'LControl' msg.\n  * - 'Menu' (alternate) messages are replaced by 'RMenu' and 'LMenu' msg.\n  */\nstruct IKeyboardDevice\t: public IInputDevice\n{\n\t/// Max number of supported keys\n\tenum { NumKeys = 256 };\n\t/// Get the delay before key repeat, in milliseconds\n\tvirtual\t\tuint getKeyRepeatDelay() const = 0;\n\t/// Get the delay before key repeat, in milliseconds\n\tvirtual\t\tvoid setKeyRepeatDelay(uint delay) = 0;\n\t/// Get the period before key repeat, in milliseconds\n\tvirtual\t\tuint getKeyRepeatPeriod() const = 0;\n\t/// Get the period before key repeat, in milliseconds\n\tvirtual\t\tvoid setKeyRepeatPeriod(uint period) = 0;\n\t/// Set a set of keys for which repetition is disabled\n\tvirtual\t\tvoid disableRepetition(const TKey *keyTab, uint numKey) = 0;\n\t/// Get the number of disabled keys\n\tvirtual\t\tuint getNumDisabledRepetition() const = 0;\n\t/** Get the disabled keys and stores in the given tab.\n\t  * NB: must ensure the destination table has the right size\n\t  * \\see getNumDisabledKeys()\n\t  */\n\tvirtual\t\tvoid getDisabledRepetitions(TKey *destTab) const = 0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_KEYBOARD_DEVICE_H\n\n/* End of keyboard_device.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/line.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LINE_H\n#define NL_LINE_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n\n\nnamespace NLMISC\n{\n\n\n\n// ***************************************************************************\n/**\n * A simple couple of vertex.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CLine\n{\npublic:\n\tCVector\t\tV0, V1;\n\npublic:\n\t/// default ctor\n\tCLine() {}\n\t// ctor from 2 points\n\tCLine(const CVector &v0, const CVector &v1) : V0(v0), V1(v1)\n\t{}\n\t/// Project a vector on this line\n\tvoid project(const CVector &inV, CVector &outV);\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_LINE_H\n\n/* End of line.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/log.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LOG_H\n#define NL_LOG_H\n\n#include \"types_nl.h\"\n#include \"mutex.h\"\n\n#include <string>\n#include <list>\n\n\nnamespace NLMISC\n{\n\nclass IDisplayer;\n\n\n/**\n * When display() is called, the logger builds a string and sends it to its attached displayers.\n * The positive filters, if any, are applied first, then the negative filters.\n * See the nldebug/nlinfo... macros in debug.h.\n *\n * \\ref log_howto\n * \\author Vianney Lecroart, Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLog {\npublic:\n\n\ttypedef enum { LOG_NO=0, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG, LOG_STAT, LOG_ASSERT, LOG_UNKNOWN } TLogType;\n\n\t// Debug information\n\tstruct TDisplayInfo\n\t{\n\t\tTDisplayInfo() : Date(0), LogType(CLog::LOG_NO), ThreadId(0), FileName(NULL), Line(-1), FuncName(NULL) {}\n\n\t\ttime_t\t\t\t\tDate;\n\t\tTLogType\t\t\tLogType;\n\t\tstd::string\t\t\tProcessName;\n\t\tsize_t\t\t\t\tThreadId;\n\t\tconst char\t\t\t*FileName;\n\t\tsint\t\t\t\tLine;\n\t\tconst char\t\t\t*FuncName;\n\n\t\tstd::string\t\t\tCallstackAndLog;\t// contains the callstack and a log with not filter of N last line (only in error/assert log type)\n\t};\n\n\tCLog (TLogType logType = LOG_NO);\n\n\t/// Add a new displayer in the log. You have to create the displayer, remove it and delete it when you have finish with it.\n\t/// For example, in a 3dDisplayer, you can add the displayer when you want, and the displayer displays the string if the 3d\n\t/// screen is available and do nothing otherwise. In this case, if you want, you could leave the displayer all the time.\n\tvoid addDisplayer (IDisplayer *displayer, bool bypassFilter = false);\n\n\t/// Return the first displayer selected by his name\n\tIDisplayer *getDisplayer (const char *displayerName);\n\n\t/// Remove a displayer. If the displayer doesn't work in a specific time, you could remove it.\n\tvoid removeDisplayer (IDisplayer *displayer);\n\n\t/// Remove a displayer using his name\n\tvoid removeDisplayer (const char *displayerName);\n\n\t/// Returns true if the specified displayer is attached to the log object\n\tbool attached (IDisplayer *displayer) const;\n\n\t/// Returns true if no displayer is attached\n\tbool noDisplayer () const { return _Displayers.empty() && _BypassFilterDisplayers.empty(); }\n\n\n\t/// Set the name of the process\n\tstatic void setProcessName (const std::string &processName);\n\n\t/// Find the process name if nobody call setProcessName before\n\tstatic void setDefaultProcessName ();\n\n\t/// If !noDisplayer(), sets line and file parameters, and enters the mutex. If !noDisplayer(), don't forget to call display...() after, to release the mutex.\n\tvoid setPosition (sint line, const char *fileName, const char *funcName = NULL);\n\n\n#ifdef NL_OS_WINDOWS\n\n#define CHECK_TYPES2(__a,__b) \\\n\tinline __a(const char *fmt) { __b(fmt); } \\\n\ttemplate<class A> __a(const char *fmt, A a) { _check(a); __b(fmt, a); } \\\n\ttemplate<class A, class B> __a(const char *fmt, A a, B b) { _check(a); _check(b); __b(fmt, a, b); } \\\n\ttemplate<class A, class B, class C> __a(const char *fmt, A a, B b, C c) { _check(a); _check(b); _check(c); __b(fmt, a, b, c); } \\\n\ttemplate<class A, class B, class C, class D> __a(const char *fmt, A a, B b, C c, D d) { _check(a); _check(b); _check(c); _check(d); __b(fmt, a, b, c, d); } \\\n\ttemplate<class A, class B, class C, class D, class E> __a(const char *fmt, A a, B b, C c, D d, E e) { _check(a); _check(b); _check(c); _check(d); _check(e); __b(fmt, a, b, c, d, e); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F> __a(const char *fmt, A a, B b, C c, D d, E e, F f) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); __b(fmt, a, b, c, d, e, f); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); __b(fmt, a, b, c, d, e, f, g); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); __b(fmt, a, b, c, d, e, f, g, h); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); __b(fmt, a, b, c, d, e, f, g, h, i); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); __b(fmt, a, b, c, d, e, f, g, h, i, j); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); __b(fmt, a, b, c, d, e, f, g, h, i, j, k); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X, class Y> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y); } \\\n\ttemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X, class Y, class Z> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); _check(z); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); }\n\n\t/// Display a string in decorated and final new line form to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid _displayNL (const char *format, ...);\n\tCHECK_TYPES2(void displayNL, _displayNL)\n\n\t/// Display a string in decorated form to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid _display (const char *format, ...);\n\tCHECK_TYPES2(void display, _display)\n\n\t/// Display a string with a final new line to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid _displayRawNL (const char *format, ...);\n\tCHECK_TYPES2(void displayRawNL, _displayRawNL)\n\n\t/// Display a string (and nothing more) to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid _displayRaw (const char *format, ...);\n\tCHECK_TYPES2(void displayRaw, _displayRaw)\n\n\t/// Display a raw text to the normal displayer but without filtering\n\t/// It's used by the Memdisplayer (little hack to work)\n\tvoid _forceDisplayRaw (const char *format, ...);\n\tCHECK_TYPES2(void forceDisplayRaw, _forceDisplayRaw)\n\n#else\n\n\t/// Display a string in decorated and final new line form to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid displayNL (const char *format, ...);\n\n\t/// Display a string in decorated form to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid display (const char *format, ...);\n\n\t/// Display a string with a final new line to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid displayRawNL (const char *format, ...);\n\n\t/// Display a string (and nothing more) to all attached displayers. Call setPosition() before. Releases the mutex.\n\tvoid displayRaw (const char *format, ...);\n\n\t/// Display a raw text to the normal displayer but without filtering\n\t/// It's used by the Memdisplayer (little hack to work)\n\tvoid forceDisplayRaw (const char *format, ...);\n\n#endif\n\n\t/// Adds a positive filter. Tells the logger to log only the lines that contain filterstr\n\tvoid addPositiveFilter( const char *filterstr );\n\n\t/// Adds a negative filter. Tells the logger to discard the lines that contain filterstr\n\tvoid addNegativeFilter( const char *filterstr );\n\n\t/// Reset both filters\n\tvoid resetFilters();\n\n\t/// Removes a filter by name (in both filters).\n\tvoid removeFilter( const char *filterstr = NULL);\n\n\t/// Displays the list of filter into a log\n\tvoid displayFilter( CLog &log );\n\n\t/// Do not call this unless you know why you're doing it, it kills the debug/log system!\n\tstatic void releaseProcessName();\n\nprotected:\n\n\t/// Symetric to setPosition(). Automatically called by display...(). Do not call if noDisplayer().\n\tvoid unsetPosition();\n\n\t/// Returns true if the string must be logged, according to the current filter\n\tbool passFilter( const char *filter );\n\n\tTLogType\t\t\t\t\t\t\t _LogType;\n\tstatic std::string\t\t\t\t\t*_ProcessName;\n\n\tconst char\t\t\t\t\t\t\t*_FileName;\n\tsint\t\t\t\t\t\t\t\t _Line;\n\tconst char\t\t\t\t\t\t\t*_FuncName;\n\n\ttypedef std::list<IDisplayer *>\t\t CDisplayers;\n\n\tCDisplayers\t\t\t\t\t\t\t _Displayers;\n\n\tCDisplayers\t\t\t\t\t\t\t _BypassFilterDisplayers;\t// these displayers always log info (by pass filter system)\n\n\tCMutex\t\t\t\t\t\t\t\t _Mutex;\n\n\tuint32\t\t\t\t\t\t\t\t _PosSet;\n\n\t/// \"Discard\" filter\n\tstd::list<std::string>\t\t\t\t _NegativeFilter;\n\n\t/// \"Crop\" filter\n\tstd::list<std::string>\t\t\t\t _PositiveFilter;\n\n\t/// Display a string in decorated form to all attached displayers.\n\tvoid displayString (const char *str);\n\n\t/// Display a Raw string to all attached displayers.\n\tvoid displayRawString (const char *str);\n\n\tstd::string\t\t\t\t\t\t\t TempString;\n\tTDisplayInfo\t\t\t\t\t\t TempArgs;\n\n};\n\n\n} // NLMISC\n\n#endif // NL_LOG_H\n\n/* End of log.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/matrix.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MATRIX_H\n#define NL_MATRIX_H\n\n#include \"vector.h\"\n#include \"vector_h.h\"\n#include \"quat.h\"\n\n\nnamespace\tNLMISC\n{\n\nclass\tCPlane;\n\n\n// ======================================================================================================\n/**\n * A 4*4 Homogeneous Matrix.\n * This is a column matrix, so operations like: \\c v1=A*B*C*v0; applies C first , then B, then A to vector v0. \\n\n * Since it is a column matrix, the first column is the I vector of the base, 2nd is J, 3th is K. \\n\n * 4th column vector is T, the translation vector.\n *\n * Angle orientation are: Xaxis: YtoZ. Yaxis: ZtoX. Zaxis: XtoY.\n *\n * This matrix keep a matrix state to improve Matrix, vector and plane computing (matrix inversion, vector multiplication...).\n * The internal matrix know if:\n * - matrix is identity\n * - matrix has a translation component\n * - matrix has a rotation component\n * - matrix has a uniform scale component (scale which is the same along the 3 axis)\n * - matrix has a non-uniform scale component\n * - matrix has a projection component (4th line of the matrix is not 0 0 0 1).\n *\n * An example of improvement is that CMatrix::operator*(const CVector &v) return v if the matrix is identity.\n *\n * By default, a matrix is identity. But for a performance view, this is just a StateBit=0...\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\n\nclass NL_ALIGN_SSE2 CMatrix\n{\npublic:\n\t/// Rotation Order.\n\tenum\tTRotOrder\n\t{\n\t\tXYZ,\n\t\tXZY,\n\t\tYXZ,\n\t\tYZX,\n\t\tZXY,\n\t\tZYX\n\t};\n\n\t/// The identity matrix. Same as CMatrix().\n\tstatic\tconst CMatrix\tIdentity;\n\npublic:\n\n\t/// \\name Object\n\t//@{\n\t/// Constructor which init to identity().\n\tCMatrix()\n\t{\n\t\tStateBit= 0;\n\t\t// Init just Pos because must always be valid for faster getPos()\n\t\tM[12]= M[13]= M[14]= 0;\n\t}\n\t/// Copy Constructor.\n\tCMatrix(const CMatrix &);\n\t/// operator=.\n\tCMatrix\t&operator=(const CMatrix &);\n\t//@}\n\n\n\n\t/// \\name Sets\n\t//@{\n\t/// Reset the matrix to identity.\n\tvoid\t\tidentity();\n\t/** Explicit setup the Rotation/Scale matrix (base).\n\t * Avoid it. It implies low compute since no check is done on base to see what type of matrix it is\n\t * (identity, rotation, scale, uniform scale...)\n\t * \\param i The I vector of the Cartesian base.\n\t * \\param j The J vector of the Cartesian base.\n\t * \\param k The K vector of the Cartesian base.\n\t * \\param hintNoScale set it to true if you are sure that your rot matrix is a pure rot matrix with no scale.\n\t * If set to true and your rotation is not an orthonormal basis, unpredictable result are excepted.\n\t */\n\tvoid\t\tsetRot(const CVector &i, const CVector &j, const CVector &k, bool hintNoScale=false);\n\t/** Explicit setup the Rotation/Scale matrix (base).\n\t * Avoid it. It implies low compute since no check is done on m33 to see what type of matrix it is\n\t * (identity, rotation, scale, uniform scale)\n\t * \\param m33 the 3*3 column rotation matrix. (3x3 matrix stored in column-major order as 9 consecutive values)\n\t * \\param hintNoScale set it to true if you are sure that your rot matrix is a pure rot matrix with no scale.\n\t * If set to true and your rotation is not an orthonormal basis, unpredictable result are excepted.\n\t */\n\tvoid\t\tsetRot(const float m33[9], bool hintNoScale=false);\n\t/** Explicit setup the Rotation matrix (base) as a Euler rotation matrix.\n\t * \\param v a vector of 3 angle (in radian), giving rotation around each axis (x,y,z)\n\t * \\param ro the order of transformation applied. if ro==XYZ, then the transform is M=M*Rx*Ry*Rz\n\t */\n\tvoid\t\tsetRot(const CVector &v, TRotOrder ro);\n\t/** Explicit setup the Rotation matrix (base) as a Quaternion rotation matrix.\n\t * \\param quat a UNIT quaternion\n\t */\n\tvoid\t\tsetRot(const CQuat &quat);\n\t/** Explicit setup the Rotation/Scale matrix (base) with the rotation part of another matrix.\n\t * \\param matrix the matrix to copy rot part.\n\t */\n\tvoid\t\tsetRot(const CMatrix &matrix);\n\t/** Explicit setup the Rotation/Scale matrix (base) with a scale (=> matrix has no Rotation).\n\t *\t1 is tested to update bits accordingly\n\t * \\param scale the scale to set\n\t */\n\tvoid\t\tsetScale(float scale);\n\t/** Explicit setup the Rotation/Scale matrix (base) with a scale (=> matrix has no Rotation).\n\t *\tcase where v.x==v.y==v.z is tested to set a uniform scale\n\t * \\param scale the scale to set\n\t */\n\tvoid\t\tsetScale(const CVector &v);\n\t/** Explicit setup the Translation component.\n\t * v==Null is tested to see if the matrix now have a translation component.\n\t * \\param v the translation vector.\n\t */\n\tvoid\t\tsetPos(const CVector &v);\n\t/** Explicit move the Translation component.\n\t * \\param v a vector to move the translation vector.\n\t */\n\tvoid\t\tmovePos(const CVector &v);\n\t/** Explicit setup the Projection component.\n\t * Proj is tested to see if the matrix now have a projection component.\n\t * \\param proj the 4th line of the matrix. Set it to 0 0 0 1 to reset it to default.\n\t */\n\tvoid\t\tsetProj(const float proj[4]);\n\t/** Reset the Projection component to 0 0 0 1.\n\t */\n\tvoid\t\tresetProj();\n\t/** Explicit setup the 4*4 matrix.\n\t * Avoid it. It implies low compute since no check is done on rotation matrix to see what type of matrix it is\n\t * (identity, rotation, scale, uniform scale).\n\t * BUT check are made to see if it has translation or projection components.\n\t * \\param m44 the 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values)\n\t */\n\tvoid\t\tset(const float m44[16]);\n\t/** Setup the (i, j) matrix coefficient\n\t *\t\\param coeff: coefficient value.\n\t *\t\\param i : column index.\n\t *\t\\param j : line index.\n\t */\n\tvoid\t\tsetCoefficient(float coeff, sint i, sint j)\n\t{\n\t\tM[ (j<<2) + i] = coeff;\n\t}\n\t//@}\n\t/** Choose an arbitrary rotation matrix for the given direction. The matrix will have I==idir\n\t *\t\\param idir: vector direction. MUST  be normalized.\n\t */\n\n\tvoid\t\tsetArbitraryRotI(const CVector &idir);\n\t/** Choose an arbitrary rotation matrix for the given direction. The matrix will have J==jdir\n\t *\t\\param jdir: vector direction. MUST  be normalized.\n\t */\n\tvoid\t\tsetArbitraryRotJ(const CVector &jdir);\n\t/** Choose an arbitrary rotation matrix for the given direction. The matrix will have K==kdir\n\t *\t\\param kdir: vector direction. MUST  be normalized.\n\t */\n\tvoid\t\tsetArbitraryRotK(const CVector &kdir);\n\t//@}\n\n\n\n\n\t/// \\name Gets.\n\t//@{\n\t/** Get the Rotation/Scale matrix (base).\n\t * \\param i The matrix's I vector of the Cartesian base.\n\t * \\param j The matrix's J vector of the Cartesian base.\n\t * \\param k The matrix's K vector of the Cartesian base.\n\t */\n\tvoid\t\tgetRot(CVector &i, CVector &j, CVector &k) const;\n\t/** Get the Rotation/Scale matrix (base).\n\t * \\param m33 the matrix's 3*3 column rotation matrix. (3x3 matrix stored in column-major order as 9 consecutive values)\n\t */\n\tvoid\t\tgetRot(float m33[9]) const;\n\t/** Get the Rotation matrix (base).\n\t * \\param quat the return quaternion.\n\t */\n\tvoid\t\tgetRot(CQuat &quat) const;\n\t/** Get the Rotation matrix (base).\n\t * \\param quat the return quaternion.\n\t */\n\tCQuat\t\tgetRot() const {CQuat\tret; getRot(ret); return ret;}\n\t/** Get the Translation component.\n\t * \\param v the matrix's translation vector.\n\t */\n\tvoid\t\t\tgetPos(CVector &v) const\t{v.x= M[12]; v.y= M[13]; v.z= M[14];}\n\t/** Get the Translation component.\n\t *\tNB: a const & works because it is a column vector\n\t * \\return the matrix's translation vector.\n\t */\n\tconst CVector\t&getPos() const\t\t\t\t{return *(CVector*)(M+12);}\n\t/** Get the Projection component.\n\t * \\param proj the matrix's projection vector.\n\t */\n\tvoid\t\tgetProj(float proj[4]) const;\n\t/// Get the I vector of the Rotation/Scale matrix (base).\n\tCVector\t\tgetI() const;\n\t/// Get the J vector of the Rotation/Scale matrix (base).\n\tCVector\t\tgetJ() const;\n\t/// Get the K vector of the Rotation/Scale matrix (base).\n\tCVector\t\tgetK() const;\n\t/** Get 4*4 matrix.\n\t * \\param m44 the matrix's 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values)\n\t */\n\tvoid\t\tget(float m44[16]) const;\n\t/** Get 4*4 matrix.\n\t * \\return the matrix's 4*4 column matrix (4x4 matrix stored in column-major order as 16 consecutive values)\n\t */\n\tconst float *get() const;\n\t//@}\n\n\n\n\t/// \\name 3D Operations.\n\t//@{\n\t/// Apply a translation to the matrix. same as M=M*T\n\tvoid\t\ttranslate(const CVector &v);\n\t/** Apply a rotation on axis X to the matrix. same as M=M*Rx\n\t * \\param a angle (in radian).\n\t */\n\tvoid\t\trotateX(float a);\n\t/** Apply a rotation on axis Y to the matrix. same as M=M*Ry\n\t * \\param a angle (in radian).\n\t */\n\tvoid\t\trotateY(float a);\n\t/** Apply a rotation on axis Z to the matrix. same as M=M*Rz\n\t * \\param a angle (in radian).\n\t */\n\tvoid\t\trotateZ(float a);\n\t/** Apply a Euler rotation.\n\t * \\param v a vector of 3 angle (in radian), giving rotation around each axis (x,y,z)\n\t * \\param ro the order of transformation applied. if ro==XYZ, then the transform is M=M*Rx*Ry*Rz\n\t */\n\tvoid\t\trotate(const CVector &v, TRotOrder ro);\n\t/** Apply a quaternion rotation.\n\t */\n\tvoid\t\trotate(const CQuat &quat);\n\t/// Apply a uniform scale to the matrix.\n\tvoid\t\tscale(float f);\n\t/// Apply a non-uniform scale to the matrix.\n\tvoid\t\tscale(const CVector &scale);\n\t//@}\n\n\n\n\t/// \\name Matrix Operations.\n\t//@{\n\t/** Matrix multiplication. Because of copy avoidance, this is the fastest method\n\t *\tEquivalent to *this= m1 * m2\n\t *\t\\warning *this MUST NOT be the same as m1 or m2, else it doesn't work (not checked/nlasserted)\n\t */\n\tvoid\t\tsetMulMatrix(const CMatrix &m1, const CMatrix &m2);\n\t/// Matrix multiplication\n\tCMatrix\t\toperator*(const CMatrix &in) const\n\t{\n\t\tCMatrix\t\tret;\n\t\tret.setMulMatrix(*this, in);\n\t\treturn ret;\n\t}\n\t/// equivalent to M=M*in\n\tCMatrix\t\t&operator*=(const CMatrix &in)\n\t{\n\t\tCMatrix\t\tret;\n\t\tret.setMulMatrix(*this, in);\n\t\t*this= ret;\n\t\treturn *this;\n\t}\n\t/** Matrix multiplication assuming no projection at all in m1/m2 and Hence this. Even Faster than setMulMatrix()\n\t *\tEquivalent to *this= m1 * m2\n\t *\tNB: Also always suppose m1 has a translation, for optimization consideration\n\t *\t\\warning *this MUST NOT be the same as m1 or m2, else it doesn't work (not checked/nlasserted)\n\t */\n\tvoid\t\tsetMulMatrixNoProj(const CMatrix &m1, const CMatrix &m2);\n\t/** transpose the rotation part only of the matrix (swap columns/lines).\n\t */\n\tvoid\t\ttranspose3x3();\n\t/** transpose the matrix (swap columns/lines).\n\t * NB: this transpose the 4*4 matrix entirely (even proj/translate part).\n\t */\n\tvoid\t\ttranspose();\n\t/** Invert the matrix.\n\t * if the matrix can't be inverted, it is set to identity.\n\t */\n\tvoid\t\tinvert();\n\t/** Return the matrix inverted.\n\t * if the matrix can't be inverted, identity is returned.\n\t */\n\tCMatrix\t\tinverted() const;\n\t/** Normalize the matrix so that the rotation part is now an orthonormal basis, ie a rotation with no scale.\n\t * NB: projection part and translation part are not modified.\n\t * \\param pref the preference axis order to normalize. ZYX means that K direction will be kept, and the plane JK\n\t * will be used to lead the I vector.\n\t * \\return false if One of the vector basis is null. true otherwise.\n\t */\n\tbool\t\tnormalize(TRotOrder pref);\n\t//@}\n\n\n\n\t/// \\ Vector Operations.\n\t//@{\n\t/// Multiply a normal. ie v.w=0 so the Translation component doesn't affect result. Projection doesn't affect result.\n\tCVector\t\tmulVector(const CVector &v) const;\n\t/// Multiply a point. ie v.w=1 so the Translation component do affect result. Projection doesn't affect result.\n\tCVector\t\tmulPoint(const CVector &v) const;\n\t/** Multiply a point. \\sa mulPoint\n\t  */\n\tCVector\t\toperator*(const CVector &v) const\n\t{\n\t\treturn mulPoint(v);\n\t}\n\n\t/// Multiply with an homogeneous vector\n\tCVectorH\toperator*(const CVectorH& v) const;\n\t//@}\n\n\t/// \\name Misc\n\t//@{\n\tvoid\t\tserial(IStream &f);\n\t/// return true if the matrix has a scale part (by scale(), by multiplication etc...)\n\tbool\t\thasScalePart() const;\n\t/// return true if hasScalePart() and if if this scale is uniform.\n\tbool\t\thasScaleUniform() const;\n\t/// return true the uniform scale. valid only if hasScaleUniform() is true, else 1 is returned.\n\tfloat\t\tgetScaleUniform() const;\n\t/// return true if the matrix has a projection part (by setProj(), by multiplication etc...)\n\tbool\t\thasProjectionPart() const;\n\t//@}\n\n\t// Friend.\n\t/// Plane (line vector) multiplication.\n\tfriend CPlane\t\toperator*(const CPlane &p, const CMatrix &m);\n\n\nprivate:\n\tfloat\tM[16];\n\tfloat\tScale33;\n\tuint32\tStateBit;\t// BitVector. 0<=>identity.\n\n\t// Methods For inversion.\n\tbool\tfastInvert33(CMatrix &ret) const;\n\tbool\tslowInvert33(CMatrix &ret) const;\n\tbool\tslowInvert44(CMatrix &ret) const;\n\t// access to M, in math conventions (mat(1,1) ... mat(4,4)). Indices from 0 to 3.\n\tfloat\t&mat(sint i, sint j)\n\t{\n\t\treturn M[ (j<<2) + i];\n\t}\n\t// access to M, in math conventions (mat(1,1) ... mat(4,4)). Indices from 0 to 3.\n\tconst float\t&mat(sint i, sint j) const\n\t{\n\t\treturn M[ (j<<2) + i];\n\t}\n\t// return the good 3x3 Id to compute the minor of (i,j);\n\tvoid\tgetCofactIndex(sint i, sint &l1, sint &l2, sint &l3) const\n\t{\n\t\tswitch(i)\n\t\t{\n\t\t\tcase 0: l1=1; l2=2; l3=3; break;\n\t\t\tcase 1: l1=0; l2=2; l3=3; break;\n\t\t\tcase 2: l1=0; l2=1; l3=3; break;\n\t\t\tcase 3: l1=0; l2=1; l3=2; break;\n\t\t\tdefault: l1=0; l2=0; l3=0; break;\n\t\t}\n\t}\n\n\t// true if MAT_TRANS.\n\t// trans part is true means the right 3x1 translation part matrix is relevant.\n\t// Else it IS initialized to (0,0,0) (exception!!!)\n\tbool\thasTrans() const;\n\t// true if MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY.\n\t// rot part is true means the 3x3 rot matrix AND Scale33 are relevant.\n\t// Else they are not initialized but are supposed to represent identity and Scale33==1.\n\tbool\thasRot() const;\n\t// true if MAT_PROJ.\n\t// proj part is true means the bottom 1x4 projection part matrix is relevant.\n\t// Else it is not initialized but is supposed to represent the line vector (0,0,0,1).\n\tbool\thasProj() const;\n\tbool\thasAll() const;\n\n\tvoid\ttestExpandRot() const;\n\tvoid\ttestExpandProj() const;\n\n\t// inline\n\tvoid\tsetScaleUni(float scale);\n};\n\n}\n\n#endif // NL_MATRIX_H\n\n/* End of matrix.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/md5.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MD5_H\n#define NL_MD5_H\n\n#include \"types_nl.h\"\n\n#include <string>\n\nnamespace NLMISC\n{\n\nclass IStream;\n\n\n\n// ****************************************************************************\n/**\n * MD5 Low level routines\n * Largely inspired from the RSA Data Security works\n * \\author Matthieu Besson\n * \\author Nevrax France\n * \\date July 2004\n */\n/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All\n   rights reserved.\n\n   License to copy and use this software is granted provided that it\n   is identified as the \"RSA Data Security, Inc. MD5 Message-Digest\n   Algorithm\" in all material mentioning or referencing this software\n   or this function.\n\n   License is also granted to make and use derivative works provided\n   that such works are identified as \"derived from the RSA Data\n   Security, Inc. MD5 Message-Digest Algorithm\" in all material\n   mentioning or referencing the derived work.\n\n   RSA Data Security, Inc. makes no representations concerning either\n   the merchantability of this software or the suitability of this\n   software for any particular purpose. It is provided \"as is\"\n   without express or implied warranty of any kind.\n\n   These notices must be retained in any copies of any part of this\n   documentation and/or software.\n   */\n\n// ****************************************************************************\nstruct CHashKeyMD5\n{\n\tuint8 Data[16];\n\n\tvoid clear();\n\tstd::string toString() const;\n\tbool fromString(const std::string &in);\n\tbool operator==(const CHashKeyMD5 &in) const;\n\tbool operator!=(const CHashKeyMD5 &in) const;\n\tbool operator<(const CHashKeyMD5 &in) const;\n\n\tvoid serial (NLMISC::IStream &s);\n};\n\n// ****************************************************************************\nclass CMD5Context\n{\n\npublic:\n\n\tvoid init();\n\tvoid update (const uint8 *pBufIn, uint32 nBufLength);\n\tvoid final (CHashKeyMD5 &out);\n\nprivate:\n\n\tuint32\tState[4];\t// state (ABCD)\n\tuint32\tCount[2];\t// number of bits, modulo 2^64 (lsb first)\n\tuint8\tBuffer[64]; // input buffer\n\n\tstatic uint8 Padding[64];\n\nprivate:\n\n\tvoid transform (uint32 state[4], const uint8 block[64]);\n\tvoid encode (uint8 *output, const uint32 *input, uint len);\n\tvoid decode (uint32 *output, const uint8 *input, uint len);\n\n};\n\n\n// ****************************************************************************\n/**\n * MD5 High level routines\n * Largely inspired from the RSA Data Security works\n * \\author Matthieu Besson\n * \\author Nevrax France\n * \\date July 2004\n */\n\n/*\ninline bool operator <(const struct CHashKeyMD5 &a,const struct CHashKeyMD5 &b)\n{\n\treturn a < b;\n}\n*/\n\n// This function get a filename (it works with big files) and returns his MD5 hash key\nCHashKeyMD5 getMD5(const std::string &filename);\n\n// This function get a buffer with size and returns his MD5 hash key\nCHashKeyMD5 getMD5(const uint8 *buffer, uint32 size);\n\n}; // namespace NLMISC\n\n#endif // NL_MD5_H\n\n/* End of md5.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/mem_displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MEM_DISPLAYER_H\n#define NL_MEM_DISPLAYER_H\n\n#include \"types_nl.h\"\n#include \"displayer.h\"\n\n#include <deque>\n#include <string>\n\n\nnamespace NLMISC {\n\n\n/**\n * Display into a string vector\n * \\author Benjamin Legros\n * \\author Nevrax France\n * \\date 2001\n */\nclass CMemDisplayer : public IDisplayer\n{\npublic:\n\t/// Constructor\n\tCMemDisplayer (const char *displayerName = \"\");\n\n\t/// Set Parameter of the displayer if not set at the ctor time\n\tvoid\t\t\tsetParam (uint32 maxStrings = 50);\n\n\t/// Write N last line into a displayer (InfoLog by default)\n\tvoid\t\t\twrite (CLog *log = NULL, bool quiet=true);\n\tvoid\t\t\twrite (std::string &str, bool crLf=false);\n\n\tconst std::deque<std::string>\t&lockStrings () { _CanUseStrings = false; return _Strings; }\n\n\tvoid unlockStrings() { _CanUseStrings = true; }\n\n\tvoid clear () { if (_CanUseStrings) _Strings.clear (); }\n\nprotected:\n\t/// Put the string into the file.\n    virtual void\tdoDisplay ( const CLog::TDisplayInfo& args, const char *message );\n\n\tbool\t\t\t\t\t\t_NeedHeader;\n\n\tuint32\t\t\t\t\t\t_MaxStrings;\t// number of string in the _Strings queue (default is 50)\n\n\tbool\t\t\t\t\t\t_CanUseStrings;\n\n\tstd::deque<std::string>\t\t_Strings;\n\n};\n\n/**\n * Same as CMemDisplayer but only display the text (no line, no date, no process...)\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2002\n */\nclass CLightMemDisplayer : public CMemDisplayer\n{\npublic:\n\t/// Constructor\n\tCLightMemDisplayer (const char *displayerName = \"\") : CMemDisplayer(displayerName) { }\n\nprotected:\n\t/// Put the string into the file.\n    virtual void\tdoDisplay ( const CLog::TDisplayInfo& args, const char *message );\n};\n\n\n\n} // NLMISC\n\n\n#endif // NL_MEM_DISPLAYER_H\n\n/* End of mem_displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/mem_stream.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MEM_STREAM_H\n#define NL_MEM_STREAM_H\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n#include \"object_vector.h\"\n#include \"fast_mem.h\"\n#include \"smart_ptr.h\"\n\n#include <algorithm>\n#include <google/protobuf/message.h>\n\nnamespace NLMISC\n{\n\n/// Exception class for CMemStream\nstruct EMemStream : public NLMISC::EStream\n{\n\tEMemStream( const std::string& str ) : EStream( str ) {}\n};\n\n\n/** This class implement a copy on write behavior for memory stream buffer.\n *\tThe goal is to allow buffer sharing between CMemStream object, so that\n *\ta CMemStream can be copied or passed by value as input/output parameter\n *\twithout copying the data buffer (thus making a CMemStrem copy almost free).\n *\tThis class reference a TMemStreamBuffer object with a smart pointer,\n *\twhen some code call the getBufferWrite() method to obtain write access\n *\tto the memory buffer, if the ref count is more than 1, then we make a copy\n *\tof the internal buffer for the current object.\n *\n *\t\\Author Boris Boucher\n */\nclass CMemStreamBuffer\n{\npublic:\n\ttypedef CObjectVector<uint8, false>\tTBuffer;\nprivate:\n\tstruct TMemStreamBuffer : public CRefCount\n\t{\n\t\t// the buffer himself\n\t\tTBuffer\t_Buffer;\n\t};\n\n\ttypedef CSmartPtr<TMemStreamBuffer>\tTMemStreamBufferPtr;\n\n\tTMemStreamBufferPtr\t\t_SharedBuffer;\n\npublic:\n\n\tmutable\tuint32\tPos;\n\n\t/// constructor, allocate a shared buffer\n\tCMemStreamBuffer()\n\t{\n\t\t_SharedBuffer = new TMemStreamBuffer;\n\t\tPos = 0;\n\t}\n\n\n\t/// Return a read accessor to the buffer\n\tconst TBuffer &getBuffer() const\n\t{\n\t\treturn _SharedBuffer->_Buffer;\n\t}\n\n\t/** Return a write accessor to the buffer, create acopy it if more than\n\t *\tone CMemStreamBuffer reference then buffer.\n\t */\n\tTBuffer &getBufferWrite()\n\t{\n\t\tif (_SharedBuffer->getRefCount() > 1)\n\t\t{\n\t\t\t// we need to duplicate the buffer\n\t\t\t_SharedBuffer = new TMemStreamBuffer(*_SharedBuffer);\n\t\t}\n\t\treturn _SharedBuffer->_Buffer;\n\t}\n\n\t/// Exchange the buffer of two CMemStreamBuffer (just swap memory pointer)\n\tvoid swap(CMemStreamBuffer &other)\n\t{\n\t\tstd::swap(_SharedBuffer, other._SharedBuffer);\n\t\tstd::swap(Pos, other.Pos);\n\t}\n\n};\n\n\n/**\n * Memory stream.\n *\n * How output mode works:\n * The buffer size is increased by factor 2. It means the stream can be smaller than the buffer size.\n * The size of the stream is the current position in the stream (given by lengthS() which is equal\n * to getPos()), because data is always written at the end (except when using poke()).\n * About seek() particularities: see comment of the seek() method.\n *\n * buffer() ----------------------------------- getPos() ---------------- size()\n *              data already serialized out        |\n *                                              length() = lengthS()\n *\n * How input mode works:\n * The stream is exactly the buffer (the size is given by lengthR()). Data is read inside the stream,\n * at the current position (given by getPos()). If you try to read data while getPos() is equal to\n * lengthR(), you'll get an EStreamOverflow exception.\n *\n * buffer() ----------------------------------- getPos() ------------------------- size()\n *              data already serialized in                   data not read yet      |\n *                                                                               length() = lengthR()\n *\n * \\seealso CBitMemStream\n * \\seealso NLNET::CMessage\n * \\author Olivier Cado, Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000, 2002\n */\nclass CMemStream : public NLMISC::IStream\n{\npublic:\n\n\t/// Initialization constructor\n\tCMemStream( bool inputStream=false, bool stringmode=false, uint32 defaultcapacity=0 ) :\n\t\tNLMISC::IStream( inputStream ), _StringMode( stringmode )\n\t{\n\t\t_DefaultCapacity = (std::max)( (uint32)defaultcapacity, (uint32)16 ); // prevent from no allocation\n\t\t_Buffer.getBufferWrite().resize (_DefaultCapacity);\n\t\t_Buffer.Pos = 0;\n\t}\n\n\t/// Copy constructor\n\tCMemStream( const CMemStream& other ) :\n\t\tIStream (other)\n\t{\n\t\toperator=( other );\n\t}\n\n\t/// Assignment operator\n\tCMemStream&\t\toperator=( const CMemStream& other )\n\t{\n\t\tIStream::operator= (other);\n\t\t_Buffer = other._Buffer;\n\t\t_StringMode = other._StringMode;\n\t\t_DefaultCapacity = other._DefaultCapacity;\n\t\treturn *this;\n\t}\n\n\t/// allocated memory exchange\n\tvoid swap(CMemStream &other);\n\n\t/// Set string mode\n\tvoid\t\t\tsetStringMode( bool stringmode ) { _StringMode = stringmode; }\n\n\t/// Return string mode\n\tbool\t\t\tstringMode() const { return _StringMode; }\n\n\t/** Returns a readable string to display it to the screen. It's only for debugging purpose!\n\t * Don't use it for anything else than to debugging, the string format could change in the future.\n\t * \\param hexFormat If true, display all bytes in hexadecimal, else display as chars (above 31, otherwise '.')\n\t */\n\tstd::string\t\ttoString( bool hexFormat=false ) const;\n\n\t/// Method inherited from IStream\n\tvirtual void\tserialBuffer(uint8 *buf, uint len);\n\n\t/// Method inherited from IStream\n\tvirtual void\tserialBit(bool &bit);\n\n\t/**\n\t * Moves the stream pointer to a specified location.\n\t *\n\t * Warning: in output mode, seek(end) does not point to the end of the serialized data,\n\t * but on the end of the whole allocated buffer (see size()).\n\t * If you seek back and want to return to the end of the serialized data, you have to\n\t * store the position (a better way is to use reserve()/poke()).\n\t *\n\t * NB: If the stream doesn't support the seek fonctionnality, it throws ESeekNotSupported.\n\t * Default implementation:\n\t * { throw ESeekNotSupported; }\n\t * \\param offset is the wanted offset from the origin.\n\t * \\param origin is the origin of the seek\n\t * \\return true if seek sucessfull.\n\t * \\see ESeekNotSupported SeekOrigin getPos\n\t */\n\tvirtual bool\tseek (sint32 offset, TSeekOrigin origin) const throw(EStream);\n\n\t/**\n\t * Get the location of the stream pointer.\n\t *\n\t * NB: If the stream doesn't support the seek fonctionnality, it throws ESeekNotSupported.\n\t * Default implementation:\n\t * { throw ESeekNotSupported; }\n\t * \\param offset is the wanted offset from the origin.\n\t * \\param origin is the origin of the seek\n\t * \\return the new offset regarding from the origin.\n\t * \\see ESeekNotSupported SeekOrigin seek\n\t */\n\tvirtual sint32\tgetPos () const throw(EStream)\n\t{\n\t\treturn sint32(_Buffer.Pos);\n\t}\n\n\t/**\n\t * When writing, skip 'len' bytes and return the position of the blank space for a future poke().\n\t * Warning: this has nothing to do with the semantics of reserve() in std::vector!\n\t */\n\tsint32\t\t\treserve( uint len )\n\t{\n\t\tsint32 pos = sint32(_Buffer.Pos);\n\t\tif ( ! isReading() )\n\t\t{\n\t\t\tincreaseBufferIfNecessary( len );\n\t\t\t_Buffer.Pos += len;\n\t\t}\n\t\treturn pos;\n\t}\n\n\t/**\n\t * When writing, fill a value previously reserved by reserve()\n\t * (warning: you MUST have called reserve() with sizeof(T) before poking).\n\t * Usually it's an alternative to use serialCont with a vector.\n\t * Example:\n\t *\t\tuint8 counter=0;\n\t *\t\tsint32 counterPos = msgout.reserve( sizeof(counter) );\n\t *\t\tcounter = serialSelectedItems( msgout );\n\t *\t\tmsgout.poke( counter, counterPos );\n\t */\n\ttemplate <class T>\n\tvoid\t\t\tpoke( T value, sint32 pos )\n\t{\n\t\tif ( ! isReading() )\n\t\t{\n\t\t\tuint8 *pokeBufPos = _Buffer.getBufferWrite().getPtr() + pos;\n\t\t\tnlassert( pokeBufPos + sizeof(T) <= pokeBufPos+_Buffer.Pos );\n\t\t\t*(T*)pokeBufPos = value;\n\t\t}\n\t}\n\n\t/// Clears the message\n\tvirtual void\tclear()\n\t{\n\t\tresetPtrTable();\n\t\t_Buffer.getBufferWrite().clear();\n\t\tif (!isReading())\n\t\t{\n\t\t\t_Buffer.getBufferWrite().resize (_DefaultCapacity);\n\t\t}\n\t\t_Buffer.Pos = 0;\n\t}\n\n\t/**\n\t * Returns the length (size) of the message, in bytes.\n\t * If isReading(), it is the number of bytes that can be read,\n\t * otherwise it is the number of bytes that have been written.\n\t */\n\tvirtual uint32\tlength() const\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treturn lengthR();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn lengthS();\n\t\t}\n\t}\n\n\t/// Returns the size of the buffer (can be greater than the length, especially in output mode)\n\tuint32\t\t\tsize() const\n\t{\n\t\treturn _Buffer.getBuffer().size();\n\t}\n\n\t/** Returns a pointer to the message buffer (read only)\n\t * Returns NULL if the buffer is empty\n\t */\n\tvirtual const uint8\t\t*buffer() const\n\t{\n\t\treturn _Buffer.getBuffer().getPtr();\n\t}\n\n\n\t/**\n\t * When you fill the buffer externaly (using bufferAsVector) you have to reset the BufPos calling this method\n\t *\n\t * If you are using the stream only in output mode, you can use this method as a faster version\n\t * of clear() *if you don't serialize pointers*.\n\t */\n\tvirtual void\t\tresetBufPos() { _Buffer.Pos = 0; }\n\n\t/**\n\t * Resize the message buffer and fill data at position 0.\n\t * Input stream: the current position is set at the beginning;\n\t * Output stream: the current position is set after the filled data.\n\t */\n\tvoid\t\t\tfill( const uint8 *srcbuf, uint32 len )\n\t{\n\t\tif (len == 0) return;\n\n\t\t_Buffer.getBufferWrite().resize( len );\n\t\tCFastMem::memcpy( _Buffer.getBufferWrite().getPtr(), srcbuf, len );\n\t\tif (isReading())\n\t\t{\n\t\t\t_Buffer.Pos = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_Buffer.Pos = _Buffer.getBuffer().size();\n\t\t}\n\t}\n\n\t/**\n\t * Resize the buffer.\n\t * Warning: the position is unchanged, only the size is changed.\n\t */\n\tvoid\t\t\tresize (uint32 size);\n\n\t/**\n\t * Resize the stream with the specified size, set the current position at the beginning\n\t * of the stream and return a pointer to the stream buffer.\n\t *\n\t * Precondition: the stream is an input stream.\n\t *\n\t * Suggested usage: construct an input stream, resize and get the buffer using bufferToFillAndRead(),\n\t * fill it with raw data using any filling function (warning: don't fill more than 'msgsize'\n\t * bytes!), then you are ready to read, using serial(), the data you've just filled.\n\t */\n\tvirtual uint8\t\t*bufferToFill( uint32 msgsize )\n\t{\n#ifdef NL_DEBUG\n\t\tnlassert( isReading() );\n#endif\n\t\tif ( msgsize == 0 )\n\t\t\treturn NULL;\n\n\t\t_Buffer.getBufferWrite().resize( msgsize );\n\t\t_Buffer.Pos = 0;\n\t\treturn _Buffer.getBufferWrite().getPtr();\n\t}\n\n\t/**\n\t * Transforms the message from input to output or from output to input\n\t *\n\t * Precondition:\n\t * - If the stream is in input mode, it must not be empty (nothing filled), otherwise the position\n\t *   will be set to the end of the preallocated buffer (see DefaultCapacity).\n\t * Postcondition:\n\t * - Read->write, the position is set at the end of the stream, it is possible to add more data\n\t - - Write->Read, the position is set at the beginning of the stream\n\t */\n\tvirtual void\tinvert()\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\t// In->Out: We want to write (serialize out) what we have read (serialized in)\n\t\t\tuint32 sizeOfReadStream = lengthR();\n\t\t\tresetPtrTable();\n\t\t\tsetInOut( false );\n\t\t\t_Buffer.Pos = sizeOfReadStream;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Out->In: We want to read (serialize in) what we have written (serialized out)\n\t\t\tresetPtrTable();\n\t\t\tsetInOut( true );\n\t\t\t// TODO : is it necessary ?\n\t\t\t_Buffer.getBufferWrite().resize (_Buffer.Pos);\n\t\t\t_Buffer.Pos = 0;\n\t\t}\n\t}\n\n\t/// Force to reset the ptr table\n\tvoid\t\t\tresetPtrTable() { IStream::resetPtrTable() ; }\n\n\t/// Increase the buffer size if 'len' can't enter, otherwise, do nothing\n#ifdef NL_OS_WINDOWS\n\t__forceinline\n#endif\n\tvoid\t\t\tincreaseBufferIfNecessary(uint32 len)\n\t{\n\t\tuint32 oldBufferSize = _Buffer.getBuffer().size();\n\t\tif (_Buffer.Pos + len > oldBufferSize)\n\t\t{\n\t\t\t// need to increase the buffer size\n\t\t\t_Buffer.getBufferWrite().resize(oldBufferSize*2 + len);\n\t\t}\n\t}\n\n\n\ttemplate <class T> void fastSerial (T &val)\n\t{\n#ifdef NL_LITTLE_ENDIAN\n\t\tif(isReading())\n\t\t{\n\t\t\t// Check that we don't read more than there is to read\n\t\t\tif ( lengthS()+sizeof(T) > length() ) // calls virtual length (cf. sub messages)\n\t\t\t\tthrow EStreamOverflow();\n\t\t\t// Serialize in\n\t\t\tval = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tincreaseBufferIfNecessary (sizeof(T));\n\t\t\t*(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = val;\n\t\t}\n\t\t_Buffer.Pos += sizeof (T);\n#else // NL_LITTLE_ENDIAN\n\t\tIStream::serial( val );\n#endif // NL_LITTLE_ENDIAN\n\t}\n\n\ttemplate <class T>\n\tvoid\t\t\tfastWrite( const T& value )\n\t{\n\t\t//nldebug( \"MEMSTREAM: Writing %u-byte value in %p at pos %u\", sizeof(value), this, _BufPos - _Buffer.getPtr() );\n\t\tincreaseBufferIfNecessary (sizeof(T));\n\t\t*(T*)(_Buffer.getBufferWrite().getPtr() + _Buffer.Pos) = value;\n\n\t\t_Buffer.Pos += sizeof (T);\n\t}\n\n\ttemplate <class T>\n\tvoid\t\t\tfastRead( T& value )\n\t{\n\t\t//nldebug( \"MEMSTREAM: Reading %u-byte value in %p at pos %u\", sizeof(value), this, _BufPos - _Buffer.getPtr() );\n\t\t// Check that we don't read more than there is to read\n\t\tif ( lengthS()+sizeof(value) > length() ) // calls virtual length (cf. sub messages)\n\t\t{\n\t\t\tthrow EStreamOverflow();\n\t\t}\n\t\t// Serialize in\n\t\tvalue = *(T*)(_Buffer.getBuffer().getPtr() + _Buffer.Pos);\n\t\t_Buffer.Pos += sizeof(value);\n\t}\n\n\n\t/// Template serialization (should take the one from IStream)\n    template<class T>\n\tvoid\t\t\tserial(T &obj) \t\t\t\t{ obj.serial(*this); }\n\n\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::vector<T> &cont) \t\t{IStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::list<T> &cont) \t\t\t{IStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::deque<T> &cont) \t\t{IStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::set<T> &cont) \t\t\t{IStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::multiset<T> &cont) \t\t{IStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::map<K, T> &cont) \t\t{IStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::multimap<K, T> &cont) \t{IStream::serialCont(cont);}\n\t/// Specialisation of serialCont() for vector<uint8>\n\tvirtual void\t\t\tserialCont(std::vector<uint8> &cont) {IStream::serialCont(cont);}\n\t/// Specialisation of serialCont() for vector<sint8>\n\tvirtual void\t\t\tserialCont(std::vector<sint8> &cont) {IStream::serialCont(cont);}\n\t/// Specialisation of serialCont() for vector<bool>\n\tvirtual void\t\t\tserialCont(std::vector<bool> &cont) {IStream::serialCont(cont);}\n\n\n\n\ttemplate<class T0,class T1>\n\tvoid\t\t\tserial(T0 &a, T1 &b)\n\t{ serial(a); serial(b);}\n\ttemplate<class T0,class T1,class T2>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c)\n\t{ serial(a); serial(b); serial(c);}\n\ttemplate<class T0,class T1,class T2,class T3>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d)\n\t{ serial(a); serial(b); serial(c); serial(d);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4,class T5>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}\n\n\t/** \\name Base types serialisation, redefined for string mode\n\t * Those method are a specialisation of template method \"void serial(T&)\".\n\t */\n\t//@{\n\tvirtual void\tserial(uint8 &b) ;\n\tvirtual void\tserial(sint8 &b) ;\n\tvirtual void\tserial(uint16 &b) ;\n\tvirtual void\tserial(sint16 &b) ;\n\tvirtual void\tserial(uint32 &b) ;\n\tvirtual void\tserial(sint32 &b) ;\n\tvirtual void\tserial(uint64 &b) ;\n\tvirtual void\tserial(sint64 &b) ;\n\tvirtual void\tserial(float &b) ;\n\tvirtual void\tserial(double &b) ;\n\tvirtual void\tserial(bool &b) ;\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b) ;\n#endif\n\tvirtual void\tserial(std::string &b) ;\n\tvirtual void\tserial(ucstring &b) ;\n\tvirtual void    serial(google::protobuf::Message* message);\n\t//@}\n\n\n\t///\\name String-specific methods\n\t//@{\n\n\t/// Input: read len bytes at most from the stream until the next separator, and return the number of bytes read. The separator is then skipped.\n\tuint\t\t\tserialSeparatedBufferIn( uint8 *buf, uint len );\n\n\t/// Output: writes len bytes from buf into the stream\n\tvoid\t\t\tserialSeparatedBufferOut( uint8 *buf, uint len );\n\n\t/// Serialisation in hexadecimal\n\tvirtual void\tserialHex(uint32 &b);\n\n\t//@}\n\nprotected:\n\n\t/// Returns the serialized length (number of bytes written or read)\n\tvirtual uint32\t\t\tlengthS() const\n\t{\n\t\treturn _Buffer.Pos; // not calling getPos() because virtual and not const!\n\t}\n\n\t/**\n\t * Returns the \"read\" message size (number of bytes to read)\n\t * Do not use directly, use length() instead in reading mode (which is virtual)\n\t */\n\tuint32\t\t\tlengthR() const\n\t{\n\t\treturn size();\n\t}\n\n\t/** Get the size for this stream. return 0 by default. Only implemented for input stream that know their size.\n\t *\tUsed internally to detect OverFlow with vector<> for instance\n\t */\n\tvirtual uint\t\t\tgetDbgStreamSize() const;\n\n\tCMemStreamBuffer\t\t\t_Buffer;\n\n\tmutable\tbool\t\t\t\t_StringMode;\n\n\tuint32\t\t\t\t\t\t_DefaultCapacity;\n};\n\n// Input\n#define readnumber(dest,thetype,digits,convfunc) \\\n\tchar number_as_cstring [digits+1]; \\\n\tuint realdigits = serialSeparatedBufferIn( (uint8*)number_as_cstring, digits ); \\\n\tnumber_as_cstring[realdigits] = '\\0'; \\\n\tdest = (thetype)convfunc( number_as_cstring );\n\n// Output\n#define writenumber(src,format,digits) \\\n\tchar number_as_cstring [digits+1]; \\\n\tsprintf( number_as_cstring, format, src ); \\\n\tserialSeparatedBufferOut( (uint8*)number_as_cstring, (uint)strlen(number_as_cstring) );\n\n/*\n * atoihex\n */\ninline uint32 atoihex( const char* ident )\n{\n\tuint32 number;\n\tsscanf( ident, \"%x\", &number );\n\treturn number;\n}\n\ninline uint32 atoui( const char *ident)\n{\n\treturn (uint32) strtoul (ident, NULL, 10);\n}\n\nstatic const char SEPARATOR = ' ';\nstatic const int SEP_SIZE = 1; // the code is easier to read with that\n\n//\n// inline serial functions\n//\n\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(uint8 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, uint8, 3, atoi ); // 255\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( (uint16)b,\"%hu\", 3 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(sint8 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, sint8, 4, atoi ); // -128\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( (sint16)b, \"%hd\", 4 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(uint16 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\t// No byte swapping in text mode\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, uint16, 5, atoi ); // 65535\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%hu\", 5 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(sint16 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, sint16, 6, atoi ); // -32768\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%hd\", 6 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(uint32 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, uint32, 10, atoui ); // 4294967295\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%u\", 10 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(sint32 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, sint32, 11, atoi ); // -2147483648\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%d\", 11 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(uint64 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, uint64, 20, atoiInt64 ); // 18446744073709551615\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%\" NL_I64 \"u\", 20 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(sint64 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, sint64, 20, atoiInt64 ); // -9223372036854775808\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%\" NL_I64 \"d\", 20 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(float &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, float, 128, atof ); // ?\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( (double)b, \"%f\", 128 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(double &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, double, 128, atof ); //\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%f\", 128 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(bool &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tserialBit(b);\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n\n\n#ifndef NL_OS_CYGWIN\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(char &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tchar buff [2];\n\t\tif ( isReading() )\n\t\t{\n\t\t\tserialBuffer( (uint8*)buff, 2 );\n\t\t\tb = buff[0];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbuff[0] = b;\n\t\t\tbuff[1] = SEPARATOR;\n\t\t\tserialBuffer( (uint8*)buff, 2 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tfastSerial (b);\n\t}\n}\n#endif\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(std::string &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tuint32\tlen=0;\n\t\t// Read/Write the length.\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcheckStreamSize((uint)len);\n\t\t\t/*if (len>1000000)\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"CMemStream/str: Trying to read a string of %u bytes\", len );\n\t\t\t*/\n\t\t\tb.resize(len);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (uint32)b.size();\n\t\t\tif (len>1000000)\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"CMemStream/str: Trying to write a string of %u bytes\", len );\n\t\t\tserial(len);\n\t\t}\n\n\t\t// Read/Write the string.\n\t\tfor(uint i=0;i!=len;++i)\n\t\t\tserialBuffer( (uint8*)&(b[i]), sizeof(b[i]) );\n\n\t\tchar sep = SEPARATOR;\n\t\tserialBuffer( (uint8*)&sep, 1 );\n\t}\n\telse\n\t{\n\t\tif (isReading())\n\t\t{\n\t\t\tif (!isXML())\n\t\t\t{\n\t\t\t\tuint32\tlen=0;\n\t\t\t\tfastSerial(len);\n\t\t\t\tcheckStreamSize((uint)len);\n\t\t\t\t/*\n\t\t\t\tif (len>1000000)\n\t\t\t\t\tthrow NLMISC::EInvalidDataStream( \"CMemStream: Trying to read a string of %u bytes\", len );\n\t\t\t\t*/\n\t\t\t\tb.resize(len);\n\t\t\t\tif (len > 0)\n\t\t\t\t{\n\t\t\t\t\t// can serial all in a single call to serialBuffer, since sizeof(char) == 1\n\t\t\t\t\tserialBuffer((uint8 *) &b[0], len);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tIStream::serial( b );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIStream::serial( b );\n\t\t}\n\t}\n}\n\n\n// ======================================================================================================\ninline\tvoid\t\tCMemStream::serial(ucstring &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tuint32\tlen=0;\n\t\t// Read/Write the length.\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcheckStreamSize((uint)len);\n\t\t\t/*\n\t\t\tif (len>1000000)\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"CMemStream/str: Trying to read an ucstring of %u bytes\", len );\n\t\t\t*/\n\t\t\tb.resize(len);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (uint32)b.size();\n\t\t\tif (len>1000000)\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"CMemStream/str: Trying to write an ucstring of %u bytes\", len );\n\t\t\tserial(len);\n\t\t}\n\t\t// Read/Write the string.\n\t\tfor(uint i=0;i!=len;++i)\n\t\t\tserialBuffer( (uint8*)&b[i], sizeof(b[i]) );\n\n\t\tchar sep = SEPARATOR;\n\t\tserialBuffer( (uint8*)&sep, 1 );\n\t}\n\telse\n\t{\n\t\tIStream::serial( b );\n\t}\n}\n\n\n\n/*\n * Serialisation in hexadecimal\n */\ninline\tvoid\tCMemStream::serialHex(uint32 &b)\n{\n\tif ( _StringMode )\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treadnumber( b, uint32, 10, atoihex ); // 4294967295\n\t\t}\n\t\telse\n\t\t{\n\t\t\twritenumber( b, \"%x\", 10 );\n\t\t}\n\t}\n\telse\n\t{\n\t\tIStream::serial( b );\n\t}\n}\n\ninline\tvoid\tCMemStream::serial( google::protobuf::Message* message )\n{\n\tif ( message==NULL )\n\t{\n\t\tthrow EInvalidDataStream();\n\t}\n\t\n\tif ( stringMode() )\n\t{\n\t\t//nlassert(0);\n        throw EInvalidDataStream();\n\t}\n\telse\n\t{\n\t\tstd::string str_buff;\n\t\tif (isReading())\n\t\t{\n\t\t\tserial(str_buff);\n\t\t\tif( !message->ParseFromString(str_buff) )\n\t\t\t{\n\t\t\t\tthrow EInvalidDataStream();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( !message->SerializeToString(&str_buff) )\n\t\t\t{\n\t\t\t\tthrow EInvalidDataStream();\n\t\t\t}\n\t\t\tserial(str_buff);\n\t\t}\n\t}\n}\n\n\n}\n\n#endif // NL_MEM_STREAM_H\n\n/* End of mem_stream.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/mouse_device.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MOUSE_DEVICE_H\n#define NL_MOUSE_DEVICE_H\n\n#include \"types_nl.h\"\n#include \"input_device.h\"\n\n\n\nnamespace NLMISC\n{\n\nclass CRect;\n\n/// An interface to a low level mouse device\nstruct IMouseDevice : public IInputDevice\n{\n\tenum TAxisMode { Raw, Clamped, AxisModeLast };\n\tenum TAxis\t{ XAxis = 0, YAxis = 1, AxisLast };\n\tenum TMessageMode { NormalMode, RawMode, MessageModeLast };\n\n\t///\\name Messages\n\t//@{\n\t\t/** Tells what messages should be sent :\n\t\t  * DEFAULT is 'raw' messages\n\t\t  * Raw messages : - no clamping nor frames applied\n\t\t  *                - no speed applied\n\t\t  *\t\t\t\t   - no factor applied\n\t\t  *                - CGDMouseMove messages are sent\n\t\t  *\t\t\t\t   - Move expressed in mickeys\n\t\t  * Normal messages : - CEventMouseMove messages are sent\n\t\t  *\t\t\t\t\t  - A frame may clamp one or both axis\n\t\t  *                   - The mouse speed can be changed\n\t\t  */\n\t\tvirtual\tvoid\t\t\t\t\tsetMessagesMode(TMessageMode mode) = 0;\n\t\t/// retrieve what kinds of messages are sent\n\t\tvirtual TMessageMode\t\t\tgetMessagesMode() const = 0;\n\t//@}\n\n\t///\\name Mouse MOVE, valid only\n\t//@{\n\t\t/** Set the mode of axis of the mouse. This can be raw, or clamped. In clamped mode, a frame is used to limit the move.\n\t\t  * NB : invalid in raw message mode\n\t\t  * \\see setMouseFrame(const CRect &rect)\n\t\t  */\n\t\tvirtual void\t\t\t\t\tsetMouseMode(TAxis axis, TAxisMode axisMode) = 0;\n\t\t/** returns the mode of the mouse for the given axis.\n\t\t  * NB : invalid in raw message mode\n\t\t  */\n\t\tvirtual TAxisMode\t\t\t\tgetMouseMode(TAxis axis) const  = 0;\n\t\t/** Set the mouse speed. It must be in the ]0, +inf] range, 1 gives the natural mouse speed.\n\t\t  * NB : invalid in raw message mode\n\t\t  */\n\t\tvirtual void\t\t\t\t\tsetMouseSpeed(float speed)  = 0;\n\t\t/** Get the mouse speed.\n\t\t  * NB : invalid in raw message mode\n\t\t  */\n\t\tvirtual float\t\t\t\t\tgetMouseSpeed() const  = 0;\n\t\t/** Set the mouse acceleration. It is the threshold in mickey, when start the acceleration. 0 means not acceleration.\n\t\t  */\n\t\tvirtual void\t\t\t\t\tsetMouseAcceleration(uint speed)  = 0;\n\t\t/** Get the mouse acceleration.\n\t\t  */\n\t\tvirtual uint\t\t\t\t\tgetMouseAcceleration() const  = 0;\n\t\t/** Set the current frame in which the mouse can move, expressed in pixels.\n\t\t  * NB do not forget to call setMouseFactors if you want the results to be reported in the 0-1 range.\n  \t\t  * NB : invalid in raw message mode.\n\t\t  * \\see setMouseFactors\n\t\t  */\n\t\tvirtual void\t\t\t\t\tsetMouseFrame(const CRect &rect)  = 0;\n\t\t/** Gives factor by which the mouse coordinates must be multiplied before an event is sent.\n\t\t  * The default factor is 1.\n  \t\t  * NB : invalid in raw message mode.\n\t\t  *\n\t\t  * Example : this set a frame of 800x600 and reports event in the [0, 1] range.\n\t\t  * \\code\n\t\t  * mouse->setMouseFrame(800, 600);\n\t\t  * mouse->setMouseMode(XAxis, IMouseDevice::Clamped);\n\t\t  * mouse->setMouseMode(YAxis, IMouseDevice::Clamped);\n\t\t  * mouse->setFactors(1.f / 800, 1.f / 600);\n\t\t  * \\endcode\n\t\t  */\n\t\tvirtual void\t\t\t\t\tsetFactors(float xFactor, float yFactor) = 0;\n\t\t/** Get the x factor, use to multiply the mouse position before an event is sent.\n\t\t  * NB : invalid in raw message mode.\n\t\t  * \\see setFactors()\n\t\t  */\n\t\tvirtual float\t\t\t\t\tgetXFactor() const = 0;\n\t\t/** Get the y factor, use to multiply the mouse position before an event is sent.\n\t\t  * NB : invalid in raw message mode.\n\t\t  * \\see setFactors()\n\t\t  */\n\t\tvirtual float\t\t\t\t\tgetYFactor() const = 0;\n\t//@}\n\n\t// Get the current frame used for limiting mouse movements\n\tvirtual const CRect\t\t\t\t&getMouseFrame() const = 0;\n\t// Set the maximum delay for a double click to be taken in account (in ms).\n\tvirtual void\t\t\t\t\tsetDoubleClickDelay(uint ms) = 0;\n\t// Get the maximum delay for double click (in ms)\n\tvirtual uint\t\t\t\t\tgetDoubleClickDelay() const = 0;\n\t// Force the position of the mouse, expressed in pixels\n\tvirtual void\t\t\t\t\tsetMousePos(float x, float y) = 0;\n\n\t/// From a delta of a mouse position input (eg from CEventMouseMove), deduce delta in mickeys (eg: like received from a CGDMouseMove)\n\tvirtual void\t\t\t\t\tconvertStdMouseMoveInMickeys(float &dx, float &dy) const = 0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_MOUSE_DEVICE_H\n\n/* End of u_mouse_device.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/mouse_smoother.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MOUSE_SMOOTHER_H\n#define NL_MOUSE_SMOOTHER_H\n\n#include \"types_nl.h\"\n#include \"vector_2f.h\"\n\nnamespace NLMISC\n{\n\n/**\n * This smooth position of mouse using cubic splines.\n * The mouse is sampled at the given period. The higher the period, the smoother the movement.\n * However there is a delay of 2 * samplingPeriod between the user moving the mouse and the pointer reaching\n * the wanted position.\n *\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 1/2004\n */\nclass CMouseSmoother\n{\npublic:\n\t// create a mouse smoother with the given sampling period.\n\tCMouseSmoother(double samplingPeriod = 0.2);\n\t/** Change the sampling period. The longer it lasts, the more smooth the movement.\n\t  * NB : this reset the smoother\n\t  */\n\tvoid\t\t\t\tsetSamplingPeriod(double period);\n\t// Get the sampling period\n\tdouble\t\t\t\tgetSamplingPeriod() const { return _SamplingPeriod; }\n\t// Reset smoother. The next returned position will be the exact position of mouse (no smoothing with previous position is done)\n\tvoid\t\t\t\treset();\n\t// \\return trueif no sampling has occured since last resetor construction\n\tbool\t\t\t\tisReseted() const { return !_Init; }\n\t// Sample pos, and return smoothed position\n\tCVector2f\t\t\tsamplePos(const CVector2f &wantedPos, double date);\nprivate:\n\t// sample of mouse position\n\tclass CSample\n\t{\n\tpublic:\n\t\tdouble\t\t      Date;\n\t\tCVector2f\t\t  Pos;\n\tpublic:\n\t\t// default ctor\n\t\tCSample() {}\n\t\t// ctor with pos & date\n\t\tCSample(double date, const NLMISC::CVector2f &pos) : Date(date), Pos(pos)\n\t\t{\n\t\t}\n\t};\n\tdouble\t\t_SamplingPeriod;\n\tbool\t\t_Init;\n\t/** 4 samples are needed to compute smoothed position :\n\t  * Sample 0 & 2 are used to compute tangent at sample 1\n\t  * Sample 1 & 3 are used to compute tangent at sample 2\n\t  */\n\tCSample _Sample[4];\n};\n\n} // NLMISC\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/mutable_container.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MUTABLE_CONTAINER_H\n#define NL_MUTABLE_CONTAINER_H\n\nnamespace NLMISC\n{\n\t/** Container wrapper that allow read/write access to element stored in\n\t *\ta const container.\n\t *\tIn fact, the template only allow calling begin() and end() over\n\t *\ta const container.\n\t *\tThis prevent the user to change the structure of the container.\n\t *\tUsage :\n\t *\n\t *\t\tclass foo\n\t *\t\t{\n\t *\t\t\ttypedef TMutableContainer<vector<string> > TMyCont;\n\t *\t\t\tTMyCont\t_MyCont;\n\t *\n\t *\t\tpublic:\n\t *\t\t\t// return the container with mutable item content but const item list\n\t *\t\t\tconst TMyCont getContainer() const { return _MyCont; };\n\t *\t\t}\n\t *\n\t */\n\ttemplate <class BaseContainer>\n\tstruct TMutableContainer : public BaseContainer\n\t{\n\t\ttypename BaseContainer::iterator begin() const\n\t\t{\n\t\t\treturn const_cast<BaseContainer*>(static_cast<const BaseContainer*>(this))->begin();\n\t\t}\n\n\t\ttypename BaseContainer::iterator end() const\n\t\t{\n\t\t\treturn const_cast<BaseContainer*>(static_cast<const BaseContainer*>(this))->end();\n\t\t}\n\t};\n\n} // namespace NLMISC\n\n#endif // NL_MUTABLE_CONTAINER_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/mutex.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MUTEX_H\n#define NL_MUTEX_H\n\n#include \"types_nl.h\"\n#include \"time_nl.h\"\n#include \"common.h\"\n#include <map>\n\n#ifdef NL_OS_WINDOWS\n#\tifdef NL_NO_ASM\n#\t\tinclude <intrin.h>\n#\tendif\n#elif defined(NL_OS_UNIX)\n#\tinclude <pthread.h> // PThread\n#\tifdef NL_OS_MAC\n#\t\tinclude <dispatch/dispatch.h>\n#\telse\n#\t\tinclude <semaphore.h> // PThread POSIX semaphores\n#\tendif\n#\tinclude <unistd.h>\n#\tdefine __forceinline\n#\tifdef NL_OS_MAC\n#\t\tinclude <libkern/OSAtomic.h>\n#\tendif\n#endif // NL_OS_WINDOWS\n\n#undef MUTEX_DEBUG\n\n\nnamespace NLMISC {\n\n\n/*\n * This define must be disabled when sharing a mutex between several processes that can\n * have a different debug mode (because when __STL_DEBUG is on, sizeof(string) is twice\n * the common string size).\n */\n#define STORE_MUTEX_NAME\n\n#ifdef NL_OS_WINDOWS\n\t// By default on Windows, all mutex/synchronization use the CFair* class to avoid freeze problem.\n#\tdefine CMutex CFairMutex\n#\tdefine CSynchronized CFairSynchronized\n#else\n\t// On GNU/Linux and Mac, we use CUnfair* everwise it creates some strange deadlock during loading and after\n#\tdefine CMutex CUnfairMutex\n#\tdefine CSynchronized CUnfairSynchronized\n#endif\n\n\n/**\n * Classic mutex implementation (not necessarly fair)\n * Don't assume the mutex are recursive (ie don't call enter() several times\n * on the same mutex from the same thread without having called leave()) ;\n * and don't assume either the threads are woken-up in the same order as they\n * were put to sleep !\n *\n * Windows: uses Mutex, cannot be shared among processes.\n * Linux: uses PThread POSIX Mutex, cannot be shared among processes.\n *\n *\\code\n CUnfairMutex m;\n m.enter ();\n // do critical stuffs\n m.leave ();\n *\\endcode\n * \\author Vianney Lecroart, Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass CUnfairMutex\n{\npublic:\n\n\t/// Constructor\n\tCUnfairMutex();\n\tCUnfairMutex( const std::string &name );\n\n\t/// Destructor\n\t~CUnfairMutex();\n\n\t/// Enter the critical section\n\tvoid\tenter ();\n\n\t/// Leave the critical section\n\tvoid\tleave ();\n\nprivate:\n\n#ifdef NL_OS_WINDOWS\n\tvoid *_Mutex;\n#elif defined NL_OS_UNIX\n\tpthread_mutex_t mutex;\n#else\n#\terror \"No unfair mutex implementation for this OS\"\n#endif\n\n};\n\n\n// Inline assembler for gcc tutorial:\n// AT&T syntax:\n// - operands reversed,\n// - l after opcode replaces dword ptr,\n// - () instead of [],\n// - immediate values prefixed by $\n\n/*\n// Tested: works on multi-processor\n#ifdef HAVE_X86_64\n#\tdefine ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \\\n\t\t\t\"mov %1, %%rcx;\" \\\n\t\t\t\"mov $1, %%eax;\" \\\n\t\t\t\"xchg %%eax, (%%rcx);\" \\\n\t\t\t\"mov %%eax, %0\" \\\n\t\t\t: \"=m\" (result) \\\n\t\t\t: \"m\" (lockPtr) \\\n\t\t\t: \"eax\", \"rcx\", \"memory\" ); // force to use registers and memory\n#else\n#\tdefine ASM_ASWAP_FOR_GCC_XCHG __asm__ volatile( \\\n\t\t\t\"mov %1, %%ecx;\" \\\n\t\t\t\"mov $1, %%eax;\" \\\n\t\t\t\"xchg %%eax, (%%ecx);\" \\\n\t\t\t\"mov %%eax, %0\" \\\n\t\t\t: \"=m\" (result) \\\n\t\t\t: \"m\" (lockPtr) \\\n\t\t\t: \"eax\", \"ecx\", \"memory\" ); // force to use registers and memory\n#endif\n*/\n\n/*\n// Tested: does not work (at least on multi-processor)! (with or without 'lock' prefix)\n#define ASM_ASWAP_FOR_GCC_CMPXCHG __asm__ volatile( \\\n\t\t\t\"mov $1, %%edx;\" \\\n\t\t\t\"mov %1, %%ecx;\" \\\n\t\t\t\"mov (%%ecx), %%eax;\" \\\n\t\t\t\"1:nop;\" \\\n\t\t\t\"lock cmpxchgl %%edx, (%%ecx);\" \\\n\t\t\t\"jne 1b;\" \\\n\t\t\t\"mov %%eax, %0\" \\\n\t\t\t: \"=m\" (result) \\\n\t\t\t: \"m\" (lockPtr) \\\n\t\t\t: \"eax\", \"ecx\", \"edx\", \"memory\" ); // force to use registers and memory\n*/\n\n// Tested: does not work on hyper-threading processors!\n/*ASM_ASWAP_FOR_MSVC_CMPXCHG\n{\n\t__asm\n\t\t{\n\t\t\tmov edx,1\n\t\t\tmov ecx,l\n\t\t\tmov eax,[ecx]\ntest_again:\n\t\t\tnop\n\t\t\tcmpxchg     dword ptr [ecx],edx\n\t\t\tjne         test_again\n\t\t\tmov [result],eax\n\t\t}\n}*/\n\n\n/**\n * Fast mutex implementation (not fairly)\n * The mutex ARE NOT recursive (ie don't call enter() several times\n * on the same mutex from the same thread without having called leave()) ;\n * The threads ARE NOT woken-up in the same order as they were put to sleep.\n * The threads ARE NOT woken-up using signals but using Sleep().\n * This mutex works but is not optimal for multiprocessors because if the mutex is locked,\n * next enter will be sleeped without waiting a little.\n *\n * Implementation notes:\n *  - Implementated under WIN32\n *  - Other OS use CMutex\n *\n * Tested: OK on Windows and Linux single & multi-processor\n *\n *\\code\n CFastMutex m;\n m.enter ();\n // do critical stuffs\n m.leave ();\n *\\endcode\n * \\author Cyril 'Hulud' Corvazier\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2002, 2003\n */\n#if defined(__ppc__) && !defined(NL_OS_MAC) && (GCC_VERSION <= 40100)\n#\terror \"no CFastMutex implementation available, try to use GCC >4.0.1\"\n#endif\n\n\n#ifdef NL_OS_WINDOWS\n#pragma managed(push, off)\n#endif\n\nclass CFastMutex\n{\npublic:\n\n\t/// Constructor\n\tCFastMutex() : _Lock(0) {}\n\n\t/// Same as constructor, useful for init in a shared memory block\n\tvoid\tinit() volatile { _Lock = 0; }\n\n\t/// Atomic swap\n\t__forceinline static bool atomic_swap (volatile uint32 *lockPtr)\n\t{\n\t\tuint32 result;\n#ifdef NL_OS_WINDOWS\n#\tifdef NL_NO_ASM\n\t\tresult = _InterlockedExchange(reinterpret_cast<volatile long *>(lockPtr), 1);\n#\telse\n#\tifdef NL_DEBUG\n\t\t// Workaround for dumb inlining bug (returning of function goes into the choux): push/pop registers\n\t\t__asm\n\t\t{\n\t\t\tpush eax\n\t\t\tpush ecx\n\t\t\tmov ecx,lockPtr\n\t\t\tmov eax,1\n\t\t\txchg [ecx],eax\n\t\t\tmov [result],eax\n\t\t\tpop ecx\n\t\t\tpop eax\n\t\t}\n#\telse\n\t\t__asm\n\t\t{\n\t\t\tmov ecx,lockPtr\n\t\t\tmov eax,1\n\t\t\txchg [ecx],eax\n\t\t\tmov [result],eax\n\t\t}\n#\tendif // NL_DEBUG\n#\tendif // NL_NO_ASM\n#elif defined(NL_OS_MAC)\n\t\treturn OSAtomicCompareAndSwap32(0, 1, reinterpret_cast<volatile sint32 *>(lockPtr));\n#elif defined(NL_OS_UNIX)\n\t\t// GCC implements the same functionality using a builtin function\n\t\t// http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html\n\t\t// the macro below crashed on Mac OS X 10.6 in a 64bit build\n#\tif (GCC_VERSION > 40100)\n\t\t// return __sync_bool_compare_and_swap(lockPtr, 0, 1);\n\t\tresult = __sync_val_compare_and_swap(lockPtr, 0, 1);\n#   elif defined(NL_COMP_CLANG)\n        result = __sync_val_compare_and_swap(lockPtr, 0, 1);\n#\telse\n\t\tASM_ASWAP_FOR_GCC_XCHG\n#\tendif\n#endif // NL_OS_WINDOWS\n\t\treturn result != 0;\n\t}\n\n\t// Enter critical section\n\t__forceinline void enter () volatile\n\t{\n\t  //std::cout << \"Entering, Lock=\" << _Lock << std::endl;\n\t\tif (atomic_swap (&_Lock))\n\t\t{\n\t\t\t// First test\n\t\t\tuint i;\n\t\t\tfor (i = 0 ;; ++i)\n\t\t\t{\n\t\t\t\tuint wait_time = i + 6;\n\n\t\t\t\t// Increment wait time with a log function\n\t\t\t\tif (wait_time > 27)\n\t\t\t\t\twait_time = 27;\n\n\t\t\t\t// Sleep\n\t\t\t\tif (wait_time <= 20)\n\t\t\t\t\twait_time = 0;\n\t\t\t\telse\n\t\t\t\t\twait_time = 1 << (wait_time - 20);\n\n\t\t\t\tif (!atomic_swap (&_Lock))\n\t\t\t\t\tbreak;\n\n#ifdef NL_OS_WINDOWS\n\t\t\t\tnlSleep (wait_time);\n#else\n\t\t\t\t//std::cout <<  \"Sleeping i=\" << i << std::endl;\n\t\t\t\tusleep( wait_time*1000 );\n#endif\n\t\t\t}\n\t\t}\n\t}\n\n\t// Leave critical section\n\t__forceinline void leave () volatile\n\t{\n\t\t_Lock = 0;\n\t\t//std::cout << \"Leave\" << std::endl;\n\t}\n\nprivate:\n\tvolatile uint32\t_Lock;\n};\n\n\n/**\n * Fast mutex for multiprocessor implementation (not fairly).\n * Used for multiprocessor critical section synchronisation.\n * The mutex ARE NOT recursive (ie don't call enter() several times\n * on the same mutex from the same thread without having called leave()) ;\n * The threads use a spin system to wait a little time before be put to sleep.\n * It waits using CPU time.\n *\n * Implementation notes:\n *  - Implementated under WIN32\n *  - Other OS use CMutex\n *\n *\\code\n CFastMutexMP m;\n m.enter ();\n // do critical stuffs\n m.leave ();\n *\\endcode\n * \\author Cyril 'Hulud' Corvazier\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2002, 2003\n */\n#ifndef __ppc__\nclass CFastMutexMP\n{\npublic:\n\n\t/// Constructor\n\tCFastMutexMP() : _Lock(0) {}\n\n\t/// Same as constructor, useful for init in a shared memory block\n\tvoid\tinit() volatile { _Lock = 0; }\n\n\t// Enter critical section\n\t__forceinline void enter () volatile\n\t{\n\t  //std::cout << \"Entering, Lock=\" << _Lock << std::endl;\n\t\twhile (CFastMutex::atomic_swap (&_Lock))\n\t\t{\n\t\t\tstatic uint last = 0;\n\t\t\tstatic uint _max = 30;\n\t\t\tuint spinMax = _max;\n\t\t\tuint lastSpins = last;\n\t\t\tvolatile uint temp = 17;\n\t\t\tuint i;\n\t\t\tfor (i = 0; i < spinMax; ++i)\n\t\t\t{\n\t\t\t\tif (i < lastSpins/2 || _Lock)\n\t\t\t\t{\n\t\t\t\t\ttemp *= temp;\n\t\t\t\t\ttemp *= temp;\n\t\t\t\t\ttemp *= temp;\n\t\t\t\t\ttemp *= temp;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (!CFastMutex::atomic_swap(&_Lock))\n\t\t\t\t\t{\n\t\t\t\t\t\tlast = i;\n\t\t\t\t\t\t_max = 1000;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_max = 30;\n\n\t\t\t// First test\n\t\t\tfor (i = 0 ;; ++i)\n\t\t\t{\n\t\t\t\tuint wait_time = i + 6;\n\n\t\t\t\t// Increment wait time with a log function\n\t\t\t\tif (wait_time > 27)\n\t\t\t\t\twait_time = 27;\n\n\t\t\t\t// Sleep\n\t\t\t\tif (wait_time <= 20)\n\t\t\t\t\twait_time = 0;\n\t\t\t\telse\n\t\t\t\t\twait_time = 1 << (wait_time - 20);\n\n\t\t\t\tif (!CFastMutex::atomic_swap (&_Lock))\n\t\t\t\t\tbreak;\n\n#ifdef NL_OS_WINDOWS\n\t\t\t\tnlSleep (wait_time);\n#else\n\t\t\t\t//std::cout <<  \"Sleeping i=\" << i << std::endl;\n\t\t\t\tusleep( wait_time*1000 );\n#endif\n\t\t\t}\n\t\t}\n\t}\n\n\t// Leave critical section\n\t__forceinline void leave () volatile\n\t{\n\t\t_Lock = 0;\n\t\t//std::cout << \"Leave\" << std::endl;\n\t}\n\nprivate:\n\tvolatile uint32\t_Lock;\n};\n#endif\n\n\n/**\n * Windows: uses Mutex, the handle can't be shared among processes, but\n * the mutex still can be be shared by passing a common object name to\n * createByName() / createByKey(). Note: the mutex must be explicitely\n * destroyed by calling destroy().\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2002\n */\nclass CSharedMutex\n{\npublic:\n\n\t/// Constructor (does not create the mutex, see createByName()/createByKey())\n\tCSharedMutex();\n\n#ifdef NL_OS_WINDOWS\n\t/// Create or access an existing mutex (created by another process) with a specific object name. Returns false if it failed.\n\tbool\tcreateByName( const char *objectName );\n#else\n\t/// Create (with createNew to true) or access an existing mutex (created by another process) with a specific key. Returns false if it failed.\n\tbool\tcreateByKey( int key, bool createNew );\n#endif\n\n\t/// Destroy the mutex\n\tvoid\tdestroy();\n\n\t/// Enter the critical section\n\tvoid\tenter ();\n\n\t/// Leave the critical section\n\tvoid\tleave ();\n\nprivate:\n\n#ifdef NL_OS_WINDOWS\n\t/// The mutex handle\n\tvoid\t*_Mutex;\n#else\n\t/// The semaphore id\n\tint\t\t_SemId;\n#endif\n};\n\n\n\n#ifdef NL_OS_WINDOWS\n/**\n * Trick to avoid including <windows.h> !\n * winbase.h: typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;\n * The original RTL_CRITICAL_SECTION is in winnt.h.\n */\nstruct TNelRtlCriticalSection {\n\tvoid\t*DebugInfo;\n\tlong\t LockCount;\n\tlong\t RecursionCount;\n\tvoid\t*OwningThread;        // from the thread's ClientId->UniqueThread\n\tvoid\t*LockSemaphore;\n\tuint32\t SpinCount;\n};\n#endif // NL_OS_WINDOWS\n\n\n/**\n * Kind of \"fair\" mutex\n *\n * Windows: uses Critical Section, cannot be shared among processes\n * Linux: uses PThread (POSIX) semaphore, cannot be shared among processes\n *\n *\\code\n CUnfairMutex m;\n m.enter ();\n // do critical stuffs\n m.leave ();\n *\\endcode\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n *\n *\\code\n CFairMutex m;\n m.enter ();\n // do critical stuffs\n m.leave ();\n *\\endcode\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CFairMutex\n{\npublic:\n\n\t/// Constructor\n\tCFairMutex();\n\tCFairMutex(const std::string &name);\n\n\t/// Destructor\n\t~CFairMutex();\n\n\tvoid enter ();\n\tvoid leave ();\n\n#ifdef STORE_MUTEX_NAME\n\tstd::string Name;\n#endif\n\nprivate:\n\n#ifdef NL_OS_WINDOWS\n\tTNelRtlCriticalSection\t_Cs;\n#elif defined(NL_OS_MAC)\n\tdispatch_semaphore_t\t_Sem;\n#elif defined(NL_OS_UNIX)\n\tsem_t\t\t\t\t\t_Sem;\n#else\n#\terror \"No fair mutex implementation for this OS\"\n#endif\n\n\n#ifdef MUTEX_DEBUG\n\t// debug stuffs\n\tvoid debugCreateMutex();\n\tvoid debugBeginEnter();\n\tvoid debugEndEnter();\n\tvoid debugLeave();\n\tvoid debugDeleteMutex();\n#endif // MUTEX_DEBUG\n\n};\n\n\n/*\n * Debug info\n */\n#ifdef MUTEX_DEBUG\n\nstruct TMutexLocks\n{\n\tTMutexLocks(uint32 m=0) : TimeToEnter(0), TimeInMutex(0), Nb(0), WaitingMutex(0), MutexNum(m), ThreadHavingTheMutex(0xFFFFFFFF), Dead(false) {}\n\n\tuint32\t\tTimeToEnter;\t\t\t// cumulated time blocking on enter\n\tuint32\t\tTimeInMutex;\t\t\t// cumulated time between enter and leave\n\tuint32\t\tNb;\t\t\t\t\t\t// number of calls of enter\n\tuint32\t\tWaitingMutex;\t\t\t// number of thread that waiting this mutex\n\tsint32\t\tMutexNum;\t\t\t\t// identifying a mutex\n\tuint\t\tThreadHavingTheMutex;\t// thread id of the thread that is in this mutex (0xFFFFFFFF if no thread)\n\tbool\t\tDead;\t\t\t\t\t// True if the mutex is dead (deleted)\n\tstd::string\tMutexName;\t\t\t\t// Name of the mutex\n\n\tNLMISC::TTicks BeginEnter;\n\tNLMISC::TTicks EndEnter;\n};\n\n/// Inits the \"mutex debugging info system\"\nvoid initAcquireTimeMap();\n\n/// Gets the debugging info for all mutexes (call it evenly)\nstd::map<CMutex*,TMutexLocks>\tgetNewAcquireTimes();\n\n/// The number of created mutexes (does not take in account the destroyed mutexes)\nextern uint32 NbMutexes;\n\n#endif // MUTEX_DEBUG\n\n\n/**\n * This class ensure that the Value is accessed by only one thread. First you have to create a CSynchronized class with your type.\n * Then, if a thread want to modify or do anything on it, you create a CAccessor in a \\b sub \\b scope. You can modify the value\n * of the CUnfairSynchronized using the value() function \\b until the end of the scope. So you have to put the smaller scope as you can.\n *\n * Internally, this class uses a CUnfairMutex object (see CUnfairMutex for programming considerations).\n *\n *\\code\n // the value that you want to be thread safe.\n CUnfairSynchronized<int> val;\n { // create a new scope for the access\n   // get an access to the value\n   CUnfairSynchronized<int>::CAccessor acces(&val);\n   // now, you have a thread safe access until the end of the scope, so you can do whatever you want. for example, change the value\n   acces.value () = 10;\n } // end of the access\n *\\endcode\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\ntemplate <class T>\nclass CUnfairSynchronized\n{\npublic:\n\n\tCUnfairSynchronized (const std::string &name) : _Mutex(name) { }\n\n\t/**\n\t * This class give you a thread safe access to the CSynchronized Value. Look at the example in the CSynchronized.\n\t */\n\tclass CAccessor\n\t{\n\t\tCUnfairSynchronized<T> *Synchronized;\n\tpublic:\n\n\t\t/// get the mutex or wait\n\t\tCAccessor(CUnfairSynchronized<T> *cs)\n\t\t{\n\t\t\tSynchronized = cs;\n\t\t\tconst_cast<CMutex&>(Synchronized->_Mutex).enter();\n\t\t}\n\n\t\t/// release the mutex\n\t\t~CAccessor()\n\t\t{\n\t\t\tconst_cast<CMutex&>(Synchronized->_Mutex).leave();\n\t\t}\n\n\t\t/// access to the Value\n\t\tT &value()\n\t\t{\n\t\t\treturn const_cast<T&>(Synchronized->_Value);\n\t\t}\n\t};\n\nprivate:\n\n\tfriend class CUnfairSynchronized::CAccessor;\n\n\t/// The mutex of the synchronized value.\n\tvolatile CUnfairMutex\t_Mutex;\n\n\t/// The synchronized value.\n\tvolatile T\t\t\t\t_Value;\n};\n\n\n/**\n * This class is similar to CUnfairSynchronized, but it ensures that the threads\n * are woken-up in the same order as they were put to sleep.\n * Internally, it uses a CFairMutex object instead of a CUnfairMutex object.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate <class T>\nclass CFairSynchronized\n{\npublic:\n\n\tCFairSynchronized (const std::string &name) : _Cs(name) { }\n\n\t/**\n\t * This class give you a thread safe access to the CFairSynchronized Value. Look at the example in CSynchronized.\n\t */\n\tclass CAccessor\n\t{\n\t\tCFairSynchronized<T> *Synchronized;\n\tpublic:\n\n\t\t/// get the mutex or wait\n\t\tCAccessor(CFairSynchronized<T> *cs)\n\t\t{\n\t\t\tSynchronized = cs;\n\t\t\tconst_cast<CFairMutex&>(Synchronized->_Cs).enter();\n\t\t}\n\n\t\t/// release the mutex\n\t\t~CAccessor()\n\t\t{\n\t\t\tconst_cast<CFairMutex&>(Synchronized->_Cs).leave();\n\t\t}\n\n\t\t/// access to the Value\n\t\tT &value()\n\t\t{\n\t\t\treturn const_cast<T&>(Synchronized->_Value);\n\t\t}\n\t};\n\nprivate:\n\n\tfriend class CFairSynchronized::CAccessor;\n\n\t/// The mutex of the synchronized value.\n\tvolatile CFairMutex\t_Cs;\n\n\t/// The synchronized value.\n\tvolatile T\t\t\t_Value;\n};\n\n\n/** Helper class that allow easy usage of mutex to protect\n *\ta local block of code with an existing mutex.\n */\ntemplate <class TMutex=CMutex>\nclass CAutoMutex\n{\n\tTMutex\t&_Mutex;\n\n\t// forbeden copy or assignent\n\tCAutoMutex(const CAutoMutex &/* other */)\n\t{\n\t}\n\n\tCAutoMutex &operator = (const CAutoMutex &/* other */)\n\t{\n\t\treturn *this;\n\t}\n\npublic:\n\tCAutoMutex(TMutex &mutex)\n\t\t:\t_Mutex(mutex)\n\t{\n\t\t_Mutex.enter();\n\t}\n\n\t~CAutoMutex()\n\t{\n\t\t_Mutex.leave();\n\t}\n\n};\n\n} // NLMISC\n\n\n#endif // NL_MUTEX_H\n\n/* End of mutex.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/noise_value.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_NOISE_VALUE_H\n#define NL_NOISE_VALUE_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n#include \"stream.h\"\n#include \"rgba.h\"\n\n\nnamespace NLMISC\n{\n\n\n\n\n\n// ***************************************************************************\n/**\n * A class which generate noisy value, according to a position\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass\tCNoiseValue\n{\npublic:\n\tfloat\tAbs;\n\tfloat\tRand;\n\tfloat\tFrequency;\n\npublic:\n\t/// Default to 0, 1, 1.\n\tCNoiseValue();\n\tCNoiseValue(float abs, float rand, float freq);\n\n\t/** return Abs + Rand* noise(Pos*Frequency).  with noise() E [0..1].\n\t *\tWarning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd().\n\t */\n\tfloat\teval(const CVector &posInWorld) const;\n\n\t/** same as eval, but eval just one random level for noise() => act much more like a random.\n\t *\tWarning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd().\n\t */\n\tfloat\tevalOneLevelRandom(const CVector &posInWorld) const;\n\n\n\tvoid\tserial(IStream &f);\n\n// *******************\nprivate:\n\t/// pos scale is in [0..1]\n\tfloat\tnoise(const CVector &pos) const;\n\tfloat\tevalRandom(const CVector &pos) const;\n};\n\n\n// ***************************************************************************\n/**\n * A noisy color generator\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass\tCNoiseColorGradient\n{\npublic:\n\t/// Abs and Rand should be 0 and 1 here. If not, some colors may not be generated...\n\tCNoiseValue\t\t\t\t\tNoiseValue;\n\tstd::vector<CRGBAF>\tGradients;\n\n\npublic:\n\t/** Use NoiseValue to compute a PerlinNoise E [0..1], and peek in Gradients, with linear interpolation.\n\t *\tresult unmodified if no colors. If only one color, copied into result.\n\t *\tWarning! Use OptFastFloor()! So call must be enclosed with a OptFastFloorBegin()/OptFastFloorEnd().\n\t */\n\tvoid\teval(const CVector &posInWorld, CRGBAF &result) const;\n\n\tvoid\tserial(IStream &f);\n};\n\n\n\n} // NL3D\n\n\n#endif // NL_NOISE_VALUE_H\n\n/* End of noise_value.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/o_xml.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_O_XML_H\n#define NL_O_XML_H\n\n//#define NL_DONT_USE_EXTERNAL_CODE\n#undef NL_DONT_USE_EXTERNAL_CODE\n\n#ifndef NL_DONT_USE_EXTERNAL_CODE\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n\n// Include from libxml2\n#include <libxml/parser.h>\n\n\nnamespace NLMISC {\n\n\n/**\n * Output xml stream\n *\n * This class is an xml formated output stream.\n *\n * This stream use an internal stream to output final xml code.\n \\code\n\t// Check exceptions\n\ttry\n\t{\n\t\t// File stream\n\t\tCOFile file;\n\n\t\t// Open the file\n\t\tfile.open (\"output.xml\");\n\n\t\t// Create the XML stream\n\t\tCOXml output;\n\n\t\t// Init\n\t\tif (output.init (&file, \"1.0\"))\n\t\t{\n\t\t\t// Serial the class\n\t\t\tmyClass.serial (output);\n\n\t\t\t// Flush the stream, write all the output file\n\t\t\toutput.flush ();\n\t\t}\n\n\t\t// Close the file\n\t\tfile.close ();\n\t}\n \tcatch (const Exception &e)\n\t{\n\t}\n\\endcode\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass COXml : public IStream\n{\n\tfriend int xmlOutputWriteCallbackForNeL ( void *context, const char *buffer, int len );\n\tfriend int xmlOutputCloseCallbackForNeL ( void *context );\n\tfriend void xmlGenericErrorFuncWrite (void *ctx, const char *msg, ...);\npublic:\n\n\t/** Stream ctor\n\t  *\n\t  */\n\tCOXml ();\n\n\t/** Stream initialisation\n\t  *\n\t  * \\param stream is the stream the class will use to output xml code.\n\t  * this pointer is held by the class but won't be deleted.\n\t  * \\param version is the version to write in the XML header. Default is 1.0.\n\t  * \\return true if initialisation is successful, false if the stream passed is not an output stream.\n\t  */\n\tbool init (IStream *stream, const char *version=\"1.0\");\n\n\t/** Return the error string.\n\t  * if not empty, something wrong appends\n\t  */\n\tconst char *getErrorString () const;\n\n\t/** Default dstor\n\t  *\n\t  * Flush the stream.\n\t  */\n\tvirtual ~COXml ();\n\n\t/** Flush the stream.\n\t  *\n\t  * You can only flush the stream when all xmlPushBegin - xmlPop have been closed.\n\t  */\n\tvoid flush ();\n\n\t/** Get root XML document pointer\n\t  */\n\txmlDocPtr getDocument ();\n\n\t/** Return true if the string is valid to be stored in a XML property without modification.\n\t  */\n\tstatic bool\t\tisStringValidForProperties (const char *str);\n\nprivate:\n\n\t/// From IStream\n\tvirtual void\tserial(uint8 &b);\n\tvirtual void\tserial(sint8 &b);\n\tvirtual void\tserial(uint16 &b);\n\tvirtual void\tserial(sint16 &b);\n\tvirtual void\tserial(uint32 &b);\n\tvirtual void\tserial(sint32 &b);\n\tvirtual void\tserial(uint64 &b);\n\tvirtual void\tserial(sint64 &b);\n\tvirtual void\tserial(float &b);\n\tvirtual void\tserial(double &b);\n\tvirtual void\tserial(bool &b);\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b);\n#endif\n\tvirtual void\tserial(std::string &b);\n\tvirtual void\tserial(ucstring &b);\n\tvirtual void\tserialBuffer(uint8 *buf, uint len);\n\tvirtual void\tserialBit(bool &bit);\n\n\tvirtual bool\txmlPushBeginInternal (const char *nodeName);\n\tvirtual bool\txmlPushEndInternal ();\n\tvirtual bool\txmlPopInternal ();\n\tvirtual bool\txmlSetAttribInternal (const char *attribName);\n\tvirtual bool\txmlBreakLineInternal ();\n\tvirtual bool\txmlCommentInternal (const char *comment);\n\n\t// Internal functions\n\tvoid\t\t\tserialSeparatedBufferOut( const char *value );\n\tinline void\t\tflushContentString ();\n\n\t// Push mode\n\tbool\t\t\t_PushBegin;\n\n\t// Attribute defined\n\tbool\t\t\t_AttribPresent;\n\n\t// Attribute name\n\tstd::string\t\t_AttribName;\n\n\t// The internal stream\n\tIStream\t\t\t*_InternalStream;\n\n\t// Document pointer\n\txmlDocPtr\t\t_Document;\n\n\t// Document version\n\tstd::string\t\t_Version;\n\n\t// Current nodes\n\txmlNodePtr\t\t_CurrentNode;\n\n\t// Current content string\n\tstd::string\t\t_ContentString;\n\n\t// Error message\n\tstd::string\t\t_ErrorString;\n\n\t// System dependant structure for locale\n\tvoid*\t\t\t_Locale;\n};\n\n\n} // NLMISC\n\n#endif // NL_DONT_USE_EXTERNAL_CODE\n\n#endif // NL_O_XML_H\n\n/* End of o_xml.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/object_arena_allocator.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_OBJECT_ARENA_ALLOCATOR_H\n#define NL_OBJECT_ARENA_ALLOCATOR_H\n\n#include \"types_nl.h\"\n#include \"singleton.h\"\n\nnamespace NLMISC\n{\n\n\nclass CFixedSizeAllocator;\n\n/** An allocator that can allocate/release in O(1) for a finite number of possible blocks size (usually small)..\n  * For a given block size, a fixed size allocator is used.\n  * One possible use is with a family of class for which new and delete have been redefined at the top of the hierarchy\n  * (which the NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR macro does)\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  */\nclass CObjectArenaAllocator\n{\npublic:\n\t/** ctor\n\t  * \\param maxAllocSize maximum intended size of allocation.\n\t  */\n\tCObjectArenaAllocator(uint maxAllocSize, uint granularity = 4);\n\t// dtor\n\t~CObjectArenaAllocator();\n\t/** Allocate a block with the given size. 0 is an invalid size an will cause an assert.\n\t  * If the size is > to the max size given at init, the allocation will succeed, but will use the standard allocator.\n\t  */\n\tvoid *alloc(uint size);\n\t// free an object that has previously been allocated with alloc. size should be remembered by the caller.\n\tvoid free(void *);\n\t// get the number of allocated objects\n\tuint getNumAllocatedBlocks() const;\n#\tifdef NL_DEBUG\n\t\t// for debug, useful to catch memory leaks\n\t\tvoid dumpUnreleasedBlocks();\n\t\t// set a break for the given allocation\n\t\tvoid setBreakForAllocID(bool enabled, uint id);\n#\tendif\n\t// for convenience, a default allocator is available\n\tstatic CObjectArenaAllocator &getDefaultAllocator();\n\nprivate:\n\tstd::vector<CFixedSizeAllocator *> _ObjectSizeToAllocator;\n\tuint\t\t\t\t\t\t\t _MaxAllocSize;\n\tuint\t\t\t\t\t\t\t _Granularity;\n#\tifdef NL_DEBUG\n\t\tuint\t\t\t\t\t\t\t _AllocID;\n\t\tstd::map<void *, uint>\t\t\t _MemBlockToAllocID;\n\t\tbool\t\t\t\t\t\t\t _WantBreakOnAlloc;\n\t\tuint\t\t\t\t\t\t\t _BreakAllocID;\n#\tendif\n\tstatic CObjectArenaAllocator\t\t *_DefaultAllocator;\n};\n\n// Macro that redefines the new & delete operator of a class so that the default arena object allocator is used.\n// This should be used inside the definition of the class.\n// All derived class will use the same allocator, so this definition can be used only at the top of the hierarchy of class for\n// which it is of interest.\n//\n// NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR // for fast alloc\n#\tdefine NL_USES_DEFAULT_ARENA_OBJECT_ALLOCATOR \\\n\t\tvoid *operator new(size_t size) { return NLMISC::CObjectArenaAllocator::getDefaultAllocator().alloc((uint) size); }\\\n\t\tvoid operator delete(void *block) { NLMISC::CObjectArenaAllocator::getDefaultAllocator().free(block); }\n\n}\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/object_vector.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_OBJECT_VECTOR_H\n#define NL_OBJECT_VECTOR_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n#include \"stream.h\"\n#include \"debug.h\"\n\n// With NeL Memory Debug, use new\n#ifndef NL_USE_DEFAULT_MEMORY_MANAGER\n# ifndef NLMISC_HEAP_ALLOCATION_NDEBUG\n#  define NL_OV_USE_NEW_ALLOCATOR\n# endif // NLMISC_HEAP_ALLOCATION_NDEBUG\n#endif // NL_USE_DEFAULT_MEMORY_MANAGER\n\n#ifndef NL_OV_USE_NEW_ALLOCATOR\n# ifdef NL_HAS_SSE2\n#  define NL_OV_USE_NEW_ALLOCATOR\n# endif // NL_HAS_SSE2\n#endif // NL_OV_USE_NEW_ALLOCATOR\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\tException raised when a reallocation fails.\n *\n */\nstruct\tEReallocationFailed : public Exception\n{\n\tEReallocationFailed() : Exception( \"Can't reallocate memory\" ) {}\n};\n\n\n// ***************************************************************************\n/**\n * The purpose of this class is to copy most (but not all) of stl vector<> features, without\n *\tsome of the speed/memory problems involved:\n *\t\t- size of a vector<T> is 16 bytes typically. size of a CObjectVector is 8 bytes (only a ptr and a size).\n *\t\t- CObjectVector<T>::size() is faster than vector::size()\n *\t\t- CObjectVector<T>::resize() is faster because it do not copy from a default value, it just call the\n *\t\t\tdefault constructor of the objects.\n *\t\t- clear() actually free memory (no reserve scheme)\n *\n *\tObject contructors, destructors, operator= are correctly called, unless\n *\tEnableObjectBehavior template argument is set to false (default is true)\n *\tIn this case: ctor, dtor are not called, and operator=() use memcpy.\n *\n *\tOf course some features are not implemented (for benefit of speed/memory):\n *\t\t- no reserve() scheme\n *\n *\tAlso, for now, not all vector<> features are implemented (iterator, erase etc...).\n *\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate<class T, bool EnableObjectBehavior=true>\tclass CObjectVector\n{\npublic:\n\n\t/// \\name Object\n\t// @{\n\tCObjectVector()\n\t{\n\t\t_Ptr= NULL;\n\t\t_Size= 0;\n\t}\n\t~CObjectVector()\n\t{\n\t\tclear();\n\t}\n\t/** copy cons.\n\t *\t\\throw EReallocationFailed() if realloc fails.\n\t */\n\tCObjectVector(const CObjectVector &vec)\n\t{\n\t\t_Ptr= NULL;\n\t\t_Size= 0;\n\t\toperator=(vec);\n\t}\n\t/** copy the array.\n\t *\t\\throw EReallocationFailed() if realloc fails.\n\t */\n\tCObjectVector\t&operator=(const CObjectVector &vec)\n\t{\n\t\t// *this=*this mgt.\n\t\tif(this==&vec)\n\t\t\treturn *this;\n\t\t// resize to the same size as vec.\n\t\tresize(vec._Size);\n\t\t// copy All the array.\n\t\tcopy(0, _Size, vec._Ptr);\n\n\t\treturn *this;\n\t}\n\t// swap this vector content with another vector\n\tvoid swap(CObjectVector<T, EnableObjectBehavior> &other)\n\t{\n\t\tstd::swap(_Ptr, other._Ptr);\n\t\tstd::swap(_Size, other._Size);\n\t}\n\t// @}\n\n\n\t/// \\name Allocation\n\t// @{\n\n\t/** clear the array.\n\t */\n\tvoid\t\tclear()\n\t{\n\t\tdestruct(0, _Size);\n#ifndef NL_OV_USE_NEW_ALLOCATOR\n\t\tfree(_Ptr);\n#else // NL_OV_USE_NEW_ALLOCATOR\n\t\tif (_Ptr)\n\t\t\tdelete [] (char*)_Ptr;\n#endif // NL_OV_USE_NEW_ALLOCATOR\n\t\t_Ptr= NULL;\n\t\t_Size= 0;\n\t}\n\n\t/** resize the array.\n\t *\tIf reallocation occurs, ptr returned by getPtr() may not be the same.\n\t *\tWhen reallocation occurs, memory is coped, but operator= are not called.\n\t *\t\\throw EReallocationFailed() if realloc fails.\n\t */\n\tvoid\t\tresize(uint32 s)\n\t{\n\t\t// if same size, no-op.\n\t\tif(s==_Size)\n\t\t\treturn;\n\n\t\t// if empty, just clear.\n\t\tif(s==0)\n\t\t\tclear();\n\t\t// crop the array?\n\t\telse if(s<_Size)\n\t\t{\n\t\t\t// destruct the objects to be freed\n\t\t\tdestruct(s, _Size);\n\t\t\t// realloc\n\t\t\tmyRealloc(s);\n\t\t\t_Size = s;\n\t\t}\n\t\t// else, enlarge the array\n\t\telse\n\t\t{\n\t\t\t// realloc first\n\t\t\tmyRealloc(s);\n\t\t\t// For all new elements, construct them.\n\t\t\tconstruct(_Size, s);\n\t\t\t// change size.\n\t\t\t_Size= s;\n\t\t}\n\t}\n\n\t// @}\n\n\n\t/// \\name Accessor\n\t// @{\n\n\t/** return true if the container is empty\n\t */\n\tbool\t\tempty() const {return _Size==0;}\n\n\t/** return size of the array (in number of elements)\n\t */\n\tuint32\t\tsize() const {return _Size;}\n\n\t/** Element accessor. no check is made on index. (No exception, no nlassert())\n\t */\n\tconst T\t\t\t&operator[](uint index) const\n\t{\n\t\treturn _Ptr[index];\n\t}\n\t/** Element accessor. no check is made on index. (No exception, no nlassert())\n\t */\n\tT\t\t\t&operator[](uint index)\n\t{\n\t\treturn _Ptr[index];\n\t}\n\n\t/** return a ptr on the first element of the array. NULL if empty.\n\t */\n\tconst T\t\t*getPtr() const {return _Ptr;}\n\t/** return a ptr on the first element of the array. NULL if empty.\n\t */\n\tT\t\t\t*getPtr() {return _Ptr;}\n\n\t// @}\n\n\n\t/// \\name Tools\n\t// @{\n\n\t/** copy elements from an array ptr to this vector, beetween dstFirst element (included) and dstLast element (not included).\n\t *\tnlassert if last is too big. copy(y, x, ...) where y>=x is valid, and nothing is copied.\n\t */\n\tvoid\t\tcopy(uint32 dstFirst, uint32 dstLast, const T *srcPtr)\n\t{\n\t\t// test if something to copy.\n\t\tif(dstFirst>=dstLast)\n\t\t\treturn;\n\t\tnlassert(dstLast<=_Size);\n\t\t// if not object elements\n\t\tif(!EnableObjectBehavior)\n\t\t{\n\t\t\t// just memcpy\n\t\t\tmemcpy(_Ptr+dstFirst, srcPtr, (dstLast-dstFirst)*sizeof(T));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// call ope= for all elements.\n\t\t\tfor(uint i=dstFirst; i<dstLast; i++, srcPtr++)\n\t\t\t{\n\t\t\t\t_Ptr[i]= *srcPtr;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/** fill elements with a value, beetween dstFirst element (included) and dstLast element (not included).\n\t */\n\tvoid\t\tfill(uint32 dstFirst, uint32 dstLast, const T &value)\n\t{\n\t\t// test if something to copy.\n\t\tif(dstFirst>=dstLast)\n\t\t\treturn;\n\t\tnlassert(dstLast<=_Size);\n\t\t// call ope= for all elements.\n\t\tfor(uint i=dstFirst; i<dstLast; i++)\n\t\t{\n\t\t\t_Ptr[i]= value;\n\t\t}\n\t}\n\n\t/** fill all elements with a value\n\t */\n\tvoid\t\tfill(const T &value)\n\t{\n\t\t// call ope= for all elements.\n\t\tfor(uint i=0; i<_Size; i++)\n\t\t{\n\t\t\t_Ptr[i]= value;\n\t\t}\n\t}\n\n\n\n\t/** Serial this ObjectVector.\n\t *\tNB: actually, the serial of a vector<> and the serial of a CObjectVector is the same in the stream.\n\t */\n\tvoid\t\tserial(NLMISC::IStream &f)\n\t{\n\t\t// Open a node header\n\t\tf.xmlPushBegin (\"VECTOR\");\n\n\t\t// Attrib size\n\t\tf.xmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(f.isReading())\n\t\t{\n\t\t\tf.serial(len);\n\n\t\t\t// Open a node header\n\t\t\tf.xmlPushEnd ();\n\n\t\t\t// special version for vector: adjut good size.\n\t\t\tcontReset(*this);\n\t\t\tresize (len);\n\n\t\t\t// Read the vector\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\tf.xmlPush (\"ELM\");\n\n\t\t\t\tf.serial(_Ptr[i]);\n\n\t\t\t\tf.xmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= size();\n\t\t\tf.serial(len);\n\n\t\t\t// Close the node header\n\t\t\tf.xmlPushEnd ();\n\n\t\t\t// Write the vector\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\tf.xmlPush (\"ELM\");\n\n\t\t\t\tf.serial(_Ptr[i]);\n\n\t\t\t\tf.xmlPop ();\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\tf.xmlPop ();\n\t}\n\n\t// @}\n\n\n\n// *******************\nprivate:\n\n\t/// Ptr on our array.\n\tT\t\t\t\t*_Ptr;\n\t/// size of the array, in number of elements.\n\tuint32\t\t\t_Size;\n\n\nprivate:\n\t// realloc, and manage allocation failure. Don't modify _Size.\n\tvoid\tmyRealloc(uint32 s)\n\t{\n#ifndef NL_OV_USE_NEW_ALLOCATOR\n\t\t// try to realloc the array.\n\t\tT\t*newPtr= (T*)realloc(_Ptr, s*sizeof(T));\n#else // NL_OV_USE_NEW_ALLOCATOR\n\t\tuint allocSize= s*sizeof(T);\n\t\tT\t*newPtr= NULL;\n\t\tif (!_Ptr || (allocSize > _Size*sizeof(T)))\n\t\t{\n\t\t\t// Reallocate\n\t\t\tchar *newblock = new char[allocSize];\n\t\t\t// if success and need to copy\n\t\t\tif (newblock && _Ptr)\n\t\t\t{\n\t\t\t\tmemcpy (newblock, _Ptr, _Size*sizeof(T));\n\t\t\t\tdelete [] (char*)_Ptr;\n\t\t\t}\n\t\t\tnewPtr = (T*)newblock;\n\t\t}\n\t\telse if(allocSize < _Size*sizeof(T))\n\t\t{\n\t\t\t// Reallocate\n\t\t\tchar *newblock = new char[allocSize];\n\t\t\t// if success and need to copy\n\t\t\tif (newblock && _Ptr)\n\t\t\t{\n\t\t\t\tmemcpy (newblock, _Ptr, s*sizeof(T));\n\t\t\t\tdelete [] (char*)_Ptr;\n\t\t\t}\n\t\t\tnewPtr = (T*)newblock;\n\t\t}\n#endif // NL_OV_USE_NEW_ALLOCATOR\n\t\t// if realloc failure\n\t\tif(newPtr==NULL)\n\t\t{\n\t\t\t// leave the array unchanged.\n\t\t\t// exception.\n\t\t\tthrow EReallocationFailed();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_Ptr= newPtr;\n\t\t}\n\t}\n\n\t// For all elements in the range, destruct.\n\tvoid\tdestruct(uint32 i0, uint32 i1)\n\t{\n\t\t// don't do it if elements don't need it.\n\t\tif(!EnableObjectBehavior)\n\t\t\treturn;\n\t\t// for all elements\n\t\tfor(uint i=i0;i<i1;i++)\n\t\t{\n\t\t\t// call dtor.\n\t\t\t_Ptr[i].~T();\n\t\t}\n\t}\n\n\t// For all elements in the range, construct.\n\tvoid\tconstruct(uint32 i0, uint32 i1)\n\t{\n\t\t// don't do it if elements don't need it.\n\t\tif(!EnableObjectBehavior)\n\t\t\treturn;\n\t\t// for all elements\n\t\tfor(uint i=i0;i<i1;i++)\n\t\t{\n\t\t\t// call ctor.\n\t\t\tnew (_Ptr+i) T;\n\t\t}\n\t}\n\n};\n\n\n// ***************************************************************************\n// Explicit Specialisation of basic types which have no special ctor/dtor\n// ***************************************************************************\n\n/* This make faster Code in Debug (no change in release)\n*/\n\ntemplate<> class CObjectVector<uint8, true> : public CObjectVector<uint8, false>\n{\n};\ntemplate<> class CObjectVector<sint8, true> : public CObjectVector<sint8, false>\n{\n};\ntemplate<> class CObjectVector<uint16, true> : public CObjectVector<uint16, false>\n{\n};\ntemplate<> class CObjectVector<sint16, true> : public CObjectVector<sint16, false>\n{\n};\ntemplate<> class CObjectVector<uint32, true> : public CObjectVector<uint32, false>\n{\n};\ntemplate<> class CObjectVector<sint32, true> : public CObjectVector<sint32, false>\n{\n};\ntemplate<> class CObjectVector<uint64, true> : public CObjectVector<uint64, false>\n{\n};\ntemplate<> class CObjectVector<sint64, true> : public CObjectVector<sint64, false>\n{\n};\n#ifdef NL_COMP_VC6\ntemplate<> class CObjectVector<uint, true> : public CObjectVector<uint, false>\n{\n};\ntemplate<> class CObjectVector<sint, true> : public CObjectVector<sint, false>\n{\n};\n#endif // !NL_COMP_VC6\ntemplate<> class CObjectVector<float, true> : public CObjectVector<float, false>\n{\n};\ntemplate<> class CObjectVector<double, true> : public CObjectVector<double, false>\n{\n};\n\n\n} // NLMISC\n\n\n#endif // NL_OBJECT_VECTOR_H\n\n/* End of object_vector.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/p_thread.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_P_THREAD_H\n#define NL_P_THREAD_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_UNIX\n\n#include \"thread.h\"\n#include <pthread.h>\n\n\nnamespace NLMISC {\n\n\n/**\n * Posix Thread\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CPThread : public IThread\n{\npublic:\n\tenum TThreadState\n\t{\n\t\tThreadStateNone,\n\t\tThreadStateRunning,\n\t\tThreadStateFinished,\n\t};\n\n\t/// Constructor\n\tCPThread( IRunnable *runnable, uint32 stackSize);\n\n\tvirtual ~CPThread();\n\n\tvirtual void start();\n\tvirtual bool isRunning();\n\tvirtual void terminate();\n\tvirtual void wait();\n\tvirtual bool setCPUMask(uint64 cpuMask);\n\tvirtual uint64 getCPUMask();\n\tvirtual void setPriority(TThreadPriority priority);\n\tvirtual std::string getUserName();\n\n\tvirtual IRunnable *getRunnable()\n\t{\n\t\treturn Runnable;\n\t}\n\n\t/// Internal use\n\tIRunnable\t*Runnable;\n\n\tTThreadState\t_State;\n\tpthread_t\t_ThreadHandle;\n\nprivate:\n\tuint32\t\t_StackSize;\n};\n\n/**\n * Posix Process\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CPProcess : public IProcess\n{\npublic:\n\tvirtual ~CPProcess() {}\n\tvirtual uint64 getCPUMask();\n\tvirtual bool setCPUMask(uint64 mask);\n};\n\n} // NLMISC\n\n\n#endif // NL_OS_UNIX\n\n#endif // NL_P_THREAD_H\n\n/* End of p_thread.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/path.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PATH_H\n#define NL_PATH_H\n\n#include \"types_nl.h\"\n#include \"time_nl.h\"\n#include \"common.h\"\n#include \"string_mapper.h\"\n\n#include <map>\n#include <string>\n#include <vector>\n\nnamespace NLMISC {\n\n/// Exception throw when a find is not found in a lookup() call\nstruct EPathNotFound : public Exception\n{\n\tEPathNotFound (const std::string& filename) : Exception (\"Path not found for \" + filename) { }\n};\n\n/** Utility to store a pre-built list of file, bnp and xml_pack\n *\tUsed by CPath to store the default application patch.\n *\tCan be used by user to build a custom set of file.\n * \\warning addSearchPath(), clearMap() and remapExtension() are not reentrant.\n * \\warning all path and files are *case sensitive* on linux.\n */\nclass CFileContainer\n{\n\t// no copy allowed\n\tCFileContainer(const CFileContainer &/* other */)\n\t{}\n\n\tCFileContainer &operator =(const CFileContainer &/* other */)\n\t{\n\t\treturn *this;\n\t}\n\npublic:\n\tCFileContainer()\n\t{\n\t\t_MemoryCompressed = false;\n\t\t_AllFileNames = NULL;\n\t}\n\n\t~CFileContainer();\n\n\n\tvoid\t\t\taddSearchPath (const std::string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack = NULL);\n\n\t/** Used only for compatibility with the old CPath. In this case, we don't use the map to have the same behavior as the old CPath */\n\tvoid\t\t\taddSearchPath (const std::string &path) { addSearchPath (path, false, true, NULL); }\n\n\t/** Same as AddSearchPath but with a file \"c:/autoexec.bat\" this file only will included. wildwards *doesn't* work */\n\tvoid\t\t\taddSearchFile (const std::string &file, bool remap = false, const std::string &virtual_ext = \"\", class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Same as AddSearchPath but with a path file \"c:/test.pth\" all files name contain in this file will be included (the extention is used to know that it's a path file) */\n\tvoid\t\t\taddSearchListFile (const std::string &filename, bool recurse, bool alternative);\n\n\t/** Same as AddSearchPath but with a big file \"c:/test.nbf\" all files name contained in the big file will be included  (the extention (Nel Big File) is used to know that it's a big file) */\n\tvoid\t\t\taddSearchBigFile (const std::string &filename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Same as AddSearchPath but with a xml pack file \"c:/test.xml_pack\" all files name contained in the xml pack will be included   */\n\tvoid\t\t\taddSearchXmlpackFile (const std::string &sXmlpackFilename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Remove all search path contains in the alternative directories */\n\tvoid\t\t\tremoveAllAlternativeSearchPath ();\n\n\t// Remove a set of big file from the search paths (and also from CBigFile)\n\tvoid\t\t\tremoveBigFiles(const std::vector<std::string> &bnpFilenames);\n\n\t/** Returns the long name (path + filename) for the specified file.\n\t * The directory separator is always '/'.\n\t * First, the lookup() lookups in standard directories (Alternative=false).\n\t * If not found, it lookups in the Alternative directories.\n\t * If not found the lookup() returns empty string \"\" (and generate an exception if throwException is true)\n\t *\n\t * The filename is not case sensitive so if the real filename is \"FooBAR.Jpg\" and you call lookup(\"fOOBar.jPg\"), it'll\n\t * return the real filename \"FooBAR.Jpg\"\n\t *\n\t * \\param filename the file name you are seeking. (ex: \"test.txt\")\n\t * \\param throwException used for backward compatibility, set to true to generate an EPathNotFound.\n\t * \\param displayWarning set to false if you don't want the function displays a warning if the file is not found\n\t * \\param lookupInLocalDirectory if true, the lookup() will first try to open the file without path.\n\t * \\return empty string if file is not found or the full path + file name (ex: \"c:/temp/test.txt\");\n\t *\n\t * ***********************************************\n\t *\tWARNING: This Method is NOT thread safe\n\t *\tuser must ensure that no mutator is called on CPath while async loading\n\t * ***********************************************\n\t *\n\t */\n\tstd::string\tlookup (const std::string &filename, bool throwException = true, bool displayWarning = true, bool lookupInLocalDirectory = true);\n\n\t/** Return if a file is present in the lookup map.\n\t * The function changes filename into lower case and removes ended spaces before searching.\n\t *\n\t * \\warning This function checks *only* in the map, not in local dir or alternative dir\n\t *\n\t * \\param filename the file name you are seeking. (ex: \"test.txt\")\n\t * \\param lookupInLocalDirectory if true, the lookup() will first try to open the file without path.\n\t * \\return true if the filename exists in the map used by lookup to know where the file is, false otherwise\n\t */\n\tbool\t\t\texists (const std::string &filename);\n\n\n\t/** Clears the map that contains all cached files (Use this function to take into account new files).\n\t */\n\tvoid clearMap ();\n\n\t/** Add a remapping function to allow file extension substitution.\n\t * - eg remapExtension(\"dds\", \"tga\", true) Where the boolean indicates whether\n\t * the \"dds\" should replace a \"tga\" if one exists - again - a warning should\n\t * be generated if the two are present.\n\t *\n\t * ie: If you have a file called pic.dds and you call remapExtension(\"dds\", \"tga\", true),\n\t *     if you call lookup(\"pic.tga\"), it'll return \"pic.dds\"\n\t *\n\t */\n\tvoid remapExtension (const std::string &ext1, const std::string &ext2, bool substitute);\n\n\t/** Add file remapping\n\t * ie: If you have a file called pic.dds, and call remapFile(\"picture.dds\", \"pic.dds\")\n\t * calling lookup(\"picture.dds\") will in fact call lookup(\"pic.dds\")\n\t */\n\tvoid remapFile (const std::string &file1, const std::string &file2);\n\n\t/** Load a file containing the remapped file (you must have done addsearchpath, this method use lookup)\n\t * Format is remapped_name_file, real_file\n\t * separators are , and \\n\n\t */\n\tvoid loadRemappedFiles (const std::string &file);\n\n\tvoid display ();\n\n\t/**\tTake a path and put it in the portable format and add a terminated / if needed\n\t * ie: \"C:\\\\Game/dir1\" will become \"C:/Game/dir1/\" or \"C:/Game/dir1\" if addFinalSlash is false\n\t */\n\tstd::string\tstandardizePath (const std::string &path, bool addFinalSlash = true);\n\n\t/**\tReplace / with \\ for dos process. Use only this function if can't do another way.\n\t * For example, if you do a system(\"copy data/toto data/tata\"); it'll not work because dos doesn't\n\t * understand /.\n\t * But in the majority of case, / working (it works for fopen for example)\n\t */\n\tstd::string\tstandardizeDosPath (const std::string &path);\n\n\n\t/** List all files in a directory.\n\t *\t\\param path path where files are scanned. No-op if empty\n\t *\t\\param recurse true if want to recurs directories\n\t *\t\\param wantDir true if want to add directories in result\n\t *\t\\param wantFile true if want to add files in result\n\t *\t\\param result list of string where directories/files names are added.\n\t *  \\param progressCallBack is a progression callback interface pointer.\n\t *  \\param showEverything false skips *.log files and CVS directories\n\t */\n\tvoid\t\t\tgetPathContent (const std::string &path, bool recurse, bool wantDir, bool wantFile, std::vector<std::string> &result, class IProgressCallback *progressCallBack = NULL, bool showEverything=false);\n\n\t/** Get the full path based on a file/path and the current directory. Example, imagine that the current path is c:\\temp and toto is a directory\n\t * getFullPath (\"toto\") returns \"c:/temp/toto/\"\n\t * getFullPath (\"../toto\") returns \"c:/temp/../toto/\"\n\t * getFullPath (\"d:\\dir\\toto\") returns \"d:/dir/toto/\"\n\t * getFullPath (\"\\toto\") returns \"c:/toto/\"\n\t * getFullPath (\"\") returns \"c:/temp/\"\n\t *\n\t * \\param path the path\n\t * \\return the full path\n\t */\n\tstd::string getFullPath (const std::string &path, bool addFinalSlash = true);\n\n\t/** Returns the current path of the application.\n\t */\n\tstd::string getCurrentPath ();\n\n\t/** Set the current path of the application.\n\t */\n\tbool setCurrentPath (const std::string &path);\n\n\t/** Create a list of file having the requested extension.\n\t */\n\tvoid getFileList(const std::string &extension, std::vector<std::string> &filenames);\n\n\t/** Create a list of file having the requested string in the filename and the requested extension.\n\t */\n\tvoid getFileListByName(const std::string &extension, const std::string &name, std::vector<std::string> &filenames);\n\n\t/** Create a list of file having the requested string in the path and the requested extension.\n\t*/\n\tvoid getFileListByPath(const std::string &extension, const std::string &path, std::vector<std::string> &filenames);\n\n\t/** Make a path relative to another if possible, else doesn't change it.\n\t * \\param basePath is the base path to be relative to.\n\t * \\param relativePath is the path to make relative to basePath.\n\t * return true if relativePath as been done relative to basePath, false is relativePath has not been changed.\n\t */\n\tbool makePathRelative (const char *basePath, std::string &relativePath);\n\n\t/** If File in this list is added more than one in an addSearchPath, it doesn't launch a warning.\n\t */\n\tvoid addIgnoredDoubleFile(const std::string &ignoredFile);\n\n\t/** For the moment after memoryCompress you cant addsearchpath anymore\n\t*/\n\tvoid memoryCompress();\n\n\tvoid memoryUncompress();\n\n\tbool isMemoryCompressed()\t{ return _MemoryCompressed; }\n\n\t/** Get the ms windows directory (in standardized way with end slash), or returns an empty string on other os\n\t*/\n\tstd::string getWindowsDirectory();\n\n\t/** Get application directory.\n\t* \\return directory where applications should write files.\n\t*/\n\tstd::string getApplicationDirectory(const std::string &appName = \"\");\n\n\t/** Get a temporary directory.\n\t* \\return temporary directory where applications should write files.\n\t*/\n\tstd::string getTemporaryDirectory();\n\nprivate:\n\n\t// All path in this vector must have a terminated '/'\n\tstd::vector<std::string> _AlternativePaths;\n\n\tstd::vector<std::string> IgnoredFiles;\n\n\tstd::map<std::string, std::string> _RemappedFiles;\n\n\t// ----------------------------------------------\n\t// MEMORY WISE\n\t// ----------------------------------------------\n\n\tbool _MemoryCompressed;\n\tCStaticStringMapper\tSSMext;\n\tCStaticStringMapper\tSSMpath;\n\n\t// If NOT memory compressed use this\n\t// ---------------------------------\n\n\tstruct CFileEntry\n\t{\n\t\tstd::string\tName;\t\t// Normal case\n\t\tuint32\tidPath\t : 16;\n\t\tuint32\tidExt\t : 15;\n\t\tuint32\tRemapped : 1;\n\t};\n\n\ttypedef std::map<std::string, CFileEntry>\tTFiles;\n\tTFiles\t _Files; // first is the filename in lowercase (can be with a remapped extension)\n\n\n\n\t// If memory compressed use this\n\t// -----------------------------\n\n\tstruct CMCFileEntry\n\t{\n\t\tchar *Name;\t\t\t\t// Normal case (the search is done by using nlstricmp)\n\t\tuint32\tidPath\t : 16;\t// Path (not with file at the end) - look in the SSMpath (65536 different path allowed)\n\t\tuint32\tidExt\t : 15;\t// real extension of the file if remapped - look in the SSMext (32768 different extension allowed)\n\t\tuint32\tRemapped : 1;\t// true if the file is remapped\n\t};\n\n\tchar *_AllFileNames;\n\n\t// first is the filename that can be with a remapped extension\n\tstd::vector<CMCFileEntry> _MCFiles;\n\n\t// Compare a MCFileEntry with a lowered string (useful for MCfind)\n\tclass CMCFileComp\n\t{\n\tpublic:\n\t\tsint specialCompare(const CMCFileEntry &fe, const char *rhs)\n\t\t{\n\t\t\tchar *lhs = fe.Name;\n\n\t\t\tuint8 lchar, rchar;\n\t\t\twhile (*lhs != '\\0' && *rhs != '\\0')\n\t\t\t{\n\t\t\t\t// lower case compare because name is in normal case\n\t\t\t\tlchar = uint8(::tolower(*lhs));\n\t\t\t\trchar = uint8(::tolower(*rhs));\n\t\t\t\tif (lchar != rchar) return ((sint)lchar) - ((sint)rchar);\n\t\t\t\t++lhs;\n\t\t\t\t++rhs;\n\t\t\t}\n\t\t\tif (*lhs != 0) return 1;\n\t\t\tif (*rhs != 0) return -1;\n\t\t\treturn 0;\n\t\t}\n\n\t\tbool operator()( const CMCFileEntry &fe, const CMCFileEntry &rhs )\n\t\t{\n\t\t\treturn specialCompare( fe, rhs.Name ) < 0;\n\t\t}\n\t};\n\n\t/// first ext1, second ext2 (ext1 could replace ext2)\n\tstd::vector<std::pair<std::string, std::string> > _Extensions;\n\n\tCMCFileEntry\t*MCfind (const std::string &filename);\n\tsint\t\t\tfindExtension (const std::string &ext1, const std::string &ext2);\n\tvoid\t\t\tinsertFileInMap (const std::string &filename, const std::string &filepath, bool remap, const std::string &extension);\n};\n\n\n/**\n * Utility class for searching files in different paths.\n *\n * Change in jun 2007 : now the implementation code is in CFileContainer, the\n * CPath class is just a wrapper class that contains one instance of CFileContainer.\n *\n * \\warning addSearchPath(), clearMap() and remapExtension() are not reentrant.\n * \\warning all path and files are *case sensitive* on linux.\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CPath\n{\n\tNLMISC_SAFE_SINGLETON_DECL_PTR(CPath);\npublic:\n\t/** Adds a search path.\n     * The path is a directory \"c:/temp\" all files in the directory will be included (and recursively if asked)\n\t *\n\t * Alternative directories are not pre-cached (instead of non Alternative files) and will be used when a file is not found in the standard directories.\n\t * For example, local data will be in the cached directories and server repository files will be in the Alternative files. If a new file is not\n\t * found in the local data, we'll try to find it on the repository.\n\t *\n\t * When Alternative is false, all added file names must be unique or a warning will be display. In the Alternative directories, it could have\n\t * more than one file with the same name.\n\t *\n\t * \\warning the path you provide is case sensitive, you must be sure that the path name is exactly the same\n\t *\n\t * \\param path the path name.k The separator for directories could be '/' or '\\' (bit '\\' will be translate into '/' in the function).\n\t * \\param recurse true if you want the function recurse in sub-directories.\n\t * \\param Alternative true if you want to add the path in the Alternative directories.\n\t * \\param progressCallBack is a progression callback interface pointer.\n\t */\n\tstatic void\t\t\taddSearchPath (const std::string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack = NULL);\n\n\t/** Used only for compatibility with the old CPath. In this case, we don't use the map to have the same behavior as the old CPath */\n\tstatic void\t\t\taddSearchPath (const std::string &path) { addSearchPath (path, false, true, NULL); }\n\n\t/** Same as AddSearchPath but with a file \"c:/autoexec.bat\" this file only will included. wildwards *doesn't* work */\n\tstatic void\t\t\taddSearchFile (const std::string &file, bool remap = false, const std::string &virtual_ext = \"\", class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Same as AddSearchPath but with a path file \"c:/test.pth\" all files name contain in this file will be included (the extention is used to know that it's a path file) */\n\tstatic void\t\t\taddSearchListFile (const std::string &filename, bool recurse, bool alternative);\n\n\t/** Same as AddSearchPath but with a big file \"c:/test.nbf\" all files name contained in the big file will be included  (the extention (Nel Big File) is used to know that it's a big file) */\n\tstatic void\t\t\taddSearchBigFile (const std::string &filename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Same as AddSearchPath but with a xml pack file \"c:/test.xml_pack\" all files name contained in the xml pack will be included   */\n\tstatic void\t\t\taddSearchXmlpackFile (const std::string &sXmlpackFilename, bool recurse, bool alternative, class NLMISC::IProgressCallback *progressCallBack = NULL);\n\n\t/** Remove all search path contains in the alternative directories */\n\tstatic void\t\t\tremoveAllAlternativeSearchPath ();\n\n\t// Remove a set of big file from the search paths (and also from CBigFile)\n\tstatic void\t\t\tremoveBigFiles(const std::vector<std::string> &bnpFilenames);\n\n\t/** Returns the long name (path + filename) for the specified file.\n\t * The directory separator is always '/'.\n\t * First, the lookup() lookups in standard directories (Alternative=false).\n\t * If not found, it lookups in the Alternative directories.\n\t * If not found the lookup() returns empty string \"\" (and generate an exception if throwException is true)\n\t *\n\t * The filename is not case sensitive so if the real filename is \"FooBAR.Jpg\" and you call lookup(\"fOOBar.jPg\"), it'll\n\t * return the real filename \"FooBAR.Jpg\"\n\t *\n\t * \\param filename the file name you are seeking. (ex: \"test.txt\")\n\t * \\param throwException used for backward compatibility, set to true to generate an EPathNotFound.\n\t * \\param displayWarning set to false if you don't want the function displays a warning if the file is not found\n\t * \\param lookupInLocalDirectory if true, the lookup() will first try to open the file without path.\n\t * \\return empty string if file is not found or the full path + file name (ex: \"c:/temp/test.txt\");\n\t *\n\t * ***********************************************\n\t *\tWARNING: This Method is NOT thread safe\n\t *\tuser must ensure that no mutator is called on CPath while async loading\n\t * ***********************************************\n\t *\n\t */\n\tstatic std::string\tlookup (const std::string &filename, bool throwException = true, bool displayWarning = true, bool lookupInLocalDirectory = true);\n\n\t/** Return if a file is present in the lookup map.\n\t * The function changes filename into lower case and removes ended spaces before searching.\n\t *\n\t * \\warning This function checks *only* in the map, not in local dir or alternative dir\n\t *\n\t * \\param filename the file name you are seeking. (ex: \"test.txt\")\n\t * \\param lookupInLocalDirectory if true, the lookup() will first try to open the file without path.\n\t * \\return true if the filename exists in the map used by lookup to know where the file is, false otherwise\n\t */\n\tstatic bool\t\t\texists (const std::string &filename);\n\n\n\t/** Clears the map that contains all cached files (Use this function to take into account new files).\n\t */\n\tstatic void clearMap ();\n\n\t/** Add a remapping function to allow file extension substitution.\n\t * - eg remapExtension(\"dds\", \"tga\", true) Where the boolean indicates whether\n\t * the \"dds\" should replace a \"tga\" if one exists - again - a warning should\n\t * be generated if the two are present.\n\t *\n\t * ie: If you have a file called pic.dds and you call remapExtension(\"dds\", \"tga\", true),\n\t *     if you call lookup(\"pic.tga\"), it'll return \"pic.dds\"\n\t *\n\t */\n\tstatic void remapExtension (const std::string &ext1, const std::string &ext2, bool substitute);\n\n\t/** Add file remapping\n\t * ie: If you have a file called pic.dds, and call remapFile(\"picture.dds\", \"pic.dds\")\n\t * calling lookup(\"picture.dds\") will in fact call lookup(\"pic.dds\")\n\t */\n\tstatic void remapFile (const std::string &file1, const std::string &file2);\n\n\t/** Load a file containing the remapped file (you must have done addsearchpath, this method use lookup)\n\t * Format is remapped_name_file, real_file\n\t * separators are , and \\n\n\t */\n\tstatic void loadRemappedFiles (const std::string &file);\n\n\tstatic void display ();\n\n\t/**\tTake a path and put it in the portable format and add a terminated / if needed\n\t * ie: \"C:\\\\Game/dir1\" will become \"C:/Game/dir1/\" or \"C:/Game/dir1\" if addFinalSlash is false\n\t */\n\tstatic std::string\tstandardizePath (const std::string &path, bool addFinalSlash = true);\n\n\t/**\tReplace / with \\ for dos process. Use only this function if can't do another way.\n\t * For example, if you do a system(\"copy data/toto data/tata\"); it'll not work because dos doesn't\n\t * understand /.\n\t * But in the majority of case, / working (it works for fopen for example)\n\t */\n\tstatic std::string\tstandardizeDosPath (const std::string &path);\n\n\n\t/** List all files in a directory.\n\t *\t\\param path path where files are scanned. No-op if empty\n\t *\t\\param recurse true if want to recurs directories\n\t *\t\\param wantDir true if want to add directories in result\n\t *\t\\param wantFile true if want to add files in result\n\t *\t\\param result list of string where directories/files names are added.\n\t *  \\param progressCallBack is a progression callback interface pointer.\n\t *  \\param showEverything false skips *.log files and CVS directories\n\t */\n\tstatic void\t\t\tgetPathContent (const std::string &path, bool recurse, bool wantDir, bool wantFile, std::vector<std::string> &result, class IProgressCallback *progressCallBack = NULL, bool showEverything=false);\n\n\t/** Get the full path based on a file/path and the current directory. Example, imagine that the current path is c:\\temp and toto is a directory\n\t * getFullPath (\"toto\") returns \"c:/temp/toto/\"\n\t * getFullPath (\"../toto\") returns \"c:/temp/../toto/\"\n\t * getFullPath (\"d:\\dir\\toto\") returns \"d:/dir/toto/\"\n\t * getFullPath (\"\\toto\") returns \"c:/toto/\"\n\t * getFullPath (\"\") returns \"c:/temp/\"\n\t *\n\t * \\param path the path\n\t * \\return the full path\n\t */\n\tstatic std::string getFullPath (const std::string &path, bool addFinalSlash = true);\n\n\t/** Returns the current path of the application.\n\t */\n\tstatic std::string getCurrentPath ();\n\n\t/** Set the current path of the application.\n\t */\n\tstatic bool setCurrentPath (const std::string &path);\n\n\t/** Create a list of file having the requested extension.\n\t */\n\tstatic void getFileList(const std::string &extension, std::vector<std::string> &filenames);\n\n\t/** Create a list of file having the requested string in the filename and the requested extension.\n\t */\n\tstatic void getFileListByName(const std::string &extension, const std::string &name, std::vector<std::string> &filenames);\n\n\t/** Create a list of file having the requested string in the path and the requested extension\n\t*/\n\tstatic void getFileListByPath(const std::string &extension, const std::string &path, std::vector<std::string> &filenames);\n\n\t/** Make a path relative to another if possible, else doesn't change it.\n\t * \\param basePath is the base path to be relative to.\n\t * \\param relativePath is the path to make relative to basePath.\n\t * return true if relativePath as been done relative to basePath, false is relativePath has not been changed.\n\t */\n\tstatic bool makePathRelative (const char *basePath, std::string &relativePath);\n\n\t/** Make path absolute\n\t* \\param relativePath - The relative path\n\t* \\param directory - the directory to which the path is relative to\n\t* returns the absolute path, or empty if something went wrong.\n\t*/\n\tstatic std::string makePathAbsolute (const std::string &relativePath, const std::string &directory );\n\n\t/** If File in this list is added more than one in an addSearchPath, it doesn't launch a warning.\n\t */\n\tstatic void addIgnoredDoubleFile(const std::string &ignoredFile);\n\n\t/** For the moment after memoryCompress you cant addsearchpath anymore\n\t*/\n\tstatic void memoryCompress();\n\n\tstatic void memoryUncompress();\n\n\tstatic bool isMemoryCompressed()\t{ return getInstance()->_FileContainer.isMemoryCompressed(); }\n\n\t/** Get the ms windows directory (in standardized way with end slash), or returns an empty string on other os\n\t*/\n\tstatic std::string getWindowsDirectory();\n\n\t/** Get application directory.\n\t* \\return directory where applications should write files.\n\t*/\n\tstatic std::string getApplicationDirectory(const std::string &appName = \"\");\n\n\t/** Get a temporary directory.\n\t* \\return temporary directory where applications should write files.\n\t*/\n\tstatic std::string getTemporaryDirectory();\n\n\t// release singleton\n\tstatic void releaseInstance();\n\nprivate:\n\n\tCPath()\n\t{\n\t}\n\n\t/// The container used by the standard CPath\n\tCFileContainer\t\t_FileContainer;\n};\n\n\n\n/**\n * Utility class for file manipulation\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nstruct CFile\n{\n\t/**\n\t * Retrieve the associated file name.\n\t * An empty string is returned if the path is invalid\n\t */\n\tstatic std::string getFilename (const std::string &filename);\n\n\t/**\n\t * Retrieve the associated file path with the trailing slash.\n\t * Returns an empty string if the path is invalid\n\t */\n\tstatic std::string getPath (const std::string &filename);\n\n\t/**\n\t * Just to know if it is a directory.\n\t * _FileName empty and path not !!!\n\t */\n\tstatic bool isDirectory (const std::string &filename);\n\n\t/**\n\t * Return true if the file exists.\n\t * Warning: this test will also tell that the file does not\n\t * exist if you don't have the rights to read it (Unix).\n\t */\n\tstatic bool fileExists (const std::string &filename);\n\n\t/**\n\t * Return true if the file OR directory exists.\n\t * Warning: this test will also tell that the file does not\n\t * exist if you don't have the rights to read it (Unix).\n\t */\n\tstatic bool isExists (const std::string& filename);\n\n\t/**\n\t * Create an empty file.\n\t * Return true if the file has been correctly created.\n\t */\n\tstatic bool createEmptyFile (const std::string& filename);\n\n\t/**\n\t * Return a new filename that doesn't exist. It's used for screenshot filename for example.\n\t * example: findNewFile(\"foobar.tga\");\n\t * will try foobar001.tga, if the file exists, try foobar002.tga and so on until it finds an unexistant file.\n\t */\n\tstatic std::string findNewFile (const std::string &filename);\n\n\t/**\n\t * Return the position between [begin,end[ of the last separator between path and filename ('/' or '\\').\n\t * If there's no separator, it returns string::npos.\n\t */\n\tstatic int getLastSeparator (const std::string &filename);\n\n\tstatic std::string getFilenameWithoutExtension (const std::string &filename);\n\tstatic std::string getExtension (const std::string &filename);\n\n\t/**\n\t * Return the size of the file (in bytes).\n\t *\n\t * You have to provide the full path of the file (the function doesn't lookup)\n\t */\n\tstatic uint32\tgetFileSize (const std::string &filename);\n\n\t/**\n\t * Return the size of the file (in bytes).\n\t */\n\tstatic uint32\tgetFileSize (FILE *f);\n\n\t/**\n\t * Return Time of last modification of file. 0 if not found.\n\t *\n\t * You have to provide the full path of the file (the function doesn't lookup)\n\t * The time is measured in second since 01-01-1970 0:0:0 UTC\n\t */\n\tstatic uint32\tgetFileModificationDate(const std::string &filename);\n\n\t/**\n\t * Set the time of last modification of file.\n\t *\n\t * You have to provide the full path of the file (the function doesn't lookup)\n\t * The time is measured in second since 01-01-1970 0:0:0 UTC\n\t * Return 'true' if the file date has been changed or false in case of error.\n\t */\n\tstatic bool\t\tsetFileModificationDate(const std::string &filename, uint32 modTime);\n\n\t/**\n\t * Return creation Time of the file. 0 if not found.\n\t *\n\t * You have to provide the full path of the file (the function doesn't lookup)\n\t */\n\tstatic uint32\tgetFileCreationDate(const std::string &filename);\n\n\t/**\n\t * Add a callback that will be call when the content file, named filename, changed.\n\t * The system use the file modification date. To work, you need to call evenly the\n\t * function checkFileChange(), this function only checks every 1s by default (you can\n\t * change the default time)\n\t *\n\t * ie:\n\t * void cb (const std::string &filename) { nlinfo (\"the file %s changed\", filename.c_str()); }\n\t * CFile::addFileChangeCallback (\"myfile.txt\", cb);\n\t *\n\t */\n\tstatic void addFileChangeCallback (const std::string &filename, void (*)(const std::string &filename));\n\n\t/**\n\t * Remove a file that was previously added by addFileChangeCallback\n\t */\n\tstatic void removeFileChangeCallback (const std::string &filename);\n\n\t/**\n\t * You have to call this function evenly (each frame for example) to enable the file change callback system.\n\t * If the file not exists and is created in the run time, the callback will be called.\n\t * If the file exists and is removed in the run time, the callback will be called.\n\t *\n\t * \\param frequency the time in millisecond that we wait before check another time (1s by default).\n\t */\n\tstatic void checkFileChange (TTime frequency = 1000);\n\n\t/** Copy a file\n\t  * NB this keeps file attributes\n\t  * \\param failIfExists If the destination file exists, nothing is done, and it returns false.\n\t  * \\return true if the copy succeeded\n\t  */\n\tstatic bool copyFile(const std::string &dest, const std::string &src, bool failIfExists = false, class IProgressCallback *progress = NULL);\n\n\t/** Compare 2 files\n\t  * \\return true if both files exist and the files have same timestamp and size\n\t  */\n\tstatic bool quickFileCompare(const std::string &fileName0, const std::string &fileName1);\n\n\t/** Compare 2 files\n\t  * \\param maxBufSize fixes max memory space to use for the pair buffers used for data comparison (eg 16 would allow 8 bytes per buffer for the 2 buffers)\n\t  * \\return true if both files exist and the files have same contents (timestamp is ignored)\n\t  */\n\tstatic bool thoroughFileCompare(const std::string &fileName0, const std::string &fileName1,uint32 maxBufSize=1024*1024*2);\n\n\t/** Move a file\n\t  * NB this keeps file attributes\n\t  */\n\tstatic bool moveFile(const char *dest, const char *src);\n\n\t/** Create a directory\n\t  *\t\\return true if success\n\t  */\n\tstatic bool\tcreateDirectory(const std::string &dirname);\n\n\t/** Create a directory and any missing parent directories\n\t  *\t\\return true if success\n\t  */\n\tstatic bool\tcreateDirectoryTree(const std::string &dirname);\n\n\t/** Try to set the file access to read/write if not already set.\n\t * return true if the file doesn't exist or if the file already have RW access.\n\t * Work actually only on Windows and returns always true on other platforms.\n\t * \\return true if RW access is granted\n\t */\n\tstatic bool\tsetRWAccess(const std::string &filename);\n\n\t/** Delete a file if possible (change the write access if possible)\n\t* \\return true if the delete occurs.\n\t*/\n\tstatic bool deleteFile(const std::string &filename);\n\n\t/** Delete a directory if possible (change the write access if possible)\n\t* \\return true if the delete occurs.\n\t*/\n\tstatic bool deleteDirectory(const std::string &filename);\n\n\t/** Get temporary output filename.\n\t*\tCall this method to get a temporary output filename. If you have successfully saved your data, delete the old filename and move the new one.\n\t*/\n\tstatic void getTemporaryOutputFilename (const std::string &originalFilename, std::string &tempFilename);\n};\n\n} // NLMISC\n\n#endif // NL_PATH_H\n\n/* End of path.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/plane.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PLANE_H\n#define NL_PLANE_H\n\n\n#include\t\"stream.h\"\n#include\t\"vector.h\"\n\n\nnamespace NLMISC\n{\n\nclass CUV;\n\n// ======================================================================================================\n/**\n * Class CPlane. a 3D Plane.\n *\n * A vector v is said \"front\" of a plane p if p*v>0.\n *\n * A \"front segment\" or a \"front polygon\" have all their vertices in front of the plane.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CPlane\n{\npublic:\n\tfloat\ta,b,c,d;\n\npublic:\n\n\t/// \\name Object.\n\t//@{\n\t/// Constructor that does nothing.\n\tCPlane() {}\n\t/// Constructor .\n\tCPlane(float _a, float _b, float _c, float _d) : a(_a), b(_b), c(_c), d(_d) {}\n\t/// Copy Constructor.\n\tCPlane(const CPlane &v) : a(v.a), b(v.b), c(v.c), d(v.d) {}\n\t//@}\n\n\n\t/// \\name Construction/Get.\n\t//@{\n\t/**\n\t * Make a plane with a normal and a vertex.\n\t * NB: the plane normal is normalized by make().\n\t */\n\tvoid\tmake(const CVector &normal, const CVector &pos);\n\t/**\n\t * Make a plane with 3 vertices.\n\t * NB: the plane normal is normalized by make().\n\t */\n\tvoid\tmake(const CVector &p0, const CVector &p1, const CVector &p2);\n\t/**\n\t * Return the normal vector of the plane.\n\t * Since the normal of the plane may not be normalized (if setuped without make()), the returned normal\n\t * may NOT be normalized.\n\t */\n\tCVector\tgetNormal() const;\n\t/**\n\t * Normalize the plane, such that getNormal() return a normalized vector.\n\t */\n\tvoid\tnormalize();\n\t/**\n\t * return the normalized version of a plane. \\see normalize()\n\t */\n\tinline CPlane\tnormed() const;\n\t//@}\n\n\n\t/// \\name Projection / clipping.\n\t//@{\n\t/**\n\t * Return the distance of p from the plane. Hence, the result is >=0.\n\t * Since the plane normal may not be normalized, distance() compute the distance with the normalized normal\n\t * of plane. If you are sure that your plane has a normalized normal, it is much faster to do a \\c fabs(p*v).\n\t */\n\tfloat\tdistance(const CVector &p) const;\n\t/// Return plane*vector.\n\tinline float\toperator*(const CVector &p) const;\n\t/// Intersect a line onto a plane. p1 is returned if line // to plane.\n\tCVector intersect(const CVector &p0,const CVector &p1) const;\n\t/// Project a point onto a plane.\n\tCVector project(const CVector &p0) const;\n\n\t/**\n\t * Clip a segment onto a plane.\n\t * The \"back segment\" is written in (p1,p2). If segment is entirely \"front\", (p1,p2) is not modified.\n\t * \\return false if segment entirely front, or true.\n\t * \\sa clipSegmentFront()\n\t */\n\tbool\tclipSegmentBack(CVector &p0, CVector &p1) const;\n\t/**\n\t * Clip a segment onto a plane.\n\t * The \"front segment\" is written in (p1,p2). If segment is entirely \"back\", (p1,p2) is not modified.\n\t * \\return false if segment entirely back, or true.\n\t * \\sa clipSegmentBack()\n\t */\n\tbool\tclipSegmentFront(CVector &p0, CVector &p1) const;\n\n\t/** Clip a polygon by a plane. The \"back polygon\" is returned.\n\t * Nb: Out must be allocated to nIn+1 (at less).\n\t * \\param in the input polygon\n\t * \\param out the clipped back polygon\n\t * \\param nIn number of vertices of input polygon\n\t * \\return number of vertices of out. 0 is returned if In polygon entirely front, or if nIn<=2.\n\t */\n\tsint\tclipPolygonBack(CVector in[], CVector out[], sint nIn) const;\n\t// Clip a polygon with uvs by a plane\n\tsint\tclipPolygonBack(const CVector in[], const CUV inUV[], CVector out[], CUV outUV[], sint nIn) const;\n\t/** Clip a polygon by a plane. The \"front polygon\" is returned.\n\t * Nb: Out must be allocated to nIn+1 (at less).\n\t * \\param in the input polygon\n\t * \\param out the clipped front polygon\n\t * \\param nIn number of vertices of input polygon\n\t * \\return number of vertices of out. 0 is returned if In polygon entirely back, or if nIn<=2.\n\t */\n\tsint\tclipPolygonFront(CVector in[], CVector out[], sint nIn) const;\n\t//@}\n\n\t/// \\name normal inversion\n\t//@{\n\t\t/// get the inverted version of this plane (same position, but inverted normal)\n\t\tCPlane  inverted() const;\n\n\t\t/// invert this plane (same position, but inverted normal)\n\t\tvoid\tinvert();\n\t//@}\n\n\t/// \\name Misc\n\t//@{\n\tvoid\tserial(IStream &f)\n\t{\n\t\tf.serial(a,b,c,d);\n\t}\n\n\t// Strict equality comparator\n\tbool\toperator==(const CPlane &o) const\n\t{\n\t\treturn a==o.a && b==o.b && c==o.c && d==o.d;\n\t}\n\n\t//@}\n\n};\n\n\n}\n\n\n#include \"plane_inline.h\"\n\n\n#endif // NL_PLANE_H\n\n/* End of plane.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/plane_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PLANE_INLINE_H\n#define NL_PLANE_INLINE_H\n\n\nnamespace NLMISC\n{\n\n\n//============================================================\ninline\tCVector\tCPlane::getNormal() const\n{\n\treturn CVector(a,b,c);\n}\n//============================================================\ninline\tfloat\tCPlane::distance(const CVector &v) const\n{\n\tCPlane\tp= normed();\n\treturn (float)fabs(p*v);\n}\n//============================================================\ninline\tfloat\tCPlane::operator*(const CVector &p) const\n{\n\treturn a*p.x + b*p.y + c*p.z + d;\n}\n//============================================================\ninline\tCVector CPlane::intersect(const CVector &p0,const CVector &p1) const\n{\n\tfloat decal;\n\tfloat\tda= (*this)*p0;\n\tfloat\tdb= (*this)*p1;\n\tif(db-da == 0)\n\t\treturn p0;\n\tdecal= ( 0-da ) / ( db - da );\n\treturn p0 + (p1-p0)*decal;\n}\n//============================================================\ninline\tCVector CPlane::project(const CVector &p0) const\n{\n\treturn intersect(p0, p0+getNormal());\n}\n\n//============================================================\ninline\tvoid\tCPlane::normalize()\n{\n\tfloat\tn= getNormal().norm();\n\tif(n)\n\t{\n\t\tfloat\toon= 1.0f/n;\n\t\ta*= oon;\n\t\tb*= oon;\n\t\tc*= oon;\n\t\td*= oon;\n\t}\n}\n//============================================================\ninline\tCPlane\tCPlane::normed() const\n{\n\tCPlane\tret= *this;\n\tret.normalize();\n\treturn ret;\n}\n\n\n}\n\n\n#endif // NL_PLANE_H\n\n/* End of plane.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/polygon.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_POLYGON_H\n#define NL_POLYGON_H\n\n#include \"types_nl.h\"\n#include \"matrix.h\"\n#include \"stream.h\"\n#include \"vector_2f.h\"\n\n#include <vector>\n\n\nnamespace NLMISC\n{\n\n\nclass CTriangle;\n\n// Used by the method toConvexPolygons\nclass CBSPNode2v;\n\n// ***************************************************************************\n/**\n * A polygon, with an unlimited size of vertices.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CPolygon\n{\npublic:\n\tstd::vector<CVector>\tVertices;\n\npublic:\n\n\t/// Constructor\n\tCPolygon() {}\n\t/// Constructor. Init with a triangle.\n\tCPolygon(const CVector &a, const CVector &b, const CVector &c);\n\n\tsint\t\t\tgetNumVertices() const {return (sint)Vertices.size();}\n\n\t// build a triangle fan from this polygon, appending resulting tris to 'dest'\n\tvoid\t\ttoTriFan(std::vector<NLMISC::CTriangle> &dest) const;\n\n\t/// Clip a polygon with a set of planes. Cohen-sutherland... clipPolygonBack() is used on planes.\n\tvoid\t\t\tclip(const CPlane *planes, uint nPlanes);\n\t/// Clip a polygon with a set of planes. Cohen-sutherland clipping... clipPolygonBack() is used on planes.\n\tvoid\t\t\tclip(const std::vector<CPlane> &planes);\n\n\tfloat\t\t\tcomputeArea() const;\n\n\t/// Serial this polygon\n\tvoid\t\t\tserial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\t/**\n\t  * Convert a concave polygon into a list of convex polygons using a 2d projection.\n\t  * The polygon mustn't overlap itself in the XY plane of the basis passed in parameter.\n\t  * The polygon must be direct in the XY plane of the basis passed in parameter. (Counter clock wise)\n\t  *\n\t  * The subdivison is in non-constant n*log(n) with n is the number of vertices.\n\t  *\n\t  * \\param outputPolygons is the list filled with clipped convex polygons. The list is not cleared at the beginning.\n\t  * New polygons are just appended at the end.\n\t  * \\param basis is the basis of the polygon projection.\n\t  * \\return true if the polygon has been subdivided. false if the polygon overlap itself in the XY plane of the basis\n\t  * or if the polygon is not direct (clock wise).\n\t  */\n\tbool\t\t\ttoConvexPolygons (std::list<CPolygon>& outputPolygons, const CMatrix& basis) const;\n\n\t/**\n\t  * Chain the arg polygons with this polygon testing 2d intersections.\n\t  * The 2d intersection test has been done in the XY plane of the basis passed at the function.\n\t  *\n\t  * The polygon a-b-c-d-e chained with f-g-h-i-j will give the polygon a-b-f-g-h-i-j-f-b-c-d-e\n\t  * if the edge b-f is not 2d clipped by any edge plane in the XY plane of basis.\n\t  *\n\t  * \\param basis is the basis of the polygon projection.\n\t  * \\return false if chain failed. else true.\n\t  */\n\tbool\t\t\tchain (const std::vector<CPolygon> &other, const CMatrix& basis);\n\n\t/// get the best triplet from this poly (the one that has the highest area)\n\tvoid\t\tgetBestTriplet(uint &index0, uint &index1, uint &index2);\n\n\t/** Takes the best triplet from this poly to build a normal.\n\t  * From this normal and a points, build a basis (the normal is the K vector of the basis)\n\t  * This can be used to transform the poly in 2D after it has been inverted\n\t  */\n\tvoid\t\tbuildBasis(CMatrix &dest);\n\n\t// Used by the method toConvexPolygons and chain\n\tvoid\t\t\ttoConvexPolygonsLocalAndBSP (std::vector<CVector> &localVertices, CBSPNode2v &root, const CMatrix &basis) const;\n\tstatic bool\t\ttoConvexPolygonsEdgeIntersect (const CVector2f& a0, const CVector2f& a1, const CVector2f& b0, const CVector2f& b1);\n\tstatic bool\t\ttoConvexPolygonsLeft (const std::vector<CVector> &vertex, uint a, uint b, uint c);\n\tstatic bool\t\ttoConvexPolygonsLeftOn (const std::vector<CVector> &vertex, uint a, uint b, uint c);\n\tstatic bool\t\ttoConvexPolygonsInCone (const std::vector<CVector> &vertex, uint a, uint b);\n\tstatic bool\t\ttoConvexPolygonsDiagonal (const std::vector<CVector> &vertex, const CBSPNode2v &bsp, uint a, uint b);\n};\n\n/**\n  * A 2d convex polygon\n  */\nclass CPolygon2D\n{\npublic:\n\ttypedef std::vector<CVector2f> TVec2fVect;\n\tTVec2fVect Vertices;\npublic:\n\t/// default ctor\n\tCPolygon2D() {}\n\n\t// swap this poly content with another poly content\n\tvoid swap(CPolygon2D &other) { Vertices.swap(other.Vertices); }\n\n\t/** Build a 2D polygon from this 3D polygon, by using the given projection matrix\n\t  * The x and y components of projected vertices are used to create the 2D polygon\n\t  */\n\tCPolygon2D(const CPolygon &src, const CMatrix &projMat = CMatrix::Identity);\n\n\t/** Reinit a 2D polygon from this 3D polygon, by using the given projection matrix\n\t  * The x and y components of projected vertices are used to create the 2D polygon\n\t  */\n\tvoid fromPolygon(const CPolygon &src, const CMatrix &projMat = CMatrix::Identity);\n\n\t/** Build a 2D polygon from the given triangle, by using the given projection matrix\n\t  * The x and y components of projected vertices are used to create the 2D polygon\n\t  */\n\tCPolygon2D(const CTriangle &tri, const CMatrix &projMat = CMatrix::Identity);\n\n\t/// Check whether this polygon is convex;\n\tbool\t\tisConvex();\n\n\t/** Build a convex hull from this polygon. The result poly is ordered, so it can also be used to order a convex\n\t  * poly given its set of vertices.\n\t  * NB: require this != &dest\n\t  */\n\tvoid\t\tbuildConvexHull(CPolygon2D &dest) const;\n\n\t/// get the best triplet of vector. e.g the triplet that has the best surface\n\tvoid\t\tgetBestTriplet(uint &index0, uint &index1, uint &index2);\n\n\t/// Serial this polygon\n\tvoid\t\tserial(NLMISC::IStream &f) throw(NLMISC::EStream);\n\n\ttypedef std::pair<sint, sint> TRaster;\n\ttypedef std::vector<TRaster>  TRasterVect;\n\n\t/** Compute the borders of this poly with sub-pixel accuracy. No clipping is performed.\n\t  * Only points exactly inside or exactly on the left border of the polygon are kept.\n\t  * This means that pixels are seen as points, not as surfaces.\n\t  * The output is in a vector of sint pairs. minimumY is filled with the minimum y value of the poly.\n\t  * Each pairs gives [xmin, xmax] for the current segment. if xmin > xmax, then no point is valid for this segment.\n\t  * Otherwise, all points from x = xmin (included)  to x = xmax (included) are valid.\n\t  * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug\n\t  */\n\tvoid\t\tcomputeBorders(TRasterVect &borders, sint &minimumY) const;\n\t/** The same as compute borders, but pixel are seen as surfaces and not as points.\n\t   * Any pixel that is touched by the poly will be selected\n\t   * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug\n\t   */\n\tvoid\t\tcomputeOuterBorders(TRasterVect &borders, sint &minimumY) const;\n\t/** The same as compute borders, but pixel are seen as surfaces and not as points\n\t  * In this version, only pixels that are entirely INSIDE the poly are kept\n\t  * IMPORTANT: coordinates must be in the -32000, 32000 range. This is checked in debug\n\t  */\n\tvoid\t\tcomputeInnerBorders(TRasterVect &borders, sint &minimumY) const;\n\t/// Test whether this polygon intersect another convex polygon. Currently not optimized.\n\tbool        intersect(const CPolygon2D &other) const;\n\n\t/// Check whether a point is contained by this poly\n\tbool\t\tcontains(const CVector2f &p, bool hintIsConvex = true) const;\n\n\t/** Get the index of a segment of this poly that is a non null segment.\n\t  * \\return true if such a segment was found\n\t  */\n\tbool  getNonNullSeg(uint &seg) const;\n\n\t/// Get a line equation of the seg starting at the given index\n\tvoid  getLineEquation(uint index, float &a, float &b, float &c) const;\n\n\t// Test if current poly is CCW oriented (in a right handed coord. system)\n\tbool  isCCWOriented() const;\n\n\t// get bounding rect (poly must not be empty)\n\tvoid getBoundingRect(CVector2f &minCorner, CVector2f &maxCorner) const;\n\n\t// test self intersection\n\tbool selfIntersect() const;\n\nprivate:\n\t/// Sum the dot product of this poly vertices against a line equation a*x + b*y + c\n\tfloat sumDPAgainstLine(float a, float b, float c) const;\n\n\t/// Get ref to the first vertex that start at index\n\tconst CVector2f &getSegRef0(uint index) const\n\t{\n\t\tnlassert(index < Vertices.size()); return Vertices[index];\n\t}\n\tconst CVector2f &getSegRef1(uint index) const\n\t{\n\t\tnlassert(index < Vertices.size());\n\t\treturn index + 1 == Vertices.size() ?\n\t\t\t   Vertices[0]                 :\n\t\t       Vertices[index + 1];\n\t}\n\tvoid checkValidBorders() const;\n};\n\n// comparison of 2D polygon\nbool operator == (const CPolygon2D &lhs, const CPolygon2D &rhs);\nbool operator < (const CPolygon2D &lhs, const CPolygon2D &rhs);\n\n} // NLMISC\n\n\n#endif // NL_POLYGON_H\n\n/* End of polygon.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/pool_memory.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_POOL_MEMORY_H\n#define NL_POOL_MEMORY_H\n\n#include \"types_nl.h\"\n\n#include <list>\n#include <vector>\n\nnamespace NLMISC\n{\n\n\n/**\n * Pool memory allocation\n *\n * This memory manager allocates bloc of elements and free all the\n * elements at the same time. Useful for temporary allocation.\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\n\ntemplate<class T>\nclass CPoolMemory\n{\npublic:\n\t/*\n\t * Constructor\n\t *\n\t * \\param blockSize is the default bloc size\n\t */\n\tCPoolMemory (uint blockSize=10)\n\t{\n\t\t_BlockSize=blockSize;\n\t\t_BlockPointer=_BlockList.end();\n\t}\n\n\t/*\n\t * Allocate an element.\n\t *\n\t * Return a pointer on the element.\n\t */\n\tT*\t\tallocate ()\n\t{\n\t\t// End of block ?\n\t\tif ( (_BlockPointer!=_BlockList.end()) && (_BlockPointer->size()>=_BlockSize) )\n\t\t{\n\t\t\t// Get next block\n\t\t\t_BlockPointer++;\n\t\t}\n\n\t\t// Out of memory ?\n\t\tif (_BlockPointer==_BlockList.end())\n\t\t{\n\t\t\t// Add a block\n\t\t\t_BlockList.resize (_BlockList.size()+1);\n\n\t\t\t// Pointer on the new block\n\t\t\t_BlockPointer=_BlockList.end ();\n\t\t\t_BlockPointer--;\n\n\t\t\t// Reserve it\n\t\t\t_BlockPointer->reserve (_BlockSize);\n\t\t}\n\n\t\t// Allocate\n\t\t_BlockPointer->resize (_BlockPointer->size()+1);\n\n\t\t// Return the pointer\n\t\treturn &*((_BlockPointer->end ()-1));\n\t}\n\n\t/*\n\t * Free all the elements allocated since last free(). Memory is kept for next allocations.\n\t */\n\tvoid\tfree ()\n\t{\n\t\ttypename std::list< std::vector<T> >::iterator ite=_BlockList.begin();\n\t\twhile (ite!=_BlockList.end())\n\t\t{\n\t\t\t// Clear the block\n\t\t\tite->clear ();\n\n\t\t\t// Check size in not zero\n\t\t\tnlassert (ite->capacity ()>0);\n\n\t\t\tite++;\n\t\t}\n\t\t// Pointer at the beginning\n\t\t_BlockPointer=_BlockList.begin();\n\t}\n\n\t/*\n\t * Purge memory. All the memory used by the allocator is freid for real.\n\t */\n\tvoid\tpurge ()\n\t{\n\t\t_BlockList.clear();\n\t\t_BlockPointer=_BlockList.end();\n\t}\n\nprivate:\n\tuint\t\t\t\t\t\t\t\t\t_BlockSize;\n\tstd::list< std::vector<T> >\t\t\t\t_BlockList;\n\ttypename std::list< std::vector<T> >::iterator\t_BlockPointer;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_POOL_MEMORY_H\n\n/* End of pool_memory.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/progress_callback.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PROGRESS_CALLBACK_H\n#define NL_PROGRESS_CALLBACK_H\n\n#include \"types_nl.h\"\n\n\nnamespace NLMISC {\n\n\n/**\n * Progress callback interface\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass IProgressCallback\n{\npublic:\n\n\tIProgressCallback ();\n\tvirtual ~IProgressCallback () {}\n\n\t/**\n\t  * Call back\n\t  *\n\t  * progressValue should be 0 ~ 1\n\t  */\n\tvirtual void progress (float progressValue);\n\n\t/**\n\t  * Push crop values\n\t  */\n\tvoid pushCropedValues (float min, float max);\n\n\t/**\n\t  * Push crop values\n\t  */\n\tvoid popCropedValues ();\n\n\t/**\n\t  * Get croped value\n\t  */\n\tfloat getCropedValue (float value) const;\n\npublic:\n\n\t/// Display string\n\tstd::string\t\tDisplayString;\n\nprivate:\n\n\tclass CCropedValues\n\t{\n\tpublic:\n\t\tCCropedValues (float min, float max)\n\t\t{\n\t\t\tMin = min;\n\t\t\tMax = max;\n\t\t}\n\t\tfloat\tMin;\n\t\tfloat\tMax;\n\t};\n\n\tstd::vector<CCropedValues>\t_CropedValues;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_PROGRESS_CALLBACK_H\n\n/* End of progress_callback.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/quad.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_QUAD_H\n#define NL_QUAD_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\n * A simple quad of vertex.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CQuad\n{\npublic:\n\tCVector\t\tV0, V1, V2, V3;\n\n\npublic:\n\n\t/// Constructor\n\tCQuad() {}\n\n\t/// Constructor\n\tCQuad(const NLMISC::CVector &v0, const NLMISC::CVector &v1, const NLMISC::CVector &v2, const NLMISC::CVector &v3)\n\t\t: V0(v0), V1(v1), V2(v2), V3(v3)\n\t{}\n\n\tvoid set(const NLMISC::CVector &v0, const NLMISC::CVector &v1, const NLMISC::CVector &v2, const NLMISC::CVector &v3)\n\t{\n\t\tV0 = v0;\n\t\tV1 = v1;\n\t\tV2 = v2;\n\t\tV3 = v3;\n\t}\n\n\tconst CQuad &operator = ( const CQuad& q)\n\t{\n\t\tV0 = q.V0;\n\t\tV1 = q.V1;\n\t\tV2 = q.V2;\n\t\tV3 = q.V3;\n\t\treturn *this;\n\t}\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_QUAD_H\n\n/* End of quad.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/quat.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_QUAT_H\n#define NL_QUAT_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n#include \"stream.h\"\n\n#include <cmath>\n\nnamespace\tNLMISC\n{\n\n\n// ***************************************************************************\nconst\tdouble\tQuatEpsilon= 0.000001;\n\n\n\n// ***************************************************************************\n/**\n * An AngleAxis.\n * \\author Antoine Viau.\n * \\author Nevrax France\n * \\date 2000\n */\nstruct\tCAngleAxis\n{\n\tCVector\t\tAxis;\t\t/// an axis.\n\tfloat\t\tAngle;\t\t/// angle in radians.\n\n\tCAngleAxis() {}\n\tCAngleAxis(const CVector &axis, float ang) : Axis(axis), Angle(ang) {}\n\n\t/// serial.\n\tvoid\tserial(IStream &f)\n\t{\n\t\tf.serial(Axis);\n\t\tf.serial(Angle);\n\t}\n};\n\n\n// ***************************************************************************\n/**\n * A Template quaternion. Use CQuat and CQuatD.\n * \\author Antoine Viau.\n * \\author Nevrax France\n * \\date 2000\n */\ntemplate <class T> class CQuatT\n{\npublic:\n\tT x,y,z,w;\n\n\npublic:\n\n\t/// \\name Object\n\t// @{\n\tCQuatT() : x((T)0.0),y((T)0.0),z((T)0.0),w((T)1.0) {}\n\tCQuatT(T X, T Y, T Z, T W) : x(X), y(Y), z(Z), w(W) {}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuatT(const CVector &axis, float angle) {setAngleAxis(axis, angle);}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuatT(const CAngleAxis &aa) {setAngleAxis(aa);}\n\t// @}\n\n\n\t/// \\name Sets.\n\t// @{\n\tvoid\tset(T X, T Y, T Z, T W)\t\t{x= X; y= Y; z= Z; w= W;}\n\t// @}\n\n\t/// \\name Comparison\n\t// @{\n\tbool\toperator==(const CQuatT& a) const\t\t{return (x==a.x && y==a.y && z==a.z && w==a.w);}\n\tbool\tequal(const CQuatT& a, float epsilon = 1E-6f) const;\n\tvoid\tidentity()\t\t\t\t\t\t{x = y = z = 0.0f ;\tw = 1.0f; }\n\tbool\tisIdentity() const\t\t\t\t{return (x==0.0f && y==0.0f && z==0.0f && w==1.0f);}\n\t// @}\n\n\t/// \\name 4D vector operations.\n\t// @{\n\tCQuatT&\toperator+=(const CQuatT&o)\t\t{x+=o.x; y+=o.y; z+=o.z; w+=o.w; return *this;}\n\tCQuatT&\toperator-=(const CQuatT&o)\t\t{x-=o.x; y-=o.y; z-=o.z; w-=o.w; return *this;}\n\tCQuatT&\toperator*=(T f)\t\t\t\t\t{x*=f;y*=f;z*=f;w*=f; return *this;}\n\tCQuatT&\toperator/=(T f)\t\t\t\t\t{double oof= 1.0/f; x=(T)(x*oof); y=(T)(y*oof); z= (T)(z*oof); w=(T)(w*oof); return *this;}\n\tCQuatT\toperator+(const CQuatT&o) const\t{return CQuatT(x+o.x,y+o.y,z+o.z,w+o.w);}\n\tCQuatT\toperator-(const CQuatT&o) const\t{return CQuatT(x-o.x,y-o.y,z-o.z,w-o.w);}\n\tCQuatT\toperator*(T f) const\t\t\t{return CQuatT(x*f,y*f,z*f,w*f);}\n\tCQuatT\toperator/(T f) const\t\t\t{double oof= 1.0/f; return CQuatT(x*oof,y*oof,z*oof,w*oof);}\n\tCQuatT\toperator-() const\t\t\t\t{return(CQuatT(-x,-y,-z,-w)); }\n\tCQuatT\toperator+() const\t\t\t\t{return *this; }\n\t/// return the square of the norm of the 4D vector.\n\tT\t\tsqrnorm() const\t\t\t\t\t{return (x*x + y*y + z*z + w*w);}\n\t/// return the norm of the 4D vector.\n\tT\t\tnorm() const\t\t\t\t\t{return (T)sqrt(sqrnorm());}\n\t/// Normalize the quaternion.\n\tvoid\tnormalize();\n\t/// Return the quaternion normalized.\n\tCQuatT\tnormed() const\t\t\t\t\t{CQuatT\tret= *this; ret.normalize(); return ret;}\n\t// @}\n\n\n\t/// \\name Basic Quaternions operations.\n\t// @{\n\t/// Quaternion multiplication/composition.\n\tCQuatT\toperator*(const CQuatT&) const;\n\tCQuatT&\toperator*=(const CQuatT&);\n\t/// Invert this quaternion. If normalized, conjugate is faster and does same thing.\n\tvoid\tinvert();\n\t/// return the quaternion inverted.\n\tCQuatT\tinverted() const\t\t\t\t{CQuatT\tret= *this; ret.invert(); return ret;}\n\t/// return the conjugate of this quaternion.\n\tCQuatT\tconjugate() const\t\t\t\t{return CQuatT(-x, -y, -z, w);}\n\t// @}\n\n\n\t/// \\name To/From other orientation.\n\t// @{\n\t/// Return the equivalent Unit axis of this quaternion.\n\tCVector\tgetAxis() const {CVector ret((float)x,(float)y,(float)z); return ret.normed();}\n\t/// Return the equivalent angle of this quaternion. (in radian).\n\tfloat\tgetAngle() const {return (float)(2*acos(w/norm()));}\n\t/// Return the equivalent Unit  AngleAxis of this quaternion.\n\tCAngleAxis\tgetAngleAxis() const {return CAngleAxis(getAxis(), getAngle());}\n\n\t/// Build a UNIT quaternion from an AngleAxis.\n\tvoid\tsetAngleAxis(const CVector &axis, float angle);\n\t/// Build a UNIT quaternion from an AngleAxis.\n\tvoid\tsetAngleAxis(const CAngleAxis &angAxis) {setAngleAxis(angAxis.Axis, angAxis.Angle);}\n\t// @}\n\n\n\t/// \\name Misc.\n\t// @{\n\t/// compute logn quaternion.\n\tCQuatT\tlog();\n\t/// compute quaternion exponent.\n\tCQuatT\texp();\n\t/// ensure that *this and q are on same side of hypersphere, ie dotProduct(*this,q) is >0, modifying this if necessary.\n\tvoid\tmakeClosest(const CQuatT &o);\n\t/// serial.\n\tvoid\tserial(IStream &f)\n\t{\n\t\tf.serial(x,y,z,w);\n\t}\n\t// @}\n\n\npublic:\n\n\t/// \\name Quaternions static functions.\n\t// @{\n\t/// Return the dotProduct of 2 quaternions.\n\tstatic\tT\t\tdotProduct(const CQuatT<T> &q0, const CQuatT<T> &q1);\n\t/** Quaternion spherical linear interpolation. when t==0, ret==q0, when t==1, ret==q1.\n\t * No hemisphere correction is made.\n\t */\n\tstatic\tCQuatT\tslerp(const CQuatT<T>& q0, const CQuatT<T>& q1, float t);\n\t/** Quaternion Quadratic spherical linear interpolation. when t==0, ret==q0, when t==1, ret==q1.\n\t * No hemisphere correction is made.\n\t */\n\tstatic\tCQuatT\tsquad(const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t);\n\t/** Quaternion Quadratic spherical linear interpolation, with multi revision support.\n\t */\n\tstatic\tCQuatT\tsquadrev(const CAngleAxis &rot, const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t);\n\n\t/// compute lnDiff of q0.inverted()*q1.\n\tstatic\tCQuatT\tlnDif(const CQuatT &q0, const CQuatT &q1);\n\n\t// @}\n\n\n};\n\n\n\n// ***************************************************************************\n\n\n/// \\name Quaternions functions.\n// @{\n\n/// f*quat operator\ntemplate <class T>\ninline\tCQuatT<T>\toperator*(T f, const CQuatT<T> &o) {return o*f;}\n\n// @}\n\n\n\n// ***************************************************************************\n// ***************************************************************************\n// Template implementation.\n// ***************************************************************************\n// ***************************************************************************\n\n\n\n// ***************************************************************************\ntemplate <class T>\ninline bool\tCQuatT<T>::equal(const CQuatT<T>& a, float epsilon) const\n{\n\tif (fabs(x-a.x)<epsilon &&\n\t\tfabs(y-a.y)<epsilon &&\n\t\tfabs(z-a.z)<epsilon &&\n\t\tfabs(w-a.w)<epsilon )\n\t{\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n\n// ***************************************************************************\ntemplate <class T>\ninline CQuatT<T>\tCQuatT<T>::operator*(const CQuatT<T>& o) const\n{\n\t// wres= ww' - v.v'\n\t// vres= wv' + w'v + v^v' ]\n\treturn\tCQuatT<T>(\n\t\t\t\t\t(w*o.x) +(x*o.w) + (y*o.z)-(z*o.y),\n\t\t\t\t\t(w*o.y) +(y*o.w) + (z*o.x)-(x*o.z),\n\t\t\t\t\t(w*o.z) +(z*o.w) + (x*o.y)-(y*o.x),\n\t\t\t\t\t(w*o.w)-(x*o.x)-(y*o.y)-(z*o.z) );\n\n}\n\n// ***************************************************************************\ntemplate <class T>\ninline CQuatT<T>&\tCQuatT<T>::operator*=(const CQuatT<T>& o)\n{\n\t*this= *this * o;\n\treturn *this;\n}\n\n\n// ***************************************************************************\ntemplate <class T>\ninline void\tCQuatT<T>::invert()\n{\n\t// Must invert the norm.\n\tT\tf= sqrnorm();\n\tif(f!=0)\n\t{\n\t\t*this/=f;\n\t}\n\n\t*this= conjugate();\n}\n\n\n// ***************************************************************************\ntemplate <class T>\ninline void\tCQuatT<T>::normalize()\n{\n\tT\tf= norm();\n\tif(f==0)\n\t\tidentity();\n\telse\n\t{\n\t\t*this/=f;\n\t}\n}\n\n\n// ***************************************************************************\ntemplate <class T>\ninline void\tCQuatT<T>::setAngleAxis(const CVector &axis, float angle)\n{\n\tCVector\t\tv= axis;\n\tv.normalize();\n\tdouble\tca= cos(angle/2);\n\tdouble\tsa= sin(angle/2);\n\tx= (T)(v.x*sa);\n\ty= (T)(v.y*sa);\n\tz= (T)(v.z*sa);\n\tw= (T)(ca);\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nT\tCQuatT<T>::dotProduct(const CQuatT<T> &q0, const CQuatT<T> &q1)\n{\n\treturn q0.x*q1.x + q0.y*q1.y + q0.z*q1.z + q0.w*q1.w;\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::slerp(const CQuatT<T>& q0, const CQuatT<T>& q1, float t)\n{\n\t// omega is the 4D angle between q0 and q1.\n\tdouble\tomega, cosom,sinom;\n\tT\tfactq0= 1;\n\tT\ts0,s1;\n\n\tcosom = CQuatT<T>::dotProduct(q0, q1);\n\n\t// Make q0 and q1 on the same hemisphere.\n\t/*if(cosom<0)\n\t{\n\t\tcosom= -cosom;\n\t\tfactq0= -1;\n\t}*/\n\t// ????\n\n\tif ( cosom < 1.0 - NLMISC::QuatEpsilon)\n\t{\n\t\tomega = acos(cosom);\n\t\tsinom = sin(omega);\n\t\ts0 = (T) (sin((1.0f - t)*omega) / sinom);\n\t\ts1 = (T) (sin(t*omega) / sinom);\n\t}\n\telse\n\t{\t// q0 and q1 are nearly the same => sinom nearly 0. We can't slerp.\n\t\t// just linear interpolate.\n\t\ts0 = (T)(1.0 - t);\n\t\ts1 = t;\n\t}\n\n\treturn\tq0*(factq0*s0) + q1*s1;\n\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::squad(const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t)\n{\n\treturn CQuatT<T>::slerp(\n\t\tCQuatT<T>::slerp(q0, q1, t),\n\t\tCQuatT<T>::slerp(tgtQ0, tgtQ1, t),\n\t\t2.f*(1.f-t)*t);\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::squadrev(const CAngleAxis &rot, const CQuatT<T>& q0, const CQuatT<T>& tgtQ0, const CQuatT<T>& tgtQ1, const CQuatT<T>& q1, float t)\n{\n\tfloat s,v;\n\tfloat omega = rot.Angle* 0.5f;\n\tfloat nrevs = 0.0f;\n\tCQuatT<T>\tret,qaxis,pp,qq;\n\n\t// just one rev?\n\t//==============\n\tif (omega<Pi-QuatEpsilon)\n\t{\n\t\tret = CQuatT<T>::squad(q0,tgtQ0,tgtQ1,q1,t);\n\t\treturn ret;\n\t}\n\n\n\t// multirev.\n\t//==============\n\n\t// rotation of 180deg around rot.Axis.  (=> sin(a/2)==sin(Pi/2)==1, and c(a/2)=0).\n\tqaxis.set(rot.Axis.x, rot.Axis.y, rot.Axis.z, 0);\n\n\t// the number of revisions (float!)\n\tnrevs= (float)(omega/Pi);\n\t// Angle>2Pi. squad from 0 to Pi, slerp from Pi to Angle-Pi, squad from Angle-Pi to Angle.\n\ts = t*2*nrevs;\n\n\n\t// So for s, squad from 0 to 1, slerp from 1 to 2*nrevs-1, squad from 2*nrevs-1 to 2*nrevs.\n\tif (s < 1.0f)\n\t{\n\t\t// first part.\n\t\tpp = q0*qaxis;\n\t\tret = CQuatT<T>::squad(q0,tgtQ0,pp,pp,s);\n\t}\n\telse\n\t{\n\t\tv = s - (2.0f*nrevs - 1.0f);\n\t\tif( v <= 0.0f)\n\t\t{\n\t\t\t// middle part\n\t\t\twhile (s >= 2.0f) s -= 2.0f;\n\t\t\tpp = q0*qaxis;\n\t\t\t// s vary from 1 to 2. This is still correct for slerp().\n\t\t\tret = CQuatT<T>::slerp(q0,pp,s);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Last part.\n\t\t\tqq = - q1*qaxis;\n\t\t\tret= CQuatT<T>::squad(qq,qq,tgtQ1,q1,v);\n\t\t}\n\t}\n\n\treturn ret;\n}\n\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::log()\n{\n\tdouble\tlen;\n\tlen = sqrt (x*x + y*y + z*z);\n\n\tif (len < QuatEpsilon)\n\t\treturn CQuatT<T>(0.f, 0.f, 0.f, 0.f);\n\telse\n\t{\n\t\tdouble div = (float) acos (w) / len;\n\t\treturn CQuatT<T>( (T)(x*div), (T)(y*div), (T)(z*div), 0.f);\n\t}\n\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::exp()\n{\n\tdouble\tlen;\n\tlen = sqrt (x*x + y*y + z*z);\n\n\tif (len < QuatEpsilon)\n\t\treturn CQuatT<T>(0.f, 0.f, 0.f, 1.f);\n\telse\n\t{\n\t\tdouble len1 = sin(len) / len;\n\t\treturn CQuatT<T>( (T)(x*len1), (T)(y*len1), (T)(z*len1), (T)cos(len));\n\t}\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nCQuatT<T>\tCQuatT<T>::lnDif(const CQuatT<T> &q0, const CQuatT<T> &q1)\n{\n\tCQuatT<T>\tdif = q0.inverted()*q1;\n\tdif.normalize();\n\n\treturn dif.log();\n}\n\n\n// ***************************************************************************\ntemplate <class T>\nvoid\tCQuatT<T>::makeClosest(const CQuatT<T> &o)\n{\n\tif( dotProduct(*this, o) < 0 )\n\t\t*this= -(*this);\n}\n\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CQuat/CQuatD\n// ***************************************************************************\n// ***************************************************************************\n\n\n\n// ***************************************************************************\n/**\n * A float quaternion.\n * \\author Antoine Viau.\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCQuat : public CQuatT<float>\n{\npublic:\n\tstatic const CQuat\t\tIdentity;\n\n\t/// \\name Object\n\t// @{\n\tCQuat\t&operator=(const CQuatT<float> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}\n\tCQuat(const CQuatT<float> &o) : CQuatT<float>(o) {}\n\tCQuat() {}\n\tCQuat(float X, float Y, float Z, float W) : CQuatT<float>(X,Y,Z,W) {}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuat(const CVector &axis, float angle) : CQuatT<float>(axis, angle) {}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuat(const CAngleAxis &aa) : CQuatT<float>(aa) {}\n\t// @}\n\n};\n\n\n// ***************************************************************************\n/**\n * A double quaternion.\n * \\author Antoine Viau.\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCQuatD : public CQuatT<double>\n{\npublic:\n\tstatic const CQuatD\t\tIdentity;\n\n\t/// \\name Object\n\t// @{\n\tCQuatD\t&operator=(const CQuatT<double> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}\n\tCQuatD(const CQuatT<double> &o) : CQuatT<double>(o) {}\n\tCQuatD() {}\n\tCQuatD(double X, double Y, double Z, double W) : CQuatT<double>(X,Y,Z,W) {}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuatD(const CVector &axis, float angle) : CQuatT<double>(axis, angle) {}\n\t/// ctor of a UNIT quaternion, from an angle axis.\n\tCQuatD(const CAngleAxis &aa) : CQuatT<double>(aa) {}\n\t// @}\n\n\n\t/// \\name CQuat conversion.\n\t// @{\n\tCQuatD(const CQuat &o) {x=o.x; y=o.y; z=o.z; w=o.w;}\n\tCQuatD\t&operator=(const CQuatT<float> &o) {x=o.x; y=o.y; z=o.z; w=o.w; return *this;}\n\toperator\tCQuat() const {return CQuat((float)x, (float)y, (float)z, (float)w);}\n\t// @}\n\n};\n\n\n\n\n\n} // NLMISC\n\n#endif // NL_QUAT_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/random.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_RANDOM_H\n#define NL_RANDOM_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\n/** A simple, os-independant random generator.\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2002\n  */\nclass CRandom\n{\npublic:\n\t// The max value that can be returned by the random generator\n\tenum { RandMax = 0x7fff };\npublic:\n\t// ctor\n\tinline CRandom();\n\t// generate a random value in [0, RandMax]\n\tinline sint32  rand();\n\t// generate a random value in [0, mod]\n\tinline sint32  rand(uint16 mod);\n\t// generate a floating point random value in [0, mod]\n\tinline float  frand(double mod=1.0f);\n\t// generate a random value in [-mod, mod]\n\tinline sint32  randPlusMinus(uint16 mod);\n\t// generate a random value in [-mod, mod]\n\tinline float  frandPlusMinus(double mod=1.0);\n\t// set a new seed for the random generator\n\tinline void   srand(sint32 seed);\nprivate:\n\tsint32 _Seed;\n};\n\n\n//===========================================================================\ninline CRandom::CRandom() : _Seed(1)\n{\n}\n\n//===========================================================================\n// NB : In fact this random generator has the same behaviour than the VC6 one\ninline sint32 CRandom::rand()\n{\n\treturn ((_Seed = _Seed * 214013L + 2531011L) >> 16) & RandMax;\n}\n\n//===========================================================================\ninline sint32 CRandom::rand(uint16 mod)\n{\n\tsint32 m=mod;\n\treturn rand()*(m+1)/(sint32(RandMax)+1);\n}\n\n//===========================================================================\ninline sint32 CRandom::randPlusMinus(uint16 mod)\n{\n\tsint32 m=mod;\n\treturn m - rand()*(2*m+1)/(sint32(RandMax)+1);\n}\n\n//===========================================================================\ninline float CRandom::frand(double mod)\n{\n\tdouble\tr = (double) rand();\n\tr /= (double) RandMax;\n\treturn (float)(r * mod);\n}\n\n//===========================================================================\ninline float CRandom::frandPlusMinus(double mod)\n{\n\treturn frand(2*mod)-(float)mod;\n}\n\n//===========================================================================\ninline void CRandom::srand(sint32 seed)\n{\n\t_Seed = seed;\n}\n\n\n\n}\n\n#endif\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/reader_writer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_READER_WRITER_H\n#define NL_READER_WRITER_H\n\n#include \"types_nl.h\"\n#include \"mutex.h\"\n\n\nnamespace NLMISC {\n\n/**\n * This class allows a reader/writer ressource usage policy.\n * \\author Benjamin Legros\n * \\author Nevrax France\n * \\date 2001\n */\nclass CReaderWriter\n{\nprivate:\n\n\tvolatile CMutex\t_Fairness;\n\tvolatile CMutex\t_ReadersMutex;\n\tvolatile CMutex\t_RWMutex;\n\tvolatile sint\t_ReadersLevel;\n\npublic:\n\n\tCReaderWriter();\n\t~CReaderWriter();\n\n\tvoid\t\t\tenterReader()\n\t{\n\t\tconst_cast<CMutex&>(_Fairness).enter();\n\t\tconst_cast<CMutex&>(_ReadersMutex).enter();\n\t\t++_ReadersLevel;\n\t\tif (_ReadersLevel == 1)\n\t\t\tconst_cast<CMutex&>(_RWMutex).enter();\n\t\tconst_cast<CMutex&>(_ReadersMutex).leave();\n\t\tconst_cast<CMutex&>(_Fairness).leave();\n\t}\n\n\tvoid\t\t\tleaveReader()\n\t{\n\t\tconst_cast<CMutex&>(_ReadersMutex).enter();\n\t\t--_ReadersLevel;\n\t\tif (_ReadersLevel == 0)\n\t\t\tconst_cast<CMutex&>(_RWMutex).leave();\n\t\tconst_cast<CMutex&>(_ReadersMutex).leave();\n\t}\n\n\tvoid\t\t\tenterWriter()\n\t{\n\t\tconst_cast<CMutex&>(_Fairness).enter();\n\t\tconst_cast<CMutex&>(_RWMutex).enter();\n\t\tconst_cast<CMutex&>(_Fairness).leave();\n\t}\n\n\tvoid\t\t\tleaveWriter()\n\t{\n\t\tconst_cast<CMutex&>(_RWMutex).leave();\n\t}\n};\n\n/**\n * This class uses a CReaderWriter object to implement a synchronized object (see mutex.h for standard CSynchronized.)\n * \\author Benjamin Legros\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate <class T>\nclass CRWSynchronized\n{\npublic:\n\n\tclass CReadAccessor\n\t{\n\t\tCRWSynchronized<T>\t\t*_RWSynchronized;\n\n\tpublic:\n\n\t\tCReadAccessor(CRWSynchronized<T> *cs)\n\t\t{\n\t\t\t_RWSynchronized = cs;\n\t\t\tconst_cast<CReaderWriter&>(_RWSynchronized->_RWSync).enterReader();\n\t\t}\n\n\t\t~CReadAccessor()\n\t\t{\n\t\t\tconst_cast<CReaderWriter&>(_RWSynchronized->_RWSync).leaveReader();\n\t\t}\n\n\t\tconst T\t\t&value()\n\t\t{\n\t\t\treturn const_cast<const T&>(_RWSynchronized->_Value);\n\t\t}\n\t};\n\n\tclass CWriteAccessor\n\t{\n\t\tCRWSynchronized<T>\t\t*_RWSynchronized;\n\n\tpublic:\n\n\t\tCWriteAccessor(CRWSynchronized<T> *cs)\n\t\t{\n\t\t\t_RWSynchronized = cs;\n\t\t\tconst_cast<CReaderWriter&>(_RWSynchronized->_RWSync).enterWriter();\n\t\t}\n\n\t\t~CWriteAccessor()\n\t\t{\n\t\t\tconst_cast<CReaderWriter&>(_RWSynchronized->_RWSync).leaveWriter();\n\t\t}\n\n\t\tT\t\t&value()\n\t\t{\n\t\t\treturn const_cast<T&>(_RWSynchronized->_Value);\n\t\t}\n\t};\n\nprivate:\n\tfriend class CRWSynchronized::CReadAccessor;\n\tfriend class CRWSynchronized::CWriteAccessor;\n\n\tvolatile CReaderWriter\t\t_RWSync;\n\n\tvolatile T\t\t\t\t\t_Value;\n\n};\n\n} // NLMISC\n\n\n#endif // NL_READER_WRITER_H\n\n/* End of reader_writer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/rect.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_RECT_H\n#define NL_RECT_H\n\n#include \"types_nl.h\"\n\n\nnamespace NLMISC {\n\nclass CVector2f;\n\n\n/**\n * This class describe an integer 2d rectangle.\n * \\author Cyril Corvazier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CRect\n{\npublic:\n\t/// default ctor\n\tCRect() {}\n\n\t/// Constructor with a 2d point, a width and a height\n\tCRect (sint32 x, sint32 y, uint32 width, uint32 height);\n\n\t/// Constructor with a single 2d point. Build a rectangle with width and height = 0.\n\tCRect (sint32 x, sint32 y)\n\t{\n\t\tX=x;\n\t\tY=y;\n\t\tWidth=0;\n\t\tHeight=0;\n\t}\n\n\t/// Set from a 2d point, a width and a height\n\tvoid setWH(sint32 x, sint32 y, uint32 width, uint32 height);\n\n\t/// Set from 2 2d points\n\tvoid set(sint32 x0, sint32 y0, sint32 x1, sint32 y1);\n\n\t/// Extend the box for including the point which coordinates are passed in parameter.\n\tvoid\t\textend (sint32 x, sint32 y);\n\n\t/// Return the lower X coordinate of the box\n\tsint32\t\tleft() const\n\t{\n\t\treturn X;\n\t}\n\n\t/// Return the higher X coordinate of the box + 1\n\tsint32\t\tright() const\n\t{\n\t\treturn X+(sint32)Width;\n\t}\n\n\t/// Return the lower Y coordinate of the box\n\tsint32\t\ttop() const\n\t{\n\t\treturn Y;\n\t}\n\n\t/// Return the higher Y coordinate of the box + 1\n\tsint32\t\tbottom() const\n\t{\n\t\treturn Y+(sint32)Height;\n\t}\n\n\t/// Compute the x center of the rectangle\n\tsint32\t\tgetXCenter() const\n\t{\n\t\treturn X+(sint32)(Width>>1);\n\t}\n\n\t/// Compute the y center of the rectangle\n\tsint32\t\tgetYCenter() const\n\t{\n\t\treturn Y+(sint32)(Height>>1);\n\t}\n\n\t/// Lower X coordinate of the rect\n\tsint32\t\tX;\n\n\t/// Lower Y coordinate of the rect\n\tsint32\t\tY;\n\n\t/// Width of the rect\n\tuint32\t\tWidth;\n\n\t/// Height of the rect\n\tuint32\t\tHeight;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_RECT_H\n\n/* End of rect.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/report.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_REPORT_H\n#define NL_REPORT_H\n\n#include \"types_nl.h\"\n\nnamespace NLMISC {\n\n/** Display a custom message box.\n *\n * \\param title set the title of the report. If empty, it'll display \"NeL report\".\n * \\param header message displayed before the edit text box. If empty, it displays the default message.\n * \\param body message displayed in the edit text box. This string will be sent by email.\n * \\param debugButton 0 for disabling it, 1 for enable with default behaviors (generate a breakpoint), 2 for enable with no behavior\n *\n *\n *\n * \\return the button clicked or error\n */\n\nenum TReportResult { ReportDebug, ReportIgnore, ReportQuit, ReportError };\n\nTReportResult report (const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const std::string &attachedFile = \"\");\n\n/** call this in the main of your appli to enable email: setReportEmailFunction (sendEmail);\n */\nvoid setReportEmailFunction (void *emailFunction);\n\n} // NLMISC\n\n#endif // NL_REPORT_H\n\n/* End of report.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/resource_ptr.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_RESOURCE_PTR_H\n#define NL_RESOURCE_PTR_H\n\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/smart_ptr.h\"\n\n#include <cstdio>\n\nnamespace NLMISC\n{\n\n// For debug only.\n#define\tREF_TRACE(_s)\t((void)0)\n//#define\tREF_TRACE(_s)\tnlinfo(\"%s: %d \\n\", _s, pinfo!=&CRefCount::NullPtrInfo?pinfo->RefCount:0)\n\n// ***************************************************************************\n/**\n * CResourcePtr: an handle on a ptr. T Must derive from CRefCount.\n * A CResourcePtr is a CRefPtr able to find its pointer using a key.\n *\n * This way, the resource can be loaded, unloaded, changed and the pointer stays valid.\n * Sample:\n *\\code\n\n\t// Our resource type\n\tclass CResource : NLMISC::CRefCount\n\t{\n\tpublic:\n\t\tint data;\n\t    void thisIsGood();\n\t};\n\n\t// Provide a class to retrieve a resource using a key (here, it is a string)\n\tclass CResourceFinder\n\t{\n\tpublic:\n\t\tstatic void *getResource (const std::string &key)\n\t\t{\n\t\t\tstatic CResource a;\n\t\t\tstatic CResource b;\n\t\t\tif (key == \"a\")\n\t\t\t\treturn &a;\n\t\t\tif (key == \"b\")\n\t\t\t\treturn &b;\n\t\t\treturn NULL;\n\t\t}\n\t};\n\n\t// Pointer typedef\n\ttypedef CResourcePtr<CResource, std::string, CResourceFinder> TAPtr;\n\n\t// Exemple of utilsation\n\tvoid\tfoo()\n\t{\n\t\t// Get the \"a\" resource\n\t\tTAPtr\trscA(\"a\");\n\n\t\t//\tThe test call the cast operator and update the cached pointer.\n\t\t//\tIf the pointer has been deleted, the function is called to retrieve a new pointer.\n\t\t//\tIf the resource doesn't exist, it returns NULL.\n\t\tif (rscA)\n\t\t{\n\t\t\t// Use the pointer in cache, this is fast\n\t\t\trscA->thisIsGood();\n\t\t}\n\n\t\t// Get the \"b\" resource\n\t\trsc = \"b\";\n\t\tif (rsc)\n\t\t{\n\t\t\t// Use the pointer in cache, this is fast\n\t\t\trsc->thisIsGood();\n\t\t}\n\t}\n\n \\endcode\n *\n * \\b PERFORMANCE \\b WARNING! operator=() and the cast operator are about 10 times slower than normal pointers. So use them wisely.\n * A good way to do it : using CResourcePtr in a debug mode in which the resources can be unloaded/reloaded, and using CStaticResourcePtr, else.\n * Also, an object used with a CResourcePtr will allocate a small PtrInfo (one only per object, not per ptr).\n * TPtr is the type of the pointed object.\n * TKey is the key used to retrieve the object pointer.\n * TResourceFinder is a class with a static method \"static void *getResource (const TKey &key)\" that returns a pointer on an object using a key.\n * If the function return a non NULL pointer (resource found), the ResourcePtr is initialised with it.\n * \\sa CSmartPtr, CRefCount, CRefPtr\n * \\author Cyril 'Hulud' Corvazier\n */\ntemplate <class TPtr, class TKey, class TResourceFinder>\nclass CResourcePtr\n{\nprivate:\n\tCRefCount::CPtrInfo\t\t*pinfo;\t\t// A ptr to the handle of the object.\n\tTKey\t\t\t\t\tKey;\t\t// The key used to find the pointer\n    mutable TPtr\t\t\t*Ptr;\t\t// A cache for pinfo->Ptr. Useful to speed up  ope->()  and  ope*()\n\n\tvoid\tunRef()  const;\t\t\t\t// Just release the handle pinfo, but do not update pinfo/Ptr, if deleted.\n\npublic:\n\n\t/// Init a NULL Ptr.\n    CResourcePtr();\n\t/// Retrieve a ptr using the key. If the pointer doesn't exist, the CResourcePtr is NULL.\n    CResourcePtr(const TKey &key);\n\t/// Copy constructor.\n    CResourcePtr(const CResourcePtr &copy);\n\t/// Release the RefPtr.\n    ~CResourcePtr(void);\n\n\n\t/// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case.\n\toperator TPtr*()\tconst;\n\t/// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case.\n\tTPtr* getPtr()\t\tconst;\n\n\t/** Indirection operator. Doesn't update the ptr and doesn't test if the pointer has been deleted, and doesn't check NULL.\n\t  * You must test the pointer first using the cast operator.\n\t  */\n    TPtr& operator*(void)\tconst;\n\t/** Selection operator. Doesn't update the ptr and doesn't test if the pointer has been deleted, and doesn't check NULL.\n\t  * You must test the pointer first using the cast operator.\n\t  */\n    TPtr* operator->(void)\tconst;\n\n\t/// Retrieve a ptr using the key. If the pointer doesn't exist, the CResourcePtr is NULL.\n\tCResourcePtr& operator=(const TKey &key);\n\t/// operator=. Giving a NULL pointer is a valid operation.\n    CResourcePtr& operator=(const CResourcePtr &copy);\n};\n\n// ***************************************************************************\n/**\n * CStaticResourcePtr: a CResourcePtr remplacement that doesn't support the resource unload/reload.\n * The object size is the same than a standard pointer.\n * The pointer resource is retrieved at once and is keeped all along the life of the object.\n * No memory / cpu overhead.\n * Typically, you will use the CResourcePtr in a \"reloadable resource version\" of your software and\n * the CStaticResourcePtr in the release version of your software.\n *\n * \\author Cyril 'Hulud' Corvazier\n */\ntemplate <class TPtr, class TKey, class TResourceFinder>\nclass CStaticResourcePtr\n{\nprivate:\n    mutable TPtr\t\t\t*Ptr;\t\t// The pointer\n\npublic:\n\n\t/// Init a NULL Ptr.\n    CStaticResourcePtr();\n\t/// Retrieve a ptr using the key. If the pointer doesn't exist, the CStaticResourcePtr is NULL.\n    CStaticResourcePtr(const TKey &key);\n\t/// Copy constructor.\n    CStaticResourcePtr(const CStaticResourcePtr &copy);\n\t/// Release the RefPtr.\n    ~CStaticResourcePtr(void);\n\n\n\t/// Cast operator. No check are done.\n\toperator TPtr*()\tconst;\n\t/// Cast operator. No check are done.\n\tTPtr* getPtr()\t\tconst;\n\n\t/// Indirection operator. No check are done.\n    TPtr& operator*(void)\tconst;\n\t/// Selection operator. No check are done.\n    TPtr* operator->(void)\tconst;\n\n\t/// Retrieve a ptr using the key. If the pointer doesn't exist, the CStaticResourcePtr is NULL.\n\tCStaticResourcePtr& operator=(const TKey &key);\n\t/// operator=. Giving a NULL pointer is a valid operation.\n    CStaticResourcePtr& operator=(const CStaticResourcePtr &copy);\n};\n\n\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// Implementation.\n// ***************************************************************************\n// ***************************************************************************\n\n\n#include \"resource_ptr_inline.h\"\n#undef\tSMART_TRACE\n#undef\tREF_TRACE\n\n#endif // NL_RESOURCE_PTR_H\n\n/* End of resource_ptr.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/resource_ptr_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_RESOURCE_PTR_INLINE_H\n#define NL_RESOURCE_PTR_INLINE_H\n\n#include \"types_nl.h\"\n\nnamespace\tNLMISC\n{\n\n\n\n// ***************************************************************************\n#ifdef NL_OS_WINDOWS\n#define\tSMART_INLINE __forceinline\n#else\n#define\tSMART_INLINE inline\n#endif\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CResourcePtr.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> SMART_INLINE void\tCResourcePtr<TPtr, TKey, TResourceFinder>::unRef() const\n{\n\tpinfo->RefCount--;\n\tif(pinfo->RefCount==0)\n\t{\n\t\t// In CResourcePtr, Never delete the object.\n\n\t\t// We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it.\n\t\tif(pinfo->IsNullPtrInfo)\n\t\t{\n\t\t\t// This should not happens, but I'm not sure :) ...\n\t\t\t// Reset the NullPtrInfo to a middle round.\n\t\t\tpinfo->RefCount= 0x7FFFFFFF;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the CResourcePtr still point to a valid object.\n\t\t\tif(pinfo->Ptr)\n\t\t\t{\n\t\t\t\t// Inform the Object that no more CResourcePtr points on it.\n\t\t\t\t((TPtr*)(pinfo->Ptr))->pinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t\t\t}\n\t\t\t// Then delete the pinfo.\n\t\t\tdelete pinfo;\n\t\t}\n\t}\n}\n\n\n// ***************************************************************************\n// Cons - dest.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CResourcePtr<TPtr, TKey, TResourceFinder>::CResourcePtr()\n{\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\tREF_TRACE(\"Smart()\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CResourcePtr<TPtr, TKey, TResourceFinder>::CResourcePtr(const TKey &key)\n{\n\tKey = key;\n\tPtr = (TPtr*)TResourceFinder::getResource(Key);\n    if(Ptr)\n\t{\n\t\t// If no CResourcePtr handles v, create a pinfo ref...\n\t\tif(Ptr->pinfo->IsNullPtrInfo)\n\t\t\tPtr->pinfo=new CRefCount::CPtrInfo(Ptr);\n\t\tpinfo=Ptr->pinfo;\n\t\t// v is now used by this.\n\t\tpinfo->RefCount++;\n\t}\n\telse\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\n\tREF_TRACE(\"Smart(TPtr*)\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CResourcePtr<TPtr, TKey, TResourceFinder>::CResourcePtr(const CResourcePtr &copy)\n{\n\tpinfo=copy.pinfo;\n\tpinfo->RefCount++;\n\tPtr= (TPtr*)pinfo->Ptr;\n\tKey= copy.Key;\n\n\tREF_TRACE(\"SmartCopy()\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CResourcePtr<TPtr, TKey, TResourceFinder>::~CResourcePtr(void)\n{\n\tREF_TRACE(\"~Smart()\");\n\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n}\n\n// ***************************************************************************\n// Operators=.\ntemplate <class TPtr, class TKey, class TResourceFinder> CResourcePtr<TPtr, TKey, TResourceFinder> &CResourcePtr<TPtr, TKey, TResourceFinder>::operator=(const TKey &key)\n{\n\tREF_TRACE(\"ope=(TPtr*)Start\");\n\n\tKey = key;\n\tPtr = (TPtr*)TResourceFinder::getResource(Key);\n\tif(Ptr)\n\t{\n\t\t// If no CResourcePtr handles v, create a pinfo ref...\n\t\tif(Ptr->pinfo->IsNullPtrInfo)\n\t\t\tPtr->pinfo=new CRefCount::CPtrInfo(Ptr);\n\t\t// The auto equality test is implicitly done by upcounting first \"Ptr\", then downcounting \"this\".\n\t\tPtr->pinfo->RefCount++;\n\t\tunRef();\n\t\tpinfo= Ptr->pinfo;\n\t}\n\telse\n\t{\n\t\tunRef();\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t}\n\n\n\tREF_TRACE(\"ope=(TPtr*)End\");\n\n\treturn *this;\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> CResourcePtr<TPtr, TKey, TResourceFinder> &CResourcePtr<TPtr, TKey, TResourceFinder>::operator=(const CResourcePtr &copy)\n{\n\tREF_TRACE(\"ope=(Smart)Start\");\n\n\t// The auto equality test is implicitly done by upcounting first \"copy\", then downcounting \"this\".\n\tcopy.pinfo->RefCount++;\n\tunRef();\n\tpinfo=copy.pinfo;\n\t// Must Refresh the ptr and the key.\n\tPtr= (TPtr*)pinfo->Ptr;\n\tKey= copy.Key;\n\n\tREF_TRACE(\"ope=(Smart)End\");\n\treturn *this;\n}\n\n// ***************************************************************************\n// Operations.\n/* Not needed for the moment in CResourcePtr\ntemplate <class TPtr, class TKey, class TResourceFinder> void\tCResourcePtr<T>::kill()\n{\n\tREF_TRACE(\"SmartKill\");\n\n\tT\t*ptr= (T*)pinfo->Ptr;\n\n\t// First, release the refptr.\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\t// Then delete the pointer.\n\tif(ptr)\n\t\tdelete ptr;\n}*/\n\n\n// ***************************************************************************\n// Cast.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CResourcePtr<TPtr, TKey, TResourceFinder>::operator TPtr*()\tconst\n{\n\tREF_TRACE(\"SmartCast TPtr*()\");\n\n\t// Refresh the Ptr.\n\tPtr= (TPtr*)pinfo->Ptr;\n\tif (pinfo != static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo))\n\t{\n\t\t// Does the pointer has been deleted ?\n\t\tif (Ptr == NULL)\n\t\t{\n\t\t\tREF_TRACE(\"SmartCast TPtr*() has been deleted, get a new one\");\n\t\t\t// Try to get it\n\t\t\tPtr = (TPtr*)TResourceFinder::getResource(Key);\n\t\t}\n\t\telse\n\t\t\tREF_TRACE(\"SmartCast TPtr*() has not been deleted\");\n\n\t}\n\telse\n\t\tREF_TRACE(\"SmartCast TPtr*() is NULL\");\n\n\treturn Ptr;\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr* CResourcePtr<TPtr, TKey, TResourceFinder>::getPtr() const\n{\n\treturn static_cast<TPtr*>(*this);\n}\n\n// ***************************************************************************\n// Operators.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr& CResourcePtr<TPtr, TKey, TResourceFinder>::operator*(void)  const\n{\n\tREF_TRACE(\"Smart *()\");\n\treturn *Ptr;\n}\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr* CResourcePtr<TPtr, TKey, TResourceFinder>::operator->(void) const\n{\n\tREF_TRACE(\"Smart ->()\");\n\treturn Ptr;\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CStaticResourcePtr.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\n// Cons - dest.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CStaticResourcePtr<TPtr, TKey, TResourceFinder>::CStaticResourcePtr()\n{\n\tPtr= NULL;\n\n\tREF_TRACE(\"Smart()\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CStaticResourcePtr<TPtr, TKey, TResourceFinder>::CStaticResourcePtr(const TKey &key)\n{\n\tPtr = (TPtr*)TResourceFinder::getResource(key);\n\n\tREF_TRACE(\"Smart(TPtr*)\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CStaticResourcePtr<TPtr, TKey, TResourceFinder>::CStaticResourcePtr(const CStaticResourcePtr &copy)\n{\n\tPtr= copy.Ptr;\n\n\tREF_TRACE(\"SmartCopy()\");\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CStaticResourcePtr<TPtr, TKey, TResourceFinder>::~CStaticResourcePtr(void)\n{\n\tREF_TRACE(\"~Smart()\");\n\n\tPtr= NULL;\n}\n\n// ***************************************************************************\n// Operators=.\ntemplate <class TPtr, class TKey, class TResourceFinder> CStaticResourcePtr<TPtr, TKey, TResourceFinder> &CStaticResourcePtr<TPtr, TKey, TResourceFinder>::operator=(const TKey &key)\n{\n\tREF_TRACE(\"ope=(TPtr*)Start\");\n\n\tPtr = (TPtr*)TResourceFinder::getResource(key);\n\n\tREF_TRACE(\"ope=(TPtr*)End\");\n\n\treturn *this;\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> CStaticResourcePtr<TPtr, TKey, TResourceFinder> &CStaticResourcePtr<TPtr, TKey, TResourceFinder>::operator=(const CStaticResourcePtr &copy)\n{\n\tREF_TRACE(\"ope=(Smart)Start\");\n\n\tPtr= copy.Ptr;\n\n\tREF_TRACE(\"ope=(Smart)End\");\n\treturn *this;\n}\n\n// ***************************************************************************\n// Operations.\n/* Not needed for the moment in CStaticResourcePtr\ntemplate <class TPtr, class TKey, class TResourceFinder> void\tCStaticResourcePtr<T>::kill()\n{\n\tREF_TRACE(\"SmartKill\");\n\n\tT\t*ptr= (T*)pinfo->Ptr;\n\n\t// First, release the refptr.\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\t// Then delete the pointer.\n\tif(ptr)\n\t\tdelete ptr;\n}*/\n\n\n// ***************************************************************************\n// Cast.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline CStaticResourcePtr<TPtr, TKey, TResourceFinder>::operator TPtr*()\tconst\n{\n\tREF_TRACE(\"SmartCast TPtr*()\");\n\n\treturn Ptr;\n}\n\n// ***************************************************************************\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr* CStaticResourcePtr<TPtr, TKey, TResourceFinder>::getPtr() const\n{\n\treturn static_cast<TPtr*>(*this);\n}\n\n// ***************************************************************************\n// Operators.\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr& CStaticResourcePtr<TPtr, TKey, TResourceFinder>::operator*(void)  const\n{\n\tREF_TRACE(\"Smart *()\");\n\treturn *Ptr;\n}\ntemplate <class TPtr, class TKey, class TResourceFinder> inline TPtr* CStaticResourcePtr<TPtr, TKey, TResourceFinder>::operator->(void) const\n{\n\tREF_TRACE(\"Smart ->()\");\n\treturn Ptr;\n}\n\n\n// ***************************************************************************\n#undef\tSMART_INLINE\n\n\n\n} // NLMISC\n\n\n#endif // NL_RESOURCE_PTR_INLINE_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/rgba.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_RGBA_H\n#define NL_RGBA_H\n\n\n#include \"types_nl.h\"\n#include \"common.h\"\n\n#include <algorithm>\n\nnamespace NLMISC\n{\n\nclass\tIStream;\n\n/**\n * Class pixel RGBA\n * \\author Cyril Corvazier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CRGBA\n{\npublic:\n\n\t/// Default constructor. do nothing\n\tCRGBA() {}\n\n\t/**\n\t * Constructor.\n\t * \\param r Red componant.\n\t * \\param g Green componant.\n\t * \\param b Blue componant.\n\t * \\param a Alpha componant.\n\t */\n\tCRGBA(uint8 r, uint8 g, uint8 b, uint8 a=255) :\n\t\tR(r), G(g), B(b), A(a) {}\n\n\t/**\n\t * setup as a packed pixel\n\t */\n\tvoid\tsetPacked(uint packed)\n\t{\n\t\tR= (packed>>24)&255;\n\t\tG= (packed>>16)&255;\n\t\tB= (packed>>8)&255;\n\t\tA= packed & 255;\n\t}\n\n\t/**\n\t * Return a packed pixel\n\t */\n\tuint\tgetPacked() const {return ((uint)R<<24) + ((uint)G<<16) + ((uint)B<<8) + A;}\n\n\t/**\n\t * Comparison operator.\n\t */\n\tbool\toperator<(CRGBA c) const {return getPacked()<c.getPacked();}\n\t/**\n\t * Comparison operator.\n\t */\n\tbool\toperator!=(CRGBA c) const {return !(*this==c);}\n\n\t/**\n\t * Equality operator.\n\t */\n\tbool\toperator==(CRGBA c) const\n\t\t{return R==c.R && G==c.G && B==c.B && A==c.A;}\n\n\t/**\n\t * Serialisation.\n\t * \\param f Stream used for serialisation.\n\t */\n\tvoid    serial (class NLMISC::IStream &f);\n\n\t/**\n\t * Blend two colors.\n\t * \\param c0 Color 0.\n\t * \\param c1 Color 1.\n\t * \\param coef Blend factor. 0~256. 0 return c0 and 256 return c1.\n\t */\n\tvoid blendFromui(CRGBA c0, CRGBA c1, uint coef) // coef must be in [0,256]\n\t{\n\t\tuint\ta1 = coef;\n\t\tuint\ta2 = 256-a1;\n\t\tR = uint8((c0.R*a2 + c1.R*a1) >>8);\n\t\tG = uint8((c0.G*a2 + c1.G*a1) >>8);\n\t\tB = uint8((c0.B*a2 + c1.B*a1) >>8);\n\t\tA = uint8((c0.A*a2 + c1.A*a1) >>8);\n\t}\n\n\t/**\n\t * Modulate colors with a constant.\n\t * \\param c0 Color 0.\n\t * \\param a E [0,256]. c0*a returned into this.\n\t */\n\tvoid\tmodulateFromui (CRGBA c0, uint a)\n\t{\n\t\tR = uint8((c0.R*a) >>8);\n\t\tG = uint8((c0.G*a) >>8);\n\t\tB = uint8((c0.B*a) >>8);\n\t\tA = uint8((c0.A*a) >>8);\n\t}\n\n\n\t/**\n\t * Modulate colors with another color.\n\t * \\param c0 Color 0.\n\t * \\param c1 Color 1. c0*c1 returned into this.\n\t */\n\tvoid\tmodulateFromColor (CRGBA c0, CRGBA c1)\n\t{\n\t\tR = (c0.R*c1.R) >>8;\n\t\tG = (c0.G*c1.G) >>8;\n\t\tB = (c0.B*c1.B) >>8;\n\t\tA = (c0.A*c1.A) >>8;\n\t}\n\n\n\t/**\n\t * Set colors.\n\t * \\param r Red componant.\n\t * \\param g Green componant.\n\t * \\param b Blue componant.\n\t * \\param a Alpha componant.\n\t */\n\tvoid\tset (uint8 r, uint8 g, uint8 b, uint8 a=255);\n\n\t/**\n\t * Convert to gray value\n\t */\n\tuint8 toGray() const;\n\n\t/**\n\t * Get a 16 bits 565 pixel.\n\t */\n\tuint16 get565 () const\n\t{\n\t\treturn ((uint16)(R&0xf8)<<8) | ((uint16)(G&0xfc)<<3) | (uint16)(B>>3);\n\t}\n\n\t/**\n\t * Set the RGB fields with a 16 bits 565 pixel.\n\t */\n\tvoid\tset565(uint16 col)\n\t{\n\t\t// unpack.\n\t\tR= col>>11;\n\t\tG= (col>>5)&0x3F;\n\t\tB= (col)&0x1F;\n\t\t// to 8 bits.\n\t\tR= (R<<3) + (R>>2);\n\t\tG= (G<<2) + (G>>4);\n\t\tB= (B<<3) + (B>>2);\n\t}\n\n\n\t/**\n\t * Compute in this the average of 2 RGBA.\n\t */\n\tvoid\tavg2(CRGBA a, CRGBA b)\n\t{\n\t\tR= ((uint)a.R+(uint)b.R)>>1;\n\t\tG= ((uint)a.G+(uint)b.G)>>1;\n\t\tB= ((uint)a.B+(uint)b.B)>>1;\n\t\tA= ((uint)a.A+(uint)b.A)>>1;\n\t}\n\n\t/**\n\t * Compute in this the average of 4 RGBA.\n\t * The average is \"correct\": +1 is added to the four color, to make a \"round\" like average.\n\t */\n\tvoid\tavg4(CRGBA a, CRGBA b, CRGBA c, CRGBA d)\n\t{\n\t\tR= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2;\n\t\tG= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2;\n\t\tB= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2;\n\t\tA= ((uint)a.A+(uint)b.A+(uint)c.A+(uint)d.A+ 1)>>2;\n\t}\n\n\t/**\n\t *\tDo the sum of 2 rgba, clamp, and store in this\n\t */\n\tvoid\tadd(CRGBA c0, CRGBA c1)\n\t{\n\t\tuint\tr,g,b,a;\n\t\tr= c0.R + c1.R;\tr= std::min(r, 255U);\tR= (uint8)r;\n\t\tg= c0.G + c1.G;\tg= std::min(g, 255U);\tG= (uint8)g;\n\t\tb= c0.B + c1.B;\tb= std::min(b, 255U);\tB= (uint8)b;\n\t\ta= c0.A + c1.A;\ta= std::min(a, 255U);\tA= (uint8)a;\n\t}\n\n\t/**\n\t *\tCompute c0 - c1, and store in this\n\t */\n\tvoid\tsub(CRGBA c0, CRGBA c1)\n\t{\n\t\tsint\tr,g,b,a;\n\t\tr= c0.R - c1.R;\tr= std::max(r, 0);\tR= (uint8)r;\n\t\tg= c0.G - c1.G;\tg= std::max(g, 0);\tG= (uint8)g;\n\t\tb= c0.B - c1.B;\tb= std::max(b, 0);\tB= (uint8)b;\n\t\ta= c0.A - c1.A;\ta= std::max(a, 0);\tA= (uint8)a;\n\t}\n\n\n\t/// \\name RGBOnly methods. Same f() as their homonym, but don't modify A component.\n\t// @{\n\n\t/// see blendFromui()\n\tvoid\tblendFromuiRGBOnly(CRGBA c0, CRGBA c1, uint coef) // coef must be in [0,256]\n\t{\n\t\tuint\ta1 = coef;\n\t\tuint\ta2 = 256-a1;\n\t\tR = uint8((c0.R*a2 + c1.R*a1) >>8);\n\t\tG = uint8((c0.G*a2 + c1.G*a1) >>8);\n\t\tB = uint8((c0.B*a2 + c1.B*a1) >>8);\n\t}\n\t/// see modulateFromui()\n\tvoid\tmodulateFromuiRGBOnly(CRGBA c0, uint a)\n\t{\n\t\tR = uint8((c0.R*a) >>8);\n\t\tG = uint8((c0.G*a) >>8);\n\t\tB = uint8((c0.B*a) >>8);\n\t}\n\t/// see modulateFromColor()\n\tvoid\tmodulateFromColorRGBOnly(CRGBA c0, CRGBA c1)\n\t{\n\t\tR = (c0.R*c1.R) >>8;\n\t\tG = (c0.G*c1.G) >>8;\n\t\tB = (c0.B*c1.B) >>8;\n\t}\n\t/// see avg2()\n\tvoid\tavg2RGBOnly(CRGBA a, CRGBA b)\n\t{\n\t\tR= ((uint)a.R+(uint)b.R)>>1;\n\t\tG= ((uint)a.G+(uint)b.G)>>1;\n\t\tB= ((uint)a.B+(uint)b.B)>>1;\n\t}\n\t/// see avg4()\n\tvoid\tavg4RGBOnly(CRGBA a, CRGBA b, CRGBA c, CRGBA d)\n\t{\n\t\tR= ((uint)a.R+(uint)b.R+(uint)c.R+(uint)d.R+ 1)>>2;\n\t\tG= ((uint)a.G+(uint)b.G+(uint)c.G+(uint)d.G+ 1)>>2;\n\t\tB= ((uint)a.B+(uint)b.B+(uint)c.B+(uint)d.B+ 1)>>2;\n\t}\n\t/// see add()\n\tvoid\taddRGBOnly(CRGBA c0, CRGBA c1)\n\t{\n\t\tuint\tr,g,b;\n\t\tr= c0.R + c1.R;\tr= std::min(r, 255U);\tR= (uint8)r;\n\t\tg= c0.G + c1.G;\tg= std::min(g, 255U);\tG= (uint8)g;\n\t\tb= c0.B + c1.B;\tb= std::min(b, 255U);\tB= (uint8)b;\n\t}\n\t/// see sub()\n\tvoid\tsubRGBOnly(CRGBA c0, CRGBA c1)\n\t{\n\t\tsint\tr,g,b;\n\t\tr= c0.R - c1.R;\tr= std::max(r, 0);\tR= (uint8)r;\n\t\tg= c0.G - c1.G;\tg= std::max(g, 0);\tG= (uint8)g;\n\t\tb= c0.B - c1.B;\tb= std::max(b, 0);\tB= (uint8)b;\n\t}\n\n\n\n\t// @}\n\n\t///\\name Color group manipulation\n\t//@{\n\t\t/** Add a group of colors with saturation, using mmx instructions when present.\n\t\t  * \\param dest The destination color buffer, encoded as CRGBA's.\n\t\t  * \\param src1 The first source color buffer, encoded as CRGBA's.\n\t\t  * \\param src2 The second source color buffer, encoded as CRGBA's.\n\t\t  * \\param numColors The number of colors to compute\n\t\t  * \\param Stride between each source color.\n\t\t  * \\param Stride between each destination color.\n\t\t  * \\param Dup the number of time the result must be duplicated in the destination.\n\t\t  */\n\t\tstatic void addColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1);\n\n\t\t/** Modulate a group of colors with saturation, using mmx instructions when present.\n\t\t  * \\param dest The destination color buffer, encoded as CRGBA's.\n\t\t  * \\param src1 The first source color buffer, encoded as CRGBA's.\n\t\t  * \\param src2 The second source color buffer, encoded as CRGBA's.\n\t\t  * \\param numColors The number of colors to compute\n\t\t  * \\param Stride between each color.  It is the same for sources and destination.\n\t\t  */\n\t\tstatic void modulateColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1);\n\n\t\t/** Subtract a group of colors with saturation (src1 - src2), using mmx instructions when present.\n\t\t  * \\param dest The destination color buffer, encoded as CRGBA's.\n\t\t  * \\param src1 The first source color buffer, encoded as CRGBA's.\n\t\t  * \\param src2 The second source color buffer, encoded as CRGBA's.\n\t\t  * \\param numColors The number of colors to compute\n\t\t  * \\param Stride between each color.  It is the same for sources and destination.\n\t\t  */\n\t\tstatic void subtractColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride = sizeof(CRGBA), uint destStride = sizeof(CRGBA), uint dup = 1);\n\t//@}\n\n\t/// \\name Color space conversions RGB only\n\t//@{\n\t\t\t/** Convert to HLS color space.\n\t\t\t  * Lightness and satuation ranges from 0 to 1\n\t\t\t  * There's no range for hue, (all hues colors range from 0 to 360, from 360 to 720 and so on)\n\t\t\t  * \\return true if the color is achromatic\n\t\t\t  */\n\t\t\tbool convertToHLS(float &h, float &l, float &S) const;\n\n\t\t\t/** Build from HLS valued\n\t\t\t  *\tEach component ranges from 0 to 1.f\n\t\t\t  */\n\t\t\tvoid buildFromHLS(float h, float l, float s);\n\t//@}\n\n\tstatic CRGBA stringToRGBA( const char *ptr );\n\n\tstd::string toString() const;\n\tbool fromString( const std::string &s );\n\n\n\t/// Swap the B and R components, to simulate a CBRGA\n\tvoid\tswapBR()\n\t{\n\t\tstd::swap(R,B);\n\t}\n\n\n\t/// Red componant.\n\tuint8\tR;\n\t/// Green componant.\n\tuint8\tG;\n\t/// Blue componant.\n\tuint8\tB;\n\t/// Alpha componant.\n\tuint8\tA;\n\n\n\t/// some colors\n\tstatic const CRGBA Black ;\n\tstatic const CRGBA Red ;\n\tstatic const CRGBA Green ;\n\tstatic const CRGBA Yellow ;\n\tstatic const CRGBA Blue ;\n\tstatic const CRGBA Magenta ;\n\tstatic const CRGBA Cyan ;\n\tstatic const CRGBA White ;\n};\n\n\n/**\n * Class pixel BGRA, Windows style pixel.\n * \\author Cyril Corvazier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CBGRA\n{\npublic:\n\n\t/// Default constructor. do nothing\n\tCBGRA() {}\n\n\t/**\n\t * Constructor from a CRGBA\n\t * \\param c CRGBA color.\n\t */\n\tCBGRA(CRGBA c)\n\t{\n\t\tR=c.R;\n\t\tG=c.G;\n\t\tB=c.B;\n\t\tA=c.A;\n\t};\n\n\t/**\n\t * Constructor.\n\t * \\param r Red componant.\n\t * \\param g Green componant.\n\t * \\param b Blue componant.\n\t * \\param a Alpha componant.\n\t */\n\tCBGRA(uint8 r, uint8 g, uint8 b, uint8 a=255) :\n\t\tB(b), G(g), R(r), A(a) {}\n\n\t/**\n\t * Cast operator to CRGBA.\n\t */\n\toperator CRGBA()\n\t{\n\t\treturn CRGBA (R, G, B, A);\n\t}\n\n\t/**\n\t * Return a packed pixel\n\t */\n\tuint\tgetPacked() const\n\t{\n\t\treturn ((uint)B<<24) + ((uint)G<<16) + ((uint)R<<8) + A;\n\t}\n\n\t/**\n\t * Comparison operator.\n\t */\n\tbool\toperator<(const CBGRA &c) const\n\t{\n\t\treturn getPacked()<c.getPacked();\n\t}\n\n\t/**\n\t * Equality operator.\n\t */\n\tbool\toperator==(const CBGRA &c) const\n\t{\n\t\treturn R==c.R && G==c.G && B==c.B && A==c.A;\n\t}\n\n\t/**\n\t * Serialisation.\n\t * \\param f Stream used for serialisation.\n\t */\n\tvoid    serial(class NLMISC::IStream &f);\n\n\t/**\n\t * Blend two colors.\n\t * \\param c0 Color 0.\n\t * \\param c1 Color 1.\n\t * \\param factor Blend factor. 0~256. 0 return c0 and 256 return c1.\n\t */\n\tvoid blendFromui(CBGRA &c0, CBGRA &c1, uint factor);\n\n\t/**\n\t * Set colors.\n\t * \\param r Red componant.\n\t * \\param g Green componant.\n\t * \\param b Blue componant.\n\t * \\param a Alpha componant.\n\t */\n\tvoid set(uint8 r, uint8 g, uint8 b, uint8 a);\n\n\t/// Blue componant.\n\tuint8\tB;\n\t/// Green componant.\n\tuint8\tG;\n\t/// Red componant.\n\tuint8\tR;\n\t/// Alpha componant.\n\tuint8\tA;\n};\n\n// specialisation of the 'blend' function found in algo.h\ntemplate <class U>\ninline CRGBA blend(CRGBA c0, CRGBA c1, U blendFactor)\n{\n\tCRGBA result;\n\tresult.blendFromui(c0, c1, (uint) ((float) blendFactor * 256.f));\n\treturn result;\n}\n\n/**\n * Class pixel float RGBA\n * \\author Cyril Corvazier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CRGBAF\n{\npublic:\n\t/// Default constructor. do nothing\n\tCRGBAF ()\n\t{}\n\n\t/**\n\t * Constructor.\n\t * \\param _r Red componant.\n\t * \\param _g Green componant.\n\t * \\param _b Blue componant.\n\t * \\param _a Alpha componant.\n\t */\n\tCRGBAF (float _r, float _g, float _b, float _a=1.f)\n\t{\n\t\tR=_r;\n\t\tG=_g;\n\t\tB=_b;\n\t\tA=_a;\n\t}\n\n\t/**\n\t * Constructor with a CRGBA.\n\t * \\param c CRGBA color.\n\t */\n\tCRGBAF (CRGBA c)\n\t{\n\t\tR=(float)c.R/255.f;\n\t\tG=(float)c.G/255.f;\n\t\tB=(float)c.B/255.f;\n\t\tA=(float)c.A/255.f;\n\t}\n\n\t/**\n\t * Cast operator to CRGBA.\n\t */\n\toperator CRGBA() const\n\t{\n\t\tuint8 _r=(uint8)(R*255.f);\n\t\tuint8 _g=(uint8)(G*255.f);\n\t\tuint8 _b=(uint8)(B*255.f);\n\t\tuint8 _a=(uint8)(A*255.f);\n\t\treturn CRGBA (_r, _g, _b, _a);\n\t}\n\n\t/**\n\t * Normalize component between [0.f,1.f]\n\t */\n\tvoid normalize ()\n\t{\n\t\tR= (R>1.f) ? 1.f : (R<0.f) ? 0.f : R;\n\t\tG= (G>1.f) ? 1.f : (G<0.f) ? 0.f : G;\n\t\tB= (B>1.f) ? 1.f : (B<0.f) ? 0.f : B;\n\t\tA= (A>1.f) ? 1.f : (A<0.f) ? 0.f : A;\n\t}\n\n\t/**\n\t * Add operator. Sum components.\n\t * \\param c CRGBA color.\n\t * \\return Return the result of the opertor\n\t */\n\tCRGBAF operator+ (const CRGBAF& c) const\n\t{\n\t\treturn CRGBAF (R+c.R, G+c.G, B+c.B, A+c.A);\n\t}\n\n\t/**\n\t * Sub operator. Substract components.\n\t * \\param c CRGBA color.\n\t * \\return Return the result of the opertor\n\t */\n\tCRGBAF operator- (const CRGBAF& c) const\n\t{\n\t\treturn CRGBAF (R-c.R, G-c.G, B-c.B, A-c.A);\n\t}\n\n\t/**\n\t * Mul operator. Mul components.\n\t * \\param c CRGBA color.\n\t * \\return Return the result of the opertor\n\t */\n\tCRGBAF operator* (const CRGBAF& c) const\n\t{\n\t\treturn CRGBAF (R*c.R, G*c.G, B*c.B, A*c.A);\n\t}\n\n\t/**\n\t * Mul float operator. Mul each component by f.\n\t * \\param f Float factor.\n\t * \\return Return the result of the opertor\n\t */\n\tCRGBAF operator* (float f) const\n\t{\n\t\treturn CRGBAF (R*f, G*f, B*f, A*f);\n\t}\n\n\t/**\n\t * Div float operator. Div each component by f.\n\t * \\param f Float factor.\n\t * \\return Return the result of the opertor\n\t */\n\tCRGBAF operator/ (float f) const\n\t{\n\t\treturn CRGBAF (R/f, G/f, B/f, A/f);\n\t}\n\n\t/**\n\t * Add operator. Add each component.\n\t * \\param c CRGBA color.\n\t * \\return Return a reference on the caller object\n\t */\n\tCRGBAF& operator+= (const CRGBAF& c)\n\t{\n\t\tR+=c.R;\n\t\tG+=c.G;\n\t\tB+=c.B;\n\t\tA+=c.A;\n\t\treturn *this;\n\t}\n\n\t/**\n\t * Sub operator. Substract each component.\n\t * \\param c CRGBA color.\n\t * \\return Return a reference on the caller object\n\t */\n\tCRGBAF& operator-= (const CRGBAF& c)\n\t{\n\t\tR-=c.R;\n\t\tG-=c.G;\n\t\tB-=c.B;\n\t\tA-=c.A;\n\t\treturn *this;\n\t}\n\n\t/**\n\t * Mul operator. Multiplate each component.\n\t * \\param c CRGBA color.\n\t * \\return Return a reference on the caller object\n\t */\n\tCRGBAF& operator*= (const CRGBAF& c)\n\t{\n\t\tR*=c.R;\n\t\tG*=c.G;\n\t\tB*=c.B;\n\t\tA*=c.A;\n\t\treturn *this;\n\t}\n\n\t/**\n\t * Mul float operator. Multiplate each component by f.\n\t * \\param f Float factor.\n\t * \\return Return a reference on the caller object\n\t */\n\tCRGBAF& operator*= (float f)\n\t{\n\t\tR*=f;\n\t\tG*=f;\n\t\tB*=f;\n\t\tA*=f;\n\t\treturn *this;\n\t}\n\n\t/**\n\t * Div float operator. Divide each component by f.\n\t * \\param f Float factor.\n\t * \\return Return a reference on the caller object\n\t */\n\tCRGBAF& operator/= (float f)\n\t{\n\t\tR/=f;\n\t\tG/=f;\n\t\tB/=f;\n\t\tA/=f;\n\t\treturn *this;\n\t}\n\n\t/**\n\t * Serialisation.\n\t * \\param f Stream used for serialisation.\n\t */\n\tvoid    serial(class NLMISC::IStream &f);\n\n\t/**\n\t * Set colors.\n\t * \\param r Red componant.\n\t * \\param g Green componant.\n\t * \\param b Blue componant.\n\t * \\param a Alpha componant.\n\t */\n\tvoid set(float r, float g, float b, float a);\n\n\t/// Red componant.\n\tfloat\tR;\n\t/// Green componant.\n\tfloat\tG;\n\t/// Blue componant.\n\tfloat\tB;\n\t/// Alpha componant.\n\tfloat\tA;\n};\n\n/**\n * Mul float operator. Multiplate each component by f.\n * \\param f Float factor.\n * \\return Return the result\n */\ninline CRGBAF operator* (float f, const CRGBAF& c)\n{\n\treturn CRGBAF (c.R*f, c.G*f, c.B*f, c.A*f);\n}\n\n#ifdef NL_LITTLE_ENDIAN\n#define NL_RGBA_R_DWORD_MASK (0x000000ff)\n#define NL_RGBA_G_DWORD_MASK (0x0000ff00)\n#define NL_RGBA_B_DWORD_MASK (0x00ff0000)\n#define NL_RGBA_A_DWORD_MASK (0xff000000)\n#else // NL_LITTLE_ENDIAN\n#define NL_RGBA_R_DWORD_MASK (0xff0000)\n#define NL_RGBA_G_DWORD_MASK (0x00ff0000)\n#define NL_RGBA_B_DWORD_MASK (0x0000ff00)\n#define NL_RGBA_A_DWORD_MASK (0x000000ff)\n#endif // NL_LITTLE_ENDIAN\n\n} // NLMISC\n\n\n#endif // NL_RGBA_H\n\n/* End of rgba.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/sha1.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SHA1_H\n#define NL_SHA1_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n#include \"stream.h\"\n\n#include <string>\n\nstruct CHashKey\n{\n\tCHashKey () { HashKeyString.resize(20); }\n\n\tCHashKey (const unsigned char Message_Digest[20])\n\t{\n\t\tHashKeyString = \"\";\n\t\tfor(sint i = 0; i < 20 ; ++i)\n\t\t{\n\t\t\tHashKeyString += Message_Digest[i];\n\t\t}\n\t}\n\n\t// Init the hash key with a binary key format or a text key format\n\tCHashKey (const std::string &str)\n\t{\n\t\tif (str.size() == 20)\n\t\t{\n\t\t\tHashKeyString = str;\n\t\t}\n\t\telse if (str.size() == 40)\n\t\t{\n\t\t\tHashKeyString = \"\";\n\t\t\tfor(uint i = 0; i < str.size(); i+=2)\n\t\t\t{\n\t\t\t\tuint8 val;\n\t\t\t\tif (isdigit((unsigned char)str[i+0]))\n\t\t\t\t\tval = str[i+0]-'0';\n\t\t\t\telse\n\t\t\t\t\tval = 10+tolower(str[i+0])-'a';\n\t\t\t\tval *= 16;\n\t\t\t\tif (isdigit((unsigned char)str[i+1]))\n\t\t\t\t\tval += str[i+1]-'0';\n\t\t\t\telse\n\t\t\t\t\tval += 10+tolower(str[i+1])-'a';\n\n\t\t\t\tHashKeyString += val;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"SHA: Bad hash key format\");\n\t\t}\n\t}\n\n\t// return the hash key in text format\n\tstd::string toString() const\n\t{\n\t\tstd::string str;\n\t\tfor (uint i = 0; i < HashKeyString.size(); i++)\n\t\t{\n\t\t\tstr += NLMISC::toString(\"%02X\", (uint8)(HashKeyString[i]));\n\t\t}\n\t\treturn str;\n\t}\n\n\t// serial the hash key in binary format\n\tvoid serial (NLMISC::IStream &stream)\n\t{\n\t\tstream.serial (HashKeyString);\n\t}\n\n\tbool\toperator==(const CHashKey &v) const\n\t{\n\t\treturn HashKeyString == v.HashKeyString;\n\t}\n\n\t// this string is always 20 bytes long and is the code in binary format (can't print it directly)\n\tstd::string HashKeyString;\n};\n\ninline bool operator <(const struct CHashKey &a,const struct CHashKey &b)\n{\n\treturn a.HashKeyString<b.HashKeyString;\n}\n\n// This function get a filename (it works with big files) and returns his SHA hash key\n// when forcePath is true, it doesn't use NLMISC::lookup\nCHashKey getSHA1(const std::string &filename, bool forcePath = false);\n\n// This function get a buffer with size and returns his SHA hash key\nCHashKey getSHA1(const uint8 *buffer, uint32 size);\n\n// This function get a buffer and key with size and returns his HMAC-SHA1 hash key\nCHashKey getHMacSHA1(const uint8 *text, uint32 text_len, const uint8 *key, uint32 key_len);\n\n#endif // NL_SHA1_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/shared_memory.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SHARED_MEMORY_H\n#define NL_SHARED_MEMORY_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n#include <map>\n#endif\n\nnamespace NLMISC {\n\n\n#ifdef NL_OS_WINDOWS\ntypedef const char *TSharedMemId;\n#else\ntypedef key_t TSharedMemId;\n#endif\n\n\n/* Helpers:\n * toSharedMemId: converts an integer to TSharedMemId\n * NL_SMID: format type used for printf syntax. Ex: nldebug( \"Segment %\"NL_SMID\" was created\", sharedMemId );\n */\n#ifdef NL_OS_WINDOWS\n#define toSharedMemId( id ) toString( \"NeLSM_%d\", id ).c_str()\n#define NL_SMID \"s\"\n#else\n#define toSharedMemId( id ) (id)\n#define NL_SMID \"d\"\n#endif\n\n\n/**\n * Encapsulation of shared memory APIs.\n * Using file mapping under Windows, System V shared memory (shm) under Linux.\n *\n * Note: under Linux, an option could be added to prevent a segment to be swapped out.\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2002\n */\nclass CSharedMemory\n{\npublic:\n\n\t// Constructor\n\t//CSharedMemory();\n\n\t/**\n\t * Create a shared memory segment and get access to it. The id must not be used.\n\t * The id 0x3a732235 is reserved by the NeL memory manager.\n\t * \\return Access address of the segment of the choosen size\n\t */\n\tstatic void *\t\tcreateSharedMemory( TSharedMemId sharedMemId, uint32 size );\n\n\t/**\n\t * Get access to an existing shared memory segment. The id must be used.\n\t * \\return Access address of the segment. Its size was determined at the creation.\n\t */\n\tstatic void *\t\taccessSharedMemory( TSharedMemId sharedMemId );\n\n\t/**\n\t * Close (detach) a shared memory segment, given the address returned by createSharedMemory()\n\t * or accessSharedMemory(). Must be called by each process that called createSharedMemory()\n\t * or accessSharedMemory().\n\t */\n\tstatic bool\t\t\tcloseSharedMemory( void * accessAddress );\n\n  /**\n   * Destroy a shared memory segment (must be called by the process that created the segment,\n   * not by the accessors).\n   *\n   * \"Rescue feature\": set \"force\" to true if a segment was created and left out of\n   * control (meaning a new createSharedMemory() with the same sharedMemId fails), but\n   * before, make sure the segment really belongs to you!\n   *\n   * Note: this method does nothing under Windows, destroying is automatic.\n   * Under Unix, the segment will actually be destroyed after the last detach\n   * (quoting shmctl man page). It means after calling destroySharedMemory(), the\n   * segment is still accessible by another process until it calls closeSharedMemory().\n   */\n  static void destroySharedMemory( TSharedMemId sharedMemId, bool force=false );\n};\n\n\n} // NLMISC\n\n\n#endif // NL_SHARED_MEMORY_H\n\n/* End of shared_memory.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/sheet_id.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SHEET_ID_H\n#define NL_SHEET_ID_H\n\n// misc\n#include \"types_nl.h\"\n#include \"stream.h\"\n#include \"static_map.h\"\n\n// std\n#include <string>\n#include <map>\n\nnamespace NLMISC {\n\n#ifdef NL_DEBUG\n#\tdefine NL_DEBUG_SHEET_ID\n#endif\n\n// Use 24 bits id and 8 bits file types\n#define NL_SHEET_ID_ID_BITS\t\t24\n#define NL_SHEET_ID_TYPE_BITS\t32 - NL_SHEET_ID_ID_BITS\n\n/**\n * CSheetId\n *\n * \\author Stephane Coutelas\n * \\author Nevrax France\n * \\date 2002\n */\nclass CSheetId\n{\n\npublic :\n\t/// Unknow CSheetId is similar as an NULL pointer.\n\tstatic const CSheetId Unknown;\n\n\t/**\n\t *\tConstructor\n\t */\n\texplicit CSheetId( uint32 sheetRef = 0 );\n\n\t/**\n\t *\tConstructor\n\t */\n\texplicit CSheetId( const std::string& sheetName );\n\n\t/**\n\t * Constructor, uses defaultType as extension when sheetName\n\t * contains no file extension.\n\t */\n\texplicit CSheetId( const std::string& sheetName, const std::string &defaultType );\n\n\t// build from a string and returns true if the build succeed\n\tbool\t buildSheetId(const std::string& sheetName);\n\n\t// build from a SubSheetId and a type\n\tvoid\t buildSheetId(uint32 shortId, uint32 type);\n\n\t/**\n\t *\tLoad the association sheet ref / sheet name\n\t */\n\tstatic void init(bool removeUnknownSheet = true);\n\n\t/**\n\t *\tInit the sheet id to work without knowlege of sheet name\n\t */\n\tstatic void initWithoutSheet();\n\n\t/**\n\t * Remove all allocated memory\n\t */\n\tstatic void uninit();\n\n\t/**\n\t * Return the **whole** sheet id (id+type)\n\t */\n\tuint32 asInt() const { return _Id.Id; }\n\n\t/**\n\t * Return the sheet type (sub part of the sheetid)\n\t */\n\tuint32 getSheetType() const { return _Id.IdInfos.Type; }\n\n\t/**\n\t * Return the sheet sub id (sub part of the sheetid)\n\t */\n\tuint32 getShortId() const { return _Id.IdInfos.Id; }\n\n\t/**\n\t *\tOperator=\n\t */\n\tCSheetId& operator=( const CSheetId& sheetId );\n\n\t/**\n\t *\tOperator=\n\t */\n\tCSheetId& operator=( const std::string& sheetName );\n\n\t/**\n\t *\tOperator=\n\t */\n\tCSheetId& operator=( uint32 sheetRef );\n\n\t/**\n\t *\tOperator<\n\t */\n\tbool operator < (const CSheetId& sheetRef ) const;\n\n\t/**\n\t *\tOperator==\n\t */\n\tinline bool operator == (const CSheetId& sheetRef ) const { return ( _Id.Id == sheetRef._Id.Id) ; }\n\n\t/**\n\t *\tOperator !=\n\t */\n\tinline bool operator != (const CSheetId& sheetRef ) const { return (_Id.Id != sheetRef._Id.Id) ; }\n\n\n\n\n\t/**\n\t * Return the sheet id as a string\n\t * If the sheet id is not found, then:\n\t * - if 'ifNotFoundUseNumericId==false' the returned string is \"<Sheet %d not found in sheet_id.bin>\" with the id in %d\n\t * - if 'ifNotFoundUseNumericId==tue'   the returned string is \"#%u\" with the id in %u\n\t */\n\tstd::string toString(bool ifNotFoundUseNumericId=false) const;\n\n\t/**\n\t *\tSerial\n\t */\n\tvoid serial(NLMISC::IStream\t&f) throw(NLMISC::EStream);\n\tvoid serialString(NLMISC::IStream &f, const std::string &defaultType = \"\") throw(NLMISC::EStream);\n\n\t/**\n\t *  Display the list of valid sheet ids with their associated file names\n\t *  if (type != -1) then restrict list to given type\n\t */\n\tstatic void display();\n\tstatic void display(uint32 type);\n\n\t/**\n\t *  Generate a vector of all the sheet ids of a given type\n\t *  This operation is non-destructive, the new entries are appended to the result vector\n\t *  note: fileExtension *not* include the '.' eg \"bla\" and *not* \".bla\"\n\t **/\n\tstatic void buildIdVector(std::vector <CSheetId> &result);\n\tstatic void buildIdVector(std::vector <CSheetId> &result, uint32 type);\n\tstatic void buildIdVector(std::vector <CSheetId> &result, std::vector <std::string> &resultFilenames, uint32 type);\n\tstatic void buildIdVector(std::vector <CSheetId> &result, const std::string &fileExtension);\n\tstatic void buildIdVector(std::vector <CSheetId> &result, std::vector <std::string> &resultFilenames, const std::string &fileExtension);\n\n\t/**\n\t *  Convert between file extensions and numeric sheet types\n\t *  note: fileExtension *not* include the '.' eg \"bla\" and *not* \".bla\"\n\t **/\n\tstatic const std::string &fileExtensionFromType(uint32 type);\n\tstatic uint32 typeFromFileExtension(const std::string &fileExtension);\n\nprivate :\n\n\t/// sheet id\n\tunion TSheetId\n\t{\n\t\tuint32\t\tId;\n\n\t\tstruct\n\t\t{\n\t\t\tuint32\tType\t: NL_SHEET_ID_TYPE_BITS;\n\t\t\tuint32\tId\t\t: NL_SHEET_ID_ID_BITS;\n\t\t} IdInfos;\n\t};\n\tTSheetId _Id;\n\n#ifdef NL_DEBUG_SHEET_ID\n\t// Add some valuable debug information to sheetId\n\tconst char\t*_DebugSheetName;\n#endif\n\n\t/// associate sheet id and sheet name\n\t//static std::map<uint32,std::string> _SheetIdToName;\n\t//static std::map<std::string,uint32> _SheetNameToId;\n\n\tclass CChar\n\t{\n\tpublic:\n\t\tchar *Ptr;\n\t\tCChar() { Ptr = NULL; }\n\t\tCChar(const CChar& c) { Ptr = c.Ptr; } // WARNING : Share Pointer\n\t};\n\n\tclass CCharComp\n\t{\n\tpublic:\n\t\tbool operator()(CChar x, CChar y) const\n\t\t{\n\t\t\treturn strcmp(x.Ptr, y.Ptr) < 0;\n\t\t}\n\t};\n\n\tstatic CChar _AllStrings;\n\tstatic CStaticMap<uint32, CChar> _SheetIdToName;\n\tstatic CStaticMap<CChar,uint32, CCharComp> _SheetNameToId;\n\n\tstatic std::vector<std::string> _FileExtensions;\n\tstatic bool _Initialised;\n\n\tstatic bool _RemoveUnknownSheet;\n\n\tstatic void loadSheetId ();\n\tstatic void loadSheetAlias ();\n\tstatic void cbFileChange (const std::string &filename);\n\n\t/**\n\t * When initialized without sheet_id.bin, the sheet id are assigned \n\t * dynamically. Separate maps are used, because in sheet_id.bin \n\t * mode it uses static maps optimized during load.\n\t */\n\tstatic bool _DontHaveSheetKnowledge;\n\tstatic std::map<std::string, uint32> _DevTypeNameToId;\n\t/// outer vector is type, inner vector is sheet id\n\tstatic std::vector<std::vector<std::string> > _DevSheetIdToName;\n\tstatic std::map<std::string, uint32> _DevSheetNameToId;\n};\n\n\n/**\n * Class to be used as a hash traits for a hash_map accessed by CSheetId\n * Ex: hash_map< CSheetId, CMyData, CSheetIdHashMapTraits> _MyHashMap;\n */\nclass CSheetIdHashMapTraits\n{\npublic:\n\tenum { bucket_size = 4, min_buckets = 8, };\n\tinline size_t operator() ( const CSheetId& sheetId ) const\n\t{\n\t\treturn sheetId.asInt() >> 5;\n\t}\n\tbool operator() (const CSheetId &strId1, const CSheetId &strId2) const\n\t{\n\t\treturn strId1.asInt() < strId2.asInt();\n\t}\n};\n\n} // NLMISC\n\n#endif // NL_SHEET_ID_H\n\n/* End of sheet_id.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/singleton.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SINGLETON_H\n#define NL_SINGLETON_H\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/app_context.h\"\n\nnamespace NLMISC\n{\n\n\t/**\n\t * Example:\n\t * \\code\n\t\tstruct CFooSingleton : public CSingleton<CFooSingleton>\n\t\t{\n\t\t\tvoid foo() { nlinfo(\"foo!\"); }\n\t\t};\n\n\t\t// call the foo function:\n\t\tCFooSingleton::getInstance().foo();\n\n\t * \\endcode\n\t * \\author Vianney Lecroart\n\t * \\author Nevrax France\n\t * \\date 2004\n\t */\n\n\ttemplate<class T>\n\tclass CSingleton\n\t{\n\tpublic:\n\t\tvirtual ~CSingleton() {}\n\n\t\t/// returns a reference and not a pointer to be sure that the user\n\t\t/// doesn't have to test the return value and can directly access the class\n\t\tstatic T &getInstance()\n\t\t{\n\t\t\tif(!Instance)\n\t\t\t{\n\t\t\t\tInstance = new T;\n\t\t\t\tnlassert(Instance);\n\t\t\t}\n\t\t\treturn *Instance;\n\t\t}\n\n\t\t/// shorter version of getInstance()\n\t\tstatic T &instance() { return getInstance(); }\n\n\t\tstatic void releaseInstance()\n\t\t{\n\t\t\tif(Instance)\n\t\t\t{\n\t\t\t\tdelete Instance;\n\t\t\t\tInstance = NULL;\n\t\t\t}\n\t\t}\n\n\tprotected:\n\t\t/// no public ctor to be sure that the user can't create an instance\n\t\tCSingleton()\n\t\t{\n\t\t}\n\n\t\tstatic T *Instance;\n\t};\n\n\ttemplate <class T>\n\tT* CSingleton<T>::Instance = 0;\n\n\n\n\t/** A variant of the singleton, not fully compliant with the standard design pattern\n\t *\tIt is more appropriate for object built from a factory but that must\n\t *\tbe instanciate only once.\n\t *\tThe singleton paradigm allow easy access to the unique instance but\n\t *\tI removed the automatic instanciation of getInstance().\n\t *\n\t *\tConsequently, the getInstance return a pointer that can be NULL\n\t *\tif the singleton has not been build yet.\n\t *\n\t * Example:\n\t * \\code\n\t\tstruct CFooSingleton : public CManualSingleton<CFooSingleton>\n\t\t{\n\t\t\tvoid foo() { nlinfo(\"foo!\"); }\n\t\t};\n\n\t\t// create an instance by any mean\n\t\tCFooSingleton\tmySingleton\n\n\t\t// call the foo function:\n\t\tCFooSingleton::getInstance()->foo();\n\n  \t\t// create another instance is forbiden\n\t\tCFooSingleton\totherInstance;\t\t// ASSERT !\n\n\n\t * \\endcode\n\t * \\author Boris 'sonix' Boucher\n\t * \\author Nevrax France\n\t * \\date 2005\n\t */\n\n\ttemplate <class T>\n\tclass CManualSingleton\n\t{\n\t\tstatic T *&_instance()\n\t\t{\n\t\t\tstatic T *instance = NULL;\n\n\t\t\treturn instance;\n\t\t}\n\n\tprotected:\n\n\n\t\tCManualSingleton()\n\t\t{\n\t\t\tnlassert(_instance() == NULL);\n\t\t\t_instance() = static_cast<T*>(this);\n\t\t}\n\n\t\t~CManualSingleton()\n\t\t{\n\t\t\tnlassert(_instance() == this);\n\t\t\t_instance() = NULL;\n\t\t}\n\n\tpublic:\n\n\t\tstatic bool isInitialized()\n\t\t{\n\t\t\treturn _instance() != NULL;\n\t\t}\n\n\t\tstatic T* getInstance()\n\t\t{\n\t\t\tnlassert(_instance() != NULL);\n\n\t\t\treturn _instance();\n\t\t}\n\t};\n\n\n\t/** A macro for safe global variable value.\n\t *\tConcept : global initialized variable value are inherently unsafe because the order of\n\t *\tinitialisation if undefined. If some init code use static value, you\n\t *\tmay encounter hazardous error, depending on you compiler will, when you\n\t *\tread the value of a global, you may read it before it is initialized.\n\t *\tThis little class is a workaround that allow a safe global value.\n\t *\tA drawback is that the value is enclosed inside a function and thus not\n\t *\taccessible in the debugger.\n\t *\tuse getGlobal_<name>() to retrieve a reference to the value.\n\t */\n#define NL_MISC_SAFE_GLOBAL(type, name, value)\t\\\n\ttype &getGlobal_##name() \\\n\t{ \\\n\t\tstatic type\ttheVar = (value); \\\n\t\treturn theVar; \\\n\t} \\\n\n#define NL_MISC_SAFE_CLASS_GLOBAL(type, name, value)\t\\\n\tstatic type &getGlobal_##name() \\\n\t{ \\\n\t\tstatic type\ttheVar = (value); \\\n\t\treturn theVar; \\\n\t} \\\n\n\n\n} // NLMISC\n\n#endif // NL_SINGLETON_H\n\n/* End of singleton.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/smart_ptr.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SMART_PTR_H\n#define NL_SMART_PTR_H\n\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n#include \"stream.h\"\n\n#include <cstdio>\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * To use CSmartPtr or CRefPtr, derive from this class.\n * Your class doens't have to be virtual, or doesn't have to provide a virtual dtor.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CRefCount\n{\npublic:\n\t/// Destructor which release pinfo if necessary.\n\t~CRefCount();\n\t/// Default constructor init crefs to 0.\n\tCRefCount() { crefs = 0; pinfo=static_cast<CPtrInfo*>(&NullPtrInfo); }\n\n\t/*  The instance handle.\n\t\tCan't put those to private since must be used by CRefPtr (and friend doesn't work with template).\n\t\tUse struct CPtrInfoBase / CPtrInfo idiom for NullPtrInfo, because of problems of static constructor:\n\t\tNullPtrInfo must be init BEFORE ANY constructor calls.\n\t*/\n\tstruct\tCPtrInfoBase\n\t{\n\t\tconst CRefCount* Ptr;\t// to know if the instance is valid.\n\t\tsint\tRefCount;\t\t// RefCount of ptrinfo (!= instance)\n\t\tbool\tIsNullPtrInfo;\t// For dll problems, must use a flag to mark NullPtrInfo.\n\t};\n\tstruct\tCPtrInfo : public CPtrInfoBase\n\t{\n\t\tCPtrInfo(CRefCount const* p) {Ptr=p; RefCount=0; IsNullPtrInfo=false;}\n\t};\n\n\t// OWN null for ref ptr. (Optimisations!!!)\n\tstatic\tCPtrInfoBase\tNullPtrInfo;\n\tfriend struct\t\t\tCPtrInfo;\n\n\t// for special case use only.\n\tinline\tconst\tsint\t&getRefCount()\tconst\n\t{\n\t\treturn\tcrefs;\n\t}\n\npublic:\n\t// Can't put this to private since must be used by CSmartPtr (and friend doesn't work with template).\n\t// Provide incref()/decref() function doen't work since decref() can't do a delete this on a non virtual dtor.\n\t// So Ptr gestion can only be used via CSmartPtr.\n\tmutable\tsint\t\tcrefs;\t// The ref counter for SmartPtr use.\n\tmutable\tCPtrInfo\t*pinfo;\t// The ref ptr for RefPtr use.\n\n\t/// operator= must NOT copy crefs/pinfo!!\n\tCRefCount &operator=(const CRefCount &) {return *this;}\n\t/// copy cons must NOT copy crefs/pinfo!!\n\tCRefCount(const CRefCount &) {crefs = 0; pinfo=static_cast<CPtrInfo*>(&NullPtrInfo);}\n};\n\n// To use CVirtualRefPtr (or if you just want to have a RefCount with virtual destructor), derive from this class.\nclass CVirtualRefCount : public CRefCount\n{\npublic:\n\t/// Virtual destructor\n\tvirtual ~CVirtualRefCount() {}\n};\n\n\n\n// ***************************************************************************\n// For debug only.\n#define\tSMART_TRACE(_s)\t((void)0)\n#define\tREF_TRACE(_s)\t((void)0)\n//#define\tSMART_TRACE(_s)\tprintf(\"%s: %d \\n\", _s, Ptr?Ptr->crefs:0)\n//#define\tREF_TRACE(_s)\tprintf(\"%s: %d \\n\", _s, pinfo!=&CRefCount::NullPtrInfo?pinfo->RefCount:0)\n\n\n/**\n * Standard SmartPtr class. T Must derive from CRefCount.\n * Once a normal ptr is assigned to a SmartPtr, the smartptr will own this pointer, and delete it when no other smartptr\n * reference the object (with a reference couting scheme). The following code works, since the object himself must herit\n * from CRefCount, and so hold the refcount.\n * \\code\n\tCSmartPtr<A>\ta0, a1;\n\tA\t\t\t\t*p0;\n\ta0= new A;\t// Ok. RefCount==1.\n\tp0= a0;\t\t// Ok, cast operator. object still owned by a0.\n\ta1= p0;\t\t// Ok!! RefCount==2. Object owned by a0 and a1;\n\t// At destruction, a1 unref(), then a0 unref() and delete the object.\n \\endcode\n *\n * The ref counter cannot be put directly in the smartptr since the preceding behavior must be supported and inheritance must be supported too.\n * Here, if A is a base class of B, Pa and Pb are smartptr of a and b respectively, then \\c Pa=Pb; is a valid operation.\n * But, doing this, you may ensure that you have a virtual dtor(), since dtor() Pa may call ~A() (or you may ensure that Pa\n * won't destruct A, which it sound much more as a normal pointer :) ).\n *\n * Sample:\n *\\code\n\tclass A : public CRefCount\n\t{\n\tpublic:\n\t\tA() {puts(\"A()\");}\n\t\tvirtual ~A() {puts(\"~A()\");}\n\t};\n\n\n\tclass B : public A\n\t{\n\tpublic:\n\t\tB() {puts(\"B()\");}\n\t\t~B() {puts(\"~B()\");}\n\t};\n\n\n\tvoid\ttestPtr()\n\t{\n\t\tCSmartPtr<A>\ta0,a1,a2;\n\t\tCSmartPtr<B>\tb0;\n\n\t\ta0= new A;\n\t\ta1= a0;\n\t\ta1= new A;\n\t\ta2= a1;\n\t\ta1=NULL;\n\t\tb0= new B;\n\t\ta0=b0;\n\n\t\tprintf(\"%d\\n\", (A*)NULL==a0);\n\t\tprintf(\"%d\\n\", b0!=a0);\n\t\tprintf(\"%d\\n\", (A*)NULL==a1);\n\t\tprintf(\"%d\\n\", a2!=a0);\n\t}\n *\\endcode\n *\n * SmartPtr are compatible with RefPtr. A ptr may be link to a CRefPtr and a CSmartPtr. As example, when the CSmartPtr\n * will destroy him, CRefPtr will be informed...\n * Sample:\n *\\code\n\tvoid\tfoo()\n\t{\n\t\tA\t\t\t\t*p;\n\t\tCSmartPtr<A>\tsp;\n\t\tCRefPtr<A>\t\trp;\n\n\t\tp= new A;\n\t\tsp= p;\t\t// OK. p is now owned by sp and will be deleted by sp.\n\t\trp= p;\t\t// OK. rp handle p.\n\t\tsp= NULL;\t// Destruction. p deleted. rp automatically informed.\n\t\tp= rp;\t\t// result: p==NULL.\n\t}\n \\endcode\n *\n * \\b PERFORMANCE \\b WARNING! operator=() are about 10 times slower than normal pointers.\n * For local use, prefer cast the smartptr to a normal Ptr.\n * \\sa CRefPtr\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\ntemplate <class T>\nclass CSmartPtr\n{\n    T* Ptr;\npublic:\n\ttypedef T element_type;\n\n\t/// Init a NULL Ptr.\n\tCSmartPtr() { Ptr=NULL; SMART_TRACE(\"ctor()\"); }\n\t/// Attach a ptr to a SmartPtr.\n\tCSmartPtr(T* p) { Ptr=p; if(Ptr) Ptr->crefs++; SMART_TRACE(\"ctor(T*)\"); }\n\t/// Copy constructor.\n\tCSmartPtr(const CSmartPtr &copy) { Ptr=copy.Ptr; if(Ptr) Ptr->crefs++; SMART_TRACE(\"ctor(Copy)\"); }\n\t/// Release the SmartPtr.\n\t~CSmartPtr();\n\n\n\t/// Cast operator.\n\toperator T*(void) const { SMART_TRACE(\"castT*()\"); return Ptr; }\n\t/// Indirection operator. Doesn't check NULL.\n\tT& operator*(void) const { SMART_TRACE(\"ope*()\"); return *Ptr; }\n\t/// Selection operator. Doesn't check NULL.\n\tT* operator->(void) const { SMART_TRACE(\"ope->()\"); return Ptr; }\n\t/// returns if there's no object pointed by this SmartPtr.\n\tbool\tisNull\t() const { return Ptr==NULL; }\n\t/// Return the pointer\n\tT *getPtr() const { return Ptr;}\n\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCSmartPtr& operator=(T* p);\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCSmartPtr& operator=(const CSmartPtr &p);\n\t/// operator<. Compare the pointers.\n\tbool operator<(const CSmartPtr &p) const;\n\n\tsint getNbRef() { if(Ptr) return Ptr->crefs; else return 0; }\n\t// No need to do any operator==. Leave the work to cast  operator T*(void).\n\n\tstd::string toString() { if(Ptr) return toString(*Ptr); else return \"<null>\"; }\n\n\t// serial using serialPtr\n\tvoid serialPtr(NLMISC::IStream &f) throw(NLMISC::EStream )\n\t{\n\t\tT*\tobj= NULL;\n\t\tif(f.isReading())\n\t\t{\n\t\t\tf.serialPtr(obj);\n\t\t\t// assign correctly (NB: obj may be NULL)\n\t\t\t*this= obj;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tobj= Ptr;\n\t\t\tf.serialPtr(obj);\n\t\t}\n\t}\n\t// serial using serialPloyPtr\n\tvoid serialPolyPtr(NLMISC::IStream &f) throw(NLMISC::EStream )\n\t{\n\t\tT*\tobj= NULL;\n\t\tif(f.isReading())\n\t\t{\n\t\t\tf.serialPolyPtr(obj);\n\t\t\t// assign correctly (NB: obj may be NULL)\n\t\t\t*this= obj;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tobj= Ptr;\n\t\t\tf.serialPolyPtr(obj);\n\t\t}\n\t}\n};\n\n\n\n// ***************************************************************************\n/**\n * CRefPtr: an handle on a ptr. T Must derive from CRefCount.\n * If you use CRefPtr, you can kill the object simply by calling delete (T*)RefPtr, or the kill() method. All other CRefPtr which\n * point to it can know if it has been deleted. (but you must be sure that this ptr is not handle by a SmartPtr, of course...)\n *\n * SmartPtr are compatible with RefPtr. A ptr may be link to a CRefPtr and a CSmartPtr. As example, when the CSmartPtr\n * will destroy him, CRefPtr will be informed...\n * Sample:\n *\\code\n\tvoid\tfoo()\n\t{\n\t\tA\t\t\t\t*p;\n\t\tCSmartPtr<A>\tsp;\n\t\tCRefPtr<A>\t\trp;\n\n\t\tp= new A;\n\t\tsp= p;\t\t// OK. p is now owned by sp and will be deleted by sp.\n\t\trp= p;\t\t// OK. rp handle p.\n\t\tsp= NULL;\t// Destruction. p deleted. rp automatically informed.\n\t\tif(rp==NULL)\n\t\t\tthisIsGood();\t// rp==NULL.\n\t}\n \\endcode\n *\n * \\b PERFORMANCE \\b WARNING! operator=() are about 10 times slower than normal pointers. So use them wisely.\n * For local use, prefer cast the refptr to a normal Ptr.\n * Also, an object used with a CRefPtr will allocate a small PtrInfo (one only per object, not per ptr).\n * \\sa CSmartPtr\n */\ntemplate <class T>\nclass CRefPtr\n{\nprivate:\n\tCRefCount::CPtrInfo\t\t*pinfo;\t\t// A ptr to the handle of the object.\n\tmutable T\t\t\t\t*Ptr;\t\t// A cache for pinfo->Ptr. Useful to speed up  ope->()  and  ope*()\n\n\tvoid\tunRef()  const;\t\t\t\t// Just release the handle pinfo, but do not update pinfo/Ptr, if deleted.\n\npublic:\n\n\t/// Init a NULL Ptr.\n\tCRefPtr();\n\t/// Attach a ptr to a RefPtr.\n\tCRefPtr(T *v);\n\t/// Copy constructor.\n\tCRefPtr(const CRefPtr &copy);\n\t/// Release the RefPtr.\n\t~CRefPtr(void);\n\n\n\t/// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case.\n\toperator T*()\tconst;\n\t/// Indirection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL.\n\tT& operator*(void)\tconst;\n\t/// Selection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL.\n\tT* operator->(void)\tconst;\n\n\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCRefPtr& operator=(T *v);\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCRefPtr& operator=(const CRefPtr &copy);\n\n\n\t/**\n\t * kill/delete the object pointed by the pointer, and inform the other RefPtr of this.\n\t * \"rp.kill()\" and \"delete (T*)rp\" do the same thing, except that rp NULLity is updated with kill().\n\t * RefPtr which point to the same object could know if the object is valid, by just testing it (\n\t * by an implicit call to the cast operator to T*). But any calls to operator->() or operator*() will have\n\t * unpredictible effects (may crash... :) ).\n\t */\n\tvoid\tkill();\n\n\t// serial using serialPloyPtr\n\tvoid serialPolyPtr(NLMISC::IStream &f) throw(NLMISC::EStream )\n\t{\n\t\tT*\tobj= NULL;\n\t\tif(f.isReading())\n\t\t{\n\t\t\tf.serialPolyPtr(obj);\n\t\t\t// assign correctly (NB: obj may be NULL)\n\t\t\t*this= obj;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tobj= Ptr;\n\t\t\tf.serialPolyPtr(obj);\n\t\t}\n\t}\n};\n\n#if defined(NL_COMP_VC) && NL_COMP_VC_VERSION >= 80\n\n// This operator only purpose is to compare with NULL value\ntemplate <class T>\nbool operator == (const CRefPtr<T> &refPtr, int null)\n{\n\tnlassert(null == 0);\n\treturn (T*)refPtr == (T*)null;\n}\n\n#endif\n\ntemplate <class T>\nbool operator == (const CRefPtr<T> &refPtr, T *ptr)\n{\n\treturn (T*)refPtr == ptr;\n}\n\ntemplate <class T>\nbool operator == (const CRefPtr<T> &leftRef, const CRefPtr<T> &rightRef)\n{\n\treturn (T*)leftRef == (T*) rightRef;\n}\n\ntemplate <class T>\nclass CVirtualRefPtr\n{\nprivate:\n\tCRefCount::CPtrInfo\t\t*pinfo;\t\t// A ptr to the handle of the object.\n    mutable T\t\t\t\t*Ptr;\t\t// A cache for pinfo->Ptr. Useful to speed up  ope->()  and  ope*()\n\n\tvoid\tunRef()  const;\t\t\t\t// Just release the handle pinfo, but do not update pinfo/Ptr, if deleted.\n\npublic:\n\n\t/// Init a NULL Ptr.\n\tCVirtualRefPtr();\n\t/// Attach a ptr to a VirtualRefPtr.\n\tCVirtualRefPtr(T *v);\n\t/// Copy constructor.\n\tCVirtualRefPtr(const CVirtualRefPtr &copy);\n\t/// Release the VirtualRefPtr.\n\t~CVirtualRefPtr(void);\n\n\n\t/// Cast operator. Check if the object has been deleted somewhere, and return NULL if this is the case.\n\toperator T*()\tconst;\n\t/// Indirection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL.\n\tT& operator*(void)\tconst;\n\t/// Selection operator. Doesn't test if ptr has been deleted somewhere, and doesn't check NULL.\n\tT* operator->(void)\tconst;\n\n\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCVirtualRefPtr& operator=(T *v);\n\t/// operator=. Giving a NULL pointer is a valid operation.\n\tCVirtualRefPtr& operator=(const CVirtualRefPtr &copy);\n\n\n\t/**\n\t * kill/delete the object pointed by the pointer, and inform the other VirtualRefPtr of this.\n\t * \"rp.kill()\" and \"delete (T*)rp\" do the same thing, except that rp NULLity is updated with kill().\n\t * VirtualRefPtr which point to the same object could know if the object is valid, by just testing it (\n\t * by an implicit call to the cast operator to T*). But any calls to operator->() or operator*() will have\n\t * unpredictible effects (may crash... :) ).\n\t */\n\tvoid\tkill();\n\n\n\t// No need to do any operator==. Leave the work to cast  operator T*(void).\n};\n\n\n\t/**\n\t * A little quick coded class made to find invalid object pointer existence while a destructor call on an objet.\n\t * Futur job is to do not have CstCDbgPtr .. (error due to a lack of time).\n\t *\n\t * Feature:\n\t *   If you try to delete an object and if there still some pointer referencing it, it causes an assertion.\n\t *   This Debug feature depends on NL_DEBUG_PTR definition (change it as your convenience).\n\t *   These are only debug classes and are not design to use information for your code comportment\n\t *  as they are made to desappear in final version (NL_DEBUG_PTR undefined),\n\t *  so don't use method calls outside NL_DEBUG_PTR scope.\n\t *\n\t * How to:\n\t *   Derivate your objet from CDbgRefCount<T> where T is the type of pointer you allow to use on this object (you can use many).\n\t *  then use CDbgPtr<T> to point an object of type T (which must derivates from CDbgRefCount<T>), its the pointer.\n\t *\n\t * Warning:\n\t *  Be carefull to derivates first from CDbgRefCount<T> as derivation order implicates constructor/destructor order calls.\n\t *  Sometimes u may have to write some explicit casts, don't worry, it would be only common courtesy ;)\n\t *\n\t * Futur work (only if you need it):\n\t *  enhanced features (like __FILE__ __LINE__ information).\n\t *\n\t * Extension by Jerome Vuarand\n\t *  I've added additional information to trace back invalid pointers. A linked list in the ref counter can be used to access to\n\t *  invalid pointers on referenced object deletion, and an additionnal data field in each pointer let pointer owner to specify\n\t *  additionnal information. The linked list insertion occurs on head. The linked is doubly-linked to avoid parsing it on deletion.\n\t *  When a reference is still present on referenced object deletion, an assert is issued and access to pointers is given. Each\n\t *  CDbgPtr owner can attach a data pointer to the CDbgPtr. A good way to use the feature is to derive the owner from IDbgPtrData,\n\t *  pass this as the data to the CDbgPtr, and to let RTTI find the owner during assert manual handling.\n\t *\n\t * \\author Stephane Le Dorze\n\t * \\author Jerome Vuarand\n\t * \\author Nevrax France\n\t * \\date 2003-2005\n\t */\n\n\n#ifdef NL_DEBUG\n\t#define NL_DEBUG_PTR\n#endif\n\ntemplate <class T>\tclass CDbgPtr;\ntemplate <class T>\tclass CstCDbgPtr;\n\nclass IDbgPtrData\n{\npublic:\n\tvirtual ~IDbgPtrData() { }\n};\n\ntemplate <class T>\nclass CDbgRefCount\n{\n#ifdef NL_DEBUG_PTR\npublic:\n\tCDbgRefCount(const CDbgRefCount& other)\n\t: _DbgCRefs(0)\n\t, _DbgCCstRefs(0)\n\t, _MaxRef(other._MaxRef)\n\t, _CheckOn(other._CheckOn)\n\t, _FirstReference(NULL)\n\t, _FirstCstReference(NULL)\n\t{\n\t}\n\tCDbgRefCount(sint32 maxRef = (1<<30))\n\t: _DbgCRefs(0)\n\t, _DbgCCstRefs(0)\n\t, _MaxRef(maxRef)\n\t, _FirstReference(NULL)\n\t, _FirstCstReference(NULL)\n\t{\n\t}\n\tvirtual\t~CDbgRefCount()\n\t{\n\t\tif (_DbgCRefs!=0 || _DbgCCstRefs!=0)\n\t\t{\n\t\t\tconst CDbgPtr<T>* ref0, *ref1, *ref2, *ref3, *ref4; ref0=ref1=ref2=ref3=ref4=(CDbgPtr<T>*)NULL;\n\t\t\tIDbgPtrData* dat0, *dat1, *dat2, *dat3, *dat4; dat0=dat1=dat2=dat3=dat4=(IDbgPtrData*)NULL;\n\t\t\tif (_DbgCRefs>0) { ref0 = _FirstReference; dat0 = ref0->getData(); }\n\t\t\tif (_DbgCRefs>1) { ref1 = ref0->getNextReference(); dat1 = ref1->getData(); }\n\t\t\tif (_DbgCRefs>2) { ref2 = ref1->getNextReference(); dat2 = ref2->getData(); }\n\t\t\tif (_DbgCRefs>3) { ref3 = ref2->getNextReference(); dat3 = ref3->getData(); }\n\t\t\tif (_DbgCRefs>4) { ref4 = ref3->getNextReference(); dat4 = ref4->getData(); }\n\t\t\tconst CstCDbgPtr<T>* cref0, *cref1, *cref2, *cref3, *cref4; cref0=cref1=cref2=cref3=cref4=(CstCDbgPtr<T>*)NULL;\n\t\t\tIDbgPtrData* cdat0, *cdat1, *cdat2, *cdat3, *cdat4; cdat0=dat1=cdat2=cdat3=cdat4=(IDbgPtrData*)NULL;\n\t\t\tif (_DbgCCstRefs>0) { cref0 = _FirstCstReference; cdat0 = cref0->getData(); }\n\t\t\tif (_DbgCCstRefs>1) { cref1 = cref0->getNextReference(); cdat1 = cref1->getData(); }\n\t\t\tif (_DbgCCstRefs>2) { cref2 = cref1->getNextReference(); cdat2 = cref2->getData(); }\n\t\t\tif (_DbgCCstRefs>3) { cref3 = cref2->getNextReference(); cdat3 = cref3->getData(); }\n\t\t\tif (_DbgCCstRefs>4) { cref4 = cref3->getNextReference(); cdat4 = cref4->getData(); }\n\t\t\tnlassert(_DbgCRefs==0);\n\t\t\tnlassert(_DbgCCstRefs==0);\n\t\t}\n\t}\n\tsint getDbgRef(const CDbgPtr<T>& ptr) const\n\t{\n\t\treturn _DbgCRefs + _DbgCCstRefs;\n\t}\n\tsint getDbgRef(const CstCDbgPtr<T>& ptr) const\n\t{\n\t\treturn _DbgCRefs + _DbgCCstRefs;\n\t}\n\tvoid incRef(const CDbgPtr<T>& ptr) const\n\t{\n\t\tif (_CheckOn)\n\t\t\tnlassert(_DbgCRefs<_MaxRef);\n\t\t++_DbgCRefs;\n\t\t// Linked list management\n\t\tnlassert(_FirstReference!=&ptr);\n\t\tptr.setNextReference(_FirstReference);\n\t\tptr.setPrevReference((CDbgPtr<T>*)NULL);\n\t\tif (_FirstReference)\n\t\t\t_FirstReference->setPrevReference(&ptr);\n\t\t_FirstReference = &ptr;\n\t}\n\tvoid decRef(const CDbgPtr<T>& ptr) const\n\t{\n\t\tnlassert(_DbgCRefs>0);\n\t\t--_DbgCRefs;\n\t\t// Linked list management\n\t\tif (ptr.getNextReference())\n\t\t\tptr.getNextReference()->setPrevReference(ptr.getPrevReference());\n\t\tif (ptr.getPrevReference())\n\t\t\tptr.getPrevReference()->setNextReference(ptr.getNextReference());\n\t\tif (_FirstReference==&ptr)\n\t\t\t_FirstReference = ptr.getNextReference();\n\t}\n\tvoid incRef(const CstCDbgPtr<T>& ptr) const\n\t{\n\t\tif (_CheckOn)\n\t\t\tnlassert(_DbgCCstRefs<_MaxRef);\n\t\t++_DbgCCstRefs;\n\t}\n\tvoid decRef(const CstCDbgPtr<T>& ptr) const\n\t{\n\t\tnlassert(_DbgCCstRefs>0);\n\t\t--_DbgCCstRefs;\n\t}\n\tvoid setCheckMax(const bool checkOnOff) const\n\t{\n\t\t_CheckOn = checkOnOff;\n\t}\nprivate:\n\tmutable\tsint\t_DbgCRefs;\n\tmutable\tsint\t_DbgCCstRefs;\n\tsint32\t\t\t_MaxRef;\n\tmutable\tbool\t_CheckOn;\n\tmutable\tconst CDbgPtr<T>*\t\t_FirstReference;\n\tmutable\tconst CstCDbgPtr<T>*\t_FirstCstReference;\n#endif\n};\n\ntemplate <class T>\nclass CDbgPtr\n{\n\tT* Ptr;\n\n#ifdef NL_DEBUG_PTR\n\t/// \\name Linked list management\n\t//@{\nprivate: // Data\n\tIDbgPtrData*\t\t\t\tData;\n\tmutable const CDbgPtr<T>*\tNextReference;\n\tmutable const CDbgPtr<T>*\tPrevReference;\npublic: // Methods\n\tvoid setData(IDbgPtrData* data) { Data = data; }\n\tIDbgPtrData* getData() const { return Data; }\n\tvoid setNextReference(const CDbgPtr<T>* reference) const { NextReference = reference; }\n\tconst CDbgPtr<T>* getNextReference() const { return NextReference; }\n\tvoid setPrevReference(const CDbgPtr<T>* reference) const { PrevReference = reference; }\n\tconst CDbgPtr<T>* getPrevReference() const { return PrevReference; }\n\t//@}\n#endif\n\npublic:\n\tCDbgPtr()\n\t: Ptr(NULL)\n#ifdef NL_DEBUG_PTR\n\t, Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t}\n\n\ttemplate <class W>\n\tCDbgPtr(const W* p)\n#ifdef NL_DEBUG_PTR\n\t: Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t\tPtr = const_cast<T*>(NLMISC::type_cast<const T*>(p));\n\t#ifdef NL_DEBUG_PTR\n\t\tif (Ptr)\n\t\t{\n\t\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(Ptr);\n\t\t\tref->incRef(*this);\n\t\t}\n\t#endif\n\t}\n\n\tCDbgPtr(const CDbgPtr& copy)\n#ifdef NL_DEBUG_PTR\n\t: Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t\tPtr = copy.Ptr;\n\t#ifdef NL_DEBUG_PTR\n\t\tif (Ptr)\n\t\t{\n\t\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(Ptr);\n\t\t\tref->incRef(*this);\n\t\t}\n\t#endif\n\t}\n\t~CDbgPtr();\n\n\tbool isNULL() const\n\t{\n\t\treturn Ptr==NULL;\n\t}\n\n\tT* ptr() const\n\t{\n\t\treturn Ptr;\n\t}\n\n\toperator T*(void) const\n\t{\n\t\treturn Ptr;\n\t}\n\n\ttemplate <class W>\n\toperator W*(void) const\n\t{\n\t\treturn NLMISC::type_cast<W*>(Ptr);\n\t}\n\n\tT& operator*(void) const { return *Ptr; }\n\tT* operator->(void) const { return Ptr; }\n\n\ttemplate <class W>\n\tCDbgPtr<T>& operator=(const W* p)\n\t{\n\t#ifdef NL_DEBUG_PTR\n\t\tCDbgRefCount<T>* oldRef = (CDbgRefCount<T>*)NULL, *newRef = (CDbgRefCount<T>*)NULL;\n\t\tif (Ptr)\n\t\t\toldRef = static_cast<CDbgRefCount<T>*>(Ptr);\n\t\tif (p)\n\t\t\tnewRef = static_cast<CDbgRefCount<T>*>(const_cast<T*>(NLMISC::type_cast<const T*>(p)));\n\t\tif (oldRef!=newRef)\n\t\t{\n\t\t\tif (oldRef) oldRef->decRef(*this);\n\t\t\tPtr = const_cast<T*>(NLMISC::type_cast<const T*>(p));\n\t\t\tif (newRef) newRef->incRef(*this);\n\t\t}\n\t#else\n\t\tPtr = const_cast<T*>(NLMISC::type_cast<const T*>(p));\n\t#endif\n\t\treturn *this;\n\t}\n\t/*\n\tCDbgPtr<T>& operator=(const int value)\n\t{\n\t#ifdef NL_DEBUG\n\t\tnlassert(value==NULL);\n\t#endif\n\n\t#ifdef NL_DEBUG_PTR\n\t\tif (Ptr)\n\t\t{\n\t\t\tCDbgRefCount<T>* ref=static_cast<CDbgRefCount<T>*>(Ptr);\n\t\t\tref->decRef(*this);\n\t\t}\n\t#endif\n\t\tPtr = NULL;\n\t\treturn *this;\n\t}\n\t*/\n\tCDbgPtr<T>& operator =(const CDbgPtr& p);\n\tbool operator <(const CDbgPtr& p) const;\n\n\ttemplate <class W>\n\tbool operator ==(const W* p) const\n\t{\n\t\treturn Ptr==NLMISC::type_cast<const T*>(p);\n\t}\n\ttemplate <class W>\n\tbool operator !=(const W* p) const\n\t{\n\t\treturn Ptr!=NLMISC::type_cast<const T*>(p);\n\t}\n\n\tbool operator ==(const CDbgPtr &p) const\n\t{\n\t\treturn Ptr==p.Ptr;\n\t}\n\tbool operator !=(const CDbgPtr &p) const\n\t{\n\t\treturn Ptr!=p.Ptr;\n\t}\n\n\tbool operator ==(int p) const\n\t{\n\t\tnlassert(p == 0);\n\t\treturn Ptr==0;\n\t}\n\tbool operator !=(int p) const\n\t{\n\t\tnlassert(p == 0);\n\t\treturn Ptr!=0;\n\t}\n};\n\ntemplate<class T>\ninline CDbgPtr<T>::~CDbgPtr(void)\n{\n#ifdef NL_DEBUG_PTR\n\tif (Ptr)\n\t{\n\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(Ptr);\n\t\tref->decRef(*this);\n\t\tPtr = NULL;\n\t}\n#else\n\tPtr=NULL;\n#endif\n}\n\n\ntemplate<class T>\nCDbgPtr<T>& CDbgPtr<T>::operator =(const CDbgPtr& p)\n{\n\treturn CDbgPtr<T>::operator =(p.Ptr);\n}\n\ntemplate<class T>\nbool CDbgPtr<T>::operator <(const CDbgPtr& p) const\n{\n\treturn Ptr<p.Ptr;\n}\n\ntemplate <class T>\nclass CstCDbgPtr\n{\n\tconst T* Ptr;\n\n#ifdef NL_DEBUG_PTR\n\t/// \\name Linked list management\n\t//@{\nprivate: // Data\n\tIDbgPtrData*\t\t\t\t\tData;\n\tmutable const CstCDbgPtr<T>*\tNextReference;\n\tmutable const CstCDbgPtr<T>*\tPrevReference;\npublic: // Methods\n\tvoid setData(IDbgPtrData* data) { Data = data; }\n\tIDbgPtrData* getData() const { return Data; }\n\tvoid setNextReference(const CstCDbgPtr<T>* reference) const { NextReference = reference; }\n\tconst CstCDbgPtr<T>* getNextReference() const { return NextReference; }\n\tvoid setPrevReference(const CstCDbgPtr<T>* reference) const { PrevReference = reference; }\n\tconst CstCDbgPtr<T>* getPrevReference() const { return PrevReference; }\n\t//@}\n#endif\n\npublic:\n\tCstCDbgPtr()\n\t: Ptr(NULL)\n#ifdef NL_DEBUG_PTR\n\t, Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t}\n\tCstCDbgPtr(const T* p)\n#ifdef NL_DEBUG_PTR\n\t: Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t\tPtr = p;\n\t#ifdef NL_DEBUG_PTR\n\t\tif (Ptr)\n\t\t{\n\t\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(const_cast<T*>(Ptr));\n\t\t\tref->incRef(*this);\n\t\t}\n\t#endif\n\t}\n\tCstCDbgPtr(const CstCDbgPtr& copy)\n#ifdef NL_DEBUG_PTR\n\t: Data(NULL)\n\t, NextReference(NULL)\n\t, PrevReference(NULL)\n#endif\n\t{\n\t\tPtr = copy.Ptr;\n\t#ifdef NL_DEBUG_PTR\n\t\tif (Ptr)\n\t\t{\n\t\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(const_cast<T*>(Ptr));\n\t\t\tref->incRef(*this);\n\t\t}\n\t#endif\n\t}\n\t~CstCDbgPtr();\n\n\tconst T* ptr() const\n\t{\n\t\treturn Ptr;\n\t}\n\n\tbool isNULL() const\n\t{\n\t\treturn Ptr==NULL;\n\t}\n\n\toperator const T*(void) const { return Ptr; }\n\tconst T& operator*(void) const { return *Ptr; }\n\tconst T* operator->(void) const { return Ptr; }\n\n\tCstCDbgPtr& operator =(const T* p);\n\tCstCDbgPtr& operator =(const CstCDbgPtr& p);\n\tbool operator <(const CstCDbgPtr& p) const;\n};\n\n\ntemplate<class T>\nCstCDbgPtr<T>::~CstCDbgPtr(void)\n{\n#ifdef NL_DEBUG_PTR\n\tif (Ptr)\n\t{\n\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(const_cast<T*>(Ptr));\n\t\tref->decRef(*this);\n\t}\n#endif\n\tPtr = NULL;\n}\n\ntemplate<class T>\nCstCDbgPtr<T>& CstCDbgPtr<T>::operator =(const T* p)\n{\n#ifdef NL_DEBUG_PTR\n\tif (p)\n\t{\n\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(const_cast<T*>(p));\n\t\tref->incRef(*this);\n\t}\n\tif (Ptr)\n\t{\n\t\tCDbgRefCount<T>* ref = static_cast<CDbgRefCount<T>*>(const_cast<T*>(Ptr));\n\t\tref->decRef(*this);\n\t}\n#endif\n\tPtr = p;\n\treturn *this;\n}\n\ntemplate<class T>\nCstCDbgPtr<T>& CstCDbgPtr<T>::operator =(const CstCDbgPtr& p)\n{\n\treturn CstCDbgPtr<T>::operator =(p.Ptr);\n}\n\ntemplate<class T>\nbool CstCDbgPtr<T>::operator <(const CstCDbgPtr& p) const\n{\n\treturn Ptr<p.Ptr;\n}\n\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// Implementation.\n// ***************************************************************************\n// ***************************************************************************\n\n\n#include \"smart_ptr_inline.h\"\n#undef\tSMART_TRACE\n#undef\tREF_TRACE\n\n\n\n#endif // NL_SMART_PTR_H\n\n/* End of smart_ptr.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/smart_ptr_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_SMARTPTR_INLINE_H\n#define NL_SMARTPTR_INLINE_H\n\n#include \"types_nl.h\"\n\nnamespace\tNLMISC\n{\n\n\n\n// ***************************************************************************\n#ifdef NL_OS_WINDOWS\n#define\tSMART_INLINE __forceinline\n#else\n#define\tSMART_INLINE inline\n#endif\n\n\n// ***************************************************************************\ninline CRefCount::~CRefCount()\n{\n\t// This is the destruction of the objet.\n#ifdef NL_DEBUG\n\tnlassert(crefs==0);\n#endif\n\n\t// If a CRefPtr still points on me...\n\tif(!pinfo->IsNullPtrInfo)\n\t{\n\t\t// inform them of my destruction.\n\t\tpinfo->Ptr= NULL;\n\t}\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CSmartPtr.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\ntemplate<class T>\ninline CSmartPtr<T>::~CSmartPtr(void)\n{\n\tSMART_TRACE(\"dtor()\");\n\n    if(Ptr)\n\t{\n#ifdef NL_DEBUG\n\t\tnlassert(Ptr->crefs>=0);\n#endif\n\t\tif (--(Ptr->crefs) == 0)\n\t\t\tdelete Ptr;\n\t\tPtr=NULL;\n\t}\n}\ntemplate<class T>\nSMART_INLINE CSmartPtr<T>& CSmartPtr<T>::operator=(T* p)\n{\n\tSMART_TRACE(\"ope=(T*)Start\");\n\n\t// Implicit manage auto-assignation.\n    if(p)\n\t\tp->crefs++;\n    if(Ptr)\n\t{\n\t\tif (--(Ptr->crefs) == 0)\n\t\t\tdelete Ptr;\n\t}\n\tPtr = p;\n\n\tSMART_TRACE(\"ope=(T*)End\");\n\n\treturn *this;\n}\ntemplate<class T>\nSMART_INLINE CSmartPtr<T>& CSmartPtr<T>::operator=(const CSmartPtr &p)\n{\n\treturn operator=(p.Ptr);\n}\ntemplate<class T>\nSMART_INLINE bool CSmartPtr<T>::operator<(const CSmartPtr &p) const\n{\n\treturn Ptr<p.Ptr;\n}\n\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CRefPtr.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\ntemplate<class T>\nSMART_INLINE void\tCRefPtr<T>::unRef() const\n{\n\tpinfo->RefCount--;\n\tif(pinfo->RefCount==0)\n\t{\n\t\t// In CRefPtr, Never delete the object.\n\n\t\t// We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it.\n\t\tif(pinfo->IsNullPtrInfo)\n\t\t{\n\t\t\t// This should not happens, but I'm not sure :) ...\n\t\t\t// Reset the NullPtrInfo to a middle round.\n\t\t\tpinfo->RefCount= 0x7FFFFFFF;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the CRefPtr still point to a valid object.\n\t\t\tif(pinfo->Ptr)\n\t\t\t{\n\t\t\t\t// Inform the Object that no more CRefPtr points on it.\n\t\t\t\tpinfo->Ptr->pinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t\t\t}\n\t\t\t// Then delete the pinfo.\n\t\t\tdelete pinfo;\n\t\t}\n\n\t}\n}\n\n\n// ***************************************************************************\n// Cons - dest.\ntemplate <class T> inline CRefPtr<T>::CRefPtr()\n{\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\tREF_TRACE(\"Smart()\");\n}\ntemplate <class T> inline CRefPtr<T>::CRefPtr(T *v)\n{\n\tPtr= v;\n    if(v)\n\t{\n\t\t// If no CRefPtr handles v, create a pinfo ref...\n\t\tif(v->pinfo->IsNullPtrInfo)\n\t\t\tv->pinfo=new CRefCount::CPtrInfo(v);\n\t\tpinfo=v->pinfo;\n\t\t// v is now used by this.\n\t\tpinfo->RefCount++;\n\n#ifdef NL_DEBUG\n\t\tnlassert(v == const_cast<T*>(static_cast<T const*>(pinfo->Ptr)));\n#endif\n\t}\n\telse\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\n\tREF_TRACE(\"Smart(T*)\");\n}\ntemplate <class T> inline CRefPtr<T>::CRefPtr(const CRefPtr &copy)\n{\n\tpinfo=copy.pinfo;\n\tpinfo->RefCount++;\n\tPtr= const_cast<T*>(static_cast<T const*>(pinfo->Ptr));\n\n\tREF_TRACE(\"SmartCopy()\");\n}\ntemplate <class T> inline CRefPtr<T>::~CRefPtr(void)\n{\n\tREF_TRACE(\"~Smart()\");\n\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n}\n\n// ***************************************************************************\n// Operators=.\ntemplate <class T> CRefPtr<T> &CRefPtr<T>::operator=(T *v)\n{\n\tREF_TRACE(\"ope=(T*)Start\");\n\n\n\tPtr= v;\n\tif(v)\n\t{\n\t\t// If no CRefPtr handles v, create a pinfo ref...\n\t\tif(v->pinfo->IsNullPtrInfo)\n\t\t\tv->pinfo=new CRefCount::CPtrInfo(v);\n\t\t// The auto equality test is implicitly done by upcounting first \"v\", then downcounting \"this\".\n\t\tv->pinfo->RefCount++;\n\t\tunRef();\n\t\tpinfo= v->pinfo;\n\n#ifdef NL_DEBUG\n\t\tnlassert(v == const_cast<T*>(static_cast<T const*>(pinfo->Ptr)));\n#endif\n\t}\n\telse\n\t{\n\t\tunRef();\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t}\n\n\n\tREF_TRACE(\"ope=(T*)End\");\n\n\treturn *this;\n}\ntemplate <class T> CRefPtr<T> &CRefPtr<T>::operator=(const CRefPtr &copy)\n{\n\tREF_TRACE(\"ope=(Smart)Start\");\n\n\t// The auto equality test is implicitly done by upcounting first \"copy\", then downcounting \"this\".\n\tcopy.pinfo->RefCount++;\n\tunRef();\n\tpinfo=copy.pinfo;\n\t// Must Refresh the ptr.\n\tPtr= const_cast<T*>(static_cast<T const*>(pinfo->Ptr));\n\n\tREF_TRACE(\"ope=(Smart)End\");\n\treturn *this;\n}\n\n\n// ***************************************************************************\n// Operations.\ntemplate <class T> void\tCRefPtr<T>::kill()\n{\n\tREF_TRACE(\"SmartKill\");\n\n\tT\t*ptr= const_cast<T*>(static_cast<T const*>(pinfo->Ptr));\n\n\t// First, release the refptr.\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\t// Then delete the pointer.\n\tif(ptr)\n\t\tdelete ptr;\n}\n\n\n// ***************************************************************************\n// Cast.\ntemplate <class T> inline CRefPtr<T>::operator T*()\tconst\n{\n\tREF_TRACE(\"SmartCast T*()\");\n\n\t// Refresh Ptr.\n\t// NB: It is preferable (faster) here to just copy than testing if NULL and set NULL if necessary.\n\t// (static_cast is like a simple copy but for multiple inheritance)\n\tPtr= const_cast<T*>(static_cast<T const*>(pinfo->Ptr));\n\treturn Ptr;\n}\n\n\n// ***************************************************************************\n// Operators.\ntemplate <class T> inline T& CRefPtr<T>::operator*(void)  const\n{\n\tREF_TRACE(\"Smart *()\");\n\treturn *Ptr;\n}\ntemplate <class T> inline T* CRefPtr<T>::operator->(void) const\n{\n\tREF_TRACE(\"Smart ->()\");\n\treturn Ptr;\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CVirtualRefPtr.\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\ntemplate<class T>\nSMART_INLINE void\tCVirtualRefPtr<T>::unRef() const\n{\n\tpinfo->RefCount--;\n\tif(pinfo->RefCount==0)\n\t{\n\t\t// In CVirtualRefPtr, Never delete the object.\n\n\t\t// We may be in the case that this==NullPtrInfo, and our NullPtrInfo has done a total round. Test it.\n\t\tif(pinfo->IsNullPtrInfo)\n\t\t{\n\t\t\t// This should not happens, but I'm not sure :) ...\n\t\t\t// Reset the NullPtrInfo to a middle round.\n\t\t\tpinfo->RefCount= 0x7FFFFFFF;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the CVirtualRefPtr still point to a valid object.\n\t\t\tif(pinfo->Ptr)\n\t\t\t{\n\t\t\t\t// Inform the Object that no more CVirtualRefPtr points on it.\n\t\t\t\tpinfo->Ptr->pinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t\t\t}\n\t\t\t// Then delete the pinfo.\n\t\t\tdelete pinfo;\n\t\t}\n\n\t}\n}\n\n\n// ***************************************************************************\n// Cons - dest.\ntemplate <class T> inline CVirtualRefPtr<T>::CVirtualRefPtr()\n{\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\tREF_TRACE(\"Smart()\");\n}\ntemplate <class T> inline CVirtualRefPtr<T>::CVirtualRefPtr(T *v)\n{\n\tPtr= v;\n    if(v)\n\t{\n\t\t// If no CVirtualRefPtr handles v, create a pinfo ref...\n\t\tif(v->pinfo->IsNullPtrInfo)\n\t\t\tv->pinfo=new CRefCount::CPtrInfo(static_cast<CVirtualRefCount const*>(v)); // v MUST derive from CVirtualRefCount\n\t\tpinfo=v->pinfo;\n\t\t// v is now used by this.\n\t\tpinfo->RefCount++;\n\n#ifdef NL_DEBUG\n\t\tnlassert(v == const_cast<T*>(dynamic_cast<T const*>(static_cast<CVirtualRefCount const*>(pinfo->Ptr))));\n#endif\n\t}\n\telse\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\n\tREF_TRACE(\"Smart(T*)\");\n}\ntemplate <class T> inline CVirtualRefPtr<T>::CVirtualRefPtr(const CVirtualRefPtr &copy)\n{\n\tpinfo=copy.pinfo;\n\tpinfo->RefCount++;\n\tPtr= const_cast<T*>(dynamic_cast<T const*>(static_cast<CVirtualRefCount const*>(pinfo->Ptr)));\n\tnlassert(Ptr != NULL || pinfo->Ptr == NULL);\n\n\tREF_TRACE(\"SmartCopy()\");\n}\ntemplate <class T> inline CVirtualRefPtr<T>::~CVirtualRefPtr(void)\n{\n\tREF_TRACE(\"~Smart()\");\n\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n}\n\n// ***************************************************************************\n// Operators=.\ntemplate <class T> CVirtualRefPtr<T> &CVirtualRefPtr<T>::operator=(T *v)\n{\n\tREF_TRACE(\"ope=(T*)Start\");\n\n\n\tPtr= v;\n\tif(v)\n\t{\n\t\t// If no CVirtualRefPtr handles v, create a pinfo ref...\n\t\tif(v->pinfo->IsNullPtrInfo)\n\t\t\tv->pinfo=new CRefCount::CPtrInfo(static_cast<CVirtualRefCount const*>(v)); // v MUST derive from CVirtualRefCount\n\t\t// The auto equality test is implicitly done by upcounting first \"v\", then downcounting \"this\".\n\t\tv->pinfo->RefCount++;\n\t\tunRef();\n\t\tpinfo= v->pinfo;\n\n#ifdef NL_DEBUG\n\t\tnlassert(v == const_cast<T*>(dynamic_cast<T const*>(static_cast<CVirtualRefCount const*>(pinfo->Ptr))));\n#endif\n\t}\n\telse\n\t{\n\t\tunRef();\n\t\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\t}\n\n\n\tREF_TRACE(\"ope=(T*)End\");\n\n\treturn *this;\n}\ntemplate <class T> CVirtualRefPtr<T> &CVirtualRefPtr<T>::operator=(const CVirtualRefPtr &copy)\n{\n\tREF_TRACE(\"ope=(Smart)Start\");\n\n\t// The auto equality test is implicitly done by upcounting first \"copy\", then downcounting \"this\".\n\tcopy.pinfo->RefCount++;\n\tunRef();\n\tpinfo=copy.pinfo;\n\t// Must Refresh the ptr.\n\tPtr= const_cast<T*>(dynamic_cast<T const*>(static_cast<CVirtualRefCount const*>(pinfo->Ptr)));\n\tnlassert(Ptr != NULL || pinfo->Ptr == NULL);\n\n\tREF_TRACE(\"ope=(Smart)End\");\n\treturn *this;\n}\n\n\n// ***************************************************************************\n// Operations.\ntemplate <class T> void\tCVirtualRefPtr<T>::kill()\n{\n\tREF_TRACE(\"SmartKill\");\n\n\tT\t*ptr= const_cast<T*>(dynamic_cast<T const*>(static_cast<CVirtualRefCount const*>(pinfo->Ptr)));\n\tnlassert(ptr != NULL || pinfo->Ptr == NULL);\n\n\t// First, release the refptr.\n\tunRef();\n\tpinfo= static_cast<CRefCount::CPtrInfo*>(&CRefCount::NullPtrInfo);\n\tPtr= NULL;\n\n\t// Then delete the pointer.\n\tif(ptr)\n\t\tdelete ptr;\n}\n\n\n// ***************************************************************************\n// Cast.\ntemplate <class T> inline CVirtualRefPtr<T>::operator T*()\tconst\n{\n\tREF_TRACE(\"SmartCast T*()\");\n\n\t// Refresh Ptr if necessary.\n\t// NB: It is preferable (faster) here to test if NULL and set NULL if necessary, than dynamic_casting the ptr.\n\tif (pinfo->Ptr == NULL)\n\t\tPtr = NULL;\n\treturn Ptr;\n}\n\n\n// ***************************************************************************\n// Operators.\ntemplate <class T> inline T& CVirtualRefPtr<T>::operator*(void)  const\n{\n\tREF_TRACE(\"Smart *()\");\n\treturn *Ptr;\n}\ntemplate <class T> inline T* CVirtualRefPtr<T>::operator->(void) const\n{\n\tREF_TRACE(\"Smart ->()\");\n\treturn Ptr;\n}\n\n// ***************************************************************************\n#undef\tSMART_INLINE\n\n\n\n} // NLMISC\n\n\n#endif // NL_SMARTPTR_INLINE_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/speaker_listener.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef SPEAKER_LISTENER_H\n#define SPEAKER_LISTENER_H\n\n\n#include \"types_nl.h\"\n\nnamespace NLMISC\n{\n\tclass ISpeaker;\n\n\tclass IListener\n\t{\n\tpublic:\n\t\tvirtual void speakerIsDead\t(ISpeaker *speaker) =0;\n\t};\n\n\tclass ISpeaker\n\t{\n\tpublic:\n\t\tvirtual void registerListener\t(IListener *listener) =0;\n\t\tvirtual void unregisterListener\t(IListener *listener) =0;\n\t};\n\n\ttemplate <class Listener>\n\tclass CSpeaker : public ISpeaker\n\t{\n\tpublic:\n\t\ttypedef std::set<IListener*>\tTListeners;\n\n\tprivate:\n\t\tTListeners\t\t_Listeners;\n\n\tpublic:\n\n\t\t~CSpeaker()\n\t\t{\n\t\t\twhile (!_Listeners.empty())\n\t\t\t{\n\t\t\t\tIListener *listener = *_Listeners.begin();\n\t\t\t\tlistener->speakerIsDead(this);\n\t\t\t\t_Listeners.erase(_Listeners.begin());\n\t\t\t}\n\t\t}\n\n\t\tvoid registerListener\t(IListener *listener)\n\t\t{\n\t\t\t_Listeners.insert(listener);\n\t\t}\n\t\tvoid unregisterListener\t(IListener *listener)\n\t\t{\n\t\t\t_Listeners.erase(listener);\n\t\t}\n\n\t\tconst TListeners &getListeners()\n\t\t{\n\t\t\treturn _Listeners;\n\t\t}\n\n\t};\n\n\n\t/** A macro to facilitate method invocation on listeners */\n#define NLMISC_BROADCAST_TO_LISTENER(listenerClass, methodAndParam)\t\\\n\tCSpeaker<listenerClass>::TListeners::const_iterator first(CSpeaker<listenerClass>::getListeners().begin()), last(CSpeaker<listenerClass>::getListeners().end()); \\\n\tfor (; first != last; ++first)\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tlistenerClass *listener = static_cast<listenerClass*>(*first);\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\tlistener->methodAndParam;\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\\\n\n\n\n\ttemplate <class Speaker>\n\tclass CListener : public IListener\n\t{\n\t\tISpeaker\t*_Speaker;\n\n\t\tvoid speakerIsDead(ISpeaker *speaker)\n\t\t{\n\t\t\tnlassert(speaker == _Speaker);\n\t\t\t_Speaker = NULL;\n\t\t}\n\n\tpublic:\n\n\t\tCListener()\n\t\t\t: _Speaker(NULL)\n\t\t{\n\t\t}\n\n\t\t~CListener()\n\t\t{\n\t\t\tif (_Speaker != NULL)\n\t\t\t\t_Speaker->unregisterListener(this);\n\t\t}\n\n\t\tvoid registerListener(ISpeaker *speaker)\n\t\t{\n\t\t\tnlassert(_Speaker == NULL);\n\t\t\t_Speaker = speaker;\n\t\t\t_Speaker->registerListener(this);\n\t\t}\n\n\t\tvoid unregisterListener(ISpeaker * /* speaker */)\n\t\t{\n\t\t\tnlassert(_Speaker != NULL);\n\t\t\t_Speaker->unregisterListener(this);\n\t\t\t_Speaker = NULL;\n\t\t}\n\n\t\tISpeaker *getSpeaker()\n\t\t{\n\t\t\treturn _Speaker;\n\t\t}\n\n\t};\n\n\n} // NLMISC\n\n#endif // SPEAKER_LISTENER_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/sstring.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SSTRING_H\n#define NL_SSTRING_H\n\n//#include \"types_nl.h\"\n#include <string>\n#include <vector>\n#include <cstdio>\n\n#include \"stream.h\"\n#include \"path.h\"\n#include \"string_common.h\"\n\nnamespace\tNLMISC\n{\n\n// advanced class declaration...\n//class CVectorSString;\nclass CSString;\ntypedef std::vector<CSString> CVectorSString;\n\n/**\n * CSString : std::string with more functionalities and case insensitive compare\n *\n * \\author Daniel Miller\n * \\author Nevrax\n * \\date 2003\n */\nclass CSString: public std::string\n{\npublic:\n\t///\tctor\n\tCSString();\n\t///\tctor\n\tCSString(const char *s);\n\t/// ctor\n\tCSString(const std::string &s);\n\t///\tctor\n\tCSString(char c);\n\t///\tctor\n\tCSString(int i,const char *fmt=\"%d\");\n\t///\tctor\n\tCSString(uint32 u,const char *fmt=\"%u\");\n\t/// ctor\n\tCSString(double d,const char *fmt=\"%f\");\n\t///\tctor\n\tCSString(const char *s,const char *fmt);\n\t///\tctor\n\tCSString(const std::string &s,const char *fmt);\n\t///\tctor\n\tCSString(const std::vector<NLMISC::CSString>& v,const std::string& separator=\"\\n\");\n\n\t/// Const [] operator\n\tstd::string::const_reference operator[](std::string::size_type idx) const;\n\t/// Non-Const [] operator\n\tstd::string::reference operator[](std::string::size_type idx);\n\n\t/// Return the first character, or '\\\\0' is the string is empty\n\tchar operator*();\n\t/// Return the n right hand most characters of a string\n\tchar back() const;\n\n\t/// Return the n left hand most characters of a string\n\tCSString left(uint32 count) const;\n\t/// Return the n right hand most characters of a string\n\tCSString right(uint32 count) const;\n\n\t/// Return the string minus the n left hand most characters of a string\n\tCSString leftCrop(uint32 count) const;\n\t/// Return the string minus the n right hand most characters of a string\n\tCSString rightCrop(uint32 count) const;\n\n\t/// Return sub string up to but not including first instance of given character, starting at 'iterator'\n\t/// on exit 'iterator' indexes first character after extracted string segment\n\tCSString splitToWithIterator(char c,uint32& iterator) const;\n\t/// Return sub string up to but not including first instance of given character\n\tCSString splitTo(char c) const;\n\t/// Return sub string up to but not including first instance of given character\n\tCSString splitTo(char c,bool truncateThis=false,bool absorbSeparator=true);\n\t/// Return sub string up to but not including first instance of given character\n\tCSString splitTo(const char *s,bool truncateThis=false);\n\t/// Return sub string up to but not including first non-quote encapsulated '//'\n\tCSString splitToLineComment(bool truncateThis=false, bool useSlashStringEscape=true);\n\n\t/// Return sub string from character following first instance of given character on\n\tCSString splitFrom(char c) const;\n\t/// Return sub string from character following first instance of given character on\n\tCSString splitFrom(const char *s) const;\n\n\t/// Behave like a s strtok() routine, returning the sun string extracted from (and removed from) *this\n\tCSString strtok(const char *separators,\n\t\t\t\t\tbool useSmartExtensions=false,\t\t\t// if true then match brackets etc (and refine with following args)\n\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t// - treat '<' and '>' as brackets\n\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// - treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\tbool useRepeatQuoteStringEscape=true);\t// - treat \"\"\"\" as '\"')\n\n\t/// Return first word (blank separated) - can remove extracted word from source string\n\tCSString firstWord(bool truncateThis=false);\n\t///\tReturn first word (blank separated)\n\tCSString firstWordConst() const;\n\t/// Return sub string remaining after the first word\n\tCSString tailFromFirstWord() const;\n\t/// Count the number of words in a string\n\tuint32 countWords() const;\n\t/// Extract the given word\n\tCSString word(uint32 idx) const;\n\n\t/// Return first word or quote-encompassed sub-string - can remove extracted sub-string from source string\n\tCSString firstWordOrWords(bool truncateThis=false,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true);\n\t///\tReturn first word or quote-encompassed sub-string\n\tCSString firstWordOrWordsConst(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const;\n\t/// Return sub string following first word (or quote-encompassed sub-string)\n\tCSString tailFromFirstWordOrWords(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const;\n\t/// Count the number of words (or quote delimited sub-strings) in a string\n\tuint32 countWordOrWords(bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const;\n\t/// Extract the given words (or quote delimited sub-strings)\n\tCSString wordOrWords(uint32 idx,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const;\n\n\t/// Return first line - can remove extracted line from source string\n\tCSString firstLine(bool truncateThis=false);\n\t///\tReturn first line\n\tCSString firstLineConst() const;\n\t/// Return sub string remaining after the first line\n\tCSString tailFromFirstLine() const;\n\t/// Count the number of lines in a string\n\tuint32 countLines() const;\n\t/// Extract the given line\n\tCSString line(uint32 idx) const;\n\n\t/// A handy utility routine for knowing if a character is a white space character or not (' ','\\t','\\n','\\r',26)\n\tstatic bool isWhiteSpace(char c);\n\t///\tTest whether character matches '{', '(','[' or '<' (the '<' test depends on the useAngleBrace parameter\n\tstatic bool isOpeningDelimiter(char c,bool useAngleBrace=false);\n\t///\tTest whether character matches '}', ')',']' or '>' (the '>' test depends on the useAngleBrace parameter\n\tstatic bool isClosingDelimiter(char c,bool useAngleBrace=false);\n\t///\tTest whether character matches '\\'' or '\\\"'\n\tstatic bool isStringDelimiter(char c);\n\t///\tTests whether the character 'b' is the closing delimiter or string delimiter corresponding to character 'a'\n\tstatic bool isMatchingDelimiter(char a,char b);\n\n\t/// A handy utility routine for knowing if a character is a valid component of a file name\n\tstatic bool isValidFileNameChar(char c);\n\t/// A handy utility routine for knowing if a character is a valid first char for a keyword (a..z, '_')\n\tstatic bool isValidKeywordFirstChar(char c);\n\t/// A handy utility routine for knowing if a character is a valid subsequent char for a keyword (a..z, '_', '0'..'9')\n\tstatic bool isValidKeywordChar(char c);\n\t/// A handy utility routine for knowing if a character is printable (isValidFileNameChar + more basic punctuation)\n\tstatic bool isPrintable(char c);\n\n\t/// A handy utility routine for knowing if a character is a hex digit 0..9, a..f\n\tstatic bool isHexDigit(char c);\n\t/// A handy utility routine for converting a hex digit to a numeric value 0..15\n\tstatic char convertHexDigit(char c);\n\n\t// a handy routine that tests whether a given string contains binary characters or not. Only characters>32 + isWhiteSpace() are valid\n\tbool isValidText();\n\t// a handy routine that tests whether a given string is a valid file name or not\n\t// \"\\\"hello there\\\\bla\\\"\"\tis valid\n\t// \"hello there\\\\bla\"\t\tis not valid - missing quotes\n\t// \"\\\"hello there\\\"\\\\bla\"\tis not valid - text after quotes\n\tbool isValidFileName() const;\n\t// a second handy routine that tests whether a given string is a valid file name or not\n\t// equivalent to ('\\\"'+*this+'\\\"').isValidFileName()\n\t// \"\\\"hello there\\\\bla\\\"\"\tis not valid  - too many quotes\n\t// \"hello there\\\\bla\"\t\tis valid\n\tbool isValidUnquotedFileName() const;\n\t// a handy routine that tests whether or not a given string is a valid keyword\n\tbool isValidKeyword() const;\n\t// a handy routine that tests whether or not a given string is quote encapsulated\n\tbool isQuoted(\tbool useAngleBrace=false,\t\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\tbool useRepeatQuoteStringEscape=true) const;\t// treat \"\"\"\" as '\"'\n\n\t///\tSearch for the closing delimiter matching the opening delimiter at position 'startPos' in the 'this' string\n\t/// on error returns startPos\n\tuint32 findMatchingDelimiterPos(bool useAngleBrace,bool useSlashStringEscape,bool useRepeatQuoteStringEscape,uint32 startPos=0) const;\n\n\t///\tExtract a chunk from the 'this' string\n\t/// if first non-blank character is a string delimiter or an opening delimiter then extracts up to the matching closing delimiter\n\t/// in all other cases an empty string is returned\n\t/// the return string includes the opening blank characters (it isn't stripped)\n\tCSString matchDelimiters(bool truncateThis=false,\n\t\t\t\t\t\t\t bool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t bool useSlashStringEscape=true,\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t bool useRepeatQuoteStringEscape=true);\t// treat \"\"\"\" as '\"'\n\n\t/// copy out section of string up to separator character, respecting quotes (but not brackets etc)\n\t/// on error tail after returned string doesn't begin with valid separator character\n\tCSString splitToStringSeparator(\tchar separator,\n\t\t\t\t\t\t\t\t\t\tbool truncateThis=false,\n\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter=false);\t// if true tail begins after separator char\n\n\t/// copy out section of string up to separator character, respecting quotes, brackets, etc\n\t/// on error tail after returned string doesn't begin with valid separator character\n\t/// eg: splitToSeparator(','); - this might be used to split some sort of ',' separated input\n\tCSString splitToSeparator(\tchar separator,\n\t\t\t\t\t\t\t\tbool truncateThis=false,\n\t\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter=false);\t// if true tail begins after separator char\n\n\tCSString splitToSeparator(\tchar separator,\n\t\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true) const;\t// treat \"\"\"\" as '\"'\n\n\t/// copy out section of string up to any of a given set of separator characters, respecting quotes, brackets, etc\n\t/// on error tail after returned string doesn't begin with valid separator character\n\t/// eg: splitToOneOfSeparators(\",;\",true,false,false,true); - this might be used to split a string read from a CSV file\n\tCSString splitToOneOfSeparators(\tconst CSString& separators,\n\t\t\t\t\t\t\t\t\t\tbool truncateThis=false,\n\t\t\t\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter=false,\t// if true tail begins after separator char\n\t\t\t\t\t\t\t\t\t\tbool splitStringAtBrackets=true);\t\t// if true consider brackets as breaks in the string\n\n\tCSString splitToOneOfSeparators(\tconst CSString& separators,\n\t\t\t\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true) const;\t// treat \"\"\"\" as '\"'\n\n\t/// Return true if the string is a single block encompassed by a pair of delimiters\n\t/// eg: \"((a)(b)(c))\" or \"(abc)\" return true wheras \"(a)(b)(c)\" or \"abc\" return false\n\tbool isDelimitedMonoBlock(\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t ) const;\n\n\t/// Return the sub string with leading and trailing delimiters ( such as '(' and ')' or '[' and ']' ) removed\n\t/// if the string isn't a delimited monoblock then the complete string is returned\n\t/// eg \"((a)b(c))\" returns \"(a)b(c)\" whereas \"(a)b(c)\" returns the identical \"(a)b(c)\"\n\tCSString stripBlockDelimiters(\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t ) const;\n\n\t/// Append the individual words in the string to the result vector\n\t/// retuns true on success\n\tbool splitWords(CVectorSString& result) const;\n\n\t/// Append the individual \"wordOrWords\" elements in the string to the result vector\n\t/// retuns true on success\n\tbool splitWordOrWords(CVectorSString& result,bool useSlashStringEscape=true,bool useRepeatQuoteStringEscape=true) const;\n\n\t/// Append the individual lines in the string to the result vector\n\t/// retuns true on success\n\tbool splitLines(CVectorSString& result) const;\n\n\t/// Append the separator-separated elements in the string to the result vector\n\t/// retuns true on success\n\tbool splitBySeparator(\tchar separator, CVectorSString& result,\n\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\tbool skipBlankEntries=false\t\t\t\t// dont add blank entries to the result vector\n\t\t\t\t\t\t ) const;\n\n\t/// Append the separator-separated elements in the string to the result vector\n\t/// retuns true on success\n\tbool splitByOneOfSeparators(\tconst CSString& separators, CVectorSString& result,\n\t\t\t\t\t\t\t\t\tbool useAngleBrace=false,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\tbool retainSeparators=false,\t\t\t// have the separators turn up in the result vector\n\t\t\t\t\t\t\t\t\tbool skipBlankEntries=false\t\t\t\t// dont add blank entries to the result vector\n\t\t\t\t\t\t\t\t ) const;\n\n\t/// join an array of strings to form a single string (appends to the existing content of this string)\n\t/// if this string is not empty then a separator is added between this string and the following\n\tconst CSString& join(const std::vector<CSString>& strings, const CSString& separator=\"\");\n\tconst CSString& join(const std::vector<CSString>& strings, char separator);\n\n\t/// Return a copy of the string with leading and trainling spaces removed\n\tCSString strip() const;\n\t/// Return a copy of the string with leading spaces removed\n\tCSString leftStrip() const;\n\t/// Return a copy of the string with trainling spaces removed\n\tCSString rightStrip() const;\n\n\t/// Making an upper case copy of a string\n\tCSString toUpper() const;\n\n\t/// Making a lower case copy of a string\n\tCSString toLower() const;\n\n\t/// encapsulate string in quotes, adding escape characters as necessary\n\tCSString quote(\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\tbool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t) const;\n\n\t/// if a string is not already encapsulated in quotes then return quote() else return *this\n\tCSString quoteIfNotQuoted(\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t) const;\n\n\t/// if a string is not a single word and is not already encapsulated in quotes then return quote() else return *this\n\tCSString quoteIfNotAtomic(\tbool useSlashStringEscape=true,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t) const;\n\n\t/// strip delimiting quotes and clear through escape characters as necessary\n\tCSString unquote(bool useSlashStringEscape=true,\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t bool useRepeatQuoteStringEscape=true\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t) const;\n\n\t/// equivalent to if (isQuoted()) unquote()\n\tCSString unquoteIfQuoted(bool useSlashStringEscape=true,\n\t\t\t\t\t bool useRepeatQuoteStringEscape=true\n\t\t\t\t\t) const;\n\n\t///\tencode special characters such as quotes, gt, lt, etc to xml encoding\n\t/// the isParameter paramter is true if the string is to be used in an XML parameter block\n\tCSString encodeXML(bool isParameter=false) const;\n\n\t///\tdecode special characters such as quotes, gt, lt, etc from xml encoding\n\tCSString decodeXML() const;\n\n\t/// verifies whether a string contains sub-strings that correspond to xml special character codes\n\tbool isEncodedXML() const;\n\n\t/// verifies whether a string contains any XML incompatible characters\n\t/// in this case the string can be converted to xml compatible format via encodeXML()\n\t/// the isParameter paramter is true if the string is to be used in an XML parameter block\n\tbool isXMLCompatible(bool isParameter=false) const;\n\n\t/// Replacing all occurences of one string with another\n\tCSString replace(const char *toFind,const char *replacement) const;\n\n\t/// Find index at which a sub-string starts (case not sensitive) - if sub-string not found then returns string::npos\n\tstd::string::size_type find(const char *toFind, std::string::size_type startLocation=0) const;\n\n\t/// Find index at which a sub-string starts (case NOT sensitive) - if sub-string not found then returns string::npos\n\tstd::string::size_type findNS(const char *toFind, std::string::size_type startLocation=0) const;\n\n\t/// Return true if this contains given sub string\n\tbool contains(const char *toFind) const;\n\n\t/// Return true if this contains given sub string\n\tbool contains(int character) const;\n\n\t/// Handy atoi routines...\n\tint atoi() const;\n\tsint32 atosi() const;\n\tuint32 atoui() const;\n\tsint64 atoi64() const;\n\tsint64 atosi64() const;\n\tuint64 atoui64() const;\n\n\t/// A handy atof routine...\n\tdouble atof() const;\n\n\t/// assignment operator\n\tCSString& operator=(const char *s);\n\t/// assignment operator\n\tCSString& operator=(const std::string &s);\n\t/// assignment operator\n\tCSString& operator=(char c);\n\t/// assignment operator\n\tCSString& operator=(int i);\n\t/// assignment operator\n\tCSString& operator=(uint32 u);\n\t/// assignment operator\n\tCSString& operator=(double d);\n\n\t/// Case insensitive string compare\n\tbool operator==(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator==(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator==(const char* other) const;\n\n\t/// Case insensitive string compare\n\tbool operator!=(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator!=(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator!=(const char* other) const;\n\n\t/// Case insensitive string compare\n\tbool operator<=(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator<=(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator<=(const char* other) const;\n\n\t/// Case insensitive string compare\n\tbool operator>=(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator>=(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator>=(const char* other) const;\n\n\t/// Case insensitive string compare\n\tbool operator>(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator>(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator>(const char* other) const;\n\n\t/// Case insensitive string compare\n\tbool operator<(const CSString &other) const;\n\t/// Case insensitive string compare\n\tbool operator<(const std::string &other) const;\n\t/// Case insensitive string compare\n\tbool operator<(const char* other) const;\n\n\t//@{\n\t//@name Easy concatenation operator to build strings\n\ttemplate <class T>\n\tCSString &operator <<(const T &value)\n\t{\n\t\toperator +=(NLMISC::toString(value));\n\n\t\treturn *this;\n\t}\n\n\t// specialisation for C string\n\tCSString &operator <<(const char *value)\n\t{\n\t\tstatic_cast<std::string*>(this)->operator +=(value);\n\n\t\treturn *this;\n\t}\n\n\t// specialisation for character\n\tCSString &operator <<(char value)\n\t{\n\t\tstatic_cast<std::string*>(this)->operator +=(value);\n\n\t\treturn *this;\n\t}\n\n\t// specialisation for std::string\n\tCSString &operator <<(const std::string &value)\n\t{\n\t\tstatic_cast<std::string*>(this)->operator +=(value);\n\n\t\treturn *this;\n\t}\n\t// specialisation for CSString\n\tCSString &operator <<(const CSString &value)\n\t{\n\t\tstatic_cast<std::string*>(this)->operator +=(value);\n\n\t\treturn *this;\n\t}\n\t//@}\n\n\t/// Case insensitive string compare (useful for use as map keys, see less<CSString> below)\n\tbool icompare(const std::string &other) const;\n\n\t/// Serial\n\tvoid serial( NLMISC::IStream& s );\n\n\t/// Read a text file into a string\n\tbool readFromFile(const CSString& fileName);\n\n\t/// Write a string to a text file\n\t// returns true on success, false on failure\n\tbool writeToFile(const CSString& fileName) const;\n\n\t/// Write a string to a text file\n\t// if the file already exists and its content is identicall to our own then it is not overwritten\n\t// returns true on success (including the case where the file exists and is not overwritten), false on failure\n\tbool writeToFileIfDifferent(const CSString& fileName) const;\n};\n\n\n/*\n * Vector of CSString compatible with vector<string>\n */\n//typedef std::vector<CSString> CVectorSString;\n\n\n/*CVectorSString &operator = (CVectorSString &left, const std::vector<std::string> &right)\n{\n\tleft = reinterpret_cast<CVectorSString&>(right);\n}\nCVectorSString &operator = (CVectorSString &left, const std::vector<CSString> &right)\n{\n\tleft = reinterpret_cast<CVectorSString&>(right);\n}\n*/\n//class CVectorSString : public std::vector<CSString>\n//{\n//public:\n//\t// cast to and convert from std::vector<std::string>\n//\toperator std::vector<std::string>& ()\n//\t{\n//\t\treturn reinterpret_cast<std::vector<std::string>&>(*this);\n//\t}\n//\toperator const std::vector<std::string>& () const\n//\t{\n//\t\treturn reinterpret_cast<const std::vector<std::string>&>(*this);\n//\t}\n//\tCVectorSString&\toperator= ( const std::vector<std::string>& v )\n//\t{\n//\t\t*this = reinterpret_cast<const CVectorSString&>(v);\n//\t\treturn *this;\n//\t}\n//\n//\t// simple ctors\n//\tCVectorSString()\t\t\t\t\t\t\t{}\n//\tCVectorSString( const CVectorSString& v )\t{ operator=(v); }\n//\n//\t// ctors for building from different vetor types\n//\tCVectorSString( const std::vector<CSString>& v ):\t\t\t\t\t\t\tstd::vector<CSString>(v)\t\t\t{}\n//\tCVectorSString( const std::vector<std::string>& v ):\t\t\t\t\t\tstd::vector<CSString>(*(std::vector<CSString>*)&v) {}\n//\n//\t// ctor for extracting sub_section of another vector\n//\tCVectorSString( const const_iterator& first, const const_iterator& last ):\tstd::vector<CSString>(first,last)\t{}\n//};\n\n\n/*\n * Inlines\n */\n\ninline CSString::CSString()\n{\n}\n\ninline CSString::CSString(const char *s)\n{\n\t*(std::string *)this=s;\n}\n\ninline CSString::CSString(const std::string &s)\n{\n    assign( s.c_str(), s.size() );\n}\n\ninline CSString::CSString(char c)\n{\n\t*(std::string *)this=c;\n}\n\ninline CSString::CSString(int i,const char *fmt)\n{\n\tchar buf[1024];\n\tsprintf(buf,fmt,i);\n\t*this=buf;\n}\n\ninline CSString::CSString(uint32 u,const char *fmt)\n{\n\tchar buf[1024];\n\tsprintf(buf,fmt,u);\n\t*this=buf;\n}\n\ninline CSString::CSString(double d,const char *fmt)\n{\n\tchar buf[1024];\n\tsprintf(buf,fmt,d);\n\t*this=buf;\n}\n\ninline CSString::CSString(const char *s,const char *fmt)\n{\n\tchar buf[1024];\n\tsprintf(buf,fmt,s);\n\t*this=buf;\n}\n\ninline CSString::CSString(const std::string &s,const char *fmt)\n{\n\tchar buf[1024];\n\tsprintf(buf,fmt,s.c_str());\n\t*this=buf;\n}\n\ninline CSString::CSString(const std::vector<NLMISC::CSString>& v,const std::string& separator)\n{\n\tfor (uint32 i=0;i<v.size();++i)\n\t{\n\t\tif (i>0)\n\t\t\t*this+=separator;\n\t\t*this+=v[i];\n\t}\n}\n\ninline char CSString::operator*()\n{\n\tif (empty())\n\t\treturn 0;\n\treturn (*this)[0];\n}\n\ninline char CSString::back() const\n{\n\treturn (*this)[size()-1];\n}\n\ninline CSString CSString::right(uint32 count) const\n{\n\tif (count>=size())\n\t\treturn *this;\n\treturn substr(size()-count);\n}\n\ninline CSString CSString::rightCrop(uint32 count) const\n{\n\tif (count>=size())\n\t\treturn CSString();\n\treturn substr(0,size()-count);\n}\n\ninline CSString CSString::left(uint32 count) const\n{\n\treturn substr(0,count);\n}\n\ninline CSString CSString::leftCrop(uint32 count) const\n{\n\tif (count>=size())\n\t\treturn CSString();\n\treturn substr(count);\n}\n\ninline CSString CSString::splitToWithIterator(char c,uint32& iterator) const\n{\n\tuint32 i;\n\tCSString result;\n\tfor (i=iterator;i<size() && (*this)[i]!=c;++i)\n\t\tresult+=(*this)[i];\n\titerator= i;\n\treturn result;\n}\n\ninline bool CSString::isWhiteSpace(char c)\n{\n\treturn c==' ' || c=='\\t' || c=='\\n' || c=='\\r' || c==26;\n}\n\ninline bool CSString::isOpeningDelimiter(char c,bool useAngleBrace)\n{\n\treturn c=='(' || c=='[' || c=='{' || (useAngleBrace && c=='<');\n}\n\ninline bool CSString::isClosingDelimiter(char c,bool useAngleBrace)\n{\n\treturn c==')' || c==']' || c=='}' || (useAngleBrace && c=='>');\n}\n\ninline bool CSString::isStringDelimiter(char c)\n{\n\treturn c=='\\\"' || c=='\\'';\n}\n\ninline bool CSString::isMatchingDelimiter(char a,char b)\n{\n\treturn\t(a=='(' && b==')') || (a=='[' && b==']') ||\n\t\t\t(a=='{' && b=='}') || (a=='<' && b=='>') ||\n\t\t\t(a=='\\\"' && b=='\\\"') || (a=='\\'' && b=='\\'');\n}\n\ninline bool CSString::isValidFileNameChar(char c)\n{\n\tif (c>='a' && c<='z') return true;\n\tif (c>='A' && c<='Z') return true;\n\tif (c>='0' && c<='9') return true;\n\tif (c=='_') return true;\n\tif (c==':') return true;\n\tif (c=='/') return true;\n\tif (c=='\\\\') return true;\n\tif (c=='.') return true;\n\tif (c=='#') return true;\n\tif (c=='-') return true;\n\treturn false;\n}\n\ninline bool CSString::isPrintable(char c)\n{\n\tif (isValidFileNameChar(c)) return true;\n\tif (c==' ') return true;\n\tif (c=='*') return true;\n\tif (c=='?') return true;\n\tif (c=='!') return true;\n\tif (c=='@') return true;\n\tif (c=='&') return true;\n\tif (c=='|') return true;\n\tif (c=='+') return true;\n\tif (c=='=') return true;\n\tif (c=='%') return true;\n\tif (c=='<') return true;\n\tif (c=='>') return true;\n\tif (c=='(') return true;\n\tif (c==')') return true;\n\tif (c=='[') return true;\n\tif (c==']') return true;\n\tif (c=='{') return true;\n\tif (c=='}') return true;\n\tif (c==',') return true;\n\tif (c==';') return true;\n\tif (c=='$') return true;\n\tif ((uint8)c==156) return true; // Sterling Pound char causing error in gcc 4.1.2\n\tif (c=='^') return true;\n\tif (c=='~') return true;\n\tif (c=='\\'') return true;\n\tif (c=='\\\"') return true;\n\treturn false;\n}\n\ninline bool CSString::isQuoted(bool useAngleBrace,bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n{\n\treturn (left(1)==\"\\\"\") && (right(1)==\"\\\"\") && isDelimitedMonoBlock(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape);\n}\n\ninline bool CSString::isValidKeywordFirstChar(char c)\n{\n\tif (c>='a' && c<='z') return true;\n\tif (c>='A' && c<='Z') return true;\n\tif (c=='_') return true;\n\treturn false;\n}\n\ninline bool CSString::isValidKeywordChar(char c)\n{\n\tif (c>='a' && c<='z') return true;\n\tif (c>='A' && c<='Z') return true;\n\tif (c>='0' && c<='9') return true;\n\tif (c=='_') return true;\n\treturn false;\n}\n\ninline bool CSString::isHexDigit(char c)\n{\n\tif (c>='0' && c<='9') return true;\n\tif (c>='A' && c<='F') return true;\n\tif (c>='a' && c<='f') return true;\n\treturn false;\n}\n\ninline char CSString::convertHexDigit(char c)\n{\n\tif (c>='0' && c<='9') return c-'0';\n\tif (c>='A' && c<='F') return c-'A'+10;\n\tif (c>='a' && c<='f') return c-'a'+10;\n\treturn 0;\n}\n\ninline CSString& CSString::operator=(const char *s)\n{\n\t*(std::string *)this=s;\n\treturn *this;\n}\n\ninline CSString& CSString::operator=(const std::string &s)\n{\n    assign( s.c_str(), s.size() );\n\treturn *this;\n}\n\ninline CSString& CSString::operator=(char c)\n{\n\t*(std::string *)this=c;\n\treturn *this;\n}\n\ninline CSString& CSString::operator=(int i)\n{\n\tCSString other(i);\n\t*this = other;\n\treturn *this;\n}\n\ninline CSString& CSString::operator=(uint32 u)\n{\n\tCSString other(u);\n\t*this = other;\n\treturn *this;\n}\n\ninline CSString& CSString::operator=(double d)\n{\n\tCSString other(d);\n\t*this = other;\n\treturn *this;\n}\n\ninline bool CSString::operator==(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())==0;\n}\n\ninline bool CSString::operator==(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())==0;\n}\n\ninline bool CSString::operator==(const char* other) const\n{\n\treturn stricmp(c_str(),other)==0;\n}\n\ninline bool CSString::operator!=(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())!=0;\n}\n\ninline bool CSString::operator!=(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())!=0;\n}\n\ninline bool CSString::operator!=(const char* other) const\n{\n\treturn stricmp(c_str(),other)!=0;\n}\n\ninline bool CSString::operator<=(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())<=0;\n}\n\ninline bool CSString::operator<=(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())<=0;\n}\n\ninline bool CSString::operator<=(const char* other) const\n{\n\treturn stricmp(c_str(),other)<=0;\n}\n\ninline bool CSString::operator>=(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())>=0;\n}\n\ninline bool CSString::operator>=(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())>=0;\n}\n\ninline bool CSString::operator>=(const char* other) const\n{\n\treturn stricmp(c_str(),other)>=0;\n}\n\ninline bool CSString::operator>(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())>0;\n}\n\ninline bool CSString::operator>(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())>0;\n}\n\ninline bool CSString::operator>(const char* other) const\n{\n\treturn stricmp(c_str(),other)>0;\n}\n\ninline bool CSString::operator<(const CSString &other) const\n{\n\treturn stricmp(c_str(),other.c_str())<0;\n}\n\ninline bool CSString::operator<(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())<0;\n}\n\ninline bool CSString::operator<(const char* other) const\n{\n\treturn stricmp(c_str(),other)<0;\n}\n\ninline std::string::const_reference CSString::operator[](std::string::size_type idx) const\n{\n\tstatic char zero=0;\n\tif (idx >= size())\n\t\treturn zero;\n\treturn data()[idx];\n}\n\ninline std::string::reference CSString::operator[](std::string::size_type idx)\n{\n\tstatic char zero=0;\n\tif (idx >= size())\n\t\treturn zero;\n\treturn const_cast<std::string::value_type&>(data()[idx]);\n}\n\n\ninline bool CSString::icompare(const std::string &other) const\n{\n\treturn stricmp(c_str(),other.c_str())<0;\n}\n\ninline void CSString::serial( NLMISC::IStream& s )\n{\n\ts.serial( reinterpret_cast<std::string&>( *this ) );\n}\n\n/*\ninline CSString operator+(const CSString& s0,char s1)\n{\n\treturn CSString(s0)+s1;\n}\n\ninline CSString operator+(const CSString& s0,const char* s1)\n{\n\treturn CSString(s0)+s1;\n}\n\ninline CSString operator+(const CSString& s0,const std::string& s1)\n{\n\treturn CSString(s0)+s1;\n}\ninline CSString operator+(const CSString& s0,const CSString& s1)\n{\n\treturn CSString(s0)+s1;\n}\n*/\ninline CSString operator+(char s0,const CSString& s1)\n{\n\treturn CSString(s0) + s1.c_str();\n}\n\ninline CSString operator+(const char* s0,const CSString& s1)\n{\n\treturn CSString(s0) + s1.c_str();\n}\n\n#if !defined(NL_COMP_VC) || (NL_COMP_VC_VERSION <= 100)\n// TODO: check if it can be disabled for other compilers too\ninline CSString operator+(const std::string& s0,const CSString& s1)\n{\n\treturn s0+static_cast<const std::string&>(s1);\n}\n#endif\n\n} // NLMISC\n\n// *** The following was commented out by Sadge because there were strange compilation/ link issues ***\n// *** The '<' operator was implemented instead ***\n//_STLP_BEGIN_NAMESPACE\n//namespace std\n//{\n//\t/*\n//\t * less<CSString> is case insensitive\n//\t */\n//\ttemplate <>\n//\tstruct less<NLMISC::CSString> : public std::binary_function<NLMISC::CSString, NLMISC::CSString, bool>\n//\t{\n//\t\tbool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x.icompare(y); }\n//\t};\n//} // std\n//_STLP_END_NAMESPACE\n//namespace std\n//{\n\n//\t/*\n//\t * less<CSString> is case insensitive\n//\t */\n//\ttemplate <>\n//\tstruct less<NLMISC::CSString> : public std::binary_function<NLMISC::CSString, NLMISC::CSString, bool>\n//\t{\n//\t\tbool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x.icompare(y); }\n//\t};\n//} // std\n//_STLP_END_NAMESPACE\n\n/**\n  * Instead of overriding std::less, please use the following predicate.\n  * For example, declare your map as:\n  *   std::map<NLMISC::CSString, CMyDataClass, NLMISC::CUnsensitiveSStringLessPred> MyMap;\n  * Caution: a map declared without CUnsensitiveSStringLessPred will behave as a\n  * standard string map.\n  *\n  * \\see also CUnsensitiveStrLessPred in misc/string_conversion.h\n  * for a similar predicate with std::string.\n  */\nstruct CUnsensitiveSStringLessPred : public std::less<NLMISC::CSString>\n{\n\tbool operator()(const NLMISC::CSString& x, const NLMISC::CSString& y) const { return x < y; /*.icompare(y);*/ }\n};\n\n\n#endif // NL_SSTRING_H\n\n/* End of sstring.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/static_map.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STATIC_MAP_H\n#define NL_STATIC_MAP_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n#include \"stream.h\"\n#include \"debug.h\"\n\n#include <map>\n\n// With NeL Memory Debug, use new\n#ifndef NL_USE_DEFAULT_MEMORY_MANAGER\n# ifndef NLMISC_HEAP_ALLOCATION_NDEBUG\n#  define NL_OV_USE_NEW_ALLOCATOR\n# endif // NLMISC_HEAP_ALLOCATION_NDEBUG\n#endif // NL_USE_DEFAULT_MEMORY_MANAGER\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\n * Implemented with a std::vector\n * Use it not like a map : begin by adding all your values with add()/del()/fromMap()\n * and then call endAdd() that performs a slow sort on the vector and then call find()\n * to find the element you want. If you have not called endAdd() its done in find(),\n * but take care that endAdd() is slow.\n * \\author Matthieu 'Trap' Besson\n * \\author Nevrax France\n * \\date October 2003\n */\ntemplate<class Key, class Typ, class Comp = std::less<Key> >\tclass CStaticMap\n{\npublic:\n\ttypedef Key\t\t\t\t\t\tkey_type;\n\ttypedef Typ\t\t\t\t\t\tdata_type;\n\ttypedef Typ\t\t\t\t\t\tmapped_type;\n\ttypedef std::pair<Key, Typ>\t\tvalue_type;\n\ttypedef Comp\t\t\t\t\tkey_compare;\n\n\tclass value_compare : public std::binary_function<value_type, value_type, bool>\n\t{\n\t\tfriend class CStaticMap<Key, Typ, Comp>;\n\tpublic:\n\t\tbool operator()(const value_type& __x, const value_type& __y) const\n\t\t{\n\t\t\treturn _CompareFunc(__x.first, __y.first);\n\t\t}\n\tprotected :\n\t\tComp _CompareFunc;\n\tprotected :\n\t\t// Constructor\n\t\tvalue_compare(Comp __c) : _CompareFunc(__c) {}\n\t};\n\nprivate:\n\n\tstd::vector<value_type> _Data;\n\tbool\t\t\t\t\t_DataSorted;\n\tComp\t\t\t\t\t_CompFunc;\n\n\npublic:\n\n\ttypedef typename std::vector<value_type>::reference\t\t\t\t\treference;\n\ttypedef typename std::vector<value_type>::const_reference\t\t\tconst_reference;\n\ttypedef typename std::vector<value_type>::iterator\t\t\t\t\titerator;\n\ttypedef typename std::vector<value_type>::const_iterator\t\t\tconst_iterator;\n\ttypedef typename std::vector<value_type>::reverse_iterator\t\t\treverse_iterator;\n\ttypedef typename std::vector<value_type>::const_reverse_iterator\tconst_reverse_iterator;\n\ttypedef typename std::vector<value_type>::size_type\t\t\t\t\tsize_type;\n\ttypedef typename std::vector<value_type>::difference_type\t\t\tdifference_type;\n\n  // allocation/deallocation\n\n\tCStaticMap() : _DataSorted(true)\n\t{\n\t}\n\n\texplicit CStaticMap (const Comp& /* __comp */) : _DataSorted(true)\n\t{\n\t}\n\n\tCStaticMap (const_iterator __first, const_iterator __last)\n\t{\n\t\t_DataSorted = false;\n\t\t_Data.insert(__first, __last);\n\t\tendAdd();\n\t}\n\n\tCStaticMap (const_iterator __first, const_iterator __last, const Comp& __comp)\n\t\t: _CompFunc(__comp)\n\t{\n\t\t_DataSorted = false;\n\t\t_Data.insert(__first, __last);\n\t\tendAdd();\n\t}\n\n\tCStaticMap(const CStaticMap<Key, Typ, Comp>& __x)\n\t\t: _Data(__x._Data) , _DataSorted(__x._DataSorted), _CompFunc(__x._CompFunc)\n\t{\n\t}\n\n\tCStaticMap<Key, Typ, Comp>& operator= (const CStaticMap<Key, Typ, Comp>& __x)\n\t{\n\t\t_Data = __x._Data;\n\t\tendAdd();\n\t\treturn *this;\n\t}\n\n\t// accessors:\n\n\tkey_compare\t\t\t\tkey_comp() const\t\t{ return _Data.key_comp(); }\n\tvalue_compare\t\t\tvalue_comp() const\t\t{ return value_compare(_CompFunc); }\n\titerator\t\t\t\tbegin()\t\t\t\t\t{ endAdd(); return _Data.begin(); }\n\tconst_iterator\t\t\tbegin() const\t\t\t{ endAdd(); return _Data.begin(); }\n\titerator\t\t\t\tend()\t\t\t\t\t{ endAdd(); return _Data.end(); }\n\tconst_iterator\t\t\tend() const\t\t\t\t{ endAdd(); return _Data.end(); }\n\treverse_iterator\t\trbegin()\t\t\t\t{ endAdd(); return _Data.rbegin(); }\n\tconst_reverse_iterator\trbegin() const\t\t\t{ endAdd(); return _Data.rbegin(); }\n\treverse_iterator\t\trend()\t\t\t\t\t{ endAdd(); return _Data.rend(); }\n\tconst_reverse_iterator\trend() const\t\t\t{ endAdd(); return _Data.rend(); }\n\tbool\t\t\t\t\tempty() const\t\t\t{ return _Data.empty(); }\n\tsize_type\t\t\t\tsize() const\t\t\t{ return _Data.size(); }\n\tsize_type\t\t\t\tmax_size() const\t\t{ return _Data.max_size(); }\n\n\tTyp& operator[](const key_type& __k)\n\t{\n\t\titerator __i = find(__k);\n\t\t// The key MUST exist no automatic insertion done in this class\n\t\tnlassert(__i != end());\n\t\treturn (*__i).second;\n\t}\n\n\tvoid swap (CStaticMap<Key, Typ, Comp>& __x)\n\t{\n\t\t_Data.swap (__x._Data);\n\t\t_DataSorted = false;\n\t}\n\n\t// Add an element in the static map\n\n\tvoid reserve(size_type n)\n\t{\n\t\t_Data.reserve(n);\n\t}\n\n\tvoid add(const value_type& __v)\n\t{\n\t\t_DataSorted = false;\n\t\t_Data.push_back (__v);\n\t}\n\n\tvoid fromMap (const std::map<Key, Typ, Comp> &m)\n\t{\n\t\t_DataSorted = false;\n\t\t_Data.reserve(m.size());\n\t\ttypename std::map<Key,Typ,Comp>::const_iterator itEnd = m.end();\n\t\ttypename std::map<Key,Typ,Comp>::const_iterator it = m.begin();\n\t\tfor (; it != itEnd; it++)\n\t\t\t_Data.push_back (std::pair<Key, Typ>(it->first, it->second));\n\t}\n\n\tvoid endAdd()\n\t{\n\t\tif (_DataSorted) return;\n\t\t_DataSorted = true;\n\t\tsort (_Data.begin(), _Data.end(), value_comp());\t// Sort the vector\n\t}\n\n\t// Delete an element from the static map\n\n\tvoid del(iterator __position)\n\t{\n\t\tnlassert(_DataSorted);\n\t\t_Data.erase (__position);\n\t}\n\n\tsize_type del(const key_type& __x)\n\t{\n\t\tendAdd();\n\t\treturn _Data.erase (__x);\n\t}\n\n\tvoid del(iterator __first, iterator __last)\n\t{\n\t\tnlassert(_DataSorted);\n\t\t_Data.erase (__first, __last);\n\t}\n\n\tvoid clear()\n\t{\n\t\t_Data.clear();\n\t}\n\n\t// map operations:\n\n\titerator find(const key_type& __x)\n\t{\n\t\tendAdd();\n\t\tvalue_type __v(__x, Typ());\n\t\titerator it = lower_bound((iterator)_Data.begin(), (iterator)_Data.end(), __v, value_comp());\n\t\tif ((it != end()) && (!value_comp()(*it,__v) && !value_comp()(__v,*it)))\n\t\t\treturn it;\n\t\telse\n\t\t\treturn end();\n\t}\n\n\tconst_iterator find(const key_type& __x) const\n\t{\n\t\tendAdd();\n\t\tvalue_type __v(__x, Typ());\n\t\titerator it = lower_bound((const_iterator)_Data.begin(), (const_iterator)_Data.end(), __v, value_comp());\n\t\tif ((it != end()) && (!value_comp()(*it,__v) && !value_comp()(__v,*it)))\n\t\t\treturn it;\n\t\telse\n\t\t\treturn end();\n\t}\n\n\tsize_type count(const key_type& __x) const\n\t{\n\t\tendAdd();\n\t\treturn find(__x) == _Data.end() ? 0 : 1;\n\t}\n};\n\n\n} // NLMISC\n\n\n#endif // NL_STATIC_MAP_H\n\n/* End of static_map.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/stl_block_allocator.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STL_BLOCK_ALLOCATOR_H\n#define NL_STL_BLOCK_ALLOCATOR_H\n\n\n#include \"types_nl.h\"\n#include \"block_memory.h\"\n\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\n * This class is a STL block allocator which use CBlockMemory. see CBlockMemory for description\n *\tof block memory management/advantages.\n *\n * This class works with STLPort. It implements __stl_alloc_rebind() (not C++ standard??) to work properly\n *\twith list<>/set<> etc... node allocations.\n *\n * NB: if used with a vector<> or a deque<> (ie if allocate(..,n) is called with n>1), it's still work,\n *\tbut it's use malloc()/free() instead, so it is fully useless in this case :)\n *\n * CSTLBlockAllocator use a pointer on a CBlockMemory, so multiple containers can share the same\n *\tblockMemory, for maximum space/speed efficiency.\n *\n * Because of CBlockMemory allocation scheme, only same containers of same types can share the\n *\tsame CBlockMemory instance (eg: \"list<uint, &myBlockMemory>; vector<uint, &myBlockMemory>;\" is invalid and\n *\twill assert when allocations will occur).\n *\n * To construct a container which use this allocator, do like this:\n *\tlist<uint, CSTLBlockAllocator<uint> >\t\tmyList( ptrOnBlockMemory );\n *\n * But see CSTLBlockList for easier list instanciation, because using it, you'll do like this:\n *\tCSTLBlockList<uint>\t\tmyList(ptrOnBlockMemory);\n *\n * Note: CSTLBlockAllocator take only 4 bytes in memory (a ptr on a CBlockMemory)\n *\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\n\n\ttemplate<class T>\n\tclass CSTLBlockAllocator : public std::allocator< T >\n\t{\n\tpublic:\n\t\t/// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory<T, false> !!!\n\t\tCSTLBlockAllocator(CBlockMemory<T, false> * /* bm */)\n\t\t{\n\t\t}\n\t\t/// copy ctor\n\t\tCSTLBlockAllocator(const CSTLBlockAllocator<T> &other) : std::allocator<T>(other)\n\t\t{\n\t\t}\n\t\t/// dtor\n\t\t~CSTLBlockAllocator()\n\t\t{\n\t\t}\n\t};\n\n#if 0\n#if defined(NL_OS_WINDOWS) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES)\n\ntemplate<class T>\nclass CSTLBlockAllocator\n{\npublic:\n\n\t/// \\name standard allocator interface.\n\t// @{\n\n\ttypedef T\t\t\tvalue_type;\n\ttypedef value_type *pointer;\n\ttypedef const T*\tconst_pointer;\n\ttypedef T&\t\t\treference;\n\ttypedef const T&\tconst_reference;\n\ttypedef size_t\t\tsize_type;\n\ttypedef ptrdiff_t\tdifference_type;\n\n\n\tpointer\tadress(reference x) const\n\t{\n\t\treturn &x;\n\t}\n\n\tconst_pointer\tadress(const_reference x) const\n\t{\n\t\treturn &x;\n\t}\n\n\tvoid\tconstruct(pointer p, const T &val)\n\t{\n\t\tnew (p) T(val);\n\t}\n\n\tvoid\tdestroy(pointer p)\n\t{\n\t\tp->T::~T();\n\t}\n\n\t// @}\n\npublic:\n\n\t/// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory<T, false> !!!\n\tCSTLBlockAllocator(CBlockMemory<T, false> *bm) : _BlockMemory(bm)\n\t{\n\t}\n\t/// copy ctor\n\tCSTLBlockAllocator(const CSTLBlockAllocator<T> &other) : _BlockMemory(other._BlockMemory)\n\t{\n\t\t// just copy the block memory from the other allocator.\n\t}\n\t/// dtor\n\t~CSTLBlockAllocator()\n\t{\n\t\t_BlockMemory= NULL;\n\t}\n\n\n\tpointer\tallocate(size_type n, const_pointer hint= NULL)\n\t{\n\t\tif(n==0)\n\t\t\treturn NULL;\n\t\t// If sizeof 1, use CBlockMemory allocation\n\t\tif(n==1)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\t// verify that we allocate with good size!! (verify __stl_alloc_rebind scheme).\n\t\t\t// ie an allocator can be used only to allocate a kind of element\n\t\t\tuint\teltSize= std::max(sizeof(T), sizeof(void*));\n\t\t\tnlassert( eltSize == _BlockMemory->__stl_alloc_getEltSize() );\n#endif\n\t\t\t// and allocate.\n\t\t\treturn _BlockMemory->allocate();\n\t\t}\n\t\t// else use std malloc\n\t\telse\n\t\t\treturn (T*)new uint8[n*sizeof(T)];\n\t}\n\n\tvoid\tdeallocate(void *p, size_type n)\n\t{\n\t\tif(n==0)\n\t\t\treturn;\n\t\t// If sizeof 1, use CBlockMemory allocation\n\t\tif(n==1)\n\t\t\t_BlockMemory->free((T*)p);\n\t\t// else use std free\n\t\telse\n\t\t\tdelete [] ((uint8*)p);\n\t}\n\n\n\ttemplate <class _Tp, class U>\n\tCSTLBlockAllocator<U>& __stl_alloc_rebind(CSTLBlockAllocator<_Tp>& __a, const U*)\n\t{\n\t\t// must change the internal eltSize of __a.\n\t\t__a._BlockMemory->__stl_alloc_changeEltSize(sizeof(U));\n\t\t// and just typecast/return him\n\t\treturn (CSTLBlockAllocator<U>&)(__a);\n\t}\n\n\ttemplate <class _Tp, class U>\n\tCSTLBlockAllocator<U> __stl_alloc_create(const CSTLBlockAllocator<_Tp>&, const U*)\n\t{\n\t\treturn CSTLBlockAllocator<U>();\n\t}\n\n\n\n// *******************\nprivate:\n\n\t// The blockMemory used to allocate elements\n\tCBlockMemory<T, false>\t\t*_BlockMemory;\n\n};\n\n\n#else // NL_OS_WINDOWS\n\n# if !defined (__STL_USE_SGI_ALLOCATORS)\ntemplate<class T>\nclass CSTLBlockAllocator : public  std::allocator< T >\n{\npublic:\n\n\t/// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory<T, false> !!!\n\tCSTLBlockAllocator(CBlockMemory<T, false> *bm)\n\t{\n\t}\n\t/// copy ctor\n\tCSTLBlockAllocator(const CSTLBlockAllocator<T> &other) : std::allocator<T>(other)\n\t{\n\t}\n\t/// dtor\n\t~CSTLBlockAllocator()\n\t{\n\t}\n\n};\n# else\t// !defined (__STL_USE_SGI_ALLOCATORS)\nclass CSTLBlockAllocator : public  __sgi_alloc\n{\npublic:\n\n\t/// Constructor. Must gives a blockMemory to ctor. NB: must gives a CBlockMemory<T, false> !!!\n\tCSTLBlockAllocator(CBlockMemory<T, false> *bm)\n\t{\n\t}\n\t/// copy ctor\n\tCSTLBlockAllocator(const CSTLBlockAllocator<T> &other) : __sgi_alloc(other)\n\t{\n\t}\n\t/// dtor\n\t~CSTLBlockAllocator()\n\t{\n\t}\n\n};\n# endif\t// !defined (__STL_USE_SGI_ALLOCATORS)\n\n\n#endif // NL_OS_WINDOWS\n\n#endif // 0\n\n} // NLMISC\n\n\n#endif // NL_STL_BLOCK_ALLOCATOR_H\n\n/* End of stl_block_allocator.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/stl_block_list.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STL_BLOCK_LIST_H\n#define NL_STL_BLOCK_LIST_H\n\n#include \"types_nl.h\"\n#include \"stl_block_allocator.h\"\n\n#include <list>\n\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\n * This class is a list<> which use CSTLBlockAllocator\n *\n * You construct such a list like this:\n *\tCSTLBlockList<uint>\t\tmyList(ptrOnBlockMemory);\n *\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate <class T>\nclass CSTLBlockList : public std::list<T, CSTLBlockAllocator<T> >\n{\npublic:\n\n\ttypedef typename NLMISC::CSTLBlockList<T>::size_type TSizeType;\n\ttypedef typename NLMISC::CSTLBlockList<T>::const_iterator TBlockListConstIt;\n\n\texplicit CSTLBlockList(CBlockMemory<T, false> *bm ) :\n\tstd::list<T, CSTLBlockAllocator<T> >(CSTLBlockAllocator<T>(bm))\n\t{\n\t}\n\n\texplicit CSTLBlockList(TSizeType n, CBlockMemory<T, false> *bm ) :\n\tstd::list<T, CSTLBlockAllocator<T> >(n,T(),CSTLBlockAllocator<T>(bm))\n\t{\n\t}\n\n\texplicit CSTLBlockList(TSizeType n, const T& v, CBlockMemory<T, false> *bm ) :\n\tstd::list<T, CSTLBlockAllocator<T> >(n,v,CSTLBlockAllocator<T>(bm))\n\t{\n\t}\n\n\n\tCSTLBlockList(TBlockListConstIt first,TBlockListConstIt last, CBlockMemory<T, false> *bm ):\n\tstd::list<T, CSTLBlockAllocator<T> >(first,last,CSTLBlockAllocator<T>(bm))\n\t{\n\t}\n\n};\n\n\n\n} // NLMISC\n\n\n#endif // NL_STL_BLOCK_LIST_H\n\n/* End of stl_block_list.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/stop_watch.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STOP_WATCH_H\n#define NL_STOP_WATCH_H\n\n#include \"types_nl.h\"\n#include \"time_nl.h\"\n\n#include <deque>\n\n\nnamespace NLMISC {\n\n\ntypedef uint32 TTickDuration;\ntypedef uint32 TMsDuration;\n\n\n/**\n * Stopwatch class used for performance measurements and statistics.\n * To measure the duration of a cycle, call stop(), get the results, then call start().\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CStopWatch\n{\npublic:\n\n\t/// Constructor. Set a non-zero queueLength for partial average calculation\n\tCStopWatch( uint queueLength=0 );\n\n\n\n\t/// Begin measurement\n\tvoid\t\t\t\t\t\tstart();\n\n\t/// Pause\n\tvoid\t\t\t\t\t\tpause();\n\n\t/// Resume\n\tvoid\t\t\t\t\t\tresume();\n\n\t/// Add time (in ticks unit) to the current measurement\n\tvoid\t\t\t\t\t\taddTime( TTickDuration t );\n\n\t/// End measurement\n\tvoid\t\t\t\t\t\tstop();\n\n\t/// Add an external duration (in ticks unit) to the average queue\n\tvoid\t\t\t\t\t\taddMeasurement( TTickDuration t );\n\n\n\n\t/// Elapsed time in millisecond (call it after stop())\n\tTMsDuration\t\t\t\t\tgetDuration() const;\n\n\t/// Average duration of the queueLength last durations (using the queueLength argument specified in the constructor)\n\tTMsDuration\t\t\t\t\tgetPartialAverage() const;\n\n\t/// Average of the duration\n\tTMsDuration\t\t\t\t\tgetAverageDuration() const;\n\n\n\n\t/// Sum of the measured durations (in ticks)\n\tTTickDuration\t\t\t\tsumTicks() const { return _SumTicks; }\n\n\t/// Number of measurements\n\tuint32\t\t\t\t\t\tmeasurementNumber() const { return _MeasurementNumber; }\n\nprivate:\n\n\tTTicks\t\t\t\t\t\t_BeginTime;\n\tTTickDuration\t\t\t\t_ElapsedTicks;\n\n\tTTickDuration\t\t\t\t_SumTicks;\n\tuint32\t\t\t\t\t\t_MeasurementNumber;\n\n\tstd::deque<TTickDuration>\t_Queue;\n\tuint\t\t\t\t\t\t_QLength;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_STOP_WATCH_H\n\n/* End of stop_watch.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/stream.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STREAM_H\n#define NL_STREAM_H\n\n#include\t\"types_nl.h\"\n#include\t\"ucstring.h\"\n#include\t\"class_registry.h\"\n#include\t\"common.h\"\n\n#include\t<utility>\n#include\t<string>\n#include\t<vector>\n#include\t<deque>\n#include\t<list>\n#include\t<set>\n#include\t<map>\n\nnamespace\tNLMISC\n{\n\n\nclass\tIStream;\nclass\tCMemStream;\n\n\n// ======================================================================================================\n// ======================================================================================================\n// Stream System.\n// ======================================================================================================\n// ======================================================================================================\n\n// For Big/little Endian.\n#  define NLMISC_BSWAP16(src)\t(src) = (((src)>>8)&0xFF) | (((src)&0xFF)<<8)\n#  if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)\n#    define NLMISC_BSWAP32(src) _asm mov eax,(src) _asm bswap eax _asm mov (src),eax\n#  else\n#    define NLMISC_BSWAP32(src) (src) = (((src)>>24)&0xFF) | ((((src)>>16)&0xFF)<<8) | ((((src)>>8)&0xFF)<<16) | (((src)&0xFF)<<24)\n#  endif\n#  define NLMISC_BSWAP64(src) (src) = (((src)>>56)&0xFF) | ((((src)>>48)&0xFF)<<8) | ((((src)>>40)&0xFF)<<16) | ((((src)>>32)&0xFF)<<24) | ((((src)>>24)&0xFF)<<32) | ((((src)>>16)&0xFF)<<40) | ((((src)>>8)&0xFF)<<48) | (((src)&0xFF)<<56)\n\n// convert a 4 characters string to uint32\n#ifdef NL_LITTLE_ENDIAN\n#\tdefine NELID(x) (uint32((x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3])))\n#else\n#\tdefine NELID(x) (uint32((x[3] << 24) | (x[2] << 16) | (x[1] << 8) | (x[0])))\n#endif\n\n// ======================================================================================================\n/**\n * Stream Exception.\n * \\author Lionel Berenguier\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nstruct EStream : public Exception\n{\n\tEStream() : Exception( \"Stream Error\" ) {}\n\n\tEStream( const std::string& str ) : Exception( str ) {}\n\n\tEStream( const IStream &f );\n\n\tEStream( const IStream &f, const std::string& str );\n\n\tvirtual ~EStream() throw() {}\n\n\t// May Not be Filled...\n\tstd::string\tStreamName;\n};\n\nstruct EOlderStream : public EStream\n{\n\tEOlderStream() : EStream(\"The version in stream is older than the class\" ) {}\n\tEOlderStream(const IStream &f) : EStream(f, \"The version in stream is older than the class\" ) {}\n};\n\nstruct ENewerStream : public EStream\n{\n\tENewerStream() : EStream(\"The version in stream is newer than the class\" ) {}\n\tENewerStream(const IStream &f) : EStream(f, \"The version in stream is newer than the class\" ) {}\n};\n\nstruct EInvalidDataStream : public EStream\n{\n\tEInvalidDataStream() : EStream(\"Invalid data format\" ) {}\n\tEInvalidDataStream(const IStream &f) : EStream(f, \"Invalid data format\" ) {}\n\n\t// msg must contain \"%u\" for the position of 'size'\n\tEInvalidDataStream(const char *msg, uint size);\n};\n\nstruct ESeekNotSupported : public EStream\n{\n\tESeekNotSupported() : EStream(\"Seek fonctionnality is not supported\" ) {}\n\tESeekNotSupported(const IStream &f) : EStream(f, \"Seek fonctionnality is not supported\" ) {}\n};\n\nstruct ENotOutputStream : public EStream\n{\n\tENotOutputStream() : EStream(\"The stream is NOT an output stream, can't write in\" ) {}\n\tENotOutputStream(const IStream &f) : EStream(f, \"The stream is NOT an output stream, can't write in\" ) {}\n};\nstruct ENotInputStream : public EStream\n{\n\tENotInputStream () : EStream(\"The stream is NOT an input stream, cannot read in\" ) {}\n\tENotInputStream (const IStream &f) : EStream(f, \"The stream is NOT an input stream, cannot read in\" ) {}\n};\n\n/// This exception is raised when someone tries to serialize in more than there is.\nstruct EStreamOverflow : public EStream\n{\n\tEStreamOverflow() : EStream( \"Stream Overflow Error\" ) {}\n\n\t// msg must contain \"%u\" for the position of 'size'\n\tEStreamOverflow(const char *msg, uint size);\n};\n\n\nclass\tIStreamable;\n\n\n// ======================================================================================================\n/**\n * A IO stream interface.\n * This is the base interface for stream objects. Differents kind of streams may be implemented,\n * by specifying serialBuffer() methods.\n *\n * \\b Deriver \\b Use:\n *\n * The deriver must:\n * - construct object specifying his type, see IStream(). A stream may be setup Input or Output at construction, but cannot\n * change during his life.\n * - specify serialBuffer(), to save or load pack of bytes.\n * - specify serialBit(), to save or load a bit.\n * - call resetPtrTable() when the stream reset itself (e.g.: CIFile::close() )\n *\n * Sample of streams: COutMemoryStream, CInFileStream ...\n *\n * \\b Client \\b Use:\n *\n * An object which can be serialized, must provide a \"void serial(IStream &)\" method. In this method, he can use\n * any of the IStream method to help himself like:\n * - serial() with a base type (uint32, string, char...), or even with an object which provide \"void serial(IStream &)\"\n * - template serial(T0&, T1&, ...) to serialize multiple object/variables in one call (up to 6).\n * - serialCont() to serialize containers.\n * - serialVersion() to check/store a version number of his class.\n * - serialPtr() to use the ptr support of IStream (see serialPtr() for more information)\n * - isReading() to know if he write in the stream, or if he read.\n *\n * The using is very simple as shown in this example:\n *\n * \\code\n class A\n {\n public:\n\tfloat\tx;\n\tuint32\ty;\n\tClass1\ta;\t\t// this class must provide a serial() method too...\n\tBase\t*c,*d;\t// Base must derive from IStreamable\n\tvector<Class2>\ttab;\n\n public:\n\tvoid\tserial(IStream &f)\n\t{\n\t\tsint\tstreamver= f.serialVersion(3);\n\t\tf.serial(x,y,a);\n\t\tf.serialPtr(c);\n\t\tf.serialCont(tab);\n\t\tif(streamver>=2)\n\t\t\tf.serialPtr(d);\n\t}\n };\n \\endcode\n *\n * NB: \\b YOU \\b CANNOT use serial with a int / uint / sint type, since those type have unspecified length.\n * \\author Lionel Berenguier\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass IStream\n{\npublic:\n\t/**\n\t * Set the behavior of IStream regarding input stream that are older/newer than the class.\n\t * If throwOnOlder==true, IStream throws a EOlderStream when needed.\n\t * If throwOnNewer==true, IStream throws a ENewerStream when needed.\n\t *\n\t * By default, the behavior is throwOnOlder=false, throwOnNewer=true.\n\t * \\see serialVersion() getVersionException()\n\t */\n\tstatic\tvoid\tsetVersionException(bool throwOnOlder, bool throwOnNewer);\n\t/**\n\t * Get the behavior of IStream regarding input stream that are older/newer than the class.\n\t * \\see serialVersion() setVersionException()\n\t */\n\tstatic\tvoid\tgetVersionException(bool &throwOnOlder, bool &throwOnNewer);\n\n\npublic:\n\n\t/**\n\t * Constructor.\n\t * Notice that those behavior can be set at construction only.\n\t * \\param inputStream is the stream an Input (read) stream?\n\t */\n\texplicit IStream(bool inputStream);\n\n\t/// Destructor.\n\tvirtual ~IStream() {}\n\n\t/// Copy constructor\n\tIStream( const IStream& other );\n\n\t/// Assignment operator\n\tIStream&\t\toperator=( const IStream& other );\n\n\t/// exchange\n\tvoid\t\t\tswap(IStream &other);\n\n\t/// Is this stream a Read/Input stream?\n\tbool\t\t\tisReading() const;\n\n\t// is it a xml stream ?\n\tbool\t\t\tisXML() const { return _XML; }\n\n\t/**\n\t * Template Object serialisation.\n\t * \\param obj any object providing a \"void serial(IStream&)\" method. The object doesn't have to derive from IStreamable.\n\t *\n\t * the VC++ error \"error C2228: left of '.serial' must have class/struct/union type\" means you don't provide\n\t * a serial() method to your object. Or you may have use serial with a int / uint / sint type. REMEMBER YOU CANNOT\n\t * do this, since those type have unspecified length.\n\t */\n    template<class T>\n\tvoid\t\t\tserial(T &obj)  { obj.serial(*this); }\n\n\t// an utility template to unconst a type\n\ttemplate <class T> static T& unconst(const T &t) { return const_cast<T&>(t);}\n\n#define nlWriteSerial(_stream, _obj) \t\t\\\n\tif ((_stream).isReading())\t\t\t\\\n\t\tthrow NLMISC::ENotOutputStream();\t\\\n\t(_stream).serial(NLMISC::IStream::unconst(_obj));\n\n#define nlWrite(_stream, _serialType, _obj)\t\\\n\tif ((_stream).isReading())\t\t\t\\\n\t\tthrow NLMISC::ENotOutputStream();\t\\\n\t(_stream)._serialType(NLMISC::IStream::unconst(_obj));\n\n#define nlReadSerial(_stream, _obj) \t\t\\\n\tif (!(_stream).isReading())\t\t\t\\\n\t\tthrow NLMISC::ENotInputStream();\t\\\n\tNLMISC::IStream::unconst(_stream).serial(_obj);\n\n#define nlRead(_stream, _serialType, _obj)\t\\\n\tif (!(_stream).isReading())\t\t\t\\\n\t\tthrow NLMISC::ENotInputStream();\t\\\n\tNLMISC::IStream::unconst(_stream)._serialType(_obj);\n\n// helper macro to serialize boolean encoded as 'bool foo : 1' (they can't be referenced)\n#define nlSerialBitBool(_stream, _boolean) \\\n\t{ \\\n\t\tbool tmpBool = _boolean; \\\n\t\t_stream.serial(tmpBool); \\\n\t\t_boolean = tmpBool; \\\n\t}\n\n\t/** \\name Base type serialization.\n\t * Those method are a specialization of template method \"void serial(T&)\".\n\t */\n\t//@{\n\n\tvirtual void\tserial(uint8 &b) ;\n\tvirtual void\tserial(sint8 &b) ;\n\tvirtual void\tserial(uint16 &b) ;\n\tvirtual void\tserial(sint16 &b) ;\n\tvirtual void\tserial(uint32 &b) ;\n\tvirtual void\tserial(sint32 &b) ;\n\tvirtual void\tserial(uint64 &b) ;\n\tvirtual void\tserial(sint64 &b) ;\n\tvirtual void\tserial(float &b) ;\n\tvirtual void\tserial(double &b) ;\n\tvirtual void\tserial(bool &b) ;\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b) ;\n#endif\n\tvirtual void\tserial(std::string &b) ;\n\tvirtual void\tserial(ucstring &b) ;\n\t//@}\n\n\n\t/// Template enum serialisation. Serialized as a sint32.\n    template<class T>\n\tvoid\t\t\tserialEnum(T &em)\n\t{\n\t\tsint32\ti;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(i);\n\t\t\tem = (T)i;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ti = em;\n\t\t\tserial(i);\n\t\t}\n\t}\n\t/// Template short enum serialisation. Serialized as a uint8 (with checking).\n    template<class T>\n\tvoid\t\t\tserialShortEnum(T &em)\n\t{\n\t\tuint8\ti;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(i);\n\t\t\tem = (T)i;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlassert(em < 0xff);\n\t\t\ti = uint8(em);\n\t\t\tserial(i);\n\t\t}\n\t}\n\n\t/// Serial memstream, bitmemstream...\n\tvirtual void serialMemStream( CMemStream &b );\n\n\t/** \\name BitField serialisation.\n\t * Unlike other serial method, The reading bitfield is returned!! If !this->isReading(), bf is returned.\n\t *\n\t * MUST use it simply like this:   a= serialBitFieldX(a);\t\t// where X== 8, 16 or 32.\n\t *\n\t * NB: Performance warning: the data is stored as an uint8, uint16 or uint32, according to the method you use.\n\t */\n\t//@{\n\t/// Serialisation of bitfield <=8 bits.\n\tuint8\t\t\tserialBitField8(uint8  bf);\n\t/// Serialisation of bitfield <=16 bits.\n\tuint16\t\t\tserialBitField16(uint16  bf);\n\t/// Serialisation of bitfield <=32 bits.\n\tuint32\t\t\tserialBitField32(uint32  bf);\n\t//@}\n\n\n\t/** \\name Multiple serialisation.\n\t * Template for easy multiple serialisation.\n\t */\n\t//@{\n\ttemplate<class T0,class T1>\n\tvoid\t\t\tserial(T0 &a, T1 &b)\n\t{ serial(a); serial(b);}\n\ttemplate<class T0,class T1,class T2>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c)\n\t{ serial(a); serial(b); serial(c);}\n\ttemplate<class T0,class T1,class T2,class T3>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d)\n\t{ serial(a); serial(b); serial(c); serial(d);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4,class T5>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}\n\t//@}\n\n\n\t/** \\name standard STL containers serialisation.\n\t * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>, map<>, multimap<>\n\t * Support up to sint32 length containers.\n\t * \\see serialContPtr() serialContPolyPtr()\n\t */\n\ttemplate<class T, class Allocator>\n\tvoid\t\t\tserialCont(std::vector<T, Allocator> &cont)\t{serialVector(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::list<T> &cont) \t{serialSTLCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::deque<T> &cont) \t{serialSTLCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::set<T> &cont) \t\t{serialSTLCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::multiset<T> &cont) \t{serialSTLCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::map<K, T> &cont) \t\t\t{serialMap(cont);}\n\ttemplate<class K, class T, class H>\n\tvoid\t\t\tserialCont(CHashMap<K, T, H> &cont) \t\t\t{serialMap(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::multimap<K, T> &cont) \t{serialMultimap(cont);}\n\n\t/** \\name standard STL containers serialisation.\n\t * Thse variants suppose contained type is a NeL smart pointer.\n\t * Known Supported containers: map<>\n\t * Support up to sint32 length containers.\n\t * \\see serialCont() serialContPtr() serialContPolyPtr()\n\t */\n\ttemplate<class K, class T>\n\tvoid\tserialPtrCont(std::map<K, T> &cont)\t{serialPtrMap(cont);}\n\n\n\t/// Specialisation of serialCont() for vector<uint8>\n\tvirtual void\t\t\tserialCont(std::vector<uint8> &cont) ;\n\t/// Specialisation of serialCont() for vector<sint8>\n\tvirtual void\t\t\tserialCont(std::vector<sint8> &cont) ;\n\t/// Specialisation of serialCont() for vector<bool>\n\tvirtual void\t\t\tserialCont(std::vector<bool> &cont) ;\n\n\n\t/** \\name standard STL containers serialisation. Elements must be pointers on a base type (uint...) or on a\n\t * object providing \"void serial(IStream&)\" method.\n\t * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>\n\t * Support up to sint32 length containers.\n\t * \\see serialCont() serialContPolyPtr()\n\t */\n\ttemplate<class T, class Allocator>\n\tvoid\t\t\tserialContPtr(std::vector<T, Allocator> &cont) \t{serialVectorPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPtr(std::list<T> &cont) \t{serialSTLContPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPtr(std::deque<T> &cont) \t{serialSTLContPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPtr(std::set<T> &cont) \t\t\t{serialSTLContPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPtr(std::multiset<T> &cont) \t{serialSTLContPtr(cont);}\n\n\n\t/** \\name standard STL containers serialisation. Elements must be pointers on a IStreamable object.\n\t * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>\n\t * Support up to sint32 length containers.\n\t * \\see serialCont() serialContPtr()\n\t */\n\ttemplate<class T, class Allocator>\n\tvoid\t\t\tserialContPolyPtr(std::vector<T, Allocator> &cont) \t{serialVectorPolyPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPolyPtr(std::list<T> &cont) \t{serialSTLContPolyPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPolyPtr(std::deque<T> &cont) \t{serialSTLContPolyPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPolyPtr(std::set<T> &cont) \t\t\t{serialSTLContPolyPtr(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialContPolyPtr(std::multiset<T> &cont) \t{serialSTLContPolyPtr(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialContPolyPtr(std::map<K, T> &cont) \t{serialMapPolyPtr(cont);}\n\n\n\t/**\n\t * Serialize Non Polymorphic Objet Ptr.\n\t * Works with NULL pointers. If the same object is found mutliple time in the stream, ONLY ONE instance is written!\n\t * NB: The ptr is serialised as a uint64 (64 bit compliant).\n\t * \\param ptr a pointer on a base type or an object.\n\t * \\see resetPtrTable()\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialPtr(T* &ptr)\n\t{\n\t\tuint64\tnode;\n\n\t\t// Open the node header\n\t\txmlPushBegin (\"PTR\");\n\n\t\txmlSetAttrib (\"id\");\n\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(node);\n\n\t\t\t// Close the header\n\t\t\txmlPushEnd ();\n\n\t\t\tif(node==0)\n\t\t\t\tptr=NULL;\n\t\t\telse\n\t\t\t{\n\t\t\t\tItIdMap\tit;\n\t\t\t\tit= _IdMap.find(node);\n\n\t\t\t\t// Test if object already created/read.\n\t\t\t\tif( it==_IdMap.end() )\n\t\t\t\t{\n\t\t\t\t\t// Construct object.\n\t\t\t\t\tptr= new T;\n\t\t\t\t\tif(ptr==NULL)\n\t\t\t\t\t\tthrow EStream();\n\n\t\t\t\t\t// Insert the node.\n\t\t\t\t\t_IdMap.insert( ValueIdMap(node, ptr) );\n\n\t\t\t\t\t// Read the object!\n\t\t\t\t\tserial(*ptr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tptr= static_cast<T*>(it->second);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(ptr==NULL)\n\t\t\t{\n\t\t\t\tnode= 0;\n\t\t\t\tserial(node);\n\n\t\t\t\t// Close the header\n\t\t\t\txmlPushEnd ();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tItIdMap\tit;\n\t\t\t\tit = _IdMap.find((uint64)ptr);\n\n\t\t\t\t// Test if object has been already written\n\t\t\t\tif( it==_IdMap.end() )\n\t\t\t\t{\n\t\t\t\t\t// Not yet written\n\n\t\t\t\t\t// Get the next available ID\n\t\t\t\t\tnode = _NextSerialPtrId++;\n\n\t\t\t\t\t// Serial the id\n\t\t\t\t\tserial(node);\n\n\t\t\t\t\t// Insert the pointer in the map with the id\n\t\t\t\t\t_IdMap.insert( ValueIdMap((uint64)ptr, (void*)node) );\n\n\t\t\t\t\t// Close the header\n\t\t\t\t\txmlPushEnd ();\n\n\t\t\t\t\t// Write the object\n\t\t\t\t\tserial(*ptr);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Write only the object id\n\t\t\t\t\tnode = (uint64)(it->second);\n\n\t\t\t\t\tserial(node);\n\n\t\t\t\t\t// Close the header\n\t\t\t\t\txmlPushEnd ();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\n\t/**\n\t * Serialize Polymorphic Objet Ptr.\n\t * Works with NULL pointers. If the same object is found mutliple time in the stream, ONLY ONE instance is written!\n\t * NB: The ptr is serialised as a uint64 (64 bit compliant).\n\t * \\param ptr a pointer on a IStreamable object.\n\t * \\see resetPtrTable()\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialPolyPtr(T* &ptr)\n\t{ IStreamable *p=ptr; serialIStreamable(p); ptr= static_cast<T*>(p);}\n\n\n\t/**\n\t * Serialize a version number.\n\t * Each object should store/read first a version number, using this method.\n\t * Then he can use the streamVersion returned to see how he should serialise himself.\n\t *\n\t * NB: Version Number is read/store as a uint8, or uint32 if too bigger..\n\t * \\param currentVersion the current version of the class, provided by user.\n\t * \\return the version of the stream. If the stream is an Output stream, currentVersion is returned.\n\t * \\see setVersionException() getVersionException()\n\t */\n\tuint\t\t\tserialVersion(uint currentVersion) ;\n\n\n\t/**\n\t * Serialize a check value.\n\t * An object can stream a check value to check integrity or format of filed or streamed data.\n\t * Just call serial check with a const value. Write will serial the value. Read will\n\t * check the value is the same. If it is not, it will throw EInvalidDataStream exception.\n\t *\n\t * NB: The type of the value must implement an operator == and must be serializable.\n\t * \\param value the value used to the check.\n\t * \\see EInvalidDataStream\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialCheck(const T& value)\n\t{\n\t\t// Open a node\n\t\txmlPush (\"CHECK\");\n\n\t\tif (isReading())\n\t\t{\n\t\t\tT read;\n\t\t\tserial (read);\n\t\t\tif (read!=value)\n\t\t\t\tthrow EInvalidDataStream(*this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tserial (const_cast<T&>(value));\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\t/// \\name Seek fonctionnality\n\n\t/**\n\t * Parameters for seek().\n\t * begin seek from the beginning of the stream.\n\t * current seek from the current location of the stream pointer.\n\t * end seek from the end of the stream.\n\t */\n\tenum TSeekOrigin { begin, current, end };\n\n\t/**\n\t * Moves the stream pointer to a specified location.\n\t *\n\t * NB: If the stream doesn't support the seek fonctionnality, it throw ESeekNotSupported.\n\t * Default implementation:\n\t * { throw ESeekNotSupported; }\n\t * \\param offset is the wanted offset from the origin.\n\t * \\param origin is the origin of the seek\n\t * \\return true if seek sucessfull.\n\t * \\see ESeekNotSupported SeekOrigin getPos\n\t */\n\tvirtual bool\t\tseek (sint32 offset, TSeekOrigin origin) const;\n\n\n\t/**\n\t * Get the location of the stream pointer.\n\t *\n\t * NB: If the stream doesn't support the seek fonctionnality, it throw ESeekNotSupported.\n\t * Default implementation:\n\t * { throw ESeekNotSupported; }\n\t * \\param offset is the wanted offset from the origin.\n\t * \\param origin is the origin of the seek\n\t * \\return the new offset regarding from the origin.\n\t * \\see ESeekNotSupported SeekOrigin seek\n\t */\n\tvirtual sint32\t\tgetPos () const;\n\n\n\t/** Get a name for this stream. maybe a fileName if FileStream.\n\t *\tDefault is to return \"\".\n\t */\n\tvirtual std::string\t\tgetStreamName() const;\n\n\t/** \\name XML user interface\n\t  *\n\t  * Those functions are used to add information in your stream to structure it like\n\t  * a XML document. Exemple of a serial sequence :\n\t  \\code\n\t\t// Start the opening of a new node named Identity\n\t\tstream.xmlPush (\"Identity\")\n\n\t\t\t// Serial some infos\n\t\t\tstream.serial (name);\n\t\t\tstream.serial (pseudo);\n\n\t\t\t// Open a new node header named Address\n\t\t\tstream.xmlPushBegin (\"Address\");\n\n\t\t\t\t\t// Set a property name\n\t\t\t\t\tstream.xmlSetAttrib (\"Street\")\n\n\t\t\t\t\t// Serial the property\n\t\t\t\t\tstream.serial (\"Street\");\n\n\t\t\t\t// Close the new node header\n\t\t\t\tstream.xmlPushEnd ();\n\n\t\t\t\t// Serial in this node\n\t\t\t\tstream.serial (cityName);\n\n\t\t\t// Close the address node\n\t\t\tstream.xmlPop ();\n\n\t\t\t// Add a comment\n\t\t\tstream.xmlComment (\"Hello\");\n\n\t\t// Close the identity node\n\t\tstream.xmlPop ();\n      \\endcode\n\t  *\n\t  * The result will be an xml document structured like this:\n\t  *\n\t  \\code\n\t\t<Identity>\n\t\t\tCorvazier Hulud\n\t\t\t<Address Street=\"rue du Faubourg Saint Antoine\">\n\t\t\t\tParis\n\t\t\t<\\Address>\n\t\t\t<!-- Hello -->\n\t\t<\\Identity>\n\t  \\endcode\n\t  *\n\t  * Node header serials are the serialisations done between xmlPushBegin() and xmlPushEnd() call. There is some restrictions on them:\n\t  * Node header serials are only available for basic types (numbers and strings).\n\t  * xmlSetAttrib() must be called before node header serial.\n\t  *\n\t  * Note that XML documents only have ONE root node, so all serialisation must be done between a xmlPush() and a xmlPop() call.\n\t  *\n\t  * When a xml input stream will try to open a node, it will scan all currrent child nodes to find the good one.\n\t  * So input xml stream can skip unknown node.\n\t  */\n\n\t/**\n\t  * xmlSerial() serial a values into a node.\n\t  */\n\ttemplate<class T>\n\tvoid xmlSerial (T& value0, const char *nodeName)\n\t{\n\t\t// Open the node\n\t\txmlPush (nodeName);\n\n\t\t// Serial the value\n\t\tserial (value0);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\ttemplate<class T>\n\tvoid xmlSerial (T& value0, T& value1, const char *nodeName)\n\t{\n\t\t// Open the node\n\t\txmlPush (nodeName);\n\n\t\t// Serial the values\n\t\tserial (value0, value1);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\ttemplate<class T>\n\tvoid xmlSerial (T& value0, T& value1, T& value2, const char *nodeName)\n\t{\n\t\t// Open the node\n\t\txmlPush (nodeName);\n\n\t\t// Serial the values\n\t\tserial (value0, value1, value2);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\ttemplate<class T>\n\tvoid xmlSerial (T& value0, T& value1, T& value2, T& value3, const char *nodeName)\n\t{\n\t\t// Open the node\n\t\txmlPush (nodeName);\n\n\t\t// Serial the values\n\t\tserial (value0, value1, value2, value3);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\t/**\n\t  * xmlPush() open recurcively a new node. You must call xmlPop to close this node.\n\t  *\n\t  * \\name is the name of the node to open\n\t  * \\return true if you can open the node, false if the stream is between a xmlPushBegin() and a xmlPushEnd() call.\n\t  */\n\tbool xmlPush (const char *name)\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\t// Open the header\n\t\t\tbool res=xmlPushBeginInternal (name);\n\t\t\tif (res)\n\t\t\t\t// close the header\n\t\t\t\txmlPushEndInternal ();\n\t\t\t// Return the result\n\t\t\treturn res;\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlPushBegin() open recurcively a new node and open its header. You must call xmlPushEnd() to close the header and xmlPop() to close this node.\n\t  *\n\t  * \\name is the name of the node to open\n\t  * \\return true if you can open the node header, false if the stream is between a xmlPushBegin() and a xmlPushEnd() call.\n\t  */\n\tbool xmlPushBegin (const char *name)\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlPushBeginInternal (name);\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlPushEnd() close the node header.\n\t  *\n\t  * \\return true if you can close the node header, false if no node header have been opened with xmlPushBegin().\n\t  */\n\tbool xmlPushEnd ()\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlPushEndInternal ();\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlPop() close the node.\n\t  *\n\t  * \\return true if you can close the node, false if the node can't be closed (its header is still opened) or if there is no node to close.\n\t  */\n\tbool xmlPop ()\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlPopInternal ();\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlSetAttrib() set the name of the next node header attribute serialised.\n\t  *\n\t  * \\param name is the name of the node header attribute serialised.\n\t  * \\return true if the attribute name have been set, false if the node header is not open (the call is not between xmlPushBegin and xmlPushEnd)\n\t  */\n\tbool xmlSetAttrib (const char *name)\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlSetAttribInternal (name);\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlBreakLine() insert a break line in the XML stream.\n\t  *\n\t  * \\return true if the break line is added, return false if no node is opened.\n\t  */\n\tbool xmlBreakLine ()\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlBreakLineInternal ();\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\n\t/**\n\t  * xmlComment() insert a comment line in the XML stream.\n\t  *\n\t  * \\return true if the comment is added, return false if no node is opened.\n\t  */\n\tbool xmlComment (const char *comment)\n\t{\n\t\t// XML Mode ?\n\t\tif (_XML)\n\t\t{\n\t\t\treturn xmlCommentInternal (comment);\n\t\t}\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\nprotected:\n\n\t/// \\name XML implementation interface\n\n\t/** Set the XML mode\n\t  * \\param on is true to enable XML mode else false\n\t  */\n\tvoid setXMLMode (bool on);\n\n\t/// xmlPushBegin implementation\n\tvirtual bool\t\txmlPushBeginInternal (const char * /* name */) { return true; };\n\n\t/// xmlPushEnd implementation\n\tvirtual bool\t\txmlPushEndInternal () { return true; };\n\n\t/// xmlPop implementation\n\tvirtual bool\t\txmlPopInternal () { return true; };\n\n\t/// xmlBreakLine implementation\n\tvirtual bool\t\txmlSetAttribInternal (const char * /* name */) { return true; };\n\n\t/// xmlBreakLine implementation\n\tvirtual bool\t\txmlBreakLineInternal () { return true; };\n\n\t/// xmlComment implementation\n\tvirtual\tbool\t\txmlCommentInternal (const char * /* comment */) { return true; };\n\n\t/**\n\t * for Deriver: reset the PtrTable in the stream.\n\t * If Derived stream provide reset()-like methods, they must call this method in their reset() methods.\n\t * For example, CFile::close() must call it, so it will work correctly with next serialPtr()\n\t */\n\tvoid\t\t\t\tresetPtrTable();\n\n\t/**\n\t * Change, in live, the state of the inputStream. This could be useful in certain case.\n\t * The deriver which would want to do such a thing must call this method, and implement his own behavior.\n\t * In certain case, it should call resetPtrTable() if he want to reset the stream ptr info (maybe always)...\n\t */\n\tvoid\t\t\t\tsetInOut(bool inputStream);\n\n\t/** Get the size for this stream. return 0 by default. Only implemented for input stream that know their size.\n\t *\tUsed internally to detect OverFlow with vector<> for instance\n\t */\n\tvirtual uint\t\t\tgetDbgStreamSize() const {return 0;}\n\n\t/**\n\t * Elementarily check at least n bytes can be serialized from this stream (or throw EStreamOverflow)\n\t */\n\tvoid\t\t\t\tcheckStreamSize(uint numBytes) const\n\t{\n\t\tuint\t\t\tssize = getDbgStreamSize();\n\t\tif (ssize > 0 && ssize < numBytes)\n\t\t\tthrow EStreamOverflow(\"stream does not contain at least %u bytes for check\", numBytes);\n\t}\n\npublic:\n\t//@{\n\t/** Method to be specified by the Deriver.\n\t * \\warning Do not call these methods from outside, unless you really know what you are doing.\n\t * Using them instead of serial() can lead to communication problems between different platforms !\n\t */\n\tvirtual void\t\tserialBuffer(uint8 *buf, uint len) =0;\n\tvirtual void\t\tserialBit(bool &bit) =0;\n\t//@}\n\n\t/// This method first serializes the size of the buffer and after the buffer itself, it enables\n\t/// the possibility to serial with a serialCont() on the other side.\n\tvirtual void\t\tserialBufferWithSize(uint8 *buf, uint32 len)\n\t{\n\t\tserial (len);\n\t\tserialBuffer (buf, len);\n\t}\n\nprivate:\n\tbool\t_InputStream;\n\tstatic\tbool\t_ThrowOnOlder;\n\tstatic\tbool\t_ThrowOnNewer;\n\n\t// Ptr registry. We store 64 bit Id, to be compatible with future 64+ bits pointers.\n\tuint32\t\t\t\t\t\t\t\t_NextSerialPtrId;\n\tCHashMap<uint64, void*>\t\t_IdMap;\n\ttypedef CHashMap<uint64, void*>::iterator\tItIdMap;\n\ttypedef CHashMap<uint64, void*>::value_type\tValueIdMap;\n\n\t// Ptr serialization.\n\tvoid\t\t\tserialIStreamable(IStreamable* &ptr) ;\n\n\n\nprivate:\n\t/**\n\t * standard STL containers serialization. Don't work with map<> and multimap<>.\n\t * Support up to sint32 length containers. serialize just len  element of the container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLContLen(T &cont, sint32 len)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\tif(isReading())\n\t\t{\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\t__value_type v;\n\t\t\t\tserial(v);\n\t\t\t\t(void)cont.insert(cont.end(), v);\n\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t__iterator\t\tit= cont.begin();\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\tserial(const_cast<__value_type&>(*it));\n\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * standard STL containers serialisation. Don't work with map<> and multimap<>.\n\t * Support up to sint32 length containers.\n\t *\n\t * the object T must provide:\n\t *\t\\li typedef iterator;\t\t(providing operator++() and operator*())\n\t *\t\\li typedef value_type;\t\t(a base type (uint...), or an object providing \"void serial(IStream&)\" method.)\n\t *\t\\li void clear();\n\t *\t\\li size_type size() const;\n\t *\t\\li iterator begin();\n\t *\t\\li iterator end();\n\t *\t\\li iterator insert(iterator it, const value_type& x);\n\t *\n\t * Known Supported containers: vector<>, list<>, deque<>, set<>, multiset<>.\n\t * \\param cont a STL container (vector<>, set<> ...).\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLCont(T &cont)\n\t{\n\t\t// Open a node header\n\t\txmlPushBegin (\"CONTAINER\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcont.clear();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\t// Close the header\n\t\txmlPushEnd ();\n\n\t\tserialSTLContLen(cont, len);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\nprotected:\n\n\t/**\n\t * special version for serializing a vector.\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialVector(T &cont)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"VECTOR\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\t// Open a node header\n\t\t\txmlPushEnd ();\n\n\t\t\t// special version for vector: adjut good size.\n\t\t\tcontReset(cont);\n\t\t\tcont.resize (len);\n\n\t\t\t// Read the vector\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\tserial(cont[i]);\n\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen = (sint32)cont.size();\n\t\t\tserial(len);\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\t// Write the vector\n\t\t\t__iterator\t\tit= cont.begin();\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\tserial(const_cast<__value_type&>(*it));\n\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\nprivate:\n\t/**\n\t * standard STL containers serialisation. Don't work with map<> and multimap<>.  Ptr version.\n\t * Support up to sint32 length containers. serialize just len  element of the container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLContLenPtr(T &cont, sint32 len)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\tif(isReading())\n\t\t{\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t__value_type\tv;\n\t\t\t\tserialPtr(v);\n\t\t\t\tcont.insert(cont.end(), v);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t__iterator\t\tit= cont.begin();\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\tserialPtr(const_cast<__value_type&>(*it));\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * standard STL containers serialisation. Don't work with map<> and multimap<>.  Ptr version.\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLContPtr(T &cont)\n\t{\n\t\t// Open a node header\n\t\txmlPushBegin (\"CONTAINER\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcont.clear();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\t// Close the node header\n\t\txmlPushEnd ();\n\n\t\tserialSTLContLenPtr(cont, len);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\n\t/**\n\t * special version for serializing a vector.  Ptr version.\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialVectorPtr(T &cont)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"VECTOR\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\t// special version for vector: adjut good size.\n\t\t\tcontReset(cont);\n\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\tcont.reserve(len);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\t// Close the node header\n\t\txmlPushEnd ();\n\n\t\tserialSTLContLenPtr(cont, len);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\nprivate:\n\t/**\n\t * standard STL containers serialisation. Don't work with map<> and multimap<>. PolyPtr version\n\t * Support up to sint32 length containers. serialize just len  element of the container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLContLenPolyPtr(T &cont, sint32 len)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\tif(isReading())\n\t\t{\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t__value_type\tv=NULL;\n\t\t\t\tserialPolyPtr(v);\n\t\t\t\tcont.insert(cont.end(), v);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t__iterator\t\tit= cont.begin();\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\tserialPolyPtr(const_cast<__value_type&>(*it));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Map serialisation. PolyPtr version\n\t * Support up to sint32 length containers. serialize just len  element of the container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialMapContLenPolyPtr(T &cont, sint32 len)\n\t{\n\t\ttypedef typename T::key_type __key_type;\n\t\ttypedef typename T::data_type __data_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\tif(isReading())\n\t\t{\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t__key_type k;\n\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial ( k );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\t__data_type\tv=NULL;\n\t\t\t\tv.serialPolyPtr(*this);\n\t\t\t\tcont[k] = v;\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t__iterator\t\tit= cont.begin();\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial( const_cast<__key_type&>((*it).first) );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\t__data_type\tv= const_cast<__data_type&>(it->second);\n\t\t\t\tv.serialPolyPtr(*this);\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * standard STL containers serialisation. Don't work with map<> and multimap<>. PolyPtr version\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialSTLContPolyPtr(T &cont)\n\t{\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcont.clear();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\tserialSTLContLenPolyPtr(cont, len);\n\t}\n\n\n\t/**\n\t * special version for serializing a vector. PolyPtr version\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialVectorPolyPtr(T &cont)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"VECTOR\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\t// special version for vector: adjut good size.\n\t\t\tcontReset(cont);\n\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\tcont.reserve(len);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\t// Close the node header\n\t\txmlPushEnd ();\n\n\t\tserialSTLContLenPolyPtr(cont, len);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\t/**\n\t * special version for serializing a map. PolyPtr version\n\t * Support up to sint32 length containers.\n\t */\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialMapPolyPtr(std::map<K, T> &cont)\n\t{\n\t\t// Open a node header\n\t\txmlPushBegin (\"MAP\");\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen=0;\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tcont.clear();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= cont.size();\n\t\t\tserial(len);\n\t\t}\n\n\t\tserialMapContLenPolyPtr(cont, len);\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\n\nprivate:\n\n\t/**\n\t * STL map<> and multimap<> serialisation.\n\t * Support up to sint32 length containers.\n\t *\n\t * the object T must provide:\n\t *\t\\li typedef iterator;\t\t(providing operator++() and operator*())\n\t *\t\\li typedef value_type;\t\t(must be a std::pair<>)\n\t *\t\\li typedef key_type;\t\t(must be the type of the key)\n\t *\t\\li void clear();\n\t *\t\\li size_type size() const;\n\t *\t\\li iterator begin();\n\t *\t\\li iterator end();\n\t *\t\\li iterator insert(iterator it, const value_type& x);\n\t *\n\t * Known Supported containers: map<>, multimap<>.\n\t * \\param cont a STL map<> or multimap<> container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialMultimap(T &cont)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::key_type __key_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"MULTIMAP\");\n\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen;\n\t\tif(isReading())\n\t\t{\n\t\t\tcont.clear();\n\t\t\tserial(len);\n\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t__value_type v;\n\n\t\t\t\txmlPush (\"KEY\");\n\n\t\t\t\tserial ( const_cast<__key_type&>(v.first) );\n\n\t\t\t\txmlPop ();\n\n\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\tserial (v.second);\n\n\t\t\t\txmlPop ();\n\n\t\t\t\tcont.insert(cont.end(), v);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t\t__iterator\t\tit= cont.begin();\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"KEY\");\n\n\t\t\t\tserial( const_cast<__key_type&>((*it).first) );\n\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\n\t\t\t\tserial((*it).second);\n\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\n\t/**\n\t * STL map<>\n\t * Support up to sint32 length containers.\n\t *\n\t * the object T must provide:\n\t *\t\\li typedef iterator;\t\t(providing operator++() and operator*())\n\t *\t\\li typedef value_type;\t\t(must be a std::pair<>)\n\t *\t\\li typedef key_type;\t\t(must be the type of the key)\n\t *\t\\li void clear();\n\t *\t\\li size_type size() const;\n\t *\t\\li iterator begin();\n\t *\t\\li iterator end();\n\t *\t\\li iterator insert(iterator it, const value_type& x);\n\t *\n\t * Known Supported containers: map<>\n\t * \\param cont a STL map<> container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialMap(T &cont)\n\t{\n\t\ttypedef typename T::value_type __value_type;\n\t\ttypedef typename T::key_type __key_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"MAP\");\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen;\n\t\tif(isReading())\n\t\t{\n\t\t\tcont.clear();\n\t\t\tserial(len);\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t// MALKAV 05/07/02 : prevent a copy of the value, copy the key instead\n\t\t\t\t__key_type k;\n\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial ( k );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\tserial (cont[k]);\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t\t__iterator\t\tit= cont.begin();\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial( const_cast<__key_type&>((*it).first) );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\tserial((*it).second);\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\t/**\n\t * STL map<>\n\t * Support up to sint32 length containers. Container must contain NeL smart pointers.\n\t *\n\t * the object T must provide:\n\t *\t\\li typedef iterator;\t\t(providing operator++() and operator*())\n\t *\t\\li typedef value_type;\t\t(must be a std::pair<>)\n\t *\t\\li typedef key_type;\t\t(must be the type of the key)\n\t *\t\\li void clear();\n\t *\t\\li size_type size() const;\n\t *\t\\li iterator begin();\n\t *\t\\li iterator end();\n\t *\t\\li iterator insert(iterator it, const value_type& x);\n\t *\n\t * Known Supported containers: map<>\n\t * \\param cont a STL map<> container.\n\t */\n\ttemplate<class T>\n\tvoid\t\t\tserialPtrMap(T &cont)\n\t{\n\t\ttypedef typename T::value_type::second_type __ptr_type;\n\t\ttypedef typename __ptr_type::element_type __value_type;\n\t\ttypedef typename T::key_type __key_type;\n\t\ttypedef typename T::iterator __iterator;\n\n\t\t// Open a node header\n\t\txmlPushBegin (\"MAP\");\n\t\t// Attrib size\n\t\txmlSetAttrib (\"size\");\n\n\t\tsint32\tlen;\n\t\tif(isReading())\n\t\t{\n\t\t\tcont.clear();\n\t\t\tserial(len);\n\t\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\t\tcheckStreamSize(len);\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\t// MALKAV 05/07/02 : prevent a copy of the value, copy the key instead\n\t\t\t\t__key_type k;\n\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial ( k );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\tcont[k] = __ptr_type(new __value_type());\n\t\t\t\tserial (*cont[k]);\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (sint32)cont.size();\n\t\t\tserial(len);\n\t\t\t__iterator\t\tit= cont.begin();\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\n\t\t\tfor(sint i=0;i<len;i++, it++)\n\t\t\t{\n\t\t\t\txmlPush (\"KEY\");\n\t\t\t\tserial( const_cast<__key_type&>((*it).first) );\n\t\t\t\txmlPop ();\n\n\t\t\t\txmlPush (\"ELM\");\n\t\t\t\tserial(*(*it).second);\n\t\t\t\txmlPop ();\n\t\t\t}\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n\n\t// Mode XML\n\tbool\t_XML;\n};\n\n\n// ======================================================================================================\n// ======================================================================================================\n// Handle for streaming Polymorphic classes.\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\n/**\n * An Object Streamable interface. Any polymorphic class which want to use serial() in a polymorphic way, must derive\n * from this interface.\n * \\author Lionel Berenguier\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass IStreamable : public IClassable\n{\npublic:\n\tvirtual void\t\tserial(IStream\t&f) =0;\n};\n\n\n} // NLMISC.\n\n\n// Inline Implementation.\n#include \"stream_inline.h\"\n\n\n#endif // NL_STREAM_H\n\n/* End of stream.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/stream_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STREAM_INLINE_H\n#define NL_STREAM_INLINE_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n\n#include <cstdio>\n\n\nnamespace\tNLMISC\n{\n\n\n// ======================================================================================================\n// ======================================================================================================\n// IBasicStream Inline Implementation.\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n// ======================================================================================================\ninline\tIStream::IStream(bool inputStream)\n{\n\t_InputStream= inputStream;\n\t_XML = false;\n\tresetPtrTable();\n}\n\n\n// ======================================================================================================\ninline\tbool\t\tIStream::isReading() const\n{\n\treturn _InputStream;\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(uint8 &b)\n{\n\tserialBuffer((uint8 *)&b, 1);\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(sint8 &b)\n{\n\tserialBuffer((uint8 *)&b, 1);\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(uint16 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 2);\n#else // NL_LITTLE_ENDIAN\n\tuint16\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 2);\n\t\tNLMISC_BSWAP16(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP16(v);\n\t\tserialBuffer((uint8 *)&v, 2);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(sint16 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 2);\n#else // NL_LITTLE_ENDIAN\n\tuint16\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 2);\n\t\tNLMISC_BSWAP16(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP16(v);\n\t\tserialBuffer((uint8 *)&v, 2);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(uint32 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 4);\n#else // NL_LITTLE_ENDIAN\n\tuint32\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 4);\n\t\tNLMISC_BSWAP32(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP32(v);\n\t\tserialBuffer((uint8 *)&v, 4);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(sint32 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 4);\n#else // NL_LITTLE_ENDIAN\n\tuint32\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 4);\n\t\tNLMISC_BSWAP32(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP32(v);\n\t\tserialBuffer((uint8 *)&v, 4);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(uint64 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 8);\n#else // NL_LITTLE_ENDIAN\n\tuint64\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 8);\n\t\tNLMISC_BSWAP64(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP64(v);\n\t\tserialBuffer((uint8 *)&v, 8);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(sint64 &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 8);\n#else // NL_LITTLE_ENDIAN\n\tuint64\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 8);\n\t\tNLMISC_BSWAP64(v);\n\t\tb=v;\n\t}\n\telse\n\t{\n\t\tv=b;\n\t\tNLMISC_BSWAP64(v);\n\t\tserialBuffer((uint8 *)&v, 8);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(float &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 4);\n#else // NL_LITTLE_ENDIAN\n\tuint32\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 4);\n\t\tNLMISC_BSWAP32(v);\n\t\tb=*((float*)&v);\n\t}\n\telse\n\t{\n\t\tv=*((uint32*)&b);\n\t\tNLMISC_BSWAP32(v);\n\t\tserialBuffer((uint8 *)&v, 4);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(double &b)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tserialBuffer((uint8 *)&b, 8);\n#else // NL_LITTLE_ENDIAN\n\tuint64\tv;\n\tif(isReading())\n\t{\n\t\tserialBuffer((uint8 *)&v, 8);\n\t\tNLMISC_BSWAP64(v);\n\t\tb=*((double*)&v);\n\t}\n\telse\n\t{\n\t\tv=*((uint64*)&b);\n\t\tNLMISC_BSWAP64(v);\n\t\tserialBuffer((uint8 *)&v, 8);\n\t}\n#endif // NL_LITTLE_ENDIAN\n}\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(bool &b)\n{\n\tserialBit(b);\n}\n\n#ifndef NL_OS_CYGWIN\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(char &b)\n{\n\tserialBuffer((uint8 *)&b, 1);\n}\n#endif\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(std::string &b)\n{\n\tuint32\tlen=0;\n\t// Read/Write the length.\n\tif(isReading())\n\t{\n\t\tserial(len);\n\n\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\tcheckStreamSize(len);\n\n\t\tb.resize(len);\n\t}\n\telse\n\t{\n\t\tlen= uint32(b.size());\n\t\tif (len>1000000)\n\t\t\tthrow NLMISC::EInvalidDataStream( \"IStream: Trying to write a string of %u bytes\", len );\n\t\tserial(len);\n\t}\n\n/*\n\t// Read/Write the string.\n\tfor(sint i=0;i<len;i++)\n\t\tserial(b[i]);\n*/\n\n\tif (len > 0)\n\t\tserialBuffer((uint8*)(&(b[0])), len);\n}\n\n\n// ======================================================================================================\ninline\tvoid\t\tIStream::serial(ucstring &b)\n{\n\tuint32\tlen=0;\n\t// Read/Write the length.\n\tif(isReading())\n\t{\n\t\tserial(len);\n\n\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\tcheckStreamSize(len);\n\n\t\tb.resize(len);\n\t}\n\telse\n\t{\n\t\tlen= uint32(b.size());\n\t\tif (len>1000000)\n\t\t\tthrow NLMISC::EInvalidDataStream( \"IStream: Trying to write an ucstring of %u bytes\", len );\n\t\tserial(len);\n\t}\n\t// Read/Write the string.\n\tfor(uint i=0;i!=len;++i)\n\t\tserial(b[i]);\n}\n\n\n\n// ======================================================================================================\ninline uint8\t\t\tIStream::serialBitField8(uint8  bf)\n{\n\tserial(bf);\n\treturn bf;\n}\n// ======================================================================================================\ninline uint16\t\t\tIStream::serialBitField16(uint16  bf)\n{\n\tserial(bf);\n\treturn bf;\n}\n// ======================================================================================================\ninline uint32\t\t\tIStream::serialBitField32(uint32  bf)\n{\n\tserial(bf);\n\treturn bf;\n}\n\n\n}\n\n\n#endif // NL_STREAM_INLINE_H\n\n/* End of stream_inline.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/string_common.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef\tNL_STRING_COMMON_H\n#define\tNL_STRING_COMMON_H\n\n#include \"types_nl.h\"\n\n#include <cstdio>\n#include <cstdarg>\n#include <errno.h>\n\nnamespace NLMISC\n{\n\n// get a string and add \\r before \\n if necessary\nstd::string addSlashR (std::string str);\nstd::string removeSlashR (std::string str);\n\n/**\n * \\def MaxCStringSize\n *\n * The maximum size allowed for C string (zero terminated string) buffer.\n * This value is used when we have to create a standard C string buffer and we don't know exactly the final size of the string.\n */\nconst int MaxCStringSize = 2048;\n\n\n/**\n * \\def NLMISC_CONVERT_VARGS(dest,format)\n *\n * This macro converts variable arguments into C string (zero terminated string).\n * This function takes care to avoid buffer overflow.\n *\n * Example:\n *\\code\n\tvoid MyFunction(const char *format, ...)\n\t{\n\t\tstring str;\n\t\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\t\t// str contains the result of the conversion\n\t}\n *\\endcode\n *\n * \\param _dest \\c string or \\c char* that contains the result of the convertion\n * \\param _format format of the string, it must be the last argument before the \\c '...'\n * \\param _size size of the buffer that will contain the C string\n */\n#define NLMISC_CONVERT_VARGS(_dest,_format,_size) \\\nchar _cstring[_size]; \\\nva_list _args; \\\nva_start (_args, _format); \\\nint _res = vsnprintf (_cstring, _size-1, _format, _args); \\\nif (_res == -1 || _res == _size-1) \\\n{ \\\n\t_cstring[_size-1] = '\\0'; \\\n} \\\nva_end (_args); \\\n_dest = _cstring\n\n\n\n/** sMart sprintf function. This function do a sprintf and add a zero at the end of the buffer\n * if there no enough room in the buffer.\n *\n * \\param buffer a C string\n * \\param count Size of the buffer\n * \\param format of the string, it must be the last argument before the \\c '...'\n */\nsint smprintf( char *buffer, size_t count, const char *format, ... );\n\n\n#ifdef NL_OS_WINDOWS\n\n//\n// These functions are needed by template system to failed the compilation if you pass bad type on nlinfo...\n//\n\ninline void _check(int /* a */) { }\ninline void _check(unsigned int /* a */) { }\ninline void _check(char /* a */) { }\ninline void _check(unsigned char /* a */) { }\ninline void _check(long /* a */) { }\ninline void _check(unsigned long /* a */) { }\n\n#ifdef NL_COMP_VC6\n\tinline void _check(uint8 /* a */) { }\n#endif // NL_COMP_VC6\n\ninline void _check(sint8 /* a */) { }\ninline void _check(uint16 /* a */) { }\ninline void _check(sint16 /* a */) { }\n\n#ifdef NL_COMP_VC6\n\tinline void _check(uint32 /* a */) { }\n\tinline void _check(sint32 /* a */) { }\n#endif // NL_COMP_VC6\n\ninline void _check(uint64 /* a */) { }\ninline void _check(sint64 /* a */) { }\ninline void _check(float /* a */) { }\ninline void _check(double /* a */) { }\ninline void _check(const char * /* a */) { }\ninline void _check(const void * /* a */) { }\n\n#define CHECK_TYPES(__a,__b) \\\ninline __a(const char *fmt) { __b(fmt); } \\\ntemplate<class A> __a(const char *fmt, A a) { _check(a); __b(fmt, a); } \\\ntemplate<class A, class B> __a(const char *fmt, A a, B b) { _check(a); _check(b); __b(fmt, a, b); } \\\ntemplate<class A, class B, class C> __a(const char *fmt, A a, B b, C c) { _check(a); _check(b); _check(c); __b(fmt, a, b, c); } \\\ntemplate<class A, class B, class C, class D> __a(const char *fmt, A a, B b, C c, D d) { _check(a); _check(b); _check(c); _check(d); __b(fmt, a, b, c, d); } \\\ntemplate<class A, class B, class C, class D, class E> __a(const char *fmt, A a, B b, C c, D d, E e) { _check(a); _check(b); _check(c); _check(d); _check(e); __b(fmt, a, b, c, d, e); } \\\ntemplate<class A, class B, class C, class D, class E, class F> __a(const char *fmt, A a, B b, C c, D d, E e, F f) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); __b(fmt, a, b, c, d, e, f); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); __b(fmt, a, b, c, d, e, f, g); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); __b(fmt, a, b, c, d, e, f, g, h); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); __b(fmt, a, b, c, d, e, f, g, h, i); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); __b(fmt, a, b, c, d, e, f, g, h, i, j); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); __b(fmt, a, b, c, d, e, f, g, h, i, j, k); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X, class Y> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y); } \\\ntemplate<class A, class B, class C, class D, class E, class F, class G, class H, class I, class J, class K, class L, class M, class N, class O, class P, class Q, class R, class S, class T, class U, class V, class W, class X, class Y, class Z> __a(const char *fmt, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j, K k, L l, M m, N n, O o, P p, Q q, R r, S s, T t, U u, V v, W w, X x, Y y, Z z) { _check(a); _check(b); _check(c); _check(d); _check(e); _check(f); _check(g); _check(h); _check(i); _check(j); _check(k); _check(l); _check(m); _check(n); _check(o); _check(p); _check(q); _check(r); _check(s); _check(t); _check(u); _check(v); _check(w); _check(x); _check(y); _check(z); __b(fmt, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); }\n\n#endif\n\n#ifdef NL_OS_WINDOWS\n\tinline std::string _toString(const char *format, ...)\n#else\n\tinline std::string toString(const char *format, ...)\n#endif\n{\n\tstd::string Result;\n\tNLMISC_CONVERT_VARGS(Result, format, NLMISC::MaxCStringSize);\n\treturn Result;\n}\n\n#ifdef NL_OS_WINDOWS\n\tCHECK_TYPES(std::string toString, return _toString)\n#endif // NL_OS_WINDOWS\n\ntemplate<class T> std::string toStringPtr(const T *val) { return toString(\"%p\", val); }\n\ntemplate<class T> std::string toStringEnum(const T &val) { return toString(\"%u\", (uint32)val); }\n\n/**\n * Template Object toString.\n * \\param obj any object providing a \"std::string toString()\" method. The object doesn't have to derive from anything.\n *\n * the VC++ error \"error C2228: left of '.toString' must have class/struct/union type\" means you don't provide\n * a toString() method to your object.\n */\n#ifndef NL_COMP_CLANG\ntemplate<class T> std::string toString(const T &obj)\n{\n\treturn obj.toString();\n}\n#endif\n\n//inline std::string toString(const char *val) { return toString(\"%s\", val); }\ninline std::string toString(const uint8 val) { return toString(\"%hu\", (uint16)val); }\ninline std::string toString(const sint8 val) { return toString(\"%hd\", (sint16)val); }\ninline std::string toString(const uint16 val) { return toString(\"%hu\", val); }\ninline std::string toString(const sint16 val) { return toString(\"%hd\", val); }\ninline std::string toString(const uint32 val) { return toString(\"%u\", val); }\ninline std::string toString(const sint32 val) { return toString(\"%d\", val); }\ninline std::string toString(const uint64 val) { return toString(\"%\" NL_I64 \"u\", val); }\ninline std::string toString(const sint64 val) { return toString(\"%\" NL_I64 \"d\", val); }\n\n#ifdef NL_COMP_GCC\n#\tif GCC_VERSION == 40102\n\n// error fix for size_t? gcc 4.1.2 requested this type instead of size_t ...\ninline std::string toString(const long unsigned int &val)\n{\n\tif (sizeof(long unsigned int) == 8)\n\t\treturn toString((uint64)val);\n\treturn toString((uint32)val);\n}\n\n#\tendif\n#endif\n\n#if (SIZEOF_SIZE_T) == 8\ninline std::string toString(const size_t &val) { return toString(\"%\" NL_I64 \"u\", val); }\n#else\n#ifdef NL_OS_MAC\ninline std::string toString(const size_t &val) { return toString(\"%u\", val); }\n#endif\n#endif\ninline std::string toString(const float &val) { return toString(\"%f\", val); }\ninline std::string toString(const double &val) { return toString(\"%lf\", val); }\ninline std::string toString(const bool &val) { return toString(\"%u\", val?1:0); }\ninline std::string toString(const std::string &val) { return val; }\n\n// stl vectors of bool use bit reference and not real bools, so define the operator for bit reference\n\n#ifdef NL_COMP_VC6\ninline std::string toString(const uint &val) { return toString(\"%u\", val); }\ninline std::string toString(const sint &val) { return toString(\"%d\", val); }\n#endif // NL_COMP_VC6\n\ntemplate<class T>\nbool fromString(const std::string &str, T &obj)\n{\n\treturn obj.fromString(str);\n}\n\ninline bool fromString(const std::string &str, uint32 &val) { if (str.find('-') != std::string::npos) { val = 0; return false; } char *end; unsigned long v; errno = 0; v = strtoul(str.c_str(), &end, 10); if (errno || v > UINT_MAX || end == str.c_str()) { val = 0; return false; } else { val = (uint32)v; return true; } }\ninline bool fromString(const std::string &str, sint32 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > INT_MAX || v < INT_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint32)v; return true; } }\ninline bool fromString(const std::string &str, uint8 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > UCHAR_MAX || v < 0 || end == str.c_str()) { val = 0; return false; } else { val = (uint8)v; return true; } }\ninline bool fromString(const std::string &str, sint8 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > SCHAR_MAX || v < SCHAR_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint8)v; return true; } }\ninline bool fromString(const std::string &str, uint16 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > USHRT_MAX || v < 0 || end == str.c_str()) { val = 0; return false; } else { val = (uint16)v; return true; } }\ninline bool fromString(const std::string &str, sint16 &val) { char *end; long v; errno = 0; v = strtol(str.c_str(), &end, 10); if (errno || v > SHRT_MAX || v < SHRT_MIN || end == str.c_str()) { val = 0; return false; } else { val = (sint16)v; return true; } }\ninline bool fromString(const std::string &str, uint64 &val) { bool ret = sscanf(str.c_str(), \"%\" NL_I64 \"u\", &val) == 1; if (!ret) val = 0; return ret; }\ninline bool fromString(const std::string &str, sint64 &val) { bool ret = sscanf(str.c_str(), \"%\" NL_I64 \"d\", &val) == 1; if (!ret) val = 0; return ret; }\ninline bool fromString(const std::string &str, float &val) { bool ret = sscanf(str.c_str(), \"%f\", &val) == 1; if (!ret) val = 0.0f; return ret; }\ninline bool fromString(const std::string &str, double &val) { bool ret = sscanf(str.c_str(), \"%lf\", &val) == 1; if (!ret) val = 0.0; return ret; }\n\ninline bool fromString(const std::string &str, bool &val)\n{\n\tif( str.length() == 1 )\n\t{\n\t\tif( str[ 0 ] == '1' )\n\t\t\tval = true;\n\t\telse\n\t\tif( str[ 0 ] == '0' )\n\t\t\tval = false;\n\t\telse\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\tif( str == \"true\" )\n\t\t\tval = true;\n\t\telse\n\t\tif( str == \"false\" )\n\t\t\tval = false;\n\t\telse\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\ninline bool fromString(const char *str, uint32 &val) { if (strstr(str, \"-\") != NULL) { val = 0; return false; } char *end; unsigned long v; errno = 0; v = strtoul(str, &end, 10); if (errno || v > UINT_MAX || end == str) { val = 0; return false; } else { val = (uint32)v; return true; } }\ninline bool fromString(const char *str, sint32 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > INT_MAX || v < INT_MIN || end == str) { val = 0; return false; } else { val = (sint32)v; return true; } }\ninline bool fromString(const char *str, uint8 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > UCHAR_MAX || v < 0 || end == str) { val = 0; return false; } else { val = (uint8)v; return true; } }\ninline bool fromString(const char *str, sint8 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > SCHAR_MAX || v < SCHAR_MIN || end == str) { val = 0; return false; } else { val = (sint8)v; return true; } }\ninline bool fromString(const char *str, uint16 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > USHRT_MAX || v < 0 || end == str) { val = 0; return false; } else { val = (uint16)v; return true; } }\ninline bool fromString(const char *str, sint16 &val) { char *end; long v; errno = 0; v = strtol(str, &end, 10); if (errno || v > SHRT_MAX || v < SHRT_MIN || end == str) { val = 0; return false; } else { val = (sint16)v; return true; } }\ninline bool fromString(const char *str, uint64 &val) { bool ret = sscanf(str, \"%\" NL_I64 \"u\", &val) == 1; if (!ret) val = 0; return ret; }\ninline bool fromString(const char *str, sint64 &val) { bool ret = sscanf(str, \"%\" NL_I64 \"d\", &val) == 1; if (!ret) val = 0; return ret; }\ninline bool fromString(const char *str, float &val) { bool ret = sscanf(str, \"%f\", &val) == 1; if (!ret) val = 0.0f; return ret; }\ninline bool fromString(const char *str, double &val) { bool ret = sscanf(str, \"%lf\", &val) == 1; if (!ret) val = 0.0; return ret; }\n\ninline bool fromString(const char *str, bool &val)\n{\n\tswitch (str[0])\n\t{\n\tcase '1':\n\tcase 't':\n\tcase 'y':\n\tcase 'T':\n\tcase 'Y':\n\t\tval = true;\n\t\treturn true;\n\tcase '0':\n\tcase 'f':\n\tcase 'n':\n\tcase 'F':\n\tcase 'N':\n\t\tval = false;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\ninline bool fromString(const std::string &str, std::string &val) { val = str; return true; }\n\n// stl vectors of bool use bit reference and not real bools, so define the operator for bit reference\n\n#ifdef NL_COMP_VC6\ninline bool fromString(const std::string &str, uint &val) { return sscanf(str.c_str(), \"%u\", &val) == 1; }\ninline bool fromString(const std::string &str, sint &val) { return sscanf(str.c_str(), \"%d\", &val) == 1; }\n#endif // NL_COMP_VC6\n\n\n} // NLMISC\n\n#endif\t// NL_STRING_COMMON_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/string_conversion.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STRING_CONVERSION_H\n#define NL_STRING_CONVERSION_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n\n#include <map>\n\nnamespace NLMISC\n{\n\n\n\n// a predicate use to do unsensitive string comparison (with operator <)\nstruct CUnsensitiveStrLessPred\n{\n\tbool operator()(const std::string &lhs, const std::string &rhs) const\n\t{\n\t\treturn nlstricmp(lhs, rhs) < 0;\n\t}\n};\n\n\n/** This class allow simple mapping between string and other type (such as integral types or enum)\n  * In fact this primarily intended to make a string / enum correspondance\n  * Example of use :\n  *\n  * // An enumerated type\n  * enum TMyType { Foo = 0, Bar, FooBar, Unknown };\n  *\n  * // The conversion table\n  * static const CStringConversion<TMyType>::CPair stringTable [] =\n  * {\n  *   { \"Foo\", Foo },\n  *   { \"Bar\", Bar },\n  *   { \"FooBar\", FooBar }\n  * };\n  *\n  * // The helper object for conversion (instance of this class)\n  *\tstatic const CStringConversion conversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]),  Unknown);\n  *\n  * // Some conversions request\n  * TMyType value1 = conversion.fromString(\"foo\");  // returns 'foo'\n  * value1 = conversion.fromString(\"Foo\");          // returns 'foo' (this is case unsensitive by default)\n  * std::string str = conversion.toString(Bar)      // returns \"Bar\"\n  *\n  * NB : Please note that that helpers macros are provided to build such a table in an easy way\n  *      \\see NL_BEGIN_STRING_CONVERSION_TABLE\n  *      \\see NL_END_STRING_CONVERSION_TABLE\n  *\n  *\n  * NB: by default this class behaves in a case unsensitive way. To change this, just change the 'Pred' template parameter\n  *     to std::less<std::string>\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2003\n  */\n\ntemplate <class DestType, class Pred = CUnsensitiveStrLessPred>\nclass CStringConversion\n{\npublic:\n\ttypedef DestType TDestType;\n\ttypedef Pred     TPred;\n\tstruct CPair\n\t{\n\t\tconst char *Str;\n\t\tTDestType   Value;\n\t};\npublic:\n\t// init from pairs of string / value\n\tCStringConversion(const CPair *pairs, uint numPairs, const DestType &notFoundValue);\n\n\t// add a pair in the array\n\tvoid insert(const char *str, TDestType value);\n\n\t// From a string, retrieve the associated value, or the 'notFoundValue' provided to the ctor of this object if the string wasn't found\n\tconst TDestType &fromString(const std::string &str) const;\n\n\t// From a value, retrieve the associated string, or an empty string if not found\n\tconst std::string &toString(const TDestType &value) const;\n\n\t// nb of pairs in the map\n\tinline uint16 getNbPairs() const { return (uint16)_String2DestType.size(); }\n\n\t// Check a value against the list a value, return true if the value exist in the container\n\tbool isValid(const DestType &value) const;\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\nprivate:\n\ttypedef std::map<std::string, TDestType, TPred> TString2DestType;\n\ttypedef std::map<TDestType, std::string>        TDestType2String;\nprivate:\n\tTString2DestType _String2DestType;\n\tTDestType2String _DestType2String;\n\tTDestType        _NotFoundValue;\n};\n\n/** This macro helps building a string conversion table\n  * Example of use :\n  *\n  * // The enumerated type for which a conversion should be defined\n  * enum TMyType { Foo = 0, Bar, FooBar, Unknown };\n  *\n  * // The conversion table\n  * NL_BEGIN_STRING_CONVERSION_TABLE(TMyType)\n  *\t  NL_STRING_CONVERSION_TABLE_ENTRY(Foo)\n  *\t  NL_STRING_CONVERSION_TABLE_ENTRY(Bar)\n  *\t  NL_STRING_CONVERSION_TABLE_ENTRY(FooBar)\n  * NL_END_STRING_CONVERSION_TABLE(TMyType, myConversionTable, Unknown)\n  *\n  * // Now, we can use the 'myConversionTable' intance\n  *\n  * std::string str = myConversionTable.toString(Bar)      // returns \"Bar\"\n  *\n  */\n#define NL_BEGIN_STRING_CONVERSION_TABLE(__type)                                               \\\nstatic const NLMISC::CStringConversion<__type>::CPair __type##_nl_string_conversion_table[] =          \\\n{\n#define NL_END_STRING_CONVERSION_TABLE(__type, __tableName, __defaultValue)                    \\\n};                                                                                             \\\nNLMISC::CStringConversion<__type>                                                                \\\n__tableName(__type##_nl_string_conversion_table, sizeof(__type##_nl_string_conversion_table)   \\\n\t\t\t/ sizeof(__type##_nl_string_conversion_table[0]),  __defaultValue);\n#define NL_STRING_CONVERSION_TABLE_ENTRY(val) { #val, val},\n\n\n\n\n\n\n//////////////////////////////////////\n// CStringConversion implementation //\n//////////////////////////////////////\n\n//=================================================================================================================\n/** CStringConversion ctor\n  */\ntemplate <class DestType, class Pred>\nCStringConversion<DestType, Pred>::CStringConversion(const CPair *pairs, uint numPairs, const DestType &notFoundValue)\n{\n\tfor(uint k = 0; k < numPairs; ++k)\n\t{\n\t\t_String2DestType[pairs[k].Str] = pairs[k].Value;\n\t\t_DestType2String[pairs[k].Value] = pairs[k].Str;\n\t}\n\t_NotFoundValue = notFoundValue;\n}\n\n//\ntemplate <class DestType, class Pred>\nvoid CStringConversion<DestType, Pred>::insert(const char *str, TDestType value)\n{\n\t_String2DestType[str] = value;\n\t_DestType2String[value] = str;\n}\n\n\n//=================================================================================================================\ntemplate <class DestType, class Pred>\nconst DestType &CStringConversion<DestType, Pred>::fromString(const std::string &str) const\n{\n\ttypename TString2DestType::const_iterator it = _String2DestType.find(str);\n\tif (it == _String2DestType.end())\n\t{\n\t\treturn _NotFoundValue;\n\t}\n\telse\n\t{\n\t\treturn it->second;\n\t}\n}\n\n//=================================================================================================================\ntemplate <class DestType, class Pred>\nconst std::string &CStringConversion<DestType, Pred>::toString(const DestType &value) const\n{\n\ttypename TDestType2String::const_iterator it = _DestType2String.find(value);\n\tif (it == _DestType2String.end())\n\t{\n\t\tstatic std::string emptyString;\n\t\treturn emptyString;\n\t}\n\telse\n\t{\n\t\treturn it->second;\n\t}\n}\n\n\n//=================================================================================================================\ntemplate <class DestType, class Pred>\nbool CStringConversion<DestType, Pred>::isValid(const DestType &value) const\n{\n\ttypename TDestType2String::const_iterator it = _DestType2String.find(value);\n\n\treturn it != _DestType2String.end();\n}\n\n\n} // NLMISC\n\n\n\n\n\n\n\n\n#endif\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/string_id_array.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STRING_ID_ARRAY_H\n#define NL_STRING_ID_ARRAY_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n\n#include <cmath>\n#include <string>\n#include <vector>\n#include <set>\n#include <algorithm>\n\n\nnamespace NLMISC {\n\n\n/**\n * The goal of this class is to associate number and string. It is used in the\n * CCallbackNetBase for message id<->string associations.\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CStringIdArray\n{\npublic:\n\n\ttypedef sint16 TStringId;\n\n\tCStringIdArray () : _IgnoreAllUnknownId(false) { }\n\n\t/// Adds a string in the string in the array\n\tvoid addString(const std::string &str, TStringId id)\n\t{\n\t\tnlassert (id >= 0 && id < pow(2.0, (sint)sizeof (TStringId)*8));\n\t\tnlassert (!str.empty());\n\n\t\tif (id >= (sint32) _StringArray.size())\n\t\t\t_StringArray.resize(id+1);\n\n\t\t_StringArray[id] = str;\n\n\t\tif (!_IgnoreAllUnknownId)\n\t\t{\n\t\t\t_AskedStringArray.erase (str);\n\t\t\t_NeedToAskStringArray.erase (str);\n\t\t}\n\t}\n\n\t/// Adds a string in the string at the end of the array\n\tvoid addString(const std::string &str)\n\t{\n\t\tnlassert (_StringArray.size () < pow(2.0, (sint)sizeof (TStringId)*8));\n\t\tnlassert (!str.empty());\n\n\t\t// add at the end\n\t\taddString (str, (TStringId)_StringArray.size ());\n\t}\n\n\t/** Returns the id associated to string str. If the id is not found, the string will be added in\n\t * _NeedToAskStringArray if ignoreAllUnknownId is false and IgnoreIfUnknown is false too.\n\t */\n\tTStringId getId (const std::string &str, bool IgnoreIfUnknown = false)\n\t{\n\t\tnlassert (!str.empty());\n\n\t\t// sorry for this bullshit but it's the simplest way ;)\n\t\tif (this == NULL) return -1;\n\n\t\tfor (TStringId i = 0; i < (TStringId) _StringArray.size(); i++)\n\t\t{\n\t\t\tif (_StringArray[i] == str)\n\t\t\t\treturn i;\n\t\t}\n\n\t\tif (!_IgnoreAllUnknownId && !IgnoreIfUnknown)\n\t\t{\n\t\t\t// the string is not found, add it to the _AskedStringArray if necessary\n\t\t\tif (_NeedToAskStringArray.find (str) == _NeedToAskStringArray.end ())\n\t\t\t{\n\t\t\t\tif (_AskedStringArray.find (str) == _AskedStringArray.end ())\n\t\t\t\t{\n\t\t\t\t\t//nldebug (\"String '%s' not found, add it to _NeedToAskStringArray\", str.c_str ());\n\t\t\t\t\t_NeedToAskStringArray.insert (str);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//nldebug (\"Found '%s' in the _AskedStringArray\", str.c_str ());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//nldebug (\"Found '%s' in the _NeedToAskStringArray\", str.c_str ());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//nldebug (\"Ignoring unknown association ('%s')\", str.c_str ());\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t/// Returns the string associated to this id\n\tstd::string getString (TStringId id) const\n\t{\n\t\t// sorry for this bullshit but it's the simplest way ;)\n\t\tif (this == NULL) return \"<NoSIDA>\";\n\n\t\tnlassert (id >= 0 && id < (TStringId)_StringArray.size());\n\n\t\treturn _StringArray[id];\n\t}\n\n\t/// Set the size of the _StringArray\n\tvoid resize (TStringId size)\n\t{\n\t\t_StringArray.resize (size);\n\t}\n\n\t/// Returns the size of the _StringArray\n\tTStringId size () const\n\t{\n\t\treturn (TStringId)_StringArray.size ();\n\t}\n\n\t/// Returns all string in the _NeedToAskStringArray\n\tconst std::set<std::string> &getNeedToAskedStringArray () const\n\t{\n\t\treturn _NeedToAskStringArray;\n\t}\n\n\t/// Returns all string in the _AskedStringArray\n\tconst std::set<std::string> &getAskedStringArray () const\n\t{\n\t\treturn _AskedStringArray;\n\t}\n\n\t/// Moves string from _NeedToAskStringArray to _AskedStringArray\n\tvoid moveNeedToAskToAskedStringArray ()\n\t{\n\t\tif (!_IgnoreAllUnknownId)\n\t\t{\n\t\t\t_AskedStringArray.insert (_NeedToAskStringArray.begin(), _NeedToAskStringArray.end());\n\t\t\t_NeedToAskStringArray.clear ();\n\t\t}\n\t}\n\n\t/// If set to true, when we ask a string with no id, we don't put it in the _NeedToAskStringArray array\n\tvoid ignoreAllUnknownId (bool b) { _IgnoreAllUnknownId = b; }\n\n\t/// Clears the string id array\n\tvoid clear ()\n\t{\n\t\t_StringArray.clear ();\n\t\t_NeedToAskStringArray.clear ();\n\t\t_AskedStringArray.clear ();\n\t}\n\n\t/// Displays all association of the array in a C style (useful to copy/paste in your C code)\n\tvoid display ()\n\t{\n\t\tnlinfo (\"static const char *OtherSideAssociations[] = {\");\n\t\tfor (uint i = 0; i < _StringArray.size(); i++)\n\t\t{\n\t\t\tnlinfo(\" \\\"%s\\\",\", _StringArray[i].c_str());\n\t\t}\n\t\tnlinfo (\"};\");\n\t}\n\nprivate:\n\n\tbool _IgnoreAllUnknownId;\n\n\tstd::vector<std::string>\t_StringArray;\n\n\tstd::set<std::string>\t_NeedToAskStringArray;\n\n\tstd::set<std::string>\t_AskedStringArray;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_STRING_ID_ARRAY_H\n\n/* End of string_id_array.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/string_mapper.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef STRING_MAPPER_H\n#define STRING_MAPPER_H\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n#include \"mutex.h\"\n\n#include <vector>\n#include <set>\n\nnamespace NLMISC\n{\n\n// const string *  as  uint (the TStringId returned by CStringMapper is a pointer to a string object)\n//#ifdef HAVE_X86_64\n//typedef uint64 TStringId;\n//#else\n//typedef uint TStringId;\n//#endif\n\ntypedef\tconst std::string *TStringId;\n\n// Traits for hash_map using CStringId\nstruct CStringIdHashMapTraits\n{\n\tenum { bucket_size = 4, min_buckets = 8, };\n\tCStringIdHashMapTraits() { }\n\tsize_t operator() (const NLMISC::TStringId &stringId) const\n\t{\n\t\treturn\t(size_t)stringId;\n\t}\n\tbool operator() (const NLMISC::TStringId &strId1, const NLMISC::TStringId &strId2) const\n\t{\n\t\treturn (size_t)strId1 < (size_t)strId2;\n\t}\n};\n\n/** A static class that map string to integer and vice-versa\n * Each different string is tranformed into an unique integer identifier.\n * If the same string is submited twice, the same id is returned.\n * The class can also return the string associated with an id.\n *\n * \\author Boris Boucher\n * \\author Nevrax France\n * \\date 2003\n */\nclass CStringMapper\n{\n\tclass CCharComp\n\t{\n\tpublic:\n\t\tbool operator()(std::string *x, std::string *y) const\n\t\t{\n\t\t\treturn (*x) < (*y);\n\t\t}\n\t};\n\n\tclass CAutoFastMutex\n\t{\n\t\tCFastMutex\t\t*_Mutex;\n\tpublic:\n\t\tCAutoFastMutex(CFastMutex *mtx) : _Mutex(mtx)\t{_Mutex->enter();}\n\t\t~CAutoFastMutex() {_Mutex->leave();}\n\t};\n\n\t// Local Data\n\tstd::set<std::string*,CCharComp>\t_StringTable;\n\tstd::string*\t\t\t_EmptyId;\n\tCFastMutex\t\t\t\t_Mutex;\t\t// Must be thread-safe (Called by CPortal/CCluster, each of them called by CInstanceGroup)\n\n\t// The 'singleton' for static methods\n\tstatic\tCStringMapper\t_GlobalMapper;\n\n\t// private constructor.\n\tCStringMapper();\n\npublic:\n\n\t~CStringMapper()\n\t{\n\t\tlocalClear();\n\t}\n\n\t/// Globaly map a string into a unique Id. ** This method IS Thread-Safe **\n\tstatic TStringId\t\t\tmap(const std::string &str) { return _GlobalMapper.localMap(str); }\n\t/// Globaly unmap a string. ** This method IS Thread-Safe **\n\tstatic const std::string\t&unmap(const TStringId &stringId) { return _GlobalMapper.localUnmap(stringId); }\n\t/// Globaly helper to serial a string id. ** This method IS Thread-Safe **\n\tstatic void\t\t\t\t\tserialString(NLMISC::IStream &f, TStringId &id) {_GlobalMapper.localSerialString(f, id);}\n\t/// Return the global id for the empty string (helper function). NB: Works with every instance of CStringMapper\n\tstatic TStringId\t\t\temptyId() { return 0; }\n\n\t// ** This method IS Thread-Safe **\n\tstatic void\t\t\t\t\tclear() { _GlobalMapper.localClear(); }\n\n\t/// Create a local mapper. You can dispose of it by deleting it.\n\tstatic CStringMapper *\tcreateLocalMapper();\n\t/// Localy map a string into a unique Id\n\tTStringId\t\t\t\tlocalMap(const std::string &str);\n\t/// Localy unmap a string\n\tconst std::string\t\t&localUnmap(const TStringId &stringId) { return (stringId==0)?*_EmptyId:*((std::string*)stringId); }\n\t/// Localy helper to serial a string id\n\tvoid\t\t\t\t\tlocalSerialString(NLMISC::IStream &f, TStringId &id);\n\n\tvoid\t\t\t\t\tlocalClear();\n\n};\n\n// linear from 0 (0 is empty string) (The TSStringId returned by CStaticStringMapper\n// is an index in the vector and begin at 0)\ntypedef uint TSStringId;\n\n/**\n * After endAdd you cannot add strings anymore or it will assert\n * \\author Matthieu Besson\n * \\author Nevrax France\n * \\date November 2003\n */\nclass CStaticStringMapper\n{\n\n\tstd::map<std::string, TSStringId>\t_TempStringTable;\n\tstd::map<TSStringId, std::string>\t_TempIdTable;\n\n\tuint32\t_IdCounter;\n\tchar\t*_AllStrings;\n\tstd::vector<char*>\t_IdToStr;\n\tbool _MemoryCompressed; // If false use the 2 maps\n\npublic:\n\n\tCStaticStringMapper()\n\t{\n\t\t_IdCounter = 0;\n\t\t_AllStrings = NULL;\n\t\t_MemoryCompressed = false;\n\t\tadd(\"\");\n\t}\n\n\t~CStaticStringMapper()\n\t{\n\t\tclear();\n\t}\n\n\t/// Globaly map a string into a unique Id\n\tTSStringId\t\t\tadd(const std::string &str);\n\n\t// see if a string is already present in the map\n\tbool\t\t\t\tisAdded(const std::string &str) const;\n\n\tvoid\t\t\t\tmemoryCompress();\n\t// Uncompress the map.\n\tvoid\t\t\t\tmemoryUncompress();\n\t/// Globaly unmap a string\n\tconst char *\t\tget(TSStringId stringId);\n\t/// Return the global id for the empty string (helper function)\n\tstatic TSStringId\temptyId() { return 0; }\n\n\tvoid\t\t\t\tclear();\n\n\tuint32 getCount() { return _IdCounter; }\n\n\t// helper serialize a string id as a string\n\tvoid\t\t\t\tserial(NLMISC::IStream &f, TSStringId &strId) throw(EStream);\n\n\t// helper serialize a string id vector\n\tvoid\t\t\t\tserial(NLMISC::IStream &f, std::vector<TSStringId> &strIdVect) throw(EStream);\n\n};\n\n} //namespace NLMISC\n\n#endif // STRING_MAPPER_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/string_stream.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STRING_STREAM_H\n#define NL_STRING_STREAM_H\n\n#include \"types_nl.h\"\n#include \"mem_stream.h\"\n\n\nnamespace NLMISC {\n\n\n/**\n * Memory stream that is serialized from/to plain text (human-readable).\n * not any comparaison with the stl class std::stringstream\n *\n * OBSOLETE! Now, use CMemStream in string mode.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CStringStream : public CMemStream\n{\npublic:\n\n\t/// Initialization constructor\n\tCStringStream( bool inputStream=false, uint32 defaultcapacity=0 ) : CMemStream( inputStream, false, defaultcapacity ) {}\n\n\t/// Copy constructor\n\tCStringStream( const CStringStream& other ) : CMemStream( other ) {}\n\n\t/// Assignment operator\n\tCStringStream&\t\toperator=( const CStringStream& other ) { CMemStream::operator=( other ); return *this; }\n\n\t/// Input: read len bytes at most from the stream until the next separator, and return the number of bytes read. The separator is then skipped.\n\tuint\t\t\tserialSeparatedBufferIn( uint8 *buf, uint len );\n\n\t/// Output: writes len bytes from buf into the stream\n\tvoid\t\t\tserialSeparatedBufferOut( uint8 *buf, uint len );\n\n\t/// Method inherited from IStream\n\tvirtual void\tserialBit(bool &bit);\n\n\t/// Template serialisation (should take the one from IStream)\n    template<class T>\n\tvoid\t\t\tserial(T &obj)\t\t\t\t\t\t\t{ obj.serial(*this); }\n\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::vector<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::list<T> &cont) \t\t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::deque<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::set<T> &cont) \t\t\t{CMemStream::serialCont(cont);}\n\ttemplate<class T>\n\tvoid\t\t\tserialCont(std::multiset<T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::map<K, T> &cont) \t\t{CMemStream::serialCont(cont);}\n\ttemplate<class K, class T>\n\tvoid\t\t\tserialCont(std::multimap<K, T> &cont) \t{CMemStream::serialCont(cont);}\n\n\ttemplate<class T0,class T1>\n\tvoid\t\t\tserial(T0 &a, T1 &b)\n\t{ serial(a); serial(b);}\n\ttemplate<class T0,class T1,class T2>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c)\n\t{ serial(a); serial(b); serial(c);}\n\ttemplate<class T0,class T1,class T2,class T3>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d)\n\t{ serial(a); serial(b); serial(c); serial(d);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e);}\n\ttemplate<class T0,class T1,class T2,class T3,class T4,class T5>\n\tvoid\t\t\tserial(T0 &a, T1 &b, T2 &c, T3 &d, T4 &e, T5 &f)\n\t{ serial(a); serial(b); serial(c); serial(d); serial(e); serial(f);}\n\n\t/** \\name Base type serialisation.\n\t * Those method are a specialisation of template method \"void serial(T&)\".\n\t */\n\t//@{\n\n\tvirtual void\tserial(uint8 &b) ;\n\tvirtual void\tserial(sint8 &b) ;\n\tvirtual void\tserial(uint16 &b) ;\n\tvirtual void\tserial(sint16 &b) ;\n\tvirtual void\tserial(uint32 &b) ;\n\tvirtual void\tserial(sint32 &b) ;\n\tvirtual void\tserial(uint64 &b) ;\n\tvirtual void\tserial(sint64 &b) ;\n\tvirtual void\tserial(float &b) ;\n\tvirtual void\tserial(double &b) ;\n\tvirtual void\tserial(bool &b) ;\n#ifndef NL_OS_CYGWIN\n\tvirtual void\tserial(char &b) ;\n#endif\n\tvirtual void\tserial(std::string &b) ;\n\tvirtual void\tserial(ucstring &b) ;\n\t//@}\n\n\t/// Specialisation of serialCont() for vector<uint8>\n\tvirtual void\t\t\tserialCont(std::vector<uint8> &cont) { serialVector(cont); }\n\t/// Specialisation of serialCont() for vector<sint8>\n\tvirtual void\t\t\tserialCont(std::vector<sint8> &cont) { serialVector(cont); }\n\t/// Specialisation of serialCont() for vector<bool>\n\tvirtual void\t\t\tserialCont(std::vector<bool> &cont);\n\n\t/// Serialisation in hexadecimal\n\tvirtual void\tserialHex(uint32 &b);\n};\n\n\n} // NLMISC\n\n\n#endif // NL_STRING_STREAM_H\n\n/* End of string_stream.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/system_info.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SYSTEM_INFO_H\n#define NL_SYSTEM_INFO_H\n\n#include \"types_nl.h\"\n\n#include <string>\n\nnamespace NLMISC {\n\n\n/**\n * This class provides general system-level information about the local machine.\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CSystemInfo\n{\npublic:\n\n\tstatic std::string getOS ();\n\tstatic std::string getProc ();\n\n\t/** Gives an evaluation of the processor frequency, in hertz\n\t  * \\param quick true to do quick frequency evaluation\n\t  * \\warning Supports only Intel architectures for now. Returns 0 if not implemented.\n\t  */\n\tstatic uint64 getProcessorFrequency (bool quick = false);\n\n\t/** Tests whether the CPUID instruction is supported\n\t  * (always false on non Intel architectures)\n\t  */\n\tstatic bool hasCPUID ();\n\n\t/** Helps to know whether the processor features MMX instruction set\n\t  * This is initialized at started, so its fast\n\t  * (always false on non 0x86 architecture ...)\n\t  */\n\tstatic bool hasMMX () {return _HaveMMX;}\n\n\t/** Helps to know whether the processor has streaming SIMD instructions (the OS must supports it)\n\t  * This is initialized at started, so its fast\n\t  * (always false on non 0x86 architecture ...)\n\t  */\n\tstatic bool hasSSE () {return _HaveSSE;}\n\n\t/** Gets the CPUID (if available). Useful for debug info\n\t  */\n\tstatic uint32 getCPUID();\n\n\t/** true if the Processor has HyperThreading\n\t  */\n\tstatic bool hasHyperThreading();\n\n\t/** true if running under NT\n\t  */\n\tstatic bool isNT();\n\n\t/** Returns the space left on the hard drive that contains the filename\n\t  */\n\tstatic std::string availableHDSpace (const std::string &filename);\n\n\t/** Returns all the physical memory available on the computer (in bytes)\n\t  */\n\tstatic uint64 availablePhysicalMemory ();\n\n\t/** Returns the physical memory on the computer (in bytes)\n\t  */\n\tstatic uint64 totalPhysicalMemory ();\n\n\t/** Returns the amount of allocated system memory (in bytes)\n\t  */\n\tstatic uint64 getAllocatedSystemMemory ();\n\n\t/** Returns all the virtual memory used by this process (in bytes)\n\t  */\n\tstatic uint64 virtualMemory ();\n\n\t/** Returns the main video card name and the video driver version\n\t  */\n\tstatic bool getVideoInfo (std::string &deviceName, uint64 &driverVersion);\n\nprivate:\n\tstatic bool _HaveMMX;\n\tstatic bool _HaveSSE;\n};\n\n} // NLMISC\n\n#endif // NL_SYSTEM_INFO_H\n\n/* End of system_info.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/system_utils.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SYSTEM_UTILS_H\n#define NL_SYSTEM_UTILS_H\n\n#include \"types_nl.h\"\n#include \"ucstring.h\"\n\nnamespace NLMISC\n{\n\n/*\n * Operating system miscellaneous functions (all methods and variables should be static)\n * \\author Kervala\n * \\date 2010\n */\nclass CSystemUtils\n{\n\tstatic nlWindow s_window;\npublic:\n\n\t/// Initialize data which needs it before using them.\n\tstatic bool init();\n\n\t/// Uninitialize data when they won't be used anymore.\n\tstatic bool uninit();\n\n\t/// Set the window which will be used by some functions.\n\tstatic void setWindow(nlWindow window);\n\n\t/// Create/update a progress bar with an appearance depending on system.\n\tstatic bool updateProgressBar(uint value, uint total);\n\n\t/// Copy a string to system clipboard.\n\tstatic bool copyTextToClipboard(const ucstring &text);\n\n\t/// Paste a string from system clipboard.\n\tstatic bool pasteTextFromClipboard(ucstring &text);\n\n\t/// Check if system supports unicode.\n\tstatic bool supportUnicode();\n\n\t/// Check if keyboard layout is AZERTY.\n\tstatic bool isAzertyKeyboard();\n\n\t/// Check if screensaver is enabled.\n\tstatic bool isScreensaverEnabled();\n\n\t/// Enable or disable screeensaver.\n\tstatic bool enableScreensaver(bool screensaver);\n\n\t/// Get the ROOT registry key used by getRegKey and setRegKey.\n\tstatic std::string getRootKey();\n\n\t/// Set the ROOT registry key used by getRegKey and setRegKey.\n\tstatic void setRootKey(const std::string &root);\n\n\t/// Read a value from registry.\n\tstatic std::string getRegKey(const std::string &Entry);\n\n\t/// Write a value to registry.\n\tstatic bool setRegKey(const std::string &ValueName, const std::string &Value);\n\n\t/// Get desktop current color depth without using UDriver.\n\tstatic uint getCurrentColorDepth();\n};\n\n} // NLMISC\n\n#endif // NL_SYSTEM_UTILS_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/task_manager.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TASK_MANAGER_H\n#define NL_TASK_MANAGER_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n\n#include <list>\n#include <vector>\n\n#include \"mutex.h\"\n#include \"thread.h\"\n\nnamespace NLMISC {\n\n\n/**\n * A class derived from IRunnable to get a position\n */\nclass IRunnablePos : public NLMISC::IRunnable\n{\npublic:\n\tNLMISC::CVector\tPosition;\n};\n\n/**\n * CTaskManager is a class that manage a list of Task with one Thread\n * \\author Alain Saffray\n * \\author Nevrax France\n * \\date 2000\n */\nclass CTaskManager : public IRunnable\n{\npublic:\n\n\t/// Constructor\n\tCTaskManager();\n\n\t/// Destructor\n\t~CTaskManager();\n\n\t/// Manage TaskQueue\n\tvoid run(void);\n\n\t/// Add a task to TaskManager and its priority\n\tvoid addTask(IRunnable *, float priority=0);\n\n\t/// Delete a task, only if task is not running, return true if found and deleted\n\tbool deleteTask(IRunnable *r);\n\n\t/// Sleep a Task\n\tvoid sleepTask(void) { nlSleep(10); }\n\n\t/// Task list size\n\tuint taskListSize(void);\n\n\t/// return false if exit() is required. task added with addTask() should test this flag.\n\tbool\tisThreadRunning() const {return _ThreadRunning;}\n\n\t/// Dump task list\n\tvoid\tdump (std::vector<std::string> &result);\n\n\t/// Clear the dump of Done files\n\tvoid\tclearDump();\n\n\t/// Get number of waiting task\n\tuint\tgetNumWaitingTasks();\n\n\t/// Is there a current task ?\n\tbool\tisTaskRunning() const {return _IsTaskRunning;}\n\n\t/// A callback to modify the task priority\n\tclass IChangeTaskPriority\n\t{\n\tpublic:\n\t\tvirtual ~IChangeTaskPriority() {}\n\t\tvirtual float getTaskPriority(const IRunnable &runable) = 0;\n\t};\n\n\t/// Register task priority callback\n\tvoid\tregisterTaskPriorityCallback (IChangeTaskPriority *callback);\n\nprivate:\n\n\t/// Register task priority callback\n\tvoid\tchangeTaskPriority ();\n\n\t/// The callback\n\tIChangeTaskPriority\t\t*_ChangePriorityCallback;\n\nprotected:\n\n\t/** If any, wait the current running task to complete\n\t *\tthis function MUST be called in a 'accessor to the _TaskQueue' statement because a mutex is required\n\t *\teg:\n\t *\t\\code\n\t *\t{\n\t *\t\tCSynchronized<list<IRunnable *> >::CAccessor acces(&_TaskQueue);\n\t *\t\twaitCurrentTaskToComplete();\n\t *\t}\n\t *\t\\endcode\n\t */\n\tvoid\twaitCurrentTaskToComplete ();\n\nprotected:\n\n\t// A task in the waiting queue with its parameters\n\tclass CWaitingTask\n\t{\n\tpublic:\n\t\tCWaitingTask (IRunnable *task, float priority)\n\t\t{\n\t\t\tTask = task;\n\t\t\tPriority = priority;\n\t\t}\n\t\tIRunnable\t\t*Task;\n\t\tfloat\t\t\tPriority;\n\n\t\t// For the sort\n\t\tbool\t\t\toperator< (const CWaitingTask &other) const\n\t\t{\n\t\t\treturn Priority < other.Priority;\n\t\t}\n\t};\n\n\t/// queue of tasks, using list container instead of queue for DeleteTask methode\n\tCSynchronized<std::string>\t\t\t\t_RunningTask;\n\tCSynchronized<std::list<CWaitingTask> >\t_TaskQueue;\n\tCSynchronized<std::deque<std::string> >\t_DoneTaskQueue;\n\n\t/// thread pointer\n\tIThread *_Thread;\n\n\t/// flag indicate thread loop, if false cause thread exit\n\tvolatile\tbool _ThreadRunning;\n\nprivate:\n\n\tvolatile\tbool _IsTaskRunning;\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_TASK_MANAGER_H\n\n/* End of task_manager.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/tds.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TDS_H\n#define NL_TDS_H\n\n#include \"types_nl.h\"\n\n\nnamespace NLMISC\n{\n\n\n/**\n * Thread dependant storage class\n *\n * This class provides a thread specific (void*).\n * It is initialized at NULL.\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2002\n */\nclass CTDS\n{\npublic:\n\n\t/// Constructor. The pointer is initialized with NULL.\n\tCTDS ();\n\n\t/// Destructor\n\t~CTDS ();\n\n\t/// Get the thread specific pointer\n\tvoid\t*getPointer () const;\n\n\t/// Set the thread specific pointer\n\tvoid\tsetPointer (void* pointer);\n\nprivate:\n#ifdef NL_OS_WINDOWS\n\tuint32\t\t\t_Handle;\n#else // NL_OS_WINDOWS\n\tpthread_key_t\t_Key;\n#endif // NL_OS_WINDOWS\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_TDS_H\n\n/* End of tds.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/thread.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_THREAD_H\n#define NL_THREAD_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n\n\nnamespace NLMISC {\n\n\n/**\n * Thread callback interface.\n * When a thread is created, it will call run() in its attached IRunnable interface.\n *\n *\\code\n\n\t#include \"thread.h\"\n\n\tclass HelloLoopThread : public IRunnable\n\t{\n\t\tvoid run ()\n\t\t{\n\t\t\tfor(;;)\tprintf(\"Hello World\\n\");\n\t\t}\n\n\t};\n\n\tIThread *thread = IThread::create (new HelloLoopThread);\n\tthread->start ();\n\n *\\endcode\n *\n *\n *\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass IRunnable\n{\npublic:\n\t// Called when a thread is run.\n\tvirtual void run()=0;\n\tvirtual ~IRunnable()\n\t{\n\t}\n\t// Return the runnable name\n\tvirtual void getName (std::string &result) const\n\t{\n\t\tresult = \"NoName\";\n\t}\n};\n\n/// Thread priorities, numbering follows Win32 for now\nenum TThreadPriority\n{\n\tThreadPriorityLowest = -2,\n\tThreadPriorityLow = -1,\n\tThreadPriorityNormal = 0,\n\tThreadPriorityHigh = 1,\n\tThreadPriorityHighest = 2,\n};\n\n/**\n * Thread base interface, must be implemented for all OS\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass IThread\n{\npublic:\n\n\t/**\n\t  * Create a new thread.\n\t  * Implemented in the derived class.\n\t  */\n\tstatic IThread *create(IRunnable *runnable, uint32 stackSize = 0);\n\n\t/**\n\t  * Return a pointer on the current thread.\n\t  * Implemented in the derived class.\n\t  */\n\tstatic IThread *getCurrentThread ();\n\n\tvirtual ~IThread () { }\n\n\t// Starts the thread.\n\tvirtual void start()=0;\n\n\t// Check if the thread is still running\n\tvirtual bool isRunning() =0;\n\n\t// Terminate the thread (risky method, use only in extreme cases)\n\tvirtual void terminate()=0;\n\n\t// In the calling program, wait until the specified thread has exited. After wait() has returned, you can delete the thread object.\n\tvirtual void wait()=0;\n\n\t/// Return a pointer to the runnable object\n\tvirtual IRunnable *getRunnable()=0;\n\n\t/**\n\t  * Set the CPU mask of this thread. Thread must have been started before.\n\t  * The mask must be a subset of the CPU mask returned by IProcess::getCPUMask() thread process.\n\t  */\n\tvirtual bool setCPUMask(uint64 cpuMask)=0;\n\n\t/**\n\t  * Get the CPU mask of this thread. Thread must have been started before.\n\t  * The mask should be a subset of the CPU mask returned by IProcess::getCPUMask() thread process.\n\t  */\n\tvirtual uint64 getCPUMask()=0;\n\n\t/// Set the thread priority. Thread must have been started before.\n\tvirtual void setPriority(TThreadPriority priority) = 0;\n\n\t/**\n\t  * Get the thread user name.\n\t  * Under Linux return thread owner, under windows return the name of the logon user.\n\t  */\n\tvirtual std::string getUserName()=0;\n};\n\n\n/*\n * Thread exception\n */\nstruct EThread : public Exception\n{\n\tEThread (const char* message) : Exception (message) {}\n};\n\n\n/**\n * Process base interface, must be implemented for all OS\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2000\n */\nclass IProcess\n{\npublic:\n\tvirtual ~IProcess() {}\n\n\t/**\n\t  * Return a pointer on the current process.\n\t  * Implemented in the derived class.\n\t  */\n\tstatic IProcess *getCurrentProcess ();\n\n\t/**\n\t  * Return process CPU mask. Each bit stand for a CPU usable by the process threads.\n\t  */\n\tvirtual uint64 getCPUMask()=0;\n\n\t/**\n\t  * Set the process CPU mask. Each bit stand for a CPU usable by the process threads.\n\t  */\n\tvirtual bool setCPUMask(uint64 mask)=0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_THREAD_H\n\n/* End of thread.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/time_nl.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TIME_H\n#define NL_TIME_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n// automatically add the win multimedia library if you use CTime class\n#\tpragma comment(lib, \"winmm.lib\")\n#endif\n\nnamespace NLMISC\n{\n\n\n/// New time types\ntypedef double TGameTime;\t\t// Time according to the game (used for determining day, night...) (double in seconds)\ntypedef sint64 TGameCycle;\t\t// Integer game cycle count from the game (in game ticks)\ntypedef double TLocalTime;\t\t// Time according to the machine's local clock (double in seconds)\ntypedef sint64 TCPUCycle;\t\t// Integer cycle count from the CPU (for profiling in cpu ticks)\n\n/// Old time type\ntypedef sint64 TTime;\ntypedef sint64 TTicks;\n\n\n/**\n * This class provide a independant local time system.\n * \\author Vianney Lecroart, Olivier Cado\n * \\author Nevrax France\n * \\date 2000-2005\n */\nclass CTime\n{\npublic:\n\tstruct CTimerInfo\n\t{\n\t\t/// Returns if there is a high precision timer that can be used.\n\t\tbool IsHighPrecisionAvailable;\n\t\t/// If a CPU specific timer is used and the values are not consistent accross threads.\n\t\tbool RequiresSingleCore;\n\t\t/// The resolution of the high resolution timer.\n\t\tTTicks HighPrecisionResolution;\n\t};\n\n\t/** Get advanced information on the used timers.\n\t */\n\tstatic void probeTimerInfo(CTimerInfo &result);\n\n\t/** Return the number of second since midnight (00:00:00), January 1, 1970,\n\t * coordinated universal time, according to the system clock.\n\t * The time returned is local, ie. it has the local time ajustement, including\n\t * daylight saving if applicable.\n\t * This values is the same on all computer if computers are synchronized (with NTP for example).\n\t */\n\tstatic uint32\tgetSecondsSince1970 ();\n\n\t/** Return the number of second since midnight (00:00:00), January 1, 1970,\n\t * coordinated universal time, according to the system clock.\n\t * The time returned is UTC (aka GMT+0), ie it does not have the local time ajustement\n\t * nor it have the daylight saving ajustement.\n\t * This values is the same on all computer if computers are synchronized (with NTP for example).\n\t */\n//\tstatic uint32\tgetSecondsSince1970UTC ();\n\n\t/** Return the local time in milliseconds.\n\t * Use it only to measure time difference, the absolute value does not mean anything.\n\t * On Unix, getLocalTime() will try to use the Monotonic Clock if available, otherwise\n\t * the value can jump backwards if the system time is changed by a user or a NTP time sync process.\n\t * The value is different on 2 different computers; use the CUniTime class to get a universal\n\t * time that is the same on all computers.\n\t * \\warning On Win32, the value is on 32 bits only, and uses the low-res timer unless probeTimerInfo was called and a high resolution timer can be used. It wraps around to 0 every about 49.71 days.\n\t */\n\tstatic TTime\tgetLocalTime();\n\n\t/** Return the time in processor ticks. Use it for profile purpose.\n\t * If the performance time is not supported on this hardware, it returns 0.\n\t * \\warning On a multiprocessor system, the value returned by each processor may\n\t * be different. The only way to workaround this is to set a processor affinity\n\t * to the measured thread.\n\t * \\warning The speed of tick increase can vary (especially on laptops or CPUs with\n\t * power management), so profiling several times and computing the average could be\n\t * a wise choice.\n\t */\n\tstatic TTicks\tgetPerformanceTime ();\n\n\t/** Convert a ticks count into second. If the performance time is not supported on this\n\t * hardware, it returns 0.0.\n\t */\n\tstatic double\tticksToSecond (TTicks ticks);\n\n\t/** Build a human readable string of a time difference in second.\n\t *\tThe result will be of the form '1 years 2 months 2 days 10 seconds'\n\t */\n\tstatic std::string\tgetHumanRelativeTime(sint32 nbSeconds);\n\n#ifdef NL_OS_WINDOWS\n\t/** Return the offset in 10th of micro sec between the windows base time (\n\t *\t01-01-1601 0:0:0 UTC) and the unix base time (01-01-1970 0:0:0 UTC).\n\t *\tThis value is used to convert windows system and file time back and\n\t *\tforth to unix time (aka epoch)\n\t */\n\tstatic uint64 getWindowsToUnixBaseTimeOffset();\n#endif\n\n};\n\n} // NLMISC\n\n#endif // NL_TIME_H\n\n/* End of time_nl.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/timeout_assertion_thread.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TIMEOUT_ASSERTION_THREAD_H\n#define NL_TIMEOUT_ASSERTION_THREAD_H\n\n#include \"common.h\"\n#include \"thread.h\"\n\n/*\n\n  example:\n\tEncapsulation of message callbacks\n\n\n  // in init\n  CTimeoutAssertionThread *myTAT = new CTimeoutAssertionThread(1000);\n  IThread::create(myTAT)->start();\n\n  ...\n\n  // in callback management\n  myTAT->activate();\n  msg->callback();\n  myTAT->disactivate();\n\n  // if the callback call is too slow, an assertion will happen\n\n*/\n\nclass CTimeoutAssertionThread: public NLMISC::IRunnable\n{\npublic:\n\tenum TControl { ACTIVE, INACTIVE, QUIT };\n\n\tCTimeoutAssertionThread(uint32 timeout = 0) : _Control(INACTIVE), _Counter(0), _Timeout(timeout)\n\t{\n\t}\n\n\tvoid run()\n\t{\n\t\tuint32 lastCounter;\n\t\twhile(_Control != QUIT)\n\t\t{\n\t\t\tif(_Control != ACTIVE || _Timeout == 0)\n\t\t\t{\n\t\t\t\t//nldebug(\"not active, sleep\");\n\t\t\t\tNLMISC::nlSleep(1000);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//nldebug(\"active, enter sleep\");\n\t\t\t\tlastCounter = _Counter;\n\n\t\t\t\tuint32 cummuledSleep = 0;\n\n\t\t\t\t// do sleep until cumulated time reached timeout value\n\t\t\t\twhile (cummuledSleep < _Timeout)\n\t\t\t\t{\n\t\t\t\t\t// sleep 1 s\n\t\t\t\t\tNLMISC::nlSleep(std::min((uint32)(1000), (uint32)(_Timeout-cummuledSleep)));\n\n\t\t\t\t\tcummuledSleep += 1000;\n\n\t\t\t\t\t// check if exit is required\n\t\t\t\t\tif (_Control == QUIT)\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t//nldebug(\"active, leave sleep, test assert\");\n\n\t\t\t\t// If this assert occured, it means that a checked part of the code was\n\t\t\t\t// to slow and then I decided to assert to display the problem.\n\t\t\t\tnlassert(!(_Control==ACTIVE && _Counter==lastCounter));\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid activate()\n\t{\n\t\tif(_Control == QUIT) return;\n\t\tnlassert(_Control == INACTIVE);\n\t\t_Counter++;\n\t\t_Control = ACTIVE;\n\t\t//nldebug(\"activate\");\n\t}\n\n\tvoid deactivate()\n\t{\n\t\tif(_Control == QUIT) return;\n\t\tnlassert(_Control == ACTIVE);\n\t\t_Control = INACTIVE;\n\t\t//nldebug(\"deactivate\");\n\t}\n\n\tvoid quit()\n\t{\n\t\tnlassert(_Control != QUIT);\n\t\t_Control = QUIT;\n\t\t//nldebug(\"quit\");\n\t}\n\n\tvoid timeout(uint32 to)\n\t{\n\t\t_Timeout = to;\n\t\t//nldebug(\"change timeout to %d\", to);\n\t}\n\nprivate:\n\tvolatile TControl\t_Control;\n\tvolatile uint32\t\t_Counter;\n\tvolatile uint32\t\t_Timeout;\t// in millisecond\n};\n\n\n#endif // NL_TIMEOUT_ASSERTION_THREAD_H\n\n/* End of timeout_assertion_thread.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/traits_nl.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TRAITS_H\n#define NL_TRAITS_H\n\n\n#include \"rgba.h\"\n#include \"vector.h\"\n\nnamespace NLMISC\n{\n\n/** Class that gives information about a type. Useful to do some optimization in templates functions / class\n  * This class is intended to be specialized and taylored for each type of interest\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  */\ntemplate <class T>\nstruct CTraits\n{\n\tenum { HasTrivialCtor = false };     // if true, the default ctor does nothing useful (example  : built-in types or Plain Old Datas structs)\n\tenum { HasTrivialDtor = false };     // the dtor does nothing useful and is not worth calling. Useful to optimize containers clean-up\n\tenum { SupportRawCopy = false };     // the object supports raw copy with memcpy\n\t// to be completed ..\n};\n\n\n#define NL_TRIVIAL_TYPE_TRAITS(type)     \\\ntemplate <>\t\t\t\t\t\t\t\t \\\nstruct CTraits<type>                     \\\n{                                        \\\n\tenum { HasTrivialCtor = true };      \\\n\tenum { HasTrivialDtor = true };      \\\n\tenum { SupportRawCopy = true };      \\\n};\n\n// integral types\nNL_TRIVIAL_TYPE_TRAITS(bool);\n#ifdef NL_COMP_VC6\nNL_TRIVIAL_TYPE_TRAITS(sint8);\nNL_TRIVIAL_TYPE_TRAITS(uint8);\n#endif // NL_COMP_VC6\nNL_TRIVIAL_TYPE_TRAITS(sint16);\nNL_TRIVIAL_TYPE_TRAITS(uint16);\nNL_TRIVIAL_TYPE_TRAITS(sint32);\nNL_TRIVIAL_TYPE_TRAITS(uint32);\nNL_TRIVIAL_TYPE_TRAITS(sint64);\nNL_TRIVIAL_TYPE_TRAITS(uint64);\n#ifdef NL_COMP_VC6\nNL_TRIVIAL_TYPE_TRAITS(sint);\nNL_TRIVIAL_TYPE_TRAITS(uint);\n#endif // NL_COMP_VC6\n\n// characters\nNL_TRIVIAL_TYPE_TRAITS(char);\nNL_TRIVIAL_TYPE_TRAITS(unsigned char);\n\n// numeric types\nNL_TRIVIAL_TYPE_TRAITS(float);\nNL_TRIVIAL_TYPE_TRAITS(double);\n\n// misc\nNL_TRIVIAL_TYPE_TRAITS(CVector);\nNL_TRIVIAL_TYPE_TRAITS(CRGBA);\n\n//.. to be completed\n\n} // NLMISC\n\n#endif\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/triangle.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TRIANGLE_H\n#define NL_TRIANGLE_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n\nnamespace NLMISC\n{\n\tclass CPlane;\n\tclass CMatrix;\n}\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * A simple triangles of 3 points.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CTriangle\n{\npublic:\n\tCVector\t\tV0,V1,V2;\n\npublic:\n\t/// Constructor\n\tCTriangle() {}\n\t/// Constructor\n\tCTriangle(const CVector &a, const CVector &b, const CVector &c) : V0(a), V1(b), V2(c) {}\n\n\t/**\n\t  *  Intersection detection with a segment. You must pass the normalized plane of the triangle as parameter.\n\t  *\n\t  *  \\param p0 is the first point of the segment.\n\t  *  \\param p1 is the second point of the segment.\n\t  *  \\param hit will receive the coordinate of the intersection if the method returns true.\n\t  *  \\param plane is the plane of the triangle. Build it like this:\n\t  *  \\code\n\t  *  CPlane plane;\n\t  *  plane.make (triangle.V0, triangle.V1, triangle.V2);\n\t  *  \\endcode\n\t  *  \\return true if the segement [p0,p1] intersects the triangle else false.\n\t  */\n\tbool intersect (const CVector& p0, const CVector& p1, CVector& hit, const class NLMISC::CPlane& plane) const;\n\n\t/** 3D Gradient computation.\n\t * Given 3 values at the 3 corners 'ci' (gouraud, uv....), this method compute the gradients Grad.\n\t * The formula to compute the interpolated value according to a 3d position 'v' in space is then simply: \\n\n\t *\tc(v)= c0 + grad*(v-V0)\n\t */\n\tvoid\tcomputeGradient(float c0, float c1, float c2, CVector &grad) const;\n\n\t// transform triangle\n\tvoid\tapplyMatrix(const CMatrix &m, CTriangle &dest) const;\n\t// compute the minimal corner of this triangle\n\tinline void getMinCorner(NLMISC::CVector &dest) const;\n\t// compute the minimal corner of this triangle\n\tinline void getMaxCorner(NLMISC::CVector &dest) const;\n};\n\n\n\n// inlines\ninline void\tCTriangle::getMinCorner(NLMISC::CVector &dest) const\n{\n\tdest.set(minof(V0.x, V1.x, V2.x),\n\t\t\t minof(V0.y, V1.y, V2.y),\n\t\t\t minof(V0.z, V1.z, V2.z));\n}\n\ninline void\tCTriangle::getMaxCorner(NLMISC::CVector &dest) const\n{\n\tdest.set(maxof(V0.x, V1.x, V2.x),\n\t\t\t maxof(V0.y, V1.y, V2.y),\n\t\t\t maxof(V0.z, V1.z, V2.z));\n}\n\n\n\n} // NLMISC\n\n\n#endif // NL_TRIANGLE_H\n\n/* End of triangle.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/twin_map.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TWIN_MAP_H\n#define NL_TWIN_MAP_H\n\n#include \"nel/misc/debug.h\"\n#include <map>\n\nnamespace NLMISC\n{\n\n\n/** Bidirectionnal association between values\n  * Behaves like a map, but key can be used as value and vice-versa\n  *\n  * Association must be bijective or assertions are raised\n  *\n  *\n  * Example of use :\n  *\n  * CTwinMap<string, int>  tm;\n  * tm.add(\"foo\", 1);\n  * tm.add(\"bar\", 2);\n  * tm.add(\"foorbar\", 3);\n  * tm.get(\"foo\");\t\t // returns 1\n  * tm.get(1);\t\t\t // returns \"foo\"\n  * tm.remove(1);\t\t // removes (\"foo\", 1) couple\n  * tm.remove(\"bar\")\t // removes (\"bar\", 2) couple\n  * tm.add(\"foobar\", 4); // assert !\n  * tm.add(\"foo\", 3);    // assrt! (3 associated with foobar)\n  *\n  * \\author Nicolas Vizerie\n  * \\author Nevrax France\n  * \\date 2004\n  */\ntemplate <class TypeA, class TypeB>\nclass CTwinMap\n{\npublic:\n\ttypedef std::map<TypeA, TypeB> TAToBMap;\n\ttypedef std::map<TypeB, TypeA> TBToAMap;\npublic:\n\t// add a couple in the twin map. An assertion is raised if either valueA or valueB were already present in the map\n\tinline void\t\t\tadd(const TypeA &valueA, const TypeB &valueB);\n\t// retrieves value of type 'TypeB' associated with 'valueA', or NULL if not found\n\tinline const TypeA *getA(const TypeB &valueB) const;\n\t// retrieves value of type 'TypeB' associated with 'valueA', or NULL if not found\n\tinline const TypeB *getB(const TypeA &valueA) const;\n\t// removes a couple from its TypeA value\n\tinline void\t\t\tremoveWithA(const TypeA &valueA);\n\t// removes a couple from its TypeB value\n\tinline void\t\t\tremoveWithB(const TypeB &valueB);\n\t// Direct read access to 'TypeA to TypeB' map\n\tconst TAToBMap\t   &getAToBMap() const { return _AToB; }\n\t// Direct read access to 'TypeB to TypeA' map\n\tconst TBToAMap\t   &getBToAMap() const { return _BToA; }\n\t// clear the twin map\n\tinline\tvoid\t\tclear();\n\nprivate:\n\tTAToBMap _AToB;\n\tTBToAMap _BToA;\n};\n\n////////////////////\n// IMPLEMENTATION //\n////////////////////\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline void\tCTwinMap<TypeA, TypeB>::clear()\n{\n\t_AToB.clear();\n\t_BToA.clear();\n}\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline void\tCTwinMap<TypeA, TypeB>::add(const TypeA &valueA, const TypeB &valueB)\n{\n\tnlassert(!getB(valueA));\n\tnlassert(!getA(valueB));\n\t_AToB[valueA] = valueB;\n\t_BToA[valueB] = valueA;\n}\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline const TypeA *CTwinMap<TypeA, TypeB>::getA(const TypeB &valueB) const\n{\n\ttypename TBToAMap::const_iterator it = _BToA.find(valueB);\n\tif (it == _BToA.end()) return NULL;\n\telse return &(it->second);\n}\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline const TypeB *CTwinMap<TypeA, TypeB>::getB(const TypeA &valueA) const\n{\n\ttypename TAToBMap::const_iterator it = _AToB.find(valueA);\n\tif (it == _AToB.end()) return NULL;\n\telse return &(it->second);\n}\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline void\tCTwinMap<TypeA, TypeB>::removeWithA(const TypeA &valueA)\n{\n\ttypename TAToBMap::iterator itA = _AToB.find(valueA);\n\tnlassert(itA != _AToB.end());\n\ttypename TBToAMap::iterator itB = _BToA.find(itA->second);\n\tnlassert(itB != _BToA.end());\n\t_AToB.erase(itA);\n\t_BToA.erase(itB);\n}\n\n//==================================================================================================\ntemplate <class TypeA, class TypeB>\ninline void\tCTwinMap<TypeA, TypeB>::removeWithB(const TypeB &valueB)\n{\n\ttypename TBToAMap::iterator itB = _BToA.find(valueB);\n\tnlassert(itB != _BToA.end());\n\ttypename TAToBMap::iterator itA = _AToB.find(itB->second);\n\tnlassert(itA != _AToB.end());\n\t_AToB.erase(itA);\n\t_BToA.erase(itB);\n}\n\n\n\n} // NLMISC\n\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/types_nl.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TYPES_H\n#define NL_TYPES_H\n\n// Wrapper for the clib time function\n#define nl_time time\n#define nl_mktime mktime\n#define nl_gmtime gmtime\n#define nl_localtime localtime\n#define nl_difftime difftime\n\n// nelconfig.h inclusion, file generated by autoconf\n#ifdef HAVE_NELCONFIG_H\n#\tinclude \"nelconfig.h\"\n#endif // HAVE_NELCONFIG_H\n\n#ifdef FINAL_VERSION\n\t// If the FINAL_VERSION is defined externally, check that the value is 0 or 1\n#\tif FINAL_VERSION != 1 && FINAL_VERSION != 0\n#\t\terror \"Bad value for FINAL_VERSION, it must be 0 or 1\"\n#\tendif\n#else\n\t// If you want to compile in final version just put 1 instead of 0\n\t// WARNING: never comment this #define\n#\tdefine FINAL_VERSION 0\n#endif // FINAL_VERSION\n\n// This way we know about _HAS_TR1 and _STLPORT_VERSION\n#include <string>\n\n// Operating systems definition\n#ifdef _WIN32\n#\tdefine NL_OS_WINDOWS\n#\tdefine NL_LITTLE_ENDIAN\n#\tdefine NL_CPU_INTEL\n#\tifndef _WIN32_WINNT\n#\t\tdefine _WIN32_WINNT 0x0500\t// Minimal OS = Windows 2000 (NeL is not supported on Windows 95/98)\n#\tendif\n#\tifdef _MSC_VER\n#\t\tdefine NL_COMP_VC\n#\t\tif _MSC_VER >= 1800\n#\t\t\tdefine NL_COMP_VC12\n#\t\t\tdefine NL_COMP_VC_VERSION 120\n#\t\telif _MSC_VER >= 1700\n#\t\t\tdefine NL_COMP_VC11\n#\t\t\tdefine NL_COMP_VC_VERSION 110\n#\t\telif _MSC_VER >= 1600\n#\t\t\tdefine NL_COMP_VC10\n#\t\t\tdefine NL_COMP_VC_VERSION 100\n#\t\telif _MSC_VER >= 1500\n#\t\t\tdefine NL_COMP_VC9\n#\t\t\tdefine NL_COMP_VC_VERSION 90\n#\t\telif _MSC_VER >= 1400\n#\t\t\tdefine NL_COMP_VC8\n#\t\t\tdefine NL_COMP_VC_VERSION 80\n#\t\t\tundef nl_time\n#\t\t\tdefine nl_time _time32\t\t// use the old 32 bit time function\n#\t\t\tundef nl_mktime\n#\t\t\tdefine nl_mktime _mktime32\t// use the old 32 bit time function\n#\t\t\tundef nl_gmtime\n#\t\t\tdefine nl_gmtime _gmtime32\t// use the old 32 bit time function\n#\t\t\tundef nl_localtime\n#\t\t\tdefine nl_localtime _localtime32\t// use the old 32 bit time function\n#\t\t\tundef nl_difftime\n#\t\t\tdefine nl_difftime _difftime32\t// use the old 32 bit time function\n#\t\telif _MSC_VER >= 1310\n#\t\t\tdefine NL_COMP_VC71\n#\t\t\tdefine NL_COMP_VC_VERSION 71\n#\t\telif _MSC_VER >= 1300\n#\t\t\tdefine NL_COMP_VC7\n#\t\t\tdefine NL_COMP_VC_VERSION 70\n#\t\telif _MSC_VER >= 1200\n#\t\t\tdefine NL_COMP_VC6\n#\t\t\tdefine NL_COMP_VC_VERSION 60\n#\t\t\tdefine NL_COMP_NEED_PARAM_ON_METHOD\n#\t\tendif\n#\telif defined(__MINGW32__)\n#\t\tdefine NL_COMP_MINGW\n#\t\tdefine NL_COMP_GCC\n#\t\tdefine NL_NO_ASM\n#\tendif\n#\tif defined(_HAS_TR1) && (_HAS_TR1 + 0) // VC9 TR1 feature pack or later\n#\t\tdefine NL_ISO_STDTR1_AVAILABLE\n#\t\tdefine NL_ISO_STDTR1_HEADER(header) <header>\n#\t\tdefine NL_ISO_STDTR1_NAMESPACE std::tr1\n#\tendif\n#\tifdef _DEBUG\n#\t\tifndef NL_DEBUG\n#\t\t\tdefine NL_DEBUG\n#\t\tendif\n#\telif defined (NDEBUG)\n#\t\tifndef NL_RELEASE\n#\t\t\tdefine NL_RELEASE\n#\t\tendif\n#\telse\n#\t\terror \"Don't know the compilation mode\"\n#\tendif\n#\tifdef _WIN64\n#\t\tdefine NL_OS_WIN64\n#\t\tifndef NL_NO_ASM\n\t\t\t// Windows 64bits platform SDK compilers doesn't support inline assembler\n#\t\t\tdefine NL_NO_ASM\n#\t\tendif\n#\t\tundef _WIN32_WINNT\n#\t\tdefine _WIN32_WINNT 0x0600 // force VISTA minimal version in 64 bits\n#\tendif\n\t// define NOMINMAX to be sure that windows includes will not define min max macros, but instead, use the stl template\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#else\n#\tifdef __APPLE__\n#\t\tdefine NL_OS_MAC\n#\t\tifdef __BIG_ENDIAN__\n#\t\t\tdefine NL_BIG_ENDIAN\n#\t\telif defined(__LITTLE_ENDIAN__)\n#\t\t\tdefine NL_LITTLE_ENDIAN\n#\t\telse\n#\t\t\terror \"Cannot detect the endianness of this Mac\"\n#\t\tendif\n#\telse\n#\t\tifdef WORDS_BIGENDIAN\n#\t\t\tdefine NL_BIG_ENDIAN\n#\t\telse\n#\t\t\tdefine NL_LITTLE_ENDIAN\n#\t\tendif\n#\tendif\n// these define are set the GNU/Linux and Mac OS\n#\tdefine NL_OS_UNIX\n\n#   ifdef __FreeBSD__\n#       define NL_OS_FREEBSD\n#   endif\n\n#   ifdef __clang__\n#       define NL_COMP_CLANG\n#   else\n#\t    define NL_COMP_GCC\n#   endif\n#endif\n\n#if defined(_HAS_CPP0X) || defined(__GXX_EXPERIMENTAL_CXX0X__)\n#\tdefine NL_ISO_CPP0X_AVAILABLE\n#endif\n\n// gcc 3.4 introduced ISO C++ with tough template rules\n//\n// NL_ISO_SYNTAX can be used using #if NL_ISO_SYNTAX or #if !NL_ISO_SYNTAX\n//\n// NL_ISO_TEMPLATE_SPEC can be used in front of an instanciated class-template member data definition,\n// because sometimes MSVC++ 6 produces an error C2908 with a definition with template <>.\n#if defined(NL_COMP_VC) || (defined(__GNUC__) && ((__GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)))\n#\tdefine NL_ISO_SYNTAX 0\n#\tdefine NL_ISO_TEMPLATE_SPEC\n#else\n#\tdefine NL_ISO_SYNTAX 1\n#\tdefine NL_ISO_TEMPLATE_SPEC template <>\n#endif\n\n#ifdef NL_COMP_CLANG\n//#\t\tdefine NL_ISO_STDTR1_AVAILABLE\n//#\t\tdefine NL_ISO_STDTR1_HEADER(header) <header>\n#endif\n\n// gcc 4.1+ provides std::tr1\n#ifdef NL_COMP_GCC\n#\tdefine GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)\n#\tif GCC_VERSION > 40100\n\t\t// new libc++ bundled with clang under Mac OS X 10.9+ doesn't define __GLIBCXX__\n#\t\tifdef __GLIBCXX__\n#\t\t\tdefine NL_ISO_STDTR1_AVAILABLE\n#\t\t\tdefine NL_ISO_STDTR1_HEADER(header) <tr1/header>\n#\t\t\tdefine NL_ISO_STDTR1_NAMESPACE std::tr1\n#\t\telse\n#\t\t\tdefine NL_ISO_STDTR1_AVAILABLE\n#\t\t\tdefine NL_ISO_STDTR1_HEADER(header) <header>\n#\t\t\tdefine NL_ISO_STDTR1_NAMESPACE std\n#\t\tendif\n#\tendif\n#endif\n\n// Remove stupid Visual C++ warnings\n#ifdef NL_OS_WINDOWS\n#\tpragma warning (disable : 4503)\t\t\t// STL: Decorated name length exceeded, name was truncated\n#\tpragma warning (disable : 4786)\t\t\t// STL: too long identifier\n#\tpragma warning (disable : 4290)\t\t\t// throw() not implemented warning\n#\tpragma warning (disable : 4250)\t\t\t// inherits via dominance (informational warning).\n#\tpragma warning (disable : 4390)\t\t\t// don't warn in empty block \"if(exp) ;\"\n#\tpragma warning (disable : 4996)\t\t\t// 'vsnprintf': This function or variable may be unsafe. Consider using vsnprintf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.\n// Debug : Sept 01 2006\n#\tif defined(NL_COMP_VC8) || defined(NL_COMP_VC9) || defined(NL_COMP_VC10)\n#\t\tpragma warning (disable : 4005)\t\t\t// don't warn on redefinitions caused by xp platform sdk\n#\tendif // NL_COMP_VC8 || NL_COMP_VC9\n#endif // NL_OS_WINDOWS\n\n\n// Standard include\n\n#include <string>\n#include <exception>\n\n// Setup extern asm functions.\n\n#ifndef NL_NO_ASM\t\t\t\t\t\t\t// If NL_NO_ASM is externely defined, don't override it.\n#\tifndef NL_CPU_INTEL\t\t\t\t\t\t// If not on an Intel compatible plateforme (BeOS, 0x86 Linux, Windows)\n#\t\tdefine NL_NO_ASM\t\t\t\t\t\t// Don't use extern ASM. Full C++ code.\n#\tendif // NL_CPU_INTEL\n#endif // NL_NO_ASM\n\n\n// Define this if you want to use GTK for gtk_displayer\n\n//#define NL_USE_GTK\n//#undef NL_USE_GTK\n\n// Define this if you want to remove all assert, debug code...\n// You should never need to define this since it's always good to have assert, even in release mode\n\n//#define NL_NO_DEBUG\n#undef NL_NO_DEBUG\n\n\n// Standard types\n\n/*\n * correct numeric types:\tsint8, uint8, sint16, uint16, sint32, uint32, sint64, uint64, sint, uint\n * correct char types:\t\tchar, string, ucchar, ucstring\n * correct misc types:\t\tvoid, bool, float, double\n *\n */\n\n/**\n * \\typedef uint8\n * An unsigned 8 bits integer (use char only as \\b character and not as integer)\n **/\n\n/**\n * \\typedef sint8\n * An signed 8 bits integer (use char only as \\b character and not as integer)\n */\n\n/**\n * \\typedef uint16\n * An unsigned 16 bits integer (don't use short)\n **/\n\n/**\n * \\typedef sint16\n * An signed 16 bits integer (don't use short)\n */\n\n/**\n * \\typedef uint32\n * An unsigned 32 bits integer (don't use int or long)\n **/\n\n/**\n * \\typedef sint32\n * An signed 32 bits integer (don't use int or long)\n */\n\n/**\n * \\typedef uint64\n * An unsigned 64 bits integer (don't use long long or __int64)\n **/\n\n/**\n * \\typedef sint64\n * An signed 64 bits integer (don't use long long or __int64)\n */\n\n/**\n * \\typedef uint\n * An unsigned integer, at least 32 bits (used only for internal loops or speedy purpose, processor dependent)\n **/\n\n/**\n * \\typedef sint\n * An signed integer at least 32 bits (used only for internal loops or speedy purpose, processor dependent)\n */\n\n/**\n * \\def NL_I64\n * Used to display a int64 in a platform independent way with printf like functions.\n \\code\n sint64 myint64 = SINT64_CONSTANT(0x123456781234);\n printf(\"This is a 64 bits int: %\" NL_I64 \"u\", myint64);\n \\endcode\n */\n\n#ifdef NL_OS_WINDOWS\n\ntypedef\tsigned\t\t__int8\t\tsint8;\ntypedef\tunsigned\t__int8\t\tuint8;\ntypedef\tsigned\t\t__int16\t\tsint16;\ntypedef\tunsigned\t__int16\t\tuint16;\ntypedef\tsigned\t\t__int32\t\tsint32;\ntypedef\tunsigned\t__int32\t\tuint32;\ntypedef\tsigned\t\t__int64\t\tsint64;\ntypedef\tunsigned\t__int64\t\tuint64;\n\ntypedef\t\t\t\tint\t\t\tsint;\t\t\t// at least 32bits (depend of processor)\ntypedef\tunsigned\tint\t\t\tuint;\t\t\t// at least 32bits (depend of processor)\n\n//#define\tNL_I64 \"I64\"\n#define\tNL_I64 \"ll\"\n\n#elif defined (NL_OS_UNIX)\n\n#include <sys/types.h>\n#include <stdint.h>\n#include <climits>\n\ntypedef\tint8_t\t\tsint8;\ntypedef\tuint8_t\t\tuint8;\ntypedef\tint16_t\t\tsint16;\ntypedef\tuint16_t\tuint16;\ntypedef\tint32_t\t\tsint32;\ntypedef\tuint32_t\tuint32;\ntypedef\tint64_t\t\tsint64;\ntypedef\tuint64_t\tuint64;\n\ntypedef\t\t\t\tint\t\t\tsint;\t\t\t// at least 32bits (depend of processor)\ntypedef\tunsigned\tint\t\t\tuint;\t\t\t// at least 32bits (depend of processor)\n\n// used for macro PRI*64\n#define __STDC_FORMAT_MACROS\n#include <inttypes.h>\n\n#if defined(__PRI_64_LENGTH_MODIFIER__)\n#\tdefine NL_I64 __PRI_64_LENGTH_MODIFIER__\n#elif defined(__PRI64_PREFIX)\n#\tdefine NL_I64 __PRI64_PREFIX\n#else\n#\tifdef _LP64\n#\t\tdefine\tNL_I64 \"l\"\n#\telse\n#\t\tdefine\tNL_I64 \"ll\"\n#\tendif // _LP64\n#endif\n\n#endif // NL_OS_UNIX\n\n\n// #ifdef NL_ENABLE_FORCE_INLINE\n#\tifdef NL_COMP_VC\n#\t\tdefine NL_FORCE_INLINE __forceinline\n#\telif defined(NL_COMP_GCC)\n#\t\tdefine NL_FORCE_INLINE inline __attribute__((always_inline))\n#\telse\n#\t\tdefine NL_FORCE_INLINE inline\n#\tendif\n// #else\n// #\tdefine NL_FORCE_INLINE inline\n// #endif\n\n\n#ifdef NL_COMP_VC\n#define NL_ALIGN(nb) __declspec(align(nb))\n#else\n#define NL_ALIGN(nb) __attribute__((aligned(nb)))\n#endif\n\n#ifdef NL_OS_WINDOWS\n#include <stdlib.h>\n#include <intrin.h>\n#include <malloc.h>\ninline void *aligned_malloc(size_t size, size_t alignment) { return _aligned_malloc(size, alignment); }\ninline void aligned_free(void *ptr) { _aligned_free(ptr); }\n#elif defined(NL_OS_MAC)\n// under Mac OS X, malloc is already aligned for SSE and Altivec (16 bytes alignment)\ninline void *aligned_malloc(size_t size, size_t alignment) { return malloc(size); }\ninline void aligned_free(void *ptr) { free(ptr); }\n#elif defined(NL_OS_FREEBSD)\n#include <stdlib.h>\ninline void *aligned_malloc(size_t size, size_t alignment)\n{\n    void *buf;\n    posix_memalign(&buf,alignment,size); \n    return buf;\n}\ninline void aligned_free(void *ptr) { free(ptr); }\n#else\n#include <malloc.h>\ninline void *aligned_malloc(size_t size, size_t alignment) { return memalign(alignment, size); }\ninline void aligned_free(void *ptr) { free(ptr); }\n#endif /* NL_COMP_ */\n\n\n#ifdef NL_HAS_SSE2\n\n#define NL_DEFAULT_MEMORY_ALIGNMENT 16\n#define NL_ALIGN_SSE2 NL_ALIGN(NL_DEFAULT_MEMORY_ALIGNMENT)\n\nextern void *operator new(size_t size) throw(std::bad_alloc);\nextern void *operator new[](size_t size) throw(std::bad_alloc);\nextern void operator delete(void *p) throw();\nextern void operator delete[](void *p) throw();\n\n#else /* NL_HAS_SSE2 */\n\n#define NL_DEFAULT_MEMORY_ALIGNMENT 4\n#define NL_ALIGN_SSE2\n\n#endif /* NL_HAS_SSE2 */\n\n\n// CHashMap, CHashSet and CHashMultiMap definitions\n#if defined(_STLPORT_VERSION) // STLport detected\n#\tinclude <hash_map>\n#\tinclude <hash_set>\n#\tifdef _STLP_HASH_MAP\n#\t\tdefine CHashMap ::std::hash_map\n#\t\tdefine CHashSet ::std::hash_set\n#\t\tdefine CHashMultiMap ::std::hash_multimap\n#\tendif // _STLP_HASH_MAP\n#elif defined(NL_ISO_STDTR1_AVAILABLE) // use std::tr1 for CHash* classes, if available (gcc 4.1+ and VC9 with TR1 feature pack)\n#\tinclude NL_ISO_STDTR1_HEADER(unordered_map)\n#\tinclude NL_ISO_STDTR1_HEADER(unordered_set)\n#\tdefine CHashMap NL_ISO_STDTR1_NAMESPACE::unordered_map\n#\tdefine CHashSet NL_ISO_STDTR1_NAMESPACE::unordered_set\n#\tdefine CHashMultiMap NL_ISO_STDTR1_NAMESPACE::unordered_multimap\n#elif defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 70 && NL_COMP_VC_VERSION <= 110) // VC7 through 9\n#\tinclude <hash_map>\n#\tinclude <hash_set>\n#\tdefine CHashMap stdext::hash_map\n#\tdefine CHashSet stdext::hash_set\n#\tdefine CHashMultiMap stdext::hash_multimap\n#elif defined(NL_COMP_VC) && (NL_COMP_VC_VERSION >= 120)\n#\tinclude <unordered_map>\n#\tinclude <unordered_set>\n#\tdefine CHashMap std::unordered_map\n#\tdefine CHashSet std::unordered_set\n#\tdefine CHashMultiMap std::unordered_multimap\n#elif defined(NL_COMP_GCC) // GCC4\n#\tinclude <ext/hash_map>\n#\tinclude <ext/hash_set>\n#\tdefine CHashMap ::__gnu_cxx::hash_map\n#\tdefine CHashSet ::__gnu_cxx::hash_set\n#\tdefine CHashMultiMap ::__gnu_cxx::hash_multimap\n\nnamespace __gnu_cxx {\n\ntemplate<> struct hash<std::string>\n{\n\tsize_t operator()(const std::string &s) const\n\t{\n\t\treturn __stl_hash_string(s.c_str());\n\t}\n};\n\ntemplate<> struct hash<uint64>\n{\n\tsize_t operator()(const uint64 x) const\n\t{\n\t\treturn x;\n\t}\n};\n\n} // END NAMESPACE __GNU_CXX\n#elif defined(NL_COMP_CLANG)\n#\tinclude <unordered_map>\n#\tinclude <unordered_set>\n#\tdefine CHashMap std::unordered_map\n#\tdefine CHashSet std::unordered_set\n#\tdefine CHashMultiMap std::unordered_multimap\n#else\n#\tpragma error(\"You need to update your compiler\")\n#endif // _STLPORT_VERSION\n\n/**\n * \\typedef ucchar\n * An Unicode character (16 bits)\n */\ntypedef\tuint16\tucchar;\n\n\n// To define a 64bits constant; ie: UINT64_CONSTANT(0x123456781234)\n#ifdef NL_COMP_VC\n#\tif (NL_COMP_VC_VERSION >= 120)\n#\t\tdefine INT64_CONSTANT(c)\t\t(c##LL)\n#\t\tdefine SINT64_CONSTANT(c)\t(c##LL)\n#\t\tdefine UINT64_CONSTANT(c)\t(c##ULL)\n#\telif (NL_COMP_VC_VERSION >= 80)\n#\t\tdefine INT64_CONSTANT(c)\t(c##LL)\n#\t\tdefine SINT64_CONSTANT(c)\t(c##LL)\n#\t\tdefine UINT64_CONSTANT(c)\t(c##LL)\n#\telse\n#\t\tdefine INT64_CONSTANT(c)\t(c)\n#\t\tdefine SINT64_CONSTANT(c)\t(c)\n#\t\tdefine UINT64_CONSTANT(c)\t(c)\n#\tendif\n#else\n#\tdefine INT64_CONSTANT(c)\t\t(c##LL)\n#\tdefine SINT64_CONSTANT(c)\t(c##LL)\n#\tdefine UINT64_CONSTANT(c)\t(c##ULL)\n#endif\n\n// Define a macro to write template function according to compiler weakness\n#ifdef NL_COMP_NEED_PARAM_ON_METHOD\n#\tdefine NL_TMPL_PARAM_ON_METHOD_1(p1)\t<p1>\n#\tdefine NL_TMPL_PARAM_ON_METHOD_2(p1, p2)\t<p1, p2>\n#else\n#\tdefine NL_TMPL_PARAM_ON_METHOD_1(p1)\n#\tdefine NL_TMPL_PARAM_ON_METHOD_2(p1, p2)\n#endif\n\n#if !defined(MAX_PATH) && !defined(NL_OS_WINDOWS)\n#\tdefine MAX_PATH 255\n#endif\n\n#ifdef NL_DEBUG\nconst std::string nlMode(\"NL_DEBUG\");\n#else\nconst std::string nlMode(\"NL_RELEASE\");\n#endif\n\n// Sanity checks\n#if defined (NL_DEBUG) && defined (NL_RELEASE)\n#\terror \"NeL cannot be configured for debug and release in the same time\"\n#endif\n#if !defined (NL_DEBUG) && !defined (NL_RELEASE)\n#\terror \"NeL must be configured for debug or release\"\n#endif\n#ifdef NL_RELEASE_DEBUG\n#\terror \"NL_RELEASE_DEBUG doesn't exist anymore, please remove it\"\n#endif\n#ifdef NL_DEBUG_FAST\n#\terror \"NL_DEBUG_FAST doesn't exist anymore, please remove it\"\n#endif\n\n#endif // NL_TYPES_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/ucstring.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UCSTRING_H\n#define NL_UCSTRING_H\n\n#include \"types_nl.h\"\n#include \"debug.h\"\n\n#include <string>\n\n/**\n * \\typedef ucstring\n * An unicode string class (16 bits per character).\n * Add features to convert and assign \\c ucstring to \\c string and \\c string to \\c ucstring.\n */\ntypedef std::basic_string<ucchar> ucstringbase;\n\nclass ucstring : public ucstringbase\n{\npublic:\n\n\tucstring () {}\n\n\tucstring (const ucstringbase &str) : ucstringbase (str) {}\n\n\tucstring (const std::string &str) : ucstringbase ()\n\t{\n\t\trawCopy(str);\n\t}\n\n\t~ucstring () {}\n\n\tucstring &operator= (ucchar c)\n\t{\n\t\tresize (1);\n\t\toperator[](0) = c;\n\t\treturn *this;\n\t}\n\n\tucstring &operator= (const char *str)\n\t{\n\t\tresize (strlen (str));\n\t\tfor (uint i = 0; i < strlen (str); i++)\n\t\t{\n\t\t\toperator[](i) = uint8(str[i]);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tucstring &operator= (const std::string &str)\n\t{\n\t\tresize (str.size ());\n\t\tfor (uint i = 0; i < str.size (); i++)\n\t\t{\n\t\t\toperator[](i) = uint8(str[i]);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tucstring &operator= (const ucstringbase &str)\n\t{\n\t\tucstringbase::operator =(str);\n\t\treturn *this;\n\t}\n\n\tucstring& operator= (const ucchar *str)\n\t{\n\t\tucstringbase::operator =(str);\n\t\treturn *this;\n\t}\n\tucstring &operator+= (ucchar c)\n\t{\n\t\tresize (size() + 1);\n\t\toperator[](size()-1) = c;\n\t\treturn *this;\n\t}\n\n\tucstring &operator+= (const char *str)\n\t{\n\t\tsize_t s = size();\n\t\tresize (s + strlen(str));\n\t\tfor (uint i = 0; i < strlen(str); i++)\n\t\t{\n\t\t\toperator[](s+i) = uint8(str[i]);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tucstring &operator+= (const std::string &str)\n\t{\n\t\tsize_t s = size();\n\t\tresize (s + str.size());\n\t\tfor (uint i = 0; i < str.size(); i++)\n\t\t{\n\t\t\toperator[](s+i) = uint8(str[i]);\n\t\t}\n\t\treturn *this;\n\t}\n\n\tucstring &operator+= (const ucstringbase &str)\n\t{\n\t\tucstringbase::operator +=(str);\n\t\treturn *this;\n\t}\n\n\tconst ucchar *c_str() const\n\t{\n\t\tconst ucchar *tmp = ucstringbase::c_str();\n\t\tconst_cast<ucchar*>(tmp)[size()] = 0;\n\t\treturn tmp;\n\t}\n\n\t/// Converts the controlled ucstring to a string str\n\tvoid toString (std::string &str) const\n\t{\n\t\tstr.resize (size ());\n\t\tfor (uint i = 0; i < str.size (); i++)\n\t\t{\n\t\t\tif (operator[](i) > 255)\n\t\t\t\tstr[i] = '?';\n\t\t\telse\n\t\t\t\tstr[i] = (char) operator[](i);\n\t\t}\n\t}\n\n\t/// Converts the controlled ucstring and returns the resulting string\n\tstd::string toString () const\n\t{\n\t\tstd::string str;\n\t\ttoString(str);\n\t\treturn str;\n\t}\n\n\t/// Convert this ucstring (16bits char) into a utf8 string\n\tstd::string toUtf8() const\n\t{\n\t\tstd::string\tres;\n\t\tucstring::const_iterator first(begin()), last(end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\t//ucchar\tc = *first;\n\t\t\tuint nbLoop = 0;\n\t\t\tif (*first < 0x80)\n\t\t\t\tres += char(*first);\n\t\t\telse if (*first < 0x800)\n\t\t\t{\n\t\t\t\tucchar c = *first;\n\t\t\t\tc = c >> 6;\n\t\t\t\tc = c & 0x1F;\n\t\t\t\tres += char(c) | 0xC0;\n\t\t\t\tnbLoop = 1;\n\t\t\t}\n\t\t\telse /*if (*first < 0x10000)*/\n\t\t\t{\n\t\t\t\tucchar c = *first;\n\t\t\t\tc = c >> 12;\n\t\t\t\tc = c & 0x0F;\n\t\t\t\tres += char(c) | 0xE0;\n\t\t\t\tnbLoop = 2;\n\t\t\t}\n\n\t\t\tfor (uint i=0; i<nbLoop; ++i)\n\t\t\t{\n\t\t\t\tucchar\tc = *first;\n\t\t\t\tc = c >> ((nbLoop - i - 1) * 6);\n\t\t\t\tc = c & 0x3F;\n\t\t\t\tres += char(c) | 0x80;\n\t\t\t}\n\t\t}\n\t\treturn res;\n\t}\n\n\tucstring substr(size_type pos = 0, size_type n = npos) const\n\t{\n\t\treturn ucstringbase::substr(pos, n);\n\t}\n\n\t// for luabind (can't bind to 'substr' else ...)\n\tucstring luabind_substr(size_type pos = 0, size_type n = npos) const\n\t{\n\t\treturn ucstringbase::substr(pos, n);\n\t}\n\n\t/// Convert the utf8 string into this ucstring (16 bits char)\n\tvoid fromUtf8(const std::string &stringUtf8)\n\t{\n\t\t// clear the string\n\t\terase();\n\n\t\tuint8 c;\n\t\tucchar code;\n\t\tsint iterations = 0;\n\n\t\tstd::string::const_iterator first(stringUtf8.begin()), last(stringUtf8.end());\n\t\tfor (; first != last; )\n\t\t{\n\t\t\tc = *first++;\n\t\t\tcode = c;\n\n\t\t\tif ((code & 0xFE) == 0xFC)\n\t\t\t{\n\t\t\t\tcode &= 0x01;\n\t\t\t\titerations = 5;\n\t\t\t}\n\t\t\telse if ((code & 0xFC) == 0xF8)\n\t\t\t{\n\t\t\t\tcode &= 0x03;\n\t\t\t\titerations = 4;\n\t\t\t}\n\t\t\telse if ((code & 0xF8) == 0xF0)\n\t\t\t{\n\t\t\t\tcode &= 0x07;\n\t\t\t\titerations = 3;\n\t\t\t}\n\t\t\telse if ((code & 0xF0) == 0xE0)\n\t\t\t{\n\t\t\t\tcode &= 0x0F;\n\t\t\t\titerations = 2;\n\t\t\t}\n\t\t\telse if ((code & 0xE0) == 0xC0)\n\t\t\t{\n\t\t\t\tcode &= 0x1F;\n\t\t\t\titerations = 1;\n\t\t\t}\n\t\t\telse if ((code & 0x80) == 0x80)\n\t\t\t{\n\t\t\t\t// If it's not a valid UTF8 string, just copy the line without utf8 conversion\n\t\t\t\trawCopy(stringUtf8);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpush_back(code);\n\t\t\t\titerations = 0;\n\t\t\t}\n\n\t\t\tif (iterations)\n\t\t\t{\n\t\t\t\tfor (sint i = 0; i < iterations; i++)\n\t\t\t\t{\n\t\t\t\t\tif (first == last)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If it's not a valid UTF8 string, just copy the line without utf8 conversion\n\t\t\t\t\t\trawCopy(stringUtf8);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tuint8 ch;\n\t\t\t\t\tch = *first ++;\n\n\t\t\t\t\tif ((ch & 0xC0) != 0x80)\n\t\t\t\t\t{\n\t\t\t\t\t\t// If it's not a valid UTF8 string, just copy the line without utf8 conversion\n\t\t\t\t\t\trawCopy(stringUtf8);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tcode <<= 6;\n\t\t\t\t\tcode |= (ucchar)(ch & 0x3F);\n\t\t\t\t}\n\t\t\t\tpush_back(code);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic ucstring makeFromUtf8(const std::string &stringUtf8)\n\t{\n\t\tucstring ret;\n\t\tret.fromUtf8(stringUtf8);\n\n\t\treturn ret;\n\t}\n\nprivate:\n\n\tvoid rawCopy(const std::string &str)\n\t{\n\t\t// We need to convert the char into 8bits unsigned int before promotion to 16 bits\n\t\t// otherwise, as char are signed on some compiler (MSCV for ex), the sign bit is extended to 16 bits.\n\t\tresize(str.size());\n\t\tstd::string::const_iterator first(str.begin()), last(str.end());\n\t\titerator dest(begin());\n\t\tfor (;first != last; ++first, ++dest)\n\t\t{\n\t\t\t*dest = uint8(*first);\n\t\t}\n\t}\n};\n\ninline ucstring operator+(const ucstringbase &ucstr, ucchar c)\n{\n\tucstring\tret;\n\tret= ucstr;\n\tret+= c;\n\treturn ret;\n}\n\ninline ucstring operator+(const ucstringbase &ucstr, const char *c)\n{\n\tucstring\tret;\n\tret= ucstr;\n\tret+= c;\n\treturn ret;\n}\n\ninline ucstring operator+(const ucstringbase &ucstr, const std::string &c)\n{\n\tucstring\tret;\n\tret= ucstr;\n\tret+= c;\n\treturn ret;\n}\n\ninline ucstring operator+(ucchar c, const ucstringbase &ucstr)\n{\n\tucstring\tret;\n\tret= c;\n\tret += ucstr;\n\treturn ret;\n}\n\ninline ucstring operator+(const char *c, const ucstringbase &ucstr)\n{\n\tucstring\tret;\n\tret= c;\n\tret += ucstr;\n\treturn ret;\n}\n\ninline ucstring operator+(const std::string &c, const ucstringbase &ucstr)\n{\n\tucstring\tret;\n\tret= c;\n\tret += ucstr;\n\treturn ret;\n}\n\nnamespace NLMISC\n{\n\n// Traits for hash_map using CEntityId\nstruct CUCStringHashMapTraits\n{\n\tenum { bucket_size = 4, min_buckets = 8, };\n\tCUCStringHashMapTraits() { }\n\tsize_t operator() (const ucstring &id ) const\n\t{\n\t\treturn id.size();\n\t}\n\tbool operator() (const ucstring &id1, const ucstring &id2) const\n\t{\n\t\treturn id1.size() < id2.size();\n\t}\n};\n\n/** Convert an unicode string in lower case.\n * Characters with accent are converted in a lowercase character with accent\n * \\param a string or a char to transform to lower case\n */\n\nucstring\ttoLower (const ucstring &str);\nvoid\t\ttoLower (ucchar *str);\nucchar\t\ttoLower (ucchar c);\n\n/** Convert an unicode string in upper case.\n * Characters with accent are converted in a uppercase character without accent\n * \\param a string or a char to transform to upper case\n */\n\nucstring\ttoUpper (const ucstring &str);\nvoid\t\ttoUpper (ucchar *str);\nucchar\t\ttoUpper (ucchar c);\n\n};\n\n#endif // NL_UCSTRING_H\n"
  },
  {
    "path": "code/nel/include/nel/misc/uv.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UV_H\n#define NL_UV_H\n\n#include \"types_nl.h\"\n#include \"stream.h\"\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * 2d UV.\n *\n */\n/* *** IMPORTANT ********************\n * *** IF YOU MODIFY THE STRUCTURE OF THIS CLASS, PLEASE INCREMENT IDriver::InterfaceVersion TO INVALIDATE OLD DRIVER DLL\n * **********************************\n */\nclass\tCUV\n{\npublic:\n\tfloat\tU,V;\n\npublic:\n\tCUV() {}\n\tCUV(float u, float v) : U(u), V(v) {}\n\t// modify uv's\n\tvoid set(float u, float v) { U = u; V = v; }\n\t// bin operators.\n\tCUV\toperator+(const CUV &v) const\n\t\t{ return CUV(U+v.U, V+v.V);}\n\t// binary -\n\tCUV\toperator-(const CUV &v) const\n\t\t{ return CUV(U-v.U, V-v.V);}\n\t// unary -\n\tCUV operator-() const\n\t\t{ return CUV(-U, -V); }\n\t// = operators.\n\tCUV\t&operator*=(float f)\n\t\t{ U*=f;V*=f; return *this;}\n\tCUV\t&operator+=(const CUV &v)\n\t\t{ U+=v.U;V+=v.V; return *this;}\n\tCUV\t&operator-=(const CUV &v)\n\t\t{ U-=v.U;V-=v.V; return *this;}\n\t/// This operator is here just for map/set insertion (no meaning). comparison order is U,V.\n\tbool\toperator<(const CUV &o) const\n\t{\n\t\tif(U!=o.U)\n\t\t\treturn U<o.U;\n\t\treturn V<o.V;\n\t}\n\tbool\toperator==(const CUV &c) const {return (U==c.U) && (V==c.V);}\n\tbool\toperator!=(const CUV &c) const {return !(*this==c);}\n\n\tvoid\tserial(NLMISC::IStream &f)\t{f.serial(U,V);}\n};\n\n\ninline CUV operator * (float f, const CUV &uv)\n{\n\treturn CUV(uv.U * f, uv.V * f);\n}\n\n\ninline CUV operator * (const CUV &uv, float f)\n{\n\treturn f * uv;\n}\n\n// blend (faster version than the generic version found in algo.h)\ninline CUV blend(const CUV &uv0, const CUV &uv1, float lambda)\n{\n\tfloat invLambda = 1.f - lambda;\n\treturn CUV(invLambda * uv0.U + lambda * uv1.U,\n\t\t       invLambda * uv0.V + lambda * uv1.V);\n\n}\n\n\n\n// ***************************************************************************\n/**\n * 3d UV.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass\tCUVW\n{\npublic:\n\tfloat\tU,V,W;\n\npublic:\n\tCUVW() {}\n\tCUVW(float u, float v, float w) : U(u), V(v), W(w) {}\n\t// bin operators.\n\tCUVW\toperator+(const CUVW &v) const\n\t\t{ return CUVW(U+v.U, V+v.V, W+v.W);}\n\tCUVW\toperator-(const CUVW &v) const\n\t\t{ return CUVW(U-v.U, V-v.V, W-v.W);}\n\tCUVW\toperator*(float f) const\n\t\t{ return CUVW(U*f, V*f, W*f);}\n\t// = operators.\n\tCUVW\t&operator*=(float f)\n\t\t{ U*=f;V*=f; W*=f; return *this;}\n\tCUVW\t&operator+=(const CUVW &v)\n\t\t{ U+=v.U;V+=v.V; W+=v.W; return *this;}\n\tCUVW\t&operator-=(const CUVW &v)\n\t\t{ U-=v.U;V-=v.V; W-=v.W; return *this;}\n\t/// This operator is here just for map/set insertion (no meaning). comparison order is U,V.\n\tbool\toperator<(const CUVW &o) const\n\t{\n\t\tif(U!=o.U)\n\t\t\treturn U<o.U;\n\t\tif(V!=o.V)\n\t\t\treturn V<o.V;\n\t\treturn W<o.W;\n\t}\n\tbool\toperator==(const CUVW &c) const {return (U==c.U) && (V==c.V) && (W==c.W);}\n\tbool\toperator!=(const CUVW &c) const {return !(*this==c);}\n\n\tvoid\tserial(NLMISC::IStream &f)\t{f.serial(U,V,W);}\n\n\t// Convert to a standard UV. The W coordinate is lost of course..\n\toperator CUV() const { return CUV(U, V); }\n};\n\n\n} // NLMISC\n\n\n#endif // NL_UV_H\n\n/* End of uv.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/value_smoother.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VALUE_SMOOTHER_H\n#define NL_VALUE_SMOOTHER_H\n\n#include \"types_nl.h\"\n\n#include <vector>\n\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n/**\n * A smoother of values.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\ntemplate <class T>\nclass CValueSmootherTemplate\n{\npublic:\n\n\t/// Constructor\n\texplicit CValueSmootherTemplate(uint n=16)\n\t{\n\t\tinit(n);\n\t}\n\n\t/// reset the ValueSmoother, and set the number of frame to smooth.\n\tvoid\t\tinit(uint n)\n\t{\n\t\t// reset all the array to 0.\n\t\t_LastFrames.clear();\n\n\t\tif (n > 0)\n\t\t\t_LastFrames.resize(n, 0);\n\n\t\t_CurFrame = 0;\n\t\t_NumFrame = 0;\n\t\t_FrameSum = 0;\n\t\t_CurrentValue = 0;\n\t}\n\n\t/// reset only the ValueSmoother\n\tvoid\t\treset()\n\t{\n\t\tstd::fill(_LastFrames.begin(), _LastFrames.end(), T(0));\n\n\t\t_CurFrame = 0;\n\t\t_NumFrame = 0;\n\t\t_FrameSum = 0;\n\t\t_CurrentValue = 0;\n\t}\n\n\t/// add a new value to be smoothed.\n\tvoid\t\taddValue(T dt)\n\t{\n\t\tif (_LastFrames.empty())\n\t\t\treturn;\n\n\t\t// update the frame sum. NB: see init(), at start, array is full of 0. so it works even for un-inited values.\n\t\t_FrameSum-= _LastFrames[_CurFrame];\n\t\t_FrameSum+= dt;\n\n\t\t// backup this value in the array.\n\t\t_LastFrames[_CurFrame]= dt;\n\t\t_CurrentValue = dt;\n\n\t\t// next frame.\n\t\t_CurFrame++;\n//\t\t_CurFrame%=_LastFrames.size();\n\t\tif (_CurFrame >= _LastFrames.size())\n\t\t\t_CurFrame -= (uint)_LastFrames.size();\n\n\t\t// update the number of frames added.\n\t\t_NumFrame++;\n\t\t_NumFrame= (std::min)(_NumFrame, (uint)_LastFrames.size());\n\t}\n\n\t/// get the smoothed value.\n\tT\t\tgetSmoothValue() const\n\t{\n\t\tif(_NumFrame>0)\n\t\t\treturn T(_FrameSum) / T(_NumFrame);\n\t\telse\n\t\t\treturn T(0);\n\t}\n\n\tT\t\tgetCurrentValue() const\n\t{\n\t\tif (_NumFrame>0)\n\t\t\treturn T(_CurrentValue);\n\t\telse\n\t\t\treturn T(0);\n\t}\n\n\tuint getNumFrame() const\n\t{\n\t\treturn _NumFrame;\n\t}\n\n\tuint getCurrentFrame() const\n\t{\n\t\treturn _CurFrame;\n\t}\n\n\tconst std::vector<T> &getLastFrames() const\n\t{\n\t\treturn _LastFrames;\n\t}\n\nprivate:\n\tstd::vector<T>\t\t\t_LastFrames;\n\tuint\t\t\t\t\t_CurFrame;\n\tuint\t\t\t\t\t_NumFrame;\n\tT\t\t\t\t\t\t_FrameSum;\n\tT\t\t\t\t\t\t_CurrentValue;\n};\n\n// ***************************************************************************\n/**\n * A smoother replacement for boolean.\n * \\author Boris Boucher\n * \\author Nevrax France\n * \\date 2003\n */\ntemplate <>\nclass CValueSmootherTemplate<bool>\n{\npublic:\n\n\t/// Constructor\n\texplicit CValueSmootherTemplate(uint n=1)\n\t{\n\t\tinit(n);\n\t}\n\n\t/// reset the ValueSmoother, and set the number of frame to smooth.\n\tvoid\t\tinit(uint n)\n\t{\n\t\t// reset all the array to 0.\n\t\t_LastFrames.clear();\n\n\t\tif (n>0)\n\t\t\t_LastFrames.resize(n, false);\n\n\t\t_NumFrame = 0;\n\t}\n\n\t/// reset only the ValueSmoother\n\tvoid\t\treset()\n\t{\n\t\tstd::fill(_LastFrames.begin(), _LastFrames.end(), false);\n \t\t_NumFrame = 0;\n\t}\n\n\t/// add a new value to be smoothed.\n\tvoid\t\taddValue(bool dt)\n\t{\n\t\tif(_NumFrame>0)\n\t\t\t_LastFrames[0] = dt;\n\t}\n\n\t/// get the smoothed value.\n\tbool\t\tgetSmoothValue() const\n\t{\n\t\tif(_NumFrame>0)\n\t\t\treturn _LastFrames[0];\n\t\telse\n\t\t\treturn false;\n\t}\n\n\tuint getNumFrame() const\n\t{\n\t\treturn _NumFrame;\n\t}\n\n\tuint getCurrentFrame() const\n\t{\n\t\treturn 0;\n\t}\n\n\tconst std::vector<bool> &getLastFrames() const\n\t{\n\t\treturn _LastFrames;\n\t}\n\nprivate:\n\tstd::vector<bool>       _LastFrames;\n\tuint            \t\t_NumFrame;\n};\n\nclass CValueSmoother : public CValueSmootherTemplate<float>\n{\npublic:\n\t/// Constructor\n\texplicit CValueSmoother(uint n=16) : CValueSmootherTemplate<float>(n)\n\t{\n\t}\n};\n\n} // NLMISC\n\n\n#endif // NL_VALUE_SMOOTHER_H\n\n/* End of value_smoother.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/variable.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VARIABLE_H\n#define NL_VARIABLE_H\n\n#include \"types_nl.h\"\n#include \"command.h\"\n#include \"value_smoother.h\"\n#include \"sstring.h\"\n\n\nnamespace NLMISC {\n\n/** WARNING:\n *   This is POSIX C/C++ linker behavior: object files\n *   that are not referenced from outside are discarded. The\n *   file in which you run your constructor is thus simply\n *   thrown away by the linker, which explains why the constructor\n *   is not run.\n */\n\n\n/**\n * Add a variable that can be modified in realtime. The variable must be global. If you must access the variable with\n * function, use NLMISC_DYNVARIABLE\n *\n * Example:\n * \\code\n\t// I want to look and change the variable 'foobar' in realtime, so, first i create it:\n\tuint8 foobar;\n\t// and then, I add it\n\tNLMISC_VARIABLE(uint8, FooBar, \"this is a dummy variable\");\n * \\endcode\n *\n * Please use the same casing than for the variable (first letter of each word in upper case)\n * ie: MyVariable, NetSpeedLoop, Time\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\n#define NLMISC_VARIABLE(__type,__var,__help) NLMISC_CATEGORISED_VARIABLE(variables,__type,__var,__help)\n#define NLMISC_CATEGORISED_VARIABLE(__category,__type,__var,__help) \\\nNLMISC::CVariablePtr<__type> __var##Instance(#__category,#__var, __help \" (\" #__type \")\", &__var)\n\n\n\n/**\n * Add a variable that can be modified in realtime. The code profide the way to access to the variable in the read\n * and write access (depending on the \\c get boolean value)\n *\n * Example:\n * \\code\n\t// a function to read the variable\n\tuint8 getVar() { return ...; }\n\n\t// a function to write the variable\n\tvoid setVar(uint8 val) { ...=val; }\n\n\t// I want to look and change the variable in realtime:\n\tNLMISC_DYNVARIABLE(uint8, FooBar, \"this is a dummy variable\")\n\t{\n\t\t// read or write the variable\n\t\tif (get)\n\t\t\t*pointer = getVar();\n\t\telse\n\t\t\tsetVar(*pointer);\n\t}\n * \\endcode\n *\n * Please use the same casing than for the variable (first letter of each word in upper case)\n * ie: MyVariable, NetSpeedLoop, Time\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\n#define NLMISC_DYNVARIABLE(__type,__name,__help) NLMISC_CATEGORISED_DYNVARIABLE(variables,__type,__name,__help)\n#define NLMISC_CATEGORISED_DYNVARIABLE(__category,__type,__name,__help) \\\nclass __name##Class : public NLMISC::IVariable \\\n{ \\\npublic: \\\n\t__name##Class () : IVariable(#__category, #__name, __help) { } \\\n\t \\\n\tvirtual bool fromString(const std::string &val, bool human=false) \\\n\t{ \\\n\t\t/*std::stringstream ss (val);*/ \\\n\t\t__type p; \\\n\t\t/*ss >> p;*/ \\\n\t\tbool ret = NLMISC::fromString(val, p) ; \\\n\t\tptr (&p, false, human); \\\n\t\treturn ret; \\\n\t} \\\n\t \\\n\tvirtual std::string toString(bool human) const \\\n\t{ \\\n\t\t__type p; \\\n\t\tptr (&p, true, human); \\\n\t\t/*std::stringstream ss;*/ \\\n\t\t/*ss << p;*/ \\\n\t\t/*return ss.str();*/ \\\n\t\treturn NLMISC::toString(p); \\\n\t} \\\n\t\\\n\tvoid ptr(__type *pointer, bool get, bool human) const; \\\n}; \\\n__name##Class __name##Instance; \\\nvoid __name##Class::ptr(__type *pointer, bool get, bool human) const\n\n/** Helper to declare a variable as friend of a class.\n *\tUseful when you want to declare variable that need to access private data to act on or display internal state of the class\n */\n\n#define NLMISC_DYNVARIABLE_FRIEND(__name) NLMISC_CATEGORISED_DYNVARIABLE_FRIEND(variables, __name)\n#define NLMISC_CATEGORISED_DYNVARIABLE_FRIEND(__category, __name) friend class __name##Class\n\n//\n//\n//\n//\n\nclass IVariable : public ICommand\n{\n\tfriend class CCommandRegistry;\npublic:\n\n\tIVariable(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs = \"[<value>]\", bool useConfigFile = false, void (*cc)(IVariable &var)=NULL) :\n\t\tICommand(categoryName,commandName, commandHelp, commandArgs), _UseConfigFile(useConfigFile), ChangeCallback(cc)\n\t{\n\t\tType = Variable;\n\t}\n\n\tvirtual bool fromString(const std::string &val, bool human=false) = 0;\n\n\tvirtual std::string toString(bool human=false) const = 0;\n\n\tvirtual bool execute(const std::string &/* rawCommandString */, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\t{\n\t\tif (args.size() > 1)\n\t\t\treturn false;\n\n\t\tif (args.size() == 1)\n\t\t{\n\t\t\t// set the value\n\t\t\tfromString (args[0], human);\n\t\t}\n\n\t\t// display the value\n\t\tif (quiet)\n\t\t{\n\t\t\tlog.displayNL(toString(human).c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog.displayNL(\"Variable %s = %s\", _CommandName.c_str(), toString(human).c_str());\n\t\t}\n\t\treturn true;\n\t}\n\n\tstatic void init (CConfigFile &configFile);\n\nprivate:\n\n\tbool _UseConfigFile;\n\nprotected:\n\n\t// TODO: replace by interface (see IVariableChangedCallback)\n\tvoid (*ChangeCallback)(IVariable &var);\n\n};\n\n\n\n\ntemplate <class T>\nclass CVariablePtr : public IVariable\n{\npublic:\n\n\tCVariablePtr (const char *categoryName, const char *commandName, const char *commandHelp, T *valueptr, bool useConfigFile = false, void (*cc)(IVariable &var)=NULL) :\n\t\tIVariable (categoryName, commandName, commandHelp, \"[<value>]\", useConfigFile, cc), _ValuePtr(valueptr)\n\t{\n\t}\n\n\tvirtual bool fromString (const std::string &val, bool /* human */=false)\n\t{\n\t\t//std::stringstream ss (val);\n\t\t//ss >> *_ValuePtr;\n\t\tbool ret = NLMISC::fromString(val, *_ValuePtr);\n\t\tif (ChangeCallback) ChangeCallback (*this);\n\t\treturn ret;\n\t}\n\n\tvirtual std::string toString (bool /* human */) const\n\t{\n\t\t//std::stringstream ss;\n\t\t//ss << *_ValuePtr;\n\t\t//return ss.str();\n\t\treturn NLMISC::toString(*_ValuePtr);\n\t}\n\nprivate:\n\n\tT *_ValuePtr;\n};\n\n\ntemplate <class T>\nclass CVariable : public IVariable\n\t{\npublic:\n\n\tCVariable (\tconst char *categoryName,\n\t\t\t\tconst char *commandName,\n\t\t\t\tconst char *commandHelp,\n\t\t\t\tconst T &defaultValue,\n\t\t\t\tuint nbMeanValue = 0,\n\t\t\t\tbool useConfigFile = false,\n\t\t\t\tvoid (*cc)(IVariable &var)=NULL,\n\t\t\t\tbool executeCallbackForDefaultValue=false ) :\n\t\tIVariable (categoryName, commandName, commandHelp, \"[<value>|stat|mean|min|max]\", useConfigFile, cc), _Mean(nbMeanValue), _First(true)\n\t{\n\t\tset (defaultValue, executeCallbackForDefaultValue);\n\t}\n\n\tvirtual bool fromString (const std::string &val, bool /* human */=false)\n\t{\n\t\tT v;\n\t\tbool ret = NLMISC::fromString(val, v);\n//\t\tstd::stringstream ss (val);\n//\t\tss >> v;\n\t\tset (v);\n\t\treturn ret;\n\t}\n\n\tvirtual std::string toString (bool /* human */) const\n\t{\n\t\treturn NLMISC::toString(_Value);\n//\t\tstd::stringstream ss;\n//\t\tss << _Value;\n//\t\treturn ss.str();\n\t}\n\n\tCVariable<T> &operator= (const T &val)\n\t{\n\t\tset (val);\n\t\treturn *this;\n\t}\n\n\toperator T () const\n\t{\n\t\treturn get ();\n\t}\n\n\tvoid set (const T &val, bool executeCallback = true)\n\t{\n\t\t_Value = val;\n\t\t_Mean.addValue (_Value);\n\t\tif (_First)\n\t\t{\n\t\t\t_First = false;\n\t\t\t_Min = _Value;\n\t\t\t_Max = _Value;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_Value > _Max) _Max = _Value;\n\t\t\tif (_Value < _Min) _Min = _Value;\n\t\t}\n\t\tif (ChangeCallback && executeCallback) ChangeCallback (*this);\n\t}\n\n\tconst T &get () const\n\t{\n\t\treturn _Value;\n\t}\n\n\tstd::string getStat (bool light = false) const\n\t{\n\t\tCSString str;\n\t\tstr << _CommandName << \"=\" << _Value << \" Min=\" << _Min;\n\t\tif (_Mean.getNumFrame()>0)\n\t\t{\n\t\t\tconst std::vector<T>& v = _Mean.getLastFrames();\n\t\t\tT theMin = *std::min_element(v.begin(), v.end());\n\t\t\tstr << \" RecentMin=\" << theMin;\n\t\t}\n\t\tstr << \" Max=\" << _Max;\n\t\tif (_Mean.getNumFrame()>0)\n\t\t{\n\t\t\tconst std::vector<T>& v = _Mean.getLastFrames();\n\t\t\tT theMax = *std::max_element(v.begin(), v.end());\n\t\t\tstr << \" RecentMax=\" << theMax;\n\t\t}\n\t\tif (_Mean.getNumFrame()>0)\n\t\t{\n\t\t\tstr << \" RecentMean=\" << _Mean.getSmoothValue();\n\t\t\tif(!light)\n\t\t\t{\n\t\t\t\tstr << \" RecentValues=\";\n\t\t\t\t// output the oldest part of the buffer first\n\t\t\t\tfor (uint i=_Mean.getCurrentFrame(); i<_Mean.getNumFrame(); ++i)\n\t\t\t\t{\n\t\t\t\t\tstr << (T)_Mean.getLastFrames()[i];\n\t\t\t\t\tif (i < _Mean.getNumFrame()-1 || _Mean.getCurrentFrame() != 0)\n\t\t\t\t\t\tstr << \",\";\n\t\t\t\t}\n\t\t\t\t// then output the newest part\n\t\t\t\tfor (uint i = 0; i < _Mean.getCurrentFrame(); i++)\n\t\t\t\t{\n\t\t\t\t\tstr << (T)_Mean.getLastFrames()[i];\n\t\t\t\t\tif (i < _Mean.getCurrentFrame()-1)\n\t\t\t\t\t\tstr << \",\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn str;\n\t}\n\n\tvirtual bool execute (const std::string &/* rawCommandString */, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\t{\n\t\tif (args.size() > 1)\n\t\t\treturn false;\n\n\t\tbool haveVal=false;\n\t\tstd::string val;\n\n\t\tif (args.size() == 1)\n\t\t{\n\t\t\tif (args[0] == \"stat\")\n\t\t\t{\n\t\t\t\t// display the stat value\n\t\t\t\tstd::string stat = getStat();\n\t\t\t\t// cut the stat line in lines of 80 chars\n\t\t\t\tstd::string::size_type pos = 0;\n\t\t\t\twhile (pos < stat.size())\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(getStat().substr(pos, 80).c_str());\n\t\t\t\t\tpos += 80;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse if (args[0] == \"mean\")\n\t\t\t{\n\t\t\t\thaveVal = true;\n\t\t\t\tval = NLMISC::toString(_Mean.getSmoothValue());\n\t\t\t}\n\t\t\telse if (args[0] == \"min\")\n\t\t\t{\n\t\t\t\thaveVal = true;\n\t\t\t\tval = NLMISC::toString(_Min);\n\t\t\t}\n\t\t\telse if (args[0] == \"max\")\n\t\t\t{\n\t\t\t\thaveVal = true;\n\t\t\t\tval = NLMISC::toString(_Max);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// set the value\n\t\t\t\tfromString (args[0], human);\n\t\t\t}\n\t\t}\n\n\t\t// display the value\n\t\tif (!haveVal)\n\t\t{\n\t\t\tval = toString(human);\n\t\t}\n\n\t\tif (quiet)\n\t\t{\n\t\t\tlog.displayNL(val.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog.displayNL(\"Variable %s = %s\", _CommandName.c_str(), val.c_str());\n\t\t}\n\t\treturn true;\n\t}\n\nprivate:\n\n\tT _Value;\n\tCValueSmootherTemplate<T> _Mean;\n\tT _Min, _Max;\n\tbool _First;\n};\n\ntemplate<> class CVariable<std::string> : public IVariable\n{\npublic:\n\n\tCVariable (const char *categoryName, const char *commandName, const char *commandHelp, const std::string &defaultValue, uint /* nbMeanValue */ = 0, bool useConfigFile = false, void (*cc)(IVariable &/* var */)=NULL, bool executeCallbackForDefaultValue=false) :\n\t\tIVariable (categoryName, commandName, commandHelp, \"[<value>]\", useConfigFile, cc)\n\t{\n\t\tset (defaultValue, executeCallbackForDefaultValue);\n\t}\n\n\tvirtual bool fromString (const std::string &val, bool /* human */=false)\n\t{\n\t\tset (val);\n\t\treturn true;\n\t}\n\n\tvirtual std::string toString (bool /* human */=false) const\n\t{\n\t\treturn _Value;\n\t}\n\n\tCVariable<std::string> &operator= (const std::string &val)\n\t{\n\t\tset (val);\n\t\treturn *this;\n\t}\n\n\toperator std::string () const\n\t{\n\t\treturn get();\n\t}\n\n\toperator const char * () const\n\t{\n\t\treturn get().c_str();\n\t}\n\n\tconst char *c_str () const\n\t{\n\t\treturn get().c_str();\n\t}\n\n\tvoid set (const std::string &val, bool executeCallback = true)\n\t{\n\t\t_Value = val;\n\t\tstatic bool RecurseSet = false;\n\t\tif (ChangeCallback && !RecurseSet && executeCallback)\n\t\t{\n\t\t\tRecurseSet = true;\n\t\t\tChangeCallback(*this);\n\t\t\tRecurseSet = false;\n\t\t}\n\t}\n\n\tconst std::string &get () const\n\t{\n\t\treturn _Value;\n\t}\n\n\tvirtual bool execute (const std::string &/* rawCommandString */, const std::vector<std::string> &args, NLMISC::CLog &log, bool quiet, bool human)\n\t{\n\t\tif (args.size () > 1)\n\t\t\treturn false;\n\n\t\tif (args.size () == 1)\n\t\t{\n\t\t\t// set the value\n\t\t\tfromString (args[0], human);\n\t\t}\n\n\t\t// convert the string from utf-8 to ascii (thrue unicode)\n\t\tucstring temp;\n\t\ttemp.fromUtf8(toString(human));\n\t\tstd::string disp = temp.toString();\n\t\t// display the value\n\t\tif (quiet)\n\t\t{\n\t\t\tlog.displayNL (disp.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog.displayNL (\"Variable %s = %s\", _CommandName.c_str(), disp.c_str());\n\t\t}\n\t\treturn true;\n\t}\n\nprivate:\n\n\tstd::string _Value;\n};\n\n\n/// This class can provide a callback called when the value of a variable has been changed\nclass IVariableChangedCallback\n{\npublic:\n\tvirtual ~IVariableChangedCallback() {}\n\tvirtual void onVariableChanged(NLMISC::IVariable& var) = 0;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_VARIABLE_H\n\n/* End of variable.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vector.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VECTOR_H\n#define NL_VECTOR_H\n\n#include \"types_nl.h\"\n\n#include <cmath>\n#include <string>\n\n#include \"stream.h\"\n\nnamespace\tNLMISC\n{\n\nclass IStream;\n\n// ======================================================================================================\n/**\n * A 3D vector of float.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CVector\n{\npublic:\t\t// Attributes.\n\tfloat\tx,y,z;\n\npublic:\t\t// const.\n\t/// Null vector (0,0,0).\n\tstatic const\tCVector\t\tNull;\n\t/// I vector (1,0,0).\n\tstatic const\tCVector\t\tI;\n\t/// J vector (0,1,0).\n\tstatic const\tCVector\t\tJ;\n\t/// K vector (0,0,1).\n\tstatic const\tCVector\t\tK;\n\npublic:\t\t// Methods.\n\t/// @name Object.\n\t//@{\n\t/// Constructor which does nothing.\n\tCVector() {}\n\t/// Constructor .\n\tCVector(float\t_x, float _y, float _z) : x(_x), y(_y), z(_z) {}\n\t/// Copy Constructor.\n\tCVector(const CVector &v) : x(v.x), y(v.y), z(v.z) {}\n\t//@}\n\n\t/// @name Base Maths.\n\t//@{\n\tCVector\t&operator+=(const CVector &v);\n\tCVector\t&operator-=(const CVector &v);\n\tCVector\t&operator*=(float f);\n\tCVector\t&operator/=(float f);\n\tCVector\toperator+(const CVector &v) const;\n\tCVector\toperator-(const CVector &v) const;\n\tCVector\toperator*(float f) const;\n\tCVector\toperator/(float f) const;\n\tCVector\toperator-() const;\n\t//@}\n\n\t/// @name Advanced Maths.\n\t//@{\n\t/// Dot product.\n\tfloat\toperator*(const CVector &v) const;\n\t/** Cross product.\n\t * compute the cross product *this ^ v.\n\t */\n\tCVector\toperator^(const CVector &v) const;\n\t/// Return the norm of the vector.\n\tfloat\tnorm() const;\n\t/// Return the square of the norm of the vector.\n\tfloat\tsqrnorm() const;\n\t/// Normalize the vector.\n\tvoid\tnormalize();\n\t/// Return the vector normalized.\n\tCVector\tnormed() const;\n\t//@}\n\n\t/// @name Misc.\n\t//@{\n\tvoid\tset(float _x, float _y, float _z);\n\tbool\toperator==(const CVector &v) const;\n\tbool\toperator!=(const CVector &v) const;\n\tbool\tisNull() const;\n\t/// This operator is here just for map/set insertion (no meaning). comparison order is x,y,z.\n\tbool\toperator<(const CVector &v) const;\n\t/**\n\t * Setup the vector with spheric coordinates.\n\t * sphericToCartesian(1,0,0) build the I vector  ((1,0,0)).\n\t * the formula is:  \\n\n\t * x= r*cos(theta)*cos(phi) \\n\n\t * y= r*sin(theta)*cos(phi) \\n\n\t * z= r*sin(phi) \\n\n\t * \\sa cartesianToSpheric()\n\t */\n\tvoid\tsphericToCartesian(float r, float theta,float phi);\n\t/**\n\t * Get the spheric coordinates of the vector.\n\t * See sphericToCartesian() to know coordinates conventions.\n\t * \\sa sphericToCartesian()\n\t */\n\tvoid\tcartesianToSpheric(float &r, float &theta,float &phi) const;\n\t/// Set all vector x/y/z as minimum of a/b x/y/z  (respectively).\n\tvoid\tminof(const CVector &a, const CVector &b);\n\t/// Set all vector x/y/z as maximum of a/b x/y/z  (respectively).\n\tvoid\tmaxof(const CVector &a, const CVector &b);\n\t/// serial.\n\tvoid\tserial(IStream &f);\n\t//@}\n\n\t/// Returns the contents as a printable string \"x y z\"\n\t/// undeprecated, use the generic function toString()\n\tstd::string\tasString() const { return toString(); }\n\n\t/// Returns the contents as a printable string \"x y z\"\n\tstd::string\ttoString() const;\n\n\t// friends.\n\tfriend\tCVector\toperator*(float f, const CVector &v0);\n};\n\n// blend (faster version than the generic version found in algo.h)\ninline CVector blend(const CVector &v0, const CVector &v1, float lambda)\n{\n\tfloat invLambda = 1.f - lambda;\n\treturn CVector(invLambda * v0.x + lambda * v1.x,\n\t\t           invLambda * v0.y + lambda * v1.y,\n\t\t\t\t   invLambda * v0.z + lambda * v1.z);\n}\n\n\n}\n\n\n#include \"vector_inline.h\"\n\n\n#endif // NL_VECTOR_H\n\n/* End of vector.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vector_2d.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VECTOR_2D_H\n#define NL_VECTOR_2D_H\n\n#include \"types_nl.h\"\n\n#include <cmath>\n#include <string>\n\n#include \"stream.h\"\n#include \"vector_2f.h\"\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * A 2D vector of double.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CVector2d\n{\npublic:\n\npublic:\t\t// Attributes.\n\tdouble\tx,y;\n\npublic:\t\t// Methods.\n\t/// @name Object.\n\t//@{\n\t/// Constructor which does nothing.\n\tCVector2d() {}\n\t/// Constructor .\n\tCVector2d(double\t_x, double _y) : x(_x), y(_y) {}\n\t/// Copy Constructor.\n\tCVector2d(const CVector2d &v) : x(v.x), y(v.y) {}\n\t/// Constructor with a CVector2f.\n\tCVector2d(const CVector2f &v) : x(v.x), y(v.y) {}\n\n\t//@}\n\n\t/// @name Base Maths.\n\t//@{\n\tCVector2d\t&operator+=(const CVector2d &v)\t\t{x+=v.x; y+=v.y; return *this;}\n\tCVector2d\t&operator-=(const CVector2d &v)\t\t{x-=v.x; y-=v.y; return *this;}\n\tCVector2d\t&operator*=(double f)\t\t\t\t{x*=f; y*=f; return *this;}\n\tCVector2d\t&operator/=(double f)\t\t\t\t{x/=f; y/=f; return *this;}\n\tCVector2d\toperator+(const CVector2d &v) const\t{return CVector2d(x+v.x, y+v.y);}\n\tCVector2d\toperator-(const CVector2d &v) const\t{return CVector2d(x-v.x, y-v.y);}\n\tCVector2d\toperator*(double f) const\t\t\t{return CVector2d(x*f, y*f);}\n\tCVector2d\toperator/(double f) const\t\t\t{return CVector2d(x/f, y/f);}\n\tCVector2d\toperator-() const\t\t\t\t\t{return CVector2d(-x, -y);}\n\t//@}\n\n\t/// @name Advanced Maths.\n\t//@{\n\t/// Dot product.\n\tdouble\toperator*(const CVector2d &v) const\t\t{return x*v.x + y*v.y;}\n\t/// Return the norm of the vector.\n\tdouble\tnorm() const\t\t\t\t\t\t\t{return (double)sqrt(sqrnorm());}\n\t/// Return the square of the norm of the vector.\n\tdouble\tsqrnorm() const\t\t\t\t\t\t\t{return x*x + y*y;}\n\t/// Normalize the vector.\n\tvoid\tnormalize()\n\t{\n\t\tdouble\tf= norm();\n\t\tif(f>0)\n\t\t\t*this/=f;\n\t}\n\t/// Return the vector normalized.\n\tCVector2d\tnormed() const\n\t{\n\t\tCVector2d\tv= *this;\n\t\tv.normalize();\n\t\treturn v;\n\t}\n\t//@}\n\n\t/// @name Misc.\n\t//@{\n\tvoid\tset(double _x, double _y)\t\t\t\t\t{x= _x; y=_y;}\n\tbool\toperator==(const CVector2d &v) const\t{return x==v.x && y==v.y;}\n\tbool\toperator!=(const CVector2d &v) const\t{return !(*this==v);}\n\tbool\tisNull() const\t\t\t\t\t\t\t{return x==0.0f && y==0.0f;}\n\t/// Set all vector x/y/z as minimum of a/b x/y/z  (respectively).\n\tvoid\tminof(const CVector2d &a, const CVector2d &b)\n\t{\n\t\tx= std::min(a.x, b.x);\n\t\ty= std::min(a.y, b.y);\n\t}\n\t/// Set all vector x/y/z as maximum of a/b x/y/z  (respectively).\n\tvoid\tmaxof(const CVector2d &a, const CVector2d &b)\n\t{\n\t\tx= std::max(a.x, b.x);\n\t\ty= std::max(a.y, b.y);\n\t}\n\t/// serial.\n\tvoid\tserial(NLMISC::IStream &f)\t\t\t\t{f.serial(x,y);}\n\t//@}\n\n\t// friends.\n\tfriend\tCVector2d\toperator*(double f, const CVector2d &v0);\n\n};\n\n\ninline\tCVector2d\toperator*(double f, const CVector2d &v)\n{\n\treturn v*f;\n}\n\n\n} // NLMISC\n\n\n#endif // NL_VECTOR_2D_H\n\n/* End of vector_2d.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vector_2f.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VECTOR_2F_H\n#define NL_VECTOR_2F_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n#include <cmath>\n#include \"stream.h\"\n#include <string>\n\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\n/**\n * A 2D vector of float.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CVector2f\n{\npublic:\n\npublic:\t\t// Attributes.\n\tfloat\tx,y;\n\npublic:\t\t// Methods.\n\t/// @name Object.\n\t//@{\n\t/// Constructor which do nothing.\n\tCVector2f() {}\n\t/// Constructor.\n\tCVector2f(float\t_x, float _y) : x(_x), y(_y) {}\n\t/// Copy Constructor.\n\tCVector2f(const CVector2f &v) : x(v.x), y(v.y) {}\n\t/// Constructor that uses the (x,y) coordinates of a CVector.\n\tCVector2f(const CVector &v) : x(v.x), y(v.y) {}\n\t// conversion operator\n\toperator CVector() const { return this->asVector(); }\n\t// convert to a CVector by setting z to 0\n\tCVector  asVector() const { return CVector(x, y, 0); }\n\t//@}\n\n\t/// @name Base Maths.\n\t//@{\n\tCVector2f\t&operator+=(const CVector2f &v)\t\t{x+=v.x; y+=v.y; return *this;}\n\tCVector2f\t&operator-=(const CVector2f &v)\t\t{x-=v.x; y-=v.y; return *this;}\n\tCVector2f\t&operator*=(float f)\t\t\t\t{x*=f; y*=f; return *this;}\n\tCVector2f\t&operator/=(float f)\t\t\t\t{x/=f; y/=f; return *this;}\n\tCVector2f\toperator+(const CVector2f &v) const\t{return CVector2f(x+v.x, y+v.y);}\n\tCVector2f\toperator-(const CVector2f &v) const\t{return CVector2f(x-v.x, y-v.y);}\n\tCVector2f\toperator*(float f) const\t\t\t{return CVector2f(x*f, y*f);}\n\tCVector2f\toperator/(float f) const\t\t\t{return CVector2f(x/f, y/f);}\n\tCVector2f\toperator-() const\t\t\t\t\t{return CVector2f(-x, -y);}\n\t//@}\n\n\t/// @name Advanced Maths.\n\t//@{\n\t/// Dot product.\n\tfloat\toperator*(const CVector2f &v) const\t\t{return x*v.x + y*v.y;}\n\t/// Return the norm of the vector.\n\tfloat\tnorm() const\t\t\t\t\t\t\t{return (float)sqrt(sqrnorm());}\n\t/// Return the square of the norm of the vector.\n\tfloat\tsqrnorm() const\t\t\t\t\t\t\t{return x*x + y*y;}\n\t/// Normalize the vector.\n\tvoid\tnormalize()\n\t{\n\t\tfloat\tf= norm();\n\t\tif(f>0)\n\t\t\t*this/=f;\n\t}\n\t/// Return the vector normalized.\n\tCVector2f\tnormed() const\n\t{\n\t\tCVector2f\tv= *this;\n\t\tv.normalize();\n\t\treturn v;\n\t}\n\t//@}\n\n\t/// @name Misc.\n\t//@{\n\tvoid\tset(float _x, float _y)\t\t\t\t\t{x= _x; y=_y;}\n\tbool\toperator==(const CVector2f &v) const\t{return x==v.x && y==v.y;}\n\tbool\toperator!=(const CVector2f &v) const\t{return !(*this==v);}\n\tbool\tisNull() const\t\t\t\t\t\t\t{return x==0.0f && y==0.0f;}\n\t/// Set all vector x/y/z as minimum of a/b x/y/z  (respectively).\n\tvoid\tminof(const CVector2f &a, const CVector2f &b)\n\t{\n\t\tx= std::min(a.x, b.x);\n\t\ty= std::min(a.y, b.y);\n\t}\n\t/// Set all vector x/y/z as maximum of a/b x/y/z  (respectively).\n\tvoid\tmaxof(const CVector2f &a, const CVector2f &b)\n\t{\n\t\tx= std::max(a.x, b.x);\n\t\ty= std::max(a.y, b.y);\n\t}\n\t/// serial.\n\tvoid\tserial(NLMISC::IStream &f)\t\t\t\t{f.serial(x,y);}\n\t//@}\n\n\t// friends.\n\tfriend\tCVector2f\toperator*(float f, const CVector2f &v0);\n\n\t/// @name Constants\n\t//@{\n\tstatic const CVector2f Null;\n\t//@}\n};\n\n\ninline\tCVector2f\toperator*(float f, const CVector2f &v)\n{\n\treturn v*f;\n}\n\n// for map/set insertion\ninline bool operator < (const CVector2f &lhs, const CVector2f &rhs)\n{\n\treturn (lhs.x != rhs.x) ? lhs.x < rhs.x : lhs.y < rhs.y;\n}\n\n} // NLMISC\n\n\n#endif // NL_VECTOR_2F_H\n\n/* End of vector_2f.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vector_h.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VECTOR_H_H\n#define NL_VECTOR_H_H\n\n#include \"types_nl.h\"\n#include \"vector.h\"\n\n\nnamespace NLMISC {\n\n\n/**\n * Homogeneus vector.\n * A CVectorH has a fourth value, w.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass CVectorH\n{\npublic:\n\n\t/// Attributes\n\tfloat\tx, y, z, w;\n\n\t/// Constructor\n\tCVectorH() {}\n\t/// Constructor .\n\tCVectorH(float\t_x, float _y, float _z, float _w) : x(_x), y(_y), z(_z), w(_w) {}\n\t/// Copy Constructor.\n\tCVectorH(const CVectorH &v) : x(v.x), y(v.y), z(v.z), w(v.w) {}\n\t/// Constructor using a vector\n\tCVectorH(const CVector &v) : x(v.x), y(v.y), z(v.z), w(1.0f) {}\n\n\t/// Set\n\tvoid\tset(float _x, float _y, float _z, float _w)\n\t{\n\t\tx=_x; y=_y; z=_z; w=_w;\n\t}\n\n\t/// Cast operator to a vector (ignoring w)\n\toperator CVector() const\n\t{\n\t\treturn CVector( x, y, z );\n\t}\n\n\n\t/// @name Misc.\n\t//@{\n\tbool\toperator==(const CVectorH &v) const\n\t{\n\t\treturn x==v.x && y==v.y && z==v.z && w==v.w;\n\t}\n\tbool\toperator!=(const CVectorH &v) const\n\t{\n\t\treturn !(*this==v);\n\t}\n\t/// This operator is here just for map/set insertion (no meaning). comparison order is x,y,z,w.\n\tbool\toperator<(const CVectorH &v) const\n\t{\n\t\tif(x!=v.x)\n\t\t\treturn x<v.x;\n\t\tif(y!=v.y)\n\t\t\treturn y<v.y;\n\t\tif(z!=v.z)\n\t\t\treturn z<v.z;\n\t\treturn w<v.w;\n\t}\n\n\t//@}\n\n};\n\n\n} // NLMISC\n\n\n#endif // NL_VECTOR_H_H\n\n/* End of vector_h.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vector_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_VECTOR_INLINE_H\n#define NL_VECTOR_INLINE_H\n\n\n#include \"types_nl.h\"\n#include \"common.h\"\n\n\nnamespace\tNLMISC\n{\n\n\n// ============================================================================================\n// Base Maths.\ninline\tCVector\t&CVector::operator+=(const CVector &v)\n{\n\tx+=v.x;\n\ty+=v.y;\n\tz+=v.z;\n\treturn *this;\n}\ninline\tCVector\t&CVector::operator-=(const CVector &v)\n{\n\tx-=v.x;\n\ty-=v.y;\n\tz-=v.z;\n\treturn *this;\n}\ninline\tCVector\t&CVector::operator*=(float f)\n{\n\tx*=f;\n\ty*=f;\n\tz*=f;\n\treturn *this;\n}\ninline\tCVector\t&CVector::operator/=(float f)\n{\n\treturn *this*= (1.0f/f);\n}\ninline\tCVector\tCVector::operator+(const CVector &v) const\n{\n\tCVector\tret(x+v.x, y+v.y, z+v.z);\n\treturn ret;\n}\ninline\tCVector\tCVector::operator-(const CVector &v) const\n{\n\tCVector\tret(x-v.x, y-v.y, z-v.z);\n\treturn ret;\n}\ninline\tCVector\tCVector::operator*(float f) const\n{\n\tCVector\tret(x*f, y*f, z*f);\n\treturn ret;\n}\ninline\tCVector\tCVector::operator/(float f) const\n{\n\treturn *this*(1.0f/f);\n}\ninline\tCVector\tCVector::operator-() const\n{\n\treturn CVector(-x,-y,-z);\n}\ninline CVector\toperator*(float f, const CVector &v)\n{\n\tCVector\tret(v.x*f, v.y*f, v.z*f);\n\treturn ret;\n}\n\n\n// ============================================================================================\n// Advanced Maths.\ninline\tfloat\tCVector::operator*(const CVector &v) const\n{\n\treturn x*v.x + y*v.y + z*v.z;\n}\ninline\tCVector\tCVector::operator^(const CVector &v) const\n{\n\tCVector\tret;\n\n\tret.x= y*v.z - z*v.y;\n\tret.y= z*v.x - x*v.z;\n\tret.z= x*v.y - y*v.x;\n\n\treturn ret;\n}\ninline\tfloat\tCVector::sqrnorm() const\n{\n\treturn (float)(x*x + y*y + z*z);\n}\ninline\tfloat\tCVector::norm() const\n{\n\treturn (float)sqrt(x*x + y*y + z*z);\n}\ninline\tvoid\tCVector::normalize()\n{\n\tfloat\tn=norm();\n\tif(n)\n\t\t*this/=n;\n}\ninline\tCVector\tCVector::normed() const\n{\n\tCVector\tret;\n\tret= *this;\n\tret.normalize();\n\treturn ret;\n}\n\n\n// ============================================================================================\n// Misc.\ninline\tvoid\tCVector::set(float _x, float _y, float _z)\n{\n\tx=_x; y=_y; z=_z;\n}\ninline\tbool\tCVector::operator==(const CVector &v) const\n{\n\treturn x==v.x && y==v.y && z==v.z;\n}\ninline\tbool\tCVector::operator!=(const CVector &v) const\n{\n\treturn !(*this==v);\n}\ninline\tbool\tCVector::isNull() const\n{\n\treturn *this==CVector::Null;\n}\ninline\tbool\tCVector::operator<(const CVector &v) const\n{\n\tif(x!=v.x)\n\t\treturn x<v.x;\n\tif(y!=v.y)\n\t\treturn y<v.y;\n\treturn z<v.z;\n}\n\ninline\tvoid\tCVector::cartesianToSpheric(float &r, float &theta,float &phi) const\n{\n\tCVector v;\n\n\tr= norm();\n\tv= normed();\n\n\t// phi E [-PI/2 et PI/2]\n\tclamp(v.z, -1.0f, 1.0f);\n\tphi= (float)asin(v.z);\n\n\t// theta [-PI,PI]\n\ttheta= (float)atan2(v.y,v.x);\n}\ninline\tvoid\tCVector::sphericToCartesian(float r, float theta,float phi)\n{\n\tdouble\tct= cos(theta);\n\tdouble\tst= sin(theta);\n\tdouble\tcp= cos(phi);\n\tdouble\tsp= sin(phi);\n\n\tx= (float)(r*ct*cp);\n\ty= (float)(r*st*cp);\n\tz= (float)(r*sp);\n}\ninline\tvoid\tCVector::minof(const CVector &a, const CVector &b)\n{\n\tx= std::min(a.x, b.x);\n\ty= std::min(a.y, b.y);\n\tz= std::min(a.z, b.z);\n}\ninline\tvoid\tCVector::maxof(const CVector &a, const CVector &b)\n{\n\tx= std::max(a.x, b.x);\n\ty= std::max(a.y, b.y);\n\tz= std::max(a.z, b.z);\n}\ninline\tvoid\tCVector::serial(IStream &f)\n{\n\tf.serial(x,y,z);\n}\n\n\n}\n\n\n#endif\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/vectord.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VECTORD_H\n#define NL_VECTORD_H\n\n#include\t<cmath>\n#include\t\"vector.h\"\n\n\nnamespace\tNLMISC\n{\n\n\n// ======================================================================================================\n/**\n * A 3D vector of double.\n * \\author Lionel Berenguier\n * \\author Nevrax France\n * \\date 2000\n */\nclass CVectorD\n{\npublic:\t\t// Attributes.\n\tdouble\tx,y,z;\n\npublic:\t\t// const.\n\t/// Null vector (0,0,0).\n\tstatic const\tCVectorD\t\tNull;\n\t/// I vector (1,0,0).\n\tstatic const\tCVectorD\t\tI;\n\t/// J vector (0,1,0).\n\tstatic const\tCVectorD\t\tJ;\n\t/// K vector (0,0,1).\n\tstatic const\tCVectorD\t\tK;\n\npublic:\t\t// Methods.\n\t/// @name Object.\n\t//@{\n\t/// Constructor which does nothing.\n\tCVectorD() {}\n\t/// Constructor .\n\tCVectorD(double\t_x, double _y, double _z) : x(_x), y(_y), z(_z) {}\n\t/// Constructor with a CVector.\n\tCVectorD(const CVector &v) : x(v.x), y(v.y), z(v.z) {}\n\t/// Copy Constructor.\n\tCVectorD(const CVectorD &v) : x(v.x), y(v.y), z(v.z) {}\n\t//@}\n\n\t/// @name Base Maths.\n\t//@{\n\tCVectorD\t&operator+=(const CVectorD &v);\n\tCVectorD\t&operator-=(const CVectorD &v);\n\tCVectorD\t&operator*=(double f);\n\tCVectorD\t&operator/=(double f);\n\tCVectorD\toperator+(const CVectorD &v) const;\n\tCVectorD\toperator-(const CVectorD &v) const;\n\tCVectorD\toperator*(double f) const;\n\tCVectorD\toperator/(double f) const;\n\tCVectorD\toperator-() const;\n\t//@}\n\n\t/// @name Advanced Maths.\n\t//@{\n\t/// Dot product.\n\tdouble\toperator*(const CVectorD &v) const;\n\t/** Cross product.\n\t * compute the cross product *this ^ v.\n\t */\n\tCVectorD\toperator^(const CVectorD &v) const;\n\t/// Return the norm of the vector.\n\tdouble\tnorm() const;\n\t/// Return the square of the norm of the vector.\n\tdouble\tsqrnorm() const;\n\t/// Normalize the vector.\n\tvoid\tnormalize();\n\t/// Return the vector normalized.\n\tCVectorD\tnormed() const;\n\t//@}\n\n\t/// @name Misc.\n\t//@{\n\tvoid\tset(double _x, double _y, double _z);\n\tbool\toperator==(const CVectorD &v) const;\n\tbool\toperator!=(const CVectorD &v) const;\n\tbool\tisNull() const;\n\t/**\n\t * Setup the vector with spheric coordinates.\n\t * sphericToCartesian(1,0,0) build the I vector  ((1,0,0)).\n\t * the formula is:  \\n\n\t * x= r*cos(theta)*cos(phi) \\n\n\t * y= r*sin(theta)*cos(phi) \\n\n\t * z= r*sin(phi) \\n\n\t * \\sa cartesianToSpheric()\n\t */\n\tvoid\tsphericToCartesian(double r, double theta,double phi);\n\t/**\n\t * Get the sphreic coordinates of the vector.\n\t * See sphericToCartesian() to know coordinates conventions.\n\t * \\sa sphericToCartesian()\n\t */\n\tvoid\tcartesianToSpheric(double &r, double &theta,double &phi) const;\n\tvoid\tserial(IStream &f);\n\tCVectorD &operator=(const CVector &v);\n\toperator CVector() const;\n\t// copy content into a CVector\n\tvoid copyTo(CVector &dest) const;\n\t// conersion to a CVector\n\tCVector asVector() const;\n\t//@}\n\n\t// friends.\n\tfriend\tCVectorD\toperator*(double f, const CVectorD &v0);\n};\n\n\n}\n\n\n#include \"vectord_inline.h\"\n\n\n#endif // NL_VECTOR_H\n\n/* End of vector.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/vectord_inline.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_VECTORD_INLINE_H\n#define NL_VECTORD_INLINE_H\n\n\n#include \"common.h\"\n\n\nnamespace\tNLMISC\n{\n\n\n// ============================================================================================\n// Base Maths.\ninline\tCVectorD\t&CVectorD::operator+=(const CVectorD &v)\n{\n\tx+=v.x;\n\ty+=v.y;\n\tz+=v.z;\n\treturn *this;\n}\ninline\tCVectorD\t&CVectorD::operator-=(const CVectorD &v)\n{\n\tx-=v.x;\n\ty-=v.y;\n\tz-=v.z;\n\treturn *this;\n}\ninline\tCVectorD\t&CVectorD::operator*=(double f)\n{\n\tx*=f;\n\ty*=f;\n\tz*=f;\n\treturn *this;\n}\ninline\tCVectorD\t&CVectorD::operator/=(double f)\n{\n\treturn *this*= (1.0f/f);\n}\ninline\tCVectorD\tCVectorD::operator+(const CVectorD &v) const\n{\n\tCVectorD\tret(x+v.x, y+v.y, z+v.z);\n\treturn ret;\n}\ninline\tCVectorD\tCVectorD::operator-(const CVectorD &v) const\n{\n\tCVectorD\tret(x-v.x, y-v.y, z-v.z);\n\treturn ret;\n}\ninline\tCVectorD\tCVectorD::operator*(double f) const\n{\n\tCVectorD\tret(x*f, y*f, z*f);\n\treturn ret;\n}\ninline\tCVectorD\tCVectorD::operator/(double f) const\n{\n\treturn *this*(1.0f/f);\n}\ninline\tCVectorD\tCVectorD::operator-() const\n{\n\treturn CVectorD(-x,-y,-z);\n}\ninline CVectorD\toperator*(double f, const CVectorD &v)\n{\n\tCVectorD\tret(v.x*f, v.y*f, v.z*f);\n\treturn ret;\n}\n\n\n// ============================================================================================\n// Advanced Maths.\ninline\tdouble\tCVectorD::operator*(const CVectorD &v) const\n{\n\treturn x*v.x + y*v.y + z*v.z;\n}\ninline\tCVectorD\tCVectorD::operator^(const CVectorD &v) const\n{\n\tCVectorD\tret;\n\n\tret.x= y*v.z - z*v.y;\n\tret.y= z*v.x - x*v.z;\n\tret.z= x*v.y - y*v.x;\n\n\treturn ret;\n}\ninline\tdouble\tCVectorD::sqrnorm() const\n{\n\treturn (double)(x*x + y*y + z*z);\n}\ninline\tdouble\tCVectorD::norm() const\n{\n\treturn (double)sqrt(x*x + y*y + z*z);\n}\ninline\tvoid\tCVectorD::normalize()\n{\n\tdouble\tn=norm();\n\tif(n)\n\t\t*this/=n;\n}\ninline\tCVectorD\tCVectorD::normed() const\n{\n\tCVectorD\tret;\n\tret= *this;\n\tret.normalize();\n\treturn ret;\n}\n\n\n// ============================================================================================\n// Misc.\ninline\tvoid\tCVectorD::set(double _x, double _y, double _z)\n{\n\tx=_x; y=_y; z=_z;\n}\ninline\tbool\tCVectorD::operator==(const CVectorD &v) const\n{\n\treturn x==v.x && y==v.y && z==v.z;\n}\ninline\tbool\tCVectorD::operator!=(const CVectorD &v) const\n{\n\treturn !(*this==v);\n}\ninline\tbool\tCVectorD::isNull() const\n{\n\treturn *this==CVectorD::Null;\n}\ninline\tvoid\tCVectorD::cartesianToSpheric(double &r, double &theta,double &phi) const\n{\n\tCVectorD v;\n\n\tr= norm();\n\tv= normed();\n\n\t// phi E [-PI/2 et PI/2]\n\tclamp(v.z, -1.0, 1.0);\n\tphi=asin(v.z);\n\n\t// theta [-PI,PI]\n\ttheta=atan2(v.y,v.x);\n}\ninline\tvoid\tCVectorD::sphericToCartesian(double r, double theta,double phi)\n{\n\tx= r*cos(theta)*cos(phi);\n\ty= r*sin(theta)*cos(phi);\n\tz= r*sin(phi);\n}\ninline CVectorD &CVectorD::operator=(const CVector &v)\n{\n\tx=v.x;\n\ty=v.y;\n\tz=v.z;\n\treturn *this;\n}\ninline CVectorD::operator CVector() const\n{\n\treturn CVector((float)x, (float)y, (float)z);\n}\ninline\tvoid\tCVectorD::serial(IStream &f)\n{\n\tf.serial(x,y,z);\n}\ninline\tvoid CVectorD::copyTo(CVector &dest) const\n{\n\tdest.set((float) x, (float) y, (float) z);\n}\ninline CVector CVectorD::asVector() const\n{\n\treturn CVector((float) x, (float) y, (float) z);\n}\n\n\n\n}\n\n\n#endif\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/voter.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef XML_PACK_H\n#define XML_PACK_H\n\n#include \"types_nl.h\"\n#include \"string_mapper.h\"\n#include \"sstring.h\"\n\nnamespace NLMISC\n{\n\n/** The xml pack is a data format to store a great number of XML file\n *\tin a simple pseudo XML format.\n *\tThe primary goal was to support the greate number of XML file\n *\tthat we handle for Ryzom in a convenient and efficient way (mainly\n *\tin the CVS point of view).\n *\n *\tIn a xml pack file, all xml files are concatenated inside\n *\tXML elements.\n *\tIn the header of each subfile, there is only the file name.\n *\tSo, it is possible to easily edit the file by hand, compare it\n *\tand add or remove file.\n *\n *\tNB : we use xml pack file as an intermediate format between the\n *\tlevel design team and the runtime data (that are ganarated by\n *\tthe loadForm function of george) that are a binary extraction of\n *\tthe content of the xml files.\n */\n\tclass CXMLPack\n\t{\n\t\tNLMISC_SAFE_SINGLETON_DECL(CXMLPack);\n\n\t\tCXMLPack(){}\n\t\t~CXMLPack() {}\n\n\tpublic:\n\t\t// Add an xml pack to the manager\n\t\tbool add (const std::string &xmlPackFileName);\n\n\t\t// List all files in an xml_pack file\n\t\tvoid list (const std::string &xmlPackFileName, std::vector<std::string> &allFiles);\n\n\t\t// Used by CIFile to get information about the files within the xml pack\n\t\tFILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rFileOffset,\n\t\t\t\t\t\tbool &rCacheFileOnOpen, bool &rAlwaysOpened);\n\n\tprivate:\n\n\t\t///@name parser functions\n\t\t///@{\n\t\t/// Consume space and tab characters (but NOT newlines)\n\t\tvoid skipWS(std::string::iterator &it, std::string::iterator end);\n\t\t/** Try to match the specified text at current position. Return false if no match\n\t\t *\treturn true and advance the it iterator if match is found.\n\t\t */\n\t\tbool matchString(std::string::iterator &it, std::string::iterator end, const char *text);\n\t\t/// Advance up to the begining of the next line, incrementing the in/out param lineCount\n\t\tvoid skipLine(std::string::iterator &it, std::string::iterator end, uint32 &lineCount);\n\t\t///@}\n\n\n\t\t/// the name of the xml_pack file\n\t\tstd::string\t\tXMLPackFileName;\n\n\t\t/// A descriptor for one file inside the pack\n\t\tstruct TXMLFileInfo\n\t\t{\n\t\t\t/// The name of the file, mapped in the string mapper\n\t\t\tTStringId\t\tFileName;\n\t\t\t/// The start position of the data for this file\n\t\t\tuint32\t\t\tFileOffset;\n\t\t\t/// The size of this file\n\t\t\tuint32\t\t\tFileSize;\n\t\t};\n\n\t\t/// A descriptor for the content of an xml pack file\n\t\tstruct TXMLPackInfo\n\t\t{\n\t\t\ttypedef std::map<TStringId, TXMLFileInfo>\tTFileList;\n\t\t\t/// the content of the xml pack\n\t\t\tTFileList\t\t_XMLFiles;\n\t\t\t/// The xml pack file handler (we keep it open)\n//\t\t\tFILE\t\t\t*FileHandler;\n\n//\t\t\tTXMLPackInfo()\n//\t\t\t\t:\t FileHandler(NULL)\n//\t\t\t{\n//\t\t\t}\n//\n//\n//\t\t\t~TXMLPackInfo()\n//\t\t\t{\n//\t\t\t\tif (FileHandler != NULL)\n//\t\t\t\t\tfclose(FileHandler);\n//\t\t\t}\n\t\t};\n\n\n\t\ttypedef std::map<TStringId, TXMLPackInfo>\tTPackList;\n\t\t/// The list of xml pack file already parsed\n\t\tTPackList\t\t\t\t_XMLPacks;\n\t};\n\n} // namespace NLMISC\n\n\n\n#endif // XML_PACK_H\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/win32_util.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WIN32_UTIL_H\n#define NL_WIN32_UTIL_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#include <windows.h>\n\nnamespace NLMISC\n{\n\n\n\tstruct CWin32Util\n\t{\n\t\t/** replace all occurence of 'uiIdentifier' in a window with their localized versions\n\t\t  * (from CI18N)\n\t\t  */\n\t\tstatic void localizeWindow(HWND wnd);\n\t\t// Append all child windows of a parent window into a vector\n\t\tstatic void appendChildWindows(HWND parentWnd, std::vector<HWND> &childWindows);\n\t};\n\n\n} // NLMISC\n\n\n#endif // NL_OS_WINDOWS\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/misc/win_displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WIN_DISPLAYER_H\n#define NL_WIN_DISPLAYER_H\n\n#include \"types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#ifndef WIN32_LEAN_AND_MEAN\n#\tdefine WIN32_LEAN_AND_MEAN\n#endif\n#ifndef _WIN32_WINDOWS\n#\tdefine _WIN32_WINDOWS 0x0410\n#endif\n#ifndef _WIN32_WINNT\n#\tdefine _WIN32_WINNT 0x0400\n#endif\n#ifndef WINVER\n#\tdefine WINVER 0x0400\n#endif\n#ifndef NOMINMAX\n#\tdefine NOMINMAX\n#endif\n#include <windows.h>\n\n#include \"displayer.h\"\n#include \"reader_writer.h\"\n\n#include \"window_displayer.h\"\n\nnamespace NLMISC {\n\n\n/**\n * this displayer displays on a win32 windows.\n * MT = Main Thread, DT = Display Thread\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CWinDisplayer : public NLMISC::CWindowDisplayer\n{\npublic:\n\n\tCWinDisplayer(const char *displayerName = \"\");\n\n\tvirtual ~CWinDisplayer ();\n\n#ifdef NL_OS_WINDOWS\n\tHWND getHWnd () const { return _HWnd; }\n#endif // NL_OS_WINDOWS\n\nprivate:\n\n\t// called by DT only\n\tvoid\tresizeLabels ();\n\t// called by DT only\n\tvoid\tupdateLabels ();\n\n\t// called by DT only\n\tvoid\topen (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log);\n\t// called by DT only\n\tvoid\tclear ();\n\t// called by DT only\n\tvoid\tdisplay_main ();\n\n\tvirtual void\tsetTitleBar (const std::string &titleBar);\n\n\tvirtual void\tgetWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h);\n\n\t// all these variables above is used only by the DT\n\n\tHWND _HEdit, _HWnd, _HInputEdit;\n\tHFONT _HFont;\n\tHMODULE _HLibModule;\n\n\tCLog *Log;\n\n\t// the MT must set the value to true to exit the thread\n\tbool Exit;\n\n\tfriend LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);\n};\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n\n#endif // NL_WIN_DISPLAYER_H\n\n/* End of win_displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/win_event_emitter.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WIN_EVENT_EMITTER_H\n#define NL_WIN_EVENT_EMITTER_H\n\n#include \"types_nl.h\"\n#include \"event_emitter.h\"\n#include \"events.h\"\n\n\n#ifdef NL_OS_WINDOWS\n\nnamespace NLMISC {\n\n/**\n * CWinEventEmitter\n * CEventEmitter Windows implementation\n */\nclass CWinEventEmitter : public IEventEmitter\n{\npublic:\n\tCWinEventEmitter () : _MouseEventsEnabled(true), _KeyboardEventsEnabled(true), _IMEEventsEnabled(true)\n\t{\n\t\t_HWnd=NULL;\n\t\tresetButtonFlagState ();\n\t}\n\tvoid setHWnd (HWND hWnd)\n\t{\n\t\t_HWnd=hWnd;\n\t\tresetButtonFlagState ();\n\t}\n\n\t/**\n\t * sends all events to server\n\t * (should call CEventServer method postEvent() )\n\t * \\param server\n\t */\n\tvirtual void submitEvents(CEventServer & server, bool allWindows);\n\n\t/// Build the flags of the current buttons state\n\tTMouseButton buildFlags() const;\n\n\t// Reset button flag state\n\tvoid resetButtonFlagState ();\n\n\t// enable / disable mouse events to be processed. The default is enabled.\n\tvoid enableMouseEvents(bool enabled = true) { _MouseEventsEnabled = enabled; }\n\n\t// enable / disable keyboard events to be processed. The default is enabled.\n\tvoid enableKeyboardEvents(bool enabled = true) { _KeyboardEventsEnabled = enabled; }\n\n\t// enable / disable other events to be processed. The default is enabled.\n\tvoid enableIMEEvents(bool enabled = true) { _IMEEventsEnabled = enabled; }\n\n\t// Test whether mouse events are enabled.\n\tbool areMouseEventsEnabled() const { return _MouseEventsEnabled; }\n\n\t// Test whether keyboard events are enabled.\n\tbool areKeyboardEventsEnabled() const { return _KeyboardEventsEnabled; }\nprivate:\n\n\n\t// Private internal server message\n\tclass CWinEventServer : CEventServer\n\t{\n\t\tfriend class CWinEventEmitter;\n\tpublic:\n\t\tvoid setServer (CEventServer *server)\n\t\t{\n\t\t\t_Server=server;\n\t\t}\n\tprivate:\n\t\tvirtual bool pumpEvent(CEvent* event)\n\t\t{\n\t\t\tCEventServer::pumpEvent(event);\n\t\t\t_Server->postEvent (event);\n\t\t\treturn false;\n\t\t}\n\tprivate:\n\t\tCEventServer *_Server;\n\t};\n\npublic:\n\t/** Process a win32 message.\n\t  * Return true if the message must be trapped, false if DefWindowProc must be called afterwards\n\t  */\n\tbool processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server=NULL);\n\nprivate:\n\tCWinEventServer\t\t_InternalServer;\n\tHWND\t\t\t\t_HWnd;\npublic:\n\t// private: may need to be in sync with direct input flags however...\n\tbool\t\t\t\t_CtrlButton;\n\tbool\t\t\t\t_ShiftButton;\n\tbool\t\t\t\t_AltButton;\n\tbool\t\t\t\t_MouseButtons[3];\n\tbool\t\t\t\t_MouseEventsEnabled;\n\tbool\t\t\t\t_KeyboardEventsEnabled;\n\tbool\t\t\t\t_IMEEventsEnabled;\nprivate:\n\tNLMISC::TMouseButton\t\tgetButtons() const;\n};\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n\n#endif // NL_WIN_EVENT_EMITTER_H\n\n/* End of win_event_emitter.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/win_thread.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WIN_THREAD_H\n#define NL_WIN_THREAD_H\n\n#include \"types_nl.h\"\n#include \"thread.h\"\n\n#ifdef NL_OS_WINDOWS\n\nnamespace NLMISC {\n\n\n/**\n * Windows implementation of CThread class (look thread.h)\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n */\nclass CWinThread : public IThread\n{\npublic:\n\n\t/// Constructor\n\tCWinThread(IRunnable *runnable, uint32 stackSize);\n\n\t/// Don't use this constructor, only used to initialise the main thread class\n\tCWinThread (void* threadHandle, uint32 threadId);\n\n\tvirtual ~CWinThread();\n\n\tvirtual void start();\n\tvirtual bool isRunning();\n\tvirtual void terminate();\n\tvirtual void wait();\n\tvirtual bool setCPUMask(uint64 cpuMask);\n\tvirtual uint64 getCPUMask();\n\tvirtual void setPriority(TThreadPriority priority);\n\tvirtual std::string getUserName();\n\n\tvirtual IRunnable *getRunnable()\n\t{\n\t\treturn Runnable;\n\t}\n\n\t// Win32 specific\n\t// Get the suspend count. Will be -1 is the thread hasn't been started yet\n\tint getSuspendCount() const { return _SuspendCount; }\n\t// Increment the suspend count, a suspend count >= 1 means the thread is suspended\n\tvoid incSuspendCount();\n\t/** Descrement the suspend count. Reaching 0 will resume the thread\n\t  * An assertion is raised is the suspend count is already 0\n\t  */\n\tvoid decSuspendCount();\n\t// Suspend the thread. No-op if already suspended\n\tvoid suspend();\n\t// Resume the thread. No-op if already resumed\n\tvoid resume();\n\t// Priority boost\n\tvoid enablePriorityBoost(bool enabled);\n\n\t/// private use\n\tIRunnable\t*Runnable;\n\nprivate:\n\tint\t\t\t_SuspendCount;\n\tuint32\t\t_StackSize;\n\tvoid\t\t*ThreadHandle;\t// HANDLE\tdon't put it to avoid including windows.h\n\tuint32\t\tThreadId;\t\t// DWORD\tdon't put it to avoid including windows.h\n\tbool\t\t_MainThread;\t// true if ths thread is the main thread, else false\n};\n\n/**\n * Windows Process\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nicolas Vizerie\n * \\author Nevrax France\n * \\date 2001, 2007\n */\nclass CWinProcess : public IProcess\n{\npublic:\n\n\tCWinProcess (void *handle);\n\tvirtual ~CWinProcess() {} // TODO do something with _ProcessHandle?\n\n\tvirtual uint64 getCPUMask();\n\tvirtual bool setCPUMask(uint64 mask);\n\n\t// processes helpers\n\tstatic bool   enumProcessesId(std::vector<uint32> &processesId);\n\t// get fully qualified path for all modules used by a given process\n\tstatic bool\t  enumProcessModules(uint32 processId, std::vector<std::string> &moduleNames);\n\tstatic uint32 getProcessIdFromModuleFilename(const std::string &moduleFileName);\n\tstatic bool\t  terminateProcess(uint32 processId, uint exitCode = 0);\n\tstatic bool\t  terminateProcessFromModuleName(const std::string &moduleName, uint exitCode = 0);\n\nprivate:\n\tvoid\t*_ProcessHandle;\n};\n\n\n\n/*\n//  I didn't use and test that code, enventually, but maybe useful in the future\n//\n// Utility class to launch a process and check if it is still running.\n// Implemented under windows only for now\n//\nclass CProcessWatch\n{\npublic:\n\tCProcessWatch();\n\t~CProcessWatch();\n\t// launch a process with the given name and arguments, return true on success\n\tbool launch(const std::string &programName, const std::string &arguments);\n\t// return true if the process is still runing\n\tbool isRunning() const;\nprivate:\n\tclass CProcessWatchImpl *_PImpl;\n};\n\n*/\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n\n#endif // NL_WIN_THREAD_H\n\n/* End of win_thread.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/win_tray.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "code/nel/include/nel/misc/window_displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WINDOW_DISPLAYER_H\n#define NL_WINDOW_DISPLAYER_H\n\n#include \"types_nl.h\"\n#include \"common.h\"\n#include \"debug.h\"\n\n#include \"displayer.h\"\n#include \"mutex.h\"\n#include \"thread.h\"\n\nnamespace NLMISC {\n\n\n/**\n * this displayer displays on a win32 windows.\n * MT = Main Thread, DT = Display Thread\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CWindowDisplayer : public NLMISC::IDisplayer\n{\npublic:\n\n\tCWindowDisplayer (const char *displayerName = \"\") :\n\t  IDisplayer(displayerName),\n\t\t_Buffer(\"CWindowDisplayer::_Buffer\"), _Labels(\"CWindowDisplayer::_Labels\"), _CommandsToExecute(\"CWindowDisplayer::_CommandsToExecute\"),\n\t\t_Continue(true), _PosInHistory(0), _Init(false), _HistorySize(0), _ToolBarHeight(22), _InputEditHeight(25), _Thread(0), Log(0)\n\t  { }\n\n\tvirtual ~CWindowDisplayer ();\n\n\t// open the window and run the display thread (MT)\n\tvoid\tcreate (std::string titleBar = \"\", bool iconified = false, sint x = -1, sint y = -1, sint w = -1, sint h = -1, sint hs = -1, sint fs = 0, const std::string &fn = \"\", bool ww = false, CLog *log = InfoLog);\n\n\t// create a new label. empty string mean separator. start with @ means that is a command (MT)\n\tuint\tcreateLabel (const char *value = \"?\");\n\n\t// change the value of a label (MT)\n\tvoid\tsetLabel (uint label, const std::string &value);\n\n\t// execute user commands (MT) return false to quit\n\tbool\tupdate ();\n\n\t// set a special title to the window bar\n\tvirtual void\tsetTitleBar (const std::string &/* titleBar */) { }\n\n\tvirtual void\tgetWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h) { x=y=w=h=0; }\n\nprotected:\n\n\t// display a string (MT)\n\tvirtual void doDisplay (const NLMISC::CLog::TDisplayInfo &args, const char *message);\n\n\t// true for windows\n\tbool needSlashR;\n\n\tstruct CLabelEntry\n\t{\n\t\tCLabelEntry (const std::string &value) : Hwnd(NULL), Value(value), NeedUpdate(true) { }\n\t\tvoid\t\t*Hwnd;\n\t\tstd::string\t Value;\n\t\tbool\t\t NeedUpdate;\n\t};\n\n\t// buffer that contains the text that the DT will have to display\n\t// uint32 is the color of the string\n\tCSynchronized<std::list<std::pair<uint32, std::string> > >\t_Buffer;\n\tCSynchronized<std::vector<CLabelEntry> >\t\t\t\t\t\t_Labels;\n\tCSynchronized<std::vector<std::string> >\t\t\t\t\t\t_CommandsToExecute;\n\n\t// called by DT only\n\tvirtual void\topen (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log) = 0;\n\t// called by DT only\n\tvirtual void\tdisplay_main () = 0;\n\n\t// all these variables above is used only by the DT\n\n\tbool _Continue;\n\n\tstd::vector<std::string>\t_History;\n\tuint\t\t\t\t\t\t_PosInHistory;\n\tbool _Init;\n\tsint _HistorySize;\n\tsint _ToolBarHeight;\n\tsint _InputEditHeight;\n\n\t// the thread used to update the display\n\tNLMISC::IThread *_Thread;\n\n\tCLog *Log;\n\n\tfriend class CUpdateThread;\n};\n\n} // NLMISC\n\n#endif // NL_WINDOW_DISPLAYER_H\n\n/* End of window_displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/words_dictionary.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WORDS_DICTIONARY_H\n#define NL_WORDS_DICTIONARY_H\n\n#include \"types_nl.h\"\n#include \"sstring.h\"\n\n\nnamespace NLMISC {\n\n\n/**\n * Words dictionary: allows to search for keys and words in <type>_words_<language>.txt\n * Unicode files. All searches are case not-sensitive.\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2003\n */\nclass CWordsDictionary\n{\n\tNL_INSTANCE_COUNTER_DECL(CWordsDictionary);\npublic:\n\n\t/// Constructor\n\tCWordsDictionary();\n\n\t/** Load the config file and the related words files. Return false in case of failure.\n\t * Config file variables:\n\t * - WordsPath: where to find <filter>_words_<languageCode>.txt\n\t * - LanguageCode: language code (ex: en for English)\n\t * - Utf8: results are in UTF8, otherwise in ANSI string\n\t * - Filter: \"*\" for all files (default) or a name (ex: \"item\").\n\t * - AdditionalFiles/AdditionalFileColumnTitles\n\t */\n\tbool\t\t\tinit( const std::string& configFileName=\"words_dic.cfg\" );\n\n\t/**\n\t * Set the result vector with strings corresponding to the input string:\n\t * - If inputStr is partially or completely found in the keys, all the matching <key,words> are returned;\n\t * - If inputStr is partially or completely in the words, all the matching <key, words> are returned.\n\t * The following tags can modify the behaviour of the search algorithm:\n\t * - ^mystring returns mystring only if it is at the beginning of a key or word\n\t * - mystring$ returns mystring only if it is at the end of a key or word\n\t * All returned words are in UTF8 string or ANSI string, depending of the config file.\n\t */\n\tvoid\t\t\tlookup( const CSString& inputStr, CVectorSString& resultVec )const;\n\n\t/// Set the result vector with the word(s) corresponding to the key\n\tvoid\t\t\texactLookupByKey( const CSString& key, CVectorSString& resultVec );\n\n\t/// Return the key contained in the provided string returned by lookup() (without extension)\n\tCSString\t\tgetWordsKey( const CSString& resultStr );\n\n\t// Accessors\n\tconst CVectorSString& getKeys() { return _Keys; }\n\tconst CVectorSString& getWords() { return _Words; }\n\n\t/// Return the list of input file loaded at init\n\tconst std::vector<std::string>& getFileList() const { return _FileList; }\n\nprotected:\n\n\t/// Make a result string\n\tstatic CSString\t\tmakeResult( const CSString &key, const CSString &word );\n\nprivate:\n\n\t/// Keys (same indices as in _Words)\n\tCVectorSString\t\t\t\t_Keys;\n\n\t/// Words (same indices as in _Keys)\n\tCVectorSString\t\t\t\t_Words;\n\n\t/// Input file list\n\tstd::vector<std::string>\t_FileList;\n};\n\n\n} // NLMISC\n\n\n#endif // NL_WORDS_DICTIONARY_H\n\n/* End of words_dictionary.h */\n"
  },
  {
    "path": "code/nel/include/nel/misc/xml_auto_ptr.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n#ifndef XML_AUTO_PTR_H\n#define XML_AUTO_PTR_H\n\n#include <string>\n\n/** Simple auto pointer for xml pointers\n  */\nclass CXMLAutoPtr\n{\npublic:\n\tCXMLAutoPtr(const char *value = NULL) : _Value(value) {}\n\tCXMLAutoPtr(const unsigned char *value) : _Value((const char *) value) {}\n\t~CXMLAutoPtr() { destroy(); }\n\toperator const char *() const { return _Value; }\n\toperator bool() const { return _Value != NULL; }\n\tinline std::string str() const { return _Value; }\n\tbool operator ! () const { return _Value == NULL; }\n\toperator const unsigned char *() const { return (const unsigned char *)  _Value; }\n\tchar operator * ()  const { nlassert(_Value); return *_Value; }\n\t/// NB : This remove previous owned pointer with xmlFree\n\tCXMLAutoPtr &operator = (const char *other)\n\t{\n\t\tif (other == _Value) return *this;\n\t\tdestroy();\n\t\t_Value = other;\n\t\treturn *this;\n\t}\n\n\tCXMLAutoPtr &operator = (const unsigned char *other)\n\t{\n\t\t*this = (const char *) other;\n\t\treturn *this;\n\t}\n\tchar *getDatas() const { return const_cast<char *>(_Value); }\n//////////////////////////////////////////////////\nprivate:\n\tconst char *_Value;\nprivate:\n\tvoid destroy()\n\t{\n\t\tif (_Value)\n\t\t{\n\t\t\txmlFree(const_cast<char *>(_Value));\n\t\t\t_Value = NULL;\n\t\t}\n\t}\n\n\t// We'd rather avoid problems\n\tCXMLAutoPtr(const CXMLAutoPtr &/* other */)\n\t{\n\t\tnlassert(0);\n\t}\n\tCXMLAutoPtr&operator = (const CXMLAutoPtr &/* other */)\n\t{\n\t\tnlassert(0);\n\t\treturn *this;\n\t}\n};\n\n\n#endif\n\n\n"
  },
  {
    "path": "code/nel/include/nel/misc/xml_pack.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef XML_PACK_H\n#define XML_PACK_H\n\n#include \"types_nl.h\"\n#include \"string_mapper.h\"\n#include \"sstring.h\"\n\nnamespace NLMISC\n{\n\n/** The xml pack is a data format to store a great number of XML file\n *\tin a simple pseudo XML format.\n *\tThe primary goal was to support the greate number of XML file\n *\tthat we handle for Ryzom in a convenient and efficient way (mainly\n *\tin the CVS point of view).\n *\n *\tIn a xml pack file, all xml files are concatenated inside\n *\tXML elements.\n *\tIn the header of each subfile, there is only the file name.\n *\tSo, it is possible to easily edit the file by hand, compare it\n *\tand add or remove file.\n *\n *\tNB : we use xml pack file as an intermediate format between the\n *\tlevel design team and the runtime data (that are ganarated by\n *\tthe loadForm function of george) that are a binary extraction of\n *\tthe content of the xml files.\n */\n\tclass CXMLPack\n\t{\n\t\tNLMISC_SAFE_SINGLETON_DECL(CXMLPack);\n\n\t\tCXMLPack(){}\n\t\t~CXMLPack() {}\n\n\tpublic:\n\t\t// Add an xml pack to the manager\n\t\tbool add (const std::string &xmlPackFileName);\n\n\t\t// List all files in an xml_pack file\n\t\tvoid list (const std::string &xmlPackFileName, std::vector<std::string> &allFiles);\n\n\t\t// Used by CIFile to get information about the files within the xml pack\n\t\tFILE* getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rFileOffset,\n\t\t\t\t\t\tbool &rCacheFileOnOpen, bool &rAlwaysOpened);\n\n\tprivate:\n\n\t\t///@name parser functions\n\t\t///@{\n\t\t/// Consume space and tab characters (but NOT newlines)\n\t\tvoid skipWS(std::string::iterator &it, std::string::iterator end);\n\t\t/** Try to match the specified text at current position. Return false if no match\n\t\t *\treturn true and advance the it iterator if match is found.\n\t\t */\n\t\tbool matchString(std::string::iterator &it, std::string::iterator end, const char *text);\n\t\t/// Advance up to the beginning of the next line, incrementing the in/out param lineCount\n\t\tvoid skipLine(std::string::iterator &it, std::string::iterator end, uint32 &lineCount);\n\t\t///@}\n\n\n\t\t/// the name of the xml_pack file\n\t\tstd::string\t\tXMLPackFileName;\n\n\t\t/// A descriptor for one file inside the pack\n\t\tstruct TXMLFileInfo\n\t\t{\n\t\t\t/// The name of the file, mapped in the string mapper\n\t\t\tTStringId\t\tFileName;\n\t\t\t/// The start position of the data for this file\n\t\t\tuint32\t\t\tFileOffset;\n\t\t\t/// The size of this file\n\t\t\tuint32\t\t\tFileSize;\n\t\t};\n\n\t\t/// A descriptor for the content of an xml pack file\n\t\tstruct TXMLPackInfo\n\t\t{\n\t\t\ttypedef std::map<TStringId, TXMLFileInfo>\tTFileList;\n\t\t\t/// the content of the xml pack\n\t\t\tTFileList\t\t_XMLFiles;\n\t\t\t/// The xml pack file handler (we keep it open)\n//\t\t\tFILE\t\t\t*FileHandler;\n\n//\t\t\tTXMLPackInfo()\n//\t\t\t\t:\t FileHandler(NULL)\n//\t\t\t{\n//\t\t\t}\n//\n//\n//\t\t\t~TXMLPackInfo()\n//\t\t\t{\n//\t\t\t\tif (FileHandler != NULL)\n//\t\t\t\t\tfclose(FileHandler);\n//\t\t\t}\n\t\t};\n\n\n\t\ttypedef std::map<TStringId, TXMLPackInfo>\tTPackList;\n\t\t/// The list of xml pack file already parsed\n\t\tTPackList\t\t\t\t_XMLPacks;\n\t};\n\n} // namespace NLMISC\n\n\n\n#endif // XML_PACK_H\n\n"
  },
  {
    "path": "code/nel/include/nel/net/CMakeLists.txt",
    "content": "FILE(GLOB HEADERS *.h)\n\nINSTALL(FILES ${HEADERS} DESTINATION include/nel/net COMPONENT headers)\n"
  },
  {
    "path": "code/nel/include/nel/net/admin.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ADMIN_H\n#define NL_ADMIN_H\n\n\n//\n// Inlcudes\n//\n\n#include <string>\n#include <vector>\n\n\nnamespace NLNET {\n\n\n//\n// Structures\n//\n\nstruct CAlarm\n{\n\tCAlarm (const std::string &n, sint l, bool gt) : Name(n), Limit(l), GT(gt), Activated(false) { }\n\n\tstd::string Name;\t\t// variable name\n\tint\t Limit;\t\t\t\t// limit value where the alarm is setted\n\tbool GT;\t\t\t\t// true if the error is produce when var is greater than bound\n\n\tbool Activated;\t\t\t// true if the limit is exceeded (mail is send everytimes the actived bool change from false to true)\n};\n\nstruct CGraphUpdate\n{\n\tCGraphUpdate (const std::string &n, sint u) : Name(n), Update(u), LastUpdate(0) { }\n\n\tstd::string Name;\t\t// variable name\n\tint\t Update;\t\t\t// delta time in second when we have to check variable\n\n\tuint32\tLastUpdate;\t\t// in second\n};\n\ntypedef void (*TRemoteClientCallback) (uint32 rid, const std::string &cmd, const std::string &entityNames);\n\n\n//\n// Externals\n//\n\nextern std::vector<CGraphUpdate> GraphUpdates;\nextern std::vector<CAlarm> Alarms;\n\n\n//\n// Types\n//\n\ntypedef std::vector<std::string> TAdminViewVarNames;\ntypedef std::vector<std::string> TAdminViewValues;\nstruct SAdminViewRow\n{\n\tTAdminViewVarNames\tVarNames;\n\tTAdminViewValues\t\tValues;\n\n\tSAdminViewRow() {}\n\tSAdminViewRow(const TAdminViewVarNames& varNames, const TAdminViewValues& values): VarNames(varNames), Values(values) {}\n};\ntypedef std::vector< SAdminViewRow > TAdminViewResult;\n\n\n//\n// Functions\n//\n\nvoid initAdmin (bool dontUseAES);\n\nvoid updateAdmin ();\n\nvoid setInformation (const std::vector<std::string> &alarms, const std::vector<std::string> &graphupdate);\n\nvoid serviceGetView (uint32 rid, const std::string &rawvarpath, TAdminViewResult& answer, bool async=false);\n\nvoid setRemoteClientCallback (TRemoteClientCallback cb);\n\nvoid addRequestAnswer (uint32 rid, const TAdminViewVarNames& varNames, const TAdminViewValues& values);\n\n} // NLNET\n\n\n#endif // NL_ALARMS_H\n\n/* End of email.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_client.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_CLIENT_H\n#define NL_BUF_CLIENT_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"buf_net_base.h\"\n#include \"tcp_sock.h\"\n#include \"buf_sock.h\"\n\n\nnamespace NLNET {\n\n\nclass CInetAddress;\nclass CBufClient;\n\n\n/**\n * Code of receiving thread for clients\n */\nclass CClientReceiveTask : public NLMISC::IRunnable\n{\npublic:\n\n\t/// Constructor (increments the reference to the object pointed to by the smart pointer sockid)\n\tCClientReceiveTask( CBufClient *client, CNonBlockingBufSock *bufsock ) : NbLoop(0), _Client(client), _NBBufSock(bufsock) {} // CHANGED: non-blocking client connection\n\n\t/// Run\n\tvirtual void run();\n\n\t/// Returns a pointer to the bufsock object\n\tCNonBlockingBufSock\t\t*bufSock() { return _NBBufSock; } // CHANGED: non-blocking client connection (previously, returned _SockId->Sock)\n\n\t/// Returns the socket identifier\n\tTSockId\t\t\t\t\tsockId() { return (TSockId)_NBBufSock; }\n\n\tuint32\tNbLoop;\n\nprivate:\n\n\tCBufClient\t\t\t\t\t*_Client;\n\n\tCNonBlockingBufSock\t\t\t*_NBBufSock; // CHANGED: non-blocking client connection\n};\n\n\n\n/**\n * Client class for layer 1\n *\n * Active connection with packet scheme and buffering.\n * The provided buffers are sent raw (no endianness conversion).\n * By default, the size time trigger is disabled, the time trigger is set to 20 ms.\n *\n * Where do the methods take place:\n * \\code\n * send()             ->  send buffer   ->  update(), flush(),\n *                                          bytesUploaded(), newBytesUploaded()\n *\n * receive(),         <- receive buffer <-  receive thread,\n * dataAvailable(),                         bytesDownloaded(), newBytesDownloaded()\n * disconnection callback\n * \\endcode\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CBufClient : public CBufNetBase\n{\npublic:\n\n\t/** Constructor. Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation)\n\t * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with\n\t * setExternalPipeForDataAvailable().\n\t */\n\tCBufClient( bool nodelay=true, bool replaymode=false, bool initPipeForDataAvailable=true );\n\n\t/// Destructor\n\tvirtual ~CBufClient();\n\n\t/// Connects to the specified host\n\tvoid\tconnect( const CInetAddress& addr );\n\n\t/** Disconnects the remote host and empties the receive queue.\n\t * Before that, tries to flush pending data to send unless quick is true.\n\t * In case of network congestion, the entire pending data may not be flushed.\n\t * If this is a problem, call flush() multiple times until it returns 0 before calling disconnect().\n\t * The disconnection callback will *not* be called.\n\t * Do not call if the socket is not connected.\n\t */\n\tvoid\tdisconnect( bool quick=false );\n\n\t/** Sends a message to the remote host (in fact the message is buffered into the send queue)\n\t */\n\t//void\tsend( const std::vector<uint8>& buffer );\n\tvoid\tsend( const NLMISC::CMemStream& buffer );\n\n\t/** Checks if there is some data to receive. Returns false if the receive queue is empty.\n\t * This is where the connection/disconnection callbacks can be called\n\t */\n\tbool\tdataAvailable();\n\n#ifdef NL_OS_UNIX\n\t/** Wait until the receive queue contains something to read (implemented with a select()).\n\t * This is where the connection/disconnection callbacks can be called.\n\t * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme).\n\t * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n\t */\n\tvoid\tsleepUntilDataAvailable( uint usecMax=100000 );\n#endif\n\n\t/** Receives next block of data in the specified buffer (resizes the vector)\n\t * You must call dataAvailable() before every call to receive()\n\t */\n\t//void\treceive( std::vector<uint8>& buffer );\n\tvoid\treceive( NLMISC::CMemStream& buffer );\n\n\t/// Update the network (call this method evenly)\n\tvoid\tupdate();\n\n\n\n\t// Returns the size in bytes of the data stored in the send queue.\n\tuint32\tgetSendQueueSize() const { return _BufSock->SendFifo.size(); }\n\n\tvoid displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog)\n\t{\n\t\t_BufSock->SendFifo.displayStats(log);\n\t}\n\n\tvoid displayThreadStat (NLMISC::CLog *log);\n\n\t/** Sets the time flush trigger (in millisecond). When this time is elapsed,\n\t * all data in the send queue is automatically sent (-1 to disable this trigger)\n\t */\n\tvoid\tsetTimeFlushTrigger( sint32 ms ) { _BufSock->setTimeFlushTrigger( ms ); }\n\n\t/** Sets the size flush trigger. When the size of the send queue reaches or exceeds this\n\t * calue, all data in the send queue is automatically sent (-1 to disable this trigger )\n\t */\n\tvoid\tsetSizeFlushTrigger( sint32 size ) { _BufSock->setSizeFlushTrigger( size ); }\n\n\t/** Force to send data pending in the send queue now. If all the data could not be sent immediately,\n\t * the returned nbBytesRemaining value is non-zero.\n\t * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n\t * \\returns False if an error has occured (e.g. the remote host is disconnected).\n\t * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n\t */\n\tbool\tflush( uint *nbBytesRemaining=NULL ) { return _BufSock->flush( nbBytesRemaining ); }\n\n\n\n\t/** Returns true if the connection is still connected (changed when a disconnection\n\t * event has reached the front of the receive queue, just before calling the disconnection callback\n\t * if there is one)\n\t */\n\tbool\tconnected() const { return _BufSock->connectedState(); }\n\n\t/// Returns the address of the remote host\n\tconst CInetAddress&\tremoteAddress() const { return _BufSock->Sock->remoteAddr(); }\n\n\t/// Returns the number of bytes downloaded (read or still in the receive buffer) since the latest connection\n\tuint64\tbytesDownloaded() const { return _BufSock->Sock->bytesReceived(); }\n\n\t/// Returns the number of bytes uploaded (flushed) since the latest connection\n\tuint64\tbytesUploaded() const { return _BufSock->Sock->bytesSent(); }\n\n\t/// Returns the number of bytes downloaded since the previous call to this method\n\tuint64\tnewBytesDownloaded();\n\n\t/// Returns the number of bytes uploaded since the previous call to this method\n\tuint64\tnewBytesUploaded();\n\n\t/*//Not right because we add callbacks in the receive queue\n\t/// Returns the number of bytes popped by receive() since the beginning (mutexed on the receive queue)\n\tuint64\tbytesReceived() {  }\n\n\t/// Returns the number of bytes pushed by send() since the beginning\n\tuint64\tbytesSent() { return bytesUploaded() + getSendQueueSize(); }\n\n\t/// Returns the number of bytes popped by receive() since the previous call to this method\n\tuint64\tnewBytesReceived();\n\n\t/// Returns the number of bytes pushed by send() since the previous call to this method\n\tuint64\tnewBytesSent();\n\t*/\n\n\t/// Returns the id of the connection\n\tTSockId\tid() const { return _BufSock; /*_RecvTask->sockId();*/ }\n\n\nprotected:\n\n\tfriend class CClientReceiveTask;\n\n\t/// Send buffer and connection\n\tCNonBlockingBufSock *_BufSock; // ADDED: non-blocking client connection\n\n\t/// True when the Nagle algorithm must be disabled (TCP_NODELAY)\n\tbool\t\t\t\t_NoDelay;\n\n\t/// Previous number of bytes downloaded\n\tuint64\t\t\t\t_PrevBytesDownloaded;\n\n\t/// Previous number of bytes uploaded\n\tuint64\t\t\t\t_PrevBytesUploaded;\n\n\t/*\n\t/// Previous number of bytes received\n\tuint32\t\t\t\t_PrevBytesReceived;\n\n\t/// Previous number of bytes sent\n\tuint32\t\t\t\t_PrevBytesSent;\n\t*/\n\nprivate:\n\n\t/// Receive task\n\tCClientReceiveTask\t*_RecvTask;\n\n\t/// Receive thread\n\tNLMISC::IThread\t\t*_RecvThread;\n\n};\n\n\n\n} // NLNET\n\n\n#endif // NL_BUF_CLIENT_H\n\n/* End of buf_client.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_net_base.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_NET_BASE_H\n#define NL_BUF_NET_BASE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/mutex.h\"\n#include \"nel/misc/buf_fifo.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/common.h\"\n\nnamespace NLNET {\n\n\nclass CBufSock;\n\n/// Socket identifier\ntypedef CBufSock *TSockId;\n\nstatic const TSockId InvalidSockId = (TSockId) NULL;\n\n/// Callback function for message processing\ntypedef void (*TNetCallback) ( TSockId from, void *arg );\n\n/// Storing a TNetCallback call for future call\ntypedef std::pair<TNetCallback,TSockId> TStoredNetCallback;\n\n/// Synchronized FIFO buffer\ntypedef NLMISC::CSynchronized<NLMISC::CBufFIFO> CSynchronizedFIFO;\n\n/// Accessor of mutexed FIFO buffer\ntypedef CSynchronizedFIFO::CAccessor CFifoAccessor;\n\n/// Size of a block\ntypedef uint32 TBlockSize;\n\nextern uint32 \tNbNetworkTask;\n\n#ifdef NL_OS_UNIX\n/// Access to the wake-up pipe (Unix only)\nenum TPipeWay { PipeRead, PipeWrite };\n#endif\n\n\n/**\n * Layer 1\n *\n * Base class for CBufClient and CBufServer.\n * The max block sizes for sending and receiving are controlled by setMaxSentBlockSize()\n * and setMaxExpectedBlockSize(). Their default value is the maximum number contained in a sint32,\n * that is 2^31-1 (i.e. 0x7FFFFFFF). The limit for sending is checked only in debug mode.\n *\n * \\author Nevrax France\n * \\date 2001\n */\nclass CBufNetBase\n{\npublic:\n\n\t/// Type of incoming events (max 256)\n\tenum TEventType { User = 'U', Connection = 'C', Disconnection = 'D' };\n\n\t/// Destructor\n\tvirtual ~CBufNetBase();\n\n#ifdef NL_OS_UNIX\n\t/** Init the pipe for data available with an external pipe.\n\t * Call it only if you set initPipeForDataAvailable to false in the constructor.\n\t * Then don't call sleepUntilDataAvailable() but use select() on the pipe.\n\t * The pipe will be written one byte when receiving a message.\n\t */\n\tvoid\tsetExternalPipeForDataAvailable( int *twoPipeHandles )\n\t{\n\t\t_DataAvailablePipeHandle[PipeRead] = twoPipeHandles[PipeRead];\n\t\t_DataAvailablePipeHandle[PipeWrite] = twoPipeHandles[PipeWrite];\n\t}\n#endif\n\n\t/// Sets callback for detecting a disconnection (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback( TNetCallback cb, void* arg ) { _DisconnectionCallback = cb; _DisconnectionCbArg = arg; }\n\n\t/// Returns the size of the receive queue (mutexed)\n\tuint32\tgetReceiveQueueSize()\n\t{\n\t\tCFifoAccessor syncfifo( &_RecvFifo );\n\t\treturn syncfifo.value().size();\n\t}\n\n\tvoid displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog)\n\t{\n\t\tCFifoAccessor syncfifo( &_RecvFifo );\n\t\tsyncfifo.value().displayStats(log);\n\t}\n\n\t/**\n\t * Sets the max size of the received messages.\n\t * If receiving a message bigger than the limit, the connection will be dropped.\n\t *\n\t * Default value: CBufNetBase::DefaultMaxExpectedBlockSize\n\t * If you put a negative number as limit, the max size is reseted to the default value.\n\t * Warning: you can call this method only at initialization time, before connecting (for a client)\n\t * or calling init() (for a server) !\n\t */\n\tvoid\tsetMaxExpectedBlockSize( sint32 limit )\n\t{\n\t\tif ( limit < 0 )\n\t\t\t_MaxExpectedBlockSize = DefaultMaxExpectedBlockSize;\n\t\telse\n\t\t\t_MaxExpectedBlockSize = (uint32)limit;\n\t}\n\n\t/**\n\t * Sets the max size of the sent messages.\n\t * Any bigger sent block will produce an assertion failure, currently.\n\t *\n\t * Default value: CBufNetBase::DefaultMaxSentBlockSize\n\t * If you put a negative number as limit, the max size is reseted to the default value.\n\t * Warning: you can call this method only at initialization time, before connecting (for a client)\n\t * or calling init() (for a server) !\n\t */\n\tvoid\tsetMaxSentBlockSize( sint32 limit )\n\t{\n\t\tif ( limit < 0 )\n\t\t\t_MaxSentBlockSize = DefaultMaxSentBlockSize;\n\t\telse\n\t\t\t_MaxSentBlockSize = (uint32)limit;\n\t}\n\n\t/// Returns the max size of the received messages (default: 2^31-1)\n\tuint32\tmaxExpectedBlockSize() const\n\t{\n\t\treturn _MaxExpectedBlockSize;\n\t}\n\n\t/// Returns the max size of the sent messages (default: 2^31-1)\n\tuint32\tmaxSentBlockSize() const\n\t{\n\t\treturn _MaxSentBlockSize;\n\t}\n\n#ifdef NL_OS_UNIX\n\t/**\n\t * Return the handle for reading the 'data available pipe'. Use it if you want to do a select on\n\t * multiple CBufNetClient/CBufNetServer objects (then, don't call sleepUntilDataAvailable() on them).\n\t */\n\tint\t\tdataAvailablePipeReadHandle() const { return _DataAvailablePipeHandle[PipeRead]; }\n#endif\n\n\t/// The value that will be used if setMaxExpectedBlockSize() is not called (or called with a negative argument)\n\tstatic uint32 DefaultMaxExpectedBlockSize;\n\n\t/// The value that will be used if setMaxSentBlockSize() is not called (or called with a negative argument)\n\tstatic uint32 DefaultMaxSentBlockSize;\n\n\n    std::string     m_SslCA;\n    std::string     m_SslCrt;\n    std::string     m_SslPrvKey;\n\n//protected:\npublic:\n\n\tfriend class NLNET::CBufSock;\n\n#ifdef NL_OS_UNIX\n\t/// Constructor\n\tCBufNetBase( bool isDataAvailablePipeSelfManaged );\n#else\n\t/// Constructor\n\tCBufNetBase();\n#endif\n\n\t/// Access to the receive queue\n\tCSynchronizedFIFO&\treceiveQueue() { return _RecvFifo; }\n\n\t/// Returns the disconnection callback\n\tTNetCallback\t\tdisconnectionCallback() const { return _DisconnectionCallback; }\n\n\t/// Returns the argument of the disconnection callback\n\tvoid*\t\t\t\targOfDisconnectionCallback() const { return _DisconnectionCbArg; }\n\n\t/// Push message into receive queue (mutexed)\n\t// TODO OPTIM never use this function\n\tvoid\t\t\t\tpushMessageIntoReceiveQueue( const std::vector<uint8>& buffer );\n\n\t/// Push message into receive queue (mutexed)\n\tvoid\t\t\t\tpushMessageIntoReceiveQueue( const uint8 *buffer, uint32 size );\n\n\t/// Sets _DataAvailable\n\tvoid\t\t\t\tsetDataAvailableFlag( bool da ) { _DataAvailable = da; }\n\n\t/// Return _DataAvailable\n\tbool\t\t\t\tdataAvailableFlag() const { return _DataAvailable; }\n\n#ifdef NL_OS_UNIX\n\t/// Pipe to select() on data available\n\tint\t\t\t\t\t_DataAvailablePipeHandle [2];\n#endif\n\nprivate:\n\n\t/// The receive queue, protected by a mutex-like device\n\tCSynchronizedFIFO\t_RecvFifo;\n\n\t/// Callback for disconnection\n\tTNetCallback\t\t_DisconnectionCallback;\n\n\t/// Argument of the disconnection callback\n\tvoid*\t\t\t\t_DisconnectionCbArg;\n\n\t/// Max size of received messages (limited by the user)\n\tuint32\t\t\t\t_MaxExpectedBlockSize;\n\n\t/// Max size of sent messages (limited by the user)\n\tuint32\t\t\t\t_MaxSentBlockSize;\n\n\t/// True if there is data available (avoids locking a mutex)\n\tvolatile bool\t\t_DataAvailable;\n\n#ifdef NL_OS_UNIX\n\tbool _IsDataAvailablePipeSelfManaged;\n#endif\n};\n\n\n} // NLNET\n\n\n#endif // NL_BUF_NET_BASE_H\n\n/* End of buf_net_base.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_server.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_SERVER_H\n#define NL_BUF_SERVER_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"buf_net_base.h\"\n#include \"listen_sock.h\"\n#include \"buf_sock.h\"\n#include \"net_log.h\"\n\n#include <list>\n#include <set>\n\n// POLL1 (ignore POLL comments)\n\nnamespace NLNET {\n\n\nclass CInetAddress;\nclass CBufServer;\n\n\n/**\n * Common part of CListenTask and CServerReceiveTask\n */\nclass CServerTask\n{\npublic:\n\n\t/// Destructor\n\tvirtual ~CServerTask();\n\n\t/// Tells the task to exit\n\tvoid\trequireExit() { _ExitRequired = true; }\n\n#ifdef NL_OS_UNIX\n\t/// Wake the thread up, when blocked in select (Unix only)\n\tvoid\twakeUp();\n#endif\n\n\tuint32 NbLoop;\n\nprotected:\n\n\t/// Constructor\n\tCServerTask();\n\n\t/// Returns true if the requireExit() has been called\n\tbool\texitRequired() const { return _ExitRequired; }\n\n#ifdef NL_OS_UNIX\n\t/// Pipe for select wake-up (Unix only)\n\tint\t\t        _WakeUpPipeHandle [2];\n#endif\n\nprivate:\n\n\tvolatile bool\t_ExitRequired;\n};\n\n\n/**\n * Code of listening thread\n */\nclass CListenTask : public NLMISC::IRunnable, public CServerTask\n{\npublic:\n\n\t/// Constructor\n\tCListenTask( CBufServer *server ) : CServerTask(), _Server(server) {}\n\n\t/// Begins to listen on the specified port (call before running thread)\n\tvoid\t\t\tinit( uint16 port, sint32 maxExpectedBlockSize );\n\n\t/// Run (exits when the listening socket disconnects)\n\tvirtual void\trun();\n\n\t/// Close listening socket\n\tvoid\t\t\tclose();\n\n\t/// Returns the listening address\n\tconst CInetAddress&\tlocalAddr() { return _ListenSock.localAddr(); }\n\nprivate:\n\n\tCBufServer\t\t\t*_Server;\n\tCListenSock\t\t\t_ListenSock;\n\tuint32\t\t\t\t_MaxExpectedBlockSize;\n\n};\n\n\ntypedef std::vector<NLMISC::IThread*> CThreadPool;\n\n\n// Mode: Small server\n#undef PRESET_BIG_SERVER\n\n#ifdef PRESET_BIG_SERVER\n// Big server\n#define DEFAULT_STRATEGY SpreadSockets\n#define DEFAULT_MAX_THREADS 64\n#define DEFAULT_MAX_SOCKETS_PER_THREADS 64\n#else\n// Small server\n#define DEFAULT_STRATEGY FillThreads\n#define DEFAULT_MAX_THREADS 64\n#define DEFAULT_MAX_SOCKETS_PER_THREADS 16\n#endif\n\n\n/**\n * Server class for layer 1\n *\n * Listening socket and accepted connections, with packet scheme.\n * The provided buffers are sent raw (no endianness conversion).\n * By default, the size time trigger is disabled, the time trigger is set to 20 ms.\n *\n * Where do the methods take place:\n * \\code\n * send(),\t                           ->  send buffer   ->  update(), flush()\n * bytesSent(), newBytesSent()\n *\n * receive(), dataAvailable(),         <- receive buffer <-  receive thread,\n * dataAvailable(),\n * bytesReceived(), newBytesReceived(),\n * connection callback, disconnection callback\n * \\endcode\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CBufServer : public CBufNetBase\n{\npublic:\n\n\tenum TThreadStategy { SpreadSockets, FillThreads };\n\n\t/** Constructor\n\t * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation)\n\t * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with\n\t * setExternalPipeForDataAvailable().\n\t */\n\tCBufServer( TThreadStategy strategy=DEFAULT_STRATEGY,\n\t\t\t\tuint16 max_threads=DEFAULT_MAX_THREADS,\n\t\t\t\tuint16 max_sockets_per_thread=DEFAULT_MAX_SOCKETS_PER_THREADS,\n\t\t\t\tbool nodelay=true, bool replaymode=false, bool initPipeForDataAvailable=true );\n\n\t/// Destructor\n\tvirtual ~CBufServer();\n\n\t/// Listens on the specified port\n\tvoid\tinit( uint16 port );\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * If quick is true, any pending data will not be sent before disconnecting.\n\t * If quick is false, a flush() will be called. In case of network congestion, the entire pending\n\t * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0\n\t * before calling disconnect().\n\t */\n\tvoid\tdisconnect( TSockId hostid, bool quick=false );\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\n\n\t/** Send a message to the specified host, or to all hosts if hostid is InvalidSockId\n\t */\n\t//void\tsend( const std::vector<uint8>& buffer, TSockId hostid );\n\tvoid\tsend( const NLMISC::CMemStream& buffer, TSockId hostid );\n\n\t/** Checks if there is some data to receive. Returns false if the receive queue is empty.\n\t * This is where the connection/disconnection callbacks can be called.\n\t */\n\tbool\tdataAvailable();\n\n#ifdef NL_OS_UNIX\n\t/** Wait until the receive queue contains something to read (implemented with a select()).\n\t * This is where the connection/disconnection callbacks can be called.\n\t * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme).\n\t * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n\t */\n\tvoid\tsleepUntilDataAvailable( uint usecMax=100000 );\n#endif\n\n\t/** Receives next block of data in the specified (resizes the vector)\n\t * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive()\n\t */\n\tvoid\treceive( NLMISC::CMemStream& buffer, TSockId* hostid );\n\n\t/// Update the network (call this method evenly)\n\tvoid\tupdate();\n\n\n\n\n\t// Returns the size in bytes of the data stored in the send queue.\n\tuint32\tgetSendQueueSize( TSockId destid );\n\n\tvoid\tdisplaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId);\n\n\tvoid displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog);\n\n\n\t/** Sets the time flush trigger (in millisecond). When this time is elapsed,\n\t * all data in the send queue is automatically sent (-1 to disable this trigger)\n\t */\n\tvoid\tsetTimeFlushTrigger( TSockId destid, sint32 ms );\n\n\t/** Sets the size flush trigger. When the size of the send queue reaches or exceeds this\n\t * value, all data in the send queue is automatically sent (-1 to disable this trigger )\n\t */\n\tvoid\tsetSizeFlushTrigger( TSockId destid, sint32 size );\n\n\t/** Force to send data pending in the send queue now. If all the data could not be sent immediately,\n\t * the returned nbBytesRemaining value is non-zero.\n\t * \\param destid The identifier of the destination connection.\n\t * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n\t * \\returns False if an error has occured (e.g. the remote host is disconnected).\n\t * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n\t */\n\tbool\tflush( TSockId destid, uint *nbBytesRemaining=NULL );\n\n\n\n\n\t/// Returns the internet address of the listening socket\n\tconst CInetAddress&\tlistenAddress() const { return _ListenTask->localAddr(); }\n\n\t/// Returns the address of the specified host\n\tconst CInetAddress& hostAddress( TSockId hostid );\n\n\t/*\n\t/// Returns the number of bytes pushed into the receive queue since the beginning (mutexed)\n\tuint32\tbytesDownloaded()\n\t{\n\t\tNLMISC::CSynchronized<uint32>::CAccessor syncbpi ( &_BytesPushedIn );\n\t\treturn syncbpi.value();\n\t}\n\t/// Returns the number of bytes downloaded since the previous call to this method\n\tuint32\tnewBytesDownloaded();\n\t*/\n\n\t/// Returns the number of bytes popped by receive() since the beginning\n\tuint64\tbytesReceived() const { return _BytesPoppedIn; }\n\n\t/// Returns the number of bytes popped by receive() since the previous call to this method\n\tuint64\tnewBytesReceived();\n\n\t/// Returns the number of bytes pushed by send() since the beginning\n\tuint64\tbytesSent() const { return _BytesPushedOut; }\n\n\t/// Returns the number of bytes pushed by send() since the previous call to this method\n\tuint64\tnewBytesSent();\n\n\t/// Returns the number of connections (at the last update())\n\tuint32\tnbConnections() const { return _NbConnections; }\n\nprotected:\n\n\tfriend class CServerBufSock;\n\tfriend class CListenTask;\n\tfriend class CServerReceiveTask;\n\n\t/// Returns the TCP_NODELAY flag\n\tbool\t\t\t\tnoDelay() const { return _NoDelay; }\n\n\t/** Binds a new socket and send buffer to an existing or a new thread (that starts)\n\t * Note: this method is called in the listening thread.\n\t */\n\tvoid\t\t\t\tdispatchNewSocket( CServerBufSock *bufsock );\n\n\t/// Returns the receive task corresponding to a particular thread\n\tCServerReceiveTask\t*receiveTask( std::vector<NLMISC::IThread*>::iterator ipt )\n\t{\n\t\treturn ((CServerReceiveTask*)((*ipt)->getRunnable()));\n\t}\n\n\t/// Pushes a buffer to the specified host's send queue and update (unless not connected)\n\t/*void pushBufferToHost( const std::vector<uint8>& buffer, TSockId hostid )\n\t{\n\t\tif ( hostid->pushBuffer( buffer ) )\n\t\t{\n\t\t\t_BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics\n\t\t}\n\t}*/\n\n\tvoid pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid )\n\t{\n\t\tnlassert( hostid != InvalidSockId );\n\t\tif ( hostid->pushBuffer( buffer ) )\n\t\t{\n\t\t\t_BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics\n\t\t}\n\t}\n\n\t// Creates a new task and run a new thread for it\n\tvoid\t\t\t\taddNewThread( CThreadPool& threadpool, CServerBufSock *bufsock );\n\n\t/// Returns the connection callback\n\tTNetCallback\t\tconnectionCallback() const { return _ConnectionCallback; }\n\n\t/// Returns the argument of the connection callback\n\tvoid*\t\t\t\targOfConnectionCallback() const { return _ConnectionCbArg; }\n\n\t/*/// Returns the synchronized number of bytes pushed into the receive queue\n\tNLMISC::CSynchronized<uint32>&\tsyncBytesPushedIn() { return _BytesPushedIn; }\n\t*/\n\nprivate:\n\n\ttypedef std::set<TSockId>\t\tTClientSet;\n\t/// List of currently connected client\n\tTClientSet\t\t\t\t\t\t_ConnectedClients;\n\n\n\t/// Thread socket-handling strategy\n\tTThreadStategy\t\t\t\t\t_ThreadStrategy;\n\n\t/// Max number of threads\n\tuint16\t\t\t\t\t\t\t_MaxThreads;\n\n\t/// Max number of sockets handled by one thread\n\tuint16\t\t\t\t\t\t\t_MaxSocketsPerThread;\n\n\t/// Listen task\n\tCListenTask\t\t\t\t\t\t*_ListenTask;\n\n\t/// Listen thread\n\tNLMISC::IThread\t\t\t\t\t*_ListenThread;\n\n\t/* Vector of receiving threads.\n\t * Thread: thread control\n\t * Thread->Runnable: access to the CServerReceiveTask object\n\t * Thread->getRunnable()->sock(): access to the socket\n\t * The purpose of this list is to delete the objects after use.\n\t */\n\tNLMISC::CSynchronized<CThreadPool>\t\t_ThreadPool;\n\n\t/// Connection callback\n\tTNetCallback\t\t\t\t\t_ConnectionCallback;\n\n\t/// Argument of the connection callback\n\tvoid*\t\t\t\t\t\t\t_ConnectionCbArg;\n\n\t/// Number of bytes pushed by send() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPushedOut;\n\n\t/// Number of bytes popped by receive() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPoppedIn;\n\n\t/// Previous number of bytes received\n\tuint64\t\t\t\t\t\t\t_PrevBytesPoppedIn;\n\n\t/// Previous number of bytes sent\n\tuint64\t\t\t\t\t\t\t_PrevBytesPushedOut;\n\n\t/// Number of connections (debug stat)\n\tuint32\t\t\t\t\t\t\t_NbConnections;\n\n\t/// TCP_NODELAY\n\tbool\t\t\t\t\t\t\t_NoDelay;\n\n\t/// Replay mode flag\n\tbool\t\t\t\t\t\t\t_ReplayMode;\n\n  /*\n\t/// Number of bytes pushed into the receive queue (by the receive threads) since the beginning.\n\tNLMISC::CSynchronized<uint32>\t_BytesPushedIn;\n\n\t/// Previous number of bytes received\n\tuint32\t\t\t\t\t\t\t_PrevBytesPushedIn;\n\t*/\n};\n\n\ntypedef std::set<TSockId>\t\t\t\t\tCConnections;\n\n\n// POLL2\n\n\n/**\n * Code of receiving threads for servers.\n * Note: the methods locations in the classes do not correspond to the threads where they are\n * executed, but to the data they use.\n */\nclass CServerReceiveTask : public NLMISC::IRunnable, public CServerTask\n{\npublic:\n\n\t/// Constructor\n\tCServerReceiveTask( CBufServer *server ) : CServerTask(), _Server(server), _Connections(\"CServerReceiveTask::_Connections\"), _RemoveSet(\"CServerReceiveTask::_RemoveSet\") {}\n\n\t/// Run\n\tvirtual void run();\n\n\t/// Returns the number of connections handled by the thread (mutexed on _Connections)\n\tuint\tnumberOfConnections()\n\t{\n\t\tuint nb;\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tnb = (uint)connectionssync.value().size();\n\t\t}\n\t\treturn nb;\n\t}\n\n\t/// Add a new connection into this thread (mutexed on _Connections)\n\tvoid\taddNewSocket( TSockId sockid )\n\t{\n\t\t//nlnettrace( \"CServerReceiveTask::addNewSocket\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tconnectionssync.value().insert( sockid );\n\t\t}\n\t\t// POLL3\n\t}\n\n// POLL4\n\n\t/** Add connection to the remove set (mutexed on _RemoveSet)\n\t * Note: you must not call this method within a mutual exclusion on _Connections, or\n\t * there will be a deadlock (see clearClosedConnection())\n\t */\n\tvoid\taddToRemoveSet( TSockId sockid )\n\t{\n\t\tnlnettrace( \"CServerReceiveTask::addToRemoveSet\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\t// Three possibilities :\n\t\t\t// - The value is inserted into the set.\n\t\t\t// - The value is already present in the set.\n\t\t\t// - The set is locked by a receive thread which is removing the closed connections.\n\t\t\t//   When the set gets unlocked, it is empty so the value is inserted. It means the\n\t\t\t//   value could be already in the set before it was cleared.\n\t\t\t//   Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex\n\t\t\t//   when it is already locked\n\t\t\t// See clearClosedConnections().\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor removesetsync( &_RemoveSet );\n\t\t\tremovesetsync.value().insert( sockid );\n\t\t\t//LNETL1_DEBUG( \"LNETL1: ic: %p - RemoveSet.size(): %d\", ic, removesetsync.value().size() );\n\t\t}\n#ifdef NL_OS_UNIX\n\t\twakeUp();\n#endif\n\t}\n\n\t/// Delete all connections referenced in the remove list (mutexed on _RemoveSet and on _Connections)\n\tvoid\tclearClosedConnections();\n\n\t/// Access to the server\n\tCBufServer\t*server()\t{ return _Server; }\n\n\tfriend\tclass CBufServer;\n\nprivate:\n\n\tCBufServer\t\t\t\t\t\t\t\t*_Server;\n\n\t/* List of sockets and send buffer.\n\t * A TSockId is a pointer to a CBufSock object\n\t */\n\tNLMISC::CSynchronized<CConnections>\t\t_Connections;\n\n\t// Connections to remove\n\tNLMISC::CSynchronized<CConnections>\t\t_RemoveSet;\n\n\t// POLL5\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_BUF_SERVER_H\n\n/* End of buf_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_server_tcp.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_SERVER_TCP_H\n#define NL_BUF_SERVER_TCP_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/mutex.h\"\n#include \"buf_net_base.h\"\n#include \"listen_sock.h\"\n#include \"buf_sock.h\"\n#include \"net_log.h\"\n\n#include <list>\n#include <set>\n\n// POLL1 (ignore POLL comments)\nstruct evconnlistener;\nstruct event_base;\n\nnamespace NLNET {\n\n\nclass CInetAddress;\nclass CBufServerTcp;\nclass CTcpReceiveTask;\n\n\n/**\n * Server class for layer 1\n *\n * Listening socket and accepted connections, with packet scheme.\n * The provided buffers are sent raw (no endianness conversion).\n * By default, the size time trigger is disabled, the time trigger is set to 20 ms.\n *\n * Where do the methods take place:\n * \\code\n * send(),\t                           ->  send buffer   ->  update(), flush()\n * bytesSent(), newBytesSent()\n *\n * receive(), dataAvailable(),         <- receive buffer <-  receive thread,\n * dataAvailable(),\n * bytesReceived(), newBytesReceived(),\n * connection callback, disconnection callback\n * \\endcode\n *\n * \\author li9chuan@qq.com\n * \\date 2018\n */\n\nclass CBufServerTcp : public CBufNetBase\n{\npublic:\n\n\tenum TThreadStategy { SpreadSockets, FillThreads };\n\n\t/** Constructor\n\t * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation)\n\t * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with\n\t * setExternalPipeForDataAvailable().\n\t */\n\tCBufServerTcp();\n\n\t/// Destructor\n\tvirtual ~CBufServerTcp();\n\n\t/// Listens on the specified port\n\tvoid\tinit( uint16 port );\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * If quick is true, any pending data will not be sent before disconnecting.\n\t * If quick is false, a flush() will be called. In case of network congestion, the entire pending\n\t * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0\n\t * before calling disconnect().\n\t */\n\tvoid\tdisconnect( TSockId hostid, bool quick=false );\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\n\n\t/** Send a message to the specified host, or to all hosts if hostid is InvalidSockId\n\t */\n\t//void\tsend( const std::vector<uint8>& buffer, TSockId hostid );\n\tvoid\tsend( const NLMISC::CMemStream& buffer, TSockId hostid );\n\n\t/** Checks if there is some data to receive. Returns false if the receive queue is empty.\n\t * This is where the connection/disconnection callbacks can be called.\n\t */\n\tbool\tdataAvailable();\n\n#ifdef NL_OS_UNIX\n\t/** Wait until the receive queue contains something to read (implemented with a select()).\n\t * This is where the connection/disconnection callbacks can be called.\n\t * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme).\n\t * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n\t */\n\tvoid\tsleepUntilDataAvailable( uint usecMax=100000 );\n#endif\n\n\t/** Receives next block of data in the specified (resizes the vector)\n\t * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive()\n\t */\n\tvoid\treceive( NLMISC::CMemStream& buffer, TSockId* hostid );\n\n\t/// Update the network (call this method evenly)\n\tvoid\tupdate();\n\n\n\n\n\t// Returns the size in bytes of the data stored in the send queue.\n\tuint32\tgetSendQueueSize( TSockId destid );\n\n\tvoid\tdisplaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId);\n\n\tvoid    displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog);\n\n\n\t/** Sets the time flush trigger (in millisecond). When this time is elapsed,\n\t * all data in the send queue is automatically sent (-1 to disable this trigger)\n\t */\n\tvoid\tsetTimeFlushTrigger( TSockId destid, sint32 ms );\n\n\t/** Sets the size flush trigger. When the size of the send queue reaches or exceeds this\n\t * value, all data in the send queue is automatically sent (-1 to disable this trigger )\n\t */\n\tvoid\tsetSizeFlushTrigger( TSockId destid, sint32 size );\n\n\t/** Force to send data pending in the send queue now. If all the data could not be sent immediately,\n\t * the returned nbBytesRemaining value is non-zero.\n\t * \\param destid The identifier of the destination connection.\n\t * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n\t * \\returns False if an error has occured (e.g. the remote host is disconnected).\n\t * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n\t */\n\tbool\tflush( TSockId destid, uint *nbBytesRemaining=NULL );\n\n\n\n\n\t/// Returns the internet address of the listening socket\n\tconst CInetAddress&\tlistenAddress() const { return _ListenSock.localAddr(); }\n\n\t/// Returns the address of the specified host\n\tconst CInetAddress& hostAddress( TSockId hostid );\n\n\t/*\n\t/// Returns the number of bytes pushed into the receive queue since the beginning (mutexed)\n\tuint32\tbytesDownloaded()\n\t{\n\t\tNLMISC::CSynchronized<uint32>::CAccessor syncbpi ( &_BytesPushedIn );\n\t\treturn syncbpi.value();\n\t}\n\t/// Returns the number of bytes downloaded since the previous call to this method\n\tuint32\tnewBytesDownloaded();\n\t*/\n\n\t/// Returns the number of bytes popped by receive() since the beginning\n\tuint64\tbytesReceived() const { return _BytesPoppedIn; }\n\n\t/// Returns the number of bytes popped by receive() since the previous call to this method\n\tuint64\tnewBytesReceived();\n\n\t/// Returns the number of bytes pushed by send() since the beginning\n\tuint64\tbytesSent() const { return _BytesPushedOut; }\n\n\t/// Returns the number of bytes pushed by send() since the previous call to this method\n\tuint64\tnewBytesSent();\n\n\t/// Returns the number of connections (at the last update())\n\tuint32\tnbConnections() const { return _NbConnections; }\n\nprotected:\n\n\tfriend class CTcpReceiveTask;\n\n\t/// Returns the receive task corresponding to a particular thread\n\tCServerReceiveTask\t*receiveTask( std::vector<NLMISC::IThread*>::iterator ipt )\n\t{\n\t\treturn ((CServerReceiveTask*)((*ipt)->getRunnable()));\n\t}\n\n\t/// Pushes a buffer to the specified host's send queue and update (unless not connected)\n\t/*void pushBufferToHost( const std::vector<uint8>& buffer, TSockId hostid )\n\t{\n\t\tif ( hostid->pushBuffer( buffer ) )\n\t\t{\n\t\t\t_BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics\n\t\t}\n\t}*/\n\n\t//void pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid )\n\t//{\n\t//\tnlassert( hostid != InvalidSockId );\n\t//\tif ( hostid->pushBuffer( buffer ) )\n\t//\t{\n\t//\t\t_BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics\n\t//\t}\n\t//}\n\n\t/// Returns the connection callback\n\tTNetCallback\t\tconnectionCallback() const { return _ConnectionCallback; }\n\n\t/// Returns the argument of the connection callback\n\tvoid*\t\t\t\targOfConnectionCallback() const { return _ConnectionCbArg; }\n\n\t/*/// Returns the synchronized number of bytes pushed into the receive queue\n\tNLMISC::CSynchronized<uint32>&\tsyncBytesPushedIn() { return _BytesPushedIn; }\n\t*/\n\nprivate:\n\n\tCListenSock\t\t\t\t\t\t_ListenSock;\n\tuint32\t\t\t\t\t\t\t_MaxExpectedBlockSize;\n\n\n\tCTcpReceiveTask\t\t\t*_WebSocketReceiveTask;\n\n\n\ttypedef std::set<TSockId>\t\tTClientSet;\n\t/// List of currently connected client\n\tTClientSet\t\t\t\t\t\t_ConnectedClients;\n\n    std::vector<TSockId>            _RmDisConnectSockids;\n\n\t/// Thread socket-handling strategy\n\tTThreadStategy\t\t\t\t\t_ThreadStrategy;\n\n\t/// Max number of threads\n\tuint16\t\t\t\t\t\t\t_MaxThreads;\n\n\t/// Max number of sockets handled by one thread\n\tuint16\t\t\t\t\t\t\t_MaxSocketsPerThread;\n\n\t/// Connection callback\n\tTNetCallback\t\t\t\t\t_ConnectionCallback;\n\n\t/// Argument of the connection callback\n\tvoid*\t\t\t\t\t\t\t_ConnectionCbArg;\n\n\t/// Number of bytes pushed by send() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPushedOut;\n\n\t/// Number of bytes popped by receive() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPoppedIn;\n\n\t/// Previous number of bytes received\n\tuint64\t\t\t\t\t\t\t_PrevBytesPoppedIn;\n\n\t/// Previous number of bytes sent\n\tuint64\t\t\t\t\t\t\t_PrevBytesPushedOut;\n\n\t/// Number of connections (debug stat)\n\tuint32\t\t\t\t\t\t\t_NbConnections;\n\n\n  /*\n\t/// Number of bytes pushed into the receive queue (by the receive threads) since the beginning.\n\tNLMISC::CSynchronized<uint32>\t_BytesPushedIn;\n\n\t/// Previous number of bytes received\n\tuint32\t\t\t\t\t\t\t_PrevBytesPushedIn;\n\t*/\n};\n\ntypedef std::set<TSockId>\t\t\t\t\tCConnections;\n\nclass CTcpReceiveTask : public NLMISC::IRunnable\n{\npublic:\n\n\t/// Constructor\n\tCTcpReceiveTask() : _Connections(\"CTcpReceiveTask::_Connections\"), _RemoveSet(\"CTcpReceiveTask::_RemoveSet\")  {}\n\n\tvoid init( CBufServerTcp*, uint16 port );\n    bool start();\n    void close();\n\n\t/// Run\n\tvirtual void run();\n\n\t/// Returns the number of connections handled by the thread (mutexed on _Connections)\n\tuint\tnumberOfConnections()\n\t{\n\t\tuint nb;\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tnb = (uint)connectionssync.value().size();\n\t\t}\n\t\treturn nb;\n\t}\n\n\t/// Add a new connection into this thread (mutexed on _Connections)\n\tvoid\taddNewSocket( TSockId sockid )\n\t{\n\t\t//nlnettrace( \"CServerReceiveTask::addNewSocket\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tconnectionssync.value().insert( sockid );\n\t\t}\n\t\t// POLL3\n\t}\n\n// POLL4\n\n\t/** Add connection to the remove set (mutexed on _RemoveSet)\n\t * Note: you must not call this method within a mutual exclusion on _Connections, or\n\t * there will be a deadlock (see clearClosedConnection())\n\t */\n\tvoid\taddToRemoveSet( TSockId sockid )\n\t{\n\t\tnlnettrace( \"CTcpReceiveTask::addToRemoveSet\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\t// Three possibilities :\n\t\t\t// - The value is inserted into the set.\n\t\t\t// - The value is already present in the set.\n\t\t\t// - The set is locked by a receive thread which is removing the closed connections.\n\t\t\t//   When the set gets unlocked, it is empty so the value is inserted. It means the\n\t\t\t//   value could be already in the set before it was cleared.\n\t\t\t//   Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex\n\t\t\t//   when it is already locked\n\t\t\t// See clearClosedConnections().\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor removesetsync( &_RemoveSet );\n\t\t\tremovesetsync.value().insert( sockid );\n\t\t\t//LNETL1_DEBUG( \"LNETL1: ic: %p - RemoveSet.size(): %d\", ic, removesetsync.value().size() );\n\t\t}\n\t}\n\n\t/// Access to the server\n\tCBufServerTcp\t*server()\t{ return _Server; }\n\n\tfriend\tclass CBufServerTcp;\n\n\n\nprotected:\n\n    /// Returns true if the requireExit() has been called\n    bool\texitRequired() const { return _ExitRequired; }\n\nprivate:\n\n\tCBufServerTcp\t\t\t\t\t\t    *_Server;\n    NLMISC::IThread*                        _ProcTableThread;\n    volatile bool\t                        _ExitRequired;\n\n    event_base                              *pEventBase;\n    evconnlistener                          *pEvListener;\n\n\t/* List of sockets and send buffer.\n\t * A TSockId is a pointer to a CBufSock object\n\t */\n\tNLMISC::CSynchronized<CConnections>\t\t_Connections;\n\n\t// Connections to remove\n\tNLMISC::CSynchronized<CConnections>\t\t_RemoveSet;\n};\n\n} // NLNET\n\n\n#endif // NL_BUF_SERVER_TCP_H\n\n/* End of buf_server_tcp.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_server_tcp_func.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_SERVER_TCP_FUNC_H\n#define NL_BUF_SERVER_TCP_FUNC_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/sstring.h\"\n\n#include \"event2/event.h\"\n#include \"event2/listener.h\"\n#include \"event2/bufferevent.h\"\n\n\nnamespace NLNET {\n\n    class CBufServerTcp;\n    class CServerBufSock;\n\n    struct TcpListenArgs\n    {\n        event_base*             pEventBase;\n        CBufServerTcp*          pServer;\n        TcpListenArgs( event_base* eventbase, CBufServerTcp* bufsvr ) : pEventBase(eventbase), pServer(bufsvr) {}\n    };\n\n\n    void    tcp_socket_event_cb( bufferevent *bev, short events, void *args );\n\n    void    tcp_socket_read_cb( bufferevent *bev, void *args ); \n\n    void    tcp_listener_cb( evconnlistener *listener, evutil_socket_t fd, sockaddr *sock, int socklen, void *args );  \n\n\n}\n\n\n#endif // NL_BUF_SERVER_TCP_FUNC_H\n\n/* End of buf_server_tcp_func.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_server_websocket.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_SERVER_WEBSOCKET_H\n#define NL_BUF_SERVER_WEBSOCKET_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/mutex.h\"\n#include \"buf_net_base.h\"\n#include \"listen_sock.h\"\n#include \"buf_sock.h\"\n#include \"net_log.h\"\n\n#include <list>\n#include <set>\n\n// POLL1 (ignore POLL comments)\nstruct evconnlistener;\nstruct event_base;\n\nnamespace NLNET {\n\n\nclass CInetAddress;\nclass CBufServerWebsocket;\nclass CWebSocketReceiveTask;\n\n\n/**\n * Server class for layer 1\n *\n * Listening socket and accepted connections, with packet scheme.\n * The provided buffers are sent raw (no endianness conversion).\n * By default, the size time trigger is disabled, the time trigger is set to 20 ms.\n *\n * Where do the methods take place:\n * \\code\n * send(),\t                           ->  send buffer   ->  update(), flush()\n * bytesSent(), newBytesSent()\n *\n * receive(), dataAvailable(),         <- receive buffer <-  receive thread,\n * dataAvailable(),\n * bytesReceived(), newBytesReceived(),\n * connection callback, disconnection callback\n * \\endcode\n *\n * \\author li9chuan@qq.com\n * \\date 2018\n */\n\nclass CBufServerWebsocket : public CBufNetBase\n{\npublic:\n\n\tenum TThreadStategy { SpreadSockets, FillThreads };\n\n\t/** Constructor\n\t * Set nodelay to true to disable the Nagle buffering algorithm (see CTcpSock documentation)\n\t * initPipeForDataAvailable is for Linux only. Set it to false if you provide an external pipe with\n\t * setExternalPipeForDataAvailable().\n\t */\n\tCBufServerWebsocket();\n\n\t/// Destructor\n\tvirtual ~CBufServerWebsocket();\n\n\t/// Listens on the specified port\n\tvoid\tinit( uint16 port );\n\n    void    setupSsl( std::string& ssl_ca, std::string& ssl_crt, std::string& ssl_prvkey );\n    void*   getSslCtx() { return _SslCtx; }\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * If quick is true, any pending data will not be sent before disconnecting.\n\t * If quick is false, a flush() will be called. In case of network congestion, the entire pending\n\t * data may not be flushed. If this is a problem, call flush() multiple times until it returns 0\n\t * before calling disconnect().\n\t */\n\tvoid\tdisconnect( TSockId hostid, bool quick=false );\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback( TNetCallback cb, void* arg ) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\n\n\t/** Send a message to the specified host, or to all hosts if hostid is InvalidSockId\n\t */\n\t//void\tsend( const std::vector<uint8>& buffer, TSockId hostid );\n\tvoid\tsend( const NLMISC::CMemStream& buffer, TSockId hostid );\n\n\t/** Checks if there is some data to receive. Returns false if the receive queue is empty.\n\t * This is where the connection/disconnection callbacks can be called.\n\t */\n\tbool\tdataAvailable();\n\n#ifdef NL_OS_UNIX\n\t/** Wait until the receive queue contains something to read (implemented with a select()).\n\t * This is where the connection/disconnection callbacks can be called.\n\t * If you use this method (blocking scheme), don't use dataAvailable() (non-blocking scheme).\n\t * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n\t */\n\tvoid\tsleepUntilDataAvailable( uint usecMax=100000 );\n#endif\n\n\t/** Receives next block of data in the specified (resizes the vector)\n\t * You must call dataAvailable() or sleepUntilDataAvailable() before every call to receive()\n\t */\n\tvoid\treceive( NLMISC::CMemStream& buffer, TSockId* hostid );\n\n\t/// Update the network (call this method evenly)\n\tvoid\tupdate();\n\n\n\n\n\t// Returns the size in bytes of the data stored in the send queue.\n\tuint32\tgetSendQueueSize( TSockId destid );\n\n\tvoid\tdisplaySendQueueStat( NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId);\n\n\tvoid    displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog);\n\n\n\t/** Sets the time flush trigger (in millisecond). When this time is elapsed,\n\t * all data in the send queue is automatically sent (-1 to disable this trigger)\n\t */\n\tvoid\tsetTimeFlushTrigger( TSockId destid, sint32 ms );\n\n\t/** Sets the size flush trigger. When the size of the send queue reaches or exceeds this\n\t * value, all data in the send queue is automatically sent (-1 to disable this trigger )\n\t */\n\tvoid\tsetSizeFlushTrigger( TSockId destid, sint32 size );\n\n\t/** Force to send data pending in the send queue now. If all the data could not be sent immediately,\n\t * the returned nbBytesRemaining value is non-zero.\n\t * \\param destid The identifier of the destination connection.\n\t * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n\t * \\returns False if an error has occured (e.g. the remote host is disconnected).\n\t * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n\t */\n\tbool\tflush( TSockId destid, uint *nbBytesRemaining=NULL );\n\n\n\n\n\t/// Returns the internet address of the listening socket\n\tconst CInetAddress&\tlistenAddress() const { return _ListenSock.localAddr(); }\n\n\t/// Returns the address of the specified host\n\tconst CInetAddress& hostAddress( TSockId hostid );\n\n\t/*\n\t/// Returns the number of bytes pushed into the receive queue since the beginning (mutexed)\n\tuint32\tbytesDownloaded()\n\t{\n\t\tNLMISC::CSynchronized<uint32>::CAccessor syncbpi ( &_BytesPushedIn );\n\t\treturn syncbpi.value();\n\t}\n\t/// Returns the number of bytes downloaded since the previous call to this method\n\tuint32\tnewBytesDownloaded();\n\t*/\n\n\t/// Returns the number of bytes popped by receive() since the beginning\n\tuint64\tbytesReceived() const { return _BytesPoppedIn; }\n\n\t/// Returns the number of bytes popped by receive() since the previous call to this method\n\tuint64\tnewBytesReceived();\n\n\t/// Returns the number of bytes pushed by send() since the beginning\n\tuint64\tbytesSent() const { return _BytesPushedOut; }\n\n\t/// Returns the number of bytes pushed by send() since the previous call to this method\n\tuint64\tnewBytesSent();\n\n\t/// Returns the number of connections (at the last update())\n\tuint32\tnbConnections() const { return _NbConnections; }\n\nprotected:\n\n\tfriend class CWebSocketReceiveTask;\n\n\t/// Returns the receive task corresponding to a particular thread\n\tCServerReceiveTask\t*receiveTask( std::vector<NLMISC::IThread*>::iterator ipt )\n\t{\n\t\treturn ((CServerReceiveTask*)((*ipt)->getRunnable()));\n\t}\n\n\t/// Pushes a buffer to the specified host's send queue and update (unless not connected)\n\t/*void pushBufferToHost( const std::vector<uint8>& buffer, TSockId hostid )\n\t{\n\t\tif ( hostid->pushBuffer( buffer ) )\n\t\t{\n\t\t\t_BytesPushedOut += buffer.size() + sizeof(TBlockSize); // statistics\n\t\t}\n\t}*/\n\n\t//void pushBufferToHost( const NLMISC::CMemStream& buffer, TSockId hostid )\n\t//{\n\t//\tnlassert( hostid != InvalidSockId );\n\t//\tif ( hostid->pushBuffer( buffer ) )\n\t//\t{\n\t//\t\t_BytesPushedOut += buffer.length() + sizeof(TBlockSize); // statistics\n\t//\t}\n\t//}\n\n\t/// Returns the connection callback\n\tTNetCallback\t\tconnectionCallback() const { return _ConnectionCallback; }\n\n\t/// Returns the argument of the connection callback\n\tvoid*\t\t\t\targOfConnectionCallback() const { return _ConnectionCbArg; }\n\n\t/*/// Returns the synchronized number of bytes pushed into the receive queue\n\tNLMISC::CSynchronized<uint32>&\tsyncBytesPushedIn() { return _BytesPushedIn; }\n\t*/\n\nprivate:\n\n\tCListenSock\t\t\t\t\t\t_ListenSock;\n\tuint32\t\t\t\t\t\t\t_MaxExpectedBlockSize;\n\n\n\tCWebSocketReceiveTask\t\t\t*_WebSocketReceiveTask;\n\n\n\ttypedef std::set<TSockId>\t\tTClientSet;\n\t/// List of currently connected client\n\tTClientSet\t\t\t\t\t\t_ConnectedClients;\n\n    std::vector<TSockId>            _RmDisConnectSockids;\n\n\t/// Thread socket-handling strategy\n\tTThreadStategy\t\t\t\t\t_ThreadStrategy;\n\n\t/// Max number of threads\n\tuint16\t\t\t\t\t\t\t_MaxThreads;\n\n\t/// Max number of sockets handled by one thread\n\tuint16\t\t\t\t\t\t\t_MaxSocketsPerThread;\n\n\t/// Connection callback\n\tTNetCallback\t\t\t\t\t_ConnectionCallback;\n\n\t/// Argument of the connection callback\n\tvoid*\t\t\t\t\t\t\t_ConnectionCbArg;\n\n\t/// Number of bytes pushed by send() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPushedOut;\n\n\t/// Number of bytes popped by receive() since the beginning\n\tuint64\t\t\t\t\t\t\t_BytesPoppedIn;\n\n\t/// Previous number of bytes received\n\tuint64\t\t\t\t\t\t\t_PrevBytesPoppedIn;\n\n\t/// Previous number of bytes sent\n\tuint64\t\t\t\t\t\t\t_PrevBytesPushedOut;\n\n\t/// Number of connections (debug stat)\n\tuint32\t\t\t\t\t\t\t_NbConnections;\n\n\n    void*                           _SslCtx;\n  /*\n\t/// Number of bytes pushed into the receive queue (by the receive threads) since the beginning.\n\tNLMISC::CSynchronized<uint32>\t_BytesPushedIn;\n\n\t/// Previous number of bytes received\n\tuint32\t\t\t\t\t\t\t_PrevBytesPushedIn;\n\t*/\n};\n\ntypedef std::set<TSockId>\t\t\t\t\tCConnections;\n\nclass CWebSocketReceiveTask : public NLMISC::IRunnable\n{\npublic:\n\n\t/// Constructor\n\tCWebSocketReceiveTask() : _Connections(\"CWebSocketReceiveTask::_Connections\"), _RemoveSet(\"CWebSocketReceiveTask::_RemoveSet\")  {}\n\n\tvoid init( CBufServerWebsocket*, uint16 port );\n    bool start();\n    void close();\n\n\t/// Run\n\tvirtual void run();\n\n\t/// Returns the number of connections handled by the thread (mutexed on _Connections)\n\tuint\tnumberOfConnections()\n\t{\n\t\tuint nb;\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tnb = (uint)connectionssync.value().size();\n\t\t}\n\t\treturn nb;\n\t}\n\n\t/// Add a new connection into this thread (mutexed on _Connections)\n\tvoid\taddNewSocket( TSockId sockid )\n\t{\n\t\t//nlnettrace( \"CServerReceiveTask::addNewSocket\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\tconnectionssync.value().insert( sockid );\n\t\t}\n\t\t// POLL3\n\t}\n\n// POLL4\n\n\t/** Add connection to the remove set (mutexed on _RemoveSet)\n\t * Note: you must not call this method within a mutual exclusion on _Connections, or\n\t * there will be a deadlock (see clearClosedConnection())\n\t */\n\tvoid\taddToRemoveSet( TSockId sockid )\n\t{\n\t\tnlnettrace( \"CWebSocketReceiveTask::addToRemoveSet\" );\n\t\tnlassert( sockid != InvalidSockId );\n\t\t{\n\t\t\t// Three possibilities :\n\t\t\t// - The value is inserted into the set.\n\t\t\t// - The value is already present in the set.\n\t\t\t// - The set is locked by a receive thread which is removing the closed connections.\n\t\t\t//   When the set gets unlocked, it is empty so the value is inserted. It means the\n\t\t\t//   value could be already in the set before it was cleared.\n\t\t\t//   Note: with a fonction such as tryAcquire(), we could avoid to enter the mutex\n\t\t\t//   when it is already locked\n\t\t\t// See clearClosedConnections().\n\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor removesetsync( &_RemoveSet );\n\t\t\tremovesetsync.value().insert( sockid );\n\t\t\t//LNETL1_DEBUG( \"LNETL1: ic: %p - RemoveSet.size(): %d\", ic, removesetsync.value().size() );\n\t\t}\n\t}\n\n\t/// Access to the server\n\tCBufServerWebsocket\t*server()\t{ return _Server; }\n\n\tfriend\tclass CBufServerWebsocket;\n\n\n\nprotected:\n\n    /// Returns true if the requireExit() has been called\n    bool\texitRequired() const { return _ExitRequired; }\n\nprivate:\n\n\tCBufServerWebsocket\t\t\t\t\t\t*_Server;\n    NLMISC::IThread*                        _ProcTableThread;\n    volatile bool\t                        _ExitRequired;\n\n    event_base                              *pEventBase;\n    evconnlistener                          *pEvListener;\n\n\t/* List of sockets and send buffer.\n\t * A TSockId is a pointer to a CBufSock object\n\t */\n\tNLMISC::CSynchronized<CConnections>\t\t_Connections;\n\n\t// Connections to remove\n\tNLMISC::CSynchronized<CConnections>\t\t_RemoveSet;\n};\n\n} // NLNET\n\n\n#endif // NL_BUF_SERVER_WEBSOCKET_H\n\n/* End of buf_server_websocket.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_server_websocket_func.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_WEBSOCKET_FUN_H\n#define NL_WEBSOCKET_FUN_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/misc/object_vector.h\"\n\n#include \"event2/event.h\"\n#include \"event2/listener.h\"\n#include \"event2/bufferevent.h\"\n\nnamespace NLNET {\n\n#define WEBSOCK_FRAME_HAVE_NEXT         (0x0)           ///     ʾһ֡OpcodeΪ0ʱʾݴݷƬǰյ֡ΪһݷƬ\n#define WEBSOCK_FRAME_TEXT\t            (0x1)           ///     %x1ʾһı֡frame    %x2ʾһ֡frame\n#define WEBSOCK_FRAME_BIN\t            (0x2)\n#define WEBSOCK_FRAME_DIS_CONNECT\t    (0x8)\n#define WEBSOCK_FRAME_PING\t            (0x9)\n#define WEBSOCK_FRAME_PONG\t            (0xa)\n\n\n    inline uint16 myhtons(uint16 n) {\n        return ((n & 0xff00) >> 8) | ((n & 0x00ff) << 8);\n    }\n\n    inline uint16 myntohs(uint16 n) {\n        return ((n & 0xff00) >> 8) | ((n & 0x00ff) << 8);\n    }\n\n    inline uint32 myhtonl(uint32 n) {\n        return ((n & 0xff000000) >> 24) | ((n & 0x00ff0000) >> 8) | ((n & 0x0000ff00) << 8) | ((n & 0x000000ff) << 24);\n    }\n\n    inline uint32 myntohl(uint32 n) {\n        return ((n & 0xff000000) >> 24) | ((n & 0x00ff0000) >> 8) | ((n & 0x0000ff00) << 8) | ((n & 0x000000ff) << 24);\n    }\n\n    inline uint64 myhtonll(uint64 n) {\n        return (uint64)myhtonl(n >> 32) | ((uint64)myhtonl(n) << 32);\n    }\n\n    inline uint64 myntohll(uint64 n) {\n        return (uint64)myhtonl(n >> 32) | ((uint64)myhtonl(n) << 32);\n    }\n\n    class CBufServerWebsocket;\n    class CServerBufSock;\n\n    struct WSListenArgs\n    {\n        event_base*             pEventBase;\n        CBufServerWebsocket*    pServer;\n        void*                   pSslCtx;\n        WSListenArgs( event_base* eventbase, CBufServerWebsocket* bufsvr ) : pEventBase(eventbase), pServer(bufsvr), pSslCtx(NULL) {}\n    };\n\n    struct WebSocketFrame\n    {\n        uint8   fin;\n        uint8   opcode;\n        uint8   mask;\n        uint64  payload_len;\n        unsigned char masking_key[4];\n    };\n\n    NLMISC::CSString generate_key(const NLMISC::CSString &key);\n\n\n    NLMISC::CSString generate_websocket_response( NLMISC::CSString& sec_websocket_key ); \n\n\n    sint32  parse_frame_header( const uint8 *buf, WebSocketFrame& frame );\n\n\n    inline void unmask_payload_data( WebSocketFrame& frame, uint8* buff )\n    {\n        for ( uint32 i = 0; i < frame.payload_len; ++i )\n        {\n            *(buff + i) = *(buff + i) ^ *(frame.masking_key + i % 4);\n        }\n    }\n\n    void    fill_frame_buffer( const uint8* payload_data, uint32 payload_len, NLMISC::CObjectVector<uint8>& out_frame, uint8 opcode, uint8 fin=1 );\n\n    void    ws_socket_event_cb( bufferevent *bev, short events, void *args );\n\n    void    ws_socket_read_cb( bufferevent *bev, void *args ); \n\n    //һ¿ͻϷ  \n    //˺ʱlibeventѾacceptͻˡÿͻ˵\n    //ļΪfd\n    void    ws_listener_cb( evconnlistener *listener, evutil_socket_t fd, sockaddr *sock, int socklen, void *args );  \n}\n\n\n#endif // NL_WEBSOCKET_FUN_H\n\n/* End of web_sock_fun.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/buf_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_BUF_SOCK_H\n#define NL_BUF_SOCK_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"buf_net_base.h\"\n#include \"tcp_sock.h\"\n#include \"net_log.h\"\n\n\n//#include <deque>\nstruct  bufferevent;\n\nnamespace NLNET {\n\n\n#define nlnettrace(__msg) //LNETL1_DEBUG(\"LNETL1: %s\",__msg);\n\n\nclass   CTcpSock;\nclass   CServerReceiveTask;\nclass   CBufNetBase;\n\n\n\n/**\n * CBufSock\n * A socket and its sending buffer\n */\nclass CBufSock\n{\npublic:\n\n\t/// Destructor\n\tvirtual ~CBufSock();\n\n\t/// Sets the application identifier\n\tvoid\t\t\t\t\tsetAppId( uintptr_t id ) { _AppId = id; }\n\n\t/// Returns the application identifier\n\tuintptr_t\t\t\t\tappId() const { return _AppId; }\n\n\t/// Returns a string with the characteristics of the object\n\tstd::string\t\t\t\tasString() const;\n\n\t/// get the TCP sock object\n\tconst CTcpSock\t\t\t*getTcpSock() const { return Sock;}\n\n\t/// Little tricky but this string is used by Layer4 to know which callback is authorized.\n\t/// This is empty when all callback are authorized.\n\tstd::string\t\t\t\tAuthorizedCallback;\n\npublic:\n\n\tfriend class CBufClient;\n\tfriend class CBufServer;\n    friend class CBufServerWebsocket;\n\tfriend class CClientReceiveTask;\n\tfriend class CServerReceiveTask;\n\n\tfriend class CCallbackClient;\n\tfriend class CCallbackServer;\n    friend class CCallbackServerWebSocket;\n\tfriend class CCallbackNetBase;\n\n\t/** Constructor\n\t * \\param sock To provide an external socket. Set it to NULL to create it internally.\n\t */\n\tCBufSock( CTcpSock *sock=NULL );\n\n\t///@name Sending data\n\t//@{\n\n\t/// Update the network sending (call this method evenly). Returns false if an error occured.\n\tbool\tupdate();\n\n\t/** Sets the time flush trigger (in millisecond). When this time is elapsed,\n\t * all data in the send queue is automatically sent (-1 to disable this trigger)\n\t */\n\tvoid\tsetTimeFlushTrigger( sint32 ms );\n\n\t/** Sets the size flush trigger. When the size of the send queue reaches or exceeds this\n\t * calue, all data in the send queue is automatically sent (-1 to disable this trigger )\n\t */\n\tvoid\tsetSizeFlushTrigger( sint32 size ) { _TriggerSize = size; }\n\n\t/** Force to send data pending in the send queue now. In the case of a non-blocking socket\n\t * (see CNonBlockingBufSock), if all the data could not be sent immediately,\n\t * the returned nbBytesRemaining value is non-zero.\n\t * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n\t * \\returns False if an error has occured (e.g. the remote host is disconnected).\n\t * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n\t */\n\tbool\tflush( uint *nbBytesRemaining=NULL );\n\n\t//@}\n\n\t/// Returns \"CLT \" (client)\n\tvirtual std::string typeStr() const { return \"CLT \"; }\n\n\t/** Pushes a disconnection message into bnb's receive queue, if it has not already been done\n\t * (returns true in this case). You can either specify a sockid (for server) or InvalidSockId (for client)\n\t */\n\tbool advertiseDisconnection( CBufNetBase *bnb, TSockId sockid )\n\t{\n#ifdef NL_DEBUG\n\t\tif ( sockid != InvalidSockId )\n\t\t{\n\t\t\tnlassert( sockid == this );\n\t\t}\n#endif\n\t\treturn advertiseSystemEvent( bnb, sockid, _KnowConnected, true, CBufNetBase::Disconnection );\n\t}\n\n\n\t/** Pushes a system message into bnb's receive queue, if the flags meets the condition, then\n\t * resets the flag and returns true. You can either specify a sockid (for server) or InvalidSockId (for client).\n\t */\n\tbool advertiseSystemEvent(\n\t\tCBufNetBase *bnb, TSockId sockid, bool& flag, bool condition, CBufNetBase::TEventType event )\n\t{\n#ifdef NL_DEBUG\n\t\tif ( sockid != InvalidSockId )\n\t\t{\n\t\t\tnlassert( sockid == this );\n\t\t}\n#endif\n\t\t// Test flag\n\t\tif ( flag==condition )\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Pushing event to %s\", asString().c_str() );\n\t\t\tstd::vector<uint8> buffer;\n\t\t\tif ( sockid == InvalidSockId )\n\t\t\t{\n\t\t\t\t// Client: event type only\n\t\t\t\tbuffer.resize( 1 );\n\t\t\t\tbuffer[0] = uint8(event);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Server: sockid + event type\n\t\t\t\tbuffer.resize( sizeof(TSockId) + 1 );\n\t\t\t\tmemcpy( &*buffer.begin(), &sockid, sizeof(TSockId) );\n\t\t\t\tbuffer[sizeof(TSockId)] = uint8(event);\n\t\t\t}\n\t\t\t// Push\n\t\t\tbnb->pushMessageIntoReceiveQueue( buffer );\n\n\t\t\t// Reset flag\n\t\t\tflag = !condition;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/** Pushes a buffer to the send queue and update,\n\t * or returns false if the socket is not physically connected the or an error occured during sending\n\t */\n\tbool pushBuffer( const NLMISC::CMemStream& buffer )\n\t{\n\t\tnlassert (this != InvalidSockId);\t// invalid bufsock\n//\t\tLNETL1_DEBUG( \"LNETL1: Pushing buffer to %s\", asString().c_str() );\n\n\t\tstatic uint32 biggerBufferSize = 64000;\n\t\tif (buffer.length() > biggerBufferSize)\n\t\t{\n\t\t\tbiggerBufferSize = buffer.length();\n\t\t\tLNETL1_DEBUG (\"LNETL1: new record! bigger network message pushed (sent) is %u bytes\", biggerBufferSize);\n\t\t}\n\n\t\tif ( Sock->connected() )\n\t\t{\n\t\t\t// Push into host's send queue\n\t\t\tSendFifo.push( buffer );\n\n\t\t\t// Update sending\n\t\t\tbool res = update ();\n\t\t\treturn res; // not checking the result as in CBufServer::update()\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool SendToLibEvent( const NLMISC::CMemStream& buffer, bool add_ws_head=false );\n\n\t/// Connects to the specified addr; set connectedstate to true if no connection advertising is needed\n\tvoid connect( const CInetAddress& addr, bool nodelay, bool connectedstate );\n\n\t/// Disconnects; set connectedstate to false if no disconnection advertising is needed\n\tvoid disconnect( bool connectedstate );\n\n\t/// Sets the \"logically connected\" state (changed when processing a connection/disconnection callback)\n\tvoid setConnectedState( bool connectedstate ) { _ConnectedState = connectedstate; }\n\n\t/// Returns the \"logically connected\" state (changed when processing a connection/disconnection callback)\n\tbool connectedState() const { return _ConnectedState; }\n\n\t// Send queue\n\tNLMISC::CBufFIFO\tSendFifo;\n\n\t// Socket (pointer because it can be allocated by an accept())\n\tCTcpSock\t\t\t*Sock;\n\n\t// Prevents from pushing a connection/disconnection event twice\n\tbool\t\t\t\t_KnowConnected;\n\n    bufferevent*        m_BEVHandle;\n    CBufNetBase*        m_BufNetHandle;\n    bool                m_Handshake;\n    void*               m_Ssl;              // SSL*\n\nprivate:\n\n#ifdef NL_DEBUG\n\tenum TFlushTrigger { FTTime, FTSize, FTManual };\n\tTFlushTrigger\t\t_FlushTrigger;\n#endif\n\n\tNLMISC::TTime\t\t_LastFlushTime; // updated only if time trigger is enabled (TriggerTime!=-1)\n\tNLMISC::TTime\t\t_TriggerTime;\n\tsint32\t\t\t\t_TriggerSize;\n\n\tNLMISC::CObjectVector<uint8> _ReadyToSendBuffer;\n\tTBlockSize\t\t\t_RTSBIndex;\n\n\tuintptr_t\t\t\t_AppId;\n\n\t// Connected state (from the user's point of view, i.e. changed when the connection/disconnection event is at the front of the receive queue)\n\tbool\t\t\t\t_ConnectedState;\n\n    \n};\n\n\n/**\n * CNonBlockingBufSock\n * A socket, its send buffer plus a nonblocking receiving system\n */\nclass CNonBlockingBufSock : public CBufSock\n{\npublic:\n\n\tfriend class CBufClient;\n\tfriend class CClientReceiveTask;\n\n\t/** Constructor\n     * \\param sock To provide an external socket. Set it to NULL to create it internally.\n     * \\maxExpectedBlockSize Default value: receiving limited to 10 M per block)\n     */\n\tCNonBlockingBufSock( CTcpSock *sock=NULL, uint32 maxExpectedBlockSize=10485760 );\n\n\t/** Call this method after connecting (for a client connection) to set the non-blocking mode.\n\t * For a server connection, call it as soon as the object is constructed\n\t */\n\tvoid\t\t\t\t\t\tsetNonBlocking() { Sock->setNonBlockingMode( true ); }\n\n\t/// Set the size limit for received blocks\n\tvoid\t\t\t\t\t\tsetMaxExpectedBlockSize( sint32 limit ) { _MaxExpectedBlockSize = limit; }\n\n\t/** Receives a part of a message (nonblocking socket only)\n\t * \\param nbExtraBytes Number of bytes to reserve for extra information such as the event type\n\t * \\return True if the message has been completely received\n\t */\n\tbool\t\t\t\t\t\treceivePart( uint32 nbExtraBytes );\n\n\t/// Fill the event type byte at pos length()(for a client connection)\n\tvoid\t\t\t\t\t\tfillEventTypeOnly() { _ReceiveBuffer[_Length] = (uint8)CBufNetBase::User; }\n\n\t/** Return the length of the received block (call after receivePart() returns true).\n\t * The total size of received buffer is length() + nbExtraBytes (passed to receivePart()).\n\t */\n\tuint32\t\t\t\t\t\tlength() const { return _Length; }\n\n\t/** Returns the filled buffer (call after receivePart() returns true).\n\t * Its size is length()+1.\n\t */\n\tconst std::vector<uint8>\treceivedBuffer() const { nlnettrace( \"CServerBufSock::receivedBuffer\" ); return _ReceiveBuffer; }\n\n    uint32                      appendToBuffer( const uint8* buffer, uint32 len )\n    {\n        _ReceiveBuffer.insert(_ReceiveBuffer.end(), buffer, buffer+len);\n        return _ReceiveBuffer.size();\n    }\n\n    uint8*                      getBuffer( uint32 offset=0 )  {  return &*_ReceiveBuffer.begin()+offset;  }\n\n\n    uint32                      leftShiftBuffer( uint32 shift_bits )\n    {\n        if( shift_bits >= _ReceiveBuffer.size() )\n        {\n            _ReceiveBuffer.clear();\n        }\n        else\n        {\n            uint32 surplus_bits = _ReceiveBuffer.size()-shift_bits;\n            NLMISC::CFastMem::memcpy( _ReceiveBuffer.data(), _ReceiveBuffer.data()+shift_bits, surplus_bits );\n            _ReceiveBuffer.resize(surplus_bits);\n        }\n\n        return _ReceiveBuffer.size();\n    }\n\n\t// Buffer for nonblocking receives\n\tstd::vector<uint8>\t\t\t_ReceiveBuffer;\n\n    NLMISC::CMemStream          CompleteMsg;\n\n\t// Max payload size than can be received in a block\n\tuint32\t\t\t\t\t\t_MaxExpectedBlockSize;\n\nprivate:\n\n\t// True if the length prefix has already been read\n\tbool\t\t\t\t\t\t_NowReadingBuffer;\n\n\t// Counts the number of bytes read for the current element (length prefix or buffer)\n\tTBlockSize\t\t\t\t\t_BytesRead;\n\n\t// Length of buffer to read\n\tTBlockSize\t\t\t\t\t_Length;\n\n};\n\n\nclass CBufServer;\n\n\n/**\n * CServerBufSock\n * A socket, its send buffer plus a nonblocking receiving system for a server connection\n */\nclass CServerBufSock : public CNonBlockingBufSock\n{\n//protected:\npublic:\n\n\tfriend class CBufServer;\n    friend class CBufServerWebsocket;\n\tfriend class CListenTask;\n\tfriend class CServerReceiveTask;\n\n\t/** Constructor with an existing socket (created by an accept()).\n\t * Don't forget to call setOwnerTask().\n\t */\n\tCServerBufSock( CTcpSock *sock );\n\n\t/// Sets the task that \"owns\" the CServerBufSock object\n\tvoid\t\t\t\t\t\tsetOwnerTask( CServerReceiveTask* owner ) { _OwnerTask = owner; }\n\n\t/// Returns the task that \"owns\" the CServerBufSock object\n\tCServerReceiveTask\t\t\t*ownerTask() { return _OwnerTask; }\n\n\t/** Pushes a connection message into bnb's receive queue, if it has not already been done\n\t * (returns true in this case).\n\t */\n\tbool\t\t\t\t\t\tadvertiseConnection( CBufNetBase *bnb )\n\t{\n\t\treturn advertiseSystemEvent( (CBufNetBase*)bnb, this, _KnowConnected, false, CBufNetBase::Connection );\n\t}\n\n\t/// Returns \"SRV \" (server)\n\tvirtual std::string\t\t\ttypeStr() const { return \"SRV \"; }\n\n\t/// Fill the sockid and the event type byte at the end of the buffer\n\tvoid\t\t\t\t\t\tfillSockIdAndEventType( TSockId sockId )\n\t{\n\t\tmemcpy( (&*_ReceiveBuffer.begin()) + length(), &sockId, sizeof(TSockId) );\n\t\t_ReceiveBuffer[length() + sizeof(TSockId)] = (uint8)CBufNetBase::User;\n\t}\n\nprivate:\n\n\t/// True after a connection callback has been sent to the user, for this connection\n\tbool\t\t\t\t_Advertised;\n\n\t// The task that \"owns\" the CServerBufSock object\n\tCServerReceiveTask\t*_OwnerTask;\n\n};\n\n\n} // NLNET\n\n#endif // NL_BUF_SOCK_H\n\n/* End of buf_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/callback_client.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CALLBACK_CLIENT_H\n#define NL_CALLBACK_CLIENT_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"callback_net_base.h\"\n#include \"buf_client.h\"\n\nnamespace NLNET {\n\n\nclass CInetAddress;\n\n\n/**\n * Client class for layer 3\n * \\author Vianney Lecroart, Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CCallbackClient : public CCallbackNetBase, public CBufClient\n{\npublic:\n\n\t/// Constructor\n\tCCallbackClient( TRecordingState rec=Off, const std::string& recfilename=\"\", bool recordall=true, bool initPipeForDataAvailable=true );\n\t~CCallbackClient();\n\n\t/// Sends a message to the remote host (the second parameter isn't used)\n\tvoid\tsend (const CMessage &buffer, TSockId hostid = InvalidSockId, bool log = true);\n\n\t/// Force to send all data pending in the send queue. hostid must be InvalidSockId here. See comment in CCallbackNetBase.\n\tbool\tflush (TSockId hostid = InvalidSockId, uint *nbBytesRemaining=NULL);\n\n\t/** Updates the network (call this method evenly).\n\t * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate().\n\t */\n\tvoid\tupdate2 (sint32 timeout=-1, sint32 mintime=0);\n\n\t/// Updates the network (call this method evenly) (legacy)\n\tvoid\tupdate (sint32 timeout=0);\n\n\t/// Connects to the specified host\n\tvoid\tconnect( const CInetAddress& addr );\n\n\t/** Returns true if the connection is still connected (changed when a disconnection\n\t * event has reached the front of the receive queue, just before calling the disconnection callback\n\t * if there is one)\n\t */\n\tvirtual bool\tconnected () const { return CBufClient::connected (); }\n\n\tvirtual const CInetAddress&\thostAddress( TSockId /* hostid */ ) { return remoteAddress(); }\n\n\t/** Disconnect a connection\n\t * Unlike in CCallbackClient, you can call disconnect() on a socket that is already disconnected\n\t * (it will do nothing)\n\t */\n\tvoid\tdisconnect (TSockId hostid = InvalidSockId);\n\n\t/// Sets callback for disconnections (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); }\n\n\t/// Returns the sockid\n\tvirtual TSockId\tgetSockId (TSockId hostid = InvalidSockId);\n\n\tuint64\tgetReceiveQueueSize () { return CBufClient::getReceiveQueueSize(); }\n\tuint64\tgetSendQueueSize () { return CBufClient::getSendQueueSize(); }\n\n\tvoid displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufClient::displayReceiveQueueStat(log); }\n\tvoid displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId /* destid */ = InvalidSockId) { CBufClient::displaySendQueueStat(log); }\n\n\tvoid displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufClient::displayThreadStat(log); }\n\nprivate:\n\n\t/// These function is public in the base class and put it private here because user cannot use it in layer 2\n\tvoid\tsend (const NLMISC::CMemStream &/* buffer */) { nlstop; }\n\n\t/// Returns true if there are messages to read\n\tbool\tdataAvailable ();\n\tvirtual bool getDataAvailableFlagV() const { return dataAvailableFlag(); }\n\n\tvoid\treceive (CMessage &buffer, TSockId *hostid = NULL);\n\n\t// ---------------------------------------\n#ifdef USE_MESSAGE_RECORDER\n\tvirtual bool replaySystemCallbacks();\n#endif\n\n\tbool LockDeletion;\n};\n\n\n} // NLNET\n\n\n#endif // NL_CALLBACK_CLIENT_H\n\n/* End of callback_client.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/callback_net_base.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CALLBACK_NET_BASE_H\n#define NL_CALLBACK_NET_BASE_H\n\n#undef USE_MESSAGE_RECORDER\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/time_nl.h\"\n\n#include \"buf_net_base.h\"\n#include \"message.h\"\n#include \"inet_address.h\"\n\n#ifdef USE_MESSAGE_RECORDER\n#include \"message_recorder.h\"\n#include <queue>\n#endif\n\n#include <vector>\n\n\nnamespace NLNET {\n\nclass CCallbackNetBase;\n\n/** Callback function type for message processing\n *\n * msgin contains parameters of the message\n * from is the SockId of the connection, for a client, from is always the same value\n */\ntypedef void (*TMsgCallback) (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\n\n/// Callback items. See CMsgSocket::update() for an explanation on how the callbacks are called.\ntypedef struct\n{\n\t/// Key C string. It is a message type name, or \"C\" for connection or \"D\" for disconnection\n\tconst char\t\t*Key;\n\t/// The callback function\n\tTMsgCallback\tCallback;\n\n} TCallbackItem;\n\n\n/**\n * Layer 3\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CCallbackNetBase\n{\npublic:\n\n\tvirtual ~CCallbackNetBase() {}\n\n\t/** Set the user data */\n\tvoid setUserData(void *userData);\n\n\t/** Get the user data */\n\tvoid *getUserData();\n\n\t/** Sends a message to special connection.\n\t * On a client, the hostid isn't used.\n\t * On a server, you must provide a hostid. If you hostid = InvalidSockId, the message will be sent to all connected client.\n\t */\n\tvirtual void\tsend (const CMessage &buffer, TSockId hostid = InvalidSockId, bool log = true) = 0;\n\n\tuint64\tgetBytesSent () { return _BytesSent; }\n\tuint64\tgetBytesReceived () { return _BytesReceived; }\n\n\tvirtual uint64\tgetReceiveQueueSize () = 0;\n\tvirtual uint64\tgetSendQueueSize () = 0;\n\n\tvirtual void displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) = 0;\n\tvirtual void displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) = 0;\n\n\tvirtual void displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) = 0;\n\n\t/** Force to send all data pending in the send queue.\n\t * On a client, the hostid isn't used and must be InvalidSockId\n\t * On a server, you must provide a hostid.\n\t * If you provide a non-null pointer for nbBytesRemaining, the value will be filled*\n\t * will the number of bytes that still remain in the sending queue after the\n\t * non-blocking flush attempt.\n\t */\n\tvirtual bool\tflush (TSockId hostid = InvalidSockId, uint *nbBytesRemaining=NULL) = 0;\n\n\t/**\tAppends callback array with the specified array. You can add callback only *after* adding the server or the client.\n\t * \\param arraysize is the number of callback items.\n\t */\n\tvoid\taddCallbackArray (const TCallbackItem *callbackarray, sint arraysize);\n\n\t/// Sets default callback for unknown message types\n\tvoid\tsetDefaultCallback(TMsgCallback defaultCallback) { _DefaultCallback = defaultCallback; }\n\n\t/// Set the pre dispatch callback. This callback is called before each message is dispatched\n\tvoid\tsetPreDispatchCallback(TMsgCallback predispatchCallback) { _PreDispatchCallback = predispatchCallback;}\n\n\t/// Sets callback for disconnections (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback (TNetCallback cb, void *arg) { _DisconnectionCallback = cb; _DisconnectionCbArg = arg; }\n\n\t/// returns the sockid of a connection. On a server, this function returns the parameter. On a client, it returns the connection.\n\tvirtual TSockId\tgetSockId (TSockId hostid = InvalidSockId) = 0;\n\n\t/** Sets the callback that you want the other side calls. If it didn't call this callback, it will be disconnected\n\t * If cb is NULL, we authorize *all* callback.\n\t * On a client, the hostid must be InvalidSockId (or ommited).\n\t * On a server, you must provide a hostid.\n\t */\n\tvoid\tauthorizeOnly (const char *callbackName, TSockId hostid = InvalidSockId);\n\n\t/// Returns true if this is a CCallbackServer\n\tbool\tisAServer () const { return _IsAServer; }\n\n\t/// This function is implemented in the client and server class\n\tvirtual bool\tdataAvailable () = 0;\n\t/// This function is implemented in the client and server class\n\tvirtual bool\tgetDataAvailableFlagV() const = 0;\n\t/// This function is implemented in the client and server class\n\tvirtual void\tupdate2 ( sint32 timeout=0, sint32 mintime=0 ) = 0;\n\t/// This function is implemented in the client and server class (legacy)\n\tvirtual void\tupdate ( sint32 timeout=0 ) = 0;\n\t/// This function is implemented in the client and server class\n\tvirtual bool\tconnected () const = 0;\n\t/// This function is implemented in the client and server class\n\tvirtual void\tdisconnect (TSockId hostid = InvalidSockId) = 0;\n\n\t/// Returns the address of the specified host\n\tvirtual const\tCInetAddress& hostAddress (TSockId hostid);\n\n\t// Defined even when USE_MESSAGE_RECORDER is not defined\n\tenum TRecordingState { Off, Record, Replay };\n\nprotected:\n\n\tuint64\t_BytesSent, _BytesReceived;\n\n\t/// Used by client and server class\n\tTNetCallback _NewDisconnectionCallback;\n\n\t/// Constructor.\n\tCCallbackNetBase( TRecordingState rec=Off, const std::string& recfilename=\"\", bool recordall=true );\n\n\t/** Used by client and server class\n\t * More info about timeout and mintime in the code.\n\t */\n\tvoid baseUpdate2 ( sint32 timeout=-1, sint32 mintime=0 );\n\n\t/// Used by client and server class (legacy)\n\tvoid baseUpdate ( sint32 timeout=0 );\n\n\t/// Read a message from the network and process it\n\tvoid processOneMessage ();\n\n\t/// On this layer, you can't call directly receive, It s the update() function that receive and call your callaback\n\tvirtual void\treceive (CMessage &buffer, TSockId *hostid) = 0;\n\n\t// contains callbacks\n\tstd::vector<TCallbackItem>\t_CallbackArray;\n\n\t// called if the received message is not found in the callback array\n\tTMsgCallback\t\t\t\t_DefaultCallback;\n\n\t// If not null, called before each message is dispached to it's callback\n\tTMsgCallback\t\t\t\t_PreDispatchCallback;\n\n\tbool _IsAServer;\n\tbool _FirstUpdate;\n\n\t// ---------------------------------------\n#ifdef USE_MESSAGE_RECORDER\n\tbool\t\t\treplayDataAvailable();\n\tvirtual bool\treplaySystemCallbacks() = 0;\n\tvoid\t\t\tnoticeDisconnection( TSockId hostid );\n\n\tTRecordingState\t\t\t\t\t\t_MR_RecordingState;\n\tsint64\t\t\t\t\t\t\t\t_MR_UpdateCounter;\n\n\tCMessageRecorder\t\t\t\t\t_MR_Recorder;\n#endif\n\t// ---------------------------------------\n\nprivate:\n\n\tvoid\t\t\t\t*_UserData;\n\n\tNLMISC::TTime\t\t_LastUpdateTime;\n\tNLMISC::TTime\t\t_LastMovedStringArray;\n\n\tTNetCallback\t\t _DisconnectionCallback;\n\tvoid\t\t\t\t*_DisconnectionCbArg;\n\n\tfriend void cbnbMessageAskAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\tfriend void cbnbMessageRecvAssociations (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\n\tfriend void cbnbNewDisconnection (TSockId from, void *data);\n};\n\n\n} // NLNET\n\n\n#endif // NL_CALLBACK_NET_BASE_H\n\n/* End of callback_net_base.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/callback_server.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CALLBACK_SERVER_H\n#define NL_CALLBACK_SERVER_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"callback_net_base.h\"\n#include \"buf_server.h\"\n\n\nnamespace NLNET {\n\n\n/**\n * Server class for layer 3\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CCallbackServer : public CCallbackNetBase, public CBufServer\n{\npublic:\n\n\t/// Constructor\n\tCCallbackServer( TRecordingState rec=Off, const std::string& recfilename=\"\", bool recordall=true, bool initPipeForDataAvailable=true );\n\n\t/// Sends a message to the specified host\n\tvoid\tsend (const CMessage &buffer, TSockId hostid, bool log = true);\n\n\t/// Force to send all data pending in the send queue. See comment in CCallbackNetBase.\n\tbool\tflush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return CBufServer::flush(destid, nbBytesRemaining); }\n\n\t/** Updates the network (call this method evenly).\n\t * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate().\n\t */\n\tvoid\tupdate2 (sint32 timeout=-1, sint32 mintime=0);\n\n\t/// Updates the network (call this method evenly) (legacy)\n\tvoid\tupdate (sint32 timeout=0);\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\t/// Sets callback for disconnections (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); }\n\n\t/// Returns true if the connection is still connected. on server, we always \"connected\"\n\tbool\tconnected () const { return true; }\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * Before disconnecting, any pending data is actually sent.\n\t */\n\tvoid\tdisconnect (TSockId hostid);\n\n\t/// Returns the address of the specified host\n\tconst CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); }\n\n\t/// Returns the sockid (cf. CCallbackClient)\n\tvirtual TSockId\tgetSockId (TSockId hostid = InvalidSockId);\n\n\tuint64\tgetReceiveQueueSize () { return CBufServer::getReceiveQueueSize(); }\n\tuint64\tgetSendQueueSize () { return CBufServer::getSendQueueSize(0); }\n\n\tvoid displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufServer::displayReceiveQueueStat(log); }\n\tvoid displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { CBufServer::displaySendQueueStat(log, destid); }\n\n\tvoid displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { CBufServer::displayThreadStat(log); }\n\nprivate:\n\n\t/// This function is public in the base class and put it private here because user cannot use it in layer 2\n\tvoid\t\t\tsend (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; }\n\n\tbool\t\t\tdataAvailable ();\n\tvirtual bool\tgetDataAvailableFlagV() const { return dataAvailableFlag(); }\n\n\tvoid\t\t\treceive (CMessage &buffer, TSockId *hostid);\n\n\tvoid\t\t\tsendAllMyAssociations (TSockId to);\n\n\tTNetCallback\t_ConnectionCallback;\n\tvoid\t\t\t*_ConnectionCbArg;\n\n\tfriend void\t\tcbsNewConnection (TSockId from, void *data);\n\n\t// ---------------------------------------\n#ifdef USE_MESSAGE_RECORDER\n\tvoid\t\t\t\t\t\tnoticeConnection( TSockId hostid );\n\tvirtual\t\t\t\t\t\tbool replaySystemCallbacks();\n\tstd::vector<CBufSock*>\t\t_MR_Connections;\n\tstd::map<TSockId,TSockId>\t_MR_SockIds; // first=sockid in file; second=CBufSock*\n#endif\n\t// ---------------------------------------\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_CALLBACK_SERVER_H\n\n/* End of callback_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/callback_server_tcp.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CALLBACK_SERVER_TCP_H\n#define NL_CALLBACK_SERVER_TCP_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/net/callback_net_base.h\"\n#include \"nel/net/buf_server.h\"\n\n#include \"buf_server_tcp.h\"\n\nnamespace NLNET {\n\n\n/**\n * Server class for layer 3\n * \\author li9chuan@qq.com\n  * \\date 2018\n */\n\nclass CCallbackServerTcp : public CCallbackNetBase, public CBufServerTcp\n{\npublic:\n\n\t/// Constructor\n\tCCallbackServerTcp( TRecordingState rec=Off, const std::string& recfilename=\"\", bool recordall=true, bool initPipeForDataAvailable=true );\n\n\t/// Sends a message to the specified host\n\tvoid\tsend (const CMessage &buffer, TSockId hostid, bool log = true);\n\n\t/// Force to send all data pending in the send queue. See comment in CCallbackNetBase.\n\tbool\tflush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return false; /*CBufServer::flush(destid, nbBytesRemaining);*/ }\n\n\t/** Updates the network (call this method evenly).\n\t * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate().\n\t */\n\tvoid\tupdate2 (sint32 timeout=-1, sint32 mintime=0);\n\n\t/// Updates the network (call this method evenly) (legacy)\n\tvoid\tupdate (sint32 timeout=0);\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\t/// Sets callback for disconnections (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); }\n\n\t/// Returns true if the connection is still connected. on server, we always \"connected\"\n\tbool\tconnected () const { return true; }\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * Before disconnecting, any pending data is actually sent.\n\t */\n\tvoid\tdisconnect (TSockId hostid);\n\n\t/// Returns the address of the specified host\n\t//const CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); }\n\n\t/// Returns the sockid (cf. CCallbackClient)\n\tvirtual TSockId\tgetSockId (TSockId hostid = InvalidSockId);\n\n\tuint64\tgetReceiveQueueSize () { return 0; }\n\tuint64\tgetSendQueueSize () { return 0; }\n\n\tvoid displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayReceiveQueueStat(log);*/ }\n\tvoid displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { /*CBufServer::displaySendQueueStat(log, destid);*/ }\n\n\tvoid displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayThreadStat(log);*/ }\n\nprivate:\n\n\t/// This function is public in the base class and put it private here because user cannot use it in layer 2\n\t//void\t\t\tsend (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; }\n\n\tbool\t\t\tdataAvailable ();\n\tvirtual bool\tgetDataAvailableFlagV() const { return dataAvailableFlag(); }\n\n\tvoid\t\t\treceive (CMessage &buffer, TSockId *hostid);\n\n\tvoid\t\t\tsendAllMyAssociations (TSockId to);\n\n\tTNetCallback\t_ConnectionCallback;\n\tvoid\t\t\t*_ConnectionCbArg;\n\n\tfriend void\t\tcbsTcpNewConnection (TSockId from, void *data);\n\n\t// ---------------------------------------\n#ifdef USE_MESSAGE_RECORDER\n\tvoid\t\t\t\t\t\tnoticeConnection( TSockId hostid );\n\tvirtual\t\t\t\t\t\tbool replaySystemCallbacks();\n\tstd::vector<CBufSock*>\t\t_MR_Connections;\n\tstd::map<TSockId,TSockId>\t_MR_SockIds; // first=sockid in file; second=CBufSock*\n#endif\n\t// ---------------------------------------\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_CALLBACK_SERVER_TCP_H\n\n/* End of callback_server_tcp.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/callback_server_websocket.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_CALLBACK_SERVER_WEBSOCKET_H\n#define NL_CALLBACK_SERVER_WEBSOCKET_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/net/callback_net_base.h\"\n#include \"nel/net/buf_server.h\"\n\n#include \"buf_server_websocket.h\"\n\nnamespace NLNET {\n\n\n/**\n * Server class for layer 3\n * \\author li9chuan@qq.com\n  * \\date 2018\n */\n\nclass CCallbackServerWebSocket : public CCallbackNetBase, public CBufServerWebsocket\n{\npublic:\n\n\t/// Constructor\n\tCCallbackServerWebSocket( TRecordingState rec=Off, const std::string& recfilename=\"\", bool recordall=true, bool initPipeForDataAvailable=true );\n\n\t/// Sends a message to the specified host\n\tvoid\tsend (const CMessage &buffer, TSockId hostid, bool log = true);\n\n\t/// Force to send all data pending in the send queue. See comment in CCallbackNetBase.\n\tbool\tflush (TSockId destid, uint *nbBytesRemaining=NULL) { nlassert( destid != InvalidSockId ); return false; /*CBufServer::flush(destid, nbBytesRemaining);*/ }\n\n\t/** Updates the network (call this method evenly).\n\t * More info about timeout and mintime in the code of CCallbackNetBase::baseUpdate().\n\t */\n\tvoid\tupdate2 (sint32 timeout=-1, sint32 mintime=0);\n\n\t/// Updates the network (call this method evenly) (legacy)\n\tvoid\tupdate (sint32 timeout=0);\n\n\t/// Sets callback for incoming connections (or NULL to disable callback)\n\tvoid\tsetConnectionCallback (TNetCallback cb, void *arg) { _ConnectionCallback = cb; _ConnectionCbArg = arg; }\n\n\t/// Sets callback for disconnections (or NULL to disable callback)\n\tvoid\tsetDisconnectionCallback (TNetCallback cb, void *arg) { CCallbackNetBase::setDisconnectionCallback (cb, arg); }\n\n\t/// Returns true if the connection is still connected. on server, we always \"connected\"\n\tbool\tconnected () const { return true; }\n\n\t/** Disconnect a connection\n\t * Set hostid to InvalidSockId to disconnect all connections.\n\t * If hostid is not InvalidSockId and the socket is not connected, the method does nothing.\n\t * Before disconnecting, any pending data is actually sent.\n\t */\n\tvoid\tdisconnect (TSockId hostid);\n\n\t/// Returns the address of the specified host\n\t//const CInetAddress& hostAddress (TSockId hostid) { nlassert(hostid!=InvalidSockId); return CBufServer::hostAddress (hostid); }\n\n\t/// Returns the sockid (cf. CCallbackClient)\n\tvirtual TSockId\tgetSockId (TSockId hostid = InvalidSockId);\n\n\tuint64\tgetReceiveQueueSize () { return 0; }\n\tuint64\tgetSendQueueSize () { return 0; }\n\n\tvoid displayReceiveQueueStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayReceiveQueueStat(log);*/ }\n\tvoid displaySendQueueStat (NLMISC::CLog *log = NLMISC::InfoLog, TSockId destid = InvalidSockId) { /*CBufServer::displaySendQueueStat(log, destid);*/ }\n\n\tvoid displayThreadStat (NLMISC::CLog *log = NLMISC::InfoLog) { /*CBufServer::displayThreadStat(log);*/ }\n\nprivate:\n\n\t/// This function is public in the base class and put it private here because user cannot use it in layer 2\n\t//void\t\t\tsend (const NLMISC::CMemStream &/* buffer */, TSockId /* hostid */) { nlstop; }\n\n\tbool\t\t\tdataAvailable ();\n\tvirtual bool\tgetDataAvailableFlagV() const { return dataAvailableFlag(); }\n\n\tvoid\t\t\treceive (CMessage &buffer, TSockId *hostid);\n\n\tvoid\t\t\tsendAllMyAssociations (TSockId to);\n\n\tTNetCallback\t_ConnectionCallback;\n\tvoid\t\t\t*_ConnectionCbArg;\n\n\tfriend void\t\tcbsWebSktNewConnection (TSockId from, void *data);\n\n\t// ---------------------------------------\n#ifdef USE_MESSAGE_RECORDER\n\tvoid\t\t\t\t\t\tnoticeConnection( TSockId hostid );\n\tvirtual\t\t\t\t\t\tbool replaySystemCallbacks();\n\tstd::vector<CBufSock*>\t\t_MR_Connections;\n\tstd::map<TSockId,TSockId>\t_MR_SockIds; // first=sockid in file; second=CBufSock*\n#endif\n\t// ---------------------------------------\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_CALLBACK_SERVER_H\n\n/* End of callback_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/cvar_log_filter.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_CVAR_LOG_FILTER_H\n#define NL_CVAR_LOG_FILTER_H\n\n#include \"nel/misc/config_file.h\"\n#include \"nel/net/service.h\"\n\n/** Declare an info logging function that works as nlinfo but that is activated with the given service config file variable\n  * Example of use :\n  * DECLARE_CVAR_INFO_LOG_FUNCTION(my_info, MyInfoEnabled)\n  *\n  * my_info(\"my_message\"); // no-op if \"MyInfoEnabled = 0;\" Is found in the service config file\n  */\n#ifdef NL_NO_DEBUG\n\t#define NL_DECLARE_CVAR_INFO_LOG_FUNCTION(func, cvar, defaultValue)\tinline void func(const char *format, ...) {}\n#else\n\t#define NL_DECLARE_CVAR_INFO_LOG_FUNCTION(func, cvar, defaultValue)                                              \\\n\tinline void func(const char *format, ...)                                                                        \\\n\t{                                                                                                                \\\n\t\tbool logWanted = (defaultValue);                                                                             \\\n\t\tNLMISC::CConfigFile::CVar *logWantedPtr = NLNET::IService::getInstance()->ConfigFile.getVarPtr(#cvar);       \\\n\t\tif (logWantedPtr)                                                                                            \\\n\t\t{                                                                                                            \\\n\t\t\tlogWanted = logWantedPtr->asInt() != 0;                                                                  \\\n\t\t}                                                                                                            \\\n\t\tif (logWanted)                                                                                               \\\n\t\t{                                                                                                            \\\n\t\t\tchar *out;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \\\n\t\t\tNLMISC_CONVERT_VARGS(out, format, 256);                                                                  \\\n\t\t\tnlinfo(out);                                                                                             \\\n\t\t}                                                                                                            \\\n\t}\n#endif\n\n\n#endif\n"
  },
  {
    "path": "code/nel/include/nel/net/dummy_tcp_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_DUMMY_TCP_SOCK_H\n#define NL_DUMMY_TCP_SOCK_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"tcp_sock.h\"\n\n\nnamespace NLNET {\n\n\n/**\n * Dummy CTcpSock replacement for replay mode\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CDummyTcpSock : public CTcpSock\n{\npublic:\n\n\t// Constructor\n\tCDummyTcpSock( bool logging = true ) : CTcpSock(logging) {}\n\n\t// Dummy connection\n\tvirtual void\t\t\tconnect( const CInetAddress& addr );\n\n\t// Dummy disconnection\n\tvirtual void\t\t\tdisconnect();\n\n\t// Nothing\n\tvirtual void\t\t\tsetNoDelay( bool /* value */ ) {}\n\n\t// Nothing\n\tvirtual void\t\t\tclose() {}\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_DUMMY_TCP_SOCK_H\n\n/* End of dummy_tcp_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/email.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_EMAIL_H\n#define NL_EMAIL_H\n\n#include <string>\n\n#include \"nel/misc/report.h\"\n\n\nnamespace NLNET {\n\n/** Send an email\n * \\param smtpServer must be a smtp email server.\n * \\param from must be a valid email address. If empty, create a fake email address with anonymous@<ipaddress>.com\n * \\param to must be a valid email address.\n * \\param subject subject of the email. Can be empty.\n * \\param body body of the email. Can be empty.\n * \\param attachedFile a filename that will be send with the email. Can be empty.\n * \\param onlyCheck If true, It'll not send the mail but only check if it could be send.\n */\n\nbool sendEmail (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile = \"\", bool onlyCheck = false);\n\n/**  If you call this function, the default from (when from is \"\") used in the sendEmail will be the one\n * you set by this function\n */\nvoid setDefaultEmailParams (const std::string &smtpServer, const std::string &from, const std::string &to);\n\n} // NLNET\n\n\n#endif // NL_EMAIL_H\n\n/* End of email.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/inet_address.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_INET_ADDRESS_H\n#define NL_INET_ADDRESS_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n#include <vector>\n\n\nstruct sockaddr_in;\nstruct in_addr;\n\n\n#ifdef NL_OS_WINDOWS\n// automatically add the win socket library if you use nel network part\n#pragma comment(lib, \"ws2_32.lib\")\n#endif\n\nnamespace NLMISC\n{\n\tclass IStream;\n}\n\n\nnamespace NLNET\n{\n\nstruct ESocket;\n\n\n/**\n * Internet address (IP + port).\n * The structure sockaddr_in is internally in network byte order\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass CInetAddress\n{\npublic:\n\n\t/// Default Constructor. The address is set to INADDR_ANY\n\tCInetAddress();\n\n\t/// Alternate constructor (calls setByName())\n\tCInetAddress( const std::string& hostName, uint16 port );\n\n\t/// Alternate constructor (calls setByName())\n\t/// example: CInetAddress(\"www.nevrax.com:80\")\n\tCInetAddress( const std::string& hostNameAndPort );\n\n\t/// Copy constructor\n\tCInetAddress( const CInetAddress& other );\n\n\t/// Assignment operator\n\tCInetAddress& operator=( const CInetAddress& other );\n\n\t/// Comparison == operator\n\tfriend bool operator==( const CInetAddress& a1, const CInetAddress& a2 );\n\n\t/// Comparison < operator\n\tfriend bool operator<( const CInetAddress& a1, const CInetAddress& a2 );\n\n\t/// Destructor\n\t~CInetAddress();\n\n\t/// Resolves a name\n\tCInetAddress&\t\tsetByName( const std::string& hostname );\n\n\t/// Sets port\n\tvoid\t\t\t\tsetPort( uint16 port );\n\n\t/// Sets hostname and port (ex: www.nevrax.com:80)\n\tvoid\t\t\t\tsetNameAndPort( const std::string& hostNameAndPort );\n\n\t/** Sets internal socket address directly (contents is copied).\n\t * It also retrieves the host name if CInetAddress::RetrieveNames is true.\n\t */\n\tvoid\t\t\t\tsetSockAddr( const sockaddr_in* saddr );\n\n\t/// Returns if object (address and port) is valid\n\tbool\t\t\t\tisValid() const;\n\n\t/// Returns internal socket address (read only)\n\tconst sockaddr_in\t *sockAddr() const;\n\n\t/// Returns internal IP address\n\tuint32\t\t\t\tinternalIPAddress() const;\n\n\t/// Returns the internal network address (it s the network address for example 192.168.0.0 for a C class)\n\tuint32\t\t\t\tinternalNetAddress () const;\n\n\t/// Returns readable IP address. (ex: \"195.68.21.195\")\n\tstd::string\t\t\tipAddress() const;\n\n\t/// Returns hostname. (ex: \"www.nevrax.org\")\n\tconst std::string&\thostName() const;\n\n\t/// Returns port\n\tuint16\t\t\t\tport() const;\n\n\t/// Returns hostname and port as a string. (ex: \"www.nevrax.org:80 (195.68.21.195)\")\n\tstd::string\t\t\tasString() const;\n\n\t/// Returns IP address and port as a string. (ex: \"195.68.21.195:80\")\n\tstd::string\t\t\tasIPString() const;\n\n\t/// Serialize\n\tvoid serial( NLMISC::IStream& s );\n\n\t/// Returns true if this CInetAddress is 127.0.0.1\n\tbool is127001 () const;\n\n\t/// Creates a CInetAddress object with local host address, port=0\n\tstatic CInetAddress\tlocalHost();\n\n\t/** Returns the list of the local host addresses (with port=0)\n\t * (especially useful if the host is multihomed)\n\t */\n\tstatic std::vector<CInetAddress> localAddresses();\n\n\t/// If true, setSockAddr() always tries to retrieve the host name from the address\n\tstatic bool RetrieveNames;\n\nprotected:\n\n\t/// Constructor with ip address, port=0\n\tCInetAddress( const in_addr *ip, const char *hostname = 0);\n\n\t/// Update _HostName from _SockAddr\n\tvoid\t\t\t\tupdateHostName();\n\nprivate:\n\n\t// Called in all constructors. Calls CBaseSocket::init().\n\tvoid\t\t\t\tinit();\n\n\tstd::string\t\t\t_HostName;\n\tsockaddr_in\t\t\t*_SockAddr;\n\tbool\t\t\t\t_Valid;\n\n};\n\n/// Take a internet dot string and convert it in an uint32 internal format for example \"128.64.32.16\" -> 0xF0804020\nuint32 stringToInternalIPAddress (const std::string &addr);\n\n/// Take an internal address and convert it to a internet dot string\nstd::string internalIPAddressToString (uint32 addr);\n\nstd::string vectorCInetAddressToString(const std::vector<CInetAddress> &addrs);\n\n}\n\n#endif // NL_INET_ADDRESS_H\n\n/* End of inet_address.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/listen_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LISTEN_SOCK_H\n#define NL_LISTEN_SOCK_H\n\n\n#include \"tcp_sock.h\"\n\nnamespace NLNET\n{\n\n\n/**\n * CListenSock: listening socket for servers.\n * How to accept connections in a simple server:\n * -# Create a CListenSock object\n * -# Listen on the port you want the clients to connect\n * -# In a loop, accept a connection and store the new socket\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000-2001\n */\nclass CListenSock : public CTcpSock\n{\npublic:\n\n\t/// Constructor\n\tCListenSock();\n\n\t///@name Socket setup\n\t//@{\n\n\t/// Prepares to receive connections on a specified port (bind+listen)\n\tvoid\t\t\tinit( uint16 port );\n\n\t/// Prepares to receive connections on a specified address/port (useful when the host has several addresses)\n\tvoid\t\t\tinit( const CInetAddress& addr );\n\n\t/// Sets the number of the pending connections queue, or -1 for the maximum possible value.\n\tvoid\t\t\tsetBacklog( sint backlog );\n\n\t/// Returns the pending connections queue.\n\tsint\t\t\tbacklog() const { return _BackLog; }\n\n\t//@}\n\n\t/// Blocks until an incoming connection is requested, accepts it, and creates a new socket (you have to delete it after use)\n\tCTcpSock\t\t*accept();\n\nprivate:\n\n\tbool\t\t\t_Bound;\n\n\tsint\t\t\t_BackLog;\n};\n\n} // NLNET\n\n#endif // NL_LISTEN_SOCK_H\n\n/* End of listen_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/login_client.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LOGIN_CLIENT_H\n#define NL_LOGIN_CLIENT_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n#include <vector>\n\n#include \"callback_client.h\"\n#include \"udp_sim_sock.h\"\n\nnamespace NLNET\n{\n\nclass CLoginCookie;\nclass CUdpSock;\nclass IDisplayer;\n\n/**\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2002\n */\nclass CLoginClient {\npublic:\n\n\tstruct CShardEntry\n\t{\n\t\tCShardEntry() { NbPlayers = 0; Id = -1; }\n\t\tCShardEntry(const ucstring &name, uint8 nbp, sint32 sid) : Id(sid), Name(name), NbPlayers(nbp) { }\n\t\tsint32\t\tId;\n\t\tucstring\tName;\n\t\tuint8\t\tNbPlayers;\n\t};\n\n\ttypedef std::vector<CShardEntry> TShardList;\n\n\t// This list is filled after a successful authenticate call\n\tstatic TShardList ShardList;\n\n\t/** Try to login with login and password. cpassword must be md5 crypted (that's why it's a string and not an ucstring)\n\t* application is the name of the application. the LS will return all shards that is available for this application (sample, snowballs, ...)\n\t* If the authentication is ok, the function return an empty string else it returns the reason of the failure.\n\t*/\n\tstatic std::string authenticate(const std::string &loginServiceAddr, const ucstring &login, const std::string &cpassword, const std::string &application);\n\tstatic std::string authenticateBegin(const std::string &loginServiceAddr, const ucstring &login, const std::string &cpassword, const std::string &application);\n\tstatic bool authenticateUpdate(std::string &error);\n\t/** Todo: fix comment.\n\t*/\n\tstatic std::string wantToConnectToShard (sint32 shardId, std::string &ip, std::string &cookie);\n\tstatic std::string selectShardBegin(sint32 shardId);\n\tstatic bool selectShardUpdate(std::string &error, std::string &ip, std::string &cookie);\n\n\t/** Try to connect to the shard and return a TCP connection to the shard.\n\t */\n\tstatic std::string connectToShard (CLoginCookie &lc, const std::string &addr, CCallbackClient &cnx);\n\n\t/** Try to connect to the shard and return an UDP connection to the shard.\n\t */\n\tstatic std::string connectToShard (const std::string &addr, CUdpSock &cnx);\n\n\t/** Try to connect to the shard and return an UDP simulate connection to the shard.\n\t */\n\tstatic std::string connectToShard (const std::string &addr, CUdpSimSock &cnx);\n\nprivate:\n\n\tstatic std::string confirmConnection (sint32 sharId);\n\tstatic CLoginClient::CShardEntry *getShard (sint32 shardId);\n\n\tstatic NLNET::CCallbackClient *_LSCallbackClient;\n\n};\n\n\n} // NLNET\n\n#endif // NL_LOGIN_CLIENT_H\n\n/* End of login_client.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/login_cookie.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LOGIN_COOKIE_H\n#define NL_LOGIN_COOKIE_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/common.h\"\n\n\nnamespace NLNET {\n\n\n/**\n * Manage cookie during the authenticate procedure.\n *\n * _UserAddr is the ipv4 address of the client in uint32\n * _UserKey is an uint32 generated by the login_service at each login password verification\n * _UserId is an uint32 uniq for each account (an account could have more than one avatar)\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLoginCookie\n{\npublic:\n\n\tCLoginCookie (uint32 addr, uint32 id);\n\tCLoginCookie () : _Valid(false) { }\n\n\tvoid serial (NLMISC::IStream &s)\n\t{\n\t\t// verify that we initialized the cookie before writing it\n\t\tif (!s.isReading() && !_Valid) nlwarning (\"LC: serialize a non valid cookie\");\n\n\t\ts.serial (_UserAddr);\n\t\ts.serial (_UserKey);\n\t\ts.serial (_UserId);\n\n\t\tif (s.isReading()) _Valid = true;\n\t}\n\n\tstd::string setToString () const\n\t{\n\t\tif (_Valid)\n\t\t{\n\t\t\tchar cstr[8*3+2+1];\n\t\t\tNLMISC::smprintf(cstr, 8*3+2+1, \"%08X|%08X|%08X\", _UserAddr, _UserKey, _UserId);\n\t\t\tnlinfo (\"LC: setToString %s -> %s\", toString().c_str (), cstr);\n\t\t\treturn cstr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn \"0|0|0\";\n\t\t}\n\t}\n\n\tvoid setFromString (const std::string &str)\n\t{\n\t\tsscanf(str.c_str(), \"%08X|%08X|%08X\", &_UserAddr, &_UserKey, &_UserId);\n\n\t\tif(str.empty () || (_UserAddr==0 && _UserKey==0 && _UserId==0))\n\t\t\t_Valid = 0;\n\t\telse\n\t\t\t_Valid = 1;\n\n\t\t//nlinfo (\"LC: setFromString %s -> %s, isValid: %d\", str.c_str (), toString().c_str (), _Valid);\n\t}\n\n\tstd::string toString () const\n\t{\n\t\tif (_Valid)\n\t\t\treturn \"'\" + NLMISC::toString(\"%08X\", (unsigned int)_UserAddr) + \"|\" + NLMISC::toString(\"%08X\", (unsigned int)_UserKey) + \"|\" + NLMISC::toString(\"%08X\", (unsigned int)_UserId) + \"'\";\n\t\telse\n\t\t\treturn \"<InvalidCookie>\";\n\t}\n\n\tuint32\tgetUserAddr () const { nlassert (_Valid); return _UserAddr; }\n\tuint32\tgetUserKey () const { nlassert (_Valid); return _UserKey; }\n\tuint32\tgetUserId () const { nlassert (_Valid); return _UserId; }\n\n\tvoid\tset (uint32 ua, uint32 uk, uint32 ui) { _Valid = true; _UserAddr = ua; _UserKey = uk; _UserId = ui; }\n\n\tbool\tisValid() const { return _Valid; }\n\tvoid\tclear () { _Valid = false; }\n\n\tuint32\tgenerateKey();\n\n\t/// Comparison == operator\n\tfriend bool operator== (const CLoginCookie &c1, const CLoginCookie &c2);\n\n\t/// Strict weak ordering operator\n\tbool operator <(const CLoginCookie &other) const\n\t{\n\t\tif(_UserAddr != other._UserAddr)\n\t\t\treturn _UserAddr < other._UserAddr;\n\t\tif(_UserKey != other._UserKey)\n\t\t\treturn _UserKey < other._UserKey;\n\t\treturn _UserId < other._UserId;\n\t}\n\nprivate:\n\n\tbool\t_Valid;\n\n\tuint32\t_UserAddr;\n\tuint32\t_UserKey;\n\tuint32\t_UserId;\n\n};\n\n/*\n * Comparison == operator\n */\nbool operator== (const CLoginCookie &c1, const CLoginCookie &c2);\n/*\n * Comparison != operator\n */\nbool operator!= (const CLoginCookie &c1, const CLoginCookie &c2);\n\n} // NLNET\n\n\n\n#endif // NL_LOGIN_COOKIE_H\n\n/* End of login_cookie.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/login_server.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LOGIN_SERVER_H\n#define NL_LOGIN_SERVER_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n#include <vector>\n\n#include \"callback_server.h\"\n#include \"login_cookie.h\"\n\nnamespace NLMISC\n{\n\tclass CConfigFile;\n}\n\nnamespace NLNET\n{\n\n/// Callback function type called when a new client is identified (with the login password procedure)\ntypedef void (*TNewClientCallback) (TSockId from, const CLoginCookie &cookie);\n\n/// Callback function type called when a new cookie is acceptable (aka as 'a player can connect with this cookie')\ntypedef void (*TNewCookieCallback) (const CLoginCookie &cookie);\n\n/// Callback function type called when a client need to be disconnected (double login...)\ntypedef void (*TDisconnectClientCallback) (uint32 userId, const std::string &reqServiceName);\n\nclass CUdpSock;\nclass IDisplayer;\n\n/** This class is the server part of the Login System. It is used in the Front End Service.\n * At the beginning, it connects to the WS. When a new player comes in and is authenticated, a\n * callback is called to warn the user code that a new player is here.\n * Example:\n * \\code\n * \\endcode\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLoginServer {\npublic:\n\n\t/// Create the connection to the Welcome Service and install callbacks to the callback server (for a TCP connection)\n\t/// init() will try to find the ListenAddress in the config file and it will be used to say to the client\n\t/// the address to connect to this frontend (using the login system). You can modify this in real time in\n\t/// the config file or with the ls_listen_address command\n\t/// The ListenAddress must be in the form of \"itsalive.nevrax.org:38000\" (ip+port)\n\tstatic void init (CCallbackServer &server, TNewClientCallback ncl);\n\n\t/// Create the connection to the Welcome Service for an UDP connection\n\t/// the dc will be call when the Welcome Service decides to disconnect a player (double login...)\n\tstatic void init (CUdpSock &server, TDisconnectClientCallback dc);\n\n\t/// Create the connection to the Welcome Service for a connection\n\t/// the dc will be call when the Welcome Service decides to disconnect a player (double login...)\n\tstatic void init (const std::string &listenAddr, TDisconnectClientCallback dc);\n\n\t/// Add a callback to be warned when a new cookie become acceptable\n\tstatic void addNewCookieCallback(TNewCookieCallback newCookieCb);\n\n\t/// Used only in UDP, check if the cookie is valid. return empty string if valid, reason otherwise\n\tstatic std::string isValidCookie (const CLoginCookie &lc, std::string &userName, std::string &userPriv, std::string &userExtended, uint32 &instanceId, uint32 &charSlot);\n\n\t/// Call this method when a user is disconnected or the server disconnect the user.\n\t/// This method will warn the login system that the user is not here anymore\n\tstatic void clientDisconnected (uint32 userId);\n\n\t/// Call this method to retrieve the listen address\n\tstatic const std::string &getListenAddress();\n\n\t/// Return true if we are in 'dev' mode\n\tstatic bool acceptsInvalidCookie();\n\n\t/// Set the actual listen address\n\tstatic void setListenAddress(const std::string &la);\n\n\t/// Return the number of pending client connection.\n\tstatic uint32 getNbPendingUsers();\n\n\t/// Refresh the list of pending cookies to remove outdated one\n\t/// (i.e. cookies for users that never connect)\n\tstatic void refreshPendingList();\n\nprivate:\n\n\t/// This function is used by init() to create the connection to the Welcome Service\n\tstatic void connectToWS ();\n\n\t// called by other init()\n\tstatic void init (const std::string &listenAddress);\n\n};\n\n\n} // NLNET\n\n#endif // NL_LOGIN_SERVER_H\n\n/* End of login_server.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/message.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MESSAGE_H\n#define NL_MESSAGE_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/mem_stream.h\"\n\n#include <vector>\n\nnamespace NLNET\n{\n\nextern const char *LockedSubMessageError;\n\n\n/**\n * Message memory stream for network. Can be serialized to/from (see SerialBuffer()). Can be sent or received\n * over a network, using the NeL network engine.\n * If MESSAGES_PLAIN_TEXT is defined, the messages will be serialized to/from plain text (human-readable),\n * instead of binary.\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CMessage : public NLMISC::CMemStream\n{\npublic:\n\n\tenum TStreamFormat\t{ UseDefault, Binary, String };\n\tenum TMessageType\t{ OneWay, Request, Response, Except};\n\n\tstruct TFormat\n\t{\n\t\tuint8\tStringMode : 1,\t// true if the message body is string encoded, binary encoded if false otherwise\n\t\t\t\tLongFormat : 1, // true if the message format is long (d'ho ? all message are long !?!, always true)\n\t\t\t\tMessageType : 2; // type of the message (from TMessageType), classical message are 'OneWay'\n\n\t\tTFormat()\n\t\t{\n\t\t\tStringMode = 0;\n\t\t\tLongFormat = 0;\n\t\t\tMessageType = 0;\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\tif (s.isReading())\n\t\t\t{\n\t\t\t\t// decode the bit field in a network independant manner\n\t\t\t\tuint8 b;\n\t\t\t\ts.serial(b);\n\t\t\t\tLongFormat = b & 1;\n\t\t\t\tStringMode = (b>>1) & 1;\n\t\t\t\tMessageType = (b>>2) & 3;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// encode the bit field in a network independant manner\n\t\t\t\tuint8 b = LongFormat | StringMode << 1 | MessageType << 2;\n\t\t\t\ts.serial(b);\n\t\t\t}\n\t\t}\n\t};\n\n\tCMessage (const std::string &name = \"\", bool inputStream = false, TStreamFormat streamformat = UseDefault, uint32 defaultCapacity = 1000);\n\n\tCMessage (NLMISC::CMemStream &memstr);\n\n\tCMessage ( const uint32 rpc_session, const std::string &name = \"\", bool inputStream = false, TStreamFormat streamformat = UseDefault, uint32 defaultCapacity = 1000);\n\n\t/// Copy constructor\n\tCMessage (const CMessage &other);\n\n\t/// Assignment operator\n\tCMessage &operator= (const CMessage &other);\n\n\t/// exchange memory data\n\tvoid swap(CMessage &other);\n\n\t/// Sets the message type as a string and put it in the buffer if we are in writing mode\n\tvoid setType (const std::string &name, TMessageType type=OneWay);\n\n\tvoid changeType (const std::string &name);\n\n\t/// Returns the size, in byte of the header that contains the type name of the message or the type number\n\tuint32 getHeaderSize () const;\n\n\t/** The message was filled with an CMemStream, Now, we'll get the message type on this buffer.\n\t * This method updates _LengthR with the actual size of the buffer (it calls resetLengthR()).\n\t */\n\tvoid readType ();\n\n\t/// Get the message name (input message only) and advance the current pos\n\tstd::string readTypeAtCurrentPos() const;\n\n\t// Returns true if the message type was already set\n\tbool typeIsSet () const;\n\n\tuint32 session();\n\tvoid   session( uint32 rpc_session );\n\n\t/**\n\t * Returns the length (size) of the message, in bytes.\n\t * If isReading(), it is the number of bytes that can be read,\n\t * otherwise it is the number of bytes that have been written.\n\t * Overloaded because uses a specific version of lengthR().\n\t */\n\tvirtual uint32\tlength() const\n\t{\n\t\tif ( isReading() )\n\t\t{\n\t\t\treturn lengthR();\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn lengthS();\n\t\t}\n\t}\n\n\tvirtual uint32\t\t\tlengthS() const\n\t{\n\t\tif (!hasLockedSubMessage())\n//\t\t\treturn _BufPos - _Buffer.getPtr();\n\t\t\treturn _Buffer.Pos;\n\t\telse\n//\t\t\treturn (_BufPos - _Buffer.getPtr()) - _SubMessagePosR;\n\t\t\treturn _Buffer.Pos - _SubMessagePosR;\n\n\t}\n\n\t/// Returns the \"read\" message size (number of bytes to read) (note: see comment about _LengthR)\n\tuint32\t\t\tlengthR() const\n\t{\n\t\treturn _LengthR;\n\t}\n\n\tvirtual sint32\tgetPos () const throw(NLMISC::EStream)\n\t{\n//\t\treturn (_BufPos - _Buffer.getPtr()) - _SubMessagePosR;\n\t\treturn _Buffer.Pos - _SubMessagePosR;\n\t}\n\n//\tvirtual sint32\t\t\tgetPos() const\n//\t{\n//\t\treturn (_BufPos - _Buffer.getPtr()) - _SubMessagePosR;\n//\t}\n\n\t/**\n\t * Set an input message to look like, from a message callback's scope, as if it began at the current\n\t * pos and ended at the current pos + msgSize, and read the header and return the name of the sub message.\n\t *\n\t * This method provides a way to pass a big message containing a set of sub messages to their message\n\t * callback, without copying each sub message to a new message. If you need to perform some actions\n\t * that are not allowed with a locked message (see postconditions), use assignFromSubMessage():\n\t * the locked sub message in M1 can be copied to a new message M2 with 'M2.assignFromSubMessage( M1 )'.\n\t *\n\t * Preconditions:\n\t * - The message is an input message (isReading())\n\t * - msgEndPos <= length()\n\t * - getPos() >= getHeaderSize()\n\t *\n\t * Postconditions:\n\t * - The sub message is ready to be read from\n\t * - length() returns the size of the sub message\n\t * - getName() return the name of the sub message\n\t * - Unless you call unlockSubMessage(), the following actions will assert or raise an exception:\n\t *   Serializing more than the sub message size, clear(), operator=() (from/to), invert().\n\t */\n\tstd::string\t\t\tlockSubMessage( uint32 subMsgSize ) const\n\t{\n\t\tnlassert(!hasLockedSubMessage());\n\t\tuint32 subMsgBeginPos = getPos();\n\t\tuint32 subMsgEndPos = subMsgBeginPos + subMsgSize;\n\t\tnlassertex( isReading() && (subMsgEndPos <= lengthR()), (\"%s %u %u\", isReading()?\"R\":\"W\", subMsgEndPos, lengthR()) );\n\t\tstd::string name = unconst(*this).readTypeAtCurrentPos();\n\t\t_SubMessagePosR = subMsgBeginPos;\n//\t\t_LengthR = subMsgEndPos;\n\t\t_LengthR = subMsgSize;\n\t\treturn name;\n\t}\n\n\t/**\n\t * Exit from sub message locking, and skip the whole sub message.\n\t *\n\t * Preconditions:\n\t * - The message is an input message (isReading()) and has been locked using lockSubMessage()\n\t * - The reading pos is within or at the end of the previous sub message (if any) (see nlassertex)\n\t *\n\t * Postconditions:\n\t * - The current pos is the next byte after the sub message\n\t */\n\tvoid\t\t\tunlockSubMessage() const\n\t{\n\t\tnlassert( isReading() && hasLockedSubMessage() );\n\t\tnlassertex( getPos() <= sint32(_SubMessagePosR+_LengthR), (\"The callback for msg %s read more data than there is in the message (pos=%d len=%u)\", getName().c_str(), getPos(), _LengthR) );\n\n\t\tuint32 subMsgEndPos = _SubMessagePosR + _LengthR;\n\t\tresetSubMessageInternals();\n\t\tseek( subMsgEndPos, IStream::begin );\n\t}\n\n\t/// Return true if a sub message has been locked\n\tbool\t\t\thasLockedSubMessage() const\n\t{\n\t\treturn (_SubMessagePosR != 0);\n\t}\n\n\t/** If a sub message is locked, return the sub message part\n\t*/\n\tvirtual const uint8\t\t*buffer() const\n\t{\n\t\tif (hasLockedSubMessage())\n\t\t{\n//\t\t\treturn _Buffer.getPtr() + _SubMessagePosR;\n\t\t\treturn _Buffer.getBuffer().getPtr() + _SubMessagePosR;\n\t\t}\n\t\telse\n\t\t\treturn CMemStream::buffer();\n\t}\n\n\n\t/**\n\t * Similar to operator=, but makes the current message contain *only* the locked sub message in msgin\n\t * or the whole msgin if it is not locked\n\t *\n\t * Preconditions:\n\t * - msgin is an input message (isReading())\n\t * - The current message is blank (new or reset with clear())\n\t *\n\t * Postconditions:\n\t * - If msgin has been locked using lockSubMessage(), the current message contains only the locked\n\t *   sub message in msgin, otherwise the current message is exactly msgin\n\t * - The current message is an input message, it is not locked\n\t */\n\tvoid\t\t\tassignFromSubMessage( const CMessage& msgin );\n\n\t/**\n\t * Transforms the message from input to output or from output to input\n\t */\n\tvoid invert()\n\t{\n\t\tnlassertex( (!isReading()) || (!hasLockedSubMessage()), (\"Inverting %s\", LockedSubMessageError) );\n\n\t\tCMemStream::invert();\n\n\t\tif ( isReading() )\n\t\t{\n\t\t\t// Write -> Read: skip the header\n\t\t\t_TypeSet = false;\n//\t\t\tif ( _Buffer.size() != 0 )\n\t\t\tif ( _Buffer.getBuffer().size() != 0 )\n\t\t\t\treadType();\n\t\t}\n\t\t// For Read -> Write, please use clear()\n\t}\n\n\t// Clear the message. With this function, you can reuse a message to create another message\n\tvoid clear ();\n\n\t/** Returns the type name in string if available. Be sure that the message have the name of the message type\n\t * In a callback driven by message name, getName() does not necessarily return the right name.\n\t */\n\tstd::string getName () const;\n\n\t/** Return the type of the message.\n\t */\n\tTMessageType getType() const;\n\n\t/** Returns a readable string to display it to the screen. It's only for debugging purpose!\n\t * Don't use it for anything else than to debugging, the string format could change in the future.\n\t * \\param hexFormat If true, display all bytes in hexadecimal\n\t * \\param textFormat If true, display all bytes as chars (above 31, otherwise '.')\n\t */\n\tstd::string toString ( bool hexFormat=false, bool textFormat=false ) const;\n\n\t/// Set default stream mode\n\tstatic void\tsetDefaultStringMode( bool stringmode ) { _DefaultStringMode = stringmode; }\n\n\t/// Return an input stream containing the stream beginning in the message at the specified pos\n\tNLMISC::CMemStream\textractStreamFromPos( sint32 pos );\n\n\t/// Encapsulate/decapsulate another message inside the current message\n\tvoid\tserialMessage( CMessage& msg );\n\nprotected:\n\n\t/// Utility method\n\tvoid\t\tinit( const std::string &name, TStreamFormat streamformat );\n\n\t/// Utility method\n\tvoid\t\tresetSubMessageInternals() const\n\t{\n\t\t_SubMessagePosR = 0;\n//\t\t_LengthR = _Buffer.size();\n\t\t_LengthR = _Buffer.getBuffer().size();\n\t}\n\nprivate:\n\tstd::string\t\t\t\t\t\t\t_Name;\n\n\tmutable TMessageType\t\t\t\t_Type;\n\n\t// When sub message lock mode is enabled, beginning position of sub message to read (before header)\n\tmutable uint32\t\t\t\t\t\t_SubMessagePosR;\n\n\t// Length (can be smaller than _Buffer.size() if limitLength() is used) (updated in reading mode only)\n\tmutable uint32\t\t\t\t\t\t_LengthR;\n\n\t// Size of the header (that contains the name type or number type)\n\tuint32\t\t\t\t\t\t\t\t_HeaderSize;\n\n\tbool\t\t\t\t\t\t\t\t_TypeSet;\n\n\t// Default stream format\n\tstatic bool\t\t\t\t\t\t\t_DefaultStringMode;\n};\n\n}\n\n#endif // NL_MESSAGE_H\n\n/* End of message.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/message_recorder.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MESSAGE_RECORDER_H\n#define NL_MESSAGE_RECORDER_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"buf_net_base.h\"\n//#include \"callback_net_base.h\"\n#include \"message.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/mem_stream.h\"\n\n#include <fstream>\n#include <queue>\n#include <string>\n\nnamespace NLNET {\n\n\nclass CInetAddress;\n\n/// Type of network events (if changed, don't forget to change EventToString() and StringToEvent()\nenum TNetworkEvent { Sending, Receiving, Connecting, ConnFailing, Accepting, Disconnecting, Error };\n\n\n/// TNetworkEvent -> string\nstd::string EventToString( TNetworkEvent e );\n\n/// string -> TNetworkEvent\nTNetworkEvent StringToEvent( std::string& s );\n\n\n/*\n * TMessageRecord\n */\nstruct TMessageRecord\n{\n\t/// Default constructor\n\tTMessageRecord( bool input = false ) : UpdateCounter(0), SockId(InvalidSockId), Message( \"\", input ) {}\n\n\t/// Alt. constructor\n\tTMessageRecord( TNetworkEvent event, TSockId sockid, CMessage& msg, sint64 updatecounter ) :\n\t\tUpdateCounter(updatecounter), Event(event), SockId(sockid), Message(msg) {}\n\n\t/// Serial to string stream\n\tvoid serial( NLMISC::CMemStream& stream )\n\t{\n\t\tnlassert( stream.stringMode() );\n\n\t\tuint32 len;\n\t\tstd::string s_event;\n\t\tstream.serial( UpdateCounter );\n\t\tif ( stream.isReading() )\n\t\t{\n\t\t\tstream.serial( s_event );\n\t\t\tEvent = StringToEvent( s_event );\n\t\t\tuint32 sockId = (uint32)(size_t)SockId;\n\t\t\tstream.serialHex( sockId );\n\t\t\tstream.serial( len );\n\t\t\tstream.serialBuffer( Message.bufferToFill( len ), len );\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts_event = EventToString( Event );\n\t\t\tstream.serial( s_event );\n\t\t\tuint32 sockId;\n\t\t\tstream.serialHex( sockId );\n\t\t\tSockId = (NLNET::TSockId)(size_t)sockId;\n\t\t\tlen = Message.length();\n\t\t\tstream.serial( len );\n\t\t\tstream.serialBuffer( const_cast<uint8*>(Message.buffer()), len ); // assumes the message contains plain text\n\t\t}\n\t}\n\n\t//NLMISC::TTime\t\tTime;\n\tsint64\t\t\t\tUpdateCounter;\n\tTNetworkEvent\t\tEvent;\n\tTSockId\t\t\t\tSockId;\n\tCMessage\t\t\tMessage;\n};\n\n\n\n/**\n * Message recorder.\n * The service performs sends normally. They are intercepted and the recorder\n * plays the receives back. No communication with other hosts.\n * Warning: it works only with messages as plain text.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CMessageRecorder\n{\npublic:\n\n\t/// Constructor\n\tCMessageRecorder();\n\n\t/// Destructor\n\t~CMessageRecorder();\n\n\t/// Start recording\n\tbool\tstartRecord( const std::string& filename, bool recordall=true );\n\n\t/// Add a record\n\tvoid\trecordNext( sint64 updatecounter, TNetworkEvent event, TSockId sockid, CMessage& message );\n\n\t/// Stop recording\n\tvoid\tstopRecord();\n\n\t/// Start replaying\n\tbool\tstartReplay( const std::string& filename );\n\n\t/// Push the received blocks for this counter into the receive queue\n\tvoid\treplayNextDataAvailable( sint64 updatecounter );\n\n\t/**\n\t * Returns the event type if the counter of the next event is updatecounter,\n\t * and skip it; otherwise return Error.\n\t */\n\tTNetworkEvent\tcheckNextOne( sint64 updatecounter );\n\n\t/// Get the first stored connection attempt corresponding to addr\n\tTNetworkEvent\treplayConnectionAttempt( const CInetAddress& addr );\n\n\t/// Stop playback\n\tvoid\tstopReplay();\n\n\t/// Receive queue (corresponding to one update count). Use empty(), front(), pop().\n\tstd::queue<NLNET::TMessageRecord>\tReceivedMessages;\n\nprotected:\n\n\t/// Load the next record from the file (throws EStreamOverflow)\n\tbool\tloadNext( TMessageRecord& record );\n\n\t/// Get the next record (from the preloaded records, or from the file)\n\tbool\tgetNext( TMessageRecord& record, sint64 updatecounter );\n\nprivate:\n\n\t// Input/output file\n\tstd::fstream\t\t\t\t\t\t\t\t_File;\n\n\t// Filename\n\tstd::string\t\t\t\t\t\t\t\t\t_Filename;\n\n\t// Preloaded records\n\tstd::deque<TMessageRecord>\t\t\t\t\t_PreloadedRecords;\n\n\t// Connection attempts\n\tstd::deque<TMessageRecord>\t\t\t\t\t_ConnectionAttempts;\n\n\t// If true, record all events including sends\n\tbool\t\t\t\t\t\t\t\t\t\t_RecordAll;\n};\n\n\n} // NLNET\n\n\n#endif // NL_MESSAGE_RECORDER_H\n\n/* End of message_recorder.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/module.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_FILE_MODULE_H\n#define NL_FILE_MODULE_H\n\n#include \"nel/misc/factory.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/string_mapper.h\"\n#include \"nel/misc/co_task.h\"\n#include \"nel/misc/algo.h\"\n#include \"nel/net/message.h\"\n#include \"nel/net/unified_network.h\"\n#include \"module_common.h\"\n\nnamespace NLNET\n{\n\tclass CGatewayRoute;\n\tclass IModuleInterceptable;\n\n\tclass IInterceptorRegistrar\n\t{\n\tpublic:\n\t\tvirtual ~IInterceptorRegistrar() { }\n\t\tvirtual void registerInterceptor(IModuleInterceptable *interceptor) =0;\n\t\tvirtual void unregisterInterceptor(IModuleInterceptable *interceptor) =0;\n\t};\n\n\t/** This interface contains some module methods that can be intercepted.\n\t *\tThis is used to build responsibility chain for message processing\n\t *\tor to intercept module up/down to automatically track a list of\n\t *\tinteresting module proxy.\n\t */\n\tclass IModuleInterceptable\n\t{\n\tpublic:\n\t\tIModuleInterceptable();\n\t\tvirtual ~IModuleInterceptable();\n\n\t\tvoid registerInterceptor(IInterceptorRegistrar *registrar);\n\n\t\tvoid interceptorUnregistered(IInterceptorRegistrar *registrar);\n\n\t\tIInterceptorRegistrar *getRegistrar();\n\n\t\t/** Building of the manifest string can involve interceptors.\n\t\t *\tThe system will call this function on each interceptor\n\t\t *\tand concatenate the returned strings to build the manifest string.\n\t\t *\tA default implementation is given that return an emty string.\n\t\t */\n\t\tvirtual std::string\t\t\tbuildModuleManifest() const { return std::string(); }\n\n\t\t//@name Callback from module sockets\n\t\t//@{\n\t\t/** Called by a socket to inform this module that another\n\t\t *\tmodule has been created OR has been made accessible (due to\n\t\t *\ta gateway connection).\n\t\t */\n\t\tvirtual void\t\t\t\tonModuleUp(IModuleProxy *moduleProxy) = 0;\n\t\t/** Called by a socket to inform this module that another\n\t\t *\tmodule has been deleted OR has been no more accessible (due to\n\t\t *\tsome gateway disconnection).\n\t\t */\n\t\tvirtual void\t\t\t\tonModuleDown(IModuleProxy *moduleProxy) =0;\n\t\t/** Called internally by basic module imp to process the message by\n\t\t *\tapplication code.\n\t\t *\tThe system will call each interceptor until one return true.\n\t\t */\n\t\tvirtual bool\t\t\t\tonProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0;\n\t\t/** Called by a socket to inform this module that the security\n\t\t *\tdata attached to a proxy have changed.\n\t\t */\n\t\tvirtual void\t\t\t\tonModuleSecurityChange(IModuleProxy *moduleProxy) =0;\n\n\tprivate:\n\t\tIInterceptorRegistrar\t\t*_Registrar;\n\t};\n\n\t/** This is the interface for the a module.\n\t *\tIt describe interaction with the module itself,\n\t *\twith the module manager, and the module socket.\n\t */\n\tclass IModule :\n\t\tpublic NLMISC::CRefCount,\n\t\tpublic IInterceptorRegistrar,\n\t\tpublic IModuleInterceptable\n\t{\n\t\tfriend class IModuleFactory;\n\n\t\tvirtual void setFactory(IModuleFactory *factory) =0;\n\n\tpublic:\n\t\t/// The module is already plugged in the specified pluging\n\t\tclass EModuleAlreadyPluggedHere : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// An operation invocation has failed (mostly because of lost server module)\n\t\tclass EInvokeFailed : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// An operation invocation has failed because of a bad return type from servant\n\t\tclass EInvokeBadReturn : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t// Module management =====================\n\n\t\tvirtual ~IModule() {}\n\n\t\t/** Module initialization.\n\t\t *\tIf the initialization return false, then the module manager deleted\n\t\t *\tthe module immediately.\n\t\t */\n\t\tvirtual bool\t\t\tinitModule(const TParsedCommandLine &initInfo) =0;\n\n\t\t//@name Basic module information\n\t\t//@{\n\t\t/** Return the module ID. Each module has a local unique ID assigned\n\t\t *\tby the manager during module creation.\n\t\t *\tThis ID is local because it is only valid inside a given process.\n\t\t *\tWhen module are declared in another process, they receive a\n\t\t *\tlocal ID that is different than the ID in their host process.\n\t\t */\n\t\tvirtual TModuleId\t\t\tgetModuleId() const =0;\n\t\t/** Return the module name. Each module instance must have a unique\n\t\t *\tname in the host process.\n\t\t *\tIf no mane is given during module creation, the module manager\n\t\t *\tbuild a unique name from the module class and a number.\n\t\t */\n\t\tvirtual const std::string\t&getModuleName() const =0;\n\t\t/// Return the module class.\n\t\tvirtual const std::string\t&getModuleClassName() const =0;\n\t\t/** Return the module fully qualified name.\n\t\t *\tthe MFQN is the identifier that is used across process to identify\n\t\t *\teach module.\n\t\t *\tThe MDQNis composed from the computer host name, the process ID and\n\t\t *\tthe module name.\n\t\t *\tFormat : <hostname>:<pid>:<moduleName>\n\t\t *\tThis name is guarantied to be unique (at least, if the host name\n\t\t *\tis unique !)\n\t\t */\n\t\tvirtual const std::string\t&getModuleFullyQualifiedName() const =0;\n\n\t\t/** Return the manifest of the module.\n\t\t *\tThe manifest is a simple string of undefined format.\n\t\t *\tThe manifest is used by a module to expose some intention\n\t\t *\tor affinity (or whatever else you could imagine) of the\n\t\t *\tmodule.\n\t\t *\tThe manifest if transmit along with the module proxy, allowing\n\t\t *\tany module seeing the proxy to read the manifest.\n\t\t *\tYou should not use manifest to put big string because it is\n\t\t *\ttransmit with proxy information.\n\t\t *\tLikewise, you should never use manifest to transmit critical data\n\t\t *\t(such as password) because any module can read it.\n\t\t */\n\t\tvirtual std::string\tgetModuleManifest() const =0;\n\n\t\t/** Tell if the module implementation support immediate dispatching.\n\t\t *\tImmediate dispatching is when a message is send between\n\t\t *\tcollocated module (i.e module on the same gateway). In that case,\n\t\t *\tthe gateway forward the module immediately to the addressee module.\n\t\t *\tIn some case, this is not the expected behavior because it give\n\t\t *\tdifferent result depending if the communicating modules are\n\t\t *\tcollocated or not.\n\t\t *\tIt you module didn't support collocation optimisation, you must\n\t\t *\toverride this method and return false.\n\t\t *\tIn this case, message are stored in a queue and dispatching occur\n\t\t *\tin the next gateway update, just before the network update.\n\t\t */\n\t\tvirtual bool isImmediateDispatchingSupported() const { return true; }\n\t\t//@}\n\n\t\t//@name Callback from the module manager\n\t\t//@{\n\t\t/// A Nel layer 5 service has started.\n\t\tvirtual void\t\t\t\tonServiceUp(const std::string &serviceName, NLNET::TServiceId serviceId) =0;\n\t\t/// A Nel layer 5 service has stopped.\n\t\tvirtual void\t\t\t\tonServiceDown(const std::string &serviceName, NLNET::TServiceId serviceId) = 0;\n\t\t/** Regular update from application.\n\t\t *\tIf the application is a service, then it call CModuleManager::updateModules at each\n\t\t *\tservice loop.\n\t\t *\tIf the application is a regular application, then you have to call manually\n\t\t *\tCModuleManager::updateModules at regular intervals.\n\t\t */\n\t\tvirtual void\t\t\t\tonModuleUpdate() =0;\n\t\t/** The service main loop is terminating it job', all module while be\n\t\t *\tdisconnected and removed after this callback.\n\t\t */\n\t\tvirtual void\t\t\t\tonApplicationExit() = 0;\n\t\t//@}\n\n\t\t// socket management =====================\n\n\t\t//@name module sockets operation\n\t\t//@{\n\t\t/** Plug this module in the specified socket.\n\t\t *\tNote that a module can be plugged in several socket at the same\n\t\t *\ttime, but not twice in the same socket.\n\t\t */\n\t\tvirtual void\t\t\t\tplugModule(IModuleSocket *moduleSocket)\n\t\t\tthrow (EModuleAlreadyPluggedHere)\n\t\t\t=0;\n\t\t/** Unplug this module from the specified socket.\n\t\t *\tNote that a module can be plugged in several socket at the same\n\t\t *\ttime, but not twice in the same socket.\n\t\t *\tThrow an exception if the socket is not currently plug into\n\t\t *\tthe specified socket.\n\t\t */\n\t\tvirtual void\t\t\t\tunplugModule(IModuleSocket *moduleSocket)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t\t=0;\n\t\t/** Fill resultList vector with the list of socket into\n\t\t *\twitch this module is currently plugged.\n\t\t *\tThis method don't clear the result vector before filling it.\n\t\t */\n\t\tvirtual void\t\t\t\tgetPluggedSocketList(std::vector<IModuleSocket*> &resultList) =0;\n\t\t//@}\n\n\n\t\t//@name Callback from module sockets\n\t\t//@{\n\t\t/** Called by a socket to inform this module that another\n\t\t *\tmodule has been created OR has been made accessible (due to\n\t\t *\ta gateway connection).\n\t\t */\n//\t\tvirtual void\t\t\t\tonModuleUp(IModuleProxy *moduleProxy) = 0;\n\t\t/** Called by a socket to inform this module that another\n\t\t *\tmodule has been deleted OR has been no more accessible (due to\n\t\t *\tsome gateway disconnection).\n\t\t */\n//\t\tvirtual void\t\t\t\tonModuleDown(IModuleProxy *moduleProxy) =0;\n\t\t/** Called by a socket to receive a message in the module context.\n\t\t *\tBasic implementation either forward directly to onProcessModuleMessage\n\t\t *\tor queue the message in the coroutine message queue (when a synchronous\n\t\t *\tmessaging coroutine is started) for later dispatching.\n\t\t */\n\t\tvirtual void\t\t\t\tonReceiveModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0;\n\t\t/** Called internally by basic module imp to process the message by\n\t\t *\tapplication code.\n\t\t */\n//\t\tvirtual void\t\t\t\tonProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message) =0;\n\t\t/** Called by a socket to inform this module that the security\n\t\t *\tdata attached to a proxy have changed.\n\t\t */\n//\t\tvirtual void\t\t\t\tonModuleSecurityChange(IModuleProxy *moduleProxy) =0;\n\n\t\t/** Do a module operation invocation.\n\t\t *\tCaller MUST be in a module task to call this method.\n\t\t *\tThe call is blocking until receptions of the operation\n\t\t *\tresult message (or detection of the dest module module is down)\n\t\t */\n\t\tvirtual void\t\tinvokeModuleOperation(IModuleProxy *destModule, const NLNET::CMessage &opMsg, NLNET::CMessage &resultMsg)\n\t\t\tthrow (EInvokeFailed)\n\t\t\t=0;\n\n\t\t//@}\n\n\t\t//@name Callback from module sockets management\n\t\t//@{\n\t\tenum TModuleSocketEvent\n\t\t{\n\t\t\tmse_plugged,\n\t\t\tmse_before_unplug,\n\t\t\tmse_unplugged,\n\t\t};\n\t\tvirtual void\tonModuleSocketEvent(IModuleSocket *moduleSocket, TModuleSocketEvent eventType) =0;\n\t\t/// Called just after a module as been effectively plugged into a socket\n\t\t//@}\n\n\t\t//@{\n\t\t//@name internal method, should not be used by client code\n\t\tvirtual void _onModuleUp(IModuleProxy *removedProxy) =0;\n\t\tvirtual void _onModuleDown(IModuleProxy *removedProxy) =0;\n\n\t\t//@}\n\n\t};\n\n\tconst TModulePtr\t\tNullModule;\n\n\n\n\t/** Base class for module identification data\n\t *\tApplication writer should derive from this\n\t *\tclass to create there own security information.\n\t *\tSecurity information are bound to proxy data\n\t *\tby a secured gateway.\n\t */\n\tstruct TSecurityData\n\t{\n\t\t// for factory system\n\t\tstruct TCtorParam\n\t\t{\n\t\t\tuint8\tDataTag;\n\n\t\t\tTCtorParam(uint8 dataTag)\n\t\t\t\t:\tDataTag(dataTag)\n\t\t\t{\n\t\t\t}\n\t\t};\n\t\t/// An application defined identifier\n\t\tuint8\t\t\tDataTag;\n\n\t\t/// Pointer to next security data item (or NULL)\n\t\tTSecurityData\t*NextItem;\n\n\t\tTSecurityData(const TCtorParam &params)\n\t\t\t: DataTag(params.DataTag),\n\t\t\tNextItem(NULL)\n\n\t\t{\n\t\t}\n\n\t\tvirtual ~TSecurityData()\n\t\t{\n\t\t\tif (NextItem != NULL)\n\t\t\t\tdelete NextItem;\n\t\t}\n\n\t\tvirtual void serial(NLMISC::CMemStream &s) =0;\n\n\t};\n\n\tstruct TUnknownSecurityData : public TSecurityData\n\t{\n\t\tuint8\t\t\t\tRealDataTag;\n\t\tstd::vector<uint8>\tData;\n\n\t\tTUnknownSecurityData(uint8 realDataTag, uint32 size)\n\t\t\t: TSecurityData(TSecurityData::TCtorParam(0xff)),\n\t\t\tRealDataTag(realDataTag),\n\t\t\tData(size)\n\t\t{\n\t\t}\n\n\t\tvoid serial(NLMISC::CMemStream &s)\n\t\t{\n\t\t\tfor (uint i=0; i<Data.size(); ++i)\n\t\t\t{\n\t\t\t\ts.serial(Data[i]);\n\t\t\t}\n\t\t}\n\t};\n\n//\tNLMISC_REGISTER_OBJECT(TSecurityData, TUnknownSecurityData, uint8, 0xff);\n\n\t/** This interface is implemented by the system\n\t *\tand it give convenient access to distant module information\n\t *\tlike module name or id,\n\t *\tit also provide a helper to send module message\n\t *\twithout knowing the gateway.\n\t *\tNote that even collocated module (i.e. module created in the\n\t *\tsame process) must be accessed by module proxy or message\n\t *\tsend by through the socket interface.\n\t */\n\tclass IModuleProxy : public NLMISC::CRefCount\n\t{\n\tpublic:\n\t\tvirtual ~IModuleProxy() {}\n\n\t\t/** Return the module ID. Each module has a local unique ID assigned\n\t\t *\tby the manager during module creation.\n\t\t *\tThis ID is local because it is only valid inside a given process.\n\t\t *\tWhen module are declared in another process, they receive a\n\t\t *\tlocal ID that is different than the ID in their host process.\n\t\t */\n\t\tvirtual TModuleId\t\tgetModuleProxyId() const =0;\n\n\t\t/** Return the foreign id of the proxy.\n\t\t *\tThis is the proxy id of this module in the\n\t\t *\tcontext at the outbound of the route.\n\t\t *\tNote that if the module distance id 0, then\n\t\t *\tthis id is the module id and if the\tdistance\n\t\t *\tis 1, then this is the id of the local\n\t\t *\tproxy for the module in his host process.\n\t\t *\n\t\t *\tMaybe you don't exactly understand the meaning of this\n\t\t *\tid, what is sure is that you should never use it !\n\t\t */\n\t\tvirtual TModuleId\t\tgetForeignModuleId() const =0;\n\n\t\t/**\tReturn the distance of this module in number of\n\t\t *\tgateway to cross.\n\t\t *\tNote that when a module is reachable via more than\n\t\t *\tone route, the gateway always use the shortest path\n\t\t *\tto communicate with the module.\n\t\t */\n\t\tvirtual uint32\t\t\t\tgetModuleDistance() const =0;\n\n\t\t/** Return the IModule instance pointer.\n\t\t *\tFor local module proxies, this allow quick access to\n\t\t *\tthe real module instance.\n\t\t *\tFor foreign module proxies, this always return NULL.\n\t\t *\tYou should never access this methods if getModuleDistance()\n\t\t *\treturned more than 0 (witch mean that the module is local).\n\t\t */\n\t\tvirtual IModule\t\t\t\t*getLocalModule() const =0;\n\n\t\t/** Return a pointer to the route used to communicate\n\t\t *\twith the module.\n\t\t *\tFor local module proxy, the return value is NULL\n\t\t */\n\t\tvirtual CGatewayRoute\t\t*getGatewayRoute() const =0;\n\n\t\t/** Return the module name. Each module instance must have a unique\n\t\t *\tname in the host process.\n\t\t *\tIf no mane is given during module creation, the module manager\n\t\t *\tbuild a unique name from the module class and a number.\n\t\t *\tDistant module name are always the FQMN, ie, it is the same as\n\t\t *\tgetModuleFullyQualifiedName()\n\t\t */\n\t\tvirtual const std::string &getModuleName() const =0;\n\t\t/** Return the module class.\n\t\t *\tFor module proxy, this is always the fully qualified module name\n\t\t */\n\t\tvirtual const std::string &getModuleClassName() const =0;\n\t\t/** Return the manifest of the module.\n\t\t *\tThe manifest is a simple string of undefined format.\n\t\t *\tThe manifest is used by a module to expose some intention\n\t\t *\tor affinity (or whaterver else yuou could imagine) of the\n\t\t *\tmodule.\n\t\t */\n\t\tvirtual const std::string &getModuleManifest() const =0;\n\n\t\t/** Return the gateways interface by witch this module is accessible\n\t\t *\tIn some case, more than one gateway can be returned when there\n\t\t *\tis multiple route to the same module.\n\t\t */\n\t\tvirtual IModuleGateway *getModuleGateway() const =0;\n\n\t\t/** Send a message to the module.\n\t\t *\tThis method do the job of finding a valid socket to effectively send\n\t\t *\tthe message.\n\t\t */\n\t\tvirtual void\t\tsendModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotReachable)\n\t\t\t=0;\n\n\t\t/** Return the first item of the security item list\n\t\t *\tIf no security data are available, the method\n\t\t *\treturn NULL.\n\t\t */\n\t\tvirtual const TSecurityData *getFirstSecurityData() const = 0;\n\n\t\t/** Look in the security data list for a block\n\t\t *\tmatching the specified tag.\n\t\t *\tThe first block having the tag is returned.\n\t\t *\tIf no block have the requested tag, NULL is returned.\n\t\t */\n\t\tvirtual const TSecurityData *findSecurityData(uint8 dataTag) const =0;\n\t};\n\n\tconst TModuleProxyPtr\tNullModuleProxy;\n\n\t/// Base class for module task (aka module coroutine)\n\tclass CModuleTask : public NLMISC::CCoTask\n\t{\n\t\tbool\t_FailInvoke;\n\tprotected:\n\t\t///only derived class can use it\n\t\tCModuleTask (class CModuleBase *module);\n\n\t\tvoid initMessageQueue(class CModuleBase *module);\n\n\t\t// A module having a module task always running MUST call this evenly to\n\t\t// process message received by the module.\n\t\tvoid flushMessageQueue(class CModuleBase *module);\n\n\tpublic:\n\t\t// for task blocked in 'invoke' to fail with an exception\n\t\tvoid failInvoke()\n\t\t{\n\t\t\t_FailInvoke = true;\n\t\t}\n\n\t\tbool mustFailInvoke()\n\t\t{\n\t\t\treturn _FailInvoke;\n\t\t}\n\n\t\tvoid resetFailInvoke()\n\t\t{\n\t\t\t_FailInvoke = false;\n\t\t}\n\n\t\tvoid processPendingMessage(class CModuleBase *module);\n\t};\n\n\t/// Template module task\n\ttemplate <class T>\n\tclass TModuleTask : public CModuleTask\n\t{\n\tpublic:\n\n\t\ttypedef void (T::*TMethodPtr)();\n\n\tprivate:\n\t\tT\t\t\t*_Module;\n\t\tTMethodPtr\t_TaskMethod;\n\n\t\t// override CTask::run\n\t\tvoid run()\n\t\t{\n\t\t\tinitMessageQueue(_Module);\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// run the module task command control to module task method\n\t\t\t\t(_Module->*_TaskMethod)();\n\t\t\t}\n\t\t\tcatch (const NLMISC::Exception &e)\n\t\t\t{\n\t\t\t\tnlwarning(\"In module task '%s', exception '%e' thrown\", typeid(this).name(), e.what());\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tnlwarning(\"In module task '%s', unknown exception thrown\", typeid(this).name());\n\t\t\t}\n\n\t\t\t// finish the dispatch\n\t\t\tflushMessageQueue(_Module);\n\t\t}\n\tpublic:\n\n\t\tTModuleTask(T *module,  void (T::*taskMethod)())\n\t\t\t:\tCModuleTask(module),\n\t\t\t\t_Module(module),\n\t\t\t\t_TaskMethod(taskMethod)\n\t\t{\n\t\t}\n\t};\n\n\t// a special macro for easy module task startup\n#define\tNLNET_START_MODULE_TASK(className, methodName) \\\n\t{ \\\n\t\tNLNET::TModuleTask<className> *task = new NLNET::TModuleTask<className>(this, &className::methodName); \\\n\t\tqueueModuleTask(task); \\\n\t} \\\n\n\t/** Interface for module factory.\n\t *\tEach module MUST provide a factory and\n\t *\tregister an instance of the factory in\n\t *\tthe module manager.\n\t */\n\tclass IModuleFactory : public NLMISC::CRefCount\n\t{\n\tprotected:\n\t\t/// The class name of the factored module\n\t\tstd::string\t\t\t\t_ModuleClassName;\n\t\t/// The list of instantiated modules\n\t\tstd::set<TModulePtr>\t_ModuleInstances;\n\tpublic:\n\n\n\t\t/// Constructor, initialize the module class name\n\t\tIModuleFactory(const std::string &moduleClassName);\n\n\t\t/** Return the class name of the factored module */\n\t\tvirtual const std::string &getModuleClassName() const;\n\t\t/** Return the initialization string helper */\n\t\tvirtual const std::string &getInitStringHelp() const =0;\n\n\t\t/** Pretty simple method. Module initialization\n\t\t *\tis done after construction, so there are\n\t\t *\tno parameter at construction.\n\t\t */\n\t\tvirtual IModule *createModule() =0;\n\n\t\t/** The module manager call this to delete a module instance.*/\n\t\tvirtual void\tdeleteModule(IModule *module);\n\n\t\t/** Virtual destructor.\n\t\t *\tThe destructor while unregister the module factory from the\n\t\t *\tfactory registry and ALL module factored\n\t\t *\twill also be deleted.\n\t\t */\n\t\tvirtual ~IModuleFactory();\n\n\t\t/** Called by concrete factory to initialise the factored object */\n\t\tvoid registerModuleInFactory(TModulePtr module);\n\t};\n\n//\tconst TModuleFactoryPtr\tNullModuleFactory;\n\n\ttemplate <class moduleClass>\n\tclass CModuleFactory : public IModuleFactory\n\t{\n\tpublic:\n\t\tCModuleFactory(const std::string &moduleClassName)\n\t\t\t: IModuleFactory(moduleClassName)\n\t\t{}\n\n\t\tvirtual IModule *createModule()\n\t\t{\n\t\t\tIModule *module = new moduleClass;\n\t\t\tregisterModuleInFactory(module);\n\t\t\treturn module;\n\t\t}\n\n\t\tvirtual const std::string &getInitStringHelp() const\n\t\t{\n\t\t\treturn moduleClass::getInitStringHelp();\n\t\t}\n\n\t};\n\n#define NLNET_REGISTER_MODULE_FACTORY(moduleClassName, registrationName) \\\n\tclass moduleClassName##Factory : public NLNET::CModuleFactory<moduleClassName> \\\n\t{ \\\n\tpublic: \\\n\t\tstatic const std::string &theModuleClassName() \\\n\t\t{ \\\n\t\t\tstatic const std::string name(registrationName); \\\n\t\t\treturn name; \\\n\t\t} \\\n\t\t\\\n\t\tmoduleClassName##Factory() \\\n\t\t\t: NLNET::CModuleFactory<moduleClassName>(theModuleClassName()) \\\n\t\t{} \\\n\t};\\\n\tNLMISC_REGISTER_OBJECT_INDIRECT(NLNET::IModuleFactory, moduleClassName##Factory, std::string, registrationName)\n\n\n//#define NLNET_MAKE_MODULE_FACTORY_TYPENAME(moduleClassName) moduleClassName##Factory\n\n#define NLNET_GET_MODULE_FACTORY(moduleClassName)\tmoduleClassName##Factory\n\n\tclass CModuleSocket;\n\n\t/** Basic module implementation.\n\t *\tModule implementor should derive from this class\n\t *\trather than rebuild a complete module from\n\t *\tscratch (from IModule in fact).\n\t *\tThis class provide name and module registration,\n\t *\tmessage dispatching to message handler,\n\t *\tmodule socket interaction.\n\t */\n\tclass CModuleBase : public IModule, public NLMISC::ICommandsHandler\n\t{\n\t\t// Module manager is our friend coz it need to feed some field here\n\t\tfriend class CModuleManager;\n\t\tfriend class CModuleTask;\n\n\t\ttypedef std::set<IModuleSocket *> \tTModuleSockets;\n\t\t/// This is the sockets where the module is plugged in\n\t\tTModuleSockets\t\t\t_ModuleSockets;\n\n\t\ttypedef std::list<IModuleInterceptable*>\tTInterceptors;\n\t\t/// This is the linked list of interceptor\n\t\tTInterceptors\t\t\t_ModuleInterceptors;\n\n\t\t//@{\n\t\t//@name Synchronous messaging\n\t\ttypedef std::list<std::pair<IModuleProxy *, CMessage> >\tTMessageList;\n\t\t/// dynamically allocated list of synchronous message to process\n\t\tTMessageList\t\t\t_SyncMessages;\n\t\ttypedef std::list<CModuleTask*> TModuleTasks;\n\t\t/// list of coroutine to run for synchronous messaging (the first in the list is running)\n\t\tTModuleTasks\t\t\t_ModuleTasks;\n\n\t\ttypedef std::vector<IModuleProxy*>\tTInvokeStack;\n\t\t/// stack of server module with pending invocation response\n\t\tTInvokeStack\t\t\t_InvokeStack;\n\n\t\t/// The current message to process sender\n\t\tIModuleProxy\t\t\t*_CurrentSender;\n\t\t/// The current message to process\n\t\tconst NLNET::CMessage\t*_CurrentMessage;\n\t\t/// True if the current message processing have generated an exception\n\t\tbool\t\t\t\t\t_CurrentMessageFailed;\n\n\t\t/// task for message dispatching\n\t\tCModuleTask\t\t\t\t*_MessageDispatchTask;\n\t\t//@}\n\n\t\tvirtual void setFactory(IModuleFactory *factory);\n\t\tvirtual IModuleFactory *getFactory();\n\tprotected:\n\t\t/// Keep track of the module factory\n\t\tIModuleFactory\t\t*_ModuleFactory;\n\t\t/// This is the local unique ID assigned to this module.\n\t\tTModuleId\t\t\t_ModuleId;\n\t\t/// This is the module name.\n\t\tstd::string\t\t\t_ModuleName;\n\t\t/// This is the fully qualified module name\n\t\tmutable std::string\t_FullyQualifedModuleName;\n\n\n\t\tCModuleBase();\n\t\t~CModuleBase();\n\n\t\tvirtual void registerInterceptor(IModuleInterceptable *interceptor);\n\t\tvirtual void unregisterInterceptor(IModuleInterceptable *interceptor);\n\n\t\tconst std::string\t&getCommandHandlerName() const;\n\t\tTModuleId\t\t\tgetModuleId() const;\n\t\tconst std::string\t&getModuleName() const;\n\n\t\tconst std::string\t&getModuleClassName() const;\n\n\t\tconst std::string\t&getModuleFullyQualifiedName() const;\n\n\t\tstd::string\t\t\tgetModuleManifest() const;\n\n\t\t/** Called by a socket to receive a message in the module context.\n\t\t *\tBasic implementation either forward directly to onProcessModuleMessage\n\t\t *\tor queue the message in the coroutine message queue (when a synchronous\n\t\t *\tmessaging coroutine is started) for later dispatching.\n\t\t */\n\t\tvirtual void\t\tonReceiveModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message);\n\n\t\t/// The message dispatching task\n\t\tvoid _receiveModuleMessageTask();\n\n\t\tvoid queueModuleTask(CModuleTask *task);\n\n\t\tCModuleTask *getActiveModuleTask();\n\n\tpublic:\n\t\t/// return the default init string (empty)\n\t\tstatic const std::string &getInitStringHelp();\n\n\t\t/** Search an interceptor in the interceptor list.\n\t\t *\tBy default, the method begin to search at the first interceptor.\n\t\t *\tIf 'previous' is set to a valid interceptor, then the search\n\t\t *\tcontinue after it.\n\t\t *\tthe search is done by attempting a dynamic cast for\n\t\t *\teach interceptor.\n\t\t *\tIf no interceptor match the required class, then NULL is\n\t\t *\treturned.\n\t\t */\n\t\ttemplate <class T>\n\t\tT *getInterceptor(T *dummy, IModuleInterceptable *previous = NULL)\n\t\t{\n\t\t\tTInterceptors::iterator it(_ModuleInterceptors.begin());\n\t\t\tif (previous != NULL)\n\t\t\t{\n\t\t\t\t// advance up to next the previous\n\t\t\t\twhile (it != _ModuleInterceptors.end() && *it != previous)\n\t\t\t\t\t++it;\n\t\t\t\tif (it != _ModuleInterceptors.end())\n\t\t\t\t\t++it;\n\t\t\t}\n\n\t\t\twhile (it != _ModuleInterceptors.end())\n\t\t\t{\n\t\t\t\tIModuleInterceptable *mi = *it;\n\t\t\t\tT *inter = dynamic_cast<T*>(mi);\n\n\t\t\t\tif (inter != NULL)\n\t\t\t\t{\n\t\t\t\t\tdummy = inter;\n\t\t\t\t\treturn inter;\n\t\t\t\t}\n\n\t\t\t\t++it;\n\t\t\t}\n\n\t\t\tdummy = NULL;\n\t\t\treturn NULL;\n\t\t}\n\tprotected:\n\t\t// Init base module, init module name\n\t\tbool\t\t\t\tinitModule(const TParsedCommandLine &initInfo);\n\n\t\tvoid\t\t\t\tplugModule(IModuleSocket *moduleSocket) throw (EModuleAlreadyPluggedHere);\n\t\tvoid\t\t\t\tunplugModule(IModuleSocket *moduleSocket)  throw (EModuleNotPluggedHere);\n\t\tvoid\t\t\t\tgetPluggedSocketList(std::vector<IModuleSocket*> &resultList);\n\t\tvoid\t\t\t\tinvokeModuleOperation(IModuleProxy *destModule, const NLNET::CMessage &opMsg, NLNET::CMessage &resultMsg) throw (EInvokeFailed);\n\t\tvoid\t\t\t\t_onModuleUp(IModuleProxy *removedProxy);\n\t\tvoid\t\t\t\t_onModuleDown(IModuleProxy *removedProxy);\n\n\t\tbool\t\t\t\t_onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message);\n\n\n\n\n\t\t/// base module command table\n\t\tNLMISC_COMMAND_HANDLER_TABLE_BEGIN(CModuleBase)\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleBase, dump, \"display information about module instance status\", \"no args\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleBase, plug, \"plug the module in a module socket\", \"<socket_name>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleBase, unplug, \"unplug the module out of a module socket\", \"<socket_name>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleBase, sendPing, \"send a ping message to another module using the first available route\", \"<addresseeModuleName>\")\n\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\t\tNLMISC_CLASS_COMMAND_DECL(dump);\n\t\tNLMISC_CLASS_COMMAND_DECL(plug);\n\t\tNLMISC_CLASS_COMMAND_DECL(unplug);\n\t\tNLMISC_CLASS_COMMAND_DECL(sendPing);\n\t};\n\n\tclass CGatewayRoute;\n\n\tclass CModuleProxy : public IModuleProxy\n\t{\n\t\tfriend class CModuleManager;\n\t\tfriend class CStandardGateway;\n\n\t\t/// The gateway that received the module information\n\t\tIModuleGateway\t\t*_Gateway;\n\t\t/// The route to use for reaching the module\n\t\tCGatewayRoute\t\t*_Route;\n\t\t/// The module distance (in term of gateway to cross)\n\t\tuint32\t\t\t\t_Distance;\n\t\t/// The module local ID\n\t\tTModuleId\t\t\t_ModuleProxyId;\n\t\t/// The module foreign ID, this is the module ID in case of a local proxy\n\t\tTModuleId\t\t\t_ForeignModuleId;\n\n\t\t/// the module instance in case of local module, NULL otherwise\n\t\tTModulePtr\t\t\t_LocalModule;\n\t\t/// The module class name;\n\t\tNLMISC::TStringId\t_ModuleClassName;\n\t\t/// The  fully qualified module name.\n\t\tNLMISC::TStringId\t_FullyQualifiedModuleName;\n\t\t/// The module manifest\n\t\tstd::string\t\t\t_Manifest;\n\t\t/// the list of security data\n\t\tTSecurityData\t\t*_SecurityData;\n\n\t\t/// Private constructor, only module manager instantiate module proxies\n\t\tCModuleProxy(TModulePtr localModule, TModuleId localModuleId, const std::string &moduleClassName, const std::string &fullyQualifiedModuleName, const std::string &moduleManifest);\n\tpublic:\n\n\t\tconst CGatewayRoute * getRoute() const\n\t\t{\n\t\t\treturn _Route;\n\t\t}\n\n\t\t/** Return the module ID. Each module has a local unique ID assigned\n\t\t *\tby the manager during module creation.\n\t\t *\tThis ID is local because it is only valid inside a given process.\n\t\t *\tWhen module are declared in another process, they receive a\n\t\t *\tlocal ID that is different than the ID in their host process.\n\t\t */\n\t\tvirtual TModuleId\tgetModuleProxyId() const;\n\n\t\tvirtual TModuleId\tgetForeignModuleId() const;\n\n\n\t\tuint32\t\t\t\tgetModuleDistance() const;\n\n\t\tIModule\t\t\t\t*getLocalModule() const;\n\n\t\tCGatewayRoute\t\t*getGatewayRoute() const;\n\n\t\t/** Return the module name. Each module instance must have a unique\n\t\t *\tname in the host process.\n\t\t *\tIf no mane is given during module creation, the module manager\n\t\t *\tbuild a unique name from the module class and a number.\n\t\t *\tDistant module name are always the FQMN, ie, it is the same as\n\t\t *\tgetModuleFullyQualifiedName()\n\t\t */\n\t\tvirtual const std::string &getModuleName() const;\n\t\t/// Return the module class.\n\t\tvirtual const std::string &getModuleClassName() const;\n\t\t/// return the module manifest\n\t\tvirtual const std::string &getModuleManifest() const;\n\n\t\t/** Return the gateways interface by witch this module is accessible.\n\t\t */\n\t\tvirtual IModuleGateway *getModuleGateway() const;\n\n\t\t/** Send a message to the module.\n\t\t */\n\t\tvirtual void\t\tsendModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotReachable);\n\n\t\tvirtual const TSecurityData *getFirstSecurityData() const\n\t\t{\n\t\t\treturn _SecurityData;\n\t\t}\n\n\t\tvirtual const TSecurityData *findSecurityData(uint8 dataTag) const;\n\t};\n\n\n\n\t/** Utility class to do broadcast with a container of proxy pointer\n\t */\n\ttemplate <class PtrContainer>\n\tclass TBroadcastModuleMessage\n\t{\n\n\t\tvoid sendMessage(IModule *sender, const PtrContainer &addresseeProxies, const NLNET::CMessage &message)\n\t\t{\n\t\t\ttypename PtrContainer::iterator first(addresseeProxies.begin()), last(addresseeProxies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModuleProxy *proxy = static_cast<IModuleProxy*>(*first);\n\n\t\t\t\tproxy->sendModuleMessage(sender, message);\n\t\t\t}\n\t\t}\n\t};\n\n\n} // namespace NLNET\n\n#endif // NL_FILE_MODULE_H\n"
  },
  {
    "path": "code/nel/include/nel/net/module_builder_parts.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef MODULE_BUILDER_PARTS_H\n#define MODULE_BUILDER_PARTS_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/mutable_container.h\"\n#include \"module.h\"\n\nnamespace NLNET\n{\n\n\ttemplate <class T>\n\tclass CEmptyModuleServiceBehav : public T\n\t{\n\tpublic:\n\t\tvirtual void\t\t\t\tonServiceUp(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{}\n\t\tvirtual void\t\t\t\tonServiceDown(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{}\n\t\tvirtual void\t\t\t\tonModuleUpdate()\n\t\t{}\n\t\tvirtual void\t\t\t\tonApplicationExit()\n\t\t{}\n\t};\n\n\ttemplate <class T>\n\tclass CEmptyModuleCommBehav : public T\n\t{\n\tpublic:\n\t\tstd::string\t\t\t\t\tbuildModuleManifest() const\n\t\t{\n\t\t\treturn \"\";\n\t\t}\n\t\tvirtual void\t\t\t\tonModuleUp(IModuleProxy * /* moduleProxy */)\n\t\t{}\n\t\tvirtual void\t\t\t\tonModuleDown(IModuleProxy * /* moduleProxy */)\n\t\t{}\n\t\tvirtual void\t\t\t\tonModuleSecurityChange(IModuleProxy * /* moduleProxy */)\n\t\t{}\n\t\tvirtual bool\t\t\t\tonProcessModuleMessage(IModuleProxy * /* senderModuleProxy */, const CMessage &/* message */)\n\t\t{\treturn false; }\n\t};\n\n\ttemplate <class T>\n\tclass CEmptySocketBehav : public T\n\t{\n\tpublic:\n\t\tvirtual void\tonModuleSocketEvent(IModuleSocket * /* moduleSocket */, IModule::TModuleSocketEvent /* eventType */)\n\t\t{\n\t\t}\n\t};\n\n\n\t/** Interceptor forwarder\n\t *\tThe trick is that if you build a module interceptor class\n\t *\tand then you want to inherit this class in a module definition, then\n\t *\tthe virtual callbacks are received by the module instead of by your\n\t *\tinterceptor (because the base module is also an interceptor and\n\t *\tit eventualy overides the calls).\n\t *\tThe workaround consist of having the interceptor implemented in\n\t *\tan inner class with method forwarded to you class with a different\n\t *\tinterface.\n\t */\n\ttemplate <class ParentClass>\n\tclass CInterceptorForwarder : public IModuleInterceptable\n\t{\n\t\tParentClass\t\t*_Parent;\n\tpublic:\n\t\tCInterceptorForwarder()\n\t\t\t:\t_Parent(NULL)\n\t\t{}\n\n\t\tvoid init(ParentClass *parent, IModule *module)\n\t\t{\n\t\t\tnlassert(parent != NULL);\n\t\t\tnlassert(module != NULL);\n\n\t\t\t_Parent = parent;\n\t\t\tregisterInterceptor(module);\n\t\t}\n\n\t\tParentClass *getParent()\n\t\t{\n\t\t\treturn _Parent;\n\t\t}\n\n\t\tvirtual std::string\t\t\tbuildModuleManifest() const\n\t\t{\n\t\t\treturn _Parent->fwdBuildModuleManifest();\n\t\t}\n\t\tvirtual void\t\t\t\tonModuleUp(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\t_Parent->fwdOnModuleUp(moduleProxy);\n\t\t}\n\t\tvirtual void\t\t\t\tonModuleDown(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\t_Parent->fwdOnModuleDown(moduleProxy);\n\t\t}\n\t\tvirtual bool\t\t\t\tonProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message)\n\t\t{\n\t\t\treturn _Parent->fwdOnProcessModuleMessage(senderModuleProxy, message);\n\t\t}\n\t\tvirtual void\t\t\t\tonModuleSecurityChange(IModuleProxy *moduleProxy)\n\t\t{\n\t\t\t_Parent->fwdOnModuleSecurityChange(moduleProxy);\n\t\t}\n\t};\n\n\t/** Callback class used by the CModuleTracker class below and to be\n\t *\timplemented if you want callback when tracked module are up/down.\n\t */\n\tclass IModuleTrackerCb\n\t{\n\tpublic:\n\t\tvirtual ~IModuleTrackerCb() { }\n\n\t\tvirtual void onTrackedModuleUp(IModuleProxy *moduleProxy) =0;\n\t\tvirtual void onTrackedModuleDown(IModuleProxy *moduleProxy) =0;\n\t};\n\n\t/** A module interceptor that keep of a set of known module that match a given\n\t *\tpredicate.\n\t *\tA typical usage is to declare an instance of this class (specialized with\n\t *\tthe appropriate predicate) as member of your module.\n\t *\tYou can also have more than one tracker with different predicate\n\t *\tif you are interested in different modules.\n\t *\n\t *\tNB : don't forget to init() each tracker in order to let it register\n\t *\tin you module interceptor list (typically, call \"_MyTracker.init(this, this)\" in\n\t *\tyour module's constructor).\n\t */\n\ttemplate <class ModulePredicate>\n\tclass CModuleTracker\n\t{\n\tpublic:\n\t\ttypedef NLMISC::TMutableContainer<std::set<TModuleProxyPtr> >\tTTrackedModules;\n\n\tprivate:\n\t\t/// this is the list of module that match the predicate\n\t\tTTrackedModules\t\t_TrackedModules;\n\n\t\t/// An instance of the predicate class\n\t\tModulePredicate\t\t_ModulePred;\n\n\t\t/// The callback interface implementation (if any)\n\t\tIModuleTrackerCb\t*_TrackerCallback;\n\n\tpublic:\n\t\tCModuleTracker(const ModulePredicate &pred)\n\t\t\t:\t_ModulePred(pred),\n\t\t\t\t_TrackerCallback(NULL)\n\t\t{\n\t\t}\n\t\t/** Init : set the owner module (to register the interceptor) and the\n\t\t *\toptional callback interface.\n\t\t */\n\t\tvoid init(NLNET::IModule *module, IModuleTrackerCb *trackerCallback = NULL)\n\t\t{\n\t\t\t_Interceptor.init(this, module);\n\t\t\t_TrackerCallback = trackerCallback;\n\t\t}\n\n\t\t/** Return the set of tracked module.\n\t\t *\tThe set is wrapped into a mutable container that allow\n\t\t *\tto call non const begin() and end() from a const container.\n\t\t */\n\t\tconst TTrackedModules &getTrackedModules() const\n\t\t{\n\t\t\treturn _TrackedModules;\n\t\t}\n\n\tprivate:\n\n\t\t// unused interceptors\n\t\tstd::string\t\t\tfwdBuildModuleManifest() const\t{ return std::string(); }\n\t\tvoid\t\t\t\tfwdOnModuleSecurityChange(NLNET::IModuleProxy * /* moduleProxy */) {}\n\t\tbool\t\t\t\tfwdOnProcessModuleMessage(NLNET::IModuleProxy * /* sender */, const NLNET::CMessage &/* message */)\t{return false;}\n\n\t\t// check module up\n\t\tvoid\t\t\t\tfwdOnModuleUp(NLNET::IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tif (_ModulePred(moduleProxy))\n\t\t\t{\n\t\t\t\tif (_TrackedModules.insert(moduleProxy).second && _TrackerCallback != NULL)\n\t\t\t\t\t// warn the callback\n\t\t\t\t\t_TrackerCallback->onTrackedModuleUp(moduleProxy);\n\t\t\t}\n\t\t};\n\n\t\t// check module down\n\t\tvoid\t\t\t\tfwdOnModuleDown(NLNET::IModuleProxy *moduleProxy)\n\t\t{\n\t\t\tif (_TrackedModules.find(moduleProxy) != _TrackedModules.end())\n\t\t\t{\n\t\t\t\t_TrackedModules.erase(moduleProxy);\n\t\t\t\tif (_TrackerCallback != NULL)\n\t\t\t\t\t_TrackerCallback->onTrackedModuleDown(moduleProxy);\n\t\t\t}\n\t\t};\n\n\t\ttypedef NLNET::CInterceptorForwarder < CModuleTracker>\tTInterceptor;\n\t\t// declare one interceptor member of the skeleton\n\t\tTInterceptor\t_Interceptor;\n\t\t// declare the interceptor forwarder as friend of this class\n\t\tfriend \t\tclass NLNET::CInterceptorForwarder < CModuleTracker>;\n\t};\n\n\t/** A canonical module predicate that test a module\n\t *\tfor a specified module class name.\n\t */\n\tstruct TModuleClassPred\n\t{\n\tprivate:\n\t\tstd::string _ClassName;\n\n\tpublic:;\n\t\tTModuleClassPred(const std::string &className)\n\t\t\t:\t_ClassName(className)\n\t\t{\n\t\t}\n\n\t\tbool operator () (IModuleProxy *moduleProxy) const\n\t\t{\n\t\t\treturn moduleProxy->getModuleClassName() == _ClassName;\n\t\t}\n\t};\n\n} // namespace NLNET\n\n#endif // MODULE_BUILDER_PARTS_H\n\n"
  },
  {
    "path": "code/nel/include/nel/net/module_common.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_MODULE_COMMON_H\n#define NL_MODULE_COMMON_H\n\n#include \"nel/misc/smart_ptr.h\"\n#include \"nel/misc/common.h\"\n\nnamespace NLNET\n{\n\t/// General type definition\n\t/// Module identifier\n\ttypedef uint32\tTModuleId;\n\n\t/// A module ID of 0 mean 'not valid module ID'\n\tconst TModuleId\tINVALID_MODULE_ID = 0;\n\n\t/// Forward smart ptr definition\n\tclass IModule;\n\ttypedef NLMISC::CSmartPtr<IModule>\t\t\tTModulePtr;\n\n\tclass IModuleProxy;\n\ttypedef NLMISC::CSmartPtr<IModuleProxy>\t\tTModuleProxyPtr;\n\n\tclass IModuleSocket;\n\tclass IModuleFactory;\n\tclass IModuleGateway;\n\tstruct TSecurityData;\n\n\t/// The destination module for a message cannot be reached by socket used\n\tclass EModuleNotReachable : public NLMISC::Exception\n\t{\n\t};\n\t/// A module use a socket where it is not plugged in\n\tclass EModuleNotPluggedHere : public NLMISC::Exception\n\t{\n\t};\n\n\n\t/** Structure for pre-parsed command line parameters\n\t *\tSupport in memory representation of parameter line like :\n\t *\t'tag1(x=1 y=2 z=3) tag2=6 tag3(a=abc b=xyz tag4)'\n\t */\n\tclass TParsedCommandLine\n\t{\n\tpublic:\n\n\t\t// copy constructor is needed because SubParams contains pointers\n\t\tTParsedCommandLine(const TParsedCommandLine& copy);\n\n\t\tTParsedCommandLine()\n\t\t{\n\n\t\t};\n\n\t\t~TParsedCommandLine();\n\n\t\t/// The parameter name\n\t\tstd::string\t\tParamName;\n\t\t/// The parameter value, empty in the case of a sub param header\n\t\tstd::string\t\tParamValue;\n\n\t\t/// The list of sub parameters. Empty in the case of a single param.\n\t\tstd::vector<TParsedCommandLine*>\tSubParams;\n\n\t\t/// Cleanup\n\t\tvoid clear();\n\n\t\t/// Parse a NeL argument list to build a module init object.\n\t\tbool parseParamList(const std::string &rawParamString);\n\n\t\t/** Ask the command line for a parameter\n\t\t *\tIf the parameter doesn't exist, the method return NULL.\n\t\t *\tYou can request a sub param directly by\n\t\t *\tconcatenating the header(s) name separated by dot.\n\t\t *\te.g. in the param string \"a(b(c=4)\", you can\n\t\t *\tquery directly with 'a.b.c' to retrieve the value 4.\n\t\t */\n\t\tconst TParsedCommandLine *getParam(const std::string &name) const;\n\n\t\t/** Add or replace a parameter in the set.\n\t\t *\tThe name can be any valid name (e.g 'a' or 'a.b.c').\n\t\t *\tIf any sub part of the name didn't exist, the function\n\t\t *\twill create the appropriate sub object.\n\t\t */\n\t\tvoid setParam(const std::string &name, const std::string &value);\n\n\t\t/** Rebuild the raw command line string */\n\t\tstd::string toString() const;\n\n\tprivate:\n\t\tbool _parseParamList(const std::string &rawParamString);\n\t\tconst TParsedCommandLine *_getParam(std::vector<std::string>::iterator it, std::vector<std::string>::iterator end) const;\n\t\tTParsedCommandLine *_getParam(std::vector<std::string>::iterator it, std::vector<std::string>::iterator end);\n\n\t};\n\n} // namespace NLNET\n\n#endif // NL_MODULE_COMMON_H\n"
  },
  {
    "path": "code/nel/include/nel/net/module_gateway.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_FILE_MODULE_GATEWAY_H\n#define NL_FILE_MODULE_GATEWAY_H\n\n#include \"nel/misc/twin_map.h\"\n#include \"module_common.h\"\n#include \"inet_address.h\"\n#include \"message.h\"\n#include \"module_message.h\"\n\nnamespace NLNET\n{\n\tclass IGatewayTransport;\n\tclass CGatewayRoute;\n\tclass CGatewaySecurity;\n\n\t/** Interface for gateway.\n\t *\tA gateway is the part of the module layer that interconnect\n\t *\tmodule locally and give access to foreign module hosted in\n\t *\tother process.\n\t *\tGateway can interconnect local module with themselves, as well as\n\t *\tconnect with another gateway in another process or host.\n\t *\n\t *\tTransport:\n\t *\t---------\n\t *\tGateway connectivity is provided by 'transport' that can\n\t *\tbe build on any support.\n\t *\tThere are available transport for NeL Layer 3 in server\n\t *\tof client mode.\n\t *\n\t *\tYou can bind at run time, any number of transport to a\n\t *\tgateway.\n\t *\tEach of these transport can then receive specific command\n\t *\tfrom passed by the gateway.\n\t *\tTransport then create routes that are active connection\n\t *\tto foreign gateways.\n\t *\n\t *\tWhen using the layer 3 transport, you can choose either\n\t *\tto instantiate a client mode transport or a server mode\n\t *\ttransport.\n\t *\tIn client mode, you can connect to one or more server, each\n\t *\tconnection generating a new route.\n\t *\tIn server mode, you can put your transport as 'open' on\n\t *\ta specified TCP port, then each client connection will\n\t *\tgenerate a new route.\n\t *\n\t *\tThese layer 3 transport are only one type of transport,\n\t *\tit it possible to build any type of transport (on raw TCP\n\t *\tsocket, or over UDP, or using named pipe...).\n\t *\n\t *\tUnique name generation :\n\t *\t------------------------\n\t *\tGateway need to generate 'fully qualified module name' witch\n\t *\tmust be unique in any gateway interconnection scheme.\n\t *\tBy default, gateway use the following scheme to build\n\t *\tunique module name :\n\t *\t\t<hostname>:<pid>:<modulename>\n\t *\tIn some case, you could not be sure that the host name will\n\t *\tbe unique (think about your hundreds simultaneously connected\n\t *\tclients, some of them can have set the same name for their\n\t *\tcomputer !). In this case, you can set register a unique name\n\t *\tgenerator on you gateway that use another naming scheme.\n\t *\tFor example, you can use you customer unique ID (with the\n\t *\trestriction that one ID can be in use once at the same time)\n\t *\tto build unique name :\n\t *\t\t<customerId>:<modulename>\n\t *\n\t *\tAdvanced transport options (i.e option settable on each transport):\n\t *\t--------------------------\n\t *\t- peer invisible : if activated on a transport, this option\n\t *\t\twill mask the modules of the other routes of the same\n\t *\t\ttransport.\n\t *\t\tThis is useful for players modules (you sure don't want\n\t *\t\tthat all players can see all other clients modules),\n\t *\t\tor for client/server structure where you don't want\n\t *\t\tall client to see all module, bu only those that are\n\t *\t\tavailable from the client side.\n\t *\t\tNote that any module that come from another transport\n\t *\t\twill be disclosed to all the route.\n\t *\n\t *\t- firewalled : if activated, this option will mask any module\n\t *\t\tto the connected unsecure route unless some module comming from another\n\t *\t\ttransport (or a local module) will try to send a message\n\t *\t\tto a module on an unsecure route. In this case, the gateway\n\t *\t\twill disclose the information about this sender module (and only\n\t *\t\tthis one) to the unsecure route.\n\t *\t\tIn firewall mode, the gateway keep a list of disclosed module\n\t *\t\tfor each route and stop any message that is addressed to an\n\t *\t\tundisclosed module (that can be considered as a hacking attempt).\n\t *\t\tModule that are disclosed by the unsecure routes are normaly\n\t *\t\tseen by all other module.\n\t *\n\t *\tThe two options above can be used in combination. This is a prefered\n\t *\tway of configuring transport for player connection : we don't want\n\t *\tplayer to see other player modules, and we don't want player to see\n\t *\tany server side module until one of them started a communication\n\t *\twith a player module.\n\t */\n\tclass IModuleGateway : public NLMISC::CRefCount\n\t{\n\tpublic:\n\t\t// Exception classes ===================================\n\n\t\t/// The gateway is already open while trying to open it.\n\t\tclass EGatewayAlreadyOpen : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// When trying to open the gateway server, the TCP port is already in use\n\t\tclass EGatewayPortInUse : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// The gateway is not open while trying to close it.\n\t\tclass EGatewayNotOpen : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// A gateway is not connected while trying to communicate with\n\t\tclass EGatewayNotConnected : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\t/// Firewall mode is activated but there is already open route !\n\t\tclass EGatewayFirewallBreak : public NLMISC::Exception\n\t\t{\n\t\t};\n\n\t\tvirtual ~IModuleGateway() {}\n\n\t\t/** Register the gateway in the module manager gateway registry\n\t\t */\n\t\tvirtual void registerGateway() =0;\n\t\t/** Unregister the gateway in the module manager gateway registry\n\t\t */\n\t\tvirtual void unregisterGateway() =0;\n\n\t\t//@{\n\t\t//@name Gateway general information and control\n\t\t/// Return the local name of the gateway\n\t\tvirtual const std::string &getGatewayName() const =0;\n\t\t/// Return the Fully Qualified Gateway Name (FQGN)\n\t\tvirtual const std::string &getFullyQualifiedGatewayName() const =0;\n\t\t//@}\n\n\t\t//@{\n\t\t//@name Gateway transport management\n\n\t\t/// Create and bind to this gateway a new transport\n\t\tvirtual void\tcreateTransport(const std::string &transportClass, const std::string &instanceName) =0;\n\t\t/// Delete a transport (this will close any open route)\n\t\tvirtual void\tdeleteTransport(const std::string &transportInstanceName) =0;\n\n\t\t/// Activate/stop peer invisible mode on a transport\n\t\tvirtual void\tsetTransportPeerInvisible(const std::string &transportInstanceName, bool peerInvisible) =0;\n\n\t\t/// Activate/stop firewalling mode on a transport\n\t\tvirtual void\tsetTransportFirewallMode(const std::string &transportInstanceName, bool firewalled)\n\t\t\tthrow (EGatewayFirewallBreak) =0;\n\n\t\t/// Send a command to a transport\n\t\tvirtual void\ttransportCommand(const TParsedCommandLine &commandLine) =0;\n\n\t\t/// Return a pointer on the named transport interface, or NULL if the transport is unknown.\n\t\tvirtual IGatewayTransport *getGatewayTransport(const std::string &transportName) const =0;\n\n\t\t/// Return the number of transport currently active on this gateway\n\t\tvirtual uint32\tgetTransportCount() const =0;\n\n\t\t/// Return the number route available\n\t\tvirtual uint32\tgetRouteCount() const =0;\n\n\t\t/// Return the number of ping received. This is incremented by special \"GW_PING\" message for unit testing\n\t\tvirtual uint32\tgetReceivedPingCount() const =0;\n\t\t//@}\n\n\t\t//@{\n\t\t//@name Gateway transport callback\n\t\t/// A new route a added by a transport\n\t\tvirtual void onRouteAdded(CGatewayRoute *route) =0;\n\n\t\t/// A route is removed by a transport\n\t\tvirtual void onRouteRemoved(CGatewayRoute *route) =0;\n\n\t\t/// A transport have received a message\n\t\tvirtual void onReceiveMessage(CGatewayRoute *from, const CMessage &msgin) =0;\n\t\t//@}\n\n\t\t//@{\n\t\t//@name Gateway security plug-in management\n\t\t/** create a security plug-in.\n\t\t *\tThere must be no security plug-in currently created.\n\t\t */\n\t\tvirtual void createSecurityPlugin(const std::string &className) = 0;\n\t\t/** Send a command to the security plug-in */\n\t\tvirtual void sendSecurityCommand(const TParsedCommandLine &command) =0;\n\t\t/** Remove the security plug-in.\n\t\t */\n\t\tvirtual void removeSecurityPlugin() = 0;\n\t\t//@}\n\n\t\t//@{\n\t\t//@name Module management\n\t\t/** Callback called when the gateway has received some new module\n\t\t *\tand eventually, need to disclose the module information to\n\t\t *\tthe connected gateway.\n\t\t *\tThe default behavior is to disclose the module to all\n\t\t *\tconnected gateway.\n\t\t */\n\t\tvirtual void onAddModuleProxy(IModuleProxy *addedModule) =0;\n\t\t/** Callback called when a module become unavailable, either\n\t\t *\tbecause it is unplugged from it's socket, or, the\n\t\t *\tgateway that disclosed it has been disconnected.\n\t\t */\n\t\tvirtual void onRemoveModuleProxy(IModuleProxy *removedModule) =0;\n\n\t\t/** Disclose module information to a connected gateway.\n\t\t *\tThis can also be this gateway itself.\n\t\t */\n\t\tvirtual void discloseModule(IModuleProxy *moduleProxy)\n\t\t\tthrow (EGatewayNotConnected)\n\t\t\t=0;\n\n\t\t/** Retrieve the proxy for a locally plugged module.\n\t\t *\tEach local module plugged in a gateway has an associated\n\t\t *\tproxy. This method return this proxy or NULL if the\n\t\t *\tmodule is not plugged here.\n\t\t */\n\t\tvirtual IModuleProxy *getPluggedModuleProxy(IModule *pluggedModule) =0;\n\n\t\t/// Return the number of proxies managed by this gateway\n\t\tvirtual uint32\tgetProxyCount() const =0;\n\n\t\t/// Fill a vector with the list of proxies managed here. The module are filled in ascending proxy id order.\n\t\tvirtual void\tgetModuleProxyList(std::vector<IModuleProxy*> &resultList) const =0;\n\t\t//@}\n\n\t\t//@{\n\t\t//@name Module messaging\n\t\t/** Callback called when a message arrive from a gateway and need\n\t\t *\tto be dispatched.\n\t\t *\tThe default behavior is to route the message in any case to\n\t\t *\tthe destination module.\n\t\t *\tYou can override this callback to add some message filtering\n\t\t *\tor hacking feature.\n\t\t */\n//\t\tvirtual void onReceiveModuleMessage(TModuleGatewayProxyPtr &senderGateway, TModuleMessagePtr &message) =0;\n\n\t\t/** Send a message to a module.\n\t\t */\n\t\tvirtual void sendModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const NLNET::CMessage &message) =0;\n\n\t\t/** Send a message to the module plugged in this gateway.\n\t\t *\tYou can override this method to change the dispatching, add filtering,\n\t\t *\tmessage hacking or interceptor.\n\t\t */\n\t\tvirtual void dispatchModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const CMessage &message) =0;\n\t\t//@}\n\t};\n\n\t/** Intermediate class must be used as base class\n\t *\tfor implementing gateway.\n\t */\n\tclass CModuleGateway : public IModuleGateway\n\t{\n\tprotected:\n\t\t/** Register the gateway in the module manager gateway registry\n\t\t */\n\t\tvirtual void registerGateway();\n\t\t/** Unregister the gateway in the module manager gateway registry\n\t\t */\n\t\tvirtual void unregisterGateway();\n\t};\n\n\t/** Interface class for gateway transport.\n\t *\tA gateway transport is an object associated to a standard gateway\n\t *\tat run time and that provide a mean to interconnect with\n\t *\tother gateway.\n\t *\tAs each transport mode as it's own command requirement,\n\t *\ta generic command system is provided for sending command message\n\t *\tto the transport implementation.\n\t *\n\t *\tAt time of writing, NeL come with 2 transport : one based on layer 3 client, and one\n\t *\tbased on layer 3 server. In a short time, there will be transport using layer 5.\n\t */\n\tclass IGatewayTransport\n\t{\n\tprotected:\n\t\t/// Back pointer to the gateway hosting this transport\n\t\tIModuleGateway\t\t\t*_Gateway;\n\tpublic:\n\t\t/// Invalid transport command\n\t\tclass EInvalidCommand : public NLMISC::Exception\n\t\t{\n\t\tpublic:\n\t\t\tEInvalidCommand() {}\n\t\t\tEInvalidCommand(const char *err) : Exception(err) {}\n\t\t};\n\n\t\t/// Error in the transport\n\t\tclass ETransportError : public NLMISC::Exception\n\t\t{\n\t\tpublic:\n\t\t\tETransportError(const char *err) : Exception(err) {}\n\t\t};\n\n\t\t//////////////// property used by gateway (not managed by transport)\n\t\t/// Flag for firewall mode\n\t\tbool\t\t\t\tFirewalled;\n\t\t/// flag for peer invisible mode\n\t\tbool\t\t\t\tPeerInvisible;\n\n\t\t/// Constructor param needed by the factory (see nel/misc/factory.h)\n\t\tstruct TCtorParam\n\t\t{\n\t\t\tIModuleGateway *Gateway;\n\t\t};\n\n\t\t/// Constructor, establish link with the associated gateway\n\t\tIGatewayTransport(const TCtorParam &param)\n\t\t\t: Firewalled(false),\n\t\t\tPeerInvisible(false)\n\t\t{\n\t\t\t_Gateway = param.Gateway;\n\t\t}\n\n\t\tvirtual ~IGatewayTransport() {}\n\n\t\t/// Return the class name from the transport factory\n\t\tvirtual const std::string &getClassName() const =0;\n\n\t\t/// The gateway send a command message to the transport\n\t\tvirtual void onCommand(const CMessage &command) throw (EInvalidCommand) = 0;\n\t\t/// The gateway send a textual command to the transport\n\t\tvirtual bool onCommand(const TParsedCommandLine &command) throw (EInvalidCommand) = 0;\n\n\t\t/// The gateway update the transport regularly\n\t\tvirtual void update() =0;\n\n\t\t/// Return the number of route currently open by the transport\n\t\tvirtual uint32 getRouteCount() const =0;\n\n\t\t/// Dump debug information in the specified log stream\n\t\tvirtual void dump(NLMISC::CLog &log) const =0;\n\t};\n\n\t/** Base class for gateway route.\n\t *\tRoute are provided by transport.\n\t *\tTransport provide a mean to build route\n\t *\tbetween gateway.\n\t *\tRoute show the list of foreign gateway that are\n\t *\treachable with it and are use to send\n\t *\tmessage to these gateways.\n\t *\n\t *\tThe route store proxy id translation table, i.e,\n\t *\tfor each module proxy that come from this route\n\t *\twe store association of the local proxy ID with\n\t *\tthe foreign proxy ID, that is the proxy that\n\t *\trepresent the module at the outbound of the route.\n\t *\n\t *\tNote that even if the route object is created\n\t *\tby the transport, the translation table is\n\t *\tfeed and managed by the gateway implementation.\n\t */\n\tclass CGatewayRoute\n\t{\n\tprotected:\n#ifdef NL_DEBUG\n\t\t/// A debug flag that trigger an assert if true and something delete this object.\n\t\tmutable bool\t\t_AssertOnDelete;\n\t\tfriend struct\t\tCAutoAssertSetter;\n#endif\n\t\t/// The transport that manage this route\n\t\tIGatewayTransport\t*_Transport;\n\tpublic:\n\t\t/// The local foreign(A) <=> local(B) proxy id translation table\n//\t\ttypedef std::map<TModuleId, TModuleId>\tTForeignToLocalIdx;\n\t\ttypedef NLMISC::CTwinMap<TModuleId, TModuleId>\tTForeignToLocalIdx;\n\t\tTForeignToLocalIdx\tForeignToLocalIdx;\n\n\n\t\tenum TPendingEventType\n\t\t{\n\t\t\tpet_disclose_module,\n\t\t\tpet_undisclose_module,\n\t\t\tpet_update_distance,\n\t\t\tpet_update_security,\n\t\t};\n\n\t\tstruct TPendingEvent\n\t\t{\n\t\t\tTPendingEventType\tEventType;\n//\t\t\tIModuleProxy\t\t*ModuleProxy;\n\t\t\tTModuleId\t\t\tModuleId;\n\t\t};\n\t\t/// A list of pending event on this route\n\t\tstd::list<TPendingEvent>\tPendingEvents;\n\n\t\t/// A list of module proxy pending disclosure\n//\t\tstd::set<IModuleProxy*>\tPendingDisclosure;\n\t\t/// A list of module proxy pending undisclosure\n//\t\tstd::set<TModuleId>\t\tPendingUndisclosure;\n\t\t/// firewall disclosed module (empty in not firewalled mode)\n\t\tstd::set<TModuleId>\t\tFirewallDisclosed;\n\n\t\t//@{\n\t\t/// @name Information on the next module message to dispatch\n\n\t\t/// next message type, set to CModuleMessageHeaderCodec::mt_invalid when no module message are awaited\n\t\tCModuleMessageHeaderCodec::TMessageType\tNextMessageType;\n\t\t/// Id of the sender proxy\n\t\tTModuleId\t\tNextSenderProxyId;\n\t\t/// Id of the addressee proxy\n\t\tTModuleId\t\tNextAddresseeProxyId;\n\t\t//@}\n\n\t\t/// constructor, must provide the transport\n\t\tCGatewayRoute(IGatewayTransport *transport)\n\t\t\t:\t_Transport(transport),\n\t\t\t\tNextMessageType(CModuleMessageHeaderCodec::mt_invalid)\n\t\t{\n#ifdef NL_DEBUG\n\t\t\t_AssertOnDelete = false;\n#endif\n\t\t}\n\n\t\tvirtual ~CGatewayRoute()\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tnlassert(!_AssertOnDelete);\n#endif\n\t\t}\n\n\t\t/// Return the transport that hold this route\n\t\tIGatewayTransport *getTransport() { return _Transport; };\n\t\t/// Send a message via the route\n\t\tvirtual void sendMessage(const CMessage &message) const =0;\n\t};\n\n#ifdef NL_DEBUG\n\tstruct CAutoAssertSetter\n\t{\n\t\tconst CGatewayRoute\t&GatewayRoute;\n\t\tCAutoAssertSetter(const CGatewayRoute &gwr)\n\t\t\t:\tGatewayRoute(gwr)\n\t\t{\n\t\t\tGatewayRoute._AssertOnDelete = true;\n\t\t}\n\n\t\t~CAutoAssertSetter()\n\t\t{\n\t\t\tGatewayRoute._AssertOnDelete = false;\n\t\t}\n\t};\n\n #define NLNET_AUTO_DELTE_ASSERT\tCAutoAssertSetter __autoDeleteAssert(static_cast<const CGatewayRoute&>(*this))\n#else\n #define NLNET_AUTO_DELTE_ASSERT\n#endif\n\n\n\tclass CGatewaySecurity\n\t{\n\tprotected:\n\t\tIModuleGateway\t*_Gateway;\n\tpublic:\n\t\tstruct TCtorParam\n\t\t{\n\t\t\tIModuleGateway\t*Gateway;\n\t\t};\n\n\t\tCGatewaySecurity (const TCtorParam &params)\n\t\t\t: _Gateway(params.Gateway)\n\t\t{\n\t\t}\n\n\t\tvirtual ~CGatewaySecurity() { }\n\n\t\t/** the gateway send a command to the security module */\n\t\tvirtual void onCommand(const TParsedCommandLine &/* command */)\t{}\n\n\t\t/** A new proxy is available, the security plug-in can add security data */\n\t\tvirtual void onNewProxy(IModuleProxy *proxy) =0;\n\n\t\t/** A proxy receive new security datas, the security plug-in can\n\t\t *\tcheck the data validity, and eventually, reject the one or mode data block\n\t\t *\tthen it must update the proxy security with the new security data.\n\t\t *\tIf the security plug-in reject one or more security data, it has\n\t\t *\tthe duty for deleting the rejected object.\n\t\t *\tFurthermore, it must free the existing security data on the proxy\n\t\t *\tif is replace them with the new one.\n\t\t *\tAny other combination is fine unless the security plug-in do a correct\n\t\t *\tmanagement of freeing unused security data.\n\t\t */\n\t\tvirtual void onNewSecurityData(CGatewayRoute *from, IModuleProxy *proxy, TSecurityData *firstSecurityData) = 0;\n\n\t\t/** Called just before delete, the security plug-in must\n\t\t *\tremove any security data that it added to the proxies.\n\t\t */\n\t\tvirtual void onDelete() =0;\n\n\t\t/** Set a security data block. If a bloc of the same type\n\t\t *\talready exist in the list, the new one will replace the\n\t\t *\texisting one.\n\t\t */\n\t\tvoid setSecurityData(IModuleProxy *proxy, TSecurityData *securityData);\n\n\t\t/** Clear a block of security data\n\t\t *\tThe block is identified by the data tag\n\t\t *\tReturn true if at least one item have been removed, false otherwise.\n\t\t */\n\t\tbool removeSecurityData(IModuleProxy *proxy, uint8 dataTag);\n\n\t\t/** Replace the complete set of security data with the new one.\n\t\t *\tSecurity data allocated on the proxy are freed,\n\t\t */\n\t\tvoid replaceAllSecurityDatas(IModuleProxy *proxy, TSecurityData *securityData);\n\n\t\t/** Ask the gateway to resend the security data.\n\t\t *\tThe plug-in call this method after having changed\n\t\t *\tthe security info for a plug-in outside of the\n\t\t *\tonNewProxy call.\n\t\t */\n\t\tvoid forceSecurityUpdate(IModuleProxy *proxy);\n\t};\n\n\n} // namespace NLNET\n\n\n#endif // NL_FILE_MODULE_GATEWAY_H\n\n"
  },
  {
    "path": "code/nel/include/nel/net/module_manager.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef MODULE_MANAGER_H\n#define MODULE_MANAGER_H\n\n#include \"nel/misc/factory.h\"\n#include \"nel/misc/dynloadlib.h\"\n#include \"nel/misc/common.h\"\n#include \"module_common.h\"\n\nnamespace NLNET\n{\n\n\tclass CGatewayRoute;\n\n\t/** This is the interface for the module manager.\n\t *\tModule manager is in charge of module factoring and\n\t *\treferencing,\n\t *\tIt is also an entry point when you need to retrieve\n\t *\ta module socket or a module gateway.\n\t */\n\tclass IModuleManager : public NLMISC::CRefCount\n\t{\n\tpublic:\n\n\t\t/// Check that the module manager is initialized\n\t\tstatic bool\t\t\tisInitialized();\n\t\t/// The module manager is a singleton\n\t\tstatic IModuleManager &getInstance();\n\n\t\t/// Must be called before releasing the instance, will call IModule::onApplicationExit on all module instance\n\t\tvirtual void applicationExit() =0;\n\n\t\t/// Release the singleton instance\n\t\tstatic void releaseInstance();\n\n\t\tvirtual ~IModuleManager() {}\n\n\t\t/** set the unique name root used for fully qualified name generation\n\t\t *\t(by default, it is the host name and process id)\n\t\t */\n\t\tvirtual void setUniqueNameRoot(const std::string &uniqueNameRoot) =0;\n\n\t\t/** get the unique name root used for fully qualified name generation\n\t\t *\t(by default, it is the host name and process id)\n\t\t */\n\t\tvirtual const std::string &getUniqueNameRoot() =0;\n\n\t\t/** Load a module library.\n\t\t *\tModule library are dll or so files that contains\n\t\t *\tone or more module implementation.\n\t\t *\tLoading the library add the modules to the module\n\t\t *\tfactory.\n\t\t *\tIf the library can be loaded, the method return true, false otherwise.\n\t\t *\n\t\t *\tThe library name is the base name that will be 'decorated'\n\t\t *\twith the nel naming standard according to compilation mode\n\t\t *\tand platform specific file extension (.dll or .so).\n\t\t *\n\t\t *\tA module library can only be loaded once. If the library\n\t\t *\tis already loaded, the call is ingored.\n\t\t */\n\t\tvirtual bool loadModuleLibrary(const std::string &libraryName) =0;\n\n\t\t/** Unload a module library.\n\t\t *\tAny module that come from the unloaded library\n\t\t *\tare immediately deleted.\n\t\t *\tIf the specified library is not loaded, the\n\t\t *\tcall is ignored.\n\t\t */\n\t\tvirtual bool unloadModuleLibrary(const std::string &libraryName) =0;\n\n\t\t/** Unregister a module factory\n\t\t*/\n\t\tvirtual void unregisterModuleFactory(class IModuleFactory *moduleFactory) =0;\n\n\n\t\t/** Fill the vector with the list of available module.\n\t\t *\tNote that the vector is not cleared before being filled.\n\t\t */\n\t\tvirtual void getAvailableModuleClassList(std::vector<std::string> &moduleClassList) =0;\n\n\t\t/** Create a new module instance.\n\t\t *\tThe method create a module of the specified class with the\n\t\t *\tspecified local name.\n\t\t *\tThe class MUST be available in the factory and the\n\t\t *\tname MUST be unique OR empty.\n\t\t *\tIf the name is empty, the method generate a name using\n\t\t *\tthe module class and a number.\n\t\t *  If the module class could not be found, NULL is returned.\n\t\t *\tIf the module fail to initialize properly, then it\n\t\t *\tdeleted and NULL is returned.\n\t\t */\n\t\tvirtual IModule *createModule(const std::string &className, const std::string &localName, const std::string &paramString) =0;\n\n\t\t/** Delete a module instance.\n\t\t *\tThis is the only mean to delete a module instance.\n\t\t */\n\t\tvirtual void deleteModule(IModule *module) =0;\n\n\t\t/** Lookup in the created module for a module having the\n\t\t *\tspecified local name.\n\t\t *\tReturn NULL if not found.\n\t\t */\n\t\tvirtual IModule *getLocalModule(const std::string &moduleName) =0;\n\n\t\t/** Call this method to update all module instances.\n\t\t *\tIf the application is a NeL service, then this method\n\t\t *\tis automaticly called in the service main loop.\n\t\t *\tIf the application is a regular one, then you\n\t\t *\thave to call manually this method regularly\n\t\t *\tto update the modules.\n\t\t */\n\t\tvirtual void updateModules() =0;\n\n\t\t/** Lookup in the created socket for a socket having the\n\t\t *\tspecified local name.\n\t\t */\n\t\tvirtual IModuleSocket *getModuleSocket(const std::string &socketName) =0;\n\t\t/** Register a socket in the manager.\n\t\t *\tTODO : make this method only available to CModuleSocket to prevent dramatic ERROR\n\t\t */\n\t\tvirtual void registerModuleSocket(IModuleSocket *moduleSocket) =0;\n\t\t/** UrRegister a socket in the manager.\n\t\t *\tTODO : make this method only available to CModuleSocket to prevent dramatic ERROR\n\t\t */\n\t\tvirtual void unregisterModuleSocket(IModuleSocket *moduleSocket) =0;\n\n\t\t/** Lookup in the created gateway for a gateway having the\n\t\t *\tspecified local name.\n\t\t */\n\t\tvirtual IModuleGateway *getModuleGateway(const std::string &gatewayName) =0;\n\t\t/** Register a gateway in the manager.\n\t\t */\n\t\tvirtual void registerModuleGateway(IModuleGateway *moduleGateway) =0;\n\t\t/** UrRegister a socket in the manager.\n\t\t */\n\t\tvirtual void unregisterModuleGateway(IModuleGateway *moduleGateway) =0;\n\n\t\t/** Get a module proxy with the module proxy ID */\n\t\tvirtual TModuleProxyPtr getModuleProxy(TModuleId moduleProxyId) =0;\n\n\t\t/** Called by the gateway module to create new module proxy\n\t\t *\tModule proxy are an easy way for implementor to send\n\t\t *\tmessage to a module, without having to retrieve\n\t\t *\tthe gateway that discovered the destination module.\n\t\t *\tWhen module are created and plugged on a gateway,\n\t\t *\tthe gateway automaticly create a proxy\n\t\t *\tfor each local module and each foreing module.\n\t\t */\n\t\tvirtual IModuleProxy *createModuleProxy(\tIModuleGateway *gateway,\n\t\t\t\t\t\t\t\t\t\t\t\t\tCGatewayRoute *route,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuint32 distance,\n\t\t\t\t\t\t\t\t\t\t\t\t\tIModule *localModule,\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst std::string &moduleClassName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst std::string &moduleFullyQualifiedName,\n\t\t\t\t\t\t\t\t\t\t\t\t\tconst std::string &moduleManifest,\n//\t\t\t\t\t\t\t\t\t\t\t\t\tconst TModuleGatewayProxyPtr &foreignGateway,\n\t\t\t\t\t\t\t\t\t\t\t\t\tTModuleId foreignModuleId) =0;\n\n\t\tvirtual void releaseModuleProxy(TModuleId moduleProxyId) =0;\n\n\t\tvirtual uint32 getNbModule() =0;\n\t\tvirtual uint32 getNbModuleProxy() =0;\n\n\t};\n\n\ttypedef NLMISC::CFactoryIndirect<IModuleFactory, std::string>\tTLocalModuleFactoryRegistry;\n\n\t/** Class for pure NeL module library */\n\tclass CNelModuleLibrary : public NLMISC::INelLibrary\n\t{\n\tpublic:\n\t\t/** Return the local module factory.*/\n\t\tvirtual TLocalModuleFactoryRegistry &getLocalModuleFactoryRegistry()\n\t\t{\n\t\t\treturn TLocalModuleFactoryRegistry::instance();\n\t\t}\n\n\t\tvirtual void onLibraryLoaded(bool /* firstTime */) {}\n\t\tvirtual void onLibraryUnloaded(bool /* lastTime */) {}\n\t};\n\n} // namespace NLNET\n\n#endif // MODULE_MANAGER_H\n\n"
  },
  {
    "path": "code/nel/include/nel/net/module_message.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_MODULE_MESSAGE_H\n#define NL_MODULE_MESSAGE_H\n\n#include \"nel/misc/enum_bitset.h\"\n#include \"nel/net/message.h\"\n#include \"module_common.h\"\n\n\nnamespace NLNET\n{\n\t/** Module message header coder/decoder\n\t *\tCodec for module message header data.\n\t */\n\tclass CModuleMessageHeaderCodec\n\t{\n\tpublic:\n\t\tenum TMessageType\n\t\t{\n\t\t\t/// Standard one way message\n\t\t\tmt_oneway,\n\t\t\t/// Two way request\n\t\t\tmt_twoway_request,\n\t\t\t/// Two way response\n\t\t\tmt_twoway_response,\n\n\n\t\t\t/// A special checking value\n\t\t\tmt_num_types,\n\t\t\t/// invalid flag\n\t\t\tmt_invalid = mt_num_types\n\n\t\t};\n\n\t\tstatic void encode(CMessage &headerMessage, TMessageType msgType, TModuleId senderProxyId, TModuleId addresseeProxyId)\n\t\t{\n\t\t\tserial(headerMessage, msgType, senderProxyId, addresseeProxyId);\n\t\t}\n\n\t\tstatic void decode(const CMessage &headerMessage, TMessageType &msgType, TModuleId &senderProxyId, TModuleId &addresseeProxyId)\n\t\t{\n\t\t\tserial(const_cast<CMessage&>(headerMessage), msgType, senderProxyId, addresseeProxyId);\n\t\t}\n\n\tprivate:\n\t\tstatic void serial(CMessage &headerMessage, TMessageType &msgType, TModuleId &senderProxyId, TModuleId &addresseeProxyId)\n\t\t{\n\t\t\tuint8 mt;\n\t\t\tif (headerMessage.isReading())\n\t\t\t{\n\t\t\t\theaderMessage.serial(mt);\n\t\t\t\tmsgType = CModuleMessageHeaderCodec::TMessageType(mt);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmt = uint8(msgType);\n\t\t\t\theaderMessage.serial(mt);\n\t\t\t}\n\t\t\theaderMessage.serial(senderProxyId);\n\t\t\theaderMessage.serial(addresseeProxyId);\n\t\t}\n\t};\n\n\n\t/** An utility struct to serial binary buffer.\n\t *\tWARNING : you must be aware that using binary buffer serialisation\n\t *\tis not fair with the portability and endiennes problem.\n\t *\tUse it ONLY when you now what you are doing and when\n\t *\tbytes ordering is not an issue.\n\t */\n\tstruct TBinBuffer\n\t{\n\tprivate:\n\t\tuint8\t\t\t*_Buffer;\n\t\tuint32\t\t\t_BufferSize;\n\t\tmutable bool\t_Owner;\n\n\tpublic:\n\n\t\t/// default constructor, used to read in stream\n\t\tTBinBuffer()\n\t\t\t:\t_Buffer(NULL),\n\t\t\t\t_BufferSize(0),\n\t\t\t\t_Owner(true)\n\t\t{\n\t\t}\n\n\t\tTBinBuffer(const uint8 *buffer, uint32 bufferSize)\n\t\t\t:\t_Buffer(const_cast<uint8*>(buffer)),\n\t\t\t\t_BufferSize(bufferSize),\n\t\t\t\t_Owner(false)\n\t\t{\n\t\t}\n\n\t\t// copy constructor transfere ownership of the buffer (if it is owned)\n\t\tTBinBuffer(const TBinBuffer &other)\n\t\t\t:\t_Buffer(other._Buffer),\n\t\t\t\t_BufferSize(other._BufferSize),\n\t\t\t\t_Owner(other._Owner)\n\t\t{\n\t\t\t// remove owning on source\n\t\t\tother._Owner = false;\n\t\t}\n\n\t\t~TBinBuffer()\n\t\t{\n\t\t\tif (_Owner && _Buffer != NULL)\n\t\t\t\tdelete _Buffer;\n\t\t}\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\tif (s.isReading())\n\t\t\t{\n\t\t\t\tnlassert(_Buffer == NULL);\n\t\t\t\ts.serial(_BufferSize);\n\n\t\t\t\t_Buffer = new uint8[_BufferSize];\n\n\t\t\t\ts.serialBuffer(_Buffer, _BufferSize);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ts.serialBufferWithSize(_Buffer, _BufferSize);\n\t\t\t}\n\t\t}\n\n\t\tuint32 getBufferSize() const\n\t\t{\n\t\t\treturn _BufferSize;\n\t\t}\n\n\t\tuint8 *getBuffer() const\n\t\t{\n\t\t\treturn _Buffer;\n\t\t}\n\n\n\t\t/** Release the buffer by returning the pointer to the caller.\n\t\t *\tThe caller is now owner and responsible of the allocated\n\t\t *\tbuffer.\n\t\t */\n\t\tuint8 *release()\n\t\t{\n\t\t\tnlassert(_Owner);\n\t\t\t_Owner = false;\n\t\t\treturn _Buffer;\n\t\t}\n\t};\n\n\n} // namespace NLNET\n\n#endif // NL_MODULE_MESSAGE_H\n"
  },
  {
    "path": "code/nel/include/nel/net/module_socket.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_FILE_MODULE_SOCKET_H\n#define NL_FILE_MODULE_SOCKET_H\n\n#include \"nel/net/message.h\"\n#include \"module_common.h\"\n\nnamespace NLNET\n{\n\tclass IModuleSocket\n\t{\n\tpublic:\n\t\tvirtual ~IModuleSocket() {}\n\t\t/** Register the socket in the module manager socket registry\n\t\t */\n\t\tvirtual void registerSocket() =0;\n\t\t/** Unregister the socket in the module manager socket registry\n\t\t */\n\t\tvirtual void unregisterSocket() =0;\n\n\t\t/** Ask derived class to obtain the socket name.\n\t\t */\n\t\tvirtual const std::string &getSocketName() =0;\n\n\t\t/** A plugged module send a message to another module.\n\t\t *\tIf the destination module is not accessible through this socket,\n\t\t *\tan exception is thrown.\n\t\t */\n\t\tvirtual void sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t\t=0;\n\t\t/** A plugged module send a message to all the module reachable\n\t\t *\twith this socket.\n\t\t */\n\t\tvirtual void broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t\t=0;\n\n\t\t/** Fill the resultList with the list of module that are\n\t\t *\treachable with this socket.\n\t\t *\tNote that the result vector is not cleared before filling.\n\t\t */\n\t\tvirtual void getModuleList(std::vector<IModuleProxy*> &resultList) =0;\n\n\t\t//@name Callback for socket implementation\n\t\t//@{\n\t\t/// Called just after a module is plugged in the socket.\n\t\tvirtual void onModulePlugged(IModule *pluggedModule) =0;\n\t\t/// Called just before a module is unplugged from the socket.\n\t\tvirtual void onModuleUnplugged(IModule *unpluggedModule) =0;\n\t\t//@}\n\t};\n\n//\tconst TModuleSocketPtr\tNullModuleSocket;\n\n\n\t/** A base class for socket.\n\t *\tIt provide plugged module management to\n\t *\timplementors.\n\t */\n\tclass CModuleSocket : public IModuleSocket\n\t{\n\tprotected:\n\t\ttypedef NLMISC::CTwinMap<TModuleId, TModulePtr>\tTPluggedModules;\n\t\t/// The list of plugged modules\n\t\tTPluggedModules\t\t\t_PluggedModules;\n\n\t\tbool\t\t\t\t\t_SocketRegistered;\n\n\t\tfriend class CModuleBase;\n\n\t\tCModuleSocket();\n\t\t~CModuleSocket();\n\n\t\tvirtual void registerSocket();\n\t\tvirtual void unregisterSocket();\n\n\n\t\tvirtual void _onModulePlugged(const TModulePtr &pluggedModule);\n\t\tvirtual void _onModuleUnplugged(const TModulePtr &pluggedModule);\n\n\t\tvirtual void _sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotPluggedHere, NLNET::EModuleNotReachable)\n\t\t\t=0;\n\n\t\tvirtual void _broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t\t=0;\n\n\t\tvirtual void sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotPluggedHere);\n\t\t/** A plugged module send a message to all the module reachable\n\t\t *\twith this socket.\n\t\t */\n\t\tvirtual void broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotPluggedHere);\n\n\t};\n\n\n} // namespace NLNET\n\n#endif // NL_FILE_MODULE_SOCKET_H\n"
  },
  {
    "path": "code/nel/include/nel/net/naming_client.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_NAMING_CLIENT_H\n#define NL_NAMING_CLIENT_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n\n#include \"nel/misc/mutex.h\"\n\n#include \"inet_address.h\"\n#include \"callback_client.h\"\n#include \"service.h\"\n\nnamespace NLNET {\n\n//typedef uint16 TServiceId;\n\ntypedef void (*TBroadcastCallback)(const std::string &name, TServiceId sid, const std::vector<CInetAddress> &addr);\n\n/**\n * Client side of Naming Service. Allows to register/unregister services, and to lookup for\n * a registered service.\n *\n * \\warning the Naming Service can be down, it will reconnect when up but if other services try to register during the\n * NS is offline, it will cause bug\n *\n * \\author Olivier Cado\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CNamingClient\n{\npublic:\n\tstruct CServiceEntry\n\t{\n\t\tCServiceEntry (std::string n, TServiceId s, std::vector<CInetAddress> a) : Name(n), SId (s), Addr(a), RunningState(ServiceOnline) { }\n\n\t\t// name of the service\n\t\tstd::string\t\t\t\t\tName;\n\t\t// id of the service\n\t\tTServiceId\t\t\t\t\tSId;\n\t\t// address to send to the service who wants to lookup this service (could have more than one)\n\t\tstd::vector<CInetAddress>\tAddr;\n\n        TServiceRunningState        RunningState;\n\t};\n\npublic:\n\n\t/// Connect to the naming service.\n\tstatic void\t\t\tconnect( const CInetAddress& addr, CCallbackNetBase::TRecordingState rec, const std::vector<CInetAddress> &addresses );\n\n\t/// Return true if the connection to the Naming Service was done.\n\tstatic bool\t\t\tconnected () { return _Connection != NULL && _Connection->connected (); }\n\n\t/// Close the connection to the naming service.\n\tstatic void\t\t\tdisconnect ();\n\n\t/// Returns information about the naming connection (connected or not, which naming service and so on)\n\tstatic std::string\tinfo ();\n\n\t/** Register a service within the naming service.\n\t * Returns false if the registration failed.\n\t */\n\tstatic bool\t\t\tregisterService (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId &sid);\n\n\t/** Register a service within the naming service, using a specified service identifier.\n\t * Returns false if the service identifier is unavailable i.e. the registration failed.\n\t */\n\tstatic bool\t\t\tregisterServiceWithSId (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid);\n\n\t/** If the NS is down and goes up, we have to send it again the registration. But in this case, the NS\n\t * must not send a registration broadcast, so we have a special message\n\t */\n\tstatic void\t\t\tresendRegisteration (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid);\n\n\t/// Unregister a service from the naming service, service identifier.\n\tstatic void\t\t\tunregisterService (TServiceId sid);\n\n\t/// Unregister all services registered by this client. You don't have to\n\tstatic void\t\t\tunregisterAllServices ();\n\n\n\t/** Requests the naming service to choose a port for the service\n\t * \\return An empty port number\n\t */\n\tstatic uint16\t\tqueryServicePort ();\n\n\n\t/** Returns true and the address of the specified service if it is found, otherwise returns false\n\t * \\param name [in] Short name of the service to find\n\t * \\param addr [out] Address of the service\n\t * \\param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary\n\t * before sending a message to the service\n\t * \\return true if all worked fine\n\t */\n\tstatic bool\t\t\tlookup (const std::string &name, CInetAddress &addr);\n\n\t/// Same as lookup(const string&, CInetAddress&, uint16&)\n\tstatic bool\t\t\tlookup (TServiceId sid, CInetAddress &addr);\n\n\t/** Tells the Naming Service the specified address does not respond for the specified service,\n\t * and returns true and another address for the service if available, otherwise returns false\n\t * \\param name [in] Short name of the service to find\n\t * \\param addr [in/out] In: Address of the service that does not respond. Out: Alternative address\n\t * \\param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary\n\t * before sending a message to the service\n\t * \\return true if all worked fine.\n\t */\n\tstatic bool\t\t\tlookupAlternate (const std::string& name, CInetAddress& addr);\n\n\n\t/**\n\t * Returns all services corresponding to the specified short name.\n\t * Ex: lookupAll (\"AS\", addresses);\n\t */\n\tstatic void\t\t\tlookupAll (const std::string &name, std::vector<CInetAddress> &addresses);\n\n\t/**\n\t * Returns all registered services.\n\t */\n\tstatic const std::list<CServiceEntry>\t&getRegisteredServices() { return RegisteredServices; }\n\n\n\t/** Obtains a socket connected to a service providing the service \\e name.\n\t * In case of failure to connect, the method informs the Naming Service and tries to get another service.\n\t * \\param name [in] Short name of the service to find and connected\n\t * \\param sock [out] The connected socket.\n\t * \\param validitytime [out] After this number of seconds are elapsed, another lookup will be necessary\n\t * before sending a message to the service.\n\t * \\return false if the service was not found.\n\t */\n\tstatic bool\t\t\tlookupAndConnect (const std::string &name, CCallbackClient &sock);\n\n\n\t/// Call it evenly\n\tstatic void\t\t\tupdate ();\n\n\n\t/// You can link a callback if you want to know when a new service is registered (NULL to disable callback)\n\tstatic void\t\t\tsetRegistrationBroadcastCallback (TBroadcastCallback cb);\n\n\n\t/// You can link a callback if you want to know when a new service is unregistered (NULL to disable callback)\n\tstatic void\t\t\tsetUnregistrationBroadcastCallback (TBroadcastCallback cb);\n\n\tstatic void displayRegisteredServices (NLMISC::CLog *log = NLMISC::DebugLog)\n\t{\n\t\tRegisteredServicesMutex.enter ();\n\t\tlog->displayNL (\"Display the %d registered services :\", RegisteredServices.size());\n\t\tfor (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t{\n\t\t\tlog->displayNL (\" > %s-%hu %d addr\", (*it).Name.c_str(), (*it).SId.get(), (*it).Addr.size());\n\t\t\tfor(uint i = 0; i < (*it).Addr.size(); i++)\n\t\t\t\tlog->displayNL (\"            '%s'\", (*it).Addr[i].asString().c_str());\n\t\t}\n\t\tlog->displayNL (\"End of the list\");\n\t\tRegisteredServicesMutex.leave ();\n\t}\n\n    static void\t\t\tSelfCanAccess ();\n    static bool         IsCanAccess( std::vector<std::string>& service_names );\n    \nprivate:\n\n\tstatic CCallbackClient *_Connection;\n\n\t// The service Id of this service\n\tstatic TServiceId _MySId;\n\n\t/// Type of map of registered services\n\ttypedef std::map<TServiceId, std::string> TRegServices;\n\n\t// this container contains the server that *this* service have registered (often, there's only one)\n\tstatic TRegServices _RegisteredServices;\n\n\t/// Constructor\n\tCNamingClient() {}\n\n\t/// Destructor\n\t~CNamingClient() {}\n\n\tstatic void doReceiveLookupAnswer (const std::string &name, std::vector<CInetAddress> &addrs);\n\n\t// This container contains the list of other registered services on the shard\n\tstatic std::list<CServiceEntry>\tRegisteredServices;\n\tstatic NLMISC::CMutex RegisteredServicesMutex;\n\n\tstatic void find (const std::string &name, std::vector<CInetAddress> &addrs)\n\t{\n\t\tRegisteredServicesMutex.enter ();\n\t\tfor (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t\tif (name == (*it).Name)\n\t\t\t\taddrs.push_back ((*it).Addr[0]);\n\t\tRegisteredServicesMutex.leave ();\n\t}\n\n\tstatic void find (TServiceId sid, std::vector<CInetAddress> &addrs)\n\t{\n\t\tRegisteredServicesMutex.enter ();\n\t\tfor (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t\t\tif (sid == (*it).SId)\n\t\t\t\taddrs.push_back ((*it).Addr[0]);\n\t\tRegisteredServicesMutex.leave ();\n\t}\n\n\tfriend void cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\tfriend void cbUnregisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n    friend void cbUpdateServiceState (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n};\n\n\n} // NLNET\n\n\n#endif // NL_NAMING_CLIENT_H\n\n/* End of naming_client.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/net_displayer.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_NET_DISPLAYER_H\n#define NL_NET_DISPLAYER_H\n\n#include \"nel/misc/log.h\"\n#include \"nel/misc/displayer.h\"\n\n#include \"callback_client.h\"\n\nnamespace NLNET {\n\n\n/**\n * Net Displayer. Sends the strings to a logger server (LOGS).\n * \\ref log_howto\n * \\bug When nlerror is called in a catch block, a connected NetDisplayer becomes an IDisplayer => pure virtual call\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass CNetDisplayer : public NLMISC::IDisplayer\n{\npublic:\n\n\t/// Constructor\n\tCNetDisplayer(bool autoConnect = true);\n\n\t/** Sets logging server address. Call this method from outside only if you want to use a LOGS not registered within the NS.\n\t * It does nothing if the displayer is already connected to a server.\n\t */\n\tvoid setLogServer( const CInetAddress& logServerAddr );\n\n\t/** Sets logging server with an already connected server.\n\t */\n\tvoid setLogServer( CCallbackClient *server );\n\n\t/// Returns true if the displayer is connected to a Logging Service.\n\tbool connected () { return _Server->connected(); }\n\n\t/// Destructor\n\tvirtual ~CNetDisplayer();\n\nprotected:\n\n\t/** Sends the string to the logging server\n\t * \\warning If not connected, tries to connect to the logging server each call. It can slow down your program a lot.\n\t */\n\tvirtual void doDisplay ( const NLMISC::CLog::TDisplayInfo& args, const char *message);\n\n\t /// Find the server (using the NS) and connect\n\tvoid findAndConnect();\n\nprivate:\n\n\tCInetAddress\t_ServerAddr;\n//\tCCallbackClient\t_Server;\n\tCCallbackClient\t*_Server;\n\tbool\t\t\t_ServerAllocated;\n//\tuint32\t\t\t_ServerNumber;\n};\n\n\n} // NLNET\n\n\n#endif // NL_NET_DISPLAYER_H\n\n/* End of net_displayer.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/net_log.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_NET_LOG_H\n#define NL_NET_LOG_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/log.h\"\n#include \"nel/misc/variable.h\"\n\nnamespace NLNET {\n\n\n//\n// Macros\n//\n\n// The following macros are here to allow logs generated by networking code to be enabled and dissabled\n\n#define LNETL0_INFO if (!VerboseLNETL0.get()) {} else nlinfo\n#define LNETL1_INFO if (!VerboseLNETL1.get()) {} else nlinfo\n#define LNETL2_INFO if (!VerboseLNETL2.get()) {} else nlinfo\n#define LNETL3_INFO if (!VerboseLNETL3.get()) {} else nlinfo\n#define LNETL4_INFO if (!VerboseLNETL4.get()) {} else nlinfo\n#define LNETL5_INFO if (!VerboseLNETL5.get()) {} else nlinfo\n#define LNETL6_INFO if (!VerboseLNETL6.get()) {} else nlinfo\n\n#define LNETL0_DEBUG if (!VerboseLNETL0.get()) {} else nldebug\n#define LNETL1_DEBUG if (!VerboseLNETL1.get()) {} else nldebug\n#define LNETL2_DEBUG if (!VerboseLNETL2.get()) {} else nldebug\n#define LNETL3_DEBUG if (!VerboseLNETL3.get()) {} else nldebug\n#define LNETL4_DEBUG if (!VerboseLNETL4.get()) {} else nldebug\n#define LNETL5_DEBUG if (!VerboseLNETL5.get()) {} else nldebug\n#define LNETL6_DEBUG if (!VerboseLNETL6.get()) {} else nldebug\n\nextern NLMISC::CVariable<bool> VerboseLNETL0;\nextern NLMISC::CVariable<bool> VerboseLNETL1;\nextern NLMISC::CVariable<bool> VerboseLNETL2;\nextern NLMISC::CVariable<bool> VerboseLNETL3;\nextern NLMISC::CVariable<bool> VerboseLNETL4;\nextern NLMISC::CVariable<bool> VerboseLNETL5;\nextern NLMISC::CVariable<bool> VerboseLNETL6;\n\n\n\n\n\n\n/**************************************************************************\n********************* THIS CLASS IS DEPRECATED ****************************\n**************************************************************************/\n\n\n\n\n\n/**\n * Logger for network transfers\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass CNetLog : public NLMISC::CLog\n{\npublic:\n\n\t/// Constructor\n\tCNetLog();\n\n\t/// Sets the name of the running service\n\tvoid\tsetServiceName( const char *name );\n\n\t/// Log an output transfer (send)\n\tvoid\toutput( const char *srchost, uint8 msgnum, const char *desthost,\n\t\t\t\t\tconst char *msgname, uint32 msgsize );\n\n\t/// Log an input transfer (receive)\n\tvoid\tinput( const char *srchost, uint8 msgnum, const char *desthost );\n\n\t/*/// Enables or disable logging.\n\tvoid\tsetLogging( bool logging )\n\t{\n\t\t_Logging = logging;\n\t}*/\n\nprivate:\n\n\tstd::string _ProcessId;\n\n};\n\n\nextern CNetLog NetLog;\n\n#define nlsetnet (servicename,displayer)\n#define nlnetoutput NetLog.output\n#define nlnetinput NetLog.input\n\n\n} // NLNET\n\n\n#endif // NL_NET_LOG_H\n\n/* End of net_log.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/net_manager.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n\n\n/**************************************************************************\n********************* THIS CLASS IS DEPRECATED ****************************\n**************************************************************************/\n\n#ifdef NL_OS_WINDOWS\n#\tpragma message(NL_LOC_WRN \"You are using a deprecated feature of NeL, consider rewriting your code with replacement feature\")\n#else // NL_OS_UNIX\n#\twarning \"You are using a deprecated feature of NeL, consider rewriting your code with replacement feature\"\n#endif\n\n#ifndef NL_NET_MANAGER_H\n#define NL_NET_MANAGER_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n#include <map>\n#include <vector>\n\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/string_id_array.h\"\n\n#include \"callback_net_base.h\"\n#include \"naming_client.h\"\n\nnamespace NLNET {\n\n/// Callback function type for message processing\ntypedef void (*TNetManagerCallback) (const std::string &serviceName, TSockId from, void *arg);\n\n/** Structure used in the second part of the map\n * If you add a client with his service name, the Name is the service name and ServiceNames is empty.\n * If you add a client with his ip, Name is the fake service name and ServiceNames[0] is the ip.\n * If you add a group (of client), Name is the name of the group and ServiceNames is names of all services in the group.\n * If you add a server, Name is the service name of the server and ServiceNames is empty.\n */\nstruct CBaseStruct\n{\n\tCBaseStruct (const std::string &sn) :\n\t\tName(sn), ConnectionCallback(NULL), ConnectionCbArg(NULL),\n\t\tDisconnectionCallback(NULL), DisconnectionCbArg(NULL), Type(Unknown)\n\t{ }\n\n\t/// the name used by all function to retrieve a service (in the case of group or ip, this name is a virtual\n\t/// name used only to find it to perform action on it\n\tstd::string\tName;\n\n\tenum TBaseStructType { Unknown, Client, ClientWithAddr, Group, Server };\n\n\tstd::vector<std::string>\t\tServiceNames;\n\n\t/// It could have more than one connection, in this case, the vector contains all connections\n\tstd::vector<CCallbackNetBase*>\t NetBase;\n\n\tTNetManagerCallback\t\t\t\t ConnectionCallback;\n\tvoid\t\t\t\t\t\t\t*ConnectionCbArg;\n\n\tTNetManagerCallback\t\t\t\t DisconnectionCallback;\n\tvoid\t\t\t\t\t\t\t*DisconnectionCbArg;\n\n\t// autoretry is used only when Type is ClientWithAddr. If true, the CNetManager will retry to reconnect if it lost the connection\n\tbool\t\t\t\t\t\t\t AutoRetry;\n\n\tTBaseStructType\t\t\t\t\t Type;\n};\n\n/**\n * Layer 4\n *\n * In case of addGroup(), messages are *not* associate with id, so the message type is always sent with string.\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2001\n */\nclass CNetManager\n{\npublic:\n\n\t/** Creates the connection to the Naming Service.\n\t * If the connection failed, ESocketConnectionFailed exception is generated.\n\t */\n\tstatic void\tinit (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec );\n\n\tstatic void release ();\n\n\t/** Sets up a server on a specific port with a specific service name (create a listen socket, register to naming service and so on)\n\t * If servicePort is 0, it will be dynamically determinated by the Naming Service.\n\t * If sid id 0, the service id will be dynamically determinated by the Naming Service.\n\t */\n\tstatic void\taddServer (const std::string &serviceName, uint16 servicePort = 0, bool external = false);\n\n\tstatic void\taddServer (const std::string &serviceName, uint16 servicePort, NLNET::TServiceId &sid, bool external = false);\n\n\t/// Creates a connection to a specific IP and associate it this a \"fake\" serviceName (to enable you to send data for example)\n\tstatic void\taddClient (const std::string &serviceName, const std::string &addr, bool autoRetry = true);\n\n\t/// Creates a connection to a service using the naming service and the serviceName\n\tstatic void\taddClient (const std::string &serviceName);\n\n\t/// Creates connections to a group of service\n\tstatic void\taddGroup (const std::string &groupName, const std::string &serviceName);\n\n\t/// Adds a callback array to a specific service connection. You can add callback only *after* adding the server, the client or the group\n\tstatic void\taddCallbackArray (const std::string &serviceName, const TCallbackItem *callbackarray, NLMISC::CStringIdArray::TStringId arraysize);\n\n\t/** Call it evenly. the parameter select the timeout value in milliseconds for each update. You are absolutely certain that this\n\t * function will not be returns before this amount of time you set.\n\t * If you set the update timeout value higher than 0, all messages in queues will be process until the time is greater than the timeout user update().\n\t * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update(). In this case, we don't nlSleep(1).\n\t */\n\tstatic void\tupdate (NLMISC::TTime timeout = 0);\n\n\t/// Sends a message to a specific serviceName\n\tstatic void\tsend (const std::string &serviceName, const CMessage &buffer, TSockId hostid = InvalidSockId);\n\n\t/** Sets callback for incoming connections (or NULL to disable callback)\n\t * On a client, the callback will be call when the connection to the server is established (the first connection or after the server shutdown and started)\n\t * On a server, the callback is called each time a new client is connected to him\n\t */\n\tstatic void\tsetConnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg);\n\n\t/** Sets callback for disconnections (or NULL to disable callback)\n\t\tOn a client, the callback will be call each time the connection to the server is lost\n\t\tOn a server, the callback is called each time a client is disconnected\n\t */\n\tstatic void\tsetDisconnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg);\n\n\t/// Returns the connection if you want to do specific calls\n\tstatic CCallbackNetBase *getNetBase (const std::string &serviceName);\n\n\tstatic void setUpdateTimeout (uint32 timeout);\n\n\tstatic void createConnection(CBaseStruct &Base, const CInetAddress &Addr, const std::string& name);\n\n\tstatic uint64 getBytesSent ();\n\tstatic uint64 getBytesReceived ();\n\n\tstatic uint64 getReceiveQueueSize ();\n\tstatic uint64 getSendQueueSize ();\n\nprivate:\n\n\ttypedef\tstd::map<std::string, CBaseStruct>\tTBaseMap;\n\ttypedef\tTBaseMap::iterator\t\t\t\t\tItBaseMap;\n\n\t// Contains all the connections (client and server)\n\tstatic\tTBaseMap\t_BaseMap;\n\n\tstatic\tCCallbackNetBase::TRecordingState _RecordingState;\n\n\t// used to synchonize the timeout in the update function\n\tstatic\tNLMISC::TTime _NextUpdateTime;\n\n\t// Finds the service or add it if not found\n\tstatic\tItBaseMap find (const std::string &serviceName);\n\n\tfriend\tvoid RegistrationBroadcast (const std::string &name, TServiceId sid, const std::vector<CInetAddress> &addr);\n\n\n\t// It's a static class, you can't instanciate it\n\tCNetManager() { }\n};\n\n\n} // NLNET\n\n\n#endif // NL_NET_MANAGER_H\n\n/* End of net_manager.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/pacs_client.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_PACS_CLIENT_H\n#define NL_PACS_CLIENT_H\n\n#include \"stdnet.h\"\n\n#include \"inet_address.h\"\n#include \"callback_client.h\"\n#include \"naming_client.h\"\n\n#include \"nel/pacs/u_move_primitive.h\"\n#include \"nel/pacs/u_collision_desc.h\"\n\n#define NLNET_PACS_PROTOCOL_VERSION 1\n\nnamespace NLNET\n{\n\nTCallbackItem PacsCallbackArray[];\n\n/**\n * Client side of Pacs Service. Allows to use PACS functionnality by the networtk.\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CPacsClient\n{\n\tfriend void cbPacsAnswer (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\npublic:\n\n\t/// Constructor\n\tCPacsClient()\n\t{\n\t\t// No connexion\n\t\t_Server=NULL;\n\t}\n\n\t~CPacsClient()\n\t{\n\t\tdisconnect ();\n\t}\n\n\tbool connect ();\n\n\tvoid disconnect ()\n\t{\n\t\tif (_Server)\n\t\t{\n\t\t\t_Server->disconnect ();\n\t\t\tdelete _Server;\n\t\t}\n\t}\n\n\t/**\n\t  * Prepare a new message\n\t  *\n\t  * You must call this method before do anything before sending the message.\n\t  */\n\tvoid\tinitMessage ()\n\t{\n\t\t_Message.clear ();\n\t\t_Message.setType (\"PACS\");\n\t\t_Message.serialCheck ((uint32)NLNET_PACS_PROTOCOL_VERSION);\n\t}\n\n\t/**\n\t  * Send the message\n\t  *\n\t  * You must call this method after initMessage and others calls to setup methods.\n\t  */\n\tvoid\tsendMessage ()\n\t{\n\t\t// Checks\n\t\tnlassert (_Server);\n\n\t\t// Close the message\n\t\tbool nlFalse=false;\n\t\t_Message.serial (nlFalse);\n\n\t\t// Send the message\n\t\t_Server->send (_Message);\n\t}\n\n\t/**\n\t  * Update method. Should be called evenly.\n\t  */\n\tvoid\tupdate ()\n\t{\n\t\t// Checks\n\t\tnlassert (_Server);\n\n\t\t_Server->update ();\n\t}\n\n\t/// \\name Global retriever methods\n\n\t/**\n\t  * Make a raytrace test on the service.\n\t  *\n\t  * The service will answer this message with a rayTestCallback message.\n\t  *\n\t  * \\param p0 is the first point of the ray.\n\t  * \\param p1 is the second point of the ray.\n\t  * \\param testId is the id of the test.\n\t  */\n\tvoid rayTest (double p0, double p1, uint32 testId)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"RY\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, p0, p1, testId);\n\t}\n\n\t/// \\name Move container methods\n\n\t/**\n\t  * Add a primitive in the service. Set the new primitive as current.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param id is the ID to attach to the new primitive.\n\t  */\n\tvoid addPrimitive (NLPACS::UMovePrimitive::TUserData id)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"AD\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, id);\n\t}\n\n\t/**\n\t  * Remove a primitive from the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param id is the ID attach to the primitive to remove.\n\t  */\n\tvoid removePrimitive (NLPACS::UMovePrimitive::TUserData id)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"RV\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, id);\n\t}\n\n\t/**\n\t  * Evaluate the collision on the servive.\n\t  *\n\t  * The service will answer this message with a triggerCallback message.\n\t  *\n\t  * \\param evalId is the id of the evaluation.\n\t  * \\param deltaTime is the delta time used to evaluate the system.\n\t  */\n\tvoid evalCollision (uint32 evalId, double deltaTime)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"EV\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, evalId, deltaTime);\n\t}\n\n\t/**\n\t  * Test a move of a primitive on the service.\n\t  *\n\t  * The service will answer this message with a testMoveCallback message.\n\t  *\n\t  * \\param id is the id of the primitive to test a move.\n\t  * \\param speed is the speed of the primitive during its move.\n\t  * \\param deltaTime is the time interval of the move to test.\n\t  */\n\tvoid testMove (NLPACS::UMovePrimitive::TUserData id, const NLMISC::CVectorD& speed, double deltaTime)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"TS\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, id, const_cast<NLMISC::CVectorD&> (speed), deltaTime);\n\t}\n\n\t/// \\name Primitives methods\n\n\t/**\n\t  * Set the current primitive on the service. The primitive stay current\n\t  * for the current message.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param id is the id of the current primitive to use.\n\t  */\n\tvoid setCurrentPrimitive (NLPACS::UMovePrimitive::TUserData id)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"CU\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, id);\n\t}\n\n\t/**\n\t  * Set the type of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param type is the new type for the primitive on the service.\n\t  */\n\tvoid setPrimitiveType (NLPACS::UMovePrimitive::TType type)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"TY\";\n\t\tuint32 t=(uint32)type;\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, t);\n\t}\n\n\t/**\n\t  * Set the reaction type of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param type is the newreaction  type for the primitive on the service.\n\t  */\n\tvoid setReactionType (NLPACS::UMovePrimitive::TReaction type)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"RT\";\n\t\tuint32 t=(uint32)type;\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, t);\n\t}\n\n\t/**\n\t  * Set the trigger type of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param type is the new trigger type for the primitive on the service.\n\t  */\n\tvoid setTriggerType (NLPACS::UMovePrimitive::TTrigger type)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"TT\";\n\t\tuint32 t=(uint32)type;\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, t);\n\t}\n\n\t/**\n\t  * Set the collision mask of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param mask is the new collision mask for the primitive on the service.\n\t  */\n\tvoid setCollisionMask (NLPACS::UMovePrimitive::TCollisionMask mask)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"CT\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, mask);\n\t}\n\n\t/**\n\t  * Set the occlusion mask of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param mask is the new occlusion mask for the primitive on the service.\n\t  */\n\tvoid setOcclusionMask (NLPACS::UMovePrimitive::TCollisionMask mask)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"OT\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, mask);\n\t}\n\n\t/**\n\t  * Set the obstacle flag of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param obstacle is the new obstacle flag for the primitive on the service.\n\t  */\n\tvoid setObstacle (bool obstacle)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"OB\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, obstacle);\n\t}\n\n\t/**\n\t  * Set the orientation the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param orientation is the new orientation for the primitive on the service.\n\t  */\n\tvoid setOrientation (double orientation)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"OR\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, orientation);\n\t}\n\n\t/**\n\t  * Set the attenuation factor of the current primitive on the service.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param absorption is the new attenuation factor for the primitive on the service.\n\t  */\n\tvoid setAbsorption (float absorption)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"AB\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, absorption);\n\t}\n\n\t/**\n\t  * Set the size of the current primitive on the service. Only for boxes primitives.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param width is the new size on X axis factor for the primitive on the service.\n\t  * \\param depth is the new size on Y axis factor for the primitive on the service.\n\t  */\n\tvoid setSize (float width, float depth)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"SZ\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, width, depth);\n\t}\n\n\t/**\n\t  * Set the height of the current primitive on the service. For boxes and cylinders primitives.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param height is the new size on Z axis factor for the primitive on the service.\n\t  */\n\tvoid setHeight (float height)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"HE\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, height);\n\t}\n\n\t/**\n\t  * Set the radius of the current primitive on the service. For cylinders primitives.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param height is the new size on Z axis factor for the primitive on the service.\n\t  */\n\tvoid setRadius (float radius)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"RD\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, radius);\n\t}\n\n\t/**\n\t  * Make the current primitive a global move. This move is slow.\n\t  * Use it only for the first placement and for teleporting.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param position is the new position for the primitive on the service.\n\t  */\n\tvoid globalMove (const NLMISC::CVectorD& position)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"GM\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, const_cast<NLMISC::CVectorD&> (position));\n\t}\n\n\t/**\n\t  * Make the current primitive a relative move. This move is fast.\n\t  * Use it for current move. Make first a relative move of all your\n\t  * primitives, then put a evalCollision message. Then you can\n\t  * query position and speed by posting getPositionSpeed message.\n\t  *\n\t  * No answer will be send by the service.\n\t  *\n\t  * \\param position is the new position for the primitive on the service.\n\t  */\n\tvoid relativeMove (const NLMISC::CVectorD& speed)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"RM\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, const_cast<NLMISC::CVectorD&> (speed));\n\t}\n\n\t/**\n\t  * Query the position and the speed of the primitive after an evalCollision message.\n\t  *\n\t  * The service will answer with a getPositionSpeedCallback message.\n\t  *\n\t  * \\param id is the id of the primitive to get the position and the speed.\n\t  */\n\tvoid getPositionSpeed (NLPACS::UMovePrimitive::TUserData id)\n\t{\n\t\t// Append to the current message\n\t\tstd::string name=\"PS\";\n\t\tbool nlTrue=true;\n\t\t_Message.serial (nlTrue, name, id);\n\t}\n\nprotected:\n\n\t/// \\name Callbacks\n\n\t/**\n\t  * This call back is called when a message is coming. Used for synchronisation.\n\t  */\n\tvirtual void\tmessageCallback ()\n\t{}\n\n\t/**\n\t  * This message is send by the service to answer the rayTest request.\n\t  *\n\t  * \\param testId is the test ID passed to rayTest().\n\t  * \\param testResult is false if the ray is not clipped, else true.\n\t  */\n\tvirtual void\trayTestCallback (uint32 testId, bool testResult)\n\t{}\n\n\t/**\n\t  * This message is send by the service to answer the evalCollision request.\n\t  *\n\t  * \\param evalId is the id of the evaluation passed to evalCollision.\n\t  * \\param triggerInfo is an array of trigger descriptor. Each entry of the array is\n\t  * a new trigger raised by evalCollision.\n\t  */\n\tvirtual void\ttriggerCallback (uint32 evalId, const std::vector<NLPACS::UTriggerInfo>& triggerInfo)\n\t{}\n\n\t/**\n\t  * This message is send by the service to answer the testMove request.\n\t  *\n\t  * \\param id is the id of the primitive tested.\n\t  * \\param testResult is true if the primitive can do that move, else false.\n\t  */\n\tvirtual void\ttestMoveCallback (NLPACS::UMovePrimitive::TUserData id, bool testResult)\n\t{}\n\n\t/**\n\t  * This message is send by the service to answer the getPositionSpeed request.\n\t  *\n\t  * \\param id is the id of the primitive.\n\t  * \\param position is the new position of the primitive.\n\t  * \\param speed is the new speed of the primitive.\n\t  */\n\tvirtual void\tgetPositionSpeedCallback (NLPACS::UMovePrimitive::TUserData id, const NLMISC::CVectorD &position, const NLMISC::CVectorD &speed)\n\t{}\n\nprivate:\n\tCCallbackClient\t\t*_Server;\n\tCMessage\t\t\t_Message;\n};\n\n// Callback to listen to the server\nstatic void cbPacsAnswer (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t// Get the client pointer\n\tCPacsClient *client=(CPacsClient*)(uint)from->appId ();\n\n\t// Check stream\n\tmsgin.serialCheck ((uint32)NLNET_PACS_PROTOCOL_VERSION);\n\n\t// Message callback\n\tclient->messageCallback ();\n\n\tbool again;\n\tmsgin.serial (again);\n\n\twhile (again)\n\t{\n\t\t// Read the message sub string\n\t\tstd::string subMessage;\n\t\tmsgin.serial (subMessage);\n\n\t\t// This code can work only if sizeof (uint) == sizeof (void*)\n\t\tnlassert (sizeof (uint)==sizeof (void*));\n\n\t\t// Raytrace callback ?\n\t\tif (subMessage==\"RY\")\n\t\t{\n\t\t\t// Read test id and test result\n\t\t\tuint32 testId;\n\t\t\tbool testResult;\n\t\t\tmsgin.serial (testId, testResult);\n\n\t\t\t// Call the callback\n\t\t\tclient->rayTestCallback (testId, testResult);\n\t\t}\n\t\t// Trigger callback ?\n\t\telse if (subMessage==\"TR\")\n\t\t{\n\t\t\t// Read eval id and trigger info\n\t\t\tuint32 evalId;\n\t\t\tstd::vector<NLPACS::UTriggerInfo> triggerInfo;\n\t\t\tmsgin.serial (evalId);\n\t\t\tmsgin.serialCont (triggerInfo);\n\n\t\t\t// Call the callback\n\t\t\tclient->triggerCallback (evalId, triggerInfo);\n\t\t}\n\t\t// Test move callback ?\n\t\telse if (subMessage==\"TM\")\n\t\t{\n\t\t\t// Read the primitive id and test result\n\t\t\tNLPACS::UMovePrimitive::TUserData id;\n\t\t\tbool testResult;\n\t\t\tmsgin.serial (id, testResult);\n\n\t\t\t// Call the callback\n\t\t\tclient->testMoveCallback (id, testResult);\n\t\t}\n\t\t// Test move callback ?\n\t\telse if (subMessage==\"PS\")\n\t\t{\n\t\t\t// Read the primitive id and test result\n\t\t\tNLPACS::UMovePrimitive::TUserData id;\n\t\t\tNLMISC::CVectorD position;\n\t\t\tNLMISC::CVectorD speed;\n\t\t\tmsgin.serial (id, position, speed);\n\n\t\t\t// Call the callback\n\t\t\tclient->getPositionSpeedCallback (id, position, speed);\n\t\t}\n\t\telse\n\t\t\tNLMISC::nlError (\"Pacs client: unkown sub message string\");\n\n\t\t// Next message ?\n\t\tmsgin.serial (again);\n\t}\n}\n\nstatic TCallbackItem PacsCallbackArray[] =\n{\n\t{ \"PACS_ASW\", cbPacsAnswer }\n};\n\ninline \tbool CPacsClient::connect ()\n{\n\t// Create a connexion\n\t_Server = new CCallbackClient;\n\n\t// Look up for PACS service\n\tCNamingClient::lookupAndConnect (\"PS\", *_Server);\n\tif (_Server->connected())\n\t{\n\t\t// Add callback array\n\t\t_Server->addCallbackArray (PacsCallbackArray, sizeof (PacsCallbackArray) / sizeof (PacsCallbackArray[0]));\n\n\t\t// This code can work only if sizeof (uint) == sizeof (void*)\n\t\tnlassert (sizeof (uint)==sizeof (void*));\n\t\t_Server->id ()->setAppId ((uint64)(uint)this);\n\n\t\t// Return ok\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n}\n\n} // NLNET\n\n\n#endif // NL_PACS_CLIENT_H\n\n/* End of pacs_client.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/service.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_SERVICE_H\n#define NL_SERVICE_H\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/cpu_time_stat.h\"\n#include \"nel/misc/sstring.h\"\n\n#include \"unified_network.h\"\n\n#include <string>\n#include <vector>\n\nnamespace NLMISC\n{\n\tclass CWindowDisplayer;\n}\n\n#if defined(NL_OS_WINDOWS) && defined(_WINDOWS)\n#ifndef WINAPI\n#define WINAPI      __stdcall\n#endif\n#ifndef APIENTRY\n#define APIENTRY    WINAPI\n#endif\n\nstruct HINSTANCE__;\ntypedef struct HINSTANCE__ *HINSTANCE;\n\ntypedef char CHAR;\ntypedef CHAR *LPSTR;\n#endif\n\nnamespace NLNET\n{\n\nclass CCallbackServer;\nclass IServiceUpdatable;\n\nenum TServiceRunningState\n{\n    ServiceClose,\n    ServiceOnline,\n    ServiceCanAccess,\n};\n\n//\n// Macros\n//\n\n\n/**\n * The goal of this macro is to simplify the service creation, it creates the main body function.\n *\n * If you don't want to give a callback array, just put EmptyCallbackArray in the last argument\n *\n * Example:\n *\\code\n\t// Create the Test Service class\n\tclass CTestService : public IService\n\t{\n\tpublic:\n\t\tvoid init () { nlinfo(\"init()\"); }\n\t\tbool update () { nlinfo (\"update();\"); return true; }\n\t\tvoid release () { nlinfo(\"release()\"); }\n\t};\n\t// Create the main() function that create a test service instance and execute it.\n\t// \"TS\" is the short service name and \"test_service\" is the long one.\n\t// The name of the config file is based on the long name!\n\t// EmptyCallbackArray means that you don't provide right now the callback\n\t// the last 2 path are where is the config file is (directory) and where to log info (directory)\n\tNLNET_SERVICE_MAIN(CTestService, \"TS\", \"test_service\", 0, EmptyCallbackArray, \"\", \"\");\n *\\endcode\n *\n * If you want the port to not be auto-assigned by the naming service, set the port to a number different than 0.\n *\n * Args used by service are always in lower case:\n *\n * -A followed by the path where to execute the service (it uses chdir())\n * -B followed by the IP address where the naming service is\n * -C followed by the path where we can find the config file\n * -D followed by the client listening address of the frontend for the login system (FS only)\n * -I to start the service iconified\n * -L followed by the directory where we have to log\n * -N followed by the alias name (used by the admin system)\n * -P followed by the listen port (ListenAddress)\n * -Q to make the service quit immediately after the first update\n * -S followed by the shard Id (sint32) (WS only)\n * -T followed by the IP address where the login service is (WS only)\n * -W followed by the path where to save all shard data (SaveFilesDirectory)\n * -Z[u] to just init the config file then return (used for test), use Zu to not release the service\n *\n *\n */\n\n\n#if defined(NL_OS_WINDOWS) && defined(_WINDOWS)\n#define NLNET_SERVICE_MAIN(__ServiceClassName, __ServiceShortName, __ServiceLongName, __ServicePort, __ServiceCallbackArray, __ConfigDir, __LogDir) \\\n \\\nint APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \\\n{ \\\n\tNLMISC::CApplicationContext\tserviceContext; \\\n\t__ServiceClassName *scn = new __ServiceClassName; \\\n\tscn->setArgs (lpCmdLine); \\\n\tNLMISC::createDebug(NULL,!scn->haveLongArg(\"nolog\"));\\\n\tscn->setCallbackArray (__ServiceCallbackArray, sizeof(__ServiceCallbackArray)/sizeof(__ServiceCallbackArray[0])); \\\n    sint retval = scn->main (__ServiceShortName, __ServiceLongName, __ServicePort, __ConfigDir, __LogDir, __DATE__\" \"__TIME__); \\\n\tdelete scn; \\\n\treturn retval; \\\n}\n\n#else\n#define NLNET_SERVICE_MAIN(__ServiceClassName, __ServiceShortName, __ServiceLongName, __ServicePort, __ServiceCallbackArray, __ConfigDir, __LogDir) \\\n \\\nint main(int argc, const char **argv) \\\n{ \\\n\tNLMISC::CApplicationContext serviceContext; \\\n\t__ServiceClassName *scn = new __ServiceClassName; \\\n\tscn->setArgs (argc, argv); \\\n\tNLMISC::createDebug(NULL,!scn->haveLongArg(\"nolog\"));\\\n\tscn->setCallbackArray (__ServiceCallbackArray, sizeof(__ServiceCallbackArray)/sizeof(__ServiceCallbackArray[0])); \\\n\tsint retval = scn->main (__ServiceShortName, __ServiceLongName, __ServicePort, __ConfigDir, __LogDir, __DATE__ \" \" __TIME__); \\\n\tdelete scn; \\\n\treturn retval; \\\n}\n\n#endif\n\n#define DEFAULT_SHARD_ID 666\n\n\n//\n// Typedefs\n//\n\n//typedef uint16 TServiceId;\n\n/// Callback where you can return true for direct clearance, or false for later clearance.\ntypedef bool (*TRequestClosureClearanceCallback) ();\n\n//\n// Variables provided to application and unused in the NeL library itself.\n//\n\nextern TUnifiedCallbackItem EmptyCallbackArray[1];\n\n\n//\n// Classes\n//\n\n/**\n * Base class for all network services.\n * You must inherite from this class to create your own service. You must not\n * create ctor and dtor but implement init() and release() methods.\n * You have to create a global callback array called CallbackArray.\n *\n * \\ref service_howto\n *\n * Temporary command line arguments :\n * \\li -n<AliasName>\n *\n * \\author Vianney Lecroart\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nclass IService\n{\npublic:\n\n\t/// \\name User overload methods. These methods can be overload by the user do handle init, update and release operation.\n\t// @{\n\n\t/** Called before the displayer is created, no displayer or network connection are built.\n\t    Use this callback to check some args and perform some command line based stuff */\n\tvirtual void\t\t\tcommandStart () {}\n\n\t/// Initializes the service (must be called before the first call to update())\n\tvirtual void\t\t\tinit () {}\n\n\t/// This function is called every \"frame\" (you must call init() before). It returns false if the service is stopped.\n\tvirtual bool\t\t\tupdate () { return true; }\n\n\t/// Finalization. Release the service. For example, this function frees all allocations made in the init() function.\n\tvirtual void\t\t\trelease () {}\n\n\t//@}\n\n\n\t/// \\name get methods. These methods provide a way to read internal service variables.\n\t// @{\n\n\t/// Returns the instance of the service to access to methods/variables class\n\tstatic IService\t\t\t\t\t*getInstance ();\n\n\t/// Returns true if the service singleton has been initialized\n\tstatic bool\t\t\t\t\t\tisServiceInitialized() { return _Instance != NULL; }\n\n\t/// Returns the current service short name (ie: TS)\n\tconst std::string\t\t\t\t&getServiceShortName () const { return _ShortName; }\n\n\t/// Returns the current service long name (ie: test_serivce)\n\tconst std::string\t\t\t\t&getServiceLongName () const { return _LongName; }\n\n\t/// Returns the current service alias name setted by AES\n\tconst std::string\t\t\t\t&getServiceAliasName () const { return _AliasName; }\n\n\t/// Returns the current service unified name that is   alias/short-id or short-id if alias is empty\n\tstd::string\t\t\t\t\t\tgetServiceUnifiedName () const;\n\n\t/// Returns the service identifier\n\tTServiceId\t\t\t\t\t\tgetServiceId () const { return _SId; }\n\n\t/// Return the host name of the host machine\n\tconst std::string\t\t\t\t&getHostName() const\t\t{ return _HostName; }\n\n\t/// Returns the status\n\tsint\t\t\t\t\t\t\tgetExitStatus () const { return _ExitStatus; }\n\n\t/// Returns the date of launch of the service. Unit: see CTime::getSecondsSince1970()\n\tuint32\t\t\t\t\t\t\tgetLaunchingDate () const;\n\n\t/// Return true if this service don't use the NS (naming service)\n\tbool\t\t\t\t\t\t\tgetDontUseNS() const { return _DontUseNS; }\n\n\t/// Return true if this service don't use the AES (admin executor service)\n\tbool\t\t\t\t\t\t\tgetDontUseAES() const { return _DontUseAES; }\n\n\t/// Returns arguments of the program pass from the user to the program using parameters (ie: \"myprog param1 param2\")\n\tconst NLMISC::CVectorSString\t&getArgs () const { return _Args; }\n\n\t/// Returns true if the argument if present in the command line (ie: haveArg('p') will return true if -p is in the command line)\n\tbool\t\t\t\t\t\t\thaveArg (char argName) const;\n\n\t/** Returns the parameter linked to an option\n\t * getArg('p') will return toto if -ptoto is in the command line\n\t * getArg('p') will return C:\\Documents and Settings\\toto.tmp if -p\"C:\\Documents and Settings\\toto.tmp\" is in the command line\n\t * It'll thrown an Exception if the argName is not found\n\t */\n\tstd::string\t\t\t\t\t\tgetArg (char argName) const;\n\n\t/// return true if named long arg is present on the commandline\n\t/// eg haveLongArg(\"toto\") returns true if \"--toto\" or \"--toto=xxx\" can be found on commandline\n\tbool\t\t\t\t\t\t\thaveLongArg (const char* argName) const;\n\n\t/// returns the value associated with the given named argument\n\t/// both \"--toto=xxx\" and \"--toto xxx\" are acceptable\n\t/// quotes round arguments are stripped\n\tstd::string\t\t\t\t\t\tgetLongArg (const char* argName) const;\n\n\t/// Returns an uniq id for an entities on this service.\n\t/*uint64\t\t\t\t\t\t\tgetEntityId (uint8 type)\n\t{\n\t\treturn NLMISC::CEntityId::getNewEntityId( type ).getRawId();\n\t}*/\n\n\t/// Returns the recording state (don't needed if you use layer5)\n\tCCallbackNetBase::TRecordingState\tgetRecordingState() const { return _RecordingState; }\n\n\n\t//@}\n\n\n\t/// \\name set methods. These methods provide a way to modify internal service variables.\n\t// @{\n\n\t/** Sets the status of the service, this status is return to the application. EXIT_SUCCESS is the default status\n\t * You can set it to EXIT_FAILURE or any value you want. It's useful when you use the service in a script and you\n\t * want to know the return value of the application to do the appropriate things.\n\t */\n\tvoid\t\t\t\t\tsetExitStatus (sint exitStatus) { _ExitStatus = exitStatus; }\n\n\t/** Call this function if you want the service quits next loop. The code will be returned outside of the application.\n\t * \\warning If you set the code to 0, it ll NOT exit the service */\n\tvoid\t\t\t\t\texit (sint code = 0x10);\n\n\t/** Selects timeout value in seconds for each update. You are absolutely certain that your update()\n\t * function will not be called before this amount of time you set.\n\t * If you set the update timeout value higher than 0, all messages in queues will be process until the time greater than the timeout user update().\n\t * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update().\n\t *\n\t * The default value is 100 (100ms) or the value found in the config file (UpdateTimeout)\n\t */\n\tvoid\t\t\t\t\tsetUpdateTimeout (NLMISC::TTime timeout) { /*if (timeout>1.0) nlerror (\"IServer::setUpdateTimeout is now a double in SECOND and not ms\");*/ _UpdateTimeout = timeout; }\n\n\t//@}\n\n\t//@{\n\t//@name Service status management methods\n\t/// Push a new status on the status stack.\n\tvoid\t\t\t\t\tsetCurrentStatus(const std::string &status);\n\t/// Remove a status from the status stack. If this status is at top of stack, the next status become the current status\n\tvoid\t\t\t\t\tclearCurrentStatus(const std::string &status);\n\t/// Add a tag in the status string\n\tvoid\t\t\t\t\taddStatusTag(const std::string &statusTag);\n\t/// Remove a tag from the status string\n\tvoid\t\t\t\t\tremoveStatusTag(const std::string &statusTag);\n\t/// Get the current status with attached tags\n\tstd::string\t\t\t\tgetFullStatus() const;\n\t//@}\n\n\t/// \\name variables. These variables can be read/modified by the user.\n\t// @{\n\n\tNLMISC::CConfigFile\tConfigFile;\n\n\t// use to display result of command (on file and windows displayer) **without** filter\n\tNLMISC::CLog CommandLog;\n\n\t//@}\n\n\n\t/// \\name private methods. These methods are used by internal system but can't be put in private, don't use them.\n\t// @{\n\n\t/// This main is called by the macro (service5 says if we have to use layer5 or not)\n\tsint main (const char *serviceShortName, const char *serviceLongName, uint16 servicePort, const char *configDir, const char *logDir, const char *compilationDate);\n\n\t/// Sets the command line and init _Args variable. You must call this before calling main()\n\tvoid setArgs (int argc, const char **argv);\n\n\t/// Sets the command line and init _Args variable. You must call this before calling main()\n\tvoid setArgs (const char *args);\n\n\t/// Sets the default callback array given from the macro\n\tvoid setCallbackArray (TUnifiedCallbackItem *array, uint nbelem) { _CallbackArray = array; _CallbackArraySize = nbelem; }\n\n\t/// Require to reset the hierarchical timer\n\tvoid requireResetMeasures();\n\n\t/// Ctor. You must not inherit ctor but overload init() function\n\tIService ();\n\n\t/// Dtor. You must not inherit dtor but overload release() function\n\tvirtual ~IService ();\n\n\t//@}\n\n\t//@{\n\t/// \\name Updatable are object that require an update at each service loop\n\t/// Register an updatable interface\n\tvoid registerUpdatable(IServiceUpdatable *updatable);\n\t/// Unregister an updatable interface\n\tvoid unregisterUpdatable(IServiceUpdatable *updatable);\n\t//@}\n\n\t/// The window displayer instance\n\tNLMISC::CWindowDisplayer\t\t\t*WindowDisplayer;\n\n\t/// Directory where to store files that the services will write but are the same for all shard instance (for example: packet_sheets)\n\t/// Use .toString() to access to the value\n\tNLMISC::CVariable<std::string>\t\tWriteFilesDirectory;\n\n\t/// Directory where to store files that the services will write during the exploitation of the game (for example: player backup, string cache)\n\t/// Use .toString() to access to the value\n\tNLMISC::CVariable<std::string>\t\tSaveFilesDirectory;\n\n\t/// If true (default), the provided SaveFilesDirectory will be converted to a full path (ex: \"saves\" -> \"/home/dir/saves\")\n\tNLMISC::CVariable<bool>\t\t\t\tConvertSavesFilesDirectoryToFullPath;\n\n\t/** You can provide a callback interface (only one) that will be called if any of the directory variables\n\t * (WriteFilesDirectory, SaveFilesDirectory, ConfigDirectory, LogDirectory, RunningDirectory) is changed\n\t * (also called for the first setting read from the .cfg file). Default is NULL.\n\t */\n\tvoid\t\t\t\t\t\t\t\tsetDirectoryChangeCallback( NLMISC::IVariableChangedCallback *cbi ) { _DirectoryChangedCBI = cbi; }\n\n\tvoid\t\t\t\t\t\t\t\tsetVersion (const std::string &version) { Version = version; }\n\n\tuint16\t\t\t\t\t\t\t\tgetPort() { return ListeningPort; }\n\n\t// Warning: can take a moment to be received from the WS. The default value (when not received yet) is DEFAULT_SHARD_ID.\n\tuint32\t\t\t\t\t\t\t\tgetShardId() const { return _ShardId; }\n\n\tconst NLMISC::CCPUTimeStat&\t\t\tgetCPUUsageStats() const\t{ return _CPUUsageStats; }\n\n\t/// Allow the service to return a status string with important value\n\tvirtual std::string\t\t\t\t\tgetServiceStatusString() const;\n\n\t/**\n\t * If your service needs a delay when it is asked to quit, provide a callback here (optional).\n\t * Then, when the service will be asked to quit, this callback will be called. Then you can\n\t * either return true to allow immediate closure, or false to delay the closure. The closure\n\t * will then happen after you call clearForClosure().\n\t *\n\t * If you don't provide a callback here, or if you call with NULL, the service will exit\n\t * immediately when asked to quit.\n\t */\n\tvoid\t\t\t\t\t\t\t\tsetClosureClearanceCallback( TRequestClosureClearanceCallback cb ) { _RequestClosureClearanceCallback = cb; }\n\n\t/**\n\t * If using clearance for closure (see setClosureClearanceCallback()), you can call this method\n\t * to allow the service to quit. If calling it while your callback has not be called yet, the\n\t * callback will be bypassed and the service will quit immediately when asked to quit. If calling it\n\t * after you callback was called (and you returned false), the service will quit shortly.\n\t */\n\tvoid\t\t\t\t\t\t\t\tclearForClosure() { _ClosureClearanceStatus = CCClearedForClosure; }\n\n\t/** Set the shard id (by the user code), when known before IService receives it by the WS).\n\t * If a non-default value is already set and different than shardId => nlerror.\n\t * If later IService receives a different value from the WS => nlerror.\n\t */\n\tvoid\t\t\t\t\t\t\t\tanticipateShardId( uint32 shardId );\n\nprivate:\n\n\t/// \\name methods. These methods are used by internal system.\n\t// @{\n\n\t/// Changes the recording state (use if you know what you are doing)\n\tvoid\t\t\t\t\t\t\t\tsetRecordingState( CCallbackNetBase::TRecordingState rec ) { _RecordingState = rec; }\n\n\t/** Set the shard id (received from the WS). See also anticipateShardId().\n\t */\n\tvoid\t\t\t\t\t\t\t\tsetShardId( uint32 shardId );\n\n\t//@}\n\n\t/// \\name variables. These variables are used by the internal system.\n\t// @{\n\n\t/// Array of arguments pass from the command line\n\tNLMISC::CVectorSString\t\t\t\t_Args;\n\n\t/// Host name of the host machine that run the service\n\tstd::string\t\t\t\t\t\t\t_HostName;\n\t/// Listening port of this service\n\tNLMISC::CVariable<uint16>\t\t\tListeningPort;\n\n\t/// Recording state\n\tCCallbackNetBase::TRecordingState\t_RecordingState;\n\n\t/// Current service name sets by the actual service when declaring NLNET_SERVICE_MAIN\n\tstd::string\t\t\t\t\t\t\t_ShortName;\t\t// ie: \"NS\"\n\tstd::string\t\t\t\t\t\t\t_LongName;\t\t// ie: \"naming_service\"\n\tstd::string\t\t\t\t\t\t\t_AliasName;\t\t// this name is initialized by the admin executor service via the args\n\n\t/// Instance of this service (singleton)\n\tstatic IService\t\t\t\t\t\t*_Instance;\n\n\t/// Select timeout value in milliseconds between to call of user update()\n\tNLMISC::TTime\t\t\t\t\t\t_UpdateTimeout;\n\n\t/// the service id of this sevice\n\tTServiceId\t\t\t\t\t\t\t_SId;\n\n\t/// the exit status of this service (the status is returned by the service at the release time)\n\tsint\t\t\t\t\t\t\t\t_ExitStatus;\n\n\t/// true if the service initialisation is passed\n\tbool\t\t\t\t\t\t\t\t_Initialized;\n\n\t/// The directory where the configfile is\n\tNLMISC::CVariable<std::string>\t\tConfigDirectory;\n\n\t/// The directory where the logfiles are\n\tNLMISC::CVariable<std::string>\t\tLogDirectory;\n\n\t/// The directory where the service is running\n\tNLMISC::CVariable<std::string>\t\tRunningDirectory;\n\n\tNLMISC::CVariable<std::string>\t\tVersion;\n\n\tTUnifiedCallbackItem\t\t\t\t*_CallbackArray;\n\tuint\t\t\t\t\t\t\t\t_CallbackArraySize;\n\n\t/// true if the service don't use the naming service\n\tbool\t\t\t\t\t\t\t\t_DontUseNS;\n\t/// true if the service don't use the admin executor service\n\tbool\t\t\t\t\t\t\t\t_DontUseAES;\n\n\t/// Require to reset the hierarchical timer\n\tbool\t\t\t\t\t\t\t\t_ResetMeasures;\n\n\t/// Shard Id\n\tuint32\t\t\t\t\t\t\t\t_ShardId;\n\n\t/// CPU usage stats\n\tNLMISC::CCPUTimeStat\t\t\t\t_CPUUsageStats;\n\n\t/// Registered updatable interface\n\tstd::set<IServiceUpdatable*>\t\t_Updatables;\n\n\t//@{\n\t//@name Service running status management\n\t/// The status stack is used to display the most recent set status.\n\tstd::vector<std::string>\t\t\t_ServiceStatusStack;\n\t/// The status tags. All added tags are displayed.\n\tstd::set<std::string>\t\t\t\t_ServiveStatusTags;\n\t//@}\n\n\tenum TClosureClearanceStatus { CCMustRequestClearance, CCWaitingForClearance, CCClearedForClosure, CCCallbackThenClose=256 };\n\n\t/// Closure clearance state (either CCMustRequestClearance, CCWaitingForClearance, CCClearedForClosure or CCCallbackThenClose + any other as a backup value)\n\tuint\t\t\t\t\t\t\t\t_ClosureClearanceStatus;\n\n\t/// Closure clearance callback (NULL if no closure clearance required)\n\tTRequestClosureClearanceCallback\t_RequestClosureClearanceCallback;\n\n\t/// Directory changed callback\n\tNLMISC::IVariableChangedCallback*\t_DirectoryChangedCBI;\n\n\tfriend void serviceGetView (uint32 rid, const std::string &rawvarpath, std::vector<std::string> &vara, std::vector<std::string> &vala);\n\tfriend void cbAESConnection (const std::string &serviceName, TServiceId sid, void *arg);\n\tfriend struct nel_serviceInfoClass;\n\tfriend struct nel_getWinDisplayerInfoClass;\n\tfriend void cbDirectoryChanged (NLMISC::IVariable &var);\n\tfriend void cbReceiveShardId (NLNET::CMessage& msgin, const std::string &serviceName, TServiceId serviceId);\n\n\tNLMISC_CATEGORISED_DYNVARIABLE_FRIEND(nel, State);\n};\n\n\n/** Interface class for object that need an update call during each service loop.\n*/\nclass IServiceUpdatable\n{\npublic:\n\tIServiceUpdatable()\n\t{\n\t\tif (IService::isServiceInitialized())\n\t\t{\n\t\t\tIService::getInstance()->registerUpdatable(this);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"IServiceUpdatable : IService is not initialized, IUpdatable will not be called\");\n\t\t}\n\t}\n\tvirtual ~IServiceUpdatable()\n\t{\n\t\tif (IService::isServiceInitialized())\n\t\t{\n\t\t\tIService *service = IService::getInstance();\n\n\t\t\tservice->unregisterUpdatable(this);\n\t\t}\n\t}\n\n\t/// implemente this virtual in you derived class\n\tvirtual void serviceLoopUpdate() =0;\n};\n\n\ninline IService *IService::getInstance()\n{\n\tif (_Instance == NULL)\n\t{\n\t\t/* the nel context MUST be initialised */\n\t\tnlassertex(NLMISC::INelContext::isContextInitialised(), (\"You are trying to access a safe singleton without having initialized a NeL context. The simplest correction is to add 'NLMISC::CApplicationContext myApplicationContext;' at the very beginning of your application.\"));\n\t\t// try to retrieve the safe singleton pointer\n\t\t_Instance = reinterpret_cast<IService*>(NLMISC::INelContext::getInstance().getSingletonPointer(\"IService\"));\n\t}\n\treturn _Instance;\n}\n\n\n\n}; // NLNET\n\n#endif // NL_SERVICE_H\n\n/* End of service.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SOCK_H\n#define NL_SOCK_H\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/mutex.h\"\n#include \"inet_address.h\"\n//#include <sstream>\n\n/// This namespace contains all network class\nnamespace NLNET {\n\n\n/**\n * Network exceptions\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000\n */\nstruct ESocket : public NLMISC::Exception\n{\n\t/** Constructor\n\t * You can provide an internet address. If so, reason *must* contain \"%s\"\n\t * where the address should be written. Moreover, the length of reason plus\n\t * the length of the address when displayed by asString() should no exceed 256.\n\t */\n\tESocket( const char *reason=\"\", bool systemerror=true, CInetAddress *addr=NULL );\n};\n\n\n/// Exception raised when connect() fails\nstruct ESocketConnectionFailed : public ESocket\n{\n\tESocketConnectionFailed( CInetAddress addr ) : ESocket( \"Connection to %s failed\", true, &addr ) {}\n};\n\n\n/// Exception raised when a connection is gracefully closed by peer\nstruct ESocketConnectionClosed : public ESocket\n{\n\tESocketConnectionClosed() : ESocket( \"Connection closed\" ) {}\n};\n\n\n/// Exception raised when an unauthorized access has been done\nstruct EAccessDenied : public ESocket\n{\n\tEAccessDenied( std::string s ): ESocket( (std::string(\"Access denied: \")+s).c_str(), false ) {}\n};\n\n\n/// Exception raised when a the NS does not find the service looked-up\nstruct EServiceNotFound : public ESocket\n{\n\tEServiceNotFound( std::string s ): ESocket( (std::string(\"Service not found: \")+s).c_str(), false ) {}\n};\n\n\n//typedef SOCKET;\n#ifdef NL_OS_WINDOWS\n\ttypedef uint SOCKET;\n#elif defined NL_OS_UNIX\n\ttypedef int SOCKET;\n#endif\n\n\n\n/**\n * CSock: base socket class.\n * One CSock object represents a communication between two hosts, the local one and the remote one.\n * This class implements layer 0 of the NeL Network Engine.\n * This class does not handle conversion between big endian and little endian ; the provided\n * buffers are sent raw.\n *\n * The \"logging\" boolean value is necessary because in this implementation we always log\n * to one single global CLog object : there is not one CLog object per socket. Therefore\n * we must prevent the socket used in CNetDisplayer from logging itself... otherwise we\n * would have an infinite recursion.\n *\n * The \"connected\" property may have a different meaning whether the socket is a stream socket\n * (e.g. using TCP) or it is a connectionless datagram socket (e.g. using UDP). In the latter,\n * \"connected\" only means that the local and the remote addresses have been set.\n *\n * Important note: this class is thread-safe, meaning you can access to a CSock object\n * from multiple threads BUT the only things you are allow to do in parallel are\n * receive/send and read the connected() property.\n *\n * You must call CSock::initNetwork() before using any network class (even CInetAddress).\n * You must call CSock::releaseNetwork() at the end of your program.\n *\n * By default, a socket is in blocking mode. Call setNonBlockingMode() to change this\n * behaviour.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000-2001\n */\nclass CSock\n{\npublic:\n\n\tenum TSockResult { Ok, WouldBlock, ConnectionClosed, Error };\n\n\t/// Initialize the network engine, if it is not already done\n\tstatic void\t\t\tinitNetwork();\n\n\t/// Releases the network engine\n\tstatic void\t\t\treleaseNetwork();\n\n\t/** Returns the code of the last error that has occured.\n\t * Note: This code is platform-dependant. On Unix, it is errno; on Windows it is the Winsock error code.\n\t * See also errorString()\n\t */\n\tstatic uint\t\t\tgetLastError();\n\n\t/// Returns a string explaining the network error (see getLastError())\n\tstatic std::string\terrorString( uint errorcode );\n\n\t/// Change the time out value used in getDataAvailable(), which is 0 by default\n\tvoid\t\t\t\tsetTimeOutValue( long sec, long ms )\n\t{\n\t\t_TimeoutS = sec;\n\t\tif ( ms > 999 )\n\t\t\tms = 999;\n\t\t_TimeoutUs = ms * 1000;\n\t}\n\n\t/// @name Socket setup\n\t//@{\n\n\t/** Connection.\n\t * This method does not return a boolean, otherwise a programmer could ignore the result and no\n\t * exception would be thrown if connection fails :\n\t * - If addr is not valid, an exception ESocket is thrown\n\t * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown\n\t */\n\tvirtual void\t\tconnect( const CInetAddress& addr );\n\n\t/** Sets the socket in nonblocking mode. Call this method *after* connect(), otherwise you will get\n\t * an \"would block\" error (10035 on Windows). In nonblocking mode, use received() and sent() instead of receive() and send()\n\t */\n\tvoid\t\t\t\tsetNonBlockingMode ( bool bm );\n\n\t/// Returns the nonblocking mode\n\tbool\t\t\t\tnonBlockingMode() const { return _NonBlocking; }\n\n\t/** Closes the socket (without shutdown)\n\t * In general you don't need to call this method. But you can call it to:\n\t * - close a listening socket (i.e. stop accepting connections), or\n\t * - stop a select() in progress in another thread (in this case, just calling the destructor is not enough)\n\t */\n\tvirtual void\t\tclose();\n\n\t/// Destructor (shutdown + close)\n\tvirtual ~CSock();\n\n\t//@}\n\n\n\t/// @name Receiving data\n\t//@{\n\n\t/// Checks if there is some data to receive, waiting (blocking) at most for the time out value.\n\tbool\t\t\t\tdataAvailable();\n\n\t/** Receive a partial or an entire block of data, depending on nonblocking mode.\n\t *\n\t * In blocking mode: the method waits until 'len' bytes have been received.\n\t *\n\t * In nonblocking mode: the method reads the bytes that have already been received only, and\n\t * resets 'len' to the number of bytes read. The actual length may be smaller than the demanded\n\t * length. In no data is available, the return value is CSock::WouldBlock. If dataAvailable()\n\t * returns true, you are sure that receive() will not return CSock::WouldBlock.\n\t *\n\t * In case of graceful disconnection:\n\t * - connected() become false\n\t * - the return value is CSock::ConnectionClosed or an ESocketConnectionClosed exception is thrown.\n\t *\n\t * In case of failure (e.g. connection reset by peer) :\n\t * - the return value is CSock::Error or an ESocket exception is thrown.\n\t * You may want to close the connection manually.\n\t */\n\tCSock::TSockResult\treceive( uint8 *buffer, uint32& len, bool throw_exception=true );\n\n\t//@}\n\n\n\t/// @name Sending data\n\t//@{\n\n\t/** Sends a message.\n\t *\n\t * In blocking mode: the method waits until 'len' bytes have been sent.\n\t *\n\t * In nonblocking mode : the method resets len to the actual number of bytes sent.\n\t * Even if less bytes than expected have been sent, it returns CSock::Ok. The caller\n\t * is expected to test the actual len to check if the remaining data must be resent.\n\t *\n\t * \\return CSock::Ok or CSock::Error (in case of failure).\n\t * When throw_exception is true, the method throws an ESocket exception in case of failure.\n     */\n\tCSock::TSockResult\tsend( const uint8 *buffer, uint32& len, bool throw_exception=true );\n\n\t//@}\n\n\n\t/// @name Properties\n\t//@{\n\n\t/// Returns if the socket is connected (volatile)\n\tbool\t\t\t\tconnected() { return _Connected; }\n\n\t/// Returns a const reference on the local address\n\tconst CInetAddress&\tlocalAddr() const {\treturn _LocalAddr; }\n\n\t/// Returns the address of the remote host\n\tconst CInetAddress&\tremoteAddr() const { return _RemoteAddr; }\n\n\t/// Returns the socket descriptor\n\tSOCKET\t\t\t\tdescriptor() const { return _Sock; }\n\n\t/// Returns the time out value in millisecond\n\tuint32\t\t\t\ttimeOutValue() const { return _TimeoutS*1000 + _TimeoutUs/1000; }\n\n\t//@}\n\n\t/// Returns the number of bytes received since the latest connection\n\tuint64\t\t\t\tbytesReceived() const { return _BytesReceived; }\n\n\t/// Returns the number of bytes sent since the latest connection\n\tuint64\t\t\t\tbytesSent() const { return _BytesSent; }\n\n\t/// Sets the send buffer size\n\tvoid\t\t\t\tsetSendBufferSize( sint32 size );\n\n\t/// Gets the send buffer size\n\tsint32\t\t\t\tgetSendBufferSize();\n\n\t/// Returns true if the network engine is initialized\n\tstatic bool\t\t\tinitialized() { return CSock::_Initialized; }\n\nprotected:\n\n\t/**\n\t * Constructor.\n\t * \\param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion\n\t */\n\tCSock( bool logging = true );\n\n\t/// Construct a CSock object using an existing connected socket descriptor and its associated remote address\n\tCSock( SOCKET sock, const CInetAddress& remoteaddr );\n\n\t/// Creates the socket and get a valid descriptor\n\tvoid\t\t\tcreateSocket( int type, int protocol );\n\n\t/// Sets the local address\n\tvoid\t\t\tsetLocalAddress();\n\n\t/// Socket descriptor\n\tSOCKET\t\t\t_Sock;\n\n\t/// Address of local host (valid if connected)\n\tCInetAddress\t_LocalAddr;\n\n\t/// Address of the remote host (valid if connected)\n\tCInetAddress\t_RemoteAddr;\n\n\t/// If false, do not log any information\n\tbool\t\t\t_Logging;\n\n\t/// If true, the socket is in nonblocking mode\n\tbool\t\t\t_NonBlocking;\n\n\t/// True after calling connect()\n\t//NLMISC::CSynchronized<bool>\t_SyncConnected;\n\tvolatile bool\t_Connected;\n\n\t/// Number of bytes received on this socket\n\tuint64\t\t\t_BytesReceived;\n\n\t/// Number of bytes sent on this socket\n\tuint64\t\t\t_BytesSent;\n\n\t/// Main time out value (sec) for select in dataAvailable()\n\tlong\t\t\t_TimeoutS;\n\n\t/// Secondary time out value (microsec) for select in dataAvailable()\n\tlong\t\t\t_TimeoutUs;\n\nprivate:\n\n\t/// True if the network library has been initialized\n\tstatic bool\t\t_Initialized;\n\n\t// Test: send & receive duration (ms)\n\tuint32\t\t\t_MaxReceiveTime;\n\tuint32\t\t\t_MaxSendTime;\n\n\t/// Flag used to determine the moments at which sends atrta an stop blocking\n\tbool\t\t\t_Blocking;\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_SOCK_H\n\n/* End of sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/tcp_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TCP_SOCK_H\n#define NL_TCP_SOCK_H\n\n#include \"sock.h\"\n\n\nnamespace NLNET {\n\n\n/**\n * CTcpSock: Reliable socket via TCP.\n * See base class CSock.\n *\n * When to set No Delay mode on ?\n * Set TCP_NODELAY (call setNoDelay(true)) *only* if you have to send small buffers that need to\n * be sent *immediately*. It should only be set for applications that send frequent small bursts\n * of information without getting an immediate response, where timely delivery of data is\n * required (the canonical example is mouse movements). Setting TCP_NODELAY on increases\n * the network traffic (more overhead).\n * In the normal behavior of CSock, TCP_NODELAY is off i.e. the Nagle buffering algorithm is enabled.\n *\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000-2001\n */\nclass CTcpSock : public CSock\n{\npublic:\n\n\t/// @name Socket setup\n\t//@{\n\n\t/**\n\t * Constructor.\n\t * \\param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion\n\t */\n\tCTcpSock( bool logging = true );\n\n\t/// Construct a CTcpSock object using an already connected socket descriptor and its associated remote address\n\tCTcpSock( SOCKET sock, const CInetAddress& remoteaddr );\n\n\t/** Connection. You can reconnect a socket after being disconnected.\n\t * This method does not return a boolean, otherwise a programmer could ignore the result and no\n\t * exception would be thrown if connection fails :\n\t * - If addr is not valid, an exception ESocket is thrown\n\t * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown\n\t */\n\tvirtual void\t\tconnect( const CInetAddress& addr );\n\n\t/** Sets a custom TCP Window size (SO_RCVBUF and SO_SNDBUF).\n\t * You must close the socket is necessary, before calling this method.\n\t *\n\t * See http://www.ncsa.uiuc.edu/People/vwelch/net_perf/tcp_windows.html\n\t */\n\tvoid\t\t\t\tconnectWithCustomWindowSize( const CInetAddress& addr, int windowsize );\n\n\t/// Returns the TCP Window Size for the current socket\n\tuint32\t\t\t\tgetWindowSize();\n\n\t/** Sets/unsets SO_KEEPALIVE (true by default).\n\t */\n\tvoid\t\tsetKeepAlive( bool keepAlive);\n\n\t/** Sets/unsets TCP_NODELAY (by default, it is off, i.e. the Nagle buffering algorithm is enabled).\n\t * You must call this method *after* connect().\n\t */\n\tvirtual void\t\tsetNoDelay( bool value );\n\n\t/// Active disconnection for download way only (partial shutdown)\n\tvoid\t\t\t\tshutdownReceiving();\n\n\t/// Active disconnection for upload way only (partial shutdown)\n\tvoid\t\t\t\tshutdownSending();\n\n\t/// Active disconnection (shutdown) (mutexed). connected() becomes false.\n\tvirtual void\t\tdisconnect();\n\n\n\t//@}\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_TCP_SOCK_H\n\n/* End of tcp_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/transport_class.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TRANSPORT_CLASS_H\n#define NL_TRANSPORT_CLASS_H\n\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/sheet_id.h\"\n#include \"nel/misc/variable.h\"\n\n#include \"unified_network.h\"\n#include \"message.h\"\n\n#include <vector>\n#include <string>\n\nnamespace NLNET {\n\n//\n// Macros\n//\n\n/**\n * Use this macro to register a class that can be transported in the init of your program.\n */\n\n#define TRANSPORT_CLASS_REGISTER(_c) \\\n\tstatic _c _c##Instance; \\\n\tCTransportClass::registerClass (_c##Instance);\n\n#define NETTC_INFO if (!VerboseNETTC.get()) {} else nlinfo\n#define NETTC_DEBUG if (!VerboseNETTC.get()) {} else nldebug\nextern NLMISC::CVariable<bool> VerboseNETTC;\n\n\n//\n// Classes\n//\n\n/**\n * You have to inherit this class and implement description() and callback() method.\n * For an example of use, take a look at nel/samples/class_transport sample.\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2002\n */\nclass CTransportClass\n{\npublic:\n\tvirtual ~CTransportClass() {}\n\t/** Different types that we can use in a Transport class\n\t * warning: if you add/change a prop, change also in CTransportClass::init()\n\t * warning: PropUKN must be the last value (used to resize a vector)\n\t */\n\tenum TProp {\n\t\tPropUInt8, PropUInt16, PropUInt32, PropUInt64,\n\t\tPropSInt8, PropSInt16, PropSInt32, PropSInt64,\n\t\tPropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropSheetId, PropUCString, PropUKN };\n//\t\tPropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropEntityId, PropSheetId, PropUKN };\n\n\n\t//\n\t// Static methods\n\t//\n\n\t/// Init the transport class system (must be called one time, in the IService5::init() for example)\n\tstatic void init ();\n\n\t/// Release the transport class system (must be called one time, in the IService5::release() for example)\n\tstatic void release ();\n\n\t/** Call this function to register a new transport class.\n\t * \\param instance A reference to a GLOBAL space of the instance of this transport class. It will be used when receive this class from network.\n\t */\n\tstatic void registerClass (CTransportClass &instance);\n\n\t/// Display registered transport class (debug purpose)\n\tstatic void displayLocalRegisteredClass ();\n\n\n\t//\n\t// Virtual methods\n\t//\n\n\t/** You have to implement this function with the description of your class. This description\n\t * is used to send the class accross the network and read it. It must contains a class name and\n\t * a set properties.\n\t * Example:\n\t *\\code\n\t\tvirtual void description ()\n\t\t{\n\t\t\tclassName (\"SharedClass\");\n\t\t\tproperty (\"i1\", PropUInt32, (uint32)11, i1);\n\t\t}\n\t *\\endcode\n\t */\n\tvirtual void description () = 0;\n\n\t/** This function will be call when we receive this class from the network. It will use the instance given at the\n\t * registration process. By default, it does nothing.\n\t */\n\tvirtual void callback (const std::string &/* name */, NLNET::TServiceId /* sid */) { }\n\n\n\t//\n\t// Other methods\n\t//\n\n\t/// send the transport class to a specified service using the service id\n\tvoid send (NLNET::TServiceId sid);\n\n\t/// send the transport class to a specified service using the service name\n\tvoid send (const std::string &serviceName);\n\n\t/** The name of the transport class. Must be unique for each class.\n\t */\n\tvoid className (const std::string &name);\n\n\t/** Return the name of the transport class.\n\t *\tThe result is valid only AFTER calling of REGISTER_TRANSPORT_CLASS.\n\t */\n\tconst std::string &className()\t\t{ return Name; }\n\n\t/** One property of the class. Look description() for an example of use.\n\t * \\param name The name of the property\n\t * \\param type Type of the property\n\t * \\param defaultValue The value you want to be set when a message comes without this property\n\t * \\param value Reference to the value where the property will be read or write\n\t */\n\ttemplate <class T> void property (const std::string &name, TProp type, T defaultValue, T &value)\n\t{\n\t\tswitch (type)\n\t\t{\n\t\tcase PropUInt8: case PropSInt8: case PropBool: nlassert(sizeof(T) == sizeof (uint8)); break;\n\t\tcase PropUInt16: case PropSInt16: nlassert(sizeof(T) == sizeof (uint16)); break;\n\t\tcase PropUInt32: case PropSInt32: case PropDataSetRow: nlassert(sizeof(T) == sizeof (uint32)); break;\n\t\tcase PropUInt64: case PropSInt64: nlassert(sizeof(T) == sizeof (uint64)); break;\n\t\tcase PropFloat: nlassert(sizeof(T) == sizeof (float)); break;\n\t\tcase PropDouble: nlassert(sizeof(T) == sizeof (double)); break;\n\t\tcase PropString: nlassert(sizeof(T) == sizeof (std::string)); break;\n//\t\tcase PropEntityId: nlassert(sizeof(T) == sizeof (NLMISC::CEntityId)); break;\n\t\tcase PropSheetId: nlassert(sizeof(T) == sizeof (NLMISC::CSheetId)); break;\n\t\tcase PropUCString: nlassert(sizeof(T) == sizeof (ucstring)); break;\n\t\tdefault: nlerror (\"property %s have unknown type %d\", name.c_str(), type);\n\t\t}\n\n\t\tif (Mode == 2)\t\t\t// write\n\t\t{\n\t\t\t// send only if needed\n\t\t\t// todo manage unknown prop\n\t\t\tTempMessage.serial (value);\n\t\t}\n\t\telse if (Mode == 3)\t// register\n\t\t{\n\t\t\t// add a new prop to the current class\n\t\t\tnlassert (TempRegisteredClass.Instance != NULL);\n\t\t\tTempRegisteredClass.Instance->Prop.push_back (new CRegisteredProp<T> (name, type, defaultValue, &value));\n\t\t}\n\t\telse if (Mode == 4)\t// display\n\t\t{\n\t\t\tstd::string val;\n\t\t\tval = \"defval: \";\n\t\t\tval += NLMISC::toString (defaultValue);\n\t\t\tval += \" val: \";\n\t\t\tval += NLMISC::toString (value);\n\t\t\tNETTC_DEBUG (\"NETTC:   prop %s %d: %s\", name.c_str(), type, val.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\t}\n\n\ttemplate <class T> void propertyVector (const std::string &name, TProp type, std::vector<T> &value)\n\t{\n\t\tif (Mode == 2)\t\t\t// write\n\t\t{\n\t\t\t// send only if needed\n\t\t\t// todo manage unknown prop\n\t\t\tTempMessage.serialCont (value);\n\t\t}\n\t\telse if (Mode == 3)\t// register\n\t\t{\n\t\t\t// add a new prop to the current class\n\t\t\tnlassert (TempRegisteredClass.Instance != NULL);\n\t\t\tTempRegisteredClass.Instance->Prop.push_back (new CRegisteredPropCont<std::vector<T> > (name, type, &value));\n\t\t}\n\t\telse if (Mode == 4)\t// display\n\t\t{\n\t\t\ttypedef typename std::vector<T>::iterator __iterator;\n\t\t\tstd::string val;\n\t\t\tfor (__iterator it = value.begin (); it != value.end(); it++)\n\t\t\t{\n\t\t\t\tval += NLMISC::toString (T(*it));\n\t\t\t\tval += \" \";\n\t\t\t}\n\t\t\tNETTC_DEBUG (\"NETTC:   prop %s %d: %d elements ( %s)\", name.c_str(), type, value.size(), val.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\t}\n\n\ttemplate <class T> void propertyCont (const std::string &name, TProp type, T &value)\n\t{\n\t\tif (Mode == 2)\t\t\t// write\n\t\t{\n\t\t\t// send only if needed\n\t\t\t// todo manage unknown prop\n\t\t\tTempMessage.serialCont (value);\n\t\t}\n\t\telse if (Mode == 3)\t// register\n\t\t{\n\t\t\t// add a new prop to the current class\n\t\t\tnlassert (TempRegisteredClass.Instance != NULL);\n\t\t\tTempRegisteredClass.Instance->Prop.push_back (new CRegisteredPropCont<T> (name, type, &value));\n\t\t}\n\t\telse if (Mode == 4)\t// display\n\t\t{\n\t\t\ttypedef typename T::iterator __iterator;\n\t\t\tstd::string val;\n\t\t\tfor (__iterator it = value.begin (); it != value.end(); it++)\n\t\t\t{\n\t\t\t\tval += NLMISC::toString (*it);\n\t\t\t\tval += \" \";\n\t\t\t}\n\t\t\tNETTC_DEBUG (\"NETTC:   prop %s %d: %d elements ( %s)\", name.c_str(), type, value.size(), val.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\t}\n\n\t// Read the header (first part of the transport class message, currently only className)\n\tstatic void readHeader(CMessage& msgin, std::string& className)\n\t{\n\t\tmsgin.serial(className);\n\t}\n\n\t/// Display with nlinfo the content of the class (debug purpose)\n\tvoid display ();\n\nprotected:\n\n\t//\n\t// Structures\n\t//\n\n\tstruct CRegisteredBaseProp\n\t{\n\t\tCRegisteredBaseProp () : Type(PropUKN) { }\n\t\tvirtual ~CRegisteredBaseProp() {}\n\n\n\t\tCRegisteredBaseProp (const std::string &name, TProp type) : Name(name), Type(type) { }\n\n\t\tstd::string\tName;\n\t\tTProp Type;\n\n\t\tvirtual void serialDefaultValue (NLMISC::IStream &/* f */) { }\n\n\t\tvirtual void serialValue (NLMISC::IStream &/* f */) { }\n\n\t\tvirtual void setDefaultValue () { }\n\t};\n\n\ttypedef std::vector<std::pair<std::string, std::vector <CRegisteredBaseProp> > > TOtherSideRegisteredClass;\n\n\tstruct CRegisteredClass\n\t{\n\t\tCTransportClass *Instance;\n\n\t\tCRegisteredClass () { clear (); }\n\n\t\tvoid clear () { Instance = NULL; }\n\t};\n\n\ttypedef std::map<std::string, CRegisteredClass> TRegisteredClass;\n\n\ttemplate <class T> struct CRegisteredProp : public CRegisteredBaseProp\n\t{\n\t\tCRegisteredProp () : Value(NULL) { }\n\n\t\tCRegisteredProp (const std::string &name, TProp type, T defaultValue, T *value = NULL) :\n\t\t\tCRegisteredBaseProp (name, type), DefaultValue(defaultValue), Value (value) { }\n\n\t\tT DefaultValue, *Value;\n\n\t\tvirtual void serialDefaultValue (NLMISC::IStream &f)\n\t\t{\n\t\t\tf.serial (DefaultValue);\n\t\t}\n\n\t\tvirtual void serialValue (NLMISC::IStream &f)\n\t\t{\n\t\t\tnlassert (Value != NULL);\n\t\t\tf.serial (*Value);\n\t\t}\n\n\t\tvirtual void setDefaultValue ()\n\t\t{\n\t\t\tnlassert (Value != NULL);\n\t\t\t*Value = DefaultValue;\n\t\t}\n\t};\n\n\ttemplate <class T> struct CRegisteredPropCont : public CRegisteredBaseProp\n\t{\n\t\tCRegisteredPropCont () : Value(NULL) { }\n\n\t\tCRegisteredPropCont (const std::string &name, TProp type, T *value = NULL) :\n\t\t\tCRegisteredBaseProp (name, type), Value (value) { }\n\n\t\tT *Value;\n\n\t\tvirtual void serialDefaultValue (NLMISC::IStream &/* f */)\n\t\t{\n\t\t\t// nothing\n\t\t}\n\n\t\tvirtual void serialValue (NLMISC::IStream &f)\n\t\t{\n\t\t\tnlassert (Value != NULL);\n\t\t\tf.serialCont (*Value);\n\t\t}\n\n\t\tvirtual void setDefaultValue ()\n\t\t{\n\t\t\tnlassert (Value != NULL);\n\t\t\tValue->clear ();\n\t\t}\n\t};\n\n\n\t//\n\t// Variables\n\t//\n\n\t// Name of the class\n\tstd::string\tName;\n\n\t// States to decode the stream from the network\n\tstd::vector<std::vector<std::pair<sint, TProp> > > States;\n\n\t// Contains all propterties for this class\n\tstd::vector<CRegisteredBaseProp *> Prop;\n\n\n\t//\n\t// Methods\n\t//\n\n\t// Read the TempMessage and call the callback\n\tbool read (const std::string &name, NLNET::TServiceId sid);\n\n\t// Used to create a TempMessage with this class\n\tNLNET::CMessage &write ();\n\n\n\t//\n\t// Static Variables\n\t//\n\n\t// Used to serialize unused properties from the TempMessage\n\tstatic std::vector<CRegisteredBaseProp *>\tDummyProp;\n\n\t// Select what the description() must do\n\tstatic uint\t\t\t\t\t\t\t\t\tMode;\t// 0=nothing 1=read 2=write 3=register 4=display\n\n\t// Contains all registered transport class\n\tstatic TRegisteredClass\t\t\t\t\t\tLocalRegisteredClass;\t// registered class that are in my program\n\n\t// The registered class that is currently filled (before put in LocalRegisteredClass)\n\tstatic CRegisteredClass\t\t\t\t\t\tTempRegisteredClass;\n\n\t// The message that is currently filled/emptyed\n\tstatic NLNET::CMessage\t\t\t\t\t\tTempMessage;\n\n\tstatic bool\t\t\t\t\t\t\t\t\tInit;\n\n\t//\n\t// Static methods\n\t//\n\n\t// Called by release() to delete all structures\n\tstatic void unregisterClass ();\n\n\t// Fill the States merging local and other side class\n\tstatic void registerOtherSideClass (NLNET::TServiceId sid, TOtherSideRegisteredClass &osrc);\n\n\t// Create a message with local transport classes to send to the other side\n\tstatic void createLocalRegisteredClassMessage ();\n\n\t// Send the local transport classes to another service using the service id\n\tstatic void sendLocalRegisteredClass (NLNET::TServiceId sid)\n\t{\n\t\tnlassert (Init);\n\t\tNETTC_DEBUG (\"NETTC: sendLocalRegisteredClass to %hu\", sid.get());\n\t\tcreateLocalRegisteredClassMessage ();\n\t\tNLNET::CUnifiedNetwork::getInstance()->send (sid, TempMessage);\n\t}\n\n\t// Display a specific registered class (debug purpose)\n\tstatic void displayLocalRegisteredClass (CRegisteredClass &c);\n\tstatic void displayDifferentClass (NLNET::TServiceId sid, const std::string &className, const std::vector<CRegisteredBaseProp> &otherClass, const std::vector<CRegisteredBaseProp *> &myClass);\n\n\n\t//\n\t// Friends\n\t//\n\n\tfriend void cbTCReceiveMessage (NLNET::CMessage &msgin, const std::string &name, NLNET::TServiceId sid);\n\tfriend void cbTCUpService (const std::string &serviceName, NLNET::TServiceId sid, void *arg);\n\tfriend void cbTCReceiveOtherSideClass (NLNET::CMessage &msgin, const std::string &name, NLNET::TServiceId sid);\n};\n\n\n\n/**\n * Get the name of message (for displaying), or extract the class name if it is a transport class.\n *\n * Preconditions:\n * - msgin is an input message that contains a valid message\n *\n * Postconditions:\n * - msgin.getPos() was modified\n * - msgName contains \"msg %s\" or \"transport class %s\" where %s is the name of message, or the name\n *   transport class is the message is a CT_MSG\n */\nvoid getNameOfMessageOrTransportClass( NLNET::CMessage& msgin, std::string& msgName );\n\n\n//\n// Inlines\n//\n\ninline void CTransportClass::className (const std::string &name)\n{\n\tif (Mode == 2)\t\t// write\n\t{\n\t\tTempMessage.serial (const_cast<std::string &> (name));\n\t}\n\telse if (Mode == 3) // register\n\t{\n\t\t// add a new entry in my registered class\n\t\tnlassert (TempRegisteredClass.Instance != NULL);\n\t\tTempRegisteredClass.Instance->Name = name;\n\t}\n\telse if (Mode == 4) // display\n\t{\n\t\tNETTC_DEBUG (\"NETTC: class %s:\", name.c_str());\n\t}\n\telse\n\t{\n\t\tnlstop;\n\t}\n}\n\n\ninline void CTransportClass::send (NLNET::TServiceId sid)\n{\n\tnlassert (Init);\n\tNLNET::CUnifiedNetwork::getInstance()->send (sid, write ());\n}\n\n\ninline void CTransportClass::send (const std::string &serviceName)\n{\n\tnlassert (Init);\n\tNLNET::CUnifiedNetwork::getInstance()->send (serviceName, write ());\n}\n\ninline void CTransportClass::display ()\n{\n\tnlassert (Mode == 0);\n\n\t// set the mode to register\n\tMode = 4;\n\n\tdescription ();\n\n\t// set to mode none\n\tMode = 0;\n}\n\ninline NLNET::CMessage &CTransportClass::write ()\n{\n\tnlassert (Init);\n\tnlassert (Mode == 0);\n\n#ifndef FINAL_VERSION\n\t// Did the programmer forget to register the transport class? Forbid sending then.\n\tnlassert( LocalRegisteredClass.find( className() ) != LocalRegisteredClass.end() );\n#endif\n\n\t// set the mode to register\n\tMode = 2;\n\n\tTempMessage.clear ();\n\tif (TempMessage.isReading())\n\t\tTempMessage.invert();\n\tTempMessage.setType (\"CT_MSG\");\n\n\tdescription ();\n\n\t// set to mode none\n\tMode = 0;\n\n\tdisplay ();\n\n\treturn TempMessage;\n}\n\ninline bool CTransportClass::read (const std::string &name, NLNET::TServiceId sid)\n{\n\tnlassert (Init);\n\tnlassert (Mode == 0);\n\n\t// there's no info about how to read this message from this sid, give up\n\tif (sid.get() >= States.size())\n\t\treturn false;\n\n\t// set flag of all prop\n\n\tstd::vector<uint8> bitfield;\n\tbitfield.resize (Prop.size(), 0);\n\n\t// init prop from the stream\n\tuint i;\n\tfor (i = 0; i < States[sid.get()].size(); i++)\n\t{\n\t\tif (States[sid.get()][i].first == -1)\n\t\t{\n\t\t\t// skip the value from the stream\n\t\t\tDummyProp[States[sid.get()][i].second]->serialDefaultValue (TempMessage);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// get the good value\n\t\t\tProp[States[sid.get()][i].first]->serialValue (TempMessage);\n\t\t\tbitfield[States[sid.get()][i].first] = 1;\n\t\t}\n\t}\n\n\t// set default value for unknown prop\n\tfor (i = 0; i < Prop.size(); i++)\n\t{\n\t\tif (bitfield[i] == 0)\n\t\t{\n\t\t\tProp[i]->setDefaultValue ();\n\t\t}\n\t}\n\n\tdisplay ();\n\n\t// call the user callback\n\tcallback (name, sid);\n\treturn true;\n}\n\n} // NLNET\n\n#endif // NL_TRANSPORT_CLASS_H\n\n/* End of transport_class.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/udp_sim_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UDP_SIM_SOCK_H\n#define NL_UDP_SIM_SOCK_H\n\n#include \"nel/misc/config_file.h\"\n#include <queue>\n\n#include \"sock.h\"\n#include \"udp_sock.h\"\n\n\nnamespace NLNET {\n\n\nstruct CBufferizedOutPacket;\n\n/**\n * CUdpSimSock: Unreliable datagram socket via UDP but packet lost, lag simulation.\n * See class CUdpSock.\n *\n * Notes: InLag must be >0 to use the InPacketLoss variable\n *\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2002\n */\nclass CUdpSimSock\n{\npublic:\n\n\tCUdpSimSock (bool logging = true) : UdpSock(logging) { }\n\n\t// this function is to call to set the simulation values\n\tstatic void\t\t\tsetSimValues (NLMISC::CConfigFile &cf);\n\n\t// CUdpSock functions wrapping\n\tvoid\t\t\t\tconnect( const CInetAddress& addr );\n\tvoid\t\t\t\tclose();\n\tbool\t\t\t\tdataAvailable();\n\tbool\t\t\t\treceive( uint8 *buffer, uint32& len, bool throw_exception=true );\n\tCSock::TSockResult\tsend( const uint8 *buffer, uint32& len, bool throw_exception=true );\n\tvoid\t\t\t\tsendTo (const uint8 *buffer, uint32& len, const CInetAddress& addr);\n\tbool\t\t\t\tconnected();\n\tconst CInetAddress&\tlocalAddr() const {\treturn UdpSock.localAddr(); }\n\n\t// Used to call CUdpSock functions that are not wrapped in this class\n\tCUdpSock\t\t\tUdpSock;\n\nprivate:\n\n\tstd::queue<CBufferizedOutPacket*> _BufferizedOutPackets;\n\tstd::queue<CBufferizedOutPacket*> _BufferizedInPackets;\n\n\tstatic uint32\t_InLag;\n\tstatic uint8\t_InPacketLoss;\n\n\tstatic uint32\t_OutLag;\n\tstatic uint8\t_OutPacketLoss;\n\tstatic uint8\t_OutPacketDuplication;\n\tstatic uint8\t_OutPacketDisordering;\n\n\tvoid updateBufferizedPackets ();\n\tvoid sendUDP (const uint8 *buffer, uint32& len, const CInetAddress *addr = NULL);\n\tvoid sendUDPNow (const uint8 *buffer, uint32 len, const CInetAddress *addr = NULL);\n\n\tfriend void cbSimVar (NLMISC::CConfigFile::CVar &var);\n};\n\n\n} // NLNET\n\n\n#endif // NL_SIM_SOCK_H\n\n/* End of udp_sim_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/udp_sock.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UDP_SOCK_H\n#define NL_UDP_SOCK_H\n\n#include \"sock.h\"\n\n\nnamespace NLNET {\n\n\n/**\n * CUdpSock: Unreliable datagram socket via UDP.\n * See base class CSock.\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2000-2001\n */\nclass CUdpSock : public CSock\n{\npublic:\n\n\t/// @name Socket setup\n\t//@{\n\n\t/**\n\t * Constructor.\n\t * \\param logging Disable logging if the server socket object is used by the logging system, to avoid infinite recursion\n\t */\n\tCUdpSock( bool logging = true );\n\n\t/** Binds the socket to the specified port. Call bind() for an unreliable socket if the host acts as a server and expects to receive\n\t * messages. If the host acts as a client, call directly sendTo(), in this case you need not bind the socket.\n\t */\n\tvoid\t\t\t\tbind( uint16 port );\n\n\t/// Same as bind(uint16) but binds on a specified address/port (useful when the host has several addresses)\n\tvoid\t\t\t\tbind( const CInetAddress& addr );\n\n\t//@}\n\n\t/// @name Receiving data\n\t//@{\n\n\t/**  Receives data from the peer. (blocking function)\n\t * The socket must be pseudo-connected.\n\t */\n\tbool\t\t\t\treceive( uint8 *buffer, uint32& len, bool throw_exception=true );\n\n\t/** Receives data and say who the sender is. (blocking function)\n\t * The socket must have been bound before, by calling either bind() or sendTo().\n\t * \\param buffer [in] Address of buffer\n\t * \\param len [in/out] Requested length of buffer, and actual number of bytes received\n\t * \\param addr [out] Address of sender\n\t */\n\tbool\t\t\t\treceivedFrom( uint8 *buffer, uint& len, CInetAddress& addr, bool throw_exception=true );\n\n\t//@}\n\n\n\t/// @name Sending data\n\t//@{\n\n\t/// Sends data to the specified host (unreliable sockets only)\n\tvoid\t\t\t\tsendTo( const uint8 *buffer, uint len, const CInetAddress& addr );\n\n\t//@}\n\nprivate:\n\n\t/// True after calling bind() or sendTo()\n\tbool\t\t\t\t_Bound;\n\n};\n\n\n} // NLNET\n\n\n#endif // NL_UDP_SOCK_H\n\n/* End of udp_sock.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/unified_network.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UNIFIED_NETWORD_H\n#define NL_UNIFIED_NETWORD_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <vector>\n#include <string>\n\n#include \"nel/misc/command.h\"\n#include \"nel/misc/time_nl.h\"\n\n#include \"callback_client.h\"\n#include \"callback_server.h\"\n\nnamespace NLNET {\n\n/** This class encapsulate the serviceId format. */\nclass TServiceId\n{\n\t/// Service are identified by a 16 bits integer\n\tuint16\t_ServiceId;\n\npublic:\n\n\ttypedef uint16\tsize_type;\n\n\t/// A constant for the invalid service id\n\tstatic const TServiceId\tInvalidId;\n\n\t/// Default constructor, set the id to 0 (no service should have 0)\n\tTServiceId() : _ServiceId(0) { }\n\n\t/// Copy constructor\n\tTServiceId(const TServiceId &other) : _ServiceId(other._ServiceId) { }\n\n\t/// Only explicit construction from an integer are allowed\n\texplicit TServiceId(uint16 sid) : _ServiceId(sid) { }\n\n\tbool operator == (const TServiceId &other) const\n\t{\n\t\treturn _ServiceId == other._ServiceId;\n\t}\n\n\tbool operator != (const TServiceId &other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n\n\tbool operator < (const TServiceId &other) const\n\t{\n\t\treturn _ServiceId < other._ServiceId;\n\t}\n\n\t/// Getter, return the integer value of the service id\n\tuint16 get() const\t\t{ return _ServiceId; }\n\n\t/// Setter, set the value of the service id\n\tvoid set(uint16 sid)\t{ _ServiceId = sid; }\n\n\tvoid serial(NLMISC::IStream &s)\n\t{\n\t\ts.serial(_ServiceId);\n\t}\n\n\tstd::string toString() const\n\t{\n\t\treturn NLMISC::toString(_ServiceId);\n\t}\n\n\tbool fromString(const std::string &str)\n\t{\n\t\treturn NLMISC::fromString(str, _ServiceId);\n\t}\n};\n\n/** This class encapsulate the 8 bits service id.\n *\t8 bits service id are used by service register on the naming service.\n *\tThis service can be used in a NLMISC::CEntityId.\n * \tImplicit constructor and conversion are provided with the 16 bits\n *\tversion above, but the constructor will assert if the 8 bits range is\n *\toverflowed.\n */\nclass TServiceId8\n{\n\t/// The 8bits service id\n\tuint8\t_ServiceId;\n\npublic:\n\n\ttypedef uint8\tsize_type;\n\n\t/// Default constructor, set the id to 0 (no service should have 0)\n\tTServiceId8()\n\t\t:\t_ServiceId(0)\n\t{}\n\n\t/// Copy constructor\n\tTServiceId8(const TServiceId8 &other)\n\t\t:\t_ServiceId(other._ServiceId)\n\t{}\n\n\t/// Only explicit construction from an integer are allowed\n\tTServiceId8(const TServiceId &other)\n\t{\n\t\tnlassert(other.get() < 256);\n\t\t_ServiceId = uint8(other.get());\n\t}\n\texplicit TServiceId8(uint8 sid)\n\t\t:\t_ServiceId(sid)\n\t{}\n\n\t/// implicit up cast to TServiceId (16bits)\n\toperator TServiceId () const\n\t{\n\t\treturn TServiceId(_ServiceId);\n\t}\n\n\tbool operator == (const TServiceId8 &other) const\n\t{\n\t\treturn _ServiceId == other._ServiceId;\n\t}\n\tbool operator != (const TServiceId8 &other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n\tbool operator == (const TServiceId &other) const\n\t{\n\t\treturn _ServiceId == other.get();\n\t}\n\tbool operator != (const TServiceId &other) const\n\t{\n\t\treturn !(*this == other);\n\t}\n\tbool operator < (const TServiceId8 &other) const\n\t{\n\t\treturn _ServiceId < other._ServiceId;\n\t}\n\n\t/// Getter, return the integer value of the service id\n\tuint8 get()\tconst\t\t{\treturn _ServiceId;}\n\t/// Setter, set the value of the service id\n\tvoid set(uint8 sid)\t\t{\t_ServiceId = sid;}\n\n\tvoid serial(NLMISC::IStream &s)\n\t{\n\t\ts.serial(_ServiceId);\n\t}\n\n\tstd::string toString() const\n\t{\n\t\treturn NLMISC::toString(_ServiceId);\n\t}\n\n\tbool fromString(const std::string &str)\n\t{\n\t\treturn NLMISC::fromString(str, _ServiceId);\n\t}\n};\n\n\n\n/** Callback function type for service up/down processing\n * \\param serviceName name of the service that is un/registered to the naming service\n * \\param arg a pointer initialized by the user\n */\ntypedef void (*TUnifiedNetCallback) (const std::string &serviceName, TServiceId sid, void *arg);\n\n/** Callback function type for message processing\n * \\param msgin message received\n * \\param serviceName name of the service that sent the message\n * \\param sid id of the service that sent the message\n */\ntypedef void (*TUnifiedMsgCallback) (CMessage &msgin, const std::string &serviceName, TServiceId sid);\n\n/// Callback items. See CMsgSocket::update() for an explanation on how the callbacks are called.\nstruct TUnifiedCallbackItem\n{\n\t/// Key C string. It is a message type name, or \"C\" for connection or \"D\" for disconnection\n\tconst char\t\t\t*Key;\n\t/// The callback function\n\tTUnifiedMsgCallback\tCallback;\n\n};\n\n/**\n * Layer 5\n *\n * When calling send(), a message is stored in a queue. It will be effectively sent\n * when a flush is done. By default, the variable FlushSendsBeforeSleep is on so that\n * the message is sent in the same update cycle as the send() call. If FlushSendsBeforeSleep\n * is set to off, more messages will be sent together, but with a greater delay.\n *\n * Handling network congestion:\n * When a destination service is not fast enough to process the incoming messages,\n * the uploading stream can get saturated. As a result, a single flush will not manage to send the\n * entire data at a time. The NeL Network Layer 5 will silently continue streaming up the remaining\n * parts of the unsent data, as long as update() is called evenly.\n * More in depth:\n * - Either let the layer 5 handle network congestions. If the destination service is slow or\n * stuck and the source service still has data to send, the delivery may be delayed for a long\n * time. If your source service is shut down (calling release()) while some data is still pending,\n * a call to release(true) may take a while or even not exit while the destination service is stuck.\n * - Or handle yourself network congestions by calling tryFlushAllQueues() multiple times. Then you can display\n * the progression of sending, abort it if too long, etc.\n *\n * \\author Vianney Lecroart, Benjamin Legros, Olivier Cado\n * \\author Nevrax France\n * \\date 2002-2004\n */\nclass CUnifiedNetwork : public NLMISC::ICommandsHandler\n{\n\tNLMISC_SAFE_SINGLETON_DECL_PTR(CUnifiedNetwork);\n\npublic:\n\n\tvirtual const std::string &getCommandHandlerName() const\n\t{\n\t\tstatic const std::string name(\"unifiedNetwork\");\n\n\t\treturn name;\n\t}\n\n\n\t/** Returns the singleton instance of the CUnifiedNetwork class.\n\t */\n//\tstatic CUnifiedNetwork *getInstance ();\n\n\t/** Returns true if the application called getInstance(). This function is used to know if the user is using layer 4 or layer 5\n\t */\n\tstatic bool isUsed ();\n\n\t/** Creates the connection to the Naming Service.\n\t * If the connection failed, ESocketConnectionFailed exception is generated.\n\t * This function is called automatically called by the service class at the beginning.\n\t *\n\t * \\param addr address of the naming service (0 is you don't want to use the naming service)\n\t * \\param rec recording state to know if we have to record or replay messages\n\t * \\return false if the instance startup was denied by the naming service\n\t */\n\tbool\tinit (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec, const std::string &shortName, uint16 port, TServiceId &sid );\n\n\t/** Registers to the Naming Service, and connects to the present services\n\t */\n\tvoid\tconnect();\n\n\t/** Closes the connection to the naming service, every other connection and free.\n\t * \\param mustFlushSendQueues If true, all send queues or only queues in namesOfOnlyServiceToFlushSending\n\t * will be really sent before disconnecting. In some cases disconnect(true) can take a while.\n\t * \\param namesOfOnlyServiceToFlushSending When mustFlushSendQueues is true, this param can hold\n\t * a list of service short names. Only the send queues to the services specified\n\t * will be flushed (and waited) at exit. If the list is empty (and mustFlushSendQueues is true),\n\t * all the queues will be flushed (and waited).\n\t * See also \"Handling network congestion\" in CUnifiedNetwork above comments, and tryFlushAllQueues().\n\t */\n\tvoid\trelease (bool mustFlushSendQueues=true, const std::vector<std::string>& namesOfOnlyServiceToFlushSending=std::vector<std::string>() );\n\n\t/** Adds a specific service to the list of connected services.\n\t *\n\t * If the connection succeeds immediately (i.e. the specified service is already online),\n\t * service up callbacks (for this service and for \"*\") will be called from within addService().\n\t * If the service is not available, the connection will be attempted evently in a background thread.\n\t * Then when it will become available, the service up callbacks will be called.\n\t *\n\t * Warning: currently, this method must not be called within a network callback.\n\t */\n\tvoid\taddService(const std::string &name, const CInetAddress &addr, bool sendId = true, bool external = true, TServiceId sid=TServiceId(), bool autoRetry = true, bool shouldBeAlreayInserted = false);\n\tvoid\taddService(const std::string &name, const std::vector<CInetAddress> &addr, bool sendId = true, bool external = true, TServiceId sid=TServiceId(), bool autoRetry = true, bool shouldBeAlreayInserted = false);\n\n\t/** Adds a callback array in the system. You can add callback only *after* adding the server, the client or the group.\n\t */\n\tvoid\taddCallbackArray (const TUnifiedCallbackItem *callbackarray, sint arraysize);\n\n\t/** Call it evenly. the parameter select the timeout value in seconds for each update. You are absolutely certain that this\n\t * function will not be returns before this amount of time you set.\n\t * If you set the update timeout value higher than 0, all messages in queues will be process until the time is greater than the timeout user update().\n\t * If you set the update timeout value to 0, all messages in queues will be process one time before calling the user update(). In this case, we don't nlSleep(1).\n\t */\n\tvoid\tupdate (NLMISC::TTime timeout = 0);\n\n\t/** Sends a message to a specific serviceName. If there's more than one service with this name, all services of this name will receive the message.\n\t * \\param serviceName name of the service you want to send the message (may not be unique.)\n\t * \\param msg the message you want to send.\n\t * \\param nid Network Id specify to which network the message must pass throw (0xFF mean the default network)\n\t * \\return the number of service instances found (may be counter even if the sending failed)\n\t */\n\tuint\tsend (const std::string &serviceName, const CMessage &msg, bool warnIfNotFound=true, uint8 nid=0xFF);\n\n\t/** Sends a message to a specific serviceId.\n\t * \\param serviceId Id of the service you want to send the message.\n\t * \\param msg the message you want to send.\n\t * \\param nid Network Id specify to which network the message must pass throw (0xFF mean the default network)\n\t * \\return true if the service was found (may return true even if the sending failed)\n\t */\n\tbool\tsend (TServiceId serviceId, const CMessage &msg, uint8 nid=0xFF);\n\n\t/** Broadcasts a message to all connected services.\n\t * \\param msg the message you want to send.\n\t * \\param nid Network Id specify to which network the message must pass throw (0xFF mean the default network)\n\t */\n\tvoid\tsendAll (const CMessage &msg, uint8 nid=0xFF);\n\n\t/** Flush all or part of the sending queues, and report the number of bytes still pending.\n\t * To ensure manually all data are sent before stopping a service, you may want\n\t * to repeat calling this method evenly until it returns 0. The default release(false) of\n\t * CUnifiedNetwork only flushes each connection once, but if the network is\n\t * congested (when there are big streams to send) the first flush may not\n\t * succeed to send entire buffers.\n\t * \\param namesOfOnlyServiceToFlushSending If not empty, only the send queues to the\n\t * services specified (by short name) will be flushed.\n\t * See also \"Handling network congestion\" in CUnifiedNetwork above comments.\n\t */\n\tuint\ttryFlushAllQueues(const std::vector<std::string>& namesOfOnlyServiceToFlushSending=std::vector<std::string>());\n\n\t/** Sets callback for incoming connections.\n\t * On a client, the callback will be called when the connection to the server is established (the first connection or after the server shutdown and started)\n\t * On a server, the callback is called each time a new client is connected to him\n\t *\n\t * You can set more than one callback, each one will be called one after one.\n\t * If the serviceName is \"*\", the callback will be call for any services, including 'external' services\n\t * (i.e. services not in the NS address space, usually connected by calling addService() manually)\n\t * If you set the same callback for a specific service S and for \"*\", the callback might be\n\t * called twice (in case the service S is up)\n\t *\n\t * \\param back if true, put the callback at the end of the callback array, otherwise but on the beginning. You should always use true\n\t */\n\tvoid\tsetServiceUpCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0, bool back=true);\n\n\t/** Remove a service up callback */\n\tvoid\tremoveServiceUpCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0);\n\n\t/** Sets callback for disconnections.\n\t * On a client, the callback will be call each time the connection to the server is lost.\n\t * On a server, the callback is called each time a client is disconnected.\n\t *\n\t * You can set more than one callback, each one will be called one after one.\n\t * If the serviceName is \"*\", the callback will be call for any services, including 'external' services\n\t * (i.e. services not in the NS address space, usually connected by calling addService() manually)\n\t * If you set the same callback for a specific service S and for \"*\", the callback might be\n\t * called twice (in case the service S is down)\n\t *\n\t * \\param back if true, put the callback at the end of the callback array, otherwise but on the beginning. You should always use true\n\t */\n\tvoid\tsetServiceDownCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0, bool back=true);\n\n\t/** Remove a service down callback */\n\tvoid\tremoveServiceDownCallback (const std::string &serviceName, TUnifiedNetCallback cb, void *arg = 0);\n\n\t/** Associate a string with a network id\n\t * If the send don't set a specific nid, it ll use the 0, so be sure that the nid 0 is set to a network.\n\t * You must call this function before the connect() function.\n\t * \\param networkName must be in a xxx.xxx.xxx.xxx format. The low value will be ignore depending of the network class.\n\t * \\param nid a number (used as an index in a vector for constant access so numbers should be contiguous) that will be use to send to this network.\n\t */\n\tvoid\taddNetworkAssociation (const std::string &networkName, uint8 nid);\n\n\t/** Clear all network association */\n\tvoid\tclearNetworkAssociation () { _NetworkAssociations.clear (); }\n\n\t/** This array says to which network we need to send the message for the default nid.\n\t * For example you can says that message for AES will use the network 0 and message for LS will use the network 1.\n\t * To do that, just call the function with string \"AES0\" and \"LS1\" the number is the nid (look at addNetworkAssociation())\n\t * addNetworkAssociation(\"192.168.0.0\", 0); addNetworkAssociation(\"192.168.1.0\", 1);\n\t * In this case if you send a message to AES with default nid, it'll be send to 192.168.0.x\n\t * In this case if you send a message to LS with default nid, it'll be send to 192.168.1.y\n\t */\n\tvoid\taddDefaultNetwork (const std::string &defnet) { nlinfo (\"HNETL5: Add default network '%s'\", defnet.c_str()); _DefaultNetwork.push_back (defnet); }\n\n\t/// Clear all default network\n\tvoid\tclearDefaultNetwork () { _DefaultNetwork.clear (); }\n\n\t/// Returns true if the sid service is on the same computer than this service\n\tbool\tisServiceLocal (TServiceId sid);\n\n\t/// Returns true if the serviceName service is on the same computer than this service\n\tbool\tisServiceLocal (const std::string &serviceName);\n\n\t/// Return the name of the specified service, or \"\" if not found\n\tstd::string\t\t\tgetServiceName(TServiceId sid);\n\n\t/// Return a string identifying the service, using the format \"NAME-sid\" (or \"sid\" only if not found)\n\tstd::string\t\t\tgetServiceUnifiedName(TServiceId sid);\n\n\t/// \\warning You should not use getNetBase functions because it could have more than one connection to a service and in this case\n\t///          it ll return the first connection\n\n\t/// Gets the CCallbackNetBase of the service\n\tCCallbackNetBase\t*getNetBase(const std::string &name, TSockId &host, uint8 nid=0xFF);\n\n\t/// Gets the CCallbackNetBase of the service\n\tCCallbackNetBase\t*getNetBase(TServiceId sid, TSockId &host, uint8 nid=0xFF);\n\n\t/// Gets the total number of bytes sent\n\tuint64\t\t\t\tgetBytesSent ();\n\n\t/// Gets the total number of bytes received\n\tuint64\t\t\t\tgetBytesReceived ();\n\n\t/// Gets the total number of bytes queued for sending\n\tuint64\t\t\t\tgetSendQueueSize ();\n\n\t/// Gets the total number of bytes queued after receiving\n\tuint64\t\t\t\tgetReceiveQueueSize ();\n\n\t/// Find a callback in the array\n\tTUnifiedMsgCallback findCallback (const std::string &callbackName);\n\n\t/// Return the service ids of the active connections\n\tconst std::vector<TServiceId>&\tgetConnectionList() const { return _UsedConnection; }\n\n\t/// Return the state of the connection (return true if the connection is fully connected)\n\tbool isConnectionConnected(TServiceId sid) const;\n\n\tvoid\t\t\t\tdisplayInternalTables (NLMISC::CLog *log = NLMISC::InfoLog);\n\n\tvoid\t\t\t\tdisplayUnifiedConnection (TServiceId sid, NLMISC::CLog *log = NLMISC::InfoLog)\n\t{\n\t\tgetUnifiedConnection(sid)->display(false, log);\n\t}\n\nprivate:\n\n\t/// A map of service ids, referred by a service name\n\tstruct TNameMappedConnection : public CHashMultiMap<std::string, TServiceId> {};\n\n\t/// A map of callbacks, referred by message name\n\ttypedef std::map<std::string, TUnifiedMsgCallback>\t\t\tTMsgMappedCallback;\n\n\t/// A callback and its user data\n\ttypedef std::pair<TUnifiedNetCallback, void *>\t\t\t\tTCallbackArgItem;\n\n\t/// A map of service up/down callbacks with their user data.\n\ttypedef CHashMap<std::string, std::list<TCallbackArgItem> >\tTNameMappedCallback;\n\n\t/// This may contains a CCallbackClient or a TSockId, depending on which type of connection it is.\n\tclass CUnifiedConnection\n\t{\n\tpublic:\n\t\t/// NotUsed    = the unified connection is empty, not used\n\t\t/// Ready      = we can use the unified connection\n\t\tenum TState { NotUsed, Ready };\n\n\t\t/// The connection structure\n\t\tstruct TConnection\n\t\t{\n\t\t\t/// If the current service is connect to the other service as a server or a client\n\t\t\tbool\t\t\t\t IsServerConnection;\n\t\t\t/// If it s a client connection, it's the client connection otherwise it s the server connection\n\t\t\tCCallbackNetBase\t*CbNetBase;\n\t\t\t/// If it s a server connection, it's the host id, it s InvalidId if it s a client\n\t\t\tTSockId\t\t\t\t HostId;\n\n\t\t\tTConnection() : IsServerConnection(false), CbNetBase(NULL), HostId(InvalidSockId) { }\n\t\t\tTConnection(CCallbackClient *cbc) : IsServerConnection(false), CbNetBase(cbc), HostId(InvalidSockId) { }\n\t\t\tTConnection(CCallbackNetBase *cbnb, TSockId hi) : IsServerConnection(true), CbNetBase(cbnb), HostId(hi) { }\n\n\t\t\tvoid setAppId (uint64 appid) { CbNetBase->getSockId (HostId)->setAppId (appid); }\n\t\t\tuint64 getAppId () { return CbNetBase->getSockId (HostId)->appId (); }\n\n\t\t\tbool valid ()\n\t\t\t{\n\t\t\t\tif(IsServerConnection)\n\t\t\t\t\treturn CbNetBase != 0 && HostId != InvalidSockId;\n\t\t\t\telse\n\t\t\t\t\treturn CbNetBase != 0;\n\t\t\t}\n\n\t\t\tvoid reset ()\n\t\t\t{\n\t\t\t\tif (CbNetBase != 0)\n\t\t\t\t{\n\t\t\t\t\tif (IsServerConnection)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (HostId != InvalidSockId)\n\t\t\t\t\t\t\tCbNetBase->disconnect (HostId);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tCbNetBase->disconnect ();\n\t\t\t\t\t\tdelete CbNetBase;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tCbNetBase = 0;\n\t\t\t\tIsServerConnection = false;\n\t\t\t\tHostId = InvalidSockId;\n\t\t\t}\n\t\t};\n\n\n\t\t/// The name of the service (may not be unique)\n\t\tstd::string\t\t\t\t\tServiceName;\n\t\t/// The id of the service (is unique)\n\t\tTServiceId\t\t\t\t\tServiceId;\n\t\t/// If the service entry is used\n\t\tTState\t\t\t\t\t\tState;\n\t\t/// If the connection is extern to the naming service\n\t\tbool\t\t\t\t\t\tIsExternal;\n\t\t/// Auto-retry mode\n\t\tbool\t\t\t\t\t\tAutoRetry;\n\t\t/// Valid External\n\t\tbool\t\t\t\t\t\tValidExternal;\n\t\t/// Validation Requested\n\t\tbool\t\t\t\t\t\tValidRequested;\n\t\t/// Auto identify at connection\n\t\tbool\t\t\t\t\t\tSendId;\n\t\t/// Used for debug purpose\n\t\tuint\t\t\t\t\t\tAutoCheck;\n\t\t/// The external connection address\n\t\tstd::vector<CInetAddress>\tExtAddress;\n\t\t/// Connection to the service (me be > 1)\n\t\tstd::vector<TConnection>\tConnections;\n\t\t/// This is used to associate a nid (look addNetworkAssociation) with a TConnection.\n\t\tstd::vector<uint8>\t\t\tNetworkConnectionAssociations;\n\t\t/// This contains the connection id that will be used for default network, it's a connection id used for Connection index\n\t\tuint8\t\t\t\t\t\tDefaultNetwork;\n\n\t\tuint32\t\t\t\t\t\tTotalCallbackCalled;\n\n\t\tCUnifiedConnection() { reset(); }\n\n\t\tCUnifiedConnection(const std::string &name, TServiceId id, bool isExternal)\n\t\t{\n\t\t\treset ();\n\t\t\tServiceName = name;\n\t\t\tServiceId = id;\n\t\t\tState = Ready;\n\t\t\tIsExternal = isExternal;\n\t\t}\n\n\t\tCUnifiedConnection(const std::string &name, TServiceId id, CCallbackClient *cbc)\n\t\t{\n\t\t\treset ();\n\t\t\tServiceName = name;\n\t\t\tServiceId = id;\n\t\t\tState = Ready;\n\t\t\tConnections.push_back(TConnection (cbc));\n\t\t}\n\n\t\tvoid display (bool full, NLMISC::CLog *log = NLMISC::InfoLog);\n\n\t\tvoid reset()\n\t\t{\n\t\t\tServiceName = \"DEAD\";\n\t\t\tServiceId = TServiceId(0xDEAD);\n\t\t\tState = NotUsed;\n\t\t\tIsExternal = false;\n\t\t\tValidExternal = false;\n\t\t\tValidRequested = false;\n\t\t\tAutoRetry = false;\n\t\t\tSendId = false;\n\t\t\tAutoCheck = false;\n\t\t\tExtAddress.clear ();\n\t\t\tfor (uint i = 0; i < Connections.size (); i++)\n\t\t\t\tConnections[i].reset();\n\t\t\tConnections.clear ();\n\t\t\tDefaultNetwork = 0xDD;\n\t\t\tNetworkConnectionAssociations.clear();\n\t\t\tTotalCallbackCalled = 0;\n\t\t}\n\n\t\t// this function wrap the global default network and network association with this specific connection because they can have\n\t\t// different index\n\t\tvoid setupNetworkAssociation (const std::vector<uint32> &networkAssociations, const std::vector<std::string> &defaultNetwork)\n\t\t{\n\t\t\tfor (uint i = 0; i < networkAssociations.size (); i++)\n\t\t\t{\n\t\t\t\tuint j;\n\t\t\t\tfor (j = 0; j < ExtAddress.size (); j++)\n\t\t\t\t{\n\t\t\t\t\tif (ExtAddress[j].internalNetAddress() == networkAssociations[i])\n\t\t\t\t\t{\n\t\t\t\t\t\t// we found an association, add it\n\t\t\t\t\t\tif (i >= NetworkConnectionAssociations.size ())\n\t\t\t\t\t\t\tNetworkConnectionAssociations.resize (i+1);\n\n\t\t\t\t\t\tNetworkConnectionAssociations[i] = uint8(j);\n\t\t\t\t\t\tnlinfo (\"HNETL5: nid %u will be use connection %u\", i, j);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (j == ExtAddress.size ())\n\t\t\t\t{\n\t\t\t\t\tnlinfo (\"HNETL5: nid %u is not found\", i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// find the default network\n\t\t\tstd::vector<std::string>::size_type j;\n\t\t\tfor (j = 0; j < defaultNetwork.size (); j++)\n\t\t\t{\n\t\t\t\tstd::string::size_type pos = defaultNetwork[j].find(ServiceName);\n\t\t\t\tif (pos != std::string::npos && pos == 0 && ServiceName.size() == defaultNetwork[j].size ()-1)\n\t\t\t\t{\n\t\t\t\t\tuint8 nid = defaultNetwork[j][defaultNetwork[j].size ()-1] - '0';\n\t\t\t\t\tDefaultNetwork = NetworkConnectionAssociations[nid];\n\t\t\t\t\tnlinfo (\"HNETL5: default network for '%s' will be nid %hu and connection id %hu\", ServiceName.c_str(), (uint16)nid, (uint16)DefaultNetwork);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (j == defaultNetwork.size ())\n\t\t\t{\n\t\t\t\tif (NetworkConnectionAssociations.size ()>0)\n\t\t\t\t\tDefaultNetwork = NetworkConnectionAssociations[0];\n\t\t\t\telse\n\t\t\t\t\tDefaultNetwork = 0;\n\n\t\t\t\tif (defaultNetwork.size () > 0)\n\t\t\t\t\tnlwarning (\"HNETL5: default network not found in the array, will use connection id %hu\", (uint16)DefaultNetwork);\n\t\t\t}\n\t\t}\n\t};\n\n\tNLMISC_COMMAND_HANDLER_TABLE_BEGIN(CUnifiedNetwork)\n\t\tNLMISC_COMMAND_HANDLER_ADD(CUnifiedNetwork, addService, \"Add a service in the unified network\", \"<serviceName> ( address=<address:port> [sid=<serviceId>] [sendId] [external] [autoRetry] )\")\n\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\tNLMISC_CLASS_COMMAND_DECL(addService);\n\nprotected:\n\n\t/// Auto-reconnect\n\tvoid\t\t\t\tautoReconnect( CUnifiedConnection &uc, uint connectionIndex );\n\n#ifdef NL_OS_UNIX\n\t/// Sleep (implemented by select())\n\tvoid\t\t\t\tsleepUntilDataAvailable( NLMISC::TTime msecMax );\n#endif\n\nprivate:\n\n\t/// Vector of connections by service id (sid is the entry in this array, it means that there s some hole)\n\tstd::vector<CUnifiedConnection>\t\t\t\t_IdCnx\t;\n\n\t/// Vector of closed connection to reset outside of the client update loop\n\tstd::vector<TServiceId>\t\t\t\t\t\t_ConnectionToReset;\n\n\t/// This vector contains only an index to the unified connection. It is used to have quick access on the available connections\n\tstd::vector<TServiceId>\t\t\t\t\t\t_UsedConnection;\n\n\t/// Map of connections by service name\n\tTNameMappedConnection\t\t\t\t\t\t_NamedCnx;\n\n\t/// The callback server\n\tCCallbackServer\t\t\t\t\t\t\t\t*_CbServer;\n\n\t/// Map of the up/down service callbacks\n\tTNameMappedCallback\t\t\t\t\t\t\t_UpCallbacks;\n\tstd::vector<TCallbackArgItem>\t\t\t\t_UpUniCallback;\n\tTNameMappedCallback\t\t\t\t\t\t\t_DownCallbacks;\n\tstd::vector<TCallbackArgItem>\t\t\t\t_DownUniCallback;\n\n\t/// Recording state\n\tCCallbackNetBase::TRecordingState\t\t\t_RecordingState;\n\n\t/// Service name\n\tstd::string\t\t\t\t\t\t\t\t\t_Name;\n\n\t/// Map of callbacks\n\tTMsgMappedCallback\t\t\t\t\t\t\t_Callbacks;\n\n\t/// The server port\n\tuint16\t\t\t\t\t\t\t\t\t\t_ServerPort;\n\n\t/// Used for external service\n\tTServiceId\t\t\t\t\t\t\t\t\t_ExtSId;\n\n\t/// Last time of retry\n\tNLMISC::TTime\t\t\t\t\t\t\t\t_LastRetry;\n\n\t/// Time of the theoretical next update\n\tNLMISC::TTime\t\t\t\t\t\t\t\t_NextUpdateTime;\n\n\t/// The main instance\n//\tstatic CUnifiedNetwork\t\t\t\t\t\t*_Instance;\n\n\t/// Naming service\n\tNLNET::CInetAddress\t\t\t\t\t\t\t_NamingServiceAddr;\n\n\t/// for each nid, which network address\n\tstd::vector<uint32>\t\t\t\t\t\t\t_NetworkAssociations;\n\n\t/// for each services, which network to take\n\tstd::vector<std::string>\t\t\t\t\t_DefaultNetwork;\n\n#ifdef NL_OS_UNIX\n\t/// Pipe to select() on data available (shared among all connections)\n\tint\t\t\t\t\t\t\t\t\t\t\t_MainDataAvailablePipe [2];\n#endif\n\n\t/// Service id of the running service\n\tTServiceId\t\t\t\t\t\t\t\t\t_SId;\n\n\t/// true if initialization function called\n\tbool\t\t\t\t\t\t\t\t\t\t_Initialised;\n\n\t//\n\tCUnifiedNetwork() :\n\t\tICommandsHandler(),\n\t\t_CbServer(0),\n\t\t_ExtSId(256),\n\t\t_LastRetry(0),\n\t\t_NextUpdateTime(0),\n\t\t_Initialised(false)\n\t{\n\t}\n\n\t~CUnifiedNetwork() {}\n\n\t//\n\tvoid\tautoCheck();\n\n\t// Return the unified connection if available or NULL.\n\t// Don't keep the pointer because it can be invalid if the table is resized.\n\tCUnifiedConnection\t*getUnifiedConnection (TServiceId sid, bool warn=true);\n\n\tbool haveNamedCnx (const std::string &name, TServiceId sid);\n\tvoid addNamedCnx (const std::string &name, TServiceId sid);\n\tvoid removeNamedCnx (const std::string &name, TServiceId sid);\n\n\t// with a sid and a nid, find a good connection to send a message\n\tuint8 findConnectionId (TServiceId sid, uint8 nid);\n\n\tvoid callServiceUpCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback = true);\n\tvoid callServiceDownCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback = true);\n\n\tfriend void\tuncbConnection(TSockId from, void *arg);\n\tfriend void\tuncbDisconnection(TSockId from, void *arg);\n\tfriend void\tuncbServiceIdentification(CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\tfriend void\tuncbMsgProcessing(CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\tfriend void\tuNetRegistrationBroadcast(const std::string &name, TServiceId sid, const std::vector<CInetAddress> &addr);\n\tfriend void\tuNetUnregistrationBroadcast(const std::string &name, TServiceId sid, const std::vector<CInetAddress> &addr);\n\tfriend struct nel_isServiceLocalClass;\n\tfriend struct nel_l5CallbackClass;\n\tfriend struct nel_l5QueuesStatsClass;\n};\n\n} // NLNET\n\n#endif // NL_UNIFIED_NETWORK_H\n\n/* End of unified_network.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/unitime.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_UNITIME_H\n#define NL_UNITIME_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"callback_net_base.h\"\n\nnamespace NLNET\n{\n\nclass CInetAddress;\nclass CCallbackServer;\nclass CCallbackClient;\n\n/**\n * This class provide a independant universal time system.\n * \\author Vianney Lecroart\n * \\author Nevrax France\n * \\date 2000\n *\n * THIS CLASS IS DEPRECATED, DON'T USE IT\n *\n */\nclass _CUniTime : public NLMISC::CTime\n{\npublic:\n\n\t/// Return the time in millisecond. This time is the same on all computers at the \\b same moment.\n\tstatic NLMISC::TTime\tgetUniTime ();\n\n\t/// Return the time in a string format to be display\n\tstatic const char\t\t*getStringUniTime ();\n\n\t/// Return the time in a string format to be display\n\tstatic const char\t\t*getStringUniTime (NLMISC::TTime ut);\n\n\n\t/** You need to call this function before calling getUniTime or an assert will occured.\n\t * This function will connect to the time service and synchronize your computer.\n\t * This function assumes that all services run on server that are time synchronized with NTP for example.\n\t * If addr is NULL, the function will connect to the Time Service via the Naming Service. In this case,\n\t * the CNamingClient must be connected to a Naming Service.\n\t * This function can be called *ONLY* by services that are inside of the shard.\n\t * Don't use it for a client or a service outside of the shard.\n\t */\n\tstatic void\t\t\t\tsyncUniTimeFromService (CCallbackNetBase::TRecordingState rec=CCallbackNetBase::Off, const CInetAddress *addr = NULL);\n\n\t/** Call this function in the init part of the front end service to enable time syncro between\n\t * shard and clients.\n\t */\n\tstatic void\t\t\t\tinstallServer (CCallbackServer *server);\n\n\t/** Call this functions in the init part of the client side to synchronize between client and shard.\n\t * client is the connection between the client and the front end. The connection must be established before\n\t * calling this function.\n\t */\n\tstatic void\t\t\t\tsyncUniTimeFromServer (CCallbackClient *client);\n\n\t/** \\internal used by the time service to set the universal time the first time\n\t  */\n\tstatic void\t\t\t\tsetUniTime (NLMISC::TTime uTime, NLMISC::TTime lTime);\n\t/** \\internal\n\t  */\n\tstatic void\t\t\t\tsetUniTime (NLMISC::TTime uTime);\n\n\t/**\n\t * Call this method before to prevent syncUniTimeFromService() from real synchronization:\n\t * syncUniTimeFromService() will still communicate with the time service, as usual,\n\t * but the local time will not be synchronized.\n\t */\n\tstatic void\t\t\t\tsimulate() { nlstop; _Simulate = true; }\n\n\tstatic bool\t\t\t\tSync;\t\t\t\t// true if the synchronization occured\nprivate:\n\n\tstatic NLMISC::TTime\t_SyncUniTime;\t\t// time in millisecond when the universal time received\n\tstatic NLMISC::TTime\t_SyncLocalTime;\t\t// time in millisecond when the syncro with universal time occured\n\n\t// If true, do not synchronize\n\tstatic bool\t\t\t\t_Simulate;\n};\n\n} // NLNET\n\n#endif // NL_UNITIME_H\n\n/* End of unitime.h */\n"
  },
  {
    "path": "code/nel/include/nel/net/varpath.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_VARPATH_H\n#define NL_VARPATH_H\n\n#include \"nel/misc/types_nl.h\"\n\nclass CVarPath\n{\npublic:\n\n\tCVarPath (const std::string &raw) : RawVarPath(raw)\n\t{\n\t\tdecode ();\n\t}\n\n\tvoid decode ();\n\n\tstd::vector<std::pair<std::string, std::string> > Destination;\n\n\tvoid display ();\n\n\t/// returns true if there's no more . in the path\n\tbool isFinal ();\n\n\tbool empty ()\n\t{\n\t\treturn Destination.empty();\n\t}\n\nprivate:\n\n\tstd::string getToken ();\n\n\tstd::string RawVarPath;\n\n\tuint32 TokenPos;\n\n};\n\n\n#endif // NL_VARPATH_H\n\n/* End of varpath.h */\n"
  },
  {
    "path": "code/nel/nel-config.in",
    "content": "#!/bin/sh\n\n#\n#\n# nel-config\n#\n# Script printing NeL's install library/include paths and some other\n# informations like NeL's version\n#\n\nprefix=@prefix@\nexec_prefix=@exec_prefix@\n\nlib_dir=\"@libdir@\"\ninclude_dir=\"@includedir@\"\n\nenable_ligo=@enable_ligo@\nenable_georges=@enable_georges@\nenable_net=@enable_net@\nenable_3d=@enable_3d@\nenable_pacs=@enable_pacs@\nenable_sound=@enable_sound@\nenable_logic=@enable_logic@\n\nusage()\n{\n    cat <<EOF\nUsage: nel-config [OPTIONS] [LIBRARIES]\nOptions:\n   [--prefix[=DIR]]\n   [--exec-prefix[=DIR]]\n   [--version]\n   [--libs]\n   [--libtool]\n   [--ldflags]\n   [--cflags]\n   [--without-ligo]\n   [--without-georges]\n   [--without-network]\n   [--without-3d]\n   [--without-pacs]\n   [--without-sound]\n   [--without-logic]\nEOF\n    exit $1\n}\n\nif test $# -eq 0\nthen\n    usage 1 1>&2\nfi\n\nwhile test $# -gt 0\ndo\n    case \"$1\" in\n        -*=*) optarg=`echo \"$1\" | sed 's/[-_a-zA-Z0-9]*=//'` ;;\n        *) optarg= ;;\n    esac\n\n    case $1 in\n        --prefix=*)\n            prefix=$optarg\n            local_prefix=yes\n            ;;\n        --prefix)\n            echo_prefix=yes\n            ;;\n        --exec-prefix=*)\n            exec_prefix=$optarg\n            exec_prefix_set=yes\n            local_prefix=yes\n            ;;\n        --exec-prefix)\n            echo_exec_prefix=yes\n            ;;\n        --version)\n            echo @VERSION@\n            exit 0\n            ;;\n        --cflags)\n            echo_cflags=yes\n            ;;\n        --ldflags)\n            echo_ldflags=yes\n            ;;\n        --libs)\n            echo_libs=yes\n            ;;\n        --libtool)\n            echo_libtool=yes\n            ;;\n        --without-ligo)\n            without_ligo=yes\n            ;;\n        --without-logic)\n            without_logic=yes\n            ;;\n        --without-georges)\n            without_georges=yes\n            ;;\n        --without-net|--without-network)\n            without_net=yes\n            ;;\n        --without-3d)\n            without_3d=yes\n            ;;\n        --without-pacs)\n            without_pacs=yes\n            ;;\n        --without-snd|--without-sound)\n            without_sound=yes\n            ;;\n        *)\n            usage 1 1>&2\n            ;;\n    esac\n    shift\ndone\n\nif test \"$local_prefix\" = \"yes\"\nthen\n    if test \"$exec_prefix_set\" != \"yes\"\n    then\n        exec_prefix=$prefix\n    fi\nfi\n\nif test \"$echo_prefix\" = \"yes\"\nthen\n    echo $prefix\nfi\n\nif test \"$echo_exec_prefix\" = \"yes\"\nthen\n    echo $exec_prefix\nfi\n\nif test \"$echo_cflags\" = \"yes\"\nthen\n    cflags=\"-I$include_dir\"\n    echo $cflags\nfi\n\nif test \"$echo_ldflags\" = \"yes\"\nthen\n    ldflags=\"-L$lib_dir\"\n    echo $ldflags\nfi\n\nif test \"$echo_libs\" = \"yes\"\nthen\n    lib_misc=\"-lnelmisc\"\n    lib_ligo=\"-lnelligo\"\n    lib_logic=\"-lnellogic\"\n    lib_georges=\"-lnelgeorges\"\n    lib_net=\"-lnelnet\"\n    lib_3d=\"-lnel3d\"\n    lib_pacs=\"-lnelpacs\"\n    lib_sound=\"-lnelsound -lnelsnd_lowlevel\"\n    lib_ai=\"-lnelai\"\n\n    libs=\"$lib_misc\"\n\n    if test \"$without_ligo\" != \"yes\" -a '(' \"$enable_ligo\" = \"yes\" -o \"$enable_ligo\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_ligo\"\n    fi\n\n    if test \"$without_logic\" != \"yes\" -a '(' \"$enable_logic\" = \"yes\" -o \"$enable_logic\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_logic\"\n    fi\n\n    if test \"$without_georges\" != \"yes\" -a '(' \"$enable_georges\" = \"yes\" -o \"$enable_georges\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_georges\"\n    fi\n\n    if test \"$without_net\" != \"yes\" -a '(' \"$enable_net\" = \"yes\" -o \"$enable_net\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_net\"\n    fi\n\n    if test \"$without_3d\" != \"yes\" -a '(' \"$enable_3d\" = \"yes\" -o \"$enable_3d\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_3d\"\n    fi\n\n    if test \"$without_pacs\" != \"yes\" -a '(' \"$enable_pacs\" = \"yes\" -o \"$enable_pacs\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_pacs\"\n    fi\n\n    if test \"$without_sound\" != \"yes\" -a '(' \"$enable_sound\" = \"yes\" -o \"$enable_sound\" = \"ON\" ')'\n    then\n        libs=\"$libs $lib_sound\"\n    fi\n\n    echo -L@libdir@ $libs\nfi\n\nif test \"$echo_libtool\" = \"yes\"\nthen\n    libtool_misc=\"$lib_dir/libnelmisc.la\"\n    libtool_ligo=\"$lib_dir/libnelligo.la\"\n    libtool_logic=\"$lib_dir/libnellogic.la\"\n    libtool_georges=\"$lib_dir/libnelgeorges.la\"\n    libtool_net=\"$lib_dir/libnelnet.la\"\n    libtool_3d=\"$lib_dir/libnel3d.la\"\n    libtool_pacs=\"$lib_dir/libnelpacs.la\"\n    libtool_sound=\"$lib_dir/libnelsnd.la\"\n\n    libtool=\"$libtool_misc\"\n\n    if test \"$without_ligo\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_ligo\"\n    fi\n\n    if test \"$without_logic\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_logic\"\n    fi\n\n    if test \"$without_georges\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_georges\"\n    fi\n\n    if test \"$without_net\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_net\"\n    fi\n\n    if test \"$without_3d\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_3d\"\n    fi\n\n    if test \"$without_pacs\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_pacs\"\n    fi\n\n    if test \"$without_sound\" != \"yes\"\n    then\n        libtool=\"$libtool $libtool_sound\"\n    fi\n\n    echo $libtool\nfi\n\n# EOF\n\n"
  },
  {
    "path": "code/nel/samples/CMakeLists.txt",
    "content": "ADD_SUBDIRECTORY(misc)\n\nIF(WITH_GEORGES)\n  ADD_SUBDIRECTORY(georges)\nENDIF(WITH_GEORGES)\n\nIF(WITH_NET)\n  ADD_SUBDIRECTORY(net)\nENDIF(WITH_NET)\n\n"
  },
  {
    "path": "code/nel/samples/georges/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_georges ${SRC})\n\nADD_DEFINITIONS(-DGF_DIR=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_georges/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_georges nelgeorges nelmisc)\nNL_DEFAULT_PROPS(nl_sample_georges \"NeL, Samples: Georges\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_georges)\n\nINSTALL(TARGETS nl_sample_georges RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesgeorges)\nINSTALL(FILES boolean.typ coolfilesinfo.dfn default.sample_config int.typ positiondata.dfn sample_config.dfn string.typ sheet_id.bin\n\tDESTINATION ${NL_SHARE_PREFIX}/nl_sample_georges/ COMPONENT samplesgeorges)\n"
  },
  {
    "path": "code/nel/samples/georges/boolean.typ",
    "content": "<?xml version=\"1.0\"?>\n<TYPE Type=\"String\" UI=\"NonEditableCombo\" Default=\"false\">\n  <DEFINITION Label=\"true\" Value=\"true\"/>\n  <DEFINITION Label=\"false\" Value=\"false\"/>\n</TYPE>\n"
  },
  {
    "path": "code/nel/samples/georges/coolfilesinfo.dfn",
    "content": "<?xml version=\"1.0\"?>\n<DFN>\n  <ELEMENT Name=\"Name\" Type=\"Type\" Filename=\"string.typ\"/>\n  <ELEMENT Name=\"ShortName\" Type=\"Type\" Filename=\"string.typ\"/>\n  <ELEMENT Name=\"Ranking\" Type=\"Type\" Filename=\"int.typ\" Default=\"101\"/>\n  <ELEMENT Name=\"TopTenRanking\" Type=\"Type\" Filename=\"int.typ\" Default=\"11\"/>\n</DFN>"
  },
  {
    "path": "code/nel/samples/georges/default.sample_config",
    "content": "<?xml version=\"1.0\"?>\n<FORM Version=\"0.0\" State=\"modified\">\n  <STRUCT>\n    <ATOM Name=\"TestVal1\" Value=\"1\"/>\n    <ATOM Name=\"TestVal2\" Value=\"2\"/>\n    <ATOM Name=\"WriteVal\" Value=\"4\"/>\n    <ARRAY Name=\"TestArray\">\n      <ATOM Value=\"Array Val 1\"/>\n      <ATOM Value=\"Array Val 2\"/>\n    </ARRAY>\n    <ARRAY Name=\"CoolFilesInfo\">\n      <STRUCT>\n        <ATOM Name=\"Name\" Value=\"Tiger Eats Man In One Bite\"/>\n        <ATOM Name=\"ShortName\" Value=\"Tiger Attack\"/>\n        <ATOM Name=\"Ranking\" Value=\"55\"/>\n        <ATOM Name=\"TopTenRanking\" Value=\"9\"/>\n      </STRUCT>\n      <STRUCT>\n        <ATOM Name=\"Name\" Value=\"Tiny Car Jumps Bridge Over River\"/>\n        <ATOM Name=\"ShortName\" Value=\"Crazy Car Jump\"/>\n        <ATOM Name=\"Ranking\" Value=\"40\"/>\n        <ATOM Name=\"TopTenRanking\" Value=\"5\"/>\n      </STRUCT>\n      <STRUCT>\n        <ATOM Name=\"Name\" Value=\"Nevrax Presents Cool Open Source Contributors Awards\"/>\n        <ATOM Name=\"ShortName\" Value=\"Nevrax Gives Awards\"/>\n        <ATOM Name=\"Ranking\" Value=\"1\"/>\n        <ATOM Name=\"TopTenRanking\" Value=\"1\"/>\n      </STRUCT>\n    </ARRAY>\n    <ARRAY Name=\"TestByBracket\">\n      <ATOM Value=\"true\"/>\n      <ATOM Value=\"false\"/>\n    </ARRAY>\n    <STRUCT Name=\"PositionData\">\n      <ATOM Name=\"x\" Value=\"1\"/>\n      <ATOM Name=\"y\" Value=\"1\"/>\n      <ATOM Name=\"z\" Value=\"2\"/>\n    </STRUCT>\n  </STRUCT>\n  <STRUCT/>\n  <STRUCT/>\n  <STRUCT/>\n  <STRUCT/>\n</FORM>\n"
  },
  {
    "path": "code/nel/samples/georges/int.typ",
    "content": "<?xml version=\"1.0\"?>\n<TYPE Type=\"SignedInt\" UI=\"EditSpin\" Default=\"0\" Min=\"-9223372036854775808\" Max=\"9223372036854775807\">\n</TYPE>\n"
  },
  {
    "path": "code/nel/samples/georges/log.log",
    "content": "\nLog Starting [2012/12/08 11:03:34]\n2012/12/08 11:03:34 INF  c24 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath(\"../share/nel/nl_sample_georges/\", not recursive, not alternative): '\"../share/nel/nl_sample_georges/\"' is not a directory, I'll call addSearchFile()\n2012/12/08 11:03:34 WRN  c24 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile(\"../share/nel/nl_sample_georges/\", 0, ''): '\"../share/nel/nl_sample_georges/\"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges'\n2012/12/08 11:04:44 WRN  c24 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar).\n2012/12/08 11:04:44 WRN  c24 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar).\n2012/12/08 11:04:56 INF  c24 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1\n2012/12/08 11:04:56 INF  c24 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2\n2012/12/08 11:04:57 INF  c24 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false\n2012/12/08 11:04:58 INF  c24 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2\n2012/12/08 11:05:00 INF  c24 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true\n2012/12/08 11:05:02 INF  c24 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1\n2012/12/08 11:05:03 INF  c24 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9)\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5)\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1)\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1\n2012/12/08 11:05:18 INF  c24 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump\n2012/12/08 11:05:21 INF  c24 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form.\n2012/12/08 11:06:04 INF  c24 nl_sample_georges.exe main.cpp 293 main : Saved sample config file.\n2012/12/08 11:06:22 INF  c24 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets.\n2012/12/08 11:07:27 WRN  c24 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory\n2012/12/08 11:07:28 INF  c24 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets'\n2012/12/08 11:07:32 INF  c24 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?)\n2012/12/08 11:07:42 INF  c24 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?))\n2012/12/08 11:08:57 INF  c24 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0\n2012/12/08 11:10:17 INF  c24 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin\n2012/12/08 11:10:20 INF  c24 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist\n2012/12/08 11:10:20 DBG  c24 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read\n2012/12/08 11:10:20 WRN  c24 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs_sheets.packed_sheets', error 2 : No such file or directory\n2012/12/08 11:10:20 INF  c24 nl_sample_georges.exe common.cpp 573 NLMISC::Exception::Exception : Exception will be launched: can't open PackedSheet sample_configs_sheets.packed_sheets\n2012/12/08 11:10:20 INF  c24 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (can't open PackedSheet sample_configs_sheets.packed_sheets)\n2012/12/08 11:10:21 INF  c24 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0\n\nLog Starting [2012/12/08 11:20:24]\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath(\"../share/nel/nl_sample_georges/\", not recursive, not alternative): '\"../share/nel/nl_sample_georges/\"' is not a directory, I'll call addSearchFile()\n2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile(\"../share/nel/nl_sample_georges/\", 0, ''): '\"../share/nel/nl_sample_georges/\"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges'\n2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar).\n2012/12/08 11:20:24 WRN 1320 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar).\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9)\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5)\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1)\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form.\n2012/12/08 11:20:24 INF 1320 nl_sample_georges.exe main.cpp 293 main : Saved sample config file.\n2012/12/08 11:20:25 INF 1320 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets.\n2012/12/08 11:20:26 WRN 1320 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory\n2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets'\n2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?)\n2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?))\n2012/12/08 11:20:26 INF 1320 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0\n2012/12/08 11:22:18 INF 1320 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin\n2012/12/08 11:23:26 INF 1320 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist\n2012/12/08 11:23:26 DBG 1320 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read\n2012/12/08 11:23:31 INF 1320 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: In Stream: sample_configs_sheets.packed_sheets: Invalid data format\n\nLog Starting [2012/12/08 13:32:04]\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath(\"../share/nel/nl_sample_georges/\", not recursive, not alternative): '\"../share/nel/nl_sample_georges/\"' is not a directory, I'll call addSearchFile()\n2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile(\"../share/nel/nl_sample_georges/\", 0, ''): '\"../share/nel/nl_sample_georges/\"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges'\n2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar).\n2012/12/08 13:32:04 WRN 1028 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar).\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9)\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5)\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1)\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form.\n2012/12/08 13:32:04 INF 1028 nl_sample_georges.exe main.cpp 293 main : Saved sample config file.\n2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets.\n2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets'\n2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?)\n2012/12/08 13:32:06 INF 1028 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?))\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file  !\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file yp\u0011 !\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file  !\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file  !\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file  !\n2012/12/08 13:32:06 DBG 1028 nl_sample_georges.exe load_form.h 968 loadForm : Can't find dependent file  !\n2012/12/08 13:32:07 INF 1028 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0\n2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin\n2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist\n2012/12/08 13:33:13 DBG 1028 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read\n2012/12/08 13:33:13 WRN 1028 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs_sheets.packed_sheets', error 2 : No such file or directory\n2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe common.cpp 573 NLMISC::Exception::Exception : Exception will be launched: can't open PackedSheet sample_configs_sheets.packed_sheets\n2012/12/08 13:33:13 INF 1028 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (can't open PackedSheet sample_configs_sheets.packed_sheets)\n2012/12/08 13:33:14 INF 1028 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0\n\nLog Starting [2012/12/08 13:33:32]\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath(\"../share/nel/nl_sample_georges/\", not recursive, not alternative): '\"../share/nel/nl_sample_georges/\"' is not a directory, I'll call addSearchFile()\n2012/12/08 13:33:32 WRN   74 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile(\"../share/nel/nl_sample_georges/\", 0, ''): '\"../share/nel/nl_sample_georges/\"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges'\n2012/12/08 13:33:32 WRN   74 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar).\n2012/12/08 13:33:32 WRN   74 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar).\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9)\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5)\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1)\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form.\n2012/12/08 13:33:32 INF   74 nl_sample_georges.exe main.cpp 293 main : Saved sample config file.\n2012/12/08 13:33:33 INF   74 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets.\n2012/12/08 13:33:33 WRN   74 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory\n2012/12/08 13:33:33 INF   74 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets'\n2012/12/08 13:33:33 INF   74 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?)\n2012/12/08 13:33:33 INF   74 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?))\n2012/12/08 13:33:33 INF   74 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0\n2012/12/08 13:33:35 INF   74 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin\n2012/12/08 13:33:36 INF   74 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read\n2012/12/08 13:33:36 INF   74 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: stream does not contain at least 256 bytes for check\n2012/12/08 13:33:36 INF   74 nl_sample_georges.exe load_form.h 219 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (stream does not contain at least 256 bytes for check)\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file  !\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file yp\u0011 !\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file  !\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file  !\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file  !\n2012/12/08 13:33:36 DBG   74 nl_sample_georges.exe load_form.h 244 loadForm : Can't find dependent file  !\n2012/12/08 13:33:36 INF   74 nl_sample_georges.exe main.cpp 317 main : Number of sheets loaded with CSheetId's: 0\n\nLog Starting [2012/12/08 13:34:04]\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe path.cpp 936 NLMISC::CFileContainer::addSearchPath : PATH: CPath::addSearchPath(\"../share/nel/nl_sample_georges/\", not recursive, not alternative): '\"../share/nel/nl_sample_georges/\"' is not a directory, I'll call addSearchFile()\n2012/12/08 13:34:04 WRN  c18 nl_sample_georges.exe path.cpp 1077 NLMISC::CFileContainer::addSearchFile : PATH: CPath::addSearchFile(\"../share/nel/nl_sample_georges/\", 0, ''): '\"../share/nel/nl_sample_georges/\"' is not found, skip it (current dir is 'D:/ext/server-0/trunk/server/code/nel/samples/georges'\n2012/12/08 13:34:04 WRN  c18 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElm::getInternalNodeByName) on node (.) in form (default.sample_config) : Getting the node (.Foobar) : Struct does not contain element named (Foobar).\n2012/12/08 13:34:04 WRN  c18 nl_sample_georges.exe form.cpp 55 NLGEORGES::warning : NeL::Georges (CFormElmStruct::getValueByName) on node () in form (default.sample_config) : Can't find the node (.Foobar).\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 180 main : Test Value 1: 1\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 181 main : Test Value 2: 2\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 182 main : Foo Retrieval was: false\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 189 main : Retrieved Position Data (x,y,z): 1, 1, 2\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 195 main : TestArray retrieval returned: true\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 1\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 210 main : Found TestArray atom: Array Val 2\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 223 main : Retrieving CoolFilesInfo returned: true\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 0: |Tiger Eats Man In One Bite| - Tiger Attack at 55 (9)\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 1: |Tiny Car Jumps Bridge Over River| - Crazy Car Jump at 40 (5)\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 244 main : Retrieved struct 2: |Nevrax Presents Cool Open Source Contributors Awards| - Nevrax Gives Awards at 1 (1)\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 258 main : Bool Backet 1: true, Bool Bracket 2: false\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 267 main : Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: 1\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 268 main : Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: Crazy Car Jump\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 286 main : Updated WriteVal, it already existed in the form.\n2012/12/08 13:34:04 INF  c18 nl_sample_georges.exe main.cpp 293 main : Saved sample config file.\n2012/12/08 13:34:05 INF  c18 nl_sample_georges.exe main.cpp 310 main : Begin loading packed sheets.\n2012/12/08 13:34:05 WRN  c18 nl_sample_georges.exe file.cpp 265 NLMISC::CIFile::open : Failed to open file 'sample_configs.packed_sheets', error 2 : No such file or directory\n2012/12/08 13:34:05 INF  c18 nl_sample_georges.exe load_form.h 878 loadForm : loadForm(): Loading packed file 'sample_configs.packed_sheets'\n2012/12/08 13:34:05 INF  c18 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: Read error in file 'sample_configs.packed_sheets' (End of file?)\n2012/12/08 13:34:05 INF  c18 nl_sample_georges.exe load_form.h 943 loadForm : loadForm(): Exception during reading the packed file, I'll reconstruct it (Read error in file 'sample_configs.packed_sheets' (End of file?))\n2012/12/08 13:34:06 INF  c18 nl_sample_georges.exe main.cpp 312 main : Number of sheets loaded: 0\n2012/12/08 13:34:06 INF  c18 nl_sample_georges.exe main.cpp 315 main : Load packed sheets using CSheetId and the sheet_id.bin\n2012/12/08 13:34:27 INF  c18 nl_sample_georges.exe sheet_id.cpp 195 NLMISC::CSheetId::loadSheetId : SHEETID: Removed 2 files on 2 from CSheetId because these files don't exist\n2012/12/08 13:34:27 DBG  c18 nl_sample_georges.exe sheet_id.cpp 274 NLMISC::CSheetId::loadSheetId : Finished loading sheet_id.bin: 0 entries read\n2012/12/08 13:35:05 INF  c18 nl_sample_georges.exe common.cpp 567 NLMISC::Exception::Exception : Exception will be launched: stream does not contain at least 256 bytes for check\n"
  },
  {
    "path": "code/nel/samples/georges/main.cpp",
    "content": "/**\n * \\file main.cpp\n * \\date October 2004\n * \\author Matt Raykowski\n *\n * This sample shows how to load a Georges form and read parts from it.\n */\n\n// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// System Includes\n//\n#include <stdio.h>\n\n//\n// NeL Includes\n//\n#include \"nel/misc/debug.h\"\n\n#include \"nel/georges/u_form_loader.h\"\n#include \"nel/georges/u_form.h\"\n#include \"nel/georges/u_form_elm.h\"\n#include \"nel/georges/load_form.h\"\n\n#ifndef GF_DIR\n#       define GF_DIR \".\"\n#endif\n\nstruct TPositionData\n{\n\tuint X, Y, Z;\n\n\t/// This class must be serializable for the form to be packed.\n\tvoid serial(NLMISC::IStream &f)\n\t{\n\t\tf.serial(X);\n\t\tf.serial(Y);\n\t\tf.serial(Z);\n\t}\t\n};\n\nstruct TSampleConfig\n{\n\t/// Load a form, if necessary, and store its data in the members of this class.\n\tvoid readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const NLMISC::CSheetId &sheetId)\n\t{\n\t\treadForm(form);\n\t}\n\n\tvoid readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const std::string &sheetId)\n\t{\n\t\treadForm(form);\n\t}\n\n\tvoid readForm(const NLMISC::CSmartPtr<NLGEORGES::UForm> &form)\n\t{\n\t\tnlinfo(\"Loading a sample config object.\");\n\t\t// The system has already loaded the form and parsed it using a loader. So get the root node:\n\t\tNLGEORGES::UFormElm &root = form->getRootNode();\n\n\t\t// And start loading the form values into the object.\n\t\troot.getValueByName(TestVal1, \".TestVal1\");\n\t\troot.getValueByName(TestVal2, \".TestVal2\");\n\n\t\troot.getValueByName(PosData.X,\"PositionData.x\");\n\t\troot.getValueByName(PosData.Y,\"PositionData.y\");\n\t\troot.getValueByName(PosData.Z,\"PositionData.z\");\n\n\t\t// Get the array called \"TestArray\"\n\t\tNLGEORGES::UFormElm *testArray;\n\t\troot.getNodeByName(&testArray, \".TestArray\");\n\t\tif(testArray != NULL) {\n\t\t\t// Get the size of the array.\n\t\t\tuint size;\n\t\t\ttestArray->getArraySize(size);\n\n\t\t\t// Cycle through the atoms in the array\n\t\t\tfor(uint idx=0 ; idx<size ; idx++) {\n\t\t\t\tstd::string arrayValue;\n\n\t\t\t\t// Get the value of the array.\n\t\t\t\ttestArray->getArrayValue(arrayValue, idx);\n\t\t\t\t// And insert it into our container.\n\t\t\t\tTestArray.push_back(arrayValue);\n\t\t\t}\n\t\t}\n\n\t\t// And so on. We'll skip the rest of the sheet, you get the idea.\n\t\t// ...\n\t}\n\n\t/// This class must be serializable for the form to be packed.\n\tvoid serial(NLMISC::IStream &f)\n\t{\n\t\tf.serial(TestVal1);\n\t\tf.serial(TestVal2);\n\t\tf.serial(PosData);\n\t\tf.serialCont(TestArray);\n\t}\n\n\t/// This is called whenever the loader needs to remove an old sheet.\n\tvoid removed()\n\t{\n\n\t}\n\n\t/// This is used to make sure that changes in form/loader versions are correctly handled. This must be > 0.\n\tstatic uint getVersion() { return 1; }\n\n\tuint32 TestVal1;\n\tuint32 TestVal2;\n\n\tTPositionData PosData;\n\n\tstd::vector<std::string> TestArray;\n};\n\n/// This contains the TSampleConfig sheets.\nstd::map<NLMISC::CSheetId, TSampleConfig> MySampleConfigsSheets;\nstd::map<std::string, TSampleConfig> MySampleConfigs;\n\nint main(void)\n{\n\tnew NLMISC::CApplicationContext;\n\n\t// get a pointer ready for the form loader.\n\tNLGEORGES::UFormLoader *formLoader = NULL;\n\n\tNLMISC::CPath::addSearchPath(GF_DIR, false, false);\n\n\ttry {\n\t\t// set the name of the form you're going to load.\n\t\tstd::string sampleConfigFile = NLMISC::CPath::lookup(\"default.sample_config\", false);\n\n\t\t// check to see if CPath found the config.\n\t\tif (!sampleConfigFile.empty()) {\n\t\t\t// we'll use this to test retrieving vars.\n\t\t\tbool res;\n\n\t\t\t// get a form loader.\n\t\t\tformLoader = NLGEORGES::UFormLoader::createLoader();\n\n\t\t\t// this will hold the form we load - it must be contained in a smart pointer.\n\t\t\tNLMISC::CSmartPtr<NLGEORGES::UForm> form;\n\n\t\t\t// load the form.\n\t\t\tform = formLoader->loadForm(sampleConfigFile.c_str());\n\n\t\t\t// get the root of the form.\n\t\t\tNLGEORGES::UFormElm &root = form->getRootNode();\n\n\t\t\t// retrieve the two test values\n\t\t\tuint32 testVal1, testVal2, badVar1;\n\t\t\troot.getValueByName(testVal1, \".TestVal1\");\n\t\t\troot.getValueByName(testVal2, \".TestVal2\");\n\n\t\t\t// try and get a var that doesn't exist.\n\t\t\tres=root.getValueByName(badVar1, \".Foobar\");\n\t\t\tif(res) {\n\t\t\t\tnlinfo(\"This should never have matched.\");\n\t\t\t\texit(1);\n\t\t\t}\n\n\t\t\t// and output them\n\t\t\tnlinfo(\"Test Value 1: %d\",testVal1);\n\t\t\tnlinfo(\"Test Value 2: %d\",testVal2);\n\t\t\tnlinfo(\"Foo Retrieval was: %s\", res ? \"true\" : \"false\");\n\n\t\t\t// Retrieve data from a root-level named struct\n\t\t\tuint xTest, yTest, zTest;\n\t\t\troot.getValueByName(xTest,\"PositionData.x\");\n\t\t\troot.getValueByName(yTest,\"PositionData.y\");\n\t\t\troot.getValueByName(zTest,\"PositionData.z\");\n\t\t\tnlinfo(\"Retrieved Position Data (x,y,z): %d, %d, %d\",xTest,yTest,zTest);\n\n\t\t\t// get a reference to the TestArray array...\n\t\t\tNLGEORGES::UFormElm *testArray;\n\t\t\tres=root.getNodeByName(&testArray, \".TestArray\");\n\n\t\t\tnlinfo(\"TestArray retrieval returned: %s\", res ? \"true\" : \"false\");\n\t\t\t// make sure it was there.\n\t\t\tif(testArray != NULL) {\n\t\t\t\t// get the size of the array.\n\t\t\t\tuint size;\n\t\t\t\ttestArray->getArraySize(size);\n\n\t\t\t\t// cycle through the atoms in the array\n\t\t\t\tfor(uint idx=0 ; idx<size ; idx++) {\n\t\t\t\t\t// string to store our array values in.\n\t\t\t\t\tstd::string arrayValue;\n\n\t\t\t\t\t// and get the value of the array, we know it's a string.\n\t\t\t\t\ttestArray->getArrayValue(arrayValue, idx);\n\n\t\t\t\t\tnlinfo(\"Found TestArray atom: %s\",arrayValue.c_str());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(res==true)\n\t\t\t\t\tnlinfo(\"TestArray wasn't configured properly but was found, double check the form.\");\n\t\t\t\telse\n\t\t\t\t\tnlinfo(\"Something's wrong, the TestArray is missing from the form.\");\n\t\t\t}\n\n\t\t\t// Next grab a set of structures from an array.\n\t\t\tNLGEORGES::UFormElm *coolFiles;\n\t\t\tres=root.getNodeByName(&coolFiles, \".CoolFilesInfo\");\n\n\t\t\tnlinfo(\"Retrieving CoolFilesInfo returned: %s\", res ? \"true\" : \"false\");\n\t\t\tif(coolFiles != NULL) {\n\t\t\t\tuint size;\n\t\t\t\tcoolFiles->getArraySize(size);\n\n\t\t\t\t// cycle through the structs in the array.\n\t\t\t\tfor(uint idx=0 ; idx<size ; idx++) {\n\t\t\t\t\t// storage for our vars in the structs\n\t\t\t\t\tstd::string name, shortname;\n\t\t\t\t\tuint rank, toptenrank;\n\n\t\t\t\t\t// since we know the structure of the file, we know the array contains structs\n\t\t\t\t\t// retrieve the struct for use.\n\t\t\t\t\tNLGEORGES::UFormElm *files;\n\t\t\t\t\tcoolFiles->getArrayNode(&files, idx);\n\n\t\t\t\t\t// we can now access this struct in the array as a root.\n\t\t\t\t\tfiles->getValueByName(rank, \".Ranking\");\n\t\t\t\t\tfiles->getValueByName(toptenrank, \".TopTenRanking\");\n\t\t\t\t\tfiles->getValueByName(name, \".Name\");\n\t\t\t\t\tfiles->getValueByName(shortname, \".ShortName\");\n\t\t\t\t\tnlinfo(\"Retrieved struct %d: |%s| - %s at %d (%d)\", idx, name.c_str(), shortname.c_str(), rank, toptenrank);\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tif(res==true)\n\t\t\t\t\tnlinfo(\"CoolFilesInfo was found, but might have been entered incorrectly, double check the form.\");\n\t\t\t\telse\n\t\t\t\t\tnlinfo(\"CoolFilesInfo wasn't found or there was a syntax error loading your form.\");\n\t\t\t}\n\n\t\t\t// we can also access elements of an array by their backet identifier.\n\t\t\tstd::string bbool1, bbool2;\n\t\t\troot.getValueByName(bbool1, \".TestByBracket[0]\");\n\t\t\troot.getValueByName(bbool2, \".TestByBracket[1]\");\n\t\t\tnlinfo(\"Bool Backet 1: %s, Bool Bracket 2: %s\",bbool1.c_str(), bbool2.c_str());\n\n\t\t\t// likewise you can access structures by index and dot notation. take the CoolFilesInfo.\n\t\t\t// the following should return 1, the ranking for the Nevrax Presents element.\n\t\t\t// and the 2nd one should return 'Crazy Car Jump' from that element.\n\t\t\tuint rankTest;\n\t\t\tstd::string nameTest;\n\t\t\troot.getValueByName(rankTest, \".CoolFilesInfo[2].Ranking\");\n\t\t\troot.getValueByName(nameTest, \".CoolFilesInfo[1].ShortName\");\n\t\t\tnlinfo(\"Retrieved .CoolFilesInfo[2].Ranking using bracket and dot notation: %d\", rankTest);\n\t\t\tnlinfo(\"Retrieved .CoolFilesInfo[1].ShortName using bracket and dot notation: %s\", nameTest.c_str());\n\n\t\t\t// if you set a value to a node name that doesn't exist, it's created. after running this you will see it listed in the form:\n\t\t\tuint writeValue;\n\n\t\t\t// first lets see if we can find it:\n\t\t\tres=root.getValueByName(writeValue,\".WriteVal\");\n\t\t\tif(res) // if it existed, save the value and increment it.\n\t\t\t\twriteValue++;\n\t\t\telse\n\t\t\t\twriteValue=3;\n\n\t\t\t// now set the value. created tells us if the value was creaed or just updated.\n\t\t\tbool created;\n\t\t\troot.setValueByName(writeValue,\".WriteVal\",&created);\n\t\t\tif(created) {\n\t\t\t\tnlinfo(\"WriteVal wasn't found and was created.\");\n\t\t\t} else {\n\t\t\t\tnlinfo(\"Updated WriteVal, it already existed in the form.\");\n\t\t\t}\n\n\t\t\t// and finally save the form out in case we made changes.\n\t\t\t// if you're accessing a form read-only (not using set*) you can skip this.\n\t\t\tNLMISC::COFile saveSample(sampleConfigFile);\n\t\t\tform->write(saveSample, false);\n\t\t\tnlinfo(\"Saved sample config file.\");\n\t\t} else {\n\t\t\t// CPath didn't find the file, just print an error and exit.\n\t\t\tnlinfo(\"Couldn't find the config file.\");\n\t\t\texit(1);\n\t\t}\n\n\t\t// finished, unload the form loader.\n\t\tNLGEORGES::UFormLoader::releaseLoader(formLoader);\n\n\t} catch(...) {\n\t\t// something went wrong, unload the form loader.\n\t\tnlinfo(\"Caught an exception, quitting.\");\n\t\tNLGEORGES::UFormLoader::releaseLoader(formLoader);\n\t}\n\n\t// Now demonstrate the packed sheet system.\n\tnlinfo(\"Begin loading packed sheets.\");\n\t::loadForm( \"sample_config\", \"sample_configs.packed_sheets\", MySampleConfigs, true, false);\n\tnlinfo(\"Number of sheets loaded: %d\", MySampleConfigs.size());\n\n\t// Now demonstrate the packed sheet system using CSheetId's and the sheet_id.bin file.\n\tnlinfo(\"Load packed sheets using CSheetId and the sheet_id.bin\");\n\t::loadForm( \"sample_config\", \"sample_configs_sheets.packed_sheets\", MySampleConfigsSheets, true, false);\n\tnlinfo(\"Number of sheets loaded with CSheetId's: %d\", MySampleConfigsSheets.size());\n\t\n\t\n}\n"
  },
  {
    "path": "code/nel/samples/georges/positiondata.dfn",
    "content": "<?xml version=\"1.0\"?>\n<DFN>\n\t<ELEMENT Name=\"x\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\" />\n\t<ELEMENT Name=\"y\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\" />\n\t<ELEMENT Name=\"z\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\" />\n</DFN>"
  },
  {
    "path": "code/nel/samples/georges/sample_config.dfn",
    "content": "<?xml version=\"1.0\"?>\n<DFN>\n\t<ELEMENT Name=\"TestVal1\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\"/>\n\t<ELEMENT Name=\"TestVal2\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\"/>\n\t<ELEMENT Name=\"WriteVal\" Type=\"Type\" Filename=\"int.typ\" Default=\"0\" />\n\t<ELEMENT Name=\"TestArray\" Type=\"Type\" Filename=\"string.typ\" Array=\"true\"/>\n\t<ELEMENT Name=\"CoolFilesInfo\" Type=\"Dfn\" Filename=\"coolfilesinfo.dfn\" Array=\"true\"/>\n\t<ELEMENT Name=\"TestByBracket\" Type=\"Type\" Filename=\"boolean.typ\" Array=\"true\"/>\n\t<ELEMENT Name=\"PositionData\" Type=\"Dfn\" Filename=\"positiondata.dfn\" Array=\"false\" />\n</DFN>\n"
  },
  {
    "path": "code/nel/samples/georges/string.typ",
    "content": "<?xml version=\"1.0\"?>\n<TYPE Type=\"String\" UI=\"Edit\" Version=\"0.0\" State=\"modified\">\n  <COMMENTS>Converted from old format</COMMENTS>\n  <LOG>Fri May 17 15:24:33 2002 (corvazier) File converted from old format</LOG>\n</TYPE>"
  },
  {
    "path": "code/nel/samples/misc/CMakeLists.txt",
    "content": "ADD_SUBDIRECTORY(command)\nADD_SUBDIRECTORY(configfile)\nADD_SUBDIRECTORY(debug)\nADD_SUBDIRECTORY(i18n)\nADD_SUBDIRECTORY(log)\nADD_SUBDIRECTORY(strings)\n"
  },
  {
    "path": "code/nel/samples/misc/command/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_command ${SRC})\n\nTARGET_LINK_LIBRARIES(nl_sample_command nelmisc)\nNL_DEFAULT_PROPS(nl_sample_command \"NeL, Samples, Misc: Commands\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_command)\n\nINSTALL(TARGETS nl_sample_command RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/command/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <iostream>\n#include <sstream>\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/log.h\"\n#include \"nel/misc/displayer.h\"\n\n// include the command system\n#include \"nel/misc/command.h\"\n#include \"nel/misc/variable.h\"\n\n\n//\n// Commands\n//\n\n// with this macro, you can execute a specific command in real time.\n// this is an example of a command, the first param is the name of the command\n// (note that it is *not* a string). the second param is the help string that will\n// be displayed when the user calls the help command. the third param is the\n// usage of the command. it can the an empty string when the command doesn't\n// need any parameters.\n// when the program is launched, you can type the name of the command with\n// parameters if needed and it will be executed.\nNLMISC_COMMAND(square,\"display the square of the parameter\",\"<value>\")\n{\n\t// this code will be executed when the user will call this command.\n\t// you have access to some variables:\n\t// - args is a vector of strings. they are the user parameters, you have to\n\t//   check if enough parameters are present and if they are in a good\n\t//   format.\n\t// - log is a CLog object that is used to display the result of the command,\n\t//   if any. see the log example to know how to use CLog.\n\n\t// this function must return true if the command successfully executed\n\t// or false is something wrong happens. for example, if there are not enough\n\t// parameters, return false. \n\n\t// check args, if there is not the right number of parameters, return bad status.\n\tif (args.size() != 1) return false;\n\n\tuint32 val;\n\tNLMISC::fromString(args[0], val);\n\n\t// display the result.\n\tlog.displayNL(\"The square of %d is %d\", val, val*val);\n\n\t// return ok status.\n\treturn true;\n}\n\n//\n// Dummy variables\n//\n\nbool MyVar1;\nuint8 MyVar2;\nsint8 MyVar3;\nuint16 MyVar4;\nsint16 MyVar5;\nuint32 MyVar6;\nsint32 MyVar7;\nuint64 MyVar8;\nsint64 MyVar9;\nstd::string MyVar10;\nucchar MyVar13;\nfloat MyVar14;\ndouble MyVar15;\n\n//\n// Create commands on all variables\n//\n\n// with this macro, you can get or set the variable in real time.\n// this is the easiest way to set or get a variable in real time. you have a direct\n// access to the variable so you can use this macro.\n// first param is the type of the variable. second one is the variable name,\n// and the third one is an help string that describes what the variable does.\n// when the program is executed, you can type the variable name with no parameter\n// to see the value of the variable or type the variable name with one parameter\n// (the value you want to set) to change the variable contents.\nNLMISC_VARIABLE(bool, MyVar1, \"a dummy variable\");\nNLMISC_VARIABLE(uint8, MyVar2, \"a dummy variable\");\nNLMISC_VARIABLE(sint8, MyVar3, \"a dummy variable\");\nNLMISC_VARIABLE(uint16, MyVar4, \"a dummy variable\");\nNLMISC_VARIABLE(sint16, MyVar5, \"a dummy variable\");\nNLMISC_VARIABLE(uint32, MyVar6, \"a dummy variable\");\nNLMISC_VARIABLE(sint32, MyVar7, \"a dummy variable\");\nNLMISC_VARIABLE(uint64, MyVar8, \"a dummy variable\");\nNLMISC_VARIABLE(sint64, MyVar9, \"a dummy variable\");\nNLMISC_VARIABLE(std::string, MyVar10, \"a dummy variable\");\nNLMISC_VARIABLE(ucchar, MyVar13, \"a dummy variable\");\nNLMISC_VARIABLE(float, MyVar14, \"a dummy variable\");\nNLMISC_VARIABLE(double, MyVar15, \"a dummy variable\");\n\n//\n// DynVariable\n//\n\nclass CDynVar\n{\nprivate:\n\tint _PrivateVar;\npublic:\n\tint get() { return _PrivateVar; }\n\tvoid set(int val) { _PrivateVar = val; }\n};\n\nCDynVar dv;\n\n// with this macro, you can get or set the variable in real time.\n// this is an example of dynamic variable. the goal of this macro is to provide an\n// easy way to get or set a variable when you don't have a direct access on this variable.\n// first param is the type of the variable. second one is the name of the variable.\n// the third one is the help string about this variable (what this variable does).\n// when the program is executed, you can type the variable name with no parameter\n// to see the value of the variable or type the variable name with one parameter\n// (the value you want to set) to change the variable contents.\nNLMISC_DYNVARIABLE(int,PrivVar,\"dummy variable\")\n{\n\t// this code will be executed to get or set the variable.\n\t// you have to provide a way to do that.\n\t// the 'get' boolean says if you have to get or set the variable.\n\t// the 'pointer' is a pointer on the variable you have to read or write.\n\t// if 'get' is true, you have to set '*pointer' with the value of your variable.\n\t// if 'get' is false, you have to set your variable with the value of *pointer\n\tif (get)\n\t\t*pointer = dv.get();\n\telse\n\t\tdv.set(*pointer);\n}\n\n\n//\n// Main\n//\n\n// look at the log sample\nNLMISC::CLog mylog;\n// look at the log sample\nNLMISC::CStdDisplayer mysd;\n\nint main (int argc, char **argv)\n{\n\t// look at the debug sample\n\tNLMISC::createDebug();\n\n\t// look at the log sample\n\tmylog.addDisplayer(&mysd);\n\n\tprintf(\"Type a command, 'help' or 'quit'\\n\");\n\n\twhile (true)\n\t{\n\t\t// display prompt\n\t\tstd::cout << \"> \";\n\t\tfflush(stdout);\n\n\t\t// get command line\n\t\tstd::string commandLine;\n\t\tstd::getline(std::cin, commandLine, '\\n');\n\n\t\tif (commandLine == \"quit\")\n\t\t\tbreak;\n\n\t\t// execute the command line. it will try to find the command or the\n\t\t// variable and call the associated code\n\t\tNLMISC::ICommand::execute(commandLine, mylog);\n\t}\n\t\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/configfile/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_configfile ${SRC})\n\nADD_DEFINITIONS(-DNL_SAMPLE_CFG=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_configfile/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_configfile nelmisc)\nNL_DEFAULT_PROPS(nl_sample_configfile \"NeL, Samples, Misc: Config Files\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_configfile)\n\nINSTALL(TARGETS nl_sample_configfile RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\nINSTALL(FILES simpletest.txt DESTINATION ${NL_SHARE_PREFIX}/nl_sample_configfile COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/configfile/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string>\n#include <sstream>\n\n// look at the debug example\n#include \"nel/misc/debug.h\"\n\n// contains the config class\n#include \"nel/misc/config_file.h\"\n\n// contains the cpath class\n#include \"nel/misc/path.h\"\n\n#ifndef NL_SAMPLE_CFG\n#define NL_SAMPLE_CFG \".\"\n#endif // NL_SAMPLE_CFG\n\nusing namespace std;\nusing namespace NLMISC;\n\n// this function will be called when the configfile will be modified by\n// an external program\nvoid mainCallback ()\n{\n\tnlinfo (\"The file was modified by external program!\");\n}\n\n// this function will be called when the variable var12 will be modified by\n// an external program\nvoid var12Callback (CConfigFile::CVar &var)\n{\n\tstringstream str;\n\t\n\tfor (uint i = 0; i < var.size (); i++)\n\t\tstr << var.asInt (i) << \" \";\n\n\tnlinfo(\"%s modified, new value: %s\\n\", var.Name.c_str (), str.str().c_str());\n}\n\n\n// the configfile\nCConfigFile cf;\n\nint main (int /* argc */, char ** /* argv */)\n{\n\n\t// look at the debug example\n\tcreateDebug();\n\n\t// Add the data directory to the search path.\n\tCPath::addSearchPath(NL_SAMPLE_CFG);\n\n\t// load and parse the configfile\n\tcf.load (CPath::lookup(\"simpletest.txt\"));\n\n\t// CConfigFile checks if the config file has been modified by an external program.\n\t// in this case, the configfile automatically reloads and reparses the file.\n\t// you can connect a callback function that will be called in this case if\n\t// you want, for example, reset variables\n\t\n\t// link a callback with this configfile.\n\tcf.setCallback (mainCallback);\n\n\t// link a callback with the var12. If and only if the var12 changed, this\n\t// callback will be called\n\tcf.setCallback (\"var12\", var12Callback);\n\n\t// display all variables\n\tcf.display(InfoLog);\n\n\t// get the value of var1 as int\n\tint var1 = cf.getVar (\"var1\").asInt();\n\tnlinfo(\"var1 (int) = %d\", var1);\n\n\t// get the value of var1 as double, in this case, a conversion from int\n\t// to double will be done\n\tdouble var2 = cf.getVar (\"var1\").asDouble();\n\tnlinfo(\"var1 (double) = %lf\", var2);\n\n\t// get the value of var2 as int, in this case, a conversion from string\n\t// to int will be done\n\tint var3 = cf.getVar (\"var2\").asInt();\n\tnlinfo(\"var2 = %d\", var3);\n\n\t// if the variable is an array of values, you can access them putting the\n\t// index of the variable you want. Example, get and print all value of var12:\n\tfor (uint i = 0; i < cf.getVar (\"var12\").size(); i++)\n\t{\n\t\tint val = cf.getVar (\"var12\").asInt(i);\n\t\tnlinfo(\"%d -> %d\", i, val);\n\t}\n\n\t// if you try to access an unknown variable or if something goes wrong, an\n\t// exception will be called, you can catch them individually or all together in a try/catch block\n\n\ttry\n\t{\n\t\t// try to access an unknown variable\n\t\tint val = cf.getVar (\"unknown_variable\").asInt();\n\t\tnlinfo(\"unknown_variable = %d\", val);\n\t}\n\tcatch (const EConfigFile &e)\n\t{\n\t\tnlinfo(\"something goes wrong with configfile: %s\", e.what());\n\t}\n\n\tcf.getVar (\"var13\").asInt (0);\n\tcf.getVar (\"var13\").asInt (1);\n\tcf.getVar (\"var13\").asInt (2);\n\t\n\tnlinfo(\"Try to modify the var12 in the configfile or any other variable.\\n\\nPress CTRL-C to exit\\n\");\n\n\twhile(true)\n\t{\n\t\tCConfigFile::checkConfigFiles();\n\t}\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/configfile/simpletest.txt",
    "content": "// one line comment\n/*\n big comment\n on more than one line\n*/\n\n\tvar1 = 123;\t\t\t// var1 type:int,    value:123\n\tvar2 = \"456.25\";\t\t// var2 type:string, value:\"456.25\"\n\tvar3 = 123.123;\t\t\t// var3 type:real,   value:123.123\n\n\t// the resulting type is type of the first left value\n\tvar4 = 123.123 + 2;\t\t// var4 type:real,   value:125.123\n\tvar5 = 123 + 2.1;\t\t// var5 type:int,    value:125\n\n\tvar6 = (-112+1) * 3 - 14;\t// var6 type:int, value:-347\n\n\tvar7 = var1 + 1;\t\t// var7 type:int, value:124\n\n\tvar8 = var2 + 10;\t\t// var8 type:string, value:456.2510 (convert 10 into a string and concat it)\n\tvar9 = 10.15 + var2;\t\t// var9 type:real, value:466.40 (convert var2 into a real and add it)\n\n\tvar10 = { 10.0, 51.1 };\t\t// var10 type:realarray, values:{10.0,51.1}\n\tvar11 = { \"str1\", \"str2\", \"str3\" }; // var11 type:stringarray, values:{\"str1\", \"str2\", \"str3\"}\n\n\tvar12 = { 133, -1 };\t// var12 type:intarray, values:{133,-1}\n\n\tvar13 = { 1, 0.5, -1 };\n"
  },
  {
    "path": "code/nel/samples/misc/debug/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_debug ${SRC})\n\nTARGET_LINK_LIBRARIES(nl_sample_debug nelmisc)\nNL_DEFAULT_PROPS(nl_sample_debug \"NeL, Samples, Misc: Debugging\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_debug)\n\nINSTALL(TARGETS nl_sample_debug RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/debug/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <stdio.h>\n#include <stdlib.h>\n\n// contains all debug features\n#include \"nel/misc/debug.h\"\n\nusing namespace NLMISC;\n\nint main (int /* argc */, char ** /* argv */)\n{\n\t// all debug functions have different behaviors in debug and in release mode.\n\t// in general, in debug mode, all debug functions are active, they display\n\t// what happens and some break the program to debug it. In release mode, they often\n\t// do nothing to increase the execution speed.\n\n\n\t// this function initializes debug functions. it adds displayers into the debug\n\t// logger.\n\t// in debug mode, all debug functions display on the std output.\n\t// in release mode, this function does nothing by default. you have to add a displayer\n\t// manually, or put true in the parameter to say to the function that you want it to\n\t// add the default displayers\n\tcreateDebug ();\n\n\t// display debug information, that will be skipped in release mode.\n\tnldebug (\"nldebug() %d\", 1);\n\n\t// display the string\n\tnlinfo (\"nlinfo() %d\", 2);\n\n\t// when something not normal, but that the program can manage, occurs, call nlwarning()\n\tnlwarning (\"nlwarning() %d\", 3);\n\n\t// nlassert() is like assert but do more powerful things. in release mode, the test is\n\t// not executed and nothing will happen. (Press F5 in Visual C++ to continue the execution)\n\tnlassert (true == false);\n\n\t// in a switch case or when you want that the program never executes a part of code, use stop.\n\t// in release, nlstop does nothing. in debug mode,\n\t// if the code reaches the nlstop, a breakpoint will be set. (In Visual C++ press F5 to continue)\n\tnlstop;\n\n\t// when the program failed, call nlerror(), it displays the message and throws a EFatalError to\n\t// exit the program. don't forget to put a try/catch block everywhere an nlerror could\n\t// occurs. (In Visual C++ press F5 to continue)\n\ttry\n\t{\n\t\tnlerror (\"nlerror() %d\", 4);\n\t}\n\tcatch(const EFatalError &)\n\t{\n\t\t// just continue...\n\t\tnlinfo (\"nlerror() generated an EFatalError exception, just ignore it\");\n\t}\n\n\tprintf(\"\\nPress <return> to exit\\n\");\n\tgetchar ();\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/i18n/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_i18n ${SRC})\n\nADD_DEFINITIONS(-DNL_LANG_DATA=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_i18n/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_i18n nelmisc)\nNL_DEFAULT_PROPS(nl_sample_i18n \"NeL, Samples, Misc: I18N\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_i18n)\n\nINSTALL(TARGETS nl_sample_i18n RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\nINSTALL(FILES de.uxt en.uxt fr.uxt DESTINATION ${NL_SHARE_PREFIX}/nl_sample_i18n COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/i18n/de.uxt",
    "content": "// This is the name of this language.\nLanguageName    [Deutsch]\nHi\t\t\t\t[Hallo]\nPresentI18N\t\t[%s prämtiert das NeL Internationalisierungs-System]\nExitStr\t\t\t[DrüEingabetaste> zum Beenden]\n"
  },
  {
    "path": "code/nel/samples/misc/i18n/en.uxt",
    "content": "// This is the name of this language.\nLanguageName    [English]\nHi\t\t\t\t[Hello]\nPresentI18N\t\t[%s is proud to present you NeL Internationalisation system]\nExitStr\t\t\t[Press <return> to exit]\n"
  },
  {
    "path": "code/nel/samples/misc/i18n/fr.uxt",
    "content": "// This is the name of the language.\nLanguageName\t[Franais]\nHi\t\t\t\t[Bonjour]\nPresentI18N\t\t[%s est fire de vous prsenter le systme d'internationalisation de NeL]\nExitStr\t\t\t[Appuyez sur <entre> pour quitter]\n"
  },
  {
    "path": "code/nel/samples/misc/i18n/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <string>\n#include <iostream>\n\n// contains all i18n features\n#include \"nel/misc/i18n.h\"\n\n// contains the path features\n#include \"nel/misc/path.h\"\n\n#ifndef NL_LANG_DATA\n#define NL_LANG_DATA \".\"\n#endif // NL_LANG_DATA\n\nusing namespace NLMISC;\n\nint main (int argc, char **argv)\n{\n\tcreateDebug();\n\n\t// Add the language data path to the search path.\n\tCPath::addSearchPath(NL_LANG_DATA);\n\n\tInfoLog->displayRawNL(\"Please, choose 'en', 'fr' or 'de' and press <return>\");\n\n\tstd::string langName;\n\tstd::getline(std::cin, langName);\n\n\t// load the language\n\tCI18N::load(langName);\n\n\tInfoLog->displayRawNL(CI18N::get(\"Hi\").toString().c_str());\n\tInfoLog->displayRawNL(CI18N::get(\"PresentI18N\").toString().c_str(), \"Nevrax\");\n\tInfoLog->displayRawNL(CI18N::get(\"ExitStr\").toString().c_str());\n\tgetchar();\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/log/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_log ${SRC})\n\nTARGET_LINK_LIBRARIES(nl_sample_log nelmisc)\nNL_DEFAULT_PROPS(nl_sample_log \"NeL, Samples, Misc: Logging\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_log)\n\nINSTALL(TARGETS nl_sample_log RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/log/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <stdio.h>\n#include <stdlib.h>\n\n// contains the logger\n#include \"nel/misc/log.h\"\n#include \"nel/misc/string_common.h\"\n\n// contains standard displayers\n#include \"nel/misc/displayer.h\"\n\nusing namespace NLMISC;\n\n// create a displayer that displays on stdout and, on Windows, if the\n// application is in debug mode and launched with the debugger (F5), it displays\n// on the output windows of Visual C++.\nCStdDisplayer sd;\n\n// create a displayer that displays in a file. The first parameter is the filename\n// and the second one says that we want to clear the file before logging.\n// If you put false (default value), then, new logs are append to the file.\nCFileDisplayer fd(\"main.log\",true);\n\n// create a displayer that displays in a message box. It actually works only on\n// Windows, it does nothing on other systems.\nCMsgBoxDisplayer mbd;\n\nint main (int /* argc */, char ** /* argv */)\n{\n\t// create a logger; it's an information logger.\n\tCLog logger (CLog::LOG_INFO);\n\n\t// the process name is used when we have more than one process logging stuffs\n\t// in the same displayer (for example for centralized displayer)\n\tlogger.setProcessName (\"my_process_name\");\n\n\t// add displayers for the logger\n\tlogger.addDisplayer (&sd);\n\tlogger.addDisplayer (&fd);\n\tlogger.addDisplayer (&mbd);\n\n\t// so, now, if we send something on the logger, it will be displayed on the 3 displayers\n\t// (stdout, file and message box)\n\n\t// display the string with decoration.\n\t// The decoration is the text that displayers add before the string.\n\t// They could add the date, the process name and so on.\n\t// Before each display/displayNL, you have to set the position of where the display\n\t// occurs. If you don't do that, the position will not be displayed on the displayers.\n\tlogger.setPosition (__LINE__, __FILE__);\n\tlogger.display (\"display using display() %d\\n\", 1);\n\n\t// display the string with decoration and a new line at the end of the string.\n\tlogger.setPosition (__LINE__, __FILE__);\n\tlogger.displayNL (\"display using displayNL() %d\", 2);\n\n\t// display the string without decoration.\n\tlogger.displayRaw (\"display using displayRaw() %d\\n\", 3);\n\n\t// display the string without decoration and with a new line at the end of the string.\n\tlogger.displayRawNL (\"display using displayRawNL() %d\", 4);\n\n\tprintf(\"\\nPress <return> to exit\\n\");\n\tgetchar();\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/strings/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_strings ${SRC})\n\nTARGET_LINK_LIBRARIES(nl_sample_strings nelmisc)\nNL_DEFAULT_PROPS(nl_sample_strings \"NeL, Samples, Misc: Strings\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_strings)\n\nINSTALL(TARGETS nl_sample_strings RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/strings/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/misc/types_nl.h\"\n\n#include <cstdlib>\n\n#include \"nel/misc/string_common.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nint main (int argc, char **argv)\n{\n\t{\n\t\tuint8 val;\n\t\tval = 0; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = -1; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 1; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 255; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\t{\n\t\tsint8 val;\n\t\tval = 0; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = -128; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 1; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 127; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\t{\n\t\tuint16 val;\n\t\tval = -12158; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 12557; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\t{\n\t\tsint16 val;\n\t\tval = -12158; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 12557; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\t{\n\t\tuint32 val;\n\t\tval = -121556418; printf(\"'%u' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 125848847; printf(\"'%u' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\t{\n\t\tsint32 val;\n\t\tval = -120547158; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t\tval = 12555857; printf(\"'%d' should be equal to '%s' \\n\", val, toString(val).c_str());\n\t}\n\n\tstring str;\n\tstr += \"This is an example of the use of toString(). It's a number \" + toString(156);\n\tstr += \" and now a float \" + toString(15.55f);\n\n\tprintf(\"%s\\n\", str.c_str());\n\n\tprintf (\"\\nPress <return> to exit\\n\");\n\tgetchar ();\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/misc/types_check/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_types_check ${SRC})\n\nTARGET_LINK_LIBRARIES(nl_sample_types_check nelmisc)\nNL_DEFAULT_PROPS(nl_sample_types_check \"Samples, MISC: Types check sample\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_types_check)\n\nINSTALL(TARGETS nl_sample_types_check RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesmisc)\n"
  },
  {
    "path": "code/nel/samples/misc/types_check/main.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <math.h>\n\n#include <string>\n#include <vector>\n#include <iostream>\nusing namespace std;\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/string_stream.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\nusing namespace NLMISC;\n\ntemplate <class T> bool check (T value)\n{\n\tT result;\n\tCMemStream msgout;\n\tmsgout.serial (value);\n\tCMemStream msgin (true);\n\tmsgin.fill (msgout.buffer(), msgout.size());\n\tmsgin.serial (result);\n\t\n\tif (value != result)\n\t{\n\t\tnlwarning (\"CHECK FAILED: %s != %s\", toString (value).c_str(), toString (result).c_str());\n\t}\n\n\tif (toString(value) != toString(result))\n\t{\n\t\tnlwarning (\"toString() CHECK FAILED: %s != %s\", toString (value).c_str(), toString (result).c_str());\n\t}\n\t\t\n\treturn value == result;\n}\n\n\n#define checkInt(__type, __start, __end, __step) \\\n{ \\\n\t__type t = (__type)(__start); \\\n\tnlinfo (\"checking \"#__type\" first %s\", toString (t).c_str()); \\\n\tfor (; t < (__type)(__end); t += (__type)(__step)) \\\n\t\tcheck ((__type)(t)); \\\n\tnlinfo (\"checking \"#__type\" last %s\", toString (t).c_str()); \\\n\tcheck ((__type)(t)); \\\n}\n\n\n\nvoid checkInts ()\n{\n\tcheckInt (uint8, 0, 255, 1);\n\tcheckInt (sint8, -128, 127, 1);\n\n\tcheckInt (uint16, 0, 65535, 1);\n\tcheckInt (sint16, -32768, 32767, 1);\n\n\tcheckInt (uint32, 0, 65535, 1);\n\tcheckInt (uint32, 4294967295-65535, 4294967295, 1);\n\n\tcheckInt (sint32, -2147483648, -2147483648+65535, 1);\n\tcheckInt (sint32, 2147483647-65535, 2147483647, 1);\n\n\tcheckInt (uint32, 0, 4294967295, 65535);\n\tcheckInt (sint32, -2147483648, 2147483647, 65535);\n\n\tuint64 start, end;\n\tend=0; end--; start=end-65535;\n\tcheckInt (uint64, 0, 65535, 1);\n\tcheckInt (uint64, start, end, 1);\n\n\tcheckInt (sint64, -9223372036854775808, -9223372036854775808+65535, 1);\n\tcheckInt (sint64, 9223372036854775807-65535, 9223372036854775807, 1);\n}\n\n\nint main (int argc, char **argv)\n{\n\tif (sizeof (uint) != sizeof (void*)) nlwarning (\"sizeof (uint) != sizeof (void*) : %d != %d\", sizeof (uint), sizeof (void*));\n\n\tif (sizeof (uint8) != 1) nlwarning (\"sizeof (uint8) != 1 : %d != %d\", sizeof (uint8), 1);\n\tif (sizeof (sint8) != 1) nlwarning (\"sizeof (sint8) != 1 : %d != %d\", sizeof (sint8), 1);\n\tif (sizeof (uint16) != 2) nlwarning (\"sizeof (uint16) != 2 : %d != %d\", sizeof (uint16), 2);\n\tif (sizeof (sint16) != 2) nlwarning (\"sizeof (sint16) != 2 : %d != %d\", sizeof (sint16), 2);\n\tif (sizeof (uint32) != 4) nlwarning (\"sizeof (uint32) != 4 : %d != %d\", sizeof (uint32), 4);\n\tif (sizeof (sint32) != 4) nlwarning (\"sizeof (sint32) != 4 : %d != %d\", sizeof (sint32), 4);\n\tif (sizeof (uint64) != 8) nlwarning (\"sizeof (uint64) != 8 : %d != %d\", sizeof (uint64), 8);\n\tif (sizeof (sint64) != 8) nlwarning (\"sizeof (sint64) != 8 : %d != %d\", sizeof (sint64), 8);\n\t\n\tcheckInts ();\n\n\tprintf (\"\\nPress <return> to exit\\n\");\n\tgetchar ();\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/net/CMakeLists.txt",
    "content": "ADD_SUBDIRECTORY(chat)\nADD_SUBDIRECTORY(udp)\nADD_SUBDIRECTORY(login_system)\nADD_SUBDIRECTORY(class_transport)\n\n#multi_shards\n#net_layer3\n#net_layer4\n#net_layer5\n#service\n#udp_ping\n"
  },
  {
    "path": "code/nel/samples/net/chat/CMakeLists.txt",
    "content": "ADD_EXECUTABLE(nl_sample_chatclient client.cpp kbhit.cpp kbhit.h)\n\nADD_EXECUTABLE(nl_sample_chatserver WIN32 server.cpp)\n\nADD_DEFINITIONS(-DCHAT_DIR=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_chat/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_chatclient nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_chatclient \"NeL, Samples, Net, Chat: Chat Client\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_chatclient)\n\nTARGET_LINK_LIBRARIES(nl_sample_chatserver nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_chatserver \"NeL, Samples, Net, Chat: Chat Server\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_chatserver)\n\nINSTALL(TARGETS nl_sample_chatclient nl_sample_chatserver RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet)\nINSTALL(FILES chat_service.cfg client.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_chat COMPONENT samplesnet)\n"
  },
  {
    "path": "code/nel/samples/net/chat/chat_service.cfg",
    "content": "//NSHost = \"localhost\";\nDontUseNS = 1;\nDontUseAES = 1;\n\n"
  },
  {
    "path": "code/nel/samples/net/chat/client.cfg",
    "content": "\nLSHost = \"localhost\";\n"
  },
  {
    "path": "code/nel/samples/net/chat/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Login system example, client.\n *\n * This client connects to a front-end server using login system.\n *\n * Before running this client, the front end service sample must run,\n * and also the NeL naming_service, time_service, login_service, welcome_service.\n *\n */\n\n//\n// Includes\n//\n\n#include <string>\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/net/callback_client.h\"\n\n#ifdef NL_OS_WINDOWS\n#include <conio.h>\n#else\n#include \"kbhit.h\"\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n// Really simple chat\n// Do not display what you are typing\n\n#ifdef NL_OS_WINDOWS\n#define KEY_ESC\t\t27\n#define KEY_ENTER\t13\n#else\n#define KEY_ESC\t\t27\n#define KEY_ENTER\t10\n#endif\n\n#ifndef CHAT_DIR\n#\tdefine CHAT_DIR \".\"\n#endif\n\nstring CurrentEditString;\n\n// ***************************************************************************\nvoid serverSentChat (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t// Called when the server sent a CHAT message\n\tstring text;\n\tmsgin.serial(text);\n\tprintf(\"%s\\n\", text.c_str());\n}\n\n// ***************************************************************************\n// All messages handled by this server\n#define NB_CB 1\nTCallbackItem CallbackArray[NB_CB] =\n{\n\t{ \"CHAT\", serverSentChat }\n};\n\n/*\n * main\n */\nint main (int argc, char **argv)\n{\n\tNLMISC::CApplicationContext applicationContext;\n\n\tCCallbackClient *Client;\n\n\tNLMISC::CPath::addSearchPath(CHAT_DIR);\n\n\t// Read the host where to connect in the client.cfg file\n\tCConfigFile ConfigFile;\t\n\tConfigFile.load (NLMISC::CPath::lookup(\"client.cfg\"));\n\tstring LSHost(ConfigFile.getVar(\"LSHost\").asString());\n\n\t// Init and Connect the client to the server located on port 3333\n\tClient = new CCallbackClient();\n\tClient->addCallbackArray (CallbackArray, NB_CB);\n\n\tprintf(\"Please wait connecting...\\n\");\n\ttry\n\t{\n\t\tCInetAddress addr(LSHost+\":3333\");\n\t\tClient->connect(addr);\n\t}\n\tcatch(const ESocket &e)\n\t{\n\t\tprintf(\"%s\\n\", e.what());\n\t\treturn 0;\n\t}\n\n\tif (!Client->connected())\n\t{\n\t\tprintf(\"Connection Error\\n\");\n\t\treturn 0;\n\t}\n\tprintf(\"Connected.\\n\");\n\n#ifdef NL_OS_UNIX\n\tinit_keyboard();\n#endif\n\t// The main loop\n\tdo\n\t{\n\t\tint c;\n\t\tif (kbhit())\n\t\t{\n\t\t\tc = getch();\n\t\t\tif (c == KEY_ESC)\n\t\t\t{\n\t\t\t\tbreak; // FINSIH\n\t\t\t}\n\t\t\telse if (c == KEY_ENTER)\n\t\t\t{\n\t\t\t\tCMessage msg;\n\t\t\t\tmsg.setType(\"CHAT\");\n\t\t\t\tmsg.serial (CurrentEditString);\n\t\t\t\tClient->send(msg);\n\t\t\t\tCurrentEditString = \"\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCurrentEditString += c;\n\t\t\t}\n\t\t}\n\t\tClient->update();\n\t}\n\twhile (Client->connected());\n\n#ifdef NL_OS_UNIX\n\tclose_keyboard();\n#endif\n\t// Finishing\n\tdelete Client;\n}\n"
  },
  {
    "path": "code/nel/samples/net/chat/kbhit.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifdef __GNUC__\n#include \"kbhit.h\"\n#include <termios.h>\n#include <unistd.h>   // for read()\n#include <stdio.h>\n\nstatic struct termios initial_settings, new_settings;\nstatic int peek_character = -1;\n\nvoid init_keyboard()\n{\n\ttcgetattr(STDIN_FILENO,&initial_settings);\n\tnew_settings = initial_settings;\n\tnew_settings.c_lflag &= ~ICANON;\n\tnew_settings.c_lflag &= ~ECHO;\n\tnew_settings.c_lflag &= ~ISIG;\n\tnew_settings.c_cc[VMIN] = 1;\n\tnew_settings.c_cc[VTIME] = 0;\n\ttcsetattr(STDIN_FILENO, TCSANOW, &new_settings);\n}\n\nvoid close_keyboard()\n{\n\ttcsetattr(STDIN_FILENO, TCSANOW, &initial_settings);\n}\n\nint kbhit()\n{\n\tunsigned char ch;\n\tint nread;\n\n\tif (peek_character != -1) return 1;\n\n\tnew_settings.c_cc[VMIN]=0;\n\ttcsetattr(STDIN_FILENO, TCSANOW, &new_settings);\n\tnread = read(STDIN_FILENO,&ch,1);\n\tnew_settings.c_cc[VMIN]=1;\n\ttcsetattr(STDIN_FILENO, TCSANOW, &new_settings);\n\n\tif(nread == 1)\n\t{\n\t\tpeek_character = ch;\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nint getch()\n{\n\tchar ch;\n\n\tif(peek_character != -1)\n\t{\n\t\tch = peek_character;\n\t\tpeek_character = -1;\n\t\treturn ch;\n\t}\n\tif (read(STDIN_FILENO,&ch,1) != 1) return ' ';\n\n\treturn ch;\n}\n\n#endif // __GNUC__\n"
  },
  {
    "path": "code/nel/samples/net/chat/kbhit.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_KBHIT_H\n#define NL_KBHIT_H\n\nvoid init_keyboard(void);\nvoid close_keyboard(void);\nint kbhit(void);\nint getch(void);\n\n#endif // NL_KBHIT_H\n\n"
  },
  {
    "path": "code/nel/samples/net/chat/server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <string>\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/path.h\"\n\n// contains the service base class\n#include \"nel/net/service.h\"\n#include \"nel/net/callback_server.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n#ifndef CHAT_DIR\n#\tdefine CHAT_DIR \"\"\n#endif\n\n// THE SERVER\n\n// Must be a pointer to control when to start listening socket and when stop it\nCCallbackServer *Server;\nvector<TSockId> Clients;\n\n// MESSAGES\n\n// ***************************************************************************\nvoid clientWantsToConnect ( TSockId from, void *arg )\n{\n\t// Called when a client wants to connect\n\tClients.push_back (from);\n}\n\n// ***************************************************************************\nvoid clientWantsToDisconnect ( TSockId from, void *arg )\n{\n\t// Called when a client wants to disconnect\n\tfor (uint i = 0; i < Clients.size(); ++i)\n\t\tif (Clients[i] == from)\n\t\t{\n\t\t\tClients.erase(Clients.begin()+i);\n\t\t\treturn;\n\t\t}\n}\n\n// ***************************************************************************\nvoid clientSentChat (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t// Called when a client sent a CHAT message\n\tstring text;\n\tmsgin.serial(text);\n\tCMessage msgout;\n\tmsgout.setType(\"CHAT\");\n\tmsgout.serial(text);\n\tfor (uint i = 0; i < Clients.size(); ++i)\n\t\tServer->send(msgout, Clients[i]);\n}\n\n// ***************************************************************************\n// All messages handled by this server\n#define NB_CB 1\nTCallbackItem CallbackArray[NB_CB] =\n{\n\t{ \"CHAT\", clientSentChat }\n};\n\n// SERVICE\n\n// ***************************************************************************\nclass CChatService : public IService\n{\npublic:\n\n\tvoid init ()\n\t{\n\t\t// Init the server on port 3333\n\t\tServer = new CCallbackServer();\n\t\tServer->init (3333);\n\t\tServer->setConnectionCallback (clientWantsToConnect, NULL);\n\t\tServer->setDisconnectionCallback (clientWantsToDisconnect, NULL);\n\t\tServer->addCallbackArray (CallbackArray, NB_CB);\n\t}\n\n\tbool update ()\n\t{\n\t\t// this function is called every \"loop\". you return true if you want\n\t\t// to continue or return false if you want to exit the service.\n\t\t// the loop is called evenly (by default, at least one time per second).\n\n\t\tServer->update();\n\n\t\treturn true;\n\t}\n\n\tvoid release ()\n\t{\n\t\t// Must delete the server here\n\t\tdelete Server;\n\t}\n};\n\n// this macro is the \"main\". the first param is the class name inherited from IService.\n// the second one is the name of the service used to register and find the service\n// using the naming service. the third one is the port where the listen socket will\n// be created. If you put 0, the system automatically finds a port.\nNLNET_SERVICE_MAIN (CChatService, \"CS\", \"chat_service\", 0, EmptyCallbackArray, CHAT_DIR, \"\");\n"
  },
  {
    "path": "code/nel/samples/net/class_transport/CMakeLists.txt",
    "content": "ADD_EXECUTABLE(nl_sample_ct_ai_service WIN32 ai_service.cpp)\n\nADD_EXECUTABLE(nl_sample_ct_gd_service WIN32 gd_service.cpp)\n\nADD_DEFINITIONS(-DNL_CT_CFG=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_class_transport/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_ct_ai_service nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_ct_ai_service \"NeL, Samples, Net, Class Transport: AI Service\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_ct_ai_service)\n\nTARGET_LINK_LIBRARIES(nl_sample_ct_gd_service nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_ct_gd_service \"NeL, Samples, Net, Class Transport: GD Service\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_ct_gd_service)\n\nINSTALL(TARGETS nl_sample_ct_ai_service nl_sample_ct_gd_service RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet)\nINSTALL(FILES ai_service.cfg gd_service.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_class_transport COMPONENT samplesnet)\n"
  },
  {
    "path": "code/nel/samples/net/class_transport/ai_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/class_transport/ai_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Transport class example, gd server.\n *\n * This service have a class (CSharedClass) that send to other service when online.\n *\n * To run this program, ensure there is a file \"ai_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n//\n// Includes\n//\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/displayer.h\"\n\n#include \"nel/net/transport_class.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\n#ifndef NL_CT_CFG\n#define NL_CT_CFG \"\"\n#endif // NL_CT_CFG\n\n//\n// Namespace\n//\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n//\n// Shared Class\n//\n\nstruct CSharedClass : public CTransportClass\n{\n\tuint32\ti1;\n\tuint16\ti2;\n\tfloat\tf1, f2;\n\t\n\tvector<uint32> vi1;\n\n\tstring str;\n\n\tCEntityId eid;\n\n\tCSharedClass () : i1(20), i2(20), f1(20), str(\"str20\"), eid (5, 1515664512) { }\n\n\tvirtual void description ()\n\t{\n\t\tclassName (\"SharedClass\");\n\t\tproperty (\"i1\", PropUInt32, (uint32)21, i1);\n\t\tproperty (\"f1\", PropFloat,  2.5f, f1);\n\t\tproperty (\"i2\", PropUInt16, (uint16)22, i2);\n\t\tpropertyCont (\"vi1\", PropUInt16, vi1);\n\t\tproperty (\"str\", PropString, (string)\"str22\", str);\n//\t\tproperty (\"eid\", PropEntityId, CEntityId::Unknown, eid);\n\t\tproperty (\"f2\", PropFloat,  2.5f, f2);\n\t}\n\n\tvirtual void callback (const string &name, uint8 sid)\n\t{\n\t\tnlinfo (\"Yes! I receive a Shared class from '%s' %d\", name.c_str(), sid);\n\t}\n};\n\n//\n// Variables\n//\n\n//\n// Functions\n//\n\nstatic void cbUpService (const std::string &serviceName, uint16 sid, void *arg)\n{\n\t// When a service comes, send the new class\n\tCSharedClass foo;\n\tfoo.send((TServiceId)sid);\n}\n\n//\n// Main class\n//\n\nstruct CAIService : public IService\n{\n\tvoid init()\n\t{\n\t\t// callback when a new service comes\n\t\tCUnifiedNetwork::getInstance()->setServiceUpCallback(\"*\", (TUnifiedNetCallback)cbUpService, NULL);\n\n\t\t// init the class transport system\n\t\tCTransportClass::init ();\n\n\t\t// register the shared class\n\t\tTRANSPORT_CLASS_REGISTER (CSharedClass);\n\t}\n\n\tvoid release ()\n\t{\n\t\t// release all the class transport system\n\t\tCTransportClass::release ();\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"AIS\" (short) and \"ai_service\" (long).\n * The port is automatically allocated (0) and the main callback array is empty.\n */\nNLNET_SERVICE_MAIN( CAIService, \"AIS\", \"ai_service\", 0, EmptyCallbackArray, NL_CT_CFG, \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/class_transport/gd_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/class_transport/gd_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Transport class example, gd server.\n *\n * This service have a class (CSharedClass) that send to other service when online.\n *\n * To run this program, ensure there is a file \"gd_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n//\n// Includes\n//\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/displayer.h\"\n\n#include \"nel/net/transport_class.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\n#ifndef NL_CT_CFG\n#define NL_CT_CFG \"\"\n#endif // NL_CT_CFG\n\n//\n// Namespace\n//\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n//\n// Shared Class\n//\n\nstruct CSharedClass : public CTransportClass\n{\n\tuint32\ti1, i2, i3;\n\tfloat\tf1;\n\n\tvector<uint32> vi1;\n\n\tstring str;\n\n\tCEntityId eid;\n\n\tCSharedClass () : i1(10), i2(10), i3(10), f1(10), str(\"str10\") { vi1.push_back(111); vi1.push_back(222); vi1.push_back(255); }\n\n\tvirtual void description ()\n\t{\n\t\tclassName (\"SharedClass\");\n\t\tproperty (\"i1\", PropUInt32, (uint32)11, i1);\n\t\tproperty (\"f1\", PropFloat,  1.5f, f1);\n//\t\tproperty (\"i2\", PropUInt32, (uint32)12, i2);\n\t\tproperty (\"i3\", PropUInt32, (uint32)13, i3);\n\t\tpropertyCont (\"vi1\", PropUInt32, vi1);\n\t\tproperty (\"str\", PropString, (string)\"str12\", str);\n//\t\tproperty (\"eid\", PropEntityId, CEntityId::Unknown, eid);\n\t}\n\n\tvirtual void callback (const string &name, uint8 sid)\n\t{\n\t\tnlinfo (\"Yes! I receive a Shared class from '%s' %d\", name.c_str(), sid);\n\t}\n};\n\n//\n// Variables\n//\n\nstatic CSharedClass SharedClass;\n\n//\n// Functions\n//\n\nstatic void cbUpService (const std::string &serviceName, uint16 sid, void *arg)\n{\n\t// When a service comes, send the new class\n\tCSharedClass foo;\n\tfoo.send((TServiceId)sid);\n}\n\n//\n// Service class\n//\n\nstruct CGDService : public IService\n{\n\tvoid init()\n\t{\n\t\t// callback when a new service comes\n\t\tCUnifiedNetwork::getInstance()->setServiceUpCallback(\"*\", (TUnifiedNetCallback)cbUpService, NULL);\n\n\t\t// init the class transport system\n\t\tCTransportClass::init ();\n\n\t\t// register the shared class\n\t\tTRANSPORT_CLASS_REGISTER (CSharedClass);\n\t}\n\n\tvoid release ()\n\t{\n\t\t// release all the class transport system\n\t\tCTransportClass::release ();\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"GDS\" (short) and \"gd_service\" (long).\n * The port is automatically allocated (0) and the main callback array is empty.\n */\nNLNET_SERVICE_MAIN( CGDService, \"GDS\", \"gd_service\", 0, EmptyCallbackArray, NL_CT_CFG, \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/login_system/CMakeLists.txt",
    "content": "ADD_EXECUTABLE(nl_sample_ls_client client.cpp)\n\nADD_EXECUTABLE(nl_sample_ls_fes WIN32 frontend_service.cpp)\n\nADD_DEFINITIONS(-DNL_LS_CFG=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_login_system/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_ls_client nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_ls_client \"NeL, Samples, Net, Login Service: LS Client\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_ls_client)\n\nTARGET_LINK_LIBRARIES(nl_sample_ls_fes nelmisc nelnet)\nNL_DEFAULT_PROPS(nl_sample_ls_fes \"NeL, Samples, Net, Login Service: LS Frontend\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_ls_fes)\n\nINSTALL(TARGETS nl_sample_ls_client nl_sample_ls_fes RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet)\nINSTALL(FILES frontend_service.cfg client.cfg DESTINATION ${NL_SHARE_PREFIX}/nl_sample_login_system COMPONENT samplesnet)\n"
  },
  {
    "path": "code/nel/samples/net/login_system/client.cfg",
    "content": "LSHost = \"localhost\";\nLogin = \"nel\";\nPassword = \"rox\";\nClientApplication = \"sample\";\nShardId = 300;\n"
  },
  {
    "path": "code/nel/samples/net/login_system/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Login system example, client.\n *\n * This client connects to a front-end server using login system.\n *\n * Before running this client, the front end service sample must run,\n * and also the NeL naming_service, time_service, login_service, welcome_service.\n *\n */\n\n//\n// Includes\n//\n\n#include <string>\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n#include \"nel/misc/md5.h\"\n\n#include \"nel/net/login_client.h\"\n#include \"nel/net/login_cookie.h\"\n\n// The UDP mode wasn't tested, you should leave USE_UDP undef\n//#define USE_UDP\n#undef USE_UDP\n\n#ifdef USE_UDP\n#\tinclude \"nel/net/udp_sock.h\"\n#endif\n\n#ifndef NL_LS_CFG\n#define NL_LS_CFG \".\"\n#endif // NL_LS_CFG\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\n//\n// Functions\n//\n\nint main (int argc, char **argv)\n{\n\tstring result;\n\t\n\tCApplicationContext myApplicationContext;\n\n\tCPath::addSearchPath(NL_LS_CFG);\n\n\tCConfigFile ConfigFile;\n\t\n\tConfigFile.load (\"client.cfg\");\n\n\tstring LSHost(ConfigFile.getVar(\"LSHost\").asString());\n\n\tucstring Login = ConfigFile.getVar(\"Login\").asString();\n\tif(Login.empty())\n\t{\n\t\tchar buf[256];\n\t\tprintf(\"Login: \");\n\t\tLogin = fgets(buf, 256, stdin);\n\t}\n\n\tucstring Password = ConfigFile.getVar(\"Password\").asString();\n\tif(Password.empty())\n\t{\n\t\tchar buf[256];\n\t\tprintf(\"Password: \");\n\t\tPassword = fgets(buf, 256, stdin);\n\t}\n\t// crypt with md5 the password\n\tCHashKeyMD5 hk = getMD5((uint8*)Password.c_str(), (uint32)Password.size());\n\tstring CPassword = hk.toString();\n\tnlinfo(\"The crypted password is %s\", CPassword.c_str());\n\n\tstring Application = ConfigFile.getVar(\"ClientApplication\").asString();\n\n\t/* Try to connect to the login service and check the login, password of the client.\n\t * return an empty string if all go well\n\t */\n\tresult = CLoginClient::authenticate(LSHost, Login, CPassword, Application);\n\n\tif(!result.empty()) nlerror (\"*** Authenticate failed '%s' ***\", result.c_str());\n\n\tnlinfo(\"%d Shards are available:\", CLoginClient::ShardList.size());\n\tfor (uint i = 0; i < CLoginClient::ShardList.size (); i++)\n\t{\n\t\tnlinfo (\"    ShardId %3d: %s (%d online players)\", CLoginClient::ShardList[i].Id, CLoginClient::ShardList[i].Name.toUtf8().c_str (), CLoginClient::ShardList[i].NbPlayers);\n\t}\n\n\tsint32 sid = ConfigFile.getVar(\"ShardId\").asInt();\n\tif(sid == 0)\n\t{\n\t\tprintf(\"Enter the ShardId you want to connect to: \");\n\t\tif (scanf(\"%d\", &sid) != 1)\n\t\t{\n\t\t\tnlwarning(\"Can't parse ShardId\");\n\t\t}\n\t}\n\n\t/* Try to connect to the shard number 0 in the list.\n\t * return an empty string if all go well\n\t */\n\n\tstring ip, cookie;\n\tresult = CLoginClient::wantToConnectToShard (sid, ip, cookie);\n\n\tif(!result.empty()) nlerror (\"*** Connection to the shard failed '%s' ***\", result.c_str());\n\n#ifndef USE_UDP\n\n\tCCallbackClient *cnx = new CCallbackClient();\n\tCLoginCookie lc;\n\tlc.setFromString(cookie);\n\tresult = CLoginClient::connectToShard (lc, ip, *cnx);\n\n\tif(!result.empty()) nlerror (\"*** Connection to the shard failed '%s' ***\", result.c_str());\n\n\tnlinfo (\"*** Connection granted! You are connected on the frond end ***\");\n\n\twhile (cnx->connected ())\n\t{\n\t\tcnx->update ();\n\t\tnlSleep(10);\n\t}\n\n\tif( cnx->connected ())\n\t\tcnx->disconnect ();\n\n#else // USE_UDP\n\n\tCUdpSock *cnx = new CUdpSock();\n\tCLoginCookie lc;\n\tresult = CLoginClient::connectToShard (0, *cnx, lc);\n\n\tif(!result.empty()) nlerror (\"*** Connection to the shard failed '%s' ***\", result.c_str());\n\n\t// we have to talk with the FES to send the cookie\n\n\tCBitMemStream msgout;\n\tmsgout.serial (lc);\n\twhile (true)\n\t{\n\t\t// send the cookie\n\t\tuint32 len = msgout.length ();\n\t\tcnx->send (msgout.buffer (), len);\n\n\t\tuint8 buf[64000];\n\t\tif (cnx->dataAvailable ())\n\t\t{\n\t\t\t// manage answer\n\t\t\tlen = 64000;\n\t\t\tcnx->receive (buf, len);\n\n\t\t\tCBitMemStream msgin (true);\n\t\t\tmsgin.clear ();\n\t\t\tmemcpy (msgin.bufferToFill (len), &buf[0], len);\n\n\t\t\tmsgin.serial (result);\n\t\t\tbreak;\n\t\t}\n\n\t\t// sleep\n\t\tnlSleep (1000);\n\t}\n\n\tif(!result.empty()) nlerror (\"*** Connection to the shard failed '%s' ***\", result.c_str());\n\n\tnlinfo (\"*** Connection granted! You are connected on the frond end ***\");\n\n\twhile (cnx->connected ())\n\t{\n\t\t// do want you want!\n\n\t\tnlSleep(10);\n\t}\n\n#endif // USE_UDP\n\n\tdelete cnx;\n\treturn 0;\n}\n"
  },
  {
    "path": "code/nel/samples/net/login_system/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\n\nFSPort = 37373;\nWindowStyle = \"WIN\";\n\nDontUseAES = 1;\n"
  },
  {
    "path": "code/nel/samples/net/login_system/frontend_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, front-end server.\n *\n * To run this program, ensure there is a file \"frontend_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory.\n * The NeL naming_service, time_service, login_service, welcome_service must be running.\n */\n\n\n// We're using the NeL Service framework and layer 5.\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/login_server.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n#ifndef NL_LS_CFG\n#define NL_LS_CFG \"\"\n#endif // NL_LS_CFG\n\n//#define USE_UDP\n#undef USE_UDP\n\n\n#ifndef USE_UDP\n\n//\n// TCP server mode\n//\n\n/*\n * Connection callback for a client\n */\nvoid onConnectionClient (TSockId from, const CLoginCookie &cookie)\n{\n\tnlinfo (\"The client with uniq Id %d is connected\", cookie.getUserId ());\n\n\t// store the user id in appId\n\tfrom->setAppId (cookie.getUserId ());\n}\n\n\n/*\n * Disconnection callback for a client\n */\nvoid onDisconnectClient (TSockId from, void *arg)\n{\n\tnlinfo (\"A client with uniq Id %d has disconnected\", from->appId ());\n\n\t// tell the login system that this client is disconnected\n\tCLoginServer::clientDisconnected ((uint32) from->appId ());\n}\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public IService\n{\nprivate:\n\t/// The server on which the clients connect\n\tCCallbackServer\t\t_FServer;\n\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// connect the front end login system\n\t\tuint16\tfsPort = 37373;\n\t\ttry\n\t\t{\n\t\t\tfsPort = IService::ConfigFile.getVar(\"FSPort\").asInt();\n\t\t}\n\t\tcatch (const EUnknownVar&)\n\t\t{\n\t\t}\n\t\t_FServer.init(fsPort);\n\t\tCLoginServer::init (_FServer, onConnectionClient); \n\n\t\t//\n\t\t_FServer.setDisconnectionCallback(onDisconnectClient, NULL);\n\t}\n\n\tbool\tupdate()\n\t{\n\t\t_FServer.update();\n\t\treturn true;\n\t}\n};\n\n#else // USE_UDP\n\n//\n// UDP server mode\n//\n\n#include \"nel/net/udp_sock.h\"\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public IService\n{\nprivate:\n\t/// The server on which the clients connect\n\tCUdpSock *_FServer;\n\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// connect the front end login system\n\t\tuint16\tfesPort = 37373;\n\t\ttry\n\t\t{\n\t\t\tfesPort = IService5::ConfigFile.getVar(\"FESPort\").asInt();\n\t\t}\n\t\tcatch (const EUnknownVar&)\n\t\t{\n\t\t}\n\n\t\t// Socket\n\t\t_FServer = new CUdpSock( false );\n\t\tnlassert( _FServer );\n\n\t\t// Test of multihomed host\n\t\tvector<CInetAddress> addrlist;\n\t\taddrlist = CInetAddress::localAddresses();\n\t\tvector<CInetAddress>::iterator ivi;\n\t\tfor ( ivi=addrlist.begin(); ivi!=addrlist.end(); ++ivi )\n\t\t{\n\t\t\tnlinfo( \"%s\", (*ivi).asIPString().c_str() );\n\t\t}\n\t\taddrlist[0].setPort( fesPort );\n\t\t_FServer->bind( addrlist[0] );\n\t\t\n\t\tCLoginServer::init (*_FServer, NULL); \n\t}\n\n\tbool\tupdate()\n\t{\n\t\tuint8 buf[64000];\n\t\tuint len;\n\t\tCInetAddress addr;\n\n\t\twhile (_FServer->dataAvailable ())\n\t\t{\n\t\t\tlen = 64000;\n\t\t\t_FServer->receivedFrom (buf, len, addr);\n\n\t\t\tCBitMemStream msgin (true);\n\t\t\tmsgin.clear ();\n\t\t\tmemcpy (msgin.bufferToFill (len), &buf[0], len);\n\n\t\t\tCLoginCookie lc;\n\t\t\tmsgin.serial (lc);\n\n\t\t\tnlinfo (\"Receive the cookie %s from %s\", lc.toString ().c_str(), addr.asString ().c_str());\n\n\t\t\tstring res = CLoginServer::isValidCookie (lc);\n\n\t\t\t// send the result\n\t\t\tCBitMemStream msgout;\n\t\t\tmsgout.serial (res);\n\t\t\tuint32 l = msgout.length ();\n\t\t\t_FServer->sendTo (msgout.buffer (), l, addr);\n\t\t}\n\t\treturn true;\n\t}\n};\n\n#endif // USE_UDP\n\n/*\n * Declare a service with the class CFrontEndService, the names \"FS\" (short) and \"frontend_service\" (long).\n * The port is dynamically find and there's no callback array.\n */\nNLNET_SERVICE_MAIN (CFrontEndService, \"FS\", \"frontend_service\", 0, EmptyCallbackArray, NL_LS_CFG, \"\")\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Login system example, client.\n *\n * This client connects to a front-end server using login system.\n *\n * Before running this client, the front end service sample must run,\n * and also the NeL naming_service, time_service, login_service, welcome_service.\n *\n */\n\n// We're using std\n#include <string>\n\n// We're using NeL\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n\n// We're using the login client\n#include \"nel/net/login_client.h\"\n#include \"nel/net/login_cookie.h\"\n\n#include \"nel/net/udp_sock.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n/*\n * main\n */\nvoid main (int argc, char **argv)\n{\n\tstring result;\n\n\tCConfigFile ConfigFile;\n\t\n\tConfigFile.load (\"client.cfg\");\n\n\tstring LSHost(ConfigFile.getVar(\"LSHost\").asString());\n\n\tchar\tbuf[256];\n\tprintf(\"Login: \");\n\tfgets(buf, 256, stdin);\n\tstring\tLogin(buf);\n\n\tprintf(\"Password: \");\n\tfgets(buf, 256, stdin);\n\tstring\tPassword(buf);\n\n\tif (Login.empty ())\n\t{\n\t\tLogin = ConfigFile.getVar(\"Login\").asString();\n\t}\n\n\tif (Password.empty ())\n\t{\n\t\tPassword = ConfigFile.getVar(\"Password\").asString();\n\t}\n\n\t/* Try to connect to the login service and check the login, password and version of the client.\n\t * return an empty string if all go well\n\t */\n\tresult = CLoginClient::authenticate(LSHost+\":49999\", Login, Password, \"sample\");\n\t\n\tif(!result.empty()) nlerror (\"*** Authenticate failed '%s' ***\", result.c_str());\n\n\t// CLoginClient::ShardList contains all available shards\n\tfor (uint i = 0; i < CLoginClient::ShardList.size (); i++)\n\t{\n\t\tnlinfo(\"*** shard %d is: %s (%d) ***\", i, CLoginClient::ShardList[i].Name.c_str (), CLoginClient::ShardList[i].Id);\n\t}\n\n\t/* Try to connect to the last shard number in the list.\n\t * return an empty string if all go well\n\t */\n\n\tstring fs_ip, login_cookie;\n\tresult = CLoginClient::wantToConnectToShard(CLoginClient::ShardList[CLoginClient::ShardList.size() - 1].Id, fs_ip, login_cookie);\n\tif (!result.empty()) nlerror(\"*** Select shard failed '%s' ***\", result.c_str());\n\tCLoginCookie cookie; cookie.setFromString(login_cookie); // who's idea was it to send the cookie as a string...\n\t\n\tCCallbackClient *cnx = new CCallbackClient();\n\tresult = CLoginClient::connectToShard(cookie, fs_ip, *cnx);\n\n\tif (!result.empty()) nlerror(\"*** Connection to the shard failed '%s' ***\", result.c_str());\n\n\tnlinfo (\"*** Connection granted! You are connected on the frond end ***\");\n\n\twhile (cnx->connected ())\n\t{\n\t\tcnx->update ();\n\t\tnlSleep(10);\n\t}\n\n\tif( cnx->connected ())\n\t\tcnx->disconnect ();\n\n\tdelete cnx;\n}\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/frontend_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * multi shard example, front-end server.\n *\n * The goal of the example is to enable you to run 2 differents shards\n * on the same computer with a login system.\n *\n * The naming service, admin executor service, login service, welcome service must be running.\n */\n\n\n// We're using the NeL Service framework and layer 5.\n#include \"nel/misc/config_file.h\"\n\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/login_server.h\"\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n/*\n * Connection callback for a client\n */\nvoid onConnectionClient (TSockId from, const CLoginCookie &cookie)\n{\n\tnlinfo (\"The client with uniq Id %d is connected\", cookie.getUserId ());\n\n\t// store the user id in appId\n\tfrom->setAppId (cookie.getUserId ());\n}\n\n\n/*\n * Disonnection callback for a client\n */\nvoid onDisconnectClient (TSockId from, void *arg)\n{\n\tnlinfo (\"A client with uniq Id %d has disconnected\", from->appId ());\n\n\t// tell the login system that this client is disconnected\n\tCLoginServer::clientDisconnected ((uint32) from->appId ());\n}\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public IService\n{\nprivate:\n\t/// The server on which the clients connect\n\tCCallbackServer\t\t_FEServer;\n\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// create a special connection for client (using TCP on port 37373)\n\t\tuint16\tfesPort = 37373;\n\t\ttry\n\t\t{\n\t\t\tfesPort = IService::ConfigFile.getVar(\"FESPort\").asInt();\n\t\t}\n\t\tcatch ( EUnknownVar& )\n\t\t{\n\t\t}\n\t\t_FEServer.init(fesPort);\n\t\t\n\t\t// connect and identify this front end to the login system\n\t\tCLoginServer::init (_FEServer, onConnectionClient); \n\n\t\t//\n\t\t_FEServer.setDisconnectionCallback(onDisconnectClient, NULL);\n\t}\n\n\tbool\tupdate()\n\t{\n\t\t_FEServer.update();\n\t\treturn true;\n\t}\n};\n\n/*\n * Declare a service with the class CFrontEndService, the names \"FS\" (short) and \"frontend_service\" (long).\n * The port is dynamicaly find and there s no callback array.\n */\nNLNET_SERVICE_MAIN (CFrontEndService, \"FS\", \"frontend_service\", 0, EmptyCallbackArray, \"\", \"\")\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/admin_executor_service.cfg",
    "content": "\nServices = { \"NS\", \"LS\", \"WS\" };\n\nNS = { \"r:\\code\\nelns\\naming_service\",\t\"r:\\code\\nelns\\naming_service\\debug\\naming_service.exe\" };\nLS = { \"r:\\code\\nelns\\login_service\",\t\"r:\\code\\nelns\\login_service\\debug\\login_service.exe\" };\nWS = { \"r:\\code\\nelns\\welcome_service\",\t\"r:\\code\\nelns\\welcome_service\\debug\\welcome_service.exe\" };\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/client.cfg",
    "content": "LSHost = \"localhost\";\nLogin = \"nevrax\";\nPassword = \"nevrax\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/login_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n\nPort = 49999;\t// port for the client connection (default is 49999)\n\nWSPort = 49998;\t// port for the welcome connection (default is 49998)\n\nServerVersion = 1;\t// version of shard (must match with the client version)\n\nAcceptNewUser = 1;\t// 1 if you want to add new player, 0 if you want to eject new player\n\nAcceptExternalShard = 1;\t// 1 is you accept external shard (not referenced in the config file), 0 if you want to eject unknown shards\n\nCryptPassword = 1;\t// 1 is you want to store password in crypted format, 0 for plain text\n\nBeep = 1;\t\t// 1 if you want to beep when a new client comes\n\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/login_service_database.cfg",
    "content": "Users = {\n \"test1\",\"test\",\"1\",\"\",\n \"test2\",\"test\",\"2\",\":priv1:\",\n \"test3\",\"test\",\"3\",\":priv2:\",\n \"test4\",\"test\",\"4\",\":priv1:priv2:\",\n};\n\nShards = {\n \"127.0.0.1\", \"local shard 1\",\n \"127.0.0.1\", \"local shard 2\",\n \"127.0.0.1\", \"local shard 3\",\n};\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard1_config/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\nNSPort = 50000;\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard1_config/naming_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard1_config/welcome_service.cfg",
    "content": "// address of the naming service\nNSHost = \"localhost\";\nNSPort = 50000;\n\n// address of the login service\nLSHost = \"localhost:49998\";\n\n// short name of the frontend service\nFrontendServiceName = \"FS\";\n\nWindowStyle = \"WIN\";\n\n//FrontEndAddress = \"195.68.21.196\";\n\nShardName = \"\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard2_config/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\nNSPort = 40000;\nWindowStyle = \"WIN\";\nFESPort = 37374;\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard2_config/naming_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n\nPort = 40000;\n\nBasePort = 41000;\n\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard2_config/welcome_service.cfg",
    "content": "// address of the naming service\nNSHost = \"localhost\";\nNSPort = 40000;\n\n// address of the login service\nLSHost = \"localhost:49998\";\n\n// short name of the frontend service\nFrontendServiceName = \"FS\";\n\nWindowStyle = \"WIN\";\n\n//FrontEndAddress = \"195.68.21.196\";\n\nShardName = \":priv1:\";\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard3_config/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\nNSPort = 30000;\nWindowStyle = \"WIN\";\nFESPort = 37375;\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard3_config/naming_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n\nPort = 30000;\n\nBasePort = 31000;\n\n"
  },
  {
    "path": "code/nel/samples/net/multi_shards/shard_config/shard3_config/welcome_service.cfg",
    "content": "// address of the naming service\nNSHost = \"localhost\";\nNSPort = 30000;\n\n// address of the login service\nLSHost = \"localhost:49998\";\n\n// short name of the frontend service\nFrontendServiceName = \"FS\";\n\nWindowStyle = \"WIN\";\n\n//FrontEndAddress = \"195.68.21.196\";\n\nShardName = \":priv2:\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer3/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 3 example, client.\n *\n * This client connects to a front-end server at localhost:37000.\n * It sends pings and expects pongs (ping replies).\n */\n\n\n// We're using NeL\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\nusing namespace NLMISC;\n\n// We're using CInetAddress, CMessage and CCallbackClient (because we're building a client)\n#include \"nel/net/inet_address.h\"\n#include \"nel/net/message.h\"\n#include \"nel/net/callback_client.h\"\nusing namespace NLNET;\n\n\n/*\n * Callback function called when receiving a \"PONG\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message\n * - from: the \"sockid\" of the sender (usually useless for a CCallbackClient)\n * - client: the CCallbackNetBase object (which really is a CCallbackClient object, for a client)\n *\n * Input (expected message): PONG\n * - uint32: ping counter\n *\n * Output (sent message): PING\n * - uint32: new ping counter\n */\nvoid cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& client )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\tnlinfo( \"Received PONG number %u\", counter );\n\tcounter++;\n\n\t// Output\n\tCMessage msgout ( \"PING\" );\n\tmsgout.serial( counter );\n\tclient.send( msgout );\n\tnlinfo( \"Sent PING number %u\", counter );\n}\n\n\n/*\n * Callback array\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PONG\", cbPong }\t// when receiving a \"PONG\" message, call cbPong()\n};\n\n\n/*\n * main\n */\nvoid main( int argc, char **argv )\n{\n\ttry\n\t{\n\t\t// Initialize and connect to the front-end server at localhost:37000\n\t\tCCallbackClient client;\n\t\tclient.addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]) );\n\t\tclient.connect( CInetAddress( \"localhost\" , 37000 ) );\n\n\t\t// Send a PING message\n\t\tuint32 counter = 0;\n\t\tCMessage msg( \"PING\" );\t// create the message\n\t\tmsg.serial( counter );\t\t\t\t\t\t// serialize the counter into the message\n\t\tclient.send( msg );\t\t\t\t\t\t\t// put into the send queue\n\t\tnlinfo( \"Sent PING number %u\", counter );\n\n\t\t// Main loop\n\t\twhile ( client.connected() )\n\t\t{\n\t\t\t// Perform sends and receives, call callbacks\n\t\t\tclient.update();\n\t\t}\n\n\t\tnlinfo( \"Disconnected\" );\n\t}\n\tcatch ( Exception &e )\n\t{\n\t\tnlerror( \"Error: %s\", e.what() );\n\t}\n}\n"
  },
  {
    "path": "code/nel/samples/net/net_layer3/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer3/frontend_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 3 and Service example, front-end server.\n *\n * This front-end server expects pings, and forward them to\n * the real ping server. When the ping server sends a pong back,\n * the front-end server forwards it to the client.\n *\n * To run this program, ensure there is a file \"frontend_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're building a server, using the NeL Service framework.\n// We need the naming service to know where the ping service is, so we're using CNamingClient.\n// We're using CCallbackClient when we talk to the naming service.\n// We're using CCallbackServer when we talk to our clients.\n#include \"nel/net/service.h\"\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\nusing namespace NLNET;\n\n#include <deque>\nusing namespace std;\n\n\n// The front-end server is also a client of the ping service\nCCallbackClient *ToPingService;\n\n// Temp storage (a queue because the connection to the ping service is reliable, the order is preserved)\ndeque<TSockId> ClientIds;\n\n\n/*\n * Callback function called when receiving a \"PING\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from a client)\n * - from: the \"sockid\" of the sender client\n * - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)\n *\n * Input (expected message from a client): PING\n * - uint32: ping counter\n *\n * Output (sent message to the ping server): PONG\n * - uint32: ping counter\n */\nvoid cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& frontendserver )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\tClientIds.push_back( from ); // store client sockid\n\n\t// Output\n\tCMessage msgout( \"PING\" );\n\tmsgout.serial( counter );\n\tvector<uint8> vect( 400000 );\n\tmsgout.serialCont( vect );\n\tToPingService->send( msgout );\n\n\tnlinfo( \"Received PING number %u from %s\", counter, frontendserver.hostAddress(from).asString().c_str() );\n}\n\n\n/*\n * Disconnection callback, called when a client disconnects\n */\nvoid discCallback( TSockId from, void *p )\n{\n\t// Remove all occurences of from in the queue\n\tdeque<TSockId>::iterator iq;\n\tfor ( iq=ClientIds.begin(); iq!=ClientIds.end(); )\n\t{\n\t\tif ( *iq == from )\n\t\t{\n\t\t\tiq = ClientIds.erase( iq );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tiq++;\n\t\t}\n\t}\n}\n\n\n/*\n * Callback function called when receiving a \"PONG\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from the ping server)\n * - from: the \"sockid\" of the sender (usually useless for a CCallbackClient)\n * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object)\n *\n * Input (expected message from the ping server): PONG\n * - uint32: ping counter\n * - TSockId: \"sock id\" of the client who sent the ping\n *\n * Output (sent message to a client): PONG\n * - uint32: ping counter\n */\nvoid cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& clientofthepingserver )\n{\n\tuint32 counter;\n\tTSockId clientfrom;\n\n\t// Input: process the reply of the ping service\n\tmsgin.serial( counter );\n\tclientfrom = ClientIds.front(); // retrieve client sockid\n\tClientIds.pop_front();\n\n\t// Output: send the reply to the client\n\tCCallbackServer *server = IService::getInstance()->getServer();\n\tCMessage msgout( \"PONG\" );\n\tmsgout.serial( counter );\n\tserver->send( msgout, clientfrom );\n\n\tnlinfo( \"Sent PONG number %u to %s\", counter, clientfrom->asString().c_str() );\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PING\", cbPing }\t// when receiving a \"PING\" message, call cbPing()\n};\n\n\n/*\n * Callback array for message received from the ping service\n */\nTCallbackItem PingServiceCallbackArray[] =\n{\n\t{ \"PONG\", cbPong }\t// when receiving a \"PONG\" message, call cbPong()\n};\n\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public IService\n{\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// Connect to the ping service\n\t\tToPingService = new CCallbackClient( IService::getRecordingState(), \"PS.nmr\" );\n\t\tToPingService->addCallbackArray( PingServiceCallbackArray, sizeof(PingServiceCallbackArray)/sizeof(PingServiceCallbackArray[0]) );\n\t\tif ( ! CNamingClient::lookupAndConnect( \"PS\", *ToPingService ) )\n\t\t{\n\t\t\tnlerror( \"Ping Service not available\" );\n\t\t}\n\n\t\t// Disconnection callback for the clients\n\t\tIService::getServer()->setDisconnectionCallback( discCallback, NULL );\n\t}\n\n\t/*\n\t * Update\n\t */\n\tbool update()\n\t{\n\t\tToPingService->update( 20 ); // 20 ms max\n\t\treturn ToPingService->connected(); // true continues, false stops the service\n\t}\n\n\t/*\n\t * Finalization\n\t */\n\tvoid release()\n\t{\n\t\tdelete ToPingService;\n\t}\n};\n\n \n/*\n * Declare a service with the class CFrontEndService, the names \"FS\" (short) and \"frontend_service\" (long).\n * The port is set to 37000 and the main callback array is CallbackArray.\n */\nNLNET_OLD_SERVICE_MAIN( CFrontEndService, \"FS\", \"frontend_service\", 37000, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer3/ping_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer3/ping_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 3 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're building a server, using the NeL Service framework\n#include \"nel/net/service.h\"\nusing namespace NLNET;\n\n\n/*\n * Callback function called when receiving a \"PING\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from a client)\n * - from: the \"sockid\" of the sender client\n * - server: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)\n *\n * Input (expected message from a client): PING\n * - uint32: ping counter\n *\n * Output (sent message to the ping server): PONG\n * - uint32: ping counter\n */\nvoid cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& server )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\n\t// Output\n\tCMessage msgout( \"PONG\" );\n\tmsgout.serial( counter );\n\tserver.send( msgout, from );\n\n\tnlinfo( \"PING -> PONG\" );\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PING\", cbPing }\n};\n\n\n// We use IService directly, no need to inherit from it\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_OLD_SERVICE_MAIN( IService, \"PS\", \"ping_service\", 0, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer4/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 example, client.\n *\n * This client connects to a front-end server at localhost:37000.\n * It sends pings and expects pongs (ping replies).\n */\n\n\n// We're using NeL\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\nusing namespace NLMISC;\n\n// We're using the layer 4\n#include \"nel/net/net_manager.h\"\nusing namespace NLNET;\n\n\n// Name of the front-end service\nconst char SVC [3] = \"FS\";\n\n\n/*\n * Callback function called when receiving a \"PONG\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message\n * - from: the \"sockid\" of the sender (usually useless for a CCallbackClient)\n * - client: the CCallbackNetBase object (which really is a CCallbackClient object, for a client)\n *\n * Input (expected message): PONG\n * - uint32: ping counter\n *\n * Output (sent message): PING\n * - uint32: new ping counter\n */\nvoid cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& client )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\tnlinfo( \"Received PONG number %u\", counter );\n\n\tcounter++;\n\n\t// Output\n\tCMessage msgout ( \"PING\" );\n\tmsgout.serial( counter );\n\tCNetManager::send( SVC, msgout );\n\tnlinfo( \"Sent PING number %u\", counter );\n}\n\n\n/*\n * Callback array\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PONG\", cbPong }\t// when receiving a \"PONG\" message, call cbPong()\n};\n\n\n/*\n * main\n */\nvoid main( int argc, char **argv )\n{\n\ttry\n\t{\n\t\t// Initialize (we don't call CNetManager::init() because we don't use the naming service)\n\n\t\t// Connect to the front-end server at localhost:37000\n\t\tCNetManager::addClient( SVC, \"localhost:37000\" );\n\t\tCNetManager::addCallbackArray( SVC, CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]) );\n\n\t\t// Send a PING message\n\t\tuint32 counter = 0;\n\t\tCMessage msg( \"PING\" );\t// create the message\n\t\tmsg.serial( counter );\t\t\t\t\t\t// serialize the counter into the message\n\t\tCNetManager::send( SVC, msg );\t\t\t\t\t\t\t// put into the send queue\n\t\tnlinfo( \"Sent PING number %u\", counter );\n\n\t\t// Main loop\n\t\twhile ( CNetManager::getNetBase( SVC )->connected() )\n\t\t{\n\t\t\t// Perform sends and receives, call callbacks\n\t\t\tCNetManager::update();\n\t\t}\n\n\t\tnlinfo( \"Disconnected\" );\n\n\t\t// We don't call CNetManager::release() because we didn't call CNetManager::init()\n\t}\n\tcatch ( Exception &e )\n\t{\n\t\tnlerror( \"Error: %s\", e.what() );\n\t}\n}\n"
  },
  {
    "path": "code/nel/samples/net/net_layer4/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer4/frontend_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, front-end server.\n *\n * This front-end server expects pings, and forward them to\n * the real ping server. When the ping server sends a pong back,\n * the front-end server forwards it to the client.\n *\n * Even if the connection to the ping server is broken, our\n * front-end server will keep storing the ping messages and\n * will forward them when the connection is restored.\n *\n * To run this program, ensure there is a file \"frontend_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n *\n * DEPRECATED: You should use layer5 (take a look in the layer5 sample directory)\n *\n */\n\n\n// We're using the NeL Service framework and layer 4.\n#include \"nel/net/service.h\"\n#include \"nel/net/net_manager.h\"\nusing namespace NLNET;\n\n#include <deque>\nusing namespace std;\n\n\n// Storage (a queue because the connection to the ping service is reliable, the order is preserved)\ndeque< pair<TSockId,uint32> > ClientIds;\n\n\n/*\n * Callback function called when receiving a \"PING\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from a client)\n * - from: the \"sockid\" of the sender client\n * - frontendserver: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)\n *\n * Input (expected message from a client): PING\n * - uint32: ping counter\n *\n * Output (sent message to the ping server): PONG\n * - uint32: ping counter\n */\nvoid cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& frontendserver )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\tClientIds.push_back( make_pair( from, counter ) ); // store client sockid\n\n\t// Output\n\tCMessage msgout( \"PING\" );\n\tmsgout.serial( counter );\n\tCNetManager::send( \"PS\", msgout ); // does not send if not connected\n\n\tnlinfo( \"Received PING number %u from %s\", counter, frontendserver.hostAddress(from).asString().c_str() );\n}\n\n\n/*\n * Callback function called when receiving a \"PONG\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from the ping server)\n * - from: the \"sockid\" of the sender (usually useless for a CCallbackClient)\n * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object)\n *\n * Input (expected message from the ping server): PONG\n * - uint32: ping counter\n * - TSockId: \"sock id\" of the client who sent the ping\n *\n * Output (sent message to a client): PONG\n * - uint32: ping counter\n */\nvoid cbPong( CMessage& msgin, TSockId from, CCallbackNetBase& clientofthepingserver )\n{\n\tuint32 counter;\n\tTSockId clientfrom;\n\n\t// Input: process the reply of the ping service\n\tmsgin.serial( counter );\n\n\t// Do not send in case of double ping service reply (see onDisconnectPS())\n\t// (does not work if two clients send the same counter at the same time)\n\tif ( ( !ClientIds.empty() ) && (ClientIds.front().second == counter) )\n\t{\n\t\tclientfrom = ClientIds.front().first; // retrieve client sockid\n\t\tClientIds.pop_front();\n\n\t\t// Output: send the reply to the client\n\t\tCMessage msgout( \"PONG\" );\n\t\tmsgout.serial( counter );\n\t\tCNetManager::send( \"FS\", msgout, clientfrom );\n\n\t\tnlinfo( \"Sent PONG number %u to %s\", counter, clientfrom->asString().c_str() );\n\t}\n}\n\n\n/*\n * Disonnection callback for the ping service\n */\nvoid onDisconnectPS( const std::string &serviceName, TSockId from, void *arg )\n{\n\t/* Note: the pings already forwarded should get no reply, but it may occur\n\t * (e.g. if the server reconnects before the forwarding of a PING and\n\t * the reconnection callbacks is called after that). Then onReconnectPS()\n\t * may send PINGs that have already been sent and the front-end may get\n\t * the same PONG twice. This is partially handled in cbPong.\n\t */\n\n\tnlinfo( \"Ping Service disconnecting: pongs will be delayed until reconnection\" );\n}\n\n\n/*\n * Connection callback for the ping service\n */\nvoid onReconnectPS( const std::string &serviceName, TSockId from, void *arg )\n{\n\tuint32 i;\n\tuint32 counter;\n\n\t// Output: forward all stored pings to the reconnected ping service\n\tfor ( i=0; i!=ClientIds.size(); i++ )\n\t{\n\t\tCMessage msgout( \"PING\" );\n\t\tcounter = ClientIds[i].second;\n\t\tmsgout.serial( counter );\n\t\tCNetManager::send( \"PS\", msgout );\n\t}\n\n\tnlinfo( \"Ping Service reconnected: %d pings forwarded\", ClientIds.size() );\n}\n\n\n/*\n * Disonnection callback for a client\n */\nvoid onDisconnectClient( const std::string &serviceName, TSockId from, void *arg )\n{\n\t// Erase all associated elements in the queue\n\tdeque< pair<TSockId,uint32> >::iterator iq = ClientIds.begin();\n \twhile ( iq!=ClientIds.end() )\n\t{\n\t\tif ( (*iq).first == from )\n\t\t{\n\t\t\tiq = ClientIds.erase( iq );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tiq++;\n\t\t}\n\t}\n\n\tnlinfo( \"A client has disconnected\" );\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PING\", cbPing }\t// when receiving a \"PING\" message, call cbPing()\n};\n\n\n/*\n * Callback array for message received from the ping service\n */\nTCallbackItem PingServiceCallbackArray[] =\n{\n\t{ \"PONG\", cbPong }\t// when receiving a \"PONG\" message, call cbPong()\n};\n\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public IService\n{\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// Connect to the ping service\n\t\tCNetManager::addClient( \"PS\" );\n\t\tCNetManager::addCallbackArray( \"PS\", PingServiceCallbackArray, sizeof(PingServiceCallbackArray)/sizeof(PingServiceCallbackArray[0]) );\n\t\tCNetManager::setConnectionCallback( \"PS\", onReconnectPS, NULL );\n\t\tCNetManager::setDisconnectionCallback( \"PS\", onDisconnectPS, NULL );\n\n\t\tCNetManager::setDisconnectionCallback( \"FS\", onDisconnectClient, NULL );\n\n\t}\n};\n\n \n/*\n * Declare a service with the class CFrontEndService, the names \"FS\" (short) and \"frontend_service\" (long).\n * The port is set to 37000 and the main callback array is CallbackArray.\n */\nNLNET_OLD_SERVICE_MAIN( CFrontEndService, \"FS\", \"frontend_service\", 37000, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer4/ping_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer4/ping_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n *\n * DEPRECATED: You should use layer5 (take a look in the layer5 sample directory)\n *\n */\n\n\n// We're using the NeL Service framework, and layer 4\n#include \"nel/net/service.h\"\nusing namespace NLNET;\n\n\n/*\n * Callback function called when receiving a \"PING\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from a client)\n * - from: the \"sockid\" of the sender client\n * - server: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)\n *\n * Input (expected message from a client): PING\n * - uint32: ping counter\n *\n * Output (sent message to the ping server): PONG\n * - uint32: ping counter\n */\nvoid cbPing( CMessage& msgin, TSockId from, CCallbackNetBase& server )\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\n\t// Output (uses layer 4 but this is not really necessary, see server.cpp in layer 3 example)\n\tCMessage msgout( \"PONG\" );\n\tmsgout.serial( counter );\n\tCNetManager::send( \"PS\", msgout, from );\n\n\tnlinfo( \"PING -> PONG %u\", counter );\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTCallbackItem CallbackArray[] =\n{\n\t{ \"PING\", cbPing }\n};\n\n\n// We use IService directly, no need to inherit from it\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_OLD_SERVICE_MAIN( IService, \"PS\", \"ping_service\", 0, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/flood_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";"
  },
  {
    "path": "code/nel/samples/net/net_layer5/flood_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n\n#include \"nel/misc/thread.h\"\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n\n//\nconst uint\t\t\tNumThreads = 10;\nvolatile TTime\t\tPingDates[NumThreads];\nvolatile bool\t\tServiceReady = false;\n\nvoid cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32\tcounter;\n\tmsgin.serial( counter );\n\tTTime\tpingTime = CTime::getLocalTime()-PingDates[counter];\n\tPingDates[counter] = 0;\n\tnlinfo(\"Received PONG %u (%u ms)\", counter, pingTime);\n\n\tCMessage msgout(\"ACK_POS\");\n\tCUnifiedNetwork::getInstance()->send(\"PLS\", msgout);\n}\n\nvoid sendPing(uint i)\n{\n\tPingDates[i] = CTime::getLocalTime();\n\tuint32 counter = i;\n\tCMessage msgout(\"PING\");\n\tmsgout.serial( counter );\n\tnlinfo( \"Send PING %d\", counter);\n\tCUnifiedNetwork::getInstance()->send(\"PS\", msgout);\n\tnlinfo( \"PING %d sent\", counter);\n}\n\nclass CPinger : public IRunnable\n{\nprivate:\n\tstatic volatile uint\t_PingerCount;\n\tuint\t\t\t\t\t_PingerId;\n\npublic:\n\tCPinger()\n\t{\n\t\t_PingerId = _PingerCount++;\n\t}\n\n\tvoid\trun()\n\t{\n\t\tuint\ti;\n\t\tuint\ttotalPing = 0;\n\n\t\twhile (!ServiceReady)\n\t\t{\n\t\t\tnlSleep(10);\n\t\t}\n\n\t\twhile (totalPing < 200)\n\t\t{\n\t\t\ti = rand()*200/RAND_MAX+200;\n\t\t\tnlSleep(i);\n\t\t\tif (PingDates[_PingerId] == 0)\n\t\t\t{\n\t\t\t\tsendPing(_PingerId);\n\t\t\t\t++totalPing;\n\t\t\t}\n\t\t}\n\t}\n};\n\nvolatile uint\tCPinger::_PingerCount = 0;\n\n//\nvoid cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tCMessage msgout(\"POS\");\n\tCUnifiedNetwork::getInstance()->send(\"GPMS\", msgout);\n\n\tnlinfo( \"Received POS from %s, send POS to GPMS\", serviceName.c_str());\n}\n\nvoid cbAckPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tnlinfo( \"Received ACK_POS from %s\", serviceName.c_str());\n}\n\n//\nvoid cbUpPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service connecting\");\n}\n\nvoid cbDownPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service disconnecting\");\n}\n\n//\nvoid cbUpService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is up\", serviceName.c_str(), sid.get());\n}\n\nvoid cbDownService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is down\", serviceName.c_str(), sid.get());\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"PONG\", cbPong },\n\t{ \"POS\", cbPos },\n\t{ \"ACK_POS\", cbAckPos }\n};\n\n\n//\nclass CFloodService : public IService\n{\npublic:\n\n\tbool\tupdate()\n\t{\n\t\tServiceReady = true;\n\t\treturn true;\n\t}\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\t// Connect to the ping service\n\t\tCUnifiedNetwork\t*instance = CUnifiedNetwork::getInstance();\n\n\t\tinstance->setServiceUpCallback(\"PS\", cbUpPS, NULL);\n\t\tinstance->setServiceDownCallback(\"PS\", cbDownPS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"*\", cbUpService, NULL);\n\t\tinstance->setServiceDownCallback(\"*\", cbDownService, NULL);\n\n\t\tuint\ti;\n\n\t\tfor (i=0; i<NumThreads; ++i)\n\t\t{\n\t\t\tIRunnable\t*runnable = (IRunnable *)(new CPinger());\n\t\t\tIThread\t\t*thread = IThread::create(runnable);\n\t\t\tthread->start();\n\t\t}\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_SERVICE_MAIN( CFloodService, \"FLS\", \"flood_service\", 0, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/frontend_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n\n//Networks = { \"192.168.0.0\", \"192.168.1.0\", };\n//DefaultNetworks = {  };\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/frontend_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 5 and Service example, front-end server.\n *\n * This front-end server expects pings, and forward them to\n * the real ping server. When the ping server sends a pong back,\n * the front-end server forwards it to the client.\n *\n * Even if the connection to the ping server is broken, our\n * front-end server will keep storing the ping messages and\n * will forward them when the connection is restored.\n *\n * To run this program, ensure there is a file \"frontend_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're using the NeL Service framework and layer 5.\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n\n#include <deque>\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n\n//\nTTime\tpingDate;\n\n/*\n * Callback function called when receiving a \"PONG\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from the ping server)\n * - from: the \"sockid\" of the sender (usually useless for a CCallbackClient)\n * - clientofthepingserver: the CCallbackNetBase object (which really is a CCallbackClient object)\n *\n * Input (expected message from the ping server): PONG\n * - uint32: ping counter\n * - TSockId: \"sock id\" of the client who sent the ping\n *\n * Output (sent message to a client): PONG\n * - uint32: ping counter\n */\nvoid cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32\tcounter;\n\tmsgin.serial( counter );\n\tTTime\tpingTime = CTime::getLocalTime()-pingDate;\n\n\tnlinfo(\"Received PONG %u (%u ms)\", counter, pingTime);\n}\n\nvoid sendPing()\n{\n\tpingDate = CTime::getLocalTime();\n\tuint32 counter = 0;\n\tCMessage msgout(\"PING\");\n\tmsgout.serial( counter );\n\tnlinfo( \"Send PING 0\");\n\tCUnifiedNetwork::getInstance()->send(\"PS\", msgout);\n}\n\n//\nvoid cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\t// decode the message\n\n\tTCPUCycle v1 = CTime::getPerformanceTime ();\n\n\tuint32 nbid;\n\tmsgin.serial (nbid);\n\n\tfor (uint i = 0; i < nbid; i++)\n\t{\n\t\tuint64 id;\n\t\tmsgin.serial (id);\n\t}\n\t\n\tTCPUCycle v2 = CTime::getPerformanceTime ();\n\n\tnlinfo(\"Received POS from %s (serial: %.2fs)\", serviceName.c_str(), CTime::ticksToSecond(v2-v1));\n}\n\nTTime t = 0;\n\nvoid sendRequestVision ()\n{\n//\tnlSleep (1000);\n\tCMessage msgout(\"ASK_VISION\");\n\tCUnifiedNetwork::getInstance()->send(\"GPMS\", msgout);\n\tnlinfo (\"ask a new vision\");\n\tt = CTime::getLocalTime ();\n}\n\nvoid cbVision(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32 NbValue;\n\tuint32 Value;\n\t\n\tt = CTime::getLocalTime() - t;\n\n\t//H_BEFORE (Vision);\n\n\tTCPUCycle v1 = CTime::getPerformanceTime ();\n\t//H_BEFORE (serial);\n\tmsgin.serial (NbValue);\n\t//H_AFTER (serial);\n\t//H_BEFORE (serials);\n\tfor (uint i = 0; i < NbValue; i++)\n\t\tmsgin.serial( Value );\n\t//H_AFTER (serials);\n\tTCPUCycle v2 = CTime::getPerformanceTime ();\n\n\tnlinfo(\"%dms of lag, Received Vision with %d values in %.2fms\", (uint32) t, NbValue, CTime::ticksToSecond (v2-v1)*1000.0f);\n//\tsendRequestVision();\n\n\t//H_AFTER (Vision);\n}\n\n\nvoid sendPos()\n{\n\tnlinfo(\"Simulate receive pos from client, send POS to GPMS\");\n\tCMessage msgout(\"POS\");\n\tCUnifiedNetwork::getInstance()->send(\"GPMS\", msgout);\n}\n\n//\nvoid cbUpGPMS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo( \"GPMS connecting.\");\n\tsendRequestVision ();\n}\n\n\n//\nvoid cbUpPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo( \"Ping Service connecting.\");\n\tsendPing();\n}\n\n\nvoid cbDownPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo( \"Ping Service disconnecting.\" );\n}\n\n//\nvoid cbUpService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is up\", serviceName.c_str(), sid.get());\n}\n\nvoid cbDownService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is down\", serviceName.c_str(), sid.get());\n}\n\n\n/*\n * Callback array for message received from the ping service\n */\nNLNET::TUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"POS\", cbPos },\n\t{ \"PONG\", cbPong },\n\t{ \"VISION\", cbVision }\n};\n\n\n/*\n * CFrontEndService, based on IService\n */\nclass CFrontEndService : public NLNET::IService\n{\npublic:\n\n\tbool\tupdate()\n\t{\n\t\tstatic TTime\tlastPing = CTime::getLocalTime();\n\t\tstatic TTime\tlastGetPos = CTime::getLocalTime();\n\n\t\tTTime\tctime = CTime::getLocalTime();\n\n\t\t// check vision every 2 seconds\n\t\tif (ctime - lastPing> 2000)\n\t\t{\n\t\t\tsendRequestVision();\n\t\t\tlastPing = ctime;\n\t\t}\n\n/*\n\t\t// check ping every 15 seconds\n\t\tif (ctime - lastPing> 15000)\n\t\t{\n\t\t\tsendPing();\n\t\t\tlastPing = ctime;\n\t\t}\n\n\t\t// do as if receive a position every second\n\t\tif (ctime - lastGetPos > 1000)\n\t\t{\n\t\t\tsendPos();\n\t\t\tlastGetPos = ctime;\n\t\t}\n*/\n\t\treturn true;\n\t}\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n/*\t\tuint32 u = 0xFFFFFFFF;\n\t\tuint32 z = 0;\n\n\t\tuint32 res = 0;\n\t\tCBitMemStream bms2;\n\n\t\tbms2.serial (u, 1);\n\t\tbms2.serial (z, 18);\n\t\tbms2.serial (u, 4);\n\t\tbms2.serial (z, 3);\n\n\t\tnlinfo (\"len %d\", bms2.length());\n\t\tbms2.invert ();\n\t\tnlinfo (\"len %d\", bms2.length());\n\t\tbms2.invert ();\n\t\tnlinfo (\"len %d\", bms2.length());\n*/\n/*\t\tCBitMemStream bms;\n\n\t\tnlinfo (\"len %d\", bms.length());\n\n\t\tbms.serial (u, 1);\n\t\tbms.serial (z, 18);\n\t\tbms.serial (u, 4);\n\t\tbms.serial (z, 3);\n\t\tbms.serial (u, 30);\n\t\tnlinfo (\"len %d\", bms.length());\n\n\t\tbms.clear ();\n\t\tnlinfo (\"len %d\", bms.length());\n\n\t\tbms.serial (z, 1);\n\t\tbms.serial (u, 18);\n\t\tbms.serial (z, 4);\n\t\tbms.serial (u, 3);\n\t\tbms.serial (z, 30);\n\t\tnlinfo (\"len %d\", bms.length());\n\n\n\t\tvector<uint32> cont;\n\t\tfor(uint i=0;i<32;i++) cont.push_back(i);\n\t\tbms.serialCont (cont);\n\n\t\tnlinfo (\"len %d\", bms.length());\n\n\n\t\tbms.invert ();\n\t\tnlinfo (\"len %d\", bms.length());\n\n\t\twhile (bms.getPosInBit() != 30+3+4+18+1)\n\t\t{\n\t\t\tnlinfo (\"%d\", bms.getPosInBit());\n\t\t\tbms.serial (res, 1);\n\t\t\tnlinfo ((res==0)?\"0\":\"1\");\n\t\t}\n\t\tnlinfo (\"%d\", bms.getPosInBit());\n\n\t\tvector<uint32> cont2;\n\t\tbms.serialCont (cont2);\n\t\tnlinfo (\"%d\", bms.getPosInBit());\n\t\tfor(uint j=0;j<cont2.size();j++) nlinfo (\"const %d %d\",j, cont2[j]);\n\n\t\tnlinfo (\"%d\", bms.getPosInBit());\n*/\n\t\t// Connect to the ping service\n\t\tNLNET::CUnifiedNetwork\t*instance = NLNET::CUnifiedNetwork::getInstance();\n\n\t\tinstance->setServiceUpCallback(\"PS\", cbUpPS, NULL);\n\t\tinstance->setServiceDownCallback(\"PS\", cbDownPS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"GPMS\", cbUpGPMS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"*\", cbUpService, NULL);\n\t\tinstance->setServiceDownCallback(\"*\", cbDownService, NULL);\n\t}\n};\n \n/*\n * Declare a service with the class CFrontEndService, the names \"FS\" (short) and \"frontend_service\" (long).\n * The port is set to 37000 and the main callback array is CallbackArray.\n */\nNLNET_SERVICE_MAIN( CFrontEndService, \"FS\", \"frontend_service\", 37000, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/gpm_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n\nNbId = 200000;\nIWinParam = 0;\n\n//Networks = { \"192.168.1.0\", \"192.168.0.0\" };\n//DefaultNetworks = { \"FS1\" };\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/gpm_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\nuint32 NbId = 0;\n\n//\nTTime\tpingDate;\n\nvoid cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32\tcounter;\n\tmsgin.serial( counter );\n\tTTime\tpingTime = CTime::getLocalTime()-pingDate;\n\n\tnlinfo(\"Received PONG %u (%u ms)\", counter, pingTime);\n}\n\nvoid sendPing()\n{\n\tpingDate = CTime::getLocalTime();\n\tuint32 counter = 0;\n\tCMessage msgout(\"PING\");\n\tmsgout.serial( counter );\n\tnlinfo( \"Send PING 0\");\n\tCUnifiedNetwork::getInstance()->send(\"PS\", msgout);\n}\n\n\n//\nvoid cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tCMessage msgout(\"ACK_POS\");\n\tCUnifiedNetwork::getInstance()->send(\"PLS\", msgout);\n\n\tTCPUCycle v1 = CTime::getPerformanceTime ();\n\n\tCMessage msgoutfe(\"POS\", false, CMessage::UseDefault, NbId*8);\n\n\tuint64 id = rand();\n\tmsgoutfe.serial (NbId);\n\tfor (uint i = 0; i < NbId; i++)\n\t{\n\t\tmsgoutfe.serial (id);\n\t\tid++;\n\t}\n\n\tTCPUCycle v2 = CTime::getPerformanceTime ();\n\t\n\tCUnifiedNetwork::getInstance()->send(\"FS\", msgoutfe);\n\t\n\tTCPUCycle v3 = CTime::getPerformanceTime ();\n\n\tnlinfo( \"Received POS, Sending POS to FS (serial %.2fs, send %.2fs)\", CTime::ticksToSecond (v2-v1), CTime::ticksToSecond (v3-v2));\n}\n\nvoid cbAskVision(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32 Value = '0ACE';\n\n//\tH_BEFORE (Vision);\n\n\tTCPUCycle v1 = CTime::getPerformanceTime ();\n\n//\tH_BEFORE (CMessage);\n\tCMessage msgout(\"VISION\", false, CMessage::UseDefault, 10000000);\n//\tH_AFTER (CMessage);\n//\tH_BEFORE (serial);\n\tmsgout.serial(NbId);\n//\tH_AFTER (serial);\n//\tH_BEFORE (serials);\n\tfor (uint i = 0; i < NbId; i++)\n\t\tmsgout.serial( Value );\n//\tH_AFTER(serials);\n//\tH_BEFORE (send);\n\tCUnifiedNetwork::getInstance()->send(\"FS\", msgout);\n//\tH_AFTER (send);\n\n\t/*\n\tCMessage msgout(\"VISION\");\n\tuint32 Nb = 10;\n\n\tfor (uint j = 0; j < 1000; j++)\n\t{\n\t\tmsgout.clear();\n\t\tmsgout.setType(\"VISION\");\n\t\tmsgout.serial(Nb);\n\t\tfor (uint i = 0; i < Nb; i++)\n\t\t\tmsgout.serial( Value );\n\t\tCUnifiedNetwork::getInstance()->send(\"FS\", msgout);\n\t}\n\t*/\n\tTCPUCycle v2 = CTime::getPerformanceTime ();\n\n//\tH_AFTER (Vision);\n\n\t// ca prend bcp de cpu un info...\n\tnlinfo(\"Sent Vision with %d values in %.2fms\", NbId, CTime::ticksToSecond (v2-v1)*1000.0f);\n}\n\n//\nvoid cbUpPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service connecting\");\n\tsendPing();\n}\n\nvoid cbDownPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service disconnecting\");\n}\n\n//\nvoid cbUpFS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"F Service connecting\");\n\tsendPing();\n}\n\nvoid cbDownFS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"F Service disconnecting\");\n}\n\n//\nvoid cbUpService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is up\", serviceName.c_str(), sid.get());\n\n\tCMessage msgout(\"TOTO\");\n\tuint32 i = 10;\n\tmsgout.serial(i);\n\tCUnifiedNetwork::getInstance()->send(sid, msgout);\n}\n\nvoid cbDownService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is down\", serviceName.c_str(), sid.get());\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"PONG\", cbPong },\n\t{ \"POS\", cbPos },\n\t{ \"ASK_VISION\", cbAskVision }\n};\n\nvoid cbVar (CConfigFile::CVar &var)\n{\n\tif (var.Name == \"NbId\") NbId = var.asInt ();\n\telse nlstop;\n}\n\n//\nclass CGPMService : public IService\n{\npublic:\n\n\tbool\tupdate()\n\t{\n\t\tstatic TTime\tlastPing = CTime::getLocalTime();\n\n\t\tTTime\tctime = CTime::getLocalTime();\n/*\n\t\t// check ping every 15 seconds\n\t\tif (ctime - lastPing > 15000)\n\t\t{\n\t\t\tsendPing();\n\t\t\tlastPing = ctime;\n\t\t}\n*/\n\n\t\treturn true;\n\t}\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n//\t\tnlerror (\"oups\");\n/*\t\t//nlassert(false);\n\t\tchar *p=0;\n\t\tp[0]=0;\n\t\tprintf(p);\n*/\n\t\tConfigFile.setCallback (\"NbId\", cbVar);\n\t\tcbVar (ConfigFile.getVar (\"NbId\"));\n\n\t\t// Connect to the ping service\n\t\tCUnifiedNetwork\t*instance = CUnifiedNetwork::getInstance();\n\n\t\tinstance->setServiceUpCallback(\"PS\", cbUpPS, NULL);\n\t\tinstance->setServiceDownCallback(\"PS\", cbDownPS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"FS\", cbUpFS, NULL);\n\t\tinstance->setServiceDownCallback(\"FS\", cbDownFS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"*\", cbUpService, NULL);\n\t\tinstance->setServiceDownCallback(\"*\", cbDownService, NULL);\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_SERVICE_MAIN( CGPMService, \"GPMS\", \"gpm_service\", 0, CallbackArray, \"\", \"\" )\n\nNLMISC_COMMAND (wait, \"\", \"<time>\")\n{\n\tif(args.size() != 1) return false;\n\n\tnlSleep (atoi (args[0].c_str()));\n\n\treturn true;\n}\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/ping_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/ping_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 5 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/displayer.h\"\n\nusing namespace NLNET;\nusing namespace NLMISC;\n\nCFileDisplayer fd(\"ps.log\");\n\n/*\n * Callback function called when receiving a \"PING\" message\n *\n * Arguments:\n * - msgin:\tthe incoming message (coming from a client)\n * - from: the \"sockid\" of the sender client\n * - server: the CCallbackNetBase object (which really is a CCallbackServer object, for a server)\n *\n * Input (expected message from a client): PING\n * - uint32: ping counter\n *\n * Output (sent message to the ping server): PONG\n * - uint32: ping counter\n */\nvoid cbPing(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tuint32 counter;\n\n\t// Input\n\tmsgin.serial( counter );\n\n\t// Output (uses layer 4 but this is not really necessary, see server.cpp in layer 3 example)\n\tCMessage msgout(\"PONG\");\n\tmsgout.serial( counter );\n\tCUnifiedNetwork::getInstance()->send(sid, msgout);\n\n\tnlinfo( \"PING -> PONG %u\", counter );\n}\n\n//\nvoid cbUpService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is up\", serviceName.c_str(), sid.get());\n\n\t// Output (uses layer 4 but this is not really necessary, see server.cpp in layer 3 example)\n\tCMessage msgout(\"PONG\");\n\tuint32 counter = 0xFFFFFFFF;\n\tmsgout.serial( counter );\n\tCUnifiedNetwork::getInstance()->send(sid, msgout);\n}\n\nvoid cbDownService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is down\", serviceName.c_str(), sid.get());\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"PING\", cbPing }\n};\n\n\n//\nclass CPingService : public IService\n{\npublic:\n\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\tDebugLog->addDisplayer (&fd);\n\t\tInfoLog->addDisplayer (&fd);\n\t\tWarningLog->addDisplayer (&fd);\n\t\tErrorLog->addDisplayer (&fd);\n\n\t\t// Connect to the ping service\n\t\tCUnifiedNetwork\t*instance = CUnifiedNetwork::getInstance();\n\n\t\tinstance->setServiceUpCallback(\"*\", cbUpService, NULL);\n\t\tinstance->setServiceDownCallback(\"*\", cbDownService, NULL);\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_SERVICE_MAIN( CPingService, \"PS\", \"ping_service\", 0, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/player_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n"
  },
  {
    "path": "code/nel/samples/net/net_layer5/player_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/*\n * Layer 4 and Service example, ping server.\n *\n * This ping service expects pings, sends pongs back.\n *\n * To run this program, ensure there is a file \"ping_service.cfg\"\n * containing the location of the naming service (NSHost, NSPort)\n * in the working directory. The naming service must be running.\n */\n\n\n// We're using the NeL Service framework, and layer 5\n#include \"nel/net/service.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/displayer.h\"\n\nusing namespace std;\nusing namespace NLNET;\nusing namespace NLMISC;\n\n\nCFileDisplayer fd(\"pls.log\");\nbool PingServiceUp = false;\n\n//\nTTime pingDate;\n\nvoid cbPong(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tnlassert (PingServiceUp);\n\tuint32\tcounter;\n\tmsgin.serial( counter );\n\tTTime\tpingTime = CTime::getLocalTime()-pingDate;\n\n\tnlinfo(\"Received PONG %u (%u ms)\", counter, pingTime);\n}\n\nvoid sendPing()\n{\n\tnlassert (PingServiceUp);\n\tpingDate = CTime::getLocalTime();\n\tuint32 counter = 0;\n\tCMessage msgout(\"PING\");\n\tmsgout.serial( counter );\n\tnlinfo( \"Send PING 0\");\n\tCUnifiedNetwork::getInstance()->send(\"PS\", msgout);\n}\n\n//\nvoid cbPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tCMessage msgout(\"POS\");\n\tCUnifiedNetwork::getInstance()->send(\"GPMS\", msgout);\n\n\tnlinfo( \"Received POS from %s, send POS to GPMS\", serviceName.c_str());\n}\n\nvoid cbAckPos(CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\tnlinfo( \"Received ACK_POS from %s\", serviceName.c_str());\n}\n\n//\nvoid cbUpPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service connecting\");\n\tPingServiceUp = true;\n\tsendPing();\n}\n\nvoid cbDownPS(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Ping Service disconnecting\");\n}\n\n//\nvoid cbUpService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is up\", serviceName.c_str(), sid.get());\n}\n\nvoid cbDownService(const std::string &serviceName, TServiceId sid, void *arg)\n{\n\tnlinfo(\"Service %s %d is down\", serviceName.c_str(), sid.get());\n}\n\n\n/*\n * Callback array for messages received from a client\n */\nTUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"PONG\", cbPong },\n\t{ \"POS\", cbPos },\n\t{ \"ACK_POS\", cbAckPos }\n};\n\n\n//\nclass CPlayerService : public IService\n{\npublic:\n\n\tbool\tupdate()\n\t{\n\t\tstatic TTime\tlastPing = CTime::getLocalTime();\n\n\t\tTTime\tctime = CTime::getLocalTime();\n\n\t\t// check ping every 15 seconds\n\t\tif (ctime - lastPing > 15000)\n\t\t{\n\t\t\tif (PingServiceUp)\n\t\t\t\tsendPing();\n\t\t\tlastPing = ctime;\n\t\t}\n\n\t\treturn true;\n\t}\n\t/*\n\t * Initialization\n\t */\n\tvoid init()\n\t{\n\t\tDebugLog->addDisplayer (&fd);\n\t\tInfoLog->addDisplayer (&fd);\n\t\tWarningLog->addDisplayer (&fd);\n\t\tErrorLog->addDisplayer (&fd);\n\n\t\t// Connect to the ping service\n\t\tCUnifiedNetwork\t*instance = CUnifiedNetwork::getInstance();\n\n\t\tinstance->setServiceUpCallback(\"PS\", cbUpPS, NULL);\n\t\tinstance->setServiceDownCallback(\"PS\", cbDownPS, NULL);\n\n\t\tinstance->setServiceUpCallback(\"*\", cbUpService, NULL);\n\t\tinstance->setServiceDownCallback(\"*\", cbDownService, NULL);\n\t}\n};\n\n\n/*\n * Declare a service with the class IService, the names \"PS\" (short) and \"ping_service\" (long).\n * The port is automatically allocated (0) and the main callback array is CallbackArray.\n */\nNLNET_SERVICE_MAIN( CPlayerService, \"PLS\", \"player_service\", 0, CallbackArray, \"\", \"\" )\n"
  },
  {
    "path": "code/nel/samples/net/service/chat_service.cfg",
    "content": "NSHost = \"localhost\";\n\nWindowStyle = \"WIN\";\n\nDontUseNS=1;\nDontUseAES=0;\n\n//DisplayedVariables += { \"\", \"MemUsed|ProcessUsedMemory\" };\n"
  },
  {
    "path": "code/nel/samples/net/service/chat_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <string>\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/system_info.h\"\n\n// contains the service base class\n#include \"nel/net/service.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n// a service is a process, a program. the goal is to automatically use\n// common initialization and features (like command line, file check,\n// debug features, signal redirection and more).\n\n// a service has a listen socket for external connection. when a message\n// comes on the socket, the message is automatically updated and the\n// associated callback is called.\n\n// to create a service, you have to inherit from IService and to implement\n// a few functions (init, update, release). you are not forced to implement\n// these functions if you have nothing to do in them.\n\n// to launch a service, the naming_service must run.\n\n\n// this stupid example creates a chat service. it's a 1 person chat, it\n// means that you can send strings to the service and it sends them back to you\n// (and only to you) so you can't see strings from other people :)\n// (i warned you! it's really stupid!)\n\nclass CChatService : public IService\n{\npublic:\n\n//\tFILE *fp;\n\n\tvoid init ()\n\t{\n\t\t// this function is called after all standard service initialization.\n\t\t// put here your code that inits your application.\n\n\t\tnlinfo (\"init() was called\");\n\n//\t\tfp = fopen (NLMISC::CFile::findNewFile(\"stat.csv\").c_str(), \"wt\");\n\t}\n\n\tbool update ()\n\t{\n\t\t// this function is called every \"loop\". you return true if you want\n\t\t// to continue or return false if you want to exit the service.\n\t\t// the loop is called evenly (by default, at least one time per second).\n\n\t\tnlinfo (\"update() was called\");\n\n\t\t/*\t\tstatic uint ii = 0;\n\t\tif(ii++ == 15)\n\t\t  {\n\t\t\tnlstop;\n\t\t\t}*/\n\n//////debug to test log flood for memory leak\n\n//\t\tDebugLog->addNegativeFilter(\"flood\");\n//\t\tInfoLog->addNegativeFilter(\"flood\");\n//\t\tWarningLog->addNegativeFilter(\"flood\");\n\n\t  /*\t\tstring s;\n\n\t\tuint v = (uint)frand(80), i;\n\t\tfor (i = 0; i < v; i++)\n\t\t{\n\t\t\ts+='a'+rand()%26;\n\t\t}\n\t\n\t\tstatic uint32 val = 0;\n\t\tfor(i = 0; i < 10; i++)\n\t\t{\n\t\t\tnldebug (\"debg flood %d %s\", val++, s.c_str());\n\t\t\tnlinfo (\"info flood %d %s\", val++, s.c_str());\n\t\t\tnlwarning (\"warn flood %d %s\", val++, s.c_str());\n//\t\t\tnldebug (\"debg flood %10d %s %d %d\", val++, bytesToHumanReadable(CSystemInfo::getAllocatedSystemMemory ()).c_str(), UserSpeedLoop, NetSpeedLoop);\n//\t\t\tnlinfo (\"info flood %10d %s %d %d\", val++, bytesToHumanReadable(CSystemInfo::getAllocatedSystemMemory ()).c_str(), UserSpeedLoop, NetSpeedLoop);\n//\t\t\tnlwarning (\"warn flood %10d %s %d %d\", val++, bytesToHumanReadable(CSystemInfo::getAllocatedSystemMemory ()).c_str(), UserSpeedLoop, NetSpeedLoop);\n\t\t}\n\t  */\n/////////\n//\t\tfprintf (fp, \"%d;%d;%d\\n\", CMemUtils::getAllocatedSystemMemory (), UserSpeedLoop, NetSpeedLoop);\n//\t\tfflush (fp);\n\t\treturn true;\n\t}\n\n\tvoid release ()\n\t{\n\t\t// this function is called before all standard service release code.\n\t\t// put here your code that releases your application.\n\n//\t\tfclose (fp);\n\n\t\tnlinfo (\"release() was called\");\n\t}\n};\n\n\n// each time the message CHAT is received, this function is called.\n// the first param contains parameters of the message. the second one is the\n// identifier of who sent this message\nstatic void cbChat (CMessage &msgin, const std::string &serviceName, TServiceId sid)\n{\n\t// get the chat string of the client\n\tstring chat;\n\tmsgin.serial (chat);\n\n\t// create the message to send to the other\n\tCMessage msgout (\"CHAT\");\n\tmsgout.serial (chat);\n\n\t// send it back to the sender\n\tCUnifiedNetwork::getInstance()->send (sid, msgout);\n}\n\n\n// this array contains all callback functions. it associates the callbackname (messagename),\n// with a callback\nTUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"CHAT\", cbChat }\n};\n\n\n// this macro is the \"main\". the first param is the class name inherited from IService.\n// the second one is the name of the service used to register and find the service\n// using the naming service. the third one is the port where the listen socket will\n// be created. If you put 0, the system automatically finds a port.\nNLNET_SERVICE_MAIN (CChatService, \"CS\", \"chat_service\", 0, CallbackArray, \"\", \"\");\n"
  },
  {
    "path": "code/nel/samples/net/udp/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp)\n\nADD_EXECUTABLE(nl_sample_udpclient client.cpp graph.cpp graph.h simlag.cpp simlag.h)\n\nADD_EXECUTABLE(nl_sample_udpserver WIN32 bench_service.cpp receive_task.cpp receive_task.h)\n\nADD_DEFINITIONS(-DUDP_DIR=\"\\\\\"${NL_SHARE_ABSOLUTE_PREFIX}/nl_sample_udp/\\\\\"\")\n\nTARGET_LINK_LIBRARIES(nl_sample_udpclient nelmisc nelnet)\nTARGET_LINK_LIBRARIES(nl_sample_udpserver nelmisc nelnet)\n\nNL_DEFAULT_PROPS(nl_sample_udpclient \"NeL, Samples, Net, UDP: UDP Client\")\nNL_DEFAULT_PROPS(nl_sample_udpserver \"NeL, Samples, Net, UDP: UDP Server\")\nNL_ADD_RUNTIME_FLAGS(nl_sample_udpclient)\nNL_ADD_RUNTIME_FLAGS(nl_sample_udpserver)\n\nINSTALL(TARGETS nl_sample_udpclient nl_sample_udpserver RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samplesnet)\nINSTALL(FILES bench_service.cfg client.cfg readme.txt DESTINATION ${NL_SHARE_PREFIX}/nl_sample_udp COMPONENT samplesnet)\n\nIF(WITH_3D)\n  INSTALL(FILES n019003l.pfb DESTINATION ${NL_SHARE_PREFIX}/nl_sample_udp COMPONENT samplesnet)\nENDIF(WITH_3D)\n"
  },
  {
    "path": "code/nel/samples/net/udp/bench_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n\nDontUseAES = 1;\nDontUseNS = 1;\n"
  },
  {
    "path": "code/nel/samples/net/udp/bench_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n\n#include <string>\n#include <map>\n#include <time.h>\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <direct.h>\n#\tdefine mkdir _mkdir\n#else\n#\tinclude <sys/stat.h>\n#\tdefine mkdir(a) mkdir(a,0755)\n#endif\n\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/mem_stream.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/net/service.h\"\n#include \"nel/net/udp_sock.h\"\n\n#include \"receive_task.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\n#ifndef UDP_DIR\n#define UDP_DIR \"\"\n#endif // UDP_DIR\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n//\n// Structures\n//\n\nstruct CClient\n{\n\tCClient (TSockId from, uint32 session, const string &cn) : From(from), Session(session), NextPingNumber(0), LastPongReceived(0), ConnectionName(cn),\n\t\tBlockNumber(0), FullMeanPongTime(0), FullNbPong(0), NbPing(0), NbPong(0), MeanPongTime(0), NbDuplicated(0), FirstWrite(true)\n\t{ PongReceived.resize (1001); }\n\n\tCInetAddress\tAddress;\t// udp address\n\tTSockId\t\t\tFrom;\t\t// used to find the TCP connection\n\tuint32\t\t\tSession;\t// used to find the link between UDP and TCP connection at startup\n\n\tvector<pair<uint8, uint16> >\tPongReceived;\t// contains the number of pong receive for each message number and the time\n\n\tuint32\t\t\tNextPingNumber, LastPongReceived;\n\tstring\t\t\tConnectionName;\n\n\t// this number is increase each time we filled the PongReceived array, the goal is to avoid a very old packet to use as a new one\n\tuint32\t\t\tBlockNumber;\n\n\tuint32\t\t\tFullMeanPongTime, FullNbPong;\n\n\t// used for stat, reset every stat update\n\tuint32\t\t\tNbPing, NbPong, MeanPongTime, NbDuplicated;\n\n\t// true if the client just connect and we don't log stat\n\tbool\t\t\tFirstWrite;\n\n\tvoid updatePong (sint64 pingTime, sint64 pongTime, uint32 pongNumber, uint32 blockNumber);\n\tvoid updateStat ();\n\tvoid updateFullStat ();\n};\n\nstruct TInetAddressHash\n{\n\tstatic const size_t bucket_size = 4;\n\tstatic const size_t min_buckets = 8;\n\n\tinline bool operator() (const NLNET::CInetAddress &x1, const NLNET::CInetAddress &x2) const\n\t{\n\t\treturn x1 == x2;\n\t}\n\n\t/// Hash function\n\tinline size_t operator() ( const NLNET::CInetAddress& x ) const\n\t{\n\t\treturn x.port();\n\t\t//return x.internalIPAddress();\n\t}\n};\n\n//\n// Types\n//\n\ntypedef CHashMap<NLNET::CInetAddress,CClient*,TInetAddressHash> TClientMap;\n#define GETCLIENTA(it) (*it).second\n\n//\n// Variables\n//\n\n// must be increase at each version and must be the same value as the client\nuint32\t\t\t\tVersion = 2;\n\nstring\t\t\t\tStatPathName = \"stats/\";\n\nuint16\t\t\t\tUDPPort = 45455;\nuint16\t\t\t\tTCPPort = 45456;\nuint32\t\t\t\tMaxUDPPacketSize = 1000;\n\nCBufFIFO\t\t\tQueue1, Queue2;\n\nCBufFIFO\t\t\t*CurrentReadQueue = NULL;\n\nTReceivedMessage\t*CurrentInMsg = NULL;\n\nIThread\t\t\t\t*ReceiveThread = NULL;\nCReceiveTask\t\t*ReceiveTask = NULL;\n\nlist<CClient>\t\tClients;\t// contains all clients\nTClientMap\t\t\tClientMap;\t// contains a quick access to the client using the udp address\n\n// TCP server for clients\nCCallbackServer\t\t*CallbackServer = NULL;\n\n//\n// Functions\n//\n\nstring getDate()\n{\n\tstruct tm *newtime;\n\ttime_t long_time;\n\ttime( &long_time );\n\tnewtime = localtime( &long_time );\n\tif (newtime)\n\t{\n\t\tstring res = toString(\"%02d\", newtime->tm_year-100) + \"_\";\n\t\tres += toString(\"%02d\", newtime->tm_mon+1) + \"_\";\n\t\tres\t+= toString(\"%02d\", newtime->tm_mday);\n\t\treturn res;\n\t}\n\n\treturn \"bad date \"+toString( (uint32)long_time);\n}\n\n//\n// Callbacks\n//\n\nvoid cbInit (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tuint64 session = (uint64)(uintptr_t) from;\n\n\tstring connectionName;\n\tmsgin.serial (connectionName);\n\n\ttry\n\t{\n\t\tuint32 version;\n\t\tmsgin.serial (version);\n\t\tif (version != Version)\n\t\t{\n\t\t\t// bad client version, disconnect it\n\t\t\tCallbackServer->disconnect (from);\n\t\t\treturn;\n\t\t}\n\t}\n\tcatch (const Exception &)\n\t{\n\t\t// bad client version, disconnect it\n\t\tCallbackServer->disconnect (from);\n\t\treturn;\n\t}\n\n\tCMessage msgout (\"INIT\");\n\tmsgout.serial (session);\n\tCallbackServer->send (msgout, from);\n\n\tClients.push_back(CClient(from, (uint32)session, connectionName));\n\tnlinfo (\"Added client TCP %s, session %x\", from->asString().c_str(), session);\n}\n\nvoid cbDisconnect (TSockId from, void *arg)\n{\n\tfor (list<CClient>::iterator it = Clients.begin(); it != Clients.end(); it++)\n\t{\n\t\tif ((*it).From == from)\n\t\t{\n\t\t\t// clear struct\n\t\t\t(*it).updateFullStat();\n\t\t\tnlinfo( \"Removing client %s\", (*it).Address.asString().c_str() );\n\t\t\tClientMap.erase ((*it).Address);\n\t\t\tClients.erase (it);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n//\n// Callback Array\n//\n\nTCallbackItem CallbackArray[] =\n{\n\t{ \"INIT\", cbInit },\n};\n\n\n\nvoid CClient::updatePong (sint64 pingTime, sint64 pongTime, uint32 pongNumber, uint32 blockNumber)\n{\n\t// it means that it s a too old packet, discard it\n\tif (blockNumber != BlockNumber)\n\t\treturn;\n\n\t// add the pong in the array to detect lost, duplication\n\tif (pongNumber >= PongReceived.size())\n\t{\n\t\t// if the array is too big, we flush actual data and restart all\n\t\tupdateFullStat ();\n\t\treturn;\n\t}\n\n\tPongReceived[pongNumber].first++;\n\n\tif (PongReceived[pongNumber].first > 1)\n\t{\n\t\tNbDuplicated++;\n\t}\n\telse\n\t{\n\t\t// increase only for new pong\n\t\tNbPong++;\n\t\tMeanPongTime += (uint32)(pongTime-pingTime);\n\t\n\t\tFullNbPong++;\n\t\tFullMeanPongTime += (uint32)(pongTime-pingTime);\n\n\t\tPongReceived[pongNumber].second = (uint16)(pongTime - pingTime);\n\t}\n\n\tif (pongNumber > LastPongReceived)\n\t\tLastPongReceived = pongNumber;\n\n\t// write each pong in a file\n\tstring ha = Address.hostName();\n\tif (ha.empty())\n\t{\n\t\tha = Address.ipAddress();\n\t}\n\tstring fn = StatPathName + ConnectionName + \"_\" + ha + \"_\" + getDate() + \".pong\";\n\t\n\tFILE *fp = fopen (fn.c_str(), \"rt\");\n\tif (fp == NULL)\n\t{\n\t\t// new file, add the header\n\t\tFILE *fp = fopen (fn.c_str(), \"wt\");\n\t\tif (fp != NULL)\n\t\t{\n\t\t\tfprintf (fp, \"#%s\\t%s\\t%s\\t%s\\n\", \"PingTime\", \"PongTime\", \"Delta\", \"PingNumber\");\n\t\t\tfclose (fp);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfclose (fp);\n\t}\n\n\tfp = fopen (fn.c_str(), \"at\");\n\tif (fp == NULL)\n\t{\n\t\tnlwarning (\"Can't open pong file name '%s'\", fn.c_str());\n\t}\n\telse\n\t{\n\t\tfprintf (fp, \"%\"NL_I64\"d\\t%\"NL_I64\"d\\t%\"NL_I64\"d\\t%d\\n\", pongTime, pingTime, (pongTime-pingTime), pongNumber);\n\t\tfclose (fp);\n\t}\n}\n\nvoid CClient::updateFullStat ()\n{\n\tuint32 NbLost = 0, NbDup = 0, NbPong = 0;\n\n/*\tif (Address.hostName().empty())\n\t{\n\t\t// don't log because we receive no pong at all\n\t\treturn;\n\t}*/\n\n\tfor (uint i = 0; i < LastPongReceived; i++)\n\t{\n\t\tif (PongReceived[i].first == 0) NbLost++;\n\t\telse \n\t\t{\n\t\t\tNbPong++;\n\t\t\tNbDup += PongReceived[i].first - 1;\n\t\t}\n\t}\n\n\t{\n\t\t// write each pong in a file\n\t\tstring ha = Address.hostName();\n\t\tif (ha.empty())\n\t\t{\n\t\t\tha = Address.ipAddress();\n\t\t}\n\t\tstring fn = StatPathName + ConnectionName + \"_\" + ha + \"_\" + getDate() + \".stat\";\n\t\t\n\t\tstring line = \"Full Summary: \";\n\t\tline += \"NbPing \" + toString(LastPongReceived) + \" \";\n\t\tline += \"NbPong \" + toString(NbPong) + \" \";\n\t\tline += \"NbLost \" + toString(NbLost) + \" \";\n\t\tif (LastPongReceived>0) line += \"(\" + toString((float)NbLost/LastPongReceived*100.0f) + \"pc) \";\n\t\tline += \"NbDuplicated \" + toString(NbDup) + \" \";\n\t\tif (LastPongReceived>0) line += \"(\" + toString((float)NbDup/LastPongReceived*100.0f) + \"pc) \";\n\n\t\tif (FullNbPong == 0)\n\t\t\tline += \"MeanPongTime <Undef> \";\n\t\telse\n\t\t\tline += \"MeanPongTime \" + toString(FullMeanPongTime/FullNbPong) + \" \";\n\n\t\tFILE *fp = fopen (fn.c_str(), \"at\");\n\t\tif (fp == NULL)\n\t\t{\n\t\t\tnlwarning (\"Can't open stat file name '%s'\", fn.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfprintf (fp, \"%s\\n\", line.c_str());\n\t\t\tfclose (fp);\n\n\t\t\t// send the full sumary to the client\n\t\t\tCMessage msgout(\"INFO\");\n\t\t\tmsgout.serial(line);\n\t\t\tCallbackServer->send (msgout, From);\n\t\t}\n\n\t\tnlinfo (line.c_str());\n\t}\n\n\n\t{\n\t\t// write each ping in a file\n\t\tstring ha = Address.hostName();\n\t\tif (ha.empty())\n\t\t{\n\t\t\tha = Address.ipAddress();\n\t\t}\n\t\tstring fn = StatPathName + ConnectionName + \"_\" + ha + \"_\" + getDate() + \".ping\";\n\t\t\n\t\tFILE *fp = fopen (fn.c_str(), \"rt\");\n\t\tif (fp == NULL)\n\t\t{\n\t\t\t// new file, add the header\n\t\t\tFILE *fp = fopen (fn.c_str(), \"wt\");\n\t\t\tif (fp != NULL)\n\t\t\t{\n\t\t\t\tfprintf (fp, \"#%s\\t%s\\n\", \"NbPongRcv\", \"Delta\");\n\t\t\t\tfclose (fp);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfclose (fp);\n\t\t}\n\n\t\tfp = fopen (fn.c_str(), \"at\");\n\t\tif (fp == NULL)\n\t\t{\n\t\t\tnlwarning (\"Can't open ping file name '%s'\", fn.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// add a fake value to know that it s a different session\n\t\t\tfprintf (fp, \"-1\\t0\\n\");\n\t\t\tfor (uint i = 0; i < LastPongReceived; i++)\n\t\t\t{\n\t\t\t\tfprintf (fp, \"%d\\t%d\\n\", PongReceived[i].first, PongReceived[i].second);\n\t\t\t}\n\t\t\tfclose (fp);\n\t\t}\n\t}\n\n\t// clear all structures\n\n\tPongReceived.clear ();\n\tPongReceived.resize (1001);\n\n\tBlockNumber++;\n\n\tNextPingNumber = LastPongReceived = 0;\n\n\tFullMeanPongTime = FullNbPong = 0;\n\n//\tNbPing = NbPong = MeanPongTime = NbDuplicated = 0;\n}\n\nvoid CClient::updateStat ()\n{\n\t// write each pong in a file\n\tstring ha = Address.hostName();\n\tif (ha.empty())\n\t{\n\t\tha = Address.ipAddress();\n\t}\n\tstring fn = StatPathName + ConnectionName + \"_\" + ha + \"_\" + getDate() + \".stat\";\n\t\n\tstring line;\n\tline += \"NbPing \" + toString(NbPing) + \" \";\n\tline += \"NbPong \" + toString(NbPong) + \" \";\n\tif (NbPong == 0)\n\t\tline += \"MeanPongTime <Undef> \";\n\telse\n\t\tline += \"MeanPongTime \" + toString(MeanPongTime/NbPong) + \" \";\n\tline += \"NbDuplicated \" + toString(NbDuplicated) + \" \";\n\n\tFILE *fp = fopen (fn.c_str(), \"at\");\n\tif (fp == NULL)\n\t{\n\t\tnlwarning (\"Can't open stat file name '%s'\", fn.c_str());\n\t}\n\telse\n\t{\n\t\tif (FirstWrite)\n\t\t{\n\t\t\t//nlassert (!Address.hostName().empty())\n\t\t\tfprintf (fp, \"HostAddress: %s\\n\", Address.asString().c_str());\n\t\t\tFirstWrite = false;\n\t\t}\n\t\t\n\t\tfprintf (fp, \"%s\\n\", line.c_str());\n\t\tfclose (fp);\n\t}\n\n\tnlinfo (line.c_str());\n\n\tCMessage msgout(\"INFO\");\n\tmsgout.serial(line);\n\tCallbackServer->send (msgout, From);\n\n\tNbPing = NbPong = MeanPongTime = NbDuplicated = 0;\n}\n\nvoid updateStat ()\n{\n\tstatic sint64 lastUpdate = CTime::getLocalTime ();\n\n\tif (CTime::getLocalTime() - lastUpdate < 2*1000)\n\t\treturn;\n\n\tlastUpdate = CTime::getLocalTime();\n\n\t// update stat only at the linked UDP-TCP connection\n\tfor (TClientMap::iterator it = ClientMap.begin (); it != ClientMap.end(); it++)\n\t{\n\t\tGETCLIENTA(it)->updateStat ();\n\t}\n}\n\n\n//\n// Functions\n//\n\n\nvoid removeClientByAddr( TClientMap::iterator iclient )\n{\n\tif ( iclient == ClientMap.end() )\n\t{\n\t\t// It may have already been removed on purpose\n\t\treturn;\n\t}\n\n\tfor (list<CClient>::iterator it = Clients.begin(); it != Clients.end(); it++)\n\t{\n\t\tif ((*it).Address == (*iclient).first)\n\t\t{\n\t\t\t(*it).updateFullStat();\n\t\t\tnlinfo( \"Removing client %s\", GETCLIENTA(iclient)->Address.asString().c_str() );\n\t\t\tClients.erase(it);\n\t\t\tbreak;\n\t\t}\n\t}\n\tClientMap.erase( iclient );\n}\n\nvoid handleReceivedPong (CClient *client, sint64 pongTime)\n{\n\t// Preconditions\n\tnlassert( CurrentInMsg && (! CurrentInMsg->data().empty()) );\n\n\t// Prepare message to read\n\tCMemStream msgin( true );\n\tuint32 currentsize = CurrentInMsg->userSize();\n\n\tmemcpy (msgin.bufferToFill (currentsize), CurrentInMsg->userDataR(), currentsize);\n\n\t// Read the header\n\tuint8 mode = 0;\n\tmsgin.serial (mode);\n\n\tif (mode == 0)\n\t{\n\t\t// init the UDP connection\n\t\tif (client == NULL)\n\t\t{\n\t\t\tuint32 session = 0;\n\t\t\tmsgin.serial (session);\n\n\t\t\t// Find a new udp connection, find the linked \n\t\t\tlist<CClient>::iterator it;\n\t\t\tfor (it = Clients.begin(); it != Clients.end(); it++)\n\t\t\t{\n\t\t\t\tif ((*it).Session == session)\n\t\t\t\t{\n\t\t\t\t\tclient = &(*it);\n\t\t\t\t\t// Found it, add in the map\n\t\t\t\t\tclient->Address = CurrentInMsg->AddrFrom;\n\t\t\t\t\tClientMap.insert (make_pair (client->Address, client));\n\t\t\t\t\tnlinfo (\"TCP-UDP linked TCP is %s, UDP is %s\", client->From->asString().c_str(), client->Address.asString().c_str());\n\n\t\t\t\t\t// Send a TCP message to the client to say that we can start\n\t\t\t\t\tCMessage msgout (\"START\");\n\t\t\t\t\tCallbackServer->send (msgout, client->From);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (it == Clients.end())\n\t\t\t{\n\t\t\t\tnlwarning (\"Unknown TCP client, discard the UDP message (hacker?)\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\telse if (mode == 1)\n\t{\n\t\tif (client == NULL)\n\t\t{\n\t\t\tnlwarning (\"Received a UDP packet from an old client (hacker?)\");\n\t\t\treturn;\n\t\t}\n\n\t\t// Read the message\n\t\tsint64 pingTime = 0;\n\t\tmsgin.serial(pingTime);\n\n\t\tuint32 pongNumber = 0;\n\t\tmsgin.serial(pongNumber);\n\n\t\tuint32 blockNumber = 0;\n\t\tmsgin.serial(blockNumber);\n\n//\t\tnlinfo (\"receive a pong from %s pongnb %d %\"NL_I64\"d\", CurrentInMsg->AddrFrom.asString().c_str(), pongNumber, pongTime - pingTime);\n\n\t\tclient->updatePong (pingTime, pongTime, pongNumber, blockNumber);\n\t}\n}\n\nvoid sendPing ()\n{\n\tCMemStream msgout;\n\tfor (TClientMap::iterator it = ClientMap.begin (); it != ClientMap.end(); it++)\n\t{\n\t\tmsgout.clear();\n\n\t\tsint64 t = CTime::getLocalTime ();\n\t\tmsgout.serial (t);\n\n\t\tuint32 p = GETCLIENTA(it)->NextPingNumber;\n\t\tmsgout.serial (p);\n\n\t\tuint32 b = GETCLIENTA(it)->BlockNumber;\n\t\tmsgout.serial (b);\n\n\t\tuint8 dummy=0;\n\t\twhile (msgout.length() < 200)\n\t\t\tmsgout.serial (dummy);\n\n\t\tuint32 size =  msgout.length();\n\t\tnlassert (size == 200);\n\n\t\ttry\n\t\t{\n\t\t\t// send the new ping to the client\n\t\t\tReceiveTask->DataSock->sendTo (msgout.buffer(), size, GETCLIENTA(it)->Address);\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\tnlwarning (\"Can't send UDP packet to '%s' (%s)\", GETCLIENTA(it)->Address.asString().c_str(), e.what());\n\t\t}\n\n\t\tGETCLIENTA(it)->NextPingNumber++;\n\t\tGETCLIENTA(it)->NbPing++;\n\t}\n}\n\n//\n// Main Class\n//\n\nclass CBenchService : public IService\n{\npublic:\n\t\n\tvoid init()\n\t{\n\t\tnlassert( ReceiveTask==NULL && ReceiveThread==NULL );\n\n\t\t// Create stat folder if necessary\n\n\t\tif (!CFile::isExists (StatPathName))\n\t\t{\n\t\t\tmkdir (StatPathName.c_str());\n\t\t}\n\n\t\t// Create and start UDP server\n\n\t\tnlinfo( \"Starting external UDP socket on port %d\", UDPPort);\n\t\tReceiveTask = new CReceiveTask (UDPPort, MaxUDPPacketSize);\n\t\tCurrentReadQueue = &Queue2;\n\t\tReceiveTask->setWriteQueue( &Queue1 );\n\t\tnlassert( ReceiveTask != NULL );\n\t\tReceiveThread = IThread::create( ReceiveTask );\n\t\tnlassert( ReceiveThread != NULL );\n\t\tReceiveThread->start();\n\n\t\t// Setup current message placeholder\n\t\tCurrentInMsg = new TReceivedMessage();\n\n\t\t// Create the TCP server\n\n\t\tnlinfo( \"Starting external TCP socket on port %d\", TCPPort);\n\t\tCallbackServer = new CCallbackServer;\n\t\tCallbackServer->addCallbackArray (CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));\n\t\tCallbackServer->init (TCPPort);\n\t\tCallbackServer->setDisconnectionCallback (cbDisconnect, NULL);\n\t}\n\n\tbool update ()\n\t{\n\t\ttry\n\t\t{\n\t\t\t// Send ping to every client\n\t\t\tsendPing();\n\n\t\t\t// Update and manage TCP connections\n\t\t\tCallbackServer->update ();\n\n\n\t\t\t// Swap queues\n\t\t\tif ( CurrentReadQueue == &Queue1 )\n\t\t\t{\n\t\t\t\tCurrentReadQueue = &Queue2;\n\t\t\t\tReceiveTask->setWriteQueue( &Queue1 );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCurrentReadQueue = &Queue1;\n\t\t\t\tReceiveTask->setWriteQueue( &Queue2 );\n\t\t\t}\n\n\t\t\t// Update and manage UDP connections\n\t\t\twhile ( ! CurrentReadQueue->empty() )\n\t\t\t{\n\t\t\t\tsint64 pongTime;\n\n\t\t\t\t// Get a UDP message\n\t\t\t\tCurrentReadQueue->front( CurrentInMsg->data() );\n\t\t\t\tCurrentReadQueue->pop();\n\t\t\t\tnlassert( ! CurrentReadQueue->empty() );\n\t\t\t\tCurrentReadQueue->front( CurrentInMsg->VAddrFrom );\n\t\t\t\tCurrentReadQueue->pop();\n\t\t\t\tCurrentInMsg->vectorToAddress();\n\t\t\t\tpongTime = CurrentInMsg->getDate ();\n\n\t\t\t\t// Handle the UDP message\n\n\t\t\t\t// Retrieve client info or add one\t\t\n\t\t\t\tTClientMap::iterator ihm = ClientMap.find( CurrentInMsg->AddrFrom );\n\t\t\t\tif ( ihm == ClientMap.end() )\n\t\t\t\t{\n\t\t\t\t\tif ( CurrentInMsg->eventType() == TReceivedMessage::User )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Handle message for a new client\n\t\t\t\t\t\thandleReceivedPong( NULL, pongTime );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo( \"Not removing already removed client\" );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Already existing\n\t\t\t\t\tif ( CurrentInMsg->eventType() == TReceivedMessage::RemoveClient )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Remove client\n\t\t\t\t\t\tremoveClientByAddr( ihm );\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Handle message\n\t\t\t\t\t\thandleReceivedPong( GETCLIENTA(ihm), pongTime );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tupdateStat ();\n\t\t\t}\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\tnlerrornoex (\"Exception not catched: '%s'\", e.what());\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid release ()\n\t{\n\t\tnlassert( ReceiveTask != NULL );\n\t\tnlassert( ReceiveThread != NULL );\n\n\t\tReceiveTask->requireExit();\n\t\tReceiveTask->DataSock->close();\n\t\tReceiveThread->wait();\n\n\t\tif (ReceiveThread != NULL)\n\t\t{\n\t\t\tdelete ReceiveThread;\n\t\t\tReceiveThread = NULL;\n\t\t}\n\t\n\t\tif (ReceiveTask != NULL)\n\t\t{\n\t\t\tdelete ReceiveTask;\n\t\t\tReceiveTask = NULL;\n\t\t}\n\n\t\tif (CurrentInMsg != NULL)\n\t\t{\n\t\t\tdelete CurrentInMsg;\n\t\t\tCurrentInMsg = NULL;\n\t\t}\n\n\t\tif (CallbackServer != NULL)\n\t\t{\n\t\t\tdelete CallbackServer;\n\t\t\tCallbackServer = NULL;\n\t\t}\n\n\t}\n};\n\n \nNLNET_SERVICE_MAIN (CBenchService, \"BS\", \"bench_service\", 45459, EmptyCallbackArray, UDP_DIR, \"\")\n"
  },
  {
    "path": "code/nel/samples/net/udp/client.cfg",
    "content": "//ServerAddress        = \"itsalive.nevrax.org\";\n//ServerAddress        = \"pc9\";\nServerAddress        = \"localhost\";\nSimInLag                = 0;\nSimInPacketLost         = 0;\nSimOutLag               = 0;\nSimOutPacketLost        = 0;\nSimOutPacketDuplication = 0;\nSimOutPacketDisordering = 0;\nConnectionName          = \"AceWork\";\n"
  },
  {
    "path": "code/nel/samples/net/udp/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/mem_stream.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/config_file.h\"\n\n#include \"nel/net/udp_sock.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/inet_address.h\"\n#include \"nel/net/udp_sim_sock.h\"\n\n#include \"graph.h\"\n\n\n#ifdef USE_3D\n\n#include \"nel/3d/u_driver.h\"\n#include \"nel/3d/u_scene.h\"\n#include \"nel/3d/u_camera.h\"\n#include \"nel/3d/u_instance.h\"\n#include \"nel/3d/u_animation_set.h\"\n#include \"nel/3d/u_play_list.h\"\n#include \"nel/3d/u_play_list_manager.h\"\n#include \"nel/3d/u_text_context.h\"\n#include \"nel/3d/u_texture.h\"\n#include \"nel/3d/event_mouse_listener.h\"\n\nusing namespace NL3D;\n#endif\n\n#ifndef UDP_DIR\n#define UDP_DIR \".\"\n#endif // UDP_DIR\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n//\n// Variables\n//\n\n// must be increase at each version and must be the same value as the server\nuint32\t\tVersion = 2;\n\nstring\t\tServerAddr = \"itsalive.nevrax.org\";\t// ldserver\nuint16\t\tUDPPort = 45455;\nuint16\t\tTCPPort = 45456;\n\nuint32\t\tMaxUDPPacketSize = 1000;\n\nCUdpSimSock\t*UdpSock = NULL;\n\nuint8\t\tMode = 0;\n\nuint64\t\tSession = 0;\n\nstring\t\tConnectionName;\n\nCConfigFile\tConfigFile;\n\n#ifdef USE_3D\n\nCGraph FpsGraph (\"frame rate (fps)\", 10.0f, 110.0f, 100.0f, 100.0f, CRGBA(128,0,0,128), 1000, 150.0f);\nCGraph DownloadGraph (\"download (bps)\", 10.0f, 260.0f, 100.0f, 100.0f, CRGBA(0,0,128,128), 1000, 20000.0f);\nCGraph UploadGraph (\"upload (bps)\", 10.0f, 360.0f, 100.0f, 100.0f, CRGBA(0,128,128,128), 1000, 20000.0f);\nCGraph LagGraph (\"lag (ms)\", 150.0f, 110.0f, 100.0f, 100.0f, CRGBA(128,64,64,128), 100000, 2000.0f);\n\n#endif\n\n//\n// Functions\n//\n\nvoid exit (const string &reason)\n{\n\tif (!reason.empty())\n\t\tInfoLog->displayRawNL (\"%s\", reason.c_str());\n\tInfoLog->displayRawNL (\"Press <enter> to exit\");\n\tgetchar ();\n\texit(EXIT_FAILURE);\n}\n\n//\n// Config file functions\n//\n\nvoid createConfigFile()\n{\n\tFILE *fp = fopen (\"client.cfg\", \"wt\");\n\tif (fp == NULL)\n\t{\n\t\tInfoLog->displayRawNL (\"Can't create client.cfg\");\n\t}\n\telse\n\t{\n\t\tfprintf (fp, \"ServerAddress = \\\"%s\\\";\\n\", ServerAddr.c_str());\n\t\tfprintf (fp, \"SimInLag = 0;\\n\");\n\t\tfprintf (fp, \"SimInPacketLost = 0;\\n\");\n\t\tfprintf (fp, \"SimOutLag = 0;\\n\");\n\t\tfprintf (fp, \"SimOutPacketLost = 0;\\n\");\n\t\tfprintf (fp, \"SimOutPacketDuplication = 0;\\n\");\n\t\tfprintf (fp, \"SimOutPacketDisordering = 0;\\n\");\n\t\tfprintf (fp, \"ConnectionName = \\\"\\\";\\n\");\n\t\tfclose (fp);\n\t}\n}\n\nvoid checkConnectionName ()\n{\n\tif (ConnectionName.size() > 30)\n\t{\n\t\texit (\"Bad connection name (must be <= 30 characters)\");\n\t}\n\n\tif (ConnectionName.size() > 0 && ConnectionName[ConnectionName.size()-1] == '\\n')\n\t{\n\t\tConnectionName = ConnectionName.substr (0, ConnectionName.size()-1);\n\t}\n\t\n\tif (ConnectionName.size() <= 0)\n\t{\n\t\texit (\"Bad connection name (must be > 0 character)\");\n\t}\n\n\tfor (uint i = 0; i < ConnectionName.size(); i++)\n\t{\n\t\tif (!isalnum(ConnectionName[i]))\n\t\t{\n\t\t\texit (\"Bad connection name, only alpha numeric characters is allowed (char '%c' is not alphanum)\");\n\t\t}\n\t}\n}\n\nvoid loadConfigFile ()\n{\n\tFILE *fp = fopen (\"client.cfg\", \"rt\");\n\tif (fp == NULL)\n\t{\n\t\tcreateConfigFile();\n\t}\n\telse\n\t{\n\t\tfclose (fp);\n\t}\n\n\tConfigFile.load (\"client.cfg\");\n\n\t// set internet simulation values\n\tCUdpSimSock::setSimValues (ConfigFile);\n\n\tServerAddr = ConfigFile.getVar(\"ServerAddress\").asString();\n\n\tConnectionName = ConfigFile.getVar(\"ConnectionName\").asString();\n\n\tif (ConnectionName.empty())\n\t{\n\t\tInfoLog->displayRawNL (\"Please, enter a connection name\");\n\t\tInfoLog->displayRawNL (\"(only alphanumeric character limited to 30 character, no space)\");\n\t\tInfoLog->displayRawNL (\"For example enter your name and/or your location (ie: \\\"AceHome\\\"),\");\n\t\tInfoLog->displayRawNL (\"It'll be use to find your stat file easier:\");\n\t\tchar cn[128];\n\t\tif (fgets (cn, 127, stdin) == NULL)\n\t\t{\n\t\t\texit (\"Error during the keyboard scanning\");\n\t\t}\n\t\tConnectionName = cn;\n\t\tcheckConnectionName ();\n\t\tConfigFile.getVar (\"ConnectionName\").setAsString(ConnectionName);\n\t\tConfigFile.save ();\n\t}\n\telse\n\t{\n\t\tcheckConnectionName ();\n\t}\n}\n\n\n//\n// Callbacks\n//\n\nvoid cbInfo (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tstring line;\n\tmsgin.serial (line);\n\tInfoLog->displayRawNL (\"%s\", line.c_str());\n\n#ifdef USE_3D\n\tstring token = \"MeanPongTime \";\n\tstring::size_type pos=line.find (token);\n\tstring::size_type pos2=line.find (\" \", pos+token.size());\n\tfloat val;\n\tNLMISC::fromString(line.substr (pos+token.size(), pos2-pos-token.size()), val);\t\n\tLagGraph.addOneValue (val);\n#endif\n}\n\nvoid cbInit (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tmsgin.serial (Session);\n\n\t// create the UDP connection\n\tnlassert (UdpSock == NULL);\n\tUdpSock = new CUdpSimSock( false );\n\ttry\n\t{\n\t\tUdpSock->connect( CInetAddress (ServerAddr, UDPPort) );\n\t}\n\tcatch (const Exception &e)\n\t{\n\t\tInfoLog->displayRawNL (\"Cannot connect to remote UDP host '%s': %s\", ServerAddr.c_str(), e.what() );\n\t\texit (\"\");\n\t}\n}\n\nvoid cbStart (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tInfoLog->displayRawNL (\"Bench is starting..\");\n\n\tMode = 1;\n}\n\nvoid cbDisconnect (TSockId from, void *arg)\n{\n\texit (\"Lost the server connection. You should not have the last client version\\nGet it here: http://www.nevrax.org/download/bench.zip\");\n}\n\nTCallbackItem CallbackArray[] =\n{\n\t{ \"INIT\", cbInit },\n\t{ \"INFO\", cbInfo },\n\t{ \"START\", cbStart },\n};\n\n\n\n//\n// Main\n//\nint main( int argc, char **argv )\n{\n\tcreateDebug ();\n\tDebugLog->addNegativeFilter(\" \");\n\t\n\tInfoLog->displayRawNL (\"\\nNevrax UDP benchmark client\\n\\nPress <CTRL-C> to exit\");\n\n\tCPath::addSearchPath(UDP_DIR);\n\n\tloadConfigFile ();\n\n\tCCallbackClient *cc = new CCallbackClient;\n\t\n\tcc->addCallbackArray (CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));\n\tcc->setDisconnectionCallback (cbDisconnect, NULL);\n\n\ttry\n\t{\n\t\tInfoLog->displayRawNL (\"Try to connect to %s:%d\", ServerAddr.c_str(), TCPPort);\n\t\tcc->connect(CInetAddress (ServerAddr, TCPPort));\n\n\t\tCMessage msgout (\"INIT\");\n\t\tmsgout.serial (ConnectionName);\n\t\tmsgout.serial (Version);\n\t\tcc->send (msgout);\n\n\t\tInfoLog->displayRawNL (\"Waiting the server answer...\");\n\t}\n\tcatch(const Exception &e)\n\t{\n\t\tInfoLog->displayRawNL (\"Can't connect to %s:%d (%s)\\n\", ServerAddr.c_str(), TCPPort, e.what());\n\t\texit (\"\");\n\t}\n\n\tuint8 *packet = new uint8[MaxUDPPacketSize];\n\tuint32 psize;\n\n#ifdef USE_3D\n\n\tUDriver *Driver = UDriver::createDriver();\n\tDriver->setDisplay(UDriver::CMode(800, 600, 32, true));\n\tUScene *Scene= Driver->createScene(false);\n\tUCamera Camera= Scene->getCam();\n\tCamera.setTransformMode(UTransform::DirectMatrix);\n\tUTextContext *TextContext= Driver->createTextContext(CPath::lookup(\"n019003l.pfb\"));\n\tTextContext->setFontSize(18);\n\n\tCamera.setPerspective(80*(float)Pi/180, 1.33f, 0.15f, 1000);\n\n\tCEvent3dMouseListener MouseListener;\n\tMouseListener.addToServer(Driver->EventServer);\n\tMouseListener.setFrustrum(Camera.getFrustum());\n\tMouseListener.setHotSpot(CVector(0,0,0));\n\tCMatrix\t\tinitMat;\n\tinitMat.setPos(CVector(0,-5,0));\n\tMouseListener.setMatrix(initMat);\n\n#endif\n\n\n\n\twhile (cc->connected ())\n\t{\n#ifdef USE_3D\n\n\t\t// Manip.\n\t\tCamera.setMatrix(MouseListener.getViewMatrix());\n\n\t\tDriver->EventServer.pump();\n\t\tif(Driver->AsyncListener.isKeyPushed(KeyESCAPE))\n\t\t\treturn EXIT_SUCCESS;\n\n\t\tDriver->clearBuffers(CRGBA(255,255,255,0));\n\n\t\tScene->render();\n\n\t\tCGraph::render (*Driver, *TextContext);\n\n\t\tDriver->swapBuffers();\n\n\t\tFpsGraph.addValue (1);\n\n#endif\n\n\n\t\tCConfigFile::checkConfigFiles ();\n\n\t\t// update TCP connection\n\t\tcc->update ();\n\n\t\t// update UDP connection\n\t\tif (UdpSock != NULL)\n\t\t{\n\t\t\tif (Mode == 0)\n\t\t\t{\n\t\t\t\t// init the UDP connection\n\t\t\t\tCMemStream msgout;\n\t\t\t\tmsgout.serial (Mode);\n\t\t\t\tmsgout.serial (Session);\n\t\t\t\tuint32 size = msgout.length();\n#ifdef USE_3D\n\t\t\t\tUploadGraph.addValue ((float)size);\n#endif\n\t\t\t\tUdpSock->send (msgout.buffer(), size);\n\t\t\t\tnldebug (\"Sent init udp connection\");\n\t\t\t\tnlSleep (100);\n\t\t\t}\n\n\t\t\twhile (UdpSock->dataAvailable())\n\t\t\t{\n\t\t\t\tpsize = MaxUDPPacketSize;\n\t\t\t\tUdpSock->receive (packet, psize);\n#ifdef USE_3D\n\t\t\t\tDownloadGraph.addValue ((float)psize);\n#endif\n\t\t\t\tCMemStream msgin( true );\n\t\t\t\tmemcpy (msgin.bufferToFill (psize), packet, psize);\n\n\t\t\t\tsint64 t = 0;\n\t\t\t\tmsgin.serial (t);\n\n\t\t\t\tuint32 p = 0;\n\t\t\t\tmsgin.serial (p);\n\n\t\t\t\tuint32 b = 0;\n\t\t\t\tmsgin.serial (b);\n\t\n\t\t\t\t// I received a ping, send a pong\n\n\t\t\t\tCMemStream msgout;\n\t\t\t\tmsgout.serial (Mode);\n\t\t\t\tmsgout.serial (t);\n\t\t\t\tmsgout.serial (p);\n\t\t\t\tmsgout.serial (b);\n\t\t\t\tuint8 dummy=0;\n\t\t\t\twhile (msgout.length() < 200)\n\t\t\t\t\tmsgout.serial (dummy);\n\n\t\t\t\tuint32 size =  msgout.length();\n\t\t\t\tnlassert (size == 200);\n\n#ifdef USE_3D\n\t\t\t\tUploadGraph.addValue ((float)size);\n#endif\n\t\t\t\tUdpSock->send (msgout.buffer(), size);\n\t\t\t}\n\t\t}\n\n\t\tnlSleep (1);\n\t}\n\t\n\texit (\"\");\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/net/udp/graph.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"graph.h\"\n\n#ifdef USE_3D\n\n#include <deque>\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/vector.h>\n#include <nel/misc/matrix.h>\n#include <nel/misc/command.h>\n\n#include <nel/3d/u_material.h>\n#include <nel/3d/u_camera.h>\n#include <nel/3d/u_driver.h>\n#include <nel/3d/u_text_context.h>\n#include <nel/3d/u_texture.h>\n#include <nel/3d/driver.h>\n#include <nel/3d/vertex_buffer.h>\n#include <nel/3d/material.h>\n#include <nel/3d/driver_user.h>\n\n//\n// Namespaces\n//\n\nusing namespace NLMISC;\nusing namespace NL3D;\nusing namespace std;\n\n//\n// Variables\n//\n\nvector<CGraph*> *CGraph::_Graphs = NULL;\n\nbool CGraph::Display = true;\nbool CGraph::DisplayAverageValue = true;\n\n//\n// Classes\n//\n\nvoid CGraph::render (NL3D::UDriver *Driver, NL3D::UTextContext *TextContext)\n{\n\t// Display the background\n\tuint32 w, h;\n\tDriver->getWindowSize (w, h);\n\tfloat ScreenWidth = (float) w;\n\tfloat ScreenHeight = (float) h;\n\tDriver->setMatrixMode2D (CFrustum (0.0f, ScreenWidth, 0.0f, ScreenHeight, 0.0f, 1.0f, false));\n\tDriver->drawQuad (X, Y, X+Width, Y+Height, BackColor);\n\n\tPeak = 0.0f;\n\tfloat sum = 0.0f;\n\t\n\tCMaterial\t\tmaterial;\n\tmaterial.initUnlit ();\n\tmaterial.setColor (CRGBA (255,255,255,BackColor.A));\n\tmaterial.setBlend (true);\n\n\t\n\tCVertexBuffer\tvbuffer;\n\tvbuffer.setVertexFormat (CVertexBuffer::PositionFlag);\n\tvbuffer.setNumVertices ((uint32)Values.size() * 2);\n\n\tfloat pos = X+Width-1;\n\tuint i = 0;\n\tfor (deque<float>::reverse_iterator it = Values.rbegin(); it != Values.rend(); it++)\n\t{\n\t\t// get a read accessor to the VB\n\t\tCVertexBufferRead vba;\n\t\tvbuffer.lock (vba);\n\n\t\tfloat value = (*it) * Height / MaxValue;\n\t\tif (value > Height) value = Height;\n\n\t\tCVector *vect1 = (CVector*)vba.getVertexCoordPointer(i*2+0);\n\t\tvect1->x = pos;\n\t\tvect1->y = Y;\n\t\tCVector *vect2 = (CVector*)vba.getVertexCoordPointer(i*2+1);\n\t\tvect2->x = pos;\n\t\tvect2->y = Y+value;\n\n//\t\tDriver->drawLine (pos, Y, pos, Y+value, CRGBA (255,255,255,BackColor.A));\n\t\tpos--;\n\t\tif ((*it) > Peak) Peak = *it;\n\t\tsum += *it;\n\t\ti++;\n\t}\n\n\t// Render\n\tIDriver\t*drv = ((CDriverUser*)Driver)->getDriver();\n\tdrv->activeVertexBuffer(vbuffer);\n\n\t// Display max\n\tfloat value = Peak * Height / MaxValue;\n\tif (value > Height) value = Height;\n\tCRGBA frontCol (min(BackColor.R*2,255),min(BackColor.G*2,255),min(BackColor.B*2,255),min(BackColor.A*2,255));\n\tfloat peakval = Y+value;\n\tDriver->drawLine (X, peakval, X+Width, peakval, frontCol);\n\t\n\tTextContext->setHotSpot (UTextContext::MiddleLeft);\n\tTextContext->setColor (frontCol);\n\tTextContext->setFontSize (10);\n\tTextContext->printfAt ((X+Width+2)/ScreenWidth, (Y+value)/ScreenHeight, \"%.2f\", Peak);\n\n\t// Display average\n\tfloat average = sum / (float)Values.size();\n\tvalue = average * Height / MaxValue;\n\tif (value > Height) value = Height;\n\tfloat avrval = Y+value;\n\tDriver->drawLine (X, avrval, X+Width, avrval, frontCol);\n\n\tif (DisplayAverageValue)\n\t{\n\t\tif (avrval+10<peakval-10 || avrval-10>peakval+10)\n\t\t{\n\t\t\tTextContext->setHotSpot (UTextContext::MiddleLeft);\n\t\t\tTextContext->setColor (frontCol);\n\t\t\tTextContext->setFontSize (10);\n\t\t\tTextContext->printfAt ((X+Width+2)/ScreenWidth, (Y+value)/ScreenHeight, \"%.2f\", average);\n\t\t}\n\t}\n\n\t// Display name\n\tTextContext->setHotSpot (UTextContext::TopLeft);\n\tTextContext->printfAt ((X+1)/ScreenWidth, (Y+Height-1)/ScreenHeight, Name.c_str());\n}\n\nvoid CGraph::addOneValue (float value)\n{\n\tif (value < 0.0f) value = 0.0f;\n\n\tValues.push_back (value);\n\twhile (Values.size () > Width)\n\t\tValues.pop_front ();\n\n//\tif (Values.back() > Peak)\n//\t\tPeak = Values.back();\n}\n\n\nvoid CGraph::addValue (float value)\n{\n\tTTime currentTime = CTime::getLocalTime ();\n\n\twhile (Values.size () == 0 || currentTime > CurrentQuantumStart + Quantum)\n\t{\n\t\tCurrentQuantumStart += Quantum;\n\t\taddOneValue ();\n\t}\n\n\tValues.back() += value;\n\n//\tif (Values.back() > Peak)\n//\t\tPeak = Values.back();\n}\n\n//\n// Variables\n//\n/*\nCGraph FpsGraph (\"fps\", 10.0f, 110.0f, 100.0f, 100.0f, CRGBA(128,0,0,128), 1000, 150.0f);\nCGraph SpfGraph (\"spf\", 10.0f, 10.0f, 100.0f, 100.0f, CRGBA(0,128,0,128), 0, 100.0f);\n\nCGraph DownloadGraph (\"download\", 10.0f, 260.0f, 100.0f, 100.0f, CRGBA(0,0,128,128), 1000, 2000.0f);\nCGraph UploadGraph (\"upload\", 10.0f, 360.0f, 100.0f, 100.0f, CRGBA(0,128,128,128), 1000, 2000.0f);\n\nCGraph DpfGraph (\"dpf\", 150.0f, 260.0f, 100.0f, 100.0f, CRGBA(128,0,128,128), 100000, 180.0f);\nCGraph UpfGraph (\"upf\", 150.0f, 360.0f, 100.0f, 100.0f, CRGBA(128,128,0,128), 100000, 180.0f);\n\n\nCGraph UserLWatchGraph (\"ul\", 10.0f, 490.0f, 100.0f, 100.0f, CRGBA(0,64,128,128), 100000, 1000.0f);\nCGraph CycleWatchGraph (\"cl\", 150.0f, 490.0f, 100.0f, 100.0f, CRGBA(0,128,64,128), 100000, 1000.0f);\nCGraph ReceiveWatchGraph (\"rl\", 300.0f, 490.0f, 100.0f, 100.0f, CRGBA(128,64,0,128), 100000, 100.0f);\nCGraph SendWatchGraph (\"sl\", 450.0f, 490.0f, 100.0f, 100.0f, CRGBA(128,0,64,128), 100000, 100.0f);\nCGraph PriorityAmountGraph (\"prio amount\", 150.0f, 110.0f, 100.0f, 100.0f, CRGBA(128,64,64,128), 100000, 16.0f);\nCGraph SeenEntitiesGraph( \"seen entities\", 150.0f, 10.0f, 100.0f, 100.0f, CRGBA(64,128,64,128), 100000, 256);\n*/\n\n//\n// Functions\n//\n\nvoid CGraph::render (NL3D::UDriver &driver, NL3D::UTextContext &tc)\n{\n\tif (!Display) return;\n\n\tif (_Graphs == NULL) return;\n\n\tfor (uint i = 0; i < _Graphs->size(); i++)\n\t{\n\t\t(*_Graphs)[i]->render (&driver, &tc);\n\t}\n}\n\n/*\nNLMISC_VARIABLE(bool, GraphShow, \"Display or not graphs\");\nNLMISC_VARIABLE(bool, GraphDisplayAverageValue, \"Display or not average values\");\n*/\n\n#endif\n"
  },
  {
    "path": "code/nel/samples/net/udp/graph.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef GRAPH_H\n#define GRAPH_H\n\n// comment this define if you don't want 3d output\n//#define USE_3D\n\n#ifdef USE_3D\n\n//\n// Includes\n//\n\n#include <deque>\n#include <string>\n\n\n#include <nel/misc/rgba.h>\n#include <nel/misc/time_nl.h>\n\n#include <nel/3d/u_driver.h>\n#include <nel/3d/u_text_context.h>\n\n//\n// External classes\n//\n\nclass CGraph\n{\npublic:\n\tstd::string Name;\n\tfloat X, Y, Width, Height;\n\tNLMISC::CRGBA BackColor;\n\tfloat MaxValue;\n\tfloat Peak;\n\n\tstd::deque<float> Values;\n\n\tNLMISC::TTime Quantum;\n\n\tNLMISC::TTime CurrentQuantumStart;\n\n\tCGraph (std::string name, float x, float y, float width, float height, NLMISC::CRGBA backColor, NLMISC::TTime quantum, float maxValue)\n\t\t: Name(name), X(x), Y(y), Width(width), Height(height), BackColor(backColor), MaxValue(maxValue), Peak(0.0f), Quantum(quantum),\n\t\tCurrentQuantumStart(NLMISC::CTime::getLocalTime())\n\t{\n\t\tif (_Graphs == NULL)\n\t\t{\n\t\t\t_Graphs = new std::vector<CGraph*>;\n\t\t}\n\n\t\t_Graphs->push_back (this);\n\t}\n\n\tvoid addOneValue (float value = 0.0f);\n\tvoid addValue (float value);\n\n\tstatic void render (NL3D::UDriver &driver, NL3D::UTextContext &tc);\n\n\tstatic bool Display;\n\tstatic bool DisplayAverageValue;\n\nprivate:\n\n\tstatic std::vector<CGraph*> *_Graphs;\n\n\tvoid render (NL3D::UDriver *Driver, NL3D::UTextContext *TextContext);\n};\n\n#endif\n\n#endif // GRAPH_H\n\n/* End of graph.h */\n"
  },
  {
    "path": "code/nel/samples/net/udp/readme.txt",
    "content": "Nevrax UDP Bench test.\n\nThis program tests the UDP connection between your computer and a Nevrax\nserver. It reports some stats about packet lost, ping time and other\ninformation.\n\nYou can launch this program for 1 minute, 1 hour, all the time if you\nwant. More often this program will run, more accurate information we'll\nhave. So if you can, leave this program always running.\n\nJust launch the program and follow instructions.\n\nIf you have any problems, please contact lecroart@nevrax.com\n"
  },
  {
    "path": "code/nel/samples/net/udp/receive_task.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"receive_task.h\"\n\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NOMINMAX\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n\n#include <unistd.h>\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include <netdb.h>\n\n#define WSAGetLastError() 0\n\n#endif\n\n\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\n/*\n * TReceivedMessage\n */\n\n/// Constructor\nTReceivedMessage::TReceivedMessage()\n{\n\tVAddrFrom.resize( sizeof(sockaddr_in) );\n}\n\n/// Return a vector containing the address info\nvoid\tTReceivedMessage::addressToVector()\n{\n\tmemcpy( &*VAddrFrom.begin(), AddrFrom.sockAddr(), sizeof(sockaddr_in) );\n}\n\n/// Set address with address info from specified vector\nvoid\tTReceivedMessage::vectorToAddress()\n{\n\tAddrFrom.setSockAddr( (sockaddr_in*)&*VAddrFrom.begin() );\n}\n\n\n/*\n * Constructor\n */\nCReceiveTask::CReceiveTask( uint16 port, uint32 msgsize ) :\n\t_DatagramLength( msgsize ),\n\t_ReceivedMessage(),\n\t_WriteQueue( \"WriteQueue\" ), // value unspecified\n\t_ExitRequired( false )\n{\n\t// Socket\n\tDataSock = new CUdpSock( false );\n\tnlassert( DataSock );\n\n\tDataSock->bind( port );\n}\n\n\n\n/*\n * Destructor\n */\nCReceiveTask::~CReceiveTask()\n{\n\tnlassert( DataSock != NULL );\n\tdelete DataSock;\n\tDataSock = NULL;\n\n}\n\n\n/*\n * Run\n */\nvoid CReceiveTask::run()\n{\n\tuint maxrecvlength = _DatagramLength;\n\twhile ( ! _ExitRequired )\n\t{\n\t\tsint64 d;\n\t\ttry\n\t\t{\n\t\t\t// Receive into _ReceivedMessage\n\t\t\t_DatagramLength = maxrecvlength;\n\t\t\t_ReceivedMessage.resizeData( _DatagramLength );\n\t\t\t_ReceivedMessage.setTypeEvent( TReceivedMessage::User );\n\t\t\tDataSock->receivedFrom( _ReceivedMessage.userDataW(), _DatagramLength, _ReceivedMessage.AddrFrom );\n\t\t\td = CTime::getLocalTime ();\n\t\t}\n\t\tcatch (const ESocket&)\n\t\t{\n\t\t\t// Remove the client corresponding to the address\n\t\t\t_ReceivedMessage.setTypeEvent( TReceivedMessage::RemoveClient );\n\t\t\t_DatagramLength = 0;\n\t\t}\n\n\t\t// Push into the write queue\n\t\t_ReceivedMessage.addressToVector();\n\t\t_ReceivedMessage.resizeData( _DatagramLength ); // _DatagramLength was modified by receivedFrom()\n\t\t_ReceivedMessage.setDate ();\n\t\t{\n\t\t\tCSynchronized<CBufFIFO*>::CAccessor wq( &_WriteQueue );\n\t\t\twq.value()->push( _ReceivedMessage.data() );\n\t\t\twq.value()->push( _ReceivedMessage.VAddrFrom );\n\t\t}\n\t}\n\n\tnlinfo( \"Exiting from front-end receive task\" );\n}\n\n\n/*\n * Set new write queue\n */\nvoid CReceiveTask::setWriteQueue( CBufFIFO *writequeue )\n{\n\tCSynchronized<CBufFIFO*>::CAccessor wq( &_WriteQueue );\n\twq.value() = writequeue;\n}\n\n"
  },
  {
    "path": "code/nel/samples/net/udp/receive_task.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_RECEIVE_TASK_H\n#define NL_RECEIVE_TASK_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/buf_fifo.h\"\n#include \"nel/misc/mutex.h\"\n\n#include \"nel/net/udp_sock.h\"\n\n#include <vector>\n\n\nconst uint32 MsgHeaderSize = 1+8;\t// 8 for the date\n\n\n/**\n * Placeholder for received messages\n */\nstruct TReceivedMessage\n{\n\t/// Type of incoming events (see also NLNET::CBufNetBase::TEventType)\n\tenum TEventType { User = 'U', RemoveClient = 'D' };\n\n\t/// Constructor\n\tTReceivedMessage();\n\n\t/// Resize data\n\tvoid\t\t\t\tresizeData( uint32 datasize )\t{ _Data.resize( MsgHeaderSize + datasize ); }\n\n\t/// Return a vector containing the address info\n\tvoid\t\t\t\taddressToVector();\n\n\t/// Set address with address info from specified vector\n\tvoid\t\t\t\tvectorToAddress();\n\n\t/// Set \"disconnection\" message for the current AddrFrom\n\tvoid\t\t\t\tsetTypeEvent( TEventType t )\t{ *_Data.begin() = (uint8)t; }\n\n\tvoid\t\t\t\tsetDate()\t{ *(sint64*)&(*(_Data.begin()+1)) = NLMISC::CTime::getLocalTime(); }\n\n\tsint64\t\t\t\tgetDate()\t{ return *(sint64*)&(*(_Data.begin()+1)); }\n\t\n\t/// Return the event type\n\tTEventType\t\t\teventType() const\t\t\t\t{ return (TEventType)(*_Data.begin()); }\n\n\t/// Return a pointer to user data for writing\n\tuint8\t\t\t\t*userDataW()\t\t\t\t\t{ return &*_Data.begin() + MsgHeaderSize; }\n\n\t/// Return a pointer to user data for reading\n\tconst uint8\t\t\t*userDataR() const\t\t\t\t{ return &*_Data.begin() + MsgHeaderSize; }\n\n\t/// Return the size of user data\n\tuint32\t\t\t\tuserSize()\t\t\t\t\t\t{ return (uint32)_Data.size() - MsgHeaderSize; }\n\n\t/// Return the data vector (event type header byte + user data)\n\tstd::vector<uint8>&\t\tdata()\t\t\t\t\t\t{ return _Data; }\n\nprivate:\n\n\t/// One byte for event type (header), followed by user data\n\tstd::vector<uint8>\t\t_Data;\n\npublic:\n\t\n\t/// Address of sender as CInetAddress\n\tNLNET::CInetAddress\tAddrFrom;\n\n\t/// Placeholder vector for address info\n\tstd::vector<uint8>\t\tVAddrFrom;\n};\n\n\n/**\n * receive task\n * \\author Olivier Cado\n * \\author Nevrax France\n * \\date 2001\n */\nclass CReceiveTask : public NLMISC::IRunnable\n{\npublic:\n\n\t/// Constructor\n\tCReceiveTask( uint16 port, uint32 msgsize );\n\n\t/// Destructor\n\t~CReceiveTask();\n\n\t/// Run\n\tvirtual void\trun();\n\n\t/// Set new write queue\n\tvoid\t\t\tsetWriteQueue( NLMISC::CBufFIFO *writequeue );\n\n\t/// Require exit\n\tvoid\t\t\trequireExit() { _ExitRequired = true; }\n\nprivate:\n\n\t/// Datagram length\n\tuint\t\t\t\t\t\t\t\t\t\t_DatagramLength;\n\n\t/// Received message\n\tTReceivedMessage\t\t\t\t\t\t\t_ReceivedMessage;\n\n\t/// Write queue access\n\tNLMISC::CSynchronized<NLMISC::CBufFIFO*>\t_WriteQueue;\n\n\t/// Exit required\n\tvolatile bool\t\t\t\t\t\t\t\t_ExitRequired;\n\npublic:\n\t\n\t/// External datagram socket\n\tNLNET::CUdpSock\t\t\t\t\t\t\t\t*DataSock;\n\n};\n\n\n#endif // NL_RECEIVE_TASK_H\n\n/* End of receive_task.h */\n"
  },
  {
    "path": "code/nel/samples/net/udp/simlag.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include <string>\n#include <queue>\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/debug.h>\n\n#include <nel/net/udp_sock.h>\n\n//\n// Using\n//\n\nusing namespace std;\n\nusing namespace NLMISC;\nusing namespace NLNET;\n\n//\n// Variables\n//\n\nstatic uint32\tLag = 0;\nstatic uint8\tPacketLoss = 0;\nstatic uint8\tPacketDuplication = 0;\nstatic uint8\tPacketDisordering = 0;\n\n//\n// Class\n//\n\nstruct CBufferizedPacket\n{\n\tCBufferizedPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):\n\t\tClient(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)\n\t{\n\t\tnlassert (packetSize > 0);\n\t\tnlassert (packet != NULL);\n\t\tnlassert (client != NULL);\n\n\t\tPacket = new uint8[packetSize];\n\t\tmemcpy (Packet, packet, packetSize);\n\n\t\tif (addr != NULL)\n\t\t{\n\t\t\tAddr = new CInetAddress;\n\t\t\t*Addr = *addr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddr = NULL;\n\t\t}\n\t}\n\n\t~CBufferizedPacket ()\n\t{\n\t\tnlassert (Packet != NULL);\n\t\tdelete [] Packet;\n\t\tPacket = NULL;\n\t\tClient = NULL;\n\t\tPacketSize = 0;\n\t\tTime = 0;\n\t\tif (Addr != NULL)\n\t\t\tdelete Addr;\n\t}\n\n\tCUdpSock\t*Client;\n\tuint8\t\t*Packet;\n\tuint32\t\t PacketSize;\n\tTTime\t\t Time;\n\tCInetAddress\t*Addr;\n};\n\n//\n// Variables\n//\n\nstatic queue<CBufferizedPacket*> BufferizedPackets;\n\n//\n// Prototypes\n//\n\nvoid sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr);\n\n//\n// Functions\n//\n\nvoid updateBufferizedPackets ()\n{\n\tTTime ct = CTime::getLocalTime ();\n\twhile (!BufferizedPackets.empty())\n\t{\n\t\tCBufferizedPacket *bp = BufferizedPackets.front ();\n\t\tif (bp->Time <= ct)\n\t\t{\n\t\t\t// time to send the message\n\t\t\tsendUDPNow (bp->Client, bp->Packet, bp->PacketSize, bp->Addr);\n\t\t\tdelete bp;\n\t\t\tBufferizedPackets.pop ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid setSimlagValues (sint32 lag, sint8 packetLoss, sint8 packetDuplication, sint8 packetDisordering)\n{\n\tif (lag != -1) Lag = lag;\n\tif (packetLoss != -1) PacketLoss = packetLoss;\n\tif (packetDuplication != -1) PacketDuplication = packetDuplication;\n\tif (packetDisordering != -1) PacketDisordering = packetDisordering;\n}\n\nvoid sendUDPNow (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)\n{\n\tif (addr == NULL)\n\t\tclient->send (packet, packetSize);\n\telse\n\t\tclient->sendTo (packet, packetSize, *addr);\n\n\tuint32 packetNumber = *(uint32 *)packet;\n//\tnlinfo (\"time %\"NL_I64\"u sending now packet %5u\", CTime::getLocalTime (), packetNumber);\n}\n\nvoid sendUDP (CUdpSock *client, const uint8 *packet, uint32 packetSize, const CInetAddress *addr)\n{\n\tnlassert (client != NULL);\n\tnlassert (packet != NULL);\n\tnlassert (packetSize > 0);\n\n\tif ((float)rand()/(float)(RAND_MAX)*100.0f >= PacketLoss)\n\t{\n\t\tsint32 lag = Lag /*+ (rand()%40) - 20*/;// void disordering\n\t\t\n\t\tif (lag > 100)\n\t\t{\n\t\t\t// send the packet later\n\n\t\t\tCBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDisordering && BufferizedPackets.size() > 0)\n\t\t\t{\n\t\t\t\tCBufferizedPacket *bp2 = BufferizedPackets.back();\n\n\t\t\t\t// exange the time\n\t\t\t\tTTime t = bp->Time;\n\t\t\t\tbp->Time = bp2->Time;\n\t\t\t\tbp2->Time = t;\n\n\t\t\t\t// exange packet in the buffer\n\t\t\t\tBufferizedPackets.back() = bp;\n\t\t\t\tbp = bp2;\n\t\t\t}\n\n\t\t\tBufferizedPackets.push (bp);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)\n\t\t\t{\n\t\t\t\tCBufferizedPacket *bp = new CBufferizedPacket (client, packet, packetSize, lag, addr);\n\t\t\t\tBufferizedPackets.push (bp);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the packet NOW\n\n\t\t\tsendUDPNow (client, packet, packetSize, addr);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < PacketDuplication)\n\t\t\t{\n\t\t\t\tsendUDPNow (client, packet, packetSize, addr);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "code/nel/samples/net/udp/simlag.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_SIMLAG_H\n#define NL_SIMLAG_H\n\n//\n// Includes\n//\n\n#include <nel/misc/types_nl.h>\n\n#include <nel/net/inet_address.h>\n#include <nel/net/udp_sock.h>\n\n//\n// Variables\n//\n\n//\n// Functions\n//\n\n// Call this function evenly to flush messages that are laged\nvoid updateBufferizedPackets ();\n\n// Set the packet lost and lag values for the simluation\nvoid setSimlagValues (sint32 lag, sint8 packetLoss, sint8 packetDuplication, sint8 packetDisordering);\n\n// Send a message using UDP connection with sim lag\nvoid sendUDP (NLNET::CUdpSock *client, const uint8 *packet, uint32 packetSize, const NLNET::CInetAddress *addr = NULL);\n\n\n#endif // NL_SIMLAG_H\n\n/* End of simlag.h */\n"
  },
  {
    "path": "code/nel/samples/net/udp_ping/client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/mem_stream.h\"\n\n#include \"nel/net/inet_address.h\"\n#include \"nel/net/udp_sim_sock.h\"\n\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\n//\n// Main\n//\n\nint main (int argc, char **argv)\n{\n\tif (argc != 3)\n\t{\n\t\tnlinfo (\"%s send udp datagram to a specific port to test a connection between client and server\", argv[0]);\n\t\tnlinfo (\"usage: <ip_address> <port>\");\n\t\texit (EXIT_FAILURE);\n\t}\n\n\tCUdpSimSock\t*UdpSock = NULL;\n\tUdpSock = new CUdpSimSock( false );\n\ttry\n\t{\n\t\tUdpSock->connect (CInetAddress (argv[1], atoi(argv[2])));\n\t}\n\tcatch (Exception &e)\n\t{\n\t\tnlwarning (\"Cannot connect to remote UDP host: %s\", e.what());\n\t\texit (EXIT_FAILURE);\n\t}\n\n\tuint8 *packet = new uint8[1000];\n\tuint32 psize;\n\t\n\twhile(true)\n\t{\n\t\tCMemStream msgout;\n\t\tuint32 foo = 10;\n\t\tmsgout.serial (foo);\n\t\tuint32 size = msgout.length();\n\t\tUdpSock->send (msgout.buffer(), size);\n\t\tnldebug (\"Sent UDP datagram size %d to %s\", size, UdpSock->localAddr().asString().c_str());\n\n\t\twhile (UdpSock->dataAvailable())\n\t\t{\n\t\t\tpsize = 1000;\n\t\t\ttry\n\t\t\t{\n\t\t\t\tUdpSock->receive (packet, psize);\n\t\t\t\tnldebug (\"Received UDP datagram size %d bytes from %s\", psize, UdpSock->localAddr().asString().c_str());\n\t\t\t}\n\t\t\tcatch ( Exception& e )\n\t\t\t{\n\t\t\t\tnlwarning (\"Received failed: %s\", e.what());\n\t\t\t}\n\t\t}\n\t\tnlSleep (1000);\n\t}\n\n\treturn EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "code/nel/samples/net/udp_ping/udp_service.cfg",
    "content": "\nWindowStyle = \"WIN\";\n\nDontUseAES = 1;\nDontUseNS = 1;\n\nUdpPort = 15410;\n"
  },
  {
    "path": "code/nel/samples/net/udp_ping/udp_service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/net/service.h\"\n#include \"nel/net/udp_sim_sock.h\"\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n//\n// Variables\n//\n\nCUdpSock\t\t\t*UdpSock = NULL;\n\n//\n// Main Class\n//\n\nclass CBenchService : public IService\n{\npublic:\n\t\n\tvoid init()\n\t{\n\t\tuint16 port = ConfigFile.getVar(\"UdpPort\").asInt();\n\t\tnlinfo (\"Starting external UDP socket on port %d\", port);\n\t\tUdpSock = new CUdpSock (false);\n\t\tnlassert (UdpSock);\n\t\tUdpSock->bind (port);\n\t}\n\n\tbool update ()\n\t{\n\t\ttry\n\t\t{\n\t\t\tuint len;\n\t\t\tCInetAddress addr;\n\t\t\tuint8 buffer[1000];\n\t\t\t\n\t\t\twhile (UdpSock->dataAvailable())\n\t\t\t{\n\t\t\t\tlen = 1000;\n\t\t\t\tUdpSock->receivedFrom((uint8*)buffer, len, addr);\n\t\t\t\tnlinfo (\"Received UDP datagram size %d from %s\", len, addr.asString().c_str());\n\n\t\t\t\tCMemStream msgout;\n\t\t\t\tuint32 foo = 10;\n\t\t\t\tmsgout.serial (foo);\n\t\t\t\tuint32 size = msgout.length();\n\t\t\t\tUdpSock->sendTo (msgout.buffer(), size, addr);\n\t\t\t\tnldebug (\"Sent UDP datagram size %d to %s\", size, addr.asString().c_str());\n\t\t\t}\n\t\t}\n\t\tcatch (Exception &e)\n\t\t{\n\t\t\tnlwarning (\"Exception catched: '%s'\", e.what());\n\t\t}\n\t\treturn true;\n\t}\n\n\tvoid release ()\n\t{\n\t\tif (UdpSock != NULL)\n\t\t\tdelete UdpSock;\n\t}\n};\n\n\nNLNET_SERVICE_MAIN (CBenchService, \"UDPS\", \"udp_service\", 0, EmptyCallbackArray, \"\", \"\")\n"
  },
  {
    "path": "code/nel/src/CMakeLists.txt",
    "content": "ADD_SUBDIRECTORY(misc)\n\nIF(WITH_GEORGES)\n  ADD_SUBDIRECTORY(georges)\nENDIF(WITH_GEORGES)\n\nIF(WITH_LIGO)\n  ADD_SUBDIRECTORY(ligo)\nENDIF(WITH_LIGO)\n\nIF(WITH_LOGIC)\n  ADD_SUBDIRECTORY(logic)\nENDIF(WITH_LOGIC)\n\nIF(WITH_NET)\n  ADD_SUBDIRECTORY(net)\nENDIF(WITH_NET)\n\n"
  },
  {
    "path": "code/nel/src/georges/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\nFILE(GLOB HEADERS ../../include/nel/georges/*.h)\n\n# SOURCE_GROUP(headers FILES ${HEADERS})\n\nNL_TARGET_LIB(nelgeorges ${HEADERS} ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(nelgeorges ${LIBXML2_LIBRARIES} nelmisc)\nSET_TARGET_PROPERTIES(nelgeorges PROPERTIES LINK_INTERFACE_LIBRARIES \"\")\nNL_DEFAULT_PROPS(nelgeorges \"NeL, Library: NeL Georges\")\nNL_ADD_RUNTIME_FLAGS(nelgeorges)\n\nNL_ADD_LIB_SUFFIX(nelgeorges)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH)\n  ADD_NATIVE_PRECOMPILED_HEADER(nelgeorges ${CMAKE_CURRENT_SOURCE_DIR}/stdgeorges.h ${CMAKE_CURRENT_SOURCE_DIR}/stdgeorges.cpp)\nENDIF(WITH_PCH)\n\nNL_GEN_PC(nel-georges.pc)\n\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS nelgeorges LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/nel/src/georges/form.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/georges/form.h\"\n#include \"nel/georges/form_loader.h\"\n\nusing namespace NLMISC;\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n// Misc\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... )\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tif (exception)\n\t{\n\t\t// Make an error message\n\t\tchar tmp[1024];\n\t\tsmprintf (tmp, 1024, \"NeL::Georges %s\", buffer);\n\t\tthrow EXmlParsingError (tmp);\n\t}\n\telse\n\t{\n\t\tnlwarning (\"NeL::Georges %s\", buffer);\n\t}\n}\n\n// ***************************************************************************\n// UForm\n// ***************************************************************************\n\nUForm::~UForm ()\n{\n}\n\n// ***************************************************************************\n\nUFormElm& CForm::getRootNode ()\n{\n\treturn Elements;\n}\n\n// ***************************************************************************\n\nconst UFormElm& CForm::getRootNode () const\n{\n\treturn Elements;\n}\n\n// ***************************************************************************\n// CForm\n// ***************************************************************************\n\nCForm::CForm () : Elements (this, NULL, NULL, 0xffffffff)\n{\n\tuint i;\n\tfor (i=0; i<HeldElementCount; i++)\n\t{\n\t\tHeldElements[i] = new CFormElmStruct (this, NULL, NULL, 0xffffffff);\n\t}\n}\n\n// ***************************************************************************\n\nCForm::~CForm ()\n{\n\tuint i;\n\tfor (i=0; i<HeldElementCount; i++)\n\t{\n\t\tdelete HeldElements[i];\n\t}\n}\n\n// ***************************************************************************\n\nvoid CForm::write (xmlDocPtr doc, const char *filename)\n{\n\t// Save the filename\n\tif (filename)\n\t\t_Filename = CFile::getFilename (filename);\n\n\t// Create the first node\n\txmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)\"FORM\", NULL);\n\txmlDocSetRootElement (doc, node);\n\n\t// List of parent\n\tfor (uint parent=0; parent<ParentList.size (); parent++)\n\t{\n\t\t// Parent name not empty ?\n\t\tif (!(ParentList[parent].ParentFilename.empty()))\n\t\t{\n\t\t\t// Add a parent node\n\t\t\txmlNodePtr parentNode = xmlNewChild ( node, NULL, (const xmlChar*)\"PARENT\", NULL );\n\t\t\txmlSetProp (parentNode, (const xmlChar*)\"Filename\", (const xmlChar*)ParentList[parent].ParentFilename.c_str());\n\t\t}\n\t}\n\n\t// Write elements\n\tElements.write (node, this, NULL, true);\n\n\t// Write held elements\n\tuint i;\n\tfor (i=0; i<HeldElementCount; i++)\n\t{\n\t\tHeldElements[i]->write (node, this, NULL, true);\n\t}\n\n\t// Header\n\tHeader.write (node);\n}\n\n// ***************************************************************************\n\nvoid CForm::readParent (const char *parent, CFormLoader &loader)\n{\n\t// Load the parent\n\tCForm *theParent = (CForm*)loader.loadForm (parent);\n\tif (theParent != NULL)\n\t{\n\t\t// Set the parent\n\t\tif (!insertParent (getParentCount (), parent, theParent))\n\t\t{\n\t\t\t// Make an error message\n\t\t\tstd::string parentName = parent;\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)parent);\n\n\t\t\t// Throw exception\n\t\t\twarning (true, \"readParent\", \"Can't set the parent FORM named (%s). Check if it is the same form or if it use a differnt formDfn.\", parentName.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Make an error message\n\t\tstd::string parentName = parent;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)parent);\n\n\t\t// Throw exception\n\t\twarning (true, \"readParent\", \"Can't load the parent FORM named (%s).\", parentName.c_str ());\n\t}\n}\n\n// ***************************************************************************\n\nvoid CForm::read (xmlNodePtr node, CFormLoader &loader, CFormDfn *dfn, const char *filename)\n{\n\t// Save the filename\n\t_Filename = CFile::getFilename (filename);\n\n\t// Reset form\n\tclean ();\n\n\t// Check node name\n\tif ( ((const char*)node->name == NULL) || (strcmp ((const char*)node->name, \"FORM\") != 0) )\n\t{\n\t\t// Make an error message\n\t\twarning (true, \"read\", \"XML Syntax error in block line %p, node (%s) should be FORM.\",\n\t\t\tnode->content, node->name);\n\t}\n\n\t// Get first struct node\n\txmlNodePtr child = CIXml::getFirstChildNode (node, \"STRUCT\");\n\tif (child == NULL)\n\t{\n\t\t// Throw exception\n\t\twarning (true, \"read\", \"Syntax error in block line %p, node (%s) should have a STRUCT child node.\",\n\t\t\tnode->content, node->name);\n\t}\n\n\t// Read the struct\n\tElements.read (child, loader, dfn, this);\n\n\t// Get next struct node\n\tchild = CIXml::getNextChildNode (node, \"STRUCT\");\n\tuint index = 0;\n\twhile ( (child != NULL) && (index < HeldElementCount))\n\t{\n\t\tHeldElements[index]->read (child, loader, dfn, this);\n\t\tindex++;\n\t}\n\twhile (index < HeldElementCount)\n\t{\n\t\t// Build the Form\n\t\tHeldElements[index]->build (dfn);\n\t\tindex++;\n\t}\n\n\t// Get the old parent parameter\n\tconst char *parent = (const char*)xmlGetProp (node, (xmlChar*)\"Parent\");\n\tif (parent)\n\t{\n\t\t// Add a parent, xmlFree is done by readParent\n\t\treadParent (parent, loader);\n\t}\n\n\t// Read the new parent nodes\n\tuint parentCount = CIXml::countChildren (node, \"PARENT\");\n\n\t// Reserve some parents\n\tParentList.reserve (ParentList.size () + parentCount);\n\n\t// Enum children node\n\tchild = CIXml::getFirstChildNode (node, \"PARENT\");\n\twhile (child)\n\t{\n\t\tparent = (const char*)xmlGetProp (child, (xmlChar*)\"Filename\");\n\n\t\t// Add a parent, xmlFree is done by readParent\n\t\treadParent (parent, loader);\n\n\t\t// Next node <PARENT>\n\t\tchild = CIXml::getNextChildNode (child, \"PARENT\");\n\t}\n\n\t// Read the header\n\tHeader.read (node);\n}\n\n// ***************************************************************************\n\nconst std::string &CForm::getComment () const\n{\n\treturn Header.Comments;\n}\n\n// ***************************************************************************\n\nvoid CForm::write (class NLMISC::IStream &stream)\n{\n\t// Xml stream\n\tCOXml xmlStream;\n\txmlStream.init (&stream);\n\n\t// Write the file\n\twrite (xmlStream.getDocument (), NULL);\n}\n\n// ***************************************************************************\n\nbool CForm::insertParent (uint before, const char *filename, CForm *parent)\n{\n\t// Set or reset ?\n\tnlassert (parent);\n\n\t// Must have the same DFN\n\tif (parent->Elements.FormDfn == Elements.FormDfn)\n\t{\n\t\t// Set members\n\t\tstd::vector<CParent>::iterator ite = ParentList.insert (ParentList.begin() + before, CParent());\n\t\tite->Parent = parent;\n\t\tite->ParentFilename = filename;\n\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Output an error\n\t\twarning (false, \"insertParent\", \"Can't insert parent form (%s) that has not the same DFN.\", filename);\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CForm::removeParent (uint parent)\n{\n\tParentList.erase (ParentList.begin() + parent);\n}\n\n// ***************************************************************************\n\nCForm *CForm::getParent (uint parent) const\n{\n\treturn ParentList[parent].Parent;\n}\n\n// ***************************************************************************\n\nconst std::string &CForm::getParentFilename (uint parent) const\n{\n\treturn ParentList[parent].ParentFilename;\n}\n\n// ***************************************************************************\n\nuint CForm::getParentCount () const\n{\n\treturn (uint)ParentList.size ();\n}\n\n// ***************************************************************************\n\nvoid CForm::clean ()\n{\n\tclearParents ();\n}\n\n// ***************************************************************************\n\nvoid CForm::clearParents ()\n{\n\tParentList.clear ();\n}\n\n// ***************************************************************************\n\nconst std::string &CForm::getFilename () const\n{\n\treturn _Filename;\n}\n\n// ***************************************************************************\n\nvoid CForm::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CForm::%s) in form (%s) : %s\", function, _Filename.c_str (), buffer);\n}\n\n// ***************************************************************************\n\nvoid CForm::getDependencies (std::set<std::string> &dependencies) const\n{\n\t// Add me\n\tif (dependencies.insert (toLower(CFile::getFilename (_Filename))).second)\n\t{\n\t\t// Add parents\n\t\tuint i;\n\t\tfor (i=0; i<ParentList.size (); i++)\n\t\t{\n\t\t\tif (ParentList[i].Parent)\n\t\t\t{\n\t\t\t\tParentList[i].Parent->getDependencies (dependencies);\n\t\t\t}\n\t\t}\n\n\t\t// Add elements\n\t\tElements.getDependencies (dependencies);\n\t}\n}\n\n// ***************************************************************************\n\nuint CForm::getNumParent () const\n{\n\treturn getParentCount();\n}\n\n// ***************************************************************************\n\nUForm *CForm::getParentForm (uint parent) const\n{\n\tCForm *form = getParent (parent);\n\treturn form;\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n\n"
  },
  {
    "path": "code/nel/src/georges/form_dfn.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/georges/form_dfn.h\"\n#include \"nel/georges/form_loader.h\"\n#include \"nel/georges/form_elm.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\n#ifndef NL_OS_WINDOWS\n#define stricmp strcasecmp\n#endif\n\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... );\n\n// ***************************************************************************\n\nvoid CFormDfn::addEntry( const std::string &name )\n{\n\tCEntry entry;\n\tentry.setName( name.c_str() );\n\tEntries.push_back( entry );\n}\n\nvoid CFormDfn::removeEntry( uint idx )\n{\n\tstd::vector< CEntry >::iterator itr = Entries.begin() + idx;\n\tEntries.erase( itr );\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::write (xmlDocPtr doc, const char *filename)\n{\n\t// Save filename\n\t_Filename = CFile::getFilename (filename);\n\n\t// Create the first node\n\txmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)\"DFN\", NULL);\n\txmlDocSetRootElement (doc, node);\n\n\t// Write elements\n\tuint parent;\n\tfor (parent=0; parent<Parents.size(); parent++)\n\t{\n\t\t// Parent name not empty ?\n\t\tif (!Parents[parent].ParentFilename.empty ())\n\t\t{\n\t\t\t// Parent node\n\t\t\txmlNodePtr parentNode = xmlNewChild ( node, NULL, (const xmlChar*)\"PARENT\", NULL);\n\n\t\t\t// Save parent\n\t\t\txmlSetProp (parentNode, (const xmlChar*)\"Name\", (const xmlChar*)Parents[parent].ParentFilename.c_str());\n\t\t}\n\t}\n\n\t// Write elements\n\tuint elm;\n\tfor (elm=0; elm<Entries.size(); elm++)\n\t{\n\t\t// Add a node\n\t\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"ELEMENT\", NULL);\n\t\txmlSetProp (elmPtr, (const xmlChar*)\"Name\", (const xmlChar*)Entries[elm].Name.c_str());\n\n\t\t// What kind of element\n\t\tswitch (Entries[elm].TypeElement)\n\t\t{\n\t\tcase UFormDfn::EntryType:\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Type\", (const xmlChar*)\"Type\");\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Filename\", (const xmlChar*)Entries[elm].Filename.c_str());\n\t\t\tif ((!Entries[elm].FilenameExt.empty ()) && Entries[elm].FilenameExt != \"*.*\")\n\t\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"FilenameExt\", (const xmlChar*)Entries[elm].FilenameExt.c_str());\n\t\t\tbreak;\n\t\tcase UFormDfn::EntryDfn:\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Type\", (const xmlChar*)\"Dfn\");\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Filename\", (const xmlChar*)Entries[elm].Filename.c_str());\n\t\t\tbreak;\n\t\tcase UFormDfn::EntryVirtualDfn:\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Type\", (const xmlChar*)\"DfnPointer\");\n\t\t\tbreak;\n\t\t}\n\n\t\t// Is an array ?\n\t\tif (Entries[elm].Array)\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Array\", (const xmlChar*)\"true\");\n\n\t\t// Default value for type\n\t\tif ((Entries[elm].TypeElement == UFormDfn::EntryType) && (!Entries[elm].Default.empty ()))\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"Default\", (const xmlChar*)Entries[elm].Default.c_str ());\n\t}\n\n\t// Header\n\tHeader.write (node);\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::read (xmlNodePtr root, CFormLoader &loader, bool forceLoad, const char *filename)\n{\n\t// Save filename\n\t_Filename = CFile::getFilename (filename);\n\n\t// Check node name\n\tif ( ((const char*)root->name == NULL) || (strcmp ((const char*)root->name, \"DFN\") != 0) )\n\t{\n\t\t// Throw exception\n\t\twarning (true, \"read\", \"XML Syntax error in block line %p, node (%s) should be DFN.\", root->content, root->name);\n\t}\n\n\t// Count the parent\n\tuint parentCount = CIXml::countChildren (root, \"PARENT\");\n\tParents.resize (parentCount);\n\n\t// For each element entry\n\tuint parentNumber = 0;\n\txmlNodePtr parent = CIXml::getFirstChildNode (root, \"PARENT\");\n\twhile (parentNumber<parentCount)\n\t{\n\t\t// Get the Parent\n\t\tconst char *parentFilename = (const char*)xmlGetProp (parent, (xmlChar*)\"Name\");\n\t\tif (parentFilename)\n\t\t{\n\t\t\tParents[parentNumber].ParentFilename = parentFilename;\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)parentFilename);\n\n\t\t\t// Load the parent\n\t\t\tParents[parentNumber].Parent = loader.loadFormDfn (Parents[parentNumber].ParentFilename.c_str (), forceLoad);\n\t\t\tif ((Parents[parentNumber].Parent == NULL) && !forceLoad)\n\t\t\t{\n\t\t\t\t// Throw exception\n\t\t\t\twarning (true, \"read\", \"Can't load parent DFN file (%s).\", Parents[parentNumber].ParentFilename.c_str ());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Throw exception\n\t\t\twarning (true, \"read\", \"XML Syntax error in block (%s) line %p, aguments Name not found.\",\n\t\t\t\tparent->name, parent->content);\n\t\t}\n\n\t\t// Next parent\n\t\tparent = CIXml::getNextChildNode (parent, \"PARENT\");\n\t\tparentNumber++;\n\t}\n\n\t// Count the element children\n\tuint childCount = CIXml::countChildren (root, \"ELEMENT\");\n\n\t// Resize the element table\n\tEntries.resize (childCount);\n\n\t// For each element entry\n\tuint childNumber = 0;\n\txmlNodePtr child = CIXml::getFirstChildNode (root, \"ELEMENT\");\n\twhile (childNumber<childCount)\n\t{\n\t\t// Checks\n\t\tnlassert (child);\n\n\t\t// Get the name\n\t\tconst char *value = (const char*)xmlGetProp (child, (xmlChar*)\"Name\");\n\t\tif (value)\n\t\t{\n\t\t\t// Store the value\n\t\t\tEntries[childNumber].Name = value;\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)value);\n\n\t\t\t// Reset\n\t\t\tEntries[childNumber].Dfn = NULL;\n\t\t\tEntries[childNumber].Type = NULL;\n\t\t\tEntries[childNumber].Default.clear ();\n\n\t\t\tconst char *filename = (const char*)xmlGetProp (child, (xmlChar*)\"Filename\");\n\n\t\t\tif ( filename )\n\t\t\t{\n\t\t\t\tEntries[childNumber].Filename = filename;\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)filename);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEntries[childNumber].Filename.clear ();\n\t\t\t}\n\n\t\t\tconst char *filenameExt = (const char*)xmlGetProp (child, (xmlChar*)\"FilenameExt\");\n\t\t\tif ( filenameExt )\n\t\t\t{\n\t\t\t\tEntries[childNumber].FilenameExt = filenameExt;\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)filenameExt);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tEntries[childNumber].FilenameExt = \"*.*\";\n\t\t\t}\n\n\t\t\t// Read the type\n\t\t\tconst char *typeName = (const char*)xmlGetProp (child, (xmlChar*)\"Type\");\n\t\t\tif (typeName)\n\t\t\t{\n\t\t\t\tbool type = false;\n\t\t\t\tbool dfn = false;\n\t\t\t\tif (stricmp (typeName, \"Type\") == 0)\n\t\t\t\t{\n\t\t\t\t\tEntries[childNumber].TypeElement = UFormDfn::EntryType;\n\t\t\t\t\ttype = true;\n\n\t\t\t\t\t// Load the filename\n\t\t\t\t\tif (!Entries[childNumber].Filename.empty ())\n\t\t\t\t\t{\n\t\t\t\t\t\tEntries[childNumber].Type = loader.loadType (Entries[childNumber].Filename.c_str ());\n\t\t\t\t\t\tif ((Entries[childNumber].Type == NULL) && !forceLoad)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Throw exception\n\t\t\t\t\t\t\twarning (true, \"read\", \"In XML block (%s) line %p, file not found %s.\",\n\t\t\t\t\t\t\t\tchild->name, child->content, Entries[childNumber].Filename.c_str ());\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read the default value\n\t\t\t\t\t\tconst char *defaultName = (const char*)xmlGetProp (child, (xmlChar*)\"Default\");\n\t\t\t\t\t\tif (defaultName)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tEntries[childNumber].Default = defaultName;\n\n\t\t\t\t\t\t\t// Delete the value\n\t\t\t\t\t\t\txmlFree ((void*)defaultName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Throw exception\n\t\t\t\t\t\twarning (true, \"read\", \"XML In block (%s) line %p, no filename found for the .typ file.\",\n\t\t\t\t\t\t\tchild->name, child->content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (stricmp (typeName, \"Dfn\") == 0)\n\t\t\t\t{\n\t\t\t\t\tEntries[childNumber].TypeElement = UFormDfn::EntryDfn;\n\t\t\t\t\tdfn = true;\n\n\t\t\t\t\t// Load the filename\n\t\t\t\t\tif (!Entries[childNumber].Filename.empty ())\n\t\t\t\t\t{\n\t\t\t\t\t\t// Load the filename\n\t\t\t\t\t\tEntries[childNumber].Dfn = loader.loadFormDfn (Entries[childNumber].Filename.c_str (), forceLoad);\n\t\t\t\t\t\tif ((Entries[childNumber].Dfn == NULL) && !forceLoad)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Throw exception\n\t\t\t\t\t\t\twarning (true, \"read\", \"XML In block (%s) line %p, file not found %s.\",\n\t\t\t\t\t\t\t\tchild->name, child->content, Entries[childNumber].Filename.c_str ());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Throw exception\n\t\t\t\t\t\twarning (true, \"read\", \"XML In block (%s) line %p, no filename found for the .typ file.\",\n\t\t\t\t\t\t\tchild->name, child->content);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (stricmp (typeName, \"DfnPointer\") == 0)\n\t\t\t\t{\n\t\t\t\t\tEntries[childNumber].TypeElement = UFormDfn::EntryVirtualDfn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Throw exception\n\t\t\t\t\twarning (true, \"read\", \"XML Syntax error in block (%s) line %p, element has not a valid type name attribut \\\"Type = %s\\\".\",\n\t\t\t\t\t\tchild->name, child->content, typeName);\n\t\t\t\t}\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)typeName);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Throw exception\n\t\t\t\twarning (true, \"read\", \"XML Syntax error in block (%s) line %p, element has no type name attribut \\\"Type = [Type][Dfn][DfnPointer]\\\".\",\n\t\t\t\t\tchild->name, child->content);\n\t\t\t}\n\n\t\t\t// Get the array attrib\n\t\t\tEntries[childNumber].Array = false;\n\t\t\tconst char* arrayFlag = (const char*)xmlGetProp (child, (xmlChar*)\"Array\");\n\t\t\tif (arrayFlag)\n\t\t\t{\n\t\t\t\tEntries[childNumber].Array =  (stricmp (arrayFlag, \"true\") == 0);\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)arrayFlag);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Throw exception\n\t\t\twarning (true, \"read\", \"XML Syntax error in block (%s) line %p, aguments Name not found.\",\n\t\t\t\troot->name, root->content);\n\t\t}\n\n\t\t// Next child\n\t\tchild = CIXml::getNextChildNode (child, \"ELEMENT\");\n\t\tchildNumber++;\n\t}\n\n\t// Read the header\n\tHeader.read (root);\n}\n\n// ***************************************************************************\n\nuint CFormDfn::countParentDfn (uint32 round) const\n{\n\t// Checkout recursive calls\n\tif (round > NLGEORGES_MAX_RECURSION)\n\t{\n\t\t// Turn around..\n\t\twarning (false, \"countParentDfn\", \"Recursive call on the same DFN, look for loop inheritances.\");\n\t\treturn 0;\n\t}\n\n\tuint count = 0;\n\tuint i;\n\tfor (i=0; i<Parents.size (); i++)\n\t{\n\t\tcount += Parents[i].Parent->countParentDfn (round+1);\n\t}\n\treturn count+1;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::getParentDfn (std::vector<CFormDfn*> &array, uint32 round)\n{\n\t// Checkout recursive calls\n\tif (round > NLGEORGES_MAX_RECURSION)\n\t{\n\t\t// Turn around..\n\t\twarning (false, \"getParentDfn\", \"Recursive call on the same DFN, look for loop inheritances.\");\n\t\treturn;\n\t}\n\n\t//uint count = 0;\n\tuint i;\n\tfor (i=0; i<Parents.size (); i++)\n\t{\n\t\tParents[i].Parent->getParentDfn (array, round+1);\n\t}\n\tarray.push_back (this);\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::getParentDfn (std::vector<const CFormDfn*> &array, uint32 round) const\n{\n\t// Checkout recursive calls\n\tif (round > NLGEORGES_MAX_RECURSION)\n\t{\n\t\t// Turn around..\n\t\twarning (false, \"getParentDfn\", \"Recursive call on the same DFN, look for loop inheritances.\");\n\t\treturn;\n\t}\n\n\t//uint count = 0;\n\tuint i;\n\tfor (i=0; i<Parents.size (); i++)\n\t{\n\t\tParents[i].Parent->getParentDfn (array, round+1);\n\t}\n\tarray.push_back (this);\n}\n\n// ***************************************************************************\n\nuint CFormDfn::getNumParent () const\n{\n\treturn (uint)Parents.size ();\n}\n\n// ***************************************************************************\n\nCFormDfn *CFormDfn::getParent (uint parent) const\n{\n\treturn Parents[parent].Parent;\n}\n\n// ***************************************************************************\n\nconst string& CFormDfn::getParentFilename (uint parent) const\n{\n\treturn Parents[parent].ParentFilename;\n}\n\n// ***************************************************************************\n\nuint CFormDfn::getNumEntry () const\n{\n\treturn (uint)Entries.size();\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::setNumEntry (uint size)\n{\n\tEntries.resize (size);\n}\n\n// ***************************************************************************\n\nconst CFormDfn::CEntry &CFormDfn::getEntry (uint entry) const\n{\n\treturn Entries[entry];\n}\n\n// ***************************************************************************\n\nCFormDfn::CEntry &CFormDfn::getEntry (uint entry)\n{\n\treturn Entries[entry];\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::setNumParent (uint size)\n{\n\tParents.resize (size);\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::setParent (uint parent, CFormLoader &loader, const char *filename)\n{\n\tif (strcmp (filename, \"\")==0)\n\t\tParents[parent].Parent = NULL;\n\telse\n\t\tParents[parent].Parent = loader.loadFormDfn (filename, false);\n\tParents[parent].ParentFilename = filename;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setType (CFormLoader &loader, const char *filename)\n{\n\tTypeElement = EntryType;\n\tDfn = NULL;\n\tFilename = filename;\n\tType = loader.loadType (filename);\n}\n\nvoid CFormDfn::CEntry::setType( TEntryType type )\n{\n\tTypeElement = type;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setDfn (CFormLoader &loader, const char *filename)\n{\n\tTypeElement = EntryDfn;\n\tFilename = filename;\n\tType = NULL;\n\tDfn = loader.loadFormDfn (filename, false);\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setDfnPointer ()\n{\n\tTypeElement = EntryVirtualDfn;\n\tFilename = \"\";\n\tType = NULL;\n\tDfn = NULL;\n}\n\n// ***************************************************************************\n\nconst std::string &CFormDfn::CEntry::getName () const\n{\n\treturn Name;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setName (const char *name)\n{\n\tName = name;\n}\n\n// ***************************************************************************\n\nconst std::string &CFormDfn::CEntry::getDefault () const\n{\n\treturn Default;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setDefault (const char *def)\n{\n\tDefault = def;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setArrayFlag (bool flag)\n{\n\tArray = flag;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::CEntry::getArrayFlag () const\n{\n\treturn Array;\n}\n\n// ***************************************************************************\n\nUFormDfn::TEntryType CFormDfn::CEntry::getType () const\n{\n\treturn TypeElement;\n}\n\n// ***************************************************************************\n\nconst std::string &CFormDfn::CEntry::getFilename() const\n{\n\treturn Filename;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setFilename (const char *def)\n{\n\tFilename = def;\n}\n\n// ***************************************************************************\n\nCType *CFormDfn::CEntry::getTypePtr ()\n{\n\treturn Type;\n}\n\n// ***************************************************************************\n\nCFormDfn *CFormDfn::CEntry::getDfnPtr ()\n{\n\treturn Dfn;\n}\n\n// ***************************************************************************\n\nconst CType *CFormDfn::CEntry::getTypePtr () const\n{\n\treturn Type;\n}\n\n// ***************************************************************************\n\nconst CFormDfn *CFormDfn::CEntry::getDfnPtr () const\n{\n\treturn Dfn;\n}\n\n// ***************************************************************************\n\nCFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex)\n{\n\t// Get the sub DFN\n\tvector<CFormDfn*> parentDfn;\n\tparentDfn.reserve (countParentDfn ());\n\tgetParentDfn (parentDfn);\n\n\t// For each parent\n\tuint dfn;\n\tdfnIndex = index;\n\tuint parentSize = (uint)parentDfn.size();\n\tfor (dfn=0; dfn<parentSize; dfn++)\n\t{\n\t\t// Good element ?\n\t\tuint size = (uint)parentDfn[dfn]->Entries.size ();\n\t\tif (dfnIndex<size)\n\t\t\treturn parentDfn[dfn];\n\t\tdfnIndex -= size;\n\t}\n\n\t// Should be found..\n\tnlstop;\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nconst CFormDfn *CFormDfn::getSubDfn (uint index, uint &dfnIndex) const\n{\n\t// Get the sub DFN\n\tvector<const CFormDfn*> parentDfn;\n\tparentDfn.reserve (countParentDfn ());\n\tgetParentDfn (parentDfn);\n\n\t// For each parent\n\tuint dfn;\n\tdfnIndex = index;\n\tuint parentSize = (uint)parentDfn.size();\n\tfor (dfn=0; dfn<parentSize; dfn++)\n\t{\n\t\t// Good element ?\n\t\tuint size = (uint)parentDfn[dfn]->Entries.size ();\n\t\tif (dfnIndex<size)\n\t\t\treturn parentDfn[dfn];\n\t\tdfnIndex -= size;\n\t}\n\n\t// Should be found..\n\tnlstop;\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryType (uint entry, TEntryType &type, bool &array) const\n{\n\tif (entry < Entries.size ())\n\t{\n\t\ttype = Entries[entry].TypeElement;\n\t\tarray = Entries[entry].Array;\n\t\treturn true;\n\t}\n\twarning (false, \"getEntryType\", \"Wrong entry ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryFilename (uint entry, std::string& filename) const\n{\n\tif (entry < Entries.size ())\n\t{\n\t\tif (Entries[entry].TypeElement != EntryVirtualDfn)\n\t\t{\n\t\t\tfilename = Entries[entry].Filename;\n\t\t\treturn true;\n\t\t}\n\t\twarning (false, \"getEntryFilename\", \"The entry is a virtual DFN.\");\n\t\treturn false;\n\t}\n\twarning (false, \"getEntryFilename\", \"Wrong entry ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryFilenameExt (uint entry, std::string& filename) const\n{\n\tif (entry < Entries.size ())\n\t{\n\t\tfilename = Entries[entry].FilenameExt;\n\t\treturn true;\n\t}\n\twarning (false, \"getEntryFilenameExt\", \"Wrong entry ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryIndexByName (uint &entry, const\tstd::string &name) const\n{\n\tuint\tentryIndex=0;\n\twhile\t(entryIndex<Entries.size ())\n\t{\n\t\tif (Entries[entryIndex].Name==name)\n\t\t{\n\t\t\tentry=entryIndex;\n\t\t\treturn\ttrue;\n\t\t}\n\t\tentryIndex++;\n\t}\n\tentry = std::numeric_limits<uint>::max();\n\treturn\tfalse;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryName (uint entry, std::string &name) const\n{\n\tif (entry < Entries.size ())\n\t{\n\t\tname = Entries[entry].Name;\n\t\treturn true;\n\t}\n\twarning (false, \"getEntryName\", \"Wrong entry ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool\tCFormDfn::getEntryDfn (uint entry, UFormDfn **dfn)\n{\n\tif (entry < Entries.size ())\n\t{\n\t\tif (Entries[entry].TypeElement == EntryDfn)\n\t\t{\n\t\t\t*dfn = Entries[entry].Dfn;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t\twarning (false, \"getEntryDfn\", \"This entry is not a DFN.\");\n\t}\n\twarning (false, \"getEntryDfn\", \"Wrong entry ID.\");\n\treturn false;\n}\n\nbool\tCFormDfn::getEntryByName (const std::string &name, CFormDfn::CEntry **entry)\n{\n\tint\tentryIndex=(int)Entries.size ()-1;\n\twhile (entryIndex>=0)\n\t{\n\t\tCEntry\t*entryPtr=&Entries[entryIndex];\n\t\tif (entryPtr->getName()==name)\n\t\t{\n\t\t\t*entry=entryPtr;\n\t\t\treturn\ttrue;\n\t\t}\n\t\tentryIndex--;\n\t}\n\t*entry=NULL;\n\treturn\tfalse;\n}\n\nbool\tCFormDfn::getEntryDfnByName (const std::string &name, UFormDfn **dfn)\n{\n\tCFormDfn::CEntry\t*entry;\n\tif\t(getEntryByName (name, &entry))\n\t{\n\t\t*dfn=entry->getDfnPtr();\n\t\treturn\ttrue;\n\t}\n\t*dfn=NULL;\n\treturn\tfalse;\n}\n\nbool\tCFormDfn::isAnArrayEntryByName\t(const std::string &name)\tconst\n{\n\tCFormDfn::CEntry\t*entry;\n\tif\t(const_cast<CFormDfn*>(this)->getEntryByName (name, &entry))\n\t{\n\t\treturn\tentry->getArrayFlag();\n\t}\n\treturn\tfalse;\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getEntryType (uint entry, UType **type)\n{\n\tif (entry < Entries.size ())\n\t{\n\t\tif (Entries[entry].TypeElement == EntryType)\n\t\t{\n\t\t\t*type = Entries[entry].Type;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t\twarning (false, \"getEntryType\", \"This entry is not a type.\");\n\t}\n\twarning (false, \"getEntryType\", \"Wrong entry ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nuint CFormDfn::getNumParents () const\n{\n\treturn (uint)Parents.size ();\n}\n\n// ***************************************************************************\n\nbool CFormDfn::getParent (uint parent, UFormDfn **parentRet)\n{\n\tif (parent < Parents.size ())\n\t{\n\t\t*parentRet = Parents[parent].Parent;\n\t\treturn true;\n\t}\n\twarning (false, \"getParent\", \"Wrong parent ID.\");\n\treturn false;\n}\n\n\n// ***************************************************************************\n\nbool CFormDfn::getParentFilename (uint parent, std::string &filename) const\n{\n\tif (parent < Parents.size ())\n\t{\n\t\tfilename = Parents[parent].ParentFilename;\n\t\treturn true;\n\t}\n\twarning (false, \"getParentFilename\", \"Wrong parent ID.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nconst std::string& CFormDfn::getComment () const\n{\n\treturn Header.Comments;\n}\n\n// ***************************************************************************\n\nconst std::string &CFormDfn::CEntry::getFilenameExt() const\n{\n\treturn FilenameExt;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::CEntry::setFilenameExt (const char *ext)\n{\n\tFilenameExt = ext;\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CFormDfn::%s) in form DFN (%s) : %s\", function, _Filename.c_str (), buffer);\n}\n\n// ***************************************************************************\n\nvoid CFormDfn::getDependencies (std::set<std::string> &dependencies) const\n{\n\t// Scan only if not already inserted\n\tif (dependencies.insert (toLower(CFile::getFilename (_Filename))).second)\n\t{\n\t\t// Add parents\n\t\tuint i;\n\t\tfor (i=0; i<Parents.size (); i++)\n\t\t{\n\t\t\tParents[i].Parent->getDependencies (dependencies);\n\t\t}\n\n\t\t// Add entries\n\t\tfor (i=0; i<Entries.size (); i++)\n\t\t{\n\t\t\tif (Entries[i].getDfnPtr ())\n\t\t\t\tEntries[i].getDfnPtr ()->getDependencies (dependencies);\n\t\t\tif (Entries[i].getTypePtr ())\n\t\t\t{\n\t\t\t\tdependencies.insert (toLower(CFile::getFilename (Entries[i].getFilename())));\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n"
  },
  {
    "path": "code/nel/src/georges/form_elm.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/i_xml.h\"\n\n#include \"nel/georges/form.h\"\n#include \"nel/georges/form_elm.h\"\n#include \"nel/georges/form_loader.h\"\n#include \"nel/georges/type.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n// class CFormElm\n// ***************************************************************************\n\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... );\n\n// ***************************************************************************\n\nbool CFormElm::isArray () const\n{\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArraySize (uint &/* size */) const\n{\n\twarning (false, \"getArraySize\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayNode (const UFormElm ** /* result */, uint /* arrayIndex */) const\n{\n\twarning (false, \"getArrayNode\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayNode (UFormElm ** /* result */, uint /* arrayIndex */)\n{\n\twarning (false, \"getArrayNode\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayNodeName (std::string &/* result */, uint /* arrayIndex */) const\n{\n\twarning (false, \"getArrayNodeName\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (std::string &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayNode\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (sint8 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (uint8 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (sint16 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (uint16 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (sint32 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (uint32 &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (float &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (double &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (bool &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getArrayValue (NLMISC::CRGBA &/* result */, uint /* arrayIndex */, TEval /* evaluate */, TWhereIsValue * /* where */) const\n{\n\twarning (false, \"getArrayValue\", \"This node is not an array.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::isStruct () const\n{\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::isVirtualStruct () const\n{\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getDfnName (std::string &/* dfnName */ ) const\n{\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getStructSize (uint &/* size */) const\n{\n\twarning (false, \"getStructSize\", \"This node is not a struct.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getStructNodeName (uint /* element */, string &/* result */) const\n{\n\twarning (false, \"getStructNodeName\", \"This node is not a struct.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getStructNode (uint /* element */, const UFormElm ** /* result */) const\n{\n\twarning (false, \"getStructNode\", \"This node is not a struct.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getStructNode (uint /* element */, UFormElm ** /* result */)\n{\n\twarning (false, \"getStructNode\", \"This node is not a struct.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::isAtom () const\n{\n\treturn false;\n}\n\n// ***************************************************************************\n\nconst CType* CFormElm::getType ()\n{\n\twarning (false, \"getType\", \"This node is not an atom.\");\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (string &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (sint8 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (uint8 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (sint16 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (uint16 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (sint32 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (uint32 &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (float &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (double &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (bool &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValue (NLMISC::CRGBA &/* result */, TEval /* evaluate */) const\n{\n\twarning (false, \"getValue\", \"This node is not an atom.\");\n\treturn false;\n}\n\n// ***************************************************************************\n\nCFormElm::CFormElm (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex)\n{\n\tForm = form;\n\tParentNode = parentNode;\n\tParentDfn = parentDfn;\n\tParentIndex = parentIndex;\n\tRound = 0xffffffff;\n}\n\n// ***************************************************************************\n\nCFormElm::~CFormElm ()\n{\n\tclean(); // it's virtual\n}\n\n// ***************************************************************************\n\nbool CFormElm::isUsed (const CForm *form) const\n{\n\treturn form == Form;\n}\n\n// ***************************************************************************\n\nCForm *CFormElm::getForm () const\n{\n\treturn Form;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getNodeByName (UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round)\n{\n\tconst UFormElm *resultConst = NULL;\n\tif (((const UFormElm*)this)->getNodeByName (&resultConst, name, where, verbose, round))\n\t{\n\t\t*result = const_cast<UFormElm*> (resultConst);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getNodeByName (const UFormElm **result, const char *name, TWhereIsNode *where, bool verbose, uint32 round) const\n{\n\t// The parent Dfn\n\tconst CFormDfn *parentDfn;\n\tconst CFormDfn *nodeDfn;\n\tconst CType *nodeType;\n\tCFormElm *node;\n\tuint indexDfn;\n\tbool array;\n\tbool parentVDfnArray;\n\tUFormDfn::TEntryType type;\n\n\t// Search for the node\n\tif (getNodeByName (name, &parentDfn, indexDfn, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, verbose, round))\n\t{\n\t\t// Set the result\n\t\t*result = node;\n\n\t\t// Where ?\n\t\tif (where && node)\n\t\t{\n\t\t\t*where = (node->getForm () == Form) ? NodeForm : NodeParentForm;\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (string& result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// The parent Dfn\n\tconst CFormDfn *parentDfn;\n\tconst CFormDfn *nodeDfn;\n\tconst CType *nodeType;\n\tCFormElm *node;\n\tuint parentIndex;\n\tbool array;\n\tbool parentVDfnArray;\n\tUFormDfn::TEntryType type;\n\n\t// Search for the node\n\tif (getNodeByName (name, &parentDfn, parentIndex, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, true, round))\n\t{\n\t\t// End, return the current index\n\t\tif (type == UFormDfn::EntryType)\n\t\t{\n\t\t\t// The atom\n\t\t\tconst CFormElmAtom *atom = node ? safe_cast<const CFormElmAtom*> (node) : NULL;\n\n\t\t\t// Evale\n\t\t\tnlassert (nodeType);\n\t\t\treturn (nodeType->getValue (result, Form, atom, *parentDfn, parentIndex, evaluate, (uint32*)where, round, name));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Error message\n\t\t\twarning (false, \"getValueByName\", \"The node (%s) is not an atom element. Can't return a value.\", name);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"getValueByName\", \"Can't find the node (%s).\", name);\n\t}\n\n\t// Error\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (sint8 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (uint8 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (sint16 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (uint16 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (sint32 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (uint32 &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (float &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (double &result, const char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (bool &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getValueByName (NLMISC::CRGBA &result,\tconst char *name, TEval evaluate, TWhereIsValue *where, uint32 round) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValueByName (value, name, evaluate, where, round))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nUFormElm *CFormElm::getParent () const\n{\n\treturn ParentNode;\n}\n\n// ***************************************************************************\n\nbool CFormElm::createNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\tbool &array, bool &created)\n{\n\t*parentDfn = ParentDfn;\n\tindexDfn = ParentIndex;\n\t*nodeDfn = NULL;\n\t*nodeType = NULL;\n\t*node = this;\n\tbool parentVDfnArray;\n\treturn getInternalNodeByName (Form, name, parentDfn, indexDfn, nodeDfn, nodeType, node, type, array, Create, created, parentVDfnArray, true, NLGEORGES_FIRST_ROUND);\n}\n\n// ***************************************************************************\n\nbool CFormElm::deleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\tbool &array)\n{\n\t*parentDfn = ParentDfn;\n\tindexDfn = ParentIndex;\n\t*nodeDfn = NULL;\n\t*nodeType = NULL;\n\t*node = this;\n\tbool created;\n\tbool parentVDfnArray;\n\treturn getInternalNodeByName (Form, name, parentDfn, indexDfn, nodeDfn, nodeType, node, type, array, Delete, created, parentVDfnArray, true, NLGEORGES_FIRST_ROUND);\n}\n\n// ***************************************************************************\n\nbool CFormElm::getNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\tbool &array, bool &parentVDfnArray, bool verbose, uint32 round) const\n{\n\t*parentDfn = ParentDfn;\n\tindexDfn = ParentIndex;\n\t*nodeDfn = NULL;\n\t*nodeType = NULL;\n\t*node = (CFormElm*)this;\n\tbool created;\n\treturn getInternalNodeByName (Form, name, parentDfn, indexDfn, nodeDfn, nodeType, node, type, array, Return, created, parentVDfnArray, verbose, round);\n}\n\n// ***************************************************************************\n\nbool CFormElm::arrayInsertNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\tbool &array, bool verbose, uint arrayIndex) const\n{\n\t// Get the node by name\n\t*parentDfn = ParentDfn;\n\tindexDfn = ParentIndex;\n\t*nodeDfn = NULL;\n\t*nodeType = NULL;\n\t*node = (CFormElm*)this;\n\tbool created;\n\tbool parentVDfnArray;\n\tif (getInternalNodeByName (Form, name, parentDfn, indexDfn, nodeDfn, nodeType, node, type, array, Create, created, parentVDfnArray, verbose, NLGEORGES_FIRST_ROUND))\n\t{\n\t\t// Must be in the same form\n\t\tnlassert ((*node) && ((*node)->Form == Form));\n\n\t\t// Get its parent\n\t\tCFormElm *parentNode = (*node)->ParentNode;\n\t\tif (parentNode->isArray ())\n\t\t{\n\t\t\t// Cast pointer\n\t\t\tCFormElmArray *array = safe_cast<CFormElmArray*>(parentNode);\n\n\t\t\t// Valid index ?\n\t\t\tif (arrayIndex<array->Elements.size ())\n\t\t\t{\n\t\t\t\t// Insert the element\n\t\t\t\tarray->Elements.insert (array->Elements.begin() + arrayIndex, CFormElmArray::CElement());\n\n\t\t\t\t// Create a new element\n\n\t\t\t\t// The new element\n\t\t\t\tCFormElm *newelm = NULL;\n\t\t\t\tswitch (type)\n\t\t\t\t{\n\t\t\t\tcase UFormDfn::EntryType:\n\t\t\t\t\t{\n\t\t\t\t\t\t// Create an atom\n\t\t\t\t\t\tCFormElmAtom *atom = new CFormElmAtom (Form, array, *parentDfn, indexDfn);\n\t\t\t\t\t\tnewelm = atom;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase UFormDfn::EntryDfn:\n\t\t\t\t\t{\n\t\t\t\t\t\tCFormElmStruct *_struct = new CFormElmStruct (Form, array, *parentDfn, indexDfn);\n\t\t\t\t\t\t_struct->build (*nodeDfn);\n\t\t\t\t\t\tnewelm = _struct;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase UFormDfn::EntryVirtualDfn:\n\t\t\t\t\t// todo array of virtual struct\n\t\t\t\t\t//newelm = new CFormElmVirtualStruct (Form, array, *parentDfn, indexDfn);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tnlstop;\n\t\t\t\t}\n\n\t\t\t\tnlassert (newelm);\n\n\t\t\t\t// Set the element pointer\n\t\t\t\tarray->Elements[arrayIndex].Element = newelm;\n\n\t\t\t\t// Ok\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::arrayDeleteNodeByName (const char *name, const CFormDfn **parentDfn, uint &indexDfn,\n\t\t\t\t\t\t\t\t\tconst CFormDfn **nodeDfn, const CType **nodeType,\n\t\t\t\t\t\t\t\t\tCFormElm **node, UFormDfn::TEntryType &type,\n\t\t\t\t\t\t\t\t\tbool &array, bool verbose, uint arrayIndex) const\n{\n\t// Get the node by name\n\t*parentDfn = ParentDfn;\n\tindexDfn = ParentIndex;\n\t*nodeDfn = NULL;\n\t*nodeType = NULL;\n\t*node = (CFormElm*)this;\n\tbool created;\n\tbool parentVDfnArray;\n\tif (getInternalNodeByName (Form, name, parentDfn, indexDfn, nodeDfn, nodeType, node, type, array, Create, created, parentVDfnArray, verbose, NLGEORGES_FIRST_ROUND))\n\t{\n\t\t// Must be in the same form\n\t\tnlassert ((*node) && ((*node)->Form == Form));\n\n\t\t// Get its parent\n\t\tCFormElm *parentNode = (*node)->ParentNode;\n\t\tif (parentNode->isArray ())\n\t\t{\n\t\t\t// Cast pointer\n\t\t\tCFormElmArray *array = safe_cast<CFormElmArray*>(parentNode);\n\n\t\t\t// Valid index ?\n\t\t\tif (arrayIndex<array->Elements.size ())\n\t\t\t{\n\t\t\t\t// Insert the element\n\t\t\t\tif (array->Elements[arrayIndex].Element)\n\t\t\t\t\tdelete array->Elements[arrayIndex].Element;\n\n\t\t\t\t// Erase the entry\n\t\t\t\tarray->Elements.erase (array->Elements.begin () + arrayIndex);\n\n\t\t\t\t// Ok\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::getInternalNodeByName (CForm *form, const char *name, const CFormDfn **parentDfn, uint &indexDfn, const CFormDfn **nodeDfn, const CType **nodeType, CFormElm **node, UFormDfn::TEntryType &type, bool &array, TNodeAction action, bool &created, bool &parentVDfnArray, bool verbose, uint32 round)\n{\n\t// *** Init output variables\n\tcreated = false;\n\tparentVDfnArray = false;\n\n\t// ParentDfn or Node..\n\tnlassert ( (*parentDfn) || (*node) );\n\n\t// Error message\n\tchar error[512];\n\n\t// Parent exist ?\n\tif (*parentDfn)\n\t{\n\t\t// Get the entry\n\t\tconst CFormDfn::CEntry &theEntry = (*parentDfn)->getEntry (indexDfn);\n\n\t\t// Get the type\n\t\ttype = theEntry.getType ();\n\t\t*nodeType = theEntry.getTypePtr ();\n\t\tif (type == UFormDfn::EntryVirtualDfn)\n\t\t{\n\t\t\tif (*node)\n\t\t\t\t*nodeDfn = safe_cast <CFormElmVirtualStruct*> (*node)->FormDfn;\n\t\t\telse\n\t\t\t\t*nodeDfn = NULL;\n\t\t}\n\t\telse\n\t\t\t*nodeDfn = theEntry.getDfnPtr ();\n\t\tarray = theEntry.getArrayFlag ();\n\t}\n\telse if (*node)\n\t{\n\t\tnlassert (!(*node)->isArray ());\n\t\tindexDfn = 0xffffffff;\n\t\t*nodeType = (*node)->isAtom () ? safe_cast<CFormElmAtom*>(*node)->Type : NULL;\n\t\t*nodeDfn = (*node)->isStruct () ? (const CFormDfn *)(safe_cast<CFormElmStruct*>(*node)->FormDfn) : NULL;\n\t\ttype = (*node)->isAtom () ? UFormDfn::EntryType : (*node)->isVirtualStruct () ? UFormDfn::EntryVirtualDfn : UFormDfn::EntryDfn;\n\t\tarray = false;\n\t}\n\n\t// Check node pointer\n\tif (action == Create)\n\t{\n\t\tnlassert (*node);\n\t\tnlassert ((*node)->getForm () == form);\n\t}\n\n\t// Backup current node\n\tCFormElm *backupFirstElm = *node;\n\n\t// *** Parsing variables\n\n\t// Current token start and end\n\tconst char *startToken = name;\n\tconst char *endToken;\n\n\t// Current token start\n\tstring token;\n\n\t// Current form name\n\tstring currentName;\n\tif (*node)\n\t\t(*node)->getFormName (currentName);\n\n\t// Error\n\tuint errorIndex;\n\n\t// Token code\n\tuint code;\n\n\t// Are we parsing an array ?\n\tbool inArrayIndex = false;\n\n\t// Index in the array\n\tuint arrayIndex;\n\n\t// Bool next token must be an array index\n\tbool wantArrayIndex = false;\n\n\t// Last struct elm\n\tCFormElmStruct *lastStructElm = ((*node)->ParentNode && (*node)->ParentNode->isStruct ()) ? safe_cast<CFormElmStruct*> ((*node)->ParentNode) : NULL;\n\tuint lastStructIndex = 0;\n\tif (lastStructElm)\n\t{\n\t\t// Look for node in the parent\n\t\tfor (; lastStructIndex<lastStructElm->Elements.size (); lastStructIndex++)\n\t\t{\n\t\t\t// The same node ?\n\t\t\tif (lastStructElm->Elements[lastStructIndex].Element == (*node))\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Must have been found\n\t\tnlassert (lastStructIndex<lastStructElm->Elements.size ());\n\t}\n\n\t// While there is tokens\n   \twhile ((endToken = tokenize (startToken, token, errorIndex, code)))\n\t{\n\t\t// Ready an array index ?\n\t\tif (!inArrayIndex)\n\t\t{\n\t\t\t// For each code\n\t\t\tswitch (code)\n\t\t\t{\n\t\t\tcase TokenString:\n\t\t\t\t{\n\t\t\t\t\t// Need an array index array ?\n\t\t\t\t\tif (wantArrayIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Token (%s) should be an array index.\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Are we a struct ?\n\t\t\t\t\tif ( ((type == UFormDfn::EntryDfn) || (type == UFormDfn::EntryVirtualDfn)) /*&& (!array)*/ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check the virtual DFN is not empty..\n\t\t\t\t\t\tif ( (type == UFormDfn::EntryVirtualDfn) && (*nodeDfn == NULL) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Is it a parent virtual DFN ?\n\t\t\t\t\t\t\tif ( (type == UFormDfn::EntryVirtualDfn) && (*node == NULL) )\n\t\t\t\t\t\t\t\tparentVDfnArray = true;\n\n\t\t\t\t\t\t\t// Create mode ?\n\t\t\t\t\t\t\tif (action == Create)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Should have a valid node\n\t\t\t\t\t\t\t\tnlassert (*node && lastStructElm);\n\n\t\t\t\t\t\t\t\t// Get the current virtual dfn\n\t\t\t\t\t\t\t\tCFormElmVirtualStruct *vStruct = safe_cast<CFormElmVirtualStruct*> (*node);\n\n\t\t\t\t\t\t\t\t// Get the form name of the current node\n\t\t\t\t\t\t\t\tstring formName;\n\t\t\t\t\t\t\t\tvStruct->getFormName (formName, NULL);\n\n\t\t\t\t\t\t\t\t// Get the parent node if available\n\t\t\t\t\t\t\t\tfor (uint parent=0; parent<form->getParentCount (); parent++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Get the parent\n\t\t\t\t\t\t\t\t\tCForm *parentPtr = form->getParent (parent);\n\t\t\t\t\t\t\t\t\tnlassert (parentPtr);\n\n\t\t\t\t\t\t\t\t\t// Get the virtual node by name\n\t\t\t\t\t\t\t\t\tUFormElm *uelm;\n\t\t\t\t\t\t\t\t\tif (parentPtr->getRootNode ().getNodeByName (&uelm, formName.c_str (), NULL, verbose, round+1) && uelm)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// Value node ?\n\t\t\t\t\t\t\t\t\t\tif (uelm->isVirtualStruct ())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// Get a virtual struct pointer\n\t\t\t\t\t\t\t\t\t\t\tCFormElmVirtualStruct *vStructParent = safe_cast<CFormElmVirtualStruct*> (uelm);\n\n\t\t\t\t\t\t\t\t\t\t\t// Copy the DFN filename\n\t\t\t\t\t\t\t\t\t\t\tvStruct->DfnFilename = vStructParent->DfnFilename;\n\n\t\t\t\t\t\t\t\t\t\t\t// Build it\n\t\t\t\t\t\t\t\t\t\t\tvStruct->build (vStructParent->FormDfn);\n\n\t\t\t\t\t\t\t\t\t\t\t// Set the current DFN\n\t\t\t\t\t\t\t\t\t\t\t*nodeDfn = vStruct->FormDfn;\n\n\t\t\t\t\t\t\t\t\t\t\t// Stop looking for parent\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// Error message\n\t\t\t\t\t\t\t\t\t\t\tsmprintf (error, 512, \"Internal node parsing error.\");\n\t\t\t\t\t\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Still no DFN ?\n\t\t\t\t\t\t\tif (*nodeDfn == NULL)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Error message\n\t\t\t\t\t\t\t\tsmprintf (error, 512, \"Empty virtual struct element. Can't look into it while it is not defined.\");\n\t\t\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Must have a nodeDfn here\n\t\t\t\t\t\tnlassert (*nodeDfn);\n\n\t\t\t\t\t\t// Look for the element\n\t\t\t\t\t\t//\t\t\t\t\t\tuint elementCount = (*nodeDfn)->getNumEntry ();\n\n\t\t\t\t\t\t// Get the parents\n\t\t\t\t\t\tvector<const CFormDfn*> arrayDfn;\n\t\t\t\t\t\tarrayDfn.reserve ((*nodeDfn)->countParentDfn ());\n\t\t\t\t\t\t(*nodeDfn)->getParentDfn (arrayDfn);\n\n\t\t\t\t\t\t// For each parent\n\t\t\t\t\t\tuint i;\n\t\t\t\t\t\tuint formElm = 0;\n\t\t\t\t\t\tfor (i=0; i<arrayDfn.size(); i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// The dfn\n\t\t\t\t\t\t\tconst CFormDfn &dfn = *(arrayDfn[i]);\n\n\t\t\t\t\t\t\t// For each elements\n\t\t\t\t\t\t\tuint element;\n\t\t\t\t\t\t\tfor (element=0; element<dfn.Entries.size(); element++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Good name ?\n\t\t\t\t\t\t\t\tif (dfn.Entries[element].Name == token)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Good one.\n\t\t\t\t\t\t\t\t\t*parentDfn = &dfn;\n\t\t\t\t\t\t\t\t\tindexDfn = element;\n\t\t\t\t\t\t\t\t\t*nodeDfn = dfn.Entries[element].Dfn;\n\t\t\t\t\t\t\t\t\t*nodeType = dfn.Entries[element].Type;\n\t\t\t\t\t\t\t\t\ttype = dfn.Entries[element].TypeElement;\n\t\t\t\t\t\t\t\t\tarray = dfn.Entries[element].Array;\n\t\t\t\t\t\t\t\t\twantArrayIndex = array;\n\n\t\t\t\t\t\t\t\t\t// Next node\n\t\t\t\t\t\t\t\t\tif (*node)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// Get next node\n\t\t\t\t\t\t\t\t\t\tCFormElmStruct *nodeStruct = safe_cast<CFormElmStruct*> (*node);\n\t\t\t\t\t\t\t\t\t\tCFormElm *nextElt = nodeStruct->Elements[formElm].Element;\n\n\t\t\t\t\t\t\t\t\t\t// If no next node, watch for parent node\n\t\t\t\t\t\t\t\t\t\t*node = nextElt;\n\n\t\t\t\t\t\t\t\t\t\t// Create node\n\t\t\t\t\t\t\t\t\t\tif ( (action == Create) && (*node == NULL) )\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// Is an array ?\n\t\t\t\t\t\t\t\t\t\t\tif (array)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t// Create an atom\n\t\t\t\t\t\t\t\t\t\t\t\tCFormElmArray *atom = new CFormElmArray (form, *nodeDfn, *nodeType, nodeStruct, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\t\t*node = atom;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t// What kind of node ?\n\t\t\t\t\t\t\t\t\t\t\t\tswitch (type)\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryType:\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Create an atom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tCFormElmAtom *atom = new CFormElmAtom (form, nodeStruct, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t*node = atom;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryDfn:\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tCFormElmStruct *_struct = new CFormElmStruct (form, nodeStruct, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t_struct->build (*nodeDfn);\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t*node = _struct;\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryVirtualDfn:\n\t\t\t\t\t\t\t\t\t\t\t\t\t*node = new CFormElmVirtualStruct (form, nodeStruct, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\t\t\t\tnlstop;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Node created\n\t\t\t\t\t\t\t\t\t\t\tcreated = true;\n\n\t\t\t\t\t\t\t\t\t\t\t// Set the node in parent\n\t\t\t\t\t\t\t\t\t\t\tnodeStruct->Elements[formElm].Element = *node;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Is a virtual DFN ?\n\t\t\t\t\t\t\t\t\t\tif ((*node) && (*node)->isVirtualStruct ())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// Should be NULL\n\t\t\t\t\t\t\t\t\t\t\tnlassert (*nodeDfn == NULL);\n\n\t\t\t\t\t\t\t\t\t\t\t// Set the current dfn\n\t\t\t\t\t\t\t\t\t\t\t*nodeDfn = safe_cast<const CFormElmVirtualStruct*> (*node)->FormDfn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Save last struct\n\t\t\t\t\t\t\t\t\t\tlastStructElm = nodeStruct;\n\t\t\t\t\t\t\t\t\t\tlastStructIndex = formElm;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// Save last struct\n\t\t\t\t\t\t\t\t\t  //\t\t\t\t\t\t\t\t\t\tCFormElmStruct *lastStructElm = NULL;\n\t\t\t\t\t\t\t\t\t  //uint lastStructIndex = 0xffffffff;\n\n\t\t\t\t\t\t\t\t\t\t*node = NULL;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tformElm++;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Breaked ?\n\t\t\t\t\t\t\tif (element!=dfn.Entries.size())\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Breaked ?\n\t\t\t\t\t\tif (i==arrayDfn.size())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Not found\n\t\t\t\t\t\t\tsmprintf (error, 512, \"Struct does not contain element named (%s).\", token.c_str());\n\t\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Not a struct element. Can't open the node (%s).\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase TokenPoint:\n\t\t\t\t{\n\t\t\t\t\t// Need an array index array ?\n\t\t\t\t\tif (wantArrayIndex)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Token (%s) should be an array index.\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Are we a struct ?\n\t\t\t\t\tif ((type != UFormDfn::EntryDfn) && (type != UFormDfn::EntryVirtualDfn))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Not a struct element. Can't open the node (%s).\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase TokenArrayBegin:\n\t\t\t\t{\n\t\t\t\t\t// Are we an array ?\n\t\t\t\t\tif (!array)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Not an array element. Can't open the node (%s).\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\t\t\t\t\tinArrayIndex = true;\n\t\t\t\t\tarrayIndex = 0xffffffff;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\t// Error message\n\t\t\t\t\tsmprintf (error, 512, \"Syntax error at keyword (%s).\", token.c_str ());\n\t\t\t\t\tgoto exit;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (code)\n\t\t\t{\n\t\t\tcase TokenString:\n\t\t\t\t{\n\t\t\t\t\t// To int\n\t\t\t\t\tif (sscanf (token.c_str(), \"%d\", &arrayIndex)!=1)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Keyword (%s) is not an array index.\", token.c_str());\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Is it a parent virtual DFN ?\n\t\t\t\t\tif (*node == NULL)\n\t\t\t\t\t\tparentVDfnArray = true;\n\n\t\t\t\t\t// Should have an array defined\n\t\t\t\t\tif (*node)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check index\n\t\t\t\t\t\tuint arraySize;\n\t\t\t\t\t\tnlverify ((*node)->getArraySize (arraySize));\n\t\t\t\t\t\tif (arrayIndex>=arraySize)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Create mode ?\n\t\t\t\t\t\t\tif (action == Create)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Must be in the same form\n\t\t\t\t\t\t\t\tnlassert ((*node)->Form == form);\n\n\t\t\t\t\t\t\t\t// The array pointer\n\t\t\t\t\t\t\t\tCFormElmArray *array = safe_cast<CFormElmArray*>(*node);\n\t\t\t\t\t\t\t\tuint oldSize = (uint)array->Elements.size ();\n\t\t\t\t\t\t\t\tarray->Elements.resize (arrayIndex+1);\n\n\t\t\t\t\t\t\t\t// Insert empty element\n\t\t\t\t\t\t\t\tuint i;\n\t\t\t\t\t\t\t\tfor (i=oldSize; i<array->Elements.size (); i++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// The new element\n\t\t\t\t\t\t\t\t\tCFormElm *newelm = NULL;\n\t\t\t\t\t\t\t\t\tswitch (type)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryType:\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// Create an atom\n\t\t\t\t\t\t\t\t\t\t\tCFormElmAtom *atom = new CFormElmAtom (form, array, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\tnewelm = atom;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryDfn:\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tCFormElmStruct *_struct = new CFormElmStruct (form, array, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\t\t_struct->build (*nodeDfn);\n\t\t\t\t\t\t\t\t\t\t\tnewelm = _struct;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase UFormDfn::EntryVirtualDfn:\n\t\t\t\t\t\t\t\t\t\t// todo array of virtual struct\n\t\t\t\t\t\t\t\t\t\t//newelm = new CFormElmVirtualStruct (form, array, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\tnlstop;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tnlassert (newelm);\n\n\t\t\t\t\t\t\t\t\t// Node created\n\t\t\t\t\t\t\t\t\tcreated = true;\n\n\t\t\t\t\t\t\t\t\t// Set the element pointer\n\t\t\t\t\t\t\t\t\tarray->Elements[i].Element = newelm;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Error message\n\t\t\t\t\t\t\t\tsmprintf (error, 512, \"Out of array bounds (%d >= %d).\", arrayIndex, arraySize);\n\t\t\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Array is not defined.\");\n\t\t\t\t\t\tgoto exit;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase TokenArrayEnd:\n\t\t\t\t{\n\t\t\t\t\t// No need of an array index any more\n\t\t\t\t\twantArrayIndex = false;\n\n\t\t\t\t\t// Index found ?\n\t\t\t\t\tif (arrayIndex == 0xffffffff)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error message\n\t\t\t\t\t\tsmprintf (error, 512, \"Missing array index.\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Let the parent DFN\n\t\t\t\t\t\tnlassert (*parentDfn);\n\n\t\t\t\t\t\t// New current node\n\t\t\t\t\t\tCFormElmArray *parentNode = safe_cast<CFormElmArray*> (*node);\n\n\t\t\t\t\t\t// Get the element\n\t\t\t\t\t\t*node = parentNode->Elements[arrayIndex].Element;\n\n\t\t\t\t\t\t// Is a dfn ?\n\t\t\t\t\t\t*nodeDfn = (*parentDfn)->getEntry (indexDfn).getDfnPtr ();\n\n\t\t\t\t\t\t// Is a type ?\n\t\t\t\t\t\t*nodeType = (*parentDfn)->getEntry (indexDfn).getTypePtr ();\n\n\t\t\t\t\t\t// Type ?\n\t\t\t\t\t\ttype = (*parentDfn)->getEntry (indexDfn).getType ();\n\n\t\t\t\t\t\t// Can't be an array of array\n\t\t\t\t\t\tarray = false;\n\n\t\t\t\t\t\t// Not any more in index\n\t\t\t\t\t\tinArrayIndex = false;\n\n\t\t\t\t\t\t// What kind of node ?\n\t\t\t\t\t\tif ( (action == Create) && ( *node == NULL) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tswitch (type)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase UFormDfn::EntryType:\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Create an atom\n\t\t\t\t\t\t\t\t\tCFormElmAtom *atom = new CFormElmAtom (form, parentNode, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t*node = atom;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase UFormDfn::EntryDfn:\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tCFormElmStruct *_struct = new CFormElmStruct (form, parentNode, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\t\t_struct->build (*nodeDfn);\n\t\t\t\t\t\t\t\t\t*node = _struct;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase UFormDfn::EntryVirtualDfn:\n\t\t\t\t\t\t\t\t// todo array of virtual struct\n\t\t\t\t\t\t\t\t// *node = new CFormElmVirtualStruct (form, parentNode, *parentDfn, indexDfn);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tnlstop;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnlassert (*node);\n\n\t\t\t\t\t\t\t// Node created\n\t\t\t\t\t\t\tcreated = true;\n\n\t\t\t\t\t\t\t// Set the element pointer\n\t\t\t\t\t\t\tparentNode->Elements[arrayIndex].Element = *node;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Is a virtual DFN ?\n\t\t\t\t\t\tif ((*node) && (*node)->isVirtualStruct ())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Should be NULL\n\t\t\t\t\t\t\tnlassert (*nodeDfn == NULL);\n\n\t\t\t\t\t\t\t// Set the current dfn\n\t\t\t\t\t\t\t*nodeDfn = safe_cast<const CFormElmVirtualStruct*> (*node)->FormDfn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\t// Error message\n\t\t\t\t\tsmprintf (error, 512, \"Keyword (%s) is not an array index.\", token.c_str());\n\t\t\t\t\tgoto exit;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Concat current address\n\t\tcurrentName += token;\n\t\tstartToken = endToken;\n\t}\nexit:;\n\n\t// Error ?\n\tbool errorAppend = endToken != NULL;\n\n\t// Continue ?\n\tif (!errorAppend)\n\t{\n\t\t// Delete the node ?\n\t\tif ( (action == Delete) && (*node) )\n\t\t{\n\t\t\t// Get its parent\n\t\t\tCFormElm *parent = safe_cast<CFormElm*> ((*node)->getParent ());\n\n\t\t\t// Don't erase the root structure\n\t\t\tif (parent && !parent->isArray ())\n\t\t\t{\n\t\t\t\t// Unlink the primitive from its parent\n\t\t\t\tparent->unlink (*node);\n\n\t\t\t\t// Erase the node\n\t\t\t\tdelete (*node);\n\t\t\t\t*node = parent;\n\t\t\t\tparent = (CFormElm*) (parent->getParent ());\n\n\t\t\t\t// For each parent\n\t\t\t\twhile (parent && !(*node)->isUsed (form) && !parent->isArray ())\n\t\t\t\t{\n\t\t\t\t\t// Unlink the primitive from its parent\n\t\t\t\t\tparent->unlink (*node);\n\n\t\t\t\t\t// Erase it and get next parent\n\t\t\t\t\tdelete (*node);\n\t\t\t\t\t*node = parent;\n\t\t\t\t\tparent = (CFormElm*) (parent->getParent ());\n\t\t\t\t}\n\n\t\t\t\t// No more node\n\t\t\t\t*node = NULL;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Node not found in get node ? Look in parents !\n\tif ( ((*node) == NULL) && (action == Return) && backupFirstElm )\n\t{\n\t\t// Get the path name\n\t\tstring formName;\n\t\tbackupFirstElm->getFormName (formName);\n\t\tuint formNameSize = (uint)formName.size ();\n\t\tif ((formNameSize > 0) && (formName[formNameSize-1] != '.') && (formName[formNameSize-1] != '['))\n\t\t\tformName += \".\";\n\t\tformName += name;\n\n\t\t// Backup first parent default value\n\t\tbool defaultValue = false;\n\t\tconst CFormDfn *defaultParentDfnParent=0;\n\t\tuint defaultIndexDfnParent=0;\n\t\tconst CFormDfn *defaultNodeDfnParent=0;\n\t\tconst CType *defaultNodeTypeParent=0;\n\t\tCFormElm *defaultNodeParent=0;\n\t\tUFormDfn::TEntryType defaultTypeParent = UFormDfn::EntryType;\n\t\tbool defaultArrayParent=false;\n\t\tbool defaultCreatedParent=false;\n\t\tbool defaultParentVDfnArray=false;\n\n\t\t// Look in parent form\n\t\tfor (uint parent=0; parent<form->getParentCount (); parent++)\n\t\t{\n\t\t\t// Get the parent\n\t\t\tCForm *parentPtr = form->getParent (parent);\n\t\t\tnlassert (parentPtr);\n\n\t\t\tif (parentPtr->getFilename() == form->getFilename())\n\t\t\t{\n\t\t\t\tnlerror(\"parent is identical to current sheet %s!\", form->getFilename().c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Get the node by name in the parent\n\t\t\tconst CFormDfn *parentDfnParent = NULL;\n\t\t\tuint indexDfnParent = 0xffffffff;\n\t\t\tconst CFormDfn *nodeDfnParent = NULL;\n\t\t\tconst CType *nodeTypeParent = NULL;\n\t\t\tCFormElm *nodeParent = (CFormElm*)&parentPtr->getRootNode ();\n\t\t\tUFormDfn::TEntryType typeParent;\n\t\t\tbool arrayParent;\n\t\t\tbool createdParent;\n\t\t\tbool parentVDfnArray;\n\t\t\tif (getInternalNodeByName (parentPtr, formName.c_str (), &parentDfnParent, indexDfnParent, &nodeDfnParent, &nodeTypeParent, &nodeParent, typeParent, arrayParent, action, createdParent, parentVDfnArray, false, round+1))\n\t\t\t{\n\t\t\t\t// Node found ?\n\t\t\t\tif (nodeParent)\n\t\t\t\t{\n\t\t\t\t\t// Found copy return values\n\t\t\t\t\t*parentDfn = parentDfnParent;\n\t\t\t\t\tindexDfn = indexDfnParent;\n\t\t\t\t\t*nodeDfn = nodeDfnParent;\n\t\t\t\t\t*nodeType = nodeTypeParent;\n\t\t\t\t\t*node = nodeParent;\n\t\t\t\t\ttype = typeParent;\n\t\t\t\t\tarray = arrayParent;\n\t\t\t\t\tcreated = createdParent;\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Backup the first parent default value found\n\t\t\t\t\tif (!defaultValue)\n\t\t\t\t\t{\n\t\t\t\t\t\tdefaultParentDfnParent = parentDfnParent;\n\t\t\t\t\t\tdefaultIndexDfnParent = indexDfnParent;\n\t\t\t\t\t\tdefaultNodeDfnParent = nodeDfnParent;\n\t\t\t\t\t\tdefaultNodeTypeParent = nodeTypeParent;\n\t\t\t\t\t\tdefaultNodeParent = nodeParent;\n\t\t\t\t\t\tdefaultTypeParent = typeParent;\n\t\t\t\t\t\tdefaultArrayParent = arrayParent;\n\t\t\t\t\t\tdefaultCreatedParent = createdParent;\n\t\t\t\t\t\tdefaultParentVDfnArray = parentVDfnArray;\n\t\t\t\t\t\tdefaultValue = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Default value available ?\n\t\tif (defaultValue)\n\t\t{\n\t\t\t*parentDfn = defaultParentDfnParent;\n\t\t\tindexDfn = defaultIndexDfnParent;\n\t\t\t*nodeDfn = defaultNodeDfnParent;\n\t\t\t*nodeType = defaultNodeTypeParent;\n\t\t\t*node = defaultNodeParent;\n\t\t\ttype = defaultTypeParent;\n\t\t\tarray = defaultArrayParent;\n\t\t\tcreated = defaultCreatedParent;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Recurse warning !\n\tif (*node)\n\t{\n\t\tif (round > NLGEORGES_MAX_RECURSION)\n\t\t{\n\t\t\t// Turn around..\n\t\t\tstring formName;\n\t\t\t(*node)->getFormName (formName);\n\t\t\twarning (false, formName.c_str (), form->getFilename ().c_str(), \"getInternalNodeByName\", \"Recursive call on the same node (%s), look for loop references or inheritances.\", name);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (verbose && errorAppend)\n\t{\n\t\tnlassert (*error);\n\n\t\t// Get the best form name\n\t\twarning (false, currentName.c_str (), form->getFilename ().c_str(), \"getInternalNodeByName\", \"Getting the node (%s) : %s\", name, error);\n\t}\n\n\treturn !errorAppend;\n}\n\n// ***************************************************************************\n\nconst char* CFormElm::tokenize (const char *name, string &str, uint &/* errorIndex */, uint &code)\n{\n\tif (*name == 0)\n\t{\n\t\treturn NULL;\n\t}\n\n\tif (*name == '[')\n\t{\n\t\tcode = TokenArrayBegin;\n\t\tstr = \"[\";\n\t\treturn name+1;\n\t}\n\n\tif (*name == ']')\n\t{\n\t\tcode = TokenArrayEnd;\n\t\tstr = \"]\";\n\t\treturn name+1;\n\t}\n\n\tif (*name == '.')\n\t{\n\t\tcode = TokenPoint;\n\t\tstr = \".\";\n\t\treturn name+1;\n\t}\n\n\tstr = \"\";\n\twhile ( (*name != '.') && (*name != '[') && (*name != ']') && (*name != 0) )\n\t{\n\t\t// Add a char\n\t\tstr += *name;\n\t\tname++;\n\t}\n\n\tcode = TokenString;\n\treturn name;\n}\n\n// ***************************************************************************\n\nvoid CFormElm::unlink (CFormElm * /* child */)\n{\n\t// No children\n\tnlstop;\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (const char *value, const char *name, bool *created)\n{\n\t// The parent Dfn\n\tconst CFormDfn *parentDfn;\n\tconst CFormDfn *nodeDfn;\n\tconst CType *nodeType;\n\tCFormElm *node;\n\tuint indexDfn;\n\tbool array;\n\tbool _created;\n\tUFormDfn::TEntryType type;\n\n\t// Search for the node\n\tif (createNodeByName (name, &parentDfn, indexDfn, &nodeDfn, &nodeType, &node, type, array, _created))\n\t{\n\t\t// Is this a type ?\n\t\tif (type == UFormDfn::EntryType)\n\t\t{\n\t\t\t// The atom\n\t\t\tCFormElmAtom *atom = node ? safe_cast<CFormElmAtom*> (node) : NULL;\n\n\t\t\t// Evale\n\t\t\tnlassert (nodeType);\n\t\t\tatom->setValue (value);\n\n\t\t\t// Created flag\n\t\t\tif (created)\n\t\t\t\t*created = _created;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Error message\n\t\t\twarning (false, \"setValueByName\", \"The node (%s) is not an atom element. Can't set the value.\", name);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Error message\n\t\twarning (false, \"setValueByName\", \"Can't created / set the node (%s).\", name);\n\n\t\t// Created flag\n\t\tif (created)\n\t\t\t*created = false;\n\t}\n\n\t// Error\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (sint8 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (uint8 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (sint16 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (uint16 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (sint32 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (uint32 value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (float value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (double value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (bool value, const char *name, bool *created)\n{\n\treturn setValueByName (toString (value).c_str (), name, created);\n}\n\n// ***************************************************************************\n\nbool CFormElm::setValueByName (NLMISC::CRGBA value, const char *name, bool *created)\n{\n\tchar tmp[512];\n\tsmprintf (tmp, 512, \"%d,%d,%d\", value.R, value.G, value.B);\n\treturn setValueByName (tmp, name, created);\n}\n\n// ***************************************************************************\n\nvoid CFormElm::warning (bool exception, const char *formName, const char *formFileName, const char *function, const char *format, ... )\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CFormElm::%s) on node (%s) in form (%s) : %s\", function, formName, formFileName, buffer);\n}\n\n// ***************************************************************************\n\nvoid CFormElm::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\tva_list args;\n\tva_start( args, format );\n\n\tstring formName;\n\tgetFormName (formName);\n\twarning (exception, formName.c_str (), getForm ()->getFilename ().c_str (), function, format, args);\n\n\tva_end( args );\n}\n\n// ***************************************************************************\n// class CFormElmStruct\n// ***************************************************************************\n\nCFormElmStruct::CFormElmStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex) : CFormElm (form, parentNode, parentDfn, parentIndex)\n{\n\tFormDfn = NULL;\n}\n\n// ***************************************************************************\n\nCFormElmStruct::~CFormElmStruct ()\n{\n\t// Job done in clean()\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::clean ()\n{\n\t// For each element of the array\n\tuint elm;\n\tfor (elm =0; elm<Elements.size(); elm++)\n\t{\n\t\tif (Elements[elm].Element)\n\t\t\tdelete Elements[elm].Element;\n\t\tElements[elm].Element = NULL;\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::isStruct () const\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::getStructSize (uint &size) const\n{\n\tsize = (uint)Elements.size();\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::getStructNodeName (uint element, string &result) const\n{\n\tif (element<Elements.size())\n\t{\n\t\tresult = Elements[element].Name;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getStructNodeName\", \"Index (%d) out of bound (%d).\", element, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::getStructNode (uint element, const UFormElm **result) const\n{\n\tif (element<Elements.size())\n\t{\n\t\t*result = Elements[element].Element;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getStructNode\", \"Index (%d) out of bound (%d).\", element, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n// ***************************************************************************\n\nUFormDfn *CFormElmStruct::getStructDfn ()\n{\n\treturn (CFormDfn*)FormDfn;\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::getStructNode (uint element, UFormElm **result)\n{\n\tif (element<Elements.size())\n\t{\n\t\t*result = Elements[element].Element;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getStructNode\", \"Index (%d) out of bound (%d).\", element, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n// ***************************************************************************\n\nxmlNodePtr  CFormElmStruct::write (xmlNodePtr root, const CForm *form, const char *structName, bool forceWrite) const\n{\n\t// Is used ?\n\tif (isUsed (form) || forceWrite)\n\t{\n\t\t// *** Header\n\t\txmlNodePtr node = xmlNewChild ( root, NULL, (const xmlChar*)\"STRUCT\", NULL);\n\n\t\t// Element name\n\t\tif (structName != NULL)\n\t\t{\n\t\t\t// Struct name\n\t\t\txmlSetProp (node, (const xmlChar*)\"Name\", (const xmlChar*)structName);\n\t\t}\n\n\t\t// For each elements of the structure\n\t\tuint elm;\n\t\tfor (elm=0; elm<Elements.size(); elm++)\n\t\t{\n\t\t\t// Create a node if it exist\n\t\t\tif (Elements[elm].Element)\n\t\t\t\tElements[elm].Element->write (node, form, Elements[elm].Name.c_str());\n\t\t}\n\n\t\t// Return the new node\n\t\treturn node;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::read (xmlNodePtr node, CFormLoader &loader, const CFormDfn *dfn, CForm *form)\n{\n\t// Get the smart pointer on the dfn\n\tFormDfn = (CFormDfn*)dfn;\n\n\t// Build the Form\n\tbuild (dfn);\n\n\t// Count parent\n\tuint dfnCount = dfn->countParentDfn ();\n\n\t// Array of Dfn\n\tstd::vector<const CFormDfn*> dfnArray;\n\tdfnArray.reserve (dfnCount);\n\tdfn->getParentDfn (dfnArray);\n\n\t// For each Dfn\n\tuint dfnId;\n\tuint elmIndex=0;\n\tfor (dfnId=0; dfnId<dfnCount; dfnId++)\n\t{\n\t\t// Lookup for the name in the DFN\n\t\tuint elm;\n\t\tfor (elm=0; elm<dfnArray[dfnId]->Entries.size(); elm++)\n\t\t{\n\t\t\t// Found ?\n\t\t  //\t\t\tbool found = false;\n\n\t\t\t// Read the struct\n\t\t\txmlNodePtr child = NULL;\n\n\t\t\t// Node can be NULL\n\t\t\tif (node)\n\t\t\t\tchild = node->children;\n\n\t\t\twhile (child)\n\t\t\t{\n\t\t\t\t// Good node ?\n\t\t\t\tconst char *name = (const char*)xmlGetProp (child, (xmlChar*)\"Name\");\n\t\t\t\tif (name && (dfnArray[dfnId]->Entries[elm].getName () == name) )\n\t\t\t\t{\n\t\t\t\t\t// Type\n\t\t\t\t\tbool atom=false;\n\t\t\t\t\tbool array=false;\n\t\t\t\t\tbool _struct=false;\n\t\t\t\t\tbool vStruct=false;\n\n\t\t\t\t\t// Is an atom ?\n\t\t\t\t\tif (strcmp ((const char*)child->name, \"ATOM\") == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tatom = true;\n\t\t\t\t\t}\n\t\t\t\t\t// Is a struct ?\n\t\t\t\t\telse if (strcmp ((const char*)child->name, \"STRUCT\") == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t_struct = true;\n\t\t\t\t\t}\n\t\t\t\t\t// Is a struct ?\n\t\t\t\t\telse if (strcmp ((const char*)child->name, \"VSTRUCT\") == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tvStruct = true;\n\t\t\t\t\t}\n\t\t\t\t\t// Is an array ?\n\t\t\t\t\telse if (strcmp ((const char*)child->name, \"ARRAY\") == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tarray = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue ?\n\t\t\t\t\tif (atom || _struct || vStruct || array)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Same type ?\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(atom && (dfnArray[dfnId]->Entries[elm].getType ()==UFormDfn::EntryType) && (!dfnArray[dfnId]->Entries[elm].getArrayFlag ()) ) ||\n\t\t\t\t\t\t\t(array && dfnArray[dfnId]->Entries[elm].getArrayFlag () && ( (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryType) || (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryDfn) ) ) ||\n\t\t\t\t\t\t\t(_struct && (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryDfn) && (!dfnArray[dfnId]->Entries[elm].getArrayFlag ()) ) ||\n\t\t\t\t\t\t\t(vStruct && (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryVirtualDfn) && (!dfnArray[dfnId]->Entries[elm].getArrayFlag ()) )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Ok keep it\n\t\t\t\t\t\t\txmlFree((void*) name);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Make a warning message\n\t\t\t\t\t\t\twarning (false, \"read\", \"In block line %p, node (%s) type in DFN have changed.\",\n\t\t\t\t\t\t\t\tchild->content, child->name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (name)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Delete the value\n\t\t\t\t\t\t\txmlFree ((void*)name);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Throw exception\n\t\t\t\t\t\twarning (true, \"read\", \"XML Syntax error in block line %p, node (%s) name should be STRUCT, ATOM or ARRAY.\",\n\t\t\t\t\t\t\tchild->content, child->name);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (name)\n\t\t\t\t{\n\t\t\t\t\t// Delete the value\n\t\t\t\t\txmlFree ((void*)name);\n\t\t\t\t}\n\n\t\t\t\t// Next child\n\t\t\t\tchild = child->next;\n\t\t\t}\n\n\t\t\t// Found ?\n\t\t\tif (child)\n\t\t\t{\n\t\t\t\t// Create a new element\n\t\t\t\tif (dfnArray[dfnId]->Entries[elm].getArrayFlag ())\n\t\t\t\t{\n\t\t\t\t\t// Array of type\n\t\t\t\t\tCFormElmArray *newElm = NULL;\n\t\t\t\t\tif (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryType)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Load the new element\n\t\t\t\t\t\tnewElm = new CFormElmArray (form, NULL, dfnArray[dfnId]->Entries[elm].getTypePtr (), this, dfnArray[dfnId], elm);\n\t\t\t\t\t}\n\t\t\t\t\t// Array of struct\n\t\t\t\t\telse if (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryDfn)\n\t\t\t\t\t{\n\t\t\t\t\t\tnewElm = new CFormElmArray (form, dfnArray[dfnId]->Entries[elm].getDfnPtr (), NULL, this, dfnArray[dfnId], elm);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Should be created\n\t\t\t\t\tnlassert (newElm);\n\t\t\t\t\tElements[elmIndex].Element = newElm;\n\t\t\t\t\tnewElm->read (child, loader, form);\n\t\t\t\t}\n\t\t\t\telse if (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryType)\n\t\t\t\t{\n\t\t\t\t\t// Load the new element\n\t\t\t\t\tCFormElmAtom *newElm = new CFormElmAtom (form, this, dfnArray[dfnId], elm);\n\t\t\t\t\tElements[elmIndex].Element = newElm;\n\t\t\t\t\tnewElm->read (child, loader, dfnArray[dfnId]->Entries[elm].getTypePtr (), form);\n\t\t\t\t}\n\t\t\t\telse if (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryDfn)\n\t\t\t\t{\n\t\t\t\t\t// Load the new element\n\t\t\t\t\tCFormElmStruct *newElm = new CFormElmStruct (form, this, dfnArray[dfnId], elm);\n\t\t\t\t\tElements[elmIndex].Element = newElm;\n\t\t\t\t\tnewElm->read (child, loader, dfnArray[dfnId]->Entries[elm].getDfnPtr (), form);\n\t\t\t\t}\n\t\t\t\telse // if dfnArray[dfnId]->Entries[elm].getType () == CFormDfn::CEntry::EntryVirtualDfn)\n\t\t\t\t{\n\t\t\t\t\t// Should be a struct\n\t\t\t\t\tnlassert (dfnArray[dfnId]->Entries[elm].getType () == UFormDfn::EntryVirtualDfn);\n\n\t\t\t\t\t// Load the new element\n\t\t\t\t\tCFormElmVirtualStruct *newElm = new CFormElmVirtualStruct (form, this, dfnArray[dfnId], elm);\n\t\t\t\t\tElements[elmIndex].Element = newElm;\n\t\t\t\t\tnewElm->read (child, loader, form);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tElements[elmIndex].Element = NULL;\n\n\t\t\telmIndex++;\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmStruct::isUsed (const CForm *form) const\n{\n\tfor (uint i=0; i<Elements.size(); i++)\n\t{\n\t\tif (Elements[i].Element && Elements[i].Element->isUsed (form))\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::build (const CFormDfn *dfn)\n{\n\t// Clean the form\n\tclean ();\n\n\t// Set the DFN\n\tFormDfn = (CFormDfn*)dfn;\n\n\t// Get the parents\n\tvector<const CFormDfn*> arrayDfn;\n\tarrayDfn.reserve (dfn->countParentDfn ());\n\tdfn->getParentDfn (arrayDfn);\n\n\t// Count element\n\tuint elementCount = 0;\n\tuint dfnIndex;\n\tfor (dfnIndex=0; dfnIndex<arrayDfn.size(); dfnIndex++)\n\t{\n\t\telementCount += arrayDfn[dfnIndex]->getNumEntry();\n\t}\n\n\t// Resize the element array\n\tElements.resize (elementCount);\n\n\telementCount = 0;\n\tfor (dfnIndex=0; dfnIndex<arrayDfn.size(); dfnIndex++)\n\t{\n\t\t// For each element\n\t\tfor (uint elm=0; elm<arrayDfn[dfnIndex]->Entries.size(); elm++)\n\t\t{\n\t\t\t// Copy the name\n\t\t\tElements[elementCount].Name = arrayDfn[dfnIndex]->Entries[elm].Name;\n\t\t\telementCount++;\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::unlink (CFormElm *child)\n{\n  uint i;\n\tfor (i=0; i<Elements.size (); i++)\n\t{\n\t\tif (Elements[i].Element == child)\n\t\t{\n\t\t\tElements[i].Element = NULL;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Element not found!\n\tnlassert (i != Elements.size ());\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::getFormName (std::string &result, const CFormElm *child) const\n{\n\t// Reset the result\n\tif (child == NULL)\n\t{\n\t\tresult = \"\";\n\t\tresult.reserve (50);\n\t}\n\n\t// Get parent form name\n\tif (ParentNode)\n\t\tParentNode->getFormName (result, this);\n\n\t// Get node name\n\tif (child)\n\t{\n\t\t// Look for the child\n\t\tuint i;\n\t\tfor (i=0; i<Elements.size (); i++)\n\t\t{\n\t\t\t// This one ?\n\t\t\tif (Elements[i].Element == child)\n\t\t\t{\n\t\t\t\t// Add the field name\n\t\t\t\tresult += \".\";\n\t\t\t\tresult += Elements[i].Name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Draw some warning\n\t\tif (i==Elements.size ())\n\t\t{\n\t\t\twarning (false, \"getFormName\", \"Child node not found.\");\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tstring formName;\n\tgetFormName (formName, NULL);\n\tNLGEORGES::warning (exception, \"(CFormElmStruct::%s) on node (%s) in form (%s) : %s\", function, formName.c_str (), Form->getFilename ().c_str (), buffer);\n}\n\n// ***************************************************************************\n\nvoid CFormElmStruct::getDependencies (std::set<std::string> &dependencies) const\n{\n\t// Visit the dfn\n\tif (FormDfn)\n\t\tFormDfn->getDependencies (dependencies);\n\n\t// Visit elements\n\tfor (uint i=0; i<Elements.size (); i++)\n\t{\n\t\tif (Elements[i].Element)\n\t\t\tElements[i].Element->getDependencies (dependencies);\n\t}\n}\n\n// ***************************************************************************\n// class CFormElmVirtualStruct\n// ***************************************************************************\n\nCFormElmVirtualStruct::CFormElmVirtualStruct (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex) : CFormElmStruct (form, parentNode, parentDfn, parentIndex)\n{\n}\n\n// ***************************************************************************\n\nxmlNodePtr  CFormElmVirtualStruct::write (xmlNodePtr root, const CForm *form, const char *structName, bool forceWrite) const\n{\n\t// Is used ?\n\tif (isUsed (form) || forceWrite)\n\t{\n\t\t// *** Header\n\t\txmlNodePtr node = xmlNewChild ( root, NULL, (const xmlChar*)\"VSTRUCT\", NULL);\n\n\t\t// Write the DFN filename in the node\n\t\txmlSetProp (node, (const xmlChar*)\"DfnName\", (const xmlChar*)DfnFilename.c_str());\n\n\t\t// Element name\n\t\tif (structName != NULL)\n\t\t{\n\t\t\t// Struct name\n\t\t\txmlSetProp (node, (const xmlChar*)\"Name\", (const xmlChar*)structName);\n\t\t}\n\n\t\t// For each elements of the structure\n\t\tuint elm;\n\t\tfor (elm=0; elm<Elements.size(); elm++)\n\t\t{\n\t\t\t// Create a node if it exist\n\t\t\tif (Elements[elm].Element)\n\t\t\t\tElements[elm].Element->write (node, form, Elements[elm].Name.c_str());\n\t\t}\n\n\t\t// Return the new node\n\t\treturn node;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid CFormElmVirtualStruct::read (xmlNodePtr node, CFormLoader &loader, CForm *form)\n{\n\t// Get the DFN filename\n\tconst char *filename = (const char*)xmlGetProp (node, (xmlChar*)\"DfnName\");\n\tif (filename)\n\t{\n\t\t// Set the name\n\t\tDfnFilename = filename;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)filename);\n\n\t\t// Load the dfn\n\t\tFormDfn = loader.loadFormDfn (DfnFilename.c_str (), false);\n\t\tif (!FormDfn)\n\t\t{\n\t\t\t// Throw exception\n\t\t\twarning (true, \"read\", \"Can't find DFN filename (%s).\", DfnFilename.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Throw exception\n\t\twarning (true, \"read\", \"XML Syntax error in virtual struct in block line %p, should have a DfnName property.\",\n\t\t\tnode->content);\n\t}\n\n\t// Read the parent\n\tCFormElmStruct::read (node, loader, FormDfn, form);\n}\n\n// ***************************************************************************\n\nbool CFormElmVirtualStruct::isVirtualStruct () const\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmVirtualStruct::getDfnName (std::string &dfnName ) const\n{\n\tdfnName = DfnFilename;\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmVirtualStruct::isUsed (const CForm * /* form */) const\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid CFormElmVirtualStruct::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tstring formName;\n\tgetFormName (formName, NULL);\n\tNLGEORGES::warning (exception, \"(CFormElmVirtualStruct::%s) on node (%s) in form (%s) : %s\", function, formName.c_str (), Form->getFilename ().c_str (), buffer);\n}\n\n// ***************************************************************************\n// class CFormElmArray\n// ***************************************************************************\n\nCFormElmArray::CFormElmArray (CForm *form, const CFormDfn *formDfn, const CType *type, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex) : CFormElm (form, parentNode, parentDfn, parentIndex)\n{\n\tFormDfn = (CFormDfn*)formDfn;\n\tType = type;\n}\n\n// ***************************************************************************\n\nCFormElmArray::~CFormElmArray ()\n{\n\t// Job done in clean()\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::clean ()\n{\n\t// For each element of the array\n\tuint elm;\n\tfor (elm =0; elm<Elements.size(); elm++)\n\t{\n\t\tif (Elements[elm].Element)\n\t\t\tdelete Elements[elm].Element;\n\t}\n\tElements.clear ();\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::isArray () const\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArraySize (uint &size) const\n{\n\tsize = (uint)Elements.size ();\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayNode (const UFormElm **result, uint arrayIndex) const\n{\n\tif (arrayIndex<Elements.size())\n\t{\n\t\t*result = Elements[arrayIndex].Element;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayNode\", \"Index (%d) out of bound (%d).\", arrayIndex, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayNodeName (std::string &result, uint arrayIndex) const\n{\n\tif (arrayIndex<Elements.size())\n\t{\n\t\tif (Elements[arrayIndex].Name.empty ())\n\t\t\tresult = \"#\" + toString (arrayIndex);\n\t\telse\n\t\t\tresult = Elements[arrayIndex].Name;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayNodeName\", \"Index (%d) out of bound (%d).\", arrayIndex, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayNode (UFormElm **result, uint arrayIndex)\n{\n\tif (arrayIndex<Elements.size())\n\t{\n\t\t*result = Elements[arrayIndex].Element;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayNode\", \"Index (%d) out of bound (%d).\", arrayIndex, Elements.size() );\n\t\treturn false;\n\t}\n}\n\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (std::string &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (arrayIndex >= Elements.size())\n\t{\n\t\twarning (false, \"getArrayValue\", \"Access out of bound, trying to access array index %u, array size is %u.\", arrayIndex, Elements.size());\n\t}\n\telse if (Type)\n\t{\n\t\treturn (Type->getValue (result, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL));\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (sint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (uint8 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (sint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (uint16 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (sint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (uint32 &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (float &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (double &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (bool &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::getArrayValue (NLMISC::CRGBA &result, uint arrayIndex, TEval evaluate, TWhereIsValue *where) const\n{\n\tif (Type)\n\t{\n\t\tstring str;\n\t\tif (Type->getValue (str, Form, safe_cast<const CFormElmAtom*> (Elements[arrayIndex].Element), *ParentDfn, ParentIndex, evaluate, (uint32*)where, NLGEORGES_FIRST_ROUND, NULL))\n\t\t{\n\t\t\treturn convertValue (result, str.c_str ());\n\t\t}\n\t}\n\telse\n\t{\n\t\twarning (false, \"getArrayValue\", \"This array is not an array of atom. This is an array of structure.\");\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CFormElmArray::write (xmlNodePtr root, const CForm *form, const char *structName, bool forceWrite) const\n{\n\t// Arrau is used ?\n\tif (isUsed (form) || forceWrite)\n\t{\n\t\t// *** Header\n\t\txmlNodePtr node = xmlNewChild ( root, NULL, (const xmlChar*)\"ARRAY\", NULL);\n\n\t\t// Element name\n\t\tif (structName != NULL)\n\t\t{\n\t\t\t// Struct name\n\t\t\txmlSetProp (node, (const xmlChar*)\"Name\", (const xmlChar*)structName);\n\t\t}\n\n\t\t// For each elements of the structure\n\t\tuint elm;\n\t\tfor (elm=0; elm<Elements.size(); elm++)\n\t\t{\n\t\t\t// Create a node\n\t\t\tif (Elements[elm].Element)\n\t\t\t\tElements[elm].Element->write (node, form, Elements[elm].Name.empty ()?NULL:Elements[elm].Name.c_str (), true);\n\t\t}\n\n\t\t// Return the new node\n\t\treturn node;\n\t}\n\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::read (xmlNodePtr node, CFormLoader &loader, CForm *form)\n{\n\t// Clean the form\n\tclean ();\n\n\t// Count child\n\tif (node)\n\t{\n\t\t// Type of DFN array\n\t\tif (Type)\n\t\t{\n\t\t\tnlassert (FormDfn == NULL);\n\n\t\t\t// Count children\n\t\t\tuint childCount = CIXml::countChildren (node, \"ATOM\");\n\n\t\t\t// Resize the table\n\t\t\tElements.resize (childCount);\n\n\t\t\t// For each children\n\t\t\tuint childNum=0;\n\t\t\txmlNodePtr child = CIXml::getFirstChildNode (node, \"ATOM\");\n\t\t\twhile (child)\n\t\t\t{\n\t\t\t\t// Get node name\n\t\t\t\tconst char *name = (const char*)xmlGetProp (child, (xmlChar*)\"Name\");\n\n\t\t\t\t// Create a new node\n\t\t\t\tCFormElmAtom *newElt = new CFormElmAtom (form, this, ParentDfn, ParentIndex);\n\t\t\t\tElements[childNum].Element = newElt;\n\t\t\t\tif (name)\n\t\t\t\t{\n\t\t\t\t\tElements[childNum].Name = name;\n\t\t\t\t\txmlFree ((void*)name);\n\t\t\t\t}\n\t\t\t\tnewElt->read (child, loader, Type, form);\n\n\t\t\t\t// Next child\n\t\t\t\tchild = CIXml::getNextChildNode (child, \"ATOM\");\n\t\t\t\tchildNum++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlassert (FormDfn);\n\t\t\tnlassert (Type == NULL);\n\n\t\t\t// Count children\n\t\t\tuint childCount = CIXml::countChildren (node, \"STRUCT\");\n\n\t\t\t// Resize the table\n\t\t\tElements.resize (childCount);\n\n\t\t\t// For each children\n\t\t\tuint childNum=0;\n\t\t\txmlNodePtr child = CIXml::getFirstChildNode (node, \"STRUCT\");\n\t\t\twhile (child)\n\t\t\t{\n\t\t\t\t// Get node name\n\t\t\t\tconst char *name = (const char*)xmlGetProp (child, (xmlChar*)\"Name\");\n\n\t\t\t\t// Create a new node\n\t\t\t\tCFormElmStruct *newElt = new CFormElmStruct (form, this, ParentDfn, ParentIndex);\n\t\t\t\tElements[childNum].Element = newElt;\n\t\t\t\tif (name)\n\t\t\t\t{\n\t\t\t\t\tElements[childNum].Name = name;\n\t\t\t\t\txmlFree ((void*)name);\n\t\t\t\t}\n\t\t\t\tnewElt->read (child, loader, FormDfn, form);\n\n\t\t\t\t// Next child\n\t\t\t\tchild = CIXml::getNextChildNode (child, \"STRUCT\");\n\t\t\t\tchildNum++;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::setParent (CFormElm * /* parent */)\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::unlink (CFormElm *child)\n{\n  uint i;\n\tfor (i=0; i<Elements.size (); i++)\n\t{\n\t\tif (Elements[i].Element == child)\n\t\t{\n\t\t\tElements[i].Element = NULL;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Element not found!\n\tnlassert (i != Elements.size ());\n}\n\n// ***************************************************************************\n\nbool CFormElmArray::isUsed (const CForm *form) const\n{\n\t/*for (uint i=0; i<Elements.size(); i++)\n\t{\n\t\tif (Elements[i] && Elements[i]->isUsed (form))\n\t\t\treturn true;\n\t}*/\n\treturn form == Form;\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::getFormName (std::string &result, const CFormElm *child) const\n{\n\t// Reset the result\n\tif (child == NULL)\n\t{\n\t\tresult = \"\";\n\t\tresult.reserve (50);\n\t}\n\n\t// Get parent form name\n\tif (ParentNode)\n\t\tParentNode->getFormName (result, this);\n\n\t// Get node name\n\tif (child)\n\t{\n\t\t// Look for the child\n\t\tuint i;\n\t\tfor (i=0; i<Elements.size (); i++)\n\t\t{\n\t\t\t// This one ?\n\t\t\tif (Elements[i].Element == child)\n\t\t\t{\n\t\t\t\tchar name[512];\n\t\t\t\tsmprintf (name, 512, \"[%d]\", i);\n\n\t\t\t\t// Add the field name\n\t\t\t\tresult += name;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Draw some warning\n\t\tif (i==Elements.size ())\n\t\t{\n\t\t\twarning (false, \"getFormName\", \"Child node not found.\");\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tstring formName;\n\tgetFormName (formName, NULL);\n\tNLGEORGES::warning (exception, \"(CFormElmArray::%s) on node (%s) in form (%s) : %s\", function, formName.c_str (), Form->getFilename ().c_str (), buffer);\n}\n\n// ***************************************************************************\n\nvoid CFormElmArray::getDependencies (std::set<std::string> &dependencies) const\n{\n\tif (FormDfn)\n\t{\n\t\t// Add the dfn\n\t\tFormDfn->getDependencies (dependencies);\n\n\t\t// Add each elements\n\t\tfor (uint i=0; i<Elements.size (); i++)\n\t\t{\n\t\t\tElements[i].Element->getDependencies (dependencies);\n\t\t}\n\t}\n\n\tif (Type)\n\t{\n\t\t// Add the type\n\t\tType->getDependencies (dependencies);\n\t}\n}\n\n// ***************************************************************************\n// CFormElmAtom\n// ***************************************************************************\n\nCFormElmAtom::CFormElmAtom (CForm *form, CFormElm *parentNode, const CFormDfn *parentDfn, uint parentIndex) : CFormElm (form, parentNode, parentDfn, parentIndex)\n{\n\tType = NULL;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::isAtom () const\n{\n\treturn true;\n}\n\n// ***************************************************************************\n\nconst CType* CFormElmAtom::getType ()\n{\n\treturn Type;\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::getDependencies (std::set<std::string> &/* dependencies */) const\n{\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (string &result, TEval evaluate) const\n{\n\tnlassert (Type);\n\n\t// Evale\n\treturn Type->getValue (result, Form, this, *ParentDfn, ParentIndex, evaluate, NULL, NLGEORGES_FIRST_ROUND, \"\");\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (sint8 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (uint8 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (sint16 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (uint16 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (sint32 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (uint32 &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (float &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (double &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (bool &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CFormElmAtom::getValue (NLMISC::CRGBA &result, TEval evaluate) const\n{\n\t// Get the string value\n\tstring value;\n\tif (getValue (value, evaluate))\n\t{\n\t\treturn convertValue (result, value.c_str ());\n\t}\n\n\treturn false;\n}\n\n// ***************************************************************************\n\nxmlNodePtr  CFormElmAtom::write (xmlNodePtr root, const CForm *form, const char *structName, bool forceWrite) const\n{\n\t// Atom is used ?\n\tif (isUsed (form) || forceWrite)\n\t{\n\t\t// *** Header\n\t\txmlNodePtr node = xmlNewChild ( root, NULL, (const xmlChar*)\"ATOM\", NULL);\n\n\t\t// Element name\n\t\tif (structName != NULL)\n\t\t{\n\t\t\t// Struct name\n\t\t\txmlSetProp (node, (const xmlChar*)\"Name\", (const xmlChar*)structName);\n\t\t}\n\n\t\t// The value\n\t\tif (!Value.empty ())\n\t\t{\n\t\t\tif (COXml::isStringValidForProperties (Value.c_str ()))\n\t\t\t\txmlSetProp (node, (const xmlChar*)\"Value\", (const xmlChar*)Value.c_str());\n\t\t\telse\n\t\t\t{\n\t\t\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)Value.c_str ());\n\t\t\t\txmlAddChild (node, textNode);\n\t\t\t}\n\t\t}\n\n\t\t// Return the new node\n\t\treturn node;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::read (xmlNodePtr node, CFormLoader &/* loader */, const CType *type, CForm * /* form */)\n{\n\t// Set the type\n\tType = type;\n\n\t// Set the value ?\n\tif (node)\n\t{\n\t\t// Get the value\n\t\tconst char *value = (const char*)xmlGetProp (node, (xmlChar*)\"Value\");\n\t\tif (value)\n\t\t{\n\t\t\t// Active value\n\t\t\tsetValue (value);\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)value);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Get content\n\t\t\tconst char *valueText = (const char*)xmlNodeGetContent (node);\n\t\t\tif (valueText)\n\t\t\t{\n\t\t\t\tsetValue (valueText);\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)valueText);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::setValue (const char *value)\n{\n\tValue = value;\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::getValue (std::string &result) const\n{\n\tresult = Value;\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::getFormName (std::string &result, const CFormElm *child) const\n{\n\t// Must be NULL\n\tnlassert (child == NULL);\n\tresult = \"\";\n\tresult.reserve (50);\n\n\t// Get parent form name\n\tif (ParentNode)\n\t\tParentNode->getFormName (result, this);\n}\n\n// ***************************************************************************\n\nvoid CFormElmAtom::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tstring formName;\n\tgetFormName (formName, NULL);\n\tNLGEORGES::warning (exception, \"(CFormElmAtom::%s) on node (%s) in form (%s) : %s\", function, formName.c_str (), Form->getFilename ().c_str (), buffer);\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n"
  },
  {
    "path": "code/nel/src/georges/form_loader.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/i_xml.h\"\n\n#include \"nel/georges/u_form.h\"\n\n#include \"nel/georges/form_loader.h\"\n#include \"nel/georges/type.h\"\n#include \"nel/georges/form.h\"\n#include \"nel/georges/form_dfn.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... );\n\n// ***************************************************************************\n// UFormLoader\n// ***************************************************************************\n\nUFormLoader *UFormLoader::createLoader ()\n{\n\treturn new CFormLoader;\n}\n\n// ***************************************************************************\n\nvoid UFormLoader::releaseLoader (UFormLoader *loader)\n{\n\tdelete ((CFormLoader*)loader);\n}\n\n// ***************************************************************************\n// CFormLoader\n// ***************************************************************************\nCFormLoader::~CFormLoader()\n{\n}\n\nCType *CFormLoader::loadType (const char *filename)\n{\n\t// Lower string filename\n\tstring lowerStr = toLower((string)filename);\n\tlowerStr = CFile::getFilename (lowerStr);\n\n\t// Already in the map ?\n\tTTypeMap::iterator ite = _MapType.find (lowerStr);\n\tif (ite != _MapType.end() && (ite->second != NULL) )\n\t{\n\t\t// Return the pointer\n\t\treturn ite->second;\n\t}\n\telse\n\t{\n\t\t// Create the type\n\t\tCType *type = new CType;\n\n\t\t// Load the type\n\t\ttry\n\t\t{\n\t\t\t// Open the file\n\t\t\tstring name = CPath::lookup (filename, false, false);\n\t\t\tif (name.empty())\n\t\t\t\tname = filename;\n\t\t\tCIFile file;\n\t\t\tif (file.open (name))\n\t\t\t{\n\t\t\t\t// Init an xml stream\n\t\t\t\tCIXml read;\n\t\t\t\tread.init (file);\n\n\t\t\t\t// Read the type\n\t\t\t\ttype->read (read.getRootNode ());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Output error\n\t\t\t\twarning (false, \"loadType\", \"Can't open the form file (%s).\", filename);\n\n\t\t\t\t// Delete the type\n\t\t\t\tdelete type;\n\t\t\t\ttype = NULL;\n\t\t\t}\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\t// Output error\n\t\t\twarning (false, \"loadType\", \"Error while loading the form (%s): %s\", filename, e.what());\n\n\t\t\t// Delete the type\n\t\t\tdelete type;\n\t\t\ttype = NULL;\n\t\t}\n\n\t\t// Loaded ?\n\t\tif (type)\n\t\t{\n\t\t\t// Insert a new entry\n\t\t\t_MapType[lowerStr]= type;\n\t\t\tite = _MapType.find (lowerStr);\n\t\t\t//CType *typeType = ite->second;\n\t\t\t//\t\t\tint toto = 0;\n\t\t}\n\t\treturn type;\n\t}\n}\n\n// ***************************************************************************\n\nCFormDfn *CFormLoader::loadFormDfn (const char *filename, bool forceLoad)\n{\n\t// Lower string filename\n\tstring lowerStr = toLower((string)filename);\n\tlowerStr = CFile::getFilename (lowerStr);\n\n\t// Already in the map ?\n\tTFormDfnMap::iterator ite = _MapFormDfn.find (lowerStr);\n\tif (ite != _MapFormDfn.end() && ite->second)\n\t{\n\t\t// Return the pointer\n\t\treturn ite->second;\n\t}\n\telse\n\t{\n\t\t// Create the formDfn\n\t\tCFormDfn *formDfn = new CFormDfn;\n\n\t\t// Insert the form first\n\t\t_MapFormDfn[lowerStr] = formDfn;\n\n\t\t// Load the type\n\t\ttry\n\t\t{\n\t\t\t// Open the file\n\t\t\tstring name = CPath::lookup (filename, false, false);\n\t\t\tif (name.empty())\n\t\t\t\tname = filename;\n\t\t\tCIFile file;\n\t\t\tif (file.open (name))\n\t\t\t{\n\t\t\t\t// Init an xml stream\n\t\t\t\tCIXml read;\n\t\t\t\tread.init (file);\n\n\t\t\t\t// Read the type\n\t\t\t\tformDfn->read (read.getRootNode (), *this, forceLoad, filename);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Output error\n\t\t\t\twarning (false, \"loadFormDfn\", \"Can't open the form file (%s).\", filename);\n\n\t\t\t\t// Delete the formDfn\n\t\t\t\tdelete formDfn;\n\t\t\t\tformDfn = NULL;\n\t\t\t\t_MapFormDfn.erase (lowerStr);\n\t\t\t}\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\t// Output error\n\t\t\twarning (false, \"loadFormDfn\", \"Error while loading the form (%s): %s\", filename, e.what());\n\n\t\t\t// Delete the formDfn\n\t\t\tdelete formDfn;\n\t\t\tformDfn = NULL;\n\t\t\t_MapFormDfn.erase (lowerStr);\n\t\t}\n\n\t\treturn formDfn;\n\t}\n}\n\n// ***************************************************************************\n\nUForm *CFormLoader::loadForm (const char *filename)\n{\n\t// Lower string filename\n\tstring lowerStr = toLower((string)filename);\n\tlowerStr = CFile::getFilename (lowerStr);\n\n\t// Already in the map ?\n\tTFormMap::iterator ite = _MapForm.find (lowerStr);\n\tif (ite != _MapForm.end() && ite->second)\n\t{\n\t\t// Return the pointer\n\t\treturn (CForm*)ite->second;\n\t}\n\telse\n\t{\n\t\t// Create the form\n\t\tCForm *form = new CForm;\n\n\t\t// Insert the form first\n\t\t_MapForm[lowerStr] = form;\n\n\t\t// Load the type\n\t\ttry\n\t\t{\n\t\t\t// Get the form DFN filename\n\t\t\tstring name = CFile::getFilename (filename);\n\t\t\tstring::size_type index = name.rfind ('.');\n\t\t\tif (index == string::npos)\n\t\t\t{\n\t\t\t\t// Output error\n\t\t\t\twarning (false, \"loadForm\", \"Form name is invalid (%s). It should have the extension of its DFN type.\", name.c_str ());\n\n\t\t\t\t// Delete the form\n\t\t\t\tdelete form;\n\t\t\t\tform = NULL;\n\t\t\t\t_MapForm.erase (lowerStr);\n\t\t\t}\n\t\t\tname = name.substr (index+1);\n\t\t\tname += \".dfn\";\n\n\t\t\t// Load the dfn\n\t\t\tCFormDfn\t*dfn = loadFormDfn (name.c_str (), false);\n\t\t\tif (dfn)\n\t\t\t{\n\t\t\t\t// Open the file\n\t\t\t\tname = CPath::lookup (filename, false, false);\n\t\t\t\tif (name.empty())\n\t\t\t\t\tname = filename;\n\t\t\t\tCIFile file;\n\t\t\t\tif (file.open (name))\n\t\t\t\t{\n\t\t\t\t\t// Init an xml stream\n\t\t\t\t\tCIXml read;\n\t\t\t\t\tread.init (file);\n\n\t\t\t\t\t// Read the form\n\t\t\t\t\tform->read (read.getRootNode (), *this, dfn, filename);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Output error\n\t\t\t\t\twarning (false, \"loadForm\", \"Can't open the form file (%s).\", filename);\n\n\t\t\t\t\t// Delete the form\n\t\t\t\t\tdelete form;\n\t\t\t\t\tform = NULL;\n\t\t\t\t\t_MapForm.erase (lowerStr);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Output error\n\t\t\t\twarning (false, \"loadForm\", \"Can't open the dfn file (%s).\", name.c_str ());\n\n\t\t\t\t// Delete the form\n\t\t\t\tdelete form;\n\t\t\t\tform = NULL;\n\t\t\t\t_MapForm.erase (lowerStr);\n\t\t\t}\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\t// Output error\n\t\t\twarning (false, \"loadForm\", \"Error while loading the form (%s): %s\", filename, e.what());\n\n\t\t\t// Delete the form\n\t\t\tdelete form;\n\t\t\tform = NULL;\n\t\t\t_MapForm.erase (lowerStr);\n\t\t}\n\n\t\treturn form;\n\t}\n}\n\n// ***************************************************************************\n\nUFormDfn *CFormLoader::loadFormDfn (const char *filename)\n{\n\treturn loadFormDfn (filename, false);\n}\n\n// ***************************************************************************\n\nUType *CFormLoader::loadFormType (const char *filename)\n{\n\treturn loadType (filename);\n}\n\n// ***************************************************************************\n\nvoid CFormLoader::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CFormLoader::%s) : %s\", function, buffer);\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n"
  },
  {
    "path": "code/nel/src/georges/georges_file_format.txt",
    "content": "Nel Georges File Format\n\nThere is 3 kind of files,\n\nType files (*.typ), define a basic element type (string, color, number with default values, limit, enums and graphic user interface).\nDfn files (*.dfn), define a structure composed of basic elements, array of basic element, sub structures, array of sub structures and virtual sub structures.\nForm files (*.dfn_name), implement a Dfn file (the name of the Dfn based file is dfn_name.dfn).\n\nType =\n\nDfn =\n\nForm =\n\n\n"
  },
  {
    "path": "code/nel/src/georges/header.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/common.h\"\n\n#include \"nel/georges/header.h\"\n\nusing namespace NLMISC;\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... );\n\n// ***************************************************************************\n\nCFileHeader::CFileHeader ()\n{\n\tMajorVersion = 0;\n\tMinorVersion = 0;\n\tState = Modified;\n}\n\n// ***************************************************************************\n\nvoid CFileHeader::write (xmlNodePtr node) const\n{\n\t// Georges version system\n\tchar tmp[512];\n\tsmprintf (tmp, 512, \"%d.%d\", MajorVersion, MinorVersion);\n\txmlSetProp (node, (const xmlChar*)\"Version\", (const xmlChar*)tmp);\n\n\t// State\n\tif (State == Modified)\n\t\txmlSetProp (node, (const xmlChar*)\"State\", (const xmlChar*)\"modified\");\n\telse\n\t\txmlSetProp (node, (const xmlChar*)\"State\", (const xmlChar*)\"checked\");\n\n\t// Comments of the form\n\tif (!Comments.empty ())\n\t{\n\t\t// Create a new node\n\t\txmlNodePtr child = xmlNewChild ( node, NULL, (const xmlChar*)\"COMMENTS\", NULL);\n\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)Comments.c_str());\n\t\txmlAddChild (child, textNode);\n\t}\n\n\t// Logs\n\tif (!Log.empty ())\n\t{\n\t\t// Create a new node\n\t\txmlNodePtr child = xmlNewChild ( node, NULL, (const xmlChar*)\"LOG\", NULL);\n\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)Log.c_str());\n\t\txmlAddChild (child, textNode);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CFileHeader::addLog (const char *log)\n{\n\ttime_t t;\n\ttime (&t);\n\tif (!Log.empty())\n\t\tLog += \"\\n\";\n\tLog += ctime(&t);\n\tLog.resize (Log.size()-1);\n\tLog += \" (\";\n\tLog += IThread::getCurrentThread ()->getUserName ();\n\tLog += \") \";\n\tLog += log;\n}\n\n// ***************************************************************************\n\nvoid CFileHeader::setComments (const char *comments)\n{\n\tComments = comments;\n}\n\n// ***************************************************************************\n\nvoid CFileHeader::read (xmlNodePtr root)\n{\n\t// Get the version\n\tconst char *value = (const char*)xmlGetProp (root, (xmlChar*)\"Version\");\n\tif (value)\n\t{\n\t\t// Read the version\n\t\tif (sscanf (value, \"%d.%d\", &MajorVersion, &MinorVersion) != 2)\n\t\t{\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)value);\n\n\t\t\t// Throw exception\n\t\t\twarning (true, \"read\", \"XML Syntax error in TYPE block line %p, the Version argument is invalid.\",\n\t\t\t\troot->content);\n\t\t}\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t{\n\t\t// Set default\n\t\tMajorVersion = 0;\n\t\tMinorVersion = 0;\n\t}\n\n\t// Get the version\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"State\");\n\tif (value)\n\t{\n\t\t// Read the version\n\t\tif (strcmp (value, \"modified\") == 0)\n\t\t{\n\t\t\tState = Modified;\n\t\t}\n\t\telse if (strcmp (value, \"checked\") == 0)\n\t\t{\n\t\t\tState = Checked;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)value);\n\n\t\t\t// Throw exception\n\t\t\twarning (true, \"read\", \"XML Syntax error in TYPE block line %p, the State argument is invalid.\",\n\t\t\t\troot->content);\n\t\t}\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t{\n\t\t// Set default\n\t\tState = Modified;\n\t}\n\n\t// Look for the comment node\n\tComments = \"\";\n\txmlNodePtr node = CIXml::getFirstChildNode (root, \"COMMENTS\");\n\tif (node)\n\t{\n\t\t// Get a text node\n\t\tnode = CIXml::getFirstChildNode (node, XML_TEXT_NODE);\n\n\t\tif (node)\n\t\t{\n\t\t\t// Get content\n\t\t\tconst char *comments = (const char*)xmlNodeGetContent (node);\n\t\t\tif (comments)\n\t\t\t{\n\t\t\t\tComments = comments;\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)comments);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Look for the log node\n\tLog = \"\";\n\tnode = CIXml::getFirstChildNode (root, \"LOG\");\n\tif (node)\n\t{\n\t\t// Get a text node\n\t\tnode = CIXml::getFirstChildNode (node, XML_TEXT_NODE);\n\n\t\tif (node)\n\t\t{\n\t\t\t// Get content\n\t\t\tconst char *log = (const char*)xmlNodeGetContent (node);\n\t\t\tif (log)\n\t\t\t{\n\t\t\t\tLog = log;\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)log);\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nconst char *CFileHeader::getStateString (TState state)\n{\n\tif (state == Modified)\n\t\treturn \"Modified\";\n\telse\n\t\treturn \"Checked\";\n}\n\n// ***************************************************************************\n\nvoid CFileHeader::warning (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CFileHeader::%s) : %s\", function, buffer);\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n"
  },
  {
    "path": "code/nel/src/georges/load_form.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdgeorges.h\"\n"
  },
  {
    "path": "code/nel/src/georges/nel-georges.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: nel-georges\nVersion: @NL_VERSION@\nDescription: NeL @NL_VERSION@\nRequires:\nLibs: -L${libdir}\nLibs.private: @LIBS@ -lc\nCflags: -I${includedir}\n"
  },
  {
    "path": "code/nel/src/georges/stdgeorges.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdgeorges.h\"\n"
  },
  {
    "path": "code/nel/src/georges/stdgeorges.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"nel/misc/types_nl.h\"\n#include <cmath>\n#include <list>\n#include <map>\n#include <vector>\n#include <string>\n#include <ctime>\n#include <limits>\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/common.h\"\n\n// Include from libxml2\n#include <libxml/parser.h>\n"
  },
  {
    "path": "code/nel/src/georges/type.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdgeorges.h\"\n\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/eval_num_expr.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/georges/u_type.h\"\n\n#include \"nel/georges/form.h\"\n#include \"nel/georges/form_elm.h\"\n#include \"nel/georges/form_loader.h\"\n#include \"nel/georges/type.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLGEORGES\n{\n\n// ***************************************************************************\n\nvoid warning (bool exception, const char *format, ... );\n\n// ***************************************************************************\n\nCType::CType ()\n{\n\tType = UnsignedInt;\n\tUIType = Edit;\n}\n\n// ***************************************************************************\n\nCType::~CType ()\n{\n  //\tint toto = 0;\n}\n\n// ***************************************************************************\n\nvoid CType::write (xmlDocPtr doc) const\n{\n\t// Create the first node\n\txmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)\"TYPE\", NULL);\n\txmlDocSetRootElement (doc, node);\n\n\t// Type\n\txmlSetProp (node, (const xmlChar*)\"Type\", (const xmlChar*)TypeNames[Type]);\n\txmlSetProp (node, (const xmlChar*)\"UI\", (const xmlChar*)UITypeNames[UIType]);\n\n\t// Default valid\n\tif (!Default.empty())\n\t{\n\t\txmlSetProp (node, (const xmlChar*)\"Default\", (const xmlChar*)Default.c_str());\n\t}\n\n\t// Min valid\n\tif (!Min.empty())\n\t{\n\t\txmlSetProp (node, (const xmlChar*)\"Min\", (const xmlChar*)Min.c_str());\n\t}\n\n\t// Max valid\n\tif (!Max.empty())\n\t{\n\t\txmlSetProp (node, (const xmlChar*)\"Max\", (const xmlChar*)Max.c_str());\n\t}\n\n\t// Increment valid\n\tif (!Increment.empty())\n\t{\n\t\txmlSetProp (node, (const xmlChar*)\"Increment\", (const xmlChar*)Increment.c_str());\n\t}\n\n\t// Definition\n\tuint def = 0;\n\tfor (def = 0; def<Definitions.size(); def++)\n\t{\n\t\txmlNodePtr defNode = xmlNewChild ( node, NULL, (const xmlChar*)\"DEFINITION\", NULL);\n\t\txmlSetProp (defNode, (const xmlChar*)\"Label\", (const xmlChar*)Definitions[def].Label.c_str());\n\t\txmlSetProp (defNode, (const xmlChar*)\"Value\", (const xmlChar*)Definitions[def].Value.c_str());\n\t}\n\n\t// Header\n\tHeader.write (node);\n}\n\n// ***************************************************************************\n\nvoid CType::read (xmlNodePtr root)\n{\n\t// Check node name\n\tif ( ((const char*)root->name == NULL) || (strcmp ((const char*)root->name, \"TYPE\") != 0) )\n\t{\n\t\t// Throw exception\n\t\twarning2 (true, \"read\", \"XML Syntax error in block line %p, node (%s) should be TYPE.\",\n\t\t\troot->content, root->name);\n\t}\n\n\t// Read the type\n\tconst char *value = (const char*)xmlGetProp (root, (xmlChar*)\"Type\");\n\tif (value)\n\t{\n\t\t// Lookup type\n\t\tuint type;\n\t\tfor (type=0; type<TypeCount; type++)\n\t\t{\n\t\t\tif (strcmp (value, TypeNames[type]) == 0)\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Type found ?\n\t\tif (type!=TypeCount)\n\t\t\tType = (TType)type;\n\t\telse\n\t\t{\n\t\t\t// Make an error message\n\t\t\tstring valueStr = value;\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)value);\n\n\t\t\t// Throw exception\n\t\t\twarning2 (true, \"read\", \"XML Syntax error in TYPE block line %p, the Type value is unknown (%s).\",\n\t\t\t\troot->content, valueStr.c_str ());\n\t\t}\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t{\n\t\t// Throw exception\n\t\twarning2 (true, \"read\", \"XML Syntax error in TYPE block line %p, the Type argument was not found.\",\n\t\t\troot->content);\n\t}\n\n\t// Read the UI\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"UI\");\n\tif (value)\n\t{\n\t\t// Lookup type\n\t\tuint type;\n\t\tfor (type=0; type<UITypeCount; type++)\n\t\t{\n\t\t\tif (strcmp (value, UITypeNames[type]) == 0)\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Type found ?\n\t\tif (type!=UITypeCount)\n\t\t\tUIType = (TUI)type;\n\t\telse\n\t\t\tUIType = Edit;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t\tUIType = Edit;\n\n\t// Read Default\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"Default\");\n\tif (value)\n\t{\n\t\tDefault = value;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t\tDefault = \"\";\n\n\t// Read Min\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"Min\");\n\tif (value)\n\t{\n\t\tMin = value;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t\tMin = \"\";\n\n\t// Read Max\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"Max\");\n\tif (value)\n\t{\n\t\tMax = value;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t\tMax = \"\";\n\n\t// Read Increment\n\tvalue = (const char*)xmlGetProp (root, (xmlChar*)\"Increment\");\n\tif (value)\n\t{\n\t\tIncrement = value;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\t}\n\telse\n\t\tIncrement = \"\";\n\n\t// Read the definitions\n\tuint childrenCount = CIXml::countChildren (root, \"DEFINITION\");\n\n\t// Resize the array\n\tDefinitions.resize (childrenCount);\n\tuint child=0;\n\txmlNodePtr childPtr = CIXml::getFirstChildNode (root, \"DEFINITION\");\n\twhile (child < childrenCount)\n\t{\n\t\t// Should not be NULL\n\t\tnlassert (childPtr);\n\n\t\t// Read Default\n\t\tconst char *label = (const char*)xmlGetProp (childPtr, (xmlChar*)\"Label\");\n\t\tif (label)\n\t\t{\n\t\t\t// Read Default\n\t\t\tvalue = (const char*)xmlGetProp (childPtr, (xmlChar*)\"Value\");\n\t\t\tif (value)\n\t\t\t{\n\t\t\t\tDefinitions[child].Label = label;\n\t\t\t\tDefinitions[child].Value = value;\n\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)value);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Delete the value\n\t\t\t\txmlFree ((void*)label);\n\n\t\t\t\t// Throw exception\n\t\t\t\twarning2 (true, \"read\", \"XML Syntax error in DEFINITION block line %p, the Value argument was not found.\",\n\t\t\t\t\tchildPtr->content);\n\t\t\t}\n\n\t\t\t// Delete the value\n\t\t\txmlFree ((void*)label);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Throw exception\n\t\t\twarning2 (true, \"read\", \"XML Syntax error in DEFINITION block line %p, the Label argument was not found.\",\n\t\t\t\tchildPtr->content);\n\t\t}\n\n\t\t// One more\n\t\tchild++;\n\n\t\tchildPtr = CIXml::getNextChildNode (childPtr, \"DEFINITION\");;\n\t}\n\n\t// Read the header\n\tHeader.read (root);\n}\n\n// ***************************************************************************\n\nconst char *CType::TypeNames[TypeCount]=\n{\n\t\"UnsignedInt\",\n\t\"SignedInt\",\n\t\"Double\",\n\t\"String\",\n\t\"Color\",\n};\n\n// ***************************************************************************\n\nconst char *CType::UITypeNames[UITypeCount]=\n{\n\t\"Edit\",\n\t\"EditSpin\",\n\t\"NonEditableCombo\",\n\t\"FileBrowser\",\n\t\"BigEdit\",\n\t\"ColorEdit\",\n};\n\n// ***************************************************************************\n\nconst char *CType::getTypeName (TType type)\n{\n\treturn TypeNames[type];\n}\n\n// ***************************************************************************\n\nconst char *CType::getUIName (TUI type)\n{\n\treturn UITypeNames[type];\n}\n\n// ***************************************************************************\n\nclass CMyEvalNumExpr : public CEvalNumExpr\n{\npublic:\n\tCMyEvalNumExpr (const CForm *form , const CType *type )\n\t{\n\t\tType = type;\n\t\tForm = form;\n\t}\n\tvirtual CEvalNumExpr::TReturnState evalValue (const char *value, double &result, uint32 round)\n\t{\n\t\t// If a form is available\n\t\tif (Form)\n\t\t{\n\t\t\t// Ask for the filename ?\n\t\t\tif (strcmp (value, \"$filename\") == 0)\n\t\t\t{\n\t\t\t\t// Get the filename\n\t\t\t\tconst string filename = CFile::getFilenameWithoutExtension (Form->getFilename ());\n\n\t\t\t\t// While the filename as a number\n\t\t\t\tsint i;\n\t\t\t\tfor (i=(sint)filename.size ()-1; i>=0; i--)\n\t\t\t\t{\n\t\t\t\t\tif ((filename[i]<'0') || (filename[i]>'9'))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Number found..\n\t\t\t\tif ((i >= 0) && (i<((sint)filename.size ()-1)))\n\t\t\t\t{\n\t\t\t\t\ti++;\n\t\t\t\t\t// Set the result\n\t\t\t\t\tNLMISC::fromString(filename.substr(i), result);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If the filename doesn't contain a number, returns 0\n\t\t\t\t\tresult = 0;\n\t\t\t\t}\n\t\t\t\treturn CEvalNumExpr::NoError;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// check if the value is a label defined in the \".typ\" file\n\t\t\t\tfor (uint i =0; i < Type->Definitions.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif ( !nlstricmp( Type->Definitions[i].Label.c_str(),value ) )\n\t\t\t\t\t{\n\t\t\t\t\t\tCMyEvalNumExpr expr(Form, Type);\n\t\t\t\t\t\tsint index;\n\t\t\t\t\t\treturn expr.evalExpression (Type->Definitions[i].Value.c_str(), result,&index,round+1);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// try to get a Form value\n\n\t\t\t\t// Is an exist request ?\n\t\t\t\tbool requestExist = false;\n\t\t\t\tif (*value == '#')\n\t\t\t\t{\n\t\t\t\t\tvalue++;\n\t\t\t\t\trequestExist = true;\n\t\t\t\t}\n\n\t\t\t\t// The parent Dfn\n\t\t\t\tconst CFormDfn *parentDfn;\n\t\t\t\tconst CFormDfn *nodeDfn;\n\t\t\t\tconst CType *nodeType;\n\t\t\t\tCFormElm *node;\n\t\t\t\tuint parentIndex;\n\t\t\t\tbool array;\n\t\t\t\tbool parentVDfnArray;\n\t\t\t\tUFormDfn::TEntryType type;\n\t\t\t\t// Search for the node\n\t\t\t\tif (((const CFormElm&)Form->getRootNode ()).getNodeByName (value, &parentDfn, parentIndex, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, false, round+1))\n\t\t\t\t{\n\t\t\t\t\t// End, return the current index\n\t\t\t\t\tif (type == UFormDfn::EntryType)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The atom\n\t\t\t\t\t\tconst CFormElmAtom *atom = node ? safe_cast<const CFormElmAtom*> (node) : NULL;\n\n\t\t\t\t\t\t// Evale\n\t\t\t\t\t\tnlassert (nodeType);\n\t\t\t\t\t\tstring res;\n\t\t\t\t\t\tif (nodeType->getValue (res, Form, atom, *parentDfn, parentIndex, UFormElm::Eval, NULL, round+1, value))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Request exist ?\n\t\t\t\t\t\t\tif (requestExist)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Doesn't exist\n\t\t\t\t\t\t\t\tresult = res.empty ()?0:1;\n\t\t\t\t\t\t\t\treturn CEvalNumExpr::NoError;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if (((const CFormElm&)Form->getRootNode ()).convertValue (result, res.c_str ()))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treturn CEvalNumExpr::NoError;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Request exist ?\n\t\t\t\t\t\tif (requestExist)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Doesn't exist\n\t\t\t\t\t\t\tresult = 0;\n\t\t\t\t\t\t\treturn CEvalNumExpr::NoError;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn CEvalNumExpr::evalValue (value, result, round+1);\n\t}\n\n\t// The working form\n\tconst CForm\t\t*Form;\n\t// the type of the field containing the expression\n\tconst CType\t\t*Type;\n};\n\n// ***************************************************************************\n\n#define NL_TOKEN_STRING 0\n#define NL_TOKEN_DOUBLE_QUOTE 1\n#define NL_TOKEN_OPEN_BRACKET 2\n#define NL_TOKEN_NAME 3\n#define NL_TOKEN_END 4\n\nuint getNextToken (const char *startString, string &token, uint &offset)\n{\n\tif (startString[offset] == 0)\n\t\treturn NL_TOKEN_END;\n\tif (startString[offset] == '\"')\n\t{\n\t\toffset++;\n\t\treturn NL_TOKEN_DOUBLE_QUOTE;\n\t}\n\tif (startString[offset] == '{')\n\t{\n\t\toffset++;\n\t\treturn NL_TOKEN_OPEN_BRACKET;\n\t}\n\tif ( (startString[offset] == '$') && (strncmp (startString+offset+1, \"filename\", 8) == 0) )\n\t{\n\t\toffset += 9;\n\t\treturn NL_TOKEN_NAME;\n\t}\n\ttoken = \"\";\n\twhile (startString[offset])\n\t{\n\t\tif (startString[offset] == '\\\\')\n\t\t{\n\t\t\tif (startString[offset+1])\n\t\t\t{\n\t\t\t\ttoken += startString[offset+1];\n\t\t\t\toffset++;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\toffset++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if (startString[offset] == '\"')\n\t\t\tbreak;\n\t\telse if (startString[offset] == '{')\n\t\t\tbreak;\n\t\telse if ( (startString[offset] == '$') && (strncmp (startString+offset+1, \"filename\", 8) == 0) )\n\t\t\tbreak;\n\t\telse\n\t\t\ttoken += startString[offset];\n\t\toffset++;\n\t}\n\treturn NL_TOKEN_STRING;\n}\n\n// ***************************************************************************\n\nuint findSpecialCharacter (const char *special, char c, uint startOffset)\n{\n\tuint offset = startOffset;\n\twhile (special[offset])\n\t{\n\t\tif (special[offset] == '\\\\')\n\t\t{\n\t\t\tif (special[offset+1])\n\t\t\t\toffset++;\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (special[offset] == c)\n\t\t\t\treturn offset;\n\t\t}\n\t\toffset++;\n\t}\n\treturn 0xffffffff;\n}\n\n// ***************************************************************************\n\nvoid buildError (char *msg, uint offset)\n{\n\tmsg[0] = 0;\n\tif (offset<512)\n\t{\n\t\tuint i;\n\t\tfor (i=0; i<offset; i++)\n\t\t\tmsg[i] = '-';\n\t\tmsg[i] = '^';\n\t\tmsg[i+1] = 0;\n\t}\n}\n\n// ***************************************************************************\n\nbool CType::getValue (string &result, const CForm *form, const CFormElmAtom *node, const CFormDfn &parentDfn, uint parentIndex, UFormElm::TEval evaluate, uint32 *where, uint32 round, const char *formName) const\n{\n\tif (round > NLGEORGES_MAX_RECURSION)\n\t{\n\t\t// Turn around..\n\t\twarning2 (false, \"getDefinition\", \"Recurcive call on the same DFN, look for loop inheritances.\");\n\t\treturn false;\n\t}\n\n\t// Node exist ?\n\tif (node && !node->Value.empty())\n\t{\n\t\tif (where)\n\t\t\t*where = (node->Form == form) ? CFormElm::ValueForm : CFormElm::ValueParentForm;\n\t\tresult = node->Value;\n\t}\n\t// Have a default dfn value ?\n\telse\n\t{\n\t\tconst string &defDfn = parentDfn.Entries[parentIndex].Default;\n\t\tif (!defDfn.empty ())\n\t\t{\n\t\t\tif (where)\n\t\t\t\t*where = CFormElm::ValueDefaultDfn;\n\t\t\tresult = defDfn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (where)\n\t\t\t\t*where = CFormElm::ValueDefaultType;\n\t\t\tresult = Default;\n\t\t}\n\t}\n\n\t// evaluate the value ?\n\tif (evaluate == UFormElm::Formula)\n\t{\n\t\t// Evaluate predefinition\n\t\tuint i;\n\t\tuint predefCount = (uint)Definitions.size ();\n\t\tfor (i=0; i<predefCount; i++)\n\t\t{\n\t\t\t// Ref on the value\n\t\t\tconst CType::CDefinition &def = Definitions[i];\n\n\t\t\t// This predefinition ?\n\t\t\tif (def.Label == result)\n\t\t\t{\n\t\t\t\tresult = def.Value;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse if (evaluate == UFormElm::Eval)\n\t{\n\t\t// Evaluate numerical expression\n\t\tif ((Type == Double) || (Type == SignedInt) || (Type == UnsignedInt) || (Type == UnsignedInt))\n\t\t{\n\t\t\t// Evaluate predefinition\n\t\t\tuint i;\n\t\t\tuint predefCount = (uint)Definitions.size ();\n\t\t\tfor (i=0; i<predefCount; i++)\n\t\t\t{\n\t\t\t\t// Ref on the value\n\t\t\t\tconst CType::CDefinition &def = Definitions[i];\n\n\t\t\t\t// This predefinition ?\n\t\t\t\tif (def.Label == result)\n\t\t\t\t{\n\t\t\t\t\tresult = def.Value;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdouble value;\n\t\t\tCMyEvalNumExpr expr (form,this);\n\t\t\tint offset;\n\t\t\tCEvalNumExpr::TReturnState error = expr.evalExpression (result.c_str (), value, &offset, round+1);\n\t\t\tif (error == CEvalNumExpr::NoError)\n\t\t\t{\n\t\t\t\t// To string\n\t\t\t\tresult = toString (value);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Build a nice error output in warning\n\t\t\t\tchar msg[512];\n\t\t\t\tbuildError (msg, offset);\n\t\t\t\twarning (false, formName, form->getFilename ().c_str (), \"getValue\", \"Syntax error in expression: %s\\n%s\\n%s\", expr.getErrorString (error), result.c_str (), msg);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse // For strings\n\t\t{\n\t\t\t// Get next text\n\t\t\tuint offset = 0;\n\t\t\tstring dest;\n\t\t\twhile (offset < result.size ())\n\t\t\t{\n\t\t\t\tstring token;\n\t\t\t\tuint tokenType = getNextToken (result.c_str (), token, offset);\n\n\t\t\t\t// Brackets, {numerical expressions} : numerical expressions to string\n\t\t\t\tif (tokenType == NL_TOKEN_OPEN_BRACKET)\n\t\t\t\t{\n\t\t\t\t\t// Find the second \"\n\t\t\t\t\tuint nextEnd = findSpecialCharacter (result.c_str (), '}', offset);\n\t\t\t\t\tif (nextEnd == 0xffffffff)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Build a nice error output in warning\n\t\t\t\t\t\tchar msg[512];\n\t\t\t\t\t\tbuildError (msg, (uint)result.size ());\n\t\t\t\t\t\twarning (false, formName, form->getFilename ().c_str (), \"getValue\", \"Missing closing quote\\n%s\\n%s\", result.c_str (), msg);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Zero padding\n\t\t\t\t\t\tchar zeroPadding = 0;\n\n\t\t\t\t\t\t// Format code ?\n\t\t\t\t\t\tif ( ( (nextEnd - offset) >= 3 ) && ( result[offset] == '$' ) && ( result[offset+1] == 'z' )\n\t\t\t\t\t\t\t&& ( result[offset+2] <= '9' ) && ( result[offset+2] >= '0'  ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Save padding\n\t\t\t\t\t\t\tzeroPadding = result[offset+2] - '0';\n\t\t\t\t\t\t\toffset += 3;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// try to get a Form value\n\t\t\t\t\t\tstring valueName = result.substr ( offset, nextEnd-offset );\n\n\t\t\t\t\t\tdouble value;\n\t\t\t\t\t\tCMyEvalNumExpr expr (form,this);\n\t\t\t\t\t\tint offsetExpr;\n\t\t\t\t\t\tCEvalNumExpr::TReturnState error = expr.evalExpression (valueName.c_str (), value, &offsetExpr, round+1);\n\t\t\t\t\t\tif (error == CEvalNumExpr::NoError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// To string\n\t\t\t\t\t\t\tchar format[200];\n\t\t\t\t\t\t\tchar result[200];\n\t\t\t\t\t\t\tsmprintf (format, 200, \"%%0%cg\", zeroPadding+'0');\n\t\t\t\t\t\t\tsmprintf (result, 200, format, value);\n\t\t\t\t\t\t\tdest += result;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Build a nice error output in warning\n\t\t\t\t\t\t\tchar msg[512];\n\t\t\t\t\t\t\tbuildError (msg, offset+offsetExpr);\n\t\t\t\t\t\t\twarning (false, formName, form->getFilename ().c_str (), \"getValue\", \"Syntax error in expression: %s\\n%s\\n%s\", expr.getErrorString (error), result.c_str (), msg);\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Next offset\n\t\t\t\t\t\toffset = nextEnd + 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (tokenType == NL_TOKEN_DOUBLE_QUOTE)\n\t\t\t\t{\n\t\t\t\t\t// Find the second \"\n\t\t\t\t\tuint nextEnd = findSpecialCharacter (result.c_str (), '\"', offset);\n\t\t\t\t\tif (nextEnd == 0xffffffff)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Build a nice error output in warning\n\t\t\t\t\t\tchar msg[512];\n\t\t\t\t\t\tbuildError (msg, (uint)result.size ());\n\t\t\t\t\t\twarning (false, formName, form->getFilename ().c_str (), \"getValue\", \"Missing double quote\\n%s\\n%s\", result.c_str (), msg);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// try to get a Form value\n\t\t\t\t\t\tstring valueName = result.substr ( offset, nextEnd-offset );\n\n\t\t\t\t\t\t// The parent Dfn\n\t\t\t\t\t\tconst CFormDfn *parentDfn;\n\t\t\t\t\t\tconst CFormDfn *nodeDfn;\n\t\t\t\t\t\tconst CType *nodeType;\n\t\t\t\t\t\tCFormElm *node;\n\t\t\t\t\t\tuint parentIndex;\n\t\t\t\t\t\tbool array;\n\t\t\t\t\t\tbool parentVDfnArray;\n\t\t\t\t\t\tUFormDfn::TEntryType type;\n\n\t\t\t\t\t\t// Search for the node\n\t\t\t\t\t\tif (((const CFormElm&)form->getRootNode ()).getNodeByName (valueName.c_str (), &parentDfn, parentIndex, &nodeDfn, &nodeType, &node, type, array, parentVDfnArray, false, round+1))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// End, return the current index\n\t\t\t\t\t\t\tif (type == UFormDfn::EntryType)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// The atom\n\t\t\t\t\t\t\t\tconst CFormElmAtom *atom = node ? safe_cast<const CFormElmAtom*> (node) : NULL;\n\n\t\t\t\t\t\t\t\t// Evale\n\t\t\t\t\t\t\t\tnlassert (nodeType);\n\t\t\t\t\t\t\t\tstring result2;\n\t\t\t\t\t\t\t\tif (nodeType->getValue (result2, form, atom, *parentDfn, parentIndex, UFormElm::Eval, NULL, round+1, valueName.c_str ()))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tdest += result2;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tchar msg[512];\n\t\t\t\t\t\t\t\tbuildError (msg, offset);\n\t\t\t\t\t\t\t\twarning (false, formName, form->getFilename ().c_str (), \"getValue\", \"Node is not an atom (%s)\\n%s\\n%s\", valueName.c_str (), result.c_str (), msg);\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Next offset\n\t\t\t\t\toffset = nextEnd + 1;\n\t\t\t\t}\n\t\t\t\telse if (tokenType == NL_TOKEN_STRING)\n\t\t\t\t{\n\t\t\t\t\t// Evaluate predefinition\n\t\t\t\t\tuint i;\n\t\t\t\t\tuint predefCount = (uint)Definitions.size ();\n\t\t\t\t\tfor (i=0; i<predefCount; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Ref on the value\n\t\t\t\t\t\tconst CType::CDefinition &def = Definitions[i];\n\n\t\t\t\t\t\t// This predefinition ?\n\t\t\t\t\t\tif (def.Label == token)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttoken = def.Value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Take the remaining of the string\n\t\t\t\t\tdest += token;\n\t\t\t\t}\n\t\t\t\telse if (tokenType == NL_TOKEN_NAME)\n\t\t\t\t{\n\t\t\t\t\tdest += form->getFilename ();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Final result\n\t\t\tresult = dest;\n\t\t}\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CType::uiCompatible (TType type, TUI ui)\n{\n\tswitch (type)\n\t{\n\tcase UnsignedInt:\n\tcase SignedInt:\n\tcase Double:\n\t\treturn (ui == Edit) || (ui == EditSpin) || (ui == NonEditableCombo);\n\tcase String:\n\t\treturn (ui == Edit) || (ui == NonEditableCombo) || (ui == FileBrowser) || (ui == BigEdit);\n\tcase Color:\n\t\treturn (ui == ColorEdit);\n\tdefault: break;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CType::warning (bool exception, const char *formName, const char *formFilename, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CType::%s) In form (%s) in node (%s) : %s\", function, formFilename, formName, buffer);\n}\n\n// ***************************************************************************\n\nvoid CType::warning2 (bool exception, const char *function, const char *format, ... ) const\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\t// Set the warning\n\tNLGEORGES::warning (exception, \"(CType::%s) : %s\", function, buffer);\n}\n\n// ***************************************************************************\n\nUType::TType CType::getType () const\n{\n\treturn Type;\n}\n\n// ***************************************************************************\n\nconst string &CType::getDefault () const\n{\n\treturn Default;\n}\n\n// ***************************************************************************\n\nconst string\t&CType::getMin () const\n{\n\treturn Min;\n}\n\n// ***************************************************************************\n\nconst string\t&CType::getMax () const\n{\n\treturn Max;\n}\n\n// ***************************************************************************\n\nconst string\t&CType::getIncrement () const\n{\n\treturn Increment;\n}\n\n// ***************************************************************************\n\nuint CType::getNumDefinition () const\n{\n\treturn (uint)Definitions.size ();\n}\n\n// ***************************************************************************\n\nbool CType::getDefinition (uint index, std::string &label, std::string &value) const\n{\n\tif (index < Definitions.size ())\n\t{\n\t\tlabel = Definitions[index].Label;\n\t\tvalue = Definitions[index].Value;\n\t\treturn true;\n\t}\n\twarning2 (false, \"getDefinition\", \"Index out of bounds (%d >= %d)\", index, Definitions.size ());\n\treturn false;\n}\n\n// ***************************************************************************\n\nconst string\t&CType::getComment () const\n{\n\treturn Header.Comments;\n}\n\n// ***************************************************************************\n\nvoid CType::getDependencies (std::set<std::string> & /* dependencies */) const\n{\n\n}\n\n// ***************************************************************************\n\n} // NLGEORGES\n"
  },
  {
    "path": "code/nel/src/ligo/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\nFILE(GLOB HEADERS ../../include/nel/ligo/*.h)\n\nNL_TARGET_LIB(nelligo ${HEADERS} ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(nelligo ${LIBXML2_LIBRARIES} nelmisc)\nSET_TARGET_PROPERTIES(nelligo PROPERTIES LINK_INTERFACE_LIBRARIES \"\")\nNL_DEFAULT_PROPS(nelligo \"NeL, Library: NeL Ligo\")\nNL_ADD_RUNTIME_FLAGS(nelligo)\n\nNL_ADD_LIB_SUFFIX(nelligo)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH)\n  ADD_NATIVE_PRECOMPILED_HEADER(nelligo ${CMAKE_CURRENT_SOURCE_DIR}/stdligo.h ${CMAKE_CURRENT_SOURCE_DIR}/stdligo.cpp)\nENDIF(WITH_PCH)\n\nNL_GEN_PC(nel-ligo.pc)\n\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS nelligo LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/nel/src/ligo/ligo_config.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/ligo/ligo_config.h\"\n\n#include \"nel/ligo/primitive.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/file.h\"\n\n#include <cstdlib>\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\nCLigoConfig::CLigoConfig()\n: _DynamicAliasBitCount(32)\n{\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::readConfigFile (const char *fileName, bool parsePrimitiveComboContent)\n{\n\t// The CF\n\tCConfigFile cf;\n\n\t// Load and parse the file\n\tcf.load (fileName);\n\n\t// Read the parameters\n\tCConfigFile::CVar &cell_size = cf.getVar (\"cell_size\");\n\tCellSize = cell_size.asFloat ();\n\tCConfigFile::CVar &snap = cf.getVar (\"snap\");\n\tSnap = snap.asFloat ();\n\tCConfigFile::CVar &snapShot = cf.getVar (\"zone_snapeshot_res\");\n\tZoneSnapShotRes = (uint)snapShot.asInt ();\n\tCConfigFile::CVar &primitiveClassFilename = cf.getVar (\"primitive_class_filename\");\n\tPrimitiveClassFilename= primitiveClassFilename.asString ();\n\n\t// Clear the previous classes\n\t_Contexts.clear();\n\t_Contexts.push_back (\"default\");\n\t_PrimitiveClasses.clear();\n\t_PrimitiveConfigurations.clear();\n\n\t// Read the primitive class name\n\tif (!PrimitiveClassFilename.empty())\n\t{\n\t\treturn readPrimitiveClass (PrimitiveClassFilename.c_str(), parsePrimitiveComboContent);\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::readPrimitiveClass (const char *_fileName, bool parsePrimitiveComboContent)\n{\n\t// File exist ?\n\tstring filename = _fileName;\n\tfilename = CPath::lookup (_fileName, false, false, false);\n\tif (filename.empty())\n\t\tfilename = _fileName;\n\n\t// The context strings\n\tset<string> contextStrings;\n\n\t// Read the document\n\tCIFile file;\n\tif (file.open (filename))\n\t{\n\t\ttry\n\t\t{\n\t\t\t// XML stream\n\t\t\tCIXml xml;\n\t\t\txml.init (file);\n\n\t\t\t// Get the root node\n\t\t\txmlNodePtr root = xml.getRootNode ();\n\t\t\tnlassert (root);\n\n\t\t\t// Check the header\n\t\t\tif (strcmp ((const char*)root->name, \"NEL_LIGO_PRIMITIVE_CLASS\") == 0)\n\t\t\t{\n\t\t\t\t// ALIAS_DYNAMIC_BITS\n\t\t\t\txmlNodePtr aliasBits = CIXml::getFirstChildNode (root, \"ALIAS_DYNAMIC_BITS\");\n\t\t\t\tif (aliasBits)\n\t\t\t\t{\n\t\t\t\t\tstring bits;\n\t\t\t\t\tif (getPropertyString (bits, filename.c_str(), aliasBits, \"BIT_COUNT\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tuint32 uBits;\n\t\t\t\t\t\tNLMISC::fromString(bits, uBits);\n\t\t\t\t\t\t_DynamicAliasBitCount = std::min((uint32)32, uBits);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\treturn false;\n\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// by default, set the size of dynamic alias to 32 bits\n\t\t\t\t\t_DynamicAliasBitCount = 32;\n\t\t\t\t}\n\t\t\t\t// ALIAS_STATIC_FILE_ID\n\t\t\t\txmlNodePtr indexFileNameNode = CIXml::getFirstChildNode (root, \"ALIAS_STATIC_FILE_ID\");\n\t\t\t\tif (indexFileNameNode)\n\t\t\t\t{\n\t\t\t\t\tstring indexFileName;\n\t\t\t\t\tif (getPropertyString (indexFileName, filename.c_str(), indexFileNameNode, \"FILE_NAME\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (CPath::lookup(indexFileName, false, false, true).empty())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// try to append the class file path\n\t\t\t\t\t\t\tindexFileName = CFile::getPath(_fileName)+indexFileName;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// load the configuration file\n\t\t\t\t\t\treloadIndexFile(indexFileName);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tnlwarning(\"Can't find XML element <FILE_NAME>, no file index available for alias\" );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// by default, set the size of dynamic alias to 32 bits\n\t\t\t\t\t_DynamicAliasBitCount = 32;\n\t\t\t\t}\n\n\n\t\t\t\t// Get the first primitive description\n\t\t\t\txmlNodePtr primitive = CIXml::getFirstChildNode (root, \"PRIMITIVE\");\n\t\t\t\tif (primitive)\n\t\t\t\t{\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get the primitive name\n\t\t\t\t\t\tstd::string name;\n\t\t\t\t\t\tif (getPropertyString (name, filename.c_str(), primitive, \"CLASS_NAME\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Add the primitive\n\t\t\t\t\t\t\tpair<std::map<std::string, CPrimitiveClass>::iterator, bool> insertResult =\n\t\t\t\t\t\t\t\t_PrimitiveClasses.insert (std::map<std::string, CPrimitiveClass>::value_type (name, CPrimitiveClass ()));\n\t\t\t\t\t\t\tif (insertResult.second)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!insertResult.first->second.read (primitive, filename.c_str(), name.c_str (), contextStrings, _ContextFilesLookup, *this, parsePrimitiveComboContent))\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsyntaxError (filename.c_str(), root, \"Class (%s) already defined\", name.c_str ());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn false;\n\n\t\t\t\t\t\tprimitive = CIXml::getNextChildNode (primitive, \"PRIMITIVE\");\n\t\t\t\t\t}\n\t\t\t\t\twhile (primitive);\n\t\t\t\t}\n\n\t\t\t\t// Add the context strings\n\t\t\t\t{\n\t\t\t\t\tset<string>::iterator ite = contextStrings.begin ();\n\t\t\t\t\twhile (ite != contextStrings.end ())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (*ite != \"default\")\n\t\t\t\t\t\t\t_Contexts.push_back (*ite);\n\t\t\t\t\t\tite++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Get the first primitive configuration\n\t\t\t\t_PrimitiveConfigurations.reserve (_PrimitiveConfigurations.size()+CIXml::countChildren (root, \"CONFIGURATION\"));\n\t\t\t\txmlNodePtr configuration = CIXml::getFirstChildNode (root, \"CONFIGURATION\");\n\t\t\t\tif (configuration)\n\t\t\t\t{\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get the configuration name\n\t\t\t\t\t\tstd::string name;\n\t\t\t\t\t\tif (getPropertyString (name, filename.c_str(), configuration, \"NAME\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Add the configuration\n\t\t\t\t\t\t\t_PrimitiveConfigurations.resize (_PrimitiveConfigurations.size()+1);\n\t\t\t\t\t\t\tif (!_PrimitiveConfigurations.back().read (configuration, filename.c_str(), name.c_str (), *this))\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn false;\n\n\t\t\t\t\t\tconfiguration = CIXml::getNextChildNode (configuration, \"CONFIGURATION\");\n\t\t\t\t\t}\n\t\t\t\t\twhile (configuration);\n\t\t\t\t}\n\n\t\t\t\t// Ok\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsyntaxError (filename.c_str(), root, \"Wrong root node, should be NEL_LIGO_PRIMITIVE_CLASS\");\n\t\t\t}\n\t\t}\n\t\tcatch (const Exception &e)\n\t\t{\n\t\t\terrorMessage (\"File read error (%s):%s\", filename.c_str(), e.what ());\n\t\t}\n\t}\n\telse\n\t{\n\t\terrorMessage (\"Can't open the file %s for reading.\", filename.c_str());\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::reloadIndexFile(const std::string &indexFileName)\n{\n\tif (_IndexFileName.empty() && indexFileName.empty())\n\t{\n\t\tnlwarning(\"CLigoConfig::reloadIndexFile: no file name specified and index file not previously loaded, can't load anything\");\n\t\treturn false;\n\t}\n\n\tif (!_IndexFileName.empty() && !indexFileName.empty() && _IndexFileName != indexFileName)\n\t{\n\t\tnlwarning(\"CLigoConfig::reloadIndexFile: index file already loaded as '%s', can't load another file '%s'!\",\n\t\t\t_IndexFileName.c_str(),\n\t\t\tindexFileName.c_str());\n\t\treturn false;\n\t}\n\n\tif (_IndexFileName.empty())\n\t\t_IndexFileName = indexFileName;\n\n\t// load the configuration file\n\tCConfigFile cf;\n\tstring pathName = CPath::lookup(_IndexFileName, false);\n\n\tif (pathName.empty())\n\t{\n\t\tnlwarning(\"Can't find index file '%s' in search path, no file index available for alias\", indexFileName.c_str());\n\t\treturn false;\n\t}\n\tcf.load(pathName);\n\n\t// get the variable\n\tCConfigFile::CVar *files = cf.getVarPtr(\"Files\");\n\tif (files != NULL)\n\t{\n\t\tfor (uint i=0; i<files->size()/2; ++i)\n\t\t{\n\t\t\tstring fileName;\n\t\t\tuint32 index;\n\n\t\t\tfileName = files->asString(i*2);\n\t\t\tindex = files->asInt(i*2+1);\n\n\t\t\tif (isFileStaticAliasMapped(fileName))\n\t\t\t{\n\t\t\t\t// check that the mapping as not changed\n\t\t\t\tif (getFileStaticAliasMapping(fileName) != index)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"CLigoConfig::reloadIndexFile: the mapping for the file '%s' as changed from %u to %u in the config file, the change is ignored\",\n\t\t\t\t\t\tfileName.c_str(),\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\tgetFileStaticAliasMapping(fileName));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tregisterFileToStaticAliasTranslation(fileName, index);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n}\n\n// ***************************************************************************\n\nNLMISC::CRGBA CLigoConfig::getPrimitiveColor (const NLLIGO::IPrimitive &primitive)\n{\n\t// Get the class\n\tstring className;\n\tif (primitive.getPropertyByName (\"class\", className))\n\t{\n\t\t// Get the class\n\t\tstd::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);\n\t\tif (ite != _PrimitiveClasses.end ())\n\t\t{\n\t\t\treturn ite->second.Color;\n\t\t}\n\t}\n\treturn DEFAULT_PRIMITIVE_COLOR;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::isPrimitiveLinked (const NLLIGO::IPrimitive &primitive)\n{\n\t// Get the class\n\tstring className;\n\tif (primitive.getPropertyByName (\"class\", className))\n\t{\n\t\t// Get the class\n\t\tstd::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);\n\t\tif (ite != _PrimitiveClasses.end ())\n\t\t{\n\t\t\treturn ite->second.LinkBrothers;\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nconst NLLIGO::IPrimitive *CLigoConfig::getLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const\n{\n\t// Get the parent\n\tconst IPrimitive *parent = primitive.getParent ();\n\tif (parent)\n\t{\n\t\tuint childId;\n\t\tif (parent->getChildId (childId, &primitive))\n\t\t{\n\t\t\t// Test the next primitive\n\n\t\t\t// Get the primitive class\n\t\t\tstring className;\n\t\t\tif (primitive.getPropertyByName (\"class\", className))\n\t\t\t{\n\t\t\t\t// Get the class\n\t\t\t\tstd::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);\n\t\t\t\tif (ite != _PrimitiveClasses.end ())\n\t\t\t\t{\n\t\t\t\t\tif (ite->second.LinkBrothers)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Add the next child\n\t\t\t\t\t\tconst IPrimitive *brother;\n\t\t\t\t\t\tif (parent->getChild (brother, childId+1))\n\t\t\t\t\t\t\treturn brother;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nconst NLLIGO::IPrimitive *CLigoConfig::getPreviousLinkedPrimitive (const NLLIGO::IPrimitive &primitive) const\n{\n\t// Get the parent\n\tconst IPrimitive *parent = primitive.getParent ();\n\tif (parent)\n\t{\n\t\tuint childId;\n\t\tif (parent->getChildId (childId, &primitive))\n\t\t{\n\t\t\t// Test the previous primitive\n\t\t\tif (childId > 0)\n\t\t\t{\n\t\t\t\tconst IPrimitive *brother;\n\t\t\t\tif (parent->getChild (brother, childId-1) && brother)\n\t\t\t\t{\n\t\t\t\t\t// Get the primitive class\n\t\t\t\t\tstring className;\n\t\t\t\t\tif (brother->getPropertyByName (\"class\", className))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get the class\n\t\t\t\t\t\tstd::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);\n\t\t\t\t\t\tif (ite != _PrimitiveClasses.end ())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (ite->second.LinkBrothers)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Return the previous child\n\t\t\t\t\t\t\t\treturn brother;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::isPrimitiveDeletable (const NLLIGO::IPrimitive &primitive)\n{\n\t// If it is a static child, it can't be deleted.\n\tif (isStaticChild (primitive))\n\t\treturn false;\n\n\t// Get the class\n\tstring className;\n\tif (primitive.getPropertyByName (\"class\", className))\n\t{\n\t\t// Get the class\n\t\tstd::map<std::string, CPrimitiveClass>::iterator ite = _PrimitiveClasses.find (className);\n\t\tif (ite != _PrimitiveClasses.end ())\n\t\t{\n\t\t\treturn ite->second.Deletable;\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::canBeChild (const NLLIGO::IPrimitive &child, const NLLIGO::IPrimitive &parent)\n{\n\t// Get the child class\n\tstring childClassName;\n\tif (child.getPropertyByName (\"class\", childClassName))\n\t{\n\t\t// Get the parent class\n\t\tconst CPrimitiveClass *parentClass = getPrimitiveClass (parent);\n\t\tif (parentClass)\n\t\t{\n\t\t\t// Search for the child class\n\t\t\tuint i;\n\t\t\tfor (i=0; i<parentClass->DynamicChildren.size (); i++)\n\t\t\t{\n\t\t\t\t// The same ?\n\t\t\t\tif (parentClass->DynamicChildren[i].ClassName == childClassName)\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (i<parentClass->DynamicChildren.size ())\n\t\t\t\treturn true;\n\n\t\t\tfor (i=0; i<parentClass->GeneratedChildren.size (); i++)\n\t\t\t{\n\t\t\t\t// The same ?\n\t\t\t\tif (parentClass->GeneratedChildren[i].ClassName == childClassName)\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn (i<parentClass->GeneratedChildren.size ());\n\t\t}\n\t\telse\n\t\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Only if it is a root node or parent class doesn't exist\n\t\tstring parentClassName;\n\t\treturn ( (parent.getParent () == NULL) || (!parent.getPropertyByName (\"class\", parentClassName) ) );\n\t}\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::canBeRoot (const NLLIGO::IPrimitive &child)\n{\n\t// Get the child class\n\tstring childClassName;\n\tif (child.getPropertyByName (\"class\", childClassName))\n\t{\n\t\t// Get the parent class\n\t\tconst CPrimitiveClass *parentClass = getPrimitiveClass (\"root\");\n\t\tif (parentClass)\n\t\t{\n\t\t\t// Search for the child class\n\t\t\tuint i;\n\t\t\tfor (i=0; i<parentClass->DynamicChildren.size (); i++)\n\t\t\t{\n\t\t\t\t// The same ?\n\t\t\t\tif (parentClass->DynamicChildren[i].ClassName == childClassName)\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn (i<parentClass->DynamicChildren.size ());\n\t\t}\n\t\telse\n\t\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Root class doesn't exist\n\t\treturn ( !getPrimitiveClass (\"root\") );\n\t}\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::getPropertyString (std::string &result, const char *filename, xmlNodePtr xmlNode, const char *propName)\n{\n\t// Call the CIXml version\n\tif (!CIXml::getPropertyString (result, xmlNode, propName))\n\t{\n\t\t// Output a formated error\n\t\tsyntaxError (filename, xmlNode, \"Missing XML node property (%s)\", propName);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid CLigoConfig::syntaxError (const char *filename, xmlNodePtr xmlNode, const char *format, ...)\n{\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\terrorMessage (\"(%s), node (%s), line (%p) :\\n%s\", filename, xmlNode->name, xmlNode->content, buffer);\n}\n\n// ***************************************************************************\n\nvoid CLigoConfig::errorMessage (const char *format, ... )\n{\n\t// Make a buffer string\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\tnlwarning (buffer);\n}\n\n// ***************************************************************************\n\nconst std::vector<std::string> &CLigoConfig::getContextString () const\n{\n\treturn _Contexts;\n}\n\n// ***************************************************************************\n\nconst CPrimitiveClass *CLigoConfig::getPrimitiveClass (const IPrimitive &primitive) const\n{\n\tconst CPrimitiveClass *primClass = NULL;\n\n\t// Get property class\n\tstring className;\n\tif (primitive.getPropertyByName (\"class\", className))\n\t{\n\t\tstd::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);\n\t\tif (ite != _PrimitiveClasses.end ())\n\t\t{\n\t\t\tprimClass = &(ite->second);\n\t\t}\n\t}\n\n\t// Not found ?\n\tif (!primClass)\n\t{\n\t\t// Root ?\n\t\tif (!primitive.getParent ())\n\t\t{\n\t\t\tstd::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (\"root\");\n\t\t\tif (ite != _PrimitiveClasses.end ())\n\t\t\t{\n\t\t\t\tprimClass = &(ite->second);\n\t\t\t}\n\t\t}\n\t}\n\treturn primClass;\n}\n\n// ***************************************************************************\n\nconst CPrimitiveClass *CLigoConfig::getPrimitiveClass (const char *className) const\n{\n\tstd::map<std::string, CPrimitiveClass>::const_iterator ite = _PrimitiveClasses.find (className);\n\tif (ite != _PrimitiveClasses.end ())\n\t{\n\t\treturn &(ite->second);\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid CLigoConfig::resetPrimitiveConfiguration ()\n{\n\t_PrimitiveConfigurations.clear ();\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::isStaticChild (const NLLIGO::IPrimitive &primitive)\n{\n\t// Has a parent ?\n\tconst IPrimitive *parent = primitive.getParent ();\n\tif (parent)\n\t{\n\t\t// Get the classes\n\t\tconst CPrimitiveClass *parentClass = getPrimitiveClass (*parent);\n\t\tstring className;\n\t\tstring name;\n\t\tif (parentClass && primitive.getPropertyByName (\"class\", className) && primitive.getPropertyByName (\"name\", name))\n\t\t{\n\t\t\t// Does it belong to the static children ?\n\t\t\tuint i;\n\t\t\tfor (i=0; i<parentClass->StaticChildren.size(); i++)\n\t\t\t{\n\t\t\t\tif (parentClass->StaticChildren[i].Name == name &&\n\t\t\t\t\tparentClass->StaticChildren[i].ClassName == className)\n\t\t\t\t{\n\t\t\t\t\t// Found\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\n/// Get the dynamic bit size for alias\nuint32 CLigoConfig::getDynamicAliasSize() const\n{\n\treturn _DynamicAliasBitCount;\n}\n\n// ***************************************************************************\n/// Get the dynamic bit mask for alias\nuint32 CLigoConfig::getDynamicAliasMask() const\n{\n\t// this 'strange' test because VC fail to generate a correct shift if\n\t// _DynamicAliasBitCount is 32 bits.\n\t// The generated code lead to no shift at all and return 0 instead of 0xffffffff\n\tif (_DynamicAliasBitCount >= 32)\n\t\treturn 0xffffffff;\n\telse\n\t\treturn (1U<<_DynamicAliasBitCount)-1;\n}\n\n// ***************************************************************************\n/// Get the static bit size for alias\nuint32 CLigoConfig::getStaticAliasSize() const\n{\n\treturn 32-_DynamicAliasBitCount;\n}\n\n// ***************************************************************************\n/// Get the static bit mask for alias\nuint32 CLigoConfig::getStaticAliasMask() const\n{\n\t// the opposite of the dynamic mask\n\treturn ~getDynamicAliasMask();\n}\n\n// ***************************************************************************\n/// Build an alias given a static and dynamic part\nuint32 CLigoConfig::buildAlias(uint32 staticPart, uint32 dynamicPart, bool warnIfOverload) const\n{\n\tif (warnIfOverload)\n\t{\n\t\tif (staticPart != (staticPart & (getStaticAliasMask()>>getDynamicAliasSize())))\n\t\t{\n\t\t\tnlwarning(\"CLigoConfig::buildAlias: staticPart 0x%x is outside the mask 0x%x\",\n\t\t\t\tstaticPart,\n\t\t\t\tgetStaticAliasMask()>>getDynamicAliasSize());\n\t\t}\n\t\tif (dynamicPart != (dynamicPart & getDynamicAliasMask()))\n\t\t{\n\t\t\tnlwarning(\"CLigoConfig::buildAlias: dynamicPart 0x%x is outside the mask 0x%x\",\n\t\t\t\tdynamicPart,\n\t\t\t\tgetDynamicAliasMask());\n\t\t}\n\t}\n\n\treturn dynamicPart | (staticPart << _DynamicAliasBitCount);\n}\n\n// ***************************************************************************\n\nvoid CLigoConfig::registerFileToStaticAliasTranslation(const std::string &fileName, uint32 staticPart)\n{\n\t// check the existing mapping\n\tstd::map<std::string, uint32>::iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tif (first->second == staticPart)\n\t\t{\n\t\t\tnlassertex(false, (\"While registering static alias %u to file '%s', the alias is already assigned to file '%s'\",\n\t\t\t\tstaticPart,\n\t\t\t\tfileName.c_str(),\n\t\t\t\tfirst->first.c_str()));\n\t\t}\n\t}\n\tif ((staticPart<<getDynamicAliasSize()) != ((staticPart<<getDynamicAliasSize()) & getStaticAliasMask()))\n\t{\n\t\tnlwarning(\"CLigoConfig::registerStaticAliasTranslation: staticPart 0x%x(%u) is outside the mask 0x%x, the staticPart will be clipped to 0x%x(%u)\",\n\t\t\tstaticPart,\n\t\t\tstaticPart,\n\t\t\tgetStaticAliasMask(),\n\t\t\tstaticPart & getStaticAliasMask(),\n\t\t\tstaticPart & getStaticAliasMask());\n\n\t\tstaticPart = (staticPart & getStaticAliasMask());\n\t}\n\n\n\t_StaticAliasFileMapping[fileName] = staticPart;\n}\n\nconst std::string &CLigoConfig::getFileNameForStaticAlias(uint32 staticAlias) const\n{\n\tstd::map<std::string, uint32>::const_iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());\n\n\tfor (; first != last; ++first)\n\t{\n\t\tif (first->second == staticAlias)\n\t\t\treturn first->first;\n\t}\n\tstatic string emptyString;\n\n\treturn emptyString;\n}\n\n\n// ***************************************************************************\n\nuint32 CLigoConfig::getFileStaticAliasMapping(const std::string &fileName) const\n{\n\tstd::map<std::string, uint32>::const_iterator it(_StaticAliasFileMapping.find(fileName));\n\n\tif (it != _StaticAliasFileMapping.end())\n\t{\n\t\treturn it->second;\n\t}\n\telse\n\t\t// no mapping defined.\n\t\treturn 0;\n}\n\n// ***************************************************************************\n\nbool CLigoConfig::isFileStaticAliasMapped(const std::string &fileName) const\n{\n\tstd::map<std::string, uint32>::const_iterator it(_StaticAliasFileMapping.find(fileName));\n\n\tif (it != _StaticAliasFileMapping.end())\n\t{\n\t\treturn true;\n\t}\n\telse\n\t\t// no mapping defined.\n\t\treturn false;\n}\n\n\nstd::string CLigoConfig::aliasToString(uint32 fullAlias)\n{\n\tuint32 staticPart;\n\tuint32 dynPart;\n\n\tstaticPart = (fullAlias & getStaticAliasMask())>>getDynamicAliasSize();\n\tdynPart = fullAlias & getDynamicAliasMask();\n\n\treturn toString(\"(A:%u:%u)\", staticPart, dynPart);\n\n}\n\nuint32 CLigoConfig::aliasFromString(std::string fullAlias)\n{\n\tuint32 staticPart;\n\tuint32 dynPart;\n\tsscanf(fullAlias.c_str(), \"(A:%u:%u)\", &staticPart, &dynPart);\n\n\treturn ((staticPart<<getDynamicAliasSize()) & getStaticAliasMask()) | (dynPart & getDynamicAliasMask());\n\n}\n\n\nvoid CLigoConfig::updateDynamicAliasBitCount(uint32 newDynamicAliasBitCount)\n{\n\tsint32 diff = _DynamicAliasBitCount - newDynamicAliasBitCount;\n\n\tif (diff <= 0)\n\t{\n\t\tnlwarning(\"New bit count must be less than previous\");\n\t\tnlassert(0);\n\n\t}\n\n\tstd::map<std::string, uint32>::iterator first(_StaticAliasFileMapping.begin()), last(_StaticAliasFileMapping.end());\n\tfor ( ; first != last; ++first)\n\t{\n\t\tfirst->second = first->second  << diff;\n\t}\n\t_DynamicAliasBitCount = newDynamicAliasBitCount;\n}\n\n\n}\n\n\n"
  },
  {
    "path": "code/nel/src/ligo/ligo_error.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"ligo_error.h\"\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n\nCLigoError::CLigoError()\n{\n\tclear ();\n}\n\n// ***************************************************************************\n\nvoid CLigoError::pushVertexError (TError code, uint id, uint edge)\n{\n\t// Check if this vertex exist in the error list\n\tuint vertex;\n\tfor (vertex=0; vertex<_VertexError.size(); vertex++)\n\t{\n\t\tif (_VertexError[vertex].Id == id)\n\t\t{\n\t\t\t_VertexError[vertex] = CVertex (code, id, edge);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Not found ?\n\tif (vertex == _VertexError.size())\n\t{\n\t\t// Add a vertex error\n\t\t_VertexError.push_back (CVertex (code, id, edge));\n\t}\n}\n\n// ***************************************************************************\n\nuint CLigoError::numVertexError () const\n{\n\treturn (uint)_VertexError.size ();\n}\n\n// ***************************************************************************\n\nCLigoError::TError CLigoError::getVertexError (uint error, uint &id, uint &edge) const\n{\n\tconst CVertex &vertex = _VertexError[error];\n\tid = vertex.Id;\n\tedge = vertex.Edge;\n\treturn vertex.Code;\n}\n\n// ***************************************************************************\n\nvoid CLigoError::clear ()\n{\n\tMainError = NoError;\n\t_VertexError.clear ();\n}\n\n// ***************************************************************************\n\nconst char* CLigoError::_StringError[CLigoError::ErrorCount]=\n{\n\t\"No error\",\t\t\t\t\t\t// NoError\n\t\"No vertex in the edge list\",\t// NoEdgeVertices\n\t\"Opened edges detected\",\t\t// OpenedEdge\n\t\"Multiple edge on the boundary\",// MultipleEdge\n\t\"Vertex list invalid. One vertex should be a corner\",\t// VertexList\n\t\"The vertex has not been inserted in the edge list\",\t// NotInserted\n\t\"The vertex has been inserted in the edge list\",\t\t// Inserted\n\t\"Flat zone, all vertices are in the same corner\",\t\t// FlatZone\n\t\"The zone must have 4 edges to define a material\",\t// MustHave4Edges\n\t\"A edge of the zone is not symetrical\",\t\t// NotSymetrical\n\t\"Not the same number of vertex\",\t// NotSameVerticesNumber\n\t\"Some vertices are not the same\",\t// NotSameVertex\n\t\"No corner found\",\t\t\t\t\t// NoCornerFound\n\t\"A edge has two times the same corner\",\t// TwoCornerVertices\n\t\"A corner is missing in this edge\", // CornerIsMissing\n\t\"A boundary vertex is used by multiple edges\", // VertexAlreadyUsed\n\t\"Unknown error\",\t\t\t\t\t\t// UnknownError\n};\n\n// ***************************************************************************\n\nconst char* CLigoError::getStringError (TError errorCode)\n{\n\tif (errorCode<=ErrorCount)\n\t{\n\t\treturn _StringError[errorCode];\n\t}\n\telse\n\t{\n\t\treturn _StringError[UnknownError];\n\t}\n}\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/ligo/ligo_error.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_LIGO_ERROR_H\n#define NL_LIGO_ERROR_H\n\n#include \"nel/misc/types_nl.h\"\n\n#include <vector>\n\nnamespace NLLIGO\n{\n\n/**\n * Error handling\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CLigoError\n{\npublic:\n\tenum TError\n\t{\n\t\t/// No error\n\t\tNoError\t\t\t\t=0,\n\n\t\t/// No vertices in the edge list\n\t\tNoEdgeVertices,\n\n\t\t/// Opened edges detected\n\t\tOpenedEdge,\n\n\t\t/// Multiple edge on the boundary\n\t\tMultipleEdge,\n\n\t\t/// Vertex list invalid. One vertex should be a corner.\n\t\tVertexList,\n\n\t\t/// The vertex has not been inserted in the edge list\n\t\tNotInserted,\n\n\t\t/// The vertex has been inserted in the edge list\n\t\tInserted,\n\n\t\t/// Flat zone, all vertex are in the same corner\n\t\tFlatZone,\n\n\t\t/// 4 edge to define a material\n\t\tMustHave4Edges,\n\n\t\t/// 4 edge to define a material\n\t\tNotSymetrical,\n\n\t\t/// Not same number of vertices\n\t\tNotSameVerticesNumber,\n\n\t\t/// Vertex is not the same\n\t\tNotSameVertex,\n\n\t\t/// No corner found\n\t\tNoCornerFound,\n\n\t\t/// Two corner vertices\n\t\tTwoCornerVertices,\n\n\t\t/// Corner is missing\n\t\tCornerIsMissing,\n\n\t\t/// Boundary vertex used by multiple edge\n\t\tVertexAlreadyUsed,\n\n\t\t/// Unknown error\n\t\tUnknownError,\n\n\t\t/// Error count\n\t\tErrorCount\n\t};\n\n\t/// Constructor\n\tCLigoError();\n\n\t/// Clear the container\n\tvoid clear ();\n\n\t/// Push a vertex error code\n\tvoid pushVertexError (TError code, uint id, uint edge=0xffffffff);\n\n\t/// Get num vertex error\n\tuint numVertexError () const;\n\n\t/// Get a vertex error\n\tTError getVertexError (uint error, uint &id, uint &edge) const;\n\n\t/// Get an error string\n\tstatic const char* getStringError (TError errorCode);\n\npublic:\n\n\t/// Main error code\n\tTError\t\tMainError;\n\nprivate:\n\n\t/// Vertex error\n\tclass CVertex\n\t{\n\tpublic:\n\n\t\t/// Constructor\n\t\tCVertex (TError code, uint id, uint edge)\n\t\t{\n\t\t\tCode = code;\n\t\t\tId = id;\n\t\t\tEdge = edge;\n\t\t}\n\tpublic:\n\n\t\t/// Error code on this vertex\n\t\tTError\tCode;\n\n\t\t/// Vertex id\n\t\tuint\tId;\n\n\t\t/// Edge id (no always used)\n\t\tuint\tEdge;\n\t};\n\n\t/// Vertex error\n\tstd::vector<CVertex>\t\t_VertexError;\n\n\t/// Error string\n\tstatic const char* _StringError[];\n};\n\n}\n\n#endif // NL_LIGO_ERROR_H\n\n/* End of ligo_error.h */\n"
  },
  {
    "path": "code/nel/src/ligo/ligo_material.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"ligo_material.h\"\n\n// Ligo include\n#include \"ligo_error.h\"\n\n//using namespace NL3D;\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n\nbool CMaterial::build (const CZoneTemplate &tplt, const CLigoConfig &config, CLigoError &errors)\n{\n\t// Clear errors\n\terrors.clear ();\n\n\t// Edge vector\n\tconst std::vector<CZoneEdge> &edges = tplt.getEdges ();\n\n\t// This template should have 4 edges\n\tif (edges.size() != 4)\n\t{\n\t\terrors.MainError = CLigoError::MustHave4Edges;\n\t\treturn false;\n\t}\n\n\t// The 1st edge must be symetrical\n\tif (!edges[0].isSymetrical (config, errors))\n\t\treturn false;\n\n\t// Error code\n\tbool ok = true;\n\n\t// The others must be the same edges\n\tuint edge;\n\tfor (edge=1; edge<edges.size(); edge++)\n\t{\n\t\t// The same edge ?\n\t\tif (!edges[0].isTheSame (edges[edge], config, errors))\n\t\t{\n\t\t\t// Error\n\t\t\tok = false;\n\t\t}\n\t}\n\n\t// Build ?\n\tif (ok)\n\t{\n\t\t// Ok, build the material\n\t\t_ZoneEdge = edges[0];\n\t}\n\n\t// Return error code\n\treturn ok;\n}\n\n// ***************************************************************************\n\nvoid CMaterial::serial (NLMISC::IStream &s)\n{\n\t// Serial the main node\n\ts.xmlPush (\"LIGO_MATERIAL\");\n\n\t\t// Serial the header\n\t\ts.serialCheck (NELID(\"TMOL\"));\n\n\t\t// Serial the version\n\t\t/*sint ver =*/ s.serialVersion (0);\n\n\t\t// Serial the zoneedge\n\t\ts.xmlSerial (_ZoneEdge, \"ZONE_EDGE\");\n\n\t// Close the main node\n\ts.xmlPop ();\n}\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/ligo/ligo_material.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_MATERIAL_LIGO_H\n#define NL_MATERIAL_LIGO_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"zone_template.h\"\n\n// NeL include\n//#include \"3d/zone.h\"\n\nnamespace NLLIGO\n{\n\nclass CLigoError;\nclass CLigoConfig;\n\n/**\n * A ligoscape material\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CMaterial\n{\npublic:\n\n\t/// Build method\n\tbool build (const CZoneTemplate &tplt, const CLigoConfig &config, CLigoError &errors);\n\n\t/// Return the material edge\n\tconst CZoneEdge& getEdge () const { return _ZoneEdge; }\n\n\t/// Serial method\n\tvoid serial (NLMISC::IStream &s);\n\nprivate:\n\n\t// The zone template for this material\n\tCZoneEdge\t\t_ZoneEdge;\n};\n\n}\n\n#endif // NL_MATERIAL_LIGO_H\n\n/* End of material.h */\n"
  },
  {
    "path": "code/nel/src/ligo/nel-ligo.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: nel-ligo\nVersion: @NL_VERSION@\nDescription: NeL @NL_VERSION@\nRequires:\nLibs: -L${libdir}\nLibs.private: @LIBS@ -lc\nCflags: -I${includedir}\n"
  },
  {
    "path": "code/nel/src/ligo/primitive.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/ligo/primitive.h\"\n#include \"nel/ligo/ligo_config.h\"\n#include \"nel/ligo/primitive_class.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nconst uint32 NLLIGO_PRIMITIVE_VERSION = 1;\n\nnamespace NLLIGO\n{\n\nCPrimitiveContext\t*CPrimitiveContext::_Instance = NULL;\n\n\n// ***************************************************************************\n// XML helpers\n// ***************************************************************************\n\nvoid Error (const char *filename, const char *format, ...)\n{\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\tnlwarning (\"In File (%s) %s\", filename, buffer);\n}\n\n// ***************************************************************************\n\nvoid XMLError (xmlNodePtr xmlNode, const char *filename, const char *format, ... )\n{\n\tva_list args;\n\tva_start( args, format );\n\tchar buffer[1024];\n\tvsnprintf( buffer, 1024, format, args );\n\tva_end( args );\n\n\tError (filename, \"node (%s), line (%p) : %s\", xmlNode->name, xmlNode->content, buffer);\n}\n\n\n// ***************************************************************************\n\nxmlNodePtr GetFirstChildNode (xmlNodePtr xmlNode, const char *filename, const char *childName)\n{\n\t// Call the CIXml version\n\txmlNodePtr result = CIXml::getFirstChildNode (xmlNode, childName);\n\tif (result) return result;\n\n\t// Output a formated error\n\tXMLError (xmlNode, filename, \"Can't find XML node named (%s)\", childName);\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nbool GetPropertyString (string &result, const char *filename, xmlNodePtr xmlNode, const char *propName)\n{\n\t// Call the CIXml version\n\tif (!CIXml::getPropertyString (result, xmlNode, propName))\n\t{\n\t\t// Output a formated error\n\t\tXMLError (xmlNode, filename, \"Can't find XML node property (%s)\", propName);\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool ReadInt (const char *propName, int &result, const char *filename, xmlNodePtr xmlNode)\n{\n\tstring value;\n\tif (GetPropertyString (value, filename, xmlNode, propName))\n\t{\n\t\tresult = atoi (value.c_str ());\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid WriteInt (const char *propName, int value, xmlNodePtr xmlNode)\n{\n\t// Set properties\n\txmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));\n}\n\n// ***************************************************************************\n\nbool ReadUInt (const char *propName, uint &result, const char *filename, xmlNodePtr xmlNode)\n{\n\tstring value;\n\tif (GetPropertyString (value, filename, xmlNode, propName))\n\t{\n\t\tresult = strtoul (value.c_str (), NULL, 10);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid WriteUInt (const char *propName, uint value, xmlNodePtr xmlNode)\n{\n\t// Set properties\n\txmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));\n}\n\n// ***************************************************************************\n\nbool ReadFloat (const char *propName, float &result, const char *filename, xmlNodePtr xmlNode)\n{\n\tstring value;\n\tif (GetPropertyString (value, filename, xmlNode, propName))\n\t{\n\t\tNLMISC::fromString(value, result);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid WriteFloat (const char *propName, float value, xmlNodePtr xmlNode)\n{\n\t// Set properties\n\txmlSetProp (xmlNode, (const xmlChar*)propName, (const xmlChar*)(toString (value).c_str ()));\n}\n\n// ***************************************************************************\n\nbool ReadVector (CPrimVector &point, const char *filename, xmlNodePtr xmlNode)\n{\n\tCPrimVector pos;\n\tif (ReadFloat (\"X\", pos.x, filename, xmlNode))\n\t{\n\t\tif (ReadFloat (\"Y\", pos.y, filename, xmlNode))\n\t\t{\n\t\t\tif (ReadFloat (\"Z\", pos.z, filename, xmlNode))\n\t\t\t{\n\t\t\t\tpos.Selected = false;\n\t\t\t\tstring result;\n\t\t\t\tif (CIXml::getPropertyString (result, xmlNode, \"SELECTED\"))\n\t\t\t\t{\n\t\t\t\t\tif (result == \"true\")\n\t\t\t\t\t\tpos.Selected = true;\n\t\t\t\t}\n\t\t\t\tpoint = pos;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid WriteVector (const CPrimVector &point, xmlNodePtr xmlNode)\n{\n\t// Set properties\n\txmlSetProp (xmlNode, (const xmlChar*)\"X\", (const xmlChar*)(toString (point.x).c_str ()));\n\txmlSetProp (xmlNode, (const xmlChar*)\"Y\", (const xmlChar*)(toString (point.y).c_str ()));\n\txmlSetProp (xmlNode, (const xmlChar*)\"Z\", (const xmlChar*)(toString (point.z).c_str ()));\n\tif (point.Selected)\n\t\txmlSetProp (xmlNode, (const xmlChar*)\"SELECTED\", (const xmlChar*)\"true\");\n}\n\n\n// ***************************************************************************\n\nbool GetNodeString (string &result, const char *filename, xmlNodePtr xmlNode, const char *nodeName)\n{\n\t// Look for the node\n\txmlNodePtr node = CIXml::getFirstChildNode (xmlNode, nodeName);\n\tif (!node)\n\t{\n\t\tXMLError (xmlNode, filename, \"Can't find XML node named (%s)\", nodeName);\n\t\treturn false;\n\t}\n\n\t// Get the node string\n\tif (!CIXml::getContentString (result, node))\n\t{\n\t\tXMLError (xmlNode, filename, \"Can't find any text in the node named (%s)\", nodeName);\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool GetContentString (string &result, const char *filename, xmlNodePtr xmlNode)\n{\n\t// Get the node string\n\tif (!CIXml::getContentString (result, xmlNode))\n\t{\n\t\tXMLError (xmlNode, filename, \"Can't find any text in the node\");\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// ***************************************************************************\n// CPropertyString\n// ***************************************************************************\n\nCPropertyString::CPropertyString (const char *str)\n{\n\tString = str;\n}\n\nCPropertyString::CPropertyString (const std::string &str)\n{\n\tString = str;\n}\n\n// ***************************************************************************\n\nCPropertyString::CPropertyString (const char *str, bool _default)\n{\n\tString = str;\n\tDefault = _default;\n}\n\n// ***************************************************************************\n// CPropertyStringArray\n// ***************************************************************************\n\nCPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray)\n{\n\tStringArray = stringArray;\n}\n\n// ***************************************************************************\n\nCPropertyStringArray::CPropertyStringArray (const std::vector<std::string> &stringArray, bool _default)\n{\n\tStringArray = stringArray;\n\tDefault = _default;\n}\n\n// ***************************************************************************\n\nvoid CPrimPoint::serial (NLMISC::IStream &f)\n{\n\t// serial base info\n\tIPrimitive::serial(f);\n\tf.serial(Point);\n\tf.serial(Angle);\n}\n\n// ***************************************************************************\nvoid CPrimPath::serial (NLMISC::IStream &f)\n{\n\tIPrimitive::serial(f);\n\tf.serialCont(VPoints);\n}\n\n// ***************************************************************************\n\nbool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points)\n{\n\tuint32 i;\n\tCVector vMin, vMax;\n\n\t// Point or line can't contains !\n\tif (points.size() < 3)\n\t\treturn false;\n\n\t// Get the bounding rectangle of the zone\n\tvMax = vMin = points[0];\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tif (vMin.x > points[i].x)\n\t\t\tvMin.x = points[i].x;\n\t\tif (vMin.y > points[i].y)\n\t\t\tvMin.y = points[i].y;\n\n\t\tif (vMax.x < points[i].x)\n\t\t\tvMax.x = points[i].x;\n\t\tif (vMax.y < points[i].y)\n\t\t\tvMax.y = points[i].y;\n\t}\n\n\tif ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))\n\t\treturn false;\n\n\tuint32 nNbIntersection = 0;\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tconst CVector &p1 = points[i];\n\t\tconst CVector &p2 = points[(i+1)%points.size()];\n\n\t\tif (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))\n\t\t\tcontinue;\n\t\tif (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))\n\t\t\tcontinue;\n\t\tfloat xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));\n\t\tif (xinter > v.x)\n\t\t\t++nNbIntersection;\n\t}\n\tif ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\n// ***************************************************************************\n\nbool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<NLMISC::CVector> &points)\n{\n\tuint32 i;\n\tCVector vMin, vMax;\n\n\t// Point or line can't contains !\n\tif (points.size() < 3)\n\t\treturn false;\n\n\t// Get the bounding rectangle of the zone\n\tvMax = vMin = points[0];\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tif (vMin.x > points[i].x)\n\t\t\tvMin.x = points[i].x;\n\t\tif (vMin.y > points[i].y)\n\t\t\tvMin.y = points[i].y;\n\n\t\tif (vMax.x < points[i].x)\n\t\t\tvMax.x = points[i].x;\n\t\tif (vMax.y < points[i].y)\n\t\t\tvMax.y = points[i].y;\n\t}\n\n\tif ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))\n\t\treturn false;\n\n\tuint32 nNbIntersection = 0;\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tconst CVector &p1 = points[i];\n\t\tconst CVector &p2 = points[(i+1)%points.size()];\n\n\t\tif (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))\n\t\t\tcontinue;\n\t\tif (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))\n\t\t\tcontinue;\n\t\tfloat xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));\n\t\tif (xinter > v.x)\n\t\t\t++nNbIntersection;\n\t}\n\tif ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\n// ***************************************************************************\n// CPrimNode\n// ***************************************************************************\n\nbool CPrimNode::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\treturn IPrimitive::read (xmlNode, filename, version, config);\n}\n\n// ***************************************************************************\n\nuint CPrimNode::getNumVector () const\n{\n\treturn 0;\n}\n\n// ***************************************************************************\n\nconst CPrimVector *CPrimNode::getPrimVector () const\n{\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nCPrimVector\t*CPrimNode::getPrimVector ()\n{\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nNLLIGO::IPrimitive *CPrimNode::copy () const\n{\n\treturn new CPrimNode (*this);\n}\n\n\n// ***************************************************************************\n// CPrimNode\n// ***************************************************************************\n\n/*void CPrimNode::operator= (const CPrimNode &node)\n{\n\t// Copy the IPrimitive\n\tIPrimitive::operator= (node);\n}\n\n// ***************************************************************************\n\nvoid CPrimPoint::operator= (const CPrimPoint &node)\n{\n\t// Copy the IPrimitive\n\tIPrimitive::operator= (node);\n}\n\n// ***************************************************************************\n\nvoid CPrimPath::operator= (const CPrimPath &node)\n{\n\t// Copy the IPrimitive\n}\n\n// ***************************************************************************\n\nvoid CPrimZone::operator= (const CPrimZone &node)\n{\n\t// Copy the IPrimitive\n\tIPrimitive::operator= (node);\n}\n*/\n\n// ***************************************************************************\n\nuint CPrimPoint::getNumVector () const\n{\n\treturn 1;\n}\n\n// ***************************************************************************\n\nconst CPrimVector *CPrimPoint::getPrimVector () const\n{\n\treturn &Point;\n}\n\n// ***************************************************************************\n\nCPrimVector\t*CPrimPoint::getPrimVector ()\n{\n\treturn &Point;\n}\n\n// ***************************************************************************\n\nNLLIGO::IPrimitive *CPrimPoint::copy () const\n{\n\treturn new CPrimPoint (*this);\n}\n\n// ***************************************************************************\n\nbool CPrimPoint::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\t// Read points\n\txmlNodePtr ptNode = GetFirstChildNode (xmlNode, filename, \"PT\");\n\tif (ptNode)\n\t{\n\t\t// Read a vector\n\t\tif (!ReadVector (Point, filename, ptNode))\n\t\t\treturn false;\n\n\t\tptNode = CIXml::getFirstChildNode (xmlNode, \"ANGLE\");\n\t\tif (ptNode)\n\t\t{\n\t\t\t// Read a float\n\t\t\tif (!ReadFloat (\"VALUE\", Angle, filename, ptNode))\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\tAngle = 0;\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\n\treturn IPrimitive::read (xmlNode, filename, version, config);\n}\n\n// ***************************************************************************\n\nvoid CPrimPoint::write (xmlNodePtr xmlNode, const char *filename) const\n{\n\t// Save the point\n\txmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"PT\", NULL);\n\tWriteVector (Point, ptNode);\n\n\t// Save the angle\n\tif (Angle != 0)\n\t{\n\t\txmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"ANGLE\", NULL);\n\t\tWriteFloat (\"VALUE\", Angle, ptNode);\n\t}\n\n\tIPrimitive::write (xmlNode, filename);\n}\n\n// ***************************************************************************\n// CPrimPath\n// ***************************************************************************\n\nuint CPrimPath::getNumVector () const\n{\n\treturn (uint)VPoints.size ();\n}\n\n// ***************************************************************************\n\nconst CPrimVector *CPrimPath::getPrimVector () const\n{\n\tif (VPoints.empty())\n\t\treturn NULL;\n\treturn &(VPoints[0]);\n}\n\n// ***************************************************************************\n\nNLLIGO::IPrimitive *CPrimPath::copy () const\n{\n\treturn new CPrimPath (*this);\n}\n\n// ***************************************************************************\n\nCPrimVector\t*CPrimPath::getPrimVector ()\n{\n\tif (VPoints.empty())\n\t\treturn NULL;\n\treturn &(VPoints[0]);\n}\n\n// ***************************************************************************\n\nbool CPrimPath::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\t// Read points\n\tVPoints.clear ();\n\tVPoints.reserve (CIXml::countChildren (xmlNode, \"PT\"));\n\txmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, \"PT\");\n\tif (ptNode)\n\t{\n\t\tdo\n\t\t{\n\t\t\t// Read a vector\n\t\t\tVPoints.push_back (CPrimVector ());\n\t\t\tif (!ReadVector (VPoints.back (), filename, ptNode))\n\t\t\t\treturn false;\n\n\t\t\tptNode = CIXml::getNextChildNode (ptNode, \"PT\");\n\t\t}\n\t\twhile (ptNode);\n\t}\n\n\treturn IPrimitive::read (xmlNode, filename, version, config);\n}\n\n// ***************************************************************************\n\nvoid CPrimPath::write (xmlNodePtr xmlNode, const char *filename) const\n{\n\t// Save the points\n\tfor (uint i=0; i<VPoints.size (); i++)\n\t{\n\t\txmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"PT\", NULL);\n\t\tWriteVector (VPoints[i], ptNode);\n\t}\n\n\tIPrimitive::write (xmlNode, filename);\n}\n\n// ***************************************************************************\n// CPrimZone\n// ***************************************************************************\n\nuint CPrimZone::getNumVector () const\n{\n\treturn (uint)VPoints.size ();\n}\n\n// ***************************************************************************\n\nconst CPrimVector *CPrimZone::getPrimVector () const\n{\n\tif (VPoints.empty())\n\t\treturn NULL;\n\treturn &(VPoints[0]);\n}\n\n// ***************************************************************************\n\nNLLIGO::IPrimitive *CPrimZone::copy () const\n{\n\treturn new CPrimZone (*this);\n}\n\n// ***************************************************************************\n\nCPrimVector\t*CPrimZone::getPrimVector ()\n{\n\tif(VPoints.empty()) return 0;\n\treturn &(VPoints[0]);\n}\n\n// ***************************************************************************\n\nbool CPrimZone::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\t// Read points\n\tVPoints.clear ();\n\tVPoints.reserve (CIXml::countChildren (xmlNode, \"PT\"));\n\txmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, \"PT\");\n\tif (ptNode)\n\t{\n\t\tdo\n\t\t{\n\t\t\t// Read a vector\n\t\t\tVPoints.push_back (CPrimVector ());\n\t\t\tif (!ReadVector (VPoints.back (), filename, ptNode))\n\t\t\t\treturn false;\n\n\t\t\tptNode = CIXml::getNextChildNode (ptNode, \"PT\");\n\t\t}\n\t\twhile (ptNode);\n\t}\n\n\treturn IPrimitive::read (xmlNode, filename, version, config);\n}\n\n// ***************************************************************************\n\nvoid CPrimZone::write (xmlNodePtr xmlNode, const char *filename) const\n{\n\t// Save the points\n\tfor (uint i=0; i<VPoints.size (); i++)\n\t{\n\t\txmlNodePtr ptNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"PT\", NULL);\n\t\tWriteVector (VPoints[i], ptNode);\n\t}\n\n\tIPrimitive::write (xmlNode, filename);\n}\n\n// ***************************************************************************\n\nbool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CPrimVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)\n{\n\tH_AUTO(NLLIGO_Contains1)\n\tuint32 i;\n\tCVector vMin, vMax;\n\tfloat nearest = FLT_MAX;\n\tCVector pos;\n\n\t// Point or line can't contains !\n\tif (points.size() < 3 || isPath)\n\t{\n\t\t// only compute the distance.\n\t\tif (points.size() == 1)\n\t\t{\n\t\t\tdistance = (points[0] - v).norm();\n\t\t\tnearPos = points[0];\n\t\t}\n\t\telse if (points.size() == 2)\n\t\t{\n\t\t\tdistance = getSegmentDist(v, points[0], points[1], nearPos);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// compute nearest segment\n\t\t\tfor (i = 0; i < points.size()-1; ++i)\n\t\t\t{\n\t\t\t\tconst CVector &p1 = points[i];\n\t\t\t\tconst CVector &p2 = points[i+1];\n\n\t\t\t\tfloat dist = getSegmentDist(v, p1, p2, pos);\n\t\t\t\tif( dist < nearest)\n\t\t\t\t{\n\t\t\t\t\tnearest = dist;\n\t\t\t\t\tnearPos = pos;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdistance = nearest;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// Get the bounding rectangle of the zone\n\tvMax = vMin = points[0];\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tvMin.x = min(vMin.x, points[i].x);\n\t\tvMin.y = min(vMin.y, points[i].y);\n\t\tvMax.x = max(vMax.x, points[i].x);\n\t\tvMax.y = max(vMax.y, points[i].y);\n\t}\n\n\tif ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))\n\t{\n\t\t// find the nearest distance of all segment\n\t\tfor (uint i=0; i<points.size(); ++i)\n\t\t{\n\t\t\tfloat dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);\n\n\t\t\tif (dist < nearest)\n\t\t\t{\n\t\t\t\tnearest = dist;\n\t\t\t\tnearPos = pos;\n\t\t\t}\n\t\t}\n\t\tdistance = nearest;\n\t\treturn false;\n\t}\n\n\tuint32 nNbIntersection = 0;\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tconst CVector &p1 = points[i];\n\t\tconst CVector &p2 = points[(i+1)%points.size()];\n\n\t\tfloat dist = getSegmentDist(v, p1, p2, pos);\n\t\tif( dist < nearest)\n\t\t{\n\t\t\tnearest = dist;\n\t\t\tnearPos = pos;\n\t\t}\n\n\t\tif (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))\n\t\t\tcontinue;\n\t\tif (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))\n\t\t\tcontinue;\n\t\tfloat xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));\n\t\tif (xinter > v.x)\n\t\t\t++nNbIntersection;\n\t}\n\n\tdistance = nearest;\n\tif ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\n// ***************************************************************************\n\nbool CPrimZone::contains (const NLMISC::CVector &v, const std::vector<CVector> &points, float &distance, NLMISC::CVector &nearPos, bool isPath)\n{\n\tH_AUTO(NLLIGO_Contains2)\n\tuint32 i;\n\tCVector vMin, vMax;\n\tfloat nearest = FLT_MAX;\n\tCVector pos;\n\n\t// Point or line can't contains !\n\tif (points.size() < 3 || isPath)\n\t{\n\t\t// only compute the distance.\n\t\tif (points.size() == 1)\n\t\t{\n\t\t\tdistance = (points[0] - v).norm();\n\t\t\tnearPos = points[0];\n\t\t}\n\t\telse if (points.size() == 2)\n\t\t{\n\t\t\tdistance = getSegmentDist(v, points[0], points[1], nearPos);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// compute nearest segment\n\t\t\tfor (i = 0; i < points.size()-1; ++i)\n\t\t\t{\n\t\t\t\tconst CVector &p1 = points[i];\n\t\t\t\tconst CVector &p2 = points[i+1];\n\n\t\t\t\tfloat dist = getSegmentDist(v, p1, p2, pos);\n\t\t\t\tif( dist < nearest)\n\t\t\t\t{\n\t\t\t\t\tnearest = dist;\n\t\t\t\t\tnearPos = pos;\n\t\t\t\t}\n\t\t\t}\n\t\t\tdistance = nearest;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// Get the bounding rectangle of the zone\n\tvMax = vMin = points[0];\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tvMin.x = min(vMin.x, points[i].x);\n\t\tvMin.y = min(vMin.y, points[i].y);\n\t\tvMax.x = max(vMax.x, points[i].x);\n\t\tvMax.y = max(vMax.y, points[i].y);\n\t}\n\n\tif ((v.x < vMin.x) || (v.y < vMin.y) || (v.x > vMax.x) || (v.y > vMax.y))\n\t{\n\t\t// find the nearest distance of all segment\n\t\tfor (uint i=0; i<points.size(); ++i)\n\t\t{\n\t\t\tfloat dist = getSegmentDist(v, points[i], points[(i+1) % points.size()], pos);\n\n\t\t\tif (dist < nearest)\n\t\t\t{\n\t\t\t\tnearest = dist;\n\t\t\t\tnearPos = pos;\n\t\t\t}\n\t\t}\n\t\tdistance = nearest;\n\t\treturn false;\n\t}\n\n\tuint32 nNbIntersection = 0;\n\tfor (i = 0; i < points.size(); ++i)\n\t{\n\t\tconst CVector &p1 = points[i];\n\t\tconst CVector &p2 = points[(i+1)%points.size()];\n\n\t\tfloat dist = getSegmentDist(v, p1, p2, pos);\n\t\tif( dist < nearest)\n\t\t{\n\t\t\tnearest = dist;\n\t\t\tnearPos = pos;\n\t\t}\n\n\t\tif (((p1.y-v.y) <= 0.0)&&((p2.y-v.y) <= 0.0))\n\t\t\tcontinue;\n\t\tif (((p1.y-v.y) > 0.0)&&((p2.y-v.y) > 0.0))\n\t\t\tcontinue;\n\t\tfloat xinter = p1.x + (p2.x-p1.x) * ((v.y-p1.y)/(p2.y-p1.y));\n\t\tif (xinter > v.x)\n\t\t\t++nNbIntersection;\n\t}\n\n\tdistance = nearest;\n\tif ((nNbIntersection&1) == 1) // odd intersections so the vertex is inside\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\n// ***************************************************************************\n\nfloat CPrimZone::getSegmentDist(const NLMISC::CVector v, const NLMISC::CVector &p1, const NLMISC::CVector &p2, NLMISC::CVector &nearPos)\n{\n\t// two points, compute distance to the segment.\n\tCVector V = (p2-p1).normed();\n\tdouble\tlength= (p2-p1).norm();\n\tfloat distance;\n\n\t// case where p1==p2\n\tif(length==0.0)\n\t{\n\t\tnearPos= p1;\n\t\tdistance = (p1-v).norm();\n\t}\n\t// standard case\n\telse\n\t{\n\t\tfloat t = (float)((double)((v-p1)*V)/length);\n\t\tif (t < 0.0f)\n\t\t{\n\t\t\tnearPos = p1;\n\t\t\tdistance = (p1-v).norm();\n\t\t}\n\t\telse if (t > 1.0f)\n\t\t{\n\t\t\tnearPos = p2;\n\t\t\tdistance = (p2-v).norm();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnearPos = p1 + t*(p2-p1);\n\t\t\tdistance = (v-nearPos).norm();\n\t\t}\n\t}\n\n\treturn distance;\n}\n\n\n// ***************************************************************************\nNLMISC::CVector CPrimZone::getBarycentre() const\n{\n\tCVector sum( CVector::Null );\n\tuint n = (uint)VPoints.size();\n\tif ( n != 0 )\n\t{\n\t\tfor ( uint i=0; i!=n; ++i )\n\t\t\tsum += VPoints[i];\n\t\treturn sum / (float)n;\n\t}\n\telse\n\t\treturn sum;\n}\n\n// ***************************************************************************\nvoid CPrimZone::getAABox( NLMISC::CVector& cornerMin, NLMISC::CVector& cornerMax ) const\n{\n\tcornerMin.x = FLT_MAX;\n\tcornerMin.y = FLT_MAX;\n\tcornerMin.z = 0;\n\tcornerMax.x = -FLT_MAX;\n\tcornerMax.y = -FLT_MAX;\n\tcornerMax.z = 0;\n\tfor ( uint i=0; i!=VPoints.size(); ++i )\n\t{\n\t\tconst CVector& p = VPoints[i];\n\t\tif ( p.x < cornerMin.x )\n\t\t\tcornerMin.x = p.x;\n\t\tif ( p.x > cornerMax.x )\n\t\t\tcornerMax.x = p.x;\n\t\tif ( p.y < cornerMin.y )\n\t\t\tcornerMin.y = p.y;\n\t\tif ( p.y > cornerMax.y )\n\t\t\tcornerMax.y = p.y;\n\t}\n}\n\n\n// ***************************************************************************\nfloat CPrimZone::getAreaOfAABox() const\n{\n\tCVector cornerMin, cornerMax;\n\tgetAABox( cornerMin, cornerMax );\n\treturn (cornerMax.x-cornerMin.x) * (cornerMax.y-cornerMin.y);\n}\n\n\n// ***************************************************************************\nvoid CPrimZone::serial (NLMISC::IStream &f)\n{\n\tIPrimitive::serial(f);\n\tf.serialCont(VPoints);\n}\n\n// ***************************************************************************\nvoid CPrimRegion::serial (NLMISC::IStream &f)\n{\n\tf.xmlPushBegin (\"REGION\");\n\n\tf.xmlSetAttrib (\"NAME\");\n\tf.serial (Name);\n\n\tf.xmlPushEnd();\n\n\tsint version = 2;\n\tversion = f.serialVersion (version);\n\tstring check = \"REGION\";\n\tf.serialCheck (check);\n\n\tf.xmlPush (\"POINTS\");\n\t\tf.serialCont (VPoints);\n\tf.xmlPop ();\n\tf.xmlPush (\"PATHES\");\n\t\tf.serialCont (VPaths);\n\tf.xmlPop ();\n\tf.xmlPush (\"ZONES\");\n\t\tf.serialCont (VZones);\n\tf.xmlPop ();\n\n\tif (version > 1)\n\t{\n\t\tf.xmlPush (\"HIDEPOINTS\");\n\t\t\tf.serialCont (VHidePoints);\n\t\tf.xmlPop ();\n\t\tf.xmlPush (\"HIDEZONES\");\n\t\t\tf.serialCont (VHideZones);\n\t\tf.xmlPop ();\n\t\tf.xmlPush (\"HIDEPATHS\");\n\t\t\tf.serialCont (VHidePaths);\n\t\tf.xmlPop ();\n\t}\n\telse\n\t{\n\t\tVHidePoints.resize\t(VPoints.size(), false);\n\t\tVHideZones.resize\t(VZones.size(),\tfalse);\n\t\tVHidePaths.resize\t(VPaths.size(), false);\n\t}\n}\n\n// ***************************************************************************\n// IPrimitive\n// ***************************************************************************\n\nIPrimitive::IPrimitive ()\n{\n\t_Parent = NULL;\n}\n\n\nIPrimitive::IPrimitive (const IPrimitive &node) : IStreamable()\n{\n\t_Parent = NULL;\n\tIPrimitive::operator= (node);\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::serial (NLMISC::IStream &f)\n{\n\t// NB : unparsed parameters are not binary serialized !\n\n\t// serialize the property container\n\tif (f.isReading())\n\t{\n\t\tuint32 size;\n\t\tf.serial(size);\n\t\tfor (uint i=0; i<size; ++i)\n\t\t{\n\t\t\tstd::string s;\n\t\t\tf.serial(s);\n\t\t\tIProperty *&pp = _Properties[s];\n\t\t\tf.serialPolyPtr(pp);\n\t\t}\n\t}\n\telse\n\t{\n\t\tuint32 size = (uint32)_Properties.size();\n\t\tf.serial(size);\n\t\tstd::map<std::string, IProperty*>::iterator first(_Properties.begin()), last(_Properties.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tstd::string &s = const_cast<std::string&>(first->first);\n\n\t\t\tf.serial(s);\n\t\t\tf.serialPolyPtr(first->second);\n\t\t}\n\t}\n\tf.serial(_ChildId);\n\n//\tf.serial(Layer);\n//\tf.serial(Name);\n//\tf.serial(Expanded);\n\n\t// serial the childrens\n\tif (f.isReading())\n\t{\n\t\tstd::vector<IPrimitive*> children;\n\t\tf.serialContPolyPtr(children);\n\t\tuint index = 0;\n\t\tfor(std::vector<IPrimitive*>::iterator it = children.begin(); it != children.end(); ++it, ++index)\n\t\t{\n\t\t\tinsertChild(*it, index);\n\t\t}\n\t}\n\telse\n\t{\n\t\tf.serialContPolyPtr(_Children);\n\t}\n\n\tif (f.isReading())\n\t{\n\t\t// reloc child link\n\t\tvector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tif (*first)\n\t\t\t\t(*first)->_Parent = this;\n\t\t}\n\t}\n}\n\n\n// ***************************************************************************\n\nvoid IPrimitive::updateChildId (uint index)\n{\n\tuint i;\n\tuint count = (uint)_Children.size ();\n\tfor (i=index; i<count; i++)\n\t\t_Children[i]->_ChildId = i;\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::branchLink()\n{\n\tonBranchLink();\n\tstd::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());\n\tfor (; first != last; ++first)\n\t{\n\t\t(*first)->branchLink();\n\t}\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::branchUnlink()\n{\n\tonBranchUnlink();\n\tstd::vector<IPrimitive*>::iterator first(_Children.begin()), last(_Children.end());\n\tfor (; first != last; ++first)\n\t{\n\t\t(*first)->branchUnlink();\n\t}\n}\n\n\n// ***************************************************************************\n\nvoid IPrimitive::operator= (const IPrimitive &node)\n{\n\t// Clean dest\n\tremoveChildren ();\n\tremoveProperties ();\n\n\t// copy deprecated param\n//\tLayer = node.Layer;\n//\tName = node.Name;\n\n\t// copy unparsed properties\n\t_UnparsedProperties = node._UnparsedProperties;\n\n\t// Copy the flags\n//\tExpanded = node.Expanded;\n\t_ChildId = node._ChildId;\n\n\t// Copy children\n\t_Children.resize (node._Children.size ());\n\tfor (uint child = 0; child < node._Children.size (); child++)\n\t{\n\t\t// Copy the child\n\t\t_Children[child] = node._Children[child]->copy ();\n\n\t\t// Set the parent\n\t\t_Children[child]->_Parent = this;\n\t}\n\n\t// Copy properties\n\tstd::map<std::string, IProperty*>::const_iterator ite = node._Properties.begin ();\n\twhile (ite != node._Properties.end ())\n\t{\n\t\t// Get the property\n\t\tCPropertyString *propString = dynamic_cast<CPropertyString *>(ite->second);\n\t\tif (propString)\n\t\t{\n\t\t\t// New property\n\t\t\tCPropertyString *newProp = new CPropertyString ();\n\t\t\t*newProp = *propString;\n\t\t\t_Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCPropertyStringArray *propStringArray = dynamic_cast<CPropertyStringArray *>(ite->second);\n\t\t\tif (propStringArray)\n\t\t\t{\n\t\t\t\t// New property\n\t\t\t\tCPropertyStringArray *newProp = new CPropertyStringArray ();\n\t\t\t\t*newProp = *propStringArray;\n\t\t\t\t_Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCPropertyColor *propColor = dynamic_cast<CPropertyColor *>(ite->second);\n\t\t\t\tnlverify (propColor);\n\n\t\t\t\t// New property\n\t\t\t\tCPropertyColor *newProp = new CPropertyColor ();\n\t\t\t\t*newProp = *propColor;\n\t\t\t\t_Properties.insert (std::map<std::string, IProperty*>::value_type (ite->first, newProp));\n\t\t\t}\n\t\t}\n\n\t\tite++;\n\t}\n\n#ifdef NLLIGO_DEBUG\n\t_DebugClassName = node._DebugClassName;\n\t_DebugPrimitiveName = node._DebugPrimitiveName;\n#endif\n}\n\n\nconst\tIPrimitive\t*IPrimitive::getPrimitive\t(const\tstd::string\t&absoluteOrRelativePath)\tconst\n{\n\tconst\tIPrimitive\t*cursor=this;\n\tstring\tpath=absoluteOrRelativePath;\n\n\tif (path.find(\"//\")==0)\t//\tan absolute path.\n\t{\n\t\twhile (cursor->getParent())\n\t\t\tcursor=cursor->getParent();\n\t\tpath.erase(0,2);\n\t}\n\n\twhile (path.size()>0)\n\t{\n\t\tif\t(path.find(\"/\")==0)\n\t\t{\n\t\t\tpath.erase(0,1);\n\t\t\tcontinue;\n\t\t}\n\t\tif\t(path.find(\"..\")==0)\n\t\t{\n\t\t\tcursor=cursor->getParent();\n\t\t\tif\t(!cursor)\n\t\t\t\treturn\tNULL;\n\n\t\t\tpath.erase(0,2);\n\t\t\tcontinue;\n\t\t}\n\n\t\tstring::size_type indexStr=path.find(\"/\");\n\t\tstring\t          childName;\n\t\tif (indexStr==string::npos)\n\t\t{\n\t\t\tchildName=path;\n\t\t\tpath=\"\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tchildName=path.substr(0,indexStr);\n\t\t\tpath.erase(0, indexStr);\n\t\t}\n\t\tchildName=toUpper(childName);\n\t\tconst\tIPrimitive*child=NULL;\n\t\tuint\tchildIndex;\n\t\tfor\t(childIndex=0;childIndex<cursor->getNumChildren();childIndex++)\n\t\t{\n\t\t\tcursor->getChild(child,childIndex);\n\t\t\tstring\tname;\n\t\t\tif\t(\tchild->getPropertyByName(\"class\", name)\n\t\t\t\t&&\ttoUpper(name)==childName\t)\n\t\t\t\tbreak;\n\t\t}\n\t\tif\t(childIndex>=cursor->getNumChildren())\n\t\t\treturn\tNULL;\n\n\t\tcursor=child;\n\t}\n\treturn\tcursor;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getProperty (uint index, std::string &property_name, const IProperty *&result) const\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::const_iterator ite = _Properties.begin ();\n\twhile (ite != _Properties.end ())\n\t{\n\t\tif (index == 0)\n\t\t{\n\t\t\tproperty_name = ite->first;\n\t\t\tresult = ite->second;\n\t\t\treturn true;\n\t\t}\n\t\tindex--;\n\t\tite ++;\n\t}\n\tnlwarning (\"NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).\", index, _Properties.size ());\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getProperty (uint index, std::string &property_name, IProperty *&result)\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::iterator ite = _Properties.begin ();\n\twhile (ite != _Properties.end ())\n\t{\n\t\tif (index == 0)\n\t\t{\n\t\t\tproperty_name = ite->first;\n\t\t\tresult = ite->second;\n\t\t\treturn true;\n\t\t}\n\t\tindex--;\n\t\tite ++;\n\t}\n\tnlwarning (\"NLLIGO::IPrimitive::getProperty : invalid index (index : %d, size : %d).\", index, _Properties.size ());\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, const IProperty *&result) const\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);\n\tif (ite != _Properties.end ())\n\t{\n\t\tresult = ite->second;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, IProperty *&result) const\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::const_iterator ite = _Properties.find (property_name);\n\tif (ite != _Properties.end ())\n\t{\n\t\tresult = ite->second;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, std::string *&result) const\n{\n\t// Get the property\n\tIProperty *prop;\n\tif (getPropertyByName (property_name, prop))\n\t{\n\t\tCPropertyString *strProp = dynamic_cast<CPropertyString *> (prop);\n\t\tif (strProp)\n\t\t{\n\t\t\tresult = &(strProp->String);\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.\", property_name);\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, std::string &result) const\n{\n\t// Get the property\n\tconst IProperty *prop;\n\tif (getPropertyByName (property_name, prop))\n\t{\n\t\tconst CPropertyString *strProp = dynamic_cast<const CPropertyString *> (prop);\n\t\tif (strProp)\n\t\t{\n\t\t\tresult = strProp->String;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.\", property_name);\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, std::vector<std::string> *&result) const\n{\n\t// Get the property\n\tIProperty *prop;\n\tif (getPropertyByName (property_name, prop))\n\t{\n\t\tCPropertyStringArray *strProp = dynamic_cast<CPropertyStringArray *> (prop);\n\t\tif (strProp)\n\t\t{\n\t\t\tresult = &(strProp->StringArray);\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.\", property_name);\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, const std::vector<std::string> *&result) const\n{\n\t// Get the property\n\tIProperty *prop;\n\tif (getPropertyByName (property_name, prop))\n\t{\n\t\tconst CPropertyStringArray *strProp = dynamic_cast<const CPropertyStringArray *> (prop);\n\t\tif (strProp)\n\t\t{\n\t\t\tresult = &(strProp->StringArray);\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a string.\", property_name);\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getPropertyByName (const char *property_name, NLMISC::CRGBA &result) const\n{\n\t// Get the property\n\tIProperty *prop;\n\tif (getPropertyByName (property_name, prop))\n\t{\n\t\tconst CPropertyColor *colorProp = dynamic_cast<const CPropertyColor *> (prop);\n\t\tif (colorProp)\n\t\t{\n\t\t\tresult = colorProp->Color;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"NLLIGO::IPrimitive::getPropertyByName : property (%s) in not a color.\", property_name);\n\t\t}\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::removeProperty (uint index)\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::iterator ite = _Properties.begin ();\n\twhile (ite != _Properties.end ())\n\t{\n\t\tif (index == 0)\n\t\t{\n\t\t\t_Properties.erase (ite);\n\t\t\treturn true;\n\t\t}\n\t\tindex--;\n\t\tite ++;\n\t}\n\tnlwarning (\"NLLIGO::IPrimitive::removeProperty : invalid index (index : %d, size : %d).\", index, _Properties.size ());\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::removePropertyByName (const char *property_name)\n{\n\t// Look for the property\n\tstd::map<std::string, IProperty*>::iterator ite = _Properties.find (property_name);\n\tif (ite != _Properties.end ())\n\t{\n\t\t_Properties.erase (ite);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::removeProperties ()\n{\n\tstd::map<std::string, IProperty*>::iterator ite = _Properties.begin ();\n\twhile (ite != _Properties.end ())\n\t{\n\t\tdelete ite->second;\n\t\tite++;\n\t}\n\t_Properties.clear ();\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getChild (const IPrimitive *&result, uint childId) const\n{\n\tif (childId < _Children.size ())\n\t{\n\t\tresult = _Children[childId];\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tnlwarning (\"NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).\", childId, _Children.size ());\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getChild (IPrimitive *&result, uint childId)\n{\n\tif (childId < _Children.size ())\n\t{\n\t\tresult = _Children[childId];\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tnlwarning (\"NLLIGO::IPrimitive::getChild : invalid index (index : %d, size %d).\", childId, _Children.size ());\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::removeChild (IPrimitive *child)\n{\n\tuint childId;\n\tif (getChildId(childId, child))\n\t{\n\t\treturn removeChild(childId);\n\t}\n\telse\n\t{\n\t\tnlwarning(\"NLLIGO::IPrimitive::removeChild : invalid child, can't remove (child : %p)\", child);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::removeChild (uint childId)\n{\n\tif (childId < _Children.size ())\n\t{\n\t\tdelete _Children[childId];\n\t\t_Children.erase (_Children.begin()+childId);\n\t\tupdateChildId (childId);\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tnlwarning (\"NLLIGO::IPrimitive::removeChild : invalid index (index : %d, size %d).\", childId, _Children.size ());\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::removeChildren ()\n{\n\t// Erase children\n\tfor (uint i=0; i<_Children.size (); i++)\n\t{\n\t\tdelete _Children[i];\n\t}\n\t_Children.clear ();\n}\n\n// ***************************************************************************\n\nbool IPrimitive::unlinkChild(IPrimitive *child)\n{\n\tuint childId;\n\tif (getChildId(childId, child))\n\t{\n\t\tchild->onUnlinkFromParent();\n\t\tchild->branchUnlink();\n\t\t_Children.erase (_Children.begin()+childId);\n\t\tupdateChildId (childId);\n\t\tchild->_Parent = NULL;\n\t\tchild->_ChildId = 0;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tnlwarning(\"NLLIGO::IPrimitive::unlinkChild : invalid child, can't unlink (child : %p)\", child);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::insertChild (IPrimitive *primitive, uint index)\n{\n\t// At the end ?\n\tif (index == AtTheEnd)\n\t\tindex = (uint)_Children.size ();\n\n\t// Index valid ?\n\tif (index>_Children.size ())\n\t\treturn false;\n\n\t// Insert\n\t_Children.insert (_Children.begin () + index, primitive);\n\n\t// Update child id\n\tupdateChildId (index);\n\n\t// Link to the parent\n\tprimitive->_Parent = this;\n\n\t// signaling\n\tprimitive->onLinkToParent();\n\tprimitive->branchLink();\n\n\treturn true;\n}\n\n// ***************************************************************************\n\nIPrimitive::~IPrimitive ()\n{\n\t// Remove children\n\tremoveChildren ();\n\n\t// Erase properties\n\tremoveProperties ();\n}\n\n// ***************************************************************************\nbool IPrimitive::checkProperty(const std::string &property_name) const\n{\n\tif (_Properties.find(property_name) == _Properties.end())\n\t\treturn false;\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::addPropertyByName (const char *property_name, IProperty *result)\n{\n\tbool inserted = _Properties.insert (std::map<std::string, IProperty*>::value_type (property_name, result)).second;\n\tif (inserted)\n\t{\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool IPrimitive::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\t// Erase old properties\n\t_Properties.clear ();\n\n\t// Read the unparsed properties (for editor view)\n\txmlNodePtr commentNode = CIXml::getFirstChildNode(xmlNode, XML_COMMENT_NODE);\n\tif (commentNode)\n\t{\n\t\t if (!CIXml::getContentString(_UnparsedProperties, commentNode))\n\t\t\t_UnparsedProperties = \"\";\n\t}\n\n\t// Read the expanded flag\n//\tstring expanded;\n//\tExpanded = true;\n//\tif (CIXml::getPropertyString (expanded, xmlNode, \"EXPANDED\"))\n//\t\tExpanded = (expanded != \"false\");\n\n\t// Read the properties\n\txmlNodePtr propNode;\n\tpropNode = CIXml::getFirstChildNode (xmlNode, \"PROPERTY\");\n\tif (propNode)\n\t{\n\t\tdo\n\t\t{\n\t\t\t// Read the name\n\t\t\tstring name;\n\t\t\tif (GetNodeString (name, filename, propNode, \"NAME\"))\n\t\t\t{\n\t\t\t\t// Get the property type\n\t\t\t\tstring type;\n\t\t\t\tif (GetPropertyString (type, filename, propNode, \"TYPE\"))\n\t\t\t\t{\n\t\t\t\t\t// The property\n\t\t\t\t\tIProperty *property = NULL;\n\n\t\t\t\t\t// Check the type\n\t\t\t\t\tif (type == \"string\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// Create a new property\n\t\t\t\t\t\tCPropertyString *propertyString = new CPropertyString;\n\t\t\t\t\t\tproperty = propertyString;\n\n\t\t\t\t\t\t// Read it\n\t\t\t\t\t\tif (!GetNodeString (propertyString->String, filename, propNode, \"STRING\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (type == \"string_array\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// Create a new property\n\t\t\t\t\t\tCPropertyStringArray *propertyStringArray = new CPropertyStringArray;\n\t\t\t\t\t\tproperty = propertyStringArray;\n\n\t\t\t\t\t\t// Read strings\n\t\t\t\t\t\txmlNodePtr stringNode;\n\t\t\t\t\t\tpropertyStringArray->StringArray.reserve (CIXml::countChildren (propNode, \"STRING\"));\n\t\t\t\t\t\tstringNode = CIXml::getFirstChildNode (propNode, \"STRING\");\n\t\t\t\t\t\tif (stringNode)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdo\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Add the string\n\t\t\t\t\t\t\t\tstring content;\n\t\t\t\t\t\t\t\tGetContentString (content, filename, stringNode);\n\t\t\t\t\t\t\t\tpropertyStringArray->StringArray.push_back (content);\n\n\t\t\t\t\t\t\t\tstringNode = CIXml::getNextChildNode (stringNode, \"STRING\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\twhile (stringNode);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (type == \"color\")\n\t\t\t\t\t{\n\t\t\t\t\t\t// Create a new property\n\t\t\t\t\t\tCPropertyColor *propertyColor= new CPropertyColor;\n\t\t\t\t\t\tproperty = propertyColor;\n\n\t\t\t\t\t\t// Read strings\n\t\t\t\t\t\txmlNodePtr colorNode;\n\t\t\t\t\t\tcolorNode = CIXml::getFirstChildNode (xmlNode, \"COLOR\");\n\t\t\t\t\t\tstring R, G, B, A;\n\t\t\t\t\t\tif (GetPropertyString (R, filename, colorNode, \"R\") &&\n\t\t\t\t\t\t\tGetPropertyString (G, filename, colorNode, \"G\") &&\n\t\t\t\t\t\t\tGetPropertyString (B, filename, colorNode, \"B\") &&\n\t\t\t\t\t\t\tGetPropertyString (A, filename, colorNode, \"A\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsint32 sR=0, sG=0, sB=0, sA=255;\n\t\t\t\t\t\t\tsR = atoi (R.c_str ());\n\t\t\t\t\t\t\tclamp (sR, 0, 255);\n\t\t\t\t\t\t\tsG = atoi (G.c_str ());\n\t\t\t\t\t\t\tclamp (sG, 0, 255);\n\t\t\t\t\t\t\tsB = atoi (B.c_str ());\n\t\t\t\t\t\t\tclamp (sB, 0, 255);\n\t\t\t\t\t\t\tsA = atoi (A.c_str ());\n\t\t\t\t\t\t\tclamp (sR, 0, 255);\n\t\t\t\t\t\t\tpropertyColor->Color.R = (uint8)sR;\n\t\t\t\t\t\t\tpropertyColor->Color.G = (uint8)sG;\n\t\t\t\t\t\t\tpropertyColor->Color.B = (uint8)sB;\n\t\t\t\t\t\t\tpropertyColor->Color.A = (uint8)sA;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Property found ?\n\t\t\t\t\tif (property == NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tXMLError (propNode, filename, \"IPrimitive::read : Unknown property type (%s)\", type.c_str ());\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Add it\n\t\t\t\t\t_Properties.insert (std::map<std::string, IProperty*>::value_type (name, property));\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tpropNode = CIXml::getNextChildNode (propNode, \"PROPERTY\");\n\t\t}\n\t\twhile (propNode);\n\t}\n\n\t// Initialise default value\n\tinitDefaultValues (config);\n\n\t// Read children\n\txmlNodePtr childNode;\n\tchildNode = CIXml::getFirstChildNode (xmlNode, \"CHILD\");\n\tif (childNode)\n\t{\n\t\tdo\n\t\t{\n\t\t\t// Get the property class\n\t\t\tstring type;\n\t\t\tif (GetPropertyString (type, filename, childNode, \"TYPE\"))\n\t\t\t{\n\t\t\t\t// Primitive\n\t\t\t\tif (type==\"node\")\n\t\t\t\t\ttype=\"CPrimNode\";\n\t\t\t\tif (type==\"point\")\n\t\t\t\t\ttype=\"CPrimPoint\";\n\t\t\t\tif (type==\"path\")\n\t\t\t\t\ttype=\"CPrimPath\";\n\t\t\t\tif (type==\"zone\")\n\t\t\t\t\ttype=\"CPrimZone\";\n\t\t\t\tif (type==\"alias\")\n\t\t\t\t\ttype=\"CPrimAlias\";\n\t\t\t\tIPrimitive *primitive = static_cast<IPrimitive *> (CClassRegistry::create (type));\n\n\t\t\t\t// Primitive type not found ?\n\t\t\t\tif (primitive == NULL)\n\t\t\t\t{\n\t\t\t\t\tXMLError (childNode, filename, \"IPrimitive::read : Unknown primitive type (%s)\", type.c_str ());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// Read it\n\t\t\t\tprimitive->read (childNode, filename, version, config);\n\n\t\t\t\t// Add it\n\t\t\t\tinsertChild (primitive);\n\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tchildNode = CIXml::getNextChildNode (childNode, \"CHILD\");\n\t\t}\n\t\twhile (childNode);\n\t}\n\n#ifdef NLLIGO_DEBUG\n\t// store debug data\n \tgetPropertyByName(\"class\", _DebugClassName);\n\tgetPropertyByName(\"name\", _DebugPrimitiveName);\n#endif\n\t// Done\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::initDefaultValues (CLigoConfig &config)\n{\n\t// Get the primitive class\n\tconst CPrimitiveClass *primitiveClass = config.getPrimitiveClass (*this);\n\tif (primitiveClass)\n\t{\n\t\t// For each properties\n\t\tuint count = (uint)primitiveClass->Parameters.size ();\n\t\tuint i;\n\t\tfor (i=0; i<count; i++)\n\t\t{\n\t\t\tconst CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];\n\n\t\t\t// Get the property\n\t\t\tIProperty *result;\n\t\t\tif (!getPropertyByName (parameter.Name.c_str(), result))\n\t\t\t{\n\t\t\t\t// Create the property\n\t\t\t\tif ((parameter.Type == CPrimitiveClass::CParameter::StringArray) || (parameter.Type == CPrimitiveClass::CParameter::ConstStringArray))\n\t\t\t\t\tresult = new CPropertyStringArray();\n\t\t\t\telse\n\t\t\t\t\tresult = new CPropertyString();\n\t\t\t\tnlverify (addPropertyByName (parameter.Name.c_str(), result));\n\t\t\t}\n\t\t}\n\n\t\t// Set the default values\n\t\tfor (i=0; i<count; i++)\n\t\t{\n\t\t\tconst CPrimitiveClass::CParameter &parameter = primitiveClass->Parameters[i];\n\n\t\t\tCPropertyString *pString = NULL;\n\t\t\tCPropertyStringArray *pStringArray = NULL;\n\n\t\t\tIProperty *result;\n\t\t\tnlverify (getPropertyByName (parameter.Name.c_str(), result));\n\t\t\tpString = dynamic_cast<CPropertyString*>(result);\n\t\t\tif (!pString)\n\t\t\t\tpStringArray = dynamic_cast<CPropertyStringArray*>(result);\n\n\t\t\t// Property have default values ?\n\t\t\tif (pString)\n\t\t\t{\n\t\t\t\t// Empty string ?\n\t\t\t\tif (pString->String.empty())\n\t\t\t\t{\n\t\t\t\t\t// Set as default\n\t\t\t\t\tpString->Default = true;\n\t\t\t\t\tparameter.getDefaultValue (pString->String, *this, *primitiveClass);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pStringArray)\n\t\t\t{\n\t\t\t\t// Empty string array ?\n\t\t\t\tif (pStringArray->StringArray.empty())\n\t\t\t\t{\n\t\t\t\t\t// Set as default\n\t\t\t\t\tpStringArray->Default = true;\n\t\t\t\t\tparameter.getDefaultValue (pStringArray->StringArray, *this, *primitiveClass);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::write (xmlNodePtr xmlNode, const char *filename) const\n{\n\t// Save the expanded flag\n//\tif (!Expanded)\n//\t\txmlSetProp (xmlNode, (const xmlChar*)\"EXPANDED\", (const xmlChar*)\"false\");\n\n\t// Set the type\n\txmlSetProp (xmlNode, (const xmlChar*)\"TYPE\", (const xmlChar*)(const_cast<IPrimitive*> (this)->getClassName ().c_str ()));\n\n\t// Save the unparsed property\n\tif (!_UnparsedProperties.empty())\n\t{\n\t\txmlNodePtr commentNode = xmlNewComment((const xmlChar*)(_UnparsedProperties.c_str()));\n\t\tnlverify(commentNode);\n\t\txmlAddChild(xmlNode, commentNode);\n\t}\n\n\t// Save the properties\n\tstd::map<std::string, IProperty*>::const_iterator ite =\t_Properties.begin ();\n\twhile (ite != _Properties.end ())\n\t{\n\t\t// Not a default property ?\n\t\tif (!ite->second->Default)\n\t\t{\n\t\t\t// Create new nodes\n\t\t\txmlNodePtr propNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"PROPERTY\", NULL);\n\t\t\txmlNodePtr nameNode = xmlNewChild ( propNode, NULL, (const xmlChar*)\"NAME\", NULL);\n\t\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)(ite->first.c_str ()));\n\t\t\txmlAddChild (nameNode, textNode);\n\n\t\t\t// Type\n\t\t\tconst CPropertyString *str = dynamic_cast<const CPropertyString *> (ite->second);\n\t\t\tif (str)\n\t\t\t{\n\t\t\t\t// Set the type\n\t\t\t\txmlSetProp (propNode, (const xmlChar*)\"TYPE\", (const xmlChar*)\"string\");\n\n\t\t\t\t// Create new nodes\n\t\t\t\txmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)\"STRING\", NULL);\n\t\t\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)(str->String.c_str ()));\n\t\t\t\txmlAddChild (stringNode, textNode);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Should be an array\n\t\t\t\tconst CPropertyStringArray *array = dynamic_cast<const CPropertyStringArray *> (ite->second);\n\t\t\t\tif (array)\n\t\t\t\t{\n\t\t\t\t\t// Set the type\n\t\t\t\t\txmlSetProp (propNode, (const xmlChar*)\"TYPE\", (const xmlChar*)\"string_array\");\n\n\t\t\t\t\t// For each strings in the array\n\t\t\t\t\tfor (uint i=0; i<array->StringArray.size (); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Create new nodes\n\t\t\t\t\t\txmlNodePtr stringNode = xmlNewChild ( propNode, NULL, (const xmlChar*)\"STRING\", NULL);\n\t\t\t\t\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)(array->StringArray[i].c_str ()));\n\t\t\t\t\t\txmlAddChild (stringNode, textNode);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Should be a color\n\t\t\t\t\tconst CPropertyColor *color = safe_cast<const CPropertyColor *> (ite->second);\n\n\t\t\t\t\t// Set the type\n\t\t\t\t\txmlSetProp (propNode, (const xmlChar*)\"TYPE\", (const xmlChar*)\"color\");\n\n\t\t\t\t\t// Create new nodes\n\t\t\t\t\txmlNodePtr colorNode = xmlNewChild ( propNode, NULL, (const xmlChar*)\"COLOR\", NULL);\n\t\t\t\t\txmlSetProp (colorNode, (const xmlChar*)\"R\", (const xmlChar*)toString (color->Color.R).c_str ());\n\t\t\t\t\txmlSetProp (colorNode, (const xmlChar*)\"G\", (const xmlChar*)toString (color->Color.G).c_str ());\n\t\t\t\t\txmlSetProp (colorNode, (const xmlChar*)\"B\", (const xmlChar*)toString (color->Color.B).c_str ());\n\t\t\t\t\txmlSetProp (colorNode, (const xmlChar*)\"A\", (const xmlChar*)toString (color->Color.A).c_str ());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tite++;\n\t}\n\n\t// Save the children\n\tfor (uint i=0; i<_Children.size (); i++)\n\t{\n\t\t// New node\n\t\txmlNodePtr childNode = xmlNewChild ( xmlNode, NULL, (const xmlChar*)\"CHILD\", NULL);\n\n\t\t// Write it\n\t\t_Children[i]->write (childNode, filename);\n\t}\n}\n\n// ***************************************************************************\n\nbool IPrimitive::getChildId (uint &childId, const IPrimitive *child) const\n{\n\tchildId = child->_ChildId;\n\treturn true;\n}\n\n// ***************************************************************************\n\nuint IPrimitive::getNumProperty () const\n{\n\treturn (uint)_Properties.size ();\n}\n\n// ***************************************************************************\n\nstd::string\t\tIPrimitive::getName() const\n{\n\tstd::string\tret;\n\tgetPropertyByName(\"name\", ret);\n\treturn ret;\n}\n\n// ***************************************************************************\n\nconst std::string &IPrimitive::getUnparsedProperties() const\n{\n\treturn _UnparsedProperties;\n}\n\n// ***************************************************************************\n\nvoid IPrimitive::setUnparsedProperties(const std::string &unparsedProperties) const\n{\n\t_UnparsedProperties = unparsedProperties;\n}\n\n// ***************************************************************************\n// CPrimAlias\n// ***************************************************************************\n\nCPrimAlias::CPrimAlias() :\n\t_Alias(0),\n\t_Container(NULL)\n{\n}\n\nCPrimAlias::CPrimAlias(const CPrimAlias &other)\n\t: IPrimitive(other)\n{\n\t// clear the container reference and alias\n\t_Container = NULL;\n\t_Alias = other._Alias;\n}\n\nCPrimAlias::~CPrimAlias()\n{\n\tif (_Container)\n\t\tonBranchUnlink();\n}\n\nvoid CPrimAlias::onBranchLink()\n{\n\tCPrimitiveContext\t&ctx = CPrimitiveContext::instance();\n\t// context must be set when handling alias\n\tnlassert(ctx.CurrentPrimitive);\n\tnlassert(_Container ==  NULL || _Container == ctx.CurrentPrimitive);\n\n\t_Container = ctx.CurrentPrimitive;\n\n\t// generate a new alias, eventually keeping the current one if any and if still available\n\t_Alias = _Container->genAlias(this, _Alias);\n}\n\nvoid CPrimAlias::onBranchUnlink()\n{\n\tnlassert(_Container !=  NULL);\n\t_Container->releaseAlias(this, _Alias);\n\t_Container = NULL;\n\n\t// NB : we keep the alias value for next linkage\n}\n\nuint32\tCPrimAlias::getAlias() const\n{\n\treturn _Alias;\n}\n\nuint32\tCPrimAlias::getFullAlias() const\n{\n\tnlassert(_Container != NULL);\n\treturn _Container->buildFullAlias(_Alias);\n}\n\nvoid CPrimAlias::regenAlias()\n{\n\t// container must exist\n\tnlassert(_Container);\n\t// generate a new alias, eventually keeping the current one if any and if still available\n\t_Alias = _Container->genAlias(this, _Alias);\n}\n\n\n// Read the primitive\nbool CPrimAlias::read (xmlNodePtr xmlNode, const char *filename, uint version, CLigoConfig &config)\n{\n\t// Read alias\n\txmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, \"ALIAS\");\n\tif (ptNode)\n\t{\n\t\tsint val = 0;\n\t\tif (ReadInt (\"VALUE\", val, filename, ptNode))\n\t\t{\n\t\t\t_Alias = uint32(val);\n\n//\t\t\tnlassert( CPrimitiveContext::instance().CurrentPrimitive);\n////\t\t\tnlassert(_Container);\n//\t\t\t CPrimitiveContext::instance().CurrentPrimitive->reserveAlias(_Alias);\n//\t\t\t// set to null, it will be rewrited by onBranchLink callback\n////\t\t\t_Container = NULL;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// error in format !\n\t\t\tnlwarning(\"CPrimAlias::read: Can't find xml property 'VALUE' in element <ALIAS>\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// error in format !\n\t\tnlwarning(\"CPrimAlias::read: Can't find xml element <ALIAS>\");\n\t\treturn false;\n\t}\n\n\treturn IPrimitive::read (xmlNode, filename, version, config);\n}\n// Write the primitive\nvoid CPrimAlias::write (xmlNodePtr xmlNode, const char *filename) const\n{\n\t// Write alias\n\txmlNodePtr ptNode = xmlNewChild(xmlNode, NULL, (const xmlChar*)\"ALIAS\", NULL);\n\tWriteInt(\"VALUE\", int(_Alias), ptNode);\n\n\tIPrimitive::write (xmlNode, filename);\n}\n\n// Create a copy of this primitive\nIPrimitive *CPrimAlias::copy () const\n{\n\t// NB : this will not call the reserveAlias on the container\n\tCPrimAlias *pa = new CPrimAlias(*this);\n\n\t// clear the alias and container reference\n//\tpa->_Alias = 0;\n//\tpa->_Container = 0;\n\n\treturn pa;\n}\n// serial for binary save\nvoid CPrimAlias::serial (NLMISC::IStream &f)\n{\n\tIPrimitive::serial(f);\n\n\tf.serial(_Alias);\n\n//\tif (f.isReading())\n//\t{\n//\t\tnlassert(_Container);\n//\t\t_Container->reserveAlias(_Alias);\n//\t}\n}\n\n\n// ***************************************************************************\n// CPrimitives\n// ***************************************************************************\n\nCPrimitives::CPrimitives () :\n\t_LigoConfig(NULL)\n{\n\t// init the alias generator\n\t_LastGeneratedAlias = 0;\n\t_AliasStaticPart = 0;\n\n\tRootNode = static_cast<CPrimNode *> (CClassRegistry::create (\"CPrimNode\"));\n\n\t// get the current ligo context (if any)\n\t_LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;\n}\n\n// ***************************************************************************\n\nCPrimitives::CPrimitives (const CPrimitives &other)\n{\n\toperator =(other);\n//\t_LastGeneratedAlias = other._LastGeneratedAlias;\n//\t// get the current ligo context (if any)\n//\t_LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;\n//\n//\tCPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;\n//\tCPrimitiveContext::instance().CurrentPrimitive = this;\n//\t// copy the nodes\n//\tRootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());\n//\tRootNode->branchLink();\n//\n//\tCPrimitiveContext::instance().CurrentPrimitive = temp;\n}\n\n// ***************************************************************************\n\nCPrimitives::~CPrimitives ()\n{\n\tdelete RootNode;\n}\n\n// ***************************************************************************\n\nuint32 CPrimitives::getAliasStaticPart()\n{\n\treturn _AliasStaticPart;\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::setAliasStaticPart(uint32 staticPart)\n{\n\t_AliasStaticPart = staticPart;\n}\n\n// ***************************************************************************\n\nuint32 CPrimitives::buildFullAlias(uint32 dynamicPart)\n{\n\tif (_LigoConfig)\n\t{\n\t\treturn _LigoConfig->buildAlias(_AliasStaticPart, dynamicPart, true);\n\t}\n\telse\n\t\treturn dynamicPart;\n}\n\n\n// ***************************************************************************\n\nuint32 CPrimitives::genAlias(IPrimitive *prim, uint32 preferedAlias)\n{\n\tnlassert(_LigoConfig);\n\tuint32 ret;\n\n\tif (preferedAlias != 0)\n\t{\n\t\t// only dynamic part allowed here\n\t\tnlassert(preferedAlias == (preferedAlias & _LigoConfig->getDynamicAliasMask()));\n\t\t// check is the prefered alias is not already in use\n\t\tmap<uint32, IPrimitive*>::iterator it(_AliasInUse.find(preferedAlias));\n\t\tif (it == _AliasInUse.end())\n\t\t{\n\t\t\t// this alias is available, just use it\n//\t\t\tnldebug(\"Alias: added alias %u, %u alias used\", preferedAlias, _AliasInUse.size()+1);\n\t\t\t_AliasInUse.insert(make_pair(preferedAlias, prim));\n\t\t\treturn preferedAlias;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check who own the alias now\n\t\t\tif (it->second == prim)\n\t\t\t{\n\t\t\t\t// ok, the alias is already own by this primitive\n//\t\t\t\tnldebug(\"Alias: using alias %u, %u alias used\", preferedAlias, _AliasInUse.size()+1);\n\t\t\t\treturn preferedAlias;\n\t\t\t}\n\t\t}\n\t}\n\n\t// make sure there are some free aliases\n\tuint32 mask = _LigoConfig->getDynamicAliasMask();\n\tnlassert(_AliasInUse.size() < mask);\n\n\t// increment alias counter\n\t++_LastGeneratedAlias;\n\t// mask with the dynamic alias mask\n\t_LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();\n\n\tret = _LastGeneratedAlias;\n\n\twhile (_AliasInUse.find(ret) != _AliasInUse.end())\n\t{\n\t\t// this alias is already in use ! generate a new one\n\t\t// increment, mask, affect...\n\t\t++_LastGeneratedAlias;\n\t\t_LastGeneratedAlias &= _LigoConfig->getDynamicAliasMask();\n\t\tret = _LastGeneratedAlias;\n\t}\n\n\t// insert the alias\n//\tnldebug(\"Alias: added alias %u, %u alias in use\", ret, _AliasInUse.size()+1);\n\t_AliasInUse.insert(make_pair(ret, prim));\n\n\t// callback\n\tprim->onModifyPrimitive (*this);\n\n\treturn ret;\n}\n\n//void CPrimitives::reserveAlias(uint32 dynamicAlias)\n//{\n//\t// need ligo config\n//\tnlassert(_LigoConfig);\n//\t// only dynamic part allowed here\n//\tnlassert(dynamicAlias == (dynamicAlias & _LigoConfig->getDynamicAliasMask()));\n//\tstd::set<uint32>::iterator it(_AliasInUse.find(dynamicAlias));\n//\t// warn if already found\n//\tif (it != _AliasInUse.end())\n//\t{\n//\t\tconst string &fileName = _LigoConfig->getFileNameForStaticAlias(_AliasStaticPart);\n//\t\tif (fileName.empty())\n//\t\t\tnlwarning(\"Dynamic Alias %u is already in use\");\n//\t\telse\n//\t\t\tnlwarning(\"Dynamic Alias %u is already in use in file '%s'\",\n//\t\t\t\tdynamicAlias,\n//\t\t\t\tfileName.c_str());\n//\t\treturn;\n//\t}\n//\n//\t// insert the alias\n//\tnldebug(\"Alias: added alias %u, %u alias in use\", dynamicAlias, _AliasInUse.size()+1);\n//\t_AliasInUse.insert(dynamicAlias);\n//}\n//\nvoid CPrimitives::releaseAlias(IPrimitive *prim, uint32 alias)\n{\n\t// need ligo config\n\tnlassert(_LigoConfig);\n\t// only dynamic part allowed here\n\tnlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));\n\tstd::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));\n\t// need to be found\n\tnlassert(it != _AliasInUse.end());\n\n\tif (it->second != prim)\n\t{\n\t\tnlwarning(\"CPrimitives::releaseAlias: The alias %u is own by another primitive !\", alias);\n\t\treturn;\n\t}\n\n\t// remove this alias\n//\tnldebug(\"Alias: remove alias %u, %u alias left\", it->first, _AliasInUse.size()-1);\n\t_AliasInUse.erase(it);\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::forceAlias(CPrimAlias *prim, uint32 alias)\n{\n\t// need ligo config\n\tnlassert(_LigoConfig);\n\t// only dynamic part allowed here\n\tnlassert(alias == (alias & _LigoConfig->getDynamicAliasMask()));\n\n\t// store the alias in the primitive\n\tprim->_Alias = alias;\n\n\tstd::map<uint32, IPrimitive*>::iterator it(_AliasInUse.find(alias));\n\tif (it != _AliasInUse.end() && it->second != prim)\n\t{\n\t\t// we need to alloc and set a new alias for the current alias holder\n\t\tCPrimAlias *pa = static_cast<CPrimAlias*>(const_cast<IPrimitive*>(it->second));\n\n\t\t// reserve the alias for the new primitive\n\t\tit->second = prim;\n\n\n\t\t// and regen an alias for the old\n\t\tpa->regenAlias();\n\t}\n\telse\n\t{\n\t\t// just store the association\n\t\t_AliasInUse.insert(make_pair(alias, prim));\n\t}\n\n}\n\n// ***************************************************************************\n\nuint32 CPrimitives::getLastGeneratedAlias()\n{\n\treturn _LastGeneratedAlias;\n}\n\n// ***************************************************************************\n\nIPrimitive\t\t*CPrimitives::getPrimitiveByAlias(uint32 primAlias)\n{\n\t// check the static part of the alias\n\tuint32 staticAlias = _LigoConfig->getStaticAliasMask() & primAlias;\n\tstaticAlias = staticAlias >> _LigoConfig->getDynamicAliasSize();\n\tif (staticAlias != _AliasStaticPart)\n\t\treturn NULL;\n\n\t// clear the static part before searching\n\tprimAlias &= _LigoConfig->getDynamicAliasMask();\n\n\tstd::map<uint32, IPrimitive*>::const_iterator it(_AliasInUse.find(primAlias));\n\n\tif (it != _AliasInUse.end())\n\t\treturn it->second->getParent();\n\telse\n\t\treturn NULL;\n}\n\n// ***************************************************************************\n\nvoid\t\tCPrimitives::buildPrimitiveWithAliasList(std::map<uint32, IPrimitive*> &result)\n{\n\tnlassert(_LigoConfig != NULL);\n\n\tstd::map<uint32, IPrimitive*>::iterator first(_AliasInUse.begin()), last(_AliasInUse.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tresult.insert(make_pair(_LigoConfig->buildAlias(_AliasStaticPart, first->first), first->second->getParent()));\n\t}\n}\n\n// ***************************************************************************\n\nCPrimitives& CPrimitives::operator= (const CPrimitives &other)\n{\n//\tRootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());\n//\treturn *this;\n\n\t_AliasStaticPart = other._AliasStaticPart;\n\t_LastGeneratedAlias = other._LastGeneratedAlias;\n\t// get the current ligo context (if any)\n\t_LigoConfig = CPrimitiveContext::instance().CurrentLigoConfig;\n\n\tCPrimitives *temp = CPrimitiveContext::instance().CurrentPrimitive;\n\tCPrimitiveContext::instance().CurrentPrimitive = this;\n\t// copy the nodes\n\tRootNode = static_cast<CPrimNode *> (((IPrimitive*)other.RootNode)->copy ());\n\tRootNode->branchLink();\n\n\tCPrimitiveContext::instance().CurrentPrimitive = temp;\n\n\treturn *this;\n}\n\n// ***************************************************************************\n\nbool CPrimitives::read (xmlNodePtr xmlNode, const char *filename, CLigoConfig &config)\n{\n\tnlassert (xmlNode);\n\n\t_Filename = CFile::getFilename(filename);\n\tif (_LigoConfig)\n\t{\n\t\t// try to get the static alias mapping\n\t\t_AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(CFile::getFilename(filename));\n\t}\n\n\t// Clear the primitives\n\tRootNode->removeChildren ();\n\tRootNode->removeProperties ();\n\n\t// Get the name\n\tif (strcmp ((const char*)xmlNode->name, \"PRIMITIVES\") == 0)\n\t{\n\t\t// Get the version\n\t\tstring versionName = \"0\";\n\t\tif (GetPropertyString (versionName, filename, xmlNode, \"VERSION\"))\n\t\t{\n\t\t\t// Get the version\n\t\t\tuint32 version = atoi (versionName.c_str ());\n\n\t\t\t// Check the version\n\t\t\tif (version <= NLLIGO_PRIMITIVE_VERSION)\n\t\t\t{\n\t\t\t\t// Read the primitives\n\t\t\t\txmlNode = GetFirstChildNode (xmlNode, filename, \"ROOT_PRIMITIVE\");\n\t\t\t\tif (xmlNode)\n\t\t\t\t{\n\t\t\t\t\tif (version > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\txmlNodePtr subNode = GetFirstChildNode(xmlNode, filename, \"ALIAS\");\n\t\t\t\t\t\tif (subNode)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint temp;\n\t\t\t\t\t\t\tReadUInt(\"LAST_GENERATED\", temp, filename, subNode);\n\t\t\t\t\t\t\t_LastGeneratedAlias = temp;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_LastGeneratedAlias = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t_LastGeneratedAlias = 0;\n\n\t\t\t\t\t// Read the primitive tree\n\t\t\t\t\t((IPrimitive*)RootNode)->read (xmlNode, filename, version, config);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tError (filename, \"CPrimitives::read : Unknown file version (%d)\", version);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tXMLError (xmlNode, filename, \"This XML document is not a NeL primitive file\");\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::write (xmlDocPtr doc, const char *filename) const\n{\n\tnlassert (doc);\n\n\t// Primitive node\n\txmlNodePtr primNode = xmlNewDocNode (doc, NULL, (const xmlChar*)\"PRIMITIVES\", NULL);\n\txmlDocSetRootElement (doc, primNode);\n\n\twrite (primNode, filename);\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::write (xmlNodePtr root, const char *filename) const\n{\n\tnlassert (root);\n\n\t// Version node\n\txmlSetProp (root, (const xmlChar*)\"VERSION\", (const xmlChar*)toString (NLLIGO_PRIMITIVE_VERSION).c_str ());\n\n\t// The primitive root node\n\txmlNodePtr nameNode = xmlNewChild ( root, NULL, (const xmlChar*)\"ROOT_PRIMITIVE\", NULL);\n\txmlNodePtr subNode = xmlNewChild ( nameNode, NULL, (const xmlChar*)\"ALIAS\", NULL);\n\tWriteUInt(\"LAST_GENERATED\", _LastGeneratedAlias, subNode);\n\n\t// Write the primitive tree\n\t((IPrimitive*)RootNode)->write (nameNode, filename);\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::serial(NLMISC::IStream &f)\n{\n\tuint currentVersion = NLLIGO_PRIMITIVE_VERSION;\n\tf.serialVersion(currentVersion);\n\n\tif (currentVersion == 0)\n\t{\n\t\tf.serial(_LastGeneratedAlias);\n\t}\n\n\tif (f.isReading())\n\t{\n\t\tRootNode->removeChildren ();\n\t\tRootNode->removeProperties ();\n\t}\n\tf.serialPolyPtr(RootNode);\n\tf.serial(_Filename);\n\tif (f.isReading() && _LigoConfig)\n\t{\n\t\t_AliasStaticPart = _LigoConfig->getFileStaticAliasMapping(_Filename);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::convertAddPrimitive (IPrimitive *child, const IPrimitive *prim, bool hidden)\n{\n\t// The primitve\n\tIPrimitive *primitive = NULL;\n\n\t// What kind of primitive ?\n\tconst CPrimPoint *oldPoint = dynamic_cast<const CPrimPoint *>(prim);\n\tif (oldPoint)\n\t{\n\t\t// Create a primitive\n\t\tCPrimPoint *point = static_cast<CPrimPoint *> (CClassRegistry::create (\"CPrimPoint\"));\n\t\tprimitive = point;\n\n\t\t// Copy it\n\t\t*point = *oldPoint;\n\t}\n\telse\n\t{\n\t\t// Path ?\n\t\tconst CPrimPath *oldPath = dynamic_cast<const CPrimPath *>(prim);\n\t\tif (oldPath)\n\t\t{\n\t\t\t// Create a primitive\n\t\t\tCPrimPath *path = static_cast<CPrimPath *> (CClassRegistry::create (\"CPrimPath\"));\n\t\t\tprimitive = path;\n\n\t\t\t// Copy it\n\t\t\t*path = *oldPath;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst CPrimZone *oldZone = safe_cast<const CPrimZone *>(prim);\n\t\t\tif (oldZone)\n\t\t\t{\n\t\t\t\t// Create a primitive\n\t\t\t\tCPrimZone *zone = static_cast<CPrimZone *> (CClassRegistry::create (\"CPrimZone\"));\n\t\t\t\tprimitive = zone;\n\n\t\t\t\t// Copy it\n\t\t\t\t*zone = *oldZone;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Primitive has been created ?\n\tif (primitive)\n\t{\n\t\t// Create a property for the name\n\t\tCPropertyString *nameProp = new CPropertyString;\n//\t\tnameProp->String = prim->Name;\n\n\t\t// Add the property\n\t\tprimitive->addPropertyByName (\"name\", nameProp);\n\n\t\t// The primitive is hidden ?\n\t\tif (hidden)\n\t\t{\n\t\t\t// Create a property for hidden\n\t\t\tnameProp = new CPropertyString;\n\n\t\t\t// Add the property\n\t\t\tprimitive->addPropertyByName (\"hidden\", nameProp);\n\t\t}\n\n\t\t// Add the child\n\t\tchild->insertChild (primitive);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::convertPrimitive (const IPrimitive *prim, bool hidden)\n{\n\t// Look for the group\n\tuint numChildren = RootNode->getNumChildren ();\n\tuint j;\n\tfor (j=0; j<numChildren; j++)\n\t{\n\t\tIPrimitive *child;\n\t\tnlverify (RootNode->getChild (child, j));\n\t\tconst IProperty *prop;\n\t\tif (child->getPropertyByName (\"name\", prop))\n\t\t{\n\t\t\t// Prop string\n\t\t\tconst CPropertyString *name = dynamic_cast<const CPropertyString *>(prop);\n\t\t\tif (name)\n\t\t\t{\n\t\t\t\t// This one ?\n/*\t\t\t\tif (name->String == prim->Layer)\n\t\t\t\t{\n\t\t\t\t\tconvertAddPrimitive (child, prim, hidden);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n*/\t\t\t}\n\t\t}\n\t}\n\n\t// Not found ?\n\tif (j==numChildren)\n\t{\n\t\t// Create a node\n\t\tCPrimNode *primNode = static_cast<CPrimNode *> (CClassRegistry::create (\"CPrimNode\"));\n\n\t\t// Create a property for the layer\n\t\tCPropertyString *nameProp = new CPropertyString;\n//\t\tnameProp->String = prim->Layer;\n\n\t\t// Add the property\n\t\tprimNode->addPropertyByName (\"name\", nameProp);\n\n\t\t// Add the child\n\t\tRootNode->insertChild (primNode);\n\n\t\t// Add the primitive\n\t\tconvertAddPrimitive (primNode, prim, hidden);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CPrimitives::convert (const CPrimRegion &region)\n{\n\t// Delete\n\tRootNode->removeChildren ();\n\tRootNode->removeProperties ();\n\n\t// For each primitives\n\tuint i;\n\tfor (i=0; i<region.VPoints.size (); i++)\n\t{\n\t\tconvertPrimitive (&(region.VPoints[i]), region.VHidePoints[i]);\n\t}\n\tfor (i=0; i<region.VPaths.size (); i++)\n\t{\n\t\tconvertPrimitive (&(region.VPaths[i]), region.VHidePaths[i]);\n\t}\n\tfor (i=0; i<region.VZones.size (); i++)\n\t{\n\t\tconvertPrimitive (&(region.VZones[i]), region.VHideZones[i]);\n\t}\n}\n\n// ***************************************************************************\n\nCPrimitiveContext::CPrimitiveContext():\n\tCurrentLigoConfig(NULL),\n\tCurrentPrimitive(NULL)\n{\n}\n\n\nstatic bool LIGORegistered = false;\n\n\nvoid Register ()\n{\n    if( LIGORegistered )\n    {\n        nlinfo( \"LIGO classes have already been registered.\" );\n        return;\n    }\n\n\tNLMISC_REGISTER_CLASS(CPropertyString);\n\tNLMISC_REGISTER_CLASS(CPropertyStringArray);\n\tNLMISC_REGISTER_CLASS(CPropertyColor);\n\tNLMISC_REGISTER_CLASS(CPrimNode);\n\tNLMISC_REGISTER_CLASS(CPrimPoint);\n\tNLMISC_REGISTER_CLASS(CPrimPath);\n\tNLMISC_REGISTER_CLASS(CPrimZone);\n\tNLMISC_REGISTER_CLASS(CPrimAlias);\n\n    LIGORegistered = true;\n}\n\n// ***************************************************************************\n\n} // namespace NLLIGO\n\n\n"
  },
  {
    "path": "code/nel/src/ligo/primitive_class.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/ligo/primitive_class.h\"\n#include \"nel/ligo/primitive.h\"\n#include \"nel/ligo/ligo_config.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLLIGO;\n\n// ***************************************************************************\n\nCPrimitiveClass::CPrimitiveClass()\n{\n}\n\n// ***************************************************************************\n\nbool ReadFloat (const char *propName, float &result, xmlNodePtr xmlNode)\n{\n\tstring value;\n\tif (CIXml::getPropertyString (value, xmlNode, propName))\n\t{\n\t\tNLMISC::fromString(value, result);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool ReadInt (const char *propName, int &result, xmlNodePtr xmlNode)\n{\n\tstring value;\n\tif (CIXml::getPropertyString (value, xmlNode, propName))\n\t{\n\t\tresult = atoi (value.c_str ());\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool ReadBool (const char *propName, bool &result, xmlNodePtr xmlNode, const char *filename, CLigoConfig &config)\n{\n\tstring str;\n\tif (CIXml::getPropertyString (str, xmlNode, propName))\n\t{\n\t\tif (str == \"true\")\n\t\t\tresult = true;\n\t\telse if (str == \"false\")\n\t\t\tresult = false;\n\t\telse\n\t\t{\n\t\t\tconfig.syntaxError (filename, xmlNode, \"Unknown (%s) parameter (%s), should be false or true\", propName, str.c_str ());\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool ReadColor (CRGBA &color, xmlNodePtr node)\n{\n\t// Read the color\n\tfloat r = DEFAULT_PRIMITIVE_COLOR.R;\n\tfloat g = DEFAULT_PRIMITIVE_COLOR.G;\n\tfloat b = DEFAULT_PRIMITIVE_COLOR.B;\n\tfloat a = DEFAULT_PRIMITIVE_COLOR.A;\n\n\t// Read the value\n\tif (!ReadFloat (\"R\", r, node))\n\t\treturn false;\n\tif (!ReadFloat (\"G\", g, node))\n\t\treturn false;\n\tif (!ReadFloat (\"B\", b, node))\n\t\treturn false;\n\tif (!ReadFloat (\"A\", a, node))\n\t\ta = 255;\n\n\t// Clamp\n\tclamp (r, 0.f, 255.f);\n\tclamp (g, 0.f, 255.f);\n\tclamp (b, 0.f, 255.f);\n\tclamp (a, 0.f, 255.f);\n\n\t// Set\n\tcolor.set((uint8)r, (uint8)g, (uint8)b, (uint8)a);\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool ReadChild (CPrimitiveClass::CChild &child, xmlNodePtr childNode, const char *filename, bool _static, CLigoConfig &config)\n{\n\t// Read the class name\n\tif (!config.getPropertyString (child.ClassName, filename, childNode, \"CLASS_NAME\"))\n\t\tgoto failed;\n\n\t// Read the name\n\tif (!_static || config.getPropertyString (child.Name, filename, childNode, \"NAME\"))\n\t{\n\t\t// Read the parameters\n\t\tchild.Parameters.reserve (CIXml::countChildren (childNode, \"PARAMETER\"));\n\t\tfor (\txmlNodePtr childParamNode = CIXml::getFirstChildNode (childNode, \"PARAMETER\");\n\t\t\t\tchildParamNode != NULL;\n\t\t\t\tchildParamNode = CIXml::getNextChildNode (childParamNode, \"PARAMETER\"))\n\t\t{\n\t\t\t// Add a static child\n\t\t\tchild.Parameters.push_back (CPrimitiveClass::CInitParameters ());\n\n\t\t\t// Child ref\n\t\t\tCPrimitiveClass::CInitParameters &childParam = child.Parameters.back ();\n\n\t\t\t// Read the class name\n\t\t\tif (!config.getPropertyString (childParam.Name, filename, childParamNode, \"NAME\"))\n\t\t\t\tgoto failed;\n\n\t\t\t// Read the parameters\n\t\t\tuint defaultId = 0;\n\t\t\tchildParam.DefaultValue.resize (CIXml::countChildren (childParamNode, \"DEFAULT_VALUE\"));\n\t\t\tfor (\txmlNodePtr childParamValueNode = CIXml::getFirstChildNode (childParamNode, \"DEFAULT_VALUE\");\n\t\t\t\t\tchildParamValueNode != NULL;\n\t\t\t\t\tchildParamValueNode = CIXml::getNextChildNode (childParamValueNode, \"DEFAULT_VALUE\"))\n\t\t\t{\n\t\t\t\t// Gen id flag\n\t\t\t\tchildParam.DefaultValue[defaultId].GenID = false;\n\n\t\t\t\t// Read the gen id flag\n\t\t\t\tstring value;\n\t\t\t\tif (CIXml::getPropertyString (value, childParamValueNode, \"GEN_ID\") && (value != \"false\"))\n\t\t\t\t{\n\t\t\t\t\tchildParam.DefaultValue[defaultId].GenID = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (!config.getPropertyString (value, filename, childParamValueNode, \"VALUE\"))\n\t\t\t\t\t\tgoto failed;\n\n\t\t\t\t\tchildParam.DefaultValue[defaultId].Name = value;\n\t\t\t\t}\n\t\t\t\tdefaultId++;\n\t\t\t}\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\nfailed:\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::read (xmlNodePtr primitiveNode,\n\t\t\t\t\t\t\tconst char *filename,\n\t\t\t\t\t\t\tconst char *className,\n\t\t\t\t\t\t\tstd::set<std::string> &contextStrings,\n\t\t\t\t\t\t\tstd::map<std::string, std::string> &contextFilesLookup,\n\t\t\t\t\t\t\tCLigoConfig &config,\n\t\t\t\t\t\t\tbool parsePrimitiveComboContent)\n{\n\t//\tinit default parameters\n\tAutoInit = false;\n\tDeletable = true;\n\tFileExtension = \"\";\n\tFileType = \"\";\n\tCollision = false;\n\tLinkBrothers = false;\n\tShowArrow = true;\n\tNumberize = true;\n\tVisible = true;\n\n\t// read parent class properties\n\tstring parentClass;\n\tif (CIXml::getPropertyString (parentClass, primitiveNode, \"PARENT_CLASS\"))\n\t{\n\t\tconst CPrimitiveClass *parent = config.getPrimitiveClass(parentClass.c_str());\n\n\t\tif (parent == NULL)\n\t\t{\n\t\t\tconfig.syntaxError (filename, primitiveNode, \"Can't find parent class (%s) for class (%s)\", parentClass.c_str (), className);\n\t\t\treturn false;\n\t\t}\n\n\t\t// copy all the properties\n\t\t*this = *parent;\n\t}\n\n\t// The name\n\tName = className;\n\n\t// Read the type\n\tstd::string type;\n\tif (!config.getPropertyString (type, filename, primitiveNode, \"TYPE\"))\n\t\tgoto failed;\n\n\t// Good type ?\n\tif (type == \"node\")\n\t\tType = Node;\n\telse if (type == \"point\")\n\t\tType = Point;\n\telse if (type == \"path\")\n\t\tType = Path;\n\telse if (type == \"zone\")\n\t\tType = Zone;\n\telse if (type == \"bitmap\")\n\t\tType = Bitmap;\n\telse if (type == \"alias\")\n\t\tType = Alias;\n\telse\n\t{\n\t\tconfig.syntaxError (filename, primitiveNode, \"Unknown primitive type (%s)\", type.c_str ());\n\t\tgoto failed;\n\t}\n\n\t// Read the color\n\tReadColor (Color, primitiveNode);\n\n\t// Autoinit\n\tReadBool (\"AUTO_INIT\", AutoInit, primitiveNode, filename, config);\n\n\t// Deletable\n\tReadBool (\"DELETABLE\", Deletable, primitiveNode, filename, config);\n\n\t// File extension\n\tCIXml::getPropertyString (FileExtension, primitiveNode, \"FILE_EXTENSION\");\n\n\t// File type\n\tCIXml::getPropertyString (FileType, primitiveNode, \"FILE_TYPE\");\n\n\t// Collision\n\tReadBool (\"COLLISION\", Collision, primitiveNode, filename, config);\n\n\t// LinkBrothers\n\tReadBool (\"LINK_BROTHERS\", LinkBrothers, primitiveNode, filename, config);\n\n\t// ShowArrow\n\tReadBool (\"SHOW_ARROW\", ShowArrow, primitiveNode, filename, config);\n\n\t// Numberize when copy the primitive\n\tReadBool (\"NUMBERIZE\", Numberize, primitiveNode, filename, config);\n\n\t// Visible ?\n\tReadBool (\"VISIBLE\", Visible, primitiveNode, filename, config);\n\n\t// Read the parameters\n\tfor (\txmlNodePtr paramNode = CIXml::getFirstChildNode (primitiveNode, \"PARAMETER\");\n\t\t\tparamNode != NULL;\n\t\t\tparamNode = CIXml::getNextChildNode (paramNode, \"PARAMETER\"))\n\t{\n\t\t// Read the property name\n\t\tif (!config.getPropertyString (type, filename, paramNode, \"NAME\"))\n\t\t\tgoto failed;\n\n\t\t// look if the parameter is not already defined by the parent class\n\t\tuint i=0;\n\t\twhile (i<Parameters.size())\n\t\t{\n\t\t\tif (Parameters[i].Name == type)\n\t\t\t{\n\t\t\t\t// the param already exist, remove parent param\n\t\t\t\tParameters.erase(Parameters.begin() + i);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t++i;\n\t\t}\n\n\t\t// Add a parameter\n\t\tParameters.push_back (CParameter ());\n\n\t\t// The parameter ref\n\t\tCParameter &parameter = Parameters.back ();\n\n\t\t// Set the name\n\t\tparameter.Name = type;\n\n\t\t// Read the type\n\t\tif (!config.getPropertyString (type, filename, paramNode, \"TYPE\"))\n\t\t\tgoto failed;\n\n\t\t// Good type ?\n\t\tif (type == \"boolean\")\n\t\t\tparameter.Type = CParameter::Boolean;\n\t\telse if (type == \"const_string\")\n\t\t\tparameter.Type = CParameter::ConstString;\n\t\telse if (type == \"string\")\n\t\t\tparameter.Type = CParameter::String;\n\t\telse if (type == \"string_array\")\n\t\t\tparameter.Type = CParameter::StringArray;\n\t\telse if (type == \"const_string_array\")\n\t\t\tparameter.Type = CParameter::ConstStringArray;\n\t\telse\n\t\t{\n\t\t\tconfig.syntaxError (filename, paramNode, \"Unknown primitive parameter type (%s)\", type.c_str ());\n\t\t\tgoto failed;\n\t\t}\n\n\t\t// Visible\n\t\tparameter.Visible = true;\n\t\tReadBool (\"VISIBLE\", parameter.Visible, paramNode, filename, config);\n\n\t\t// Filename\n\t\tparameter.Filename = false;\n\t\tReadBool (\"FILENAME\", parameter.Filename, paramNode, filename, config);\n\n\t\t// Lookup\n\t\tparameter.Lookup = false;\n\t\tReadBool (\"LOOKUP\", parameter.Lookup, paramNode, filename, config);\n\n\t\t// Read only primitive\n\t\tparameter.ReadOnly = false;\n\t\tReadBool (\"READ_ONLY\", parameter.ReadOnly, paramNode, filename, config);\n\n\t\t// Deletable\n\t\tparameter.Editable = false;\n\t\tReadBool (\"EDITABLE\", parameter.Editable, paramNode, filename, config);\n\n\t\t// sort combo box entries\n\t\tparameter.SortEntries = false;\n\t\tReadBool (\"SORT_ENTRIES\", parameter.SortEntries, paramNode, filename, config);\n\n\t\t// Display horizontal scroller in multi-line edit box\n\t\tparameter.DisplayHS = false;\n\t\tReadBool (\"SHOW_HS\", parameter.DisplayHS, paramNode, filename, config);\n\n\t\t// Lookup\n\t\tparameter.WidgetHeight = 100;\n\t\tint temp;\n\t\tif (ReadInt (\"WIDGET_HEIGHT\", temp, paramNode))\n\t\t\tparameter.WidgetHeight = (uint)temp;\n\n\t\t// Read the file extension\n\t\tparameter.FileExtension = \"\";\n\t\tCIXml::getPropertyString (parameter.FileExtension, paramNode, \"FILE_EXTENSION\");\n\t\tparameter.FileExtension = toLower(parameter.FileExtension);\n\n\t\t// Autonaming preference\n\t\tparameter.Autoname = \"\";\n\t\tCIXml::getPropertyString (parameter.Autoname, paramNode, \"AUTONAME\");\n\n\t\t// Read the file extension\n\t\tparameter.Folder = \"\";\n\t\tCIXml::getPropertyString (parameter.Folder, paramNode, \"FOLDER\");\n\t\tparameter.Folder = toLower(parameter.Folder);\n\n\t\t// Read the combo values\n\t\tfor (\txmlNodePtr comboValueNode = CIXml::getFirstChildNode (paramNode, \"COMBO_VALUES\");\n\t\t\t\tcomboValueNode != NULL;\n\t\t\t\tcomboValueNode = CIXml::getNextChildNode (comboValueNode, \"COMBO_VALUES\"))\n\t\t{\n\t\t\t// Read the context\n\t\t\tif (!config.getPropertyString (type, filename, comboValueNode, \"CONTEXT_NAME\"))\n\t\t\t\tgoto failed;\n\n\t\t\t// Add this context\n\t\t\tcontextStrings.insert (type);\n\n\t\t\t// Add a combo value\n\t\t\tpair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =\n\t\t\t\tparameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));\n\n\t\t\t// The combo value ref\n\t\t\tCParameter::CConstStringValue &comboValue = insertResult.first->second;\n\n\t\t\t// Read the values\n\t\t\tfor (\txmlNodePtr comboValueValueNode = CIXml::getFirstChildNode (comboValueNode, \"CONTEXT_VALUE\");\n\t\t\t\t\tcomboValueValueNode != NULL;\n\t\t\t\t\tcomboValueValueNode = CIXml::getNextChildNode (comboValueValueNode, \"CONTEXT_VALUE\"))\n\t\t\t{\n\t\t\t\t// Read the value\n\t\t\t\tif (!config.getPropertyString (type, filename, comboValueValueNode, \"VALUE\"))\n\t\t\t\t\tgoto failed;\n\n\t\t\t\tcomboValue.Values.push_back (type);\n\t\t\t}\n\t\t}\n\n\t\t// Read the combo files\n\t\tfor (\txmlNodePtr comboValueNode = CIXml::getFirstChildNode (paramNode, \"COMBO_FILES\");\n\t\t\t\tcomboValueNode != NULL;\n\t\t\t\tcomboValueNode = CIXml::getNextChildNode (comboValueNode, \"COMBO_FILES\"))\n\t\t{\n\t\t\t// Read the context\n\t\t\tif (!config.getPropertyString (type, filename, comboValueNode, \"CONTEXT_NAME\"))\n\t\t\t\tgoto failed;\n\n\t\t\t// Read the path to search\n\t\t\tstring path;\n\t\t\tif\t(CIXml::getPropertyString (path, comboValueNode, \"PATH\"))\n\t\t\t{\n\t\t\t\tif (!parsePrimitiveComboContent)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Look for files in the path\n\t\t\t\tstd::vector<std::string> files;\n\t\t\t\tCPath::getPathContent (path, true, false, true, files);\n\n\t\t\t\t// Not empty ?\n\t\t\t\tif (files.empty ())\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Add this context\n\t\t\t\tcontextStrings.insert (type);\n\n\t\t\t\t// For each file\n\t\t\t\tfor (uint i=0; i<files.size (); i++)\n\t\t\t\t{\n\t\t\t\t\t// Good extension ?\n\t\t\t\t\tif (toLower(NLMISC::CFile::getExtension (files[i])) != parameter.FileExtension)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t// Add a combo value\n\t\t\t\t\tpair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =\n\t\t\t\t\t\tparameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));\n\n\t\t\t\t\t// The combo value ref\n\t\t\t\t\tCParameter::CConstStringValue &comboValue = insertResult.first->second;\n\n\t\t\t\t\t// Get the filename without extension\n\t\t\t\t\tstring nameWithoutExt = toLower(NLMISC::CFile::getFilenameWithoutExtension (files[i]));\n\n\t\t\t\t\t// Add the values\n\t\t\t\t\tcomboValue.Values.push_back (nameWithoutExt);\n\n\t\t\t\t\t// Add the value for lookup\n\t\t\t\t\tcontextFilesLookup.insert (map<string, string>::value_type (nameWithoutExt, files[i]));\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstring\tprimpath;\n\t\t\t\tif\t(!config.getPropertyString (primpath, filename, comboValueNode, \"PRIM_PATH\"))\n\t\t\t\t\tgoto failed;\n\n\t\t\t\t// Add this context\n\t\t\t\tcontextStrings.insert (type);\n\n\t\t\t\t// Add a combo value\n\t\t\t\tpair<std::map<std::string, CParameter::CConstStringValue>::iterator, bool> insertResult =\n\t\t\t\t\tparameter.ComboValues.insert (std::map<std::string, CParameter::CConstStringValue>::value_type (type, CParameter::CConstStringValue ()));\n\n\t\t\t\t// The combo value ref\n\t\t\t\tCParameter::CConstStringValue &comboValue = insertResult.first->second;\n\n\t\t\t\tcomboValue.PrimitivePath.push_back(primpath);\n\t\t\t}\n\t\t}\n\n\t\t// Read parameters default values\n\t\tuint defaultId = 0;\n\t\tparameter.DefaultValue.resize (CIXml::countChildren (paramNode, \"DEFAULT_VALUE\"));\n\t\tfor (\txmlNodePtr defaultValueNode = CIXml::getFirstChildNode (paramNode, \"DEFAULT_VALUE\");\n\t\t\t\tdefaultValueNode != NULL;\n\t\t\t\tdefaultValueNode = CIXml::getNextChildNode (defaultValueNode, \"DEFAULT_VALUE\"))\n\t\t{\n\t\t\t// Gen id flag\n\t\t\tparameter.DefaultValue[defaultId].GenID = false;\n\n\t\t\t// Read the gen id flag\n\t\t\tstring value;\n\t\t\tif (CIXml::getPropertyString (value, defaultValueNode, \"GEN_ID\") && (value != \"false\"))\n\t\t\t{\n\t\t\t\tparameter.DefaultValue[defaultId].GenID = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!config.getPropertyString (value, filename, defaultValueNode, \"VALUE\"))\n\t\t\t\t\tgoto failed;\n\t\t\t\tparameter.DefaultValue[defaultId].Name = value;\n\t\t\t}\n\t\t\tdefaultId++;\n\t\t}\n\t}\n\n\t// Read static children\n\tStaticChildren.reserve (StaticChildren.size() + CIXml::countChildren (primitiveNode, \"STATIC_CHILD\"));\n\tfor (\txmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, \"STATIC_CHILD\");\n\t\t\tchildrenNode != NULL;\n\t\t\tchildrenNode = CIXml::getNextChildNode (childrenNode, \"STATIC_CHILD\"))\n\t{\n\t\t// Add a static child\n\t\tStaticChildren.push_back (CChild ());\n\n\t\t// Child ref\n\t\tCChild &child = StaticChildren.back ();\n\n\t\t// Read the child\n\t\tif (!ReadChild (child, childrenNode, filename, true, config))\n\t\t\tgoto failed;\n\t}\n\n\t// Read dynamic children\n\tDynamicChildren.reserve (DynamicChildren.size() + CIXml::countChildren (primitiveNode, \"DYNAMIC_CHILD\"));\n\tfor (\txmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, \"DYNAMIC_CHILD\");\n\t\t\tchildrenNode != NULL;\n\t\t\tchildrenNode = CIXml::getNextChildNode (childrenNode, \"DYNAMIC_CHILD\"))\n\t{\n\t\t// Add a static child\n\t\tDynamicChildren.push_back (CChild ());\n\n\t\t// Child ref\n\t\tCChild &child = DynamicChildren.back ();\n\n\t\t// Read the child\n\t\tif (!ReadChild (child, childrenNode, filename, false, config))\n\t\t\tgoto failed;\n\t}\n\n\t// Read generated children\n\tGeneratedChildren.reserve (GeneratedChildren.size() + CIXml::countChildren (primitiveNode, \"GENERATED_CHILD\"));\n\tfor (\txmlNodePtr childrenNode = CIXml::getFirstChildNode (primitiveNode, \"GENERATED_CHILD\");\n\t\t\tchildrenNode != NULL;\n\t\t\tchildrenNode = CIXml::getNextChildNode (childrenNode, \"GENERATED_CHILD\"))\n\t{\n\t\t// Add a static child\n\t\tGeneratedChildren.push_back (CChild ());\n\n\t\t// Child ref\n\t\tCChild &child = GeneratedChildren.back ();\n\n\t\t// Read the child\n\t\tif (!ReadChild (child, childrenNode, filename, false, config))\n\t\t\tgoto failed;\n\t}\n\n\treturn true;\nfailed:\n\treturn false;\n}\n\n// ***************************************************************************\n\nCPrimitiveClass::CParameter::CParameter (const NLLIGO::IProperty &property, const char *propertyName)\n{\n\tName = propertyName;\n\tFilename = false;\n\tVisible = true;\n\tType = (typeid (property) == typeid (CPropertyString)) ? CPrimitiveClass::CParameter::String : CPrimitiveClass::CParameter::StringArray;\n}\n\n// ***************************************************************************\n// CPrimitiveClass::CParameter\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::operator== (const CParameter &other) const\n{\n\treturn (Type == other.Type) &&\n\t\t(Name == other.Name) &&\n\t\t(Visible == other.Visible) &&\n\t\t(Filename == other.Filename) &&\n\t\t(ComboValues == other.ComboValues) &&\n\t\t(DefaultValue == other.DefaultValue);\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::operator< (const CParameter &other) const\n{\n\treturn (Name < other.Name) ? true : (Name > other.Name) ? false :\n\t\t(Type < other.Type) ? true : (Type > other.Type) ? false :\n\t\t(Visible < other.Visible) ? true : (Visible > other.Visible) ? false :\n\t\t(Filename < other.Filename) ? true : (Filename > other.Filename) ? false :\n\t\t(ComboValues < other.ComboValues) ? true : (ComboValues > other.ComboValues) ? false :\n\t\t(DefaultValue < other.DefaultValue) ? true : (DefaultValue > other.DefaultValue) ? false :\n\t\tfalse;\n}\n\n// ***************************************************************************\n// CPrimitiveClass::CParameter::CConstStringValue\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::CConstStringValue::operator== (const CConstStringValue &other) const\n{\n\treturn Values == other.Values;\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::CConstStringValue::operator< (const CConstStringValue &other) const\n{\n\treturn Values < other.Values;\n}\n\n\nvoid\tCPrimitiveClass::CParameter::CConstStringValue::appendFilePath(std::vector<std::string> &pathList)\tconst\n{\n\tpathList.insert(pathList.end(), Values.begin(), Values.end());\n}\n\nvoid\tCPrimitiveClass::CParameter::CConstStringValue::appendPrimPath(std::vector<std::string> &pathList, const\tstd::vector<const IPrimitive*>\t&relativePrimPaths)\tconst\n{\n\tstd::set<std::string>\trelativePrimPathString;\n\tfor\t(std::vector<const IPrimitive*>::const_iterator it=relativePrimPaths.begin(), itEnd=relativePrimPaths.end(); it!=itEnd;++it)\n\t{\n\t\tconst\tuint\tnbChilds=(*it)->getNumChildren();\n\t\tfor (uint childIndex=0;childIndex<nbChilds;childIndex++)\n\t\t{\n\t\t\tconst\tIPrimitive*child=NULL;\n\t\t\tif\t(\t!(*it)->getChild(child,childIndex)\n\t\t\t\t||\t!child\t)\n\t\t\t\tcontinue;\n\t\t\tstd::string\tstr;\n\t\t\tif\t(child->getPropertyByName(\"name\", str))\n\t\t\t\trelativePrimPathString.insert(str);\n\t\t}\n\n\t}\n\tpathList.insert(pathList.end(), relativePrimPathString.begin(), relativePrimPathString.end());\n}\n\nvoid\tCPrimitiveClass::CParameter::CConstStringValue::getPrimitivesForPrimPath\t(std::vector<const IPrimitive*>\t&relativePrimPaths, const\tstd::vector<const IPrimitive*>\t&startPrimPath)\tconst\n{\n\tfor\t(uint i=0; i<PrimitivePath.size (); i++)\n\t{\n\t\tset<const IPrimitive*>\trelativePrimPath;\n\t\tfor (uint locIndex=0;locIndex<startPrimPath.size();locIndex++)\n\t\t{\n\t\t\tconst\tIPrimitive *const\tcursor=startPrimPath[locIndex]->getPrimitive(PrimitivePath[i]);\n\t\t\tif\t(cursor)\n\t\t\t\trelativePrimPath.insert(cursor);\n\t\t}\n\t\tif\t(relativePrimPath.size()==1)\n\t\t\trelativePrimPaths.push_back(*relativePrimPath.begin());\n\t}\n\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::translateAutoname (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass) const\n{\n\tresult = \"\";\n\tstring::size_type strBegin = 0;\n\tstring::size_type strEnd = 0;\n\twhile (strBegin != Autoname.size())\n\t{\n\t\tstrEnd = Autoname.find ('$', strBegin);\n\t\tif (strEnd == string::npos)\n\t\t{\n\t\t\tstrEnd = Autoname.size();\n\t\t\tresult += Autoname.substr (strBegin, strEnd-strBegin);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Copy the remaining string\n\t\t\tresult += Autoname.substr (strBegin, strEnd-strBegin);\n\t\t\tif (strEnd != Autoname.size())\n\t\t\t{\n\t\t\t\tstrBegin = strEnd+1;\n\t\t\t\tstrEnd = Autoname.find ('$', strBegin);\n\t\t\t\tif (strEnd == string::npos)\n\t\t\t\t\tstrEnd = Autoname.size();\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstring keyWord = Autoname.substr (strBegin, strEnd-strBegin);\n\n\t\t\t\t\t// Loop for the parameter\n\t\t\t\t\tuint i;\n\t\t\t\t\tfor (i=0; i<primitiveClass.Parameters.size (); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (primitiveClass.Parameters[i].Name == keyWord)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Get its string value\n\t\t\t\t\t\t\tstring str;\n\t\t\t\t\t\t\tconst IProperty *prop;\n\t\t\t\t\t\t\tif (primitive.getPropertyByName (keyWord.c_str(), prop))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// The property has been found ?\n\t\t\t\t\t\t\t\tif (prop)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Array or string ?\n\t\t\t\t\t\t\t\t\tconst CPropertyString *_string = dynamic_cast<const CPropertyString *>(prop);\n\n\t\t\t\t\t\t\t\t\t// Is a string ?\n\t\t\t\t\t\t\t\t\tif (_string)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif (!(_string->String.empty()))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tresult += _string->String;\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// Try an array\n\t\t\t\t\t\t\t\t\t\tconst CPropertyStringArray *array = dynamic_cast<const CPropertyStringArray *>(prop);\n\n\t\t\t\t\t\t\t\t\t\t// Is an array ?\n\t\t\t\t\t\t\t\t\t\tif (array)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (!(array->StringArray.empty()))\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tuint i;\n\t\t\t\t\t\t\t\t\t\t\t\tfor (i=0; i<array->StringArray.size()-1; i++)\n\t\t\t\t\t\t\t\t\t\t\t\t\tresult += array->StringArray[i] + \"\\n\";\n\t\t\t\t\t\t\t\t\t\t\t\tresult += array->StringArray[i];\n\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Get its default value\n\t\t\t\t\t\t\tstd::string result2;\n\t\t\t\t\t\t\tif (primitiveClass.Parameters[i].getDefaultValue (result2, primitive, primitiveClass))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tresult += result2;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tstrEnd++;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t\tstrBegin = strEnd;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::getDefaultValue (std::string &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string *fromWhere) const\n{\n\tresult = \"\";\n\tif (!Autoname.empty())\n\t{\n\t\tif (fromWhere)\n\t\t\t*fromWhere = \"Autoname value : \"+Autoname;\n\t\treturn translateAutoname (result, primitive, primitiveClass);\n\t}\n\telse\n\t{\n\t\tif (fromWhere)\n\t\t\t*fromWhere = \"Default value\";\n\t\tif (!DefaultValue.empty())\n\t\t\tresult = DefaultValue[0].Name;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CPrimitiveClass::CParameter::getDefaultValue (std::vector<std::string> &result, const IPrimitive &primitive, const CPrimitiveClass &primitiveClass, std::string * /* fromWhere */) const\n{\n\tif (!Autoname.empty())\n\t{\n\t\tstring temp;\n\t\tif (translateAutoname (temp, primitive, primitiveClass))\n\t\t{\n\t\t\tresult.clear ();\n\t\t\tif (!temp.empty())\n\t\t\t{\n\t\t\t\tstring tmp;\n\t\t\t\tuint i;\n\t\t\t\tfor (i=0; i<temp.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif (temp[i] == '\\n')\n\t\t\t\t\t{\n\t\t\t\t\t\tresult.push_back (tmp);\n\t\t\t\t\t\ttmp.clear();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttmp.push_back(temp[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!tmp.empty())\n\t\t\t\t\tresult.push_back (tmp);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\tuint i;\n\t\tresult.resize (DefaultValue.size());\n\t\tfor (i=0; i<DefaultValue.size(); i++)\n\t\t\tresult[i] = DefaultValue[i].Name;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\n\n"
  },
  {
    "path": "code/nel/src/ligo/primitive_configuration.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/ligo/primitive_configuration.h\"\n#include \"nel/ligo/ligo_config.h\"\n#include \"nel/ligo/primitive.h\"\n#include \"nel/misc/i_xml.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLLIGO;\n\nextern bool ReadColor (CRGBA &color, xmlNodePtr node);\n\n// ***************************************************************************\n\nbool CPrimitiveConfigurations::read (xmlNodePtr configurationNode, const char *filename, const char *name, NLLIGO::CLigoConfig &config)\n{\n\t// The name\n\tName = name;\n\n\t// Read the color\n\tReadColor (Color, configurationNode);\n\n\t// Get the first matching pair\n\tMatchPairs.reserve (CIXml::countChildren (configurationNode, \"MATCH_GROUP\"));\n\txmlNodePtr matchGroups = CIXml::getFirstChildNode (configurationNode, \"MATCH_GROUP\");\n\tif (matchGroups)\n\t{\n\t\tdo\n\t\t{\n\t\t\t// Add a pair\n\t\t\tMatchPairs.push_back(CMatchGroup());\n\t\t\tCMatchGroup &matchGroup = MatchPairs.back();\n\n\t\t\t// Get the first matching pair\n\t\t\tmatchGroup.Pairs.reserve (CIXml::countChildren (matchGroups, \"MATCH\"));\n\t\t\txmlNodePtr match = CIXml::getFirstChildNode (matchGroups, \"MATCH\");\n\t\t\tif (match)\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// Add the match\n\t\t\t\t\tmatchGroup.Pairs.resize (matchGroup.Pairs.size()+1);\n\t\t\t\t\tstd::pair<std::string, std::string> &pair = matchGroup.Pairs.back();\n\n\t\t\t\t\t// Get the match name\n\t\t\t\t\tstd::string name;\n\t\t\t\t\tif (config.getPropertyString (name, filename, match, \"NAME\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tpair.first = name;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tconfig.syntaxError (filename, match, \"Missing match name in configuration (%s)\", name.c_str());\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Get the match value\n\t\t\t\t\tif (config.getPropertyString (name, filename, match, \"VALUE\"))\n\t\t\t\t\t{\n\t\t\t\t\t\tpair.second = name;\n\t\t\t\t\t}\n\n\t\t\t\t\tmatch = CIXml::getNextChildNode (match, \"MATCH\");\n\t\t\t\t}\n\t\t\t\twhile (match);\n\t\t\t}\n\n\t\t\tmatchGroups = CIXml::getNextChildNode (matchGroups, \"MATCH_GROUP\");\n\t\t}\n\t\twhile (matchGroups);\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool\tCPrimitiveConfigurations::belong (const IPrimitive &primitive) const\n{\n\t// For each match group\n\tuint group;\n\tconst uint numGroup = (uint)MatchPairs.size();\n\tfor (group=0; group<numGroup; group++)\n\t{\n\t\tconst CMatchGroup &matchGroup = MatchPairs[group];\n\n\t\t// For each rules\n\t\tuint rules;\n\t\tconst uint numRules = (uint)matchGroup.Pairs.size();\n\t\tfor (rules=0; rules<numRules; rules++)\n\t\t{\n\t\t\tconst std::pair<std::string, std::string> &pairs = matchGroup.Pairs[rules];\n\t\t\tstring key = toLower(pairs.second);\n\n\t\t\t// Get the property\n\t\t\tstring value;\n\t\t\tif (primitive.getPropertyByName (pairs.first.c_str(), value))\n\t\t\t{\n\t\t\t\tif (toLower(value) == key)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Get the property\n\t\t\tconst std::vector<string> *array = NULL;\n\t\t\tif (primitive.getPropertyByName (pairs.first.c_str(), array) && array)\n\t\t\t{\n\t\t\t\tuint i;\n\t\t\t\tfor (i=0; i<array->size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif (toLower((*array)[i]) == key)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (i!=array->size())\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Don't match\n\t\t\tbreak;\n\t\t}\n\n\t\t// Match ?\n\t\tif (rules == numRules)\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\n"
  },
  {
    "path": "code/nel/src/ligo/primitive_utils.cpp",
    "content": "// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/ligo/primitive_utils.h\"\n\n\nnamespace NLLIGO\n{\n\nstd::string buildPrimPath(const IPrimitive *prim)\n{\n\tstd::string path;\n\n\twhile (prim != NULL)\n\t{\n\t\tstd::string name;\n\t\tprim->getPropertyByName(\"name\", name);\n\t\tif (path.empty())\n\t\t\tpath = name;\n\t\telse\n\t\t\tpath = name + \".\" + path;\n\n\t\tprim = prim->getParent();\n\t}\n\treturn path;\n}\n\nvoid selectPrimByPath(IPrimitive *rootNode, const std::string &path, TPrimitiveSet &result)\n{\n\tstd::vector<std::string>\tparts;\n\tNLMISC::explode(path, std::string(\".\"), parts, false);\n//\tIPrimitive * tmpChild;\n\n\tresult.clear();\n\n\tif (parts.empty())\n\t\treturn;\n\n\t// handle a special case\n\tif (parts.size() > 1 && parts[1] == \"primitive\")\n\t{\n\t\tparts[0] += \".primitive\";\n\t\tparts.erase(parts.begin()+1);\n\t}\n\n\tTPrimitiveSet\tcandidats, nextStep;\n\tcandidats.push_back(rootNode);\n\n\t// check root validity\n\tstd::string name;\n\trootNode->getPropertyByName(\"name\", name);\n\tif (name != parts.front())\n\t\treturn;\n\n\tfor (uint i=1; i<parts.size(); ++i)\n\t{\n\t\tfor (uint j=0; j<candidats.size(); ++j)\n\t\t{\n\t\t\tfor (uint k=0; k<candidats[j]->getNumChildren(); ++k)\n\t\t\t{\n\t\t\t\tstd::string name;\n\t\t\t\tIPrimitive *child;\n\t\t\t\tcandidats[j]->getChild(child, k);\n\n\t\t\t\tchild->getPropertyByName(\"name\", name);\n\n\t\t\t\tif (name == parts[i])\n\t\t\t\t{\n\t\t\t\t\tnextStep.push_back(child);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcandidats.swap(nextStep);\n\t\tnextStep.clear();\n\t}\n\n\tresult.swap(candidats);\n\n//\tfor (uint i=0; i<parts.size(); ++i)\n//\t{\n//\t\tfor (uint j=0; j<candidats.size(); ++j)\n//\t\t{\n//\t\t\tstd::string tmpName;\n//\t\t\tstd::vector<std::string> name;\n//\t\t\tcandidats[j]->getPropertyByName(\"name\", tmpName);\n//\t\t\tNLMISC::explode(tmpName,\".\",name);\n//\n//\t\t\tbool test=false;\n//\t\t\tfor(uint k=0;k<name.size();k++)\n//\t\t\t{\n//\t\t\t\tif (name.at(k)==parts[i+k])\n//\t\t\t\t\ttest=true;\n//\t\t\t\telse\n//\t\t\t\t{\n//\t\t\t\t\ttest=false;\n//\t\t\t\t\tbreak;\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\tif (test)\n//\t\t\t{\n//\t\t\t\tif (i == parts.size()-1)\n//\t\t\t\t{\n//\t\t\t\t}\n//\t\t\t\telse\n//\t\t\t\t{\n//\t\t\t\t\tfor(uint k=0;k<candidats[j]->getNumChildren();k++)\n//\t\t\t\t\t{\n//\t\t\t\t\t\tcandidats[j]->getChild(tmpChild,k);\n//\t\t\t\t\t\tnextStep.push_back(tmpChild);\n//\t\t\t\t\t}\n//\t\t\t\t}\n////\t\t\t\tresult.clear();\n////\t\t\t\tresult.push_back(candidats[j]);\n//\t\t\t\ti+=name.size()-1;\n//\t\t\t\tbreak;\n//\t\t\t}\n//\n//\t\t}\n//\n//\t\tcandidats.swap(nextStep);\n//\t\tnextStep.clear();\n//\n//\t\tif (candidats.empty())\n//\t\t\treturn;\n//\t}\n\n\t// store the result\n//\tresult.swap(candidats);\n\t//result.push_back(candidats.at(0)->getParent());\n}\n\n} // namespace NLLIGO\n\n\n\n"
  },
  {
    "path": "code/nel/src/ligo/stdligo.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n"
  },
  {
    "path": "code/nel/src/ligo/stdligo.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"nel/misc/types_nl.h\"\n\n#include <algorithm>\n#include <cmath>\n#include <csignal>\n#include <cstdarg>\n#include <cstddef>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <ctime>\n#include <deque>\n#include <exception>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <limits>\n#include <list>\n#include <map>\n#include <memory>\n#include <numeric>\n#include <set>\n#include <string>\n#include <typeinfo>\n#include <utility>\n#include <vector>\n#include <cstdlib>\n\n// Include from libxml2\n#include <libxml/parser.h>\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/fast_mem.h\"\n#include \"nel/misc/system_info.h\"\n#include \"nel/misc/mem_displayer.h\"\n#include \"nel/misc/matrix.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/string_common.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/o_xml.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/vector.h\"\n#include \"nel/misc/rgba.h\"\n#include \"nel/misc/file.h\"\n\n#ifdef NL_OS_WINDOWS\n\t#ifndef NL_COMP_MINGW\n\t\t#define NOMINMAX\n\t#endif\n\t#include <windows.h>\n#endif\n"
  },
  {
    "path": "code/nel/src/ligo/transition.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"transition.h\"\n\n// Ligo include\n#include \"zone_template.h\"\n#include \"ligo_error.h\"\n#include \"ligo_material.h\"\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n\nsint32 CTransition::TransitionZoneEdges[TransitionZoneCount][4]=\n{\n\t{+2, +2, -4, +4},\t// 0\n\t{+4, +2, +2, -3},\t// 1\n\t{+1, +3, +2, -3},\t// 2\n\t{-3, +3, +2, +2},\t// 3\n\t{+1, +1, +3, -4},\t// 4\n\t{+1, +4, -4, +1},\t// 5\n\t{+4, +2, -4, +1},\t// 6\n\t{+4, +2, -3, +1},\t// 7\n\t{+3, -3, +1, +1},\t// 8\n};\n\n// ***************************************************************************\n\nsint32 CTransition::TransitionZoneOffset[TransitionZoneCount][2]=\n{\n\t{0, 1},\t\t// 0\n\t{1, 1},\t\t// 1\n\t{1, 2},\t\t// 2\n\t{1, 3},\t\t// 3\n\t{0, 3},\t\t// 4\n\t{0, 4},\t\t// 5\n\t{1, 4},\t\t// 6\n\t{2, 4},\t\t// 7\n\t{3, 4},\t\t// 8\n};\n\n// ***************************************************************************\n\nbool CTransition::build (const CMaterial &mat0, const CMaterial &mat1, const std::vector<const CZoneTemplate*> &arrayTemplate,\n\t\t\t\t\t\t const CLigoConfig &config, CLigoError *errors, CLigoError &mainErrors)\n{\n\t// Check size\n\tif ((arrayTemplate.size() != TransitionZoneCount))\n\t{\n\t\t// Error message\n\t\tmainErrors.MainError = CLigoError::UnknownError;\n\t\treturn false;\n\t}\n\n\t// Ok ?\n\tbool ok=true;\n\n\t// Check zone template edge count\n\tuint i;\n\tfor (i=0; i<TransitionZoneCount; i++)\n\t{\n\t\t// Must have 4 edges\n\t\tif (arrayTemplate[i]&&(arrayTemplate[i]->getEdges ().size()!=4))\n\t\t{\n\t\t\t// Error code\n\t\t\tmainErrors.MainError = CLigoError::MustHave4Edges;\n\t\t\terrors[i].MainError = CLigoError::MustHave4Edges;\n\t\t}\n\t}\n\n\t// continue ?\n\tif (ok)\n\t{\n\t\t// Get first edge\n\t\t_EdgeZone[0]=mat0.getEdge ();\n\n\t\t// Get second edge\n\t\t_EdgeZone[1]=mat1.getEdge ();\n\n\t\t// For the two others edges\n\t\tfor (sint32 k=2; k<(sint32)ZoneEdgeCount; k++)\n\t\t{\n\t\t\t// Get the first third edge found\n\t\t\tfor (i=0; i<TransitionZoneCount; i++)\n\t\t\t{\n\t\t\t\t// This template exist ?\n\t\t\t\tif (arrayTemplate[i])\n\t\t\t\t{\n\t\t\t\t\tuint j;\n\t\t\t\t\tfor (j=0; j<4; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get edge\n\t\t\t\t\t\tsint32 edge = TransitionZoneEdges[i][j];\n\n\t\t\t\t\t\t// The good edge ?\n\t\t\t\t\t\tif (((edge==k+1)||(edge==-(k+1))))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Back the ege\n\t\t\t\t\t\t\t_EdgeZone[k]=arrayTemplate[i]->getEdges ()[j];\n\n\t\t\t\t\t\t\t// Invert it if negative\n\t\t\t\t\t\t\tif (edge<0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Invert\n\t\t\t\t\t\t\t\t_EdgeZone[k].invert (config);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Break\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (j<4)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Get the inverted edges\n\t\tCZoneEdge invertedEdges[4];\n\t\tfor (i=0; i<4; i++)\n\t\t{\n\t\t\t// Copy the edge\n\t\t\tinvertedEdges[i]=_EdgeZone[i];\n\n\t\t\t// Invert it\n\t\t\tinvertedEdges[i].invert(config);\n\t\t}\n\n\t\t// false if can't build because some template are missing\n\t\tbool build=true;\n\n\t\t// Now check each zones against the edges\n\t\tfor (i=0; i<TransitionZoneCount; i++)\n\t\t{\n\t\t\t// Template present ?\n\t\t\tif (arrayTemplate[i])\n\t\t\t{\n\t\t\t\t// For each edge\n\t\t\t\tfor (uint j=0; j<4; j++)\n\t\t\t\t{\n\t\t\t\t\t// Get the edge number\n\t\t\t\t\tsint32 edge=TransitionZoneEdges[i][j];\n\n\t\t\t\t\t// Compare the edge\n\t\t\t\t\tif (edge<0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The same edge ?\n\t\t\t\t\t\tif (!invertedEdges[-edge-1].isTheSame (arrayTemplate[i]->getEdges()[j], config, errors[i]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tok=false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The same edge ?\n\t\t\t\t\t\tif (!_EdgeZone[edge-1].isTheSame (arrayTemplate[i]->getEdges()[j], config, errors[i]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tok=false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\t// Can't build\n\t\t\t\tbuild=false;\n\t\t}\n\n\t\t// Ok to build ?\n\t\tif (ok && build)\n\t\t{\n\t\t}\n\t}\n\n\t// Return error code\n\treturn ok;\n}\n\n// ***************************************************************************\n\nvoid CTransition::serial (NLMISC::IStream &s)\n{\n\t// Serial the main node\n\ts.xmlPush (\"LIGO_TRANSITION\");\n\n\t\t// Serial the header\n\t\ts.serialCheck (NELID(\"STGL\"));\n\n\t\t// Serial the version\n\t\t/*sint ver =*/ s.serialVersion (0);\n\n\t\t// Serial the edgezones\n\t\tuint i;\n\t\ts.xmlPush (\"EDGE_ZONES\");\n\t\t\tfor (i=0; i<ZoneEdgeCount; i++)\n\t\t\t\ts.xmlSerial (_EdgeZone[i], \"ELM\");\n\t\ts.xmlPop ();\n\n\t// Close the main node\n\ts.xmlPop ();\n}\n\n// ***************************************************************************\n\nbool CTransition::check (const CZoneTemplate &zoneTemplate, uint transitionNumber, const CLigoConfig &config, CLigoError &errors) const\n{\n\t// Return value\n\tbool ok = true;\n\n\t// For each edge\n\tfor (uint j=0; j<4; j++)\n\t{\n\t\t// Get the edge number\n\t\tsint32 edge=TransitionZoneEdges[transitionNumber][j];\n\n\t\t// Compare the edge\n\t\tif (edge<0)\n\t\t{\n\t\t\t// Invert the edge\n\t\t\tCZoneEdge invertedEdges = _EdgeZone[-edge-1];\n\t\t\tinvertedEdges.invert(config);\n\n\t\t\t// The same edge ?\n\t\t\tif (!invertedEdges.isTheSame (zoneTemplate.getEdges()[j], config, errors))\n\t\t\t{\n\t\t\t\tok=false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The same edge ?\n\t\t\tif (!_EdgeZone[edge-1].isTheSame (zoneTemplate.getEdges()[j], config, errors))\n\t\t\t{\n\t\t\t\tok=false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return status\n\treturn ok;\n}\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/ligo/transition.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_TRANSITION_H\n#define NL_TRANSITION_H\n\n#include \"nel/misc/types_nl.h\"\n\n// Ligo include\n#include \"zone_edge.h\"\n\n// NeL include\n//#include \"3d/zone.h\"\n\nnamespace NLLIGO\n{\n\nclass CZoneTemplate;\nclass CMaterial;\n\n/**\n * A transition template\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CTransition\n{\npublic:\n\n\t/// Some define\n\tenum\n\t{\n\t\tZoneEdgeCount = 4,\n\t\tTransitionZoneCount = 9,\n\t};\n\n\n\t/** Build method\n\t  *\n\t  *\n\t\tWe need 9 zone templates to create a transition set\n\n\t\t0\n\t\t********\n\t\t*1*0000*\n\t\t*1*0000*\n\t\t*1*0000*\n\t\t*1*0000*\n\t\t*1******\n\t\t*111111*\n\t\t********\n\n\t\t1\n\t\t********\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t***1111*\n\t\t*111111*\n\t\t********\n\n\t\t2\n\t\t********\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t*0*1111*\n\t\t********\n\n\t\t3\n\t\t********\n\t\t*111111*\n\t\t*111111*\n\t\t*111111*\n\t\t*111111*\n\t\t***1111*\n\t\t*0*1111*\n\t\t********\n\n\t\t4\n\t\t********\n\t\t*0000*1*\n\t\t*0000*1*\n\t\t*0000*1*\n\t\t*0000*1*\n\t\t*0000***\n\t\t*000000*\n\t\t********\n\n\t\t5\n\t\t********\n\t\t*000000*\n\t\t*000000*\n\t\t*000000*\n\t\t*000000*\n\t\t*0000***\n\t\t*0000*1*\n\t\t********\n\n\t\t6\n\t\t********\n\t\t*000000*\n\t\t*000000*\n\t\t*000000*\n\t\t*000000*\n\t\t********\n\t\t*111111*\n\t\t********\n\n\t\t7\n\t\t********\n\t\t*000000*\n\t\t*0000***\n\t\t*000*11*\n\t\t*00*111*\n\t\t***1111*\n\t\t*111111*\n\t\t********\n\n\t\t8\n\t\t********\n\t\t*000000*\n\t\t******0*\n\t\t*1111*0*\n\t\t*1111*0*\n\t\t*1111*0*\n\t\t*1111*0*\n\t\t********\n\n\t\tThe nine zones must be assembled like this:\n\n\t\tOy\n\n\t\t^\n\t\t|\n\t\t+-+-+-+-+\n\t\t|5|6|7|8|\n\t\t+-+-+-+-+\n\t\t|4|3| | |\n\t\t+-+-+-+-+\n\t\t| |2| | |\n\t\t+-+-+-+-+\n\t\t|0|1| | |\n\t\t-----------> Ox\n\t  *\n\t  * \\param tplt0 is the material lingo config file\n\t  * \\param config is the current lingo config file\n\t  * \\param arrayTemplate is an array of ligo zone template pointer of size 9. If a pointer is NULL, checks will be done on non NULL pointer\n\t  * but build will not be done.\n\t  * \\param arrayZone is an array of nel zone pointer of size 9. If a pointer is NULL, checks will be done but build will not be done.\n\t  * \\param config is the current lingo config file\n\t  * \\param errors is an array of error structure of size 9. One error structure by zone.\n\t  * \\return true if check success false if problem detected. Build is done if all the 18 pointers are not NULL.\n\t  */\n\tbool build (const CMaterial &mat0, const CMaterial &mat1, const std::vector<const CZoneTemplate*> &arrayTemplate,\n\t\t\t\tconst CLigoConfig &config, CLigoError *errors, CLigoError &mainErrors);\n\n\t/**\n\t  * Check if a transition zone template match with this transition template.\n\t  *\n\t  * \\param zoneTemplate is a zone template.\n\t  * \\param transition number is the number of the transition to test (0 ~ 8)\n\t  * \\param config is the current lingo config file\n\t  * \\param errors is an error handler filled with error code and message if the method return false.\n\t  *\n\t  * \\return true if check success false if problem detected. Errors are reported in the error[0].\n\t  */\n\tbool check (const CZoneTemplate &zoneTemplate, uint transitionNumber, const CLigoConfig &config, CLigoError &errors) const;\n\n\t/// Serial\n\tvoid serial (NLMISC::IStream &s);\n\nprivate:\n\n\t/** The 4 Edges that define the transitions set\n\t  *\n\t  * the 4 transitions are:\n\t  * 0 : *000000*\n\t  * 1 : *111111*\n\t  * 2 : *0*1111*\n\t  * 3 : *0000*1*\n\t  */\n\tCZoneEdge\t\t_EdgeZone[ZoneEdgeCount];\n\n\t/// Some static arries\n\tstatic\tsint32 TransitionZoneEdges[TransitionZoneCount][4];\n\tstatic\tsint32 TransitionZoneOffset[TransitionZoneCount][2];\n};\n\n}\n\n#endif // NL_TRANSITION_H\n\n/* End of transition.h */\n"
  },
  {
    "path": "code/nel/src/ligo/zone_bank.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdligo.h\"\n\n#include \"nel/ligo/zone_bank.h\"\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/o_xml.h\"\n\n#ifdef NL_OS_WINDOWS\n#ifndef NL_COMP_MINGW\n#define NOMINMAX\n#endif\n#include <windows.h>\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n// CZoneBankElement\n// ***************************************************************************\n\nstring CZoneBankElement::_NoCatTypeFound = STRING_NO_CAT_TYPE;\n\n// ---------------------------------------------------------------------------\nCZoneBankElement::CZoneBankElement()\n{\n\t_SizeX = _SizeY = 0;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBankElement::addCategory (const std::string &CatType, const std::string &CatValue)\n{\n\t_CategoriesMap.insert(pair<string,string>(CatType, CatValue));\n}\n\n// ---------------------------------------------------------------------------\nconst string& CZoneBankElement::getName ()\n{\n\treturn getCategory (\"zone\");\n}\n\n// ---------------------------------------------------------------------------\nconst string& CZoneBankElement::getSize ()\n{\n\treturn getCategory (\"size\");\n}\n\n// ---------------------------------------------------------------------------\nconst string& CZoneBankElement::getCategory (const string &CatType)\n{\n\tmap<string,string>::iterator it = _CategoriesMap.find (CatType);\n\tif (it == _CategoriesMap.end())\n\t\treturn _NoCatTypeFound;\n\telse\n\t\treturn it->second;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBankElement::convertSize()\n{\n\tconst string &sizeString =  getSize();\n\tstring sTmp;\n\tuint32 i;\n\n\tfor (i = 0; i < sizeString.size(); ++i)\n\t{\n\t\tif (sizeString[i] == 'x')\n\t\t\tbreak;\n\t\telse\n\t\t\tsTmp += sizeString[i];\n\t}\n\tfromString(sTmp, _SizeX);\n\n\t++i; sTmp = \"\";\n\tfor (; i < sizeString.size(); ++i)\n\t{\n\t\tsTmp += sizeString[i];\n\t}\n\tfromString(sTmp, _SizeY);\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBankElement::serial (NLMISC::IStream &f)\n{\n\tf.xmlPush (\"LIGOZONE\");\n\n\tsint version = 1;\n\tf.serialVersion (version);\n\tstring check = \"LIGOZONE\";\n\tf.serialCheck (check);\n\n\tf.xmlPush (\"CATEGORIES\");\n\t\tf.serialCont (_CategoriesMap);\n\tf.xmlPop ();\n\n\tf.xmlPush (\"MASK\");\n\t\tf.serialCont (_Mask);\n\tf.xmlPop ();\n\n\tf.xmlPop ();\n\n\tconvertSize();\n}\n\n\n// ---------------------------------------------------------------------------\nvoid CZoneBankElement::setMask (const std::vector<bool> &mask, uint8 sizeX, uint8 sizeY)\n{\n\t_SizeX = sizeX;\n\t_SizeY = sizeY;\n\t_Mask = mask;\n}\n\n// ***************************************************************************\n// CZoneBank\n// ***************************************************************************\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::debugSaveInit (CZoneBankElement &zbeTmp, const string &fileName)\n{\n\ttry\n\t{\n\t\tCOFile fileOut;\n\t\tfileOut.open (fileName);\n\t\tCOXml output;\n\t\toutput.init (&fileOut);\n\t\tzbeTmp.serial (output);\n\t}\n\tcatch (const Exception& /*e*/)\n\t{\n\t}\n\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::debugInit(const std::string &sPath) // \\ todo trap remove this\n{\n\tCZoneBankElement zbeTmp;\n\tzbeTmp.addCategory (\"zone\", \"Zone001\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"material\", \"titFleur\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone001.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\n\n\tzbeTmp.addCategory (\"zone\", \"Zone002\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"material\", \"titFleur\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone002.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone003\");\n\tzbeTmp.addCategory (\"size\", \"2x2\");\n\tzbeTmp.addCategory (\"material\", \"titFleur\");\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (false);\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone003.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone004\");\n\tzbeTmp.addCategory (\"size\", \"2x2\");\n\tzbeTmp.addCategory (\"material\", \"grozFleur\");\n\tzbeTmp._Mask.push_back (false);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone004.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone005\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"material\", \"grozFleur\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone005.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone006\");\n\tzbeTmp.addCategory (\"size\", \"4x2\");\n\tzbeTmp.addCategory (\"material\", \"grozFleur\");\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (false);\n\tzbeTmp._Mask.push_back (false);\n\tzbeTmp._Mask.push_back (false);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (false);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone006.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone007\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"material\", \"grozFleur\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone007.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone008\");\n\tzbeTmp.addCategory (\"size\", \"2x2\");\n\tzbeTmp.addCategory (\"material\", \"prairie\");\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone008.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone009\");\n\tzbeTmp.addCategory (\"size\", \"2x2\");\n\tzbeTmp.addCategory (\"material\", \"prairie\");\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone009.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"Zone010\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"material\", \"prairie\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"Zone010.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT0\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"0\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT0.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT1\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"1\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT1.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT2\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"2\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT2.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT3\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"3\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT3.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT4\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"4\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT4.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT5\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"5\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT5.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT6\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"6\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT6.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT7\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"7\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT7.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"WT8\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"grozFleur-prairie\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"8\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"WT8.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT0\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"0\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT0.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT1\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"1\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT1.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT2\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"Flat\");\n\tzbeTmp.addCategory (\"transnum\", \"2\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT2.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT3\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"3\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT3.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT4\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"4\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT4.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT5\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerA\");\n\tzbeTmp.addCategory (\"transnum\", \"5\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT5.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT6\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"6\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT6.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT7\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"7\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT7.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n\tzbeTmp.addCategory (\"zone\", \"ZT8\");\n\tzbeTmp.addCategory (\"size\", \"1x1\");\n\tzbeTmp.addCategory (\"transname\", \"titFleur-grozFleur\");\n\tzbeTmp.addCategory (\"transtype\", \"CornerB\");\n\tzbeTmp.addCategory (\"transnum\", \"8\");\n\tzbeTmp._Mask.push_back (true);\n\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(), zbeTmp));\n\tdebugSaveInit (zbeTmp, sPath + \"ZT8.ligozone\");\n\tzbeTmp._CategoriesMap.clear ();\n\tzbeTmp._Mask.clear ();\n\t_ElementsMap.clear ();\n\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::reset ()\n{\n\t_ElementsMap.clear ();\n\t_Selection.clear ();\n}\n\n#ifdef NL_OS_WINDOWS\n// ---------------------------------------------------------------------------\nbool CZoneBank::initFromPath(const std::string &sPathName, std::string &error)\n{\n\tchar sDirBackup[512];\n\tGetCurrentDirectory (512, sDirBackup);\n\tSetCurrentDirectory (sPathName.c_str());\n\tWIN32_FIND_DATA findData;\n\tHANDLE hFind;\n\thFind = FindFirstFile (\"*.ligozone\", &findData);\n\n\twhile (hFind != INVALID_HANDLE_VALUE)\n\t{\n\t\t// If the name of the file is not . or .. then its a valid entry in the DataBase\n\t\tif (!((strcmp (findData.cFileName, \".\") == 0) || (strcmp (findData.cFileName, \"..\") == 0)))\n\t\t{\n\t\t\tif (!addElement (findData.cFileName, error))\n\t\t\t\treturn false;\n\t\t}\n\t\tif (FindNextFile (hFind, &findData) == 0)\n\t\t\tbreak;\n\t}\n\tSetCurrentDirectory (sDirBackup);\n\treturn true;\n}\n#endif // NL_OS_WINDOWS\n\n// ---------------------------------------------------------------------------\nbool CZoneBank::addElement (const std::string &elementName, std::string &error)\n{\n\ttry\n\t{\n\t\tCZoneBankElement zbeTmp;\n\t\tCIFile fileIn;\n\t\tif (fileIn.open (elementName))\n\t\t{\n\t\t\tCIXml input;\n\t\t\tinput.init (fileIn);\n\t\t\tzbeTmp.serial (input);\n\t\t\t_ElementsMap.insert (pair<string,CZoneBankElement>(zbeTmp.getName(),zbeTmp));\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\terror = \"Can't open file \" + elementName;\n\t\t}\n\t}\n\tcatch (const Exception& e)\n\t{\n\t\terror = \"Error while loading ligozone \"+elementName+\" : \"+e.what();\n\t}\n\treturn false;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::getCategoriesType (std::vector<std::string> &CategoriesType)\n{\n\tmap<string,CZoneBankElement>::iterator itElt = _ElementsMap.begin();\n\n\twhile (itElt != _ElementsMap.end())\n\t{\n\t\tCZoneBankElement &rZBE = itElt->second;\n\n\t\tmap<string,string>::iterator it = rZBE._CategoriesMap.begin();\n\n\t\twhile (it != rZBE._CategoriesMap.end())\n\t\t{\n\t\t\tbool bFound = false;\n\t\t\tfor (uint32 k = 0; k < CategoriesType.size(); ++k)\n\t\t\t\tif (it->first == CategoriesType[k])\n\t\t\t\t{\n\t\t\t\t\tbFound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (!bFound)\n\t\t\t\tCategoriesType.push_back (it->first);\n\n\t\t\t++it;\n\t\t}\n\t\t++itElt;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::getCategoryValues (const std::string &CategoryType, std::vector<std::string> &CategoryValues)\n{\n\tmap<string,CZoneBankElement>::iterator itElt = _ElementsMap.begin();\n\n\twhile (itElt != _ElementsMap.end())\n\t{\n\t\tCZoneBankElement &rZBE = itElt->second;\n\n\t\tmap<string,string>::iterator it = rZBE._CategoriesMap.find (CategoryType);\n\n\t\tif (it != rZBE._CategoriesMap.end())\n\t\t{\n\t\t\tbool bFound = false;\n\t\t\tfor (uint32 k = 0; k < CategoryValues.size(); ++k )\n\t\t\t\tif (it->second == CategoryValues[k])\n\t\t\t\t{\n\t\t\t\t\tbFound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (!bFound)\n\t\t\t\tCategoryValues.push_back (it->second);\n\t\t}\n\t\t++itElt;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nCZoneBankElement *CZoneBank::getElementByZoneName (const std::string &ZoneName)\n{\n\tmap<string,CZoneBankElement>::iterator it = _ElementsMap.find (ZoneName);\n\tif (it != _ElementsMap.end())\n\t{\n\t\treturn &(it->second);\n\t}\n\treturn NULL;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::resetSelection ()\n{\n\t_Selection.clear ();\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::addOrSwitch (const std::string &CategoryType, const std::string &CategoryValue)\n{\n\tmap<string,CZoneBankElement>::iterator itElt = _ElementsMap.begin();\n\n\twhile (itElt != _ElementsMap.end())\n\t{\n\t\tCZoneBankElement &rZBE = itElt->second;\n\n\t\tmap<string,string>::iterator it = rZBE._CategoriesMap.find (CategoryType);\n\n\t\tif (it != rZBE._CategoriesMap.end())\n\t\t{\n\t\t\tif (it->second == CategoryValue)\n\t\t\t{\n\t\t\t\t// Check if the element is not already present in the selection\n\t\t\t\tbool bFound = false;\n\t\t\t\tfor (uint32 k = 0; k < _Selection.size(); ++k )\n\t\t\t\t\tif (&rZBE == _Selection[k])\n\t\t\t\t\t{\n\t\t\t\t\t\tbFound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\tif (!bFound)\n\t\t\t\t\t_Selection.push_back (&rZBE);\n\t\t\t}\n\t\t}\n\t\t++itElt;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::addAndSwitch (const std::string &CategoryType, const std::string &CategoryValue)\n{\n\tuint32 i, j;\n\t// And the selection with some constraints\n\t// All elements of the selection must have a catType and catValue equal to those given in parameters\n\tfor (i = 0; i < _Selection.size(); ++i)\n\t{\n\t\tCZoneBankElement *pZBE = _Selection[i];\n\t\tbool bFound = false;\n\n\t\tmap<string,string>::iterator it = pZBE->_CategoriesMap.find (CategoryType);\n\t\tif (it != pZBE->_CategoriesMap.end())\n\t\t{\n\t\t\tif (it->second == CategoryValue)\n\t\t\t\tbFound = true;\n\t\t}\n\t\tif (!bFound)\n\t\t{\n\t\t\t_Selection[i] = NULL; // Mark this item to be removed\n\t\t}\n\t}\n\t// Remove all unused items\n\tfor (i = 0, j = 0; i < _Selection.size(); ++i)\n\t{\n\t\tif (_Selection[i] != NULL)\n\t\t{\n\t\t\t_Selection[j] = _Selection[i];\n\t\t\t++j;\n\t\t}\n\t}\n\t_Selection.resize (j);\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneBank::getSelection (std::vector<CZoneBankElement*> &SelectedElements)\n{\n\tSelectedElements = _Selection;\n}\n\n// ***************************************************************************\n\n} // namespace NLLIGO\n"
  },
  {
    "path": "code/nel/src/ligo/zone_edge.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n// Ligo include\n#include \"zone_edge.h\"\n#include \"nel/ligo/ligo_config.h\"\n#include \"ligo_error.h\"\n\n// NeL include\n#include \"nel/misc/matrix.h\"\n\nusing namespace NLMISC;\n\nnamespace NLLIGO\n{\n\n// ***************************************************************************\n\nbool CZoneEdge::build (const std::vector<NLMISC::CVector> &theEdge, const std::vector<uint32> &theId, uint rotation,\n\t\t\t\tsint32 offsetX, sint32 offsetY, const CLigoConfig &config, CLigoError &errors)\n{\n\t// Some checks\n// no need, it s an uint\tnlassert (rotation>=0);\n\tnlassert (rotation<=3);\n\tnlassert (theEdge.size() == theId.size());\n\n\t// Cancels errors\n\terrors.clear ();\n\n\t// Errors ?\n\tbool ok = true;\n\n\t// Check first position\n\tCVector toCheck (theEdge[0].x, theEdge[0].y, 0);\n\tif ((float)fabs (toCheck.norm())>config.Snap)\n\t{\n\t\t// Vertex error\n\t\terrors.pushVertexError (CLigoError::UnknownError, 0);\n\t\tok = false;\n\t}\n\n\t// Check last position\n\tuint lastIndex = (uint)theEdge.size()-1;\n\ttoCheck  = CVector (theEdge[lastIndex].x, theEdge[lastIndex].y, 0);\n\tif (((toCheck-CVector (config.CellSize, 0, 0)).norm())>config.Snap)\n\t{\n\t\t// Vertex error\n\t\terrors.pushVertexError (CLigoError::UnknownError, 0);\n\t\tok = false;\n\t}\n\n\t// No error ? Build!\n\tif (ok)\n\t{\n\t\t_TheEdge = theEdge;\n\t\t_Rotation = rotation;\n\t\t_OffsetX = offsetX;\n\t\t_OffsetY = offsetY;\n\t\t_Id = theId;\n\t}\n\n\treturn ok;\n}\n\n// ***************************************************************************\n\nbool CZoneEdge::isSymetrical (const CLigoConfig &config, CLigoError &errors) const\n{\n\t// Cancels errors\n\terrors.clear ();\n\n\t// Errors ?\n\tbool ok = true;\n\n\t// For each internal vertices\n\tuint vert;\n\tfor (vert=0; vert<_TheEdge.size(); vert++)\n\t{\n\t\t// Symmetrical value\n\t\tCVector sym = CVector (config.CellSize-_TheEdge[vert].x, _TheEdge[vert].y, _TheEdge[vert].z);\n\n\t\t// Others vertices\n\t\tuint vert2;\n\t\tfor (vert2=0; vert2<_TheEdge.size(); vert2++)\n\t\t{\n\t\t\t// Not the same ?\n\t\t\tif (vert != vert2)\n\t\t\t{\n\t\t\t\t// Snapped ?\n\t\t\t\tif ((_TheEdge[vert2]-sym).norm() <= config.Snap)\n\t\t\t\t{\n\t\t\t\t\t// Good, next one\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Not found ?\n\t\tif (vert2>=_TheEdge.size())\n\t\t{\n\t\t\t// Error\n\t\t\tok = false;\n\n\t\t\t// Push error message\n\t\t\terrors.pushVertexError (CLigoError::NotSymetrical, _Id[vert]);\n\t\t\terrors.MainError = CLigoError::NotSymetrical;\n\t\t}\n\t}\n\n\t// Return error code\n\treturn ok;\n}\n\n// ***************************************************************************\n\nbool CZoneEdge::isTheSame (const CZoneEdge &other, const CLigoConfig &config, CLigoError &errors) const\n{\n\t// Same vertex count ?\n\tif (_TheEdge.size() != other._TheEdge.size())\n\t{\n\t\t// Error\n\t\terrors.MainError = CLigoError::NotSameVerticesNumber;\n\t\treturn false;\n\t}\n\n\t// Errors ?\n\tbool ok = true;\n\n\t// For each internal vertices\n\tuint vert;\n\tfor (vert=0; vert<_TheEdge.size(); vert++)\n\t{\n\t\t// The same ?\n\t\tconst CVector &pos0 = _TheEdge[vert];\n\t\tconst CVector &pos1 = other._TheEdge[vert];\n\t\tif ((pos0-pos1).norm() > config.Snap)\n\t\t{\n\t\t\t// Error\n\t\t\tok = false;\n\n\t\t\t// Push error message\n\t\t\terrors.pushVertexError (CLigoError::NotSameVertex, other._Id[vert]);\n\t\t\terrors.MainError = CLigoError::NotSameVertex;\n\t\t}\n\t}\n\n\t// Return error code\n\treturn ok;\n}\n\n// ***************************************************************************\n\nvoid CZoneEdge::serial (NLMISC::IStream& s)\n{\n\t// Serial the version\n\t/*sint ver =*/ s.serialVersion (0);\n\n\ts.xmlPush (\"VERTICES\");\n\t\ts.serialCont (_TheEdge);\n\ts.xmlPop ();\n\n\ts.xmlPush (\"VERTICES_ID\");\n\t\ts.serialCont (_Id);\n\ts.xmlPop ();\n\n\ts.xmlSerial (_Rotation, \"ROTATION\");\n\n\ts.xmlSerial (_OffsetX, _OffsetY, \"OFFSET\");\n}\n\n// ***************************************************************************\n\nvoid CZoneEdge::invert (const CLigoConfig &config)\n{\n\t// Copy the array\n\tconst std::vector<NLMISC::CVector>\tcopy = _TheEdge;\n\n\t// For each internal vertices\n\tuint vert;\n\tfor (vert=0; vert<_TheEdge.size(); vert++)\n\t{\n\t\t// Invert\n\t\tconst CVector &pos = copy[_TheEdge.size()-vert-1];\n\t\t_TheEdge[vert] = CVector (config.CellSize - pos.x, pos.y, pos.z);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CZoneEdge::buildMatrix (NLMISC::CMatrix& mat, const CLigoConfig &config) const\n{\n\t// Build a transformation matrix\n\tmat.identity();\n\tmat.rotateZ ((float)Pi*(float)_Rotation/2.f);\n\tmat.setPos (CVector (config.CellSize*(float)_OffsetX, config.CellSize*(float)_OffsetY, 0));\n}\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/ligo/zone_edge.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ZONE_EDGE_H\n#define NL_ZONE_EDGE_H\n\n// NeL include\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/vector.h\"\n\n// STL include\n#include <vector>\n\nnamespace NLMISC\n{\n\tclass IStream;\n\tclass CMatrix;\n}\n\nnamespace NLLIGO\n{\n\nclass CLigoError;\nclass CLigoConfig;\n\n/**\n * A ZoneEdge descriptor\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CZoneEdge\n{\npublic:\n\n\t/// Build a edge zone\n\tbool build (const std::vector<NLMISC::CVector> &theEdge, const std::vector<uint32> &theId, uint rotation,\n\t\t\t\tsint32 offsetX, sint32 offsetY, const CLigoConfig &config, CLigoError &errors);\n\n\t/// Serial\n\tvoid serial (NLMISC::IStream& s);\n\n\t/// Is symetrical ?\n\tbool isSymetrical (const CLigoConfig &config, CLigoError &errors) const;\n\n\t/// Is the same edge ?\n\tbool isTheSame (const CZoneEdge &other, const CLigoConfig &config, CLigoError &errors) const;\n\n\t/// Invert the edge\n\tvoid invert (const CLigoConfig &config);\n\n\t/// Return the vertex count\n\tuint getNumVertex () const { return (uint)_TheEdge.size(); }\n\n\t/// Return the vertex\n\tconst NLMISC::CVector& getVertex (uint id) const { return _TheEdge[id]; }\n\n\t/// Return the matrix\n\tvoid buildMatrix (NLMISC::CMatrix& mat, const CLigoConfig &config) const;\n\n\t/// Get values\n\tuint32 getRotation () const { return _Rotation; }\n\tsint32 getOffsetX () const { return _OffsetX; }\n\tsint32 getOffsetY () const { return _OffsetY; }\n\nprivate:\n\n\t/// The vector of position for this edge\n\tstd::vector<NLMISC::CVector>\t_TheEdge;\n\n\t/// Id of the vertices\n\tstd::vector<uint32>\t\t\t\t_Id;\n\n\t/// Rotation of the edge. Must be 0, 1, 2, 3. The rotation angle is Pi/2 * (double)_Rotation in CCW.\n\tuint32\t\t\t\t\t\t\t_Rotation;\n\n\t/// X an Y offset of the edge. the position of the i-th vertex is rotate (_Rotation) * (theEdge[i], 0, 0) + (_OffsetX, _OffsetY, 0)\n\tsint32\t\t\t\t\t\t\t_OffsetX;\n\tsint32\t\t\t\t\t\t\t_OffsetY;\n};\n\n}\n\n#endif // NL_ZONE_EDGE_H\n\n/* End of zone_edge.h */\n"
  },
  {
    "path": "code/nel/src/ligo/zone_region.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"nel/ligo/zone_region.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLLIGO\n{\n\nstring CZoneRegion::_StringOutOfBound;\n\n// ***************************************************************************\n// SZoneUnit\n// ***************************************************************************\n\n// ---------------------------------------------------------------------------\nCZoneRegion::SZoneUnit::SZoneUnit()\n{\n\tZoneName = STRING_UNUSED;\n\tPosX = PosY = 0;\n\tRot = Flip = 0;\n\tSharingMatNames[0] = STRING_UNUSED;\n\tSharingMatNames[1] = STRING_UNUSED;\n\tSharingMatNames[2] = STRING_UNUSED;\n\tSharingMatNames[3] = STRING_UNUSED;\n\tSharingCutEdges[0] = 0;\n\tSharingCutEdges[1] = 0;\n\tSharingCutEdges[2] = 0;\n\tSharingCutEdges[3] = 0;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneRegion::SZoneUnit::serial (NLMISC::IStream &f)\n{\n\tf.xmlSerial (ZoneName, \"NAME\");\n\tf.xmlSerial (PosX, \"X\");\n\tf.xmlSerial (PosY, \"Y\");\n\tf.xmlSerial (Rot, \"ROT\");\n\tf.xmlSerial (Flip, \"FLIP\");\n\n\tfor (uint32 i = 0; i < 4; ++i)\n\t{\n\t\tf.xmlSerial (SharingMatNames[i], \"MAT_NAMES\");\n\t\tf.xmlSerial (SharingCutEdges[i], \"CUR_EDGES\");\n\t}\n}\n\n// ---------------------------------------------------------------------------\nconst CZoneRegion::SZoneUnit& CZoneRegion::SZoneUnit::operator=(const CZoneRegion::SZoneUnit&zu)\n{\n\tthis->ZoneName\t= zu.ZoneName;\n\tthis->PosX\t\t= zu.PosX;\n\tthis->PosY\t\t= zu.PosY;\n\tthis->Rot\t\t= zu.Rot;\n\tthis->Flip\t\t= zu.Flip;\n\tfor (uint32 i = 0; i < 4; ++i)\n\t{\n\t\tthis->SharingMatNames[i] = zu.SharingMatNames[i];\n\t\tthis->SharingCutEdges[i] = zu.SharingCutEdges[i];\n\t}\n\treturn *this;\n}\n\n\n// ***************************************************************************\n// SZoneUnit2\n// ***************************************************************************\n\n// ---------------------------------------------------------------------------\nCZoneRegion::SZoneUnit2::SZoneUnit2()\n{\n\tDateLow = 0;\n\tDateHigh = 0;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneRegion::SZoneUnit2::serial (NLMISC::IStream &f)\n{\n\t/*sint32 version =*/ f.serialVersion (0);\n\n\tSZoneUnit::serial (f);\n\tf.xmlSerial (DateLow, \"LOW\");\n\tf.xmlSerial (DateHigh, \"HIGH\");\n}\n\n// ---------------------------------------------------------------------------\nconst CZoneRegion::SZoneUnit2& CZoneRegion::SZoneUnit2::operator=(const CZoneRegion::SZoneUnit2&zu)\n{\n\tthis->ZoneName\t= zu.ZoneName;\n\tthis->PosX\t\t= zu.PosX;\n\tthis->PosY\t\t= zu.PosY;\n\tthis->Rot\t\t= zu.Rot;\n\tthis->Flip\t\t= zu.Flip;\n\tfor (uint32 i = 0; i < 4; ++i)\n\t{\n\t\tthis->SharingMatNames[i] = zu.SharingMatNames[i];\n\t\tthis->SharingCutEdges[i] = zu.SharingCutEdges[i];\n\t}\n\tthis->DateLow\t= zu.DateLow;\n\tthis->DateHigh\t= zu.DateHigh;\n\treturn *this;\n}\n\n// ---------------------------------------------------------------------------\nconst CZoneRegion::SZoneUnit2& CZoneRegion::SZoneUnit2::operator=(const CZoneRegion::SZoneUnit&zu)\n{\n\tthis->ZoneName\t= zu.ZoneName;\n\tthis->PosX\t\t= zu.PosX;\n\tthis->PosY\t\t= zu.PosY;\n\tthis->Rot\t\t= zu.Rot;\n\tthis->Flip\t\t= zu.Flip;\n\tfor (uint32 i = 0; i < 4; ++i)\n\t{\n\t\tthis->SharingMatNames[i] = zu.SharingMatNames[i];\n\t\tthis->SharingCutEdges[i] = zu.SharingCutEdges[i];\n\t}\n\tthis->DateLow\t= 0;\n\tthis->DateHigh\t= 0;\n\treturn *this;\n}\n\n// ***************************************************************************\n// CZoneRegion\n// ***************************************************************************\n\n// ---------------------------------------------------------------------------\nCZoneRegion::CZoneRegion()\n{\n\t_StringOutOfBound = STRING_OUT_OF_BOUND;\n\t_MinX = _MinY = 0;\n\t_MaxX = _MaxY = -1;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneRegion::serial (NLMISC::IStream &f)\n{\n\tf.xmlPush (\"LAND\");\n\n\t\tsint32 version = f.serialVersion (1);\n\t\tf.serialCheck (NELID(\"DNAL\"));\n\n\t\tf.xmlSerial (_MinX, \"MIN_X\");\n\t\tf.xmlSerial (_MinY, \"MIN_Y\");\n\t\tf.xmlSerial (_MaxX, \"MAX_X\");\n\t\tf.xmlSerial (_MaxY, \"MAX_Y\");\n\n\t\tif (version == 1)\n\t\t{\n\t\t\tf.serialCont (_Zones);\n\t\t}\n\n\t\tif (version == 0)\n\t\t{\n\t\t\tstd::vector<SZoneUnit> vZonesTmp;\n\t\t\tf.serialCont (vZonesTmp);\n\t\t\t_Zones.resize (vZonesTmp.size());\n\t\t\tfor (uint32 i = 0; i < vZonesTmp.size(); ++i)\n\t\t\t\t_Zones[i] = vZonesTmp[i];\n\t\t}\n\n\tf.xmlPop ();\n}\n\n// ---------------------------------------------------------------------------\nconst string &CZoneRegion::getName (sint32 x, sint32 y) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn _StringOutOfBound;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].ZoneName;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint8 CZoneRegion::getPosX (sint32 x, sint32 y) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].PosX;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint8 CZoneRegion::getPosY (sint32 x, sint32 y) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].PosY;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint8 CZoneRegion::getRot (sint32 x, sint32 y) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].Rot;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint8 CZoneRegion::getFlip (sint32 x, sint32 y) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].Flip;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint8 CZoneRegion::getCutEdge (sint32 x, sint32 y, uint8 pos) const\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].SharingCutEdges[pos];\n\t}\n}\n\n// ---------------------------------------------------------------------------\nuint32 CZoneRegion::getDate (sint32 x, sint32 y, uint8 lowOrHigh) const // lowOrHigh == 0 -> low\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tif (lowOrHigh == 0)\n\t\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].DateLow;\n\t\telse\n\t\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].DateHigh;\n\t}\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneRegion::resize (sint32 newMinX, sint32 newMaxX, sint32 newMinY, sint32 newMaxY)\n{\n\tsint32 i, j;\n\tvector<SZoneUnit2> newZones;\n\tSZoneUnit2 zuTmp;\n\n\tnewZones.resize ((1+newMaxX-newMinX)*(1+newMaxY-newMinY));\n\tsint32 newStride = 1+newMaxX-newMinX;\n\tsint32 Stride = 1+_MaxX-_MinX;\n\tfor (j = newMinY; j <= newMaxY; ++j)\n\tfor (i = newMinX; i <= newMaxX; ++i)\n\t{\n\t\tif ((i >= _MinX)&&(i <= _MaxX)&&(j >= _MinY)&&(j <= _MaxY))\n\t\t{\n\t\t\tnewZones[(i-newMinX)+(j-newMinY)*newStride] = _Zones[(i-_MinX)+(j-_MinY)*Stride];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnewZones[(i-newMinX)+(j-newMinY)*newStride] = zuTmp;\n\t\t}\n\t}\n\t_MinX = newMinX; _MaxX = newMaxX;\n\t_MinY = newMinY; _MaxY = newMaxY;\n\t_Zones = newZones;\n}\n\n// ---------------------------------------------------------------------------\nvoid CZoneRegion::basicSet (sint32 x, sint32 y, sint32 PosX, sint32 PosY,  const std::string &ZoneName)\n{\n\t// Do we need to resize ?\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\tsint32 newMinX = (x<_MinX?x:_MinX), newMinY = (y<_MinY?y:_MinY);\n\t\tsint32 newMaxX = (x>_MaxX?x:_MaxX), newMaxY = (y>_MaxY?y:_MaxY);\n\n\t\tresize (newMinX, newMaxX, newMinY, newMaxY);\n\t}\n\tsint32 stride = (1+_MaxX-_MinX); // Nb to go to next line\n\n\t_Zones[(x-_MinX)+(y-_MinY)*stride].ZoneName = ZoneName;\n\t_Zones[(x-_MinX)+(y-_MinY)*stride].PosX = (uint8)PosX;\n\t_Zones[(x-_MinX)+(y-_MinY)*stride].PosY = (uint8)PosY;\n}\n\n// ---------------------------------------------------------------------------\nvoid SPiece::rotFlip (uint8 rot, uint8 flip)\n{\n\tuint8 nTmp;\n\tsint32 i, j;\n\n\tif (flip == 1)\n\t{\n\t\tfor (j = 0; j < h; ++j)\n\t\tfor (i = 0; i < (w/2); ++i)\n\t\t{\n\t\t\tnTmp = Tab[i+j*w];\n\t\t\tTab[i+j*w] = Tab[(w-1-i)+j*w];\n\t\t\tTab[(w-1-i)+j*w] = nTmp;\n\t\t}\n\t}\n\n\tif (rot == 1)\n\t{\n\t\tvector<uint8> TabDest;\n\t\tTabDest.resize (Tab.size());\n\t\tfor (j = 0; j < h; ++j)\n\t\tfor (i = 0; i < w;  ++i)\n\t\t\tTabDest[j+i*h] = Tab[i+(h-1-j)*w];\n\t\tTab = TabDest;\n\t\ti = w;\n\t\tw = h;\n\t\th = i;\n\t}\n\n\tif (rot == 2)\n\t{\n\t\tfor (j = 0; j < (h/2); ++j)\n\t\tfor (i = 0; i < w; ++i)\n\t\t{\n\t\t\tnTmp = Tab[i+j*w];\n\t\t\tTab[i+j*w] = Tab[(w-1-i)+(h-1-j)*w];\n\t\t\tTab[(w-1-i)+(h-1-j)*w] = nTmp;\n\t\t}\n\t\tif ((h/2)*2 != h)\n\t\t{\n\t\t\tj = (h/2);\n\t\t\tfor (i = 0; i < (w/2); ++i)\n\t\t\t{\n\t\t\t\tnTmp = Tab[i+j*w];\n\t\t\t\tTab[i+j*w] = Tab[(w-1-i)+j*w];\n\t\t\t\tTab[(w-1-i)+j*w] = nTmp;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (rot == 3)\n\t{\n\t\tvector<uint8> TabDest;\n\t\tTabDest.resize (Tab.size());\n\t\tfor (j = 0; j < h; ++j)\n\t\tfor (i = 0; i < w;  ++i)\n\t\t\tTabDest[j+i*h] = Tab[w-1-i+j*w];\n\t\tTab = TabDest;\n\t\ti = w;\n\t\tw = h;\n\t\th = i;\n\t}\n}\n\n// ***************************************************************************\n\nstd::string\tCZoneRegion::getSharingMatNames (sint32 x, sint32 y, uint edge)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn _StringOutOfBound;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].SharingMatNames[edge];\n\t}\n}\n\n// ***************************************************************************\n\nuint8 CZoneRegion::getSharingCutEdges (sint32 x, sint32 y, uint edge)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn 0xff;\n\t}\n\telse\n\t{\n\t\treturn _Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].SharingCutEdges[edge];\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setName (sint32 x, sint32 y, const std::string &newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].ZoneName = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setPosX (sint32 x, sint32 y, uint8 newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].PosX = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setPosY (sint32 x, sint32 y, uint8 newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].PosY = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setRot (sint32 x, sint32 y, uint8 newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].Rot = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setFlip (sint32 x, sint32 y, uint8 newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].Flip = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setSharingMatNames (sint32 x, sint32 y, uint edge, const std::string &newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].SharingMatNames[edge] = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CZoneRegion::setSharingCutEdges (sint32 x, sint32 y, uint edge, uint8 newValue)\n{\n\tif ((x < _MinX) || (x > _MaxX) ||\n\t\t(y < _MinY) || (y > _MaxY))\n\t{\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\t_Zones[(x-_MinX)+(y-_MinY)*(1+_MaxX-_MinX)].SharingCutEdges[edge] = newValue;\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\n\n} // namespace NLLIGO\n"
  },
  {
    "path": "code/nel/src/ligo/zone_template.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdligo.h\"\n#include \"zone_template.h\"\n#include \"ligo_error.h\"\n#include \"nel/ligo/ligo_config.h\"\n\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/matrix.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLLIGO\n{\n\nconst uint SnappedXFlag = 1;\nconst uint SnappedYFlag = 2;\n\n// ***************************************************************************\n\ninline void CZoneTemplate::snap (float& value, float snap)\n{\n\t// Snap it\n\tvalue  = snap * (float) floor ( (value / snap) + 0.5f );\n}\n\n// ***************************************************************************\n\ninline bool CZoneTemplate::snapOnGrid (float& value, float resolution, float snap)\n{\n\t// Calc the floor\n\tfloat _floor = (float) ( resolution * floor (value / resolution) );\n\tnlassert (_floor<=value);\n\n\t// Calc the remainder\n\tfloat remainder = value - _floor;\n\t//nlassert ( (remainder>=0) && (remainder<resolution) );\n\n\t// Check the snape\n\tif ( remainder <= snap )\n\t{\n\t\t// Flag it\n\t\tvalue = _floor;\n\n\t\t// Floor is good\n\t\treturn true;\n\t}\n\telse if ( (resolution - remainder) <= snap )\n\t{\n\t\t// Flag it\n\t\tvalue = _floor + resolution;\n\n\t\t// Floor + resolution is good\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\ninline bool CZoneTemplate::isSnapedOnGrid (float value, float resolution, float snap)\n{\n\t// Snapped\n\tfloat snapped = value;\n\treturn snapOnGrid (snapped, resolution, snap);\n}\n\n// ***************************************************************************\n\ninline sint32 CZoneTemplate::getSnappedIndex (float value, float resolution, float snap)\n{\n\t// Snapped\n\tfloat snapped = value;\n\n\t// This value must be snapped\n\tnlverify (snapOnGrid (snapped, resolution, snap));\n\n\t// Return the index\n\treturn (sint32) floor ( (snapped / resolution) + 0.5f );\n}\n\n// ***************************************************************************\n\nbool CZoneTemplate::build (const std::vector<NLMISC::CVector> &vertices, const std::vector< std::pair<uint, uint> > &indexes, const CLigoConfig &config, CLigoError &errors)\n{\n\t// Clear the error message\n\terrors.clear ();\n\n\t// Make an boundary flag array\n\tvector<uint>\t\tboundaryFlags;\n\n\t// Vertices count\n\tuint vertexCount = (uint)vertices.size();\n\n\t// Resize the array\n\tboundaryFlags.resize (vertexCount, 0);\n\n\t// *** Build the flag array and the snapped vertex array\n\n\t// For each vertices\n\tuint vertex;\n\tfor (vertex = 0; vertex < vertexCount; vertex++)\n\t{\n\t\t// Snap the point on the X grid\n\t\tif (isSnapedOnGrid (vertices[vertex].x, config.CellSize, config.Snap))\n\t\t\t// Flag on X\n\t\t\tboundaryFlags[vertex]|=SnappedXFlag;\n\n\t\t// Snap the point on the Y grid\n\t\tif (isSnapedOnGrid (vertices[vertex].y, config.CellSize, config.Snap))\n\t\t\t// Flag on Y\n\t\t\tboundaryFlags[vertex]|=SnappedYFlag;\n\t}\n\n\t// *** Build the edge set\n\tmultimap<uint, uint>\tedgePair;\n\tmultimap<uint, uint>\tedgePairReverse;\n\n\t// Index count\n\tuint edgeCount = (uint)indexes.size();\n\n\t// For each vertices\n\tuint edge;\n\tfor (edge = 0; edge < edgeCount; edge++)\n\t{\n\t\t// Ref on the pair\n\t\tconst pair<uint, uint> &theEdge = indexes[edge];\n\n\t\t// Vertex snapped ?\n\t\tif ( boundaryFlags[theEdge.first] && boundaryFlags[theEdge.second] )\n\t\t{\n\t\t\t// Common coordinates\n\t\t\tuint common = boundaryFlags[theEdge.first] & boundaryFlags[theEdge.second];\n\n\t\t\t// Snapped on the same kind of coordinates ?\n\t\t\tif ( common )\n\t\t\t{\n\t\t\t\t// Keep this edge ?\n\t\t\t\tbool keep = false;\n\n\t\t\t\t// Snapped both on X ?\n\t\t\t\tif ( common & SnappedXFlag )\n\t\t\t\t{\n\t\t\t\t\t// Keep it\n\t\t\t\t\tkeep = true;\n\t\t\t\t}\n\n\t\t\t\t// Snapped both on X ?\n\t\t\t\tif ( common & SnappedYFlag )\n\t\t\t\t{\n\t\t\t\t\t// Keep it\n\t\t\t\t\tkeep = true;\n\t\t\t\t}\n\n\t\t\t\t// Keep this edge ?\n\t\t\t\tif (keep)\n\t\t\t\t{\n\t\t\t\t\t// Already inserted ?\n\t\t\t\t\tbool first = edgePair.find (theEdge.first) != edgePair.end();\n\t\t\t\t\tbool second = edgePairReverse.find (theEdge.second) != edgePairReverse.end();\n\n\t\t\t\t\t// First already inserted\n\t\t\t\t\tif (first || second)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error, two times the same vertex\n\t\t\t\t\t\terrors.MainError = CLigoError::VertexAlreadyUsed;\n\n\t\t\t\t\t\tif (first)\n\t\t\t\t\t\t\terrors.pushVertexError (CLigoError::VertexAlreadyUsed, theEdge.first, 0);\n\n\t\t\t\t\t\tif (second)\n\t\t\t\t\t\t\terrors.pushVertexError (CLigoError::VertexAlreadyUsed, theEdge.second, 0);\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ((!first) && (!second))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Add to the map\n\t\t\t\t\t\tedgePair.insert (map<uint, uint>::value_type(theEdge.first, theEdge.second));\n\t\t\t\t\t\tedgePairReverse.insert (map<uint, uint>::value_type(theEdge.second, theEdge.first));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// *** Build the list of non included vertices\n\n\t// For each vertices\n\tfor (uint i=0; i<vertexCount; i++)\n\t{\n\t\t// Vertex is inserted ?\n\t\tif (edgePair.find (i) == edgePair.end())\n\t\t{\n\t\t\t// No, add an error message\n\t\t\terrors.pushVertexError (CLigoError::NotInserted, i, 0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No, add an error message\n\t\t\terrors.pushVertexError (CLigoError::Inserted, i, 0);\n\t\t}\n\t}\n\n\t// *** Build the linked list\n\n\t// No vertices found ?\n\tif (edgePair.begin() == edgePair.end())\n\t{\n\t\t// Error message\n\t\terrors.MainError = CLigoError::NoEdgeVertices;\n\t\treturn false;\n\t}\n\n\t// Build the linked segments\n\tlist<list<uint> >\tsegmentList;\n\tmultimap<uint, uint>::iterator currentVert = edgePair.begin();\n\n\t// For each remaining segment\n\twhile (currentVert != edgePair.end())\n\t{\n\t\t// Get next vert\n\t\tuint first = currentVert->first;\n\t\tuint next = currentVert->second;\n\n\t\t// New list\n\t\tsegmentList.push_front (list<uint>());\n\t\tlist<uint> &listVert = *segmentList.begin();\n\n\t\t// Put the first vertices of the edge list\n\t\tlistVert.push_back (first);\n\t\tlistVert.push_back (next);\n\n\t\t// Erase it and\n\t\tedgePair.erase (currentVert);\n\n\t\t// Erase the reverse one\n\t\tcurrentVert = edgePairReverse.find (next);\n\t\tnlassert (currentVert != edgePairReverse.end());\n\t\tedgePairReverse.erase (currentVert);\n\n\t\t// Look forward\n\t\tcurrentVert = edgePair.find (next);\n\t\twhile (currentVert != edgePair.end())\n\t\t{\n\t\t\t// Backup\n\t\t\t//uint current = currentVert->first;\n\t\t\tnext = currentVert->second;\n\n\t\t\t// Push the next vertex\n\t\t\tlistVert.push_back (next);\n\n\t\t\t// Erase it and\n\t\t\tedgePair.erase (currentVert);\n\n\t\t\t// Erase the reverse one\n\t\t\tcurrentVert = edgePairReverse.find (next);\n\t\t\tnlassert (currentVert != edgePairReverse.end());\n\t\t\tedgePairReverse.erase (currentVert);\n\n\t\t\t// Look forward\n\t\t\tcurrentVert = edgePair.find (next);\n\t\t}\n\n\t\t// Edgelist ok ?\n\t\tif (next != first)\n\t\t{\n\t\t\t// No, look backward\n\t\t\tcurrentVert = edgePairReverse.find (first);\n\t\t\twhile (currentVert != edgePairReverse.end())\n\t\t\t{\n\t\t\t\t// Backup\n\t\t\t\tuint current = currentVert->second;\n\t\t\t\tnext = currentVert->first;\n\n\t\t\t\t// Push the next vertex\n\t\t\t\tlistVert.push_front (current);\n\n\t\t\t\t// Erase it\n\t\t\t\tedgePairReverse.erase (currentVert);\n\n\t\t\t\t// Erase the reverse one\n\t\t\t\tcurrentVert = edgePair.find (current);\n\t\t\t\tnlassert (currentVert != edgePair.end());\n\t\t\t\tedgePair.erase (currentVert);\n\n\t\t\t\t// Look forward\n\t\t\t\tcurrentVert = edgePairReverse.find (current);\n\t\t\t}\n\t\t}\n\n\t\t// Next edge list\n\t\tcurrentVert = edgePair.begin();\n\t}\n\n\t// ** Error traitment\n\n\t// Ok\n\tbool ok = true;\n\n\t// Edge index\n\tuint edgeIndex = 0;\n\n\t// List ok ?\n\tlist<list<uint> >::iterator iteList = segmentList.begin ();\n\twhile (iteList != segmentList.end())\n\t{\n\t\t// Only one list\n\t\tlist<uint> &listVert = *iteList;\n\n\t\t// First and last edge\n\t\tuint first = *listVert.begin();\n\t\tuint last = *(--listVert.end());\n\n\t\t// Opened edge ?\n\t\tif ( first != last )\n\t\t{\n\t\t\t// Opened edge\n\t\t\terrors.pushVertexError (CLigoError::OpenedEdge, first, edgeIndex);\n\t\t\terrors.pushVertexError (CLigoError::OpenedEdge, last, edgeIndex);\n\n\t\t\t// Main error\n\t\t\terrors.MainError = CLigoError::OpenedEdge;\n\n\t\t\t// Not ko\n\t\t\tok = false;\n\t\t}\n\n\t\t// Next edge list\n\t\tedgeIndex++;\n\t\titeList++;\n\t}\n\n\tif (segmentList.size () > 1)\n\t{\n\t\t// Main error\n\t\terrors.MainError = CLigoError::MultipleEdge;\n\n\t\t// Not ok\n\t\tok = false;\n\t}\n\n\t// Ok ?\n\tif (ok)\n\t{\n\t\t// Only one list\n\t\tlist<uint> &listVert = *segmentList.begin ();\n\n\t\t// Test vertex enchainement\n\t\tlist<uint>::iterator vertIte = listVert.begin();\n\n\t\t// Current vertex id\n\t\tuint previous = *(--listVert.end());\n\t\tvertIte++;\n\n\t\t// Error vertex set\n\t\tset<uint> errored;\n\n\t\t// For each vertices\n\t\twhile (vertIte != listVert.end ())\n\t\t{\n\t\t\t// Vertex id\n\t\t\tuint next = *vertIte;\n\n\t\t\t// Common flags\n\t\t\tuint commonFlags = boundaryFlags[previous]&boundaryFlags[next];\n\n\t\t\t// The both on X ?\n\t\t\tif ( commonFlags & SnappedXFlag )\n\t\t\t{\n\t\t\t\t// Get x index\n\t\t\t\tsint32 prevIndex = getSnappedIndex (vertices[previous].x, config.CellSize, config.Snap);\n\t\t\t\tsint32 nextIndex = getSnappedIndex (vertices[next].x, config.CellSize, config.Snap);\n\n\t\t\t\t// Not the same ?\n\t\t\t\tif (prevIndex != nextIndex)\n\t\t\t\t{\n\t\t\t\t\t// Vertex list error\n\t\t\t\t\tif (errored.insert (previous).second)\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::VertexList, previous, 0);\n\t\t\t\t\tif (errored.insert (next).second)\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::VertexList, next, 0);\n\n\t\t\t\t\t// Main error\n\t\t\t\t\terrors.MainError = CLigoError::VertexList;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Next vertex\n\t\t\tprevious = next;\n\t\t\tvertIte++;\n\t\t}\n\n\t\t// No error ?\n\t\tif (errored.empty())\n\t\t{\n\t\t\t// Only one list\n\t\t\tnlassert (segmentList.size()==1);\n\n\t\t\t// First of the list\n\t\t\tvertIte = listVert.begin();\n\n\t\t\t// Remove first\n\t\t\tlistVert.erase (vertIte);\n\n\t\t\t// Find a corner\n\t\t\tlist<uint>::iterator firstIte = listVert.begin();\n\t\t\twhile (firstIte != listVert.end())\n\t\t\t{\n\t\t\t\t// Corner ?\n\t\t\t\tif ( (boundaryFlags[*firstIte] & (SnappedXFlag|SnappedYFlag)) == (SnappedXFlag|SnappedYFlag) )\n\t\t\t\t\t// Yes, exit\n\t\t\t\t\tbreak;\n\n\t\t\t\t// Next\n\t\t\t\tfirstIte++;\n\t\t\t}\n\n\t\t\t// Can't be the last\n\t\t\tif (firstIte == listVert.end())\n\t\t\t{\n\t\t\t\t// No corner found\n\t\t\t\terrors.MainError = CLigoError::NoCornerFound;\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// First of the segment\n\t\t\tvertIte = firstIte;\n\n\t\t\t// Current edge list\n\t\t\tstd::vector<uint32> edge;\n\n\t\t\t// Push the first\n\t\t\tedge.push_back (*vertIte);\n\n\t\t\t// Next\n\t\t\tvertIte++;\n\n\t\t\t// End ?\n\t\t\tif (vertIte == listVert.end())\n\t\t\t\t// Start\n\t\t\t\tvertIte = listVert.begin();\n\n\t\t\t// Edge index\n\t\t\tuint edgeIndex = 0;\n\n\t\t\t// Build the edges\n\t\t\tfor(;;)\n\t\t\t{\n\t\t\t\t// Add it\n\t\t\t\tedge.push_back (*vertIte);\n\n\t\t\t\t// Corner ?\n\t\t\t\tif ( (boundaryFlags[*vertIte] & (SnappedXFlag|SnappedYFlag)) == (SnappedXFlag|SnappedYFlag) )\n\t\t\t\t{\n\t\t\t\t\t// Get the index of start and end of the edge\n\t\t\t\t\tsint32 startX = getSnappedIndex (vertices[edge[0]].x, config.CellSize, config.Snap);\n\t\t\t\t\tsint32 startY = getSnappedIndex (vertices[edge[0]].y, config.CellSize, config.Snap);\n\t\t\t\t\tsint32 endX = getSnappedIndex (vertices[edge[edge.size()-1]].x, config.CellSize, config.Snap);\n\t\t\t\t\tsint32 endY = getSnappedIndex (vertices[edge[edge.size()-1]].y, config.CellSize, config.Snap);\n\n\t\t\t\t\t// Same point ?\n\t\t\t\t\tif ((startX==endX) && (startY==endY))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error, two times the same vertex\n\t\t\t\t\t\terrors.MainError = CLigoError::TwoCornerVertices;\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::TwoCornerVertices, edge[0], 0);\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::TwoCornerVertices, edge[edge.size()-1], 0);\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Same point ?\n\t\t\t\t\tif ((abs(startX-endX)>1) || (abs(startY-endY)>1))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Error, two times the same vertex\n\t\t\t\t\t\terrors.MainError = CLigoError::CornerIsMissing;\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::CornerIsMissing, edge[0], 0);\n\t\t\t\t\t\terrors.pushVertexError (CLigoError::CornerIsMissing, edge[edge.size()-1], 0);\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Get rotation\n\t\t\t\t\tuint rotation = 4;\n\t\t\t\t\tif ((endX-startX)==1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((endY-startY)==0)\n\t\t\t\t\t\t\trotation = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((endX-startX)==-1)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((endY-startY)==0)\n\t\t\t\t\t\t\trotation = 2;\n\t\t\t\t\t}\n\t\t\t\t\telse if ((endX-startX)==0)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((endY-startY)==1)\n\t\t\t\t\t\t\trotation = 1;\n\t\t\t\t\t\telse if ((endY-startY)==-1)\n\t\t\t\t\t\t\trotation = 3;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Checks\n\t\t\t\t\tnlassert (rotation != 4);\n\n\t\t\t\t\t// Build the vertex array\n\t\t\t\t\tvector<CVector> vertexArray;\n\t\t\t\t\tvertexArray.resize (edge.size());\n\n\t\t\t\t\t// Rotate matrix\n\t\t\t\t\tCMatrix mat;\n\t\t\t\t\tmat.identity();\n\t\t\t\t\tmat.rotateZ ((float)rotation * (float)Pi / 2);\n\t\t\t\t\tmat.setPos (CVector (vertices[edge[0]].x, vertices[edge[0]].y, 0));\n\t\t\t\t\tmat.invert ();\n\n\t\t\t\t\t// Rotate the array\n\t\t\t\t\tfor (uint i=0; i<edge.size(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Get the value on the edge\n\t\t\t\t\t\tvertexArray[i] = mat * vertices[edge[i]];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Build the edge\n\t\t\t\t\t_Edges.resize (edgeIndex+1);\n\n\t\t\t\t\t// It must work without errors\n\t\t\t\t\tCLigoError errorBis;\n\t\t\t\t\tif (!_Edges[edgeIndex].build (vertexArray, edge, rotation, startX, startY, config, errorBis))\n\t\t\t\t\t{\n\t\t\t\t\t\t// Flat zone\n\t\t\t\t\t\terrors.MainError = CLigoError::FlatZone;\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// One more edge\n\t\t\t\t\tedgeIndex++;\n\n\t\t\t\t\t// Exit ?\n\t\t\t\t\tif (vertIte == firstIte)\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t// Clear the temp edge\n\t\t\t\t\tedge.clear ();\n\n\t\t\t\t\t// Push back the last vertex\n\t\t\t\t\tedge.push_back (*vertIte);\n\t\t\t\t}\n\n\t\t\t\t// Next vertex\n\t\t\t\tvertIte++;\n\n\t\t\t\t// End ?\n\t\t\t\tif (vertIte == listVert.end())\n\t\t\t\t\t// Start\n\t\t\t\t\tvertIte = listVert.begin();\n\t\t\t}\n\n\t\t\tsint32 bestX = 0x7fffffff;\n\t\t\tsint32 bestY = 0x80000000;\n\t\t\tuint bestEdge = 0xffffffff;\n\n\t\t\t// Sort edges : the first as the lower x then greater y\n\t\t\tuint edgeId;\n\t\t\tfor (edgeId=0; edgeId<_Edges.size(); edgeId++)\n\t\t\t{\n\t\t\t\t// Get the matrix\n\t\t\t\tCMatrix mat;\n\t\t\t\t_Edges[edgeId].buildMatrix (mat, config);\n\n\t\t\t\t// First vertex\n\t\t\t\tCVector pos = mat * _Edges[edgeId].getVertex (0);\n\n\t\t\t\t// Get X and Y\n\t\t\t\tsint32 x = getSnappedIndex (pos.x, config.CellSize, config.Snap);\n\t\t\t\tsint32 y = getSnappedIndex (pos.y, config.CellSize, config.Snap);\n\n\t\t\t\t// Best ?\n\t\t\t\tif ((x<bestX)||((x==bestX)&&(y>bestY)))\n\t\t\t\t{\n\t\t\t\t\t// This edgeId is best\n\t\t\t\t\tbestX=x;\n\t\t\t\t\tbestY=y;\n\t\t\t\t\tbestEdge = edgeId;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check\n\t\t\tnlassert (bestEdge!=0xffffffff);\n\n\t\t\t// Reoder\n\t\t\tstd::vector<CZoneEdge>\tnewEdge (_Edges.size());\n\t\t\tfor (edgeId=0; edgeId<_Edges.size(); edgeId++)\n\t\t\t{\n\t\t\t\t// Copy the edge\n\t\t\t\tnewEdge[edgeId]=_Edges[bestEdge++];\n\n\t\t\t\t// Next\n\t\t\t\tif (bestEdge==_Edges.size())\n\t\t\t\t\tbestEdge=0;\n\t\t\t}\n\n\t\t\t// Copy the final array\n\t\t\t_Edges=newEdge;\n\n\t\t\t// Return ok\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// Errors.\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CZoneTemplate::serial (NLMISC::IStream& s)\n{\n\t// open an XML node\n\ts.xmlPush (\"LIGO_ZONE_TEMPLATE\");\n\n\t\t// An header file\n\t\ts.serialCheck (string (\"LigoZoneTemplate\") );\n\n\t\t// Node for the boundaries\n\t\ts.xmlPush (\"EDGES\");\n\n\t\t\t// Serial the Vertices\n\t\t\ts.serialCont (_Edges);\n\n\t\t// Node for the boundaries\n\t\ts.xmlPop ();\n\n\t// Close the node\n\ts.xmlPop ();\n}\n\n// ***************************************************************************\n\nvoid CZoneTemplate::getMask (std::vector<bool> &mask, uint &width, uint &height)\n{\n\t// Some constantes\n\tstatic const sint32 addX[4] = { 1, 0, -1, 0 };\n\tstatic const sint32 addY[4] = { 0, 1, 0, -1 };\n\tstatic const sint32 cellX[4] = { 0, -1, -1, 0 };\n\tstatic const sint32 cellY[4] = { 0, 0, -1, -1 };\n\tstatic const sint32 moveX[4] = { 0, 1, 0, -1 };\n\tstatic const sint32 moveY[4] = { -1, 0, 1, 0 };\n\n\t// Max\n\tsint32 xMax = 0x80000000;\n\tsint32 yMax = 0x80000000;\n\n\t// For each edges\n\tuint edges;\n\tfor (edges=0; edges<_Edges.size(); edges++)\n\t{\n\t\t// Get the rotation\n\t\tuint32 rot = _Edges[edges].getRotation ();\n\t\tnlassert (rot<4);\n\n\t\t// Get X and Y max coordinates\n\t\tsint32 x = _Edges[edges].getOffsetX () + addX[rot];\n\t\tsint32 y = _Edges[edges].getOffsetY () + addY[rot];\n\n\t\t// Greater ?\n\t\tif (x > xMax)\n\t\t\txMax = x;\n\t\tif (y > yMax)\n\t\t\tyMax = y;\n\t}\n\n\t// Build the array\n\twidth = (uint32) xMax;\n\theight = (uint32) yMax;\n\n\t// Bit array for each cell\n\tvector<uint32> edgeArray (xMax*yMax, 0);\n\n\t// Resize it\n\tmask.resize (xMax*yMax, false);\n\n\t// Set of the cells in the mask\n\tset<pair<sint32, sint32> > setCell;\n\n\t// For each edge\n\tfor (edges=0; edges<_Edges.size(); edges++)\n\t{\n\t\t// Get the rotation\n\t\tuint32 rot = _Edges[edges].getRotation ();\n\t\tnlassert (rot<4);\n\n\t\t// Get its x and y cell coordinate\n\t\tsint32 x = _Edges[edges].getOffsetX () + cellX[rot];\n\t\tsint32 y = _Edges[edges].getOffsetY () + cellY[rot];\n\n\t\t// Fill the edge array\n\t\tedgeArray[x+y*width] |= (1<<rot);\n\n\t\t// Insert the cell\n\t\tsetCell.insert ( pair<sint32, sint32> (x, y) );\n\t}\n\n\t// Second set\n\tset<pair<sint32, sint32> > setCell2;\n\n\t// For each element in the set\n\tset<pair<sint32, sint32> >::iterator ite = setCell.begin();\n\twhile (ite != setCell.end())\n\t{\n\t\t// For each direction\n\t\tfor (uint dir=0; dir<4; dir++)\n\t\t{\n\t\t\t// Get its x and y cell coordinate\n\t\t\tsint32 x = ite->first;\n\t\t\tsint32 y = ite->second;\n\n\t\t\t// Edge in this direction ?\n\t\t\twhile ( (edgeArray[x+y*width] & (1<<dir) ) == 0)\n\t\t\t{\n\t\t\t\t// Move in this direction\n\t\t\t\tx += moveX[dir];\n\t\t\t\ty += moveY[dir];\n\n\t\t\t\t// insert it\n\t\t\t\tsetCell2.insert ( pair<sint32, sint32> (x, y) );\n\n\t\t\t\t// Some checks\n\t\t\t\tnlassert (x>=0);\n\t\t\t\tnlassert (x<(sint32)width);\n\t\t\t\tnlassert (y>=0);\n\t\t\t\tnlassert (y<(sint32)height);\n\t\t\t}\n\t\t}\n\n\t\t// Next one\n\t\tite++;\n\t}\n\n\t// Merge the two set\n\tite = setCell2.begin();\n\twhile (ite != setCell2.end())\n\t{\n\t\t// Merge\n\t\tsetCell.insert (*ite);\n\n\t\t// Next element\n\t\tite++;\n\t}\n\n\t// Done, fill the array\n\tite = setCell.begin();\n\twhile (ite != setCell.end())\n\t{\n\t\t// Merge\n\t\tmask[ite->first+ite->second*width] = true;\n\n\t\t// Next element\n\t\tite++;\n\t}\n}\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/ligo/zone_template.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_ZONE_TEMPLATE_H\n#define NL_ZONE_TEMPLATE_H\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/vector.h\"\n\n#include \"zone_edge.h\"\n\n#include <map>\n\nnamespace NLLIGO\n{\n\nclass CLigoConfig;\nclass CLigoError;\n\n/**\n * Ligo zone template\n *\n * \\author Cyril 'Hulud' Corvazier\n * \\author Nevrax France\n * \\date 2001\n */\nclass CZoneTemplate\n{\npublic:\n\n\t/**\n\t  * Build method. Build the zone template with a vertex list and an edge list.\n\t  *\n\t  * \\param vertices is the vertex array\n\t  * \\param indexes is the edge array\n\t  * \\param config is the current lingo config file\n\t  * \\param errors is the error structure\n\t  * \\return true if the build success, else return false\n\t  */\n\tbool build (const std::vector<NLMISC::CVector> &vertices, const std::vector< std::pair<uint, uint> > &indexes, const CLigoConfig &config, CLigoError &errors);\n\n\t/// Serialisation\n\tvoid serial (NLMISC::IStream& s);\n\n\t/// Get the vertex array of the template\n\tconst std::vector<CZoneEdge>\t&getEdges () const { return _Edges; }\n\n\t/// Get the mask of the template\n\tvoid getMask (std::vector<bool> &mask, uint &width, uint &height);\n\nprivate:\n\n\t/// Round a value on the snap resolution\n\tstatic inline void snap (float& value, float snap);\n\n\t/// Snap a value on the grid\n\tstatic inline bool snapOnGrid (float& value, float resolution, float snap);\n\n\t/// Return true if this value is snapped\n\tstatic inline bool isSnapedOnGrid (float value, float resolution, float snap);\n\n\t/// Return the interger index of a snappable value\n\tstatic inline sint32 getSnappedIndex (float value, float resolution, float snap);\n\n\t/// Vertex array\n\tstd::vector<CZoneEdge>\t_Edges;\n\n};\n\n}\n\n#endif // NL_ZONE_TEMPLATE_H\n\n/* End of zone_template.h */\n"
  },
  {
    "path": "code/nel/src/logic/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\nFILE(GLOB HEADERS ../../include/nel/logic/*.h)\n\nNL_TARGET_LIB(nellogic ${HEADERS} ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(nellogic ${LIBXML2_LIBRARIES} nelmisc nelnet)\nSET_TARGET_PROPERTIES(nellogic PROPERTIES LINK_INTERFACE_LIBRARIES \"\")\nNL_DEFAULT_PROPS(nellogic \"NeL, Library: NeL Logic\")\nNL_ADD_RUNTIME_FLAGS(nellogic)\n\nNL_ADD_LIB_SUFFIX(nellogic)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS nellogic LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/nel/src/logic/logic_condition.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/misc/o_xml.h\"\n\n#include \"nel/logic/logic_condition.h\"\n#include \"nel/logic/logic_variable.h\"\n#include \"nel/logic/logic_state_machine.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLLOGIC\n{\n\n//-------------------------------------------------\n// setLogicStateMachine :\n//\n//-------------------------------------------------\nvoid CLogicComparisonBlock::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicComparisonBlock::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t_LogicStateMachine = logicStateMachine;\n\t}\n\n} // setLogicStateMachine //\n\n\n//-------------------------------------------------\n// testLogic :\n//\n//-------------------------------------------------\nbool CLogicComparisonBlock::testLogic()\n{\n\tCLogicVariable var;\n\tif( _LogicStateMachine->getVariable( VariableName, var ) == false )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicComparisonBlock::testLogic> The variable %s is unknown in the state machine\",VariableName.c_str());\n\t\treturn false;\n\t}\n\n\tif( Operator == \"<\"  )\treturn ( var.getValue() <  Comparand );\n\tif( Operator == \"<=\" )\treturn ( var.getValue() <= Comparand );\n\tif( Operator == \">\"  )\treturn ( var.getValue() >  Comparand );\n\tif( Operator == \">=\" )\treturn ( var.getValue() >= Comparand );\n\tif( Operator == \"==\" )\treturn ( var.getValue() == Comparand );\n\tif( Operator == \"!=\" )\treturn ( var.getValue() != Comparand );\n\n\tnlwarning(\"(LOGIC)<CLogicComparisonBlock::testLogic> The comparison block operator %s is unknown\",Operator.c_str());\n\treturn false;\n\n} // testLogic //\n\n\n//-------------------------------------------------\n// serial :\n//\n//-------------------------------------------------\n/*void CLogicComparisonBlock::serial( IStream &f )\n{\n\tf.xmlPush(\"COMPARISON_BLOCK\");\n\n\tf.serial( VariableName );\n\tf.serial( Operator );\n\tf.serial( Comparand );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicComparisonBlock::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"COMPARISON_BLOCK\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"VariableName\", (const xmlChar*)VariableName.c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Operator\", (const xmlChar*)Operator.c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Comparand\", (const xmlChar*)toString(Comparand).c_str());\n}\n\nvoid CLogicComparisonBlock::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"COMPARISON_BLOCK\");\n\n\tVariableName = getXMLProp (node, \"VariableName\");\n\tOperator = getXMLProp (node, \"Operator\");\n\tComparand = atoiInt64(getXMLProp (node, \"Comparand\").c_str());\n}\n\n\n\n\n\n\n\n//-------------------------------------------------\n// setLogicStateMachine :\n//\n//-------------------------------------------------\nvoid CLogicConditionLogicBlock::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CCLogicConditionLogicBlock::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t// set the state machine of this node\n\t\t_LogicStateMachine = logicStateMachine;\n\n\t\t// set the state machine of the logic block\n\t\tComparisonBlock.setLogicStateMachine( logicStateMachine );\n\t}\n\n} // setLogicStateMachine //\n\n\n//-------------------------------------------------\n// testLogic :\n//\n//-------------------------------------------------\nbool CLogicConditionLogicBlock::testLogic()\n{\n\tswitch( Type )\n\t{\n\t\tcase NOT :\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\tbreak;\n\n\t\tcase COMPARISON :\n\t\t{\n\t\t\treturn ComparisonBlock.testLogic();\n\t\t}\n\t\tbreak;\n\n\t\tcase SUB_CONDITION :\n\t\t{\n\t\t\tCLogicCondition condition;\n\t\t\tif( _LogicStateMachine->getCondition(SubCondition,condition) )\n\t\t\t{\n\t\t\t\treturn condition.testLogic();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning(\"(LOGIC)<CLogicConditionLogicBlock::testLogic> The subcondition \\\"%s\\\" is unknown in the state machine \\\"%s\\\"\",\n\t\t\t\t\tSubCondition.c_str(),_LogicStateMachine->getName().c_str());\n\t\t\t}\n\n\t\t}\n\n\t\tdefault :\n\t\t\tnlerror(\"(LOGIC)<CLogicConditionLogicBlock::testLogic> logic block type %d is unknown\",Type);\n\t}\n\n\treturn false;\n\n} // testLogic //\n\n\n\n//-------------------------------------------------\n// fillVarSet :\n//\n//-------------------------------------------------\nvoid CLogicConditionLogicBlock::fillVarSet( set<string>& condVars )\n{\n\tif( Type == COMPARISON )\n\t{\n\t\tcondVars.insert( ComparisonBlock.VariableName );\n\t}\n\telse\n\t{\n\t\tif( Type == SUB_CONDITION )\n\t\t{\n\t\t\tCLogicCondition condition;\n\t\t\tif( _LogicStateMachine->getCondition(SubCondition,condition) )\n\t\t\t{\n\t\t\t\tcondition.fillVarSet( condVars );\n\t\t\t}\n\t\t}\n\t}\n\n} // fillVarSet //\n\n\n//-------------------------------------------------\n// serial :\n//\n//-------------------------------------------------\n/*void CLogicConditionLogicBlock::serial( IStream &f )\n{\n\tf.xmlPush(\"CONDITION_LOGIC_BLOCK\");\n\n\tf.serialEnum( Type );\n\tswitch( Type )\n\t{\n\t\tcase NOT : break;\n\n\t\tcase COMPARISON :\n\t\t{\n\t\t\tf.serial( ComparisonBlock );\n\t\t}\n\t\tbreak;\n\n\t\tcase SUB_CONDITION :\n\t\t{\n\t\t\tf.serial( SubCondition );\n\t\t}\n\t\tbreak;\n\t};\n\n\tf.xmlPop();\n};*/\n\nvoid CLogicConditionLogicBlock::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"CONDITION_LOGIC_NODE\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Type\", (const xmlChar*)toString((uint32)Type).c_str());\n\tswitch( Type )\n\t{\n\t\tcase NOT : break;\n\n\t\tcase COMPARISON :\n\t\t{\n\t\t\tComparisonBlock.write(elmPtr);\n\t\t}\n\t\tbreak;\n\n\t\tcase SUB_CONDITION :\n\t\t{\n\t\t\txmlSetProp (elmPtr, (const xmlChar*)\"SubCondition\", (const xmlChar*)SubCondition.c_str());\n\t\t}\n\t\tbreak;\n\t};\n}\n\nvoid CLogicConditionLogicBlock::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"CONDITION_LOGIC_NODE\");\n\tuint32 uType;\n\tNLMISC::fromString(getXMLProp(node, \"Type\"), uType);\n\tType = (TLogicConditionLogicBlockType)uType;\n\tswitch( Type )\n\t{\n\t\tcase NOT : break;\n\n\t\tcase COMPARISON :\n\t\t{\n\t\t\tComparisonBlock.read (node);\n\t\t}\n\t\tbreak;\n\n\t\tcase SUB_CONDITION :\n\t\t{\n\t\t\tSubCondition = getXMLProp (node, \"SubCondition\");\n\t\t}\n\t\tbreak;\n\t};\n}\n\n//-----------------------------------------\n\n\n\n//-------------------------------------------------\n// setLogicStateMachine :\n//\n//-------------------------------------------------\nvoid CLogicConditionNode::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicConditionNode::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t// set the state machine of this node\n\t\t_LogicStateMachine = logicStateMachine;\n\n\t\t// set the state machine of the logic block\n\t\tLogicBlock.setLogicStateMachine( logicStateMachine );\n\n\t\t// set the state machine for the sub nodes\n\t\tvector<CLogicConditionNode *>::iterator itNodes;\n\t\tfor( itNodes = _Nodes.begin(); itNodes != _Nodes.end(); ++itNodes )\n\t\t{\n\t\t\t(*itNodes)->setLogicStateMachine( logicStateMachine );\n\t\t}\n\t}\n\n} // setLogicStateMachine //\n\n\n//-------------------------------------------------\n// addNode :\n//\n//-------------------------------------------------\nvoid CLogicConditionNode::addNode( CLogicConditionNode * node )\n{\n\tnode->setLogicStateMachine( _LogicStateMachine );\n\t_Nodes.push_back( node );\n\n} // addToSubNodes //\n\n\n//-------------------------------------------------\n// testLogic :\n//\n//-------------------------------------------------\nbool CLogicConditionNode::testLogic()\n{\n\t// test the logic block\n\tif( LogicBlock.testLogic() == false )\n\t{\n\t\treturn false;\n\t}\n\n\t// if there's no subtree we assess the subtree is true\n\tif( _Nodes.size() == 0 )\n\t{\n\t\treturn true;\n\t}\n\n\t// test the subtree\n\tif( LogicBlock.isNotBlock() )\n\t{\n\t\t// the subtree is false if at least one node is true\n\t\tvector<CLogicConditionNode *>::iterator itNodes;\n\t\tfor( itNodes = _Nodes.begin(); itNodes != _Nodes.end(); ++itNodes )\n\t\t{\n\t\t\tif( (*itNodes)->testLogic() == true )\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// the subtree is true if at least one node is true\n\t\tvector<CLogicConditionNode *>::iterator itNodes;\n\t\tfor( itNodes = _Nodes.begin(); itNodes != _Nodes.end(); ++itNodes )\n\t\t{\n\t\t\tif( (*itNodes)->testLogic() == true )\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n} // testLogic //\n\n\n//-------------------------------------------------\n// fillVarSet :\n//\n//-------------------------------------------------\nvoid CLogicConditionNode::fillVarSet( set<string>& condVars )\n{\n\tif( Type == LOGIC_NODE )\n\t{\n\t\tLogicBlock.fillVarSet( condVars );\n\t}\n\n\tvector<CLogicConditionNode *>::iterator itNode;\n\tfor( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t{\n\t\t(*itNode)->fillVarSet( condVars );\n\t}\n\n} // fillVarSet //\n\n\n//-------------------------------------------------\n// serial :\n//\n//-------------------------------------------------\n/*void CLogicConditionNode::serial( IStream &f )\n{\n\tf.xmlPush(\"CONDITION_NODE\");\n\n\tf.serialEnum( Type );\n\tswitch( Type )\n\t{\n\t\tcase TERMINATOR : break;\n\t\tcase LOGIC_NODE :\n\t\t{\n\t\t\tf.serial( LogicBlock );\n\t\t\tif( f.isReading() )\n\t\t\t{\n\t\t\t\tuint32 sz;\n\t\t\t\tf.serial( sz );\n\t\t\t\tuint i;\n\t\t\t\tfor( i = 0; i < sz; i++ )\n\t\t\t\t{\n\t\t\t\t\tCLogicConditionNode * node = new CLogicConditionNode();\n\t\t\t\t\tf.serial( *node );\n\t\t\t\t\t_Nodes.push_back( node );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 sz = _Nodes.size();\n\t\t\t\tf.serial( sz );\n\t\t\t\tvector<CLogicConditionNode *>::iterator itNode;\n\t\t\t\tfor( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t\t\t\t{\n\t\t\t\t\tf.serial( **itNode );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t};\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicConditionNode::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"CONDITION_NODE\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Type\", (const xmlChar*)toString((uint32)Type).c_str());\n\n\tswitch( Type )\n\t{\n\t\tcase TERMINATOR : break;\n\t\tcase LOGIC_NODE :\n\t\t{\n\t\t\tLogicBlock.write(elmPtr);\n\t\t\tvector<CLogicConditionNode *>::const_iterator itNode = _Nodes.begin();\n\t\t\tfor( ; itNode != _Nodes.end(); ++itNode )\n\t\t\t{\n\t\t\t\t(*itNode)->write(elmPtr);\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t};\n}\n\nvoid CLogicConditionNode::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"CONDITION_NODE\");\n\tuint32 uType;\n\tNLMISC::fromString(getXMLProp(node, \"Type\"), uType);\n\tType = (TConditionNodeType )uType;\n\tswitch( Type )\n\t{\n\t\tcase TERMINATOR : break;\n\t\tcase LOGIC_NODE :\n\t\t{\n\t\t\tLogicBlock.read (node);\n\n\t\t\t{\n\t\t\t\t// Count the parent\n\t\t\t\tuint nb = CIXml::countChildren (node, \"CONDITION_NODE\");\n\t\t\t\tuint i = 0;\n\t\t\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"CONDITION_NODE\");\n\t\t\t\twhile (i<nb)\n\t\t\t\t{\n\t\t\t\t\tCLogicConditionNode *v = new CLogicConditionNode();\n\t\t\t\t\tv->read(parent);\n\t\t\t\t\t_Nodes.push_back (v);\n\n\t\t\t\t\t// Next parent\n\t\t\t\t\tparent = CIXml::getNextChildNode (parent, \"CONDITION_NODE\");\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t};\n}\n\n//-------------------------------------------------\n// ~CLogicConditionNode :\n//\n//-------------------------------------------------\nCLogicConditionNode::~CLogicConditionNode()\n{\n\tvector<CLogicConditionNode *>::iterator itNodes;\n\tfor( itNodes = _Nodes.begin(); itNodes != _Nodes.end(); ++itNodes )\n\t{\n\t\tdelete (*itNodes);\n\t}\n\n} // ~CLogicConditionNode //\n\n\n\n\n\n\n\n//-------------------------------------------------\n// setLogicStateMachine :\n//\n//-------------------------------------------------\nvoid CLogicCondition::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicCondition::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t// init the logic state machine for each node\n\t\tvector<CLogicConditionNode>::iterator itNodes;\n\t\tfor( itNodes = Nodes.begin(); itNodes != Nodes.end(); ++itNodes )\n\t\t{\n\t\t\t(*itNodes).setLogicStateMachine( logicStateMachine );\n\t\t}\n\t}\n\n} // setLogicStateMachine //\n\n\n//-------------------------------------------------\n// testLogic :\n//\n//-------------------------------------------------\nbool CLogicCondition::testLogic()\n{\n\tvector<CLogicConditionNode>::iterator itNodes;\n\tfor( itNodes = Nodes.begin(); itNodes != Nodes.end(); ++itNodes )\n\t{\n\t\tif( (*itNodes).testLogic() == false )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n\n} // testLogic //\n\n\n\n//-------------------------------------------------\n// fillVarSet :\n//\n//-------------------------------------------------\nvoid CLogicCondition::fillVarSet( set<string>& condVars )\n{\n\tvector<CLogicConditionNode>::iterator itNode;\n\tfor( itNode = Nodes.begin(); itNode != Nodes.end(); ++itNode )\n\t{\n\t\t(*itNode).fillVarSet( condVars );\n\t}\n\n} // fillVarSet //\n\n\n\n//-------------------------------------------------\n// serial :\n//\n//-------------------------------------------------\n/*void CLogicCondition::serial( IStream &f )\n{\n\tf.xmlPush(\"CONDITION\");\n\n\tf.serial( _ConditionName );\n\tf.serialCont( Nodes );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicCondition::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"CONDITION\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Name\", (const xmlChar*)_ConditionName.c_str());\n\n\tuint i;\n\tfor (i = 0; i < Nodes.size(); i++)\n\t{\n\t\tNodes[i].write(elmPtr);\n\t}\n}\n\nvoid CLogicCondition::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"CONDITION\");\n\n\t_ConditionName = getXMLProp (node, \"Name\");\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"CONDITION_NODE\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"CONDITION_NODE\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicConditionNode v;\n\t\t\tv.read(parent);\n\t\t\tNodes.push_back (v);\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"CONDITION_NODE\");\n\t\t\ti++;\n\t\t}\n\t}\n}\n\n\n} // NLLOGIC\n"
  },
  {
    "path": "code/nel/src/logic/logic_event.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/logic/logic_event.h\"\n#include \"nel/logic/logic_state_machine.h\"\n\n#include \"nel/net/service.h\"\n\nusing namespace NLMISC;\nusing namespace NLNET;\nusing namespace std;\n\nnamespace NLLOGIC\n{\n\n//----------------------------------- MESSAGE ----------------------------------\n\n\n//-------------------------------------------------\n// serial\n//\n//-------------------------------------------------\n/*void CLogicEventMessage::serial( IStream &f )\n{\n\tf.xmlPush(\"EVENT_MESSAGE\");\n\n\tf.serial( Destination );\n\tf.serial( DestinationId );\n\tf.serial( MessageId );\n\tf.serial( Arguments );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicEventMessage::write (xmlNodePtr node, const char *subName) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)string(string(subName)+string(\"EVENT_MESSAGE\")).c_str(), NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Destination\", (const xmlChar*)Destination.c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"DestinationId\", (const xmlChar*)toString(DestinationId).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"MessageId\", (const xmlChar*)toString(MessageId).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Arguments\", (const xmlChar*)toString(Arguments).c_str());\n}\n\nvoid CLogicEventMessage::read (xmlNodePtr node, const char *subName)\n{\n\txmlCheckNodeName (node, string(string(subName)+string(\"EVENT_MESSAGE\")).c_str());\n\n\tDestination = getXMLProp (node, \"Destination\");\n\tDestinationId = atoiInt64(getXMLProp (node, \"DestinationId\").c_str());\n\tMessageId = getXMLProp (node, \"MessageId\");\n\tArguments = getXMLProp (node, \"Arguments\");\n}\n\n\n\n\n\n//----------------------------------- ACTION ----------------------------------\n\n\n//-------------------------------------------------\n// enableSendMessage\n//\n//-------------------------------------------------\nvoid CLogicEventAction::enableSendMessage()\n{\n\tEventMessage.ToSend = true;\n\n} // enableSendMessage //\n\n\n//-------------------------------------------------\n// serial\n//\n//-------------------------------------------------\n/*void CLogicEventAction::serial( IStream &f )\n{\n\tf.xmlPush(\"EVENT_ACTION\");\n\n\tf.serial( IsStateChange );\n\tif( IsStateChange )\n\t{\n\t\tf.serial( StateChange );\n\t}\n\telse\n\t{\n\t\tf.serial( EventMessage );\n\t}\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicEventAction::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"EVENT_ACTION\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"IsStateChange\", (const xmlChar*)toString(IsStateChange).c_str());\n\tif (IsStateChange)\n\t{\n\t\txmlSetProp (elmPtr, (const xmlChar*)\"StateChange\", (const xmlChar*)StateChange.c_str());\n\t}\n\telse\n\t{\n\t\tEventMessage.write(elmPtr);\n\t}\n}\n\nvoid CLogicEventAction::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"EVENT_ACTION\");\n\n\tNLMISC::fromString(getXMLProp(node, \"IsStateChange\"), IsStateChange);\n\tif (IsStateChange)\n\t{\n\t\tStateChange = getXMLProp (node, \"StateChange\");\n\t}\n\telse\n\t{\n\t\tEventMessage.read(node);\n\t}\n}\n\n\n\n\n\n\n\n\n//----------------------------------- EVENT ----------------------------------\n\n\n\n//-------------------------------------------------\n// reset\n//\n//-------------------------------------------------\nvoid CLogicEvent::reset()\n{\n\tEventAction.EventMessage.Sent = false;\n\tEventAction.EventMessage.ToSend = false;\n\n} // reset //\n\n\n\n//-------------------------------------------------\n// setLogicStateMachine\n//\n//-------------------------------------------------\nvoid CLogicEvent::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicEvent::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t// init the logic state machine for this event\n\t\t_LogicStateMachine = logicStateMachine;\n\t}\n\n} // setLogicStateMachine //\n\n\n\n//-------------------------------------------------\n// testCondition\n//\n//-------------------------------------------------\nbool CLogicEvent::testCondition()\n{\n\tif( _LogicStateMachine )\n\t{\n\t\tif( ConditionName != \"no_condition\" )\n\t\t{\n\t\t\tCLogicCondition cond;\n\t\t\tif( _LogicStateMachine->getCondition( ConditionName, cond ) )\n\t\t\t{\n\t\t\t\treturn cond.testLogic();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning(\"(LOGIC)<CLogicEvent::testCondition> Condition %s not found in the state machine\",ConditionName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"(LOGIC)<CLogicEvent::testCondition> Condition undefined\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicEvent::testCondition> The state machine managing this event is Null\");\n\t}\n\n\treturn false;\n\n} // testCondition //\n\n\n//-------------------------------------------------\n// serial\n//\n//-------------------------------------------------\n/*void CLogicEvent::serial( IStream &f )\n{\n\tf.xmlPush(\"EVENT\");\n\n\tf.serial( ConditionName );\n\tf.serial( EventAction );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicEvent::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"EVENT\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"ConditionName\", (const xmlChar*)ConditionName.c_str());\n\tEventAction.write(elmPtr);\n}\n\nvoid CLogicEvent::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"EVENT\");\n\n\tConditionName = getXMLProp (node, \"ConditionName\");\n\tEventAction.read(node);\n}\n\n} // NLLOGIC\n\n\n"
  },
  {
    "path": "code/nel/src/logic/logic_state.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/logic/logic_state.h\"\n#include \"nel/logic/logic_state_machine.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nnamespace NLLOGIC\n{\n\n//---------------------------------------------------\n//\tCLogicState\n//\n//---------------------------------------------------\nCLogicState::CLogicState()\n{\n\t_StateName = \"no_state\";\n\t_LogicStateMachine = 0;\n\n} // CLogicState //\n\n\n//---------------------------------------------------\n//\tsetLogicStateMachine\n//\n//---------------------------------------------------\nvoid CLogicState::setLogicStateMachine( CLogicStateMachine * logicStateMachine )\n{\n\tif( logicStateMachine == 0 )\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicCondition::setLogicStateMachine> The state machine is null\");\n\t}\n\telse\n\t{\n\t\t// init the logic state machine for this state\n\t\t_LogicStateMachine = logicStateMachine;\n\n\t\t// init the logic state machine in each event\n\t\tvector<CLogicEvent>::iterator itEvent;\n\t\tfor( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent )\n\t\t{\n\t\t\t(*itEvent).setLogicStateMachine( logicStateMachine );\n\t\t}\n\t}\n\n} // setLogicStateMachine //\n\n\n\n//---------------------------------------------------\n// addEvent :\n//\n//---------------------------------------------------\nvoid CLogicState::addEvent( CLogicEvent event )\n{\n\tevent.setLogicStateMachine( _LogicStateMachine );\n\t_Events.push_back( event );\n\n} // addEvent //\n\n\n\n//---------------------------------------------------\n// addSIdMap :\n//\n// looks in all the messages of the state if the\n// destination names can be associated with a sid.\n//---------------------------------------------------\nvoid CLogicState::addSIdMap( const TSIdMap& sIdMap )\n{\n\tvector<CLogicEventMessage>::iterator itMsg;\n\n\t/// entry messages\n\tfor( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg )\n\t{\n\t\tTSIdMap::const_iterator itId = sIdMap.find( (*itMsg).Destination );\n\t\t// if message destination exists in the map we associate the sid with the message\n\t\tif( itId != sIdMap.end() )\n\t\t{\n\t\t\t(*itMsg).DestinationId = (*itId).second;\n\t\t}\n\t}\n\t/// send the entry messages that can be sent\n\ttrySendEntryMessages();\n\n\n\t// event messages\n\tvector<CLogicEvent>::iterator itEvt;\n\tfor( itEvt = _Events.begin(); itEvt != _Events.end(); ++itEvt )\n\t{\n\t\tstring dest = (*itEvt).EventAction.EventMessage.Destination;\n\t\tTSIdMap::const_iterator itId = sIdMap.find( dest );\n\t\t// if message destination exists in the map we associate the sid with the message\n\t\tif( itId != sIdMap.end() )\n\t\t{\n\t\t\t(*itEvt).EventAction.EventMessage.DestinationId = (*itId).second;\n\t\t}\n\t}\n\t/// send the event messages that can be sent\n\ttrySendEventMessages();\n\n\n\t/// exit messages\n\tfor( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg )\n\t{\n\t\tTSIdMap::const_iterator itId = sIdMap.find( (*itMsg).Destination );\n\t\t// if message destination exists in the map we associate the sid with the message\n\t\tif( itId != sIdMap.end() )\n\t\t{\n\t\t\t(*itMsg).DestinationId = (*itId).second;\n\t\t}\n\t}\n\n} // addSIdMap //\n\n\n//---------------------------------------------------\n// processLogic :\n//\n//---------------------------------------------------\nvoid CLogicState::processLogic()\n{\n\t// test all conditions managed by this state\n\tvector<CLogicEvent>::iterator itEvent;\n\tfor( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent )\n\t{\n\t\tif( (*itEvent).testCondition() )\n\t\t{\n\t\t\t//nlinfo(\"The condition %s is valid\",(*itEvent).ConditionName.c_str());\n\t\t\tif( (*itEvent).EventAction.IsStateChange )\n\t\t\t{\n\t\t\t\t_LogicStateMachine->setCurrentState( (*itEvent).EventAction.StateChange );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// this message will be sent as soon as the dest id will be given\n\t\t\t\t(*itEvent).EventAction.enableSendMessage();\n\n\t\t\t\t/// send the event messages that must and can be sent\n\t\t\t\ttrySendEventMessages();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// reset message send status here to be able to send messages several times in the logic state\n\t\t\t// --> this has to be done if we want messages to be sent every time the condition becomes verified\n\t\t}\n\t}\n\n} // processLogic //\n\n\n//---------------------------------------------------\n// enterState :\n//\n//---------------------------------------------------\nvoid CLogicState::enterState()\n{\n\t/// send the entry messages that can be sent\n\ttrySendEntryMessages();\n\n} // enterState //\n\n\n//---------------------------------------------------\n// exitState :\n//\n//---------------------------------------------------\nvoid CLogicState::exitState()\n{\n\tvector<CLogicEventMessage>::iterator itMsg;\n\tfor( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg )\n\t{\n\t\tif( (*itMsg).DestinationId != CEntityId() )\n\t\t{\n\t\t\tCMessage msgOut( (*itMsg).MessageId );\n\t\t\tmsgOut.serial( (*itMsg).Arguments );\n\n\t\t\t_MessagesToSend.insert( make_pair((*itMsg).DestinationId,msgOut) );\n\t\t}\n\t}\n\n\t// reset the entry messages send status\n\tfor( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg )\n\t{\n\t\t(*itMsg).ToSend = false;\n\t\t(*itMsg).Sent = false;\n\t}\n\n\t// reset all events\n\tvector<CLogicEvent>::iterator itEvent;\n\tfor( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent )\n\t{\n\t\t(*itEvent).reset();\n\t}\n\n\t// reset the exit messages send status\n\tfor( itMsg = _ExitMessages.begin(); itMsg != _ExitMessages.end(); ++itMsg )\n\t{\n\t\t(*itMsg).ToSend = false;\n\t\t(*itMsg).Sent = false;\n\t}\n\n} // exitState //\n\n\n\n//---------------------------------------------------\n// trySendEntryMessages :\n//\n//---------------------------------------------------\nvoid CLogicState::trySendEntryMessages()\n{\n\t/// send the entry messages that can be sent\n\tvector<CLogicEventMessage>::iterator itMsg;\n\tfor( itMsg = _EntryMessages.begin(); itMsg != _EntryMessages.end(); ++itMsg )\n\t{\n\t\tif( !(*itMsg).Sent && (*itMsg).DestinationId.getType() != 0xfe )\n\t\t{\n\t\t\tCMessage msgOut( (*itMsg).MessageId );\n\t\t\tmsgOut.serial( (*itMsg).Arguments );\n\n\t\t\t_MessagesToSend.insert( make_pair((*itMsg).DestinationId,msgOut) );\n\n\t\t\t(*itMsg).ToSend = false;\n\t\t\t(*itMsg).Sent = true;\n\t\t}\n\t}\n\n} // trySendEntryMessages //\n\n\n\n//---------------------------------------------------\n// trySendEventMessages :\n//\n//---------------------------------------------------\nvoid CLogicState::trySendEventMessages()\n{\n\t// test all conditions managed by this state\n\tvector<CLogicEvent>::iterator itEvent;\n\tfor( itEvent = _Events.begin(); itEvent != _Events.end(); ++itEvent )\n\t{\n\t\tif( (*itEvent).EventAction.EventMessage.ToSend == true )\n\t\t{\n\t\t\tif( (*itEvent).EventAction.EventMessage.Sent == false )\n\t\t\t{\n\t\t\t\tif( (*itEvent).EventAction.EventMessage.DestinationId.getType() != 0xfe )\n\t\t\t\t{\n\t\t\t\t\tCMessage msgOut( (*itEvent).EventAction.EventMessage.MessageId );\n\t\t\t\t\tmsgOut.serial( (*itEvent).EventAction.EventMessage.Arguments );\n\n\t\t\t\t\t_MessagesToSend.insert( make_pair((*itEvent).EventAction.EventMessage.DestinationId,msgOut) );\n\n\t\t\t\t\t(*itEvent).EventAction.EventMessage.ToSend = false;\n\t\t\t\t\t(*itEvent).EventAction.EventMessage.Sent = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n} // trySendEventMessages //\n\n\n//---------------------------------------------------\n// getMessagesToSend :\n//\n//---------------------------------------------------\nvoid CLogicState::getMessagesToSend( multimap<CEntityId,CMessage>& msgs )\n{\n\tmultimap<CEntityId,CMessage>::iterator itMsg;\n\tfor( itMsg = _MessagesToSend.begin(); itMsg != _MessagesToSend.end(); ++itMsg )\n\t{\n\t\tmsgs.insert( *itMsg );\n\t}\n\n\t// erase all the messages\n\t_MessagesToSend.clear();\n\n} // getMessagesToSend //\n\n\n\n//---------------------------------------------------\n// fillVarMap :\n//\n//---------------------------------------------------\nvoid CLogicState::fillVarMap( multimap<CEntityId,string >& stateMachineVariables )\n{\n\t// events\n\tvector<CLogicEvent>::iterator itEvt;\n\tfor( itEvt = _Events.begin(); itEvt != _Events.end(); ++itEvt )\n\t{\n\t\t// get the condition used in the event\n\t\tCLogicCondition condition;\n\t\tif( _LogicStateMachine->getCondition((*itEvt).ConditionName,condition) )\n\t\t{\n\t\t\t// get vars used in the conditions\n\t\t\tset<string> condVars;\n\t\t\tcondition.fillVarSet( condVars );\n\n\t\t\t// add var with related service\n\t\t\tset<string>::iterator itCV;\n\t\t\tfor( itCV = condVars.begin(); itCV != condVars.end(); ++itCV )\n\t\t\t{\n\t\t\t\tstateMachineVariables.insert( make_pair((*itEvt).EventAction.EventMessage.DestinationId,*itCV) );\n\t\t\t}\n\t\t}\n\t}\n\n} // fillVarMap //\n\n\n\n//---------------------------------------------------\n// serial :\n//\n//---------------------------------------------------\n/*void CLogicState::serial( IStream &f )\n{\n\tf.xmlPush( \"STATE\");\n\n\tf.serial( _StateName );\n\tf.serialCont( _EntryMessages );\n\tf.serialCont( _ExitMessages );\n\tf.serialCont( _Events );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicState::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"STATE\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Name\", (const xmlChar*)_StateName.c_str());\n\n\tuint i;\n\tfor (i = 0; i < _EntryMessages.size(); i++)\n\t{\n\t\t_EntryMessages[i].write(elmPtr, \"ENTRY_\");\n\t}\n\tfor (i = 0; i < _ExitMessages.size(); i++)\n\t{\n\t\t_ExitMessages[i].write(elmPtr, \"EXIT_\");\n\t}\n\tfor (i = 0; i < _Events.size(); i++)\n\t{\n\t\t_Events[i].write(elmPtr);\n\t}\n}\n\nvoid CLogicState::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"STATE\");\n\n\t_StateName = getXMLProp (node, \"Name\");\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"ENTRY_EVENT_MESSAGE\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"ENTRY_EVENT_MESSAGE\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicEventMessage v;\n\t\t\tv.read(parent);\n\t\t\t_EntryMessages.push_back(v);\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"ENTRY_EVENT_MESSAGE\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"EXIT_EVENT_MESSAGE\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"EXIT_EVENT_MESSAGE\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicEventMessage v;\n\t\t\tv.read(parent);\n\t\t\t_ExitMessages.push_back(v);\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"EXIT_EVENT_MESSAGE\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"EVENT\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"EVENT\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicEvent v;\n\t\t\tv.read(parent);\n\t\t\t_Events.push_back(v);\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"EVENT\");\n\t\t\ti++;\n\t\t}\n\t}\n\n}\n\n\n} // NLLOGIC\n\n"
  },
  {
    "path": "code/nel/src/logic/logic_state_machine.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/logic/logic_state_machine.h\"\n\n#include \"nel/net/service.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nnamespace NLLOGIC\n{\n\n// test if a string is valid considering a filter and a motif\nbool testNameWithFilter( sint8 filter, string motif, string varName );\n\nvoid xmlCheckNodeName (xmlNodePtr &node, const char *nodeName)\n{\n\t// Check node name\n\tif ( node == NULL || ((const char*)node->name == NULL) || (strcmp ((const char*)node->name, nodeName) != 0) )\n\t{\n\n\t\t// try to find a child\n\t\tif (node != NULL)\n\t\t{\n\t\t\tnode = CIXml::getFirstChildNode (node, nodeName);\n\t\t\tif ( node != NULL && ((const char*)node->name != NULL) && (strcmp ((const char*)node->name, nodeName) == 0) )\n\t\t\t{\n\t\t\t\tnlinfo (\"check node %s ok in the child\", nodeName);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Make an error message\n\t\tchar tmp[512];\n\t\tsmprintf (tmp, 512, \"LogicStateMachine STATE_MACHINE XML Syntax error in block line %d, node %s should be %s\",\n\t\t\t(int)node->line, node->name, nodeName);\n\n\t\tnlinfo (tmp);\n\t\tnlstop;\n\t\tthrow EXmlParsingError (tmp);\n\t}\n\n\tnlinfo (\"check node %s ok\", nodeName);\n}\n\nstd::string getXMLProp (xmlNodePtr node, const char *propName)\n{\n\tconst char *name = (const char*)xmlGetProp (node, (xmlChar*)propName);\n\tif (name)\n\t{\n\t\tnlinfo (\"get prop %s = %s\", propName, name);\n\t\tstring n = name;\n\t\txmlFree ((void*)name);\n\t\treturn n;\n\t}\n\telse\n\t{\n\t\t// Make an error message\n\t\tchar tmp[512];\n\t\tsmprintf (tmp, 512, \"LogicStateMachine XML Syntax error in block %s line %d, aguments Name not found\",\n\t\t\tnode->name, (int)node->line);\n\t\tthrow EXmlParsingError (tmp);\n\t\treturn \"\";\n\t}\n}\n\n\n//---------------------------------------------------\n// setCurrentState :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::setCurrentState( string stateName )\n{\n\tmap<string,CLogicState>::iterator itStates = _States.find( stateName );\n\tif( itStates != _States.end() )\n\t{\n\t\t(*itStates).second.exitState();\n\n\t\t_CurrentState = stateName;\n\n\t\t(*itStates).second.enterState();\n\n\t\tnlinfo(\"Switching to state \\\"%s\\\"\",_CurrentState.c_str());\n\t}\n\telse\n\t{\n\t\tnlwarning(\"(LOGIC)<CLogicStateMachine::setCurrentState> The state \\\"%s\\\" is not in the state machine \\\"%s\\\"\",stateName.c_str(),_Name.c_str());\n\t}\n\n} // setCurrentState //\n\n\n\n//---------------------------------------------------\n// addCondition :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::addCondition( CLogicCondition condition )\n{\n\tcondition.setLogicStateMachine(this);\n\t_Conditions.insert(make_pair(condition.getName(),condition));\n\n} // addCondition //\n\n\n\n//---------------------------------------------------\n// addState :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::addState( CLogicState logicState )\n{\n\tlogicState.setLogicStateMachine( this );\n\t_States.insert( std::make_pair(logicState.getName(),logicState) );\n\n} // addState //\n\n\n\n\n//---------------------------------------------------\n// addSIdMap :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::addSIdMap( const TSIdMap& sIdMap )\n{\n\t// call addSIdMap for each state\n\tmap<string,CLogicState>::iterator itStates;\n\tfor( itStates = _States.begin(); itStates != _States.end(); ++itStates )\n\t{\n\t\t(*itStates).second.addSIdMap( sIdMap );\n\t}\n\n} // addSIdMap //\n\n\n\n//---------------------------------------------------\n// processLogic :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::processLogic()\n{\n\t// call processLogic for the current state\n\tmap<string,CLogicState>::iterator itStates = _States.find( _CurrentState );\n\tnlassert( itStates != _States.end() );\n\t(*itStates).second.processLogic();\n\n\t// update the counters\n\tmap<string,CLogicCounter>::iterator itCount;\n\tfor( itCount = _Counters.begin(); itCount != _Counters.end(); ++itCount )\n\t{\n\t\t(*itCount).second.update();\n\t}\n\n} // processLogic //\n\n\n\n//---------------------------------------------------\n// getMessagesToSend :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::getMessagesToSend( multimap<CEntityId,CMessage>& msgs )\n{\n\tmap<std::string, CLogicState>::iterator itState;\n\tfor( itState = _States.begin(); itState != _States.end(); ++itState )\n\t{\n\t\t(*itState).second.getMessagesToSend( msgs );\n\t}\n\n} // getMessagesToSend //\n\n\n\n\n//---------------------------------------------------\n// getVariable :\n//\n//---------------------------------------------------\nbool CLogicStateMachine::getVariable( std::string& varName, CLogicVariable& var )\n{\n\tmap<string,CLogicVariable>::iterator itVar = _Variables.find( varName );\n\tif( itVar != _Variables.end() )\n\t{\n\t\tvar = (*itVar).second;\n\t\treturn true;\n\t}\n\n\tmap<string,CLogicCounter>::iterator itCount = _Counters.find( varName );\n\tif( itCount != _Counters.end() )\n\t{\n\t\tvar = (*itCount).second;\n\t\treturn true;\n\t}\n\n\treturn false;\n\n} // getVariable //\n\n\n\n//---------------------------------------------------\n// getCondition :\n//\n//---------------------------------------------------\nbool CLogicStateMachine::getCondition( const std::string& condName, CLogicCondition& cond )\n{\n\tmap<string,CLogicCondition>::iterator itCond = _Conditions.find( condName );\n\tif( itCond != _Conditions.end() )\n\t{\n\t\tcond = (*itCond).second;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\n} // getCondition //\n\n\n//---------------------------------------------------\n// modifyVariable :\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::modifyVariable( string varName, string modifOperator, sint64 value )\n{\n\tmap<string,CLogicVariable>::iterator itVar = _Variables.find( varName );\n\tif( itVar != _Variables.end() )\n\t{\n\t\t(*itVar).second.applyModification( modifOperator, value );\n\t\treturn;\n\t}\n\tmap<string,CLogicCounter>::iterator itCount = _Counters.find( varName );\n\tif( itCount != _Counters.end() )\n\t{\n\t\t(*itCount).second.applyModification( modifOperator, value );\n\t\treturn;\n\t}\n\n\tnlwarning(\"(LOGIC)<CLogicStateMachine::modifyVariable> The variable \\\"%s\\\" is not in the state machine \\\"%s\\\"\",varName.c_str(),_Name.c_str());\n\n} // modifyVariable //\n\n\n\n//---------------------------------------------------\n// serial :\n//\n//---------------------------------------------------\n/*void CLogicStateMachine::serial( IStream &f )\n{\n\tf.xmlPush(\"STATE_MACHINE\");\n\n\n\tf.serialCont( _Variables );\n\tf.serialCont( _Counters );\n\tf.serialCont( _Conditions );\n\tf.serialCont( _States );\n\tf.serial( _CurrentState );\n\tf.serial( _Name );\n\n\tif( f.isReading() )\n\t{\n\t\t// set the logic state machine addr in each state\n\t\tmap<string,CLogicState>::iterator itStates;\n\t\tfor( itStates = _States.begin(); itStates != _States.end(); ++itStates )\n\t\t{\n\t\t\t(*itStates).second.setLogicStateMachine( this );\n\t\t}\n\n\t\t// set the logic state machine addr in each conditions\n\t\tmap<string,CLogicCondition>::iterator itCond;\n\t\tfor( itCond = _Conditions.begin(); itCond != _Conditions.end(); ++itCond )\n\t\t{\n\t\t\t(*itCond).second.setLogicStateMachine( this );\n\t\t}\n\t}\n\n\tf.xmlPop();\n\n} // serial //*/\n\n\n//---------------------------------------------------\n//\tDisplay the variables\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::displayVariables()\n{\n\tmultimap<CEntityId,string> allVariables;\n\n\t// // get vars referenced in the states\n\tmap<string, CLogicState>::iterator itS;\n\tfor( itS = _States.begin(); itS != _States.end(); ++itS )\n\t{\n\t\t(*itS).second.fillVarMap( allVariables );\n\t}\n\n\t// extract the unclaimed variables from all the variables\n\tvector<string> unclaimedVariables;\n\tCEntityId unknown;\n\tunknown.setType( 0xfe );\n\tunknown.setCreatorId( 0 );\n\tunknown.setDynamicId( 0 );\n\tpair<multimap<CEntityId,string>::iterator,multimap<CEntityId,string>::iterator> itVarsRng = allVariables.equal_range(unknown);\n\tmultimap<CEntityId,string>::iterator itVars;\n\n\tfor( itVars = itVarsRng.first; itVars != itVarsRng.second; )\n\t{\n\t\tmultimap<CEntityId,string>::iterator itDel = itVars++;\n\t\tunclaimedVariables.push_back( (*itDel).second );\n\t\tallVariables.erase( itDel );\n\t}\n\t/*\n\tif( itVarsRng.first != allVariables.end() )\n\t{\n\t\titVars = itVarsRng.first;\n\t\tdo\n\t\t{\n\t\t\tmultimap<CEntityId,string>::iterator itDel = itVars++;\n\t\t\tunclaimedVariables.push_back( (*itDel).second );\n\t\t\tallVariables.erase( itDel );\n\t\t}\n\t\twhile( itVars != itVarsRng.second );\n\t}\n\t*/\n\n\n\tnlinfo(\"VARIABLES/COUNTERS in %s : %d/%d are registered : \",_Name.c_str(),allVariables.size(),allVariables.size()+unclaimedVariables.size());\n\t// display the registered variables\n\tfor( itVars = allVariables.begin(); itVars != allVariables.end(); ++itVars )\n\t{\n\t\tmap<string, CLogicVariable>::const_iterator itV = _Variables.find( (*itVars).second );\n\t\tnlinfo(\"[%d] %s = %f\",(uint8)(*itVars).first.getDynamicId(),(*itV).first.c_str(),(double)(*itV).second.getValue());\n\t}\n\n\t// display the unclaimed variables\n\tsort( unclaimedVariables.begin(), unclaimedVariables.end() );\n\tvector<string>::iterator itUV;\n\tfor( itUV = unclaimedVariables.begin(); itUV != unclaimedVariables.end(); ++itUV )\n\t{\n\t\tmap<string, CLogicVariable>::const_iterator itV = _Variables.find( *itUV );\n\t\tnlinfo(\"(-)%s = %f\",(*itV).first.c_str(),(double)(*itV).second.getValue());\n\t}\n\n} // displayVariables //\n\n\n//---------------------------------------------------\n//\tDisplay the states\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::displayStates()\n{\n\tnlinfo(\"There are %d STATES in the state machine \\\"%s\\\": \",_States.size(),_Name.c_str());\n\tmap<string, CLogicState>::const_iterator itS;\n\tfor( itS = _States.begin(); itS != _States.end(); ++itS )\n\t{\n\t\tnlinfo(\"%s\",(*itS).first.c_str());\n\t}\n\tnlinfo(\"The current state is : \\\"%s\\\"\",_CurrentState.c_str());\n\n} // displayStates //\n\n\n//---------------------------------------------------\n//\tSet the verbose mode for the variable\n//\n//---------------------------------------------------\nvoid CLogicStateMachine::setVerbose( string varName, bool b )\n{\n\tif( varName == \"all\" )\n\t{\n\t\tmap<string, CLogicVariable>::iterator itV;\n\t\tfor( itV = _Variables.begin(); itV != _Variables.end(); ++itV )\n\t\t{\n\t\t\t(*itV).second.setVerbose( b );\n\t\t}\n\t\tmap<string, CLogicCounter>::iterator itC;\n\t\tfor( itC = _Counters.begin(); itC != _Counters.end(); ++itC )\n\t\t{\n\t\t\t(*itC).second.setVerbose( b );\n\t\t}\n\t\tif(b)\n\t\t{\n\t\t\tnlinfo(\"the verbose mode has been activated for all the variables\",varName.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo(\"the verbose mode has been desactivated for all the variables\",varName.c_str());\n\t\t}\n\t\treturn;\n\t}\n\n\tsint8 filter = -1;\n\tstring motif;\n\t// *xxx* => we look for a string with xxx inside\n\tif( varName[0]=='*' && varName[varName.size()-1]=='*')\n\t{\n\t\tmotif = varName.substr(1,varName.size()-2);\n\t\tfilter = 0;\n\t}\n\telse\n\t// *xxx => we look for a string with xxx at the end\n\tif( varName[0]=='*' )\n\t{\n\t\tmotif = varName.substr(1,varName.size()-1);\n\t\tfilter = 1;\n\t}\n\telse\n\t// xxx* => we look for a string with xxx at the beginning\n\tif( varName[varName.size()-1]=='*' )\n\t{\n\t\tmotif = varName.substr(0,varName.size()-1);\n\t\tfilter = 2;\n\t}\n\n\t// if no filter\n\tif( filter == -1 )\n\t{\n\t\tmap<string, CLogicVariable>::iterator itV = _Variables.find( varName );\n\t\tif( itV != _Variables.end() )\n\t\t{\n\t\t\t(*itV).second.setVerbose( b );\n\t\t}\n\t\tmap<string, CLogicCounter>::iterator itC = _Counters.find( varName );\n\t\tif( itC != _Counters.end() || varName ==\"all\" )\n\t\t{\n\t\t\t(*itC).second.setVerbose( b );\n\t\t}\n\t}\n\t// if filter\n\telse\n\t{\n\t\tmap<string, CLogicVariable>::iterator itV;\n\t\tfor( itV = _Variables.begin(); itV != _Variables.end(); ++itV )\n\t\t{\n\t\t\tif( testNameWithFilter( filter, motif,(*itV).second.getName()) )\n\t\t\t{\n\t\t\t\t(*itV).second.setVerbose( b );\n\t\t\t}\n\t\t}\n\t\tmap<string, CLogicCounter>::iterator itC;\n\t\tfor( itC = _Counters.begin(); itC != _Counters.end(); ++itC )\n\t\t{\n\t\t\tif( testNameWithFilter( filter, motif,(*itC).second.getName()) )\n\t\t\t{\n\t\t\t\t(*itC).second.setVerbose( b );\n\t\t\t}\n\t\t}\n\t}\n\tif(b)\n\t{\n\t\tnlinfo(\"the verbose mode for variable \\\"%s\\\" has been activated\",varName.c_str());\n\t}\n\telse\n\t{\n\t\tnlinfo(\"the verbose mode for variable \\\"%s\\\" has been desactivated\",varName.c_str());\n\t}\n\n} // setVerbose //\n\n\n\n//---------------------------------------------------\n//\ttestNameWithFilter :\n//\n//---------------------------------------------------\nbool testNameWithFilter( sint8 filter, string motif, string varName )\n{\n\tif( varName.size() > motif.size() )\n\t{\n\t\tswitch( filter )\n\t\t{\n\t\t\t// *xxx*\n\t\t\tcase 0 :\n\t\t\t{\n\t\t\t\tif(varName.find(motif) != string::npos)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\t\t// *xxx\n\t\t\tcase 1 :\n\t\t\t{\n\t\t\t\tsint beginIndex = (sint)(varName.size() - motif.size() - 1);\n\t\t\t\tstring endOfVarName = varName.substr(beginIndex,motif.size());\n\t\t\t\tif( endOfVarName == motif )\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\t\t// xxx*\n\t\t\tcase 2 :\n\t\t\t{\n\t\t\t\tstring beginOfVarName = varName.substr(0,motif.size());\n\t\t\t\tif( beginOfVarName == motif )\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn false;\n\n} // testNameWithFilter //\n\nvoid CLogicStateMachine::write (xmlDocPtr doc) const\n{\n\t// Create the first node\n\txmlNodePtr node = xmlNewDocNode (doc, NULL, (const xmlChar*)\"STATE_MACHINE\", NULL);\n\txmlDocSetRootElement (doc, node);\n\txmlSetProp (node, (const xmlChar*)\"Name\", (const xmlChar*)_Name.c_str());\n\txmlSetProp (node, (const xmlChar*)\"CurrentState\", (const xmlChar*)_CurrentState.c_str());\n\n\tfor (std::map<std::string, CLogicVariable>::const_iterator vit = _Variables.begin(); vit != _Variables.end(); vit++)\n\t{\n\t\t(*vit).second.write(node);\n\t}\n\n\tfor (std::map<std::string, CLogicCounter>::const_iterator cit = _Counters.begin(); cit != _Counters.end(); cit++)\n\t{\n\t\t(*cit).second.write(node);\n\t}\n\n\tfor (std::map<std::string, CLogicCondition>::const_iterator c2it = _Conditions.begin(); c2it != _Conditions.end(); c2it++)\n\t{\n\t\t(*c2it).second.write(node);\n\t}\n\n\tfor (std::map<std::string, CLogicState>::const_iterator sit = _States.begin(); sit != _States.end(); sit++)\n\t{\n\t\t(*sit).second.write(node);\n\t}\n}\n\nvoid CLogicStateMachine::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"STATE_MACHINE\");\n\n\tsetName (getXMLProp (node, \"Name\"));\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"VARIABLE\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"VARIABLE\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicVariable v;\n\t\t\tv.read(parent);\n\t\t\t_Variables.insert (make_pair(v.getName(), v));\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"VARIABLE\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"COUNTER\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"COUNTER\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicCounter v;\n\t\t\tv.read(parent);\n\t\t\t_Counters.insert (make_pair(v.getName(), v));\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"COUNTER\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"CONDITION\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"CONDITION\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicCondition v;\n\t\t\tv.read(parent);\n\t\t\t_Conditions.insert (make_pair(v.getName(), v));\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"CONDITION\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\t{\n\t\t// Count the parent\n\t\tuint nb = CIXml::countChildren (node, \"STATE\");\n\t\tuint i = 0;\n\t\txmlNodePtr parent = CIXml::getFirstChildNode (node, \"STATE\");\n\t\twhile (i<nb)\n\t\t{\n\t\t\tCLogicState v;\n\t\t\tv.read(parent);\n\t\t\t_States.insert (make_pair(v.getName(), v));\n\n\t\t\t// Next parent\n\t\t\tparent = CIXml::getNextChildNode (parent, \"STATE\");\n\t\t\ti++;\n\t\t}\n\t}\n\n\tsetCurrentState (getXMLProp (node, \"CurrentState\"));\n}\n\n} // NLLOGIC\n"
  },
  {
    "path": "code/nel/src/logic/logic_variable.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"nel/logic/logic_state_machine.h\"\n#include \"nel/logic/logic_variable.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLLOGIC\n{\n\n\n//---------------------------------------------------\n// CLogicVariable :\n//\n//---------------------------------------------------\nCLogicVariable::CLogicVariable()\n{\n\t_Value = 0;\n\t_Name = \"unamed_var\";\n\t_Verbose = false;\n\n} // CLogicVariable //\n\n\n\n//---------------------------------------------------\n// setValue :\n//\n//---------------------------------------------------\nvoid CLogicVariable::setValue( sint64 value )\n{\n\t_Value = value;\n\n\tif( _Verbose )\n\t{\n\t\tnlinfo(\"variable \\\"%s\\\" value is now %f\",_Name.c_str(),(double)_Value);\n\t}\n\n} // setValue //\n\n\n\n//---------------------------------------------------\n// applyModification :\n//\n//---------------------------------------------------\nvoid CLogicVariable::applyModification( string op, sint64 value )\n{\n\tif( op == \"SET\" || op == \"set\" )\n\t{\n\t\t_Value = value;\n\t}\n\telse\n\tif( op == \"ADD\" || op == \"add\" )\n\t{\n\t\t_Value += value;\n\t}\n\telse\n\tif( op == \"SUB\" || op == \"sub\" )\n\t{\n\t\t_Value -= value;\n\t}\n\telse\n\tif( op == \"MUL\" || op == \"mul\")\n\t{\n\t\t_Value *= value;\n\t}\n\telse\n\tif( op == \"DIV\" || op == \"div\")\n\t{\n\t\tif( value != 0 ) _Value /= value;\n\t}\n\telse\n\t{\n\t\tnlwarning(\"(LGCS)<CLogicVariable::applyModification> The operator \\\"%s\\\" is unknown\",op.c_str());\n\t\treturn;\n\t}\n\n\tif( _Verbose )\n\t{\n\t\tnlinfo(\"variable \\\"%s\\\" value is now %f\",_Name.c_str(),(double)_Value);\n\t}\n\n} // applyModification //\n\n\n//---------------------------------------------------\n// processLogic :\n//\n//---------------------------------------------------\nvoid CLogicVariable::processLogic()\n{\n\n\n} // processLogic //\n\n\n//---------------------------------------------------\n// serial :\n//\n//---------------------------------------------------\n/*void CLogicVariable::serial( IStream &f )\n{\n\tf.xmlPush( \"VARIABLE\");\n\n\tf.serial( _Value );\n\tf.serial( _Name );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicVariable::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"VARIABLE\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Name\", (const xmlChar*)_Name.c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Value\", (const xmlChar*)toString(_Value).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Verbose\", (const xmlChar*)toString(_Verbose).c_str());\n}\n\nvoid CLogicVariable::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"VARIABLE\");\n\n\t_Name = getXMLProp (node, \"Name\");\n\t_Value = atoiInt64 (getXMLProp (node, \"Value\").c_str());\n\tNLMISC::fromString(getXMLProp(node, \"Verbose\"), _Verbose);\n}\n\n//---------------------------------------------------\n// CLogicCounter :\n//\n//---------------------------------------------------\nCLogicCounter::CLogicCounter()\n{\n\t_TickCount = 0;\n\t_Value = 0;\n\t_Name = \"unamed_counter\";\n\n\tPeriod.setValue( 10 );\n\tPeriod.setName(\"Period\");\n\n\tPhase.setValue( 0 );\n\tPhase.setName(\"Phase\");\n\n\tStep.setValue( 1 );\n\tStep.setName(\"Step\");\n\n\tLowLimit.setValue( 0 );\n\tLowLimit.setName(\"LowLimit\");\n\n\tHighLimit.setValue( 100 );\n\tHighLimit.setName(\"HighLimit\");\n\n\tMode.setValue( STOP_AT_LIMIT );\n\tMode.setName(\"Mode\");\n\n\tControl.setValue( RUN );\n\tControl.setName(\"Control\");\n\n} // CLogicCounter //\n\n\n//---------------------------------------------------\n// update :\n//\n//---------------------------------------------------\nvoid CLogicCounter::update()\n{\n\tif( Control.getValue() == STOPPED )\n\t{\n\t\treturn;\n\t}\n\n\t_TickCount++;\n\tif( _TickCount < Period.getValue() )\n\t{\n\t\treturn;\n\t}\n\telse\n\t{\n\t\t_TickCount = 0;\n\t}\n\n\tswitch( Control.getValue() )\n\t{\n\t\tcase RUN :\n\t\t{\n\t\t\t_Value += Step.getValue();\n\t\t\tmanageRunningMode();\n\t\t}\n\t\tbreak;\n\n\t\tcase REWIND :\n\t\t{\n\t\t\t_Value = LowLimit.getValue();\n\t\t\tControl.setValue( RUN );\n\t\t}\n\t\tbreak;\n\n\t\tcase FAST_FORWARD :\n\t\t{\n\t\t\t_Value = HighLimit.getValue();\n\t\t\tControl.setValue( RUN );\n\t\t}\n\t\tbreak;\n\n\t}\n\n\tif( _Verbose )\n\t{\n\t\tnlinfo(\"variable \\\"%s\\\" value is now %f\",_Name.c_str(),(double)_Value);\n\t}\n\n} // update //\n\n\n//---------------------------------------------------\n// manageRunningMode :\n//\n//---------------------------------------------------\nvoid CLogicCounter::manageRunningMode()\n{\n\t// loop on one value\n\tif( HighLimit.getValue() == LowLimit.getValue() )\n\t{\n\t\t_Value = HighLimit.getValue();\n\t\treturn;\n\t}\n\n\tswitch( Mode.getValue() )\n\t{\n\t\tcase STOP_AT_LIMIT :\n\t\t{\n\t\t\tif( _Value > HighLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = HighLimit.getValue();\n\t\t\t}\n\t\t\tif( _Value < LowLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = LowLimit.getValue();\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t\tcase LOOP :\n\t\t{\n\t\t\t// value is higher than high limit\n\t\t\tif( _Value > HighLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = LowLimit.getValue() + _Value - HighLimit.getValue() - 1;\n\t\t\t}\n\t\t\t// value is lower than low limit\n\t\t\telse\n\t\t\t{\n\t\t\t\tif( _Value < LowLimit.getValue() )\n\t\t\t\t{\n\t\t\t\t\t_Value = HighLimit.getValue() - (LowLimit.getValue() -_Value) + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t\tcase SHUTTLE :\n\t\t{\n\t\t\t// value is higher than high limit\n\t\t\tif( _Value > HighLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = HighLimit.getValue() - (_Value - HighLimit.getValue());\n\t\t\t\tStep.setValue( -Step.getValue() );\n\t\t\t}\n\t\t\t// value is lower than low limit\n\t\t\telse\n\t\t\t{\n\t\t\t\tif( _Value < LowLimit.getValue() )\n\t\t\t\t{\n\t\t\t\t\t_Value = LowLimit.getValue() + LowLimit.getValue() - _Value;\n\t\t\t\t\tStep.setValue( -Step.getValue() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t\tcase DOWN_UP :\n\t\t{\n\t\t\t// low limit reached, we go up\n\t\t\tif( _Value < LowLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = LowLimit.getValue() + LowLimit.getValue() - _Value;\n\t\t\t\tStep.setValue( -Step.getValue() );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// high limit reached we stop\n\t\t\t\tif( _Value > HighLimit.getValue() )\n\t\t\t\t{\n\t\t\t\t\t_Value = HighLimit.getValue();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t\tcase UP_DOWN :\n\t\t{\n\t\t\t// high limit reached, we go down\n\t\t\tif( _Value > HighLimit.getValue() )\n\t\t\t{\n\t\t\t\t_Value = HighLimit.getValue() - (_Value - HighLimit.getValue());\n\t\t\t\tStep.setValue( -Step.getValue() );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// low limit reached, we stop\n\t\t\t\tif( _Value < LowLimit.getValue() )\n\t\t\t\t{\n\t\t\t\t\t_Value = LowLimit.getValue();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n} // manageRunningMode //\n\n\n//---------------------------------------------------\n// serial :\n//\n//---------------------------------------------------\n/*void CLogicCounter::serial( IStream &f )\n{\n\tf.xmlPush( \"COUNTER\");\n\n\tf.serial( _Value );\n\tf.serial( _Name );\n\tf.serial( Period );\n\tf.serial( Phase );\n\tf.serial( Step );\n\tf.serial( LowLimit );\n\tf.serial( HighLimit );\n\tf.serial( Mode );\n\n\tf.xmlPop();\n\n} // serial //*/\n\nvoid CLogicCounter::write (xmlNodePtr node) const\n{\n\txmlNodePtr elmPtr = xmlNewChild ( node, NULL, (const xmlChar*)\"COUNTER\", NULL);\n\txmlSetProp (elmPtr, (const xmlChar*)\"Name\", (const xmlChar*)_Name.c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Value\", (const xmlChar*)toString(_Value).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Verbose\", (const xmlChar*)toString(_Verbose).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Period\", (const xmlChar*)toString(Period.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Phase\", (const xmlChar*)toString(Phase.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Step\", (const xmlChar*)toString(Step.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"LowLimit\", (const xmlChar*)toString(LowLimit.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"HighLimit\", (const xmlChar*)toString(HighLimit.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Mode\", (const xmlChar*)toString(Mode.getValue()).c_str());\n\txmlSetProp (elmPtr, (const xmlChar*)\"Control\", (const xmlChar*)toString(Control.getValue()).c_str());\n}\n\nvoid CLogicCounter::read (xmlNodePtr node)\n{\n\txmlCheckNodeName (node, \"COUNTER\");\n\n\t_Name = getXMLProp (node, \"Name\");\n\t_Value = atoiInt64 (getXMLProp (node, \"Value\").c_str());\n\tNLMISC::fromString(getXMLProp (node, \"Verbose\"), _Verbose);\n\tPeriod.setValue(atoiInt64(getXMLProp (node, \"Period\").c_str()));\n\tPhase.setValue(atoiInt64(getXMLProp (node, \"Phase\").c_str()));\n\tStep.setValue(atoiInt64(getXMLProp (node, \"Step\").c_str()));\n\tLowLimit.setValue(atoiInt64(getXMLProp (node, \"LowLimit\").c_str()));\n\tHighLimit.setValue(atoiInt64(getXMLProp (node, \"HighLimit\").c_str()));\n\tMode.setValue(atoiInt64(getXMLProp (node, \"Mode\").c_str()));\n\tControl.setValue(atoiInt64(getXMLProp (node, \"Control\").c_str()));\n}\n\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h config_file/*.cpp config_file/*.h)\nFILE(GLOB HEADERS ../../include/nel/misc/*.h)\n\nFILE(GLOB NLMISC_CDB\n\tcdb.cpp ../../include/nel/misc/cdb.h\n\tcdb_*.cpp ../../include/nel/misc/cdb_*.h\n)\n\nFILE(GLOB NLMISC_EVENT\n\tevents.cpp ../../include/nel/misc/events.h\n\tevent_*.cpp ../../include/nel/misc/event_*.h\n\t*_event_*.cpp ../../include/nel/misc/*_event_*.h\n)\n\nFILE(GLOB NLMISC_DEBUG\n\tdebug.cpp ../../include/nel/misc/debug.h\n\treport.cpp ../../include/nel/misc/report.h\n\tlog.cpp ../../include/nel/misc/log.h\n)\n\nFILE(GLOB NLMISC_FILESYSTEM\n\tasync_file_manager.cpp ../../include/nel/misc/async_file_manager.h\n\tfile.cpp ../../include/nel/misc/file.h\n\tpath.cpp ../../include/nel/misc/path.h\n\tbig_file.cpp ../../include/nel/misc/big_file.h\n\t*_xml.cpp ../../include/nel/misc/*_xml.h\n\txml_*.cpp ../../include/nel/misc/xml_*.h\n)\n\nFILE(GLOB NLMISC_STREAM\n\t*_stream.cpp ../../include/nel/misc/*_stream.h\n\tstream.cpp ../../include/nel/misc/stream.h\n\tstream_*.cpp ../../include/nel/misc/stream_*.h\n)\n\nFILE(GLOB NLMISC_DISPLAYER\n\tdisplayer.cpp ../../include/nel/misc/displayer.h\n\t*_displayer.cpp ../../include/nel/misc/*_displayer.h\n)\n\nFILE(GLOB NLMISC_MATH\n\tplane.cpp ../../include/nel/misc/plane.h\n\t../../include/nel/misc/plane_inline.h\n\tpolygon.cpp ../../include/nel/misc/polygon.h\n\tquad.cpp ../../include/nel/misc/quad.h\n\tquat.cpp ../../include/nel/misc/quat.h\n\trect.cpp ../../include/nel/misc/rect.h\n\trgba.cpp ../../include/nel/misc/rgba.h\n\ttriangle.cpp ../../include/nel/misc/triangle.h\n\tuv.cpp ../../include/nel/misc/uv.h\n\tvector*.cpp ../../include/nel/misc/vector*.h\n\taabbox.cpp ../../include/nel/misc/aabbox.h\n\talgo.cpp ../../include/nel/misc/algo.h\n\tbsphere.cpp ../../include/nel/misc/bsphere.h\n\tfast_floor.cpp ../../include/nel/misc/fast_floor.h\n\tgeom_ext.cpp ../../include/nel/misc/geom_ext.h\n\tline.cpp ../../include/nel/misc/line.h\n\tmatrix.cpp ../../include/nel/misc/matrix.h\n)\n\nFILE(GLOB NLMISC_PLATFORM\n\t*_nl.cpp ../../include/nel/misc/*_nl.h\n\tcommon.cpp ../../include/nel/misc/common.h\n\tapp_context.cpp ../../include/nel/misc/app_context.h\n\tcheck_fpu.cpp ../../include/nel/misc/check_fpu.h\n\tcpu_time_stat.cpp ../../include/nel/misc/cpu_time_stat.h\n\tdummy_window.cpp ../../include/nel/misc/dummy_window.h\n\tdynloadlib.cpp ../../include/nel/misc/dynloadlib.h\n\tfast_mem.cpp ../../include/nel/misc/fast_mem.h\n\tinter_window_msg_queue.cpp ../../include/nel/misc/inter_window_msg_queue.h\n\tsystem_*.cpp ../../include/nel/misc/system_*.h\n\twin32_util.cpp ../../include/nel/misc/win32_util.h\n\twin_tray.cpp ../../include/nel/misc/win_tray.h\n)\n\nFILE(GLOB NLMISC_GENERIC\n\t../../include/nel/misc/array_2d.h\n\t*_memory.cpp ../../include/nel/misc/*_memory.h\n\tbuf_fifo.cpp ../../include/nel/misc/buf_fifo.h\n\t../../include/nel/misc/callback.h\n\t*_allocator.cpp ../../include/nel/misc/*_allocator.h\n\t../../include/nel/misc/enum_bitset.h\n\tfast_id_map.cpp ../../include/nel/misc/fast_id_map.h\n\thierarchical_timer.cpp ../../include/nel/misc/hierarchical_timer.h\n\t../../include/nel/misc/historic.h\n\t../../include/nel/misc/mutable_container.h\n\t../../include/nel/misc/random.h\n\tsmart_ptr.cpp ../../include/nel/misc/smart_ptr.h\n\t../../include/nel/misc/smart_ptr_inline.h\n\t../../include/nel/misc/resource_ptr.h\n\t../../include/nel/misc/resource_ptr_inline.h\n\tbit_set.cpp ../../include/nel/misc/bit_set.h\n\tstop_watch.cpp ../../include/nel/misc/stop_watch.h\n\t../../include/nel/misc/twin_map.h\n\tobject_vector.cpp ../../include/nel/misc/object_vector.h\n\t../../include/nel/misc/singleton.h\n\tspeaker_listener.cpp ../../include/nel/misc/speaker_listener.h\n\t../../include/nel/misc/static_map.h\n\tstl_block_list.cpp ../../include/nel/misc/stl_block_list.h\n)\n\nFILE(GLOB NLMISC_UTILITY\n\tconfig_file.cpp ../../include/nel/misc/config_file.h\n\tcf_*.cpp ../../include/nel/misc/cf_*.h\n\tconfig_file/config_file.cpp config_file/config_file.h\n\tconfig_file/cf_*.cpp config_file/cf_*.h\n\tclass_id.cpp ../../include/nel/misc/class_id.h\n\tclass_registry.cpp ../../include/nel/misc/class_registry.h\n\tcmd_args.cpp ../../include/nel/misc/cmd_args.h\n\tcommand.cpp ../../include/nel/misc/command.h\n\teid_translator.cpp ../../include/nel/misc/eid_translator.h\n\tentity_id.cpp ../../include/nel/misc/entity_id.h\n\teval_num_expr.cpp ../../include/nel/misc/eval_num_expr.h\n\tfactory.cpp ../../include/nel/misc/factory.h\n\tgrid_traversal.cpp ../../include/nel/misc/grid_traversal.h\n\tmouse_smoother.cpp ../../include/nel/misc/mouse_smoother.h\n\tnoise_value.cpp ../../include/nel/misc/noise_value.h\n\tprogress_callback.cpp ../../include/nel/misc/progress_callback.h\n\tsheet_id.cpp ../../include/nel/misc/sheet_id.h\n\tvariable.cpp ../../include/nel/misc/variable.h\n\tvalue_smoother.cpp ../../include/nel/misc/value_smoother.h\n)\n\nFILE(GLOB NLMISC_STRING\n\tstring_*.cpp ../../include/nel/misc/string_*.h\n\t../../include/nel/misc/ucstring.h\n\tunicode.cpp\n\tsstring.cpp ../../include/nel/misc/sstring.h\n)\n\nFILE(GLOB NLMISC_I18N\n\tdiff_tool.cpp ../../include/nel/misc/diff_tool.h\n\ti18n.cpp ../../include/nel/misc/i18n.h\n\twords_dictionary.cpp ../../include/nel/misc/words_dictionary.h\n)\n\nFILE(GLOB NLMISC_THREAD\n\tco_task.cpp ../../include/nel/misc/co_task.h\n\tmutex.cpp ../../include/nel/misc/mutex.h\n\t*_thread.cpp ../../include/nel/misc/*_thread.h\n\ttask_*.cpp ../../include/nel/misc/task_*.h\n\treader_writer.cpp ../../include/nel/misc/reader_writer.h\n\ttds.cpp ../../include/nel/misc/tds.h\n\tthread.cpp ../../include/nel/misc/thread.h\n)\n\nFILE(GLOB NLMISC_BITMAP\n\tbitmap.cpp ../../include/nel/misc/bitmap.h\n\tbitmap_*.cpp\n)\n\nFILE(GLOB NLMISC_CRYPT\n\tmd5.cpp ../../include/nel/misc/md5.h\n\tsha1.cpp ../../include/nel/misc/sha1.h\n)\n\nSOURCE_GROUP(\"\" FILES ${SRC} ${HEADERS})\nSOURCE_GROUP(\"cdb\" FILES ${NLMISC_CDB})\nSOURCE_GROUP(\"event\" FILES ${NLMISC_EVENT})\nSOURCE_GROUP(\"debug\" FILES ${NLMISC_DEBUG})\nSOURCE_GROUP(\"platform\" FILES ${NLMISC_PLATFORM})\nSOURCE_GROUP(\"filesystem\" FILES ${NLMISC_FILESYSTEM})\nSOURCE_GROUP(\"stream\" FILES ${NLMISC_STREAM})\nSOURCE_GROUP(\"displayer\" FILES ${NLMISC_DISPLAYER})\nSOURCE_GROUP(\"math\" FILES ${NLMISC_MATH})\nSOURCE_GROUP(\"generic\" FILES ${NLMISC_GENERIC})\nSOURCE_GROUP(\"utility\" FILES ${NLMISC_UTILITY})\nSOURCE_GROUP(\"bitmap\" FILES ${NLMISC_BITMAP})\nSOURCE_GROUP(\"thread\" FILES ${NLMISC_THREAD})\nSOURCE_GROUP(\"i18n\" FILES ${NLMISC_I18N})\nSOURCE_GROUP(\"crypt\" FILES ${NLMISC_CRYPT})\nSOURCE_GROUP(\"string\" FILES ${NLMISC_STRING})\n\nNL_TARGET_LIB(nelmisc ${HEADERS} ${SRC})\n\nIF(WITH_GTK)\n  IF(GTK2_FOUND)\n    INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})\n    ADD_DEFINITIONS(-DNL_USE_GTK)\n    TARGET_LINK_LIBRARIES(nelmisc ${GTK2_LIBRARIES})\n  ENDIF(GTK2_FOUND)\nENDIF(WITH_GTK)\n\nIF(JPEG_FOUND)\n  INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})\n  ADD_DEFINITIONS(-DUSE_JPEG)\n  TARGET_LINK_LIBRARIES(nelmisc ${JPEG_LIBRARY})\nENDIF(JPEG_FOUND)\n\nIF(WITH_STATIC OR WIN32)\n  TARGET_LINK_LIBRARIES(nelmisc ${PNG_LIBRARIES})\nELSE(WITH_STATIC OR WIN32)\n  # Link only with libpng shared library\n  TARGET_LINK_LIBRARIES(nelmisc ${PNG_LIBRARY})\nENDIF(WITH_STATIC OR WIN32)\n\n# For DirectInput (di_event_emitter)\n#IF(WIN32)\n#  INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR})\n#  TARGET_LINK_LIBRARIES(nelmisc ${DXSDK_DINPUT_LIBRARY} ${DXSDK_GUID_LIBRARY})\n#ENDIF(WIN32)\n\nIF(UNIX)\n  \n  IF(FreeBSD)\n\tTARGET_LINK_LIBRARIES(nelmisc -lc -I/usr/local/include -L/usr/local/lib/ -lexecinfo)\n\t\n  ELSE(FreeBSD)\n\tTARGET_LINK_LIBRARIES(nelmisc -lc -ldl)\n  ENDIF(FreeBSD)\n  \n#  CMAKE_SYSTEM_NAME\n#  TARGET_LINK_LIBRARIES(nelmisc -lc -I/usr/local/include -L/usr/local/lib/ -lexecinfo)\n  IF(NOT APPLE)\n    TARGET_LINK_LIBRARIES(nelmisc -lrt)\n  ENDIF(NOT APPLE)\nENDIF(UNIX)\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${PNG_INCLUDE_DIR} config_file)\n\nTARGET_LINK_LIBRARIES(nelmisc ${CMAKE_THREAD_LIBS_INIT} ${LIBXML2_LIBRARIES} ${PROTOBUF_LIBRARIES} ${ZLIB_LIBRARY})\nSET_TARGET_PROPERTIES(nelmisc PROPERTIES LINK_INTERFACE_LIBRARIES \"\")\nNL_DEFAULT_PROPS(nelmisc \"NeL, Library: NeL Misc\")\nNL_ADD_RUNTIME_FLAGS(nelmisc)\n\nNL_ADD_LIB_SUFFIX(nelmisc)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS})\n\nIF(WITH_PCH)\n  ADD_NATIVE_PRECOMPILED_HEADER(nelmisc ${CMAKE_CURRENT_SOURCE_DIR}/stdmisc.h ${CMAKE_CURRENT_SOURCE_DIR}/stdmisc.cpp)\nENDIF(WITH_PCH)\n\nNL_GEN_PC(nel-misc.pc)\n\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS nelmisc LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/nel/src/misc/aabbox.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/aabbox.h\"\n#include \"nel/misc/polygon.h\"\n#include \"nel/misc/bsphere.h\"\n#include \"nel/misc/matrix.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\nbool\tCAABBox::clipFront(const CPlane &p) const\n{\n\tCVector\t\thswap;\n\n\t// The bbox is front of the plane if only one of his vertex is in front.\n\tif(p*(Center + HalfSize) > 0)\treturn true;\n\tif(p*(Center - HalfSize) > 0)\treturn true;\n\thswap.set(-HalfSize.x, HalfSize.y, HalfSize.z);\n\tif(p*(Center + hswap) > 0)\treturn true;\n\tif(p*(Center - hswap) > 0)\treturn true;\n\thswap.set(HalfSize.x, -HalfSize.y, HalfSize.z);\n\tif(p*(Center + hswap) > 0)\treturn true;\n\tif(p*(Center - hswap) > 0)\treturn true;\n\thswap.set(HalfSize.x, HalfSize.y, -HalfSize.z);\n\tif(p*(Center + hswap) > 0)\treturn true;\n\tif(p*(Center - hswap) > 0)\treturn true;\n\n\treturn false;\n}\n// ***************************************************************************\nbool\tCAABBox::clipBack(const CPlane &p) const\n{\n\tCVector\t\thswap;\n\n\t// The bbox is back of the plane if only one of his vertex is in back.\n\tif(p*(Center + HalfSize) < 0)\treturn true;\n\tif(p*(Center - HalfSize) < 0)\treturn true;\n\thswap.set(-HalfSize.x, HalfSize.y, HalfSize.z);\n\tif(p*(Center + hswap) < 0)\treturn true;\n\tif(p*(Center - hswap) < 0)\treturn true;\n\thswap.set(HalfSize.x, -HalfSize.y, HalfSize.z);\n\tif(p*(Center + hswap) < 0)\treturn true;\n\tif(p*(Center - hswap) < 0)\treturn true;\n\thswap.set(HalfSize.x, HalfSize.y, -HalfSize.z);\n\tif(p*(Center + hswap) < 0)\treturn true;\n\tif(p*(Center - hswap) < 0)\treturn true;\n\n\treturn false;\n}\n\n\n// ***************************************************************************\nbool\t\t\tCAABBox::include(const CVector &a) const\n{\n\tif(Center.x+HalfSize.x<a.x)\treturn false;\n\tif(Center.x-HalfSize.x>a.x)\treturn false;\n\tif(Center.y+HalfSize.y<a.y)\treturn false;\n\tif(Center.y-HalfSize.y>a.y)\treturn false;\n\tif(Center.z+HalfSize.z<a.z)\treturn false;\n\tif(Center.z-HalfSize.z>a.z)\treturn false;\n\treturn true;\n}\n\n\n// ***************************************************************************\nbool\t\t\tCAABBox::include(const CAABBox &box) const\n{\n\tif(Center.x+HalfSize.x < box.Center.x+box.HalfSize.x)\treturn false;\n\tif(Center.x-HalfSize.x > box.Center.x-box.HalfSize.x)\treturn false;\n\tif(Center.y+HalfSize.y < box.Center.y+box.HalfSize.y)\treturn false;\n\tif(Center.y-HalfSize.y > box.Center.y-box.HalfSize.y)\treturn false;\n\tif(Center.z+HalfSize.z < box.Center.z+box.HalfSize.z)\treturn false;\n\tif(Center.z-HalfSize.z > box.Center.z-box.HalfSize.z)\treturn false;\n\treturn true;\n}\n\n\n// ***************************************************************************\nbool\t\t\tCAABBox::intersect(const CAABBox &box) const\n{\n\tCVector\tmina = getMin(), maxa = getMax(),\n\t\t\tminb = box.getMin(), maxb = box.getMax();\n\n\treturn ! ( mina.x > maxb.x ||\n\t\t\t   mina.y > maxb.y ||\n\t\t\t   mina.z > maxb.z ||\n\t\t\t   minb.x > maxa.x ||\n\t\t\t   minb.y > maxa.y ||\n\t\t\t   minb.z > maxa.z);\n}\n\n// ***************************************************************************\nbool\t\t\tCAABBox::intersect(const CVector &a, const CVector &b, const CVector &c) const\n{\n\t// Trivial test.\n\tif(include(a) || include(b) || include(c))\n\t\treturn true;\n\t// Else, must test if the polygon intersect the pyamid.\n\tCPlane\t\tplanes[6];\n\tmakePyramid(planes);\n\tCPolygon\tpoly(a,b,c);\n\tpoly.clip(planes, 6);\n\tif(poly.getNumVertices()==0)\n\t\treturn false;\n\treturn true;\n}\n\n// ***************************************************************************\nbool\t\t\tCAABBox::intersect(const CVector &a, const CVector &b) const\n{\n\t// Trivial test.\n\tif(include(a) || include(b))\n\t\treturn true;\n\t// Else, must test if the segment intersect the pyamid.\n\tCPlane\t\tplanes[6];\n\tmakePyramid(planes);\n\tCVector\t\tp0=a , p1=b;\n\t// clip the segment against all planes\n\tfor(uint i=0;i<6;i++)\n\t{\n\t\tif(!planes[i].clipSegmentBack(p0, p1))\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\nbool\t\t\tCAABBox::clipSegment(CVector &a, CVector &b) const\n{\n\t// Trivial test. If both are in, they are inchanged\n\tif(include(a) && include(b))\n\t\treturn true;\n\t// Else, must clip the segment againts the pyamid.\n\tCPlane\t\tplanes[6];\n\tmakePyramid(planes);\n\tCVector\t\tp0=a , p1=b;\n\t// clip the segment against all planes\n\tfor(uint i=0;i<6;i++)\n\t{\n\t\tif(!planes[i].clipSegmentBack(p0, p1))\n\t\t\treturn false;\n\t}\n\t// get result\n\ta= p0;\n\tb= p1;\n\treturn true;\n}\n\n// ***************************************************************************\nbool\t\t\tCAABBox::intersect(const CBSphere &s) const\n{\n\tif (Center.x + HalfSize.x < s.Center.x - s.Radius) return false;\n\tif (Center.y + HalfSize.y < s.Center.y - s.Radius) return false;\n\tif (Center.z + HalfSize.z < s.Center.z - s.Radius) return false;\n\n\tif (Center.x - HalfSize.x > s.Center.x + s.Radius) return false;\n\tif (Center.y - HalfSize.y > s.Center.y + s.Radius) return false;\n\tif (Center.z - HalfSize.z > s.Center.z + s.Radius) return false;\n\n\treturn true;\n}\n\n\n\n// ***************************************************************************\nvoid\t\t\tCAABBox::makePyramid(CPlane\tplanes[6]) const\n{\n\tplanes[0].make(CVector(-1,0,0), Center-HalfSize);\n\tplanes[1].make(CVector(+1,0,0), Center+HalfSize);\n\tplanes[2].make(CVector(0,-1,0), Center-HalfSize);\n\tplanes[3].make(CVector(0,+1,0), Center+HalfSize);\n\tplanes[4].make(CVector(0,0,-1), Center-HalfSize);\n\tplanes[5].make(CVector(0,0,+1), Center+HalfSize);\n}\n\n\n// ***************************************************************************\nvoid\t\t\tCAABBox::serial(NLMISC::IStream &f)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\t(void)f.serialVersion(0);\n\tf.serial(Center);\n\tf.serial(HalfSize);\n}\n\n\n// ***************************************************************************\nvoid\tCAABBox::extend(const CVector &v)\n{\n\tCVector\t\tbmin= getMin(), bmax= getMax();\n\n\tbmin.minof(bmin, v);\n\tbmax.maxof(bmax, v);\n\tsetMinMax(bmin, bmax);\n}\n\n\n//==========================================================================\n/**\n* Compute the union of 2 aabboxes, that is the  aabbox that contains the 2.\n* Should end up in NLMISC\n*/\n\nCAABBox CAABBox::computeAABBoxUnion(const CAABBox &b1, const CAABBox &b2)\n{\n\tCAABBox result;\n\tCVector min, max;\n\tCVector min1 = b1.getMin()\n\t\t    ,max1 = b1.getMax()\n\t\t\t,min2 = b2.getMin()\n\t\t    ,max2 = b2.getMax();\n\tmax.maxof(max1, max2);\n\tmin.minof(min1, min2);\n\tresult.setMinMax(min, max);\n\treturn result;\n}\n\n\n//==========================================================================\nvoid\tCAABBox::computeIntersection(const CAABBox &b1, const CAABBox &b2)\n{\n\tCVector\tmin1 = b1.getMin(), max1 = b1.getMax(),\n\t\t\tmin2 = b2.getMin(), max2 = b2.getMax();\n\tCVector\tminr, maxr;\n\n\t// don't test if intersect or not.\n\tmaxr.minof(max1, max2);\n\tminr.maxof(min1, min2);\n\n\tsetMinMax(minr, maxr);\n}\n\n\n//==========================================================================\nCAABBox CAABBox::transformAABBox(const CMatrix &mat, const CAABBox &box)\n{\n\t// TODO : optimize this a bit if possible...\n\tCAABBox result;\n\n\t/* OMG. Old code was false!!\n\t\tif we have ht= M * h\n\t\tthen CVector(-ht.x, ht.y, ht.z) != M * CVector(-h.x, h.y, h.z) !!!!\n\t*/\n\t// compute corners.\n\tCVector\tp[8];\n\tCVector\tmin= box.getMin();\n\tCVector\tmax= box.getMax();\n\tp[0].set(min.x, min.y, min.z);\n\tp[1].set(max.x, min.y, min.z);\n\tp[2].set(min.x, max.y, min.z);\n\tp[3].set(max.x, max.y, min.z);\n\tp[4].set(min.x, min.y, max.z);\n\tp[5].set(max.x, min.y, max.z);\n\tp[6].set(min.x, max.y, max.z);\n\tp[7].set(max.x, max.y, max.z);\n\tCVector tmp;\n\tmin = max = mat * p[0];\n\t// transform corners.\n\tfor(uint i=1;i<8;i++)\n\t{\n\t\ttmp= mat * p[i];\n\t\tmin.minof(min, tmp);\n\t\tmax.maxof(max, tmp);\n\t}\n\n\tresult.setMinMax(min, max);\n\n\treturn result;\n}\n\n\n\n// ***************************************************************************\nbool\tCAABBoxExt::clipFront(const CPlane &p) const\n{\n\t// Assume normalized planes.\n\n\t// if( SpherMax OUT )\treturn false.\n\tfloat\td= p*Center;\n\tif(d<-RadiusMax)\n\t\treturn false;\n\t// if( SphereMin IN )\treturn true;\n\tif(d>-RadiusMin)\n\t\treturn true;\n\n\t// else, standard clip box.\n\treturn CAABBox::clipFront(p);\n}\n\n\n// ***************************************************************************\nbool\tCAABBoxExt::clipBack(const CPlane &p) const\n{\n\t// Assume normalized planes.\n\n\t// if( SpherMax OUT )\treturn false.\n\tfloat\td= p*Center;\n\tif(d>RadiusMax)\n\t\treturn false;\n\t// if( SphereMin IN )\treturn true;\n\tif(d<RadiusMin)\n\t\treturn true;\n\n\t// else, standard clip box.\n\treturn CAABBox::clipBack(p);\n}\n\n\n// ***************************************************************************\nvoid\t\t\tCAABBoxExt::serial(NLMISC::IStream &f)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\tCAABBox::serial(f);\n\tif(f.isReading())\n\t\tupdateRadius();\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/algo.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/algo.h\"\n\n\nusing\tnamespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nbool\t\ttestWildCard(const std::string &strIn, const std::string &wildCard)\n{\n\treturn testWildCard(strIn.c_str(), wildCard.c_str());\n}\n\n\n// ***************************************************************************\nbool\t\ttestWildCard(const char *strIn, const char *wildCard)\n{\n\t// run the 2 string in //el\n\twhile(*wildCard!=0 && *strIn!=0)\n\t{\n\t\t// if same char, continue.\n\t\tif(*wildCard==*strIn)\n\t\t{\n\t\t\twildCard++;\n\t\t\tstrIn++;\n\t\t}\n\t\t// if wildCard is ?, continue\n\t\telse if(*wildCard=='?')\n\t\t{\n\t\t\twildCard++;\n\t\t\tstrIn++;\n\t\t}\n\t\t// if wildcard is *, recurs check.\n\t\telse if(*wildCard=='*')\n\t\t{\n\t\t\twildCard++;\n\t\t\t// if last *, its OK.\n\t\t\tif(*wildCard==0)\n\t\t\t\treturn true;\n\t\t\t// else must check next strings.\n\t\t\telse\n\t\t\t{\n\t\t\t\t// build the wilcard token. eg from \"*pipo?\", take \"pipo\"\n\t\t\t\tstring\ttoken;\n\t\t\t\twhile(*wildCard!='*' && *wildCard!='?' && *wildCard!=0)\n\t\t\t\t{\n\t\t\t\t\ttoken+= *wildCard;\n\t\t\t\t\twildCard++;\n\t\t\t\t}\n\t\t\t\t// if token size is empty, error\n\t\t\t\tif(token.empty())\n\t\t\t\t\treturn false;\n\n\t\t\t\t// in strIn, search all the occurence of token. For each solution, recurs test.\n\t\t\t\tstring\tsCopy= strIn;\n\t\t\t\tstring::size_type pos= sCopy.find(token, 0);\n\t\t\t\twhile(pos!=string::npos)\n\t\t\t\t{\n\t\t\t\t\t// do a testWildCard test on the remaining string/wildCard\n\t\t\t\t\tif( testWildCard(strIn+pos+token.size(), wildCard) )\n\t\t\t\t\t\t// if succeed, end\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t// fails=> test with another occurence of token in the string.\n\t\t\t\t\tpos= sCopy.find(token, pos+1);\n\t\t\t\t}\n\n\t\t\t\t// if all failed, fail\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t// else fail\n\t\telse\n\t\t\treturn false;\n\t}\n\n\t// If quit here because end Of 2 strs, OK.\n\tif(*wildCard==0 && *strIn==0)\n\t\treturn true;\n\t// if quit here because wildCard==\"*\" and s=\"\", OK too.\n\tif(*strIn==0 && wildCard[0]=='*' && wildCard[1]==0)\n\t\treturn true;\n\n\t/*\n\t\tElse false:\n\t\t\tIt may be wildCard=\"?aez\" and s=\"\" => error\n\t\t\tIt may be wildCard=\"\" and s=\"aer\" => error\n\t*/\n\treturn false;\n}\n\n\n// ***************************************************************************\nvoid\t\tsplitString(const std::string &str, const std::string &separator, std::vector<std::string> &retList)\n{\n\tstring::size_type pos=0;\n\tstring::size_type newPos=0;\n\tretList.clear();\n\twhile( (newPos= str.find(separator,pos)) != string::npos)\n\t{\n\t\t// if not empty sub str. (skip repetition of separator )\n\t\tif(newPos-pos>0)\n\t\t\tretList.push_back(str.substr(pos, newPos-pos));\n\t\t// skip token\n\t\tpos= newPos+separator.size();\n\t}\n\t// copy the last substr\n\tif( pos<str.size() )\n\t\tretList.push_back(str.substr(pos, str.size()-pos));\n}\n\n\n// ***************************************************************************\nvoid\t\tsplitUCString(const ucstring &ucstr, const ucstring &separator, std::vector<ucstring> &retList)\n{\n\tucstring::size_type pos=0;\n\tucstring::size_type newPos=0;\n\tretList.clear();\n\twhile( (newPos= ucstr.find(separator,pos)) != ucstring::npos)\n\t{\n\t\t// if not empty sub str. (skip repetition of separator )\n\t\tif(newPos-pos>0)\n\t\t\tretList.push_back(ucstr.substr(pos, newPos-pos));\n\t\t// skip token\n\t\tpos= newPos+separator.size();\n\t}\n\t// copy the last substr\n\tif( pos<ucstr.size() )\n\t\tretList.push_back(ucstr.substr(pos, ucstr.size()-pos));\n}\n\n// ***************************************************************************\n\nvoid drawFullLine (float x0, float y0, float x1, float y1, std::vector<std::pair<sint, sint> > &result)\n{\n\tresult.clear ();\n\t// x0 must be < x1\n\tfloat dx = (float) fabs (x0-x1);\n\tfloat dy = (float) fabs (y0-y1);\n\tif ((dx == 0) && (dy == 0))\n\t\tresult.push_back (pair<sint, sint> ((sint)floor (x0), (sint)floor (y0)));\n\telse if (dx > dy)\n\t{\n\t\tif (x0 > x1)\n\t\t{\n\t\t\t// Xchg 0 and 1\n\t\t\tfloat temp = x0;\n\t\t\tx0 = x1;\n\t\t\tx1 = temp;\n\t\t\ttemp = y0;\n\t\t\ty0 = y1;\n\t\t\ty1 = temp;\n\t\t}\n\n\t\tfloat deltaX = x1 - x0;\n\t\tconst float deltaY = (y1-y0)/deltaX;\n\n\t\t// Current integer pixel\n\t\tsint currentX = (sint)floor (x0);\n\t\tsint currentY = (sint)floor (y0);\n\n\t\twhile (deltaX >= 0)\n\t\t{\n\t\t\t// Next point\n\t\t\tsint previousY = currentY;\n\n\t\t\t// Next y0\n\t\t\tif (deltaX > 1)\n\t\t\t\ty0 += deltaY;\n\t\t\telse\n\t\t\t\ty0 += deltaX * deltaY;\n\n\t\t\tdeltaX -= 1;\n\n\t\t\tcurrentY = (sint)y0;\n\n\t\t\t// Add point\n\t\t\tif (currentY<=previousY)\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tresult.push_back (pair<sint, sint> (currentX, previousY));\n\t\t\t\t\tpreviousY--;\n\t\t\t\t}\n\t\t\t\twhile (currentY<=previousY);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tresult.push_back (pair<sint, sint> (currentX, previousY));\n\t\t\t\t\tpreviousY++;\n\t\t\t\t}\n\t\t\t\twhile (currentY>=previousY);\n\t\t\t}\n\n\t\t\t// Next X\n\t\t\tcurrentX++;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (y0 > y1)\n\t\t{\n\t\t\t// Xchg 0 and 1\n\t\t\tfloat temp = y0;\n\t\t\ty0 = y1;\n\t\t\ty1 = temp;\n\t\t\ttemp = x0;\n\t\t\tx0 = x1;\n\t\t\tx1 = temp;\n\t\t}\n\n\t\tfloat deltaY = y1 - y0;\n\t\tconst float deltaX = (x1-x0)/deltaY;\n\n\t\t// Current integer pixel\n\t\tsint currentY = (sint)floor (y0);\n\t\tsint currentX = (sint)floor (x0);\n\n\t\twhile (deltaY >= 0)\n\t\t{\n\t\t\t// Next point\n\t\t\tsint previousX = currentX;\n\n\t\t\t// Next x0\n\t\t\tif (deltaY > 1)\n\t\t\t\tx0 += deltaX;\n\t\t\telse\n\t\t\t\tx0 += deltaY * deltaX;\n\n\t\t\tdeltaY -= 1;\n\n\t\t\tcurrentX = (sint)x0;\n\n\t\t\t// Add point\n\t\t\tif (currentX<=previousX)\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tresult.push_back (pair<sint, sint> (previousX, currentY));\n\t\t\t\t\tpreviousX--;\n\t\t\t\t}\n\t\t\t\twhile (currentX<=previousX);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tresult.push_back (pair<sint, sint> (previousX, currentY));\n\t\t\t\t\tpreviousX++;\n\t\t\t\t}\n\t\t\t\twhile (currentX>=previousX);\n\t\t\t}\n\n\t\t\t// Next Y\n\t\t\tcurrentY++;\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid drawLine (float x0, float y0, float x1, float y1, vector<pair<sint, sint> > &result)\n{\n\tfloat\tdx = (float)(floor(x1+0.5) - floor(x0+0.5));\n\tfloat\tdy = (float)(floor(y1+0.5) - floor(y0+0.5));\n\n\tfloat\trdx = x1-x0;\n\tfloat\trdy = y1-y0;\n\n\tsint\td = (sint)std::max(fabs(dx), fabs(dy));\n\tfloat\tmaxd = (float)(std::max(fabs(rdx), fabs(rdy)));\n\n\trdx /= maxd;\n\trdy /= maxd;\n\n\tfor (; d>=0; --d)\n\t{\n\t\tresult.push_back(make_pair<sint,sint>((sint)floor(x0+0.5), (sint)floor(y0+0.5)));\n\n\t\tx0 += rdx;\n\t\ty0 += rdy;\n\t}\n}\n\n// ***************************************************************************\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/app_context.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/app_context.h\"\n#include \"nel/misc/dynloadlib.h\"\n#include \"nel/misc/command.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n//INelContext *NelContext = NULL;\nINelContext *INelContext::_NelContext = NULL;\n\nINelContext ** INelContext::_getInstance()\n{\n\tstatic INelContext *nelContext = NULL;\n\n\treturn &nelContext;\n}\n\n\nINelContext &INelContext::getInstance()\n{\n\tif (*(_getInstance()) == NULL)\n\t{\n\t\t_NelContext = new CApplicationContext;\n\t\t*(_getInstance()) = _NelContext;\n\t}\n\n\treturn *_NelContext;\n}\n\nbool INelContext::isContextInitialised()\n{\n\treturn (*_getInstance()) != NULL;\n}\n\n\nINelContext::~INelContext()\n{\n\t// unregister still undeleted local command into the global command registry\n\tif (ICommand::LocalCommands)\n\t{\n\t\tICommand::TCommand::iterator first(ICommand::LocalCommands->begin()), last(ICommand::LocalCommands->end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tICommand *command = first->second;\n\t\t\tCCommandRegistry::getInstance().unregisterCommand(command);\n\t\t}\n\t}\n\n\tCInstanceCounterLocalManager::releaseInstance();\n\n\t_NelContext = NULL;\n\t*(_getInstance()) = NULL;\n}\n\n\n\nvoid INelContext::contextReady()\n{\n\t// Register the NeL Context\n\t// This assert doesn't work for Linux due to ELF symbol relocation\n#ifdef NL_OS_WINDOWS\n\tnlassert(*(_getInstance()) == NULL);\n#endif // NL_OS_WINDOWS\n\t_NelContext = this;\n\t*(_getInstance()) = this;\n\n\t// register any pending thinks\n\n\t// register local instance counter in the global instance counter manager\n\tCInstanceCounterLocalManager::getInstance().registerLocalManager();\n\n\t// register local commands into the global command registry (except it there is no command at all)\n\tif (ICommand::LocalCommands != NULL)\n\t{\n\t\tICommand::TCommand::iterator first(ICommand::LocalCommands->begin()), last(ICommand::LocalCommands->end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tCCommandRegistry::getInstance().registerCommand(first->second);\n\t\t}\n\t}\n}\n\nCApplicationContext::CApplicationContext()\n{\n\t// init\n\tErrorLog = NULL;\n\tWarningLog = NULL;\n\tInfoLog = NULL;\n\tDebugLog = NULL;\n\tAssertLog = NULL;\n\tDefaultMemDisplayer = NULL;\n\tDefaultMsgBoxDisplayer = NULL;\n\tDebugNeedAssert = false;\n\tNoAssert = false;\n\tAlreadyCreateSharedAmongThreads = false;\n\tWindowedApplication = false;\n\n\tcontextReady();\n}\n\nvoid *CApplicationContext::getSingletonPointer(const std::string &singletonName)\n{\n\tTSingletonRegistry::iterator it(_SingletonRegistry.find(singletonName));\n\tif (it != _SingletonRegistry.end())\n\t\treturn it->second;\n\n//\tnlwarning(\"Can't find singleton '%s'\", singletonName.c_str());\n\treturn NULL;\n}\n\nvoid CApplicationContext::setSingletonPointer(const std::string &singletonName, void *ptr)\n{\n\tnlassert(_SingletonRegistry.find(singletonName) == _SingletonRegistry.end());\n\t_SingletonRegistry[singletonName] = ptr;\n}\n\nvoid CApplicationContext::releaseSingletonPointer(const std::string &singletonName, void *ptr)\n{\n\tnlassert(_SingletonRegistry.find(singletonName) != _SingletonRegistry.end());\n\tnlassert(_SingletonRegistry.find(singletonName)->second == ptr);\n\t_SingletonRegistry.erase(singletonName);\n}\n\n\nCLog *CApplicationContext::getErrorLog()\n{\n\treturn ErrorLog;\n}\n\nvoid CApplicationContext::setErrorLog(CLog *errorLog)\n{\n\tErrorLog = errorLog;\n}\n\nCLog *CApplicationContext::getWarningLog()\n{\n\treturn WarningLog;\n}\n\nvoid CApplicationContext::setWarningLog(CLog *warningLog)\n{\n\tWarningLog = warningLog;\n}\n\nCLog *CApplicationContext::getInfoLog()\n{\n\treturn InfoLog;\n}\n\nvoid CApplicationContext::setInfoLog(CLog *infoLog)\n{\n\tInfoLog = infoLog;\n}\n\nCLog *CApplicationContext::getDebugLog()\n{\n\treturn DebugLog;\n}\n\nvoid CApplicationContext::setDebugLog(CLog *debugLog)\n{\n\tDebugLog = debugLog;\n}\n\nCLog *CApplicationContext::getAssertLog()\n{\n\treturn AssertLog;\n}\n\nvoid CApplicationContext::setAssertLog(CLog *assertLog)\n{\n\tAssertLog = assertLog;\n}\n\nCMemDisplayer *CApplicationContext::getDefaultMemDisplayer()\n{\n\treturn DefaultMemDisplayer;\n}\n\nvoid CApplicationContext::setDefaultMemDisplayer(CMemDisplayer *memDisplayer)\n{\n\tDefaultMemDisplayer = memDisplayer;\n}\n\nCMsgBoxDisplayer *CApplicationContext::getDefaultMsgBoxDisplayer()\n{\n\treturn DefaultMsgBoxDisplayer;\n}\n\nvoid CApplicationContext::setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer)\n{\n\tDefaultMsgBoxDisplayer = msgBoxDisplayer;\n}\n\nbool CApplicationContext::getDebugNeedAssert()\n{\n\treturn DebugNeedAssert;\n}\n\nvoid CApplicationContext::setDebugNeedAssert(bool needAssert)\n{\n\tDebugNeedAssert = needAssert;\n}\n\nbool CApplicationContext::getNoAssert()\n{\n\treturn NoAssert;\n}\n\nvoid CApplicationContext::setNoAssert(bool noAssert)\n{\n\tNoAssert = noAssert;\n}\n\nbool CApplicationContext::getAlreadyCreateSharedAmongThreads()\n{\n\treturn AlreadyCreateSharedAmongThreads;\n}\n\nvoid CApplicationContext::setAlreadyCreateSharedAmongThreads(bool b)\n{\n\tAlreadyCreateSharedAmongThreads = b;\n}\n\nbool CApplicationContext::isWindowedApplication()\n{\n\treturn WindowedApplication;\n}\n\nvoid CApplicationContext::setWindowedApplication(bool b)\n{\n\tWindowedApplication = b;\n}\n\nCLibraryContext::CLibraryContext(INelContext &applicationContext)\n: _ApplicationContext(&applicationContext)\n{\n\tcontextReady();\n}\n\n\nvoid *CLibraryContext::getSingletonPointer(const std::string &singletonName)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getSingletonPointer(singletonName);\n}\n\nvoid CLibraryContext::setSingletonPointer(const std::string &singletonName, void *ptr)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setSingletonPointer(singletonName, ptr);\n}\n\nvoid CLibraryContext::releaseSingletonPointer(const std::string &singletonName, void *ptr)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->releaseSingletonPointer(singletonName, ptr);\n}\n\n\nCLog *CLibraryContext::getErrorLog()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getErrorLog();\n}\n\nvoid CLibraryContext::setErrorLog(CLog *errorLog)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setErrorLog(errorLog);\n}\n\nCLog *CLibraryContext::getWarningLog()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getWarningLog();\n}\n\nvoid CLibraryContext::setWarningLog(CLog *warningLog)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setWarningLog(warningLog);\n}\n\nCLog *CLibraryContext::getInfoLog()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getInfoLog();\n}\n\nvoid CLibraryContext::setInfoLog(CLog *infoLog)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setInfoLog(infoLog);\n}\n\nCLog *CLibraryContext::getDebugLog()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getDebugLog();\n}\n\nvoid CLibraryContext::setDebugLog(CLog *debugLog)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setDebugLog(debugLog);\n}\n\nCLog *CLibraryContext::getAssertLog()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getAssertLog();\n}\n\nvoid CLibraryContext::setAssertLog(CLog *assertLog)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setAssertLog(assertLog);\n}\n\nCMemDisplayer *CLibraryContext::getDefaultMemDisplayer()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getDefaultMemDisplayer();\n}\n\nvoid CLibraryContext::setDefaultMemDisplayer(CMemDisplayer *memDisplayer)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setDefaultMemDisplayer(memDisplayer);\n}\n\nCMsgBoxDisplayer *CLibraryContext::getDefaultMsgBoxDisplayer()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getDefaultMsgBoxDisplayer();\n}\n\nvoid CLibraryContext::setDefaultMsgBoxDisplayer(CMsgBoxDisplayer *msgBoxDisplayer)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setDefaultMsgBoxDisplayer(msgBoxDisplayer);\n}\n\nbool CLibraryContext::getDebugNeedAssert()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getDebugNeedAssert();\n}\n\nvoid CLibraryContext::setDebugNeedAssert(bool needAssert)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setDebugNeedAssert(needAssert);\n}\n\nbool CLibraryContext::getNoAssert()\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\treturn _ApplicationContext->getNoAssert();\n}\n\n\n\nvoid CLibraryContext::setNoAssert(bool noAssert)\n{\n//\tnlassert(_ApplicationContext != NULL);\n\n\t// just forward the call\n\t_ApplicationContext->setNoAssert(noAssert);\n}\n\nbool CLibraryContext::getAlreadyCreateSharedAmongThreads()\n{\n\treturn _ApplicationContext->getAlreadyCreateSharedAmongThreads();\n}\n\nvoid CLibraryContext::setAlreadyCreateSharedAmongThreads(bool b)\n{\n\t_ApplicationContext->setAlreadyCreateSharedAmongThreads(b);\n}\n\nbool CLibraryContext::isWindowedApplication()\n{\n\treturn _ApplicationContext->isWindowedApplication();\n}\n\nvoid CLibraryContext::setWindowedApplication(bool b)\n{\n\t_ApplicationContext->setWindowedApplication(b);\n}\n\nvoid initNelLibrary(NLMISC::CLibrary &lib)\n{\n\tnlassert(lib.isLibraryLoaded());\n\n\tTInitLibraryFunc *funptrptr = reinterpret_cast<TInitLibraryFunc*>(lib.getSymbolAddress(\"libraryEntry\"));\n\tnlassert(funptrptr != NULL);\n\n\tTInitLibraryFunc funptr = *funptrptr;\n\n\t// call the initialisation function\n\tfunptr(NLMISC::INelContext::getInstance());\n}\n\n\n\n} // namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/async_file_manager.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/async_file_manager.h\"\n\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n//CAsyncFileManager *CAsyncFileManager::_Singleton = NULL;\nNLMISC_SAFE_SINGLETON_IMPL(CAsyncFileManager);\n\n\n// ***************************************************************************\n\n/*CAsyncFileManager::CAsyncFileManager()\n{\n}\n*/\n// ***************************************************************************\n\n/*CAsyncFileManager &CAsyncFileManager::getInstance()\n{\n\tif (_Singleton == NULL)\n\t{\n\t\t_Singleton = new CAsyncFileManager();\n\t}\n\treturn *_Singleton;\n}\n*/\n// ***************************************************************************\n\nvoid CAsyncFileManager::terminate ()\n{\n\tif (_Instance != NULL)\n\t{\n\t\tINelContext::getInstance().releaseSingletonPointer(\"CAsyncFileManager\", _Instance);\n\t\tdelete _Instance;\n\t\t_Instance = NULL;\n\t}\n}\n\n\nvoid CAsyncFileManager::addLoadTask(IRunnable *ploadTask)\n{\n\taddTask(ploadTask);\n}\n\nbool CAsyncFileManager::cancelLoadTask(const CAsyncFileManager::ICancelCallback &callback)\n{\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tlist<CWaitingTask> &rTaskQueue = acces.value ();\n\tlist<CWaitingTask>::iterator it = rTaskQueue.begin();\n\n\twhile (it != rTaskQueue.end())\n\t{\n\t\tIRunnable *pR = it->Task;\n\n\t\t// check the task with the cancel callback.\n\t\tif (callback.callback(pR))\n\t\t{\n\t\t\t// Delete the load task\n\t\t\tdelete pR;\n\t\t\trTaskQueue.erase (it);\n\t\t\treturn true;\n\t\t}\n\t\t++it;\n\t}\n\n\t// If not found, the current running task may be the one we want to cancel. Must wait it.\n\t// Beware that this code works because of the CSynchronized access we made above (ensure that the\n\t// taskmanager will end just the current task async (if any) and won't start an other one.\n\twaitCurrentTaskToComplete ();\n\n\treturn false;\n}\n\n// ***************************************************************************\n/*\nvoid CAsyncFileManager::loadMesh(const std::string& meshName, IShape **ppShp, IDriver *pDriver)\n{\n\taddTask (new CMeshLoad(meshName, ppShp, pDriver));\n}\n*/\n// ***************************************************************************\n/*\nbool CAsyncFileManager::cancelLoadMesh(const std::string& sMeshName)\n{\n\tCSynchronized<list<IRunnable *> >::CAccessor acces(&_TaskQueue);\n\tlist<IRunnable*> &rTaskQueue = acces.value ();\n\tlist<IRunnable*>::iterator it = rTaskQueue.begin();\n\n\twhile (it != rTaskQueue.end())\n\t{\n\t\tIRunnable *pR = *it;\n\t\tCMeshLoad *pML = dynamic_cast<CMeshLoad*>(pR);\n\t\tif (pML != NULL)\n\t\t{\n\t\t\tif (pML->MeshName == sMeshName)\n\t\t\t{\n\t\t\t\t// Delete mesh load task\n\t\t\t\tdelete pML;\n\t\t\t\trTaskQueue.erase (it);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t++it;\n\t}\n\treturn false;\n}\n*/\n// ***************************************************************************\n/*\nvoid CAsyncFileManager::loadIG (const std::string& IGName, CInstanceGroup **ppIG)\n{\n\taddTask (new CIGLoad(IGName, ppIG));\n}\n\n// ***************************************************************************\n\nvoid CAsyncFileManager::loadIGUser (const std::string& IGName, UInstanceGroup **ppIG)\n{\n\taddTask (new CIGLoadUser(IGName, ppIG));\n}\n*/\n// ***************************************************************************\n\nvoid CAsyncFileManager::loadFile (const std::string& sFileName, uint8 **ppFile)\n{\n\taddTask (new CFileLoad (sFileName, ppFile));\n}\n\n// ***************************************************************************\n\nvoid CAsyncFileManager::loadFiles (const std::vector<std::string> &vFileNames, const std::vector<uint8**> &vPtrs)\n{\n\taddTask (new CMultipleFileLoad (vFileNames, vPtrs));\n}\n\n// ***************************************************************************\n\nvoid CAsyncFileManager::signal (bool *pSgn)\n{\n\taddTask (new CSignal (pSgn));\n}\n\n// ***************************************************************************\n\nvoid CAsyncFileManager::cancelSignal (bool *pSgn)\n{\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tlist<CWaitingTask> &rTaskQueue = acces.value ();\n\tlist<CWaitingTask>::iterator it = rTaskQueue.begin();\n\n\twhile (it != rTaskQueue.end())\n\t{\n\t\tIRunnable *pR = it->Task;\n\t\tCSignal *pS = dynamic_cast<CSignal*>(pR);\n\t\tif (pS != NULL)\n\t\t{\n\t\t\tif (pS->Sgn == pSgn)\n\t\t\t{\n\t\t\t\t// Delete signal task\n\t\t\t\tdelete pS;\n\t\t\t\trTaskQueue.erase (it);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t++it;\n\t}\n}\n\n// ***************************************************************************\n// FileLoad\n// ***************************************************************************\n\n// ***************************************************************************\nCAsyncFileManager::CFileLoad::CFileLoad (const std::string& sFileName, uint8 **ppFile)\n{\n\t_FileName = sFileName;\n\t_ppFile = ppFile;\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CFileLoad::run (void)\n{\n\tFILE *f = fopen (_FileName.c_str(), \"rb\");\n\tif (f != NULL)\n\t{\n\t\tuint8 *ptr;\n\t\tlong filesize=CFile::getFileSize (f);\n\t\t//fseek (f, 0, SEEK_END);\n\t\t//long filesize = ftell (f);\n\t\t//nlSleep(5);\n\t\t//fseek (f, 0, SEEK_SET);\n\t\tptr = new uint8[filesize];\n\t\tif (fread (ptr, filesize, 1, f) != 1)\n\t\t\tnlwarning(\"AFM: Couldn't read '%s'\", _FileName.c_str());\n\t\tfclose (f);\n\n\t\t*_ppFile = ptr;\n\t}\n\telse\n\t{\n\t\tnlwarning (\"AFM: Couldn't load '%s'\", _FileName.c_str());\n\t\t*_ppFile = (uint8*)-1;\n\t}\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CFileLoad::getName (std::string &result) const\n{\n\tresult = \"FileLoad (\" + _FileName + \")\";\n}\n\n// ***************************************************************************\n// MultipleFileLoad\n// ***************************************************************************\n\n// ***************************************************************************\nCAsyncFileManager::CMultipleFileLoad::CMultipleFileLoad (const std::vector<std::string> &vFileNames,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t const std::vector<uint8**> &vPtrs)\n{\n\t_FileNames = vFileNames;\n\t_Ptrs = vPtrs;\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CMultipleFileLoad::run (void)\n{\n\tfor (uint32 i = 0; i < _FileNames.size(); ++i)\n\t{\n\t\tFILE *f = fopen (_FileNames[i].c_str(), \"rb\");\n\t\tif (f != NULL)\n\t\t{\n\t\t\tuint8 *ptr;\n\t\t\tlong filesize=CFile::getFileSize (f);\n\t\t\t//fseek (f, 0, SEEK_END);\n\t\t\t//long filesize = ftell (f);\n\t\t\t//nlSleep(5);\n\t\t\t//fseek (f, 0, SEEK_SET);\n\t\t\tptr = new uint8[filesize];\n\t\t\tif (fread (ptr, filesize, 1, f) != 1)\n\t\t\t\tnlwarning(\"AFM: Couldn't read '%s'\", _FileNames[i].c_str());\n\t\t\tfclose (f);\n\n\t\t\t*_Ptrs[i] = ptr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"AFM: Couldn't load '%s'\", _FileNames[i].c_str());\n\t\t\t*_Ptrs[i] = (uint8*)-1;\n\t\t}\n\t}\n\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CMultipleFileLoad::getName (std::string &result) const\n{\n\tresult = \"MultipleFileLoad (\";\n\tuint i;\n\tfor (i=0; i<_FileNames.size (); i++)\n\t{\n\t\tif (i)\n\t\t\tresult += \", \";\n\t\tresult += _FileNames[i];\n\t}\n\tresult += \")\";\n}\n// ***************************************************************************\n// Signal\n// ***************************************************************************\n\n// ***************************************************************************\nCAsyncFileManager::CSignal::CSignal (bool *pSgn)\n{\n\tSgn = pSgn;\n\t*Sgn = false;\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CSignal::run (void)\n{\n\t*Sgn = true;\n}\n\n// ***************************************************************************\nvoid CAsyncFileManager::CSignal::getName (std::string &result) const\n{\n\tresult = \"Signal\";\n}\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/base64.cpp",
    "content": "/* \n   base64.cpp and base64.h\n\n   Copyright (C) 2004-2008 René Nyffenegger\n\n   This source code is provided 'as-is', without any express or implied\n   warranty. In no event will the author be held liable for any damages\n   arising from the use of this software.\n\n   Permission is granted to anyone to use this software for any purpose,\n   including commercial applications, and to alter it and redistribute it\n   freely, subject to the following restrictions:\n\n   1. The origin of this source code must not be misrepresented; you must not\n   claim that you wrote the original source code. If you use this source code\n   in a product, an acknowledgment in the product documentation would be\n   appreciated but is not required.\n\n   2. Altered source versions must be plainly marked as such, and must not be\n   misrepresented as being the original source code.\n\n   3. This notice may not be removed or altered from any source distribution.\n\n   René Nyffenegger rene.nyffenegger@adp-gmbh.ch\n\n*/\n\n#include \"nel/misc/base64.h\"\n#include <iostream>\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nstatic const std::string base64_chars = \n\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n\"abcdefghijklmnopqrstuvwxyz\"\n\"0123456789+/\";\n\n\nstatic inline bool is_base64(unsigned char c) \n{\n\treturn (isalnum(c) || (c == '+') || (c == '/'));\n}\n\nstd::string base64_encode( std::string const& s ) \n{\n\tstd::string ret;\n\tint i = 0;\n\tint j = 0;\n\tunsigned char char_array_3[3];\n\tunsigned char char_array_4[4];\n    unsigned char const* bytes_to_encode = (unsigned char const*)s.c_str();\n    uint in_len = s.size();\n\n\twhile (in_len--) {\n\t\tchar_array_3[i++] = *(bytes_to_encode++);\n\t\tif (i == 3) {\n\t\t\tchar_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n\t\t\tchar_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);\n\t\t\tchar_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);\n\t\t\tchar_array_4[3] = char_array_3[2] & 0x3f;\n\n\t\t\tfor(i = 0; (i <4) ; i++)\n\t\t\t\tret += base64_chars[char_array_4[i]];\n\t\t\ti = 0;\n\t\t}\n\t}\n\n\tif (i)\n\t{\n\t\tfor(j = i; j < 3; j++)\n\t\t\tchar_array_3[j] = '\\0';\n\n\t\tchar_array_4[0] = (char_array_3[0] & 0xfc) >> 2;\n\t\tchar_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);\n\t\tchar_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);\n\t\tchar_array_4[3] = char_array_3[2] & 0x3f;\n\n\t\tfor (j = 0; (j < i + 1); j++)\n\t\t\tret += base64_chars[char_array_4[j]];\n\n\t\twhile((i++ < 3))\n\t\t\tret += '=';\n\n\t}\n\n\treturn ret;\n\n}\n\nstd::string base64_decode(std::string const& encoded_string) \n{\n\tint in_len = encoded_string.size();\n\tint i = 0;\n\tint j = 0;\n\tint in_ = 0;\n\tunsigned char char_array_4[4], char_array_3[3];\n\tstd::string ret;\n\n\twhile (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {\n\t\tchar_array_4[i++] = encoded_string[in_]; in_++;\n\t\tif (i ==4) {\n\t\t\tfor (i = 0; i <4; i++)\n\t\t\t\tchar_array_4[i] = base64_chars.find(char_array_4[i]);\n\n\t\t\tchar_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n\t\t\tchar_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n\t\t\tchar_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n\t\t\tfor (i = 0; (i < 3); i++)\n\t\t\t\tret += char_array_3[i];\n\t\t\ti = 0;\n\t\t}\n\t}\n\n\tif (i) {\n\t\tfor (j = i; j <4; j++)\n\t\t\tchar_array_4[j] = 0;\n\n\t\tfor (j = 0; j <4; j++)\n\t\t\tchar_array_4[j] = base64_chars.find(char_array_4[j]);\n\n\t\tchar_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);\n\t\tchar_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);\n\t\tchar_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];\n\n\t\tfor (j = 0; (j < i - 1); j++) ret += char_array_3[j];\n\t}\n\n\treturn ret;\n}\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/big_file.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/big_file.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n//CBigFile *CBigFile::_Singleton = NULL;\nNLMISC_SAFE_SINGLETON_IMPL(CBigFile);\n\n// ***************************************************************************\nvoid CBigFile::releaseInstance()\n{\n\tif (_Instance)\n\t{\n\t\tNLMISC::INelContext::getInstance().releaseSingletonPointer(\"CBigFile\", _Instance);\n\t\tdelete _Instance;\n\t\t_Instance = NULL;\n\t}\n}\n// ***************************************************************************\nCBigFile::CThreadFileArray::CThreadFileArray()\n{\n\t_CurrentId= 0;\n}\n// ***************************************************************************\nuint32\t\t\t\t\t\tCBigFile::CThreadFileArray::allocate()\n{\n\treturn _CurrentId++;\n}\n\n// ***************************************************************************\nCBigFile::CHandleFile\t\t&CBigFile::CThreadFileArray::get(uint32 index)\n{\n\t// If the thread struct ptr is NULL, must allocate it.\n\tvector<CHandleFile>\t\t*ptr= (vector<CHandleFile>*)_TDS.getPointer();\n\tif(ptr==NULL)\n\t{\n\t\tptr= new vector<CHandleFile>;\n\t\t_TDS.setPointer(ptr);\n\t}\n\n\t// if the vector is not allocated, allocate it (empty entries filled with NULL => not opened FILE* in this thread)\n\tif(index>=ptr->size())\n\t{\n\t\tptr->resize(index+1);\n\t}\n\n\treturn (*ptr)[index];\n}\n\n\n// ***************************************************************************\nvoid CBigFile::currentThreadFinished()\n{\n\t_ThreadFileArray.currentThreadFinished();\n}\n\n// ***************************************************************************\nvoid CBigFile::CThreadFileArray::currentThreadFinished()\n{\n\tvector<CHandleFile>\t\t*ptr= (vector<CHandleFile>*)_TDS.getPointer();\n\tif (ptr==NULL) return;\n\tfor (uint k = 0; k < ptr->size(); ++k)\n\t{\n\t\tif ((*ptr)[k].File)\n\t\t{\n\t\t\tfclose((*ptr)[k].File);\n\t\t\t(*ptr)[k].File = NULL;\n\t\t}\n\t}\n\tdelete ptr;\n\t_TDS.setPointer(NULL);\n}\n\n\n// ***************************************************************************\n//CBigFile::CBigFile ()\n//{\n//}\n//\n//// ***************************************************************************\n//CBigFile &CBigFile::getInstance ()\n//{\n//\tif (_Singleton == NULL)\n//\t{\n//\t\t_Singleton = new CBigFile();\n//\t}\n//\treturn *_Singleton;\n//}\n\n// ***************************************************************************\nbool CBigFile::add (const std::string &sBigFileName, uint32 nOptions)\n{\n\t// Is already the same bigfile name ?\n\tstring bigfilenamealone = toLower(CFile::getFilename (sBigFileName));\n\tif (_BNPs.find(bigfilenamealone) != _BNPs.end())\n\t{\n\t\tnlwarning (\"CBigFile::add : bigfile %s already added.\", bigfilenamealone.c_str());\n\t\treturn false;\n\t}\n\n\t// Create the new bnp entry\n\tBNP &bnp = _BNPs[bigfilenamealone];\n\n\tbnp.BigFileName= sBigFileName;\n\n\n\t// Allocate a new ThreadSafe FileId for this bnp.\n\tbnp.ThreadFileId= _ThreadFileArray.allocate();\n\n\t// Get a ThreadSafe handle on the file\n\tCHandleFile\t\t&handle= _ThreadFileArray.get(bnp.ThreadFileId);\n\t// Open the big file.\n\thandle.File = fopen (sBigFileName.c_str(), \"rb\");\n\tif (handle.File == NULL)\n\t\treturn false;\n\tuint32 nFileSize=CFile::getFileSize (handle.File);\n\t//nlfseek64 (handle.File, 0, SEEK_END);\n\t//uint32 nFileSize = ftell (handle.File);\n\n\t// Result\n\tif (nlfseek64 (handle.File, nFileSize-4, SEEK_SET) != 0)\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\treturn false;\n\t}\n\n\tuint32 nOffsetFromBeginning;\n\tif (fread (&nOffsetFromBeginning, sizeof(uint32), 1, handle.File) != 1)\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\treturn false;\n\t}\n\n#ifdef NL_BIG_ENDIAN\n\tNLMISC_BSWAP32(nOffsetFromBeginning);\n#endif\n\n\tif (nlfseek64 (handle.File, nOffsetFromBeginning, SEEK_SET) != 0)\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\treturn false;\n\t}\n\n\t// Read the file count\n\tuint32 nNbFile;\n\tif (fread (&nNbFile, sizeof(uint32), 1, handle.File) != 1)\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\treturn false;\n\t}\n\n#ifdef NL_BIG_ENDIAN\n\tNLMISC_BSWAP32(nNbFile);\n#endif\n\n\tmap<string,BNPFile> tempMap;\n\tfor (uint32 i = 0; i < nNbFile; ++i)\n\t{\n\t\tchar FileName[256];\n\t\tuint8 nStringSize;\n\t\tif (fread (&nStringSize, 1, 1, handle.File) != 1)\n\t\t{\n\t\t\tfclose (handle.File);\n\t\t\thandle.File = NULL;\n\t\t\treturn false;\n\t\t}\n\n\t\tif (fread (FileName, nStringSize, 1, handle.File) != 1)\n\t\t{\n\t\t\tfclose (handle.File);\n\t\t\thandle.File = NULL;\n\t\t\treturn false;\n\t\t}\n\n\t\tFileName[nStringSize] = 0;\n\t\tuint32 nFileSize2;\n\t\tif (fread (&nFileSize2, sizeof(uint32), 1, handle.File) != 1)\n\t\t{\n\t\t\tfclose (handle.File);\n\t\t\thandle.File = NULL;\n\t\t\treturn false;\n\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\tNLMISC_BSWAP32(nFileSize2);\n#endif\n\n\t\tuint32 nFilePos;\n\t\tif (fread (&nFilePos, sizeof(uint32), 1, handle.File) != 1)\n\t\t{\n\t\t\tfclose (handle.File);\n\t\t\thandle.File = NULL;\n\t\t\treturn false;\n\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\tNLMISC_BSWAP32(nFilePos);\n#endif\n\n\t\tBNPFile bnpfTmp;\n\t\tbnpfTmp.Pos = nFilePos;\n\t\tbnpfTmp.Size = nFileSize2;\n\t\ttempMap.insert (make_pair(toLower(string(FileName)), bnpfTmp));\n\t}\n\n\tif (nlfseek64 (handle.File, 0, SEEK_SET) != 0)\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\treturn false;\n\t}\n\n\t// Convert temp map\n\tif (nNbFile > 0)\n\t{\n\t\tuint nSize = 0, nNb = 0;\n\t\tmap<string,BNPFile>::iterator it = tempMap.begin();\n\t\twhile (it != tempMap.end())\n\t\t{\n\t\t\tnSize += (uint)it->first.size() + 1;\n\t\t\tnNb++;\n\t\t\tit++;\n\t\t}\n\n\t\tbnp.FileNames = new char[nSize];\n\t\tmemset(bnp.FileNames, 0, nSize);\n\t\tbnp.Files.resize(nNb);\n\n\t\tit = tempMap.begin();\n\t\tnSize = 0;\n\t\tnNb = 0;\n\t\twhile (it != tempMap.end())\n\t\t{\n\t\t\tstrcpy(bnp.FileNames+nSize, it->first.c_str());\n\n\t\t\tbnp.Files[nNb].Name = bnp.FileNames+nSize;\n\t\t\tbnp.Files[nNb].Size = it->second.Size;\n\t\t\tbnp.Files[nNb].Pos = it->second.Pos;\n\n\t\t\tnSize += (uint)it->first.size() + 1;\n\t\t\tnNb++;\n\t\t\tit++;\n\t\t}\n\t}\n\t// End of temp map conversion\n\n\tif (nOptions&BF_CACHE_FILE_ON_OPEN)\n\t\tbnp.CacheFileOnOpen = true;\n\telse\n\t\tbnp.CacheFileOnOpen = false;\n\n\tif (!(nOptions&BF_ALWAYS_OPENED))\n\t{\n\t\tfclose (handle.File);\n\t\thandle.File = NULL;\n\t\tbnp.AlwaysOpened = false;\n\t}\n\telse\n\t{\n\t\tbnp.AlwaysOpened = true;\n\t}\n\n\t//nldebug(\"BigFile : added bnp '%s' to the collection\", bigfilenamealone.c_str());\n\n\treturn true;\n}\n\n// ***************************************************************************\nvoid CBigFile::remove (const std::string &sBigFileName)\n{\n\tif (_BNPs.find (sBigFileName) != _BNPs.end())\n\t{\n\t\tmap<string, BNP>::iterator it = _BNPs.find (sBigFileName);\n\t\tBNP &rbnp = it->second;\n\t\t// Get a ThreadSafe handle on the file\n\t\tCHandleFile\t\t&handle= _ThreadFileArray.get(rbnp.ThreadFileId);\n\t\t// close it if needed\n\t\tif (handle.File != NULL)\n\t\t{\n\t\t\tfclose (handle.File);\n\t\t\thandle.File= NULL;\n\t\t}\n\t\tdelete [] rbnp.FileNames;\n\t\t_BNPs.erase (it);\n\t}\n}\n\n// ***************************************************************************\nbool CBigFile::isBigFileAdded(const std::string &sBigFileName) const\n{\n\t// Is already the same bigfile name ?\n\tstring bigfilenamealone = CFile::getFilename (sBigFileName);\n\treturn _BNPs.find(bigfilenamealone) != _BNPs.end();\n}\n\n// ***************************************************************************\nstd::string CBigFile::getBigFileName(const std::string &sBigFileName) const\n{\n\tstring bigfilenamealone = CFile::getFilename (sBigFileName);\n\tmap<string, BNP>::const_iterator it = _BNPs.find(bigfilenamealone);\n\tif (it != _BNPs.end())\n\t\treturn it->second.BigFileName;\n\telse\n\t\treturn \"\";\n}\n\n\n// ***************************************************************************\nvoid CBigFile::list (const std::string &sBigFileName, std::vector<std::string> &vAllFiles)\n{\n\tstring lwrFileName = toLower(sBigFileName);\n\tif (_BNPs.find (lwrFileName) == _BNPs.end())\n\t\treturn;\n\tvAllFiles.clear ();\n\tBNP &rbnp = _BNPs.find (lwrFileName)->second;\n\tvector<BNPFile>::iterator it = rbnp.Files.begin();\n\twhile (it != rbnp.Files.end())\n\t{\n\t\tvAllFiles.push_back (string(it->Name)); // Add the name of the file to the return vector\n\t\t++it;\n\t}\n}\n\n// ***************************************************************************\nvoid CBigFile::removeAll ()\n{\n\twhile (_BNPs.begin() != _BNPs.end())\n\t{\n\t\tremove (_BNPs.begin()->first);\n\t}\n}\n\n// ***************************************************************************\nbool CBigFile::getFileInternal (const std::string &sFileName, BNP *&zeBnp, BNPFile *&zeBnpFile)\n{\n\tstring zeFileName, zeBigFileName, lwrFileName = toLower(sFileName);\n\tstring::size_type i, nPos = sFileName.find ('@');\n\tif (nPos == string::npos)\n\t{\n\t\treturn false;\n\t}\n\n\tfor (i = 0; i < nPos; ++i)\n\t\tzeBigFileName += lwrFileName[i];\n\t++i; // Skip @\n\tfor (; i < lwrFileName.size(); ++i)\n\t\tzeFileName += lwrFileName[i];\n\n\tif (_BNPs.find (zeBigFileName) == _BNPs.end())\n\t{\n\t\treturn false;\n\t}\n\n\tBNP &rbnp = _BNPs.find (zeBigFileName)->second;\n\tif (rbnp.Files.size() == 0)\n\t{\n\t\treturn false;\n\t}\n\n\tvector<BNPFile>::iterator itNBPFile;\n\n\tBNPFile temp_bnp_file;\n\ttemp_bnp_file.Name = (char*)zeFileName.c_str();\n\titNBPFile = lower_bound(rbnp.Files.begin(), rbnp.Files.end(), temp_bnp_file, CBNPFileComp());\n\n\tif (itNBPFile != rbnp.Files.end())\n\t{\n\t\tif (strcmp(itNBPFile->Name, zeFileName.c_str()) != 0)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\n\tBNPFile &rbnpfile = *itNBPFile;\n\n\t// set ptr on found bnp/bnpFile\n\tzeBnp= &rbnp;\n\tzeBnpFile= &rbnpfile;\n\n\treturn true;\n}\n\n// ***************************************************************************\nFILE* CBigFile::getFile (const std::string &sFileName, uint32 &rFileSize,\n\t\t\t\t\t\t uint32 &rBigFileOffset, bool &rCacheFileOnOpen, bool &rAlwaysOpened)\n{\n\tBNP\t\t*bnp= NULL;\n\tBNPFile\t*bnpFile= NULL;\n\tif(!getFileInternal(sFileName, bnp, bnpFile))\n\t{\n\t\tnlwarning (\"BF: Couldn't load '%s'\", sFileName.c_str());\n\t\treturn NULL;\n\t}\n\tnlassert(bnp && bnpFile);\n\n\t// Get a ThreadSafe handle on the file\n\tCHandleFile\t\t&handle= _ThreadFileArray.get(bnp->ThreadFileId);\n\t/* If not opened, open it now. There is 2 reason for it to be not opened:\n\t\trbnp.AlwaysOpened==false, or it is a new thread which use it for the first time.\n\t*/\n\tif(handle.File== NULL)\n\t{\n\t\thandle.File = fopen (bnp->BigFileName.c_str(), \"rb\");\n\t\tif (handle.File == NULL)\n\t\t{\n\t\t\tnlwarning (\"bnp: can't fopen big file '%s' error %d '%s'\", bnp->BigFileName.c_str(), errno, strerror(errno));\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\trCacheFileOnOpen = bnp->CacheFileOnOpen;\n\trAlwaysOpened = bnp->AlwaysOpened;\n\trBigFileOffset = bnpFile->Pos;\n\trFileSize = bnpFile->Size;\n\treturn handle.File;\n}\n\n// ***************************************************************************\nbool CBigFile::getFileInfo (const std::string &sFileName, uint32 &rFileSize, uint32 &rBigFileOffset)\n{\n\tBNP\t\t*bnp= NULL;\n\tBNPFile\t*bnpFile= NULL;\n\tif(!getFileInternal(sFileName, bnp, bnpFile))\n\t{\n\t\tnlwarning (\"BF: Couldn't find '%s' for info\", sFileName.c_str());\n\t\treturn false;\n\t}\n\tnlassert(bnp && bnpFile);\n\n\t// get infos\n\trBigFileOffset = bnpFile->Pos;\n\trFileSize = bnpFile->Size;\n\treturn true;\n}\n\n// ***************************************************************************\nchar *CBigFile::getFileNamePtr(const std::string &sFileName, const std::string &sBigFileName)\n{\n\tstring bigfilenamealone = CFile::getFilename (sBigFileName);\n\tif (_BNPs.find(bigfilenamealone) != _BNPs.end())\n\t{\n\t\tBNP &rbnp = _BNPs.find (bigfilenamealone)->second;\n\t\tvector<BNPFile>::iterator itNBPFile;\n\t\tif (rbnp.Files.size() == 0)\n\t\t\treturn NULL;\n\t\tstring lwrFileName = toLower(sFileName);\n\n\t\tBNPFile temp_bnp_file;\n\t\ttemp_bnp_file.Name = (char*)lwrFileName.c_str();\n\t\titNBPFile = lower_bound(rbnp.Files.begin(), rbnp.Files.end(), temp_bnp_file, CBNPFileComp());\n\n\t\tif (itNBPFile != rbnp.Files.end())\n\t\t{\n\t\t\tif (strcmp(itNBPFile->Name, lwrFileName.c_str()) == 0)\n\t\t\t{\n\t\t\t\treturn itNBPFile->Name;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NULL;\n}\n\n// ***************************************************************************\nvoid CBigFile::getBigFilePaths(std::vector<std::string> &bigFilePaths)\n{\n\tbigFilePaths.clear();\n\tfor(std::map<std::string, BNP>::iterator it = _BNPs.begin(); it != _BNPs.end(); ++it)\n\t{\n\t\tbigFilePaths.push_back(it->second.BigFileName);\n\t}\n}\n\n\n} // namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/bit_mem_stream.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/bit_mem_stream.h\"\n#include \"nel/misc/bit_set.h\"\n\n#ifdef LOG_ALL_TRAFFIC\n#include \"nel/misc/command.h\"\n#endif\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n#ifdef LOG_ALL_TRAFFIC\nbool VerboseAllTraffic = false;\n#endif\n\n\nconst char * SerialTypeToCStr [ TBMSSerialInfo::NbSerialTypes ] = { \"Bool \", \"Ui32N\", \"Ui64N\", \"Float\", \"Btfld\", \"Buffr\" };\n\n\n/*\n * Constructor\n */\nCBitMemStream::CBitMemStream( bool inputStream, uint32 defaultcapacity ) :\n\tCMemStream( inputStream, false, defaultcapacity ),\n\t_FreeBits( 0 )\n{\n\tresetBufPos();\n}\n\n\n/*\n * Copy constructor\n */\nCBitMemStream::CBitMemStream( const CBitMemStream& other ) :\n\tCMemStream( other ),\n\t_FreeBits( other._FreeBits ),\n\t_DbgInfo( other._DbgInfo )\n{\n}\n\n/*\n *\tExchange\n */\nvoid CBitMemStream::swap(CBitMemStream &other)\n{\n\tCMemStream::swap(other);\n\tstd::swap(_FreeBits, other._FreeBits);\n\t_DbgInfo.swap(other._DbgInfo);\n}\n\n\n/*\n * Serialize a buffer\n */\nvoid CBitMemStream::serialBuffer( uint8 *buf, uint len )\n{\n\t_DbgInfo.addSerial( getPosInBit(), len*8, TBMSSerialInfo::Buffer );\n\tuint i;\n\tuint32 v;\n\tif ( isReading() )\n\t{\n\t\tfor ( i=0; i!=len; ++i )\n\t\t{\n\t\t\tinternalSerial( v, 8 );\n\t\t\tbuf[i] = (uint8)v;\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor ( i=0; i!=len; ++i )\n\t\t{\n\t\t\tv = (uint32)buf[i];\n\t\t\tinternalSerial( v, 8 );\n\t\t}\n\t}\n}\n\n\n/*\n * Serialize one bit\n */\nvoid CBitMemStream::serialBit( bool& bit )\n{\n\t_DbgInfo.addSerial( getPosInBit(), 1, TBMSSerialInfo::B );\n\tuint32 ubit=0;\n\tif ( isReading() )\n\t{\n\t\tinternalSerial( ubit, 1 );\n\t\tbit = ( ubit!=0 );\n\t}\n\telse\n\t{\n\t\tubit = bit;\n\t\tinternalSerial( ubit, 1 );\n\t}\n}\n\n\n//sint32 CBitMemStream::getPosInBit ()\n\n\n#ifdef LOG_ALL_TRAFFIC\n\nvoid\tCBitMemStream::_serialAndLog( const char *argstr, uint32& value, uint nbits )\n{\n\t_DbgInfo.setSymbolOfNextSerialEvent( argstr );\n\tsint32 bitpos = getPosInBit();\n\tserial( value, nbits );\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: %s: %u bits at bitpos %d (%u)\", this, isReading()?\"I\":\"O\", argstr, nbits, bitpos, value );\n}\n\nvoid\tCBitMemStream::_serialAndLog( const char *argstr, uint64& value, uint nbits )\n{\n\t_DbgInfo.setSymbolOfNextSerialEvent( argstr );\n\tsint32 bitpos = getPosInBit();\n\tserial( value, nbits );\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: %s: %u bits at bitpos %d (%u)\", this, isReading()?\"I\":\"O\", argstr, nbits, bitpos, value );\n}\n\nvoid\tCBitMemStream::_serialBitAndLog( const char *argstr, bool& bit )\n{\n\t_DbgInfo.setSymbolOfNextSerialEvent( argstr );\n\tsint32 bitpos = getPosInBit();\n\tserialBit( bit );\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: %s: 1 bit at bitpos %d (%hu)\", this, isReading()?\"I\":\"O\", argstr, bitpos, (uint16)bit );\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, verboseAllTraffic, \"Verbose the all-traffic logs\", \"\" )\n{\n\tif(args.size()>1)\n\t\treturn false;\n\n\tif(args.size()==1)\n\t{\n\t\tif(args[0]==string(\"on\")||args[0]==string(\"ON\")||args[0]==string(\"true\")||args[0]==string(\"TRUE\")||args[0]==string(\"1\"))\n\t\t\tVerboseAllTraffic=true;\n\t\telse if(args[0]==string(\"off\")||args[0]==string(\"OFF\")||args[0]==string(\"false\")||args[0]==string(\"FALSE\")||args[0]==string(\"0\"))\n\t\t\tVerboseAllTraffic=false;\n\t}\n\n\tnlinfo(\"BMS: verboseAllTraffic is %s\",VerboseAllTraffic?\"ON\":\"OFF\");\n\treturn true;\n}\n\n#endif\n\n\n/*\n * Serialize only the nbits lower bits of value\n */\nvoid\tCBitMemStream::internalSerial( uint32& value, uint nbits, bool resetvalue )\n{\n\tif ( nbits == 0 )\n\t\treturn;\n\tif ( nbits > 32 )\n\t\tthrow EMemStream (string(\"trying to serial \")+NLMISC::toString(nbits)+string(\" bits\"));\n\n\tif ( isReading() )\n\t{\n\t\tconst uint8 *buffer = _Buffer.getBuffer().getPtr();\n\t\t// Check that we don't read more than there is to read\n\t\tuint32 pib = getPosInBit();\n\t\tuint32 len = ((uint32)lengthR());\n\t\tif ( pib + nbits > len * 8 )\n\t\t{\n\t\t\t//displayStream( \"Stream Overflow\" );\n\t\t\tthrow EStreamOverflow( \"CBitMemStream overflow: Read past %u bytes\", len );\n\t\t}\n\n\t\tif ( resetvalue )\n\t\t{\n\t\t\tvalue = 0;\n\t\t}\n\n\t\t// Clear high-order bits after _FreeBits\n\t\tuint8 v = *(buffer + _Buffer.Pos) & ((1 << _FreeBits) - 1);\n\n\t\tif ( nbits > _FreeBits )\n\t\t{\n\t\t\t//nldebug( \"Reading byte %u from %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t\tvalue |= (v << (nbits-_FreeBits));\n//\t\t\t++_BufPos;\n\t\t\t++_Buffer.Pos;\n\t\t\tuint readbits = _FreeBits;\n\t\t\t//displayByteBits( *_BufPos, 8, readbits-1, false );\n\t\t\t_FreeBits = 8;\n\t\t\tinternalSerial( value, nbits - readbits, false ); // read without resetting value\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//nlinfo( \"Reading last byte %u from %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t\t//displayByteBits( *_BufPos, 8, _FreeBits-1, false );\n\t\t\tvalue |= (v >> (_FreeBits-nbits));\n\t\t\t//displayByteBits( *_BufPos, 8, _FreeBits-1, false );\n\t\t\t_FreeBits -= nbits;\n\t\t\tif ( _FreeBits == 0 )\n\t\t\t{\n\t\t\t\t_FreeBits = 8;\n//\t\t\t\t++_BufPos;\n\t\t\t\t++_Buffer.Pos;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tuint8 *buffer = _Buffer.getBufferWrite().getPtr();\n\t\t// Clear high-order bits after nbits\n\t\t//displayDwordBits( value, 32, nbits-1, false );\n\n\t\t//uint32 mask = (-1 >> (32-nbits)); // does not work\n\t\tuint32 v;\n\t\tif ( nbits != 32 ) // arg of shl/sal/shr/sal ranges from 0 to 31\n\t\t{\n\t\t\tuint32 mask = (1 << nbits) - 1;\n\t\t\tv = value & mask;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tv = value;\n\t\t}\n\n#ifdef NL_DEBUG\n\t\t// Check that the current byte is prepared\n\t\tnlassert( ! ((_FreeBits == 8) && (*(buffer+_Buffer.Pos) != 0)) );\n#endif\n\n\t\t// Set\n\t\tif ( nbits > _FreeBits )\n\t\t{\n\t\t\t// Longer than the room in the current byte\n\t\t\t//nldebug( \"Writing byte %u into %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t\t//displayDwordBits( value, 32, nbits-1, false );\n//\t\t\t*_BufPos |= (v >> (nbits - _FreeBits));\n\t\t\t*(buffer+_Buffer.Pos) |= (v >> (nbits - _FreeBits));\n\t\t\tuint filledbits = _FreeBits;\n\t\t\t//displayByteBits( *_BufPos, 8, filledbits-1, false );\n\t\t\tprepareNextByte();\n\t\t\tinternalSerial( v, nbits - filledbits );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Shorter or equal\n\t\t\t//nldebug( \"Writing last byte %u into %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t\t//displayByteBits( *_BufPos, 8, 7, false );\n//\t\t\t*_BufPos |= (v << (_FreeBits-nbits));\n\t\t\t*(buffer+_Buffer.Pos) |= (v << (_FreeBits-nbits));\n\t\t\t//displayByteBits( *_BufPos, 8, _FreeBits-1, false );\n\t\t\t_FreeBits -= nbits;\n\t\t\tif ( _FreeBits == 0 )\n\t\t\t{\n\t\t\t\tprepareNextByte();\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n * Same as CMemStream::reserve()\n */\nsint32\tCBitMemStream::reserve( uint byteLen )\n{\n\tsint32 p = getPos();\n\treserveBits( byteLen * 8 );\n\treturn p;\n}\n\n\n/*\n * In a output bit stream, serialize nbits bits (no matter their value).\n * Works even if the number of bits to add is larger than 64. See also poke() and pokeBits().\n */\nvoid\tCBitMemStream::reserveBits( uint nbits )\n{\n#ifdef LOG_ALL_TRAFFIC\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: Reserving %u bits at bitpos %d\", this, isReading()?\"I\":\"O\", nbits, getPosInBit() );\n#endif\n\n\tuint32 v = 0;\n\twhile ( nbits > 32 )\n\t{\n\t\tserial( v, 32 );\n\t\tnbits -= 32;\n\t}\n\tif ( nbits != 0 )\n\t\tserial( v, nbits );\n}\n\n\n/*\n * Helper for poke(), to write a value inside an output stream (works because reserveBits sets to 0)\n */\nvoid\tCBitMemStream::serialPoke( uint32 value, uint nbits )\n{\n\tuint32 v;\n\tif ( nbits != 32 ) // arg of shl/sal/shr/sal ranges from 0 to 31\n\t{\n\t\tuint32 mask = (1 << nbits) - 1;\n\t\tv = value & mask;\n\t}\n\telse\n\t{\n\t\tv = value;\n\t}\n\n\tuint8 *buffer = _Buffer.getBufferWrite().getPtr();\n\n\t// Set\n\tif ( nbits > _FreeBits )\n\t{\n\t\t// Longer than the room in the current byte\n\t\t//nldebug( \"Writing byte %u into %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t//displayDwordBits( value, 32, nbits-1, false );\n//\t\t*_BufPos |= (v >> (nbits - _FreeBits));\n\t\t*(buffer + _Buffer.Pos) |= (v >> (nbits - _FreeBits));\n\t\tuint filledbits = _FreeBits;\n\t\t//displayByteBits( *_BufPos, 8, filledbits-1, false );\n\t\tpointNextByte(); // do not set next byte to 0!\n//\t\tnlassert( _BufPos < _Buffer.getPtr() + _Buffer.size() );\n\t\tnlassert( _Buffer.Pos < _Buffer.getBuffer().size() );\n\t\tserialPoke( v, nbits - filledbits );\n\t}\n\telse\n\t{\n\t\t// Shorter or equal\n\t\t//nldebug( \"Writing last byte %u into %u free bits (%u remaining bits)\", lengthS(), _FreeBits, nbits );\n\t\t//displayByteBits( *_BufPos, 8, 7, false );\n//\t\t*_BufPos |= (v << (_FreeBits-nbits));\n\t\t*(buffer + _Buffer.Pos) |= (v << (_FreeBits-nbits));\n\t\t//displayByteBits( *_BufPos, 8, _FreeBits-1, false );\n\t\t_FreeBits -= nbits;\n\t\tif ( _FreeBits == 0 )\n\t\t{\n\t\t\tpointNextByte(); // do not set next byte to 0!\n//\t\t\tnlassert( _BufPos < _Buffer.getPtr() + _Buffer.size() );\n\t\t\tnlassert( _Buffer.Pos < _Buffer.getBuffer().size() );\n\t\t}\n\t}\n}\n\n\n/*\n * Rewrite the nbbits lowest bits of a value at the specified position bitpos of the current output bit stream.\n *\n * Preconditions:\n * - bitpos+nbbits <= the current length in bit of the stream.\n * - The bits poked must have been reserved by reserve() (i.e. set to 0)\n */\nvoid\tCBitMemStream::poke( uint32 value, uint bitpos, uint nbits )\n{\n#ifdef NL_DEBUG\n\tnlassert( (nbits <= 32) && (nbits != 0) );\n\tnlassert( ! isReading() );\n\tnlassert( bitpos+nbits <= (uint)getPosInBit() );\n#endif\n\n\t// Save the current pointers of the stream, and make them point to the required position\n\tuint savedFreeBits = _FreeBits;\n\tuint bytepos = bitpos >> 3;\n\t_FreeBits = 8 - (bitpos - (bytepos << 3));\n//\tuint8 *savedBufPos = _BufPos;\n\tuint32 savedBufPos = _Buffer.Pos;\n//\t_BufPos = _Buffer.getPtr() + bytepos;\n\t_Buffer.Pos = bytepos;\n\n\t// Serial\n\t_DbgInfo.addPoke( bitpos, nbits, TBMSSerialInfo::U );\n\tserialPoke( value, nbits );\n\n\t// Restore the current pointers\n\t_FreeBits = savedFreeBits;\n//\t_BufPos = savedBufPos;\n\t_Buffer.Pos = savedBufPos;\n}\n\n\n/* Rewrite the bitfield at the specified position bitpos of the current output bit stream.\n * The size of the bitfield is *not* written into stream (unlike serialCont()).\n * Precondition: bitpos+bitfield.size() <= the current length in bit of the stream. See also reserveBits().\n */\nvoid\tCBitMemStream::pokeBits( const CBitSet& bitfield, uint bitpos )\n{\n#ifdef NL_DEBUG\n\tnlassert( ! isReading() );\n\tnlassert( bitpos+bitfield.size() <= (uint)getPosInBit() );\n#endif\n\n\t// Save the current pointers of the stream, and make them point to the required position\n\tuint savedFreeBits = _FreeBits;\n\tuint bytepos = bitpos >> 3;\n\t_FreeBits = 8 - (bitpos - (bytepos << 3));\n//\tuint8 *savedBufPos = _BufPos;\n\tuint32 savedBufPos = _Buffer.Pos;\n//\t_BufPos = _Buffer.getPtr() + bytepos;\n\t_Buffer.Pos = bytepos;\n\n\t// Serial\n\t_DbgInfo.addPoke( bitpos, bitfield.size(), TBMSSerialInfo::BF );\n\tconst vector<uint32>& uintVec = bitfield.getVector();\n\tif ( ! uintVec.empty() )\n\t{\n\t\tuint len = bitfield.size();\n\t\tuint i = 0;\n\t\twhile ( len > 32 )\n\t\t{\n\t\t\tserialPoke( uintVec[i], 32 );\n\t\t\tlen -= 32;\n\t\t\t++i;\n\t\t}\n\t\tif ( len != 0 )\n\t\t\tserialPoke( uintVec[i], len );\n\t}\n\n\t// Restore the current pointers\n\t_FreeBits = savedFreeBits;\n//\t_BufPos = savedBufPos;\n\t_Buffer.Pos = savedBufPos;\n}\n\n\n/*\n * Read bitfield.size() bits from the input stream to fill the bitfield.\n * It means you have to know the size and to resize the bitfield yourself.\n */\nvoid\tCBitMemStream::readBits( NLMISC::CBitSet& bitfield )\n{\n#ifdef NL_DEBUG\n\tnlassert( isReading() );\n#endif\n\tuint len = bitfield.size();\n\tif ( len != 0 )\n\t{\n#ifdef LOG_ALL_TRAFFIC\n\t\tif ( VerboseAllTraffic )\n\t\t\tnldebug( \"TRAFFIC/%p/%s: Reading %u bits bitfield at bitpos %d\", this, isReading()?\"I\":\"O\", len, getPosInBit() );\n#endif\n\t\tuint i = 0;\n\t\tuint32 v;\n\t\twhile ( len > 32 )\n\t\t{\n\t\t\tserial( v, 32 );\n\t\t\t//nldebug( \"Bitfield: Read %u at %d\", v, _BufPos-_Buffer.getPtr()-4 );\n\t\t\tbitfield.setUint( v, i );\n\t\t\tlen -= 32;\n\t\t\t++i;\n\t\t}\n\t\tserial( v, len );\n\t\t//nldebug( \"Bitfield: Read %u at %d\", v, _BufPos-_Buffer.getPtr()-4 );\n\t\tbitfield.setUint( v, i );\n\t}\n}\n\n\n/*\n * Serial float\n */\nvoid\tCBitMemStream::serial(float &b)\n{\n\t_DbgInfo.addSerial( getPosInBit(), sizeof(b)*8, TBMSSerialInfo::F );\n\tuint32 uf=0;\n\tif ( isReading() )\n\t{\n\t\tinternalSerial( uf, sizeof(b)*8 );\n\t\tmemcpy(&b, &uf, sizeof(b));\n\t}\n\telse\n\t{\n\t\tmemcpy(&uf, &b, sizeof(b));\n\t\tinternalSerial( uf, sizeof(b)*8 );\n\t}\n}\n\n\n/*\n * Serial string\n */\nvoid\tCBitMemStream::serial(std::string &b)\n{\n#ifdef LOG_ALL_TRAFFIC\n\tsint32 bitpos = getPosInBit();\n#endif\n\n\tuint32 len=0;\n\n\t// Serialize length\n\tif ( isReading() )\n\t{\n\t\tserial( len );\n\t\tif (len > length()-(uint32)getPos())\n\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to read a string of %u bytes, past stream size\", len );\n\t\tb.resize( len );\n\t}\n\telse\n\t{\n\t\tlen = (uint32)b.size();\n\t\tif (len>1000000)\n\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to write a string of %u bytes\", len );\n\t\tserial( len );\n\t}\n\n\t// Serialize buffer\n\tif ( len != 0 )\n\t{\n\t\tserialBuffer( (uint8*)(&*b.begin()), len );\n\t}\n\n#ifdef LOG_ALL_TRAFFIC\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: String (size 32+%u*8 bits) at bitpos %d\", this, isReading()?\"I\":\"O\", len, bitpos );\n#endif\n}\n\n\n/*\n * Serial string\n */\ninline\tvoid\t\tCBitMemStream::serial(ucstring &b)\n{\n#ifdef LOG_ALL_TRAFFIC\n\tsint32 bitpos = getPosInBit();\n#endif\n\n\tif ( _StringMode )\n\t{\n\t\tuint32\tlen=0;\n\t\t// Read/Write the length.\n\t\tif(isReading())\n\t\t{\n\t\t\tserial(len);\n\t\t\tif (len > (uint32)(sint32(length())-sint32(getPos())))\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to read an ucstring of %u bytes, past stream size\", len );\n\t\t\tb.resize(len);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlen= (uint32)b.size();\n\t\t\tif (len>1000000)\n\t\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to write an ucstring of %u bytes\", len );\n\t\t\tserial(len);\n\t\t}\n\t\t// Read/Write the string.\n\t\tfor(uint i=0;i!=len;++i)\n\t\t\tserialBuffer( (uint8*)&b[i], sizeof(b[i]) );\n\n\t\tchar sep = SEPARATOR;\n\t\tserialBuffer( (uint8*)&sep, 1 );\n\t}\n\telse\n\t{\n\t\tIStream::serial( b );\n\t}\n\n#ifdef LOG_ALL_TRAFFIC\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: Ucstring at bitpos %d\", this, isReading()?\"I\":\"O\", bitpos );\n#endif\n\n}\n\n\n/*\n * Append the contents of a bitmemstream at the end of our bitmemstream\n */\nvoid\tCBitMemStream::append( const CBitMemStream& newBits )\n{\n\tnlassert ( !isReading() );\n\tserialBuffer( const_cast<uint8*>(newBits.buffer()), newBits.getPos() );\n\n\tuint nbRemainingBits = 8 - newBits._FreeBits;\n\t_DbgInfo.addSerial( getPosInBit(), nbRemainingBits, TBMSSerialInfo::Buffer );\n\tuint32 lastByte = (uint32)(*(newBits.buffer() + newBits.getPos())) >> newBits._FreeBits;\n\tinternalSerial( lastByte, nbRemainingBits );\n}\n\n\n/*\n * Serial bitmemstream\n */\nvoid\tCBitMemStream::serialMemStream(CMemStream &b)\n{\n#ifdef LOG_ALL_TRAFFIC\n\tsint32 bitpos = getPosInBit();\n#endif\n\n\tuint32 len=0;\n\n\t// Serialize length\n\tif ( isReading() )\n\t{\n\t\t// fill b with data from this\n\t\tserial (len);\n\t\tif (len > length()-getPos())\n\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to read a BMS of %u bytes, past stream size\", len );\n\n\t\tserialBuffer (b.bufferToFill (len), len);\n\t\tb.resetBufPos ();\n\t}\n\telse\n\t{\n\t\t// fill this with data from b\n\t\tlen = b.length();\n\t\t// Accept to write a big sized BMS\n\n\t\tserial( len );\n\t\tserialBuffer( (uint8*) b.buffer (), len );\n\t}\n\n#ifdef LOG_ALL_TRAFFIC\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: Sub-bitmemstream (size 32+%u*8 bits) at bitpos %d\", this, isReading()?\"I\":\"O\", len, bitpos );\n#endif\n}\n\n/*\n * Specialisation of serialCont() for vector<bool>\n */\nvoid CBitMemStream::serialCont(std::vector<bool> &cont)\n{\n#ifdef LOG_ALL_TRAFFIC\n\tsint32 bitpos = getPosInBit();\n#endif\n\n\tsint32\tlen=0;\n\tif(isReading())\n\t{\n\t\tserial(len);\n\t\tif (len/8 > (sint32)(length()-getPos()))\n\t\t{\n\t\t\tthrow NLMISC::EInvalidDataStream( \"BMS: Trying to read a vec<bool> of %u bytes, past stream size\", len/8 );\n\t\t}\n\t\t// special version for vector: adjust good size.\n\t\tcontReset(cont);\n\t\tcont.reserve(len);\n\n\t\tfor(sint i=0;i<len;i++)\n\t\t{\n\t\t\tbool\tv;\n\t\t\tserialBit(v);\n\t\t\tcont.insert(cont.end(), v);\n\t\t}\n\t}\n\telse\n\t{\n\t\tlen= (sint32)cont.size();\n\t\tserial(len);\n\n\t\tstd::vector<bool>::iterator it= cont.begin();\n\t\tfor(sint i=0;i<len;i++, it++)\n\t\t{\n\t\t\tbool b = *it;\n\t\t\tserialBit( b );\n\t\t}\n\t}\n\n#ifdef LOG_ALL_TRAFFIC\n\tif ( VerboseAllTraffic )\n\t\tnldebug( \"TRAFFIC/%p/%s: Container (header: 32 bits) at bitpos %d\", this, isReading()?\"I\":\"O\", bitpos );\n#endif\n\n}\n\n\n/*\n * Display the bits of the stream just before the current pos\n */\nvoid\tCBitMemStream::displayLastBits( sint nbits, sint bitpos, NLMISC::CLog *log )\n{\n\tif ( bitpos == -1 )\n\t\tbitpos = getPosInBit();\n\tdisplayBitStream( *this, max(bitpos-nbits, 0), bitpos-1, log );\n}\n\n\n/*\n * Display a part of a bitmemstream\n */\nvoid\tdisplayBitStream( const CBitMemStream& msg, sint beginbitpos, sint endbitpos, NLMISC::CLog *log )\n{\n\tsint beginpos = beginbitpos/8;\n\tsint endpos = endbitpos/8;\n\tnlinfo( \"BMS: beginpos %d endpos %d beginbitpos %d endbitpos %d\", beginpos, endpos, beginbitpos, endbitpos );\n\tdisplayByteBits( *(msg.buffer()+beginpos), 8, 8-(beginbitpos-beginpos*8), true, log );\n\tconst uint8 *p;\n\tfor ( p=msg.buffer()+beginpos+1; p<msg.buffer()+endpos-1; ++p )\n\t{\n\t\tdisplayByteBits( *p, 8, 0, false, log );\n\t}\n\tif ( endpos > beginpos )\n\t{\n\t\tdisplayByteBits( *(msg.buffer()+endpos), 8, 0, false, log );\n\t}\n}\n\n\n/*\n * Returns the stream as a string with 0 and 1.\n */\nvoid\t\tCBitMemStream::displayStream( const char *title, CLog *log )\n{\n//\tnlassert( (_BufPos >= _Buffer.getPtr()) && (_BufPos <= _Buffer.getPtr() + _Buffer.size()) );\n\tnlassert( _Buffer.Pos <= _Buffer.getBuffer().size() );\n\n\t// Display title and information\n\tstring s = (isReading()?string(\"I\"):string(\"O\")) + string(\"BMS \") + string(title) + \": \";\n\tstring sLegend;\n//\tif ( _BufPos == _Buffer.getPtr() )\n\tif ( _Buffer.Pos == 0 )\n\t{\n\t\tlog->displayNL( (s + \"Empty\").c_str() );\n\t\treturn;\n\t}\n\n//\ts += NLMISC::toString( \"BitPos=%d Pos=%u FreeBits=%u Size=%u \", getPosInBit(), (uint32)(_BufPos-_Buffer.getPtr()), _FreeBits, _Buffer.size() );\n\ts += NLMISC::toString( \"BitPos=%d Pos=%u FreeBits=%u Size=%u \", getPosInBit(), _Buffer.Pos, _FreeBits, _Buffer.getBuffer().size() );\n\tlog->displayNL( s.c_str() );\n\ts.clear();\n\n\t// Display bitstream (output: until _BufPos/_FreeBits; input: whole buffer)\n\t_DbgInfo.beginEventBrowsing();\n\tsint32 eventId;\n\tuint32 bitpos = 0;\n\tconst uint8 *p;\n//\tuint8 *endPos = isReading() ? (_Buffer.getPtr() + _Buffer.size()) : (_BufPos+1);\n\tconst uint8 *endPos = isReading() ? (_Buffer.getBuffer().getPtr() + _Buffer.getBuffer().size()) : (_Buffer.getBuffer().getPtr() + _Buffer.Pos+1);\n//\tfor ( p=_Buffer.getPtr(); p!=endPos; ++p )\n\tfor ( p=_Buffer.getBuffer().getPtr(); p!=endPos; ++p )\n\t{\n\t\tsint i;\n\t\tfor ( i=7; i!=-1; --i )\n\t\t{\n\t\t\t//bitpos = (p-_Buffer.getPtr())*8 + (7-i);\n\t\t\tif ( bitpos == (uint32)getPosInBit() )\n\t\t\t\ts += \"<P>\"; // display the current position\n\t\t\ts += _DbgInfo.getEventIdAtBitPos( bitpos, &eventId );\n\t\t\ts += ( ((*p) >> i) & 1 ) ? '1' : '0';\n\t\t\tsLegend += _DbgInfo.getEventLegendAtBitPos( *this, eventId );\n\t\t\t++bitpos;\n\t\t}\n\n\t\ts += ' '; // a blank char between each byte\n\t\tif ( bitpos % 64 == 0 ) // limit to 8 bytes per line\n\t\t{\n\t\t\tlog->displayRawNL( s.c_str() );\n\t\t\ts.clear();\n\t\t}\n\t}\n\tif ( bitpos % 64 != 0 )\n\t\tlog->displayRawNL( s.c_str() );\n\t_DbgInfo.endEventBrowsing();\n\n\t// Display legend\n\tstring::size_type lineStart = 0;\n\tstring::size_type crp = sLegend.find( '\\n', lineStart );\n\twhile ( crp != string::npos )\n\t{\n\t\tlog->displayRawNL( sLegend.substr( lineStart, crp-lineStart ).c_str() );\n\t\tlineStart = crp + 1;\n\t\tcrp = sLegend.find( '\\n', lineStart );\n\t}\n\t// sLegend ends with a '\\n'\n}\n\n\n/*\n * Return a string showing the serial item\n */\nstd::string\t\tCBitMemStream::getSerialItem( const TBMSSerialInfo& serialItem )\n{\n\t// Save the current pointers of the stream, and make them point to the required position\n\tuint savedFreeBits = _FreeBits;\n\tuint bytepos = serialItem.BitPos >> 3;\n\t_FreeBits = 8 - (serialItem.BitPos - (bytepos << 3));\n//\tuint8 *savedBufPos = _BufPos;\n\tuint32 savedBufPos = _Buffer.Pos;\n//\t_BufPos = _Buffer.getPtr() + bytepos;\n\t_Buffer.Pos = bytepos;\n\n\tbool wasOutput = false;;\n\tif ( ! isReading() )\n\t{\n\t\tsetInOut( true ); // lighter than invert()\n\t\twasOutput = true;\n\t}\n\n\t// Read and format string\n\tstring s;\n\tif ( getPosInBit() + serialItem.BitSize > lengthR() * 8 )\n\t{\n\t\ts = \"<Stream Overflow>\";\n\t}\n\telse\n\t{\n\t\tswitch ( serialItem.Type )\n\t\t{\n\t\tcase TBMSSerialInfo::B:\n\t\t\t{\n\t\t\t\tbool b;\n\t\t\t\tserialBit( b );\n\t\t\t\ts = NLMISC::toString( \"%s\", b?\"TRUE\":\"FALSE\" );\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase TBMSSerialInfo::U: // no distinction with signed int!\n\t\t\t{\n\t\t\t\tuint32 u;\n\t\t\t\tserial( u, serialItem.BitSize );\n\t\t\t\ts = NLMISC::toString( \"%u\", u );\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase TBMSSerialInfo::U64: // no distinction with signed int64!\n\t\t\t{\n\t\t\t\tuint64 u;\n\t\t\t\tserial( u, serialItem.BitSize );\n\t\t\t\ts = NLMISC::toString( \"%\" NL_I64 \"u\", u );\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase TBMSSerialInfo::F: // what about double?\n\t\t\t{\n\t\t\t\tfloat f;\n\t\t\t\tserial( f );\n\t\t\t\ts = NLMISC::toString( \"%g\", f );\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase TBMSSerialInfo::BF:\n\t\t\t{\n\t\t\t\tCBitSet bs;\n\t\t\t\tbs.resize( serialItem.BitSize );\n\t\t\t\treadBits( bs );\n\t\t\t\ts = bs.toString();\n\t\t\t\tbreak;\n\t\t\t}\n\t\tcase TBMSSerialInfo::Buffer:\n\t\t\t{\n\t\t\t\tuint32 len = serialItem.BitSize / 8;\n\t\t\t\ts.resize( len + 2 );\n\t\t\t\tif ( len != 0 )\n\t\t\t\t{\n\t\t\t\t\tserialBuffer( &((uint8&)(s[1])), len );\n\t\t\t\t\tstring::size_type p;\n\t\t\t\t\tfor ( p=1; p!=len+1; ++p )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( ! isalnum(s[p]) )\n\t\t\t\t\t\t\ts[p] = '?'; // remove end-of-c_string\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ts[0] = '[';\n\t\t\t\ts[len+1] = ']';\n\t\t\t\tbreak;\n\t\t\t}\n\t\tdefault:\n\t\t  break;\n\t\t}\n\t}\n\n\t// Restore the current pointers\n\tif ( wasOutput )\n\t{\n\t\tsetInOut( false );\n\t}\n\n\t_FreeBits = savedFreeBits;\n//\t_BufPos = savedBufPos;\n\t_Buffer.Pos = savedBufPos;\n\n\treturn s;\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/bit_set.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/bit_set.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n// must be defined elsewhere\n#ifndef min\n#define min(a,b)            (((a) < (b)) ? (a) : (b))\n#endif\n\n\n\n// ***************************************************************************\nCBitSet::CBitSet()\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\tNumBits= 0;\n\tMaskLast= 0;\n}\nCBitSet::CBitSet(uint numBits)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\tNumBits= 0;\n\tMaskLast= 0;\n\tresize(numBits);\n}\nCBitSet::CBitSet(const CBitSet &bs)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\tNumBits= bs.NumBits;\n\tMaskLast= bs.MaskLast;\n\tArray= bs.Array;\n}\nCBitSet::~CBitSet()\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n}\nCBitSet\t&CBitSet::operator=(const CBitSet &bs)\n{\n\tNumBits= bs.NumBits;\n\tMaskLast= bs.MaskLast;\n\tArray= bs.Array;\n\n\treturn *this;\n}\n\n\n// ***************************************************************************\nvoid\tCBitSet::clear()\n{\n\tArray.clear();\n\tNumBits= 0;\n\tMaskLast=0;\n}\nvoid\tCBitSet::resize(uint numBits)\n{\n\tif(numBits==0)\n\t\tclear();\n\n\tNumBits= numBits;\n\tArray.resize( (NumBits+NL_BITLEN-1) / NL_BITLEN );\n\tuint\tnLastBits= NumBits & (NL_BITLEN-1) ;\n\t// Generate the mask for the last word.\n\tif(nLastBits==0)\n\t\tMaskLast= ~((uint)0);\n\telse\n\t\tMaskLast= (1<< nLastBits) -1;\n\n\t// reset to 0.\n\tclearAll();\n}\nvoid\tCBitSet::resizeNoReset(uint numBits, bool value)\n{\n\tif(numBits==0)\n\t\tclear();\n\n\tuint oldNum=NumBits;\n\tNumBits= numBits;\n\tArray.resize( (NumBits+NL_BITLEN-1) / NL_BITLEN );\n\tuint\tnLastBits= NumBits & (NL_BITLEN-1) ;\n\t// Generate the mask for the last word.\n\tif(nLastBits==0)\n\t\tMaskLast= ~((uint)0);\n\telse\n\t\tMaskLast= (1<< nLastBits) -1;\n\n\t// Set new bit to value\n\tfor (uint i=oldNum; i<(uint)NumBits; i++)\n\t\tset(i, value);\n}\nvoid\tCBitSet::setAll()\n{\n\tconst vector<uint32>::size_type s = Array.size();\n\tfill_n(Array.begin(), s, ~((uint)0));\n\n\tif (s)\n\t\tArray[s-1]&= MaskLast;\n}\nvoid\tCBitSet::clearAll()\n{\n\tfill_n(Array.begin(), Array.size(), 0);\n}\n\n\n// ***************************************************************************\nCBitSet\tCBitSet::operator~() const\n{\n\tCBitSet\tret;\n\n\tret= *this;\n\tret.flip();\n\treturn ret;\n}\nCBitSet\tCBitSet::operator&(const CBitSet &bs) const\n{\n\tCBitSet\tret;\n\n\tret= *this;\n\tret&=bs;\n\treturn ret;\n}\nCBitSet\tCBitSet::operator|(const CBitSet &bs) const\n{\n\tCBitSet\tret;\n\n\tret= *this;\n\tret|=bs;\n\treturn ret;\n}\nCBitSet\tCBitSet::operator^(const CBitSet &bs) const\n{\n\tCBitSet\tret;\n\n\tret= *this;\n\tret^=bs;\n\treturn ret;\n}\n\n\n// ***************************************************************************\nvoid\tCBitSet::flip()\n{\n\tif(NumBits==0)\n\t\treturn;\n\n\tfor(sint i=0;i<(sint)Array.size();i++)\n\t\tArray[i]= ~Array[i];\n\n\tArray[Array.size()-1]&= MaskLast;\n}\nCBitSet\t&CBitSet::operator&=(const CBitSet &bs)\n{\n\tif(NumBits==0)\n\t\treturn *this;\n\n\tvector<uint32>::size_type minSize = min(Array.size(), bs.Array.size());\n\tvector<uint32>::size_type i;\n\tfor(i=0;i<minSize;i++)\n\t\tArray[i]= Array[i] & bs.Array[i];\n\tfor(i=minSize;i<Array.size();i++)\n\t\tArray[i]=0;\n\n\tArray[Array.size()-1]&= MaskLast;\n\n\treturn *this;\n}\nCBitSet\t&CBitSet::operator|=(const CBitSet &bs)\n{\n\tif(NumBits==0)\n\t\treturn *this;\n\n\tvector<uint32>::size_type minSize = min(Array.size(), bs.Array.size());\n\tvector<uint32>::size_type i;\n\tfor(i=0;i<minSize;i++)\n\t\tArray[i]= Array[i] | bs.Array[i];\n\t// Do nothing for bits word from minSize to Array.size().\n\n\tArray[Array.size()-1]&= MaskLast;\n\n\treturn *this;\n}\nCBitSet\t&CBitSet::operator^=(const CBitSet &bs)\n{\n\tif(NumBits==0)\n\t\treturn *this;\n\n\tvector<uint32>::size_type minSize= min(Array.size(), bs.Array.size());\n\tvector<uint32>::size_type i;\n\tfor(i=0;i<minSize;i++)\n\t\tArray[i]= Array[i] ^ bs.Array[i];\n\t// Do nothing for bits word from minSize to Array.size().\n\n\tArray[Array.size()-1]&= MaskLast;\n\n\treturn *this;\n}\n\n\n// ***************************************************************************\nbool\tCBitSet::operator==(const CBitSet &bs) const\n{\n\tif(NumBits!=bs.NumBits)\n\t\treturn false;\n\n\tfor(sint i=0;i<(sint)Array.size();i++)\n\t{\n\t\tif(Array[i]!=bs.Array[i])\n\t\t\treturn false;\n\t}\n\treturn true;\n}\nbool\tCBitSet::operator!=(const CBitSet &bs) const\n{\n\treturn (!operator==(bs));\n}\nbool\tCBitSet::compareRestrict(const CBitSet &bs) const\n{\n\tsint\tn=min(NumBits, bs.NumBits);\n\tif(n==0) return true;\n\n\tsint\tnA= (n+NL_BITLEN-1) / NL_BITLEN;\n\tuint\tmask;\n\n\tuint\tnLastBits= n & (NL_BITLEN-1) ;\n\t// Generate the mask for the last common word.\n\tif(nLastBits==0)\n\t\tmask= ~((uint)0);\n\telse\n\t\tmask= (1<< nLastBits) -1;\n\n\n\tfor(sint i=0;i<nA-1;i++)\n\t{\n\t\tif(Array[i]!=bs.Array[i])\n\t\t\treturn false;\n\t}\n\tif( (Array[nA-1]&mask) != (bs.Array[nA-1]&mask) )\n\t\treturn false;\n\n\n\treturn true;\n}\nbool\tCBitSet::allSet()\n{\n\tif(NumBits==0)\n\t\treturn false;\n\tfor(sint i=0;i<(sint)Array.size()-1;i++)\n\t{\n\t\tif( Array[i]!= (~((uint)0)) )\n\t\t\treturn false;\n\t}\n\tif( Array[Array.size()-1]!= MaskLast )\n\t\treturn false;\n\treturn true;\n}\nbool\tCBitSet::allCleared()\n{\n\tif(NumBits==0)\n\t\treturn false;\n\tfor(sint i=0;i<(sint)Array.size();i++)\n\t{\n\t\tif( Array[i]!= 0 )\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n\n\nvoid\tCBitSet::serial(IStream &f)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\t(void)f.serialVersion(0);\n\tuint32\tsz=0;\n\tvector<uint32>\tarray32;\n\n\t// Must support any size of uint.\n\tif(f.isReading())\n\t{\n\t\tf.serial(sz);\n\t\tresize(sz);\n\n\t\tf.serialCont(array32);\n\t\tfor(sint i=0;i<(sint)sz;i++)\n\t\t{\n\t\t\tuint32\ta=array32[i/32];\n\t\t\ta&= 1<<(i&31);\n\t\t\tset(i, a!=0);\n\t\t}\n\t}\n\telse\n\t{\n\t\tsz= size();\n\t\tf.serial(sz);\n\n\t\tarray32.resize(sz/32);\n\t\tfill_n(array32.begin(), array32.size(), 0);\n\t\tfor(sint i=0;i<(sint)sz;i++)\n\t\t{\n\t\t\tif(get(i))\n\t\t\t\tarray32[i/32]|= 1<<(i&31);\n\t\t}\n\t\tf.serialCont(array32);\n\t}\n}\n\n\n/*\n * Return a string representing the bitfield with 1 and 0 (from left to right)\n */\nstd::string\tCBitSet::toString() const\n{\n\tstring s;\n\tfor ( sint i=0; i!=(sint)size(); ++i )\n\t{\n\t\ts += (get(i) ? '1' : '0');\n\t}\n\treturn s;\n}\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/bitmap.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/bitmap.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/system_info.h\"\n\n// Define this to force all bitmap white (debug)\n// #define NEL_ALL_BITMAP_WHITE\n\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nstruct EDDSBadHeader : public NLMISC::EStream\n{\n\tEDDSBadHeader() : EStream( \"Bad or unrecognized DDS file header\" ) {}\n};\n\nstruct ESeekFailed : public NLMISC::EStream\n{\n\tESeekFailed() : EStream( \"Seek failed\" ) {}\n};\n\nstruct EAllocationFailure : public Exception\n{\n\tEAllocationFailure() : Exception( \"Can't allocate memory\" ) {}\n};\n\nvoid blendFromui(NLMISC::CRGBA &c0, NLMISC::CRGBA &c1, uint coef);\nuint32 blend(uint32 &n0, uint32 &n1, uint32 coef0);\n\nconst uint32 CBitmap::bitPerPixels[ModeCount]=\n{\n\t32,\t\t// RGBA\n\t8,\t\t// Luminance\n\t8,\t\t// Alpha\n\t16,\t\t// AlphaLuminance\n\t4,\t\t// DXTC1\n\t4,\t\t// DXTC1Alpha\n\t8,\t\t// DXTC3\n\t8,\t\t// DXTC5\n\t16\t\t// DsDt\n};\n\nconst uint32 CBitmap::DXTC1HEADER = NL_MAKEFOURCC('D','X', 'T', '1');\nconst uint32 CBitmap::DXTC3HEADER = NL_MAKEFOURCC('D','X', 'T', '3');\nconst uint32 CBitmap::DXTC5HEADER = NL_MAKEFOURCC('D','X', 'T', '5');\n\n\n#ifdef NEL_ALL_BITMAP_WHITE\n// Make all the textures white\nvoid MakeWhite(CBitmap &bitmaps)\n{\n\tfor (uint i=0; i<bitmaps.getMipMapCount (); i++)\n\t{\n\t\tuint size = bitmaps.getPixels (i).size ();\n\t\tbitmaps.getPixels (i).resize (0);\n\t\tbitmaps.getPixels (i).resize (size);\n\t\tbitmaps.getPixels (i).fill (0xff);\n\t}\n}\n#endif // NEL_ALL_BITMAP_WHITE\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\t\tload\n\\*-------------------------------------------------------------------*/\nuint8 CBitmap::load(NLMISC::IStream &f, uint mipMapSkip)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\tnlassert(f.isReading());\n\n\t// testing if DDS\n\tuint32 fileType = 0;;\n\tf.serial(fileType);\n\tif(fileType == DDS_HEADER)\n\t{\n#ifdef NEL_ALL_BITMAP_WHITE\n\t\tuint8 result = readDDS(f, mipMapSkip);\n\t\tMakeWhite (*this);\n\t\treturn result;\n#else // NEL_ALL_BITMAP_WHITE\n\t\treturn readDDS(f, mipMapSkip);\n#endif // NEL_ALL_BITMAP_WHITE\n\t}\n\n\tif (fileType == PNG_HEADER)\n\t{\n#ifdef NEL_ALL_BITMAP_WHITE\n\t\tuint8 result = readPNG(f);\n\t\tMakeWhite (*this);\n\t\treturn result;\n#else // NEL_ALL_BITMAP_WHITE\n\t\treturn readPNG(f);\n#endif // NEL_ALL_BITMAP_WHITE\n\t}\n\n#ifdef USE_JPEG\n\tif (fileType == JPG_HEADER)\n\t{\n#ifdef NEL_ALL_BITMAP_WHITE\n\t\tuint8 result = readJPG(f);\n\t\tMakeWhite (*this);\n\t\treturn result;\n#else // NEL_ALL_BITMAP_WHITE\n\t\treturn readJPG(f);\n#endif // NEL_ALL_BITMAP_WHITE\n\t}\n#endif // USE_JPEG\n\n\t// assuming it's TGA\n\tNLMISC::IStream::TSeekOrigin origin= f.begin;\n\tif(!f.seek (0, origin))\n\t{\n\t\tthrow ESeekFailed();\n\t}\n\n\t// Reading header,\n\t// To make sure that the bitmap is TGA, we check imageType and imageDepth.\n\tuint8\tlengthID;\n\tuint8\tcMapType;\n\tuint8\timageType;\n\tuint16\ttgaOrigin;\n\tuint16\tlength;\n\tuint8\tdepth;\n\tuint16\txOrg;\n\tuint16\tyOrg;\n\tuint16\twidth;\n\tuint16\theight;\n\tuint8\timageDepth;\n\tuint8\tdesc;\n\n\tf.serial(lengthID);\n\tf.serial(cMapType);\n\tf.serial(imageType);\n\tif(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11) return 0;\n\tf.serial(tgaOrigin);\n\tf.serial(length);\n\tf.serial(depth);\n\tf.serial(xOrg);\n\tf.serial(yOrg);\n\tf.serial(width);\n\tf.serial(height);\n\tf.serial(imageDepth);\n\tif(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32) return 0;\n\tf.serial(desc);\n\n\tif(!f.seek (0, origin))\n\t{\n\t\tthrow ESeekFailed();\n\t}\n#ifdef NEL_ALL_BITMAP_WHITE\n\tuint8 result = readTGA(f);\n\tMakeWhite (*this);\n\treturn result;\n#else // NEL_ALL_BITMAP_WHITE\n\treturn readTGA(f);\n#endif // NEL_ALL_BITMAP_WHITE\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\t\tmakeDummy\n\\*-------------------------------------------------------------------*/\nvoid\tCBitmap::makeDummy()\n{\n\tstatic\tconst uint8\tbitmap[1024]= {\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t};\n\n\tmakeDummyFromBitField(bitmap);\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\t\tmakeDummy\n\\*-------------------------------------------------------------------*/\nvoid\tCBitmap::makeNonPowerOf2Dummy()\n{\n\tstatic\tconst uint8\tbitmap[1024]= {\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t\t0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n\t};\n\n\tmakeDummyFromBitField(bitmap);\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\tmakeDummyFromBitField\n\\*-------------------------------------------------------------------*/\nvoid\tCBitmap::makeDummyFromBitField(const uint8\tbitmap[1024])\n{\n\tPixelFormat = RGBA;\n\t_MipMapCount = 1;\n\t_Width= 32;\n\t_Height= 32;\n\t_Data[0].resize(_Width*_Height*sizeof(NLMISC::CRGBA));\n\tfor(sint m=1;m<MAX_MIPMAP;m++)\n\t\t_Data[m].clear();\n\tNLMISC::CRGBA\t*pix= (NLMISC::CRGBA*)(_Data[0].getPtr());\n\n\tfor(sint i=0;i<(sint)(_Width*_Height);i++)\n\t{\n\t\tif(bitmap[i])\n\t\t\tpix[i].set(255,255,255,255);\n\t\telse\n\t\t\tpix[i].set(0x80,0x80,0x80,0x40);\n\t}\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\t\treadDDS\n\\*-------------------------------------------------------------------*/\nuint8 CBitmap::readDDS(NLMISC::IStream &f, uint mipMapSkip)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\t//------------------ Reading Header ------------------------\n\n\t//-------------- reading entire header\n\n\tuint32 size = 0;\n\tf.serial(size); // size in Bytes of header(without \"DDS\")\n\t uint32 * _DDSSurfaceDesc = new uint32[size];\n\t_DDSSurfaceDesc[0]= size;\n\n#ifdef NL_LITTLE_ENDIAN\n\tf.serialBuffer((uint8*)(_DDSSurfaceDesc+1), size-4);\n#else\n\tfor(uint i= 0; i<size/4 - 1; i++)\n\t{\n\t\tf.serial(_DDSSurfaceDesc[i+1]);\n\t}\n#endif\n\n\t// flags determines which members of the header structure contain valid data\n\tuint32 flags = _DDSSurfaceDesc[1];\n\n\t//verify if file have linearsize set\n\tif(!(flags & DDSD_LINEARSIZE))\n    {\n\t\tnlwarning(\"A DDS doesn't have the flag DDSD_LINEARSIZE\");\n\t\t//delete [] _DDSSurfaceDesc;\n\t\t//throw EDDSBadHeader();\n\t}\n\n\t//-------------- extracting and testing useful info\n\n\t_Height = _DDSSurfaceDesc[2];\n\t_Width  = _DDSSurfaceDesc[3];\n\t_MipMapCount= (uint8) _DDSSurfaceDesc[6];\n\t// If no mipmap.\n\tif(_MipMapCount==0)\n\t\t_MipMapCount=1;\n\tswitch (_DDSSurfaceDesc[20])\n\t{\n\tcase DXTC1HEADER:\n\t\tPixelFormat=DXTC1;\n\t\tbreak;\n\tcase DXTC3HEADER:\n\t\tPixelFormat=DXTC3;\n\t\tbreak;\n\tcase DXTC5HEADER:\n\t\tPixelFormat=DXTC5;\n\t\tbreak;\n\t}\n\n\tflags = _DDSSurfaceDesc[19]; //PixelFormat flags\n\n/*\tace: I changed this code because it's not a way to detect if DXTC1 has a alpha channel or not\n\t\tThere's no easy way to detect if the DXTC1 has an alpha channel or not, so, for now, we'll suppose\n\t\tthat all DXTC1 has alpha channel per default.\n\n\t\t\"There is no flag unfortunately, you need to read each block of DXT1 data, check if one of the colors\n\t\tcontains alpha, and check if that color is used in the data.\n\t\tIt's not that hard to write, but it IS a pain that it's the only way that I've found to check for alpha.\"\n\t\thttp://www.gamedev.net/community/forums/topic.asp?topic_id=177475\n\n\t\tUPDATE: worst... on linux/opengl, it generates random alpha values\n\t\tif we use alpha dxtc1 by default. So I only to that for windows\n\t\tand leave the old test on linux\n\n\t\tkervala: some used textures don't have an alpha channel and they are\n\t\t(very) bad rendered with this fix\tso we have to deactivate it the for moment\n*/\n\n//#ifdef NL_OS_WINDOWS\n//\tif(PixelFormat==DXTC1) //AlphaBitDepth\n//\t{\n//\t\tPixelFormat = DXTC1Alpha;\n//\t}\n//#else\n\tif(PixelFormat==DXTC1 && _DDSSurfaceDesc[21]>0) //AlphaBitDepth\n\t{\n\t\tPixelFormat = DXTC1Alpha;\n\t}\n//#endif\n\n\tif(PixelFormat!= DXTC1 && PixelFormat!= DXTC1Alpha && PixelFormat!= DXTC3 && PixelFormat!= DXTC5)\n\t{\n\t\tdelete [] _DDSSurfaceDesc;\n\t\tthrow EDDSBadHeader();\n\t}\n\n\t// compute the min power of 2 between width and height\n\tuint\tminSizeLevel= min(_Width, _Height);\n\tminSizeLevel= getPowerOf2(minSizeLevel);\n\n\t//------------- manage mipMapSkip\n\tif(_MipMapCount>1 && mipMapSkip>0 && minSizeLevel>2)\n\t{\n\t\t// Keep at least the level where width and height are at least 4.\n\t\tmipMapSkip= min(mipMapSkip, minSizeLevel-2);\n\t\t// skip any mipmap\n\t\tuint\tseekSize= 0;\n\t\twhile(mipMapSkip>0 && _MipMapCount>1)\n\t\t{\n\t\t\t// raise to next multiple of 4\n\t\t\tuint32 wtmp= (_Width+3)&(~3);\n\t\t\tuint32 htmp= (_Height+3)&(~3);\n\t\t\twtmp= max(wtmp, uint32(4));\n\t\t\thtmp= max(htmp, uint32(4));\n\n\t\t\tuint32 mipMapSz;\n\t\t\tif(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)\n\t\t\t\tmipMapSz = wtmp*htmp/2;\n\t\t\telse\n\t\t\t\tmipMapSz = wtmp*htmp;\n\n\t\t\t// add to how many to skip\n\t\t\tseekSize+= mipMapSz;\n\n\t\t\t// Size of final bitmap is reduced.\n\t\t\t_Width>>=1;\n\t\t\t_Height>>=1;\n\t\t\t_MipMapCount--;\n\t\t\tmipMapSkip--;\n\t\t}\n\t\t// skip data in file\n\t\tif(seekSize>0)\n\t\t{\n\t\t\tif(!f.seek(seekSize, IStream::current))\n\t\t\t{\n\t\t\t\tdelete [] _DDSSurfaceDesc;\n\t\t\t\tthrow ESeekFailed();\n\t\t\t}\n\t\t}\n\n\t}\n\n\t//------------- preload all the mipmaps (one serialBuffer() is faster)\n\tuint32 w = _Width;\n\tuint32 h = _Height;\n\tuint32\ttotalSize= 0;\n\n\tuint8\tm;\n\tfor(m= 0; m<_MipMapCount; m++)\n\t{\n\t\t// raise to next multiple of 4\n\t\tuint32 wtmp= (w+3)&(~3);\n\t\tuint32 htmp= (h+3)&(~3);\n\t\twtmp= max(wtmp, uint32(4));\n\t\thtmp= max(htmp, uint32(4));\n\n\t\tuint32 mipMapSz;\n\t\tif(PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha)\n\t\t\tmipMapSz = wtmp*htmp/2;\n\t\telse\n\t\t\tmipMapSz = wtmp*htmp;\n\n\n\t\t_Data[m].resize(mipMapSz);\n\t\ttotalSize+= mipMapSz;\n\n\t  \tw = (w+1)/2;\n\t\th = (h+1)/2;\n\t}\n\n\t// Read all the data in one block.\n\tvector<uint8>\tpixData;\n\tpixData.resize(totalSize);\n\tf.serialBuffer(&(*pixData.begin()), totalSize);\n\n\n\t//------------- reading mipmap levels from pixData\n\n\tuint32 pixIndex= 0;\n\n\tfor(m= 0; m<_MipMapCount; m++)\n\t{\n\t\tuint32\tmipMapSz= _Data[m].size();\n\t\tmemcpy(_Data[m].getPtr(), &(pixData[pixIndex]), mipMapSz);\n\t\tpixIndex+= mipMapSz;\n\t}\n\n\t//------------- End\n\n\tdelete [] _DDSSurfaceDesc;\n\n\tswitch(PixelFormat)\n\t{\n\t\tcase DXTC1  : return 24;\n\t\tcase DXTC1Alpha : return 32;\n\t\tcase DXTC3  : return 32;\n\t\tcase DXTC5  : return 32;\n\t\tdefault  : break;\n\t}\n\n\treturn 0;\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToDXTC5\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToDXTC5()\n{\n\t/* Yoyo: RGB encoding for DXTC1 and DXTC5/3 are actually different!!\n\t\tDXTC3/5 don't rely on sign of color0>color1 to setup special encoding (ie use a special compression for Black)\n\t\tSince this can arise if the src is DXTC1 , we can't simply compress it into DXTC5 without doing a\n\t\theavy compression...\n\t\t(the inverse is false: DXTC5 to DXTC1 is possible, with maybe swap color0/color1 and bits).\n\t*/\n\n\treturn false;\n\n/*\tuint32 i,j;\n\n\tif(PixelFormat!=DXTC1) return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(2*_Data[m].size());\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=8)\n\t\t{\n\t\t\t//64 bits alpha\n\t\t\tfor(j=0; j<8; j++)\n\t\t\t{\n\t\t\t\tdataTmp[dstId++]= 255;\n\t\t\t}\n\n\t\t\t//64 bits RGB\n\t\t\tfor(j=0; j<8; j++)\n\t\t\t{\n\t\t\t\tdataTmp[dstId++]= _Data[m][i+j];\n\t\t\t}\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = DXTC5;\n\treturn true;\n*/\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tluminanceToRGBA()\n\\*-------------------------------------------------------------------*/\nbool CBitmap::luminanceToRGBA()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()*4);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i++)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= 255;\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaToRGBA()\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaToRGBA()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()*4);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i++)\n\t\t{\n\t\t\tdataTmp[dstId++]= 255;\n\t\t\tdataTmp[dstId++]= 255;\n\t\t\tdataTmp[dstId++]= 255;\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaLuminanceToRGBA()\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaLuminanceToRGBA()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()*2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=2)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= _Data[m][i+1];\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\trgbaToAlphaLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::rgbaToAlphaLuminance()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()/2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=4)\n\t\t{\n\t\t\tdataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;\n\t\t\tdataTmp[dstId++]= _Data[m][i+3];\n\t\t}\n\t\tNLMISC::contReset(_Data[m]);\n\t\t_Data[m].resize(0);\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = AlphaLuminance;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tluminanceToAlphaLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::luminanceToAlphaLuminance()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()*2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i++)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t\tdataTmp[dstId++]= 255;\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = AlphaLuminance;\n\treturn true;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaToAlphaLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaToAlphaLuminance()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()*2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i++)\n\t\t{\n\t\t\tdataTmp[dstId++]= 0;\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = AlphaLuminance;\n\treturn true;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\trgbaToLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::rgbaToLuminance()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()/4);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=4)\n\t\t{\n\t\t\tdataTmp[dstId++]= (_Data[m][i]*77 + _Data[m][i+1]*150 + _Data[m][i+2]*28)/255;\n\t\t}\n\t\tNLMISC::contReset(_Data[m]);\n\t\t_Data[m].resize(0);\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = Luminance;\n\treturn true;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaToLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaToLuminance()\n{\n\tif(_Width*_Height == 0)  return false;\n\n\tPixelFormat = Luminance;\n\treturn true;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaLuminanceToLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaLuminanceToLuminance()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()/2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=2)\n\t\t{\n\t\t\tdataTmp[dstId++]= 0;\n\t\t\tdataTmp[dstId++]= 0;\n\t\t\tdataTmp[dstId++]= 0;\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t}\n\t\tNLMISC::contReset(_Data[m]);\n\t\t_Data[m].resize(0);\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = Luminance;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\trgbaToAlpha\n\\*-------------------------------------------------------------------*/\nbool CBitmap::rgbaToAlpha()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()/4);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=4)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i+3];\n\t\t}\n\t\tNLMISC::contReset(_Data[m]);\n\t\t_Data[m].resize(0);\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = Alpha;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tluminanceToAlpha\n\\*-------------------------------------------------------------------*/\nbool CBitmap::luminanceToAlpha()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size());\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i++)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i];\n\t\t}\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = Alpha;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\talphaLuminanceToAlpha\n\\*-------------------------------------------------------------------*/\nbool CBitmap::alphaLuminanceToAlpha()\n{\n\tuint32 i;\n\n\tif(_Width*_Height == 0)  return false;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tCObjectVector<uint8> dataTmp;\n\t\tdataTmp.resize(_Data[m].size()/2);\n\t\tuint\tdstId= 0;\n\n\t\tfor(i=0; i<_Data[m].size(); i+=2)\n\t\t{\n\t\t\tdataTmp[dstId++]= _Data[m][i+1];\n\t\t}\n\t\tNLMISC::contReset(_Data[m]);\n\t\t_Data[m].resize(0);\n\t\t_Data[m] = dataTmp;\n\t}\n\tPixelFormat = Alpha;\n\treturn true;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToLuminance()\n{\n\tswitch(PixelFormat)\n\t{\n\t\tcase RGBA :\n\t\t\treturn rgbaToLuminance();\n\t\t\tbreak;\n\n\t\tcase Luminance :\n\t\t\treturn true;\n\t\t\tbreak;\n\n\t\tcase Alpha :\n\t\t\treturn alphaToLuminance();\n\t\t\tbreak;\n\n\t\tcase AlphaLuminance :\n\t\t\treturn alphaLuminanceToLuminance();\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\treturn false;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToAlpha\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToAlpha()\n{\n\tswitch(PixelFormat)\n\t{\n\t\tcase RGBA :\n\t\t\treturn rgbaToAlpha();\n\t\t\tbreak;\n\n\t\tcase Luminance :\n\t\t\treturn luminanceToAlpha();\n\t\t\tbreak;\n\n\t\tcase Alpha :\n\t\t\treturn true;\n\t\t\tbreak;\n\n\t\tcase AlphaLuminance :\n\t\t\treturn alphaLuminanceToAlpha();\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\treturn false;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToAlphaLuminance\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToAlphaLuminance()\n{\n\tswitch(PixelFormat)\n\t{\n\t\tcase RGBA :\n\t\t\treturn rgbaToAlphaLuminance();\n\t\t\tbreak;\n\n\t\tcase Luminance :\n\t\t\treturn luminanceToAlphaLuminance();\n\t\t\tbreak;\n\n\t\tcase Alpha :\n\t\t\treturn alphaToAlphaLuminance();\n\t\t\tbreak;\n\n\t\tcase AlphaLuminance :\n\t\t\treturn true;\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\treturn false;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToRGBA\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToRGBA()\n{\n\tswitch(PixelFormat)\n\t{\n\t\tcase DXTC1 :\n\t\t\treturn decompressDXT1(false);\n\t\t\tbreak;\n\n\t\tcase DXTC1Alpha :\n\t\t\treturn decompressDXT1(true);\n\t\t\tbreak;\n\n\t\tcase DXTC3 :\n\t\t\treturn decompressDXT3();\n\t\t\tbreak;\n\n\t\tcase DXTC5 :\n\t\t\treturn decompressDXT5();\n\t\t\tbreak;\n\n\t\tcase Luminance :\n\t\t\treturn luminanceToRGBA();\n\t\t\tbreak;\n\n\t\tcase Alpha :\n\t\t\treturn alphaToRGBA();\n\t\t\tbreak;\n\n\t\tcase AlphaLuminance :\n\t\t\treturn alphaLuminanceToRGBA();\n\t\t\tbreak;\n\t\tcase RGBA:\n\t\t\treturn true;\n\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\treturn false;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tconvertToType\n\\*-------------------------------------------------------------------*/\nbool CBitmap::convertToType(CBitmap::TType type)\n{\n\tif(PixelFormat==type) return true;\n\n\tswitch(type)\n\t{\n\t\tcase RGBA :\n\t\t\treturn convertToRGBA();\n\t\t\tbreak;\n\n\t\tcase DXTC5 :\n\t\t\treturn convertToDXTC5();\n\t\t\tbreak;\n\n\t\tcase Luminance :\n\t\t\treturn convertToLuminance();\n\t\t\tbreak;\n\n\t\tcase Alpha :\n\t\t\treturn convertToAlpha();\n\t\t\tbreak;\n\n\t\tcase AlphaLuminance :\n\t\t\treturn convertToAlphaLuminance();\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\treturn false;\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tdecompressDXT1\n\\*-------------------------------------------------------------------*/\nbool CBitmap::decompressDXT1(bool alpha)\n{\n\tuint32 i,j,k;\n\tNLMISC::CRGBA\tc[4];\n\tCObjectVector<uint8> dataTmp[MAX_MIPMAP];\n\n\tuint32 width= _Width;\n\tuint32 height= _Height;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tuint32 wtmp, htmp;\n\t\tif(width<4)\n\t\t\twtmp = 4;\n\t\telse\n\t\t\twtmp = width;\n\t\tif(height < 4)\n\t\t\thtmp = 4;\n\t\telse\n\t\t\thtmp = height;\n\t\tuint32 mipMapSz = wtmp*htmp*4;\n\t\tdataTmp[m].resize(mipMapSz);\n\t\tif(dataTmp[m].size()<mipMapSz)\n\t\t{\n\t\t\tthrow EAllocationFailure();\n\t\t}\n\t\tuint32 wBlockCount= wtmp/4;\n\n\n\n\t\tfor(i=0; i < _Data[m].size(); i+=8)\n\t\t{\n\t\t\tuint16 color0;\n\t\t\tuint16 color1;\n\t\t\tuint32 bits;\n\t\t\tmemcpy(&color0,&_Data[m][i],2);\n\t\t\tmemcpy(&color1,&_Data[m][i+2],2);\n\t\t\tmemcpy(&bits,&_Data[m][i+4],4);\n\n\t\t\tuncompress(color0,c[0]);\n\t\t\tuncompress(color1,c[1]);\n\n\t\t\tif (alpha)\n\t\t\t{\n\t\t\t\tc[0].A= 0;\n\t\t\t\tc[1].A= 0;\n\t\t\t\tc[2].A= 0;\n\t\t\t\tc[3].A= 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tc[0].A= 255;\n\t\t\t\tc[1].A= 255;\n\t\t\t\tc[2].A= 255;\n\t\t\t\tc[3].A= 255;\n\t\t\t}\n\n\t\t\tif(color0>color1)\n\t\t\t{\n\t\t\t\tc[2].blendFromui(c[0],c[1],85);\n\t\t\t\tif(alpha) c[2].A= 255;\n\n\t\t\t\tc[3].blendFromui(c[0],c[1],171);\n\t\t\t\tif(alpha) c[3].A= 255;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tc[2].blendFromui(c[0],c[1],128);\n\t\t\t\tif(alpha) c[2].A= 255;\n\n\t\t\t\tc[3].set(0,0,0,0);\n\t\t\t}\n\n\t\t\t// computing the 16 RGBA of the block\n\n\t\t\tuint32 blockNum= i/8; //(64 bits)\n\t\t\t// <previous blocks in above lines> * 4 (rows) * _Width (columns) + 4pix*4rgba*<same line previous blocks>\n\t\t\tuint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);\n\t\t\tfor(j=0; j<4; j++)\n\t\t\t{\n\t\t\t\tfor(k=0; k<4; k++)\n\t\t\t\t{\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= c[bits&3].A;\n\t\t\t\t\tbits>>=2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Copy result into the mipmap level.\n\t\tif(wtmp==width && htmp==height)\n\t\t{\n\t\t\t// For mipmaps level >4 pixels.\n\t\t\t_Data[m]= dataTmp[m];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// For last mipmaps, level <4 pixels.\n\t\t\t_Data[m].resize(width*height*4);\n\t\t\tCRGBA\t*src= (CRGBA*)&dataTmp[m][0];\n\t\t\tCRGBA\t*dst= (CRGBA*)&_Data[m][0];\n\t\t\tuint\tx,y;\n\t\t\tfor(y=0;y<height;y++)\n\t\t\t{\n\t\t\t\tfor(x=0;x<width;x++)\n\t\t\t\t\tdst[y*width+x]= src[y*wtmp+x];\n\t\t\t}\n\t\t}\n\n\t\t// Next mipmap size.\n\t\twidth = (width+1)/2;\n\t\theight = (height+1)/2;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tdecompressDXT3\n\\*-------------------------------------------------------------------*/\nbool CBitmap::decompressDXT3()\n{\n\tuint32 i,j,k;\n\tNLMISC::CRGBA\tc[4];\n\tCObjectVector<uint8> dataTmp[MAX_MIPMAP];\n\n\tuint32 width= _Width;\n\tuint32 height= _Height;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tuint32 wtmp, htmp;\n\t\tif(width<4)\n\t\t\twtmp = 4;\n\t\telse\n\t\t\twtmp = width;\n\t\tif(height < 4)\n\t\t\thtmp = 4;\n\t\telse\n\t\t\thtmp = height;\n\t\tuint32 mipMapSz = wtmp*htmp*4;\n\t\tdataTmp[m].resize(mipMapSz);\n\t\tif(dataTmp[m].size()<mipMapSz)\n\t\t{\n\t\t\tthrow EAllocationFailure();\n\t\t}\n\t\tuint32 wBlockCount= wtmp/4;\n\n\n\t\tfor(i=0; i < _Data[m].size(); i+=16)\n\t\t{\n\t\t\tuint8 alpha[16];\n\t\t\tuint64 alphatmp;\n\t\t\tmemcpy(&alphatmp,&_Data[m][i],8);\n\n\t\t\tfor(j=0; j<16; j++)\n\t\t\t{\n\t\t\t\tuint8\ta= (uint8)(alphatmp&15);\n\t\t\t\t// expand to 0-255.\n\t\t\t\talpha[j]= a+(a<<4);\n\t\t\t\talphatmp>>=4;\n\t\t\t}\n\n\n\t\t\tuint16 color0;\n\t\t\tuint16 color1;\n\t\t\tuint32 bits;\n\t\t\tmemcpy(&color0,&_Data[m][i+8],2);\n\t\t\tmemcpy(&color1,&_Data[m][i+10],2);\n\t\t\tmemcpy(&bits,&_Data[m][i+12],4);\n\n\t\t\tuncompress(color0,c[0]);\n\t\t\tuncompress(color1,c[1]);\n\n\t\t\t// ignore color0>color1 for DXT3 and DXT5.\n\t\t\tc[2].blendFromui(c[0],c[1],85);\n\t\t\tc[3].blendFromui(c[0],c[1],171);\n\n\t\t\t// computing the 16 RGBA of the block\n\n\t\t\tuint32 blockNum= i/16; //(128 bits)\n\t\t\t// <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*4rgba*<same line previous blocks>\n\t\t\tuint32 pixelsCount= 4*(blockNum/wBlockCount)*wtmp*4 + 4*4*(blockNum%wBlockCount);\n\t\t\tfor(j=0; j<4; j++)\n\t\t\t{\n\t\t\t\tfor(k=0; k<4; k++)\n\t\t\t\t{\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k]= c[bits&3].R;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+1]= c[bits&3].G;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+2]= c[bits&3].B;\n\t\t\t\t\tdataTmp[m][pixelsCount + j*wtmp*4 + 4*k+3]= alpha[4*j+k];\n\t\t\t\t\tbits>>=2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Copy result into the mipmap level.\n\t\tif(wtmp==width && htmp==height)\n\t\t{\n\t\t\t// For mipmaps level >4 pixels.\n\t\t\t_Data[m]= dataTmp[m];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// For last mipmaps, level <4 pixels.\n\t\t\t_Data[m].resize(width*height*4);\n\t\t\tCRGBA\t*src= (CRGBA*)&dataTmp[m][0];\n\t\t\tCRGBA\t*dst= (CRGBA*)&_Data[m][0];\n\t\t\tuint\tx,y;\n\t\t\tfor(y=0;y<height;y++)\n\t\t\t{\n\t\t\t\tfor(x=0;x<width;x++)\n\t\t\t\t\tdst[y*width+x]= src[y*wtmp+x];\n\t\t\t}\n\t\t}\n\n\t\t// Next mipmap size.\n\t\twidth = (width+1)/2;\n\t\theight = (height+1)/2;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tdecompressDXT5\n\\*-------------------------------------------------------------------*/\nbool CBitmap::decompressDXT5()\n{\n\tuint32 i,j,k;\n\tNLMISC::CRGBA\tc[4];\n\tCObjectVector<uint8> dataTmp[MAX_MIPMAP];\n\n\tuint32 width= _Width;\n\tuint32 height= _Height;\n\n\tfor(uint8 m= 0; m<_MipMapCount; m++)\n\t{\n\t\tuint32 wtmp, htmp;\n\t\tif(width<4)\n\t\t\twtmp = 4;\n\t\telse\n\t\t\twtmp = width;\n\t\tif(height < 4)\n\t\t\thtmp = 4;\n\t\telse\n\t\t\thtmp = height;\n\t\tuint32 mipMapSz = wtmp*htmp*4;\n\t\tdataTmp[m].resize(mipMapSz);\n\t\tif(dataTmp[m].size()<mipMapSz)\n\t\t{\n\t\t\tthrow EAllocationFailure();\n\t\t}\n\t\tuint32 wBlockCount= wtmp/4;\n\n\n\n\t\tfor(i=0; i < _Data[m].size(); i+=16)\n\t\t{\n\t\t\tuint64 bitsAlpha;\n\t\t\tmemcpy(&bitsAlpha,&_Data[m][i],8);\n\t\t\tbitsAlpha>>= 16;\n\n\t\t\tuint32 alpha[8];\n\t\t\talpha[0]= _Data[m][i+0];\n\t\t\talpha[1]= _Data[m][i+1];\n\n\t\t\tif(alpha[0]>alpha[1])\n\t\t\t{\n\t\t\t\talpha[2]= blend(alpha[0], alpha[1], 219);\n\t\t\t\talpha[3]= blend(alpha[0], alpha[1], 183);\n\t\t\t\talpha[4]= blend(alpha[0], alpha[1], 146);\n\t\t\t\talpha[5]= blend(alpha[0], alpha[1], 110);\n\t\t\t\talpha[6]= blend(alpha[0], alpha[1], 73);\n\t\t\t\talpha[7]= blend(alpha[0], alpha[1], 37);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\talpha[2]= blend(alpha[0], alpha[1], 204);\n\t\t\t\talpha[3]= blend(alpha[0], alpha[1], 154);\n\t\t\t\talpha[4]= blend(alpha[0], alpha[1], 102);\n\t\t\t\talpha[5]= blend(alpha[0], alpha[1], 51);\n\t\t\t\talpha[6]= 0;\n\t\t\t\talpha[7]= 255;\n\t\t\t}\n\n\t\t\tuint8 codeAlpha[16];\n\t\t\tfor(j=0; j<16; j++)\n\t\t\t{\n\t\t\t\tcodeAlpha[j] = (uint8)(bitsAlpha & 7);\n\t\t\t\tbitsAlpha>>=3;\n\t\t\t}\n\n\n\t\t\tuint16 color0;\n\t\t\tuint16 color1;\n\t\t\tuint32 bits;\n\t\t\tmemcpy(&color0,&_Data[m][i+8],2);\n\t\t\tmemcpy(&color1,&_Data[m][i+10],2);\n\t\t\tmemcpy(&bits,&_Data[m][i+12],4);\n\n\t\t\tuncompress(color0,c[0]);\n\t\t\tuncompress(color1,c[1]);\n\n\t\t\t// ignore color0>color1 for DXT3 and DXT5.\n\t\t\tc[2].blendFromui(c[0],c[1],85);\n\t\t\tc[3].blendFromui(c[0],c[1],171);\n\n\t\t\t// computing the 16 RGBA of the block\n\n\t\t\tuint32 blockNum= i/16; //(128 bits)\n\n\t\t\t// <previous blocks in above lines> * 4 (rows) * wtmp (columns) + 4pix*<same line previous blocks>\n\t\t\tuint32 pixelsCount= (blockNum/wBlockCount)*wtmp*4 + 4*(blockNum%wBlockCount);\n\t\t\t// *sizeof(RGBA)\n\t\t\tpixelsCount*=4;\n\t\t\tfor(j=0; j<4; j++)\n\t\t\t{\n\t\t\t\tfor(k=0; k<4; k++)\n\t\t\t\t{\n\t\t\t\t\tdataTmp[m][pixelsCount + (j*wtmp+k)*4 +0]= c[bits&3].R;\n\t\t\t\t\tdataTmp[m][pixelsCount + (j*wtmp+k)*4 +1]= c[bits&3].G;\n\t\t\t\t\tdataTmp[m][pixelsCount + (j*wtmp+k)*4 +2]= c[bits&3].B;\n\t\t\t\t\tdataTmp[m][pixelsCount + (j*wtmp+k)*4 +3]= (uint8) alpha[codeAlpha[4*j+k]];\n\t\t\t\t\tbits>>=2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\n\t\t// Copy result into the mipmap level.\n\t\tif(wtmp==width && htmp==height)\n\t\t{\n\t\t\t// For mipmaps level >4 pixels.\n\t\t\t_Data[m]= dataTmp[m];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// For last mipmaps, level <4 pixels.\n\t\t\t_Data[m].resize(width*height*4);\n\t\t\tCRGBA\t*src= (CRGBA*)&dataTmp[m][0];\n\t\t\tCRGBA\t*dst= (CRGBA*)&_Data[m][0];\n\t\t\tuint\tx,y;\n\t\t\tfor(y=0;y<height;y++)\n\t\t\t{\n\t\t\t\tfor(x=0;x<width;x++)\n\t\t\t\t\tdst[y*width+x]= src[y*wtmp+x];\n\t\t\t}\n\t\t}\n\n\t\t// Next mipmap size.\n\t\twidth = (width+1)/2;\n\t\theight = (height+1)/2;\n\t}\n\tPixelFormat = RGBA;\n\treturn true;\n\n}\n\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tblend\n\\*-------------------------------------------------------------------*/\nuint32 CBitmap::blend(uint32 &n0, uint32 &n1, uint32 coef0)\n{\n\tint\ta0 = coef0;\n\tint\ta1 = 256-a0;\n\treturn ((n0*a0 + n1*a1) >>8);\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tuncompress\n\\*-------------------------------------------------------------------*/\ninline void CBitmap::uncompress(uint16 color, NLMISC::CRGBA &r)\n{\n\tr.A= 0;\n\tr.R= ((color>>11)&31) << 3; r.R+= r.R>>5;\n\tr.G= ((color>>5)&63) << 2;  r.G+= r.G>>6;\n\tr.B= ((color)&31) << 3;     r.B+= r.B>>5;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tgetWidth\n\\*-------------------------------------------------------------------*/\nuint32 CBitmap::getWidth(uint32 mipMap) const\n{\n\tif(mipMap==0) return _Width;\n\n\tuint32 w = _Width;\n\tuint32 h = _Height;\n\tuint32 m = 0;\n\n\tdo\n\t{\n\t\tm++;\n\t\tw = (w+1)/2;\n\t\th = (h+1)/2;\n\t\tif(m==mipMap) return w;\n\t}\n\twhile(w!=1 || h!=1);\n\n\treturn 0;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tgetHeight\n\\*-------------------------------------------------------------------*/\nuint32 CBitmap::getHeight(uint32 mipMap) const\n{\n\tif(mipMap==0) return _Height;\n\n\tuint32 w = _Width;\n\tuint32 h = _Height;\n\tuint32 m = 0;\n\n\tdo\n\t{\n\t\tm++;\n\t\tw = (w+1)/2;\n\t\th = (h+1)/2;\n\t\tif(m==mipMap) return h;\n\t}\n\twhile(w!=1 || h!=1);\n\n\treturn 0;\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tgetSize\n\\*-------------------------------------------------------------------*/\nuint32 CBitmap::getSize(uint32 numMipMap) const\n{\n\treturn getHeight(numMipMap)*getWidth(numMipMap);\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tbuildMipMaps\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::buildMipMaps()\n{\n\tuint32 i,j;\n\n\tif(PixelFormat!=RGBA) return;\n\tif(_MipMapCount!=1) return;\n\tif(!NLMISC::isPowerOf2(_Width)) return;\n\tif(!NLMISC::isPowerOf2(_Height)) return;\n\n\tuint32 w = _Width;\n\tuint32 h = _Height;\n\n\twhile(w>1 || h>1)\n\t{\n\t\tuint32 precw = w;\n\t\tuint32 prech = h;\n\t\tw = (w+1)/2;\n\t\th = (h+1)/2;\n\t\tuint32\tmulw= precw/w;\n\t\tuint32\tmulh= prech/h;\n\n\t\t_Data[_MipMapCount].resize(w*h*4);\n\n\t\tNLMISC::CRGBA *pRgba = (NLMISC::CRGBA*)&_Data[_MipMapCount][0];\n\t\tNLMISC::CRGBA *pRgbaPrev = (NLMISC::CRGBA*)&_Data[_MipMapCount-1][0];\n\t\tfor(i=0; i<h; i++)\n\t\t{\n\t\t\tsint\ti0= mulh*i;\n\t\t\tsint\ti1= mulh*i+1;\n\t\t\tif(mulh==1)\n\t\t\t\ti1=i0;\n\t\t\ti0*=precw;\n\t\t\ti1*=precw;\n\t\t\tfor(j=0; j<w; j++)\n\t\t\t{\n\t\t\t\tsint\tj0= mulw*j;\n\t\t\t\tsint\tj1= mulw*j+1;\n\t\t\t\tif(mulw==1)\n\t\t\t\t\tj1=j0;\n\t\t\t\tCRGBA\t&c0= pRgbaPrev[i0+j0];\n\t\t\t\tCRGBA\t&c1= pRgbaPrev[i0+j1];\n\t\t\t\tCRGBA\t&c2= pRgbaPrev[i1+j0];\n\t\t\t\tCRGBA\t&c3= pRgbaPrev[i1+j1];\n\t\t\t\tpRgba[i*w + j].R = (c0.R +\n\t\t\t\t\t\t\t\t\tc1.R +\n\t\t\t\t\t\t\t\t\tc2.R +\n\t\t\t\t\t\t\t\t\tc3.R + 2 ) /4;\n\t\t\t\tpRgba[i*w + j].G = (c0.G +\n\t\t\t\t\t\t\t\t\tc1.G +\n\t\t\t\t\t\t\t\t\tc2.G +\n\t\t\t\t\t\t\t\t\tc3.G + 2 ) /4;\n\t\t\t\tpRgba[i*w + j].B = (c0.B +\n\t\t\t\t\t\t\t\t\tc1.B +\n\t\t\t\t\t\t\t\t\tc2.B +\n\t\t\t\t\t\t\t\t\tc3.B + 2 ) /4;\n\t\t\t\tpRgba[i*w + j].A = (c0.A +\n\t\t\t\t\t\t\t\t\tc1.A +\n\t\t\t\t\t\t\t\t\tc2.A +\n\t\t\t\t\t\t\t\t\tc3.A + 2 ) /4;\n\t\t\t}\n\t\t}\n\n\t\t_MipMapCount++;\n\t}\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tcomputeNeededMipMapCount\n\\*-------------------------------------------------------------------*/\nuint32 CBitmap::computeNeededMipMapCount() const\n{\n\tif(_MipMapCount == 0) return 0;\n\tif(!NLMISC::isPowerOf2(_Width)) return 1;\n\tif(!NLMISC::isPowerOf2(_Height)) return 1;\n\n\tuint32 mipMapCount = 1;\n\tuint32 w = _Width;\n\tuint32 h = _Height;\n\n\twhile(w>1 || h>1)\n\t{\n\t\tw = (w+1)/2;\n\t\th = (h+1)/2;\n\t\t++mipMapCount;\n\t}\n\treturn mipMapCount;\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\treleaseMipMaps\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::releaseMipMaps()\n{\n\tif(_MipMapCount<=1) return;\n\n\t_MipMapCount=1;\n\tfor(sint i=1;i<MAX_MIPMAP;i++)\n\t{\n\t\tNLMISC::contReset(_Data[i]);\n\t}\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tresample\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::resample(sint32 nNewWidth, sint32 nNewHeight)\n{\n\tnlassert(PixelFormat == RGBA);\n\tbool needRebuild = false;\n\n\t// Deleting mipmaps\n\t//logResample(\"Resample: 10\");\n\tif(_MipMapCount>1)\n\t\tneedRebuild = true;\n\treleaseMipMaps();\n\t//logResample(\"Resample: 20\");\n\n\tif(nNewWidth==0 || nNewHeight==0)\n\t{\n\t\t_Width = _Height = 0;\n\t\t//logResample(\"Resample: 25\");\n\t\treturn;\n\t}\n\n\t//logResample(\"Resample: 30\");\n\tCObjectVector<uint8> pDestui;\n\tpDestui.resize(nNewWidth*nNewHeight*4);\n\t//logResample(\"Resample: 40\");\n\tNLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];\n\t//logResample(\"Resample: 50\");\n\n\tresamplePicture32 ((NLMISC::CRGBA*)&_Data[0][0], pDestRgba, _Width, _Height, nNewWidth, nNewHeight);\n\t//logResample(\"Resample: 60\");\n\n\tNLMISC::contReset(_Data[0]); // free memory\n\t//logResample(\"Resample: 70\");\n\n\t_Data[0] =  pDestui;\n\t//logResample(\"Resample: 80\");\n\t_Width= nNewWidth;\n\t_Height= nNewHeight;\n\n\t// Rebuilding mipmaps\n\t//logResample(\"Resample: 90\");\n\tif(needRebuild)\n\t{\n\t\tbuildMipMaps();\n\t\t//logResample(\"Resample: 95\");\n\t}\n\t//logResample(\"Resample: 100\");\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tresize\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::resize (sint32 nNewWidth, sint32 nNewHeight, TType newType, bool resetTo0)\n{\n\t// Deleting mipmaps\n\treleaseMipMaps();\n\n\t// Change type of bitmap ?\n\tif (newType!=DonTKnow)\n\t\tPixelFormat=newType;\n\n\t_Width = nNewWidth;\n\t_Height = nNewHeight;\n\n\t// resize the level 0 only.\n\tresizeMipMap(0, nNewWidth, nNewHeight, resetTo0);\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tresizeMipMap\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::resizeMipMap (uint32 numMipMap, sint32 nNewWidth, sint32 nNewHeight, bool resetTo0)\n{\n\tnlassert(numMipMap<MAX_MIPMAP);\n\n\t// free memory\n\tNLMISC::contReset(_Data[numMipMap]);\n\n\t// DXTC compressed??\n\t//bool\tisDXTC= PixelFormat==DXTC1 || PixelFormat==DXTC1Alpha || PixelFormat==DXTC3 || PixelFormat==DXTC5;\n\t// if yes, must round up width and height to 4, for allocation\n\tnNewWidth= 4*((nNewWidth+3)/4);\n\tnNewHeight= 4*((nNewHeight+3)/4);\n\n\t// resize the buffer\n\t_Data[numMipMap].resize (((uint32)(nNewWidth*nNewHeight)*bitPerPixels[PixelFormat])/8);\n\n\t// Fill 0?\n\tif( resetTo0 )\n\t\t_Data[numMipMap].fill(0);\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\treset\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::setMipMapCount(uint32 mmc)\n{\n\t_MipMapCount= uint8(mmc);\n}\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\treset\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::reset(TType type)\n{\n\tfor(uint i=0; i<_MipMapCount; i++)\n\t{\n\t\tNLMISC::contReset(_Data[i]);\n\t\t_Data[i].resize(0);\n\t}\n\t_Width = _Height = 0;\n\t_MipMapCount= 1;\n\n\t// Change pixel format\n\tPixelFormat=type;\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tresamplePicture32\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::resamplePicture32 (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,\n\t\t\t\t\t\t\t\t sint32 nSrcWidth, sint32 nSrcHeight,\n\t\t\t\t\t\t\t\t sint32 nDestWidth, sint32 nDestHeight)\n{\n\t//logResample(\"RP32: 0 pSrc=%p pDest=%p, Src=%d x %d Dest=%d x %d\", pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);\n\tif ((nSrcWidth<=0)||(nSrcHeight<=0)||(nDestHeight<=0)||(nDestHeight<=0))\n\t\treturn;\n\n\t// If we're reducing it by 2, call the fast resample\n\tif (((nSrcHeight / 2) == nDestHeight) && ((nSrcHeight % 2) == 0) &&\n\t\t((nSrcWidth  / 2) == nDestWidth)  && ((nSrcWidth  % 2) == 0))\n\t{\n\t\tresamplePicture32Fast(pSrc, pDest, nSrcWidth, nSrcHeight, nDestWidth, nDestHeight);\n\t\treturn;\n\t}\n\n\tbool bXMag=(nDestWidth>=nSrcWidth);\n\tbool bYMag=(nDestHeight>=nSrcHeight);\n\tbool bXEq=(nDestWidth==nSrcWidth);\n\tbool bYEq=(nDestHeight==nSrcHeight);\n\tstd::vector<NLMISC::CRGBAF> pIterm (nDestWidth*nSrcHeight);\n\n\tif (bXMag)\n\t{\n\t\tfloat fXdelta=(float)(nSrcWidth)/(float)(nDestWidth);\n\t\tNLMISC::CRGBAF *pItermPtr=&*pIterm.begin();\n\t\tsint32 nY;\n\t\tfor (nY=0; nY<nSrcHeight; nY++)\n\t\t{\n\t\t\tconst NLMISC::CRGBA *pSrcLine=pSrc;\n\t\t\tfloat fX=0.f;\n\t\t\tsint32 nX;\n\t\t\tfor (nX=0; nX<nDestWidth; nX++)\n\t\t\t{\n\t\t\t\tfloat fVirgule=fX-(float)floor(fX);\n\t\t\t\tnlassert (fVirgule>=0.f);\n\t\t\t\tNLMISC::CRGBAF vColor;\n\t\t\t\tif (fVirgule>=0.5f)\n\t\t\t\t{\n\t\t\t\t\tif (fX<(float)(nSrcWidth-1))\n\t\t\t\t\t{\n\t\t\t\t\t\tNLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);\n\t\t\t\t\t\tNLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)+1]);\n\t\t\t\t\t\tvColor=vColor1*(1.5f-fVirgule)+vColor2*(fVirgule-0.5f);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tvColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (fX>=1.f)\n\t\t\t\t\t{\n\t\t\t\t\t\tNLMISC::CRGBAF vColor1 (pSrcLine[(sint32)floor(fX)]);\n\t\t\t\t\t\tNLMISC::CRGBAF vColor2 (pSrcLine[(sint32)floor(fX)-1]);\n\t\t\t\t\t\tvColor=vColor1*(0.5f+fVirgule)+vColor2*(0.5f-fVirgule);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tvColor=NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);\n\t\t\t\t}\n\t\t\t\t*(pItermPtr++)=vColor;\n\t\t\t\tfX+=fXdelta;\n\t\t\t}\n\t\t\tpSrc+=nSrcWidth;\n\t\t}\n\t}\n\telse if (bXEq)\n\t{\n\t\tNLMISC::CRGBAF *pItermPtr=&*pIterm.begin();\n\t\tfor (sint32 nY=0; nY<nSrcHeight; nY++)\n\t\t{\n\t\t\tconst NLMISC::CRGBA *pSrcLine=pSrc;\n\t\t\tsint32 nX;\n\t\t\tfor (nX=0; nX<nDestWidth; nX++)\n\t\t\t\t*(pItermPtr++)=NLMISC::CRGBAF (pSrcLine[nX]);\n\t\t\tpSrc+=nSrcWidth;\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble fXdelta=(double)(nSrcWidth)/(double)(nDestWidth);\n\t\tnlassert (fXdelta>1.f);\n\t\tNLMISC::CRGBAF *pItermPtr=&*pIterm.begin();\n\t\tsint32 nY;\n\t\tfor (nY=0; nY<nSrcHeight; nY++)\n\t\t{\n\t\t\tconst NLMISC::CRGBA *pSrcLine=pSrc;\n\t\t\tdouble fX=0.f;\n\t\t\tsint32 nX;\n\t\t\tfor (nX=0; nX<nDestWidth; nX++)\n\t\t\t{\n\t\t\t\tNLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);\n\t\t\t\tdouble fFinal=fX+fXdelta;\n\t\t\t\twhile ((fX<fFinal)&&((sint32)fX!=nSrcWidth))\n\t\t\t\t{\n\t\t\t\t\tdouble fNext=(double)floor (fX)+1.f;\n\t\t\t\t\tif (fNext>fFinal)\n\t\t\t\t\t\tfNext=fFinal;\n\t\t\t\t\tvColor+=((float)(fNext-fX))*NLMISC::CRGBAF (pSrcLine[(sint32)floor(fX)]);\n\t\t\t\t\tfX=fNext;\n\t\t\t\t}\n\t\t\t\tfX = fFinal; // ensure fX == fFinal\n\t\t\t\tvColor/=(float)fXdelta;\n\t\t\t\t*(pItermPtr++)=vColor;\n\t\t\t}\n\t\t\tpSrc+=nSrcWidth;\n\t\t}\n\t}\n\n\tif (bYMag)\n\t{\n\t\tdouble fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);\n\t\tsint32 nX;\n\t\tfor (nX=0; nX<nDestWidth; nX++)\n\t\t{\n\t\t\tdouble fY=0.f;\n\t\t\tsint32 nY;\n\t\t\tfor (nY=0; nY<nDestHeight; nY++)\n\t\t\t{\n\t\t\t\tdouble fVirgule=fY-(double)floor(fY);\n\t\t\t\tnlassert (fVirgule>=0.f);\n\t\t\t\tNLMISC::CRGBAF vColor;\n\t\t\t\tif (fVirgule>=0.5f)\n\t\t\t\t{\n\t\t\t\t\tif (fY<(double)(nSrcHeight-1))\n\t\t\t\t\t{\n\t\t\t\t\t\tNLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];\n\t\t\t\t\t\tNLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))+1)*nDestWidth+nX];\n\t\t\t\t\t\tvColor=vColor1*(1.5f-(float)fVirgule)+vColor2*((float)fVirgule-0.5f);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tvColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (fY>=1.f)\n\t\t\t\t\t{\n\t\t\t\t\t\tNLMISC::CRGBAF vColor1=pIterm[((sint32)floor(fY))*nDestWidth+nX];\n\t\t\t\t\t\tNLMISC::CRGBAF vColor2=pIterm[(((sint32)floor(fY))-1)*nDestWidth+nX];\n\t\t\t\t\t\tvColor=vColor1*(0.5f+(float)fVirgule)+vColor2*(0.5f-(float)fVirgule);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tvColor=pIterm[((sint32)floor(fY))*nDestWidth+nX];\n\t\t\t\t}\n\t\t\t\tpDest[nX+nY*nDestWidth]=vColor;\n\t\t\t\tfY+=fYdelta;\n\t\t\t}\n\t\t}\n\t}\n\telse if (bYEq)\n\t{\n\t\tfor (sint32 nX=0; nX<nDestWidth; nX++)\n\t\t{\n\t\t\tsint32 nY;\n\t\t\tfor (nY=0; nY<nDestHeight; nY++)\n\t\t\t{\n\t\t\t\tpDest[nX+nY*nDestWidth]=pIterm[nY*nDestWidth+nX];\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tdouble fYdelta=(double)(nSrcHeight)/(double)(nDestHeight);\n\t\tnlassert (fYdelta>1.f);\n\t\tsint32 nX;\n\t\tfor (nX=0; nX<nDestWidth; nX++)\n\t\t{\n\t\t\tdouble fY=0.f;\n\t\t\tsint32 nY;\n\t\t\tfor (nY=0; nY<nDestHeight; nY++)\n\t\t\t{\n\t\t\t\tNLMISC::CRGBAF vColor (0.f, 0.f, 0.f, 0.f);\n\t\t\t\tdouble fFinal=fY+fYdelta;\n\t\t\t\twhile ((fY<fFinal)&&((sint32)fY!=nSrcHeight))\n\t\t\t\t{\n\t\t\t\t\tdouble fNext=(double)floor (fY)+1.f;\n\t\t\t\t\tif (fNext>fFinal)\n\t\t\t\t\t\tfNext=fFinal;\n\t\t\t\t\tvColor+=((float)(fNext-fY))*pIterm[((sint32)floor(fY))*nDestWidth+nX];\n\t\t\t\t\tfY=fNext;\n\t\t\t\t}\n\t\t\t\tvColor/=(float)fYdelta;\n\t\t\t\tpDest[nX+nY*nDestWidth]=vColor;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tresamplePicture32Fast\n\\*-------------------------------------------------------------------*/\nvoid CBitmap::resamplePicture32Fast (const NLMISC::CRGBA *pSrc, NLMISC::CRGBA *pDest,\n\t\t\t\t\t\t\t\t\t sint32 nSrcWidth, sint32 nSrcHeight,\n\t\t\t\t\t\t\t\t\t sint32 nDestWidth, sint32 nDestHeight)\n{\n\t// the image is divided by two : 1 pixel in dest = 4 pixels in src\n\t// the resulting pixel in dest is an average of the four pixels in src\n\n\tnlassert(nSrcWidth  % 2 == 0);\n\tnlassert(nSrcHeight % 2 == 0);\n\tnlassert(nSrcWidth  / 2 == nDestWidth);\n\tnlassert(nSrcHeight / 2 == nDestHeight);\n\n\tsint32 x, y, twoX, twoSrcWidthByY;\n\n\tfor (y=0 ; y<nDestHeight ; y++)\n\t{\n\t\ttwoSrcWidthByY = 2*nSrcWidth*y;\n\t\tfor (x=0 ; x<nDestWidth ; x++)\n\t\t{\n\t\t\ttwoX = 2*x;\n\t\t\tpDest[x+y*nDestWidth].avg4( pSrc[twoX   + twoSrcWidthByY             ],\n\t\t\t\t\t\t\t\t\t\tpSrc[twoX   + twoSrcWidthByY + nSrcWidth ],\n\t\t\t\t\t\t\t\t\t\tpSrc[twoX+1 + twoSrcWidthByY             ],\n\t\t\t\t\t\t\t\t\t\tpSrc[twoX+1 + twoSrcWidthByY + nSrcWidth ]);\n\t\t}\n\t}\n}\n\n\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\treadTGA\n\\*-------------------------------------------------------------------*/\nuint8 CBitmap::readTGA( NLMISC::IStream &f)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\n\tif(!f.isReading()) return 0;\n\n\tuint32\t\t\tsize;\n\tuint32\t\t\tx,y;\n\tsint32\t\t\tslsize;\n\tuint8\t\t\t*scanline;\n\tuint8\t\t\tr,g,b;\n\tsint32\t\t\ti,j,k;\n\n\t// TGA file header fields\n\tuint8\tlengthID;\n\tuint8\tcMapType;\n\tuint8\timageType;\n\tuint16\torigin;\n\tuint16\tlength;\n\tuint8\tdepth;\n\tuint16\txOrg;\n\tuint16\tyOrg;\n\tuint16\twidth;\n\tuint16\theight;\n\tuint8\timageDepth;\n\tuint8\tdesc;\n\n\n\t// Determining whether file is in Original or New TGA format\n\n\tbool newTgaFormat;\n\tuint32 extAreaOffset;\n\tuint32 devDirectoryOffset;\n\tchar signature[16];\n\n\tf.seek (0, f.end);\n\tnewTgaFormat = false;\n\tif (f.getPos() >= 26)\n\t{\n\t\tf.seek (-26, f.end);\n\t\tf.serial(extAreaOffset);\n\t\tf.serial(devDirectoryOffset);\n\t\tfor(i=0; i<16; i++)\n\t\t{\n\t\t\tf.serial(signature[i]);\n\t\t}\n\t\tif(strncmp(signature,\"TRUEVISION-XFILE\",16)==0)\n\t\t\tnewTgaFormat = true;\n\t}\n\n\n\n\t// Reading TGA file header\n\tf.seek (0, f.begin);\n\n\tf.serial(lengthID);\n\tf.serial(cMapType);\n\tf.serial(imageType);\n\tf.serial(origin);\n\tf.serial(length);\n\tf.serial(depth);\n\tf.serial(xOrg);\n\tf.serial(yOrg);\n\tf.serial(width);\n\tf.serial(height);\n\tf.serial(imageDepth);\n\tf.serial(desc);\n\n\tif(cMapType!=0)\n\t{\n\t\tnlinfo(\"readTga : color-map not supported\");\n\t}\n\n\tif(lengthID>0)\n\t{\n\t\tuint8\tdummy;\n\t\tfor(i=0; i<lengthID; i++)\n\t\t\tf.serial(dummy);\n\t}\n\n\n\n\t// Reading TGA image data\n\n\t_Width = width;\n\t_Height = height;\n\tsize = _Width * _Height * (imageDepth/8);\n\n\tswitch(imageType)\n\t{\n\t\t// Uncompressed RGB or RGBA\n\t\tcase 2:\n\t\t{\n\t\t\t_Data[0].resize(_Width*_Height*4);\n\t\t\tuint8 upSideDown = ((desc & (1 << 5))==0);\n\t\t\tslsize = _Width * imageDepth / 8;\n\n\t\t\tscanline = new uint8[slsize];\n\t\t\tif(!scanline)\n\t\t\t{\n\t\t\t\tthrow EAllocationFailure();\n\t\t\t}\n\n\t\t\tfor(y=0; y<_Height;y++)\n\t\t\t{\n\t\t\t\t// Serial buffer: more efficient way to load.\n\t\t\t\tf.serialBuffer (scanline, slsize);\n\n\t\t\t\tif(imageDepth==24 || imageDepth==32)\n\t\t\t\t{\n\t\t\t\t\tsint32 mult = 3;\n\t\t\t\t\tif(imageDepth==16)\n\t\t\t\t\t{\n\t\t\t\t\t\tmult = 2;\n\t\t\t\t\t}\n\t\t\t\t\tif(imageDepth==32)\n\t\t\t\t\t{\n\t\t\t\t\t\tmult = 4;\n\t\t\t\t\t}\n\t\t\t\t\tif(imageDepth!=16)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(x=0; x<_Width; x++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// RGB(A)\n\t\t\t\t\t\t\tr = scanline[x*mult+0];\n\t\t\t\t\t\t\tg = scanline[x*mult+1];\n\t\t\t\t\t\t\tb = scanline[x*mult+2];\n\t\t\t\t\t\t\t// Switching to BGR(A)\n\t\t\t\t\t\t\tscanline[x*mult+0] = b;\n\t\t\t\t\t\t\tscanline[x*mult+1] = g;\n\t\t\t\t\t\t\tscanline[x*mult+2] = r;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tk=0;\n\t\t\t\tfor(i=0; i<width; i++)\n\t\t\t\t{\n\t\t\t\t\tif(upSideDown)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(imageDepth==16)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint16 toto = (uint16)scanline[k++];\n\t\t\t\t\t\t\ttoto |= scanline[k++]<<8;\n\t\t\t\t\t\t\tuint _r = toto>>10;\n\t\t\t\t\t\t\tuint _g = (toto>>5)&0x1f;\n\t\t\t\t\t\t\tuint _b = toto&0x1f;\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i] = scanline[k++];\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 1] = scanline[k++];\n\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 2] = scanline[k++];\n\t\t\t\t\t\t\tif(imageDepth==32)\n\t\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 3] = scanline[k++];\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t_Data[0][(height-y-1)*width*4 + 4*i + 3] = 255;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif(imageDepth==16)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint16 toto = (uint16)scanline[k++];\n\t\t\t\t\t\t\ttoto |= scanline[k++]<<8;\n\t\t\t\t\t\t\tint _r = toto>>10;\n\t\t\t\t\t\t\tint _g = toto&(0x3e0)>>5;\n\t\t\t\t\t\t\tint _b = toto&0x1f;\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i] = uint8((_r<<3) | (_r>>2));\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 1] = uint8((_g<<3) | (_g>>2));\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 2] = uint8((_b<<3) | (_b>>2));\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 3] = 255;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i] = scanline[k++];\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 1] = scanline[k++];\n\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 2] = scanline[k++];\n\t\t\t\t\t\t\tif(imageDepth==32)\n\t\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 3] = scanline[k++];\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t_Data[0][y*width*4 + 4*i + 3] = 255;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPixelFormat = RGBA;\n\t\t\tdelete []scanline;\n\t\t};\n\t\tbreak;\n\n\t\t// Uncompressed Grayscale bitmap\n\t\tcase 3:\n\t\t{\n\t\t\t_Data[0].resize(_Width*_Height);\n\t\t\tuint8 upSideDown = ((desc & (1 << 5))==0);\n\t\t\tslsize = _Width;\n\n\t\t\tscanline = new uint8[slsize];\n\t\t\tif(!scanline)\n\t\t\t{\n\t\t\t\tthrow EAllocationFailure();\n\t\t\t}\n\n\t\t\tfor(y=0; y<_Height;y++)\n\t\t\t{\n\t\t\t\t// Serial buffer: more efficient way to load.\n\t\t\t\tf.serialBuffer (scanline, slsize);\n\n\t\t\t\tk=0;\n\t\t\t\tfor(i=0; i<width; i++)\n\t\t\t\t{\n\t\t\t\t\tif(upSideDown)\n\t\t\t\t\t\t_Data[0][(height-y-1)*width + i] = scanline[k++];\n\t\t\t\t\telse\n\t\t\t\t\t\t_Data[0][y*width + i] = scanline[k++];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tPixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;\n\t\t\tdelete []scanline;\n\t\t};\n\t\tbreak;\n\n\t\t// Compressed RGB or RGBA\n\t\tcase 10:\n\t\t{\n\t\t\tuint8 packet;\n\t\t\tuint8 pixel[4];\n\t\t\tuint32 imageSize = width*height;\n\t\t\tuint32 readSize = 0;\n\t\t\tuint8 upSideDown = ((desc & (1 << 5))==0);\n\t\t\t_Data[0].resize(_Width*_Height*4);\n\t\t\tuint\tdstId= 0;\n\n\t\t\twhile(readSize < imageSize)\n\t\t\t{\n\t\t\t\tf.serial(packet);\n\t\t\t\tif((packet & 0x80) > 0) // packet RLE\n\t\t\t\t{\n\t\t\t\t\tfor(i=0; i<imageDepth/8; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tf.serial(pixel[i]);\n\t\t\t\t\t}\n\t\t\t\t\tfor (i=0; i < (packet & 0x7F) + 1; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(imageDepth==32)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[2];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[1];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[3];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(imageDepth==24)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[2];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[1];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t\t\t_Data[0][dstId++]= 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\t// packet Raw\n\t\t\t\t{\n\t\t\t\t\tfor(i=0; i<((packet & 0x7F) + 1); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(j=0; j<imageDepth/8; j++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tf.serial(pixel[j]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(imageDepth==32)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[2];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[1];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[3];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(imageDepth==24)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[2];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[1];\n\t\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t\t\t_Data[0][dstId++]= 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n  \t\t\t\t}\n\t\t\t\treadSize += (packet & 0x7F) + 1;\n\t\t\t}\n\t\t\tPixelFormat = RGBA;\n\n\t\t\tif (upSideDown) flipV();\n\t\t};\n\t\tbreak;\n\n\t\t// Compressed Grayscale bitmap (not tested)\n\t\tcase 11:\n\t\t{\n\t\t\tuint8 packet;\n\t\t\tuint8 pixel[4];\n\t\t\tuint32 imageSize = width*height;\n\t\t\tuint32 readSize = 0;\n\t\t\t_Data[0].resize(_Width*_Height);\n\t\t\tuint\tdstId= 0;\n\n\t\t\twhile(readSize < imageSize)\n\t\t\t{\n\t\t\t\tf.serial(packet);\n\t\t\t\tif((packet & 0x80) > 0) // packet RLE\n\t\t\t\t{\n\t\t\t\t\tf.serial(pixel[0]);\n\t\t\t\t\tfor (i=0; i < (packet & 0x7F) + 1; i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\t// packet Raw\n\t\t\t\t{\n\t\t\t\t\tfor(i=0; i<((packet & 0x7F) + 1); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tf.serial(pixel[0]);\n\t\t\t\t\t\t_Data[0][dstId++]= pixel[0];\n\t\t\t\t\t}\n  \t\t\t\t}\n\t\t\t\treadSize += (packet & 0x7F) + 1;\n\t\t\t}\n\t\t\tPixelFormat = _LoadGrayscaleAsAlpha?Alpha:Luminance;\n\t\t};\n\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn 0;\n\t}\n\n\t_MipMapCount = 1;\n\treturn(imageDepth);\n\n}\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\twriteTGA\n\\*-------------------------------------------------------------------*/\nbool CBitmap::writeTGA( NLMISC::IStream &f, uint32 d, bool upsideDown)\n{\n\tif(f.isReading()) return false;\n\tif (d==0)\n\t{\n\t\tswitch (PixelFormat)\n\t\t{\n\t\tcase RGBA:\n\t\t\td = 32;\n\t\t\tbreak;\n\t\tcase Luminance:\n\t\t\td = 8;\n\t\t\tbreak;\n\t\tcase Alpha:\n\t\t\td = 8;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t;\n\t\t}\n\t}\n\tif(d!=24 && d!=32 && d!=16 && d!=8) return false;\n\tif ((PixelFormat != RGBA)&&(PixelFormat != Alpha)&&(PixelFormat != Luminance)) return false;\n\tif ((PixelFormat == Alpha) && (d != 8)) return false;\n\tif ((PixelFormat == Luminance) && (d != 8)) return false;\n\n\tsint32\ti,j,x,y;\n\tuint8\t* scanline;\n\tuint8\tr,g,b,a;\n\n\tuint8\tlengthID = 0;\n\tuint8\tcMapType = 0;\n\tuint8\timageType = 2;\n\tuint16\torigin = 0;\n\tuint16\tlength = 0;\n\tuint8\tdepth = 0;\n\tuint16\txOrg = 0;\n\tuint16\tyOrg = 0;\n\tuint16\twidth = (uint16)_Width;\n\tuint16\theight = (uint16)_Height;\n\tuint8\timageDepth = (uint8)d;\n\tuint8\tdesc = 0;\n\tif (upsideDown)\n\t\tdesc |= 1<<5;\n\n\tif ((PixelFormat == Alpha) || (PixelFormat == Luminance))\n\t\timageType = 3; // Uncompressed grayscale\n\n\tf.serial(lengthID);\n\tf.serial(cMapType);\n\tf.serial(imageType);\n\tf.serial(origin);\n\tf.serial(length);\n\tf.serial(depth);\n\tf.serial(xOrg);\n\tf.serial(yOrg);\n\tf.serial(width);\n\tf.serial(height);\n\tf.serial(imageDepth);\n\tf.serial(desc);\n\n\tif ((PixelFormat == Alpha)||(PixelFormat == Luminance))\n\t\tscanline = new uint8[width];\n\telse\n\t\tscanline = new uint8[width*4];\n\tif(!scanline)\n\t{\n\t\tthrow EAllocationFailure();\n\t}\n\n\tfor(y=0; y<(sint32)height; y++)\n\t{\n\n\t\tuint32 k=0;\n\t\tif (PixelFormat == Alpha)\n\t\t{\n\t\t\tfor(i=0; i<width; ++i) // Alpha\n\t\t\t{\n\t\t\t\tscanline[k++] = _Data[0][(height-y-1)*width + i];\n\t\t\t}\n\t\t}\n\t\telse if (PixelFormat == Luminance)\n\t\t{\n\t\t\tfor(i=0; i<width; ++i) // Luminance\n\t\t\t{\n\t\t\t\tscanline[k++] = _Data[0][(height-y-1)*width + i];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor(i=0; i<width*4; i+=4) // 4:RGBA\n\t\t\t{\n\t\t\t\tif(d==16)\n\t\t\t\t{\n\t\t\t\t\tfor(j=0; j<(sint32)4; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tscanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfor(j=0; j<(sint32)d/8; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tscanline[k++] = _Data[0][(height-y-1)*width*4 + i + j];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(d==16)\n\t\t{\n\t\t\tfor(x=0; x<(sint32)width; x++)\n\t\t\t{\n\t\t\t\tr = scanline[x*4+0];\n\t\t\t\tg = scanline[x*4+1];\n\t\t\t\tb = scanline[x*4+2];\n\t\t\t\tint rr = r >>3;\n\t\t\t\tint gg = g >>3;\n\t\t\t\tint bb = b >>3;\n\t\t\t\tuint16 c16 = uint16((rr<<10) | (gg<<5) | bb);\n\t\t\t\tscanline[x*2+0] = c16&0xff;\n\t\t\t\tscanline[x*2+1] = c16>>8;\n\t\t\t}\n\t\t}\n\t\tif(d==24)\n\t\t{\n\t\t\tfor(x=0; x<(sint32)width; x++)\n\t\t\t{\n\t\t\t\tr = scanline[x*3+0];\n\t\t\t\tg = scanline[x*3+1];\n\t\t\t\tb = scanline[x*3+2];\n\t\t\t\tscanline[x*3+0] = b;\n\t\t\t\tscanline[x*3+1] = g;\n\t\t\t\tscanline[x*3+2] = r;\n\t\t\t}\n\t\t}\n\t\tif(d==32)\n\t\t{\n\t\t\tfor(x=0; x<(sint32)width; x++)\n\t\t\t{\n\t\t\t\tr = scanline[x*4+0];\n\t\t\t\tg = scanline[x*4+1];\n\t\t\t\tb = scanline[x*4+2];\n\t\t\t\ta= scanline[x*4+3];\n\t\t\t\tscanline[x*4+0] = b;\n\t\t\t\tscanline[x*4+1] = g;\n\t\t\t\tscanline[x*4+2] = r;\n\t\t\t\tscanline[x*4+3] = a;\n\t\t\t}\n\t\t}\n\n\t\tint finaleSize=width*d/8;\n\t\tfor(i=0; i<finaleSize; i++)\n\t\t{\n\t\t\tf.serial(scanline[i]);\n\t\t}\n\t}\n\tdelete []scanline;\n\treturn true;\n}\n\n\ntemplate<class T>\nvoid rotateCCW (const T* src, T* dst, uint srcWidth, uint srcHeight)\n{\n\tfor (uint y=0; y<srcHeight; y++)\n\tfor (uint x=0; x<srcWidth; x++)\n\t{\n\t\tuint dstX=y;\n\t\tuint dstY=srcWidth-x-1;\n\t\tdst[dstX+dstY*srcHeight]=src[x+y*srcWidth];\n\t}\n}\n\n/*template<class T>\nvoid rotateCCW (const vector<T>& src, vector<T>& dst, uint srcWidth, uint srcHeight)\n{\n\tfor (uint y=0; y<srcHeight; y++)\n\tfor (uint x=0; x<srcWidth; x++)\n\t{\n\t\tuint dstX=y;\n\t\tuint dstY=srcWidth-x;\n\t\tdst[dstX+dstY*srcHeight]=src[x+y*srcWidth];\n\t}\n}\n*/\nvoid CBitmap::rotateCCW()\n{\n\t// Copy the array\n\tCObjectVector<uint8> copy=_Data[0];\n\n\tswitch (PixelFormat)\n\t{\n\tcase RGBA:\n\t\tNLMISC::rotateCCW ((uint32*)&(_Data[0][0]), (uint32*)&(copy[0]), _Width, _Height);\n\t\tbreak;\n\tcase Luminance:\n\tcase Alpha:\n\t\tNLMISC::rotateCCW (&_Data[0][0], &copy[0], _Width, _Height);\n\t\tbreak;\n\tcase AlphaLuminance:\n\t\tNLMISC::rotateCCW ((uint16*)&(_Data[0][0]), (uint16*)&(copy[0]), _Width, _Height);;\n\t\tbreak;\n\tdefault: break;\n\t}\n\n\tuint32 tmp=_Width;\n\t_Width=_Height;\n\t_Height=tmp;\n\t_Data[0]=copy;\n}\n\nvoid CBitmap::blit(const CBitmap &src, sint srcX, sint srcY, sint srcWidth, sint srcHeight, sint destX, sint destY)\n{\n\tnlassert(PixelFormat == RGBA);\n\tnlassert(src.PixelFormat == RGBA);\n\t// clip x\n\tif (srcX < 0)\n\t{\n\t\tsrcWidth += srcX;\n\t\tif (srcWidth <= 0) return;\n\t\tdestX -= srcX;\n\t\tsrcX = 0;\n\t}\n\tif (srcX + srcWidth > (sint) src.getWidth())\n\t{\n\t\tsrcWidth = src.getWidth() - srcX;\n\t\tif (srcWidth <= 0) return;\n\t}\n\tif (destX < 0)\n\t{\n\t\tsrcWidth += destX;\n\t\tif (srcWidth <= 0) return;\n\t\tsrcX -= destX;\n\t\tdestX = 0;\n\t}\n\tif (destX + srcWidth > (sint) getWidth())\n\t{\n\t\tsrcWidth = getWidth() - destX;\n\t\tif (srcWidth <= 0) return;\n\t}\n\t// clip y\n\tif (srcY < 0)\n\t{\n\t\tsrcHeight += srcY;\n\t\tif (srcHeight <= 0) return;\n\t\tdestY -= srcY;\n\t\tsrcY = 0;\n\t}\n\tif (srcY + srcHeight > (sint) src.getHeight())\n\t{\n\t\tsrcHeight = src.getHeight() - srcY;\n\t\tif (srcHeight <= 0) return;\n\t}\n\tif (destY < 0)\n\t{\n\t\tsrcHeight += destY;\n\t\tif (srcHeight <= 0) return;\n\t\tsrcY -= destY;\n\t\tdestY = 0;\n\t}\n\tif (destY + srcHeight > (sint) getHeight())\n\t{\n\t\tsrcHeight = getHeight() - destY;\n\t\tif (srcHeight <= 0) return;\n\t}\n\tuint32 *srcPixels = (uint32 *) &src.getPixels()[0];\n\tuint32 *srcPtr = &(srcPixels[srcX + srcY * src.getWidth()]);\n\tuint32 *srcEndPtr = srcPtr + srcHeight * src.getWidth();\n\tuint32 *destPixels = (uint32 *) &getPixels()[0];\n\tuint32 *destPtr = \t&(destPixels[destX + destY * getWidth()]);\n\twhile (srcPtr != srcEndPtr)\n\t{\n\t\tmemcpy(destPtr, srcPtr, sizeof(uint32) * srcWidth);\n\t\tsrcPtr += src.getWidth();\n\t\tdestPtr += getWidth();\n\t}\n\n}\n\n\nbool CBitmap::blit(const CBitmap *src, sint32 x, sint32 y)\n{\n\n\tnlassert(this->PixelFormat == src->PixelFormat);\n\tif (this->PixelFormat != src->PixelFormat)\n\t{\n\t\treturn false;\n\t}\n\n\n\t// check for dxtc use\n\n\tconst bool useDXTC   =  PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha || PixelFormat == DXTC3 || PixelFormat ==\tDXTC5;\n\n\t// number of bits for a 4x4 pix block\n\tconst uint dxtcNumBits  =  PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha ? 64 : 128;\n\n\n\tif (useDXTC)\n\t{\n\t\t// blit pos must be multiple of 4\n\n\t\tnlassert(! (x & 3 || y & 3) );\n\t\tif (x & 3 || y & 3) return false;\n\n\t}\n\n\tnlassert(PixelFormat != DonTKnow);\n\n\t// the width to copy\n\tsint width = src->_Width;\n\t// the height to copy\n\tsint height = src->_Height;\n\n\tuint destStartX, destStartY;\n\tuint srcStartX, srcStartY;\n\n\n\t// clip against left\n\tif (x < 0)\n\t{\n\t\twidth += x;\n\t\tif (width <= 0) return true;\n\t\tdestStartX = 0;\n\t\tsrcStartX = -x;\n\t}\n\telse\n\t{\n\t\tdestStartX = x;\n\t\tsrcStartX = 0;\n\t}\n\n\t// clip against top\n\tif (y < 0)\n\t{\n\t\theight += y;\n\t\tif (height <= 0) return true;\n\t\tsrcStartY = -y;\n\t\tdestStartY = 0;\n\t}\n\telse\n\t{\n\t\tdestStartY = y;\n\t\tsrcStartY = 0;\n\t}\n\n\t// clip against right\n\tif ((destStartX + width - 1) >= _Width)\n\t{\n\t\twidth = _Width - destStartX;\n\t\tif (width <= 0) return true;\n\t}\n\n\t// clip against bottom\n\tif ((destStartY + height - 1) >= _Height)\n\t{\n\t\theight = _Height - destStartY;\n\t\tif (width <= 0) return true;\n\t}\n\n\n\t// divide all distance by 4 when using DXTC\n\tif (useDXTC)\n\t{\n\t\tdestStartX >>= 2;\n\t\tdestStartY >>= 2;\n\t\tsrcStartX >>= 2;\n\t\tsrcStartY >>= 2;\n\t\twidth >>= 2;\n\t\theight >>= 2;\n\t}\n\n\n\t// bytes per pixs is for either one pixel or 16 (a 4x4 block in DXTC)\n\tconst uint bytePerPixs = ( useDXTC ? dxtcNumBits : bitPerPixels[PixelFormat] ) >> 3 /* divide by 8 to get the number of bytes */;\n\n\n\tconst uint destRealWidth = useDXTC ? (_Width >> 2) : _Width;\n\tconst uint srcRealWidth = useDXTC ? (src->_Width >> 2) : src->_Width;\n\n\n\t// size to go to the next line in the destination\n\tconst uint destStride = destRealWidth * bytePerPixs;\n\n\t// size to go to the next line in the source\n\tconst uint srcStride = srcRealWidth * bytePerPixs;\n\n\t// length in bytes of a line to copy\n\tconst uint lineLength = width * bytePerPixs;\n\n\n\tuint8  *destPos = &(_Data[0][0]) + destStride * destStartY + bytePerPixs * destStartX;\n\tconst uint8 *srcPos = &(src->_Data[0][0]) + srcStride * srcStartY + bytePerPixs * srcStartX;\n\n\t// copy each hline\n\tfor (sint k = 0; k < height; ++k)\n\t{\n\t\t::memcpy(destPos, srcPos, lineLength);\n\t\tdestPos += destStride;\n\t\tsrcPos += srcStride;\n\t}\n\n\n\treturn true;\n}\n\n// Private :\nfloat CBitmap::getColorInterp (float x, float y, float colorInXY00, float colorInXY10, float colorInXY01, float colorInXY11) const\n{\n\tfloat res =\tcolorInXY00*(1.0f-x)*(1.0f-y) +\n\t\t\t\tcolorInXY10*(     x)*(1.0f-y) +\n\t\t\t\tcolorInXY01*(1.0f-x)*(     y) +\n\t\t\t\tcolorInXY11*(     x)*(     y);\n\tclamp (res, 0.0f, 255.0f);\n\treturn res;\n}\n\n// Public:\nCRGBAF CBitmap::getColor (float x, float y) const\n{\n\t\tif (x < 0.0f) x = 0.0f;\n\tif (x > 1.0f) x = 1.0f;\n\tif (y < 0.0f) y = 0.0f;\n\tif (y > 1.0f) y = 1.0f;\n\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\n\tif (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);\n\n\tconst CObjectVector<uint8> &rBitmap = getPixels(0);\n\tsint32 nX[4], nY[4];\n\n\tx *= nWidth-1;\n\ty *= nHeight-1;\n\n\t// Integer part of (x,y)\n\t//nX[0] = ((sint32)floor(x-0.5f));\n\t//nY[0] = ((sint32)floor(y-0.5f));\n\tnX[0] = ((sint32)floor(x));\n\tnY[0] = ((sint32)floor(y));\n\n\tnX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);\n\tnY[1] = nY[0];\n\n\tnX[2] = nX[0];\n\tnY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);\n\n\tnX[3] = nX[1];\n\tnY[3] = nY[2];\n\n\tuint32 i;\n\n\tfor (i = 0; i < 4; ++i)\n\t{\n\t\tnlassert (nX[i] >= 0);\n\t\tnlassert (nY[i] >= 0 );\n\t\tnlassert (nX[i] < nWidth);\n\t\tnlassert (nY[i] < nHeight);\n\t}\n\n\t// Decimal part of (x,y)\n\tx = x - (float)nX[0];\n\ty = y - (float)nY[0];\n\n\tswitch (this->PixelFormat)\n\t{\n\t\tcase RGBA:\n\t\tcase DXTC1:\n\t\tcase DXTC1Alpha:\n\t\tcase DXTC3:\n\t\tcase DXTC5:\n\t\t{\n\t\t\tCRGBAF finalVal;\n\t\t\tCRGBA val[4];\n\n\t\t\tif (this->PixelFormat == RGBA)\n\t\t\t{\n\t\t\t\tfor (i = 0; i < 4; ++i)\n\t\t\t\t{\n\t\t\t\t\tval[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+1],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+2],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+3]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// slower version : get from DXT\n\t\t\t\tfor (i = 0; i < 4; ++i)\n\t\t\t\t{\n\t\t\t\t\tval[i] = getPixelColor(nX[i], nY[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfinalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);\n\t\t\tfinalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);\n\t\t\tfinalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);\n\t\t\tfinalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);\n\t\t\tfinalVal /= 255.f;\n\n\t\t\treturn finalVal;\n\t\t}\n\t\tbreak;\n\t\tcase Alpha:\n\t\tcase Luminance:\n\t\t{\n\n\t\t\tfloat finalVal;\n\t\t\tfloat val[4];\n\n\t\t\tfor (i = 0; i < 4; ++i)\n\t\t\t\tval[i] = rBitmap[(nX[i]+nY[i]*nWidth)];\n\n\t\t\tfinalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);\n\t\t\tfinalVal /= 255.f;\n\n\t\t\tif (this->PixelFormat == Alpha)\n\t\t\t\treturn CRGBAF (1.f, 1.f, 1.f, finalVal);\n\t\t\telse // Luminance\n\t\t\t\treturn CRGBAF (finalVal, finalVal, finalVal, 1.f);\n\t\t}\n\t\tbreak;\n\t\tdefault: break;\n\t}\n\n\treturn CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);\n}\n\n// wrap a value inside the given range (for positive value it is like a modulo)\nstatic inline uint32 wrap(sint32 value, uint32 range)\n{\n\treturn value >= 0 ? (value % range) : range - 1 - (- value - 1) % range;\n}\n\n\nCRGBAF CBitmap::getColor(float x, float y, bool tileU, bool tileV) const\n{\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tif (nWidth == 0 || nHeight == 0) return CRGBAF(0, 0, 0, 0);\n\n\tsint32 nX[4], nY[4];\n\n\tif (!tileU)\n\t{\n\t\tif (x < 0.0f) x = 0.0f;\n\t\tif (x > 1.0f) x = 1.0f;\n\t\tx *= nWidth-1;\n\t\tnX[0] = ((sint32)floor(x));\n\t\tnX[1] = (nX[0] < (nWidth-1) ? nX[0]+1 : nX[0]);\n\t\tnX[2] = nX[0];\n\t\tnX[3] = nX[1];\n\t\tuint32 i;\n\t\tfor (i = 0; i < 4; ++i)\n\t\t{\n\t\t\tnlassert (nX[i] >= 0);\n\t\t\tnlassert (nX[i] < nWidth);\n\t\t}\n\t}\n\telse\n\t{\n\t\tx *= nWidth;\n\t\tnX[0] = wrap((sint32)floorf(x), nWidth);\n\t\tnX[1] = wrap(nX[0] + 1, nWidth);\n\t\tnX[2] = nX[0];\n\t\tnX[3] = nX[1];\n\t}\n\t//\n\tif (!tileV)\n\t{\n\t\tif (y < 0.0f) y = 0.0f;\n\t\tif (y > 1.0f) y = 1.0f;\n\t\ty *= nHeight-1;\n\t\tnY[0] = ((sint32)floor(y));\n\t\tnY[1] = nY[0];\n\t\tnY[2] = (nY[0] < (nHeight-1) ? nY[0]+1 : nY[0]);\n\t\tnY[3] = nY[2];\n\t\tuint32 i;\n\t\tfor (i = 0; i < 4; ++i)\n\t\t{\n\t\t\tnlassert (nY[i] >= 0 );\n\t\t\tnlassert (nY[i] < nHeight);\n\t\t}\n\t}\n\telse\n\t{\n\t\ty *= nHeight;\n\t\tnY[0] = wrap((sint32)floorf(y), nHeight);\n\t\tnY[1] = nY[0];\n\t\tnY[2] = wrap(nY[0] + 1, nHeight);\n\t\tnY[3] = nY[2];\n\t}\n\t// Decimal part of (x,y)\n\tx = x - (float)nX[0];\n\ty = y - (float)nY[0];\n\tconst CObjectVector<uint8> &rBitmap = getPixels(0);\n\tswitch (this->PixelFormat)\n\t{\n\t\tcase RGBA:\n\t\tcase DXTC1:\n\t\tcase DXTC1Alpha:\n\t\tcase DXTC3:\n\t\tcase DXTC5:\n\t\t{\n\t\t\tCRGBAF finalVal;\n\t\t\tCRGBA val[4];\n\n\t\t\tif (this->PixelFormat == RGBA)\n\t\t\t{\n\t\t\t\tfor (uint32 i = 0; i < 4; ++i)\n\t\t\t\t{\n\t\t\t\t\tval[i] = CRGBA (rBitmap[(nX[i]+nY[i]*nWidth)*4+0],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+1],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+2],\n\t\t\t\t\t\t\t\t\trBitmap[(nX[i]+nY[i]*nWidth)*4+3]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// slower version : get from DXT\n\t\t\t\tfor (uint32 i = 0; i < 4; ++i)\n\t\t\t\t{\n\t\t\t\t\tval[i] = getPixelColor(nX[i], nY[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfinalVal.R = getColorInterp (x, y, val[0].R, val[1].R, val[2].R, val[3].R);\n\t\t\tfinalVal.G = getColorInterp (x, y, val[0].G, val[1].G, val[2].G, val[3].G);\n\t\t\tfinalVal.B = getColorInterp (x, y, val[0].B, val[1].B, val[2].B, val[3].B);\n\t\t\tfinalVal.A = getColorInterp (x, y, val[0].A, val[1].A, val[2].A, val[3].A);\n\t\t\tfinalVal /= 255.f;\n\n\t\t\treturn finalVal;\n\t\t}\n\t\tbreak;\n\t\tcase Alpha:\n\t\tcase Luminance:\n\t\t{\n\n\t\t\tfloat finalVal;\n\t\t\tfloat val[4];\n\n\t\t\tfor (uint32 i = 0; i < 4; ++i)\n\t\t\t\tval[i] = rBitmap[(nX[i]+nY[i]*nWidth)];\n\n\t\t\tfinalVal = getColorInterp (x, y, val[0], val[1], val[2], val[3]);\n\t\t\tfinalVal /= 255.f;\n\n\t\t\tif (this->PixelFormat == Alpha)\n\t\t\t\treturn CRGBAF (1.f, 1.f, 1.f, finalVal);\n\t\t\telse // Luminance\n\t\t\t\treturn CRGBAF (finalVal, finalVal, finalVal, 1.f);\n\t\t}\n\t\tbreak;\n\t\tdefault: break;\n\t}\n\treturn CRGBAF (0.0f, 0.0f, 0.0f, 0.0f);\n}\n\n\n\nvoid\tCBitmap::loadSize(NLMISC::IStream &f, uint32 &retWidth, uint32 &retHeight)\n{\n\tretWidth= 0;\n\tretHeight= 0;\n\n\tnlassert(f.isReading());\n\n\t// testing if DDS\n\tuint32 fileType = 0;\n\tf.serial(fileType);\n\tif(fileType == DDS_HEADER)\n\t{\n\t\t// read entire DDS header.\n\t\tuint32 size = 0;\n\t\tf.serial(size); // size in Bytes of header(without \"DDS\")\n\t\tuint32 * _DDSSurfaceDesc = new uint32[size];\n\t\t_DDSSurfaceDesc[0]= size;\n\n\t\tfor(uint i= 0; i<size/4 - 1; i++)\n\t\t{\n\t\t\tf.serial(_DDSSurfaceDesc[i+1]);\n\t\t}\n\n\t\t// flags determines which members of the header structure contain valid data\n\t\tuint32 flags = _DDSSurfaceDesc[1];\n\n\t\t//verify if file have linearsize set\n\t\tif(!(flags & DDSD_LINEARSIZE))\n\t\t{\n\t\t\tnlwarning(\"A DDS doesn't have the flag DDSD_LINEARSIZE\");\n\t\t\t//delete [] _DDSSurfaceDesc;\n\t\t\t//throw EDDSBadHeader();\n\t\t}\n\n\t\t//-------------- extracting and testing useful info\n\t\tretHeight  = _DDSSurfaceDesc[2];\n\t\tretWidth = _DDSSurfaceDesc[3];\n\n\t\tdelete [] _DDSSurfaceDesc;\n\t}\n\telse if(fileType == PNG_HEADER)\n\t{\n\t\t// check second part of header\n\t\tf.serialCheck(0x0a1a0a0d);\n\n\t\tuint32 chunkLength = 0;\n\t\tuint32 chunkName = 0;\n\t\tbool eof = false;\n\n\t\tdo\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// length of chunk data\n\t\t\t\tf.serial(chunkLength);\n\t\t\t\tNLMISC_BSWAP32(chunkLength);\n\n\t\t\t\t// name of chunk\n\t\t\t\tf.serial(chunkName);\n\n\t\t\t\t// size of image is a part of IHDR chunk\n\t\t\t\tif (chunkName == NL_MAKEFOURCC('I', 'H', 'D', 'R'))\n\t\t\t\t{\n\t\t\t\t\tuint32 val;\n\t\t\t\t\tf.serial(val);\n\t\t\t\t\tNLMISC_BSWAP32(val);\n\t\t\t\t\tretWidth = val;\n\n\t\t\t\t\tf.serial(val);\n\t\t\t\t\tNLMISC_BSWAP32(val);\n\t\t\t\t\tretHeight = val;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// end of file chunk\n\t\t\t\telse if (chunkName == NL_MAKEFOURCC('I', 'E', 'N', 'D'))\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// skip data of this chunk and CRC32\n\t\t\t\tf.seek(chunkLength+4, IStream::current);\n\t\t\t}\n\t\t\tcatch(...)\n\t\t\t{\n\t\t\t\teof = true;\n\t\t\t}\n\t\t}\n\t\twhile(!eof);\n\t}\n\telse if(fileType == JPG_HEADER)\n\t{\n\t\tuint8 blockMarker1 = 0;\n\t\tuint8 blockMarker2 = 0;\n\t\tuint16 blockSize = 0;\n\t\tbool eof = false;\n\n\t\tdo\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// marker of a block\n\t\t\t\tf.serial(blockMarker1);\n\n\t\t\t\tif (blockMarker1 == 0xff)\n\t\t\t\t{\n\t\t\t\t\t// marker of a block\n\t\t\t\t\tf.serial(blockMarker2);\n\n\t\t\t\t\t// 0xff00 is only found in image data\n\t\t\t\t\tif (blockMarker2 == 0x00)\n\t\t\t\t\t{\n\t\t\t\t\t\t// image data 0xff\n\t\t\t\t\t}\n\t\t\t\t\t// 0xffda is image data\n\t\t\t\t\telse if (blockMarker2 == 0xda)\n\t\t\t\t\t{\n\t\t\t\t\t\t// next data is image data which must end with 0xffd9\n\t\t\t\t\t}\n\t\t\t\t\t// 0xffd9 is the end of an image\n\t\t\t\t\telse if (blockMarker2 == 0xd9)\n\t\t\t\t\t{\n\t\t\t\t\t\t// real end of file\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if (blockMarker2 == 0xdd || blockMarker2 == 0xdc)\n\t\t\t\t\t{\n\t\t\t\t\t\tf.seek(4, IStream::current);\n\t\t\t\t\t}\n\t\t\t\t\telse if (blockMarker2 == 0xdf)\n\t\t\t\t\t{\n\t\t\t\t\t\tf.seek(3, IStream::current);\n\t\t\t\t\t}\n\t\t\t\t\telse if (blockMarker2 >= 0xd0 && blockMarker2 <= 0xd8)\n\t\t\t\t\t{\n\t\t\t\t\t\t// no content\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// size of a block\n\t\t\t\t\t\tf.serial(blockSize);\n\t\t\t\t\t\tNLMISC_BSWAP16(blockSize);\n\n\t\t\t\t\t\t// frame marker (which contains image width and height)\n\t\t\t\t\t\tif (blockMarker2 >= 0xc0 && blockMarker2 <= 0xc3)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint8 imagePrecision = 0; // sample precision\n\t\t\t\t\t\t\tuint32 imageSize = 0; // width and height\n\t\t\t\t\t\t\tf.serial(imagePrecision); \n\t\t\t\t\t\t\tf.serial(imageSize);\n\t\t\t\t\t\t\tNLMISC_BSWAP32(imageSize);\n\n\t\t\t\t\t\t\tretWidth = imageSize & 0xffff;\n\t\t\t\t\t\t\tretHeight = (imageSize & 0xffff0000) >> 16;\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// skip the block\n\t\t\t\t\t\tf.seek(blockSize - 2, IStream::current);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(...)\n\t\t\t{\n\t\t\t\teof = true;\n\t\t\t}\n\t\t}\n\t\twhile(!eof);\n\t}\n\t// assuming it's TGA\n\telse\n\t{\n\t\tif(!f.seek (0, NLMISC::IStream::begin))\n\t\t{\n\t\t\tthrow ESeekFailed();\n\t\t}\n\n\t\t// Reading header,\n\t\t// To make sure that the bitmap is TGA, we check imageType and imageDepth.\n\t\tuint8\tlengthID;\n\t\tuint8\tcMapType;\n\t\tuint8\timageType;\n\t\tuint16\ttgaOrigin;\n\t\tuint16\tlength;\n\t\tuint8\tdepth;\n\t\tuint16\txOrg;\n\t\tuint16\tyOrg;\n\t\tuint16\twidth;\n\t\tuint16\theight;\n\t\tuint8\timageDepth;\n\t\tuint8\tdesc;\n\n\t\tf.serial(lengthID);\n\t\tf.serial(cMapType);\n\t\tf.serial(imageType);\n\t\tif(imageType!=2 && imageType!=3 && imageType!=10 && imageType!=11)\n\t\t{\n\t\t\tnlwarning(\"Invalid TGA format, type %u in not supported (must be 2,3,10 or 11)\", imageType);\n\t\t\treturn;\n\t\t}\n\t\tf.serial(tgaOrigin);\n\t\tf.serial(length);\n\t\tf.serial(depth);\n\t\tf.serial(xOrg);\n\t\tf.serial(yOrg);\n\t\tf.serial(width);\n\t\tf.serial(height);\n\t\tf.serial(imageDepth);\n\t\tif(imageDepth!=8 && imageDepth!=16 && imageDepth!=24 && imageDepth!=32)\n\t\t{\n\t\t\tnlwarning(\"Invalid TGA format, bit depth %u in not supported (must be 8,16,24 or 32)\", imageDepth);\n\t\t\treturn;\n\t\t}\n\t\tf.serial(desc);\n\n\t\t// Ok, we have width and height.\n\t\tretWidth= width;\n\t\tretHeight= height;\n\t}\n\n\t// reset stream.\n\tif(!f.seek (0, NLMISC::IStream::begin))\n\t{\n\t\tthrow ESeekFailed();\n\t}\n}\n\n\nvoid\tCBitmap::loadSize(const std::string &path, uint32 &retWidth, uint32 &retHeight)\n{\n\tretWidth= 0;\n\tretHeight= 0;\n\n\tCIFile\t\tf(path);\n\tif(f.open(path))\n\t\tloadSize(f, retWidth, retHeight);\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipHDXTCBlockColor(uint8 *bitColor, uint32 w)\n{\n\t// pack each line in a u32 (NB: the following works either in Little and Big Endian)\n\tuint32\tbits= *(uint32*)bitColor;\n\n\t// swap in X for each line\n\tuint32\tres;\n\tif(w!=2)\n\t{\n\t\tres = (bits & 0xC0C0C0C0) >> 6;\n\t\tres+= (bits & 0x30303030) >> 2;\n\t\tres+= (bits & 0x0C0C0C0C) << 2;\n\t\tres+= (bits & 0x03030303) << 6;\n\t}\n\t// special case where w==2\n\telse\n\t{\n\t\tres = (bits & 0x0C0C0C0C) >> 2;\n\t\tres+= (bits & 0x03030303) << 2;\n\t}\n\n\t// copy\n\t*((uint32*)bitColor)= res;\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipVDXTCBlockColor(uint8 *bitColor, uint32 h)\n{\n\t// swap just bytes (work either in Little and Big Endian)\n\tif(h!=2)\n\t{\n\t\tstd::swap(bitColor[0], bitColor[3]);\n\t\tstd::swap(bitColor[1], bitColor[2]);\n\t}\n\t// special case where h==2)\n\telse\n\t{\n\t\t// whatever Little or Big endian, the first byte is the first line, and the second byte is the second line\n\t\tstd::swap(bitColor[0], bitColor[1]);\n\t}\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipHDXTCBlockAlpha3(uint8 *blockAlpha, uint32 w)\n{\n#ifdef NL_LITTLE_ENDIAN\n\tuint64\tbits= *(uint64*)blockAlpha;\n#else\n\tuint64\tbits= (uint64)blockAlpha[0] + ((uint64)blockAlpha[1]<<8) +\n\t\t((uint64)blockAlpha[2]<<16) + ((uint64)blockAlpha[3]<<24) +\n\t\t((uint64)blockAlpha[4]<<32) + ((uint64)blockAlpha[5]<<40) +\n\t\t((uint64)blockAlpha[6]<<48) + ((uint64)blockAlpha[7]<<56);\n#endif\n\n\t// swap in X for each line\n\tuint64\tres;\n\tif(w!=2)\n\t{\n\t\tres = (bits & INT64_CONSTANT(0xF000F000F000F000)) >> 12;\n\t\tres+= (bits & INT64_CONSTANT(0x0F000F000F000F00)) >> 4;\n\t\tres+= (bits & INT64_CONSTANT(0x00F000F000F000F0)) << 4;\n\t\tres+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 12;\n\t}\n\t// special case where w==2\n\telse\n\t{\n\t\tres = (bits & INT64_CONSTANT(0x00F000F000F000F0)) >> 4;\n\t\tres+= (bits & INT64_CONSTANT(0x000F000F000F000F)) << 4;\n\t}\n\n\t// copy\n#ifdef NL_LITTLE_ENDIAN\n\t*((uint64*)blockAlpha)= res;\n#else\n\tblockAlpha[0]= res & 255;\n\tblockAlpha[1]= (res>>8) & 255;\n\tblockAlpha[2]= (res>>16) & 255;\n\tblockAlpha[3]= (res>>24) & 255;\n\tblockAlpha[4]= (res>>32) & 255;\n\tblockAlpha[5]= (res>>40) & 255;\n\tblockAlpha[6]= (res>>48) & 255;\n\tblockAlpha[7]= (res>>56) & 255;\n#endif\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipVDXTCBlockAlpha3(uint8 *blockAlpha, uint32 h)\n{\n\tuint16\t*wAlpha= (uint16*)blockAlpha;\n\n\t// swap just words (work either in Little and Big Endian)\n\tif(h!=2)\n\t{\n\t\tstd::swap(wAlpha[0], wAlpha[3]);\n\t\tstd::swap(wAlpha[1], wAlpha[2]);\n\t}\n\t// special case where h==2)\n\telse\n\t{\n\t\t// whatever Little or Big endian, the first byte is the first line, and the second byte is the second line\n\t\tstd::swap(wAlpha[0], wAlpha[1]);\n\t}\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipHDXTCBlockAlpha5(uint8 *bitAlpha, uint32 w)\n{\n\t// pack into bits. Little Indian in all cases\n\tuint64\tbits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +\n\t\t((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +\n\t\t((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);\n\n\t// swap in X for each line\n\tuint64\tres;\n\tif(w!=2)\n\t{\n\t\tres = (bits & INT64_CONSTANT(0xE00E00E00E00)) >> 9;\n\t\tres+= (bits & INT64_CONSTANT(0x1C01C01C01C0)) >> 3;\n\t\tres+= (bits & INT64_CONSTANT(0x038038038038)) << 3;\n\t\tres+= (bits & INT64_CONSTANT(0x007007007007)) << 9;\n\t}\n\t// special case where w==2\n\telse\n\t{\n\t\tres = (bits & INT64_CONSTANT(0x038038038038)) >> 3;\n\t\tres+= (bits & INT64_CONSTANT(0x007007007007)) << 3;\n\t}\n\n\t// copy. Little Indian in all cases\n\tbitAlpha[0]= uint8(res & 255);\n\tbitAlpha[1]= uint8((res>>8) & 255);\n\tbitAlpha[2]= uint8((res>>16) & 255);\n\tbitAlpha[3]= uint8((res>>24) & 255);\n\tbitAlpha[4]= uint8((res>>32) & 255);\n\tbitAlpha[5]= uint8((res>>40) & 255);\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipVDXTCBlockAlpha5(uint8 *bitAlpha, uint32 h)\n{\n\t// pack into bits. Little Indian in all cases\n\tuint64\tbits= (uint64)bitAlpha[0] + ((uint64)bitAlpha[1]<<8) +\n\t\t((uint64)bitAlpha[2]<<16) + ((uint64)bitAlpha[3]<<24) +\n\t\t((uint64)bitAlpha[4]<<32) + ((uint64)bitAlpha[5]<<40);\n\n\t// swap in Y\n\tuint64\tres;\n\tif(h!=2)\n\t{\n\t\tres = (bits & INT64_CONSTANT(0xFFF000000000)) >> 36;\n\t\tres+= (bits & INT64_CONSTANT(0x000FFF000000)) >> 12;\n\t\tres+= (bits & INT64_CONSTANT(0x000000FFF000)) << 12;\n\t\tres+= (bits & INT64_CONSTANT(0x000000000FFF)) << 36;\n\t}\n\t// special case where h==2\n\telse\n\t{\n\t\tres = (bits & INT64_CONSTANT(0x000000FFF000)) >> 12;\n\t\tres+= (bits & INT64_CONSTANT(0x000000000FFF)) << 12;\n\t}\n\n\t// copy. Little Indian in all cases\n\tbitAlpha[0]= uint8(res & 255);\n\tbitAlpha[1]= uint8((res>>8) & 255);\n\tbitAlpha[2]= uint8((res>>16) & 255);\n\tbitAlpha[3]= uint8((res>>24) & 255);\n\tbitAlpha[4]= uint8((res>>32) & 255);\n\tbitAlpha[5]= uint8((res>>40) & 255);\n}\n\n// ***************************************************************************\nvoid\tCBitmap::flipDXTCMipMap(bool vertical, uint mm, uint type)\n{\n\tnlassert(mm<MAX_MIPMAP);\n\t// size of a DXTC block. 64 bits (2 U32) for DXTC1, else 128 bits (4*U32)\n\tuint\tblockSizeU32= type==1? 2 : 4;\n\t// get size in block\n\tsint32\twidth = getWidth(mm);\n\tsint32\theight = getHeight(mm);\n\tif(width==0 || height==0)\n\t\treturn;\n\tuint32\twBlock= (width+3)/4;\n\tuint32\thBlock= (height+3)/4;\n\t// get data ptr and check size.\n\tuint32\t*data= (uint32*)(&_Data[mm][0]);\n\tnlassert(_Data[mm].size()==wBlock*hBlock*blockSizeU32*4);\n\n\t// get the offset (in bytes) to the start of color pixels bits\n\tuint32\toffsetColorBits= type==1? 4 : 12;\n\n\t// abort if swap is nonsense\n\tif(vertical && height==1)\n\t\treturn;\n\tif(!vertical && width==1)\n\t\treturn;\n\n\t// *** First reverse Blocks\n\tif(vertical)\n\t{\n\t\t// reverse vertical\n\t\tfor(uint yBlock=0;yBlock<hBlock/2;yBlock++)\n\t\t{\n\t\t\tuint32\t*src0= data + (yBlock*wBlock)*blockSizeU32;\n\t\t\tuint32\t*src1= data + ((hBlock-yBlock-1)*wBlock)*blockSizeU32;\n\t\t\tfor(uint xBlock=0;xBlock<wBlock;xBlock++, src0+=blockSizeU32, src1+=blockSizeU32)\n\t\t\t{\n\t\t\t\tuint32\t*block0= src0;\n\t\t\t\tuint32\t*block1= src1;\n\t\t\t\t// swap the blocks\n\t\t\t\tfor(uint i=0;i<blockSizeU32;i++, block0++, block1++)\n\t\t\t\t{\n\t\t\t\t\tstd::swap(*block0, *block1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// reverse horizontal\n\t\tfor(uint yBlock=0;yBlock<hBlock;yBlock++)\n\t\t{\n\t\t\tuint32\t*src0= data + (yBlock*wBlock)*blockSizeU32;\n\t\t\tuint32\t*src1= data + (yBlock*wBlock + wBlock-1)*blockSizeU32;\n\t\t\tfor(uint xBlock=0;xBlock<wBlock/2;xBlock++, src0+=blockSizeU32, src1-=blockSizeU32)\n\t\t\t{\n\t\t\t\tuint32\t*block0= src0;\n\t\t\t\tuint32\t*block1= src1;\n\t\t\t\t// swap the blocks\n\t\t\t\tfor(uint i=0;i<blockSizeU32;i++, block0++, block1++)\n\t\t\t\t{\n\t\t\t\t\tstd::swap(*block0, *block1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// *** Then reverse Bits\n\tfor(uint yBlock=0;yBlock<hBlock;yBlock++)\n\t{\n\t\tuint32\t*src= data + (yBlock*wBlock)*blockSizeU32;\n\t\tfor(uint xBlock=0;xBlock<wBlock;xBlock++, src+=blockSizeU32)\n\t\t{\n\t\t\tuint8\t*block= (uint8*)src;\n\n\t\t\t// flip color bits\n\t\t\tif(vertical)\tflipVDXTCBlockColor(block+offsetColorBits, height);\n\t\t\telse\t\t\tflipHDXTCBlockColor(block+offsetColorBits, width);\n\n\t\t\t// flip alpha bits if any\n\t\t\tif(type==3)\n\t\t\t{\n\t\t\t\t// point to the alpha part (16*4 bits)\n\t\t\t\tif(vertical)\tflipVDXTCBlockAlpha3(block, height);\n\t\t\t\telse\t\t\tflipHDXTCBlockAlpha3(block, width);\n\t\t\t}\n\t\t\telse if(type==5)\n\t\t\t{\n\t\t\t\t// point to the bit alpha part (16*3 bits)\n\t\t\t\tif(vertical)\tflipVDXTCBlockAlpha5(block+2, height);\n\t\t\t\telse\t\t\tflipHDXTCBlockAlpha5(block+2, width);\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n\n// ***************************************************************************\nvoid\tCBitmap::flipDXTC(bool vertical)\n{\n\t// get type\n\tuint\ttype;\n\tif(PixelFormat == DXTC1 || PixelFormat == DXTC1Alpha )\n\t\ttype=1;\n\telse if(PixelFormat == DXTC3)\n\t\ttype=3;\n\telse if(PixelFormat == DXTC5)\n\t\ttype=5;\n\telse\n\t\treturn;\n\n\t// correct width/height?\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tif(!isPowerOf2(nWidth) || !isPowerOf2(nHeight))\n\t\treturn;\n\n\t// flip all mipmaps\n\tfor(uint mm=0;mm<_MipMapCount;mm++)\n\t{\n\t\tflipDXTCMipMap(vertical, mm, type);\n\t}\n}\n\n\n// ***************************************************************************\nvoid\tCBitmap::flipH()\n{\n\tif (PixelFormat != RGBA)\n\t{\n\t\t// try for DXTC\n\t\tflipDXTC(false);\n\n\t\t// then quit (whether it worked or not)\n\t\treturn;\n\t}\n\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tsint32 i, j;\n\tNLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];\n\tbool needRebuild = false;\n\tCRGBA temp;\n\n\tif(_MipMapCount>1)\n\t\tneedRebuild = true;\n\treleaseMipMaps();\n\n\tfor( i = 0; i < nHeight; ++i )\n\t\tfor( j = 0; j < nWidth/2; ++j )\n\t\t{\n\t\t\ttemp = pBitmap[i*nWidth+j];\n\t\t\tpBitmap[i*nWidth+j] = pBitmap[i*nWidth+nWidth-j-1];\n\t\t\tpBitmap[i*nWidth+nWidth-j-1] = temp;\n\t\t}\n\n\t// Rebuilding mipmaps\n\tif(needRebuild)\n\t{\n\t\tbuildMipMaps();\n\t}\n}\n\n\n// ***************************************************************************\nvoid\tCBitmap::flipV()\n{\n\tif (PixelFormat != RGBA)\n\t{\n\t\t// try for DXTC\n\t\tflipDXTC(true);\n\n\t\t// then quit (whether it worked or not)\n\t\treturn;\n\t}\n\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tsint32 i, j;\n\tNLMISC::CRGBA *pBitmap = (NLMISC::CRGBA*)&_Data[0][0];\n\tbool needRebuild = false;\n\tCRGBA temp;\n\n\tif(_MipMapCount>1)\n\t\tneedRebuild = true;\n\treleaseMipMaps();\n\n\tfor( j = 0; j < nHeight/2; ++j )\n\t\tfor( i = 0; i < nWidth; ++i )\n\t\t{\n\t\t\ttemp = pBitmap[j*nWidth+i];\n\t\t\tpBitmap[j*nWidth+i] = pBitmap[(nHeight-j-1)*nWidth+i];\n\t\t\tpBitmap[(nHeight-j-1)*nWidth+i] = temp;\n\t\t}\n\n\t// Rebuilding mipmaps\n\tif(needRebuild)\n\t{\n\t\tbuildMipMaps();\n\t}\n}\n\n\nvoid\tCBitmap::rot90CW()\n{\n\tif (PixelFormat != RGBA)\n\t\treturn;\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tsint32 i, j;\n\tNLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];\n\tbool needRebuild = false;\n\n\tif(_MipMapCount>1)\n\t\tneedRebuild = true;\n\treleaseMipMaps();\n\n\tCObjectVector<uint8> pDestui;\n\tpDestui.resize(nWidth*nHeight*4);\n\tNLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];\n\n\tfor( j = 0; j < nHeight; ++j )\n\tfor( i = 0; i < nWidth;  ++i )\n\t\tpDestRgba[j+i*nHeight] = pSrcRgba[i+(nHeight-1-j)*nWidth];\n\n\tuint32 nTemp = _Width;\n\t_Width = _Height;\n\t_Height = nTemp;\n\n\tNLMISC::contReset(_Data[0]); // free memory\n\t_Data[0] =  pDestui;\n\t// Rebuilding mipmaps\n\tif(needRebuild)\n\t{\n\t\tbuildMipMaps();\n\t}\n}\n\nvoid\tCBitmap::rot90CCW()\n{\n\tif (PixelFormat != RGBA)\n\t\treturn;\n\tsint32 nWidth = getWidth(0);\n\tsint32 nHeight = getHeight(0);\n\tsint32 i, j;\n\tNLMISC::CRGBA *pSrcRgba = (NLMISC::CRGBA*)&_Data[0][0];\n\tbool needRebuild = false;\n\n\tif(_MipMapCount>1)\n\t\tneedRebuild = true;\n\treleaseMipMaps();\n\n\tCObjectVector<uint8> pDestui;\n\tpDestui.resize(nWidth*nHeight*4);\n\tNLMISC::CRGBA *pDestRgba = (NLMISC::CRGBA*)&pDestui[0];\n\n\tfor( j = 0; j < nHeight; ++j )\n\tfor( i = 0; i < nWidth;  ++i )\n\t\tpDestRgba[j+i*nHeight] = pSrcRgba[nWidth-1-i+j*nWidth];\n\n\tuint32 nTemp = _Width;\n\t_Width = _Height;\n\t_Height = nTemp;\n\n\tNLMISC::contReset(_Data[0]); // free memory\n\t_Data[0] =  pDestui;\n\t// Rebuilding mipmaps\n\tif(needRebuild)\n\t{\n\t\tbuildMipMaps();\n\t}\n}\n\n//===========================================================================\nvoid CBitmap::blend(CBitmap &Bm0, CBitmap &Bm1, uint16 factor, bool inputBitmapIsMutable /*= false*/)\n{\n\tnlassert(factor <= 256);\n\n\tnlassert(Bm0._Width != 0 && Bm0._Height != 0\n\t\t\t && Bm1._Width != 0 && Bm1._Height != 0);\n\n\tnlassert(Bm0._Width  == Bm1._Width);\t// the bitmap should have the same size\n\tnlassert(Bm0._Height == Bm1._Height);\n\n\tconst CBitmap *nBm0, *nBm1; // pointer to the bitmap that is used for blending, or to a copy is a conversion wa required\n\n\tCBitmap cp0, cp1; // these bitmap are copies of Bm1 and Bm0 if a conversion was needed\n\n\tif (Bm0.PixelFormat != RGBA)\n\t{\n\t\tif (inputBitmapIsMutable)\n\t\t{\n\t\t\tBm0.convertToRGBA();\n\t\t\tnBm0 = &Bm0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcp0 = Bm0;\n\t\t\tcp0.convertToRGBA();\n\t\t\tnBm0 = &cp0;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnBm0 = &Bm0;\n\t}\n\n\n\tif (Bm1.PixelFormat != RGBA)\n\t{\n\t\tif (inputBitmapIsMutable)\n\t\t{\n\t\t\tBm1.convertToRGBA();\n\t\t\tnBm1 = &Bm1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcp1 = Bm1;\n\t\t\tcp1.convertToRGBA();\n\t\t\tnBm1 = &cp1;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnBm1 = &Bm1;\n\t}\n\n\tif (this != nBm0 && this != nBm1)\n\t{\n\t\t// if source is the same than the dets, don't resize because this clear the bitmap\n\t\tthis->resize(Bm0._Width, Bm0._Height, RGBA);\n\t}\n\n\tuint numPix = _Width * _Height; // 4 component per pixels\n\n\n\tconst uint8 *src0\t\t= &(nBm0->_Data[0][0]);\n\tconst uint8 *src1\t\t= &(nBm1->_Data[0][0]);\n\tuint8 *dest\t\t\t\t= &(this->_Data[0][0]);\n\n\n\t#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)\n\tif (CSystemInfo::hasMMX())\n\t{\n\t\t// On a P4 2GHz, with a 256x256 texture, I got the following results :\n\t\t// without mmx : 5.2 ms\n\t\t// with mmx    : 1.7 ms\n\t\t// I'm sure this can be further optimized..\n\n\t\tuint numPixLeft = numPix & 1; // process 2 pixels at once, so special case for odd number\n\t\tnumPix = numPix & ~1;\n\t\t// do fast blend with mmx\n\t\tuint64 blendFactor0;\n\t\tuint64 blendFactor1;\n\t\tuint16 *bf0 = (uint16 *) &blendFactor0;\n\t\tuint16 *bf1 = (uint16 *) &blendFactor1;\n\t\tbf0[0] = bf0[1] = bf0[2] = bf0[3] = (1 << 6) * (factor);\n\t\tbf1[0] = bf1[1] = bf1[2] = bf1[3] = (1 << 6) * (256 - factor);\n\t\t__asm\n\t\t{\n\t\t\tmov esi, src0\n\t\t\tmov eax, src1\n\t\t\tmov edi, dest\n\t\t\tmov ebx, -8\n\t\t\tmov ecx, numPix\n\t\t\tshr ecx, 1 // process pixels 2 by 2\n\t\t\tmovq mm1, blendFactor0\n\t\t\tmovq mm0, blendFactor1\n\n\t\tmyLoop:\n\t\t\tpxor mm6, mm6\n\t\t\tlea  ebx, [ebx + 8] // points next location\n\t\t\tpxor mm7, mm7\n\t\t\tmovq mm2, [esi + ebx]\n\t\t\tmovq mm3, [eax + ebx]\n\t\t\t// do blend\n\t\t\tpunpckhbw mm7, mm2  // mm7 contains src0 color 0 in high bytes\n\t\t\tpunpckhbw mm6, mm3  // mm6 contains src1 color 0 in high bytes\n\t\t\tpsrl\t  mm7, 1\n\t\t\tpxor mm4, mm4       // mm4 = 0\n\t\t\tpsrl\t  mm6, 1\n\t\t\tpmulhw mm7, mm0     // src0 = src0 * blendFactor\n\t\t\tpxor mm5, mm5       // mm5 = 0\n\t\t\tpmulhw mm6, mm1     // src1 = src1 * (1 - blendfactor)\n\t\t\tpunpcklbw mm4, mm2  // mm4 contains src0 color 1 in high bytes\n\t\t\tpaddusw mm6, mm7    // mm6 = src0[0] blended with src1[0]\n\t\t\tpsrl      mm4, 1\n\t\t\tpsrlw     mm6, 5\n\t\t\tpunpcklbw mm5, mm3  // mm4 contains src1 color 1 in high bytes\n\t\t\tpsrl      mm5, 1\n\t\t\tpmulhw    mm4, mm0     // src0 = src0 * blendFactor\n\t\t\tpmulhw    mm5, mm1     // src1 = src1 * (1 - blendfactor)\n\t\t\tpaddusw   mm4, mm5    // mm6 = src0[1] blended with src1[1]\n\t\t\tpsrlw     mm4, 5\n\t\t\t// pack result\n\t\t\tpackuswb  mm4, mm6\n\t\t\tdec\t\t  ecx\n\t\t\tmovq      [edi + ebx], mm4  // store result\n\t\t\tjne myLoop\n\t\t\temms\n\t\t}\n\t\tif (numPixLeft)\n\t\t{\n\t\t\t// case of odd number of pixels\n\t\t\tsrc0 += 4 * numPix;\n\t\t\tsrc1 += 4 * numPix;\n\t\t\tdest += 4 * numPix;\n\t\t\tuint blendFact    = (uint) factor;\n\t\t\tuint invblendFact = 256 - blendFact;\n\t\t\t*dest = (uint8) (((blendFact * *src1)\t\t+ (invblendFact * *src0)) >> 8);\n\t\t\t*(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);\n\t\t\t*(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);\n\t\t\t*(dest + 3)  = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);\n\t\t}\n\t}\n\telse\n\t#endif //#ifdef NL_OS_WINDOWS\n\t{\n\t\tuint8 *endPix\t\t\t= dest + (numPix << 2);\n\t\t// no mmx version\n\t\tuint blendFact    = (uint) factor;\n\t\tuint invblendFact = 256 - blendFact;\n\t\tdo\n\t\t{\n\t\t\t/// blend 4 component at each pass\n\t\t\t*dest = (uint8) (((blendFact * *src1)\t\t+ (invblendFact * *src0)) >> 8);\n\t\t\t*(dest + 1) = (uint8) (((blendFact * *(src1 + 1)) + (invblendFact * *(src0 + 1))) >> 8);\n\t\t\t*(dest + 2) = (uint8) (((blendFact * *(src1 + 2)) + (invblendFact * *(src0 + 2))) >> 8);\n\t\t\t*(dest + 3)  = (uint8) (((blendFact * *(src1 + 3)) + (invblendFact * *(src0 + 3))) >> 8);\n\n\t\t\tsrc0 = src0 + 4;\n\t\t\tsrc1 = src1 + 4;\n\t\t\tdest = dest + 4;\n\t\t}\n\t\twhile (dest != endPix);\n\t}\n}\n\n\n\n//-----------------------------------------------\nCRGBA CBitmap::getRGBAPixel(sint x, sint y, uint32 numMipMap /*=0*/) const\n{\n\tuint w = getWidth(numMipMap);\n\tuint h = getHeight(numMipMap);\n\tif (w == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases\n\tconst uint8 *pix = &getPixels(numMipMap)[(x + y * w) << 2];\n\treturn CRGBA(pix[0], pix[1], pix[2], pix[3]);\n}\n\n//-----------------------------------------------\nCRGBA CBitmap::getDXTCColorFromBlock(const uint8 *block, sint x, sint y)\n{\n\tuint16  col0;\n\tuint16  col1;\n\tmemcpy(&col0, block, sizeof(uint16));\n\tmemcpy(&col1, block + 2, sizeof(uint16));\n\tuint\tcolIndex = (block[4 + (y & 3)] >> ((x & 3) << 1)) & 3;\n\tCRGBA   result, c0, c1;\n\tif (col0 > col1)\n\t{\n\t\tswitch(colIndex)\n\t\t{\n\t\t\tcase 0:\n\t\t\t\tuncompress(col0, result);\n\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tuncompress(col1, result);\n\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tuncompress(col0, c0);\n\t\t\t\tuncompress(col1, c1);\n\t\t\t\tresult.blendFromui(c0, c1, 85);\n\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tuncompress(col0, c0);\n\t\t\t\tuncompress(col1, c1);\n\t\t\t\tresult.blendFromui(c0, c1, 171);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t;\n\t\t}\n\t\tresult.A = 255;\n\t}\n\telse\n\t{\n\t\tswitch(colIndex)\n\t\t{\n\t\t\tcase 0:\n\t\t\t\tuncompress(col0, result);\n\t\t\t\tresult.A = 255;\n\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tuncompress(col1, result);\n\t\t\t\tresult.A = 255;\n\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tuncompress(col0, c0);\n\t\t\t\tuncompress(col1, c1);\n\t\t\t\tresult.blendFromui(c0, c1, 128);\n\t\t\t\tresult.A = 255;\n\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tresult.set(0, 0, 0, 0);\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn result;\n}\n\n//-----------------------------------------------\nCRGBA CBitmap::getDXTC1Texel(sint x, sint y, uint32 numMipMap) const\n{\n\tuint w = getWidth(numMipMap);\n\tuint h = getHeight(numMipMap);\n\tif (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases\n\tuint numRowBlocks   = std::max((w + 3) >> 2, 1u);\n\tconst uint8 *pix    = &getPixels(numMipMap)[0];\n\tconst uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 3) + ((x >> 2) << 3));\n\treturn getDXTCColorFromBlock(block, x, y);\n}\n\n\n//-----------------------------------------------\nCRGBA CBitmap::getDXTC3Texel(sint x, sint y, uint32 numMipMap) const\n{\n\tuint w = getWidth(numMipMap);\n\tuint h = getHeight(numMipMap);\n\tif (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases\n\tuint numRowBlocks   = std::max((w + 3) >> 2, 1u);\n\tconst uint8 *pix    = &getPixels(numMipMap)[0];\n\tconst uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));\n\tCRGBA result = getDXTCColorFromBlock(block + 8, x, y);\n\t// get alpha part\n\tuint8 alphaByte = block[((y & 3) << 1) + ((x & 2) >> 1)];\n\tresult.A = (x & 1) ?  (alphaByte & 0xf0) : ((alphaByte & 0x0f) << 4);\n\treturn result;\n}\n\n//-----------------------------------------------\nCRGBA CBitmap::getDXTC5Texel(sint x, sint y, uint32 numMipMap) const\n{\n\tuint w = getWidth(numMipMap);\n\tuint h = getHeight(numMipMap);\n\tif (w == 0 || h == 0 || (uint) x >= w || (uint) y >= h) return CRGBA::Black; // include negative cases\n\tuint numRowBlocks   = std::max((w + 3) >> 2, 1u);\n\tconst uint8 *pix    = &getPixels(numMipMap)[0];\n\tconst uint8 *block  = pix + ((y >> 2) * (numRowBlocks << 4) + ((x >> 2) << 4));\n\tCRGBA result = getDXTCColorFromBlock(block + 8, x, y);\n\t// get alpha part\n\tuint8 alpha0 = block[0];\n\tuint8 alpha1 = block[1];\n\n\tuint alphaIndex;\n\tuint tripletIndex = (x & 3) + ((y & 3) << 2);\n\tif (tripletIndex < 8)\n\t{\n\t\talphaIndex = (((uint32 &) block[2]) >> (tripletIndex * 3)) & 7;\n\t}\n\telse\n\t{\n\t\talphaIndex = (((uint32 &) block[5]) >> ((tripletIndex - 8) * 3)) & 7; // we can read a dword there because there are color datas following he alpha datas\n\t}\n\n\tif (alpha0 > alpha1)\n\t{\n\t\tswitch (alphaIndex)\n\t\t{\n\t\t\tcase 0: result.A = alpha0; break;\n\t\t\tcase 1: result.A = alpha1; break;\n\t\t\tcase 2: result.A = (uint8) ((6 * (uint) alpha0 + (uint) alpha1) / 7); break;\n\t\t\tcase 3: result.A = (uint8) ((5 * (uint) alpha0 + 2 * (uint) alpha1) / 7); break;\n\t\t\tcase 4: result.A = (uint8) ((4 * (uint) alpha0 + 3 * (uint) alpha1) / 7); break;\n\t\t\tcase 5: result.A = (uint8) ((3 * (uint) alpha0 + 4 * (uint) alpha1) / 7); break;\n\t\t\tcase 6: result.A = (uint8) ((2 * (uint) alpha0 + 5 * (uint) alpha1) / 7); break;\n\t\t\tcase 7: result.A = (uint8) (((uint) alpha0 + (uint) 6 * alpha1) / 7); break;\n\t\t}\n\t}\n\telse\n\t{\n\t\tswitch (alphaIndex)\n\t\t{\n\t\t\tcase 0: result.A = alpha0; break;\n\t\t\tcase 1: result.A = alpha1; break;\n\t\t\tcase 2: result.A = (uint8) ((4 * (uint) alpha0 + (uint) alpha1) / 5); break;\n\t\t\tcase 3: result.A = (uint8) ((3 * (uint) alpha0 + 2 * (uint) alpha1) / 5); break;\n\t\t\tcase 4: result.A = (uint8) ((2 * (uint) alpha0 + 3 * (uint) alpha1) / 5); break;\n\t\t\tcase 5: result.A = (uint8) (((uint) alpha0 + 4 * (uint) alpha1) / 5); break;\n\t\t\tcase 6: result.A = 0;\tbreak;\n\t\t\tcase 7: result.A = 255; break;\n\t\t}\n\t}\n\treturn result;\n}\n\n\n//-----------------------------------------------\nCRGBA CBitmap::getPixelColor(sint x, sint y, uint32 numMipMap /*=0*/) const\n{\n\n\tswitch (PixelFormat)\n\t{\n\t\tcase RGBA:\n\t\t\treturn getRGBAPixel(x, y, numMipMap);\n\t\tcase DXTC1:\n\t\tcase DXTC1Alpha:\n\t\t\treturn getDXTC1Texel(x, y, numMipMap);\n\t\tcase DXTC3:\n\t\t\treturn getDXTC3Texel(x, y, numMipMap);\n\t\tcase DXTC5:\n\t\t\treturn getDXTC5Texel(x, y, numMipMap);\n\t\tdefault:\n\t\t\tnlstop;\n\t\tbreak;\n\t}\n\treturn CRGBA::Black;\n}\n\n\n//-----------------------------------------------\nvoid CBitmap::swap(CBitmap &other)\n{\n\tstd::swap(PixelFormat, other.PixelFormat);\n\tstd::swap(_MipMapCount, other._MipMapCount);\n\tstd::swap(_LoadGrayscaleAsAlpha, other._LoadGrayscaleAsAlpha);\n\tstd::swap(_Width, other._Width);\n\tstd::swap(_Height, other._Height);\n\tfor(uint k = 0; k < MAX_MIPMAP; ++k)\n\t{\n\t\t_Data[k].swap(other._Data[k]);\n\t}\n}\n\n//-----------------------------------------------\nvoid CBitmap::unattachPixels(CObjectVector<uint8> *mipmapDestArray, uint maxMipMapCount /*=MAX_MIPMAP*/)\n{\n\tif (!mipmapDestArray) return;\n\tuint k;\n\tfor(k = 0; k < std::min((uint) _MipMapCount, maxMipMapCount); ++k)\n\t{\n\t\tmipmapDestArray[k].swap(_Data[k]);\n\t\t_Data[k].clear();\n\t}\n\tfor(; k < _MipMapCount; ++k)\n\t{\n\t\t_Data[k].clear();\n\t}\n\t#ifdef NL_DEBUG\n\t\t// check that remaining mipmaps are empty\n\t\tfor(; k < _MipMapCount; ++k)\n\t\t{\n\t\t\tnlassert(_Data[k].empty());\n\t\t}\n\t#endif\n\t_MipMapCount = 1;\n\t_Width = 0;\n\t_Height = 0;\n\tPixelFormat = RGBA;\n\t_LoadGrayscaleAsAlpha = true;\n}\n\n\n\n\nvoid CBitmap::getData(uint8*& extractData)\n{\n\n\tuint32 size=0;\n\tif(PixelFormat==RGBA)\n\t\tsize=_Width*_Height*4;\n\telse if(PixelFormat==Alpha||PixelFormat==Luminance)\n\t\tsize=_Width*_Height;\n\telse\n\t{\n\t\tnlstop;\n\t}\n\n\tfor(uint32 pix=0;pix<size;pix++)\n\t\textractData[pix]=_Data[0][pix];\n\n}\n\nvoid CBitmap::getDibData(uint8*& extractData)\n{\n\n\tuint32 lineSize=0,size;\n\tuint8** buf;\n\tbuf=new uint8*[_Height];\n\tif(PixelFormat==RGBA)\n\t{\n\t\tlineSize=_Width*4;\n\n\n\t}\n\telse if(PixelFormat==Alpha||PixelFormat==Luminance)\n\t{\n\t\tlineSize=_Width;\n\t}\n\telse\n\t{\n\t\tnlstop;\n\t}\n\n\tfor(sint32 i=_Height-1;i>=0;i--)\n\t{\n\t\tbuf[_Height-1-i]=&_Data[0][i*lineSize];\n\t}\n\n\tsize=lineSize*_Height;\n\n\tfor(uint32 line=0;line<_Height;line++)\n\t{\n\t\tfor(uint32 pix=0;pix<lineSize;pix++)\n\t\t\textractData[line*lineSize+pix]=_Data[0][size-(line+1)*lineSize+pix];\n\t}\n\tdelete []buf;\n\n}\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/bitmap_jpeg.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/bitmap.h\"\n\n#ifdef USE_JPEG\n#define XMD_H\n#undef FAR\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/file.h\"\n#include <csetjmp>\nextern \"C\"\n{\n\t#ifdef NL_COMP_MINGW\n\t#\tdefine HAVE_BOOLEAN\n\t#endif\n\t#include <jpeglib.h>\n}\n#endif\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n#ifdef USE_JPEG\n\nstatic NLMISC::IStream *JPGStream = NULL;\nstatic const uint32 JPGBufferSize = 4096;\nstatic uint32 JPGStreamSize = 0;\nstatic char JPGBuffer[JPGBufferSize];\n\nstruct my_error_mgr\n{\n\tstruct jpeg_error_mgr pub;\n\tjmp_buf setjmp_buffer;\n};\n\nvoid my_error_exit(j_common_ptr cinfo)\n{\n\tmy_error_mgr *myerr = (my_error_mgr *) cinfo->err;\n\n\tnlwarning(\"error while processing JPEG image\");\n\n\tlongjmp(myerr->setjmp_buffer, 1);\n}\n\nstatic void jpgDecompressInit(j_decompress_ptr cinfo)\n{\n\t// get stream size if possible\n\tif (JPGStream->seek(0, IStream::end))\n\t\tJPGStreamSize = JPGStream->getPos();\n\telse\n\t\tnlwarning(\"can't get JPEG stream size\");\n\n\t// reset current position to the beginning\n\tJPGStream->seek(0, IStream::begin);\n\n\tcinfo->src->next_input_byte = (unsigned char *)JPGBuffer;\n\tcinfo->src->bytes_in_buffer = 0;\n}\n\nstatic boolean jpgDecompressFill(j_decompress_ptr cinfo)\n{\n\tuint length = std::min(JPGBufferSize, JPGStreamSize - JPGStream->getPos());\n\n\ttry\n\t{\n\t\tJPGStream->serialBuffer((uint8*) JPGBuffer, length);\n\t}\n\tcatch(...)\n\t{\n\t\tnlwarning(\"error while reading JPEG image\");\n\t\tcinfo->src->next_input_byte = (unsigned char *)JPGBuffer;\n\t\tcinfo->src->bytes_in_buffer = 0;\n\t\treturn FALSE;\n\t}\n\n\tcinfo->src->next_input_byte = (unsigned char *)JPGBuffer;\n\tcinfo->src->bytes_in_buffer = length;\n\treturn TRUE;\n}\n\nstatic void jpgDecompressSkip(j_decompress_ptr cinfo, long num_bytes)\n{\n\tif (num_bytes > 0)\n\t{\n\t\twhile (num_bytes > (long) cinfo->src->bytes_in_buffer)\n\t\t{\n\t\t\tnum_bytes -= (long) cinfo->src->bytes_in_buffer;\n\t\t\tjpgDecompressFill(cinfo);\n\t\t}\n\n\t\tcinfo->src->next_input_byte += (size_t) num_bytes;\n\t\tcinfo->src->bytes_in_buffer -= (size_t) num_bytes;\n\t}\n}\n\nstatic void jpgDecompressTerm(j_decompress_ptr /* cinfo */)\n{\n}\n\nstatic jpeg_source_mgr jpgSourceManager = { NULL, 0,\n\tjpgDecompressInit, jpgDecompressFill, jpgDecompressSkip, jpeg_resync_to_restart, jpgDecompressTerm };\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\treadJPG\n\\*-------------------------------------------------------------------*/\nuint8 CBitmap::readJPG( NLMISC::IStream &f )\n{\n\tif(!f.isReading()) return false;\n\n\tstruct jpeg_decompress_struct cinfo;\n\n\t// set up errors manager\n\tstruct my_error_mgr jerr;\n\tcinfo.err = jpeg_std_error(&jerr.pub);\n\tjerr.pub.error_exit = my_error_exit;\n\n\tif (setjmp(jerr.setjmp_buffer))\n\t{\n\t\tjpeg_destroy_decompress(&cinfo);\n\t\tnlwarning(\"failed to setjump\");\n\t\treturn 0;\n\t}\n\n\t// set the stream to read from\n\tJPGStream = &f;\n\n\t// init decompress\n\tjpeg_create_decompress(&cinfo);\n\tcinfo.src = &jpgSourceManager;\n\n\t// read header of image\n\tif (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK)\n\t{\n\t\tjpeg_destroy_decompress(&cinfo);\n\t\tnlwarning(\"failed to read header\");\n\t\treturn 0;\n\t}\n\n\tuint dstChannels, srcChannels;\n\n\tif (cinfo.jpeg_color_space == JCS_GRAYSCALE)\n\t{\n\t\tdstChannels = 1;\n\t\tsrcChannels = 1;\n\t\tresize (cinfo.image_width, cinfo.image_height, _LoadGrayscaleAsAlpha ? Alpha : Luminance);\n\t}\n\telse\n\t{\n\t\t// force conversion of color spaces in RGB\n\t\tdstChannels = 4;\n\t\tsrcChannels = 3;\n\t\tcinfo.out_color_space = JCS_RGB;\n\t\tresize (cinfo.image_width, cinfo.image_height, RGBA);\n\t}\n\n\t// start decompression of image data\n\tif (!jpeg_start_decompress(&cinfo))\n\t{\n\t\tjpeg_destroy_decompress(&cinfo);\n\t\tnlwarning(\"failed to start decompressing\");\n\t\treturn 0;\n\t}\n\n\tJSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo,\n\t\tJPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);\n\n\tuint i, j;\n\n\twhile (cinfo.output_scanline < cinfo.output_height)\n\t{\n\t\tconst uint offset = cinfo.output_scanline * _Width * dstChannels;\n\n\t\tif (jpeg_read_scanlines(&cinfo, buffer, 1) != 1)\n\t\t{\n\t\t\tnlwarning(\"failed to read scanline\");\n\t\t\tbreak;\n\t\t}\n\n\t\tfor (i = 0; i < _Width; i++)\n\t\t{\n\t\t\tfor (j = 0; j < srcChannels; ++j)\n\t\t\t\t_Data[0][offset+i*dstChannels+j] = buffer[0][i*srcChannels+j];\n\n\t\t\tif (PixelFormat == RGBA)\n\t\t\t\t_Data[0][offset+i*dstChannels+j] = 255;\n\t\t}\n\t}\n\n\tif (!jpeg_finish_decompress(&cinfo))\n\t\tnlwarning(\"failed to finish decompressing\");\n\n\tjpeg_destroy_decompress(&cinfo);\n\n\tJPGStream = NULL;\n\n\treturn uint8(srcChannels * 8);\n}\n\nstatic void jpgCompressInit(j_compress_ptr cinfo)\n{\n\tcinfo->dest->next_output_byte = (unsigned char *)JPGBuffer;\n\tcinfo->dest->free_in_buffer = JPGBufferSize;\n}\n\nstatic boolean jpgCompressEmpty(j_compress_ptr cinfo)\n{\n\tJPGStream->serialBuffer((uint8*) JPGBuffer, JPGBufferSize);\n\tcinfo->dest->next_output_byte = (unsigned char *)JPGBuffer;\n\tcinfo->dest->free_in_buffer = JPGBufferSize;\n\treturn TRUE;\n}\n\nstatic void jpgCompressTerm(j_compress_ptr cinfo)\n{\n\tif(JPGBufferSize - cinfo->dest->free_in_buffer > 0)\n\t\tJPGStream->serialBuffer((uint8*) JPGBuffer, (uint)(JPGBufferSize - cinfo->dest->free_in_buffer));\n}\n\nstatic jpeg_destination_mgr jpgDestinationManager = { 0, 0,\n\tjpgCompressInit, jpgCompressEmpty, jpgCompressTerm };\n\n/*-------------------------------------------------------------------*\\\n\t\t\t\t\t\t\twriteJPG\n\\*-------------------------------------------------------------------*/\nbool CBitmap::writeJPG( NLMISC::IStream &f, uint8 quality)\n{\n\tif (f.isReading()) return false;\n\n\tif (PixelFormat > AlphaLuminance) return false;\n\tif (!_Width || !_Height) return false;\n\n\tstruct jpeg_compress_struct cinfo;\n\n\t// set up errors manager\n\tstruct my_error_mgr jerr;\n\tcinfo.err = jpeg_std_error(&jerr.pub);\n\tjerr.pub.error_exit = my_error_exit;\n\n\tif (setjmp(jerr.setjmp_buffer))\n\t{\n\t\tjpeg_destroy_compress(&cinfo);\n\t\tnlwarning(\"failed to setjump\");\n\t\treturn false;\n\t}\n\n\t// set the stream to write to\n\tJPGStream = &f;\n\n\t// init compress\n\tjpeg_create_compress(&cinfo);\n\n\tuint srcChannels, dstChannels;\n\n\tif (PixelFormat == RGBA)\n\t{\n\t\tsrcChannels = 4;\n\t\tdstChannels = cinfo.input_components = 3;\n\t\tcinfo.in_color_space = JCS_RGB;\n\t}\n\telse\n\t{\n\t\tsrcChannels = PixelFormat == AlphaLuminance ? 2:1;\n\t\tdstChannels = cinfo.input_components = 1;\n\t\tcinfo.in_color_space = JCS_GRAYSCALE;\n\t}\n\n\tcinfo.image_width = _Width;\n\tcinfo.image_height = _Height;\n\tcinfo.dest = &jpgDestinationManager;\n\n\t// set default compression parameters\n\tjpeg_set_defaults(&cinfo);\n\n\t// set image quality\n\tjpeg_set_quality(&cinfo, quality, TRUE);\n\n\t// start to compress image\n\tjpeg_start_compress(&cinfo, TRUE);\n\n\tJSAMPROW row_pointer[1];\n\trow_pointer[0] = new uint8[_Width*dstChannels];\n\n\tuint i, j;\n\n\twhile (cinfo.next_scanline < cinfo.image_height)\n\t{\n\t\tconst uint offset = cinfo.next_scanline * _Width * srcChannels;\n\n\t\tfor (i = 0; i < _Width; ++i)\n\t\t{\n\t\t\tfor (j = 0; j < dstChannels; ++j)\n\t\t\t{\n\t\t\t\trow_pointer[0][i*dstChannels+j] = (uint8) _Data[0][offset + i*srcChannels+j];\n\t\t\t}\n\t\t}\n\n\t\t// write image scanline\n\t\tif (jpeg_write_scanlines(&cinfo, row_pointer, 1) != 1)\n\t\t{\n\t\t\tnlwarning(\"failed to write scanline\");\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tjpeg_finish_compress(&cinfo);\n\tjpeg_destroy_compress(&cinfo);\n\n\tdelete row_pointer[0];\n\trow_pointer[0] = NULL;\n\tJPGStream = NULL;\n\n\treturn true;\n}\n\n#else\n\nbool CBitmap::writeJPG( NLMISC::IStream &/* f */, uint8 /* quality */)\n{\n\tnlwarning (\"You must compile NLMISC with USE_JPEG if you want jpeg support\");\n\treturn false;\n}\n\nuint8 CBitmap::readJPG( NLMISC::IStream &/* f */)\n{\n\tnlwarning (\"You must compile NLMISC with USE_JPEG if you want jpeg support\");\n\treturn 0;\n}\n\n#endif\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/bitmap_png.cpp",
    "content": "//// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n//// Copyright (C) 2010  Winch Gate Property Limited\n////\n//// This program is free software: you can redistribute it and/or modify\n//// it under the terms of the GNU Affero General Public License as\n//// published by the Free Software Foundation, either version 3 of the\n//// License, or (at your option) any later version.\n////\n//// This program is distributed in the hope that it will be useful,\n//// but WITHOUT ANY WARRANTY; without even the implied warranty of\n//// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n//// GNU Affero General Public License for more details.\n////\n//// You should have received a copy of the GNU Affero General Public License\n//// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n//\n//#include \"stdmisc.h\"\n//\n//#include \"nel/misc/bitmap.h\"\n//\n//#include \"nel/misc/stream.h\"\n//#include \"nel/misc/file.h\"\n//#include \"nel/misc/rgba.h\"\n//#include \"nel/misc/dynloadlib.h\"\n//#include <png.h>\n//#include <csetjmp>\n//\n//using namespace std;\n//\n//#ifdef DEBUG_NEW\n//\t#define new DEBUG_NEW\n//#endif\n//\n//namespace NLMISC\n//{\n//\n//static void readPNGData(png_structp png_ptr, png_bytep data, png_size_t length)\n//{\n//\tIStream *stream = static_cast<IStream*>(png_get_io_ptr(png_ptr));\n//\tif (stream)\n//\t\tstream->serialBuffer((uint8*)data, (uint)length);\n//}\n//\n//static void writePNGData(png_structp png_ptr, png_bytep data, png_size_t length)\n//{\n//\tIStream *stream = static_cast<IStream*>(png_get_io_ptr(png_ptr));\n//\tif (stream)\n//\t\tstream->serialBuffer((uint8*)data, (uint)length);\n//}\n//\n//static void setPNGWarning(png_struct * /* png_ptr */, const char* message)\n//{\n//\tnlwarning(message);\n//}\n//\n//static void setPNGError(png_struct *png_ptr, const char* message)\n//{\n//\tsetPNGWarning(png_ptr, message);\n//\n//\tlongjmp(png_jmpbuf(png_ptr), 1);\n//}\n//\n///*-------------------------------------------------------------------*\\\n//\t\t\t\t\t\t\treadPNG\n//\\*-------------------------------------------------------------------*/\n//uint8 CBitmap::readPNG( NLMISC::IStream &f )\n//{\n//\tif(!f.isReading()) return false;\n//\n//\t// initialize the info header\n//\tpng_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, setPNGError, setPNGWarning);\n//\n//\tif (png_ptr == NULL)\n//\t{\n//\t\tnlwarning(\"failed to create the png read struct\");\n//\t\treturn 0;\n//\t}\n//\n//\t// allocate/initialize the memory for image information.\n//\tpng_info *info_ptr = png_create_info_struct(png_ptr);\n//\n//\tif (info_ptr == NULL)\n//\t{\n//\t\tpng_destroy_read_struct(&png_ptr, NULL, NULL);\n//\t\tnlwarning(\"failed to create the png info struct\");\n//\t\treturn 0;\n//\t}\n//\n//\tif (setjmp(png_jmpbuf(png_ptr)))\n//\t{\n//\t\t// free all of the memory associated with the png_ptr and info_ptr\n//\t\tpng_destroy_read_struct(&png_ptr, &info_ptr, NULL);\n//\t\t// if we get here, we had a problem reading the file\n//\t\tnlwarning(\"failed to setjump\");\n//\t\treturn 0;\n//\t}\n//\n//\t// set the read function\n//\tpng_set_read_fn(png_ptr, (void*)&f, readPNGData);\n//\n//\t// set number of bit already read (in order to step back)\n//\tpng_set_sig_bytes(png_ptr, 4);\n//\n//\t// read header info and use it\n//\tpng_read_info(png_ptr, info_ptr);\n//\n//\t// get header infos\n//\tpng_uint_32 width, height;\n//\tint iBitDepth, iColorType;\n//\tpng_get_IHDR(png_ptr, info_ptr, &width, &height, &iBitDepth, &iColorType, NULL, NULL, NULL);\n//\n//\t// expand images of all color-type and bit-depth to 3x8 bit RGB images\n//\t// let the library process things like alpha, transparency, background\n//\tdouble dGamma;\n//\n//\t// make sure it will use 8 bits per channel\n//\tif (iBitDepth == 16)\n//\t\tpng_set_strip_16(png_ptr);\n//\telse if (iBitDepth < 8)\n//\t\tpng_set_packing(png_ptr);\n//\n//\t// expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel\n//\tif (iBitDepth < 8 || iColorType == PNG_COLOR_TYPE_PALETTE || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))\n//\t\tpng_set_expand(png_ptr);\n//\n//\t// if required set gamma conversion\n//\tif (png_get_gAMA(png_ptr, info_ptr, &dGamma))\n//\t\tpng_set_gamma(png_ptr, (double) 2.2, dGamma);\n//\n//\t// add alpha byte after each RGB triplet if it doesn't exist\n//\tpng_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);\n//\n//\t// after the transformations have been registered update info_ptr data\n//\tpng_read_update_info(png_ptr, info_ptr);\n//\n//\t// get again width, height and the new bit-depth and color-type\n//\tpng_get_IHDR(png_ptr, info_ptr, &width, &height, &iBitDepth, &iColorType, NULL, NULL, NULL);\n//\n//\t// at this point, the image must be converted to an 24bit image RGB\n//\n//\t// rowbytes is the width x number of channels\n//\tuint32 rowbytes = (uint32)png_get_rowbytes(png_ptr, info_ptr);\n//\tuint32 srcChannels = png_get_channels(png_ptr, info_ptr);\n//\n//\t// allocates buffer to copy image data\n//\tpng_bytepp row_pointers = (png_bytepp)png_malloc(png_ptr, height * sizeof(png_bytep));\n//\n//\tfor (uint row = 0; row < height; row++)\n//\t\trow_pointers[row] = (png_bytep)png_malloc(png_ptr, rowbytes);\n//\n//\t// effective read of the image\n//\tpng_read_image(png_ptr, row_pointers);\n//\n//\t// read rest of file, and get additional chunks in info_ptr\n//\tpng_read_end(png_ptr, info_ptr);\n//\n//\tuint32 dstChannels = 0, firstChannel = 0, lastChannel = 0;\n//\n//\tif (iColorType == PNG_COLOR_TYPE_RGBA || iColorType == PNG_COLOR_TYPE_RGB || iColorType == PNG_COLOR_TYPE_PALETTE)\n//\t{\n//\t\t// get all channels\n//\t\tdstChannels = 4;\n//\t\tfirstChannel = 0;\n//\t\tlastChannel = 3;\n//\t\tresize (width, height, RGBA);\n//\t}\n//\telse if (iColorType == PNG_COLOR_TYPE_GRAY)\n//\t{\n//\t\t// only get gray channel\n//\t\tdstChannels = 1;\n//\t\tfirstChannel = 0;\n//\t\tlastChannel = 0;\n//\t\tresize (width, height, _LoadGrayscaleAsAlpha ? Alpha : Luminance);\n//\t}\n//\telse if (iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)\n//\t{\n//\t\t// get gray and alpha channels\n//\t\tdstChannels = 2;\n//\t\tfirstChannel = 0;\n//\t\tlastChannel = 1;\n//\t\tresize (width, height, AlphaLuminance);\n//\t}\n//\telse\n//\t{\n//\t\tpng_error(png_ptr, \"unknown iColorType\");\n//\t}\n//\n//\tfor (uint32 y = 0; y < height; y++)\n//\t{\n//\t\tfor (uint32 x = 0; x < width; x++)\n//\t\t{\n//\t\t\tuint32 dstOffset = y*width*dstChannels+x*dstChannels;\n//\t\t\tconst uint32 srcOffset = x*srcChannels;\n//\n//\t\t\tfor (uint32 pix = firstChannel; pix <= lastChannel; pix++)\n//\t\t\t\t_Data[0][dstOffset++] = row_pointers[y][srcOffset+pix];\n//\t\t}\n//\t}\n//\n//\t// free allocated memory to copy each rows\n//\tfor (uint row = 0; row < height; row++)\n//\t\tpng_free(png_ptr, row_pointers[row]);\n//\n//\t// free allocated memory to copy the image\n//\tpng_free(png_ptr, row_pointers);\n//\n//\t// clean up after the read, and free any memory allocated\n//\tpng_destroy_read_struct(&png_ptr, &info_ptr, NULL);\n//\n//\t//return the size of a pixel, either 8,24,32 bit\n//\treturn uint8(dstChannels * iBitDepth);\n//}\n//\n///*-------------------------------------------------------------------*\\\n//\t\t\t\t\t\t\twritePNG\n//\\*-------------------------------------------------------------------*/\n//bool CBitmap::writePNG( NLMISC::IStream &f, uint32 d)\n//{\n//\tif(f.isReading()) return false;\n//\n//\tif (PixelFormat > AlphaLuminance) return false;\n//\tif (!_Width || !_Height) return false;\n//\n//\tif (d == 0) d = bitPerPixels[PixelFormat];\n//\n//\tif (d!=32 && d!=24 && d!=16 && d!=8) return false;\n//\n//\t// create image write structure\n//\tpng_struct *png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, setPNGError, setPNGWarning);\n//\n//\tif (!png_ptr)\n//\t{\n//\t\tnlwarning(\"couldn't save PNG image.\");\n//\t\treturn false;\n//\t}\n//\n//\t// create info structure\n//\tpng_info *info_ptr = png_create_info_struct(png_ptr);\n//\n//\tif (info_ptr == NULL)\n//\t{\n//\t\tpng_destroy_write_struct( &png_ptr, (png_info**)NULL );\n//\t\tnlwarning(\"couldn't save PNG image.\");\n//\t\treturn false;\n//\t}\n//\n//\tif (setjmp(png_jmpbuf(png_ptr)))\n//\t{\n//\t\tpng_destroy_write_struct( &png_ptr, (png_info**)NULL );\n//\t\tnlwarning(\"couldn't set setjmp\");\n//\t\treturn false;\n//\t}\n//\n//\t// set the write function\n//\tpng_set_write_fn(png_ptr, (void*)&f, writePNGData, NULL);\n//\n//\tint iColorType;\n//\t\n//\t// only RGBA color, RGB color and gray type are implemented\n//\tif (d == 8)\n//\t{\n//\t\tiColorType = PNG_COLOR_TYPE_GRAY;\n//\t}\n//\telse if (d == 16)\n//\t{\n//\t\tiColorType = PNG_COLOR_TYPE_GRAY_ALPHA;\n//\t}\n//\telse if (d == 24)\n//\t{\n//\t\tiColorType = PNG_COLOR_TYPE_RGB;\n//\t}\n//\telse\n//\t{\n//\t\tiColorType = PNG_COLOR_TYPE_RGBA;\n//\t}\n//\n//\t// we don't have to implement 16bits formats because NeL only uses 8bits\n//\tconst int iBitDepth = 8;\n//\n//\t// set correct values for PNG header\n//\tpng_set_IHDR(png_ptr, info_ptr, _Width, _Height, iBitDepth, iColorType,\n//\t\tPNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);\n//\n//\tpng_color_8 sig_bit;\n//\n//\tif (iColorType & PNG_COLOR_MASK_COLOR)\n//\t{\n//\t\tsig_bit.red = sig_bit.green = sig_bit.blue = (uint8)iBitDepth;\n//\t}\n//\telse\n//\t{\n//\t\tsig_bit.gray = (uint8)iBitDepth;\n//\t}\n//\n//\tif (iColorType & PNG_COLOR_MASK_ALPHA)\n//\t{\n//\t\tsig_bit.alpha = (uint8)iBitDepth;\n//\t}\n//\telse\n//\t{\n//\t\tsig_bit.alpha = 0;\n//\t}\n//\n//\t// set bit depths\n//\tpng_set_sBIT(png_ptr, info_ptr, &sig_bit);\n//\n//\t// Optional gamma chunk is strongly suggested if you have any guess\n//\t// as to the correct gamma of the image.\n////\tdouble gamma = 2.2;\n////\tpng_set_gAMA(png_ptr, info_ptr, gamma);\n//\n//\t// Optionally write comments into the image\n////\tpng_text text_ptr[3];\n////\ttext_ptr[0].key = \"Title\";\n////\ttext_ptr[0].text = \"Mona Lisa\";\n////\ttext_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;\n////\ttext_ptr[1].key = \"Author\";\n////\ttext_ptr[1].text = \"Leonardo DaVinci\";\n////\ttext_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;\n////\ttext_ptr[2].key = \"Description\";\n////\ttext_ptr[2].text = \"<long text>\";\n////\ttext_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;\n//\n////\tpng_set_text(png_ptr, info_ptr, text_ptr, 3);\n//\n//\t// write the file header information\n//\tpng_write_info(png_ptr, info_ptr);\n//\n//\t// shift the pixels up to a legal bit depth\n//\tpng_set_shift(png_ptr, &sig_bit);\n//\n//\t// pack pixels into bytes\n//\tpng_set_packing(png_ptr);\n//\n//\t// rowbytes is the width x number of channels\n//\tuint32 rowbytes = (uint32)png_get_rowbytes(png_ptr, info_ptr);\n//\tuint32 dstChannels = png_get_channels(png_ptr, info_ptr);\n//\n//\t// get channels number of bitmap\n//\tsint srcChannels = bitPerPixels[PixelFormat]/8;\n//\n//\t// get size of bitmap\n//\tsint height = _Height;\n//\tsint width = _Width;\n//\n//\t// allocates buffer to copy image data\n//\tpng_bytepp row_pointers = (png_bytepp)png_malloc(png_ptr, height * sizeof(png_bytep));\n//\n//\tfor (sint row = 0; row < height; row++)\n//\t\trow_pointers[row] = (png_bytep)png_malloc(png_ptr, rowbytes);\n//\n//\tsint y, x, i;\n//\n//\tfor(y=0; y<height; ++y)\n//\t{\n//\t\tfor(x=0; x<width; ++x)\n//\t\t{\n//\t\t\tconst uint srcOffset = y*width*srcChannels + x*srcChannels;\n//\t\t\tconst uint dstOffset = x*dstChannels;\n//\n//\t\t\tif (dstChannels <= 2 && srcChannels == 4)\n//\t\t\t{\n//\t\t\t\t// convert colors to gray\n//\t\t\t\trow_pointers[y][dstOffset] = CRGBA(_Data[0][srcOffset+0],\n//\t\t\t\t\t_Data[0][srcOffset+1], _Data[0][srcOffset+2]).toGray();\n//\n//\t\t\t\tif (sig_bit.alpha)\n//\t\t\t\t{\n//\t\t\t\t\t// copy alpha value\n//\t\t\t\t\trow_pointers[y][dstOffset+1] = _Data[0][srcOffset+3];\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\telse if (dstChannels >= 3 && srcChannels <= 2)\n//\t\t\t{\n//\t\t\t\t// convert gray to colors\n//\t\t\t\tfor(i=0; i<3; ++i)\n//\t\t\t\t{\n//\t\t\t\t\trow_pointers[y][dstOffset+i] = _Data[0][srcOffset];\n//\t\t\t\t}\n//\n//\t\t\t\tif (sig_bit.alpha)\n//\t\t\t\t{\n//\t\t\t\t\t// copy alpha value\n//\t\t\t\t\trow_pointers[y][dstOffset+3] = PixelFormat ==\n//\t\t\t\t\t\tLuminance ? 255:_Data[0][srcOffset+1];\n//\t\t\t\t}\n//\t\t\t}\n//\t\t\telse\n//\t\t\t{\n//\t\t\t\t// copy all values\n//\t\t\t\tfor(i=0; i<(sint)dstChannels; ++i)\n//\t\t\t\t{\n//\t\t\t\t\trow_pointers[y][dstOffset+i] = _Data[0][srcOffset+i];\n//\t\t\t\t}\n//\t\t\t}\n//\t\t}\n//\t}\n//\n//\t// writing image data\n//\tpng_write_image(png_ptr, row_pointers);\n//\n//\t// writing the rest of the file\n//\tpng_write_end(png_ptr, info_ptr);\n//\n//\t// free allocated memory to copy each rows\n//\tfor (sint row = 0; row < height; row++)\n//\t\tpng_free(png_ptr, row_pointers[row]);\n//\n//\t// free allocated memory to copy the image\n//\tpng_free(png_ptr, row_pointers);\n//\n//\t// clean up after the write, and free any memory allocated\n//\tpng_destroy_write_struct(&png_ptr, &info_ptr);\n//\n//\treturn true;\n//}\n//\n//}//namespace\n"
  },
  {
    "path": "code/nel/src/misc/block_memory.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/block_memory.h\"\n\n// remove stupid VC6 warnings\nvoid foo_block_memory_cpp() {}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\nbool\t\tNL3D_BlockMemoryAssertOnPurge= true;\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/bsphere.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/bsphere.h\"\n\nusing namespace\tNLMISC;\nusing namespace\tstd;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\nbool\tCBSphere::clipFront(const CPlane &p) const\n{\n\t// assume normalized planes.\n\n\t// if( SpherMax OUT )\treturn false.\n\tfloat\td= p*Center;\n\tif(d<-Radius)\n\t\treturn false;\n\n\treturn true;\n}\n\n\nbool\tCBSphere::clipBack(const CPlane &p) const\n{\n\t// assume normalized planes.\n\n\t// if( SpherMax OUT )\treturn false.\n\tfloat\td= p*Center;\n\tif(d>Radius)\n\t\treturn false;\n\n\treturn true;\n}\n\n\nbool\tCBSphere::include(const CVector &p) const\n{\n\tfloat\tr2= (p-Center).sqrnorm();\n\treturn (r2<=sqr(Radius));\n}\n\nbool\tCBSphere::include(const CBSphere &s) const\n{\n\t// if smaller than s, how could we include it???\n\tif(Radius<=s.Radius)\n\t\treturn false;\n\tfloat\tr2= (s.Center-Center).sqrnorm();\n\t// Because of prec test, Radius-s.Radius>0.\n\treturn  r2<=sqr(Radius-s.Radius);\n}\n\nbool\tCBSphere::intersect(const CBSphere &s) const\n{\n\tfloat\tr2= (s.Center-Center).sqrnorm();\n\n\treturn r2<=sqr(Radius+s.Radius);\n\n}\n\n\nvoid\tCBSphere::applyTransform(const CMatrix &mat, CBSphere &res)\n{\n\tres.Center= mat*Center;\n\n\tif(!mat.hasScalePart())\n\t\tres.Radius= Radius;\n\telse\n\t{\n\t\tif(mat.hasScaleUniform())\n\t\t\tres.Radius= Radius*mat.getScaleUniform();\n\t\telse\n\t\t{\n\t\t\t// must compute max of 3 axis.\n\t\t\tfloat\tm, mx;\n\t\t\tCVector\ti,j,k;\n\t\t\ti= mat.getI();\n\t\t\tj= mat.getJ();\n\t\t\tk= mat.getK();\n\t\t\t// take the max of the 3 axis.\n\t\t\tm= i.sqrnorm();\n\t\t\tmx= m;\n\t\t\tm= j.sqrnorm();\n\t\t\tmx= max(m, mx);\n\t\t\tm= k.sqrnorm();\n\t\t\tmx= max(m, mx);\n\n\t\t\t// result.\n\t\t\tres.Radius= Radius * (float)sqrt(mx);\n\t\t}\n\t}\n}\n\n\n// ***************************************************************************\nvoid\tCBSphere::setUnion(const CBSphere &sa, const CBSphere &sb)\n{\n\tfloat\tr2= (sb.Center-sa.Center).norm();\n\n\t// Name Sphere 0 the biggest one, and Sphere 1 the other\n\tconst CBSphere\t*s0;\n\tconst CBSphere\t*s1;\n\tif(sa.Radius>sb.Radius)\n\t{\n\t\ts0= &sa;\n\t\ts1= &sb;\n\t}\n\telse\n\t{\n\t\ts0= &sb;\n\t\ts1= &sa;\n\t}\n\tfloat\tr0= s0->Radius;\n\tfloat\tr1= s1->Radius;\n\n\t// If Sphere1 is included into Sphere0, then the union is simply Sphere0\n\tif(r2<=(r0-r1))\n\t{\n\t\t*this= *s0;\n\t}\n\telse\n\t{\n\t\t/* Compute the Union sphere Diameter. It is D= r0 + r2 + r1\n\t\t\tdo the draw, works for intersect and don't intersect case,\n\t\t\tacknowledge that Sphere1 not included inton Sphere0\n\t\t*/\n\t\tfloat\tdiameter= r0 + r2 + r1;\n\n\t\t// compute dir from big center to small one.\n\t\tCVector\tdir= s1->Center - s0->Center;\n\t\tdir.normalize();\n\n\t\t// Then finally set Radius and center\n\t\tCenter= s0->Center + dir * (diameter/2 - r0);\n\t\tRadius= diameter/2;\n\t}\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/buf_fifo.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/buf_fifo.h\"\n\nusing namespace std;\n\n#define DEBUG_FIFO 0\n\n// if 0, don't stat the time of different function\n#define STAT_FIFO 1\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n#ifdef BUFFIFO_TRACK_ALL_BUFFERS\nCBufFIFO::TAllBuffers\t\tCBufFIFO::_AllBuffers;\n#endif\n\n\nCBufFIFO::CBufFIFO() : _Buffer(NULL), _BufferSize(0), _Empty(true), _Head(NULL), _Tail(NULL), _Rewinder(NULL)\n{\n#ifdef BUFFIFO_TRACK_ALL_BUFFERS\n\t_AllBuffers.insert(this);\n#endif\n\n\t// reset statistic\n\t_BiggestBlock = 0;\n\t_SmallestBlock = 999999999;\n\t_BiggestBuffer = 0;\n\t_SmallestBuffer = 999999999;\n\t_Pushed = 0;\n\t_Fronted = 0;\n\t_Resized = 0;\n\t_PushedTime = 0;\n\t_FrontedTime = 0;\n\t_ResizedTime = 0;\n}\n\nCBufFIFO::~CBufFIFO()\n{\n#ifdef BUFFIFO_TRACK_ALL_BUFFERS\n\t_AllBuffers.erase(this);\n#endif\n\n\tif (_Buffer != NULL)\n\t{\n\t\tdelete []_Buffer;\n#if DEBUG_FIFO\n\t\tnldebug(\"%p delete\", this);\n#endif\n\t}\n}\n\nvoid\t CBufFIFO::push (const uint8 *buffer, uint32 s)\n{\n\t// if the buffer is more than 1 meg, there s surely a problem, no?\n//\tnlassert( buffer.size() < 1000000 ); // size check in debug mode\n\n#if STAT_FIFO\n\tTTicks before = CTime::getPerformanceTime();\n#endif\n\n#if DEBUG_FIFO\n\tnldebug(\"%p push(%d)\", this, s);\n#endif\n\n\tnlassert(s > 0 && s < pow(2.0, static_cast<double>(sizeof(TFifoSize)*8)));\n\n\t// stat code\n\tif (s > _BiggestBlock) _BiggestBlock = s;\n\tif (s < _SmallestBlock) _SmallestBlock = s;\n\t_Pushed++;\n\n\twhile (!canFit (s + sizeof (TFifoSize)))\n\t{\n\t\tresize(_BufferSize * 2);\n\t}\n\n\t*(TFifoSize *)_Head = s;\n\t_Head += sizeof(TFifoSize);\n\n\tCFastMem::memcpy(_Head, buffer, s);\n\n\t_Head += s;\n\n\t_Empty = false;\n\n#if STAT_FIFO\n\t// stat code\n\tTTicks after = CTime::getPerformanceTime();\n\t_PushedTime += after - before;\n#endif\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n}\n\nvoid CBufFIFO::push(const std::vector<uint8> &buffer1, const std::vector<uint8> &buffer2)\n{\n#if STAT_FIFO\n\tTTicks before = CTime::getPerformanceTime();\n#endif\n\n\tTFifoSize s = (TFifoSize)(buffer1.size() + buffer2.size());\n\n#if DEBUG_FIFO\n\tnldebug(\"%p push2(%d)\", this, s);\n#endif\n\n\tnlassert((buffer1.size() + buffer2.size ()) > 0 && (buffer1.size() + buffer2.size ()) < pow(2.0, static_cast<double>(sizeof(TFifoSize)*8)));\n\n\t// avoid too big fifo\n\tif (this->size() > 10000000)\n\t{\n\t\tthrow Exception (\"CBufFIFO::push(): stack full (more than 10mb)\");\n\t}\n\n\n\t// stat code\n\tif (s > _BiggestBlock) _BiggestBlock = s;\n\tif (s < _SmallestBlock) _SmallestBlock = s;\n\n\t_Pushed++;\n\n\t// resize while the buffer is enough big to accept the block\n\twhile (!canFit (s + sizeof (TFifoSize)))\n\t{\n\t\tresize(_BufferSize * 2);\n\t}\n\n\t// store the size of the block\n\t*(TFifoSize *)_Head = s;\n\t_Head += sizeof(TFifoSize);\n\n\t// store the block itself\n\tCFastMem::memcpy(_Head, &(buffer1[0]), buffer1.size());\n\tCFastMem::memcpy(_Head + buffer1.size(), &(buffer2[0]), buffer2.size());\n\t_Head += s;\n\n\t_Empty = false;\n\n#if STAT_FIFO\n\t// stat code\n\tTTicks after = CTime::getPerformanceTime();\n\t_PushedTime += after - before;\n#endif\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n}\n\nvoid CBufFIFO::pop ()\n{\n\tif (empty ())\n\t{\n\t\tnlwarning(\"BF: Try to pop an empty fifo!\");\n\t\treturn;\n\t}\n\n\tif (_Rewinder != NULL && _Tail == _Rewinder)\n\t{\n#if DEBUG_FIFO\n\t\tnldebug(\"%p pop rewind!\", this);\n#endif\n\n\t\t// need to rewind\n\t\t_Tail = _Buffer;\n\t\t_Rewinder = NULL;\n\t}\n\n\tTFifoSize s = *(TFifoSize *)_Tail;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p pop(%d)\", this, s);\n#endif\n\n#ifdef NL_DEBUG\n\t// clear the message to be sure user doesn't use it anymore\n\tmemset (_Tail, '-', s + sizeof (TFifoSize));\n#endif\n\n\t_Tail += s + sizeof (TFifoSize);\n\n\tif (_Tail == _Head) _Empty = true;\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n}\n\nuint8 CBufFIFO::frontLast ()\n{\n\tuint8\t*tail = _Tail;\n\n\tif (empty ())\n\t{\n\t\tnlwarning(\"BF: Try to get the front of an empty fifo!\");\n\t\treturn 0;\n\t}\n\n\tif (_Rewinder != NULL && tail == _Rewinder)\n\t{\n#if DEBUG_FIFO\n\t\tnldebug(\"%p front rewind!\", this);\n#endif\n\n\t\t// need to rewind\n\t\ttail = _Buffer;\n\t}\n\n\tTFifoSize s = *(TFifoSize *)tail;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p frontLast() returns %d \", this, s, *(tail+sizeof(TFifoSize)+size-1));\n#endif\n\n\treturn *(tail+sizeof(TFifoSize)+s-1);\n}\n\n\nvoid CBufFIFO::front (vector<uint8> &buffer)\n{\n\tuint8 *tmpbuffer;\n\tuint32 s=0;\n\n\tbuffer.clear ();\n\n\tfront (tmpbuffer, s);\n\n\tbuffer.resize (s);\n\n\tCFastMem::memcpy (&(buffer[0]), tmpbuffer, s);\n\n/*\tTTicks before = CTime::getPerformanceTime ();\n\n\tuint8\t*tail = _Tail;\n\n\tbuffer.clear ();\n\n\tif (empty ())\n\t{\n\t\tnlwarning(\"Try to get the front of an empty fifo!\");\n\t\treturn;\n\t}\n\n\t_Fronted++;\n\n\tif (_Rewinder != NULL && tail == _Rewinder)\n\t{\n#if DEBUG_FIFO\n\t\tnldebug(\"%p front rewind!\", this);\n#endif\n\n\t\t// need to rewind\n\t\ttail = _Buffer;\n\t}\n\n\tTFifoSize size = *(TFifoSize *)tail;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p front(%d)\", this, size);\n#endif\n\n\ttail += sizeof (TFifoSize);\n\n\tbuffer.resize (size);\n\n\tCFastMem::memcpy (&(buffer[0]), tail, size);\n\n\t// stat code\n\tTTicks after = CTime::getPerformanceTime ();\n\t_FrontedTime += after - before;\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n*/}\n\n\nvoid CBufFIFO::front (NLMISC::CMemStream &buffer)\n{\n\tuint8 *tmpbuffer;\n\tuint32 s;\n\n\tbuffer.clear ();\n\n\tfront (tmpbuffer, s);\n\n\tbuffer.fill (tmpbuffer, s);\n\n\t/*\n\tTTicks before = CTime::getPerformanceTime ();\n\n\tuint8\t*tail = _Tail;\n\n\tbuffer.clear ();\n\n\tif (empty ())\n\t{\n\t\tnlwarning(\"Try to get the front of an empty fifo!\");\n\t\treturn;\n\t}\n\n\t_Fronted++;\n\n\tif (_Rewinder != NULL && tail == _Rewinder)\n\t{\n#if DEBUG_FIFO\n\t\tnldebug(\"%p front rewind!\", this);\n#endif\n\n\t\t// need to rewind\n\t\ttail = _Buffer;\n\t}\n\n\tTFifoSize size = *(TFifoSize *)tail;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p front(%d)\", this, size);\n#endif\n\n\ttail += sizeof (TFifoSize);\n\n\t//buffer.resize (size);\n\t//CFastMem::memcpy (&(buffer[0]), tail, size);\n\n\tbuffer.fill (tail, size);\n\n\t// stat code\n\tTTicks after = CTime::getPerformanceTime ();\n\t_FrontedTime += after - before;\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif*/\n}\n\nvoid CBufFIFO::front (uint8 *&buffer, uint32 &s)\n{\n#if STAT_FIFO\n\tTTicks before = CTime::getPerformanceTime ();\n#endif\n\n\tuint8\t*tail = _Tail;\n\n\tif (empty ())\n\t{\n\t\tnlwarning(\"BF: Try to get the front of an empty fifo!\");\n\t\treturn;\n\t}\n\n\t_Fronted++;\n\n\tif (_Rewinder != NULL && tail == _Rewinder)\n\t{\n#if DEBUG_FIFO\n\t\tnldebug(\"%p front rewind!\", this);\n#endif\n\n\t\t// need to rewind\n\t\ttail = _Buffer;\n\t}\n\n\ts = *(TFifoSize *)tail;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p front(%d)\", this, s);\n#endif\n\n\ttail += sizeof (TFifoSize);\n\n#if STAT_FIFO\n\t// stat code\n\tTTicks after = CTime::getPerformanceTime ();\n\t_FrontedTime += after - before;\n#endif\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n\n\tbuffer = tail;\n}\n\n\n\nvoid CBufFIFO::clear ()\n{\n\t_Tail = _Head = _Buffer;\n\t_Rewinder = NULL;\n\t_Empty = true;\n}\n\nuint32 CBufFIFO::size ()\n{\n\tif (empty ())\n\t{\n\t\treturn 0;\n\t}\n\telse if (_Head == _Tail)\n\t{\n\t\t// buffer is full\n\t\tif (_Rewinder == NULL)\n\t\t\treturn _BufferSize;\n\t\telse\n\t\t\treturn (uint32)(_Rewinder - _Buffer);\n\t}\n\telse if (_Head > _Tail)\n\t{\n\t\treturn (uint32)(_Head - _Tail);\n\t}\n\telse if (_Head < _Tail)\n\t{\n\t\tnlassert (_Rewinder != NULL);\n\t\treturn (uint32)((_Rewinder - _Tail) + (_Head - _Buffer));\n\t}\n\tnlstop;\n\treturn 0;\n}\n\nvoid CBufFIFO::resize (uint32 s)\n{\n#if STAT_FIFO\n\tTTicks before = CTime::getPerformanceTime();\n#endif\n\n\tif (s == 0) s = 100;\n\n#if DEBUG_FIFO\n\tnldebug(\"%p resize(%d)\", this, s);\n#endif\n\n\tif (s > _BiggestBuffer) _BiggestBuffer = s;\n\tif (s < _SmallestBuffer) _SmallestBuffer = s;\n\n\t_Resized++;\n\n\tuint32 UsedSize = CBufFIFO::size();\n\n\t// create a new array and copy the old in the new one\n\tif (s < _BufferSize && UsedSize > s)\n\t{\n\t\t// problem, we don't have enough room for putting data => don't do it\n\t\tnlwarning(\"BF: Can't resize the FIFO because there's not enough room in the new wanted buffer (%d bytes needed at least)\", UsedSize);\n\t\treturn;\n\t}\n\n\tuint8 *NewBuffer = new uint8[s];\n\tif (NewBuffer == NULL)\n\t{\n\t\tnlerror(\"Not enough memory to resize the FIFO to %u bytes\", s);\n\t}\n#ifdef NL_DEBUG\n\t// clear the message to be sure user doesn't use it anymore\n\tmemset (NewBuffer, '-', s);\n#endif\n\n#if DEBUG_FIFO\n\tnldebug(\"%p new %d bytes\", this, s);\n#endif\n\n\t// copy the old buffer to the new one\n\t// if _Tail == _Head => empty fifo, don't copy anything\n\tif (!empty())\n\t{\n\t\tif (_Tail < _Head)\n\t\t{\n\t\t\tCFastMem::memcpy (NewBuffer, _Tail, UsedSize);\n\t\t}\n\t\telse if (_Tail >= _Head)\n\t\t{\n\t\t\tnlassert (_Rewinder != NULL);\n\n\t\t\tuint size1 = (uint)(_Rewinder - _Tail);\n\t\t\tCFastMem::memcpy (NewBuffer, _Tail, size1);\n\t\t\tuint size2 = (uint)(_Head - _Buffer);\n\t\t\tCFastMem::memcpy (NewBuffer + size1, _Buffer, size2);\n\n\t\t\tnlassert (size1+size2==UsedSize);\n\t\t}\n\t}\n\n\t// resync the circular pointer\n\t// Warning: don't invert these 2 lines position or it ll not work\n\t_Tail = NewBuffer;\n\t_Head = NewBuffer + UsedSize;\n\t_Rewinder = NULL;\n\n\t// delete old buffer if needed\n\tif (_Buffer != NULL)\n\t{\n\t\tdelete []_Buffer;\n#if DEBUG_FIFO\n\t\tnldebug (\"delete\", this);\n#endif\n\t}\n\n\t// affect new buffer\n\t_Buffer = NewBuffer;\n\t_BufferSize = s;\n\n#if STAT_FIFO\n\tTTicks after = CTime::getPerformanceTime();\n\t_ResizedTime += after - before;\n#endif\n\n#if DEBUG_FIFO\n\tdisplay ();\n#endif\n}\n\nvoid CBufFIFO::displayStats (CLog *log)\n{\n\tlog->displayNL (\"%p CurrentQueueSize: %d, TotalQueueSize: %d\", this, size(), _BufferSize);\n\tlog->displayNL (\"%p InQueue: %d\", this, _Pushed - _Fronted);\n\n\tlog->displayNL (\"%p BiggestBlock: %d, SmallestBlock: %d\", this, _BiggestBlock, _SmallestBlock);\n\tlog->displayNL (\"%p BiggestBuffer: %d, SmallestBuffer: %d\", this, _BiggestBuffer, _SmallestBuffer);\n\tlog->displayNL (\"%p Pushed: %d, PushedTime: total %\" NL_I64 \"d ticks, mean %f ticks\", this, _Pushed, _PushedTime, (_Pushed>0?(double)(sint64)_PushedTime / (double)_Pushed:0.0));\n\tlog->displayNL (\"%p Fronted: %d, FrontedTime: total %\" NL_I64 \"d ticks, mean %f ticks\", this, _Fronted, _FrontedTime, (_Fronted>0?(double)(sint64)_FrontedTime / (double)_Fronted:0.0));\n\tlog->displayNL (\"%p Resized: %d, ResizedTime: total %\" NL_I64 \"d ticks, mean %f ticks\", this, _Resized, _ResizedTime, (_Resized>0?(double)(sint64)_ResizedTime / (double)_Resized:0.0));\n}\n\nvoid CBufFIFO::display ()\n{\n\tint s = 64;\n\tint gran = s/30;\n\n\tchar str[1024];\n\n\tsmprintf(str, 1024, \"%p %p (%5d %5d) %p %p %p \", this, _Buffer, _BufferSize, CBufFIFO::size(), _Rewinder, _Tail, _Head);\n\n\tint i;\n\tfor (i = 0; i < (sint32) _BufferSize; i+= gran)\n\t{\n\t\tuint8 *pos = _Buffer + i;\n\t\tif (_Tail >= pos && _Tail < pos + gran)\n\t\t{\n\t\t\tif (_Head >= pos && _Head < pos + gran)\n\t\t\t{\n\t\t\t\tif (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)\n\t\t\t\t{\n\t\t\t\t\tstrncat (str, \"*\", 1);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstrncat (str, \"@\", 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstrncat (str, \"T\", 1);\n\t\t\t}\n\t\t}\n\t\telse if (_Head >= pos && _Head < pos + gran)\n\t\t{\n\t\t\tstrncat (str, \"H\", 1);\n\t\t}\n\t\telse if (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)\n\t\t{\n\t\t\tstrncat (str, \"R\", 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (strlen(str) < 1023)\n\t\t\t{\n\t\t\t\tuint32 p = (uint32)strlen(str);\n\t\t\t\tif (isprint(*pos))\n\t\t\t\t\tstr[p] = *pos;\n\t\t\t\telse\n\t\t\t\t\tstr[p] = '$';\n\n\t\t\t\tstr[p+1] = '\\0';\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (; i < s; i+= gran)\n\t{\n\t\tstrncat (str, \" \", 1);\n\t}\n#ifdef NL_DEBUG\n\tstrncat (str, \"\\n\", 1);\n#else\n\tstrncat (str, \"\\r\", 1);\n#endif\n\tDebugLog->display (str);\n}\n\nbool CBufFIFO::canFit (uint32 s)\n{\n\tif (_Tail == _Head)\n\t{\n\t\tif (empty())\n\t\t{\n\t\t\t// is the buffer large enough?\n\t\t\tif (_BufferSize >= s)\n\t\t\t{\n\t\t\t\t// reset the pointer\n#if DEBUG_FIFO\n\t\t\t\tnldebug(\"%p reset tail and head\", this);\n#endif\n\t\t\t\t_Head = _Tail = _Buffer;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// buffer not big enough\n#if DEBUG_FIFO\n\t\t\t\tnldebug(\"%p buffer full buffersize<size\", this);\n#endif\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// buffer full\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p buffer full h=t\", this);\n#endif\n\t\t\treturn false;\n\t\t}\n\t}\n\telse if (_Tail < _Head)\n\t{\n\t\tif (_Buffer + _BufferSize - _Head >= (sint32) s)\n\t\t{\n\t\t\t// can fit after _Head\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p fit after\", this);\n#endif\n\t\t\treturn true;\n\t\t}\n\t\telse if (_Tail - _Buffer >= (sint32) s)\n\t\t{\n\t\t\t// can fit at the beginning\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p fit at beginning\", this);\n#endif\n\t\t\t_Rewinder = _Head;\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p set the rewinder\", this);\n#endif\n\t\t\t_Head = _Buffer;\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// can't fit\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p no room t<h\", this);\n#endif\n\t\t\treturn false;\n\t\t}\n\t}\n\telse // the last case is : if (_Tail > _Head)\n\t{\n\t\tif (_Tail - _Head >= (sint32) s)\n\t\t{\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p fit t>h\", this);\n#endif\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n#if DEBUG_FIFO\n\t\t\tnldebug(\"%p no room t>h\", this);\n#endif\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\n#ifdef BUFFIFO_TRACK_ALL_BUFFERS\nNLMISC_CATEGORISED_COMMAND(misc, dumpAllBuffers, \"Dump all the fifo buffer\", \"no args\")\n{\n\tlog.displayNL(\"Dumping %u FIFO buffers :\", CBufFIFO::_AllBuffers.size());\n\n\tCBufFIFO::TAllBuffers::iterator first(CBufFIFO::_AllBuffers.begin()), last(CBufFIFO::_AllBuffers.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tCBufFIFO *buf = *first;\n\n\t\tlog.displayNL(\"Dumping buffer %p:\", buf);\n\n\t\tbuf->displayStats(&log);\n\t}\n\n\treturn true;\n}\n#endif\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/cdb.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n//////////////\n// Includes //\n//////////////\n#include \"nel/misc/cdb.h\"\n#include \"nel/misc/cdb_branch.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n\n////////////////\n// Namespaces //\n////////////////\nusing namespace std;\n\nnamespace NLMISC{\n\nCStringMapper *ICDBNode::_DBSM = NULL;\nbool ICDBNode::verboseDatabase = false;\n\n\nstd::string ICDBNode::getFullName()\n{\n\tCSString sTmp;\n\tsTmp.reserve(256);\n\t_buildFullName(sTmp);\n\treturn sTmp;\n//\tCCDBNodeBranch *pParent = getParent();\n//\tif (pParent == NULL)\n//\t\treturn _DBSM->localUnmap(_Name);\n//\tCSString sTmp;\n//\t_buildFullName(sTmp);\n//\tsTmp << \":\" << sTmp;\n//\treturn sTmp;\n\n//\t// climb the parent hierarchie\n//\twhile (pParent->getParent() != NULL)\n//\t\tpParent = pParent->getParent();\n//\n//\t// now build the full name in desc order\n//\twhile (p)\n//\n//\twhile (pParent->getParent() != NULL)\n//\t{\n//\t\tsTmp = *pParent->getName()) << \":\" << sTmp;\n//\t\tpParent = pParent->getParent();\n//\t}\n//\treturn sTmp;\n}\n\nvoid ICDBNode::_buildFullName(CSString &fullName)\n{\n\t// we do not want to recurse up to the ROOT node - we stop 1 level down from the root\n\tif (getParent() != NULL && getParent()->getParent() != NULL)\n\t{\n\t\tgetParent()->_buildFullName(fullName);\n\t\tfullName << \":\" << _DBSM->localUnmap(_Name);\n\t}\n\telse\n\t\tfullName = _DBSM->localUnmap(_Name);\n}\n\nvoid ICDBNode::releaseStringMapper()\n{\n\tif( _DBSM )\n\t\tdelete _DBSM;\n\t_DBSM = NULL;\n}\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_bank_handler.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/cdb_bank_handler.h\"\n\nnamespace NLMISC{\n\tCCDBBankHandler::CCDBBankHandler(uint maxbanks) :\n_CDBBankToUnifiedIndexMapping( maxbanks, std::vector< uint >() ),\n_FirstLevelIdBitsByBank( maxbanks )\n\t{\n\t\tstd::fill( _FirstLevelIdBitsByBank.begin(), _FirstLevelIdBitsByBank.end(), 0 );\n\t\tmaxBanks = maxbanks;\n\t}\n\n\tuint CCDBBankHandler::getUIDForBank( uint bank ) const\n\t{\n\t\tuint uid = static_cast< uint >( -1 );\n\n\t\tfor( uint i = 0; i < _UnifiedIndexToBank.size(); i++ )\n\t\t\tif( _UnifiedIndexToBank[ i ] == bank )\n\t\t\t\treturn i;\n\n\t\treturn uid;\n\t}\n\n\tuint CCDBBankHandler::getBankByName( const std::string &name ) const\n\t{\n\t\tuint b = static_cast< uint >( -1 );\n\n\t\tfor( uint i = 0; i < _CDBBankNames.size(); i++ )\n\t\t\tif( _CDBBankNames[ i ].compare( name ) == 0 )\n\t\t\t\treturn i;\n\n\t\treturn b;\n\t}\n\n\tvoid CCDBBankHandler::mapNodeByBank( const std::string &bankName )\n\t{\n\t\tuint b = getBankByName( bankName );\n\t\t// no such bank\n\t\tif( b == static_cast< uint >( -1 ) )\n\t\t\treturn;\n\t\t\n\t\t_CDBBankToUnifiedIndexMapping[ b ].push_back( _CDBLastUnifiedIndex );\n\t\t++_CDBLastUnifiedIndex;\n\t\t_UnifiedIndexToBank.push_back( b );\n\t}\n\n\tvoid CCDBBankHandler::fillBankNames( const char **strings, uint size )\n\t{\n\t\t_CDBBankNames.clear();\n\n\t\tfor( uint i = 0; i < size; i++ )\n\t\t\t_CDBBankNames.push_back( std::string( strings[ i ] ) );\n\t}\n\n\tvoid CCDBBankHandler::reset()\n\t{\n\t\tfor( std::vector< std::vector< uint > >::iterator itr =_CDBBankToUnifiedIndexMapping.begin();\n\t\t\titr != _CDBBankToUnifiedIndexMapping.end(); ++itr )\n\t\t\titr->clear();\n\n\t\t_UnifiedIndexToBank.clear();\n\t\t_CDBLastUnifiedIndex = 0;\n\t}\n\n\tvoid CCDBBankHandler::calcIdBitsByBank()\n\t{\n\t\tfor( uint bank = 0; bank != maxBanks; bank++ )\n\t\t{\n\t\t\tuint nbNodesOfBank = static_cast< uint >( _CDBBankToUnifiedIndexMapping[ bank ].size() );\n\t\t\tuint idb = 0; \n\t\t\t\n\t\t\tif ( nbNodesOfBank > 0 )\n\t\t\t\tfor ( idb = 1; nbNodesOfBank > unsigned( 1 << idb ) ; idb++ )\n\t\t\t\t\t;\n\n\t\t\t_FirstLevelIdBitsByBank[ bank ] = idb;\n\t\t}\n\t}\n\n\tvoid CCDBBankHandler::resize( uint newSize )\n\t{\n\t\treset();\n\n\t\t_CDBBankNames.clear();\n\t\t_CDBBankToUnifiedIndexMapping.clear();\n\t\t_FirstLevelIdBitsByBank.clear();\n\n\t\t_CDBBankToUnifiedIndexMapping.reserve( newSize );\n\t\t_FirstLevelIdBitsByBank.reserve( newSize );\n\t}\n}\n\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_branch.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n//#define TRACE_READ_DELTA\n//#define TRACE_WRITE_DELTA\n//#define TRACE_SET_VALUE\n\n\n\n\n//////////////\n// Includes //\n//////////////\n#include \"nel/misc/cdb_branch.h\"\n#include \"nel/misc/cdb_leaf.h\"\n#include \"nel/misc/xml_auto_ptr.h\"\n//#include <iostream.h>\n\n////////////////\n// Namespaces //\n////////////////\nusing namespace std;\n\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/progress_callback.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n#include \"nel/misc/bit_set.h\"\n#include \"nel/misc/cdb_bank_handler.h\"\n\n#include <libxml/parser.h>\n//#include <io.h>\n#include <fcntl.h>\n#include <string.h>\n\n#include <string>\n\n\nusing namespace std;\n\n\nnamespace NLMISC{\n\n//-----------------------------------------------\n//\tinit\n//\n//-----------------------------------------------\nstatic /*inline*/ void addNode( ICDBNode *newNode, std::string newName, CCDBNodeBranch* parent,\n\t\t\t\t\t\t    std::vector<ICDBNode *> &nodes, std::vector<ICDBNode *> &nodesSorted,\n\t\t\t\t\t\t\txmlNodePtr &child, const string& bankName,\n\t\t\t\t\t\t\tbool atomBranch, bool clientOnly,\n\t\t\t\t\t\t\tIProgressCallback &progressCallBack,\n\t\t\t\t\t\t\tbool mapBanks, CCDBBankHandler *bankHandler = NULL )\n{\n\tnodesSorted.push_back(newNode);\n\tnodes.push_back(newNode);\n\tnodes.back()->setParent(parent);\n\tnodes.back()->setAtomic( parent->isAtomic() || atomBranch );\n\tnodes.back()->init(child, progressCallBack);\n\n\t// Setup bank mapping for first-level node\n\tif ( mapBanks && (parent->getParent() == NULL) )\n\t{\n\t\tif ( ! bankName.empty() )\n\t\t{\n\t\t\tbankHandler->mapNodeByBank( bankName );\n\t\t\t//nldebug( \"CDB: Mapping %s for %s (node %u)\", newName.c_str(), bankName.c_str(), nodes.size()-1 );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror( \"Missing bank for first-level node %s\", newName.c_str() );\n\t\t}\n\t}\n}\n\nvoid CCDBNodeBranch::init( xmlNodePtr node, IProgressCallback &progressCallBack, bool mapBanks, CCDBBankHandler *bankHandler )\n{\n\txmlNodePtr child;\n\n\t_Sorted = false;\n\t// look for other branches within this branch\n\tuint countNode = CIXml::countChildren (node, \"branch\") + CIXml::countChildren (node, \"leaf\");\n\tuint nodeId = 0;\n\tfor (child = CIXml::getFirstChildNode (node, \"branch\"); child; \tchild = CIXml::getNextChildNode (child, \"branch\"))\n\t{\n\t\t// Progress bar\n\t\tprogressCallBack.progress ((float)nodeId/(float)countNode);\n\t\tprogressCallBack.pushCropedValues ((float)nodeId/(float)countNode, (float)(nodeId+1)/(float)countNode);\n\n\t\tCXMLAutoPtr name((const char*)xmlGetProp (child, (xmlChar*)\"name\"));\n\t\tCXMLAutoPtr count((const char*)xmlGetProp (child, (xmlChar*)\"count\"));\n\t\tCXMLAutoPtr bank((const char*)xmlGetProp (child, (xmlChar*)\"bank\"));\n\t\tCXMLAutoPtr atom((const char*)xmlGetProp (child, (xmlChar*)\"atom\"));\n\t\tCXMLAutoPtr clientonly((const char*)xmlGetProp (child, (xmlChar*)\"clientonly\"));\n\n\t\tstring sBank, sAtom, sClientonly;\n\t\tif ( bank ) sBank = bank.getDatas();\n\t\tif ( atom ) sAtom = (const char*)atom;\n\t\tif ( clientonly ) sClientonly = clientonly.getDatas();\n\t\tnlassert((const char *) name != NULL);\n\t\tif ((const char *) count != NULL)\n\t\t{\n\t\t\t// dealing with an array of entries\n\t\t\tuint countAsInt;\n\t\t\tfromString((const char*) count, countAsInt);\n\n\t\t\tfor (uint i=0;i<countAsInt;i++)\n\t\t\t{\n\t\t\t\t// Progress bar\n\t\t\t\tprogressCallBack.progress ((float)i/(float)countAsInt);\n\t\t\t\tprogressCallBack.pushCropedValues ((float)i/(float)countAsInt, (float)(i+1)/(float)countAsInt);\n\n//\t\t\t\tnlinfo(\"+ %s%d\",name,i);\n\t\t\t\tstring newName = string(name.getDatas())+toString(i);\n\t\t\t\taddNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom==\"1\", sClientonly==\"1\", progressCallBack, mapBanks, bankHandler );\n//\t\t\t\tnlinfo(\"-\");\n\n\t\t\t\t// Progress bar\n\t\t\t\tprogressCallBack.popCropedValues ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// dealing with a single entry\n//\t\t\tnlinfo(\"+ %s\",name);\n\t\t\tstring newName = string(name.getDatas());\n\t\t\taddNode( new CCDBNodeBranch(newName), newName, this, _Nodes, _NodesByName, child, sBank, sAtom==\"1\", sClientonly==\"1\", progressCallBack, mapBanks, bankHandler );\n//\t\t\tnlinfo(\"-\");\n\t\t}\n\n\t\t// Progress bar\n\t\tprogressCallBack.popCropedValues ();\n\t\tnodeId++;\n\t}\n\n\t// look for leaves of this branch\n\tfor (child = CIXml::getFirstChildNode (node, \"leaf\"); child; \tchild = CIXml::getNextChildNode (child, \"leaf\"))\n\t{\n\t\t// Progress bar\n\t\tprogressCallBack.progress ((float)nodeId/(float)countNode);\n\t\tprogressCallBack.pushCropedValues ((float)nodeId/(float)countNode, (float)(nodeId+1)/(float)countNode);\n\n\t\tCXMLAutoPtr name((const char*)xmlGetProp (child, (xmlChar*)\"name\"));\n\t\tCXMLAutoPtr count((const char*)xmlGetProp (child, (xmlChar*)\"count\"));\n\t\tCXMLAutoPtr bank((const char*)xmlGetProp (child, (xmlChar*)\"bank\"));\n\n\t\tstring sBank;\n\t\tif ( bank ) sBank = bank.getDatas();\n\t\tnlassert((const char *) name != NULL);\n\t\tif ((const char *) count != NULL)\n\t\t{\n\t\t\t// dealing with an array of entries\n\t\t\tuint countAsInt;\n\t\t\tfromString((const char *) count, countAsInt);\n\n\t\t\tfor (uint i=0;i<countAsInt;i++)\n\t\t\t{\n\t\t\t\t// Progress bar\n\t\t\t\tprogressCallBack.progress ((float)i/(float)countAsInt);\n\t\t\t\tprogressCallBack.pushCropedValues ((float)i/(float)countAsInt, (float)(i+1)/(float)countAsInt);\n\n//\t\t\t\tnlinfo(\"  %s%d\",name,i);\n\t\t\t\tstring newName = string(name.getDatas())+toString(i);\n\t\t\t\taddNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks, bankHandler );\n\n\t\t\t\t// Progress bar\n\t\t\t\tprogressCallBack.popCropedValues ();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n//\t\t\tnlinfo(\"  %s\",name);\n\t\t\tstring newName = string(name.getDatas());\n\t\t\taddNode( new CCDBNodeLeaf(newName), newName, this, _Nodes, _NodesByName, child, sBank, false, false, progressCallBack, mapBanks, bankHandler );\n\t\t}\n\n\t\t// Progress bar\n\t\tprogressCallBack.popCropedValues ();\n\t\tnodeId++;\n\t}\n\n\t// count number of bits required to store the id\n\tif ( (mapBanks) && (getParent() == NULL) )\n\t{\t\t\n\t\tnlassert( bankHandler != NULL );\n\t\tnlassertex( bankHandler->getUnifiedIndexToBankSize() == countNode, (\"Mapped: %u Nodes: %u\", bankHandler->getUnifiedIndexToBankSize(), countNode) );\n\t\tbankHandler->calcIdBitsByBank();\n\t\t_IdBits = 0;\n\t}\n\telse\n\t{\n\t\tif ( _Nodes.size() > 0 )\n\t\t\tfor ( _IdBits=1; _Nodes.size() > unsigned(1<<_IdBits) ; _IdBits++ ) {}\n\t\telse\n\t\t\t_IdBits = 0;\n\t}\n\n\tfind(\"\"); // Sort !\n}\n\n\n//-----------------------------------------------\n//\tattachChild\n//\n//-----------------------------------------------\nvoid CCDBNodeBranch::attachChild( ICDBNode * node, string nodeName )\n{\n\tnlassert(_Parent==NULL);\n\n\tif (node)\n\t{\n\t\tnode->setParent(this);\n\t\t_Nodes.push_back( node );\n\t\t//nldebug ( \"CDB: Attaching node\" );\n\t\t_NodesByName.push_back( node );\n\t\t_Sorted = false;\n#if NL_CDB_OPTIMIZE_PREDICT\n\t\t_PredictNode = node;\n#endif\n\t}\n\n} // attachChild //\n\n//-----------------------------------------------\n//\tgetLeaf\n//\n//-----------------------------------------------\nCCDBNodeLeaf *CCDBNodeBranch::getLeaf( const char *id, bool bCreate )\n{\n\t// get the last name piece\n\tconst char *last = strrchr( id, ':' );\n\tif( !last )\n\t\treturn NULL;\n\tICDBNode *pNode = find( &last[1] );\n\tif( !pNode && bCreate )\n\t{\n\t\tpNode = new CCDBNodeLeaf( id );\n\t\t_Nodes.push_back( pNode );\n\t\t_NodesByName.push_back( pNode );\n\t\t_Sorted = false;\n\t\tpNode->setParent(this);\n\t}\n\treturn dynamic_cast<CCDBNodeLeaf *>(pNode);\n}\n\n//-----------------------------------------------\n//\tgetNode\n//\n//-----------------------------------------------\nICDBNode * CCDBNodeBranch::getNode (const CTextId& id, bool bCreate)\n{\n\t// lookup next element from textid in my index => idx\n\tconst string &str = id.readNext();\n\n\tICDBNode *pNode = find(str);\n\t// If the node do not exists\n\tif ( pNode == NULL )\n\t{\n\t\tif (bCreate)\n\t\t{\n\t\t\t// Yoyo: must not be SERVER or LOCAL, cause definied through xml.\n\t\t\t// This may cause some important crash error\n\t\t\t//nlassert(id.size()>0);\n\t\t\t//nlassert(id.getElement(0)!=\"SERVER\");\n\t\t\t//nlassert(id.getElement(0)!=\"LOCAL\");\n\t\t\tICDBNode *newNode;\n\t\t\tif (id.getCurrentIndex() == id.size() )\n\t\t\t\tnewNode= new CCDBNodeLeaf (str);\n\t\t\telse\n\t\t\t\tnewNode= new CCDBNodeBranch (str);\n\n\t\t\t_Nodes.push_back( newNode );\n\t\t\t_NodesByName.push_back( newNode );\n\t\t\t_Sorted = false;\n\t\t\tnewNode->setParent(this);\n\t\t\tpNode = newNode;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\t}\n\n\t// get property from child\n\tif (!id.hasElements())\n\t\treturn pNode;\n\n\treturn pNode->getNode( id, bCreate );\n\n} // getNode //\n\n\n//-----------------------------------------------\n//\tgetNode\n//\n//-----------------------------------------------\nICDBNode * CCDBNodeBranch::getNode( uint16 idx )\n{\n\tif ( idx < _Nodes.size() )\n\t\treturn _Nodes[idx];\n\telse\n\t\treturn NULL;\n\n} // getNode //\n\n\n//-----------------------------------------------\n//\twrite\n//\n//-----------------------------------------------\nvoid CCDBNodeBranch::write( CTextId& id, FILE * f)\n{\n\tuint i;\n\tfor( i = 0; i < _Nodes.size(); i++ )\n\t{\n\t\tid.push (*_Nodes[i]->getName());\n\t\t_Nodes[i]->write(id,f);\n\t\tid.pop();\n\t}\n\n} // write //\n\n//-----------------------------------------------\n//\tgetProp\n//\n//-----------------------------------------------\nsint64 CCDBNodeBranch::getProp( CTextId& id )\n{\n\t// lookup next element from textid in my index => idx\n\tconst string &str = id.readNext();\n\tICDBNode *pNode = find( str );\n\tnlassert( pNode != NULL );\n\n\t// get property from child\n\treturn pNode->getProp( id );\n\n} // getProp //\n\n\n\n//-----------------------------------------------\n// setProp :\n// Set the value of a property (the update flag is set to true)\n// \\param id is the text id of the property/grp\n// \\param name is the name of the property\n// \\param value is the value of the property\n// \\return bool : 'true' if property found.\n//-----------------------------------------------\nbool CCDBNodeBranch::setProp( CTextId& id, sint64 value )\n{\n\n\t// lookup next element from textid in my index => idx\n\tconst string &str = id.readNext();\n\tICDBNode *pNode = find( str );\n\n\t// Property not found.\n\tif(pNode == NULL)\n\t{\n\t\tnlwarning(\"Property %s not found in %s\", str.c_str(), id.toString().c_str());\n\t\treturn false;\n\t}\n\n\t// set property in child\n\tpNode->setProp(id,value);\n\t// Done\n\treturn true;\n}// setProp //\n\n\n/*\n * Update the database from the delta, but map the first level with the bank mapping (see _CDBBankToUnifiedIndexMapping)\n */\nvoid CCDBNodeBranch::readAndMapDelta( TGameCycle gc, CBitMemStream& s, uint bank, CCDBBankHandler *bankHandler )\n{\n\tnlassert( ! isAtomic() ); // root node mustn't be atomic\n\n\t// Read index\n\tuint32 idx;\n\ts.serial( idx, bankHandler->getFirstLevelIdBits( bank ) );\n\n\t// Translate bank index -> unified index\n\tidx = bankHandler->getServerToClientUIDMapping( bank, idx );\n\tif (idx >= _Nodes.size())\n\t{\n\t\tthrow Exception (\"idx %d > _Nodes.size() %d \", idx, _Nodes.size());\n\t}\n\n\t// Display the Name if we are in verbose mode\n\tif ( verboseDatabase )\n\t{\n\t\tstring displayStr = string(\"Reading: \") +  *(_Nodes[idx]->getName());\n\t\t//CInterfaceManager::getInstance()->getChatOutput()->addTextChild( ucstring( displayStr ),CRGBA(255,255,255,255));\n\t\tnlinfo( \"CDB: %s%s %u/%d\", (!getParent())?\"[root] \":\"-\", displayStr.c_str(), idx, _IdBits );\n\t}\n\n\t// Apply delta to children nodes\n\t_Nodes[idx]->readDelta( gc, s );\n}\n\n\n//-----------------------------------------------\n//\treadDelta\n//\n//-----------------------------------------------\nvoid CCDBNodeBranch::readDelta( TGameCycle gc, CBitMemStream & f )\n{\n\tif ( isAtomic() )\n\t{\n\t\t// Read the atom bitfield\n\t\tuint nbAtomElements = countLeaves();\n\t\tif(verboseDatabase)\n\t\t\tnlinfo( \"CDB/ATOM: %u leaves\", nbAtomElements );\n\t\tCBitSet bitfield( nbAtomElements );\n\t\tf.readBits( bitfield );\n\t\tif ( ! bitfield.getVector().empty() )\n\t\t{\n\t\t\tif(verboseDatabase)\n\t\t\t{\n\t\t\t\tnldebug( \"CDB/ATOM: Bitfield: %s LastBits:\", bitfield.toString().c_str() );\n\t\t\t\tf.displayLastBits( bitfield.size() );\n\t\t\t}\n\t\t}\n\n\t\t// Set each modified property\n\t\tuint atomIndex;\n\t\tfor ( uint i=0; i!=bitfield.size(); ++i )\n\t\t{\n\t\t\tif ( bitfield[i] )\n\t\t\t{\n\t\t\t\tif(verboseDatabase)\n\t\t\t\t{\n\t\t\t\t\tnldebug( \"CDB/ATOM: Reading prop[%u] of atom\", i );\n\t\t\t\t}\n\n\t\t\t\tatomIndex = i;\n\t\t\t\tCCDBNodeLeaf *leaf = findLeafAtCount( atomIndex );\n\t\t\t\tif ( leaf )\n\t\t\t\t\tleaf->readDelta( gc, f );\n\t\t\t\telse\n\t\t\t\t\tnlwarning( \"CDB: Can't find leaf with index %u in atom branch %s\", i, getParent()?getName()->c_str():\"(root)\" );\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tuint32 idx;\n\n\t\tf.serial(idx,_IdBits);\n\n\t\tif (idx >= _Nodes.size())\n\t\t{\n\t\t\tthrow Exception (\"idx %d > _Nodes.size() %d \", idx, _Nodes.size());\n\t\t}\n\n\t\t// Display the Name if we are in verbose mode\n\t\tif ( verboseDatabase )\n\t\t{\n\t\t\tstring displayStr = string(\"Reading: \") +  *(_Nodes[idx]->getName());\n\t\t\t//CInterfaceManager::getInstance()->getChatOutput()->addTextChild( ucstring( displayStr ),CRGBA(255,255,255,255));\n\t\t\tnlinfo( \"CDB: %s%s %u/%d\", (!getParent())?\"[root] \":\"-\", displayStr.c_str(), idx, _IdBits );\n\t\t}\n\n\t\t_Nodes[idx]->readDelta(gc, f);\n\t}\n}// readDelta //\n\n\n\n//-----------------------------------------------\n//\tclear\n//\n//-----------------------------------------------\n// For old debug of random crash (let it in case it come back)\n//static bool\tAllowTestYoyoWarning= true;\nvoid CCDBNodeBranch::clear()\n{\n\t// TestYoyo. Track the random crash at exit\n\t/*if(AllowTestYoyoWarning)\n\t{\n\t\tstd::string\tname= getFullName();\n\t\tnlinfo(\"** clear: %s\", name.c_str());\n\t}*/\n\n\tvector<ICDBNode *>::iterator itNode;\n\tfor( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t{\n\t\t(*itNode)->clear();\n\t\t// TestYoyo\n\t\t//AllowTestYoyoWarning= false;\n\t\tdelete (*itNode);\n\t\t//AllowTestYoyoWarning= true;\n\t}\n\t_Nodes.clear();\n\t_NodesByName.clear();\n\t// must remove all branch observers, to avoid any problem in subsequent flushObserversCalls()\n\tremoveAllBranchObserver();\n} // clear //\n\n\n/*\n * Find the leaf which count is specified (if found, the returned value is non-null and count is 0)\n */\nCCDBNodeLeaf *CCDBNodeBranch::findLeafAtCount( uint& count )\n{\n\tvector<ICDBNode *>::const_iterator itNode;\n\tfor ( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t{\n\t\tCCDBNodeLeaf *leaf = (*itNode)->findLeafAtCount( count );\n\t\tif ( leaf )\n\t\t\treturn leaf;\n\t}\n\treturn NULL;\n}\n\n/*\n * Count the leaves\n */\nuint CCDBNodeBranch::countLeaves() const\n{\n\tuint n = 0;\n\tvector<ICDBNode *>::const_iterator itNode;\n\tfor ( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t{\n\t\tn += (*itNode)->countLeaves();\n\t}\n\treturn n;\n}\n\n\nvoid CCDBNodeBranch::display (const std::string &prefix)\n{\n\tnlinfo(\"%sB %s\", prefix.c_str(), _DBSM->localUnmap(_Name).c_str());\n\tstring newPrefix = \" \" + prefix;\n\tvector<ICDBNode *>::const_iterator itNode;\n\tfor ( itNode = _Nodes.begin(); itNode != _Nodes.end(); ++itNode )\n\t{\n\t\t(*itNode)->display(newPrefix);\n\t}\n}\n\nvoid CCDBNodeBranch::removeNode (const CTextId& id)\n{\n\t// Look for the node\n\tCCDBNodeBranch *pNode = dynamic_cast<CCDBNodeBranch*>(getNode(id,false));\n\tif (pNode == NULL)\n\t{\n\t\tnlwarning(\"node %s not found\", id.toString().c_str());\n\t\treturn;\n\t}\n\tCCDBNodeBranch *pParent = pNode->_Parent;\n\tif (pParent== NULL)\n\t{\n\t\tnlwarning(\"parent node not found\");\n\t\treturn;\n\t}\n\t// search index node unsorted\n\tuint\tindexNode;\n\tfor (indexNode = 0; indexNode < pParent->_Nodes.size(); ++indexNode)\n\t\tif (pParent->_Nodes[indexNode] == pNode)\n\t\t\tbreak;\n\tif (indexNode == pParent->_Nodes.size())\n\t{\n\t\tnlwarning(\"node not found\");\n\t\treturn;\n\t}\n\t// search index node sorted\n\tuint\tindexSorted;\n\tfor (indexSorted = 0; indexSorted < pParent->_NodesByName.size(); ++indexSorted)\n\t\tif (pParent->_NodesByName[indexSorted] == pNode)\n\t\t\tbreak;\n\tif (indexSorted == pParent->_NodesByName.size())\n\t{\n\t\tnlwarning(\"node not found\");\n\t\treturn;\n\t}\n\n\t// Remove node from parent\n\tpParent->_Nodes.erase (pParent->_Nodes.begin()+indexNode);\n\tpParent->_NodesByName.erase (pParent->_NodesByName.begin()+indexSorted);\n\tpParent->_Sorted = false;\n\n\t// Delete the node\n\tpNode->clear();\n\tdelete pNode;\n}\n\nvoid CCDBNodeBranch::onLeafChanged( NLMISC::TStringId leafName )\n{\n\tfor( TObserverHandleList::iterator itr = observerHandles.begin(); itr != observerHandles.end(); ++itr )\n\t\tif( (*itr)->observesLeaf( *leafName ) )\n\t\t\t(*itr)->addToFlushableList();\n\n\tif( _Parent != NULL )\n\t\t_Parent->onLeafChanged( leafName );\n}\n\n\n//-----------------------------------------------\n//\taddObserver\n//\n//-----------------------------------------------\nbool CCDBNodeBranch::addObserver(IPropertyObserver* observer,CTextId& id)\n{\n\t//test if this node is the desired one, if yes, add the observer to all the children nodes\n\tif ( id.getCurrentIndex() == id.size() )\n\t{\n\t\tfor (uint i = 0; i < _Nodes.size(); ++i)\n\t\t{\n\t\t\tif (!_Nodes[i]->addObserver(observer,id))\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// lookup next element from textid in my index => idx\n\tconst string &str = id.readNext();\n\tICDBNode *pNode = find( str );\n\t// Property not found.\n\tif(pNode == NULL)\n\t{\n\t\tnlwarning(\" Property %s not found\", id.toString().c_str());\n\t\treturn false;\n\t}\n\n\t// set property in child\n\tpNode->addObserver(observer,id);\n\treturn true;\n\n} // addObserver //\n\n//-----------------------------------------------\n//\tremoveObserver\n//\n//-----------------------------------------------\nbool CCDBNodeBranch::removeObserver(IPropertyObserver* observer, CTextId& id)\n{\n\t//test if this node is the desired one, if yes, remove the observer to all the children nodes\n\tif ( id.getCurrentIndex() == id.size() )\n\t{\n\t\tfor (uint i = 0; i < _Nodes.size(); ++i)\n\t\t{\n\t\t\tif (!_Nodes[i]->removeObserver(observer, id))\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// lookup next element from textid in my index => idx\n\tconst string &str = id.readNext();\n\tICDBNode *pNode = find( str );\n\t// Property not found.\n\tif(pNode == NULL)\n\t{\n\t\tnlwarning(\" Property %s not found\", id.toString().c_str());\n\t\treturn false;\n\t}\n\n\t// remove observer in child\n\tpNode->removeObserver(observer,id);\n\treturn true;\n\n} // removeObserver //\n\n\n\n//-----------------------------------------------\nvoid CCDBNodeBranch::addBranchObserver( ICDBDBBranchObserverHandle *handle, const std::vector<std::string>& positiveLeafNameFilter)\n{\n\tCCDBNodeBranch::TObserverHandleList::iterator itr\n\t\t= std::find( observerHandles.begin(), observerHandles.end(), handle );\n\n\tif( itr != observerHandles.end() ){\n\t\tdelete handle;\n\t\treturn;\n\t}\n\n\tobserverHandles.push_back( handle );\n}\n\n//-----------------------------------------------\nvoid CCDBNodeBranch::addBranchObserver( ICDBDBBranchObserverHandle *handle, const char *dbPathFromThisNode, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize)\n{\n\tCCDBNodeBranch *branchNode;\n\tif (dbPathFromThisNode[0] == '\\0') // empty string\n\t{\n\t\tbranchNode = this;\n\t}\n\telse\n\t{\n\t\tbranchNode = safe_cast<CCDBNodeBranch*>(getNode(ICDBNode::CTextId(dbPathFromThisNode), false));\n\t\tif( branchNode == NULL ){\n\t\t\tstd::string msg = *getName();\n\t\t\tmsg += \":\";\n\t\t\tmsg += dbPathFromThisNode;\n\t\t\tmsg += \" branch missing in DB\";\n\n\t\t\tnlerror( msg.c_str() );\n\t\t\tdelete handle;\n\t\t\treturn;\n\t\t}\n\t}\n\tstd::vector<std::string> leavesToMonitor(positiveLeafNameFilterSize);\n\tfor (uint i=0; i!=positiveLeafNameFilterSize; ++i)\n\t{\n\t\tleavesToMonitor[i] = string(positiveLeafNameFilter[i]);\n\t}\n\tbranchNode->addBranchObserver(handle, leavesToMonitor);\n}\n\n//-----------------------------------------------\nvoid CCDBNodeBranch::removeBranchObserver(const char *dbPathFromThisNode, ICDBNode::IPropertyObserver& observer)\n{\n\tCCDBNodeBranch *branchNode = safe_cast<CCDBNodeBranch*>(getNode(ICDBNode::CTextId(dbPathFromThisNode), false));\n\tif( branchNode == NULL ){\n\t\tstd::string msg = *getName();\n\t\tmsg += \":\";\n\t\tmsg += dbPathFromThisNode;\n\t\tmsg += \" branch missing in DB\";\n\t\tnlerror( msg.c_str() );\n\t\treturn;\n\t}\n\tbranchNode->removeBranchObserver(&observer);\n}\n\n\n//-----------------------------------------------\nbool CCDBNodeBranch::removeBranchObserver(IPropertyObserver* observer)\n{\n\tbool found = false;\n\n\tTObserverHandleList::iterator itr = observerHandles.begin();\n\twhile( itr != observerHandles.end() )\n\t{\n\t\tif( (*itr)->observer() == observer )\n\t\t{\n\t\t\t(*itr)->removeFromFlushableList();\n\t\t\tdelete *itr;\n\t\t\titr = observerHandles.erase( itr );\n\t\t\tfound = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t++itr;\n\t\t}\n\t}\n\n\treturn found;\n}\n\n//-----------------------------------------------\nvoid CCDBNodeBranch::removeAllBranchObserver()\n{\n\tfor( TObserverHandleList::iterator itr = observerHandles.begin();\n\t\titr != observerHandles.end(); ++itr ){\n\t\t(*itr)->removeFromFlushableList();\n\t\tdelete *itr;\n\t}\n\n\tobserverHandles.clear();\n}\n\n//-----------------------------------------------\n// Useful for find\n//-----------------------------------------------\nclass CCDBNodeBranchComp : public std::binary_function<ICDBNode *, ICDBNode *, bool>\n{\npublic:\n\tbool operator()(const ICDBNode * x, const ICDBNode * y) const\n\t{\n\t\treturn *(x->getName()) < *(y->getName());\n\t}\n};\n\nclass CCDBNodeBranchComp2 : public std::binary_function<ICDBNode *, const string &, bool>\n{\npublic:\n\tbool operator()(const ICDBNode * x, const string & y) const\n\t{\n\t\treturn *(x->getName()) < y;\n\t}\n};\n\n\n//-----------------------------------------------\nICDBNode *CCDBNodeBranch::find(const std::string &nodeName)\n{\n#if NL_CDB_OPTIMIZE_PREDICT\n\tICDBNode *predictNode = _PredictNode;\n\tif (predictNode)\n\t{\n\t\tif (predictNode->getParent() == this \n\t\t\t&& *predictNode->getName() == nodeName)\n\t\t{\n\t\t\treturn predictNode;\n\t\t}\n\t}\n#endif\n\n\tif (!_Sorted)\n\t{\n\t\t_Sorted = true;\n\t\tsort(_NodesByName.begin(), _NodesByName.end(), CCDBNodeBranchComp());\n\t}\n\n\tCCDBNodeLeaf tmp(nodeName);\n\tvector<ICDBNode*>::iterator it = lower_bound(_NodesByName.begin(), _NodesByName.end(), &tmp, CCDBNodeBranchComp());\n\tif (it == _NodesByName.end())\n\t\treturn NULL;\n\telse\n\t{\n\t\tif (*(*it)->getName() == nodeName)\n\t\t{\n#if NL_CDB_OPTIMIZE_PREDICT\n\t\t\tICDBNode *node = *it;\n\t\t\t_PredictNode = node;\n\t\t\treturn node;\n#else\n\t\t\treturn *it;\n#endif\n\t\t}\n\t\telse\n\t\t\treturn NULL;\n\t}\n}\n\n\n\n#ifdef TRACE_READ_DELTA\n#undef TRACE_READ_DELTA\n#endif\n\n#ifdef TRACE_WRITE_DELTA\n#undef TRACE_WRITE_DELTA\n#endif\n\n#ifdef TRACE_SET_VALUE\n#undef TRACE_SET_VALUE\n#endif\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_branch_observing_handler.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/cdb_branch_observing_handler.h\"\n\nnamespace NLMISC{\n\tCCDBBranchObservingHandler::CCDBBranchObservingHandler()\n\t{\n\t\treset();\n\t}\n\n\tCCDBBranchObservingHandler::~CCDBBranchObservingHandler()\n\t{\n\t\treset();\n\t}\n\n\tvoid CCDBBranchObservingHandler::flushObserverCalls()\n\t{\n\t\tbool flushed = false;\n\n\t\tdo\n\t\t{\n\t\t\tflushed = false;\n\t\t\tuint oldList = currentList;\n\t\t\tcurrentList = 1 - currentList;\n\t\t\t\n\t\t\tstd::list< CCDBNodeBranch::ICDBDBBranchObserverHandle* >::iterator itr\n\t\t\t\t= flushableObservers[ oldList ].begin();\n\t\t\t\n\t\t\twhile( itr != flushableObservers[ oldList ].end() )\n\t\t\t{\n\t\t\t\tcurrentHandle = *itr;\n\t\t\t\t++itr;\n\t\t\t\t\n\t\t\t\tif( currentHandle->observer() != NULL )\n\t\t\t\t\tcurrentHandle->observer()->update( currentHandle->owner() );\n\t\t\t\t\n\t\t\t\t// Update might have removed it\n\t\t\t\tif( currentHandle != NULL )\n\t\t\t\t\tcurrentHandle->removeFromFlushableList( oldList );\n\n\t\t\t\tcurrentHandle = NULL;\n\t\t\t\tflushed = true;\n\t\t\t}\n\t\t\ttriggerFlushObservers();\n\n\t\t}while( flushed );\n\n\t\ttriggerFlushObservers();\n\t}\n\n\tvoid CCDBBranchObservingHandler::reset()\n\t{\n\t\tcurrentList = 0;\n\t\tcurrentHandle = NULL;\n\n\t\tfor( uint i = 0; i < MAX_OBS_LST; i++ )\n\t\t\tflushableObservers[ i ].clear();\n\t}\n\n\tvoid CCDBBranchObservingHandler::addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\n\t\tCCDBDBBranchObserverHandle *handle = new CCDBDBBranchObserverHandle( observer, branch, this );\n\t\tbranch->addBranchObserver( handle, positiveLeafNameFilter );\n\t}\n\n\tvoid CCDBBranchObservingHandler::addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\n\t\tCCDBDBBranchObserverHandle *handle = new CCDBDBBranchObserverHandle( &observer, branch, this );\n\t\tbranch->addBranchObserver( handle, dbPathFromThisNode, positiveLeafNameFilter, positiveLeafNameFilterSize );\n\t}\n\n\tvoid CCDBBranchObservingHandler::removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer )\n\t{\n\t\tbranch->removeBranchObserver( observer );\n\t}\n\n\tvoid CCDBBranchObservingHandler::removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer )\n\t{\n\t\tbranch->removeBranchObserver( dbPathFromThisNode, observer );\n\t}\n\t\n\tvoid CCDBBranchObservingHandler::triggerFlushObservers()\n\t{\n\t\tfor( std::vector< IBranchObserverCallFlushObserver* >::iterator itr = flushObservers.begin();\n\t\t\t itr != flushObservers.end(); itr++ )\n\t\t\t (*itr)->onObserverCallFlush();\n\t}\n\t\n\tvoid CCDBBranchObservingHandler::addFlushObserver( IBranchObserverCallFlushObserver *observer )\n\t{\n\t\tstd::vector< IBranchObserverCallFlushObserver* >::iterator itr\n\t\t\t= std::find( flushObservers.begin(), flushObservers.end(), observer );\n\t\t\n\t\tif( itr != flushObservers.end() )\n\t\t\treturn;\n\t\t\n\t\tflushObservers.push_back( observer );\n\t}\n\t\n\tvoid CCDBBranchObservingHandler::removeFlushObserver( IBranchObserverCallFlushObserver *observer )\n\t{\n\t\tstd::vector< IBranchObserverCallFlushObserver* >::iterator itr\n\t\t\t= std::find( flushObservers.begin(), flushObservers.end(), observer );\n\t\t\n\t\tif( itr == flushObservers.end() )\n\t\t\treturn;\n\t\t\n\t\tflushObservers.erase( itr );\n\t}\n\n\tCCDBBranchObservingHandler::CCDBDBBranchObserverHandle::CCDBDBBranchObserverHandle( NLMISC::ICDBNode::IPropertyObserver *observer, NLMISC::CCDBNodeBranch *owner, CCDBBranchObservingHandler *handler )\n\t{\n\t\tstd::fill( _inList, _inList + MAX_OBS_LST, false );\n\t\t_observer = observer;\n\t\t_owner = owner;\n\t\t_handler = handler;\n\t}\n\n\tCCDBBranchObservingHandler::CCDBDBBranchObserverHandle::~CCDBDBBranchObserverHandle()\n\t{\n\t\t_observer = NULL;\n\t}\n\n\tbool CCDBBranchObservingHandler::CCDBDBBranchObserverHandle::observesLeaf( const std::string &leafName )\n\t{\n\t\tif( !_observedLeaves.empty() ){\n\t\t\tstd::vector< std::string >::iterator itr\n\t\t\t\t= std::find( _observedLeaves.begin(), _observedLeaves.end(), leafName );\n\t\t\t\n\t\t\tif( itr == _observedLeaves.end() )\n\t\t\t\treturn false;\n\t\t\telse\n\t\t\t\treturn true;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tbool CCDBBranchObservingHandler::CCDBDBBranchObserverHandle::inList( uint list )\n\t{\n\t\treturn _inList[ list ];\n\t}\n\n\tvoid CCDBBranchObservingHandler::CCDBDBBranchObserverHandle::addToFlushableList()\n\t{\n\t\tuint list = _handler->currentList;\n\n\t\tif( _inList[ list ] )\n\t\t\treturn;\n\n\t\t_handler->flushableObservers[ list ].push_back( this );\n\t\t_inList[ list ] = true;\n\t}\n\n\tvoid CCDBBranchObservingHandler::CCDBDBBranchObserverHandle::removeFromFlushableList( uint list )\n\t{\n\t\tif( !_inList[ list ] )\n\t\t\treturn;\n\n\t\tstd::list< CCDBNodeBranch::ICDBDBBranchObserverHandle* >::iterator itr\n\t\t\t= std::find( _handler->flushableObservers[ list ].begin(),\n\t\t\t             _handler->flushableObservers[ list ].end(), this );\n\n\t\tif( itr == _handler->flushableObservers[ list ].end() )\n\t\t\treturn;\n\n\t\tif( _handler->currentHandle == this )\n\t\t\t_handler->currentHandle = NULL;\n\n\t\t_handler->flushableObservers[ list ].erase( itr );\n\t\t_inList[ list ] = false;\n\t\t\n\t}\n\n\tvoid CCDBBranchObservingHandler::CCDBDBBranchObserverHandle::removeFromFlushableList()\n\t{\n\t\tfor( uint i = 0; i < MAX_OBS_LST; i++ )\n\t\t\tremoveFromFlushableList( i );\n\t}\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_check_sum.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/cdb_check_sum.h\"\n\n\nnamespace NLMISC{\n\n/*\n * Constructor\n */\n\nCCDBCheckSum::CCDBCheckSum()\n{\n\t//arbitrary values\n\t_Sum = 0;\n\t_Factor = 55665;\n\t_Const1 = 52845;\n\t_Const2 = 22719;\n};\n\n///add an uint8 to the sum\nvoid CCDBCheckSum::add(uint8 el)\n{\n\tuint32 cipher = (el ^ (_Factor >> 8));\n\t_Factor = (cipher + _Factor) * _Const1 + _Const2;\n\t_Sum += cipher;\n}\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_leaf.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n//#define TRACE_READ_DELTA\n//#define TRACE_WRITE_DELTA\n//#define TRACE_SET_VALUE\n\n#define DELAYED_OBSERVERS\n\n//////////////\n// Includes //\n//////////////\n#include \"nel/misc/cdb_leaf.h\"\n#include \"nel/misc/xml_auto_ptr.h\"\n#include \"nel/misc/bit_mem_stream.h\"\n//#include <iostream.h>\n\n////////////////\n// Namespaces //\n////////////////\nusing namespace std;\n\nnamespace NLMISC{\n\n\n//-----------------------------------------------\n//\tinit\n//-----------------------------------------------\nvoid CCDBNodeLeaf::init(  xmlNodePtr node, IProgressCallback &/* progressCallBack */, bool /* mapBanks */, CCDBBankHandler * /* bankHandler */ )\n{\n\tCXMLAutoPtr type((const char*)xmlGetProp (node, (xmlChar*)\"type\"));\n\tnlassert((const char *) type != NULL);\n\n\t// IF type is an INT with n bits [1,64].\n\tif ((type.getDatas()[0] == 'I') || (type.getDatas()[0] == 'U'))\n\t{\n\t\tuint nbBit;\n\t\tfromString((const char *) (type.getDatas() + 1), nbBit);\n\n\t\tif(nbBit>=1 && nbBit<=64)\n\t\t\t_Type=(ICDBNode::EPropType)nbBit;\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"CCDBNodeLeaf::init : property is an INT and should be between [1,64] but it is %d bit(s).\", nbBit);\n\t\t\t_Type = ICDBNode::UNKNOWN;\n\t\t}\n\t}\n\telse if (type.getDatas()[0] == 'S')\n\t{\n\t\tuint nbBit;\n\t\tfromString((const char *) (type.getDatas() + 1), nbBit);\n\n\t\tif(nbBit>=1 && nbBit<=64)\n\t\t\t_Type = (ICDBNode::EPropType)(nbBit+64);\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"CCDBNodeLeaf::init : property is an SINT and should be between [1,64] but it is %d bit(s).\", nbBit);\n\t\t\t_Type = ICDBNode::UNKNOWN;\n\t\t}\n\t}\n\t// ELSE\n\telse\n\t{\n\t\t// IF it is a TEXT.\n\t\tif(!strcmp(type, \"TEXT\"))\n\t\t\t_Type = ICDBNode::TEXT;\n\t\t// ELSE type unknown.\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"CCDBNodeLeaf::init : type '%s' is unknown.\", type.getDatas());\n\t\t\t_Type = ICDBNode::UNKNOWN;\n\t\t}\n\t}\n\n} // init //\n\n\n//-----------------------------------------------\n//\tgetNode\n//\n//-----------------------------------------------\nICDBNode * CCDBNodeLeaf::getNode( uint16 /* idx */ )\n{\n\treturn this;\n} // getNode //\n\n\n//-----------------------------------------------\n//\tgetNode\n//\n//-----------------------------------------------\nICDBNode * CCDBNodeLeaf::getNode (const CTextId& id, bool /* bCreate */)\n{\n\tif (_DBSM->localUnmap(_Name) == id.readNext())\n\t{\n\t\tif (id.size() == id.getCurrentIndex())\n\t\t\treturn this;\n\t}\n\treturn NULL;\n} // getNode //\n\n//-----------------------------------------------\n//\twrite\n//\n//-----------------------------------------------\nvoid CCDBNodeLeaf::write( CTextId& id, FILE * f)\n{\n\tfprintf(f,\"%\" NL_I64 \"d\\t%s\\n\",_Property,id.toString().c_str());\n} // write //\n\n//-----------------------------------------------\n//\treadDelta\n//-----------------------------------------------\nvoid CCDBNodeLeaf::readDelta(TGameCycle gc, CBitMemStream & f )\n{\n\t// If the property Type is valid.\n\tif(_Type > UNKNOWN && _Type < Nb_Prop_Type)\n\t{\n\t\t// Read the Property Value according to the Property Type.\n\t\tuint64 recvd = 0;\n\t\tuint bits;\n\t\tif (_Type == TEXT)\n\t\t\tbits = 32;\n\t\telse if (_Type <= I64)\n\t\t\tbits = _Type;\n\t\telse\n\t\t\tbits = _Type - 64;\n\t\tf.serial(recvd, bits);\n\n\n\t\t// if the DB update is older than last DB update, abort (but after the read!!)\n\t\tif(gc<_LastChangeGC)\n\t\t\treturn;\n\n\t\t// bkup _oldProperty\n\t\t_oldProperty = _Property;\n\n\t\t// setup new one\n\t\t_Property = (sint64)recvd;\n\n\t\t// if signed\n\t\tif (! ((_Type == TEXT) || (_Type <= I64)))\n\t\t{\n\t\t\t// extend bit sign\n\t\t\tsint64 mask = (((sint64)1)<<bits)-(sint64)1;\n\t\t\tif( (_Property >> (bits-1))==1 )\n\t\t\t{\n\t\t\t\t_Property |= ~mask;\n\t\t\t}\n\t\t}\n\t\tif ( verboseDatabase )\n\t\t{\n\t\t\tnlinfo( \"CDB: Read value (%u bits) %\" NL_I64 \"d\", bits, _Property );\n\t\t}\n\n\t\t// bkup the date of change\n\t\t_LastChangeGC= gc;\n\n\t\tnotifyObservers();\n\n\t}\n\telse\n\t\tnlwarning(\"CCDBNodeLeaf::readDelta : Property Type Unknown ('%d') -> not serialized.\", (uint)_Type);\n}// readDelta //\n\n\n//-----------------------------------------------\n// resetData\n//-----------------------------------------------\nvoid CCDBNodeLeaf::resetData(TGameCycle gc, bool forceReset)\n{\n\tif(forceReset)\n\t{\n\t\t_LastChangeGC = 0;\n\t\tsetValue64(0);\n\t}\n\telse if (gc>=_LastChangeGC)\t// apply only if happens after the DB change\n\t{\n\t\t_LastChangeGC = gc;\n\t\tsetValue64(0);\n\t}\n\n//  Same version but without observer notification:\n//\tif ((!forceReset) && (gc<_LastChangeGC)) // if !forceReset, apply only if happens after the DB change\n//\t\treturn;\n//\n//\tif (forceReset)\n//\t\tgc = 0;\n//\n//\t_LastChangeGC = gc;\n//\t_oldProperty = _Property;\n//\tif (_Property != 0)\n//\t\t_Changed = true;\n//\t_Property = 0;\n}\n\n//-----------------------------------------------\n//\tgetProp\n//\n//-----------------------------------------------\nsint64 CCDBNodeLeaf::getProp( CTextId& id )\n{\n\t// assert that there are no lines left in the textid\n\tnlassert( id.getCurrentIndex() == id.size() );\n\n\t// Return the property value.\n\treturn getValue64();\n} // getProp //\n\n\n\n//-----------------------------------------------\n//\tsetProp\n// Set the value of a property (the update flag is set to true)\n// \\param id is the text id of the property/grp\n// \\param name is the name of the property\n// \\param value is the value of the property\n// \\return bool : 'false' if id is too long.\n//-----------------------------------------------\nbool CCDBNodeLeaf::setProp( CTextId& id, sint64 value )\n{\n\t// assert that there are no lines left in the textid\n\tif(id.getCurrentIndex() != id.size())\n\t\treturn false;\n\n\t// Set the property value (and set \"_Changed\" flag with 'true');\n\tCCDBNodeLeaf::setValue64(value);\n\n\t// Done\n\treturn true;\n}// setProp //\n\n\n//-----------------------------------------------\n//\tsetPropCheckGC\n//-----------------------------------------------\nbool CCDBNodeLeaf::setPropCheckGC(TGameCycle gc, sint64 value)\n{\n\t// Apply only if happens after the DB change\n\tif(gc>=_LastChangeGC)\n\t{\n\t\t// new recent date\n\t\t_LastChangeGC= gc;\n\n\t\t// Set the property value (and set \"_Changed\" flag with 'true');\n\t\tCCDBNodeLeaf::setValue64(value);\n\n\t\treturn true;\n\t}\n\telse\n\t\treturn false;\n}\n\n//-----------------------------------------------\n//\tclear\n//\n//-----------------------------------------------\nvoid CCDBNodeLeaf::clear()\n{\n\n} // clear //\n\n\n\n//-----------------------------------------------\n//-----------------------------------------------\nvoid CCDBNodeLeaf::setValue64(sint64 prop)\n{\n\tif (_Property != prop)\n\t{\n\t\tif (!_Changed)\n\t\t{\n\t\t\t_Changed = true;\n\t\t}\n\n\t\t_oldProperty = _Property;\n\t\t_Property = prop;\n\t\t// notify observer\n\t\tnotifyObservers();\n\t}\n}\n\nvoid CCDBNodeLeaf::setValue32(sint32 prop)\n{\n\tsint64 newVal = (sint64)prop;\n\tsetValue64(newVal);\n}\n\nvoid CCDBNodeLeaf::setValue16(sint16 prop)\n{\n\tsint64 newVal = (sint64)prop;\n\tsetValue64(newVal);\n\n}\n\nvoid CCDBNodeLeaf::setValue8(sint8 prop)\n{\n\tsint64 newVal = (sint64)prop;\n\tsetValue64(newVal);\n}\n\nvoid CCDBNodeLeaf::setValueBool(bool prop)\n{\n\tsint64 newVal = (sint64)prop;\n\tsetValue64(newVal);\n}\n\nvoid CCDBNodeLeaf::setValueRGBA (const CRGBA &color)\n{\n\tsint64 newVal = (uint32)(color.R+(color.G<<8)+(color.B<<16)+(color.A<<24));\n\tsetValue64(newVal);\n}\n\n\nvoid CCDBNodeLeaf::display(const std::string &prefix)\n{\n\tnlinfo(\"%sL %s\", prefix.c_str(), _DBSM->localUnmap(_Name).c_str());\n}\n\n//-----------------------------------------------\n//\taddObserver\n//\n//-----------------------------------------------\nbool CCDBNodeLeaf::addObserver(IPropertyObserver* observer,CTextId& /* id */)\n{\n\t_Observers.push_back(observer);\n\treturn true;\n}\n\n//-----------------------------------------------\n//\tremoveObserver\n//\n//-----------------------------------------------\nbool CCDBNodeLeaf::removeObserver(IPropertyObserver* observer, CTextId& /* id */)\n{\n\tstd::vector<IPropertyObserver *>::iterator endIt = std::remove(_Observers.begin(), _Observers.end(), observer);\n\tif (endIt == _Observers.end()) return false; // no observer has been removed..\n\t_Observers.erase(endIt, _Observers.end());\n\treturn true;\n}\n\n//-----------------------------------------------\nvoid CCDBNodeLeaf::notifyObservers()\n{\n\tstd::vector<IPropertyObserver*> obs = _Observers;\n\t// notify observer\n\tfor (std::vector<IPropertyObserver*>::const_iterator it = obs.begin(); it != obs.end(); it++)\n\t{\n\t\t(*it)->update(this);\n\t}\n\t// mark parent branchs\n\tif (_Parent)\n\t\t_Parent->onLeafChanged( _Name );\n}\n\n\n\n\n\n\n#ifdef TRACE_READ_DELTA\n#undef TRACE_READ_DELTA\n#endif\n\n#ifdef TRACE_WRITE_DELTA\n#undef TRACE_WRITE_DELTA\n#endif\n\n#ifdef TRACE_SET_VALUE\n#undef TRACE_SET_VALUE\n#endif\n//#############################################################################################\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/cdb_manager.cpp",
    "content": "// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/cdb_manager.h\"\n\nnamespace NLMISC{\n\n\tCCDBManager::CCDBManager( const char *rootNodeName, uint maxBanks ) : bankHandler( maxBanks )\n\t{\n\t\t_Database = new CCDBNodeBranch( std::string( rootNodeName ) );\n\t}\n\n\tCCDBManager::~CCDBManager()\n\t{\n\t\tif( _Database != NULL )\n\t\t{\n\t\t\t_Database->clear();\n\t\t\tdelete _Database;\n\t\t\t_Database = NULL;\n\t\t}\n\t}\n\n\tCCDBNodeLeaf* CCDBManager::getDbLeaf( const std::string &name, bool create )\n\t{\n\t\tif( name.empty() )\n\t\t\treturn NULL;\n\n\t\tCCDBNodeLeaf *leaf = NULL;\n\t\tleaf = dynamic_cast< CCDBNodeLeaf* >( _Database->getNode( ICDBNode::CTextId( name ), create ) );\n\t\treturn leaf;\n\t}\n\n\tCCDBNodeBranch* CCDBManager::getDbBranch( const std::string &name )\n\t{\n\t\tif( name.empty() )\n\t\t\treturn NULL;\n\t\t\n\t\tCCDBNodeBranch\t*branch = NULL;\n\t\tbranch = dynamic_cast< CCDBNodeBranch* >( _Database->getNode( ICDBNode::CTextId( name ), false ) );\n\t\treturn branch;\n\t}\n\n\n\tvoid CCDBManager::delDbNode( const std::string &name )\n\t{\n\t\tif( name.empty() )\n\t\t\treturn;\n\t\t\n\t\t_Database->removeNode( ICDBNode::CTextId( name ) );\n\t}\n\t\n\tvoid CCDBManager::addBranchObserver( const char *branchName, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter )\n\t{\n\t\tCCDBNodeBranch *b = dynamic_cast< CCDBNodeBranch* >( _Database->getNode( ICDBNode::CTextId( std::string( branchName ) ), false ) );\n\t\tif( b == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.addBranchObserver( b, observer, positiveLeafNameFilter );\n\t}\n\t\n\tvoid CCDBManager::addBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver *observer, const std::vector< std::string >& positiveLeafNameFilter )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.addBranchObserver( branch, observer, positiveLeafNameFilter );\n\t}\n\t\n\tvoid CCDBManager::addBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize )\n\t{\n\t\tCCDBNodeBranch *b = dynamic_cast< CCDBNodeBranch* >( _Database->getNode( ICDBNode::CTextId( std::string( branchName ) ), false ) );\n\t\tif( b == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.addBranchObserver( b, dbPathFromThisNode, observer, positiveLeafNameFilter, positiveLeafNameFilterSize );\n\t}\n\t\n\tvoid CCDBManager::addBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer, const char **positiveLeafNameFilter, uint positiveLeafNameFilterSize )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.addBranchObserver( branch, dbPathFromThisNode, observer, positiveLeafNameFilter, positiveLeafNameFilterSize );\n\t}\n\t\n\tvoid CCDBManager::removeBranchObserver( const char *branchName, ICDBNode::IPropertyObserver* observer )\n\t{\n\t\tCCDBNodeBranch *b = dynamic_cast< CCDBNodeBranch* >( _Database->getNode( ICDBNode::CTextId( std::string( branchName ) ), false ) );\n\t\tif( b == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.removeBranchObserver( b, observer );\n\t}\n\t\n\tvoid CCDBManager::removeBranchObserver( CCDBNodeBranch *branch, ICDBNode::IPropertyObserver* observer )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.removeBranchObserver( branch, observer );\n\t}\n\t\n\tvoid CCDBManager::removeBranchObserver( const char *branchName, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer )\n\t{\n\t\tCCDBNodeBranch *b = dynamic_cast< CCDBNodeBranch* >( _Database->getNode( ICDBNode::CTextId( std::string( branchName ) ), false ) );\n\t\tif( b == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.removeBranchObserver( b, dbPathFromThisNode, observer );\n\t}\n\t\n\tvoid CCDBManager::removeBranchObserver( CCDBNodeBranch *branch, const char *dbPathFromThisNode, ICDBNode::IPropertyObserver &observer )\n\t{\n\t\tif( branch == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.removeBranchObserver( branch, dbPathFromThisNode, observer );\n\t}\n\t\n\tvoid CCDBManager::addFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer )\n\t{\n\t\tif( observer == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.addFlushObserver( observer );\n\t}\n\t\n\tvoid CCDBManager::removeFlushObserver( CCDBBranchObservingHandler::IBranchObserverCallFlushObserver *observer )\n\t{\n\t\tif( observer == NULL )\n\t\t\treturn;\n\t\tbranchObservingHandler.removeFlushObserver( observer );\n\t}\n\t\n\tvoid CCDBManager::flushObserverCalls()\n\t{\n\t\tbranchObservingHandler.flushObserverCalls();\n\t}\n\n\tvoid CCDBManager::resetBank( uint gc, uint bank )\n\t{\n\t\t_Database->resetNode( gc, bankHandler.getUIDForBank( bank ) );\n\t}\n\n\tvoid CCDBManager::resizeBanks( uint newSize )\n\t{\n\t\tbankHandler.resize( newSize );\n\t}\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/check_fpu.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#include \"nel/misc/check_fpu.h\"\n#include \"nel/misc/fast_floor.h\"\n\n\n#pragma optimize(\"\", off )\n\n\nnamespace NLMISC\n{\n\n\nint\t\tCFpuChecker::_RefFpuCtrl= 0x00090013;\n\n\nCFpuChecker::CFpuChecker()\n{\n\tcheck();\n}\nCFpuChecker::~CFpuChecker()\n{\n\tcheck();\n}\n\nvoid CFpuChecker::dumpFpu(int value)\n{\n\tnlwarning(\"_MCW_DN = %s\", value & _MCW_DN ? \"_DN_FLUSH\" : \"_DN_SAVE\");\n\tnlwarning(\"_MCW_EM = %x\", _MCW_EM);\n\tswitch(value & _MCW_EM)\n\t{\n\t\tcase _EM_INVALID: nlwarning(\"_EM_INVALID\"); break;\n\t\tcase _EM_DENORMAL: nlwarning(\"_EM_DENORMAL\"); break;\n\t\tcase _EM_ZERODIVIDE: nlwarning(\"_EM_ZERODIVIDE\"); break;\n\t\tcase _EM_OVERFLOW: nlwarning(\"_EM_OVERFLOW\"); break;\n\t\tcase _EM_UNDERFLOW: nlwarning(\"_EM_UNDERFLOW\"); break;\n\t\tcase _EM_INEXACT: nlwarning(\"_EM_INEXACT\"); break;\n\t\tdefault:\n\t\t\tnlwarning(\"_MCW_EM = %x\", value & _MCW_EM);\n\t\tbreak;\n\t}\n\tnlwarning(\"_MCW_IC = %s\", value & _MCW_IC ? \"_IC_AFFINE\" : \"_IC_PROJECTIVE\");\n\tswitch(value & _MCW_RC)\n\t{\n\t\tcase _RC_CHOP: nlwarning(\"_RC_CHOP\"); break;\n\t\tcase _RC_UP: nlwarning(\"_RC_UP\"); ; break;\n\t\tcase _RC_DOWN: nlwarning(\"_RC_DOWN\"); break;\n\t\tcase _RC_NEAR: nlwarning(\"_RC_NEAR\"); break;\n\t}\n\tswitch(value & _MCW_PC)\n\t{\n\t\tcase _PC_24: nlwarning(\"_PC_24\"); break;\n\t\tcase _PC_53: nlwarning(\"_PC_53\"); ; break;\n\t\tcase _PC_64: nlwarning(\"_PC_64\"); break;\n\t}\n\n\n}\n\nvoid CFpuChecker::check()\n{\n#if defined(NL_OS_WINDOWS) && defined(NL_COMP_VC6)\n\t// don't Check if in a user control state\n\tif (NLMISC::OptFastFloorCWStackPtr != NLMISC::OptFastFloorCWStack) return;\n\n\t// check standard control state\n\tvolatile int cfp = _controlfp(0, 0);\n\tif ((cfp & ~_MCW_EM) != (_RefFpuCtrl & ~_MCW_EM))\n\t{\n\t\tnlwarning(\"Ref = \");\n\t\tnlwarning(\"=========================\");\n\t\tdumpFpu(_RefFpuCtrl);\n\t\tnlwarning(\"Current = \");\n\t\tnlwarning(\"=========================\");\n\t\tdumpFpu(cfp);\n\t\tnlassert(0);\n\t}\n#endif\n}\n\n}\n\n#endif // NL_OS_WINDOWS\n"
  },
  {
    "path": "code/nel/src/misc/class_id.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/class_id.h\"\n\n\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n\nconst\tCClassId\tCClassId::Null(0);\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/class_registry.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/class_registry.h\"\n#include \"nel/misc/debug.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n// ======================================================================================================\nCClassRegistry::TClassMap\t\t*CClassRegistry::RegistredClasses = NULL;\n\n\n// ======================================================================================================\nvoid\t\tCClassRegistry::init()\n{\n\tif (RegistredClasses == NULL)\n\t\tRegistredClasses = new TClassMap;\n}\n\n// ======================================================================================================\nvoid\t\tCClassRegistry::release()\n{\n\tif( RegistredClasses )\n\t\tdelete RegistredClasses;\n\tRegistredClasses = NULL;\n}\n\n// ======================================================================================================\nIClassable\t*CClassRegistry::create(const string &className)  throw(ERegistry)\n{\n\tinit();\n\n\tTClassMap::iterator\tit;\n\n\tit=RegistredClasses->find(className);\n\n\tif(it==RegistredClasses->end())\n\t\treturn NULL;\n\telse\n\t{\n\t\tIClassable\t*ptr;\n\t\tptr=it->second.Creator();\n\t\t#ifdef NL_DEBUG\n\t\t\tnlassert(CClassRegistry::checkObject(ptr));\n\t\t#endif\n\t\treturn ptr;\n\t}\n\n}\n\n// ======================================================================================================\nvoid\t\tCClassRegistry::registerClass(const string &className, IClassable* (*creator)(), const string &typeidCheck)  throw(ERegistry)\n{\n\tinit();\n\n\tCClassNode\tnode;\n\tnode.Creator=creator;\n\tnode.TypeIdCheck= typeidCheck;\n\tstd::pair<TClassMap::iterator, bool> result;\n\tresult = RegistredClasses->insert(TClassMap::value_type(className, node));\n\tif(!result.second)\n\t{\n\t\tnlstop;\n\t\tthrow ERegisteredClass();\n\t}\n}\n\n// ======================================================================================================\nbool\t\tCClassRegistry::checkObject(IClassable* obj)\n{\n\tinit();\n\n\tTClassMap::iterator\tit;\n\tit=RegistredClasses->find(obj->getClassName());\n\tif(it==RegistredClasses->end())\n\t\treturn false;\n\n\tif( it->second.TypeIdCheck != string(typeid(*obj).name()) )\n\t\treturn false;\n\n\treturn true;\n}\n\n\n\n}\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/nel/src/misc/cmd_args.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/sstring.h\"\n\n#include \"nel/misc/cmd_args.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nbool CCmdArgs::haveArg(char argName) const\n{\n\tfor(uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif(_Args[i].size() >= 2 && _Args[i][0] == '-')\n\t\t{\n\t\t\tif(_Args[i][1] == argName)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nstd::string CCmdArgs::getArg(char argName) const\n{\n\tfor(uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif(_Args[i].size() >= 2 && _Args[i][0] == '-')\n\t\t{\n\t\t\tif(_Args[i][1] == argName)\n\t\t\t{\n\t\t\t\t/* Remove the first and last '\"' : \n\t\t\t\t-c\"C:\\Documents and Settings\\toto.tmp\" \n\t\t\t\twill return :\n\t\t\t\tC:\\Documents and Settings\\toto.tmp\n\t\t\t\t*/\n\t\t\t\tuint begin = 2;\n\t\t\t\tif(_Args[i].size() < 3)\n\t\t\t\t\treturn \"\";\n\t\t\t\t\t//throw Exception (\"Parameter '-%c' is malformed, missing content\", argName);\n\n\t\t\t\tif(_Args[i][begin] == '\"')\n\t\t\t\t\tbegin++;\n\n\t\t\t\t// End\n\t\t\t\tuint size = (uint)_Args[i].size();\n\t\t\t\tif(size && _Args[i][size-1] == '\"')\n\t\t\t\t\tsize--;\n\t\t\t\tsize = (uint)(std::max((int)0, (int)size-(int)begin));\n\t\t\t\treturn _Args[i].substr(begin, size);\n\t\t\t}\n\t\t}\n\t}\n\tthrow Exception(\"Parameter '-%c' is not found in command line\", argName);\n}\n\nbool CCmdArgs::haveLongArg(const char* argName) const\n{\n\tfor(uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif(_Args[i].left(2)==\"--\" && _Args[i].leftCrop(2).splitTo('=')==argName)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nstd::string CCmdArgs::getLongArg (const char* argName) const\n{\n        for (uint32 i = 0; i < _Args.size(); i++)\n        {\n\t\tif (_Args[i].left(2)==\"--\" && _Args[i].leftCrop(2).splitTo('=')==argName)\n\t\t{\n\t\t\tNLMISC::CSString val= _Args[i].splitFrom('=');\n\t\t\tif (!val.empty())\n\t\t\t{\n\t\t\t\treturn val.unquoteIfQuoted();\n\t\t\t}\n\t\t\tif (i+1<_Args.size() && _Args[i+1].c_str()[0]!='-')\n\t\t\t{\n\t\t\t\treturn _Args[i+1].unquoteIfQuoted();\n\t\t\t}\n\n\t\t\treturn std::string();\n\t\t}\n\t}\n\treturn std::string();\n}\n\nvoid CCmdArgs::setArgs(const char *args)\n{\n\t_Args.push_back (\"<ProgramName>\");\n\n\tstd::string sargs (args);\n\tstd::string::size_type pos1 = 0, pos2 = 0;\n\n\tdo\n\t{\n\t\t// Look for the first non space character\n\t\tpos1 = sargs.find_first_not_of (\" \", pos2);\n\t\tif(pos1 == std::string::npos) break;\n\n\t\t// Look for the first space or \"\n\t\tpos2 = sargs.find_first_of (\" \\\"\", pos1);\n\t\tif(pos2 != std::string::npos)\n\t\t{\n\t\t\t// \" ?\n\t\t\tif(sargs[pos2] == '\"')\n\t\t\t{\n\t\t\t\t// Look for the final \\\"\n\t\t\t\tpos2 = sargs.find_first_of (\"\\\"\", pos2+1);\n\t\t\t\tif(pos2 != std::string::npos)\n\t\t\t\t{\n\t\t\t\t\t// Look for the first space\n\t\t\t\t\tpos2 = sargs.find_first_of (\" \", pos2+1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Compute the size of the string to extract\n\t\tstd::string::difference_type length = (pos2 != std::string::npos) ? pos2-pos1 : std::string::npos;\n\n\t\tstd::string tmp = sargs.substr (pos1, length);\n\t\t_Args.push_back (tmp);\n\t}\n\twhile(pos2 != std::string::npos);\n}\n\nvoid CCmdArgs::setArgs(int argc, const char **argv)\n{\n\tfor (sint i = 0; i < argc; i++)\n\t{\n\t\t_Args.push_back (argv[i]);\n\t}\n}\n\n}; // NAMESPACE NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/co_task.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/co_task.h\"\n#include \"nel/misc/tds.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/debug.h\"\n\n// Flag to use thread instead of coroutine primitives (i.e windows fibers or gcc context)\n#ifndef NL_OS_WINDOWS\n#define NL_USE_THREAD_COTASK\n#endif\n// flag to activate debug message\n//#define NL_GEN_DEBUG_MSG\n\n#ifdef NL_GEN_DEBUG_MSG\n#define NL_CT_DEBUG nldebug\n#else\n#define NL_CT_DEBUG while(0)nldebug\n#endif\n\n#if defined(NL_USE_THREAD_COTASK)\n\t#ifndef __GNUC__\n\t#pragma message(NL_LOC_MSG \"Using threaded coroutine\")\n\t#endif\n\t# include \"nel/misc/thread.h\"\n#else //NL_USE_THREAD_COTASK\n// some platform specifics\n#if defined (NL_OS_WINDOWS)\n#\tdefine NL_WIN_CALLBACK CALLBACK\n#elif defined (NL_OS_UNIX)\n#\tdefine NL_WIN_CALLBACK\n#\tinclude <ucontext.h>\n#else\n#\terror \"Coroutine task are not supported yet by your platform, do it ?\"\n#endif\n#endif //NL_USE_THREAD_COTASK\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\t// platform specific data\n#if  defined(NL_USE_THREAD_COTASK)\n\tstruct TCoTaskData : public IRunnable\n#else //NL_USE_THREAD_COTASK\n\tstruct TCoTaskData\n#endif //NL_USE_THREAD_COTASK\n\t{\n#if  defined(NL_USE_THREAD_COTASK)\n\t\t/// The thread id for the co task\n//\t\tTThreadId\t*_TaskThreadId;\n\t\t/// The parent thread id\n//\t\tTThreadId\t*_ParentThreadId;\n\n\t\t// the thread of the task\n\t\tIThread\t\t\t\t*_TaskThread;\n\t\t/// The mutex of the task task\n\t\tCFastMutex\t\t\t_TaskMutex;\n\n\t\tCCoTask\t\t\t\t*_CoTask;\n\n\t\t// set by master, cleared by task\n\t\tvolatile bool\t\t_ResumeTask;\n\t\t// set by task, cleared by master\n\t\tvolatile bool\t\t_TaskHasYield;\n\n\n\t\tTCoTaskData(CCoTask *task)\n\t\t\t:\t_TaskThread(NULL),\n\t\t\t\t_CoTask(task),\n\t\t\t\t_ResumeTask(false),\n\t\t\t\t_TaskHasYield(false)\n\t\t{\n\t\t}\n\n\t\tvirtual ~TCoTaskData()\n\t\t{\n\t\t\tNL_CT_DEBUG(\"CoTaskData : ~TCoTaskData %p : deleting cotask data\", this);\n\t\t\tif (_TaskThread != NULL)\n\t\t\t{\n\t\t\t\tNL_CT_DEBUG(\"CoTask : ~TCoTaskData (%p) waiting for thread termination\", this);\n\n\t\t\t\t// waiting for thread to terminate\n\t\t\t\t_TaskThread->wait();\n\n\t\t\t\tdelete _TaskThread;\n\t\t\t\t_TaskThread = NULL;\n\t\t\t}\n\t\t}\n\n\t\tvoid run();\n\n#else //NL_USE_THREAD_COTASK\n#if defined (NL_OS_WINDOWS)\n\t\t/// The fiber pointer for the task fiber\n\t\tLPVOID\t_Fiber;\n\t\t/// The fiber pointer of the main (or master, or parent, as you want)\n\t\tLPVOID\t_ParentFiber;\n#elif defined (NL_OS_UNIX)\n\t\t/// The coroutine stack pointer (allocated memory)\n\t\tuint8\t\t*_Stack;\n\t\t/// The task context\n\t\tucontext_t\t_Ctx;\n\t\t/// The main (or master or parent, as you want) task context\n\t\tucontext_t\t_ParentCtx;\n#endif\n#endif //NL_USE_THREAD_COTASK\n\n#if !defined(NL_USE_THREAD_COTASK)\n\t\t/** task bootstrap function\n\t\t *\tNB : this function is in this structure because of the\n\t\t *\tNL_WIN_CALLBACK symbol that need <windows.h> to be defined, so\n\t\t *\tto remove it from the header, I moved the function here\n\t\t *\t(otherwise, it should be declared in the CCoTask class as\n\t\t *\ta private member)\n\t\t */\n\t\tstatic void NL_WIN_CALLBACK startFunc(void* param)\n\t\t{\n\t\t\tCCoTask *task = reinterpret_cast<CCoTask*>(param);\n\n\t\t\tNL_CT_DEBUG(\"CoTask : task %p start func called\", task);\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// run the task\n\t\t\t\ttask->run();\n\t\t\t}\n\t\t\tcatch(...)\n\t\t\t{\n\t\t\t\tnlwarning(\"CCoTask::startFunc : the task has generated an unhandled exeption and will terminate\");\n\t\t\t}\n\n\t\t\ttask->_Finished = true;\n\n\t\t\tNL_CT_DEBUG(\"CoTask : task %p finished, entering infinite yield loop (waiting destruction)\", task);\n\n\t\t\t// nothing more to do\n\t\t\tfor (;;)\n\t\t\t\t// return to parent task\n\t\t\t\ttask->yield();\n\t\t}\n#endif //NL_USE_THREAD_COTASK\n\t};\n\n\t/** Management of current task in a thread.\n\t *\tThis class is used to store and retrieve the current\n\t *\tCCoTask pointer in the current thread.\n\t *\tIt is build upon the SAFE_SINGLETON paradigm, making it\n\t *\tsafe to use with NeL DLL.\n\t *\tFor windows platform, this singleton also hold the\n\t *\tfiber pointer of the current thread. This is needed because\n\t *\tof the bad design of the fiber API before Windows XP.\n\t */\n\tclass CCurrentCoTask\n\t{\n\t\tNLMISC_SAFE_SINGLETON_DECL(CCurrentCoTask);\n\n\t\t/// A thread dependent storage to hold by thread coroutine info\n\t\tCTDS\t_CurrentTaskTDS;\n\n#if defined (NL_OS_WINDOWS)\n\t\t/// A Thread dependent storage to hold fiber pointer.\n\t\tCTDS\t_ThreadMainFiber;\n#endif\n\n\t\tCCurrentCoTask()\n\t\t{}\n\n\tpublic:\n\t\t/// Set the current task for the calling thread\n\t\tvoid setCurrentTask(CCoTask *task)\n\t\t{\n\t\t\tNL_CT_DEBUG(\"CoTask : setting current co task to %p\", task);\n\t\t\t_CurrentTaskTDS.setPointer(task);\n\t\t}\n\n\t\t/// retrieve the current task for the calling thread\n\t\tCCoTask *getCurrentTask()\n\t\t{\n\t\t\treturn reinterpret_cast<CCoTask*>(_CurrentTaskTDS.getPointer());\n\t\t}\n#if defined (NL_OS_WINDOWS) && !defined(NL_USE_THREAD_COTASK)\n\t\tvoid setMainFiber(LPVOID fiber)\n\t\t{\n\t\t\t_ThreadMainFiber.setPointer(fiber);\n\t\t}\n\n\t\t/** Return the main fiber for the calling thread. Return NULL if\n\t\t *\tthe thread has not been converted to fiber.\n\t\t */\n\t\tLPVOID getMainFiber()\n\t\t{\n\t\t\treturn _ThreadMainFiber.getPointer();\n\t\t}\n#endif\n\t};\n\n\tNLMISC_SAFE_SINGLETON_IMPL(CCurrentCoTask);\n\n\tCCoTask *CCoTask::getCurrentTask()\n\t{\n\t\treturn CCurrentCoTask::getInstance().getCurrentTask();\n\t}\n\n\n\tCCoTask::CCoTask(uint stackSize)\n\t\t: _Started(false),\n\t\t_TerminationRequested(false),\n\t\t_Finished(false)\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : creating task %p\", this);\n#if defined(NL_USE_THREAD_COTASK)\n\t\t// allocate platform specific data storage\n\t\t_PImpl = new TCoTaskData(this);\n//\t\t_PImpl->_TaskThreadId = 0;\n//\t\t_PImpl->_ParentThreadId = 0;\n\t\tnlunreferenced(stackSize);\n#else //NL_USE_THREAD_COTASK\n\t\t// allocate platform specific data storage\n\t\t_PImpl = new TCoTaskData;\n\t\tnlunreferenced(stackSize);\n#if defined (NL_OS_WINDOWS)\n\t\t_PImpl->_Fiber = NULL;\n\t\t_PImpl->_ParentFiber = NULL;\n\t\tnlunreferenced(stackSize);\n#elif defined(NL_OS_UNIX)\n\t\t// allocate the stack\n\t\t_PImpl->_Stack = new uint8[stackSize];\n#endif\n#endif //NL_USE_THREAD_COTASK\n\t}\n\n\tCCoTask::~CCoTask()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : deleting task %p\", this);\n\t\t_TerminationRequested = true;\n\n\t\tif (_Started)\n\t\t{\n\t\t\twhile (!_Finished)\n\t\t\t\tresume();\n\t\t}\n\n#if defined(NL_USE_THREAD_COTASK)\n\n#else //NL_USE_THREAD_COTASK\n#if defined (NL_OS_WINDOWS)\n\t\tif (_PImpl->_Fiber)\n\t\t{\n\t\t\tDeleteFiber(_PImpl->_Fiber);\n\t\t}\n#elif defined(NL_OS_UNIX)\n\t\t// free the stack\n\t\tdelete [] _PImpl->_Stack;\n#endif\n#endif //NL_USE_THREAD_COTASK\n\n\t\t// free platform specific storage\n\t\tdelete _PImpl;\n\t}\n\n\tvoid CCoTask::start()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : Starting task %p\", this);\n\t\tnlassert(!_Started);\n\n\t\t_Started = true;\n\n#if defined(NL_USE_THREAD_COTASK)\n\n\t\t// create the thread\n\t\t_PImpl->_TaskThread = IThread::create(_PImpl);\n\n\t\tNL_CT_DEBUG(\"CoTask : start() task %p entering mutex\", this);\n\t\t// get the mutex\n\t\t_PImpl->_TaskMutex.enter();\n\t\tNL_CT_DEBUG(\"CoTask : start() task %p mutex entered\", this);\n\n\t\t// set the resume flag to true\n\t\t_PImpl->_ResumeTask = true;\n\n\t\t// start the thread\n\t\t_PImpl->_TaskThread->start();\n\n\t\tNL_CT_DEBUG(\"CoTask : start() task %p leaving mutex\", this);\n\t\t// leave the mutex\n\t\t_PImpl->_TaskMutex.leave();\n\n\t\t// wait until the task has yield\n\t\tfor (;;)\n\t\t{\n\t\t\t// give up the time slice to the co task\n\t\t\tnlSleep(0);\n\t\t\tNL_CT_DEBUG(\"CoTask : start() task %p entering mutex\", this);\n\t\t\t// get the mutex\n\t\t\t_PImpl->_TaskMutex.enter();\n\t\t\tNL_CT_DEBUG(\"CoTask : start() task %p mutex entered\", this);\n\n\t\t\tif (!_PImpl->_TaskHasYield)\n\t\t\t{\n\t\t\t\t// not finished\n\t\t\t\tNL_CT_DEBUG(\"CoTask : start() task %p has not yield, leaving mutex\", this);\n\t\t\t\t// leave the mutex\n\t\t\t\t_PImpl->_TaskMutex.leave();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// clear the yield flag\n\t\t_PImpl->_TaskHasYield = false;\n\n\t\tNL_CT_DEBUG(\"CoTask : start() task %p has yield\", this);\n\n\t\t// in the treaded mode, there is no need to call resume() inside start()\n\n#else //NL_USE_THREAD_COTASK\n  #if defined (NL_OS_WINDOWS)\n\n\t\tLPVOID mainFiber = CCurrentCoTask::getInstance().getMainFiber();\n\n\t\tif (mainFiber == NULL)\n\t\t{\n\t\t\t// we need to convert this thread to a fiber\n\t\t\tmainFiber = ConvertThreadToFiber(NULL);\n\n\t\t\tif (mainFiber == NULL)\n\t\t\t{\n\t\t\t\tDWORD dw = GetLastError();\n#if defined(ERROR_ALREADY_FIBER)\n\t\t\t\tif (dw == ERROR_ALREADY_FIBER) nlerror(\"ConvertThreadToFiber ERROR_ALREADY_FIBER: \"\n\t\t\t\t\t\"If you are using nel in dynamic libraries, you should have a 'pure \"\n\t\t\t\t\t\"nel library' entry point, see definition of NLMISC_DECL_PURE_LIB\");\n\t\t\t\telse\n#endif\n\t\t\t\tnlerror(\"ConvertThreadToFiber error %u\", dw);\n\t\t\t}\n\n\t\t\tCCurrentCoTask::getInstance().setMainFiber(mainFiber);\n\t\t}\n\n\t\t_PImpl->_ParentFiber = mainFiber;\n\t\t_PImpl->_Fiber = CreateFiber(NL_TASK_STACK_SIZE, TCoTaskData::startFunc, this);\n\t\tnlassert(_PImpl->_Fiber != NULL);\n  #elif defined (NL_OS_UNIX)\n\t\t// store the parent ctx\n\t\tnlverify(getcontext(&_PImpl->_ParentCtx) == 0);\n\t\t// build the task context\n\t\tnlverify(getcontext(&_PImpl->_Ctx) == 0);\n\n\t\t// change the task context\n\t\t_PImpl->_Ctx.uc_stack.ss_sp = _PImpl->_Stack;\n\t\t_PImpl->_Ctx.uc_stack.ss_size = NL_TASK_STACK_SIZE;\n\n\t\t_PImpl->_Ctx.uc_link = NULL;\n\t\t_PImpl->_Ctx.uc_stack.ss_flags = 0;\n\n\t\tmakecontext(&_PImpl->_Ctx, reinterpret_cast<void (*)()>(TCoTaskData::startFunc), 1, this);\n  #endif\n\t\tresume();\n#endif //NL_USE_THREAD_COTASK\n\t}\n\n\tvoid CCoTask::yield()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : task %p yield\", this);\n\t\tnlassert(_Started);\n\t\tnlassert(CCurrentCoTask::getInstance().getCurrentTask() == this);\n#if defined(NL_USE_THREAD_COTASK)\n\n\t\t// set the yield flag\n\t\t_PImpl->_TaskHasYield = true;\n\n\t\t// release the mutex\n\t\tNL_CT_DEBUG(\"CoTask : yield() task %p leaving mutex\", this);\n\t\t_PImpl->_TaskMutex.leave();\n\n\t\t// now, wait until the resume flag is set\n\t\tfor (;;)\n\t\t{\n\t\t\t// give up the time slice to the master thread\n\t\t\tnlSleep(0);\n\t\t\t// And get back the mutex for waiting for next resume (this should lock)\n\t\t\tNL_CT_DEBUG(\"CoTask : yield() task %p entering mutex\", this);\n\t\t\t_PImpl->_TaskMutex.enter();\n\t\t\tNL_CT_DEBUG(\"CoTask : yield() task %p mutex entered\", this);\n\n\t\t\tif (!_PImpl->_ResumeTask)\n\t\t\t{\n\t\t\t\t// not time to resume, release the mutex and sleep\n\t\t\t\tNL_CT_DEBUG(\"CoTask : yield() task %p not time to resume, leaving mutex\", this);\n\t\t\t\t_PImpl->_TaskMutex.leave();\n//\t\t\t\tnlSleep(0);\n\t\t\t}\n\t\t\telse\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// clear the resume flag\n\t\t_PImpl->_ResumeTask = false;\n\n#else //NL_USE_THREAD_COTASK\n\t\tCCurrentCoTask::getInstance().setCurrentTask(NULL);\n#if defined (NL_OS_WINDOWS)\n\t\tSwitchToFiber(_PImpl->_ParentFiber);\n#elif defined (NL_OS_UNIX)\n\t\t// swap to the parent context\n\t\tnlverify(swapcontext(&_PImpl->_Ctx, &_PImpl->_ParentCtx) == 0);\n#endif\n#endif //NL_USE_THREAD_COTASK\n\n\t\tNL_CT_DEBUG(\"CoTask : task %p have been resumed\", this);\n\t}\n\n\tvoid CCoTask::resume()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : resuming task %p\", this);\n\t\tnlassert(CCurrentCoTask::getInstance().getCurrentTask() != this);\n\t\tif (!_Started)\n\t\t\tstart();\n\t\telse if (!_Finished)\n\t\t{\n\t\t\tnlassert(_Started);\n\n#if defined(NL_USE_THREAD_COTASK)\n\n\t\t\t// set the resume flag to true\n\t\t\t_PImpl->_ResumeTask = true;\n\t\t\t_PImpl->_TaskHasYield = false;\n\t\t\t// Release the mutex\n\t\t\tNL_CT_DEBUG(\"CoTask : resume() task %p leaving mutex\", this);\n\t\t\t_PImpl->_TaskMutex.leave();\n\t\t\t// wait that the task has started\n\t\t\twhile (_PImpl->_ResumeTask)\n\t\t\t\tnlSleep(0);\n\n\t\t\tNL_CT_DEBUG(\"CoTask : resume() task %p is started, waiting yield\", this);\n\t\t\t// ok the task has started\n\t\t\t// now wait for task to yield\n\t\t\tfor (;;)\n\t\t\t{\n\t\t\t\t// give up the time slice to the co task\n\t\t\t\tnlSleep(0);\n\n\t\t\t\t// acquire the mutex\n\t\t\t\tNL_CT_DEBUG(\"CoTask : resume() task %p entering mutex\", this);\n\t\t\t\t_PImpl->_TaskMutex.enter();\n\t\t\t\tNL_CT_DEBUG(\"CoTask : resume() task %p mutex entered\", this);\n\n\t\t\t\tif (!_PImpl->_TaskHasYield)\n\t\t\t\t{\n\t\t\t\t\tNL_CT_DEBUG(\"CoTask : resume() task %p still not yielding, leaving mutex\", this);\n\t\t\t\t\t_PImpl->_TaskMutex.leave();\n\t\t\t\t\t// give the focus to another thread before acquiring the mutex\n//\t\t\t\t\tnlSleep(0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// the task has yield\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// clear the yield flag\n\t\t\t_PImpl->_TaskHasYield = false;\n\n#else // NL_USE_THREAD_COTASK\n\t\t\tCCurrentCoTask::getInstance().setCurrentTask(this);\n#if defined (NL_OS_WINDOWS)\n\t\t\tSwitchToFiber(_PImpl->_Fiber);\n#elif defined (NL_OS_UNIX)\n\t\t\t// swap to the parent context\n\t\t\tnlverify(swapcontext(&_PImpl->_ParentCtx, &_PImpl->_Ctx) == 0);\n#endif\n#endif //NL_USE_THREAD_COTASK\n\t\t}\n\n\t\tNL_CT_DEBUG(\"CoTask : task %p has yield\", this);\n\t}\n\n\t/// wait until the task terminate\n\tvoid CCoTask::wait()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : waiting for task %p to terminate\", this);\n\t\t// resume the task until termination\n\t\twhile (!_Finished)\n\t\t\tresume();\n\t}\n\n#if  defined(NL_USE_THREAD_COTASK)\n\tvoid TCoTaskData::run()\n\t{\n\t\tNL_CT_DEBUG(\"CoTask : entering TCoTaskData::run for task %p\", _CoTask);\n\t\t// set the current task\n\t\tCCurrentCoTask::getInstance().setCurrentTask(_CoTask);\n\t\t// Set the task as running\n//\t\t_Running = true;\n\t\tNL_CT_DEBUG(\"CoTask : TCoTaskData::run() task %p entering mutex\", this);\n\t\t// Acquire the task mutex\n\t\t_TaskMutex.enter();\n\t\tNL_CT_DEBUG(\"CoTask : TCoTaskData::run mutex aquired, calling '_CoTask->run()' for task %p\", _CoTask);\n\n\t\t// clear the resume flag\n\t\t_CoTask->_PImpl->_ResumeTask = false;\n\n\t\t// run the task\n\t\t_CoTask->run();\n\n\t\t// mark the task has yielding\n\t\t_CoTask->_PImpl->_TaskHasYield = true;\n\t\t// mark the task has finished\n\t\t_CoTask->_Finished = true;\n\n\t\t// nothing more to do, just return to terminate the thread\n\t\tNL_CT_DEBUG(\"CoTask : leaving TCoTaskData::run for task %p\", _CoTask);\n\n\t\tNL_CT_DEBUG(\"CoTask : TCoTaskData::run() task %p leaving mutex\", this);\n\t\t// Release the parent mutex\n\t\t_TaskMutex.leave();\n\n\t}\n#endif //NL_USE_THREAD_COTASK\n\n\tvoid CCoTask::requestTerminate()\n\t{\n\t\t_TerminationRequested = true;\n\t}\n\n\tvoid CCoTask::sleep(uint milliseconds)\n\t{\n\t\tnlassert(getCurrentTask() == this); // called outside run() !\n\t\tTTime startTime = CTime::getLocalTime();\n\t\twhile(!isTerminationRequested())\n\t\t{\n\t\t\tTTime currTime = CTime::getLocalTime();\n\t\t\tif (currTime - startTime >= milliseconds) break;\n\t\t\tyield();\n\t\t}\n\t}\n\n} // namespace NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/command.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/command.h\"\n#include \"nel/misc/algo.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n//ICommand::TCategorySet* ICommand::_Categories;\nICommand::TCommand *ICommand::LocalCommands = NULL;\nbool ICommand::LocalCommandsInit = false;\n//set<std::string>\t\tICommand::_CommandsDisablingControlChar;\n\nNLMISC_SAFE_SINGLETON_IMPL(CCommandRegistry);\n\nICommand::ICommand(const char *categoryName, const char *commandName, const char *commandHelp, const char *commandArgs)\n{\n\t// self registration\n\n\tif (!LocalCommandsInit)\n\t{\n\t\tLocalCommands = new TCommand;\n\t\tLocalCommandsInit = true;\n\t}\n\n\tTCommand::iterator comm = LocalCommands->find(commandName);\n\n\tif (comm != LocalCommands->end ())\n\t{\n\t\t// 2 commands have the same name\n\t\tnlstopex ((\"There are 2 commands that have the same name in the project (command name '%s'), skip the second definition\", commandName));\n\t}\n\telse\n\t{\n\t\t// insert the new command in the map\n\t\t//nlinfo (\"add command '%s'\", commandName);\n\t\tCategoryName = categoryName;\n\t\tHelpString = commandHelp;\n\t\tCommandArgs = commandArgs;\n\t\t_CommandName = commandName;\n\t\tType = Command;\n\t\t(*LocalCommands)[commandName] = this;\n\t}\n\n\tif (INelContext::isContextInitialised())\n\t{\n\t\t// directly register this command\n\t\tCCommandRegistry::getInstance().registerCommand(this);\n\t}\n}\n\nICommand::~ICommand()\n{\n\t// self deregistration\n\n\t// find the command\n\n\tfor (TCommand::iterator comm = LocalCommands->begin(); comm != LocalCommands->end(); comm++)\n\t{\n\t\tif ((*comm).second == this)\n\t\t{\n\t\t\t//printf(\"remove command\\n\");\n\t\t\tLocalCommands->erase (comm);\n\n\t\t\t// delete local commands if all gone\n\t\t\tif (!LocalCommands->size())\n\t\t\t{\n\t\t\t\tdelete LocalCommands;\n\t\t\t\tLocalCommands = NULL;\n\t\t\t\tLocalCommandsInit = false;\n\t\t\t}\n\n\t\t\t// Yoyo: if no nlinfo()/nlwarning() (thus no createDebug(), thus no new CApplicationContext)\n\t\t\t// done in the .dll, it is possible that the nel context is never initialized\n\t\t\tif (INelContext::isContextInitialised())\n\t\t\t{\n\t\t\t\tCCommandRegistry::getInstance().unregisterCommand(this);\n\t\t\t}\n\n\n\t\t\treturn;\n\t\t}\n\t}\n\t// commands is not found\n//\tnlstop;\n}\n\nvoid CCommandRegistry::registerCommand(ICommand *command)\n{\n\tif (_Commands.find(command->getName()) != _Commands.end())\n\t{\n//\t\tnlwarning(\"There are 2 commands that have the same name in the project (command name '%s'), skip the second definition\", command->getName().c_str());\n\t\treturn;\n\t}\n\t_Commands[command->getName()] = command;\n\t_Categories.insert(command->CategoryName);\n}\n\nvoid CCommandRegistry::unregisterCommand(ICommand *command)\n{\n\tfor (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); ++comm)\n\t{\n\t\tif (comm->second == command)\n\t\t{\n\t\t\t//printf(\"remove command\\n\");\n\t\t\t_Commands.erase (comm);\n\t\t\treturn;\n\t\t}\n\t}\n\t//nlwarning(\"CCommandRegistry::unregisterCommand : the command '%s' is not registered\", command->getName().c_str());\n}\n\nvoid CCommandRegistry::registerNamedCommandHandler(ICommandsHandler *handler, const std::string &className)\n{\n\tconst std::string &name = handler->getCommandHandlerName();\n\tif (_CommandsHandlers.getB(name) != NULL)\n\t{\n\t\tnlwarning(\"CCommandRegistry : a commands handler with the name '%s' already exist, ignoring new candidat\", name.c_str());\n\t\treturn;\n\t}\n\t_CommandsHandlers.add(name, handler);\n\n\tTCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);\n\n\tif (it == _CommandsHandlersClass.end())\n\t{\n\t\tnlinfo(\"CCommandRegistry : adding commands handler for class '%s'\", className.c_str());\n\t}\n\n\t// register the class and commands name\n\tTCommandHandlerClassInfo &chci = _CommandsHandlersClass[className];\n\n\t// add an instance to the counter\n\t++chci.InstanceCount;\n\t// store the command list\n\tTCommandHandlerClassInfo::TCommandsInfo commands;\n\thandler->fillCommandsHandlerList(commands);\n\tnlassert(chci._Commands.empty() || chci._Commands == commands);\n\n\tif (chci._Commands.empty())\n\t\tstd::swap(chci._Commands, commands);\n\n}\n\nvoid CCommandRegistry::unregisterNamedCommandHandler(ICommandsHandler *handler, const std::string &className)\n{\n\tif (_CommandsHandlers.getA(handler) == NULL)\n\t\treturn;\n\n\t_CommandsHandlers.removeWithB(handler);\n\n\t// update the handler class commands tables\n\tTCommandsHandlersClass::iterator it = _CommandsHandlersClass.find(className);\n\tif (it != _CommandsHandlersClass.end())\n\t{\n\t\t--(it->second.InstanceCount);\n\n\t\tif (it->second.InstanceCount == 0)\n\t\t{\n\t\t\tnlinfo(\"CCommandRegistry : removing commands handler for class '% s'\", className.c_str());\n\t\t\t_CommandsHandlersClass.erase(it);\n\t\t}\n\t}\n}\n\n\nbool ICommand::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)\n{\n\ttry\n\t{\n\t\treturn CCommandRegistry::getInstance().execute(commandWithArgs, log, quiet, human);\n\t}\n\tcatch(const exception &e)\n\t{\n\t\tlog.displayNL(\"Command '%s' thrown an exception :\", commandWithArgs.c_str());\n\t\tlog.displayNL(e.what());\n\n\t\treturn false;\n\t}\n}\n\nstruct TCommandParams\n{\n\tstring\t\t\tCommandName;\n\tstring\t\t\tRawCommandString;\n\tvector<string>\tCommandArgs;\n};\n\nbool CCommandRegistry::execute (const std::string &commandWithArgs, CLog &log, bool quiet, bool human)\n{\n\tif (!quiet)\n\t{\n\t\tlog.displayNL (\"Executing command : '%s'\", commandWithArgs.c_str());\n\t}\n\n\t// true to indicate that '\"', ';' and '\\' are special character sequence control\n\tbool allowControlChar= true;\n\t// Start of each command in the command line\n\tstring::size_type commandBegin = 0;\n\n\t// convert the buffer into string vector\n\tvector<TCommandParams>\tcommands;\n\tbool firstArg = true;\n\tuint i = 0;\n\tfor(;;)\n\t{\n\t\t// skip whitespace\n\t\tfor(;;)\n\t\t{\n\t\t\tif (i == commandWithArgs.size())\n\t\t\t{\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t\tif (commandWithArgs[i] != ' ' && commandWithArgs[i] != '\\t' && commandWithArgs[i] != '\\n' && commandWithArgs[i] != '\\r')\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ti++;\n\t\t}\n\n\t\t// get param\n\t\tstring arg;\n\t\tif (allowControlChar && commandWithArgs[i] == '\\\"')\n\t\t{\n\t\t\t// starting with a quote \"\n\t\t\ti++;\n\t\t\tfor(;;)\n\t\t\t{\n\t\t\t\tif (i == commandWithArgs.size())\n\t\t\t\t{\n\t\t\t\t\tif (!quiet) log.displayNL (\"Missing end quote character \\\"\");\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (commandWithArgs[i] == '\"')\n\t\t\t\t{\n\t\t\t\t\ti++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (commandWithArgs[i] == '\\\\')\n\t\t\t\t{\n\t\t\t\t\t// manage escape char backslash\n\t\t\t\t\ti++;\n\t\t\t\t\tif (i == commandWithArgs.size())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!quiet) log.displayNL (\"Missing character after the backslash \\\\ character\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tswitch (commandWithArgs[i])\n\t\t\t\t\t{\n\t\t\t\t\t\tcase '\\\\':\targ += '\\\\'; break; // double backslash\n\t\t\t\t\t\tcase 'n':\targ += '\\n'; break; // new line\n\t\t\t\t\t\tcase '\"':\targ += '\"'; break; // \"\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tif (!quiet) log.displayNL (\"Unknown escape code '\\\\%c'\", commandWithArgs[i]);\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\targ += commandWithArgs[i++];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// normal word\n\t\t\tfor(;;)\n\t\t\t{\n\t\t\t\tif (allowControlChar && commandWithArgs[i] == '\\\\')\n\t\t\t\t{\n\t\t\t\t\t// manage escape char backslash\n\t\t\t\t\ti++;\n\t\t\t\t\tif (i == commandWithArgs.size())\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!quiet) log.displayNL (\"Missing character after the backslash \\\\ character\");\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tswitch (commandWithArgs[i])\n\t\t\t\t\t{\n\t\t\t\t\t\tcase '\\\\':\targ += '\\\\'; break; // double backslash\n\t\t\t\t\t\tcase 'n':\targ += '\\n'; break; // new line\n\t\t\t\t\t\tcase '\"':\targ += '\"'; break; // \"\n\t\t\t\t\t\tcase ';':\targ += ';'; break; // ;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tif (!quiet) log.displayNL (\"Unknown escape code '\\\\%c'\", commandWithArgs[i]);\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (allowControlChar && commandWithArgs[i] == ';')\n\t\t\t\t{\n\t\t\t\t\t// command separator\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\targ += commandWithArgs[i];\n\t\t\t\t}\n\n\t\t\t\ti++;\n\n\t\t\t\tif (i == commandWithArgs.size() || commandWithArgs[i] == ' ' || commandWithArgs[i] == '\\t' || commandWithArgs[i] == '\\n' || commandWithArgs[i] == '\\r')\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!arg.empty())\n\t\t{\n\t\t\tif (firstArg)\n\t\t\t{\n\t\t\t\t// the first arg is the command\n\t\t\t\tTCommandParams cp;\n\t\t\t\tcp.CommandName = arg;\n\t\t\t\tcommands.push_back(cp);\n\t\t\t\tfirstArg = false;\n\n\t\t\t\t// does this command disable control char for remaining params?\n\t\t\t\tif(!isControlCharForCommandEnabled(arg))\n\t\t\t\t\tallowControlChar= false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcommands[commands.size()-1].CommandArgs.push_back (arg);\n\t\t\t}\n\t\t}\n\n\t\t// separator\n\t\tif (i < commandWithArgs.size() && allowControlChar && commandWithArgs[i] == ';')\n\t\t{\n\t\t\t// store the raw command\n\t\t\tif (!commands.empty() && commands.back().RawCommandString.empty())\n\t\t\t\tcommands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);\n\t\t\tfirstArg = true;\n\t\t\ti++;\n\t\t\tcommandBegin = i;\n\t\t}\n\t}\nend:\n\t// store the last raw command string\n\tif (!commands.empty() && commands.back().RawCommandString.empty())\n\t\tcommands.back().RawCommandString = string(commandWithArgs.begin()+commandBegin, commandWithArgs.begin()+i);\n\n\tbool ret = true;\n\n\tfor (uint u = 0; u < commands.size (); u++)\n\t{\n\t\tTCommandParams &cp = commands[u];\n\t\t// find the command\n\t\t// check for object name\n\t\tstring::size_type pos = cp.CommandName.find(\".\");\n\t\tif (pos != string::npos)\n\t\t{\n\t\t\t// there is an object name, separate it and look in the object registry\n\t\t\tstring objectName = cp.CommandName.substr(0, pos);\n\t\t\tstring commandName = cp.CommandName.substr(pos+1);\n\t\t\tICommandsHandler *const *ppch = _CommandsHandlers.getB(objectName);\n\t\t\tif (ppch != NULL)\n\t\t\t{\n\t\t\t\t// ok, we found the object\n\t\t\t\tret = ret && (*ppch)->execute(commands[u].RawCommandString, commandName, commands[u].CommandArgs, log, quiet, human);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (!quiet)\n\t\t\t\t\tlog.displayNL(\"Command '%s' : can't found object named '%s'\",\n\t\t\t\t\t\tcp.CommandName.c_str(),\n\t\t\t\t\t\tobjectName.c_str());\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// this is a global command\n\t\t\tTCommand::iterator comm = _Commands.find(commands[u].CommandName);\n\t\t\tif (comm == _Commands.end ())\n\t\t\t{\n\t\t\t\t// the command doesn't exist\n\t\t\t\tret = false;\n\t\t\t\tif (!quiet)\n\t\t\t\t\tlog.displayNL(\"Command '%s' not found, try 'help'\", commands[u].CommandName.c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbool res = comm->second->execute (commands[u].RawCommandString, commands[u].CommandArgs, log, quiet, human);\n\t\t\t\tret = ret & res;\n\t\t\t\tif (!res)\n\t\t\t\t{\n\t\t\t\t\tif (!quiet)\n\t\t\t\t\t\tlog.displayNL(\"Bad command usage, try 'help %s'\", commands[u].CommandName.c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// false if at least one command returned false\n\treturn ret;\n}\n\n\n/*\n * Command name completion.\n * Case-sensitive. Displays the list after two calls with the same non-unique completion.\n * Completes commands used with prefixes (such as \"help \" for example) as well.\n */\nvoid ICommand::expand (std::string &commandName, NLMISC::CLog &log)\n{\n\t// forward to command registry\n\tCCommandRegistry::getInstance().expand(commandName, log);\n}\n\nvoid CCommandRegistry::expand (std::string &commandName, NLMISC::CLog &log)\n{\n\t// Take out the string before the last separator and remember it as a prefix\n\tstring objectName;\n\tstring::size_type lastseppos = commandName.find_last_of( \" \" );\n\t{\n\t\t// eventually use the last dot as separator\n\t\tstring::size_type lastDot = commandName.find_last_of( \".\" );\n\t\tif (lastDot != string::npos\n\t\t\t&& (lastseppos == string::npos || lastDot > lastseppos))\n\t\t{\n\t\t\tlastseppos = lastDot;\n\t\t\t// store the object name to limit the matching scope\n\t\t\tstring::size_type spcPos = commandName.find_last_of(\" \", lastDot);\n\t\t\tif (spcPos == string::npos)\n\t\t\t\tspcPos = 0;\n\t\t\telse\n\t\t\t\tspcPos++;\n\t\t\tobjectName = commandName.substr(spcPos, lastDot-spcPos);\n\t\t}\n\t}\n\tstring prefix;\n\tbool useprefix;\n\tif ( lastseppos != string::npos )\n\t{\n\t\tprefix = commandName.substr( 0, lastseppos+1 );\n\t\tcommandName.erase( 0, lastseppos+1 );\n\t\tuseprefix = true;\n\t}\n\telse\n\t{\n\t\tuseprefix = false;\n\t}\n\n\tstring lowerCommandName = toLower(commandName);\n\t// Build the list of matching command names\n\tvector<string> matchingnames;\n\t{\n\t\tif (objectName.empty())\n\t\t{\n\t\t\t// list of global commands\n\t\t\tfor (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)\n\t\t\t{\n\t\t\t\tstring first = toLower((*comm).first);\n\t\t\t\tif (first.find( lowerCommandName ) == 0)\n\t\t\t\t{\n\t\t\t\t\tmatchingnames.push_back( (*comm).first );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// list of object instance\n\t\t\tfor (TCommandsHandlers::TAToBMap::const_iterator it(_CommandsHandlers.getAToBMap().begin()); it != _CommandsHandlers.getAToBMap().end(); ++it)\n\t\t\t{\n\t\t\t\tstring first = toLower(it->first);\n\t\t\t\tif (first.find( lowerCommandName ) == 0)\n\t\t\t\t{\n\t\t\t\t\tmatchingnames.push_back( it->first );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tICommandsHandler *const *pch = _CommandsHandlers.getB(objectName);\n\t\t\tif (pch != NULL)\n\t\t\t{\n\t\t\t\t// ok, an object of this name exist, lookup the class\n\t\t\t\tTCommandsHandlersClass::iterator it = _CommandsHandlersClass.find((*pch)->getCommandHandlerClassName());\n\n\t\t\t\t// list of class commands\n\t\t\t\tif (it != _CommandsHandlersClass.end())\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo &chci = it->second;\n\n\t\t\t\t\tfor (TCommandHandlerClassInfo::TCommandsInfo::iterator it(chci._Commands.begin()); it != chci._Commands.end(); ++it)\n\t\t\t\t\t{\n\t\t\t\t\t\tstring first = toLower(it->first);\n\t\t\t\t\t\tif (first.find( lowerCommandName ) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmatchingnames.push_back( it->first );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\t// Do not complete if there is no result\n\tif ( matchingnames.empty() )\n\t{\n\t\tlog.displayNL( \"No matching command\" );\n\t\tgoto returnFromExpand;\n\t}\n\n\t// Complete if there is a single result\n\tif ( matchingnames.size() == 1 )\n\t{\n\t\tif (_CommandsHandlers.getAToBMap().find(matchingnames.front()) != _CommandsHandlers.getAToBMap().end())\n\t\t{\n\t\t\t// this is an object, complete with '.'\n\t\t\tcommandName = matchingnames.front() + \".\";\n\t\t}\n\t\telse\n\t\t\tcommandName = matchingnames.front() + \" \";\n\t\tgoto returnFromExpand;\n\t}\n\n\t// Try to complete to the common part if there are several results\n\t{\n\t\t// Stop loop when a name size is i or names[i] are different\n\t\tstring commonstr = commandName;\n\t\tsize_t i = commandName.size();\n\t\twhile ( true )\n\t\t{\n\t\t\tchar letter = 0;\n\t\t\tvector<string>::iterator imn;\n\t\t\tfor ( imn=matchingnames.begin(); imn!=matchingnames.end(); ++imn )\n\t\t\t{\n\t\t\t\t// Return common string if the next letter is not the same in all matching names\n\t\t\t\tif ( ((*imn).size() == i) || ( (letter!=0) && ((*imn)[i] != letter) ) )\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL( \"(Matching command not unique)\" );\n\t\t\t\t\tstatic string lastCommandName;\n\t\t\t\t\tcommandName = commonstr;\n\t\t\t\t\tif ( lastCommandName == commandName )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Display all the matching names\n\t\t\t\t\t\tvector<string>::iterator imn2;\n\t\t\t\t\t\t//stringstream ss;\n\t\t\t\t\t\tstring str;\n\t\t\t\t\t\t//ss << \"Matching commands:\" << endl;\n\t\t\t\t\t\tstr += \"Matching commands:\\n\";\n\t\t\t\t\t\tfor ( imn2=matchingnames.begin(); imn2!=matchingnames.end(); ++imn2 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//ss << \" \" << (*imn2);\n\t\t\t\t\t\t\tstr += \" \" + (*imn2);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlog.displayNL( \"%s\", str.c_str() );\n\t\t\t\t\t}\n\t\t\t\t\tlastCommandName = commandName;\n\t\t\t\t\tgoto returnFromExpand;\n\t\t\t\t}\n\t\t\t\t// Add the next letter to the common string if it is the same in all matching names\n\t\t\t\telse if ( letter == 0 )\n\t\t\t\t{\n\t\t\t\t\tletter = (*imn)[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tcommonstr += letter;\n\t\t\t++i;\n\t\t}\n\t}\n\nreturnFromExpand:\n\n\t// Put back the prefix\n\tif ( useprefix )\n\t{\n\t\tcommandName = prefix + commandName;\n\t}\n}\n\n\nvoid ICommand::serialCommands (IStream &f)\n{\n\tCCommandRegistry::getInstance().serialCommands(f);\n}\n\nvoid CCommandRegistry::serialCommands (IStream &f)\n{\n\tvector<CSerialCommand> cmd;\n\tfor (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)\n\t{\n\t\tcmd.push_back (CSerialCommand ((*comm).first, (*comm).second->Type));\n\t}\n\tf.serialCont (cmd);\n}\n\nbool ICommand::exists (std::string const &commandName)\n{\n\treturn CCommandRegistry::getInstance().exists(commandName);\n}\nbool CCommandRegistry::exists (std::string const &commandName)\n{\n\treturn (_Commands.find(commandName) != _Commands.end ());\n}\n\nbool CCommandRegistry::isNamedCommandHandler(const std::string &handlerName)\n{\n\treturn _CommandsHandlers.getB(handlerName) != NULL;\n}\n\nbool ICommand::isCommand (const std::string &str)\n{\n\treturn CCommandRegistry::getInstance().isCommand(str);\n}\n\nbool CCommandRegistry::isCommand (const std::string &str)\n{\n\tif (str.empty())\n\t\treturn false;\n\n\treturn isupper(str[0]) == 0;\n}\n\nICommand *ICommand::getCommand(const std::string &commandName)\n{\n\treturn CCommandRegistry::getInstance().getCommand(commandName);\n}\n\nICommand *CCommandRegistry::getCommand(const std::string &commandName)\n{\n\tTCommand::iterator it(_Commands.find(commandName));\n\n\tif (it == _Commands.end())\n\t\treturn NULL;\n\telse\n\t\treturn it->second;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel,help,\"display help on a specific variable/commands or on all variables and commands\", \"[<variable>|<command>]\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n//\tnlassert (_Commands != NULL);\n\n\t// make sure we have a valid number of parameters\n\tif (args.size()>1)\n\t\treturn false;\n\n\tCCommandRegistry &cr = CCommandRegistry::getInstance();\n\n\t// treat the case where we have no parameters\n\tif (args.size() == 0)\n\t{\n\t\t// display a list of all command categories\n\t\tlog.displayNL(\"Help commands:\");\n\t\tlog.displayNL(\"- help all\");\n\t\tfor (CCommandRegistry::TCategorySet::iterator it=cr._Categories.begin();it!=cr._Categories.end();++it)\n\t\t{\n\t\t\tlog.displayNL(\"- help %s\",it->c_str());\n\t\t}\n\t\tlog.displayNL(\"- help <wildcard>\");\n\t\tlog.displayNL(\"- help <command name>\");\n\t\treturn true;\n\t}\n\n\t// treat the case where the supplied parameter is \"all\"\n\tif (args[0]==\"all\")\n\t{\n\t\t// display all commands\n\t\tlog.displayNL(\"Displaying all %d variables and commands: \", cr._Commands.size());\n\t\tuint i = 0;\n\t\tfor (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm, i++)\n\t\t{\n\t\t\tlog.displayNL(\"%2d %-15s: %s\", i, comm->first.c_str(), comm->second->HelpString.c_str());\n\t\t}\n\n\t\t// display the class commands\n\t\t{\n\t\t\tCCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"%-15s :\", first->first.c_str());\n\t\t\t\tTCommandHandlerClassInfo &chci = first->second;\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"  %-15s: %s\", first->first.c_str(), first->second.CommandHelp.c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// display the named instance instance\n\t\t{\n\t\t\tlog.displayNL(\"Listing named object instance : <name> : <className>\");\n\t\t\tCCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tlog.displayNL(\" %-15s: %s\",\n\t\t\t\t\tfirst->first.c_str(),\n\t\t\t\t\tfirst->second->getCommandHandlerClassName().c_str());\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// treat the case where the supplied parameter is a category name\n\t{\n\t\tif (cr._Categories.find(args[0])!=cr._Categories.end())\n\t\t{\n\t\t\tlog.displayNL(\"Displaying commands and variables from category: %s\", args[0].c_str());\n\t\t\tuint i = 0;\n\t\t\tfor (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)\n\t\t\t{\n\t\t\t\tif (comm->second->CategoryName == args[0])\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"%2d %-15s: %s\", i, comm->first.c_str(), comm->second->HelpString.c_str());\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t}\n\t// treat the case where the supplied parameter is a class name\n\t{\n\t\tstring className = args[0].substr(0, args[0].find(\".\"));\n\t\tif (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())\n\t\t{\n\t\t\tTCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];\n\t\t\tif (className != args[0])\n\t\t\t{\n\t\t\t\tstring cmdName = args[0].substr(className.size()+1);\n\t\t\t\t// we are looking for a particular command in this class\n\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tif (first->first == cmdName)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"%s::%s\", className.c_str(), cmdName.c_str());\n\t\t\t\t\t\tlog.displayNL(\"usage: <instanceName>.%s %s : %s\",\n\t\t\t\t\t\t\tcmdName.c_str(),\n\t\t\t\t\t\t\tfirst->second.CommandArgs.c_str(),\n\t\t\t\t\t\t\tfirst->second.CommandHelp.c_str());\n//\t\t\t\t\t\tlog.displayNL(\"  %s::%-15s: %s\", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlog.displayNL(\"%-15s :\", args[0].c_str());\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"  %-15s: %s\", first->first.c_str(), first->second.CommandHelp.c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// list the instance of this class\n\t\t\t\tlog.displayNL(\" Here is a list of the %u named instance of this class\", chci.InstanceCount);\n\t\t\t\tfor (CCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator it=cr._CommandsHandlers.getAToBMap().begin(); it != cr._CommandsHandlers.getAToBMap().end(); ++it)\n\t\t\t\t{\n\t\t\t\t\tif (it->second->getCommandHandlerClassName() == args[0])\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"  %-15s\", it->first.c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\t// treat the case where the supplied parameter is an object name\n\t{\n\t\tstring objName = args[0].substr(0, args[0].find(\".\"));\n\n\t\tif (cr._CommandsHandlers.getB(objName) != NULL)\n\t\t{\n\t\t\tconst string &className = (*(cr._CommandsHandlers.getB(objName)))->getCommandHandlerClassName();\n\t\t\tif (cr._CommandsHandlersClass.find(className) != cr._CommandsHandlersClass.end())\n\t\t\t{\n\t\t\t\tTCommandHandlerClassInfo &chci = cr._CommandsHandlersClass[className];\n\t\t\t\tif (objName != args[0])\n\t\t\t\t{\n\t\t\t\t\t// only display a particular command of this class instance\n\t\t\t\t\tstring cmdName = args[0].substr(objName.size()+1);\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (first->first == cmdName)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlog.displayNL(\"%s.%s\", objName.c_str(), cmdName.c_str());\n\t\t\t\t\t\t\tlog.displayNL(\"usage: %s.%s %s : %s\",\n\t\t\t\t\t\t\t\tobjName.c_str(),\n\t\t\t\t\t\t\t\tcmdName.c_str(),\n\t\t\t\t\t\t\t\tfirst->second.CommandArgs.c_str(),\n\t\t\t\t\t\t\t\tfirst->second.CommandHelp.c_str());\n//\t\t\t\t\t\t\tlog.displayNL(\"  %s.%-15s: %s\", className.c_str(), cmdName.c_str(), first->second.CommandHelp.c_str());\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"  %-15s: %s\", first->first.c_str(), first->second.CommandHelp.c_str());\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// treat the case where the supplied parameter is a wildcard\n\tif (args[0].find('*')!=std::string::npos || args[0].find('?')!=std::string::npos)\n\t{\n\t\tlog.displayNL(\"Displaying commands, variables and objects matching wildcard: '%s'\", args[0].c_str());\n\t\tlog.displayNL(\" Global commands and variables :\");\n\t\tuint i = 0;\n\t\tfor (TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); ++comm)\n\t\t{\n\t\t\tif (testWildCard(comm->first,args[0]))\n\t\t\t{\n\t\t\t\tlog.displayNL(\"%2d %-15s: %s\", i, comm->first.c_str(), comm->second->HelpString.c_str());\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\t// display the named instance instance that match\n\t\t{\n\t\t\tlog.displayNL(\" Named objects instances : <name> : <className>\");\n\t\t\tCCommandRegistry::TCommandsHandlers::TAToBMap::const_iterator first(cr._CommandsHandlers.getAToBMap().begin()), last(cr._CommandsHandlers.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (testWildCard(first->first, args[0]))\n\t\t\t\t{\n\t\t\t\t\tlog.displayNL(\"  %-15s: '%s'\",\n\t\t\t\t\t\tfirst->first.c_str(),\n\t\t\t\t\t\tfirst->second->getCommandHandlerClassName().c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// display the class commands that match\n\t\t{\n\t\t\tlog.displayNL(\" Class commands :\");\n\t\t\tCCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst string &className = first->first;\n\t\t\t\tTCommandHandlerClassInfo &chci = first->second;\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator first(chci._Commands.begin()), last(chci._Commands.end());\n\t\t\t\t\tfor (;first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (testWildCard(first->first, args[0]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlog.displayNL(\"  %s::%-15s: %s\",\n\t\t\t\t\t\t\t\tclassName.c_str(),\n\t\t\t\t\t\t\t\tfirst->first.c_str(),\n\t\t\t\t\t\t\t\tfirst->second.CommandHelp.c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// treat the case where we're looking at help on a given command\n\t{\n\t\t// look in global commands\n\t\tif (cr._Commands.find(args[0]) != cr._Commands.end())\n\t\t{\n\t\t\tTCommand::iterator comm = cr._Commands.find(args[0]);\n\t\t\tlog.displayNL(\"%s\", comm->second->HelpString.c_str());\n\n\t\t\tstd::vector<std::string> commandArgs;\n\t\t\tsplitString(comm->second->CommandArgs, \"\\n\", commandArgs);\n\n\t\t\tlog.displayNL(\"usage: %s %s\",\n\t\t\t\tcomm->first.c_str(),\n\t\t\t\tcommandArgs.empty() ? \"\":commandArgs.front().c_str());\n\n\t\t\tfor(uint i = 1; i < commandArgs.size(); ++i)\n\t\t\t\tlog.displayNL(\"%s\", commandArgs[i].c_str());\n\n\t\t\treturn true;\n\t\t}\n\t\t// look in the class commands\n\t\t{\n\t\t\tCCommandRegistry::TCommandsHandlersClass::iterator first(cr._CommandsHandlersClass.begin()), last(cr._CommandsHandlersClass.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTCommandHandlerClassInfo &chci = first->second;\n\t\t\t\t{\n\t\t\t\t\tTCommandHandlerClassInfo::TCommandsInfo::iterator it = chci._Commands.find(args[0]);\n\t\t\t\t\tif (it != chci._Commands.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"%s\", it->second.CommandHelp.c_str());\n\n\t\t\t\t\t\tstd::vector<std::string> commandArgs;\n\t\t\t\t\t\tsplitString(it->second.CommandArgs, \"\\n\", commandArgs);\n\n\t\t\t\t\t\tlog.displayNL(\"usage: %s %s\",\n\t\t\t\t\t\t\tit->first.c_str(),\n\t\t\t\t\t\t\tcommandArgs.empty() ? \"\":commandArgs.front().c_str());\n\n\t\t\t\t\t\tfor(uint i = 1; i < commandArgs.size(); ++i)\n\t\t\t\t\t\t\tlog.displayNL(\"%s\", commandArgs[i].c_str());\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// we've failed to find a case that works so display an error message and prompt the player\n\tlog.displayNL(\"'%s' is not a command, category or wildcard. Type 'help' for more information\", args[0].c_str());\n\treturn true;\n}\n\n// ***************************************************************************\nvoid\tICommand::enableControlCharForCommand(const std::string &commandName, bool state)\n{\n\tCCommandRegistry::getInstance().enableControlCharForCommand(commandName, state);\n}\nvoid\tCCommandRegistry::enableControlCharForCommand(const std::string &commandName, bool state)\n{\n\tif(state)\n\t\t// allow, so erase from the set of those who disable\n\t\t_CommandsDisablingControlChar.erase(commandName);\n\telse\n\t\t// disable, so insert in the set of those who disable\n\t\t_CommandsDisablingControlChar.insert(commandName);\n}\n\n// ***************************************************************************\nbool\tICommand::isControlCharForCommandEnabled(const std::string &commandName)\n{\n\treturn CCommandRegistry::getInstance().isControlCharForCommandEnabled(commandName);\n}\nbool\tCCommandRegistry::isControlCharForCommandEnabled(const std::string &commandName)\n{\n\t// true if not in the set\n\treturn _CommandsDisablingControlChar.find(commandName)==_CommandsDisablingControlChar.end();\n}\n\nICommandsHandler::ICommandsHandler()\n: _ClassName(NULL)\n{\n}\n\nvoid ICommandsHandler::registerCommandsHandler()\n{\n\tif (_ClassName == NULL)\n\t{\n\t\t// store the class name for unregistering during destruction\n\t\t_ClassName = &getCommandHandlerClassName();\n\t\tCCommandRegistry::getInstance().registerNamedCommandHandler(this, *_ClassName);\n\t}\n}\n\nvoid ICommandsHandler::unregisterCommandsHandler()\n{\n\tif (_ClassName != NULL)\n\t{\n\t\tCCommandRegistry::getInstance().unregisterNamedCommandHandler(this, *_ClassName);\n\t\t_ClassName = NULL;\n\t}\n}\n\n\nICommandsHandler::~ICommandsHandler()\n{\n\tunregisterCommandsHandler();\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/common.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/common.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <ShellAPI.h>\n#\tinclude <io.h>\n#\tinclude <tchar.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <cerrno>\n#\tinclude <pthread.h>\n#\tinclude <sched.h>\n#endif\n\n#include \"nel/misc/command.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/i18n.h\"\n\nusing namespace std;\n\n#ifndef NL_COMP_MINGW\n#ifdef NL_OS_WINDOWS\n#\tpragma message( \" \" )\n\n#\tif FINAL_VERSION\n#\t\tpragma message( \"************************\" )\n#\t\tpragma message( \"**** FINAL_VERSION *****\" )\n#\t\tpragma message( \"************************\" )\n#\telse\n#\t\tpragma message( \"Not using FINAL_VERSION\")\n#\tendif // FINAL_VERSION\n\n#\tifdef ASSERT_THROW_EXCEPTION\n#\t\tpragma message( \"nlassert throws exceptions\" )\n#\telse\n#\t\tpragma message( \"nlassert does not throw exceptions\" )\n#\tendif // ASSERT_THROW_EXCEPTION\n\n#\tifdef _STLPORT_VERSION\n#\t\tpragma message( \"Using STLport\" )\n#\telse\n#\t\tpragma message( \"Using standard STL\" )\n#\tendif // _STLPORT_VERSION\n\n#\tpragma message( \" \" )\n\n#\tif (_MSC_VER >= 1200) && (_MSC_VER < 1400) && (WINVER < 0x0500)\n//Using VC7 and later lib, need this to compile on VC6\nextern \"C\" long _ftol2( double dblSource ) { return _ftol( dblSource ); }\n#\tendif\n\n\n#endif // NL_OS_WINDOWS\n#endif // !NL_COMP_MINGW\n\n\n#ifdef NL_HAS_SSE2\n\nvoid *operator new(size_t size) throw(std::bad_alloc)\n{\n\tvoid *p = aligned_malloc(size, NL_DEFAULT_MEMORY_ALIGNMENT);\n\tif (p == NULL) throw std::bad_alloc();\n\treturn p;\n}\n\nvoid *operator new[](size_t size) throw(std::bad_alloc)\n{\n\tvoid *p = aligned_malloc(size, NL_DEFAULT_MEMORY_ALIGNMENT);\n\tif (p == NULL) throw std::bad_alloc();\n\treturn p;\n}\n\nvoid operator delete(void *p) throw()\n{\n\taligned_free(p);\n}\n\nvoid operator delete[](void *p) throw()\n{\n\taligned_free(p);\n}\n\n#endif /* NL_HAS_SSE2 */\n\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n/*\n * Portable Sleep() function that suspends the execution of the calling thread for a number of milliseconds.\n * Note: the resolution of the timer is system-dependant and may be more than 1 millisecond.\n */\nvoid nlSleep( uint32 ms )\n{\n#ifdef NL_OS_WINDOWS\n\n#ifdef NL_DEBUG\n\t// a Sleep(0) \"block\" the other thread in DEBUG/_CONSOLE, so we clamp\n\tms = max(ms, (uint32)1);\n#endif\n\n\tSleep( ms );\n\n#elif defined NL_OS_UNIX\n\t//usleep( ms*1000 ); // resolution: 20 ms!\n\n\ttimespec ts;\n\tts.tv_sec = ms/1000;\n\tts.tv_nsec = (ms%1000)*1000000;\n\tint res;\n\tdo\n\t{\n\t\tres = nanosleep( &ts, &ts ); // resolution: 10 ms (with common scheduling policy)\n\t}\n    while ( (res != 0) && (errno==EINTR) );\n    //while ( res > 0 );\n#endif\n}\n\n\n/*\n * Returns Thread Id (note: on Linux, Process Id is the same as the Thread Id)\n */\nsize_t getThreadId()\n{\n#ifdef NL_OS_WINDOWS\n\treturn GetCurrentThreadId();\n#elif defined NL_OS_UNIX\n\treturn size_t(pthread_self());\n\t// doesnt work on linux kernel 2.6\treturn getpid();\n#endif\n\n}\n\n\n/*\n * Returns a readable string from a vector of bytes. '\\0' are replaced by ' '\n */\nstring stringFromVector( const vector<uint8>& v, bool limited )\n{\n\tstring s;\n\n\tif (!v.empty())\n\t{\n\t\tint size = (int)v.size ();\n\t\tif (limited && size > 1000)\n\t\t{\n\t\t\tstring middle = \"...<buf too big,skip middle part>...\";\n\t\t\ts.resize (1000 + middle.size());\n\t\t\tmemcpy (&*s.begin(), &*v.begin(), 500);\n\t\t\tmemcpy (&*s.begin()+500, &*middle.begin(), middle.size());\n\t\t\tmemcpy (&*s.begin()+500+middle.size(), &*v.begin()+size-500, 500);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ts.resize (size);\n\t\t\tmemcpy( &*s.begin(), &*v.begin(), v.size() );\n\t\t}\n\n\t\t// Replace '\\0' characters\n\t\tstring::iterator is;\n\t\tfor ( is=s.begin(); is!=s.end(); ++is )\n\t\t{\n\t\t\t// remplace non printable char and % with '?' chat\n\t\t\tif ( ! isprint((uint8)(*is)) || (*is) == '%')\n\t\t\t{\n\t\t\t\t(*is) = '?';\n\t\t\t}\n\t\t}\n\t}\n/*\n\tif ( ! v.empty() )\n\t{\n\t\t// Copy contents\n\t\ts.resize( v.size() );\n\t\tmemcpy( &*s.begin(), &*v.begin(), v.size() );\n\n\t\t// Replace '\\0' characters\n\t\tstring::iterator is;\n\t\tfor ( is=s.begin(); is!=s.end(); ++is )\n\t\t{\n\t\t\t// remplace non printable char and % with '?' chat\n\t\t\tif ( ! isprint((*is)) || (*is) == '%')\n\t\t\t{\n\t\t\t\t(*is) = '?';\n\t\t\t}\n\t\t}\n\t}\n*/\treturn s;\n}\n\n\nsint smprintf( char *buffer, size_t count, const char *format, ... )\n{\n\tsint ret;\n\n\tva_list args;\n\tva_start( args, format );\n\tret = vsnprintf( buffer, count, format, args );\n\tif ( ret == -1 )\n\t{\n\t\tbuffer[count-1] = '\\0';\n\t}\n\tva_end( args );\n\n\treturn( ret );\n}\n\n\nsint64 atoiInt64 (const char *ident, sint64 base)\n{\n\tsint64 number = 0;\n\tbool neg = false;\n\n\t// NULL string\n\tnlassert (ident != NULL);\n\n\t// empty string\n\tif (*ident == '\\0') goto end;\n\n\t// + sign\n\tif (*ident == '+') ident++;\n\n\t// - sign\n\tif (*ident == '-') { neg = true; ident++; }\n\n\twhile (*ident != '\\0')\n\t{\n\t\tif (isdigit((unsigned char)*ident))\n\t\t{\n\t\t\tnumber *= base;\n\t\t\tnumber += (*ident)-'0';\n\t\t}\n\t\telse if (base > 10 && islower((unsigned char)*ident))\n\t\t{\n\t\t\tnumber *= base;\n\t\t\tnumber += (*ident)-'a'+10;\n\t\t}\n\t\telse if (base > 10 && isupper((unsigned char)*ident))\n\t\t{\n\t\t\tnumber *= base;\n\t\t\tnumber += (*ident)-'A'+10;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgoto end;\n\t\t}\n\t\tident++;\n\t}\nend:\n\tif (neg) number = -number;\n\treturn number;\n}\n\nchar* itoaInt64 (sint64 number, char *str, sint64 base)\n{\n\tstr[0] = '\\0';\n\tchar b[256];\n\tif(!number)\n\t{\n\t\tstr[0] = '0';\n\t\tstr[1] = '\\0';\n\t\treturn str;\n\t}\n\tmemset(b,'\\0',255);\n\tmemset(b,'0',64);\n\tsint n;\n\tsint64 x = number;\n\tif (x < 0) x = -x;\n\tchar baseTable[] = \"0123456789abcdefghijklmnopqrstuvwyz\";\n\tfor(n = 0; n < 64; n ++)\n\t{\n\t\tsint num = (sint)(x % base);\n\t\tb[64 - n] = baseTable[num];\n\t\tif(!x)\n\t\t{\n\t\t\tint k;\n\t\t\tint j = 0;\n\n\t\t\tif (number < 0)\n\t\t\t{\n\t\t\t\tstr[j++] = '-';\n\t\t\t}\n\n\t\t\tfor(k = 64 - n + 1; k <= 64; k++)\n\t\t\t{\n\t\t\t\tstr[j ++] = b[k];\n\t\t\t}\n\t\t\tstr[j] = '\\0';\n\t\t\tbreak;\n\t\t}\n\t\tx /= base;\n\t}\n\n    return str;\n}\n\nuint raiseToNextPowerOf2(uint v)\n{\n\tuint\tres=1;\n\twhile(res<v)\n\t\tres<<=1;\n\n\treturn res;\n}\n\nuint\tgetPowerOf2(uint v)\n{\n\tuint\tres=1;\n\tuint\tret=0;\n\twhile(res<v)\n\t{\n\t\tret++;\n\t\tres<<=1;\n\t}\n\n\treturn ret;\n}\n\nbool isPowerOf2(sint32 v)\n{\n\twhile(v)\n\t{\n\t\tif(v&1)\n\t\t{\n\t\t\tv>>=1;\n\t\t\tif(v)\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\tv>>=1;\n\t}\n\n\treturn true;\n}\n\nstring bytesToHumanReadable (const std::string &bytes)\n{\n\treturn bytesToHumanReadable (atoiInt64(bytes.c_str()));\n}\n\nstring bytesToHumanReadable (uint64 bytes)\n{\n\tstatic const char *divTable[]= { \"B\", \"KB\", \"MB\", \"GB\", \"TB\" };\n\tuint div = 0;\n\tuint64 res = bytes;\n\tuint64 newres = res;\n\tfor(;;)\n\t{\n\t\tnewres /= 1024;\n\t\tif(newres < 8 || div > 3)\n\t\t\tbreak;\n\t\tdiv++;\n\t\tres = newres;\n\t}\n\treturn toString (\"%\" NL_I64 \"u%s\", res, divTable[div]);\n}\n\nuint32 humanReadableToBytes (const string &str)\n{\n\tuint32 res;\n\n\tif(str.empty())\n\t\treturn 0;\n\n\t// not a number\n\tif(str[0]<'0' || str[0]>'9')\n\t\treturn 0;\n\n\tres = atoi (str.c_str());\n\n\tif(str[str.size()-1] == 'B')\n\t{\n\t\tif (str.size()<3)\n\t\t\treturn res;\n\n\t\t// there's no break and it's **normal**\n\t\tswitch (str[str.size()-2])\n\t\t{\n\t\tcase 'G': res *= 1024;\n\t\tcase 'M': res *= 1024;\n\t\tcase 'K': res *= 1024;\n\t\tdefault: ;\n\t\t}\n\t}\n\n\treturn res;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel,btohr, \"Convert a bytes number into an human readable number\", \"<int>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif (args.size() != 1)\n\t\treturn false;\n\n\tlog.displayNL(\"%s -> %s\", args[0].c_str(), bytesToHumanReadable(args[0]).c_str());\n\n\treturn true;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel,hrtob, \"Convert a human readable number into a bytes number\", \"<hr>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif (args.size() != 1)\n\t\treturn false;\n\n\tlog.displayNL(\"%s -> %u\", args[0].c_str(), humanReadableToBytes(args[0]));\n\n\treturn true;\n}\n\n\nstring secondsToHumanReadable (uint32 time)\n{\n\tstatic const char *divTable[] = { \"s\", \"mn\", \"h\", \"d\" };\n\tstatic uint  divCoef[]  = { 60, 60, 24 };\n\tuint div = 0;\n\tuint32 res = time;\n\tuint32 newres = res;\n\tfor(;;)\n\t{\n\t\tif(div > 2)\n\t\t\tbreak;\n\n\t\tnewres /= divCoef[div];\n\n\t\tif(newres < 3)\n\t\t\tbreak;\n\n\t\tdiv++;\n\t\tres = newres;\n\t}\n\treturn toString (\"%u%s\", res, divTable[div]);\n}\n\nuint32 fromHumanReadable (const std::string &str)\n{\n\tif (str.size() == 0)\n\t\treturn 0;\n\n\tuint32 val;\n\tfromString(str, val);\n\n\tswitch (str[str.size()-1])\n\t{\n\tcase 's': return val;\t\t\t// second\n\tcase 'n': return val*60;\t\t// minutes (mn)\n\tcase 'h': return val*60*60;\t\t// hour\n\tcase 'd': return val*60*60*24;\t// day\n\tcase 'b':\t// bytes\n\t\tswitch (str[str.size()-2])\n\t\t{\n\t\tcase 'k': return val*1024;\n\t\tcase 'm': return val*1024*1024;\n\t\tcase 'g': return val*1024*1024*1024;\n\t\tdefault : return val;\n\t\t}\n\tdefault: return val;\n\t}\n\treturn 0;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel,stohr, \"Convert a second number into an human readable time\", \"<int>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif (args.size() != 1)\n\t\treturn false;\n\n\tuint32 seconds;\n\tfromString(args[0], seconds);\n\tlog.displayNL(\"%s -> %s\", args[0].c_str(), secondsToHumanReadable(seconds).c_str());\n\n\treturn true;\n}\n\n\nstd::string\ttoLower(const std::string &str)\n{\n\tstring res;\n\tres.reserve(str.size());\n\tfor(uint i = 0; i < str.size(); i++)\n\t{\n\t\tif( (str[i] >= 'A') && (str[i] <= 'Z') )\n\t\t\tres += str[i] - 'A' + 'a';\n\t\telse\n\t\t\tres += str[i];\n\t}\n\treturn res;\n}\n\nchar toLower(const char ch)\n{\n\tif( (ch >= 'A') && (ch <= 'Z') )\n\t{\n\t\treturn ch - 'A' + 'a';\n\t}\n\telse\n\t{\n\t\treturn ch;\n\t}\n}\n\nvoid toLower(char *str)\n{\n\tif (str == 0)\n\t\treturn;\n\n\twhile(*str != '\\0')\n\t{\n\t\tif( (*str >= 'A') && (*str <= 'Z') )\n\t\t{\n\t\t\t*str = *str - 'A' + 'a';\n\t\t}\n\t\tstr++;\n\t}\n}\n\nstd::string\ttoUpper(const std::string &str)\n{\n\tstring res;\n\tres.reserve(str.size());\n\tfor(uint i = 0; i < str.size(); i++)\n\t{\n\t\tif( (str[i] >= 'a') && (str[i] <= 'z') )\n\t\t\tres += str[i] - 'a' + 'A';\n\t\telse\n\t\t\tres += str[i];\n\t}\n\treturn res;\n}\n\nvoid\t\ttoUpper(char *str)\n{\n\tif (str == 0)\n\t\treturn;\n\n\twhile(*str != '\\0')\n\t{\n\t\tif( (*str >= 'a') && (*str <= 'z') )\n\t\t{\n\t\t\t*str = *str - 'a' + 'A';\n\t\t}\n\t\tstr++;\n\t}\n}\n\nstd::string formatThousands(const std::string& s)\n{\n\tsint i, k;\n\tsint remaining = (sint)s.length() - 1;\n\tstatic std::string separator = NLMISC::CI18N::get(\"uiThousandsSeparator\").toUtf8();\n\n\t// Don't add separator if the number is < 10k\n\tif (remaining < 4) return s;\n\n\tstd::string ns;\n\n\tdo\n\t{\n\t\tfor (i = remaining, k = 0; i >= 0 && k < 3; --i, ++k )\n\t\t{\n\t\t\tns = s[i] + ns; // New char is added to front of ns\n\t\t\tif ( i > 0 && k == 2) ns = separator + ns; // j > 0 means still more digits\n\t\t}\n\n\t\tremaining -= 3;\n\t}\n\twhile (remaining >= 0);\n\n\treturn ns;\n}\n\n//\n// Exceptions\n//\n\nException::Exception() : _Reason(\"Unknown Exception\")\n{\n//\tnlinfo(\"Exception will be launched: %s\", _Reason.c_str());\n}\n\nException::Exception(const std::string &reason) : _Reason(reason)\n{\n\tnlinfo(\"Exception will be launched: %s\", _Reason.c_str());\n}\n\nException::Exception(const char *format, ...)\n{\n\tNLMISC_CONVERT_VARGS (_Reason, format, NLMISC::MaxCStringSize);\n\tnlinfo(\"Exception will be launched: %s\", _Reason.c_str());\n}\n\nconst char\t*Exception::what() const throw()\n{\n\treturn _Reason.c_str();\n}\n\nbool killProgram(uint32 pid)\n{\n#ifdef NL_OS_UNIX\n\tint res = kill(pid, SIGKILL);\n\tif(res == -1)\n\t{\n\t\tchar *err = strerror (errno);\n\t\tnlwarning(\"Failed to kill '%d' err %d: '%s'\", pid, errno, err);\n\t}\n\treturn res == 0;\n/*#elif defined(NL_OS_WINDOWS)\n\t// it doesn't work because pid != handle and i don't know how to kill a pid or know the real handle of another service (not -1)\n\tint res = TerminateProcess((HANDLE)pid, 888);\n\tLPVOID lpMsgBuf;\n\tFormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);\n\tnlwarning(\"Failed to kill '%d' err %d: '%s'\", pid, GetLastError (), lpMsgBuf);\n\tLocalFree(lpMsgBuf);\n\treturn res != 0;\n*/\n#else\n\tnlwarning(\"kill not implemented on this OS\");\n\treturn false;\n#endif\n}\n\nbool abortProgram(uint32 pid)\n{\n#ifdef NL_OS_UNIX\n\tint res = kill(pid, SIGABRT);\n\tif(res == -1)\n\t{\n\t\tchar *err = strerror (errno);\n\t\tnlwarning(\"Failed to abort '%d' err %d: '%s'\", pid, errno, err);\n\t}\n\treturn res == 0;\n#else\n\tnlwarning(\"abort not implemented on this OS\");\n\treturn false;\n#endif\n}\n\nbool launchProgram (const std::string &programName, const std::string &arguments)\n{\n\n#ifdef NL_OS_WINDOWS\n\tSTARTUPINFOA         si;\n    PROCESS_INFORMATION pi;\n\n    memset(&si, 0, sizeof(si));\n    memset(&pi, 0, sizeof(pi));\n\n    si.cb = sizeof(si);\n\n/*\tSECURITY_ATTRIBUTES sa;\n\tsa.nLength = sizeof (sa);\n\tsa.lpSecurityDescriptor = NULL;\n\tsa.bInheritHandle = FALSE;\n\n\tSTARTUPINFO si;\n\tsi.cb = sizeof (si);\n\tsi.lpReserved = NULL;\n\tsi.lpDesktop = NULL;\n\tsi.lpTitle = NULL;\n\tsi.dwFlags = STARTF_USESHOWWINDOW;\n\tsi.cbReserved2 = 0;\n\tsi.wShowWindow = SW_MINIMIZE;\n\tsi.lpReserved2 = NULL;\n\n\tPROCESS_INFORMATION pi;\n*/\n\n\t// Enable nlassert/nlstop to display the error reason & callstack\n\tconst TCHAR *SE_TRANSLATOR_IN_MAIN_MODULE = _T(\"NEL_SE_TRANS\");\n\tTCHAR envBuf [2];\n\tif ( GetEnvironmentVariable( SE_TRANSLATOR_IN_MAIN_MODULE, envBuf, 2 ) != 0)\n\t{\n\t\tSetEnvironmentVariable( SE_TRANSLATOR_IN_MAIN_MODULE, NULL );\n\t}\n\n\tstring arg = \" \" + arguments;\n\tBOOL res = CreateProcessA(programName.c_str(), (char*)arg.c_str(), 0, 0, FALSE, CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW, 0, 0, &si, &pi);\n\n\tif (res)\n\t{\n\t\t//nldebug(\"LAUNCH: Successful launch '%s' with arg '%s'\", programName.c_str(), arguments.c_str());\n\t\tCloseHandle( pi.hProcess );\n\t\tCloseHandle( pi.hThread );\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tLPVOID lpMsgBuf;\n\t\tFormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);\n\t\tnlwarning(\"LAUNCH: Failed launched '%s' with arg '%s' err %d: '%s'\", programName.c_str(), arguments.c_str(), GetLastError (), lpMsgBuf);\n\t\tLocalFree(lpMsgBuf);\n\t\tCloseHandle( pi.hProcess );\n\t\tCloseHandle( pi.hThread );\n\t}\n\n#elif defined(NL_OS_UNIX)\n\n\tstatic bool firstLaunchProgram = true;\n\tif (firstLaunchProgram)\n\t{\n\t\t// The aim of this is to avoid defunct process.\n\t\t//\n\t\t// From \"man signal\":\n\t\t//------\n\t\t// According to POSIX (3.3.1.3) it is unspecified what happens when SIGCHLD is set to SIG_IGN.   Here\n\t\t// the  BSD  and  SYSV  behaviours  differ,  causing BSD software that sets the action for SIGCHLD to\n\t\t// SIG_IGN to fail on Linux.\n\t\t//------\n\t\t//\n\t\t// But it works fine on my GNU/Linux so I do this because it's easier :) and I don't know exactly\n\t\t// what to do to be portable.\n\t\tsignal(SIGCHLD,SIG_IGN);\n\n\t\tfirstLaunchProgram = false;\n\t}\n\n\t// convert one arg into several args\n\tvector<string> args;\n\tstring::size_type pos1 = 0, pos2 = 0;\n\tdo\n\t{\n\t\tpos1 = arguments.find_first_not_of (\" \", pos2);\n\t\tif (pos1 == string::npos) break;\n\t\tpos2 = arguments.find_first_of (\" \", pos1);\n\t\targs.push_back (arguments.substr (pos1, pos2-pos1));\n\t}\n\twhile (pos2 != string::npos);\n\n\t// Store the size of each arg\n\tvector<char *> argv(args.size()+2);\n\tuint i = 0;\n\targv[i] = (char *)programName.c_str();\n\tfor (; i < args.size(); i++)\n\t{\n\t\targv[i+1] = (char *) args[i].c_str();\n\t}\n\targv[i+1] = NULL;\n\n\tint status = vfork ();\n\t/////////////////////////////////////////////////////////\n\t/// WARNING : NO MORE INSTRCUTION AFTER VFORK !\n\t/// READ VFORK manual\n\t/////////////////////////////////////////////////////////\n\tif (status == -1)\n\t{\n\t\tchar *err = strerror (errno);\n\t\tnlwarning(\"LAUNCH: Failed launched '%s' with arg '%s' err %d: '%s'\", programName.c_str(), arguments.c_str(), errno, err);\n\t}\n\telse if (status == 0)\n    {\n\n\t\t// Exec (the only allowed instruction after vfork)\n\t\tstatus = execvp(programName.c_str(), &argv.front());\n\n\t\tif (status == -1)\n\t\t{\n\t\t\tperror(\"Failed launched\");\n\t\t\t_exit(EXIT_FAILURE);\n\t\t}\n\t}\n\telse\n\t{\n\t\t//nldebug(\"LAUNCH: Successful launch '%s' with arg '%s'\", programName.c_str(), arguments.c_str());\n\t\treturn true;\n\t}\n#else\n\tnlwarning (\"LAUNCH: launchProgram() not implemented\");\n#endif\n\n\treturn false;\n\n}\n\n/*\n * Display the bits (with 0 and 1) composing a byte (from right to left)\n */\nvoid displayByteBits( uint8 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log )\n{\n\tstring s1, s2;\n\tsint i;\n\tfor ( i=nbits-1; i!=-1; --i )\n\t{\n\t\ts1 += ( (b >> i) & 1 ) ? '1' : '0';\n\t}\n\tlog->displayRawNL( \"%s\", s1.c_str() );\n\tif ( displayBegin )\n\t{\n\t\tfor ( i=nbits; i>beginpos+1; --i )\n\t\t{\n\t\t\ts2 += \" \";\n\t\t}\n\t\ts2 += \"^\";\n\t\tlog->displayRawNL( \"%s beginpos=%u\", s2.c_str(), beginpos );\n\t}\n}\n\n\n//#define displayDwordBits(a,b,c)\n\n/*\n * Display the bits (with 0 and 1) composing a number (uint32) (from right to left)\n */\nvoid displayDwordBits( uint32 b, uint nbits, sint beginpos, bool displayBegin, NLMISC::CLog *log )\n{\n\tstring s1, s2;\n\tsint i;\n\tfor ( i=nbits-1; i!=-1; --i )\n\t{\n\t\ts1 += ( (b >> i) & 1 ) ? '1' : '0';\n\t}\n\tlog->displayRawNL( \"%s\", s1.c_str() );\n\tif ( displayBegin )\n\t{\n\t\tfor ( i=nbits; i>beginpos+1; --i )\n\t\t{\n\t\t\ts2 += \" \";\n\t\t}\n\t\ts2 += \"^\";\n\t\tlog->displayRawNL( \"%s beginpos=%u\", s2.c_str(), beginpos );\n\t}\n}\n\n\nint\tnlfseek64( FILE *stream, sint64 offset, int origin )\n{\n#ifdef NL_OS_WINDOWS\n\n\t//\n\tfpos_t pos64 = 0;\n\tswitch (origin)\n\t{\n\tcase SEEK_CUR:\n\t\tif (fgetpos(stream, &pos64) != 0)\n\t\t\treturn -1;\n\tcase SEEK_END:\n\t\tpos64 = _filelengthi64(_fileno(stream));\n\t\tif (pos64 == -1L)\n\t\t\treturn -1;\n\t};\n\n\t// Seek\n\tpos64 += offset;\n\n\t// Set the final position\n\treturn fsetpos (stream, &pos64);\n\n#else // NL_OS_WINDOWS\n\t// TODO: to fix for Linux and Mac OS X\n\n\t// This code doesn't work under windows : fseek() implementation uses a signed 32 bits offset. What ever we do, it can't seek more than 2 Go.\n\t// For the moment, i don't know if it works under linux for seek of more than 2 Go.\n\n\tnlassert ((offset < SINT64_CONSTANT(2147483647)) && (offset > SINT64_CONSTANT(-2147483648)));\n\n\tbool first = true;\n\tdo\n\t{\n\t\t// Get the size of the next fseek\n\t\tsint nextSeek;\n\t\tif (offset > 0)\n\t\t\tnextSeek = (sint)std::min ((sint64)SINT64_CONSTANT(2147483647), offset);\n\t\telse\n\t\t\tnextSeek = (sint)std::max ((sint64)-SINT64_CONSTANT(2147483648), offset);\n\n\t\t// Make a seek\n\t\tint result = fseek ( stream, nextSeek, first?origin:SEEK_CUR );\n\t\tif (result != 0)\n\t\t\treturn result;\n\n\t\t// Remaining\n\t\toffset -= nextSeek;\n\t\tfirst = false;\n\t}\n\twhile (offset);\n\n\treturn 0;\n\n#endif // NL_OS_WINDOWS\n}\n\nsint64 nlftell64(FILE *stream)\n{\n#ifdef NL_OS_WINDOWS\n\tfpos_t pos64 = 0;\n\tif (fgetpos(stream, &pos64) == 0)\n\t{\n\t\treturn (sint64) pos64;\n\t}\n\telse return -1;\n#else\n\tnlunreferenced(stream);\n\n\t// TODO: implement for Linux and Mac OS X\n\tnlerror(\"Not implemented\");\n\treturn -1;\n#endif\n}\n\n\n//////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////\n/// Commands\n//////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////\n\nNLMISC_CATEGORISED_COMMAND(nel, sleep, \"Freeze the service for N seconds (for debug purpose)\", \"<N>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 1) return false;\n\n\tsint32 n;\n\tfromString(args[0], n);\n\n\tlog.displayNL (\"Sleeping during %d seconds\", n);\n\n\tnlSleep(n * 1000);\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, system, \"Execute the command line using system() function call (wait until the end of the command)\", \"<commandline>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 1) return false;\n\n\tstring cmd = args[0];\n\tlog.displayNL (\"Executing '%s'\", cmd.c_str());\n\tsint error = system(cmd.c_str());\n\tif (error)\n\t{\n\t\tlog.displayNL (\"Execution of '%s' failed with error code %d\", cmd.c_str(), error);\n\t}\n\telse\n\t{\n\t\tlog.displayNL (\"End of Execution of '%s'\", cmd.c_str());\n\t}\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, launchProgram, \"Execute the command line using launcProgram() function call (launch in background task without waiting the end of the execution)\", \"<programName> <arguments>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 2) return false;\n\n\tstring cmd = args[0];\n\tstring arg = args[1];\n\tlog.displayNL (\"Executing '%s' with argument '%s'\", cmd.c_str(), arg.c_str());\n\tlaunchProgram(cmd, arg);\n\tlog.displayNL (\"End of Execution of '%s' with argument '%s'\", cmd.c_str(), arg.c_str());\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, killProgram, \"kill a program given the pid\", \"<pid>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 1) return false;\n\tuint32 pid;\n\tfromString(args[0], pid);\n\tkillProgram(pid);\n\treturn true;\n}\n\n#ifdef NL_OS_WINDOWS\nLONG GetRegKey(HKEY key, LPCSTR subkey, LPSTR retdata)\n{\n    HKEY hkey;\n    LONG retval = RegOpenKeyExA(key, subkey, 0, KEY_QUERY_VALUE, &hkey);\n\n    if (retval == ERROR_SUCCESS)\n\t{\n        long datasize = MAX_PATH;\n        char data[MAX_PATH];\n        RegQueryValueA(hkey, NULL, data, &datasize);\n        lstrcpyA(retdata,data);\n        RegCloseKey(hkey);\n    }\n\n    return retval;\n}\n#endif // NL_OS_WINDOWS\n\nbool openURL (const char *url)\n{\n#ifdef NL_OS_WINDOWS\n    char key[1024];\n    if (GetRegKey(HKEY_CLASSES_ROOT, \".html\", key) == ERROR_SUCCESS)\n\t{\n        lstrcatA(key, \"\\\\shell\\\\open\\\\command\");\n\n        if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS)\n\t\t{\n            char *pos;\n            pos = strstr(key, \"\\\"%1\\\"\");\n            if (pos == NULL) {                     // No quotes found\n                pos = strstr(key, \"%1\");       // Check for %1, without quotes\n                if (pos == NULL)                   // No parameter at all...\n                    pos = key+lstrlenA(key)-1;\n                else\n                    *pos = '\\0';                   // Remove the parameter\n            }\n            else\n                *pos = '\\0';                       // Remove the parameter\n\n            lstrcatA(pos, \" \");\n            lstrcatA(pos, url);\n            int res = WinExec(key,SW_SHOWDEFAULT);\n\t\t\treturn (res>31);\n\t\t}\n\t}\n#elif defined(NL_OS_MAC)\n\treturn launchProgram(\"open\", url);\n#elif defined(NL_OS_UNIX)\n\treturn launchProgram(\"/etc/alternatives/x-www-browser\", url);\n#else\n\tnlwarning(\"openURL() is not implemented for this OS\");\n#endif // NL_OS_WINDOWS\n\treturn false;\n}\n\nbool openDoc (const char *document)\n{\n#ifdef NL_OS_WINDOWS\n\tstring ext = CFile::getExtension (document);\n    char key[MAX_PATH + MAX_PATH];\n\n    // First try ShellExecute()\n    HINSTANCE result = ShellExecuteA(NULL, \"open\", document, NULL,NULL, SW_SHOWDEFAULT);\n\n    // If it failed, get the .htm regkey and lookup the program\n    if ((uintptr_t)result <= HINSTANCE_ERROR)\n\t{\n        if (GetRegKey(HKEY_CLASSES_ROOT, ext.c_str(), key) == ERROR_SUCCESS)\n\t\t{\n            lstrcatA(key, \"\\\\shell\\\\open\\\\command\");\n\n            if (GetRegKey(HKEY_CLASSES_ROOT,key,key) == ERROR_SUCCESS)\n\t\t\t{\n                char *pos;\n                pos = strstr(key, \"\\\"%1\\\"\");\n                if (pos == NULL) {                     // No quotes found\n                    pos = strstr(key, \"%1\");       // Check for %1, without quotes\n                    if (pos == NULL)                   // No parameter at all...\n                        pos = key+lstrlenA(key)-1;\n                    else\n                        *pos = '\\0';                   // Remove the parameter\n                }\n                else\n                    *pos = '\\0';                       // Remove the parameter\n\n                lstrcatA(pos, \" \");\n                lstrcatA(pos, document);\n                int res = WinExec(key,SW_SHOWDEFAULT);\n\t\t\t\treturn (res>31);\n            }\n        }\n    }\n\telse\n\t\treturn true;\n#else\n\t// TODO: implement for Linux and Mac OS X\n\tnlunreferenced(document);\n#endif // NL_OS_WINDOWS\n\treturn false;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_bison.simple",
    "content": "/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */\n#line 3 \"cfbison.simple\"\n/* This file comes from bison-1.28.  */\n\n/* Skeleton output parser for bison,\n   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2, or (at your option)\n   any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 59 Temple Place - Suite 330,\n   Boston, MA 02111-1307, USA.  */\n\n/* As a special exception, when this file is copied by Bison into a\n   Bison output file, you may use that output file without restriction.\n   This special exception was added by the Free Software Foundation\n   in version 1.24 of Bison.  */\n\n/* This is the parser code that is written into each bison parser\n  when the %semantic_parser declaration is not specified in the grammar.\n  It was written by Richard Stallman by simplifying the hairy parser\n  used when %semantic_parser is specified.  */\n\n#ifndef YYSTACK_USE_ALLOCA\n#ifdef alloca\n#define YYSTACK_USE_ALLOCA\n#else /* alloca not defined */\n#ifdef __GNUC__\n#define YYSTACK_USE_ALLOCA\n#define alloca __builtin_alloca\n#else /* not GNU C.  */\n#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))\n#define YYSTACK_USE_ALLOCA\n#include <alloca.h>\n#else /* not sparc */\n/* We think this test detects Watcom and Microsoft C.  */\n/* This used to test MSDOS, but that is a bad idea\n   since that symbol is in the user namespace.  */\n#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)\n#if 0 /* No need for malloc.h, which pollutes the namespace;\n\t instead, just don't use alloca.  */\n#include <malloc.h>\n#endif\n#else /* not MSDOS, or __TURBOC__ */\n#if defined(_AIX)\n/* I don't know what this was needed for, but it pollutes the namespace.\n   So I turned it off.   rms, 2 May 1997.  */\n/* #include <malloc.h>  */\n #pragma alloca\n#define YYSTACK_USE_ALLOCA\n#else /* not MSDOS, or __TURBOC__, or _AIX */\n#if 0\n#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,\n\t\t and on HPUX 10.  Eventually we can turn this on.  */\n#define YYSTACK_USE_ALLOCA\n#define alloca __builtin_alloca\n#endif /* __hpux */\n#endif\n#endif /* not _AIX */\n#endif /* not MSDOS, or __TURBOC__ */\n#endif /* not sparc */\n#endif /* not GNU C */\n#endif /* alloca not defined */\n#endif /* YYSTACK_USE_ALLOCA not defined */\n\n#ifdef YYSTACK_USE_ALLOCA\n#define YYSTACK_ALLOC alloca\n#else\n#define YYSTACK_ALLOC malloc\n#endif\n\n/* Note: there must be only one dollar sign in this file.\n   It is replaced by the list of actions, each action\n   as one case of the switch.  */\n\n#define yyerrok\t\t(yyerrstatus = 0)\n#define yyclearin\t(yychar = YYEMPTY)\n#define YYEMPTY\t\t-2\n#define YYEOF\t\t0\n#define YYACCEPT\tgoto yyacceptlab\n#define YYABORT \tgoto yyabortlab\n#define YYERROR\t\tgoto yyerrlab1\n/* Like YYERROR except do call yyerror.\n   This remains here temporarily to ease the\n   transition to the new meaning of YYERROR, for GCC.\n   Once GCC version 2 has supplanted version 1, this can go.  */\n#define YYFAIL\t\tgoto yyerrlab\n#define YYRECOVERING()  (!!yyerrstatus)\n#define YYBACKUP(token, value) \\\ndo\t\t\t\t\t\t\t\t\\\n  if (yychar == YYEMPTY && yylen == 1)\t\t\t\t\\\n    { yychar = (token), yylval = (value);\t\t\t\\\n      yychar1 = YYTRANSLATE (yychar);\t\t\t\t\\\n      YYPOPSTACK;\t\t\t\t\t\t\\\n      goto yybackup;\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\\\n  else\t\t\t\t\t\t\t\t\\\n    { yyerror (\"syntax error: cannot back up\"); YYERROR; }\t\\\nwhile (0)\n\n#define YYTERROR\t1\n#define YYERRCODE\t256\n\n#ifndef YYPURE\n#define YYLEX\t\tyylex()\n#endif\n\n#ifdef YYPURE\n#ifdef YYLSP_NEEDED\n#ifdef YYLEX_PARAM\n#define YYLEX\t\tyylex(&yylval, &yylloc, YYLEX_PARAM)\n#else\n#define YYLEX\t\tyylex(&yylval, &yylloc)\n#endif\n#else /* not YYLSP_NEEDED */\n#ifdef YYLEX_PARAM\n#define YYLEX\t\tyylex(&yylval, YYLEX_PARAM)\n#else\n#define YYLEX\t\tyylex(&yylval)\n#endif\n#endif /* not YYLSP_NEEDED */\n#endif\n\n/* If nonreentrant, generate the variables here */\n\n#ifndef YYPURE\n\nint\tyychar;\t\t\t/*  the lookahead symbol\t\t*/\nYYSTYPE\tyylval;\t\t\t/*  the semantic value of the\t\t*/\n\t\t\t\t/*  lookahead symbol\t\t\t*/\n\n#ifdef YYLSP_NEEDED\nYYLTYPE yylloc;\t\t\t/*  location data for the lookahead\t*/\n\t\t\t\t/*  symbol\t\t\t\t*/\n#endif\n\nint yynerrs;\t\t\t/*  number of parse errors so far       */\n#endif  /* not YYPURE */\n\n#if YYDEBUG != 0\nint yydebug;\t\t\t/*  nonzero means print parse trace\t*/\n/* Since this is uninitialized, it does not stop multiple parsers\n   from coexisting.  */\n#endif\n\n/*  YYINITDEPTH indicates the initial size of the parser's stacks\t*/\n\n#ifndef\tYYINITDEPTH\n#define YYINITDEPTH 200\n#endif\n\n/*  YYMAXDEPTH is the maximum size the stacks can grow to\n    (effective only if the built-in stack extension method is used).  */\n\n#if YYMAXDEPTH == 0\n#undef YYMAXDEPTH\n#endif\n\n#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 10000\n#endif\n\f\n/* Define __yy_memcpy.  Note that the size argument\n   should be passed with type unsigned int, because that is what the non-GCC\n   definitions require.  With GCC, __builtin_memcpy takes an arg\n   of type size_t, but it can handle unsigned int.  */\n\n#if __GNUC__ > 1\t\t/* GNU C and GNU C++ define this.  */\n#define __yy_memcpy(TO,FROM,COUNT)\t__builtin_memcpy(TO,FROM,COUNT)\n#else\t\t\t\t/* not GNU C or C++ */\n#ifndef __cplusplus\n\n/* This is the most reliable way to avoid incompatibilities\n   in available built-in functions on various systems.  */\nstatic void\n__yy_memcpy (to, from, count)\n     char *to;\n     char *from;\n     unsigned int count;\n{\n  register char *f = from;\n  register char *t = to;\n  register int i = count;\n\n  while (i-- > 0)\n    *t++ = *f++;\n}\n\n#else /* __cplusplus */\n\n/* This is the most reliable way to avoid incompatibilities\n   in available built-in functions on various systems.  */\nstatic void\n__yy_memcpy (char *to, char *from, unsigned int count)\n{\n  register char *t = to;\n  register char *f = from;\n  register int i = count;\n\n  while (i-- > 0)\n    *t++ = *f++;\n}\n\n#endif\n#endif\n\f\n#line 217 \"cfbison.simple\"\n\n/* The user can define YYPARSE_PARAM as the name of an argument to be passed\n   into yyparse.  The argument should have type void *.\n   It should actually point to an object.\n   Grammar actions can access the variable by casting it\n   to the proper pointer type.  */\n\n#ifdef YYPARSE_PARAM\n#ifdef __cplusplus\n#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM\n#define YYPARSE_PARAM_DECL\n#else /* not __cplusplus */\n#define YYPARSE_PARAM_ARG YYPARSE_PARAM\n#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;\n#endif /* not __cplusplus */\n#else /* not YYPARSE_PARAM */\n#define YYPARSE_PARAM_ARG\n#define YYPARSE_PARAM_DECL\n#endif /* not YYPARSE_PARAM */\n\n/* Prevent warning if -Wstrict-prototypes.  */\n#ifdef __GNUC__\n#ifdef YYPARSE_PARAM\nint yyparse (void *);\n#else\nint yyparse (void);\n#endif\n#endif\n\nint\nyyparse(YYPARSE_PARAM_ARG)\n     YYPARSE_PARAM_DECL\n{\n  register int yystate;\n  register int yyn;\n  register short *yyssp;\n  register YYSTYPE *yyvsp;\n  int yyerrstatus;\t/*  number of tokens to shift before error messages enabled */\n  int yychar1 = 0;\t\t/*  lookahead token as an internal (translated) token number */\n\n  short\tyyssa[YYINITDEPTH];\t/*  the state stack\t\t\t*/\n  YYSTYPE yyvsa[YYINITDEPTH];\t/*  the semantic value stack\t\t*/\n\n  short *yyss = yyssa;\t\t/*  refer to the stacks thru separate pointers */\n  YYSTYPE *yyvs = yyvsa;\t/*  to allow yyoverflow to reallocate them elsewhere */\n\n#ifdef YYLSP_NEEDED\n  YYLTYPE yylsa[YYINITDEPTH];\t/*  the location stack\t\t\t*/\n  YYLTYPE *yyls = yylsa;\n  YYLTYPE *yylsp;\n\n#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)\n#else\n#define YYPOPSTACK   (yyvsp--, yyssp--)\n#endif\n\n  int yystacksize = YYINITDEPTH;\n  int yyfree_stacks = 0;\n\n#ifdef YYPURE\n  int yychar;\n  YYSTYPE yylval;\n  int yynerrs;\n#ifdef YYLSP_NEEDED\n  YYLTYPE yylloc;\n#endif\n#endif\n\n  YYSTYPE yyval;\t\t/*  the variable used to return\t\t*/\n\t\t\t\t/*  semantic values from the action\t*/\n\t\t\t\t/*  routines\t\t\t\t*/\n // ace: big fake for VC7 because it checks if yyval is init or not\n  yyval.Val.Int = 0;\n  int yylen;\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Starting parse\\n\");\n#endif\n\n  yystate = 0;\n  yyerrstatus = 0;\n  yynerrs = 0;\n  yychar = YYEMPTY;\t\t/* Cause a token to be read.  */\n\n  /* Initialize stack pointers.\n     Waste one element of value and location stack\n     so that they stay on the same level as the state stack.\n     The wasted elements are never initialized.  */\n\n  yyssp = yyss - 1;\n  yyvsp = yyvs;\n#ifdef YYLSP_NEEDED\n  yylsp = yyls;\n#endif\n\n/* Push a new state, which is found in  yystate  .  */\n/* In all cases, when you get here, the value and location stacks\n   have just been pushed. so pushing a state here evens the stacks.  */\nyynewstate:\n\n  *++yyssp = yystate;\n\n  if (yyssp >= yyss + yystacksize - 1)\n    {\n      /* Give user a chance to reallocate the stack */\n      /* Use copies of these so that the &'s don't force the real ones into memory. */\n      YYSTYPE *yyvs1 = yyvs;\n      short *yyss1 = yyss;\n#ifdef YYLSP_NEEDED\n      YYLTYPE *yyls1 = yyls;\n#endif\n\n      /* Get the current used size of the three stacks, in elements.  */\n      int size = (int)(yyssp - yyss + 1);\n\n#ifdef yyoverflow\n      /* Each stack pointer address is followed by the size of\n\t the data in use in that stack, in bytes.  */\n#ifdef YYLSP_NEEDED\n      /* This used to be a conditional around just the two extra args,\n\t but that might be undefined if yyoverflow is a macro.  */\n      yyoverflow(\"parser stack overflow\",\n\t\t &yyss1, size * sizeof (*yyssp),\n\t\t &yyvs1, size * sizeof (*yyvsp),\n\t\t &yyls1, size * sizeof (*yylsp),\n\t\t &yystacksize);\n#else\n      yyoverflow(\"parser stack overflow\",\n\t\t &yyss1, size * sizeof (*yyssp),\n\t\t &yyvs1, size * sizeof (*yyvsp),\n\t\t &yystacksize);\n#endif\n\n      yyss = yyss1; yyvs = yyvs1;\n#ifdef YYLSP_NEEDED\n      yyls = yyls1;\n#endif\n#else /* no yyoverflow */\n      /* Extend the stack our own way.  */\n      if (yystacksize >= YYMAXDEPTH)\n\t{\n\t  yyerror(\"parser stack overflow\");\n\t  if (yyfree_stacks)\n\t    {\n\t      free (yyss);\n\t      free (yyvs);\n#ifdef YYLSP_NEEDED\n\t      free (yyls);\n#endif\n\t    }\n\t  return 2;\n\t}\n      yystacksize *= 2;\n      if (yystacksize > YYMAXDEPTH)\n\tyystacksize = YYMAXDEPTH;\n#ifndef YYSTACK_USE_ALLOCA\n      yyfree_stacks = 1;\n#endif\n      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));\n      __yy_memcpy ((char *)yyss, (char *)yyss1,\n\t\t   size * (unsigned int) sizeof (*yyssp));\n      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));\n      __yy_memcpy ((char *)yyvs, (char *)yyvs1,\n\t\t   size * (unsigned int) sizeof (*yyvsp));\n#ifdef YYLSP_NEEDED\n      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));\n      __yy_memcpy ((char *)yyls, (char *)yyls1,\n\t\t   size * (unsigned int) sizeof (*yylsp));\n#endif\n#endif /* no yyoverflow */\n\n      yyssp = yyss + size - 1;\n      yyvsp = yyvs + size - 1;\n#ifdef YYLSP_NEEDED\n      yylsp = yyls + size - 1;\n#endif\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Stack size increased to %d\\n\", yystacksize);\n#endif\n\n      if (yyssp >= yyss + yystacksize - 1)\n\tYYABORT;\n    }\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Entering state %d\\n\", yystate);\n#endif\n\n  goto yybackup;\n yybackup:\n\n/* Do appropriate processing given the current state.  */\n/* Read a lookahead token if we need one and don't already have one.  */\n/* yyresume: */\n\n  /* First try to decide what to do without reference to lookahead token.  */\n\n  yyn = yypact[yystate];\n  if (yyn == YYFLAG)\n    goto yydefault;\n\n  /* Not known => get a lookahead token if don't already have one.  */\n\n  /* yychar is either YYEMPTY or YYEOF\n     or a valid token in external form.  */\n\n  if (yychar == YYEMPTY)\n    {\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Reading a token: \");\n#endif\n      yychar = YYLEX;\n    }\n\n  /* Convert token to internal form (in yychar1) for indexing tables with */\n\n  if (yychar <= 0)\t\t/* This means end of input. */\n    {\n      yychar1 = 0;\n      yychar = YYEOF;\t\t/* Don't call YYLEX any more */\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Now at end of input.\\n\");\n#endif\n    }\n  else\n    {\n      yychar1 = YYTRANSLATE(yychar);\n\n#if YYDEBUG != 0\n      if (yydebug)\n\t{\n\t  fprintf (stderr, \"Next token is %d (%s\", yychar, yytname[yychar1]);\n\t  /* Give the individual parser a way to print the precise meaning\n\t     of a token, for further debugging info.  */\n#ifdef YYPRINT\n\t  YYPRINT (stderr, yychar, yylval);\n#endif\n\t  fprintf (stderr, \")\\n\");\n\t}\n#endif\n    }\n\n  yyn += yychar1;\n  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)\n    goto yydefault;\n\n  yyn = yytable[yyn];\n\n  /* yyn is what to do for this token type in this state.\n     Negative => reduce, -yyn is rule number.\n     Positive => shift, yyn is new state.\n       New state is final state => don't bother to shift,\n       just return success.\n     0, or most negative number => error.  */\n\n  if (yyn < 0)\n    {\n      if (yyn == YYFLAG)\n\tgoto yyerrlab;\n      yyn = -yyn;\n      goto yyreduce;\n    }\n  else if (yyn == 0)\n    goto yyerrlab;\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n  /* Shift the lookahead token.  */\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Shifting token %d (%s), \", yychar, yytname[yychar1]);\n#endif\n\n  /* Discard the token being shifted unless it is eof.  */\n  if (yychar != YYEOF)\n    yychar = YYEMPTY;\n\n  *++yyvsp = yylval;\n#ifdef YYLSP_NEEDED\n  *++yylsp = yylloc;\n#endif\n\n  /* count tokens shifted since error; after three, turn off error status.  */\n  if (yyerrstatus) yyerrstatus--;\n\n  yystate = yyn;\n  goto yynewstate;\n\n/* Do the default action for the current state.  */\nyydefault:\n\n  yyn = yydefact[yystate];\n  if (yyn == 0)\n    goto yyerrlab;\n\n/* Do a reduction.  yyn is the number of a rule to reduce with.  */\nyyreduce:\n  yylen = yyr2[yyn];\n  if (yylen > 0)\n    yyval = yyvsp[1-yylen]; /* implement default value of the action */\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      int i;\n\n      fprintf (stderr, \"Reducing via rule %d (line %d), \",\n\t       yyn, yyrline[yyn]);\n\n      /* Print the symbols being reduced, and their result.  */\n      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)\n\tfprintf (stderr, \"%s \", yytname[yyrhs[i]]);\n      fprintf (stderr, \" -> %s\\n\", yytname[yyr1[yyn]]);\n    }\n#endif\n\n$   /* the action file gets copied in in place of this dollarsign */\n#line 543 \"cfbison.simple\"\n\f\n  yyvsp -= yylen;\n  yyssp -= yylen;\n#ifdef YYLSP_NEEDED\n  yylsp -= yylen;\n#endif\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      short *ssp1 = yyss - 1;\n      fprintf (stderr, \"state stack now\");\n      while (ssp1 != yyssp)\n\tfprintf (stderr, \" %d\", *++ssp1);\n      fprintf (stderr, \"\\n\");\n    }\n#endif\n\n  *++yyvsp = yyval;\n\n#ifdef YYLSP_NEEDED\n  yylsp++;\n  if (yylen == 0)\n    {\n      yylsp->first_line = yylloc.first_line;\n      yylsp->first_column = yylloc.first_column;\n      yylsp->last_line = (yylsp-1)->last_line;\n      yylsp->last_column = (yylsp-1)->last_column;\n      yylsp->text = 0;\n    }\n  else\n    {\n      yylsp->last_line = (yylsp+yylen-1)->last_line;\n      yylsp->last_column = (yylsp+yylen-1)->last_column;\n    }\n#endif\n\n  /* Now \"shift\" the result of the reduction.\n     Determine what state that goes to,\n     based on the state we popped back to\n     and the rule number reduced by.  */\n\n  yyn = yyr1[yyn];\n\n  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;\n  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)\n    yystate = yytable[yystate];\n  else\n    yystate = yydefgoto[yyn - YYNTBASE];\n\n  goto yynewstate;\n\nyyerrlab:   /* here on detecting error */\n\n  if (! yyerrstatus)\n    /* If not already recovering from an error, report this error.  */\n    {\n      ++yynerrs;\n\n#ifdef YYERROR_VERBOSE\n      yyn = yypact[yystate];\n\n      if (yyn > YYFLAG && yyn < YYLAST)\n\t{\n\t  int size = 0;\n\t  char *msg;\n\t  int x, count;\n\n\t  count = 0;\n\t  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */\n\t  for (x = (yyn < 0 ? -yyn : 0);\n\t       x < (sizeof(yytname) / sizeof(char *)); x++)\n\t    if (yycheck[x + yyn] == x)\n\t      size += strlen(yytname[x]) + 15, count++;\n\t  msg = (char *) malloc(size + 15);\n\t  if (msg != 0)\n\t    {\n\t      strcpy(msg, \"parse error\");\n\n\t      if (count < 5)\n\t\t{\n\t\t  count = 0;\n\t\t  for (x = (yyn < 0 ? -yyn : 0);\n\t\t       x < (sizeof(yytname) / sizeof(char *)); x++)\n\t\t    if (yycheck[x + yyn] == x)\n\t\t      {\n\t\t\tstrcat(msg, count == 0 ? \", expecting `\" : \" or `\");\n\t\t\tstrcat(msg, yytname[x]);\n\t\t\tstrcat(msg, \"'\");\n\t\t\tcount++;\n\t\t      }\n\t\t}\n\t      yyerror(msg);\n\t      free(msg);\n\t    }\n\t  else\n\t    yyerror (\"parse error; also virtual memory exceeded\");\n\t}\n      else\n#endif /* YYERROR_VERBOSE */\n\tyyerror(\"parse error\");\n    }\n\n  goto yyerrlab1;\nyyerrlab1:   /* here on error raised explicitly by an action */\n\n  if (yyerrstatus == 3)\n    {\n      /* if just tried and failed to reuse lookahead token after an error, discard it.  */\n\n      /* return failure if at end of input */\n      if (yychar == YYEOF)\n\tYYABORT;\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Discarding token %d (%s).\\n\", yychar, yytname[yychar1]);\n#endif\n\n      yychar = YYEMPTY;\n    }\n\n  /* Else will try to reuse lookahead token\n     after shifting the error token.  */\n\n  yyerrstatus = 3;\t\t/* Each real token shifted decrements this */\n\n  goto yyerrhandle;\n\nyyerrdefault:  /* current state does not do anything special for the error token. */\n\n#if 0\n  /* This is wrong; only states that explicitly want error tokens\n     should shift them.  */\n  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/\n  if (yyn) goto yydefault;\n#endif\n\nyyerrpop:   /* pop the current state because it cannot handle the error token */\n\n  if (yyssp == yyss) YYABORT;\n  yyvsp--;\n  yystate = *--yyssp;\n#ifdef YYLSP_NEEDED\n  yylsp--;\n#endif\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      short *ssp1 = yyss - 1;\n      fprintf (stderr, \"Error: state stack now\");\n      while (ssp1 != yyssp)\n\tfprintf (stderr, \" %d\", *++ssp1);\n      fprintf (stderr, \"\\n\");\n    }\n#endif\n\nyyerrhandle:\n\n  yyn = yypact[yystate];\n  if (yyn == YYFLAG)\n    goto yyerrdefault;\n\n  yyn += YYTERROR;\n  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)\n    goto yyerrdefault;\n\n  yyn = yytable[yyn];\n  if (yyn < 0)\n    {\n      if (yyn == YYFLAG)\n\tgoto yyerrpop;\n      yyn = -yyn;\n      goto yyreduce;\n    }\n  else if (yyn == 0)\n    goto yyerrpop;\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Shifting error token, \");\n#endif\n\n  *++yyvsp = yylval;\n#ifdef YYLSP_NEEDED\n  *++yylsp = yylloc;\n#endif\n\n  yystate = yyn;\n  goto yynewstate;\n\n yyacceptlab:\n  /* YYACCEPT comes here.  */\n  if (yyfree_stacks)\n    {\n      free (yyss);\n      free (yyvs);\n#ifdef YYLSP_NEEDED\n      free (yyls);\n#endif\n    }\n  return 0;\n\n yyabortlab:\n  /* YYABORT comes here.  */\n  if (yyfree_stacks)\n    {\n      free (yyss);\n      free (yyvs);\n#ifdef YYLSP_NEEDED\n      free (yyls);\n#endif\n    }\n  return 1;\n}\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_flex.skl",
    "content": "/* A lexical scanner generated by flex */\n\n/* Scanner skeleton version:\n * $Header: /cvs/code/nel/src/misc/config_file/cf_flex.skl,v 1.1 2002/08/20 11:37:35 lecroart Exp $\n */\n\n#define FLEX_SCANNER\n#define YY_FLEX_MAJOR_VERSION 2\n#define YY_FLEX_MINOR_VERSION 5\n\n%-\n#include <stdio.h>\n%*\n\n\n/* cfront 1.2 defines \"c_plusplus\" instead of \"__cplusplus\" */\n#ifdef c_plusplus\n#ifndef __cplusplus\n#define __cplusplus\n#endif\n#endif\n\n\n#ifdef __cplusplus\n\n#include <stdlib.h>\n%+\nclass istream;\n%*\n#ifdef WIN32\n#include <io.h>\n#else\n#include <unistd.h>\n#define isatty _isatty\n#endif\n\n/* Use prototypes in function declarations. */\n#define YY_USE_PROTOS\n\n/* The \"const\" storage-class-modifier is valid. */\n#define YY_USE_CONST\n\n#else\t/* ! __cplusplus */\n\n#if __STDC__\n\n#define YY_USE_PROTOS\n#define YY_USE_CONST\n\n#endif\t/* __STDC__ */\n#endif\t/* ! __cplusplus */\n\n#ifdef __TURBOC__\n #pragma warn -rch\n #pragma warn -use\n#include <io.h>\n#include <stdlib.h>\n#define YY_USE_CONST\n#define YY_USE_PROTOS\n#endif\n\n#ifdef YY_USE_CONST\n#define yyconst const\n#else\n#define yyconst\n#endif\n\n\n#ifdef YY_USE_PROTOS\n#define YY_PROTO(proto) proto\n#else\n#define YY_PROTO(proto) ()\n#endif\n\n/* Returned upon end-of-file. */\n#define YY_NULL 0\n\n/* Promotes a possibly negative, possibly signed char to an unsigned\n * integer for use as an array index.  If the signed char is negative,\n * we want to instead treat it as an 8-bit unsigned char, hence the\n * double cast.\n */\n#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)\n\n/* Enter a start condition.  This macro really ought to take a parameter,\n * but we do it the disgusting crufty way forced on us by the ()-less\n * definition of BEGIN.\n */\n#define BEGIN yy_start = 1 + 2 *\n\n/* Translate the current start state into a value that can be later handed\n * to BEGIN to return to the state.  The YYSTATE alias is for lex\n * compatibility.\n */\n#define YY_START ((yy_start - 1) / 2)\n#define YYSTATE YY_START\n\n/* Action number for EOF rule of a given start state. */\n#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)\n\n/* Special action meaning \"start processing a new file\". */\n#define YY_NEW_FILE yyrestart( yyin )\n\n#define YY_END_OF_BUFFER_CHAR 0\n\n/* Size of default input buffer. */\n#define YY_BUF_SIZE 16384\n\ntypedef struct yy_buffer_state *YY_BUFFER_STATE;\n\nextern int yyleng;\n%-\nextern FILE *yyin, *yyout;\n%*\n\n#define EOB_ACT_CONTINUE_SCAN 0\n#define EOB_ACT_END_OF_FILE 1\n#define EOB_ACT_LAST_MATCH 2\n\n/* The funky do-while in the following #define is used to turn the definition\n * int a single C statement (which needs a semi-colon terminator).  This\n * avoids problems with code like:\n *\n * \tif ( condition_holds )\n *\t\tyyless( 5 );\n *\telse\n *\t\tdo_something_else();\n *\n * Prior to using the do-while the compiler would get upset at the\n * \"else\" because it interpreted the \"if\" statement as being all\n * done when it reached the ';' after the yyless() call.\n */\n\n/* Return all but the first 'n' matched characters back to the input stream. */\n\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up yytext. */ \\\n\t\t*yy_cp = yy_hold_char; \\\n\t\tYY_RESTORE_YY_MORE_OFFSET \\\n\t\tyy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \\\n\t\tYY_DO_BEFORE_ACTION; /* set up yytext again */ \\\n\t\t} \\\n\twhile ( 0 )\n\n#define unput(c) yyunput( c, yytext_ptr )\n\n/* The following is because we cannot portably get our hands on size_t\n * (without autoconf's help, which isn't available because we want\n * flex-generated scanners to compile on their own).\n */\ntypedef unsigned int yy_size_t;\n\n\nstruct yy_buffer_state\n\t{\n%-\n\tFILE *yy_input_file;\n%+\n\tistream* yy_input_file;\n%*\n\n\tchar *yy_ch_buf;\t\t/* input buffer */\n\tchar *yy_buf_pos;\t\t/* current position in input buffer */\n\n\t/* Size of input buffer in bytes, not including room for EOB\n\t * characters.\n\t */\n\tyy_size_t yy_buf_size;\n\n\t/* Number of characters read into yy_ch_buf, not including EOB\n\t * characters.\n\t */\n\tint yy_n_chars;\n\n\t/* Whether we \"own\" the buffer - i.e., we know we created it,\n\t * and can realloc() it to grow it, and should free() it to\n\t * delete it.\n\t */\n\tint yy_is_our_buffer;\n\n\t/* Whether this is an \"interactive\" input source; if so, and\n\t * if we're using stdio for input, then we want to use getc()\n\t * instead of fread(), to make sure we stop fetching input after\n\t * each newline.\n\t */\n\tint yy_is_interactive;\n\n\t/* Whether we're considered to be at the beginning of a line.\n\t * If so, '^' rules will be active on the next match, otherwise\n\t * not.\n\t */\n\tint yy_at_bol;\n\n\t/* Whether to try to fill the input buffer when we reach the\n\t * end of it.\n\t */\n\tint yy_fill_buffer;\n\n\tint yy_buffer_status;\n#define YY_BUFFER_NEW 0\n#define YY_BUFFER_NORMAL 1\n\t/* When an EOF's been seen but there's still some text to process\n\t * then we mark the buffer as YY_EOF_PENDING, to indicate that we\n\t * shouldn't try reading from the input source any more.  We might\n\t * still have a bunch of tokens to match, though, because of\n\t * possible backing-up.\n\t *\n\t * When we actually see the EOF, we change the status to \"new\"\n\t * (via yyrestart()), so that the user can continue scanning by\n\t * just pointing yyin at a new input file.\n\t */\n#define YY_BUFFER_EOF_PENDING 2\n\t};\n\n%- Standard (non-C++) definition\nstatic YY_BUFFER_STATE yy_current_buffer = 0;\n%*\n\n/* We provide macros for accessing buffer states in case in the\n * future we want to put the buffer states in a more general\n * \"scanner state\".\n */\n#define YY_CURRENT_BUFFER yy_current_buffer\n\n\n%- Standard (non-C++) definition\n/* yy_hold_char holds the character lost when yytext is formed. */\nstatic char yy_hold_char;\n\nstatic int yy_n_chars;\t\t/* number of characters read into yy_ch_buf */\n\n\nint yyleng;\n\n/* Points to current character in buffer. */\nstatic char *yy_c_buf_p = (char *) 0;\nstatic int yy_init = 1;\t\t/* whether we need to initialize */\nstatic int yy_start = 0;\t/* start state number */\n\n/* Flag which is used to allow yywrap()'s to do buffer switches\n * instead of setting up a fresh yyin.  A bit of a hack ...\n */\nstatic int yy_did_buffer_switch_on_eof;\n\nvoid yyrestart YY_PROTO(( FILE *input_file ));\n\nvoid yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));\nvoid yy_load_buffer_state YY_PROTO(( void ));\nYY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));\nvoid yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));\nvoid yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));\nvoid yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));\n#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )\n\nYY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));\nYY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));\nYY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));\n%*\n\nstatic void *yy_flex_alloc YY_PROTO(( yy_size_t ));\nstatic void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));\nstatic void yy_flex_free YY_PROTO(( void * ));\n\n#define yy_new_buffer yy_create_buffer\n\n#define yy_set_interactive(is_interactive) \\\n\t{ \\\n\tif ( ! yy_current_buffer ) \\\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\\n\tyy_current_buffer->yy_is_interactive = is_interactive; \\\n\t}\n\n#define yy_set_bol(at_bol) \\\n\t{ \\\n\tif ( ! yy_current_buffer ) \\\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\\n\tyy_current_buffer->yy_at_bol = at_bol; \\\n\t}\n\n#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)\n\n%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here\n\n%- Standard (non-C++) definition\nstatic yy_state_type yy_get_previous_state YY_PROTO(( void ));\nstatic yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));\nstatic int yy_get_next_buffer YY_PROTO(( void ));\nstatic void yy_fatal_error YY_PROTO(( yyconst char msg[] ));\n%*\n\n/* Done after the current pattern has been matched and before the\n * corresponding action - sets up yytext.\n */\n#define YY_DO_BEFORE_ACTION \\\n\tyytext_ptr = yy_bp; \\\n%% code to fiddle yytext and yyleng for yymore() goes here\n\tyy_hold_char = *yy_cp; \\\n\t*yy_cp = '\\0'; \\\n%% code to copy yytext_ptr to yytext[] goes here, if %array\n\tyy_c_buf_p = yy_cp;\n\n%% data tables for the DFA and the user's section 1 definitions go here\n\n/* Macros after this point can all be overridden by user definitions in\n * section 1.\n */\n\n#ifndef YY_SKIP_YYWRAP\n#ifdef __cplusplus\nextern \"C\" int yywrap YY_PROTO(( void ));\n#else\nextern int yywrap YY_PROTO(( void ));\n#endif\n#endif\n\n%-\n#ifndef YY_NO_UNPUT\nstatic void yyunput YY_PROTO(( int c, char *buf_ptr ));\n#endif\n%*\n\n#ifndef yytext_ptr\nstatic void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));\n#endif\n\n#ifdef YY_NEED_STRLEN\nstatic int yy_flex_strlen YY_PROTO(( yyconst char * ));\n#endif\n\n#ifndef YY_NO_INPUT\n%- Standard (non-C++) definition\n#ifdef __cplusplus\nstatic int yyinput YY_PROTO(( void ));\n#else\nstatic int input YY_PROTO(( void ));\n#endif\n%*\n#endif\n\n#if YY_STACK_USED\nstatic int yy_start_stack_ptr = 0;\nstatic int yy_start_stack_depth = 0;\nstatic int *yy_start_stack = 0;\n#ifndef YY_NO_PUSH_STATE\nstatic void yy_push_state YY_PROTO(( int new_state ));\n#endif\n#ifndef YY_NO_POP_STATE\nstatic void yy_pop_state YY_PROTO(( void ));\n#endif\n#ifndef YY_NO_TOP_STATE\nstatic int yy_top_state YY_PROTO(( void ));\n#endif\n\n#else\n#define YY_NO_PUSH_STATE 1\n#define YY_NO_POP_STATE 1\n#define YY_NO_TOP_STATE 1\n#endif\n\n#ifdef YY_MALLOC_DECL\nYY_MALLOC_DECL\n#else\n#if __STDC__\n#ifndef __cplusplus\n#include <stdlib.h>\n#endif\n#else\n/* Just try to get by without declaring the routines.  This will fail\n * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)\n * or sizeof(void*) != sizeof(int).\n */\n#endif\n#endif\n\n/* Amount of stuff to slurp up with each read. */\n#ifndef YY_READ_BUF_SIZE\n#define YY_READ_BUF_SIZE 8192\n#endif\n\n/* Copy whatever the last rule matched to the standard output. */\n\n#ifndef ECHO\n%- Standard (non-C++) definition\n/* This used to be an fputs(), but since the string might contain NUL's,\n * we now use fwrite().\n */\n#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )\n%+ C++ definition\n#define ECHO LexerOutput( yytext, yyleng )\n%*\n#endif\n\n/* Gets input and stuffs it into \"buf\".  number of characters read, or YY_NULL,\n * is returned in \"result\".\n */\n#ifndef YY_INPUT\n#define YY_INPUT(buf,result,max_size) \\\n%% fread()/read() definition of YY_INPUT goes here unless we're doing C++\n%+ C++ definition\n\tif ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \\\n\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );\n%*\n#endif\n\n/* No semi-colon after return; correct usage is to write \"yyterminate();\" -\n * we don't want an extra ';' after the \"return\" because that will cause\n * some compilers to complain about unreachable statements.\n */\n#ifndef yyterminate\n#define yyterminate() return YY_NULL\n#endif\n\n/* Number of entries by which start-condition stack grows. */\n#ifndef YY_START_STACK_INCR\n#define YY_START_STACK_INCR 25\n#endif\n\n/* Report a fatal error. */\n#ifndef YY_FATAL_ERROR\n%-\n#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )\n%+\n#define YY_FATAL_ERROR(msg) LexerError( msg )\n%*\n#endif\n\n/* Default declaration of generated scanner - a define so the user can\n * easily add parameters.\n */\n#ifndef YY_DECL\n%- Standard (non-C++) definition\n#define YY_DECL int yylex YY_PROTO(( void ))\n%+ C++ definition\n#define YY_DECL int yyFlexLexer::yylex()\n%*\n#endif\n\n/* Code executed at the beginning of each rule, after yytext and yyleng\n * have been set up.\n */\n#ifndef YY_USER_ACTION\n#define YY_USER_ACTION\n#endif\n\n/* Code executed at the end of each rule. */\n#ifndef YY_BREAK\n#define YY_BREAK break;\n#endif\n\n%% YY_RULE_SETUP definition goes here\n\nYY_DECL\n\t{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp, *yy_bp;\n\tregister int yy_act;\n\n%% user's declarations go here\n\n\tif ( yy_init )\n\t\t{\n\t\tyy_init = 0;\n\n#ifdef YY_USER_INIT\n\t\tYY_USER_INIT;\n#endif\n\n\t\tif ( ! yy_start )\n\t\t\tyy_start = 1;\t/* first start state */\n\n\t\tif ( ! yyin )\n%-\n\t\t\tyyin = stdin;\n%+\n\t\t\tyyin = &cin;\n%*\n\n\t\tif ( ! yyout )\n%-\n\t\t\tyyout = stdout;\n%+\n\t\t\tyyout = &cout;\n%*\n\n\t\tif ( ! yy_current_buffer )\n\t\t\tyy_current_buffer =\n\t\t\t\tyy_create_buffer( yyin, YY_BUF_SIZE );\n\n\t\tyy_load_buffer_state();\n\t\t}\n\n\twhile ( 1 )\t\t/* loops until end-of-file is reached */\n\t\t{\n%% yymore()-related code goes here\n\t\tyy_cp = yy_c_buf_p;\n\n\t\t/* Support of yytext. */\n\t\t*yy_cp = yy_hold_char;\n\n\t\t/* yy_bp points to the position in yy_ch_buf of the start of\n\t\t * the current run.\n\t\t */\n\t\tyy_bp = yy_cp;\n\n%% code to set up and find next match goes here\n\nyy_find_action:\n%% code to find the action number goes here\n\n\t\tYY_DO_BEFORE_ACTION;\n\n%% code for yylineno update goes here\n\ndo_action:\t/* This label is used only to access EOF actions. */\n\n%% debug code goes here\n\n\t\tswitch ( yy_act )\n\t{ /* beginning of action switch */\n%% actions go here\n\n\tcase YY_END_OF_BUFFER:\n\t\t{\n\t\t/* Amount of text matched not including the EOB char. */\n\t\tint yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;\n\n\t\t/* Undo the effects of YY_DO_BEFORE_ACTION. */\n\t\t*yy_cp = yy_hold_char;\n\t\tYY_RESTORE_YY_MORE_OFFSET\n\n\t\tif ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )\n\t\t\t{\n\t\t\t/* We're scanning a new file or input source.  It's\n\t\t\t * possible that this happened because the user\n\t\t\t * just pointed yyin at a new source and called\n\t\t\t * yylex().  If so, then we have to assure\n\t\t\t * consistency between yy_current_buffer and our\n\t\t\t * globals.  Here is the right place to do so, because\n\t\t\t * this is the first action (other than possibly a\n\t\t\t * back-up) that will match for the new input source.\n\t\t\t */\n\t\t\tyy_n_chars = yy_current_buffer->yy_n_chars;\n\t\t\tyy_current_buffer->yy_input_file = yyin;\n\t\t\tyy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;\n\t\t\t}\n\n\t\t/* Note that here we test for yy_c_buf_p \"<=\" to the position\n\t\t * of the first EOB in the buffer, since yy_c_buf_p will\n\t\t * already have been incremented past the NUL character\n\t\t * (since all states make transitions on EOB to the\n\t\t * end-of-buffer state).  Contrast this with the test\n\t\t * in input().\n\t\t */\n\t\tif ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )\n\t\t\t{ /* This was really a NUL. */\n\t\t\tyy_state_type yy_next_state;\n\n\t\t\tyy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;\n\n\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t/* Okay, we're now positioned to make the NUL\n\t\t\t * transition.  We couldn't have\n\t\t\t * yy_get_previous_state() go ahead and do it\n\t\t\t * for us because it doesn't know how to deal\n\t\t\t * with the possibility of jamming (and we don't\n\t\t\t * want to build jamming into it because then it\n\t\t\t * will run more slowly).\n\t\t\t */\n\n\t\t\tyy_next_state = yy_try_NUL_trans( yy_current_state );\n\n\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\n\t\t\tif ( yy_next_state )\n\t\t\t\t{\n\t\t\t\t/* Consume the NUL. */\n\t\t\t\tyy_cp = ++yy_c_buf_p;\n\t\t\t\tyy_current_state = yy_next_state;\n\t\t\t\tgoto yy_match;\n\t\t\t\t}\n\n\t\t\telse\n\t\t\t\t{\n%% code to do back-up for compressed tables and set up yy_cp goes here\n\t\t\t\tgoto yy_find_action;\n\t\t\t\t}\n\t\t\t}\n\n\t\telse switch ( yy_get_next_buffer() )\n\t\t\t{\n\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t{\n\t\t\t\tyy_did_buffer_switch_on_eof = 0;\n\n\t\t\t\tif ( yywrap() )\n\t\t\t\t\t{\n\t\t\t\t\t/* Note: because we've taken care in\n\t\t\t\t\t * yy_get_next_buffer() to have set up\n\t\t\t\t\t * yytext, we can now set up\n\t\t\t\t\t * yy_c_buf_p so that if some total\n\t\t\t\t\t * hoser (like flex itself) wants to\n\t\t\t\t\t * call the scanner after we return the\n\t\t\t\t\t * YY_NULL, it'll still work - another\n\t\t\t\t\t * YY_NULL will get returned.\n\t\t\t\t\t */\n\t\t\t\t\tyy_c_buf_p = yytext_ptr + YY_MORE_ADJ;\n\n\t\t\t\t\tyy_act = YY_STATE_EOF(YY_START);\n\t\t\t\t\tgoto do_action;\n\t\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tif ( ! yy_did_buffer_switch_on_eof )\n\t\t\t\t\t\tYY_NEW_FILE;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\tyy_c_buf_p =\n\t\t\t\t\tyytext_ptr + yy_amount_of_matched_text;\n\n\t\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t\tyy_cp = yy_c_buf_p;\n\t\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\t\t\t\tgoto yy_match;\n\n\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\tyy_c_buf_p =\n\t\t\t\t&yy_current_buffer->yy_ch_buf[yy_n_chars];\n\n\t\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t\tyy_cp = yy_c_buf_p;\n\t\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\t\t\t\tgoto yy_find_action;\n\t\t\t}\n\t\tbreak;\n\t\t}\n\n\tdefault:\n\t\tYY_FATAL_ERROR(\n\t\t\t\"fatal flex scanner internal error--no action found\" );\n\t} /* end of action switch */\n\t\t} /* end of scanning one token */\n\t} /* end of yylex */\n\n%+\nyyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )\n\t{\n\tyyin = arg_yyin;\n\tyyout = arg_yyout;\n\tyy_c_buf_p = 0;\n\tyy_init = 1;\n\tyy_start = 0;\n\tyy_flex_debug = 0;\n\tyylineno = 1;\t// this will only get updated if %option yylineno\n\n\tyy_did_buffer_switch_on_eof = 0;\n\n\tyy_looking_for_trail_begin = 0;\n\tyy_more_flag = 0;\n\tyy_more_len = 0;\n\tyy_more_offset = yy_prev_more_offset = 0;\n\n\tyy_start_stack_ptr = yy_start_stack_depth = 0;\n\tyy_start_stack = 0;\n\n\tyy_current_buffer = 0;\n\n#ifdef YY_USES_REJECT\n\tyy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];\n#else\n\tyy_state_buf = 0;\n#endif\n\t}\n\nyyFlexLexer::~yyFlexLexer()\n\t{\n\tdelete yy_state_buf;\n\tyy_delete_buffer( yy_current_buffer );\n\t}\n\nvoid yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )\n\t{\n\tif ( new_in )\n\t\t{\n\t\tyy_delete_buffer( yy_current_buffer );\n\t\tyy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );\n\t\t}\n\n\tif ( new_out )\n\t\tyyout = new_out;\n\t}\n\n#ifdef YY_INTERACTIVE\nint yyFlexLexer::LexerInput( char* buf, int /* max_size */ )\n#else\nint yyFlexLexer::LexerInput( char* buf, int max_size )\n#endif\n\t{\n\tif ( yyin->eof() || yyin->fail() )\n\t\treturn 0;\n\n#ifdef YY_INTERACTIVE\n\tyyin->get( buf[0] );\n\n\tif ( yyin->eof() )\n\t\treturn 0;\n\n\tif ( yyin->bad() )\n\t\treturn -1;\n\n\treturn 1;\n\n#else\n\t(void) yyin->read( buf, max_size );\n\n\tif ( yyin->bad() )\n\t\treturn -1;\n\telse\n\t\treturn yyin->gcount();\n#endif\n\t}\n\nvoid yyFlexLexer::LexerOutput( const char* buf, int size )\n\t{\n\t(void) yyout->write( buf, size );\n\t}\n%*\n\n/* yy_get_next_buffer - try to read in a new buffer\n *\n * Returns a code representing an action:\n *\tEOB_ACT_LAST_MATCH -\n *\tEOB_ACT_CONTINUE_SCAN - continue scanning from current position\n *\tEOB_ACT_END_OF_FILE - end of file\n */\n\n%-\nstatic int yy_get_next_buffer()\n%+\nint yyFlexLexer::yy_get_next_buffer()\n%*\n\t{\n\tregister char *dest = yy_current_buffer->yy_ch_buf;\n\tregister char *source = yytext_ptr;\n\tregister int number_to_move, i;\n\tint ret_val;\n\n\tif ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )\n\t\tYY_FATAL_ERROR(\n\t\t\"fatal flex scanner internal error--end of buffer missed\" );\n\n\tif ( yy_current_buffer->yy_fill_buffer == 0 )\n\t\t{ /* Don't try to fill the buffer, so this is an EOF. */\n\t\tif ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )\n\t\t\t{\n\t\t\t/* We matched a single character, the EOB, so\n\t\t\t * treat this as a final EOF.\n\t\t\t */\n\t\t\treturn EOB_ACT_END_OF_FILE;\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\t/* We matched some text prior to the EOB, first\n\t\t\t * process it.\n\t\t\t */\n\t\t\treturn EOB_ACT_LAST_MATCH;\n\t\t\t}\n\t\t}\n\n\t/* Try to read more data. */\n\n\t/* First move last chars to start of buffer. */\n\tnumber_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;\n\n\tfor ( i = 0; i < number_to_move; ++i )\n\t\t*(dest++) = *(source++);\n\n\tif ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )\n\t\t/* don't do the read, it's not guaranteed to return an EOF,\n\t\t * just force an EOF\n\t\t */\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars = 0;\n\n\telse\n\t\t{\n\t\tint num_to_read =\n\t\t\tyy_current_buffer->yy_buf_size - number_to_move - 1;\n\n\t\twhile ( num_to_read <= 0 )\n\t\t\t{ /* Not enough room in the buffer - grow it. */\n#ifdef YY_USES_REJECT\n\t\t\tYY_FATAL_ERROR(\n\"input buffer overflow, can't enlarge buffer because scanner uses REJECT\" );\n#else\n\n\t\t\t/* just a shorter name for the current buffer */\n\t\t\tYY_BUFFER_STATE b = yy_current_buffer;\n\n\t\t\tint yy_c_buf_p_offset =\n\t\t\t\t(int) (yy_c_buf_p - b->yy_ch_buf);\n\n\t\t\tif ( b->yy_is_our_buffer )\n\t\t\t\t{\n\t\t\t\tint new_size = b->yy_buf_size * 2;\n\n\t\t\t\tif ( new_size <= 0 )\n\t\t\t\t\tb->yy_buf_size += b->yy_buf_size / 8;\n\t\t\t\telse\n\t\t\t\t\tb->yy_buf_size *= 2;\n\n\t\t\t\tb->yy_ch_buf = (char *)\n\t\t\t\t\t/* Include room in for 2 EOB chars. */\n\t\t\t\t\tyy_flex_realloc( (void *) b->yy_ch_buf,\n\t\t\t\t\t\t\t b->yy_buf_size + 2 );\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t/* Can't grow it, we don't own it. */\n\t\t\t\tb->yy_ch_buf = 0;\n\n\t\t\tif ( ! b->yy_ch_buf )\n\t\t\t\tYY_FATAL_ERROR(\n\t\t\t\t\"fatal error - scanner input buffer overflow\" );\n\n\t\t\tyy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];\n\n\t\t\tnum_to_read = yy_current_buffer->yy_buf_size -\n\t\t\t\t\t\tnumber_to_move - 1;\n#endif\n\t\t\t}\n\n\t\tif ( num_to_read > YY_READ_BUF_SIZE )\n\t\t\tnum_to_read = YY_READ_BUF_SIZE;\n\n\t\t/* Read in more data. */\n\t\tYY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),\n\t\t\tyy_n_chars, num_to_read );\n\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars;\n\t\t}\n\n\tif ( yy_n_chars == 0 )\n\t\t{\n\t\tif ( number_to_move == YY_MORE_ADJ )\n\t\t\t{\n\t\t\tret_val = EOB_ACT_END_OF_FILE;\n\t\t\tyyrestart( yyin );\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\tret_val = EOB_ACT_LAST_MATCH;\n\t\t\tyy_current_buffer->yy_buffer_status =\n\t\t\t\tYY_BUFFER_EOF_PENDING;\n\t\t\t}\n\t\t}\n\n\telse\n\t\tret_val = EOB_ACT_CONTINUE_SCAN;\n\n\tyy_n_chars += number_to_move;\n\tyy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;\n\tyy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;\n\n\tyytext_ptr = &yy_current_buffer->yy_ch_buf[0];\n\n\treturn ret_val;\n\t}\n\n\n/* yy_get_previous_state - get the state just before the EOB char was reached */\n\n%-\nstatic yy_state_type yy_get_previous_state()\n%+\nyy_state_type yyFlexLexer::yy_get_previous_state()\n%*\n\t{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp;\n\n%% code to get the start state into yy_current_state goes here\n\n\tfor ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )\n\t\t{\n%% code to find the next state goes here\n\t\t}\n\n\treturn yy_current_state;\n\t}\n\n\n/* yy_try_NUL_trans - try to make a transition on the NUL character\n *\n * synopsis\n *\tnext_state = yy_try_NUL_trans( current_state );\n */\n\n%-\n#ifdef YY_USE_PROTOS\nstatic yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )\n#else\nstatic yy_state_type yy_try_NUL_trans( yy_current_state )\nyy_state_type yy_current_state;\n#endif\n%+\nyy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )\n%*\n\t{\n\tregister int yy_is_jam;\n%% code to find the next state, and perhaps do backing up, goes here\n\n\treturn yy_is_jam ? 0 : yy_current_state;\n\t}\n\n\n%-\n#ifndef YY_NO_UNPUT\n#ifdef YY_USE_PROTOS\nstatic void yyunput( int c, register char *yy_bp )\n#else\nstatic void yyunput( c, yy_bp )\nint c;\nregister char *yy_bp;\n#endif\n%+\nvoid yyFlexLexer::yyunput( int c, register char* yy_bp )\n%*\n\t{\n\tregister char *yy_cp = yy_c_buf_p;\n\n\t/* undo effects of setting up yytext */\n\t*yy_cp = yy_hold_char;\n\n\tif ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\n\t\t{ /* need to shift things up to make room */\n\t\t/* +2 for EOB chars. */\n\t\tregister int number_to_move = yy_n_chars + 2;\n\t\tregister char *dest = &yy_current_buffer->yy_ch_buf[\n\t\t\t\t\tyy_current_buffer->yy_buf_size + 2];\n\t\tregister char *source =\n\t\t\t\t&yy_current_buffer->yy_ch_buf[number_to_move];\n\n\t\twhile ( source > yy_current_buffer->yy_ch_buf )\n\t\t\t*--dest = *--source;\n\n\t\tyy_cp += (int) (dest - source);\n\t\tyy_bp += (int) (dest - source);\n\t\tyy_current_buffer->yy_n_chars =\n\t\t\tyy_n_chars = yy_current_buffer->yy_buf_size;\n\n\t\tif ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\n\t\t\tYY_FATAL_ERROR( \"flex scanner push-back overflow\" );\n\t\t}\n\n\t*--yy_cp = (char) c;\n\n%% update yylineno here\n\n\tyytext_ptr = yy_bp;\n\tyy_hold_char = *yy_cp;\n\tyy_c_buf_p = yy_cp;\n\t}\n%-\n#endif\t/* ifndef YY_NO_UNPUT */\n%*\n\n\n%-\n#ifdef __cplusplus\nstatic int yyinput()\n#else\nstatic int input()\n#endif\n%+\nint yyFlexLexer::yyinput()\n%*\n\t{\n\tint c;\n\n\t*yy_c_buf_p = yy_hold_char;\n\n\tif ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )\n\t\t{\n\t\t/* yy_c_buf_p now points to the character we want to return.\n\t\t * If this occurs *before* the EOB characters, then it's a\n\t\t * valid NUL; if not, then we've hit the end of the buffer.\n\t\t */\n\t\tif ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )\n\t\t\t/* This was really a NUL. */\n\t\t\t*yy_c_buf_p = '\\0';\n\n\t\telse\n\t\t\t{ /* need more input */\n\t\t\tint offset = (int)(yy_c_buf_p - yytext_ptr);\n\t\t\t++yy_c_buf_p;\n\n\t\t\tswitch ( yy_get_next_buffer() )\n\t\t\t\t{\n\t\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\t\t/* This happens because yy_g_n_b()\n\t\t\t\t\t * sees that we've accumulated a\n\t\t\t\t\t * token and flags that we need to\n\t\t\t\t\t * try matching the token before\n\t\t\t\t\t * proceeding.  But for input(),\n\t\t\t\t\t * there's no matching to consider.\n\t\t\t\t\t * So convert the EOB_ACT_LAST_MATCH\n\t\t\t\t\t * to EOB_ACT_END_OF_FILE.\n\t\t\t\t\t */\n\n\t\t\t\t\t/* Reset buffer status. */\n\t\t\t\t\tyyrestart( yyin );\n\n\t\t\t\t\t/* fall through */\n\n\t\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t\t{\n\t\t\t\t\tif ( yywrap() )\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tif ( ! yy_did_buffer_switch_on_eof )\n\t\t\t\t\t\tYY_NEW_FILE;\n#ifdef __cplusplus\n\t\t\t\t\treturn yyinput();\n#else\n\t\t\t\t\treturn input();\n#endif\n\t\t\t\t\t}\n\n\t\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\t\tyy_c_buf_p = yytext_ptr + offset;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tc = *(unsigned char *) yy_c_buf_p;\t/* cast for 8-bit char's */\n\t*yy_c_buf_p = '\\0';\t/* preserve yytext */\n\tyy_hold_char = *++yy_c_buf_p;\n\n%% update BOL and yylineno\n\n\treturn c;\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nvoid yyrestart( FILE *input_file )\n#else\nvoid yyrestart( input_file )\nFILE *input_file;\n#endif\n%+\nvoid yyFlexLexer::yyrestart( istream* input_file )\n%*\n\t{\n\tif ( ! yy_current_buffer )\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );\n\n\tyy_init_buffer( yy_current_buffer, input_file );\n\tyy_load_buffer_state();\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nvoid yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )\n#else\nvoid yy_switch_to_buffer( new_buffer )\nYY_BUFFER_STATE new_buffer;\n#endif\n%+\nvoid yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )\n%*\n\t{\n\tif ( yy_current_buffer == new_buffer )\n\t\treturn;\n\n\tif ( yy_current_buffer )\n\t\t{\n\t\t/* Flush out information for old buffer. */\n\t\t*yy_c_buf_p = yy_hold_char;\n\t\tyy_current_buffer->yy_buf_pos = yy_c_buf_p;\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars;\n\t\t}\n\n\tyy_current_buffer = new_buffer;\n\tyy_load_buffer_state();\n\n\t/* We don't actually know whether we did this switch during\n\t * EOF (yywrap()) processing, but the only time this flag\n\t * is looked at is after yywrap() is called, so it's safe\n\t * to go ahead and always set it.\n\t */\n\tyy_did_buffer_switch_on_eof = 1;\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nvoid yy_load_buffer_state( void )\n#else\nvoid yy_load_buffer_state()\n#endif\n%+\nvoid yyFlexLexer::yy_load_buffer_state()\n%*\n\t{\n\tyy_n_chars = yy_current_buffer->yy_n_chars;\n\tyytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;\n\tyyin = yy_current_buffer->yy_input_file;\n\tyy_hold_char = *yy_c_buf_p;\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_create_buffer( FILE *file, int size )\n#else\nYY_BUFFER_STATE yy_create_buffer( file, size )\nFILE *file;\nint size;\n#endif\n%+\nYY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )\n%*\n\t{\n\tYY_BUFFER_STATE b;\n\n\tb = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );\n\n\tb->yy_buf_size = size;\n\n\t/* yy_ch_buf has to be 2 characters longer than the size given because\n\t * we need to put in 2 end-of-buffer characters.\n\t */\n\tb->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );\n\tif ( ! b->yy_ch_buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );\n\n\tb->yy_is_our_buffer = 1;\n\n\tyy_init_buffer( b, file );\n\n\treturn b;\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nvoid yy_delete_buffer( YY_BUFFER_STATE b )\n#else\nvoid yy_delete_buffer( b )\nYY_BUFFER_STATE b;\n#endif\n%+\nvoid yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )\n%*\n\t{\n\tif ( ! b )\n\t\treturn;\n\n\tif ( b == yy_current_buffer )\n\t\tyy_current_buffer = (YY_BUFFER_STATE) 0;\n\n\tif ( b->yy_is_our_buffer )\n\t\tyy_flex_free( (void *) b->yy_ch_buf );\n\n\tyy_flex_free( (void *) b );\n\t}\n\n\n%-\n#ifndef YY_ALWAYS_INTERACTIVE\n#ifndef YY_NEVER_INTERACTIVE\nextern int isatty YY_PROTO(( int ));\n#endif\n#endif\n\n#ifdef YY_USE_PROTOS\nvoid yy_init_buffer( YY_BUFFER_STATE b, FILE *file )\n#else\nvoid yy_init_buffer( b, file )\nYY_BUFFER_STATE b;\nFILE *file;\n#endif\n\n%+\nextern \"C\" int isatty YY_PROTO(( int ));\nvoid yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )\n%*\n\n\t{\n\tyy_flush_buffer( b );\n\n\tb->yy_input_file = file;\n\tb->yy_fill_buffer = 1;\n\n%-\n#if YY_ALWAYS_INTERACTIVE\n\tb->yy_is_interactive = 1;\n#else\n#if YY_NEVER_INTERACTIVE\n\tb->yy_is_interactive = 0;\n#else\n\tb->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;\n#endif\n#endif\n%+\n\tb->yy_is_interactive = 0;\n%*\n\t}\n\n\n%-\n#ifdef YY_USE_PROTOS\nvoid yy_flush_buffer( YY_BUFFER_STATE b )\n#else\nvoid yy_flush_buffer( b )\nYY_BUFFER_STATE b;\n#endif\n\n%+\nvoid yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )\n%*\n\t{\n\tif ( ! b )\n\t\treturn;\n\n\tb->yy_n_chars = 0;\n\n\t/* We always need two end-of-buffer characters.  The first causes\n\t * a transition to the end-of-buffer state.  The second causes\n\t * a jam in that state.\n\t */\n\tb->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;\n\tb->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;\n\n\tb->yy_buf_pos = &b->yy_ch_buf[0];\n\n\tb->yy_at_bol = 1;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tif ( b == yy_current_buffer )\n\t\tyy_load_buffer_state();\n\t}\n%*\n\n\n#ifndef YY_NO_SCAN_BUFFER\n%-\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )\n#else\nYY_BUFFER_STATE yy_scan_buffer( base, size )\nchar *base;\nyy_size_t size;\n#endif\n\t{\n\tYY_BUFFER_STATE b;\n\n\tif ( size < 2 ||\n\t     base[size-2] != YY_END_OF_BUFFER_CHAR ||\n\t     base[size-1] != YY_END_OF_BUFFER_CHAR )\n\t\t/* They forgot to leave room for the EOB's. */\n\t\treturn 0;\n\n\tb = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_scan_buffer()\" );\n\n\tb->yy_buf_size = size - 2;\t/* \"- 2\" to take care of EOB's */\n\tb->yy_buf_pos = b->yy_ch_buf = base;\n\tb->yy_is_our_buffer = 0;\n\tb->yy_input_file = 0;\n\tb->yy_n_chars = b->yy_buf_size;\n\tb->yy_is_interactive = 0;\n\tb->yy_at_bol = 1;\n\tb->yy_fill_buffer = 0;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tyy_switch_to_buffer( b );\n\n\treturn b;\n\t}\n%*\n#endif\n\n\n#ifndef YY_NO_SCAN_STRING\n%-\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )\n#else\nYY_BUFFER_STATE yy_scan_string( yy_str )\nyyconst char *yy_str;\n#endif\n\t{\n\tint len;\n\tfor ( len = 0; yy_str[len]; ++len )\n\t\t;\n\n\treturn yy_scan_bytes( yy_str, len );\n\t}\n%*\n#endif\n\n\n#ifndef YY_NO_SCAN_BYTES\n%-\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )\n#else\nYY_BUFFER_STATE yy_scan_bytes( bytes, len )\nyyconst char *bytes;\nint len;\n#endif\n\t{\n\tYY_BUFFER_STATE b;\n\tchar *buf;\n\tyy_size_t n;\n\tint i;\n\n\t/* Get memory for full buffer, including space for trailing EOB's. */\n\tn = len + 2;\n\tbuf = (char *) yy_flex_alloc( n );\n\tif ( ! buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_scan_bytes()\" );\n\n\tfor ( i = 0; i < len; ++i )\n\t\tbuf[i] = bytes[i];\n\n\tbuf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;\n\n\tb = yy_scan_buffer( buf, n );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"bad buffer in yy_scan_bytes()\" );\n\n\t/* It's okay to grow etc. this buffer, and we should throw it\n\t * away when we're done.\n\t */\n\tb->yy_is_our_buffer = 1;\n\n\treturn b;\n\t}\n%*\n#endif\n\n\n#ifndef YY_NO_PUSH_STATE\n%-\n#ifdef YY_USE_PROTOS\nstatic void yy_push_state( int new_state )\n#else\nstatic void yy_push_state( new_state )\nint new_state;\n#endif\n%+\nvoid yyFlexLexer::yy_push_state( int new_state )\n%*\n\t{\n\tif ( yy_start_stack_ptr >= yy_start_stack_depth )\n\t\t{\n\t\tyy_size_t new_size;\n\n\t\tyy_start_stack_depth += YY_START_STACK_INCR;\n\t\tnew_size = yy_start_stack_depth * sizeof( int );\n\n\t\tif ( ! yy_start_stack )\n\t\t\tyy_start_stack = (int *) yy_flex_alloc( new_size );\n\n\t\telse\n\t\t\tyy_start_stack = (int *) yy_flex_realloc(\n\t\t\t\t\t(void *) yy_start_stack, new_size );\n\n\t\tif ( ! yy_start_stack )\n\t\t\tYY_FATAL_ERROR(\n\t\t\t\"out of memory expanding start-condition stack\" );\n\t\t}\n\n\tyy_start_stack[yy_start_stack_ptr++] = YY_START;\n\n\tBEGIN(new_state);\n\t}\n#endif\n\n\n#ifndef YY_NO_POP_STATE\n%-\nstatic void yy_pop_state()\n%+\nvoid yyFlexLexer::yy_pop_state()\n%*\n\t{\n\tif ( --yy_start_stack_ptr < 0 )\n\t\tYY_FATAL_ERROR( \"start-condition stack underflow\" );\n\n\tBEGIN(yy_start_stack[yy_start_stack_ptr]);\n\t}\n#endif\n\n\n#ifndef YY_NO_TOP_STATE\n%-\nstatic int yy_top_state()\n%+\nint yyFlexLexer::yy_top_state()\n%*\n\t{\n\treturn yy_start_stack[yy_start_stack_ptr - 1];\n\t}\n#endif\n\n#ifndef YY_EXIT_FAILURE\n#define YY_EXIT_FAILURE 2\n#endif\n\n%-\n#ifdef YY_USE_PROTOS\nstatic void yy_fatal_error( yyconst char msg[] )\n#else\nstatic void yy_fatal_error( msg )\nchar msg[];\n#endif\n\t{\n\t(void) fprintf( stderr, \"%s\\n\", msg );\n\texit( YY_EXIT_FAILURE );\n\t}\n\n%+\n\nvoid yyFlexLexer::LexerError( yyconst char msg[] )\n\t{\n\tcerr << msg << '\\n';\n\texit( YY_EXIT_FAILURE );\n\t}\n%*\n\n\n/* Redefine yyless() so it works in section 3 code. */\n\n#undef yyless\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up yytext. */ \\\n\t\tyytext[yyleng] = yy_hold_char; \\\n\t\tyy_c_buf_p = yytext + n; \\\n\t\tyy_hold_char = *yy_c_buf_p; \\\n\t\t*yy_c_buf_p = '\\0'; \\\n\t\tyyleng = n; \\\n\t\t} \\\n\twhile ( 0 )\n\n\n/* Internal utility routines. */\n\n#ifndef yytext_ptr\n#ifdef YY_USE_PROTOS\nstatic void yy_flex_strncpy( char *s1, yyconst char *s2, int n )\n#else\nstatic void yy_flex_strncpy( s1, s2, n )\nchar *s1;\nyyconst char *s2;\nint n;\n#endif\n\t{\n\tregister int i;\n\tfor ( i = 0; i < n; ++i )\n\t\ts1[i] = s2[i];\n\t}\n#endif\n\n#ifdef YY_NEED_STRLEN\n#ifdef YY_USE_PROTOS\nstatic int yy_flex_strlen( yyconst char *s )\n#else\nstatic int yy_flex_strlen( s )\nyyconst char *s;\n#endif\n\t{\n\tregister int n;\n\tfor ( n = 0; s[n]; ++n )\n\t\t;\n\n\treturn n;\n\t}\n#endif\n\n\n#ifdef YY_USE_PROTOS\nstatic void *yy_flex_alloc( yy_size_t size )\n#else\nstatic void *yy_flex_alloc( size )\nyy_size_t size;\n#endif\n\t{\n\treturn (void *) malloc( size );\n\t}\n\n#ifdef YY_USE_PROTOS\nstatic void *yy_flex_realloc( void *ptr, yy_size_t size )\n#else\nstatic void *yy_flex_realloc( ptr, size )\nvoid *ptr;\nyy_size_t size;\n#endif\n\t{\n\t/* The cast to (char *) in the following accommodates both\n\t * implementations that use char* generic pointers, and those\n\t * that use void* generic pointers.  It works with the latter\n\t * because both ANSI C and C++ allow castless assignment from\n\t * any pointer type to void*, and deal with argument conversions\n\t * as though doing an assignment.\n\t */\n\treturn (void *) realloc( (char *) ptr, size );\n\t}\n\n#ifdef YY_USE_PROTOS\nstatic void yy_flex_free( void *ptr )\n#else\nstatic void yy_flex_free( ptr )\nvoid *ptr;\n#endif\n\t{\n\tfree( ptr );\n\t}\n\n#if YY_MAIN\nint main()\n\t{\n\tyylex();\n\treturn 0;\n\t}\n#endif\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_gramatical.cpp",
    "content": "\n/*  A Bison parser, made from cf_gramatical.yxx\n    by GNU Bison version 1.28  */\n\n#define YYBISON 1  /* Identify Bison output.  */\n\n#define yyparse cfparse\n#define yylex cflex\n#define yyerror cferror\n#define yylval cflval\n#define yychar cfchar\n#define yydebug cfdebug\n#define yynerrs cfnerrs\n#define\tADD_ASSIGN\t257\n#define\tASSIGN\t258\n#define\tVARIABLE\t259\n#define\tSTRING\t260\n#define\tSEMICOLON\t261\n#define\tPLUS\t262\n#define\tMINUS\t263\n#define\tMULT\t264\n#define\tDIVIDE\t265\n#define\tRPAREN\t266\n#define\tLPAREN\t267\n#define\tRBRACE\t268\n#define\tLBRACE\t269\n#define\tCOMMA\t270\n#define\tINTEGER\t271\n#define\tREAL\t272\n#define\tFILELINE\t273\n\n#line 1 \"cf_gramatical.yxx\"\n\n\n/* Includes */\n\n#ifdef NL_OS_WINDOWS\n#pragma warning (disable : 4786)\n#endif // NL_OS_WINDOWS\n\n\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n\n#include <cstdio>\n#include <vector>\n#include <string>\n\nusing namespace std;\nusing namespace NLMISC;\n\n/* Constantes */\n\n#define YYPARSE_PARAM pvararray\n\n// WARNING!!!! DEBUG_PRINTF are commented using // so IT MUST HAVE NO INSTRUCTION AFTER A DEBUG_PRINTF OR THEY LL BE COMMENTED\n/*\n#define DEBUG_PRINTF\tInfoLog->displayRaw\n#define DEBUG_PRINT(a)\tInfoLog->displayRaw(a)\n*/\n\n#define DEBUG_PRINT(a)\n#ifdef __GNUC__\n#define DEBUG_PRINTF(format, args...)\n#else // __GNUC__\n#define DEBUG_PRINTF\t// InfoLog->displayRaw\n#endif // __GNUC__\n\n\n/* Types */\n\nenum cf_operation { OP_PLUS, OP_MINUS, OP_MULT, OP_DIVIDE, OP_NEG };\n\nstruct cf_value\n{\n\tNLMISC::CConfigFile::CVar::TVarType\tType;\n\tint\t\t\t\t\t\tInt;\n\tdouble\t\t\t\t\tReal;\n\tchar\t\t\t\t\tString[1024];\n};\n\n/* Externals */\n\nextern bool cf_Ignore;\n\nextern bool LoadRoot;\n\nextern FILE *yyin;\n\n/* Variables */\n\nNLMISC::CConfigFile::CVar\t\tcf_CurrentVar;\n\nint\t\tcf_CurrentLine;\nchar\t*cf_CurrentFile;\n\nbool\tcf_OverwriteExistingVariable;\t// setup in the config_file.cpp reparse()\n\n\n\n/* Prototypes */\n\nint yylex (void);\n\ncf_value cf_op (cf_value a, cf_value b, cf_operation op);\n\nvoid cf_print (cf_value Val);\n\nvoid cf_setVar (NLMISC::CConfigFile::CVar &Var, cf_value Val);\n\nint yyerror (const char *);\n\n\n#line 85 \"cf_gramatical.yxx\"\ntypedef union\t{\n\t\t\tcf_value Val;\n\t\t} YYSTYPE;\n#include <cstdio>\n\n#ifndef __cplusplus\n#ifndef __STDC__\n#define const\n#endif\n#endif\n\n\n\n#define\tYYFINAL\t\t47\n#define\tYYFLAG\t\t-32768\n#define\tYYNTBASE\t20\n\n#define YYTRANSLATE(x) ((unsigned)(x) <= 273 ? yytranslate[x] : 29)\n\nstatic const char yytranslate[] = {     0,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,\n     2,     2,     2,     2,     2,     1,     3,     4,     5,     6,\n     7,     8,     9,    10,    11,    12,    13,    14,    15,    16,\n    17,    18,    19\n};\n\n#if YYDEBUG != 0\nstatic const short yyprhs[] = {     0,\n     0,     2,     3,     6,     8,    12,    17,    22,    24,    28,\n    33,    36,    38,    42,    44,    48,    52,    54,    58,    62,\n    65,    68,    72,    74,    76,    78,    80\n};\n\nstatic const short yyrhs[] = {    21,\n     0,     0,    21,    22,     0,    22,     0,    19,     6,    17,\n     0,     5,     4,    23,     7,     0,     5,     3,    23,     7,\n     0,    25,     0,    15,    24,    14,     0,    15,    24,    16,\n    14,     0,    15,    14,     0,    25,     0,    24,    16,    25,\n     0,    26,     0,    25,     8,    26,     0,    25,     9,    26,\n     0,    27,     0,    26,    10,    27,     0,    26,    11,    27,\n     0,     8,    27,     0,     9,    27,     0,    13,    23,    12,\n     0,    17,     0,    18,     0,     6,     0,    28,     0,     5,\n     0\n};\n\n#endif\n\n#if YYDEBUG != 0\nstatic const short yyrline[] = { 0,\n   104,   104,   107,   108,   111,   123,   185,   245,   246,   247,\n   248,   251,   252,   255,   256,   257,   260,   261,   262,   265,\n   266,   267,   268,   269,   270,   271,   274\n};\n#endif\n\n\n#if YYDEBUG != 0 || defined (YYERROR_VERBOSE)\n\nstatic const char * const yytname[] = {   \"$\",\"error\",\"$undefined.\",\"ADD_ASSIGN\",\n\"ASSIGN\",\"VARIABLE\",\"STRING\",\"SEMICOLON\",\"PLUS\",\"MINUS\",\"MULT\",\"DIVIDE\",\"RPAREN\",\n\"LPAREN\",\"RBRACE\",\"LBRACE\",\"COMMA\",\"INTEGER\",\"REAL\",\"FILELINE\",\"ROOT\",\"instlist\",\n\"inst\",\"expression\",\"exprbrace\",\"expr2\",\"expr3\",\"expr4\",\"variable\", NULL\n};\n#endif\n\nstatic const short yyr1[] = {     0,\n    20,    20,    21,    21,    22,    22,    22,    23,    23,    23,\n    23,    24,    24,    25,    25,    25,    26,    26,    26,    27,\n    27,    27,    27,    27,    27,    27,    28\n};\n\nstatic const short yyr2[] = {     0,\n     1,     0,     2,     1,     3,     4,     4,     1,     3,     4,\n     2,     1,     3,     1,     3,     3,     1,     3,     3,     2,\n     2,     3,     1,     1,     1,     1,     1\n};\n\nstatic const short yydefact[] = {     2,\n     0,     0,     1,     4,     0,     0,     0,     3,    27,    25,\n     0,     0,     0,     0,    23,    24,     0,     8,    14,    17,\n    26,     0,     5,    20,    21,     0,    11,     0,    12,     7,\n     0,     0,     0,     0,     6,    22,     9,     0,    15,    16,\n    18,    19,    10,    13,     0,     0,     0\n};\n\nstatic const short yydefgoto[] = {    45,\n     3,     4,    17,    28,    18,    19,    20,    21\n};\n\nstatic const short yypact[] = {    -4,\n    17,     2,    -4,-32768,     1,     1,   -15,-32768,-32768,-32768,\n    50,    50,     1,    22,-32768,-32768,    10,    14,    23,-32768,\n-32768,    25,-32768,-32768,-32768,    31,-32768,    -3,    14,-32768,\n    50,    50,    50,    50,-32768,-32768,-32768,    36,    23,    23,\n-32768,-32768,-32768,    14,    29,    46,-32768\n};\n\nstatic const short yypgoto[] = {-32768,\n-32768,    44,    -1,-32768,   -14,     6,    -8,-32768\n};\n\n\n#define\tYYLAST\t\t68\n\n\nstatic const short yytable[] = {    29,\n     1,    23,    24,    25,    22,     9,    10,     7,    11,    12,\n    37,    26,    38,    13,     2,    14,    30,    15,    16,     5,\n     6,    31,    32,    44,    41,    42,     9,    10,    46,    11,\n    12,    35,    33,    34,    13,    27,    39,    40,    15,    16,\n     9,    10,    36,    11,    12,    47,     8,     0,    13,    43,\n     0,     0,    15,    16,     9,    10,     0,    11,    12,     0,\n     0,     0,    13,     0,     0,     0,    15,    16\n};\n\nstatic const short yycheck[] = {    14,\n     5,    17,    11,    12,     6,     5,     6,     6,     8,     9,\n    14,    13,    16,    13,    19,    15,     7,    17,    18,     3,\n     4,     8,     9,    38,    33,    34,     5,     6,     0,     8,\n     9,     7,    10,    11,    13,    14,    31,    32,    17,    18,\n     5,     6,    12,     8,     9,     0,     3,    -1,    13,    14,\n    -1,    -1,    17,    18,     5,     6,    -1,     8,     9,    -1,\n    -1,    -1,    13,    -1,    -1,    -1,    17,    18\n};\n/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */\n#line 3 \"cfbison.simple\"\n/* This file comes from bison-1.28.  */\n\n/* Skeleton output parser for bison,\n   Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc.\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2, or (at your option)\n   any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 59 Temple Place - Suite 330,\n   Boston, MA 02111-1307, USA.  */\n\n/* As a special exception, when this file is copied by Bison into a\n   Bison output file, you may use that output file without restriction.\n   This special exception was added by the Free Software Foundation\n   in version 1.24 of Bison.  */\n\n/* This is the parser code that is written into each bison parser\n  when the %semantic_parser declaration is not specified in the grammar.\n  It was written by Richard Stallman by simplifying the hairy parser\n  used when %semantic_parser is specified.  */\n\n#ifndef YYSTACK_USE_ALLOCA\n#ifdef alloca\n#define YYSTACK_USE_ALLOCA\n#else /* alloca not defined */\n#ifdef __GNUC__\n#define YYSTACK_USE_ALLOCA\n#define alloca __builtin_alloca\n#else /* not GNU C.  */\n#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386))\n#define YYSTACK_USE_ALLOCA\n#include <alloca.h>\n#else /* not sparc */\n/* We think this test detects Watcom and Microsoft C.  */\n/* This used to test MSDOS, but that is a bad idea\n   since that symbol is in the user namespace.  */\n#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__)\n#if 0 /* No need for malloc.h, which pollutes the namespace;\n\t instead, just don't use alloca.  */\n#include <malloc.h>\n#endif\n#else /* not MSDOS, or __TURBOC__ */\n#if defined(_AIX)\n/* I don't know what this was needed for, but it pollutes the namespace.\n   So I turned it off.   rms, 2 May 1997.  */\n/* #include <malloc.h>  */\n #pragma alloca\n#define YYSTACK_USE_ALLOCA\n#else /* not MSDOS, or __TURBOC__, or _AIX */\n#if 0\n#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up,\n\t\t and on HPUX 10.  Eventually we can turn this on.  */\n#define YYSTACK_USE_ALLOCA\n#define alloca __builtin_alloca\n#endif /* __hpux */\n#endif\n#endif /* not _AIX */\n#endif /* not MSDOS, or __TURBOC__ */\n#endif /* not sparc */\n#endif /* not GNU C */\n#endif /* alloca not defined */\n#endif /* YYSTACK_USE_ALLOCA not defined */\n\n#ifdef YYSTACK_USE_ALLOCA\n#define YYSTACK_ALLOC alloca\n#else\n#define YYSTACK_ALLOC malloc\n#endif\n\n/* Note: there must be only one dollar sign in this file.\n   It is replaced by the list of actions, each action\n   as one case of the switch.  */\n\n#define yyerrok\t\t(yyerrstatus = 0)\n#define yyclearin\t(yychar = YYEMPTY)\n#define YYEMPTY\t\t-2\n#define YYEOF\t\t0\n#define YYACCEPT\tgoto yyacceptlab\n#define YYABORT \tgoto yyabortlab\n#define YYERROR\t\tgoto yyerrlab1\n/* Like YYERROR except do call yyerror.\n   This remains here temporarily to ease the\n   transition to the new meaning of YYERROR, for GCC.\n   Once GCC version 2 has supplanted version 1, this can go.  */\n#define YYFAIL\t\tgoto yyerrlab\n#define YYRECOVERING()  (!!yyerrstatus)\n#define YYBACKUP(token, value) \\\ndo\t\t\t\t\t\t\t\t\\\n  if (yychar == YYEMPTY && yylen == 1)\t\t\t\t\\\n    { yychar = (token), yylval = (value);\t\t\t\\\n      yychar1 = YYTRANSLATE (yychar);\t\t\t\t\\\n      YYPOPSTACK;\t\t\t\t\t\t\\\n      goto yybackup;\t\t\t\t\t\t\\\n    }\t\t\t\t\t\t\t\t\\\n  else\t\t\t\t\t\t\t\t\\\n    { yyerror (\"syntax error: cannot back up\"); YYERROR; }\t\\\nwhile (0)\n\n#define YYTERROR\t1\n#define YYERRCODE\t256\n\n#ifndef YYPURE\n#define YYLEX\t\tyylex()\n#endif\n\n#ifdef YYPURE\n#ifdef YYLSP_NEEDED\n#ifdef YYLEX_PARAM\n#define YYLEX\t\tyylex(&yylval, &yylloc, YYLEX_PARAM)\n#else\n#define YYLEX\t\tyylex(&yylval, &yylloc)\n#endif\n#else /* not YYLSP_NEEDED */\n#ifdef YYLEX_PARAM\n#define YYLEX\t\tyylex(&yylval, YYLEX_PARAM)\n#else\n#define YYLEX\t\tyylex(&yylval)\n#endif\n#endif /* not YYLSP_NEEDED */\n#endif\n\n/* If nonreentrant, generate the variables here */\n\n#ifndef YYPURE\n\nint\tyychar;\t\t\t/*  the lookahead symbol\t\t*/\nYYSTYPE\tyylval;\t\t\t/*  the semantic value of the\t\t*/\n\t\t\t\t/*  lookahead symbol\t\t\t*/\n\n#ifdef YYLSP_NEEDED\nYYLTYPE yylloc;\t\t\t/*  location data for the lookahead\t*/\n\t\t\t\t/*  symbol\t\t\t\t*/\n#endif\n\nint yynerrs;\t\t\t/*  number of parse errors so far       */\n#endif  /* not YYPURE */\n\n#if YYDEBUG != 0\nint yydebug;\t\t\t/*  nonzero means print parse trace\t*/\n/* Since this is uninitialized, it does not stop multiple parsers\n   from coexisting.  */\n#endif\n\n/*  YYINITDEPTH indicates the initial size of the parser's stacks\t*/\n\n#ifndef\tYYINITDEPTH\n#define YYINITDEPTH 200\n#endif\n\n/*  YYMAXDEPTH is the maximum size the stacks can grow to\n    (effective only if the built-in stack extension method is used).  */\n\n#if YYMAXDEPTH == 0\n#undef YYMAXDEPTH\n#endif\n\n#ifndef YYMAXDEPTH\n#define YYMAXDEPTH 10000\n#endif\n\f\n/* Define __yy_memcpy.  Note that the size argument\n   should be passed with type unsigned int, because that is what the non-GCC\n   definitions require.  With GCC, __builtin_memcpy takes an arg\n   of type size_t, but it can handle unsigned int.  */\n\n#if __GNUC__ > 1\t\t/* GNU C and GNU C++ define this.  */\n#define __yy_memcpy(TO,FROM,COUNT)\t__builtin_memcpy(TO,FROM,COUNT)\n#else\t\t\t\t/* not GNU C or C++ */\n#ifndef __cplusplus\n\n/* This is the most reliable way to avoid incompatibilities\n   in available built-in functions on various systems.  */\nstatic void\n__yy_memcpy (to, from, count)\n     char *to;\n     char *from;\n     unsigned int count;\n{\n  register char *f = from;\n  register char *t = to;\n  register int i = count;\n\n  while (i-- > 0)\n    *t++ = *f++;\n}\n\n#else /* __cplusplus */\n\n/* This is the most reliable way to avoid incompatibilities\n   in available built-in functions on various systems.  */\nstatic void\n__yy_memcpy (char *to, char *from, unsigned int count)\n{\n  register char *t = to;\n  register char *f = from;\n  register int i = count;\n\n  while (i-- > 0)\n    *t++ = *f++;\n}\n\n#endif\n#endif\n\f\n#line 217 \"cfbison.simple\"\n\n/* The user can define YYPARSE_PARAM as the name of an argument to be passed\n   into yyparse.  The argument should have type void *.\n   It should actually point to an object.\n   Grammar actions can access the variable by casting it\n   to the proper pointer type.  */\n\n#ifdef YYPARSE_PARAM\n#ifdef __cplusplus\n#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM\n#define YYPARSE_PARAM_DECL\n#else /* not __cplusplus */\n#define YYPARSE_PARAM_ARG YYPARSE_PARAM\n#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;\n#endif /* not __cplusplus */\n#else /* not YYPARSE_PARAM */\n#define YYPARSE_PARAM_ARG\n#define YYPARSE_PARAM_DECL\n#endif /* not YYPARSE_PARAM */\n\n/* Prevent warning if -Wstrict-prototypes.  */\n#ifdef __GNUC__\n#ifdef YYPARSE_PARAM\nint yyparse (void *);\n#else\nint yyparse (void);\n#endif\n#endif\n\nint\nyyparse(YYPARSE_PARAM_ARG)\n     YYPARSE_PARAM_DECL\n{\n  register int yystate;\n  register int yyn;\n  register short *yyssp;\n  register YYSTYPE *yyvsp;\n  int yyerrstatus;\t/*  number of tokens to shift before error messages enabled */\n  int yychar1 = 0;\t\t/*  lookahead token as an internal (translated) token number */\n\n  short\tyyssa[YYINITDEPTH];\t/*  the state stack\t\t\t*/\n  YYSTYPE yyvsa[YYINITDEPTH];\t/*  the semantic value stack\t\t*/\n\n  short *yyss = yyssa;\t\t/*  refer to the stacks thru separate pointers */\n  YYSTYPE *yyvs = yyvsa;\t/*  to allow yyoverflow to reallocate them elsewhere */\n\n#ifdef YYLSP_NEEDED\n  YYLTYPE yylsa[YYINITDEPTH];\t/*  the location stack\t\t\t*/\n  YYLTYPE *yyls = yylsa;\n  YYLTYPE *yylsp;\n\n#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)\n#else\n#define YYPOPSTACK   (yyvsp--, yyssp--)\n#endif\n\n  int yystacksize = YYINITDEPTH;\n  int yyfree_stacks = 0;\n\n#ifdef YYPURE\n  int yychar;\n  YYSTYPE yylval;\n  int yynerrs;\n#ifdef YYLSP_NEEDED\n  YYLTYPE yylloc;\n#endif\n#endif\n\n  YYSTYPE yyval;\t\t/*  the variable used to return\t\t*/\n\t\t\t\t/*  semantic values from the action\t*/\n\t\t\t\t/*  routines\t\t\t\t*/\n // ace: big fake for VC7 because it checks if yyval is init or not\n  yyval.Val.Int = 0;\n  int yylen;\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Starting parse\\n\");\n#endif\n\n  yystate = 0;\n  yyerrstatus = 0;\n  yynerrs = 0;\n  yychar = YYEMPTY;\t\t/* Cause a token to be read.  */\n\n  /* Initialize stack pointers.\n     Waste one element of value and location stack\n     so that they stay on the same level as the state stack.\n     The wasted elements are never initialized.  */\n\n  yyssp = yyss - 1;\n  yyvsp = yyvs;\n#ifdef YYLSP_NEEDED\n  yylsp = yyls;\n#endif\n\n/* Push a new state, which is found in  yystate  .  */\n/* In all cases, when you get here, the value and location stacks\n   have just been pushed. so pushing a state here evens the stacks.  */\nyynewstate:\n\n  *++yyssp = yystate;\n\n  if (yyssp >= yyss + yystacksize - 1)\n    {\n      /* Give user a chance to reallocate the stack */\n      /* Use copies of these so that the &'s don't force the real ones into memory. */\n      YYSTYPE *yyvs1 = yyvs;\n      short *yyss1 = yyss;\n#ifdef YYLSP_NEEDED\n      YYLTYPE *yyls1 = yyls;\n#endif\n\n      /* Get the current used size of the three stacks, in elements.  */\n      int size = yyssp - yyss + 1;\n\n#ifdef yyoverflow\n      /* Each stack pointer address is followed by the size of\n\t the data in use in that stack, in bytes.  */\n#ifdef YYLSP_NEEDED\n      /* This used to be a conditional around just the two extra args,\n\t but that might be undefined if yyoverflow is a macro.  */\n      yyoverflow(\"parser stack overflow\",\n\t\t &yyss1, size * sizeof (*yyssp),\n\t\t &yyvs1, size * sizeof (*yyvsp),\n\t\t &yyls1, size * sizeof (*yylsp),\n\t\t &yystacksize);\n#else\n      yyoverflow(\"parser stack overflow\",\n\t\t &yyss1, size * sizeof (*yyssp),\n\t\t &yyvs1, size * sizeof (*yyvsp),\n\t\t &yystacksize);\n#endif\n\n      yyss = yyss1; yyvs = yyvs1;\n#ifdef YYLSP_NEEDED\n      yyls = yyls1;\n#endif\n#else /* no yyoverflow */\n      /* Extend the stack our own way.  */\n      if (yystacksize >= YYMAXDEPTH)\n\t{\n\t  yyerror(\"parser stack overflow\");\n\t  if (yyfree_stacks)\n\t    {\n\t      free (yyss);\n\t      free (yyvs);\n#ifdef YYLSP_NEEDED\n\t      free (yyls);\n#endif\n\t    }\n\t  return 2;\n\t}\n      yystacksize *= 2;\n      if (yystacksize > YYMAXDEPTH)\n\tyystacksize = YYMAXDEPTH;\n#ifndef YYSTACK_USE_ALLOCA\n      yyfree_stacks = 1;\n#endif\n      yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp));\n      __yy_memcpy ((char *)yyss, (char *)yyss1,\n\t\t   size * (unsigned int) sizeof (*yyssp));\n      yyvs = (YYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp));\n      __yy_memcpy ((char *)yyvs, (char *)yyvs1,\n\t\t   size * (unsigned int) sizeof (*yyvsp));\n#ifdef YYLSP_NEEDED\n      yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp));\n      __yy_memcpy ((char *)yyls, (char *)yyls1,\n\t\t   size * (unsigned int) sizeof (*yylsp));\n#endif\n#endif /* no yyoverflow */\n\n      yyssp = yyss + size - 1;\n      yyvsp = yyvs + size - 1;\n#ifdef YYLSP_NEEDED\n      yylsp = yyls + size - 1;\n#endif\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Stack size increased to %d\\n\", yystacksize);\n#endif\n\n      if (yyssp >= yyss + yystacksize - 1)\n\tYYABORT;\n    }\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Entering state %d\\n\", yystate);\n#endif\n\n  goto yybackup;\n yybackup:\n\n/* Do appropriate processing given the current state.  */\n/* Read a lookahead token if we need one and don't already have one.  */\n/* yyresume: */\n\n  /* First try to decide what to do without reference to lookahead token.  */\n\n  yyn = yypact[yystate];\n  if (yyn == YYFLAG)\n    goto yydefault;\n\n  /* Not known => get a lookahead token if don't already have one.  */\n\n  /* yychar is either YYEMPTY or YYEOF\n     or a valid token in external form.  */\n\n  if (yychar == YYEMPTY)\n    {\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Reading a token: \");\n#endif\n      yychar = YYLEX;\n    }\n\n  /* Convert token to internal form (in yychar1) for indexing tables with */\n\n  if (yychar <= 0)\t\t/* This means end of input. */\n    {\n      yychar1 = 0;\n      yychar = YYEOF;\t\t/* Don't call YYLEX any more */\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Now at end of input.\\n\");\n#endif\n    }\n  else\n    {\n      yychar1 = YYTRANSLATE(yychar);\n\n#if YYDEBUG != 0\n      if (yydebug)\n\t{\n\t  fprintf (stderr, \"Next token is %d (%s\", yychar, yytname[yychar1]);\n\t  /* Give the individual parser a way to print the precise meaning\n\t     of a token, for further debugging info.  */\n#ifdef YYPRINT\n\t  YYPRINT (stderr, yychar, yylval);\n#endif\n\t  fprintf (stderr, \")\\n\");\n\t}\n#endif\n    }\n\n  yyn += yychar1;\n  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)\n    goto yydefault;\n\n  yyn = yytable[yyn];\n\n  /* yyn is what to do for this token type in this state.\n     Negative => reduce, -yyn is rule number.\n     Positive => shift, yyn is new state.\n       New state is final state => don't bother to shift,\n       just return success.\n     0, or most negative number => error.  */\n\n  if (yyn < 0)\n    {\n      if (yyn == YYFLAG)\n\tgoto yyerrlab;\n      yyn = -yyn;\n      goto yyreduce;\n    }\n  else if (yyn == 0)\n    goto yyerrlab;\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n  /* Shift the lookahead token.  */\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Shifting token %d (%s), \", yychar, yytname[yychar1]);\n#endif\n\n  /* Discard the token being shifted unless it is eof.  */\n  if (yychar != YYEOF)\n    yychar = YYEMPTY;\n\n  *++yyvsp = yylval;\n#ifdef YYLSP_NEEDED\n  *++yylsp = yylloc;\n#endif\n\n  /* count tokens shifted since error; after three, turn off error status.  */\n  if (yyerrstatus) yyerrstatus--;\n\n  yystate = yyn;\n  goto yynewstate;\n\n/* Do the default action for the current state.  */\nyydefault:\n\n  yyn = yydefact[yystate];\n  if (yyn == 0)\n    goto yyerrlab;\n\n/* Do a reduction.  yyn is the number of a rule to reduce with.  */\nyyreduce:\n  yylen = yyr2[yyn];\n  if (yylen > 0)\n    yyval = yyvsp[1-yylen]; /* implement default value of the action */\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      int i;\n\n      fprintf (stderr, \"Reducing via rule %d (line %d), \",\n\t       yyn, yyrline[yyn]);\n\n      /* Print the symbols being reduced, and their result.  */\n      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)\n\tfprintf (stderr, \"%s \", yytname[yyrhs[i]]);\n      fprintf (stderr, \" -> %s\\n\", yytname[yyr1[yyn]]);\n    }\n#endif\n\n\n  switch (yyn) {\n\ncase 2:\n#line 104 \"cf_gramatical.yxx\"\n{ ;\n    break;}\ncase 3:\n#line 107 \"cf_gramatical.yxx\"\n{ ;\n    break;}\ncase 4:\n#line 108 \"cf_gramatical.yxx\"\n{ ;\n    break;}\ncase 5:\n#line 112 \"cf_gramatical.yxx\"\n{\n\t\t\t\tDEBUG_PRINTF(\"Forcing current file %s and line %u\\n\", yyvsp[-1].Val.String, yyvsp[0].Val.Int-1);\n\n\t\t\t\tif (cf_CurrentFile != NULL)\n\t\t\t\t\tfree(cf_CurrentFile);\n\t\t\t\t// store the filename\n\t\t\t\tcf_CurrentFile = (char*)malloc(1024);\n\t\t\t\tstrcpy(cf_CurrentFile, yyvsp[-1].Val.String);\n\t\t\t\t//cf_CurrentFile = strdup(yyvsp[-1].Val.String);\n\t\t\t\t// store the current line minus 1 because the #fileline count for a line\n\t\t\t\tcf_CurrentLine = yyvsp[0].Val.Int-1;\n\t\t\t;\n    break;}\ncase 6:\n#line 124 \"cf_gramatical.yxx\"\n{\n\t\t\t\tDEBUG_PRINTF(\"                                   (TYPE %d VARIABLE=\", yyvsp[-3].Val.Type);\n\t\t\t\tcf_print (yyvsp[-3].Val);\n\t\t\t\tDEBUG_PRINTF(\"), (TYPE %d VALUE=\", yyvsp[-1].Val.Type);\n\t\t\t\tcf_print (yyvsp[-1].Val);\n\t\t\t\tDEBUG_PRINT(\")\\n\");\n\t\t\t\tint i;\n\t\t\t\t// on recherche l'existence de la variable\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == yyvsp[-3].Val.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cf_OverwriteExistingVariable || (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Root || !strcmp(yyvsp[-3].Val.String,\"RootConfigFilename\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDEBUG_PRINTF(\"Variable '%s' existe deja, ecrasement\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tNLMISC::CConfigFile::CVar Var;\n\t\t\t\tVar.Comp = false;\n\t\t\t\tVar.Callback = NULL;\n\t\t\t\tif (cf_CurrentVar.Comp)\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign complex variable '%s'\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\tVar = cf_CurrentVar;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign normal variable '%s'\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\tcf_setVar (Var, yyvsp[-1].Val);\n\t\t\t\t}\n\t\t\t\tVar.Name = yyvsp[-3].Val.String;\n\t\t\t\tif (i == (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size ()))\n\t\t\t\t{\n\t\t\t\t\t// nouvelle variable\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign var '%s'\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).push_back (Var);\n\t\t\t\t}\n\t\t\t\telse if (cf_OverwriteExistingVariable || (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Root || !strcmp(yyvsp[-3].Val.String,\"RootConfigFilename\"))\n\t\t\t\t{\n\t\t\t\t\t// reaffectation d'une variable\n\t\t\t\t\tVar.Callback = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Callback;\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: reassign var name '%s' type %d\\n\", Var.Name.c_str(), Var.Type);\n\t\t\t\t\tif (Var != (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] && Var.Callback != NULL)\n\t\t\t\t\t\t(Var.Callback)(Var);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] = Var;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: don't reassign var '%s' because the variable already exists\\n\", yyvsp[-3].Val.String);\n\t\t\t\t}\n\n\t\t\t\tcf_CurrentVar.IntValues.clear ();\n\t\t\t\tcf_CurrentVar.RealValues.clear ();\n\t\t\t\tcf_CurrentVar.StrValues.clear ();\n\t\t\t\tcf_CurrentVar.Comp = false;\n\t\t\t\tcf_CurrentVar.Type = NLMISC::CConfigFile::CVar::T_UNKNOWN;\n\t\t\t;\n    break;}\ncase 7:\n#line 186 \"cf_gramatical.yxx\"\n{\n\t\t\t\tDEBUG_PRINT(\"                                   (VARIABLE+=\");\n\t\t\t\tcf_print (yyvsp[-3].Val);\n\t\t\t\tDEBUG_PRINT(\"), (VALUE=\");\n\t\t\t\tcf_print (yyvsp[-1].Val);\n\t\t\t\tDEBUG_PRINT(\")\\n\");\n\t\t\t\tint i;\n\t\t\t\t// on recherche l'existence de la variable\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == yyvsp[-3].Val.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tDEBUG_PRINTF(\"Variable '%s' existe deja, ajout\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tNLMISC::CConfigFile::CVar Var;\n\t\t\t\tVar.Comp = false;\n\t\t\t\tVar.Callback = NULL;\n\t\t\t\tif (cf_CurrentVar.Comp) Var = cf_CurrentVar;\n\t\t\t\telse cf_setVar (Var, yyvsp[-1].Val);\n\t\t\t\tVar.Name = yyvsp[-3].Val.String;\n\t\t\t\tif (i == (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size ()))\n\t\t\t\t{\n\t\t\t\t\t// nouvelle variable\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new add assign var '%s'\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).push_back (Var);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// reaffectation d'une variable\n\t\t\t\t\tVar.Callback = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Callback;\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: add assign var '%s'\\n\", yyvsp[-3].Val.String);\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].FromLocalFile)\n\t\t\t\t\t{\n\t\t\t\t\t\t// this var was created in the current cfg, append the new value at the end\n\t\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].add(Var);\n\n\t\t\t\t\t\tif (Var.size() > 0 && Var.Callback != NULL)\n\t\t\t\t\t\t\t(Var.Callback)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// this var has been created in a parent Cfg, append at the beginning of the array\n\t\t\t\t\t\tVar.add ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i]);\n\t\t\t\t\t\tif (Var != (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] && Var.Callback != NULL)\n\t\t\t\t\t\t\t(Var.Callback)(Var);\n\t\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] = Var;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcf_CurrentVar.IntValues.clear ();\n\t\t\t\tcf_CurrentVar.RealValues.clear ();\n\t\t\t\tcf_CurrentVar.StrValues.clear ();\n\t\t\t\tcf_CurrentVar.Comp = false;\n\t\t\t\tcf_CurrentVar.Type = NLMISC::CConfigFile::CVar::T_UNKNOWN;\n\t\t\t;\n    break;}\ncase 8:\n#line 245 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; cf_CurrentVar.Comp = false; DEBUG_PRINT(\"false\\n\"); ;\n    break;}\ncase 9:\n#line 246 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[-1].Val; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); ;\n    break;}\ncase 10:\n#line 247 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[-2].Val; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); ;\n    break;}\ncase 11:\n#line 248 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); ;\n    break;}\ncase 12:\n#line 251 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; /*cf_CurrentVar.Type = $1.Type;*/ cf_setVar (cf_CurrentVar, yyvsp[0].Val); ;\n    break;}\ncase 13:\n#line 252 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; /*cf_CurrentVar.Type = $3.Type;*/ cf_setVar (cf_CurrentVar, yyvsp[0].Val); ;\n    break;}\ncase 14:\n#line 255 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; ;\n    break;}\ncase 15:\n#line 256 \"cf_gramatical.yxx\"\n{ yyval.Val = cf_op(yyvsp[-2].Val, yyvsp[0].Val, OP_PLUS); ;\n    break;}\ncase 16:\n#line 257 \"cf_gramatical.yxx\"\n{ yyval.Val = cf_op(yyvsp[-2].Val, yyvsp[0].Val, OP_MINUS); ;\n    break;}\ncase 17:\n#line 260 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; ;\n    break;}\ncase 18:\n#line 261 \"cf_gramatical.yxx\"\n{ yyval.Val = cf_op(yyvsp[-2].Val, yyvsp[0].Val, OP_MULT); ;\n    break;}\ncase 19:\n#line 262 \"cf_gramatical.yxx\"\n{ yyval.Val = cf_op (yyvsp[-2].Val, yyvsp[0].Val, OP_DIVIDE); ;\n    break;}\ncase 20:\n#line 265 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; ;\n    break;}\ncase 21:\n#line 266 \"cf_gramatical.yxx\"\n{ cf_value v; v.Type=NLMISC::CConfigFile::CVar::T_INT; /* just to avoid a warning, I affect 'v' with a dummy value */ yyval.Val = cf_op(yyvsp[0].Val,v,OP_NEG); ;\n    break;}\ncase 22:\n#line 267 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[-1].Val; ;\n    break;}\ncase 23:\n#line 268 \"cf_gramatical.yxx\"\n{ yyval.Val = yylval.Val; ;\n    break;}\ncase 24:\n#line 269 \"cf_gramatical.yxx\"\n{ yyval.Val = yylval.Val; ;\n    break;}\ncase 25:\n#line 270 \"cf_gramatical.yxx\"\n{ yyval.Val = yylval.Val; ;\n    break;}\ncase 26:\n#line 271 \"cf_gramatical.yxx\"\n{ yyval.Val = yyvsp[0].Val; ;\n    break;}\ncase 27:\n#line 275 \"cf_gramatical.yxx\"\n{\n\t\t\t\tDEBUG_PRINT(\"yacc: cont\\n\");\n\t\t\t\tbool ok=false;\n\t\t\t\tint i;\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == yyvsp[0].Val.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tok = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (ok)\n\t\t\t\t{\n\t\t\t\t\tcf_value Var;\n\t\t\t\t\tVar.Type = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Type;\n\t\t\t\t\tDEBUG_PRINTF(\"vart %d\\n\", Var.Type);\n\t\t\t\t\tswitch (Var.Type)\n\t\t\t\t\t{\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_INT: Var.Int = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].IntValues[0]; break;\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL: Var.Real = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].RealValues[0]; break;\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING: strcpy (Var.String, (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].StrValues[0].c_str()); break;\n\t\t\t\t\tdefault: DEBUG_PRINT(\"*** CAN T DO THAT!!!\\n\"); break;\n\t\t\t\t\t}\n\t\t\t\t\tyyval.Val = Var;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINT(\"var existe pas\\n\");\n\t\t\t\t}\n\t\t\t;\n    break;}\n}\n   /* the action file gets copied in in place of this dollarsign */\n#line 543 \"cfbison.simple\"\n\f\n  yyvsp -= yylen;\n  yyssp -= yylen;\n#ifdef YYLSP_NEEDED\n  yylsp -= yylen;\n#endif\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      short *ssp1 = yyss - 1;\n      fprintf (stderr, \"state stack now\");\n      while (ssp1 != yyssp)\n\tfprintf (stderr, \" %d\", *++ssp1);\n      fprintf (stderr, \"\\n\");\n    }\n#endif\n\n  *++yyvsp = yyval;\n\n#ifdef YYLSP_NEEDED\n  yylsp++;\n  if (yylen == 0)\n    {\n      yylsp->first_line = yylloc.first_line;\n      yylsp->first_column = yylloc.first_column;\n      yylsp->last_line = (yylsp-1)->last_line;\n      yylsp->last_column = (yylsp-1)->last_column;\n      yylsp->text = 0;\n    }\n  else\n    {\n      yylsp->last_line = (yylsp+yylen-1)->last_line;\n      yylsp->last_column = (yylsp+yylen-1)->last_column;\n    }\n#endif\n\n  /* Now \"shift\" the result of the reduction.\n     Determine what state that goes to,\n     based on the state we popped back to\n     and the rule number reduced by.  */\n\n  yyn = yyr1[yyn];\n\n  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;\n  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)\n    yystate = yytable[yystate];\n  else\n    yystate = yydefgoto[yyn - YYNTBASE];\n\n  goto yynewstate;\n\nyyerrlab:   /* here on detecting error */\n\n  if (! yyerrstatus)\n    /* If not already recovering from an error, report this error.  */\n    {\n      ++yynerrs;\n\n#ifdef YYERROR_VERBOSE\n      yyn = yypact[yystate];\n\n      if (yyn > YYFLAG && yyn < YYLAST)\n\t{\n\t  int size = 0;\n\t  char *msg;\n\t  int x, count;\n\n\t  count = 0;\n\t  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */\n\t  for (x = (yyn < 0 ? -yyn : 0);\n\t       x < (sizeof(yytname) / sizeof(char *)); x++)\n\t    if (yycheck[x + yyn] == x)\n\t      size += strlen(yytname[x]) + 15, count++;\n\t  msg = (char *) malloc(size + 15);\n\t  if (msg != 0)\n\t    {\n\t      strcpy(msg, \"parse error\");\n\n\t      if (count < 5)\n\t\t{\n\t\t  count = 0;\n\t\t  for (x = (yyn < 0 ? -yyn : 0);\n\t\t       x < (sizeof(yytname) / sizeof(char *)); x++)\n\t\t    if (yycheck[x + yyn] == x)\n\t\t      {\n\t\t\tstrcat(msg, count == 0 ? \", expecting `\" : \" or `\");\n\t\t\tstrcat(msg, yytname[x]);\n\t\t\tstrcat(msg, \"'\");\n\t\t\tcount++;\n\t\t      }\n\t\t}\n\t      yyerror(msg);\n\t      free(msg);\n\t    }\n\t  else\n\t    yyerror (\"parse error; also virtual memory exceeded\");\n\t}\n      else\n#endif /* YYERROR_VERBOSE */\n\tyyerror(\"parse error\");\n    }\n\n  goto yyerrlab1;\nyyerrlab1:   /* here on error raised explicitly by an action */\n\n  if (yyerrstatus == 3)\n    {\n      /* if just tried and failed to reuse lookahead token after an error, discard it.  */\n\n      /* return failure if at end of input */\n      if (yychar == YYEOF)\n\tYYABORT;\n\n#if YYDEBUG != 0\n      if (yydebug)\n\tfprintf(stderr, \"Discarding token %d (%s).\\n\", yychar, yytname[yychar1]);\n#endif\n\n      yychar = YYEMPTY;\n    }\n\n  /* Else will try to reuse lookahead token\n     after shifting the error token.  */\n\n  yyerrstatus = 3;\t\t/* Each real token shifted decrements this */\n\n  goto yyerrhandle;\n\nyyerrdefault:  /* current state does not do anything special for the error token. */\n\n#if 0\n  /* This is wrong; only states that explicitly want error tokens\n     should shift them.  */\n  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/\n  if (yyn) goto yydefault;\n#endif\n\nyyerrpop:   /* pop the current state because it cannot handle the error token */\n\n  if (yyssp == yyss) YYABORT;\n  yyvsp--;\n  yystate = *--yyssp;\n#ifdef YYLSP_NEEDED\n  yylsp--;\n#endif\n\n#if YYDEBUG != 0\n  if (yydebug)\n    {\n      short *ssp1 = yyss - 1;\n      fprintf (stderr, \"Error: state stack now\");\n      while (ssp1 != yyssp)\n\tfprintf (stderr, \" %d\", *++ssp1);\n      fprintf (stderr, \"\\n\");\n    }\n#endif\n\nyyerrhandle:\n\n  yyn = yypact[yystate];\n  if (yyn == YYFLAG)\n    goto yyerrdefault;\n\n  yyn += YYTERROR;\n  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)\n    goto yyerrdefault;\n\n  yyn = yytable[yyn];\n  if (yyn < 0)\n    {\n      if (yyn == YYFLAG)\n\tgoto yyerrpop;\n      yyn = -yyn;\n      goto yyreduce;\n    }\n  else if (yyn == 0)\n    goto yyerrpop;\n\n  if (yyn == YYFINAL)\n    YYACCEPT;\n\n#if YYDEBUG != 0\n  if (yydebug)\n    fprintf(stderr, \"Shifting error token, \");\n#endif\n\n  *++yyvsp = yylval;\n#ifdef YYLSP_NEEDED\n  *++yylsp = yylloc;\n#endif\n\n  yystate = yyn;\n  goto yynewstate;\n\n yyacceptlab:\n  /* YYACCEPT comes here.  */\n  if (yyfree_stacks)\n    {\n      free (yyss);\n      free (yyvs);\n#ifdef YYLSP_NEEDED\n      free (yyls);\n#endif\n    }\n  return 0;\n\n yyabortlab:\n  /* YYABORT comes here.  */\n  if (yyfree_stacks)\n    {\n      free (yyss);\n      free (yyvs);\n#ifdef YYLSP_NEEDED\n      free (yyls);\n#endif\n    }\n  return 1;\n}\n#line 307 \"cf_gramatical.yxx\"\n\n\n/* compute the good operation with a, b and op */\ncf_value cf_op (cf_value a, cf_value b, cf_operation op)\n{\n\tDEBUG_PRINTF(\"[OP:%d; \", op);\n\tcf_print(a);\n\tDEBUG_PRINT(\"; \");\n\tcf_print(b);\n\tDEBUG_PRINT(\"; \");\n\n\tswitch (op)\n\t{\n\tcase OP_MULT:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  *********************\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int *= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int *= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int*str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Real *= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real *= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real*str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tDEBUG_PRINT(\"ERROR: str*int\\n\");  break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str*real\\n\");  break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str*str\\n\");  break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_DIVIDE:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  //////////////////////\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int /= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int /= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int/str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Real /= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real /= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real/str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tDEBUG_PRINT(\"ERROR: str/int\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str/real\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str/str\\n\"); break;\n\t\t\t default: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_PLUS:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  ++++++++++++++++++++++++\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Int += b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int += (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\ta.Int += atoi(b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Real += (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real += b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\ta.Real += atof (b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t{ char str2[60]; NLMISC::smprintf(str2, 60, \"%d\", b.Int); strcat(a.String, str2); break; }\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t{ char str2[60]; NLMISC::smprintf(str2, 60, \"%f\", b.Real); strcat(a.String, str2); break; }\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tstrcat (a.String, b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_MINUS:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  -------------------------\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Int -= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int -= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Real -= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real -= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\tDEBUG_PRINT(\"ERROR: str-int\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str-real\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_NEG:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// neg\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int = -a.Int; break;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t\ta.Real = -a.Real; break;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t\tDEBUG_PRINT(\"ERROR: -str\\n\"); break;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\t}\n\tcf_print(a);\n\tDEBUG_PRINT(\"]\\n\");\n\treturn a;\n}\n\n/* print a value, it's only for debug purpose */\nvoid cf_print (cf_value Val)\n{\n\tswitch (Val.Type)\n\t{\n\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\tDEBUG_PRINTF(\"'%d'\", Val.Int);\n\t\tbreak;\n\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\tDEBUG_PRINTF(\"`%f`\", Val.Real);\n\t\tbreak;\n\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\tDEBUG_PRINTF(\"\\\"%s\\\"\", Val.String);\n\t\tbreak;\n\tdefault: break;\n\t}\n}\n\n/* put a value into a var */\nvoid cf_setVar (NLMISC::CConfigFile::CVar &Var, cf_value Val)\n{\n\tDEBUG_PRINTF(\"Set var (type %d var name '%s') with new var type %d with value : \", Var.Type, Var.Name.c_str(), Val.Type);\n\tcf_print(Val);\n\tDEBUG_PRINTF(\"\\n\");\n\tVar.Root = LoadRoot;\n\tif (Var.Type == NLMISC::CConfigFile::CVar::T_UNKNOWN || Var.Type == Val.Type)\n\t{\n\t\tif (Var.Type == NLMISC::CConfigFile::CVar::T_UNKNOWN)\n\t\t{\n\t\t\tDEBUG_PRINTF(\"var type is unknown, set to the val type\\n\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDEBUG_PRINTF(\"val type is same var type, just add\\n\");\n\t\t}\n\n\t\tVar.Type = Val.Type;\n\t\tswitch (Val.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT: Var.IntValues.push_back (Val.Int); break;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL: Var.RealValues.push_back (Val.Real); break;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING: Var.StrValues.push_back(Val.String); break;\n\t\tdefault: break;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// need to convert the type\n\t\tswitch (Var.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t\tVar.IntValues.push_back ((int)Val.Real); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t{ int val = 0; NLMISC::fromString(Val.String, val); Var.IntValues.push_back(val); break; }\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tVar.RealValues.push_back ((double)Val.Int); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t{ double val = 0.0; NLMISC::fromString(Val.String, val); Var.RealValues.push_back(val); break; }\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\tVar.StrValues.push_back(toString(Val.Int)); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tVar.StrValues.push_back(toString(Val.Real)); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t}\n}\n\nint yyerror (const char *s)\n{\n\tDEBUG_PRINTF(\"%s\\n\",s);\n\treturn 1;\n}\n\n\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_gramatical.h",
    "content": "typedef union\t{\n\t\t\tcf_value Val;\n\t\t} YYSTYPE;\n#define\tADD_ASSIGN\t257\n#define\tASSIGN\t258\n#define\tVARIABLE\t259\n#define\tSTRING\t260\n#define\tSEMICOLON\t261\n#define\tPLUS\t262\n#define\tMINUS\t263\n#define\tMULT\t264\n#define\tDIVIDE\t265\n#define\tRPAREN\t266\n#define\tLPAREN\t267\n#define\tRBRACE\t268\n#define\tLBRACE\t269\n#define\tCOMMA\t270\n#define\tINTEGER\t271\n#define\tREAL\t272\n#define\tFILELINE\t273\n\n\nextern YYSTYPE cflval;\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_gramatical.ypp",
    "content": "%{\n\n/* Includes */\n\n#ifdef NL_OS_WINDOWS\n#pragma warning (disable : 4786)\n#endif // NL_OS_WINDOWS\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n\n#include <stdio.h>\n#include <vector>\n#include <string>\n\nusing namespace std;\nusing namespace NLMISC;\n\n/* Constantes */\n\n#define YYPARSE_PARAM pvararray\n\n// WARNING!!!! DEBUG_PRINTF are commented using // so IT MUST HAVE NO INSTRUCTION AFTER A DEBUG_PRINTF OR THEY LL BE COMMENTED\n/*\n#define DEBUG_PRINTF\tInfoLog->displayRaw\n#define DEBUG_PRINT(a)\tInfoLog->displayRaw(a)\n*/\n\n#define DEBUG_PRINT(a)\n#ifdef __GNUC__\n#define DEBUG_PRINTF(format, args...)\n#else // __GNUC__\n#define DEBUG_PRINTF\t// InfoLog->displayRaw\n#endif // __GNUC__\n\n\n/* Types */\n\nenum cf_operation { OP_PLUS, OP_MINUS, OP_MULT, OP_DIVIDE, OP_NEG };\n\nstruct cf_value\n{\n\tNLMISC::CConfigFile::CVar::TVarType\tType;\n\tint\t\t\t\t\t\tInt;\n\tdouble\t\t\t\t\tReal;\n\tchar\t\t\t\t\tString[1024];\n};\n\n/* Externals */\n\nextern bool cf_Ignore;\n\nextern bool LoadRoot;\n\nextern FILE *yyin;\n\n/* Variables */\n\nNLMISC::CConfigFile::CVar\t\tcf_CurrentVar;\n\nint\t\tcf_CurrentLine;\nchar\t*cf_CurrentFile;\n\nbool\tcf_OverwriteExistingVariable;\t// setup in the config_file.cpp reparse()\n\n\n\n/* Prototypes */\n\nint yylex (void);\n\ncf_value cf_op (cf_value a, cf_value b, cf_operation op);\n\nvoid cf_print (cf_value Val);\n\nvoid cf_setVar (NLMISC::CConfigFile::CVar &Var, cf_value Val);\n\nint yyerror (const char *);\n\n%}\n\n%start ROOT\n\n%union\t{\n\t\t\tcf_value Val;\n\t\t}\n\n%token <Val> ADD_ASSIGN ASSIGN VARIABLE STRING SEMICOLON\n%token <Val> PLUS MINUS MULT DIVIDE\n%token <Val> RPAREN LPAREN RBRACE LBRACE\n%token <Val> COMMA INTEGER REAL FILELINE\n\n%type <Val> inst\n%type <Val> expression\n%type <Val> expr2\n%type <Val> expr3\n%type <Val> expr4\n%type <Val> exprbrace\n%type <Val> variable\n\n%%\n\nROOT:\t\tinstlist | { }\n\t\t\t;\n\ninstlist:\tinstlist inst { }\n\t\t|\tinst { }\n\t\t;\n\ninst\t:\tFILELINE STRING INTEGER\n\t\t\t{\n\t\t\t\tDEBUG_PRINTF(\"Forcing current file %s and line %u\\n\", $2.String, $3.Int-1);\n\n\t\t\t\tif (cf_CurrentFile != NULL)\n\t\t\t\t\tfree(cf_CurrentFile);\n\t\t\t\t// store the filename\n\t\t\t\tcf_CurrentFile = strdup($2.String);\n\t\t\t\t// store the current line minus 1 because the #fileline count for a line\n\t\t\t\tcf_CurrentLine = $3.Int-1;\n\t\t\t}\n\ninst:\t\tVARIABLE ASSIGN expression SEMICOLON\n\t\t\t{\n\t\t\t\tDEBUG_PRINTF(\"                                   (TYPE %d VARIABLE=\", $1.Type);\n\t\t\t\tcf_print ($1);\n\t\t\t\tDEBUG_PRINTF(\"), (TYPE %d VALUE=\", $3.Type);\n\t\t\t\tcf_print ($3);\n\t\t\t\tDEBUG_PRINT(\")\\n\");\n\t\t\t\tint i;\n\t\t\t\t// on recherche l'existence de la variable\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == $1.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (cf_OverwriteExistingVariable || (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Root || !strcmp($1.String,\"RootConfigFilename\"))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tDEBUG_PRINTF(\"Variable '%s' existe deja, ecrasement\\n\", $1.String);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tNLMISC::CConfigFile::CVar Var;\n\t\t\t\tVar.Comp = false;\n\t\t\t\tVar.Callback = NULL;\n\t\t\t\tif (cf_CurrentVar.Comp)\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign complex variable '%s'\\n\", $1.String);\n\t\t\t\t\tVar = cf_CurrentVar;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign normal variable '%s'\\n\", $1.String);\n\t\t\t\t\tcf_setVar (Var, $3);\n\t\t\t\t}\n\t\t\t\tVar.Name = $1.String;\n\t\t\t\tif (i == (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size ()))\n\t\t\t\t{\n\t\t\t\t\t// nouvelle variable\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new assign var '%s'\\n\", $1.String);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).push_back (Var);\n\t\t\t\t}\n\t\t\t\telse if (cf_OverwriteExistingVariable || (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Root || !strcmp($1.String,\"RootConfigFilename\"))\n\t\t\t\t{\n\t\t\t\t\t// reaffectation d'une variable\n\t\t\t\t\tVar.Callback = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Callback;\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: reassign var name '%s' type %d\\n\", Var.Name.c_str(), Var.Type);\n\t\t\t\t\tif (Var != (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] && Var.Callback != NULL)\n\t\t\t\t\t\t(Var.Callback)(Var);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] = Var;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: don't reassign var '%s' because the variable already exists\\n\", $1.String);\n\t\t\t\t}\n\n\t\t\t\tcf_CurrentVar.IntValues.clear ();\n\t\t\t\tcf_CurrentVar.RealValues.clear ();\n\t\t\t\tcf_CurrentVar.StrValues.clear ();\n\t\t\t\tcf_CurrentVar.Comp = false;\n\t\t\t\tcf_CurrentVar.Type = NLMISC::CConfigFile::CVar::T_UNKNOWN;\n\t\t\t}\n\t\t\t;\n\ninst:\t\tVARIABLE ADD_ASSIGN expression SEMICOLON\n\t\t\t{\n\t\t\t\tDEBUG_PRINT(\"                                   (VARIABLE+=\");\n\t\t\t\tcf_print ($1);\n\t\t\t\tDEBUG_PRINT(\"), (VALUE=\");\n\t\t\t\tcf_print ($3);\n\t\t\t\tDEBUG_PRINT(\")\\n\");\n\t\t\t\tint i;\n\t\t\t\t// on recherche l'existence de la variable\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == $1.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tDEBUG_PRINTF(\"Variable '%s' existe deja, ajout\\n\", $1.String);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tNLMISC::CConfigFile::CVar Var;\n\t\t\t\tVar.Comp = false;\n\t\t\t\tVar.Callback = NULL;\n\t\t\t\tif (cf_CurrentVar.Comp) Var = cf_CurrentVar;\n\t\t\t\telse cf_setVar (Var, $3);\n\t\t\t\tVar.Name = $1.String;\n\t\t\t\tif (i == (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size ()))\n\t\t\t\t{\n\t\t\t\t\t// nouvelle variable\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: new add assign var '%s'\\n\", $1.String);\n\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).push_back (Var);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// reaffectation d'une variable\n\t\t\t\t\tVar.Callback = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Callback;\n\t\t\t\t\tDEBUG_PRINTF (\"yacc: add assign var '%s'\\n\", $1.String);\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].FromLocalFile)\n\t\t\t\t\t{\n\t\t\t\t\t\t// this var was created in the current cfg, append the new value at the end\n\t\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].add(Var);\n\n\t\t\t\t\t\tif (Var.size() > 0 && Var.Callback != NULL)\n\t\t\t\t\t\t\t(Var.Callback)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i]);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// this var has been created in a parent Cfg, append at the beginning of the array\n\t\t\t\t\t\tVar.add ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i]);\n\t\t\t\t\t\tif (Var != (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] && Var.Callback != NULL)\n\t\t\t\t\t\t\t(Var.Callback)(Var);\n\t\t\t\t\t\t(*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i] = Var;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcf_CurrentVar.IntValues.clear ();\n\t\t\t\tcf_CurrentVar.RealValues.clear ();\n\t\t\t\tcf_CurrentVar.StrValues.clear ();\n\t\t\t\tcf_CurrentVar.Comp = false;\n\t\t\t\tcf_CurrentVar.Type = NLMISC::CConfigFile::CVar::T_UNKNOWN;\n\t\t\t}\n\t\t\t;\n\nexpression:\texpr2 { $$ = $1; cf_CurrentVar.Comp = false; DEBUG_PRINT(\"false\\n\"); }\n\t\t\t| LBRACE exprbrace RBRACE { $$ = $2; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); }\n\t\t\t| LBRACE exprbrace COMMA RBRACE { $$ = $2; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); }\n\t\t\t| LBRACE RBRACE { $$ = $2; cf_CurrentVar.Comp = true; DEBUG_PRINT(\"true\\n\"); }\n\t\t\t;\n\nexprbrace:\texpr2\t\t\t\t\t{ $$ = $1; /*cf_CurrentVar.Type = $1.Type;*/ cf_setVar (cf_CurrentVar, $1); }\n\t\t\t| exprbrace COMMA expr2 { $$ = $3; /*cf_CurrentVar.Type = $3.Type;*/ cf_setVar (cf_CurrentVar, $3); }\n\t\t\t;\n\nexpr2:\t\texpr3 { $$ = $1; }\n\t\t\t| expr2 PLUS expr3 { $$ = cf_op($1, $3, OP_PLUS); }\n\t\t\t| expr2 MINUS expr3 { $$ = cf_op($1, $3, OP_MINUS); }\n\t\t\t;\n\nexpr3:\t\texpr4 { $$ = $1; }\n\t\t\t| expr3 MULT expr4 { $$ = cf_op($1, $3, OP_MULT); }\n\t\t\t| expr3 DIVIDE expr4 { $$ = cf_op ($1, $3, OP_DIVIDE); }\n\t\t\t;\n\nexpr4:\t\tPLUS expr4 { $$ = $2; }\n\t\t\t| MINUS expr4 { cf_value v; v.Type=NLMISC::CConfigFile::CVar::T_INT; /* just to avoid a warning, I affect 'v' with a dummy value */ $$ = cf_op($2,v,OP_NEG); }\n\t\t\t| LPAREN expression RPAREN { $$ = $2; }\n\t\t\t| INTEGER { $$ = yylval.Val; }\n\t\t\t| REAL { $$ = yylval.Val; }\n\t\t\t| STRING { $$ = yylval.Val; }\n\t\t\t| variable { $$ = $1; }\n\t\t\t;\n\nvariable:\tVARIABLE\n\t\t\t{\n\t\t\t\tDEBUG_PRINT(\"yacc: cont\\n\");\n\t\t\t\tbool ok=false;\n\t\t\t\tint i;\n\t\t\t\tfor(i = 0; i < (int)((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM))).size()); i++)\n\t\t\t\t{\n\t\t\t\t\tif ((*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Name == $1.String)\n\t\t\t\t\t{\n\t\t\t\t\t\tok = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (ok)\n\t\t\t\t{\n\t\t\t\t\tcf_value Var;\n\t\t\t\t\tVar.Type = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].Type;\n\t\t\t\t\tDEBUG_PRINTF(\"vart %d\\n\", Var.Type);\n\t\t\t\t\tswitch (Var.Type)\n\t\t\t\t\t{\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_INT: Var.Int = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].IntValues[0]; break;\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL: Var.Real = (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].RealValues[0]; break;\n\t\t\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING: strcpy (Var.String, (*((vector<NLMISC::CConfigFile::CVar>*)(YYPARSE_PARAM)))[i].StrValues[0].c_str()); break;\n\t\t\t\t\tdefault: DEBUG_PRINT(\"*** CAN T DO THAT!!!\\n\"); break;\n\t\t\t\t\t}\n\t\t\t\t\t$$ = Var;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tDEBUG_PRINT(\"var existe pas\\n\");\n\t\t\t\t}\n\t\t\t}\n\t\t\t;\n%%\n\n/* compute the good operation with a, b and op */\ncf_value cf_op (cf_value a, cf_value b, cf_operation op)\n{\n\tDEBUG_PRINTF(\"[OP:%d; \", op);\n\tcf_print(a);\n\tDEBUG_PRINT(\"; \");\n\tcf_print(b);\n\tDEBUG_PRINT(\"; \");\n\n\tswitch (op)\n\t{\n\tcase OP_MULT:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  *********************\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int *= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int *= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int*str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Real *= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real *= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real*str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tDEBUG_PRINT(\"ERROR: str*int\\n\");  break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str*real\\n\");  break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str*str\\n\");  break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_DIVIDE:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  //////////////////////\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int /= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int /= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int/str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Real /= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real /= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real/str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tDEBUG_PRINT(\"ERROR: str/int\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str/real\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str/str\\n\"); break;\n\t\t\t default: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_PLUS:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  ++++++++++++++++++++++++\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Int += b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int += (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\ta.Int += atoi(b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Real += (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real += b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\ta.Real += atof (b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t{ char str2[60]; NLMISC::smprintf(str2, 60, \"%d\", b.Int); strcat(a.String, str2); break; }\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t{ char str2[60]; NLMISC::smprintf(str2, 60, \"%f\", b.Real); strcat(a.String, str2); break; }\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tstrcat (a.String, b.String); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_MINUS:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//  -------------------------\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Int -= b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Int -= (int)b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: int-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\ta.Real -= (double)b.Int; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\ta.Real -= b.Real; break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: real-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (b.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\tDEBUG_PRINT(\"ERROR: str-int\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tDEBUG_PRINT(\"ERROR: str-real\\n\"); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\tDEBUG_PRINT(\"ERROR: str-str\\n\"); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\tcase OP_NEG:\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t// neg\n\t\tswitch (a.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\ta.Int = -a.Int; break;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t\ta.Real = -a.Real; break;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t\tDEBUG_PRINT(\"ERROR: -str\\n\"); break;\n\t\tdefault: break;\n\t\t}\n\t\tbreak;\n\t}\n\tcf_print(a);\n\tDEBUG_PRINT(\"]\\n\");\n\treturn a;\n}\n\n/* print a value, it's only for debug purpose */\nvoid cf_print (cf_value Val)\n{\n\tswitch (Val.Type)\n\t{\n\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\tDEBUG_PRINTF(\"'%d'\", Val.Int);\n\t\tbreak;\n\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\tDEBUG_PRINTF(\"`%f`\", Val.Real);\n\t\tbreak;\n\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\tDEBUG_PRINTF(\"\\\"%s\\\"\", Val.String);\n\t\tbreak;\n\tdefault: break;\n\t}\n}\n\n/* put a value into a var */\nvoid cf_setVar (NLMISC::CConfigFile::CVar &Var, cf_value Val)\n{\n\tDEBUG_PRINTF(\"Set var (type %d var name '%s') with new var type %d with value : \", Var.Type, Var.Name.c_str(), Val.Type);\n\tcf_print(Val);\n\tDEBUG_PRINTF(\"\\n\");\n\tVar.Root = LoadRoot;\n\tif (Var.Type == NLMISC::CConfigFile::CVar::T_UNKNOWN || Var.Type == Val.Type)\n\t{\n\t\tif (Var.Type == NLMISC::CConfigFile::CVar::T_UNKNOWN)\n\t\t{\n\t\t\tDEBUG_PRINTF(\"var type is unknown, set to the val type\\n\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDEBUG_PRINTF(\"val type is same var type, just add\\n\");\n\t\t}\n\n\t\tVar.Type = Val.Type;\n\t\tswitch (Val.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT: Var.IntValues.push_back (Val.Int); break;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL: Var.RealValues.push_back (Val.Real); break;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING: Var.StrValues.push_back(Val.String); break;\n\t\tdefault: break;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// need to convert the type\n\t\tswitch (Var.Type)\n\t\t{\n\t\tcase NLMISC::CConfigFile::CVar::T_INT:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\t\tVar.IntValues.push_back ((int)Val.Real); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t{ int val = 0; NLMISC::fromString(Val.String, val); Var.RealValues.push_back(val); break; }\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\t\tVar.RealValues.push_back ((double)Val.Int); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\t{ double val = 0.0; NLMISC::fromString(Val.String, val); Var.RealValues.push_back(val); break; }\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase NLMISC::CConfigFile::CVar::T_STRING:\n\t\t\tswitch (Val.Type)\n\t\t\t{\n\t\t\tcase NLMISC::CConfigFile::CVar::T_INT:\tVar.StrValues.push_back(toString(Val.Int)); break;\n\t\t\tcase NLMISC::CConfigFile::CVar::T_REAL:\tVar.StrValues.push_back(toString(Val.Real)); break;\n\t\t\tdefault: break;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault: break;\n\t\t}\n\t}\n}\n\nint yyerror (const char *s)\n{\n\tDEBUG_PRINTF(\"%s\\n\",s);\n\treturn 1;\n}\n\n\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_lexical.cpp",
    "content": "#define yy_create_buffer cf_create_buffer\n#define yy_delete_buffer cf_delete_buffer\n#define yy_scan_buffer cf_scan_buffer\n#define yy_scan_string cf_scan_string\n#define yy_scan_bytes cf_scan_bytes\n#define yy_flex_debug cf_flex_debug\n#define yy_init_buffer cf_init_buffer\n#define yy_flush_buffer cf_flush_buffer\n#define yy_load_buffer_state cf_load_buffer_state\n#define yy_switch_to_buffer cf_switch_to_buffer\n#define yyin cfin\n#define yyleng cfleng\n#define yylex cflex\n#define yyout cfout\n#define yyrestart cfrestart\n#define yytext cftext\n#define yywrap cfwrap\n\n#line 20 \"cf_lexical.cpp\"\n/* A lexical scanner generated by flex */\n\n/* Scanner skeleton version:\n * $Header: /cvs/code/nel/src/misc/config_file/cf_flex.skl,v 1.1 2002/08/20 11:37:35 lecroart Exp $\n */\n\n#define FLEX_SCANNER\n#define YY_FLEX_MAJOR_VERSION 2\n#define YY_FLEX_MINOR_VERSION 5\n\n#include <stdio.h>\n\n\n/* cfront 1.2 defines \"c_plusplus\" instead of \"__cplusplus\" */\n#ifdef c_plusplus\n#ifndef __cplusplus\n#define __cplusplus\n#endif\n#endif\n\n\n#ifdef __cplusplus\n\n#include <stdlib.h>\n#ifdef WIN32\n#include <io.h>\n#else\n#include <unistd.h>\n#define isatty _isatty\n#endif\n\n/* Use prototypes in function declarations. */\n#define YY_USE_PROTOS\n\n/* The \"const\" storage-class-modifier is valid. */\n#define YY_USE_CONST\n\n#else\t/* ! __cplusplus */\n\n#if __STDC__\n\n#define YY_USE_PROTOS\n#define YY_USE_CONST\n\n#endif\t/* __STDC__ */\n#endif\t/* ! __cplusplus */\n\n#ifdef __TURBOC__\n #pragma warn -rch\n #pragma warn -use\n#include <io.h>\n#include <stdlib.h>\n#define YY_USE_CONST\n#define YY_USE_PROTOS\n#endif\n\n#ifdef YY_USE_CONST\n#define yyconst const\n#else\n#define yyconst\n#endif\n\n\n#ifdef YY_USE_PROTOS\n#define YY_PROTO(proto) proto\n#else\n#define YY_PROTO(proto) ()\n#endif\n\n/* Returned upon end-of-file. */\n#define YY_NULL 0\n\n/* Promotes a possibly negative, possibly signed char to an unsigned\n * integer for use as an array index.  If the signed char is negative,\n * we want to instead treat it as an 8-bit unsigned char, hence the\n * double cast.\n */\n#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)\n\n/* Enter a start condition.  This macro really ought to take a parameter,\n * but we do it the disgusting crufty way forced on us by the ()-less\n * definition of BEGIN.\n */\n#define BEGIN yy_start = 1 + 2 *\n\n/* Translate the current start state into a value that can be later handed\n * to BEGIN to return to the state.  The YYSTATE alias is for lex\n * compatibility.\n */\n#define YY_START ((yy_start - 1) / 2)\n#define YYSTATE YY_START\n\n/* Action number for EOF rule of a given start state. */\n#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)\n\n/* Special action meaning \"start processing a new file\". */\n#define YY_NEW_FILE yyrestart( yyin )\n\n#define YY_END_OF_BUFFER_CHAR 0\n\n/* Size of default input buffer. */\n#define YY_BUF_SIZE 16384\n\ntypedef struct yy_buffer_state *YY_BUFFER_STATE;\n\nextern int yyleng;\nextern FILE *yyin, *yyout;\n\n#define EOB_ACT_CONTINUE_SCAN 0\n#define EOB_ACT_END_OF_FILE 1\n#define EOB_ACT_LAST_MATCH 2\n\n/* The funky do-while in the following #define is used to turn the definition\n * int a single C statement (which needs a semi-colon terminator).  This\n * avoids problems with code like:\n *\n * \tif ( condition_holds )\n *\t\tyyless( 5 );\n *\telse\n *\t\tdo_something_else();\n *\n * Prior to using the do-while the compiler would get upset at the\n * \"else\" because it interpreted the \"if\" statement as being all\n * done when it reached the ';' after the yyless() call.\n */\n\n/* Return all but the first 'n' matched characters back to the input stream. */\n\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up yytext. */ \\\n\t\t*yy_cp = yy_hold_char; \\\n\t\tYY_RESTORE_YY_MORE_OFFSET \\\n\t\tyy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \\\n\t\tYY_DO_BEFORE_ACTION; /* set up yytext again */ \\\n\t\t} \\\n\twhile ( 0 )\n\n#define unput(c) yyunput( c, yytext_ptr )\n\n/* The following is because we cannot portably get our hands on size_t\n * (without autoconf's help, which isn't available because we want\n * flex-generated scanners to compile on their own).\n */\ntypedef unsigned int yy_size_t;\n\n\nstruct yy_buffer_state\n\t{\n\tFILE *yy_input_file;\n\n\tchar *yy_ch_buf;\t\t/* input buffer */\n\tchar *yy_buf_pos;\t\t/* current position in input buffer */\n\n\t/* Size of input buffer in bytes, not including room for EOB\n\t * characters.\n\t */\n\tyy_size_t yy_buf_size;\n\n\t/* Number of characters read into yy_ch_buf, not including EOB\n\t * characters.\n\t */\n\tint yy_n_chars;\n\n\t/* Whether we \"own\" the buffer - i.e., we know we created it,\n\t * and can realloc() it to grow it, and should free() it to\n\t * delete it.\n\t */\n\tint yy_is_our_buffer;\n\n\t/* Whether this is an \"interactive\" input source; if so, and\n\t * if we're using stdio for input, then we want to use getc()\n\t * instead of fread(), to make sure we stop fetching input after\n\t * each newline.\n\t */\n\tint yy_is_interactive;\n\n\t/* Whether we're considered to be at the beginning of a line.\n\t * If so, '^' rules will be active on the next match, otherwise\n\t * not.\n\t */\n\tint yy_at_bol;\n\n\t/* Whether to try to fill the input buffer when we reach the\n\t * end of it.\n\t */\n\tint yy_fill_buffer;\n\n\tint yy_buffer_status;\n#define YY_BUFFER_NEW 0\n#define YY_BUFFER_NORMAL 1\n\t/* When an EOF's been seen but there's still some text to process\n\t * then we mark the buffer as YY_EOF_PENDING, to indicate that we\n\t * shouldn't try reading from the input source any more.  We might\n\t * still have a bunch of tokens to match, though, because of\n\t * possible backing-up.\n\t *\n\t * When we actually see the EOF, we change the status to \"new\"\n\t * (via yyrestart()), so that the user can continue scanning by\n\t * just pointing yyin at a new input file.\n\t */\n#define YY_BUFFER_EOF_PENDING 2\n\t};\n\nstatic YY_BUFFER_STATE yy_current_buffer = 0;\n\n/* We provide macros for accessing buffer states in case in the\n * future we want to put the buffer states in a more general\n * \"scanner state\".\n */\n#define YY_CURRENT_BUFFER yy_current_buffer\n\n\n/* yy_hold_char holds the character lost when yytext is formed. */\nstatic char yy_hold_char;\n\nstatic int yy_n_chars;\t\t/* number of characters read into yy_ch_buf */\n\n\nint yyleng;\n\n/* Points to current character in buffer. */\nstatic char *yy_c_buf_p = (char *) 0;\nstatic int yy_init = 1;\t\t/* whether we need to initialize */\nstatic int yy_start = 0;\t/* start state number */\n\n/* Flag which is used to allow yywrap()'s to do buffer switches\n * instead of setting up a fresh yyin.  A bit of a hack ...\n */\nstatic int yy_did_buffer_switch_on_eof;\n\nvoid yyrestart YY_PROTO(( FILE *input_file ));\n\nvoid yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));\nvoid yy_load_buffer_state YY_PROTO(( void ));\nYY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));\nvoid yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));\nvoid yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));\nvoid yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));\n#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )\n\nYY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));\nYY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));\nYY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));\n\nstatic void *yy_flex_alloc YY_PROTO(( yy_size_t ));\nstatic void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));\nstatic void yy_flex_free YY_PROTO(( void * ));\n\n#define yy_new_buffer yy_create_buffer\n\n#define yy_set_interactive(is_interactive) \\\n\t{ \\\n\tif ( ! yy_current_buffer ) \\\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\\n\tyy_current_buffer->yy_is_interactive = is_interactive; \\\n\t}\n\n#define yy_set_bol(at_bol) \\\n\t{ \\\n\tif ( ! yy_current_buffer ) \\\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\\n\tyy_current_buffer->yy_at_bol = at_bol; \\\n\t}\n\n#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)\n\ntypedef unsigned char YY_CHAR;\nFILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;\ntypedef int yy_state_type;\nextern char *yytext;\n#define yytext_ptr yytext\nstatic yyconst short yy_nxt[][256] =\n    {\n    {\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0\n    },\n\n    {\n        3,    4,    4,    4,    4,    4,    4,    4,    4,    5,\n        6,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    5,    4,    7,    8,    4,    4,    4,    4,\n\n        9,   10,   11,   12,   13,   14,   15,   16,   17,   18,\n       18,   18,   18,   18,   18,   18,   18,   18,    4,   19,\n        4,   20,    4,    4,    4,   21,   21,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,    4,    4,    4,    4,   21,    4,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,   21,   21,   22,    4,   23,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4\n    },\n\n    {\n        3,    4,    4,    4,    4,    4,    4,    4,    4,    5,\n        6,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    5,    4,    7,    8,    4,    4,    4,    4,\n        9,   10,   11,   12,   13,   14,   15,   16,   17,   18,\n       18,   18,   18,   18,   18,   18,   18,   18,    4,   19,\n        4,   20,    4,    4,    4,   21,   21,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,    4,    4,    4,    4,   21,    4,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,   21,   21,   21,   21,   21,   21,   21,   21,   21,\n       21,   21,   21,   22,    4,   23,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4,    4,    4,    4,    4,\n        4,    4,    4,    4,    4,    4\n    },\n\n    {\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,\n       -3,   -3,   -3,   -3,   -3,   -3\n    },\n\n    {\n        3,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,\n       -4,   -4,   -4,   -4,   -4,   -4\n\n    },\n\n    {\n        3,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,\n       -5,   -5,   -5,   -5,   -5,   -5\n    },\n\n    {\n        3,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n\n       -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,\n       -6,   -6,   -6,   -6,   -6,   -6\n    },\n\n    {\n        3,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       -7,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   25,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24\n    },\n\n    {\n        3,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   26,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,   -8,\n       -8,   -8,   -8,   -8,   -8,   -8\n    },\n\n    {\n        3,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,   -9,\n       -9,   -9,   -9,   -9,   -9,   -9\n\n    },\n\n    {\n        3,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,  -10,\n      -10,  -10,  -10,  -10,  -10,  -10\n    },\n\n    {\n        3,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,   27,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n\n      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,\n      -11,  -11,  -11,  -11,  -11,  -11\n    },\n\n    {\n        3,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,   28,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,\n      -12,  -12,  -12,  -12,  -12,  -12\n    },\n\n    {\n        3,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,\n      -13,  -13,  -13,  -13,  -13,  -13\n    },\n\n    {\n        3,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,\n      -14,  -14,  -14,  -14,  -14,  -14\n\n    },\n\n    {\n        3,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,   29,   29,\n       29,   29,   29,   29,   29,   29,   29,   29,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,\n      -15,  -15,  -15,  -15,  -15,  -15\n    },\n\n    {\n        3,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n\n      -16,  -16,   30,  -16,  -16,  -16,  -16,   31,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n\n      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,\n      -16,  -16,  -16,  -16,  -16,  -16\n    },\n\n    {\n        3,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,   32,  -17,   33,   33,\n       33,   33,   33,   33,   33,   33,   33,   33,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n       34,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,\n      -17,  -17,  -17,  -17,  -17,  -17\n    },\n\n    {\n        3,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,   32,  -18,   33,   33,\n       33,   33,   33,   33,   33,   33,   33,   33,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,\n      -18,  -18,  -18,  -18,  -18,  -18\n    },\n\n    {\n        3,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,\n      -19,  -19,  -19,  -19,  -19,  -19\n\n    },\n\n    {\n        3,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,\n      -20,  -20,  -20,  -20,  -20,  -20\n    },\n\n    {\n        3,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,  -21,  -21,  -21,  -21,   35,  -21,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n\n      -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  -21,\n      -21,  -21,  -21,  -21,  -21,  -21\n    },\n\n    {\n        3,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,\n      -22,  -22,  -22,  -22,  -22,  -22\n    },\n\n    {\n        3,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,\n      -23,  -23,  -23,  -23,  -23,  -23\n    },\n\n    {\n        3,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n      -24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   25,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24,   24,   24,   24,   24,\n       24,   24,   24,   24,   24,   24\n\n    },\n\n    {\n        3,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,\n      -25,  -25,  -25,  -25,  -25,  -25\n    },\n\n    {\n        3,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,   36,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n\n      -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,\n      -26,  -26,  -26,  -26,  -26,  -26\n    },\n\n    {\n        3,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,\n      -27,  -27,  -27,  -27,  -27,  -27\n    },\n\n    {\n        3,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,\n      -28,  -28,  -28,  -28,  -28,  -28\n    },\n\n    {\n        3,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,   29,   29,\n       29,   29,   29,   29,   29,   29,   29,   29,  -29,  -29,\n\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,   37,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,   37,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,\n      -29,  -29,  -29,  -29,  -29,  -29\n\n    },\n\n    {\n        3,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,\n      -30,  -30,  -30,  -30,  -30,  -30\n    },\n\n    {\n        3,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n\n      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,\n      -31,  -31,  -31,  -31,  -31,  -31\n    },\n\n    {\n        3,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,   29,   29,\n       29,   29,   29,   29,   29,   29,   29,   29,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,   38,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,   38,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,\n      -32,  -32,  -32,  -32,  -32,  -32\n    },\n\n    {\n        3,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,   32,  -33,   33,   33,\n       33,   33,   33,   33,   33,   33,   33,   33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,\n      -33,  -33,  -33,  -33,  -33,  -33\n    },\n\n    {\n        3,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,   39,   39,\n       39,   39,   39,   39,   39,   39,   39,   39,  -34,  -34,\n\n      -34,  -34,  -34,  -34,  -34,   39,   39,   39,   39,   39,\n       39,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,   39,   39,   39,\n       39,   39,   39,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,\n      -34,  -34,  -34,  -34,  -34,  -34\n\n    },\n\n    {\n        3,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,  -35,  -35,  -35,  -35,   35,  -35,   35,   35,   35,\n\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,\n       35,   35,   35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,\n      -35,  -35,  -35,  -35,  -35,  -35\n    },\n\n    {\n        3,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,   40,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n\n      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,\n      -36,  -36,  -36,  -36,  -36,  -36\n    },\n\n    {\n        3,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,   41,  -37,   41,  -37,  -37,   42,   42,\n       42,   42,   42,   42,   42,   42,   42,   42,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,\n      -37,  -37,  -37,  -37,  -37,  -37\n    },\n\n    {\n        3,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,   43,  -38,   43,  -38,  -38,   44,   44,\n       44,   44,   44,   44,   44,   44,   44,   44,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,\n      -38,  -38,  -38,  -38,  -38,  -38\n    },\n\n    {\n        3,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,   39,   39,\n       39,   39,   39,   39,   39,   39,   39,   39,  -39,  -39,\n\n      -39,  -39,  -39,  -39,  -39,   39,   39,   39,   39,   39,\n       39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,   39,   39,   39,\n       39,   39,   39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,  -39,\n      -39,  -39,  -39,  -39,  -39,  -39\n\n    },\n\n    {\n        3,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n\n      -40,   45,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,\n      -40,  -40,  -40,  -40,  -40,  -40\n    },\n\n    {\n        3,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,   42,   42,\n       42,   42,   42,   42,   42,   42,   42,   42,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n\n      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,\n      -41,  -41,  -41,  -41,  -41,  -41\n    },\n\n    {\n        3,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,   42,   42,\n       42,   42,   42,   42,   42,   42,   42,   42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,\n      -42,  -42,  -42,  -42,  -42,  -42\n    },\n\n    {\n        3,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,   44,   44,\n       44,   44,   44,   44,   44,   44,   44,   44,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,\n      -43,  -43,  -43,  -43,  -43,  -43\n    },\n\n    {\n        3,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,   44,   44,\n       44,   44,   44,   44,   44,   44,   44,   44,  -44,  -44,\n\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,\n      -44,  -44,  -44,  -44,  -44,  -44\n\n    },\n\n    {\n        3,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,   46,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,\n      -45,  -45,  -45,  -45,  -45,  -45\n    },\n\n    {\n        3,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,   47,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n\n      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,\n      -46,  -46,  -46,  -46,  -46,  -46\n    },\n\n    {\n        3,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n       48,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,\n      -47,  -47,  -47,  -47,  -47,  -47\n    },\n\n    {\n        3,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,   49,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,\n      -48,  -48,  -48,  -48,  -48,  -48\n    },\n\n    {\n        3,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,\n      -49,  -49,  -49,  -49,  -49,  -49\n\n    },\n\n    } ;\n\n\nstatic yy_state_type yy_get_previous_state YY_PROTO(( void ));\nstatic yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));\nstatic int yy_get_next_buffer YY_PROTO(( void ));\nstatic void yy_fatal_error YY_PROTO(( yyconst char msg[] ));\n\n/* Done after the current pattern has been matched and before the\n * corresponding action - sets up yytext.\n */\n#define YY_DO_BEFORE_ACTION \\\n\tyytext_ptr = yy_bp; \\\n\tyyleng = (int) (yy_cp - yy_bp); \\\n\tyy_hold_char = *yy_cp; \\\n\t*yy_cp = '\\0'; \\\n\tyy_c_buf_p = yy_cp;\n\n#define YY_NUM_RULES 24\n#define YY_END_OF_BUFFER 25\nstatic yyconst short int yy_accept[50] =\n    {   0,\n        0,    0,   25,   24,   14,   15,   24,   24,    6,    5,\n        3,    1,   12,    2,   24,    4,   22,   22,    9,    7,\n       20,   11,   10,    0,   19,    0,   18,    8,   21,   17,\n       16,   21,   22,    0,   20,    0,    0,    0,   23,    0,\n        0,   21,    0,   21,    0,    0,    0,    0,   13\n    } ;\n\nstatic yy_state_type yy_last_accepting_state;\nstatic char *yy_last_accepting_cpos;\n\nstatic yyconst yy_state_type yy_NUL_trans[50] =\n    {   0,\n        4,    4,    0,    0,    0,    0,   24,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,   24,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n        0,    0,    0,    0,    0,    0,    0,    0,    0\n    } ;\n\n/* The intent behind this definition is that it'll catch\n * any uses of REJECT which flex missed.\n */\n#define REJECT reject_used_but_not_detected\n#define yymore() yymore_used_but_not_detected\n#define YY_MORE_ADJ 0\n#define YY_RESTORE_YY_MORE_OFFSET\nchar *yytext;\n#line 1 \"cf_lexical.lpp\"\n#define INITIAL 0\n#line 2 \"cf_lexical.lpp\"\n\n/* Includes */\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/mem_stream.h\"\n\n#include <vector>\n#include <string>\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n/* Constantes */\n\n// WARNING!!!! DEBUG_PRINTF are commented using // so IT MUST HAVE NO INSTRUCTION AFTER A DEBUG_PRINTF OR THEY LL BE COMMENTED\n\n//#define DEBUG_PRINTF\tInfoLog->displayRaw\n#ifdef __GNUC__\n#define DEBUG_PRINTF(format, args...)\n#else // __GNUC__\n#define DEBUG_PRINTF\t// InfoLog->displayRaw\n#endif // __GNUC__\n\n#define YY_NEVER_INTERACTIVE 1\n\n#ifdef WIN32\n#define read _read\n#endif\n\n/* Types */\n\nenum cf_type { T_UNKNOWN, T_INT, T_STRING, T_REAL };\n\nstruct cf_value\n{\n\tcf_type\tType;\n\tint\t\tInt;\n\tdouble\tReal;\n\tchar\tString[1024];\n};\n// use to parse the file, opened by CConfigFile::reparse()\nCMemStream cf_ifile;\n\n#define YY_INPUT(buf,result,max_size) { \\\n\tif (cf_ifile.length() == 0) \\\n\t{ \\\n\t\tDEBUG_PRINTF(\"YY_INPUT: eof\");\\\n\t\tresult = YY_NULL; \\\n\t} else { \\\n\t\tuint32 nbc = std::min((uint32)max_size, (uint32)(cf_ifile.length() - cf_ifile.getPos())); \\\n\t\tDEBUG_PRINTF(\"YY_INPUT: wanted %d bytes, will read %d\\n\", max_size, nbc);\\\n\t\tcf_ifile.serialBuffer ((uint8 *)buf, nbc); \\\n\t\tresult = nbc; \\\n\t} \\\n}\n\n/* special include, need to know cf_value */\n\n#include \"cf_gramatical.h\"\n\n/* Externals */\n\nextern int cf_CurrentLine;\n\n/* Variables */\n\nbool cf_Ignore;\n\nvoid comment ();\n\n#define YY_NO_UNPUT 1\n#line 2001 \"cf_lexical.cpp\"\n\n/* Macros after this point can all be overridden by user definitions in\n * section 1.\n */\n\n#ifndef YY_SKIP_YYWRAP\n#ifdef __cplusplus\nextern \"C\" int yywrap YY_PROTO(( void ));\n#else\nextern int yywrap YY_PROTO(( void ));\n#endif\n#endif\n\n#ifndef YY_NO_UNPUT\nstatic void yyunput YY_PROTO(( int c, char *buf_ptr ));\n#endif\n\n#ifndef yytext_ptr\nstatic void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));\n#endif\n\n#ifdef YY_NEED_STRLEN\nstatic int yy_flex_strlen YY_PROTO(( yyconst char * ));\n#endif\n\n#ifndef YY_NO_INPUT\n#ifdef __cplusplus\nstatic int yyinput YY_PROTO(( void ));\n#else\nstatic int input YY_PROTO(( void ));\n#endif\n#endif\n\n#if YY_STACK_USED\nstatic int yy_start_stack_ptr = 0;\nstatic int yy_start_stack_depth = 0;\nstatic int *yy_start_stack = 0;\n#ifndef YY_NO_PUSH_STATE\nstatic void yy_push_state YY_PROTO(( int new_state ));\n#endif\n#ifndef YY_NO_POP_STATE\nstatic void yy_pop_state YY_PROTO(( void ));\n#endif\n#ifndef YY_NO_TOP_STATE\nstatic int yy_top_state YY_PROTO(( void ));\n#endif\n\n#else\n#define YY_NO_PUSH_STATE 1\n#define YY_NO_POP_STATE 1\n#define YY_NO_TOP_STATE 1\n#endif\n\n#ifdef YY_MALLOC_DECL\nYY_MALLOC_DECL\n#else\n#if __STDC__\n#ifndef __cplusplus\n#include <stdlib.h>\n#endif\n#else\n/* Just try to get by without declaring the routines.  This will fail\n * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)\n * or sizeof(void*) != sizeof(int).\n */\n#endif\n#endif\n\n/* Amount of stuff to slurp up with each read. */\n#ifndef YY_READ_BUF_SIZE\n#define YY_READ_BUF_SIZE 8192\n#endif\n\n/* Copy whatever the last rule matched to the standard output. */\n\n#ifndef ECHO\n/* This used to be an fputs(), but since the string might contain NUL's,\n * we now use fwrite().\n */\n#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )\n#endif\n\n/* Gets input and stuffs it into \"buf\".  number of characters read, or YY_NULL,\n * is returned in \"result\".\n */\n#ifndef YY_INPUT\n#define YY_INPUT(buf,result,max_size) \\\n\tif ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \\\n\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );\n#endif\n\n/* No semi-colon after return; correct usage is to write \"yyterminate();\" -\n * we don't want an extra ';' after the \"return\" because that will cause\n * some compilers to complain about unreachable statements.\n */\n#ifndef yyterminate\n#define yyterminate() return YY_NULL\n#endif\n\n/* Number of entries by which start-condition stack grows. */\n#ifndef YY_START_STACK_INCR\n#define YY_START_STACK_INCR 25\n#endif\n\n/* Report a fatal error. */\n#ifndef YY_FATAL_ERROR\n#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )\n#endif\n\n/* Default declaration of generated scanner - a define so the user can\n * easily add parameters.\n */\n#ifndef YY_DECL\n#define YY_DECL int yylex YY_PROTO(( void ))\n#endif\n\n/* Code executed at the beginning of each rule, after yytext and yyleng\n * have been set up.\n */\n#ifndef YY_USER_ACTION\n#define YY_USER_ACTION\n#endif\n\n/* Code executed at the end of each rule. */\n#ifndef YY_BREAK\n#define YY_BREAK break;\n#endif\n\n#define YY_RULE_SETUP \\\n\tYY_USER_ACTION\n\nYY_DECL\n\t{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp, *yy_bp;\n\tregister int yy_act;\n\n#line 90 \"cf_lexical.lpp\"\n\n\n#line 2142 \"cf_lexical.cpp\"\n\n\tif ( yy_init )\n\t\t{\n\t\tyy_init = 0;\n\n#ifdef YY_USER_INIT\n\t\tYY_USER_INIT;\n#endif\n\n\t\tif ( ! yy_start )\n\t\t\tyy_start = 1;\t/* first start state */\n\n\t\tif ( ! yyin )\n\t\t\tyyin = stdin;\n\n\t\tif ( ! yyout )\n\t\t\tyyout = stdout;\n\n\t\tif ( ! yy_current_buffer )\n\t\t\tyy_current_buffer =\n\t\t\t\tyy_create_buffer( yyin, YY_BUF_SIZE );\n\n\t\tyy_load_buffer_state();\n\t\t}\n\n\twhile ( 1 )\t\t/* loops until end-of-file is reached */\n\t\t{\n\t\tyy_cp = yy_c_buf_p;\n\n\t\t/* Support of yytext. */\n\t\t*yy_cp = yy_hold_char;\n\n\t\t/* yy_bp points to the position in yy_ch_buf of the start of\n\t\t * the current run.\n\t\t */\n\t\tyy_bp = yy_cp;\n\n\t\tyy_current_state = yy_start;\nyy_match:\n\t\twhile ( (yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)]) > 0 )\n\t\t\t{\n\t\t\tif ( yy_accept[yy_current_state] )\n\t\t\t\t{\n\t\t\t\tyy_last_accepting_state = yy_current_state;\n\t\t\t\tyy_last_accepting_cpos = yy_cp;\n\t\t\t\t}\n\n\t\t\t++yy_cp;\n\t\t\t}\n\n\t\tyy_current_state = -yy_current_state;\n\nyy_find_action:\n\t\tyy_act = yy_accept[yy_current_state];\n\n\t\tYY_DO_BEFORE_ACTION;\n\n\ndo_action:\t/* This label is used only to access EOF actions. */\n\n\n\t\tswitch ( yy_act )\n\t{ /* beginning of action switch */\n\t\t\tcase 0: /* must back up */\n\t\t\t/* undo the effects of YY_DO_BEFORE_ACTION */\n\t\t\t*yy_cp = yy_hold_char;\n\t\t\tyy_cp = yy_last_accepting_cpos + 1;\n\t\t\tyy_current_state = yy_last_accepting_state;\n\t\t\tgoto yy_find_action;\n\ncase 1:\nYY_RULE_SETUP\n#line 92 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return PLUS; }\n\tYY_BREAK\ncase 2:\nYY_RULE_SETUP\n#line 93 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return MINUS; }\n\tYY_BREAK\ncase 3:\nYY_RULE_SETUP\n#line 94 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return MULT; }\n\tYY_BREAK\ncase 4:\nYY_RULE_SETUP\n#line 95 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return DIVIDE; }\n\tYY_BREAK\ncase 5:\nYY_RULE_SETUP\n#line 96 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return RPAREN; }\n\tYY_BREAK\ncase 6:\nYY_RULE_SETUP\n#line 97 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return LPAREN; }\n\tYY_BREAK\ncase 7:\nYY_RULE_SETUP\n#line 98 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return ASSIGN; }\n\tYY_BREAK\ncase 8:\nYY_RULE_SETUP\n#line 99 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return ADD_ASSIGN; }\n\tYY_BREAK\ncase 9:\nYY_RULE_SETUP\n#line 100 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return SEMICOLON; }\n\tYY_BREAK\ncase 10:\nYY_RULE_SETUP\n#line 101 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return RBRACE; }\n\tYY_BREAK\ncase 11:\nYY_RULE_SETUP\n#line 102 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return LBRACE; }\n\tYY_BREAK\ncase 12:\nYY_RULE_SETUP\n#line 103 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return COMMA; }\n\tYY_BREAK\ncase 13:\nYY_RULE_SETUP\n#line 104 \"cf_lexical.lpp\"\n{ if (!cf_Ignore) return FILELINE; }\n\tYY_BREAK\ncase 14:\nYY_RULE_SETUP\n#line 107 \"cf_lexical.lpp\"\n{ /* ignore tabulation and spaces */; }\n\tYY_BREAK\ncase 15:\nYY_RULE_SETUP\n#line 109 \"cf_lexical.lpp\"\n{\n\t\t\t\t/* ignore new line but count them */\n\t\t\t\tcf_CurrentLine++;\n\t\t\t\tDEBUG_PRINTF(\"*****line++ %d\\n\", cf_CurrentLine);\n\t\t\t}\n\tYY_BREAK\ncase 16:\nYY_RULE_SETUP\n#line 115 \"cf_lexical.lpp\"\n{ comment(); }\n\tYY_BREAK\ncase 17:\nYY_RULE_SETUP\n#line 117 \"cf_lexical.lpp\"\n{ /* Start of a comment */ cf_Ignore = true; }\n\tYY_BREAK\ncase 18:\nYY_RULE_SETUP\n#line 119 \"cf_lexical.lpp\"\n{ /* End of a comment */ cf_Ignore = false; }\n\tYY_BREAK\ncase 19:\nYY_RULE_SETUP\n#line 121 \"cf_lexical.lpp\"\n{ /* A string */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_STRING;\n\t\t\t\t\tstrcpy (cflval.Val.String, yytext+1);\n\t\t\t\t\tcflval.Val.String[strlen(cflval.Val.String)-1] = '\\0';\n\t\t\t\t\tDEBUG_PRINTF(\"lex: string '%s' '%s'\\n\", yytext, cflval.Val.String);\n\t\t\t\t\treturn STRING;\n\t\t\t\t}\n\t\t\t}\n\tYY_BREAK\ncase 20:\nYY_RULE_SETUP\n#line 132 \"cf_lexical.lpp\"\n{ /* A variable */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_STRING;\n\t\t\t\t\tstrcpy (cflval.Val.String, yytext);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: variable '%s' '%s'\\n\", yytext, cflval.Val.String);\n\t\t\t\t\treturn VARIABLE;\n\t\t\t\t}\n\t\t\t}\n\tYY_BREAK\ncase 21:\nYY_RULE_SETUP\n#line 142 \"cf_lexical.lpp\"\n{ /* A real */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_REAL;\n\t\t\t\t\tNLMISC::fromString(yytext, cflval.Val.Real);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: real '%s' '%f\\n\", yytext, cflval.Val.Real);\n\t\t\t\t\treturn REAL;\n\t\t\t\t}\n\t\t\t}\n\tYY_BREAK\ncase 22:\nYY_RULE_SETUP\n#line 152 \"cf_lexical.lpp\"\n{ /* An int */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_INT;\n\t\t\t\t\tcflval.Val.Int = atoi (yytext);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: int '%s' '%d'\\n\", yytext, cflval.Val.Int);\n\t\t\t\t\treturn INTEGER;\n\t\t\t\t}\n\t\t\t}\n\tYY_BREAK\ncase 23:\nYY_RULE_SETUP\n#line 162 \"cf_lexical.lpp\"\n{ /* An hex int */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_INT;\n\t\t\t\t\tsscanf (yytext, \"%x\", &(cflval.Val.Int));\n\t\t\t\t\tDEBUG_PRINTF(\"lex: hexa '%s' '0x%x' '%d'\\n\", yytext, cflval.Val.Int, cflval.Val.Int);\n\t\t\t\t\treturn INTEGER;\n\t\t\t\t}\n\t\t\t}\n\tYY_BREAK\ncase 24:\nYY_RULE_SETUP\n#line 172 \"cf_lexical.lpp\"\nECHO;\n\tYY_BREAK\n#line 2378 \"cf_lexical.cpp\"\ncase YY_STATE_EOF(INITIAL):\n\tyyterminate();\n\n\tcase YY_END_OF_BUFFER:\n\t\t{\n\t\t/* Amount of text matched not including the EOB char. */\n\t\tint yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;\n\n\t\t/* Undo the effects of YY_DO_BEFORE_ACTION. */\n\t\t*yy_cp = yy_hold_char;\n\t\tYY_RESTORE_YY_MORE_OFFSET\n\n\t\tif ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )\n\t\t\t{\n\t\t\t/* We're scanning a new file or input source.  It's\n\t\t\t * possible that this happened because the user\n\t\t\t * just pointed yyin at a new source and called\n\t\t\t * yylex().  If so, then we have to assure\n\t\t\t * consistency between yy_current_buffer and our\n\t\t\t * globals.  Here is the right place to do so, because\n\t\t\t * this is the first action (other than possibly a\n\t\t\t * back-up) that will match for the new input source.\n\t\t\t */\n\t\t\tyy_n_chars = yy_current_buffer->yy_n_chars;\n\t\t\tyy_current_buffer->yy_input_file = yyin;\n\t\t\tyy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;\n\t\t\t}\n\n\t\t/* Note that here we test for yy_c_buf_p \"<=\" to the position\n\t\t * of the first EOB in the buffer, since yy_c_buf_p will\n\t\t * already have been incremented past the NUL character\n\t\t * (since all states make transitions on EOB to the\n\t\t * end-of-buffer state).  Contrast this with the test\n\t\t * in input().\n\t\t */\n\t\tif ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )\n\t\t\t{ /* This was really a NUL. */\n\t\t\tyy_state_type yy_next_state;\n\n\t\t\tyy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;\n\n\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t/* Okay, we're now positioned to make the NUL\n\t\t\t * transition.  We couldn't have\n\t\t\t * yy_get_previous_state() go ahead and do it\n\t\t\t * for us because it doesn't know how to deal\n\t\t\t * with the possibility of jamming (and we don't\n\t\t\t * want to build jamming into it because then it\n\t\t\t * will run more slowly).\n\t\t\t */\n\n\t\t\tyy_next_state = yy_try_NUL_trans( yy_current_state );\n\n\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\n\t\t\tif ( yy_next_state )\n\t\t\t\t{\n\t\t\t\t/* Consume the NUL. */\n\t\t\t\tyy_cp = ++yy_c_buf_p;\n\t\t\t\tyy_current_state = yy_next_state;\n\t\t\t\tgoto yy_match;\n\t\t\t\t}\n\n\t\t\telse\n\t\t\t\t{\n\t\t\t\tyy_cp = yy_c_buf_p;\n\t\t\t\tgoto yy_find_action;\n\t\t\t\t}\n\t\t\t}\n\n\t\telse switch ( yy_get_next_buffer() )\n\t\t\t{\n\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t{\n\t\t\t\tyy_did_buffer_switch_on_eof = 0;\n\n\t\t\t\tif ( yywrap() )\n\t\t\t\t\t{\n\t\t\t\t\t/* Note: because we've taken care in\n\t\t\t\t\t * yy_get_next_buffer() to have set up\n\t\t\t\t\t * yytext, we can now set up\n\t\t\t\t\t * yy_c_buf_p so that if some total\n\t\t\t\t\t * hoser (like flex itself) wants to\n\t\t\t\t\t * call the scanner after we return the\n\t\t\t\t\t * YY_NULL, it'll still work - another\n\t\t\t\t\t * YY_NULL will get returned.\n\t\t\t\t\t */\n\t\t\t\t\tyy_c_buf_p = yytext_ptr + YY_MORE_ADJ;\n\n\t\t\t\t\tyy_act = YY_STATE_EOF(YY_START);\n\t\t\t\t\tgoto do_action;\n\t\t\t\t\t}\n\n\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\tif ( ! yy_did_buffer_switch_on_eof )\n\t\t\t\t\t\tYY_NEW_FILE;\n\t\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\tyy_c_buf_p =\n\t\t\t\t\tyytext_ptr + yy_amount_of_matched_text;\n\n\t\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t\tyy_cp = yy_c_buf_p;\n\t\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\t\t\t\tgoto yy_match;\n\n\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\tyy_c_buf_p =\n\t\t\t\t&yy_current_buffer->yy_ch_buf[yy_n_chars];\n\n\t\t\t\tyy_current_state = yy_get_previous_state();\n\n\t\t\t\tyy_cp = yy_c_buf_p;\n\t\t\t\tyy_bp = yytext_ptr + YY_MORE_ADJ;\n\t\t\t\tgoto yy_find_action;\n\t\t\t}\n\t\tbreak;\n\t\t}\n\n\tdefault:\n\t\tYY_FATAL_ERROR(\n\t\t\t\"fatal flex scanner internal error--no action found\" );\n\t} /* end of action switch */\n\t\t} /* end of scanning one token */\n\t} /* end of yylex */\n\n\n/* yy_get_next_buffer - try to read in a new buffer\n *\n * Returns a code representing an action:\n *\tEOB_ACT_LAST_MATCH -\n *\tEOB_ACT_CONTINUE_SCAN - continue scanning from current position\n *\tEOB_ACT_END_OF_FILE - end of file\n */\n\nstatic int yy_get_next_buffer()\n\t{\n\tregister char *dest = yy_current_buffer->yy_ch_buf;\n\tregister char *source = yytext_ptr;\n\tregister int number_to_move, i;\n\tint ret_val;\n\n\tif ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )\n\t\tYY_FATAL_ERROR(\n\t\t\"fatal flex scanner internal error--end of buffer missed\" );\n\n\tif ( yy_current_buffer->yy_fill_buffer == 0 )\n\t\t{ /* Don't try to fill the buffer, so this is an EOF. */\n\t\tif ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )\n\t\t\t{\n\t\t\t/* We matched a single character, the EOB, so\n\t\t\t * treat this as a final EOF.\n\t\t\t */\n\t\t\treturn EOB_ACT_END_OF_FILE;\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\t/* We matched some text prior to the EOB, first\n\t\t\t * process it.\n\t\t\t */\n\t\t\treturn EOB_ACT_LAST_MATCH;\n\t\t\t}\n\t\t}\n\n\t/* Try to read more data. */\n\n\t/* First move last chars to start of buffer. */\n\tnumber_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;\n\n\tfor ( i = 0; i < number_to_move; ++i )\n\t\t*(dest++) = *(source++);\n\n\tif ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )\n\t\t/* don't do the read, it's not guaranteed to return an EOF,\n\t\t * just force an EOF\n\t\t */\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars = 0;\n\n\telse\n\t\t{\n\t\tint num_to_read =\n\t\t\tyy_current_buffer->yy_buf_size - number_to_move - 1;\n\n\t\twhile ( num_to_read <= 0 )\n\t\t\t{ /* Not enough room in the buffer - grow it. */\n#ifdef YY_USES_REJECT\n\t\t\tYY_FATAL_ERROR(\n\"input buffer overflow, can't enlarge buffer because scanner uses REJECT\" );\n#else\n\n\t\t\t/* just a shorter name for the current buffer */\n\t\t\tYY_BUFFER_STATE b = yy_current_buffer;\n\n\t\t\tint yy_c_buf_p_offset =\n\t\t\t\t(int) (yy_c_buf_p - b->yy_ch_buf);\n\n\t\t\tif ( b->yy_is_our_buffer )\n\t\t\t\t{\n\t\t\t\tint new_size = b->yy_buf_size * 2;\n\n\t\t\t\tif ( new_size <= 0 )\n\t\t\t\t\tb->yy_buf_size += b->yy_buf_size / 8;\n\t\t\t\telse\n\t\t\t\t\tb->yy_buf_size *= 2;\n\n\t\t\t\tb->yy_ch_buf = (char *)\n\t\t\t\t\t/* Include room in for 2 EOB chars. */\n\t\t\t\t\tyy_flex_realloc( (void *) b->yy_ch_buf,\n\t\t\t\t\t\t\t b->yy_buf_size + 2 );\n\t\t\t\t}\n\t\t\telse\n\t\t\t\t/* Can't grow it, we don't own it. */\n\t\t\t\tb->yy_ch_buf = 0;\n\n\t\t\tif ( ! b->yy_ch_buf )\n\t\t\t\tYY_FATAL_ERROR(\n\t\t\t\t\"fatal error - scanner input buffer overflow\" );\n\n\t\t\tyy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];\n\n\t\t\tnum_to_read = yy_current_buffer->yy_buf_size -\n\t\t\t\t\t\tnumber_to_move - 1;\n#endif\n\t\t\t}\n\n\t\tif ( num_to_read > YY_READ_BUF_SIZE )\n\t\t\tnum_to_read = YY_READ_BUF_SIZE;\n\n\t\t/* Read in more data. */\n\t\tYY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),\n\t\t\tyy_n_chars, num_to_read );\n\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars;\n\t\t}\n\n\tif ( yy_n_chars == 0 )\n\t\t{\n\t\tif ( number_to_move == YY_MORE_ADJ )\n\t\t\t{\n\t\t\tret_val = EOB_ACT_END_OF_FILE;\n\t\t\tyyrestart( yyin );\n\t\t\t}\n\n\t\telse\n\t\t\t{\n\t\t\tret_val = EOB_ACT_LAST_MATCH;\n\t\t\tyy_current_buffer->yy_buffer_status =\n\t\t\t\tYY_BUFFER_EOF_PENDING;\n\t\t\t}\n\t\t}\n\n\telse\n\t\tret_val = EOB_ACT_CONTINUE_SCAN;\n\n\tyy_n_chars += number_to_move;\n\tyy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;\n\tyy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;\n\n\tyytext_ptr = &yy_current_buffer->yy_ch_buf[0];\n\n\treturn ret_val;\n\t}\n\n\n/* yy_get_previous_state - get the state just before the EOB char was reached */\n\nstatic yy_state_type yy_get_previous_state()\n\t{\n\tregister yy_state_type yy_current_state;\n\tregister char *yy_cp;\n\n\tyy_current_state = yy_start;\n\n\tfor ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )\n\t\t{\n\t\tif ( *yy_cp )\n\t\t\t{\n\t\t\tyy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)];\n\t\t\t}\n\t\telse\n\t\t\tyy_current_state = yy_NUL_trans[yy_current_state];\n\t\tif ( yy_accept[yy_current_state] )\n\t\t\t{\n\t\t\tyy_last_accepting_state = yy_current_state;\n\t\t\tyy_last_accepting_cpos = yy_cp;\n\t\t\t}\n\t\t}\n\n\treturn yy_current_state;\n\t}\n\n\n/* yy_try_NUL_trans - try to make a transition on the NUL character\n *\n * synopsis\n *\tnext_state = yy_try_NUL_trans( current_state );\n */\n\n#ifdef YY_USE_PROTOS\nstatic yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )\n#else\nstatic yy_state_type yy_try_NUL_trans( yy_current_state )\nyy_state_type yy_current_state;\n#endif\n\t{\n\tregister int yy_is_jam;\n\tregister char *yy_cp = yy_c_buf_p;\n\n\tyy_current_state = yy_NUL_trans[yy_current_state];\n\tyy_is_jam = (yy_current_state == 0);\n\n\tif ( ! yy_is_jam )\n\t\t{\n\t\tif ( yy_accept[yy_current_state] )\n\t\t\t{\n\t\t\tyy_last_accepting_state = yy_current_state;\n\t\t\tyy_last_accepting_cpos = yy_cp;\n\t\t\t}\n\t\t}\n\n\treturn yy_is_jam ? 0 : yy_current_state;\n\t}\n\n\n#ifndef YY_NO_UNPUT\n#ifdef YY_USE_PROTOS\nstatic void yyunput( int c, register char *yy_bp )\n#else\nstatic void yyunput( c, yy_bp )\nint c;\nregister char *yy_bp;\n#endif\n\t{\n\tregister char *yy_cp = yy_c_buf_p;\n\n\t/* undo effects of setting up yytext */\n\t*yy_cp = yy_hold_char;\n\n\tif ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\n\t\t{ /* need to shift things up to make room */\n\t\t/* +2 for EOB chars. */\n\t\tregister int number_to_move = yy_n_chars + 2;\n\t\tregister char *dest = &yy_current_buffer->yy_ch_buf[\n\t\t\t\t\tyy_current_buffer->yy_buf_size + 2];\n\t\tregister char *source =\n\t\t\t\t&yy_current_buffer->yy_ch_buf[number_to_move];\n\n\t\twhile ( source > yy_current_buffer->yy_ch_buf )\n\t\t\t*--dest = *--source;\n\n\t\tyy_cp += (int) (dest - source);\n\t\tyy_bp += (int) (dest - source);\n\t\tyy_current_buffer->yy_n_chars =\n\t\t\tyy_n_chars = yy_current_buffer->yy_buf_size;\n\n\t\tif ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\n\t\t\tYY_FATAL_ERROR( \"flex scanner push-back overflow\" );\n\t\t}\n\n\t*--yy_cp = (char) c;\n\n\n\tyytext_ptr = yy_bp;\n\tyy_hold_char = *yy_cp;\n\tyy_c_buf_p = yy_cp;\n\t}\n#endif\t/* ifndef YY_NO_UNPUT */\n\n\n#ifdef __cplusplus\nstatic int yyinput()\n#else\nstatic int input()\n#endif\n\t{\n\tint c;\n\n\t*yy_c_buf_p = yy_hold_char;\n\n\tif ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )\n\t\t{\n\t\t/* yy_c_buf_p now points to the character we want to return.\n\t\t * If this occurs *before* the EOB characters, then it's a\n\t\t * valid NUL; if not, then we've hit the end of the buffer.\n\t\t */\n\t\tif ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )\n\t\t\t/* This was really a NUL. */\n\t\t\t*yy_c_buf_p = '\\0';\n\n\t\telse\n\t\t\t{ /* need more input */\n\t\t\tint offset = (int)(yy_c_buf_p - yytext_ptr);\n\t\t\t++yy_c_buf_p;\n\n\t\t\tswitch ( yy_get_next_buffer() )\n\t\t\t\t{\n\t\t\t\tcase EOB_ACT_LAST_MATCH:\n\t\t\t\t\t/* This happens because yy_g_n_b()\n\t\t\t\t\t * sees that we've accumulated a\n\t\t\t\t\t * token and flags that we need to\n\t\t\t\t\t * try matching the token before\n\t\t\t\t\t * proceeding.  But for input(),\n\t\t\t\t\t * there's no matching to consider.\n\t\t\t\t\t * So convert the EOB_ACT_LAST_MATCH\n\t\t\t\t\t * to EOB_ACT_END_OF_FILE.\n\t\t\t\t\t */\n\n\t\t\t\t\t/* Reset buffer status. */\n\t\t\t\t\tyyrestart( yyin );\n\n\t\t\t\t\t/* fall through */\n\n\t\t\t\tcase EOB_ACT_END_OF_FILE:\n\t\t\t\t\t{\n\t\t\t\t\tif ( yywrap() )\n\t\t\t\t\t\treturn EOF;\n\n\t\t\t\t\tif ( ! yy_did_buffer_switch_on_eof )\n\t\t\t\t\t\tYY_NEW_FILE;\n#ifdef __cplusplus\n\t\t\t\t\treturn yyinput();\n#else\n\t\t\t\t\treturn input();\n#endif\n\t\t\t\t\t}\n\n\t\t\t\tcase EOB_ACT_CONTINUE_SCAN:\n\t\t\t\t\tyy_c_buf_p = yytext_ptr + offset;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\tc = *(unsigned char *) yy_c_buf_p;\t/* cast for 8-bit char's */\n\t*yy_c_buf_p = '\\0';\t/* preserve yytext */\n\tyy_hold_char = *++yy_c_buf_p;\n\n\n\treturn c;\n\t}\n\n\n#ifdef YY_USE_PROTOS\nvoid yyrestart( FILE *input_file )\n#else\nvoid yyrestart( input_file )\nFILE *input_file;\n#endif\n\t{\n\tif ( ! yy_current_buffer )\n\t\tyy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );\n\n\tyy_init_buffer( yy_current_buffer, input_file );\n\tyy_load_buffer_state();\n\t}\n\n\n#ifdef YY_USE_PROTOS\nvoid yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )\n#else\nvoid yy_switch_to_buffer( new_buffer )\nYY_BUFFER_STATE new_buffer;\n#endif\n\t{\n\tif ( yy_current_buffer == new_buffer )\n\t\treturn;\n\n\tif ( yy_current_buffer )\n\t\t{\n\t\t/* Flush out information for old buffer. */\n\t\t*yy_c_buf_p = yy_hold_char;\n\t\tyy_current_buffer->yy_buf_pos = yy_c_buf_p;\n\t\tyy_current_buffer->yy_n_chars = yy_n_chars;\n\t\t}\n\n\tyy_current_buffer = new_buffer;\n\tyy_load_buffer_state();\n\n\t/* We don't actually know whether we did this switch during\n\t * EOF (yywrap()) processing, but the only time this flag\n\t * is looked at is after yywrap() is called, so it's safe\n\t * to go ahead and always set it.\n\t */\n\tyy_did_buffer_switch_on_eof = 1;\n\t}\n\n\n#ifdef YY_USE_PROTOS\nvoid yy_load_buffer_state( void )\n#else\nvoid yy_load_buffer_state()\n#endif\n\t{\n\tyy_n_chars = yy_current_buffer->yy_n_chars;\n\tyytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;\n\tyyin = yy_current_buffer->yy_input_file;\n\tyy_hold_char = *yy_c_buf_p;\n\t}\n\n\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_create_buffer( FILE *file, int size )\n#else\nYY_BUFFER_STATE yy_create_buffer( file, size )\nFILE *file;\nint size;\n#endif\n\t{\n\tYY_BUFFER_STATE b;\n\n\tb = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );\n\n\tb->yy_buf_size = size;\n\n\t/* yy_ch_buf has to be 2 characters longer than the size given because\n\t * we need to put in 2 end-of-buffer characters.\n\t */\n\tb->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );\n\tif ( ! b->yy_ch_buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );\n\n\tb->yy_is_our_buffer = 1;\n\n\tyy_init_buffer( b, file );\n\n\treturn b;\n\t}\n\n\n#ifdef YY_USE_PROTOS\nvoid yy_delete_buffer( YY_BUFFER_STATE b )\n#else\nvoid yy_delete_buffer( b )\nYY_BUFFER_STATE b;\n#endif\n\t{\n\tif ( ! b )\n\t\treturn;\n\n\tif ( b == yy_current_buffer )\n\t\tyy_current_buffer = (YY_BUFFER_STATE) 0;\n\n\tif ( b->yy_is_our_buffer )\n\t\tyy_flex_free( (void *) b->yy_ch_buf );\n\n\tyy_flex_free( (void *) b );\n\t}\n\n\n#ifndef YY_ALWAYS_INTERACTIVE\n#ifndef YY_NEVER_INTERACTIVE\nextern int isatty YY_PROTO(( int ));\n#endif\n#endif\n\n#ifdef YY_USE_PROTOS\nvoid yy_init_buffer( YY_BUFFER_STATE b, FILE *file )\n#else\nvoid yy_init_buffer( b, file )\nYY_BUFFER_STATE b;\nFILE *file;\n#endif\n\n\n\t{\n\tyy_flush_buffer( b );\n\n\tb->yy_input_file = file;\n\tb->yy_fill_buffer = 1;\n\n#if YY_ALWAYS_INTERACTIVE\n\tb->yy_is_interactive = 1;\n#else\n#if YY_NEVER_INTERACTIVE\n\tb->yy_is_interactive = 0;\n#else\n\tb->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;\n#endif\n#endif\n\t}\n\n\n#ifdef YY_USE_PROTOS\nvoid yy_flush_buffer( YY_BUFFER_STATE b )\n#else\nvoid yy_flush_buffer( b )\nYY_BUFFER_STATE b;\n#endif\n\n\t{\n\tif ( ! b )\n\t\treturn;\n\n\tb->yy_n_chars = 0;\n\n\t/* We always need two end-of-buffer characters.  The first causes\n\t * a transition to the end-of-buffer state.  The second causes\n\t * a jam in that state.\n\t */\n\tb->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;\n\tb->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;\n\n\tb->yy_buf_pos = &b->yy_ch_buf[0];\n\n\tb->yy_at_bol = 1;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tif ( b == yy_current_buffer )\n\t\tyy_load_buffer_state();\n\t}\n\n\n#ifndef YY_NO_SCAN_BUFFER\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )\n#else\nYY_BUFFER_STATE yy_scan_buffer( base, size )\nchar *base;\nyy_size_t size;\n#endif\n\t{\n\tYY_BUFFER_STATE b;\n\n\tif ( size < 2 ||\n\t     base[size-2] != YY_END_OF_BUFFER_CHAR ||\n\t     base[size-1] != YY_END_OF_BUFFER_CHAR )\n\t\t/* They forgot to leave room for the EOB's. */\n\t\treturn 0;\n\n\tb = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_scan_buffer()\" );\n\n\tb->yy_buf_size = size - 2;\t/* \"- 2\" to take care of EOB's */\n\tb->yy_buf_pos = b->yy_ch_buf = base;\n\tb->yy_is_our_buffer = 0;\n\tb->yy_input_file = 0;\n\tb->yy_n_chars = b->yy_buf_size;\n\tb->yy_is_interactive = 0;\n\tb->yy_at_bol = 1;\n\tb->yy_fill_buffer = 0;\n\tb->yy_buffer_status = YY_BUFFER_NEW;\n\n\tyy_switch_to_buffer( b );\n\n\treturn b;\n\t}\n#endif\n\n\n#ifndef YY_NO_SCAN_STRING\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )\n#else\nYY_BUFFER_STATE yy_scan_string( yy_str )\nyyconst char *yy_str;\n#endif\n\t{\n\tint len;\n\tfor ( len = 0; yy_str[len]; ++len )\n\t\t;\n\n\treturn yy_scan_bytes( yy_str, len );\n\t}\n#endif\n\n\n#ifndef YY_NO_SCAN_BYTES\n#ifdef YY_USE_PROTOS\nYY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )\n#else\nYY_BUFFER_STATE yy_scan_bytes( bytes, len )\nyyconst char *bytes;\nint len;\n#endif\n\t{\n\tYY_BUFFER_STATE b;\n\tchar *buf;\n\tyy_size_t n;\n\tint i;\n\n\t/* Get memory for full buffer, including space for trailing EOB's. */\n\tn = len + 2;\n\tbuf = (char *) yy_flex_alloc( n );\n\tif ( ! buf )\n\t\tYY_FATAL_ERROR( \"out of dynamic memory in yy_scan_bytes()\" );\n\n\tfor ( i = 0; i < len; ++i )\n\t\tbuf[i] = bytes[i];\n\n\tbuf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;\n\n\tb = yy_scan_buffer( buf, n );\n\tif ( ! b )\n\t\tYY_FATAL_ERROR( \"bad buffer in yy_scan_bytes()\" );\n\n\t/* It's okay to grow etc. this buffer, and we should throw it\n\t * away when we're done.\n\t */\n\tb->yy_is_our_buffer = 1;\n\n\treturn b;\n\t}\n#endif\n\n\n#ifndef YY_NO_PUSH_STATE\n#ifdef YY_USE_PROTOS\nstatic void yy_push_state( int new_state )\n#else\nstatic void yy_push_state( new_state )\nint new_state;\n#endif\n\t{\n\tif ( yy_start_stack_ptr >= yy_start_stack_depth )\n\t\t{\n\t\tyy_size_t new_size;\n\n\t\tyy_start_stack_depth += YY_START_STACK_INCR;\n\t\tnew_size = yy_start_stack_depth * sizeof( int );\n\n\t\tif ( ! yy_start_stack )\n\t\t\tyy_start_stack = (int *) yy_flex_alloc( new_size );\n\n\t\telse\n\t\t\tyy_start_stack = (int *) yy_flex_realloc(\n\t\t\t\t\t(void *) yy_start_stack, new_size );\n\n\t\tif ( ! yy_start_stack )\n\t\t\tYY_FATAL_ERROR(\n\t\t\t\"out of memory expanding start-condition stack\" );\n\t\t}\n\n\tyy_start_stack[yy_start_stack_ptr++] = YY_START;\n\n\tBEGIN(new_state);\n\t}\n#endif\n\n\n#ifndef YY_NO_POP_STATE\nstatic void yy_pop_state()\n\t{\n\tif ( --yy_start_stack_ptr < 0 )\n\t\tYY_FATAL_ERROR( \"start-condition stack underflow\" );\n\n\tBEGIN(yy_start_stack[yy_start_stack_ptr]);\n\t}\n#endif\n\n\n#ifndef YY_NO_TOP_STATE\nstatic int yy_top_state()\n\t{\n\treturn yy_start_stack[yy_start_stack_ptr - 1];\n\t}\n#endif\n\n#ifndef YY_EXIT_FAILURE\n#define YY_EXIT_FAILURE 2\n#endif\n\n#ifdef YY_USE_PROTOS\nstatic void yy_fatal_error( yyconst char msg[] )\n#else\nstatic void yy_fatal_error( msg )\nchar msg[];\n#endif\n\t{\n\t(void) fprintf( stderr, \"%s\\n\", msg );\n\texit( YY_EXIT_FAILURE );\n\t}\n\n\n\n/* Redefine yyless() so it works in section 3 code. */\n\n#undef yyless\n#define yyless(n) \\\n\tdo \\\n\t\t{ \\\n\t\t/* Undo effects of setting up yytext. */ \\\n\t\tyytext[yyleng] = yy_hold_char; \\\n\t\tyy_c_buf_p = yytext + n; \\\n\t\tyy_hold_char = *yy_c_buf_p; \\\n\t\t*yy_c_buf_p = '\\0'; \\\n\t\tyyleng = n; \\\n\t\t} \\\n\twhile ( 0 )\n\n\n/* Internal utility routines. */\n\n#ifndef yytext_ptr\n#ifdef YY_USE_PROTOS\nstatic void yy_flex_strncpy( char *s1, yyconst char *s2, int n )\n#else\nstatic void yy_flex_strncpy( s1, s2, n )\nchar *s1;\nyyconst char *s2;\nint n;\n#endif\n\t{\n\tregister int i;\n\tfor ( i = 0; i < n; ++i )\n\t\ts1[i] = s2[i];\n\t}\n#endif\n\n#ifdef YY_NEED_STRLEN\n#ifdef YY_USE_PROTOS\nstatic int yy_flex_strlen( yyconst char *s )\n#else\nstatic int yy_flex_strlen( s )\nyyconst char *s;\n#endif\n\t{\n\tregister int n;\n\tfor ( n = 0; s[n]; ++n )\n\t\t;\n\n\treturn n;\n\t}\n#endif\n\n\n#ifdef YY_USE_PROTOS\nstatic void *yy_flex_alloc( yy_size_t size )\n#else\nstatic void *yy_flex_alloc( size )\nyy_size_t size;\n#endif\n\t{\n\treturn (void *) malloc( size );\n\t}\n\n#ifdef YY_USE_PROTOS\nstatic void *yy_flex_realloc( void *ptr, yy_size_t size )\n#else\nstatic void *yy_flex_realloc( ptr, size )\nvoid *ptr;\nyy_size_t size;\n#endif\n\t{\n\t/* The cast to (char *) in the following accommodates both\n\t * implementations that use char* generic pointers, and those\n\t * that use void* generic pointers.  It works with the latter\n\t * because both ANSI C and C++ allow castless assignment from\n\t * any pointer type to void*, and deal with argument conversions\n\t * as though doing an assignment.\n\t */\n\treturn (void *) realloc( (char *) ptr, size );\n\t}\n\n#ifdef YY_USE_PROTOS\nstatic void yy_flex_free( void *ptr )\n#else\nstatic void yy_flex_free( ptr )\nvoid *ptr;\n#endif\n\t{\n\tfree( ptr );\n\t}\n\n#if YY_MAIN\nint main()\n\t{\n\tyylex();\n\treturn 0;\n\t}\n#endif\n#line 172 \"cf_lexical.lpp\"\n\n\nint cfwrap()\n{\n\treturn 1;\n}\n\n//\"//\".*\\n\t{ /* ignore one line comment but count the new line */ cf_CurrentLine++; DEBUG_PRINTF(\"*****line++ %d\\n\", cf_CurrentLine); }\nvoid comment ()\n{\n\tint c;\n\n\tdo\n\t{\n\t\tc = yyinput ();\n\t}\n\twhile (c != '\\n' && c != -1);\n\n\tif (c == '\\n')\n\t\tcf_CurrentLine++;\n}\n"
  },
  {
    "path": "code/nel/src/misc/config_file/cf_lexical.lpp",
    "content": "%{\n\n/* Includes */\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/mem_stream.h\"\n\n#include <vector>\n#include <string>\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n/* Constantes */\n\n// WARNING!!!! DEBUG_PRINTF are commented using // so IT MUST HAVE NO INSTRUCTION AFTER A DEBUG_PRINTF OR THEY LL BE COMMENTED\n\n//#define DEBUG_PRINTF\tInfoLog->displayRaw\n#ifdef __GNUC__\n#define DEBUG_PRINTF(format, args...)\n#else // __GNUC__\n#define DEBUG_PRINTF\t// InfoLog->displayRaw\n#endif // __GNUC__\n\n#define YY_NEVER_INTERACTIVE 1\n\n#ifdef WIN32\n#define YY_NO_UNISTD_H 1\n#include <io.h>\n#define read _read\n#define isatty _isatty\n#endif\n\n/* Types */\n\nenum cf_type { T_UNKNOWN, T_INT, T_STRING, T_REAL };\n\nstruct cf_value\n{\n\tcf_type\tType;\n\tint\t\tInt;\n\tdouble\tReal;\n\tchar\tString[1024];\n};\n// use to parse the file, opened by CConfigFile::reparse()\nCMemStream cf_ifile;\n\n#define YY_INPUT(buf,result,max_size) { \\\n\tif (cf_ifile.length() == 0) \\\n\t{ \\\n\t\tDEBUG_PRINTF(\"YY_INPUT: eof\");\\\n\t\tresult = YY_NULL; \\\n\t} else { \\\n\t\tuint32 nbc = std::min((uint32)max_size, (uint32)(cf_ifile.length() - cf_ifile.getPos())); \\\n\t\tDEBUG_PRINTF(\"YY_INPUT: wanted %d bytes, will read %d\\n\", max_size, nbc);\\\n\t\tcf_ifile.serialBuffer ((uint8 *)buf, nbc); \\\n\t\tresult = nbc; \\\n\t} \\\n}\n\n/* special include, need to know cf_value */\n\n#include \"cf_gramatical.h\"\n\n/* Externals */\n\nextern int cf_CurrentLine;\n\n/* Variables */\n\nbool cf_Ignore;\n\nvoid comment ();\n\n%}\n\n%option nounput prefix=\"cf\"\n%option 8bit full\n%pointer\n\nalpha\t\t[A-Za-z]\ndigit\t\t[0-9]\nvariable\t({alpha}|[_])({alpha}|{digit}|[_])*\nnum1\t\t{digit}+\\.([eE][-+]?{digit}+)?\nnum2\t\t{digit}*\\.{digit}+([eE][-+]?{digit}+)?\nreal\t\t{num1}|{num2}\nint\t\t\t{digit}+\nhex\t\t\t0x[0-9a-fA-F]+\nstring\t\t\\\"[^\\\"\\n]*\\\"\n\n%%\n\n\"+\"\t\t\t{ if (!cf_Ignore) return PLUS; }\n\"-\"\t\t\t{ if (!cf_Ignore) return MINUS; }\n\"*\"\t\t\t{ if (!cf_Ignore) return MULT; }\n\"/\"\t\t\t{ if (!cf_Ignore) return DIVIDE; }\n\")\"\t\t\t{ if (!cf_Ignore) return RPAREN; }\n\"(\"\t\t\t{ if (!cf_Ignore) return LPAREN; }\n\"=\"\t\t\t{ if (!cf_Ignore) return ASSIGN; }\n\"+=\"\t\t{ if (!cf_Ignore) return ADD_ASSIGN; }\n\";\"\t\t\t{ if (!cf_Ignore) return SEMICOLON; }\n\"}\"\t\t\t{ if (!cf_Ignore) return RBRACE; }\n\"{\"\t\t\t{ if (!cf_Ignore) return LBRACE; }\n\",\"\t\t\t{ if (!cf_Ignore) return COMMA; }\n\"#fileline\"\t{ if (!cf_Ignore) return FILELINE; }\n\n\n(\\ |\\t)\t\t{ /* ignore tabulation and spaces */; }\n\n\"\\n\"\t\t{\n\t\t\t\t/* ignore new line but count them */\n\t\t\t\tcf_CurrentLine++;\n\t\t\t\tDEBUG_PRINTF(\"*****line++ %d\\n\", cf_CurrentLine);\n\t\t\t}\n\n\"//\"\t\t{ comment(); }\n\n\\/\\*\t\t{ /* Start of a comment */ cf_Ignore = true; }\n\n\\*\\/\t\t{ /* End of a comment */ cf_Ignore = false; }\n\n{string}\t{ /* A string */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_STRING;\n\t\t\t\t\tif (strlen(yytext+1) >= sizeof(cflval.Val.String))\n\t\t\t\t\t{\n\t\t\t\t\t\tstrcpy (cflval.Val.String, \"\");\n\t\t\t\t\t\tDEBUG_PRINTF(\"lex: string '%s' exceeds max length\\n\", yytext);\n\t\t\t\t\t\treturn STRING;\n\t\t\t\t\t}\n\t\t\t\t\tstrcpy (cflval.Val.String, yytext+1);\n\t\t\t\t\tcflval.Val.String[strlen(cflval.Val.String)-1] = '\\0';\n\t\t\t\t\tDEBUG_PRINTF(\"lex: string '%s' '%s'\\n\", yytext, cflval.Val.String);\n\t\t\t\t\treturn STRING;\n\t\t\t\t}\n\t\t\t}\n\n{variable}\t{ /* A variable */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_STRING;\n\t\t\t\t\tif (strlen(yytext+1) >= sizeof(cflval.Val.String))\n\t\t\t\t\t{\n\t\t\t\t\t\tstrcpy (cflval.Val.String, \"\");\n\t\t\t\t\t\tDEBUG_PRINTF(\"lex: string '%s' exceeds max length\\n\", yytext);\n\t\t\t\t\t\treturn VARIABLE;\n\t\t\t\t\t}\n\t\t\t\t\tstrcpy (cflval.Val.String, yytext);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: variable '%s' '%s'\\n\", yytext, cflval.Val.String);\n\t\t\t\t\treturn VARIABLE;\n\t\t\t\t}\n\t\t\t}\n\n{real}\t\t{ /* A real */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_REAL;\n\t\t\t\t\tcflval.Val.Real = atof (yytext);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: real '%s' '%f\\n\", yytext, cflval.Val.Real);\n\t\t\t\t\treturn REAL;\n\t\t\t\t}\n\t\t\t}\n\n{int}\t\t{ /* An int */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_INT;\n\t\t\t\t\tcflval.Val.Int = atoi (yytext);\n\t\t\t\t\tDEBUG_PRINTF(\"lex: int '%s' '%d'\\n\", yytext, cflval.Val.Int);\n\t\t\t\t\treturn INTEGER;\n\t\t\t\t}\n\t\t\t}\n\n{hex}\t\t{ /* An hex int */\n\t\t\t\tif (!cf_Ignore)\n\t\t\t\t{\n\t\t\t\t\tcflval.Val.Type = T_INT;\n\t\t\t\t\tsscanf (yytext, \"%x\", &(cflval.Val.Int));\n\t\t\t\t\tDEBUG_PRINTF(\"lex: hexa '%s' '0x%x' '%d'\\n\", yytext, cflval.Val.Int, cflval.Val.Int);\n\t\t\t\t\treturn INTEGER;\n\t\t\t\t}\n\t\t\t}\n\n%%\n\nint cfwrap()\n{\n\treturn 1;\n}\n\n//\"//\".*\\n\t{ /* ignore one line comment but count the new line */ cf_CurrentLine++; DEBUG_PRINTF(\"*****line++ %d\\n\", cf_CurrentLine); }\nvoid comment ()\n{\n\tint c;\n\n\tdo\n\t{\n\t\tc = yyinput ();\n\t}\n\twhile (c != '\\n' && c != -1);\n\n\tif (c == '\\n')\n\t\tcf_CurrentLine++;\n}\n"
  },
  {
    "path": "code/nel/src/misc/config_file/config_file.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"../stdmisc.h\"\n#include \"nel/misc/config_file.h\"\n\n#include <ctime>\n#include <sys/types.h>\n#include <sys/stat.h>\n\n#include \"nel/misc/file.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/i18n.h\"\n#include \"nel/misc/mem_stream.h\"\n#include \"locale.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\n\nextern void cfrestart (FILE *);\t// used to reinit the file\nextern int cfparse (void *);\t// used to parse the file\n//extern FILE *cfin;\nextern int cf_CurrentLine;\nextern char *cf_CurrentFile;\nextern bool cf_Ignore;\nextern bool cf_OverwriteExistingVariable;\nextern CMemStream cf_ifile;\n\n// put true if you want that the config file class check type when you call asFunctions\n// (for example, check when you call asInt() that the variable is an int).\n// when it's false, the function will convert to the wanted type (if he can)\nconst bool CheckType = false;\nbool LoadRoot = false;\n\nnamespace NLMISC\n{\n\nconst char *CConfigFile::CVar::TypeName[] = { \"Integer\", \"String\", \"Float\", \"Boolean\" };\n\nint CConfigFile::CVar::asInt (int index) const\n{\n\tif (CheckType && Type != T_INT) throw EBadType (Name, Type, T_INT);\n\tswitch (Type)\n\t{\n\tcase T_STRING:\n\t{\n\t\tif (index >= (int)StrValues.size () || index < 0) throw EBadSize (Name, (int)StrValues.size (), index);\n\t\tint ret = 0;\n\t\tNLMISC::fromString(StrValues[index], ret);\n\t\treturn ret;\n\t}\n\tcase T_REAL:\n\t\tif (index >= (int)RealValues.size () || index < 0) throw EBadSize (Name, (int)RealValues.size (), index);\n\t\treturn (int)RealValues[index];\n\tdefault:\n\t\tif (index >= (int)IntValues.size () || index < 0) throw EBadSize (Name, (int)IntValues.size (), index);\n\t\treturn IntValues[index];\n\t}\n}\n\ndouble CConfigFile::CVar::asDouble (int index) const\n{\n\tif (CheckType && Type != T_REAL) throw EBadType (Name, Type, T_REAL);\n\tswitch (Type)\n\t{\n\tcase T_INT:\n\t\tif (index >= (int)IntValues.size () || index < 0) throw EBadSize (Name, (int)IntValues.size (), index);\n\t\treturn (double)IntValues[index];\n\tcase T_STRING:\n\t{\n\t\tif (index >= (int)StrValues.size () || index < 0) throw EBadSize (Name, (int)StrValues.size (), index);\n\t\tdouble val;\n\t\tNLMISC::fromString(StrValues[index], val);\n\t\treturn val;\n\t}\n\tdefault:\n\t\tif (index >= (int)RealValues.size () || index < 0) throw EBadSize (Name, (int)RealValues.size (), index);\n\t\treturn RealValues[index];\n\t}\n}\n\nfloat CConfigFile::CVar::asFloat (int index) const\n{\n\treturn (float) asDouble (index);\n}\n\nstd::string CConfigFile::CVar::asString (int index) const\n{\n\tif (CheckType && Type != T_STRING) throw EBadType (Name, Type, T_STRING);\n\tswitch (Type)\n\t{\n\tcase T_INT:\n\t\tif (index >= (int)IntValues.size () || index < 0) throw EBadSize (Name, (int)IntValues.size (), index);\n\t\treturn toString(IntValues[index]);\n\tcase T_REAL:\n\t\tif (index >= (int)RealValues.size () || index < 0) throw EBadSize (Name, (int)RealValues.size (), index);\n\t\treturn toString(RealValues[index]);\n\tdefault:\n\t\tif (index >= (int)StrValues.size () || index < 0) throw EBadSize (Name, (int)StrValues.size (), index);\n\t\treturn StrValues[index];\n\t}\n}\n\nbool CConfigFile::CVar::asBool (int index) const\n{\n\tswitch (Type)\n\t{\n\tcase T_STRING:\n\t\tif (index >= (int)StrValues.size () || index < 0) throw EBadSize (Name, (int)StrValues.size (), index);\n\t\tif(StrValues[index] == \"true\")\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\tcase T_REAL:\n\t\tif (index >= (int)RealValues.size () || index < 0) throw EBadSize (Name, (int)RealValues.size (), index);\n\t\tif ((int)RealValues[index] == 1)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\tdefault:\n\t\tif (index >= (int)IntValues.size () || index < 0) throw EBadSize (Name, (int)IntValues.size (), index);\n\t\tif (IntValues[index] == 1)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\nvoid CConfigFile::CVar::setAsInt (int val, int index)\n{\n\tif (Type != T_INT) throw EBadType (Name, Type, T_INT);\n\telse if (index > (int)IntValues.size () || index < 0) throw EBadSize (Name, (int)IntValues.size (), index);\n\telse if (index == (int)IntValues.size ()) IntValues.push_back(val);\n\telse IntValues[index] = val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsDouble (double val, int index)\n{\n\tif (Type != T_REAL) throw EBadType (Name, Type, T_REAL);\n\telse if (index > (int)RealValues.size () || index < 0) throw EBadSize (Name, (int)RealValues.size (), index);\n\telse if (index == (int)RealValues.size ()) RealValues.push_back(val);\n\telse RealValues[index] = val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsFloat (float val, int index)\n{\n\tsetAsDouble (val, index);\n}\n\nvoid CConfigFile::CVar::setAsString (const std::string &val, int index)\n{\n\tif (Type != T_STRING) throw EBadType (Name, Type, T_STRING);\n\telse if (index > (int)StrValues.size () || index < 0) throw EBadSize (Name, (int)StrValues.size (), index);\n\telse if (index == (int)StrValues.size ()) StrValues.push_back(val);\n\telse StrValues[index] = val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::forceAsInt\t(int val)\n{\n\tType= T_INT;\n\tIntValues.resize(1);\n\tRealValues.clear();\n\tStrValues.clear();\n\tIntValues[0]= val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::forceAsDouble\t(double val)\n{\n\tType= T_REAL;\n\tIntValues.clear();\n\tRealValues.resize(1);\n\tStrValues.clear();\n\tRealValues[0]= val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::forceAsString\t(const std::string &val)\n{\n\tType= T_STRING;\n\tIntValues.clear();\n\tRealValues.clear();\n\tStrValues.resize(1);\n\tStrValues[0]= val;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsInt (const std::vector<int> &vals)\n{\n\tif (Type != T_INT) throw EBadType (Name, Type, T_INT);\n\telse IntValues = vals;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsDouble (const std::vector<double> &vals)\n{\n\tif (Type != T_REAL) throw EBadType (Name, Type, T_REAL);\n\telse RealValues = vals;\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsFloat (const std::vector<float> &vals)\n{\n\tif (Type != T_REAL) throw EBadType (Name, Type, T_REAL);\n\telse\n\t{\n\t\tRealValues.clear ();\n\t\tRealValues.resize (vals.size ());\n\t\tfor (uint i = 0; i < vals.size (); i++)\n\t\t\tRealValues[i] = (double)vals[i];\n\t}\n\tRoot = false;\n}\n\nvoid CConfigFile::CVar::setAsString (const std::vector<std::string> &vals)\n{\n\tif (Type != T_STRING) throw EBadType (Name, Type, T_STRING);\n\telse StrValues = vals;\n\tRoot = false;\n}\n\nbool CConfigFile::CVar::operator==\t(const CVar& var) const\n{\n\tif (Type == var.Type)\n\t{\n\t\tswitch (Type)\n\t\t{\n\t\tcase T_INT: return IntValues == var.IntValues; break;\n\t\tcase T_REAL: return RealValues == var.RealValues; break;\n\t\tcase T_STRING: return StrValues == var.StrValues; break;\n\t\tdefault: break;\n\t\t}\n\t}\n\treturn false;\n}\n\nbool CConfigFile::CVar::operator!=\t(const CVar& var) const\n{\n\treturn !(*this==var);\n}\n\nvoid CConfigFile::CVar::add (const CVar &var)\n{\n\tif (Type == var.Type)\n\t{\n\t\tswitch (Type)\n\t\t{\n\t\tcase T_INT: IntValues.insert (IntValues.end(), var.IntValues.begin(), var.IntValues.end()); break;\n\t\tcase T_REAL: RealValues.insert (RealValues.end(), var.RealValues.begin(), var.RealValues.end()); break;\n\t\tcase T_STRING: StrValues.insert (StrValues.end(), var.StrValues.begin(), var.StrValues.end()); break;\n\t\tdefault: break;\n\t\t}\n\t}\n}\n\nuint CConfigFile::CVar::size () const\n{\n\tswitch (Type)\n\t{\n\tcase T_INT: return (uint)IntValues.size ();\n\tcase T_REAL: return (uint)RealValues.size ();\n\tcase T_STRING: return (uint)StrValues.size ();\n\tdefault: return 0;\n\t}\n}\n\nCConfigFile::~CConfigFile ()\n{\n\tif (_ConfigFiles == NULL || (*_ConfigFiles).empty ()) return;\n\n\tvector<CConfigFile *>::iterator it = find ((*_ConfigFiles).begin (), (*_ConfigFiles).end (), this);\n\tif (it != (*_ConfigFiles).end ())\n\t{\n\t\t(*_ConfigFiles).erase (it);\n\t}\n\n\tif ((*_ConfigFiles).empty())\n\t{\n\t\tdelete _ConfigFiles;\n\t\t_ConfigFiles = NULL;\n\t}\n}\n\nvoid CConfigFile::load (const string &fileName, bool lookupPaths )\n{\n\tif(fileName.empty())\n\t{\n\t\tnlwarning (\"CF: Can't load a empty file name configfile\");\n\t\treturn;\n\t}\n\n\tFileNames.clear ();\n\tFileNames.push_back (fileName);\n\n\tif (_ConfigFiles == NULL)\n\t{\n\t\t_ConfigFiles = new std::vector<CConfigFile *>;\n\t}\n\t(*CConfigFile::_ConfigFiles).push_back (this);\n\treparse (lookupPaths);\n\n/* \t_FileName.clear ();\n\t_FileName.push_back (fileName);\n\n\tif (_ConfigFiles == NULL)\n\t{\n\t\t_ConfigFiles = new std::vector<CConfigFile *>;\n\t}\n\t(*CConfigFile::_ConfigFiles).push_back (this);\n\treparse ();\n\n\t// If we find a linked config file, load it but don't overload already existing variable\n\tCVar *var = getVarPtr (\"RootConfigFilename\");\n\tif (var)\n\t{\n\t\tstring RootConfigFilename = var->asString();\n\t\tnlinfo (\"RootConfigFilename variable found in the '%s' config file, parse it (%s)\", fileName.c_str(), RootConfigFilename.c_str());\n\n\t\tstring path = CFile::getPath(fileName);\n\n\t\tif (!path.empty())\n\t\t\tpath +=  \"/\";\n\n\t\tpath += RootConfigFilename;\n\n\t\treparse (path.c_str());\n\t}\n*/\n//\tprint ();\n}\n\nbool CConfigFile::loaded()\n{\n\treturn !CConfigFile::FileNames.empty();\n}\n\nuint32 CConfigFile::getVarCount()\n{\n\treturn (uint32)_Vars.size();\n}\n\n\nvoid CConfigFile::reparse (bool lookupPaths)\n{\n\tif (FileNames.empty())\n\t{\n\t\tnlwarning (\"CF: Can't reparse config file because file name is empty\");\n\t\treturn;\n\t}\n\n\tstring fn = FileNames[0];\n\n\tFileNames.clear ();\n\tLastModified.clear ();\n\n//\tclearVars ();\n\n\twhile (!fn.empty())\n\t{\n\t\tif (lookupPaths)\n\t\t{\n\t\t\tfn = CPath::lookup(fn, true);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfn = NLMISC::CPath::getFullPath(fn, false);\n\t\t}\n\t\tnldebug (\"CF: Adding config file '%s' in the config file\", fn.c_str());\n\t\tFileNames.push_back (fn);\n\t\tLastModified.push_back (CFile::getFileModificationDate(fn));\n\n\t\tif (!CPath::lookup(fn, false).empty())\n\t\t{\n\t\t\tucstring content;\n\t\t\tCI18N::readTextFile(fn, content, true, true, true);\n\t\t\tstring utf8 = content.toUtf8();\n\n\t\t\tCMemStream stream;\n\t\t\tstream.serialBuffer((uint8*)(utf8.data()), (uint)utf8.size());\n\t\t\tcf_ifile = stream;\n\t\t\tif (!cf_ifile.isReading())\n\t\t\t{\n\t\t\t\tcf_ifile.invert();\n\t\t\t}\n\n\t\t\tcfrestart (NULL);\n\t\t\tcf_CurrentLine = 0;\n\t\t\tcf_CurrentFile = NULL;\n\t\t\tcf_Ignore = false;\n\t\t\tcf_OverwriteExistingVariable = (FileNames.size()==1);\n\t\t\tLoadRoot = (FileNames.size()>1);\n\t\t\tbool parsingOK = (cfparse (&(_Vars)) == 0);\n//\t\t\tcf_ifile.close();\n\t\t\tif (!parsingOK)\n\t\t\t{\n\t\t\t\t// write the result of preprocessing in a temp file\n\t\t\t\tstring debugFileName;\n\t\t\t\tdebugFileName += \"debug_\";\n\t\t\t\tdebugFileName += CFile::getFilename(fn);\n\n\t\t\t\tCI18N::writeTextFile(debugFileName, content, true);\n\t\t\t\tnlwarning (\"CF: Parsing error in file %s line %d, look in '%s' for a preprocessed version of the config file\",\n\t\t\t\t\tcf_CurrentFile,\n\t\t\t\t\tcf_CurrentLine,\n\t\t\t\t\tdebugFileName.c_str());\n\t\t\t\tthrow EParseError (fn, cf_CurrentLine);\n\t\t\t}\n\n\t\t\tif (cf_CurrentFile != NULL)\n\t\t\t\tfree(cf_CurrentFile);\n\n\t\t\t// reset all 'FromLocalFile' flag on created vars before reading next root cfg\n\t\t\tfor (uint i=0; i<_Vars.size(); ++i)\n\t\t\t{\n\t\t\t\t_Vars[i].FromLocalFile = false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"CF: Config file '%s' not found in the path '%s'\", fn.c_str(), CPath::getCurrentPath().c_str());\n\t\t\tthrow EFileNotFound (fn);\n\t\t}\n//\t\tcf_ifile.close ();\n\t\tcf_ifile.clear();\n\n\t\t// If we find a linked config file, load it but don't overload already existing variable\n\t\tCVar *var = getVarPtr (\"RootConfigFilename\");\n\t\tif (var)\n\t\t{\n\t\t\tstring RootConfigFilename = var->asString();\n\n\t\t\tif (!NLMISC::CFile::fileExists(RootConfigFilename))\n\t\t\t{\n\t\t\t\t// file is not found, try with the path of the master cfg\n\t\t\t\tstring path = NLMISC::CPath::standardizePath (NLMISC::CFile::getPath(FileNames[0]));\n\t\t\t\tRootConfigFilename = path + RootConfigFilename;\n\t\t\t}\n\n\t\t\tRootConfigFilename = NLMISC::CPath::getFullPath(RootConfigFilename, false);\n\n\t\t\tif (RootConfigFilename != fn)\n\t\t\t{\n\t\t\t\tnlinfo (\"CF: RootConfigFilename variable found in the '%s' config file, parse the root config file '%s'\", fn.c_str(), RootConfigFilename.c_str());\n\t\t\t\tfn = RootConfigFilename;\n\t\t\t}\n\t\t\telse\n\t\t\t\tfn.clear ();\n\t\t}\n\t\telse\n\t\t\tfn.clear ();\n\t}\n\n\tif (_Callback != NULL)\n\t\t_Callback();\n\n/*\tif (filename == NULL)\n\t{\n\t\t_LastModified = getLastModified ();\n\n\t\tnlassert (!_FileName.empty());\n\n\t\tif (cf_ifile.open (_FileName[0]))\n\t\t{\n\t\t\t// if we clear all the array, we'll lost the callback on variable and all information\n\t\t\t//\t\t_Vars.clear();\n\t\t\tcfrestart (NULL);\n\t\t\tcf_CurrentLine = 1;\n\t\t\tcf_Ignore = false;\n\t\t\tcf_OverwriteExistingVariable = true;\n\t\t\tLoadRoot = false;\n\t\t\tbool parsingOK = (cfparse (&(_Vars)) == 0);\n\t\t\tcf_ifile.close();\n\t\t\tif (!parsingOK)\n\t\t\t{\n\t\t\t\tnlwarning (\"Parsing error in file %s line %d\", _FileName.c_str(), cf_CurrentLine);\n\t\t\t\tthrow EParseError (_FileName, cf_CurrentLine);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"ConfigFile '%s' not found in the path '%s'\", _FileName.c_str(), CPath::getCurrentPath().c_str());\n\t\t\tthrow EFileNotFound (_FileName);\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlassert (strlen(filename)>0);\n\n\t\t// load external config filename, don't overwrite existing variable\n\t\tif (cf_ifile.open (filename))\n\t\t{\n\t\t\tcfrestart (NULL);\n\t\t\tcf_CurrentLine = 1;\n\t\t\tcf_Ignore = false;\n\t\t\tcf_OverwriteExistingVariable = false;\n\t\t\tLoadRoot = true;\n\t\t\tbool parsingOK = (cfparse (&(_Vars)) == 0);\n\t\t\tcf_ifile.close ();\n\t\t\tif (!parsingOK)\n\t\t\t{\n\t\t\t\tnlwarning (\"Parsing error in file %s line %d\", filename, cf_CurrentLine);\n\t\t\t\tthrow EParseError (filename, cf_CurrentLine);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"RootConfigFilename '%s' not found\", _FileName.c_str());\n\t\t}\n\t}\n\n\tif (callingCallback)\n\t{\n\t\tif (_Callback != NULL)\n\t\t\t_Callback();\n\t}\n*/\n\n}\n\n\n\nCConfigFile::CVar &CConfigFile::getVar (const std::string &varName)\n{\n\tCVar *var =  getVarPtr (varName);\n\tif (var == 0)\n\t\tthrow EUnknownVar (getFilename(), varName);\n\telse\n\t\treturn *var;\n}\n\n\nCConfigFile::CVar *CConfigFile::getVarPtr (const std::string &varName)\n{\n\tuint i;\n\tfor (i = 0; i < _Vars.size(); i++)\n\t{\n\t\t// the type could be T_UNKNOWN if we add a callback on this name but this var is not in the config file\n\t\tif (_Vars[i].Name == varName && (_Vars[i].Type != CVar::T_UNKNOWN || _Vars[i].Comp))\n\t\t\treturn &(_Vars[i]);\n\t}\n\n\t// if not found, add it in the array if necessary\n\tfor (i = 0; i < UnknownVariables.size(); i++)\n\t\tif(UnknownVariables[i] == varName)\n\t\t\tbreak;\n\tif (i == UnknownVariables.size())\n\t\tUnknownVariables.push_back(varName);\n\n\treturn NULL;\n}\n\nbool CConfigFile::exists (const std::string &varName)\n{\n\tfor (uint i = 0; i < _Vars.size(); i++)\n\t{\n\t\t// the type could be T_UNKNOWN if we add a callback on this name but this var is not in the config file\n\t\tif (_Vars[i].Name == varName && (_Vars[i].Type != CVar::T_UNKNOWN || _Vars[i].Comp))\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid CConfigFile::save () const\n{\n\t// Avoid any problem, Force Locale to default\n\tsetlocale(LC_ALL, \"C\");\n\n\tFILE *fp = fopen (getFilename().c_str (), \"w\");\n\tif (fp == NULL)\n\t{\n\t\tnlwarning (\"CF: Couldn't create %s file\", getFilename().c_str ());\n\t\treturn;\n\t}\n\n\t// write the UTF-8 bom in order to be able to re-read a config file with \n\t// unicode content.\n\t/* ace: we need to test this before commit it\n\tstatic char utf8Header[] = {char(0xef), char(0xbb), char(0xbf), 0};\n\tfprintf(fp, utf8Header);\n\t*/\n\n\tfor(int i = 0; i < (int)_Vars.size(); i++)\n\t{\n\t\t// Not a root value\n\t\tif (!_Vars[i].Root)\n\t\t{\n\t\t\tif (_Vars[i].Comp)\n\t\t\t{\n\t\t\t\tfprintf(fp, \"%-20s = {\", _Vars[i].Name.c_str());\n\t\t\t\tswitch (_Vars[i].Type)\n\t\t\t\t{\n\t\t\t\tcase CConfigFile::CVar::T_INT:\n\t\t\t\t{\n\t\t\t\t\tfor (int it=0; it < (int)_Vars[i].IntValues.size(); it++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (it%_Vars[i].SaveWrap == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfprintf(fp, \"\\n\\t\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfprintf(fp, \"%d%s\", _Vars[i].IntValues[it], it<(int)_Vars[i].IntValues.size()-1?\", \":\" \");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CConfigFile::CVar::T_STRING:\n\t\t\t\t{\n\t\t\t\t\tfor (int st=0; st < (int)_Vars[i].StrValues.size(); st++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (st%_Vars[i].SaveWrap == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfprintf(fp, \"\\n\\t\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfprintf(fp, \"\\\"%s\\\"%s\", _Vars[i].StrValues[st].c_str(), st<(int)_Vars[i].StrValues.size()-1?\", \":\" \");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CConfigFile::CVar::T_REAL:\n\t\t\t\t{\n\t\t\t\t\tfor (int rt=0; rt < (int)_Vars[i].RealValues.size(); rt++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (rt%_Vars[i].SaveWrap == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfprintf(fp, \"\\n\\t\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfprintf(fp, \"%.10f%s\", _Vars[i].RealValues[rt], rt<(int)_Vars[i].RealValues.size()-1?\", \":\" \");\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault: break;\n\t\t\t\t}\n\t\t\t\tfprintf(fp, \"\\n};\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (_Vars[i].Type)\n\t\t\t\t{\n\t\t\t\tcase CConfigFile::CVar::T_INT:\n\t\t\t\t\tfprintf(fp, \"%-20s = %d;\\n\", _Vars[i].Name.c_str(), _Vars[i].IntValues[0]);\n\t\t\t\t\tbreak;\n\t\t\t\tcase CConfigFile::CVar::T_STRING:\n\t\t\t\t\tfprintf(fp, \"%-20s = \\\"%s\\\";\\n\", _Vars[i].Name.c_str(), _Vars[i].StrValues[0].c_str());\n\t\t\t\t\tbreak;\n\t\t\t\tcase CConfigFile::CVar::T_REAL:\n\t\t\t\t\tfprintf(fp, \"%-20s = %.10f;\\n\", _Vars[i].Name.c_str(), _Vars[i].RealValues[0]);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault: break;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tfclose (fp);\n}\n\nvoid CConfigFile::display () const\n{\n\tdisplay (InfoLog);\n}\n\nvoid CConfigFile::display (CLog *log) const\n{\n\tcreateDebug ();\n\n\tlog->displayRawNL (\"Config file %s have %d variables and %d root config file:\", getFilename().c_str(), _Vars.size(), FileNames.size()-1);\n\tlog->displayRaw (\"Root config files: \");\n\tfor(int i = 1; i < (int)FileNames.size(); i++)\n\t{\n\t\tlog->displayRaw (FileNames[i].c_str());\n\t}\n\tlog->displayRawNL (\"\");\n\tlog->displayRawNL (\"------------------------------------------------------\");\n\tfor(int i = 0; i < (int)_Vars.size(); i++)\n\t{\n\t\tlog->displayRaw ((_Vars[i].Callback==NULL)?\"   \":\"CB \");\n\t\tlog->displayRaw ((_Vars[i].Root)?\"Root \":\"     \");\n\t\tif (_Vars[i].Comp)\n\t\t{\n\t\t\tswitch (_Vars[i].Type)\n\t\t\t{\n\t\t\tcase CConfigFile::CVar::T_INT:\n\t\t\t{\n\t\t\t\tlog->displayRaw (\"%-20s { \", _Vars[i].Name.c_str());\n\t\t\t\tfor (int it=0; it < (int)_Vars[i].IntValues.size(); it++)\n\t\t\t\t{\n\t\t\t\t\tlog->displayRaw (\"'%d' \", _Vars[i].IntValues[it]);\n\t\t\t\t}\n\t\t\t\tlog->displayRawNL (\"}\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CConfigFile::CVar::T_STRING:\n\t\t\t{\n\t\t\t\tlog->displayRaw (\"%-20s { \", _Vars[i].Name.c_str());\n\t\t\t\tfor (int st=0; st < (int)_Vars[i].StrValues.size(); st++)\n\t\t\t\t{\n\t\t\t\t\tlog->displayRaw (\"\\\"%s\\\" \", _Vars[i].StrValues[st].c_str());\n\t\t\t\t}\n\t\t\t\tlog->displayRawNL (\"}\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CConfigFile::CVar::T_REAL:\n\t\t\t{\n\t\t\t\tlog->displayRaw (\"%-20s { \" , _Vars[i].Name.c_str());\n\t\t\t\tfor (int rt=0; rt < (int)_Vars[i].RealValues.size(); rt++)\n\t\t\t\t{\n\t\t\t\t\tlog->displayRaw (\"`%f` \", _Vars[i].RealValues[rt]);\n\t\t\t\t}\n\t\t\t\tlog->displayRawNL (\"}\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CConfigFile::CVar::T_UNKNOWN:\n\t\t\t{\n\t\t\t\t log->displayRawNL (\"%-20s { }\" , _Vars[i].Name.c_str());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tlog->displayRawNL (\"%-20s <default case comp> (%d)\" , _Vars[i].Name.c_str(), _Vars[i].Type);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (_Vars[i].Type)\n\t\t\t{\n\t\t\tcase CConfigFile::CVar::T_INT:\n\t\t\t\tlog->displayRawNL (\"%-20s '%d'\", _Vars[i].Name.c_str(), _Vars[i].IntValues[0]);\n\t\t\t\tbreak;\n\t\t\tcase CConfigFile::CVar::T_STRING:\n\t\t\t\tlog->displayRawNL (\"%-20s \\\"%s\\\"\", _Vars[i].Name.c_str(), _Vars[i].StrValues[0].c_str());\n\t\t\t\tbreak;\n\t\t\tcase CConfigFile::CVar::T_REAL:\n\t\t\t\tlog->displayRawNL (\"%-20s `%f`\", _Vars[i].Name.c_str(), _Vars[i].RealValues[0]);\n\t\t\t\tbreak;\n\t\t\tcase CConfigFile::CVar::T_UNKNOWN:\n\t\t\t\tlog->displayRawNL (\"%-20s <Unknown>\", _Vars[i].Name.c_str());\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tlog->displayRawNL (\"%-20s <default case> (%d)\" , _Vars[i].Name.c_str(), _Vars[i].Type);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CConfigFile::setCallback (void (*cb)())\n{\n\t_Callback = cb;\n\tif( !FileNames.empty() )\n\t\tnlinfo (\"CF: Setting callback to reload the file '%s' when modified externally\", getFilename().c_str());\n}\n\nvoid CConfigFile::setCallback (const string &VarName, void (*cb)(CConfigFile::CVar &var))\n{\n\tfor (vector<CVar>::iterator it = _Vars.begin (); it != _Vars.end (); it++)\n\t{\n\t\tif (VarName == (*it).Name)\n\t\t{\n\t\t\t(*it).Callback = cb;\n\t\t\t//nldebug(\"CF: Setting callback to reload the variable '%s' in the file '%s' when modified externally\", VarName.c_str(), getFilename().c_str());\n\t\t\treturn;\n\t\t}\n\t}\n\t// VarName doesn't exist, add it now for the future\n\tCVar Var;\n\tVar.Name = VarName;\n\tVar.Callback = cb;\n\tVar.Type = CVar::T_UNKNOWN;\n\tVar.Comp = false;\n\t_Vars.push_back (Var);\n\t//nldebug(\"CF: Setting callback to reload the variable '%s' in the file '%s' when modified externally (currently unknown)\", VarName.c_str(), getFilename().c_str());\n}\n\n// ***************************************************************************\n\n\nvector<CConfigFile *> *CConfigFile::_ConfigFiles = NULL;\n\nuint32\tCConfigFile::_Timeout = 1000;\n\nvoid CConfigFile::checkConfigFiles ()\n{\n\tif (_ConfigFiles == NULL) return;\n\n\tstatic time_t LastCheckTime = time (NULL);\n\tif (_Timeout > 0 && (float)(time (NULL) - LastCheckTime)*1000.0f < (float)_Timeout) return;\n\n\tLastCheckTime = time (NULL);\n\n\tbool needReparse;\n\tfor (vector<CConfigFile *>::iterator it = (*_ConfigFiles).begin (); it != (*_ConfigFiles).end (); it++)\n\t{\n\t\tneedReparse = false;\n\t\tnlassert ((*it)->FileNames.size() == (*it)->LastModified.size());\n\t\tfor (uint i = 0; i < (*it)->FileNames.size(); i++)\n\t\t{\n\t\t\tif ((*it)->LastModified[i] != CFile::getFileModificationDate((*it)->FileNames[i]))\n\t\t\t{\n\t\t\t\tneedReparse = true;\n\t\t\t\t(*it)->LastModified[i] = CFile::getFileModificationDate((*it)->FileNames[i]);\n\t\t\t}\n\t\t}\n\t\tif (needReparse)\n\t\t{\n\t\t\ttry\n\t\t\t{\n\t\t\t\t(*it)->reparse ();\n\t\t\t}\n\t\t\tcatch (const EConfigFile &e)\n\t\t\t{\n\t\t\t\tnlwarning (\"CF: Exception will re-read modified config file '%s': %s\", (*it)->getFilename().c_str(), e.what ());\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CConfigFile::setTimeout (uint32 timeout)\n{\n\t_Timeout = timeout;\n}\n\nvoid CConfigFile::clear()\n{\n\t_Vars.clear ();\n}\n\nvoid CConfigFile::clearVars ()\n{\n\tfor (vector<CVar>::iterator it = _Vars.begin (); it != _Vars.end (); it++)\n\t{\n\t\t(*it).Type = CVar::T_UNKNOWN;\n\t}\n}\n\nuint CConfigFile::getNumVar () const\n{\n\treturn (uint)_Vars.size ();\n}\n\nCConfigFile::CVar *CConfigFile::getVar (uint varId)\n{\n\treturn &(_Vars[varId]);\n}\n\nCConfigFile::CVar *CConfigFile::insertVar (const std::string &varName, const CVar &varToCopy)\n{\n\t// Get the var\n\tCVar *var = getVarPtr (varName);\n\tif (!var)\n\t{\n\t\t_Vars.push_back (varToCopy);\n\t\tvar = &(_Vars.back ());\n\t\tvar->Root = false;\n\t\tvar->Name = varName;\n\t}\n\treturn var;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/config_file/do.bat",
    "content": "@echo off\necho Generating cf_lexical.cpp\nflex -f -8 -Pcf -Scf_flex.skl -ocf_lexical.cpp cf_lexical.lpp\n\necho Generating cf_gramatical.cpp\nset BISON_SIMPLE=cf_bison.simple\nbison -d -p cf -o cf_gramatical.cpp cf_gramatical.ypp\nmove cf_gramatical.hpp cf_gramatical.h\npause\n"
  },
  {
    "path": "code/nel/src/misc/contiguous_block_allocator.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/contiguous_block_allocator.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// *********************************************************************************************************\nCContiguousBlockAllocator::CContiguousBlockAllocator()\n{\n\t_BlockStart = NULL;\n\t_NextAvailablePos = NULL;\n\t_BlockEnd = 0;\n\t_NumAllocatedBytes = 0;\n\t#ifdef NL_DEBUG\n\t\t_NumAlloc = 0;\n\t\t_NumFree = 0;\n\t#endif\n}\n\n// *********************************************************************************************************\nCContiguousBlockAllocator::~CContiguousBlockAllocator()\n{\n\tinit(0);\n}\n\n// *********************************************************************************************************\nvoid CContiguousBlockAllocator::init(uint numBytes /*=0*/)\n{\n\tif (_BlockStart) _DefaultAlloc.deallocate(_BlockStart, _BlockEnd - _BlockStart);\n\t_BlockEnd =  NULL;\n\t_BlockStart = NULL;\n\t_NumAllocatedBytes = 0;\n\t_NextAvailablePos = NULL;\n\tif (numBytes != 0)\n\t{\n\t\t_BlockStart = _DefaultAlloc.allocate(numBytes);\n\t\t_NextAvailablePos = _BlockStart;\n\t\t_BlockEnd = _BlockStart + numBytes;\n\t\t_NumAllocatedBytes = 0;\n\t}\n\t#ifdef NL_DEBUG\n\t\t_NumAlloc = 0;\n\t\t_NumFree = 0;\n\t#endif\n}\n\n// *********************************************************************************************************\nvoid *CContiguousBlockAllocator::alloc(uint numBytes)\n{\n\tif (numBytes == 0) return NULL;\n\t_NumAllocatedBytes += numBytes;\n\tif (_BlockStart)\n\t{\n\t\tif (_NextAvailablePos + numBytes <= _BlockEnd)\n\t\t{\n\t\t\tuint8 *block = _NextAvailablePos;\n\t\t\t_NextAvailablePos += numBytes;\n\t\t\t#ifdef NL_DEBUG\n\t\t\t\t++ _NumAlloc;\n\t\t\t#endif\n\t\t\treturn block;\n\t\t}\n\t}\n\t// just uses standard new\n\t#ifdef NL_DEBUG\n\t\t++ _NumAlloc;\n\t#endif\n\treturn _DefaultAlloc.allocate(numBytes);\n}\n\n// *********************************************************************************************************\nvoid CContiguousBlockAllocator::free(void *block, uint numBytes)\n{\n\tif (!block) return;\n\t#ifdef NL_DEBUG\n\t\t++ _NumFree;\n\t#endif\n\t// no-op if block not inside the big block (sub-block are never deallocated until init(0) is encountered)\n\tif (block < _BlockStart || block >= _BlockEnd)\n\t{\n\t\t// the block was allocated with std allocator\n\t\t_DefaultAlloc.deallocate((uint8 *) block, numBytes);\n\t}\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/cpu_time_stat.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/cpu_time_stat.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef NL_OS_UNIX\n#include <unistd.h>\n#else\n#include <process.h>\n#endif\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n#ifdef NL_OS_FREEBSD\n#define PROC_BASE_PATH \"/usr/compat/linux/proc\"\n#elif defined(NL_OS_UNIX)\n#define PROC_BASE_PATH \"/proc\"\n#endif\n\n// Get absolute ticks value for the whole cpu set\nbool\tCCPUTimeStat::getCPUTicks(uint64& user, uint64& nice, uint64& system, uint64& idle, uint64& iowait)\n{\n#ifdef NL_OS_UNIX\n\n\tconst char*\tstatfile = PROC_BASE_PATH\"/stat\";\n\tFILE*\t\tf = fopen(statfile, \"r\");\n\n\tif (f == NULL)\n\t\treturn false;\n\n\t// /proc/stat\n\t\t\t// cpu  [user]     [nice]    [system]    [idle]     [iowait]   [irq] [softirq]\n#ifdef NL_OS_FREEBSD\n    iowait=0;\n    if (fscanf(f, \"cpu %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u\", &user, &nice, &system, &idle) != 4)\n#else\n    if (fscanf(f, \"cpu  %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u\", &user, &nice, &system, &idle, &iowait) != 5)\n#endif\n    {\n       nlwarning(\"Failed to parse \" PROC_BASE_PATH \"/stat\");\n    }\n\n\tfclose(f);\n\n\treturn true;\n#else\n\treturn false;\n#endif\n}\n\n// Get absolute ticks values for a specified pid\nbool\tCCPUTimeStat::getPIDTicks(uint64& utime, uint64& stime, uint64& cutime, uint64& cstime, uint pid)\n{\n#ifdef NL_OS_UNIX\n\n\tstd::string\tstatfile = NLMISC::toString(PROC_BASE_PATH\"/%u/stat\", pid);\n\tFILE*\tf = fopen(statfile.c_str(), \"r\");\n\n\tif (f == NULL)\n\t\treturn false;\n\n\t// /proc/<pid>/stat\n\t\t\t// pid com sta ppi pgi ses tty tpg fla mif maf cmi cma [utime]    [stime]    [cutime]   [cstime] ...\n\tif (fscanf(f, \"%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u %\" NL_I64 \"u\", &utime, &stime, &cutime, &cstime) != 4)\n\t\tnlwarning(\"Failed to parse \" PROC_BASE_PATH \"/<pid>/stat\");\n\n\tfclose(f);\n\n\treturn true;\n#else\n\tutime = 0;\n\tstime = 0;\n\tcutime = 0;\n\tcstime = 0;\n\tnlunreferenced(pid);\n\treturn false;\n#endif\n}\n\nCCPUTimeStat::CCPUTimeStat() :  _PID(0), _FirstTime(true), _LastCPUTicks(0), _LastPIDTicks(0)\n{\n#ifdef NL_OS_UNIX\n\n\t_PID = getpid();\n\n#else\n\n\t_PID = _getpid();\n\n#endif\n\n}\n\n\n// Peek measure\nvoid\tCCPUTimeStat::peekMeasures()\n{\n\tNLMISC::TTime\tctime = NLMISC::CTime::getLocalTime();\n\n\tuint64\tu, n, s, i, io;\n\tuint64\tut, st, cut, cst;\n\tif (getCPUTicks(u, n, s, i, io) && getPIDTicks(ut, st, cut, cst, _PID))\n\t{\n\t\tuint64\tcpuTicks = u+n+s+i+io;\n\t\tuint64\tpidTicks = ut+st+cut+cst;\n\n\t\t// only compute diff\n\t\tif (_LastCPUTicks == cpuTicks || _LastPIDTicks == pidTicks)\n\t\t\treturn;\n\n\t\t_LastCPUTicks = cpuTicks;\n\t\t_CPUUser.computeDiff(u);\n\t\t_CPUNice.computeDiff(n);\n\t\t_CPUSystem.computeDiff(s);\n\t\t_CPUIdle.computeDiff(i);\n\t\t_CPUIOWait.computeDiff(io);\n\n\t\t_LastPIDTicks = pidTicks;\n\t\t_PIDUTime.computeDiff(ut);\n\t\t_PIDSTime.computeDiff(st);\n\t\t_PIDCUTime.computeDiff(cut);\n\t\t_PIDCSTime.computeDiff(cst);\n\n\t\tif (!_FirstTime)\n\t\t{\n\t\t\tuint32\tcpuTotal = _CPUUser.Diff+_CPUNice.Diff+_CPUSystem.Diff+_CPUIdle.Diff+_CPUIOWait.Diff;\n\n\t\t\t_CPUUser.computeLoad(cpuTotal, ctime);\n\t\t\t_CPUNice.computeLoad(cpuTotal, ctime);\n\t\t\t_CPUSystem.computeLoad(cpuTotal, ctime);\n\t\t\t_CPUIdle.computeLoad(cpuTotal, ctime);\n\t\t\t_CPUIOWait.computeLoad(cpuTotal, ctime);\n\n\t\t\tuint32\tpidTotal = _PIDUTime.Diff+_PIDSTime.Diff+_PIDCUTime.Diff+_PIDCSTime.Diff;\n\t\t\tif (pidTotal > cpuTotal)\n\t\t\t{\n\t\t\t\t// EEK! should not happen!!\n\t\t\t\tcpuTotal = pidTotal;\n\t\t\t}\n\n\t\t\t_PIDUTime.computeLoad(cpuTotal, ctime);\n\t\t\t_PIDSTime.computeLoad(cpuTotal, ctime);\n\t\t\t_PIDCUTime.computeLoad(cpuTotal, ctime);\n\t\t\t_PIDCSTime.computeLoad(cpuTotal, ctime);\n\t\t}\n\n\t\t_FirstTime = false;\n\t}\n}\n\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/debug.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <direct.h>\n#\tinclude <tchar.h>\n#\tinclude <imagehlp.h>\n#\tpragma comment(lib, \"imagehlp.lib\")\n#\tdefine getcwd(_a, _b) (_getcwd(_a,_b))\n#\tifdef NL_OS_WIN64\n#\t\tdefine DWORD_TYPE DWORD64\n#\telse\n#\t\tdefine DWORD_TYPE DWORD\n#\tendif // NL_OS_WIN64\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tdefine IsDebuggerPresent() false\n#   ifndef NL_OS_MAC\n#\t    include <execinfo.h>\n#   endif\n//#\tinclude <malloc.h>\n#\tinclude <errno.h>\n#endif\n\n#include \"nel/misc/debug.h\"\n\n#ifdef HAVE_NELCONFIG_H\n#  include \"nelconfig.h\"\n#endif // HAVE_NELCONFIG_H\n\n#include \"nel/misc/log.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/mem_displayer.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/report.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/system_info.h\"\n\n#define NL_NO_DEBUG_FILES 1\n\nusing namespace std;\n\n// If you don't want to add default displayer, put 0 instead of 1. In this case, you\n// have to manage yourself displayer (in final release for example, we have to put 0)\n// Alternatively, you can use --without-logging when using configure to set\n// it to 0.\n#ifndef NEL_DEFAULT_DISPLAYER\n#define NEL_DEFAULT_DISPLAYER 1\n#endif // NEL_DEFAULT_DISPLAYER\n\n// Put 0 if you don't want to display in file \"log.log\"\n// Alternatively, you can use --without-logging when using configure to set\n// it to 0.\n#ifndef NEL_LOG_IN_FILE\n#define NEL_LOG_IN_FILE 1\n#endif // NEL_LOG_IN_FILE\n\n#define DEFAULT_DISPLAYER NEL_DEFAULT_DISPLAYER\n\n#define LOG_IN_FILE NEL_LOG_IN_FILE\n\n// If true, debug system will trap crash even if the application is in debugger\nstatic const bool TrapCrashInDebugger = false;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n//\n// Globals\n//\n\nbool DisableNLDebug= false;\nNLMISC::CVariablePtr<bool> _DisableNLDebug(\"nel\",\"DisableNLDebug\",\"Disables generation and output of nldebug logs (no code associated with the log generation is executed)\",&DisableNLDebug,true);\n\nstatic std::string LogPath;\n\n//bool DebugNeedAssert = false;\n//bool NoAssert = false;\n\n\n// ***************************************************************************\nCImposterLog::CImposterLog(TAccessor accessor)\n\t: _Accessor(accessor)\n{}\n\nCLog* CImposterLog::operator -> ()\n{\n\tif(NLMISC::INelContext::isContextInitialised())\n\t{\n\t\treturn (NLMISC::INelContext::getInstance().*_Accessor)();\n\t}\n\treturn NULL;\n}\n\nCImposterLog::operator CLog*()\n{\n\tif(NLMISC::INelContext::isContextInitialised())\n\t{\n\t\treturn (NLMISC::INelContext::getInstance().*_Accessor)();\n\t}\n\treturn NULL;\n}\n\nCLog &CImposterLog::operator ()()\n{\n\treturn *(operator CLog*());\n}\n\n\n//CLog *ErrorLog = NULL;\nCImposterLog\tErrorLog(&INelContext::getErrorLog);\n//CLog *WarningLog = NULL;\nCImposterLog\tWarningLog(&INelContext::getWarningLog);\n//CLog *InfoLog = NULL;\nCImposterLog\tInfoLog(&INelContext::getInfoLog);\n//CLog *DebugLog = NULL;\nCImposterLog\tDebugLog(&INelContext::getDebugLog);\n//CLog *AssertLog = NULL;\nCImposterLog\tAssertLog(&INelContext::getAssertLog);\n\n\n// ***************************************************************************\nCMemDisplayer *DefaultMemDisplayer = NULL;\nCMsgBoxDisplayer *DefaultMsgBoxDisplayer = NULL;\n\nstatic CStdDisplayer *sd = NULL;\nstatic CFileDisplayer *fd = NULL;\n\nstatic TCrashCallback CrashCallback = NULL;\n\nvoid setCrashCallback(TCrashCallback crashCallback)\n{\n\tCrashCallback = crashCallback;\n}\n\n// Yoyo: allow only the crash report to be emailed once\nstatic bool\tCrashAlreadyReported = false;\nbool\tisCrashAlreadyReported()\n{\n\treturn CrashAlreadyReported;\n}\nvoid\tsetCrashAlreadyReported(bool state)\n{\n\tCrashAlreadyReported= state;\n}\n\n\nvoid setAssert (bool assert)\n{\n\tINelContext::getInstance().setNoAssert(!assert);\n}\n\nvoid nlFatalError (const char *format, ...)\n{\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tINelContext::getInstance().setDebugNeedAssert( NLMISC::DefaultMsgBoxDisplayer==0 );\n\n\tNLMISC::ErrorLog->displayNL (str);\n\n\tif (INelContext::getInstance().getDebugNeedAssert())\n\t\t\tNLMISC_BREAKPOINT;\n\n#ifndef NL_OS_WINDOWS\n\n\t//\texit(EXIT_FAILURE);\n\tabort ();\n#endif\n}\n\nvoid nlError (const char *format, ...)\n{\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tINelContext::getInstance().setDebugNeedAssert( NLMISC::DefaultMsgBoxDisplayer==0 );\n\n\tNLMISC::ErrorLog->displayNL (str);\n\n\tif (INelContext::getInstance().getDebugNeedAssert())\n\t\tNLMISC_BREAKPOINT;\n\n#ifndef NL_OS_WINDOWS\n//\texit(EXIT_FAILURE);\n\tabort ();\n#endif\n}\n\n// the default behavior is to display all in standard output and to a file named \"log.log\";\n\nstatic void initDebug2 (bool logInFile)\n{\n#if DEFAULT_DISPLAYER\n\n\t// put the standard displayer everywhere\n\n//#ifdef NL_DEBUG\n\tINelContext::getInstance().getDebugLog()->addDisplayer (sd);\n//#endif // NL_DEBUG\n\tINelContext::getInstance().getInfoLog()->addDisplayer (sd);\n\tINelContext::getInstance().getWarningLog()->addDisplayer (sd);\n\tINelContext::getInstance().getAssertLog()->addDisplayer (sd);\n\tINelContext::getInstance().getErrorLog()->addDisplayer (sd);\n\n\t// put the memory displayer everywhere\n\n\t// use the memory displayer and bypass all filter (even for the debug mode)\n\tINelContext::getInstance().getDebugLog()->addDisplayer (DefaultMemDisplayer, true);\n\tINelContext::getInstance().getInfoLog()->addDisplayer (DefaultMemDisplayer, true);\n\tINelContext::getInstance().getWarningLog()->addDisplayer (DefaultMemDisplayer, true);\n\tINelContext::getInstance().getAssertLog()->addDisplayer (DefaultMemDisplayer, true);\n\tINelContext::getInstance().getErrorLog()->addDisplayer (DefaultMemDisplayer, true);\n\n\t// put the file displayer only if wanted\n\n#if LOG_IN_FILE\n\tif (logInFile)\n\t{\n//#ifdef NL_DEBUG\n\t\tINelContext::getInstance().getDebugLog()->addDisplayer (fd);\n//#endif // NL_DEBUG\n\t\tINelContext::getInstance().getInfoLog()->addDisplayer (fd);\n\t\tINelContext::getInstance().getWarningLog()->addDisplayer (fd);\n\t\tINelContext::getInstance().getAssertLog()->addDisplayer (fd);\n\t\tINelContext::getInstance().getErrorLog()->addDisplayer (fd);\n\t}\n#endif // LOG_IN_FILE\n\n\t// put the message box only in release for error\n\n\tif (DefaultMsgBoxDisplayer)\n\t{\n\t\tINelContext::getInstance().getAssertLog()->addDisplayer (DefaultMsgBoxDisplayer);\n\t\tINelContext::getInstance().getErrorLog()->addDisplayer (DefaultMsgBoxDisplayer);\n\t}\n\n#endif // DEFAULT_DISPLAYER\n}\n\n\n// ***************************************************************************\n// Method called when an assert arise\n\nvoid _assertex_stop_0(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp)\n{\n\tINelContext::getInstance().setDebugNeedAssert( false );\n\tNLMISC::createDebug ();\n\tif (NLMISC::DefaultMsgBoxDisplayer)\n\t\tNLMISC::DefaultMsgBoxDisplayer->IgnoreNextTime = ignoreNextTime;\n\telse if(!INelContext::getInstance().getNoAssert())\n\t\tINelContext::getInstance().setDebugNeedAssert(true);\n\tNLMISC::AssertLog->setPosition (line, file, funcName);\n\tif(exp)\t\tNLMISC::AssertLog->displayNL (\"\\\"%s\\\" \", exp);\n\telse\t\tNLMISC::AssertLog->displayNL (\"STOP\");\n}\n\nbool _assertex_stop_1(bool &ignoreNextTime)\n{\n\tif (NLMISC::DefaultMsgBoxDisplayer)\n\t\tignoreNextTime = NLMISC::DefaultMsgBoxDisplayer->IgnoreNextTime;\n\treturn INelContext::getInstance().getDebugNeedAssert();\n}\n\nbool _assert_stop(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp)\n{\n\t_assertex_stop_0(ignoreNextTime, line, file, funcName, exp);\n\treturn _assertex_stop_1(ignoreNextTime);\n}\n\n\n#ifdef NL_OS_WINDOWS\n\n/*\n// ***************************************************************************\nstatic DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress)\n{\n\tIMAGEHLP_MODULE moduleInfo;\n\n\tif (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))\n\t\treturn moduleInfo.BaseOfImage;\n\telse\n\t{\n\t\tMEMORY_BASIC_INFORMATION memoryBasicInfo;\n\n\t\tif (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,\n\t\t\t&memoryBasicInfo, sizeof(memoryBasicInfo)))\n\t\t{\n\t\t\tDWORD cch = 0;\n\t\t\tchar szFile[MAX_PATH] = { 0 };\n\n\t\t cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,\n\t\t\t\t\t\t\t\t szFile, MAX_PATH);\n\n\t\tif (cch && (lstrcmpA(szFile, \"DBFN\")== 0))\n\t\t{\n\t\t\t if (!SymLoadModule(hProcess,\n\t\t\t\t   NULL, \"MN\",\n\t\t\t\t   NULL, (DWORD) memoryBasicInfo.AllocationBase, 0))\n\t\t\t\t{\n\t\t\t\t\tDWORD dwError = GetLastError();\n//\t\t\t\t\tnlinfo(\"Error: %d\", dwError);\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t if (!SymLoadModule(hProcess,\n\t\t\t   NULL, ((cch) ? szFile : NULL),\n\t\t\t   NULL, (DWORD) memoryBasicInfo.AllocationBase, 0))\n\t\t\t{\n\t\t\t\tDWORD dwError = GetLastError();\n//\t\t\t\tnlinfo(\"Error: %d\", dwError);\n\t\t\t }\n\n\t\t}\n\n\t\t return (DWORD) memoryBasicInfo.AllocationBase;\n\t  }\n//\t\telse\n//\t\t\tnlinfo(\"Error is %d\", GetLastError());\n\t}\n\n\treturn 0;\n}\n\nLPVOID __stdcall FunctionTableAccess (HANDLE hProcess, DWORD AddrBase)\n{\n\tAddrBase = 0x40291f;\n\tDWORD addr = SymGetModuleBase (hProcess, AddrBase);\n\tHRESULT hr = GetLastError ();\n\n\tIMAGEHLP_MODULE moduleInfo;\n\tmoduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE);\n\tSymGetModuleInfo(hProcess, addr, &moduleInfo);\n\thr = GetLastError ();\n\tSymLoadModule(hProcess, NULL, NULL, NULL, 0, 0);\n\thr = GetLastError ();\n\n\tLPVOID temp = SymFunctionTableAccess (hProcess, AddrBase);\n\thr = GetLastError ();\n\treturn temp;\n}\n*/\n\n/* can't include dbghelp.h */\ntypedef struct _NEL_MINIDUMP_EXCEPTION_INFORMATION {  DWORD ThreadId;  PEXCEPTION_POINTERS ExceptionPointers;  BOOL ClientPointers;\n} NEL_MINIDUMP_EXCEPTION_INFORMATION, *PNEL_MINIDUMP_EXCEPTION_INFORMATION;\ntypedef enum _NEL_MINIDUMP_TYPE\n{\n  MiniDumpNormal = 0x00000000,\n  MiniDumpWithDataSegs = 0x00000001,\n  MiniDumpWithFullMemory = 0x00000002,\n  MiniDumpWithHandleData = 0x00000004,\n  MiniDumpFilterMemory = 0x00000010,\n  MiniDumpWithUnloaded = 0x00000020,\n  MiniDumpWithIndirectlyReferencedMemory = 0x00000040,\n  MiniDumpFilterModulePaths = 0x00000080,\n  MiniDumpWithProcessThreadData = 0x00000100,\n  MiniDumpWithPrivateReadWriteMemory = 0x00000200,\n  MiniDumpWithoutOptionalData = 0x00000400,\n  MiniDumpWithFullMemoryInfo = 0x00000800,\n  MiniDumpWithThreadInfo = 0x00001000,\n  MiniDumpWithCodeSegs = 0x00002000\n} NEL_MINIDUMP_TYPE;\n\nstatic void DumpMiniDump(PEXCEPTION_POINTERS excpInfo)\n{\n\tHANDLE file = CreateFileA (NL_CRASH_DUMP_FILE, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\n\tif (file)\n\t{\n\t\tHMODULE hm = LoadLibraryA (\"dbghelp.dll\");\n\t\tif (hm)\n\t\t{\n\t\t\tBOOL (WINAPI* MiniDumpWriteDump)(\n\t\t\t  HANDLE hProcess,\n\t\t\t  DWORD ProcessId,\n\t\t\t  HANDLE hFile,\n\t\t\t  NEL_MINIDUMP_TYPE DumpType,\n\t\t\t  PNEL_MINIDUMP_EXCEPTION_INFORMATION ExceptionParam,\n\t\t\t  PNEL_MINIDUMP_EXCEPTION_INFORMATION UserStreamParam,\n\t\t\t  PNEL_MINIDUMP_EXCEPTION_INFORMATION CallbackParam\n\t\t\t) = NULL;\n\t\t\t*(FARPROC*)&MiniDumpWriteDump = GetProcAddress(hm, \"MiniDumpWriteDump\");\n\t\t\tif (MiniDumpWriteDump)\n\t\t\t{\n\t\t\t\t// OutputDebugString(_T(\"writing minidump\\r\\n\"));\n\t\t\t\tNEL_MINIDUMP_EXCEPTION_INFORMATION eInfo;\n\t\t\t\teInfo.ThreadId = GetCurrentThreadId();\n\t\t\t\teInfo.ExceptionPointers = excpInfo;\n\t\t\t\teInfo.ClientPointers = FALSE;\n\n\t\t\t\t// note:  MiniDumpWithIndirectlyReferencedMemory does not work on Win98\n\t\t\t\tMiniDumpWriteDump(\n\t\t\t\t\tGetCurrentProcess(),\n\t\t\t\t\tGetCurrentProcessId(),\n\t\t\t\t\tfile,\n\t\t\t\t\tMiniDumpNormal,\n\t\t\t\t\texcpInfo ? &eInfo : NULL,\n\t\t\t\t\tNULL,\n\t\t\t\t\tNULL);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning (\"Can't get proc MiniDumpWriteDump in dbghelp.dll\");\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"Can't load dbghelp.dll\");\n\t\t}\n\t\tCloseHandle (file);\n\t}\n\telse\n\t\tnlwarning (\"Can't create mini dump file\");\n}\n\nclass EDebug : public ETrapDebug\n{\npublic:\n\n\tEDebug() { _Reason = \"Nothing about EDebug\"; }\n\n\tvirtual ~EDebug() throw() {}\n\n\tEDebug(EXCEPTION_POINTERS * pexp) : m_pexp(pexp) { nlassert(pexp != 0); createWhat(); }\n\tEDebug(const EDebug& se) : m_pexp(se.m_pexp) { createWhat(); }\n\n\tvoid createWhat ()\n\t{\n\t\tstring shortExc, longExc, subject;\n\t\tstring addr, ext;\n\t\tULONG_PTR skipNFirst = 0;\n\t\t_Reason = \"\";\n\n\t\tif (m_pexp == NULL)\n\t\t{\n\t\t\t_Reason = \"Unknown exception, don't have context.\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch (m_pexp->ExceptionRecord->ExceptionCode)\n\t\t\t{\n\t\t\tcase EXCEPTION_ACCESS_VIOLATION          : shortExc=\"Access Violation\"; longExc=\"The thread attempted to read from or write to a virtual address for which it does not have the appropriate access\";\n\t\t\t\text = \", thread attempts to \";\n\t\t\t\text += m_pexp->ExceptionRecord->ExceptionInformation[0]?\"write\":\"read\";\n\t\t\t\tif (m_pexp->ExceptionRecord->ExceptionInformation[1])\n\t\t\t\t\text += toString(\" at 0x%X\",m_pexp->ExceptionRecord->ExceptionInformation[1]);\n\t\t\t\telse\n\t\t\t\t\text += \" at <NULL>\";\n\t\t\t\tbreak;\n\t\t\tcase EXCEPTION_DATATYPE_MISALIGNMENT     : shortExc=\"Datatype Misalignment\"; longExc=\"The thread attempted to read or write data that is misaligned on hardware that does not provide alignment. For example, 16-bit values must be aligned on 2-byte boundaries, 32-bit values on 4-byte boundaries, and so on\"; break;\n\t\t\tcase EXCEPTION_BREAKPOINT                : shortExc=\"Breakpoint\"; longExc=\"A breakpoint was encountered\"; break;\n\t\t\tcase EXCEPTION_SINGLE_STEP               : shortExc=\"Single Step\"; longExc=\"A trace trap or other single-instruction mechanism signaled that one instruction has been executed\"; break;\n\t\t\tcase EXCEPTION_ARRAY_BOUNDS_EXCEEDED     : shortExc=\"Array Bounds Exceeded\"; longExc=\"The thread attempted to access an array element that is out of bounds, and the underlying hardware supports bounds checking\"; break;\n\t\t\tcase EXCEPTION_FLT_DENORMAL_OPERAND      : shortExc=\"Float Denormal Operand\"; longExc=\"One of the operands in a floating-point operation is denormal. A denormal value is one that is too small to represent as a standard floating-point value\"; break;\n\t\t\tcase EXCEPTION_FLT_DIVIDE_BY_ZERO        : shortExc=\"Float Divide By Zero\"; longExc=\"The thread attempted to divide a floating-point value by a floating-point divisor of zero\"; break;\n\t\t\tcase EXCEPTION_FLT_INEXACT_RESULT        : shortExc=\"Float Inexact Result\"; longExc=\"The result of a floating-point operation cannot be represented exactly as a decimal fraction\"; break;\n\t\t\tcase EXCEPTION_FLT_INVALID_OPERATION     : shortExc=\"Float Invalid Operation\"; longExc=\"This exception represents any floating-point exception not included in this list\"; break;\n\t\t\tcase EXCEPTION_FLT_OVERFLOW              : shortExc=\"Float Overflow\"; longExc=\"The exponent of a floating-point operation is greater than the magnitude allowed by the corresponding type\"; break;\n\t\t\tcase EXCEPTION_FLT_STACK_CHECK           : shortExc=\"Float Stack Check\"; longExc=\"The stack overflowed or underflowed as the result of a floating-point operation\"; break;\n\t\t\tcase EXCEPTION_FLT_UNDERFLOW             : shortExc=\"Float Underflow\"; longExc=\"The exponent of a floating-point operation is less than the magnitude allowed by the corresponding type\"; break;\n\t\t\tcase EXCEPTION_INT_DIVIDE_BY_ZERO        : shortExc=\"Integer Divide By Zero\"; longExc=\"The thread attempted to divide an integer value by an integer divisor of zero\"; break;\n\t\t\tcase EXCEPTION_INT_OVERFLOW              : shortExc=\"Integer Overflow\"; longExc=\"The result of an integer operation caused a carry out of the most significant bit of the result\"; break;\n\t\t\tcase EXCEPTION_PRIV_INSTRUCTION          : shortExc=\"Privileged Instruction\"; longExc=\"The thread attempted to execute an instruction whose operation is not allowed in the current machine mode\"; break;\n\t\t\tcase EXCEPTION_IN_PAGE_ERROR             : shortExc=\"In Page Error\"; longExc=\"The thread tried to access a page that was not present, and the system was unable to load the page. -ie. the program or memory mapped file couldn't be paged in because it isn't accessable any more. Device drivers can return this exception if something went wrong with the read (i.e hardware problems)\"; break;\n\t\t\tcase EXCEPTION_ILLEGAL_INSTRUCTION       : shortExc=\"Illegal Instruction\"; longExc=\"The thread tried to execute an invalid instruction -such as MMX opcodes on a non MMX system. Branching to an invalid location can cause this -something stack corruption often causes\"; break;\n\t\t\tcase EXCEPTION_NONCONTINUABLE_EXCEPTION  : shortExc=\"Noncontinuable Exception\"; longExc=\"The thread attempted to continue execution after a noncontinuable exception occurred\"; break;\n\t\t\tcase EXCEPTION_STACK_OVERFLOW            : shortExc=\"Stack Overflow\"; longExc=\"Stack overflow. Can occur during errant recursion, or when a function creates a particularly large array on the stack\"; break;\n\t\t\tcase EXCEPTION_INVALID_DISPOSITION       : shortExc=\"Invalid Disposition\"; longExc=\"Whatever number the exception filter returned, it wasn't a value the OS knows about\"; break;\n\t\t\tcase EXCEPTION_GUARD_PAGE                : shortExc=\"Guard Page\"; longExc=\"Memory Allocated as PAGE_GUARD by VirtualAlloc() has been accessed\"; break;\n\t\t\tcase EXCEPTION_INVALID_HANDLE            : shortExc=\"Invalid Handle\"; longExc=\"\"; break;\n\t\t\tcase CONTROL_C_EXIT                      : shortExc=\"Control-C\"; longExc=\"Lets the debugger know the user hit Ctrl-C. Seemingly for console apps only\"; break;\n\t\t\tcase STATUS_NO_MEMORY                    : shortExc=\"No Memory\"; longExc=\"Called by HeapAlloc() if you specify HEAP_GENERATE_EXCEPTIONS and there is no memory or heap corruption\";\n\t\t\t\text = \", unable to allocate \";\n\t\t\t\text += toString (\"%d bytes\", m_pexp->ExceptionRecord->ExceptionInformation [0]);\n\t\t\t\tbreak;\n\t\t\tcase STATUS_WAIT_0                       : shortExc=\"Wait 0\"; longExc=\"\"; break;\n\t\t\tcase STATUS_ABANDONED_WAIT_0             : shortExc=\"Abandoned Wait 0\"; longExc=\"\"; break;\n\t\t\tcase STATUS_USER_APC                     : shortExc=\"User APC\"; longExc=\"A user APC was delivered to the current thread before the specified Timeout interval expired\"; break;\n\t\t\tcase STATUS_TIMEOUT                      : shortExc=\"Timeout\"; longExc=\"\"; break;\n\t\t\tcase STATUS_PENDING                      : shortExc=\"Pending\"; longExc=\"\"; break;\n\t\t\tcase STATUS_SEGMENT_NOTIFICATION         : shortExc=\"Segment Notification\"; longExc=\"\"; break;\n\t\t\tcase STATUS_FLOAT_MULTIPLE_FAULTS        : shortExc=\"Float Multiple Faults\"; longExc=\"\"; break;\n\t\t\tcase STATUS_FLOAT_MULTIPLE_TRAPS         : shortExc=\"Float Multiple Traps\"; longExc=\"\"; break;\n#ifdef NL_COMP_VC6\n\t\t\tcase STATUS_ILLEGAL_VLM_REFERENCE        : shortExc=\"Illegal VLM Reference\"; longExc=\"\"; break;\n#endif\n\t\t\tcase 0xE06D7363                          : shortExc=\"Microsoft C++ Exception\"; longExc=\"Microsoft C++ Exception\"; break;\t// cpp exception\n\t\t\tcase 0xACE0ACE                           : shortExc=\"\"; longExc=\"\";\n\t\t\t\tif (m_pexp->ExceptionRecord->NumberParameters == 1)\n\t\t\t\t\tskipNFirst = m_pexp->ExceptionRecord->ExceptionInformation [0];\n\t\t\t\tbreak;\t// just want the stack\n\t\t\tdefault                                  : shortExc=\"Unknown Exception\"; longExc=\"Unknown Exception \"+toString(\"0x%X\", m_pexp->ExceptionRecord->ExceptionCode); break;\n\t\t\t};\n\n\t\t\tif(m_pexp->ExceptionRecord != NULL)\n\t\t\t{\n\t\t\t\tif (m_pexp->ExceptionRecord->ExceptionAddress)\n\t\t\t\t\taddr = toString(\" at 0x%X\", m_pexp->ExceptionRecord->ExceptionAddress);\n\t\t\t\telse\n\t\t\t\t\taddr = \" at <NULL>\";\n\t\t\t}\n\n\t\t\tstring progname;\n\t\t\tif(!shortExc.empty() || !longExc.empty())\n\t\t\t{\n\t\t\t\tchar name[1024];\n\t\t\t\tGetModuleFileNameA (NULL, name, 1023);\n\t\t\t\tprogname = CFile::getFilename(name);\n\t\t\t\tprogname += \" \";\n\t\t\t}\n\n\t\t\tsubject = progname + shortExc + addr;\n\n\t\t\tif (_Reason.empty())\n\t\t\t{\n\t\t\t\tif (!shortExc.empty()) _Reason += shortExc + \" exception generated\" + addr + ext + \".\\n\";\n\t\t\t\tif (!longExc.empty()) _Reason += longExc + \".\\n\";\n\t\t\t}\n\n\t\t\t// display the stack\n\t\t\taddStackAndLogToReason (skipNFirst);\n\n\t\t\tif(!shortExc.empty() || !longExc.empty())\n\t\t\t{\n\t\t\t\t// yoyo: allow only to send the crash report once. Because users usually click ignore,\n\t\t\t\t// which create noise into list of bugs (once a player crash, it will surely continues to do it).\n\t\t\t\tbool i = false;\n\t\t\t\treport (progname+shortExc, \"\", subject, _Reason, true, 1, true, 1, !isCrashAlreadyReported(), i, NL_CRASH_DUMP_FILE);\n\n\t\t\t\t// no more sent mail for crash\n\t\t\t\tsetCrashAlreadyReported(true);\n\t\t\t}\n\t\t}\n\t}\n\n\t// display the callstack\n\tvoid addStackAndLogToReason (ULONG_PTR /* skipNFirst */ = 0)\n\t{\n#ifdef NL_OS_WINDOWS\n\t\t// ace hack\n/*\t\tskipNFirst = 0;\n\n\t\tDWORD symOptions = SymGetOptions();\n\t\tsymOptions |= SYMOPT_LOAD_LINES;\n\t\tsymOptions &= ~SYMOPT_UNDNAME;\n\t\tSymSetOptions (symOptions);\n\n\t\tnlverify (SymInitialize(getProcessHandle(), NULL, FALSE) == TRUE);\n\n\t\tSTACKFRAME callStack;\n\t\t::ZeroMemory (&callStack, sizeof(callStack));\n\t\tcallStack.AddrPC.Mode      = AddrModeFlat;\n\t\tcallStack.AddrPC.Offset    = m_pexp->ContextRecord->Eip;\n\t\tcallStack.AddrStack.Mode   = AddrModeFlat;\n\t\tcallStack.AddrStack.Offset = m_pexp->ContextRecord->Esp;\n\t\tcallStack.AddrFrame.Mode   = AddrModeFlat;\n\t\tcallStack.AddrFrame.Offset = m_pexp->ContextRecord->Ebp;\n\n\t\t_Reason += \"\\nCallstack:\\n\";\n\t\t_Reason += \"-------------------------------\\n\";\n\t\tfor (sint32 i = 0; ; i++)\n\t\t{\n\t\t\tSetLastError(0);\n\t\t\tBOOL res = StackWalk (IMAGE_FILE_MACHINE_I386, getProcessHandle(), GetCurrentThread(), &callStack,\n\t\t\t\tm_pexp->ContextRecord, NULL, FunctionTableAccess, GetModuleBase, NULL);\n\n\t\t\tif (res == FALSE || callStack.AddrFrame.Offset == 0)\n\t\t\t\tbreak;\n\n\t\t\tstring symInfo, srcInfo;\n\n\t\t\tif (i >= skipNFirst)\n\t\t\t{\n\t\t\t\tsrcInfo = getSourceInfo (callStack.AddrPC.Offset);\n\t\t\t\tsymInfo = getFuncInfo (callStack.AddrPC.Offset, callStack.AddrFrame.Offset);\n\t\t\t\t_Reason += srcInfo + \": \" + symInfo + \"\\n\";\n\t\t\t}\n\t\t}\n\t\tSymCleanup(getProcessHandle());\n\t\t*/\n#elif !defined(NL_OS_MAC)\n\t\t// Make place for stack frames and function names\n\t\tconst uint MaxFrame=64;\n\t\tvoid *trace[MaxFrame];\n\t\tchar **messages = (char **)NULL;\n\t\tint i, trace_size = 0;\n\n\t\ttrace_size = backtrace(trace, MaxFrame);\n\t\tmessages = backtrace_symbols(trace, trace_size);\n\t\tresult += \"Callstack:\\n\";\n\t\t_Reason += \"-------------------------------\\n\";\n\t\tfor (i=0; i<trace_size; ++i)\n\t\t\t_Reason += toString(\"%i : %s\\n\", i, messages[i]);\n\t\t// free the messages\n\t\tfree(messages);\n#endif\n\n// \t\t_Reason += \"-------------------------------\\n\";\n// \t\t_Reason += \"\\n\";\n// \t\tif(DefaultMemDisplayer)\n// \t\t{\n// \t\t\t_Reason += \"Log with no filter:\\n\";\n// \t\t\t_Reason += \"-------------------------------\\n\";\n// \t\t\tDefaultMemDisplayer->write (_Reason);\n// \t\t}\n// \t\telse\n// \t\t{\n// \t\t\t_Reason += \"No log\\n\";\n// \t\t}\n//\t\t_Reason += \"-------------------------------\\n\";\n\n\t\t// add specific information about the application\n// \t\tif(CrashCallback)\n// \t\t{\n// \t\t\t_Reason += \"User Crash Callback:\\n\";\n// \t\t\t_Reason += \"-------------------------------\\n\";\n// \t\t\tstatic bool looping = false;\n// \t\t\tif(looping)\n// \t\t\t{\n// \t\t\t\t_Reason += \"******* WARNING: crashed in the user crash callback *******\\n\";\n// \t\t\t\tlooping = false;\n// \t\t\t}\n// \t\t\telse\n// \t\t\t{\n// \t\t\t\tlooping = true;\n// \t\t\t\t_Reason += CrashCallback();\n// \t\t\t\tlooping = false;\n// \t\t\t}\n// \t\t\t_Reason += \"-------------------------------\\n\";\n// \t\t}\n\t}\n\n\tstring getSourceInfo (DWORD_TYPE addr)\n\t{\n\t\tstring str;\n\n\t\tIMAGEHLP_LINE  line;\n\t\t::ZeroMemory (&line, sizeof (line));\n\t\tline.SizeOfStruct = sizeof(line);\n\n\t\t// ACE: removed the next code because \"SymGetLineFromAddr\" is not available on windows 98\n\t\tbool ok = false;\n\t\tDWORD displacement = 0 ;\n\t\tDWORD resdisp = 0;\n\n//\n\t\t/*\n\t\t// \"Debugging Applications\" John Robbins\n\t\t// The problem is that the symbol engine finds only those source\n\t\t// line addresses (after the first lookup) that fall exactly on\n\t\t// a zero displacement. I'll walk backward 100 bytes to\n\t\t// find the line and return the proper displacement.\n\t\tbool ok = true;\n\t\tDWORD displacement = 0 ;\n\t\tDWORD resdisp;\n\n\t\twhile (!SymGetLineFromAddr (getProcessHandle(), addr - displacement, (DWORD*)&resdisp, &line))\n\t\t{\n\t\t\tif (100 == ++displacement)\n\t\t\t{\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t*/\n//\n\n\t\t// \"Debugging Applications\" John Robbins\n\t\t// I found the line, and the source line information is correct, so\n\t\t// change the displacement if I had to search backward to find the source line.\n\t\tif (displacement)\n\t\t\tresdisp = displacement;\n\n\t\tif (ok)\n\t\t{\n\t\t\tstr = line.FileName;\n\t\t\tstr += \"(\" + toString ((uint32)line.LineNumber) + \")\";\n\t\t\tstr += toString(\": 0x%X\", addr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tIMAGEHLP_MODULE module;\n\t\t\t::ZeroMemory (&module, sizeof(module));\n\t\t\tmodule.SizeOfStruct = sizeof(module);\n\n\t\t\tif (SymGetModuleInfo (getProcessHandle(), addr, &module))\n\t\t\t{\n\t\t\t\tstr = module.ModuleName;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstr = \"<NoModule>\";\n\t\t\t}\n\t\t\tstr += toString(\"!0x%X\", addr);\n\t\t}\n\n//\n\n\t\t/*DWORD disp;\n\t\tif (SymGetLineFromAddr (getProcessHandle(), addr, &disp, &line))\n\t\t{\n\t\t\tstr = line.FileName;\n\t\t\tstr += \"(\" + toString (line.LineNumber) + \")\";\n\t\t}\n\t\telse\n\t\t{*/\n\t\t\tIMAGEHLP_MODULE module;\n\t\t\t::ZeroMemory (&module, sizeof(module));\n\t\t\tmodule.SizeOfStruct = sizeof(module);\n\n\t\t\tif (SymGetModuleInfo (getProcessHandle(), addr, &module))\n\t\t\t{\n\t\t\t\tstr = module.ModuleName;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstr = \"<NoModule>\";\n\t\t\t}\n\t\t\tchar tmp[32];\n\t\t\tsprintf (tmp, \"!0x%p\", addr);\n\t\t\tstr += tmp;\n\t\t//}\n\t\tstr +=\" DEBUG:\"+toString(\"0x%p\", addr);\n\n//\n\n\t\treturn str;\n\t}\n\n\tHANDLE getProcessHandle()\n\t{\n\t\treturn CSystemInfo::isNT()?GetCurrentProcess():(HANDLE)(uintptr_t)GetCurrentProcessId();\n\t}\n\n\t// return true if found\n\tbool findAndErase(string &str, const char *token, const char *replace = NULL)\n\t{\n\t\tstring::size_type pos;\n\t\tif ((pos = str.find(token)) != string::npos)\n\t\t{\n\t\t\tstr.erase (pos,strlen(token));\n\t\t\tif (replace != NULL)\n\t\t\t\tstr.insert (pos, replace);\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t\treturn false;\n\t}\n\n\t// remove space and const stuffs\n\t// rawType contains the type without anything (to compare with known type)\n\t// displayType contains the type without std:: and stl ugly things\n\tvoid cleanType(string &rawType, string &displayType)\n\t{\n\t\twhile (findAndErase(rawType, \"std::\")) ;\n\t\twhile (findAndErase(displayType, \"std::\")) ;\n\n\t\twhile (findAndErase(rawType, \"_STL::\")) ;\n\t\twhile (findAndErase(displayType, \"_STL::\")) ;\n\n\t\twhile (findAndErase(rawType, \"const\")) ;\n\n\t\twhile (findAndErase(rawType, \" \")) ;\n\n\t\twhile (findAndErase(rawType, \"&\")) ;\n\n\t\t// rename ugly stl type\n\n\t\twhile (findAndErase(rawType, \"classbasic_string<char,classchar_traits<char>,classallocator<char>>\", \"string\")) ;\n\t\twhile (findAndErase(displayType, \"class basic_string<char,class char_traits<char>,class allocator<char> >\", \"string\")) ;\n\t\twhile (findAndErase(rawType, \"classvector<char,class char_traits<char>,class allocator<char> >\", \"string\")) ;\n\t}\n\n\tstring getFuncInfo (uintptr_t funcAddr, uintptr_t stackAddr)\n\t{\n\t\tstring str (\"NoSymbol\");\n\n\t\tDWORD symSize = 10000;\n\t\tPIMAGEHLP_SYMBOL  sym = (PIMAGEHLP_SYMBOL) GlobalAlloc (GMEM_FIXED, symSize);\n\t\t::ZeroMemory (sym, symSize);\n\t\tsym->SizeOfStruct = symSize;\n\t\tsym->MaxNameLength = symSize - sizeof(IMAGEHLP_SYMBOL);\n\n\t\tDWORD_TYPE disp = 0;\n\t\tif (SymGetSymFromAddr (getProcessHandle(), funcAddr, &disp, sym) == FALSE)\n\t\t{\n\t\t\treturn str;\n\t\t}\n\n\t\tCHAR undecSymbol[1024];\n\t\tif (UnDecorateSymbolName (sym->Name, undecSymbol, 1024, UNDNAME_COMPLETE | UNDNAME_NO_THISTYPE | UNDNAME_NO_SPECIAL_SYMS | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS ) > 0)\n\t\t{\n\t\t\tstr = undecSymbol;\n\t\t}\n\t\telse if (SymUnDName (sym, undecSymbol, 1024) == TRUE)\n\t\t{\n\t\t\tstr = undecSymbol;\n\t\t}\n\n\t\t// replace param with the value of the stack for this param\n\n\t\tstring parse = str;\n\t\tstr = \"\";\n\t\tuint pos2 = 0;\n\t\tsint stop = 0;\n\n\t\tstring type;\n\n\t\tstring::size_type i = parse.find (\"(\");\n\n\t\t// copy the function name\n\t\tstr = parse.substr(0, i);\n\n//\t\tnlinfo (\"not parsed '%s'\", parse.c_str());\n\n\t\t// if there s parameter, parse them\n\t\tif(i!=string::npos)\n\t\t{\n\t\t\t// copy the '('\n\t\t\tstr += parse[i];\n\t\t\tfor (i++; i < parse.size (); i++)\n\t\t\t{\n\t\t\t\tif (parse[i] == '<')\n\t\t\t\t\t stop++;\n\t\t\t\tif (parse[i] == '>')\n\t\t\t\t\t stop--;\n\n\t\t\t\tif (stop==0 && (parse[i] == ',' || parse[i] == ')'))\n\t\t\t\t{\n\t\t\t\t\tuintptr_t *addr = (uintptr_t*)(stackAddr) + 2 + pos2++;\n\n\t\t\t\t\tstring displayType = type;\n\t\t\t\t\tcleanType (type, displayType);\n\n\t\t\t\t\tchar tmp[1024];\n\t\t\t\t\tif(type == \"void\")\n\t\t\t\t\t{\n\t\t\t\t\t\ttmp[0]='\\0';\n\t\t\t\t\t}\n\t\t\t\t\telse if(type == \"int\")\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsBadReadPtr(addr,sizeof(int)))\n\t\t\t\t\t\t\tsprintf (tmp, \"%d\", *addr);\n\t\t\t\t\t}\n\t\t\t\t\telse if (type == \"char\")\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsBadReadPtr(addr,sizeof(char)))\n\t\t\t\t\t\t\tif (nlisprint(*addr))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsprintf (tmp, \"'%c'\", *addr);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tsprintf (tmp, \"%d\", *addr);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (type == \"char*\")\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsBadReadPtr(addr,sizeof(char*)) && *addr != 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!IsBadStringPtrA((char*)*addr,32))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuint pos = 0;\n\t\t\t\t\t\t\t\ttmp[pos++] = '\\\"';\n\t\t\t\t\t\t\t\tfor (uint j = 0; j < 32; j++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tchar c = ((char *)*addr)[j];\n\t\t\t\t\t\t\t\t\tif (c == '\\0')\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\telse if (c == '\\n')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = '\\\\';\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = 'n';\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (c == '\\r')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = '\\\\';\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = 'r';\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse if (c == '\\t')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = '\\\\';\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = 't';\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\ttmp[pos++] = c;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttmp[pos++] = '\\\"';\n\t\t\t\t\t\t\t\ttmp[pos++] = '\\0';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (type == \"string\") // we assume a string is always passed by reference (i.e. addr is a string**)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsBadReadPtr(addr,sizeof(string*)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (*addr != 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (!IsBadReadPtr((void*)*addr,sizeof(string)))\n\t\t\t\t\t\t\t\t\tsprintf (tmp, \"\\\"%s\\\"\", ((string*)*addr)->c_str());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (!IsBadReadPtr(addr,sizeof(uintptr_t*)))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(*addr == 0)\n\t\t\t\t\t\t\t\tsprintf (tmp, \"<NULL>\");\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tsprintf (tmp, \"0x%p\", *addr);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tstr += displayType;\n\t\t\t\t\tif(tmp[0]!='\\0')\n\t\t\t\t\t{\n\t\t\t\t\t\tstr += \"=\";\n\t\t\t\t\t\tstr += tmp;\n\t\t\t\t\t}\n\t\t\t\t\tstr += parse[i];\n\t\t\t\t\ttype = \"\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttype += parse[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tGlobalFree (sym);\n\t\t\tif (disp != 0)\n\t\t\t{\n\t\t\t\tstr += \" + \";\n\t\t\t\tstr += toString ((uintptr_t)disp);\n\t\t\t\tstr += \" bytes\";\n\t\t\t}\n\t\t}\n\n//\t\tnlinfo (\"after parsing '%s'\", str.c_str());\n\n\t\treturn str;\n\t}\n\nprivate:\n\tEXCEPTION_POINTERS * m_pexp;\n};\n\n// workaround of VCPP synchronous exception and se translator\nbool global_force_exception_flag = false;\n#define WORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION  if (global_force_exception_flag) force_exception_frame();\nvoid force_exception_frame(...) {std::cout.flush();}\n\nstatic void exceptionTranslator(unsigned, EXCEPTION_POINTERS *pexp)\n{\n#ifndef NL_NO_DEBUG_FILES\n\tCFile::createEmptyFile(getLogDirectory() + \"exception_catched\");\n#endif\n\tif (pexp->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)\n\t{\n#ifndef NL_NO_DEBUG_FILES\n\t\tCFile::createEmptyFile(getLogDirectory() + \"breakpointed\");\n#endif\n\t\treturn;\n\t}\n#if FINAL_VERSION\n\t// In final version, throw EDebug to display a smart dialog box with callstack & log when crashing\n#\tpragma message ( \"Smart crash enabled\" )\n\tDumpMiniDump(pexp);\n\tthrow EDebug (pexp);\n#else\n\t// In debug version, let the program crash and use a debugger (clicking \"Cancel\")\n\t// Ace: 'if' not activated because we can't debug if enabled: keeping only 0xACE0ACE for nlstop...\n\t//if (!TrapCrashInDebugger && IsDebuggerPresent ())\n\t{\n\t\tif (pexp->ExceptionRecord->ExceptionCode == 0xACE0ACE)\n\t\t\tthrow EDebug (pexp);\n\t\telse\n\t\t\treturn;\n\t}\n\t/*else\n\t{\n\t\tif (pexp->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)\n\t\t\treturn;\n\t\telse\n\t\t\tthrow EDebug (pexp);\n\t}*/\n#endif\n}\n\n#endif // NL_OS_WINDOWS\n\nvoid getCallStack(std::string &result, sint skipNFirst)\n{\n#ifdef NL_OS_WINDOWS\n\ttry\n\t{\n\t\tWORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION // force to install a exception frame\n\n\t\tDWORD_PTR array[1];\n\t\tarray[0] = skipNFirst;\n\t\tRaiseException (0xACE0ACE, 0, 1, array);\n\t}\n\tcatch (const EDebug &e)\n\t{\n\t\tresult += e.what();\n\t}\n#elif !defined(NL_OS_MAC)\n\t// Make place for stack frames and function names\n\tconst uint MaxFrame=64;\n\tvoid *trace[MaxFrame];\n\tchar **messages = (char **)NULL;\n\tint i, trace_size = 0;\n\n\t// on mac, require at least os 10.5\n\ttrace_size = backtrace(trace, MaxFrame);\n\tmessages = backtrace_symbols(trace, trace_size);\n\tresult += \"Dumping call stack :\\n\";\n\tfor (i=0; i<trace_size; ++i)\n\t\tresult += toString(\"%i : %s\\n\", i, messages[i]);\n\t// free the messages\n\tfree(messages);\n#endif\n}\n\n\nvoid getCallStackAndLog (string &result, sint /* skipNFirst */)\n{\n\t//getCallStack(result, skipNFirst);\n//#ifdef NL_OS_WINDOWS\n//\ttry\n//\t{\n//\t\tWORKAROUND_VCPP_SYNCHRONOUS_EXCEPTION // force to install a exception frame\n//\n//\t\tDWORD array[1];\n//\t\tarray[0] = skipNFirst;\n//\t\tRaiseException (0xACE0ACE, 0, 1, array);\n//\t}\n//\tcatch (const EDebug &e)\n//\t{\n//\t\tresult += e.what();\n//\t}\n//#else\n//\n//\t// Make place for stack frames and function names\n//\tconst uint MaxFrame=64;\n//\tvoid *trace[MaxFrame];\n//\tchar **messages = (char **)NULL;\n//\tint i, trace_size = 0;\n//\n//\ttrace_size = backtrace(trace, MaxFrame);\n//\tmessages = backtrace_symbols(trace, trace_size);\n//\tresult += \"Dumping call stack :\\n\";\n//\tfor (i=0; i<trace_size; ++i)\n//\t\tresult += toString(\"%i : %s\\n\", i, messages[i]);\n//\t// free the messages\n//\tfree(messages);\n//#endif\n//\n\tresult += \"-------------------------------\\n\";\n\tresult += \"\\n\";\n\tif(DefaultMemDisplayer)\n\t{\n\t\tresult += \"Log with no filter:\\n\";\n\t\tresult += \"-------------------------------\\n\";\n\t\tDefaultMemDisplayer->write (result);\n\t}\n\telse\n\t{\n\t\tresult += \"No log\\n\";\n\t}\n\tresult += \"-------------------------------\\n\";\n\n\t// add specific information about the application\n\tif(CrashCallback)\n\t{\n\t\tresult += \"User Crash Callback:\\n\";\n\t\tresult += \"-------------------------------\\n\";\n\t\tstatic bool looping = false;\n\t\tif(looping)\n\t\t{\n\t\t\tresult += \"******* WARNING: crashed in the user crash callback *******\\n\";\n\t\t\tlooping = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlooping = true;\n\t\t\tresult += CrashCallback();\n\t\t\tlooping = false;\n\t\t}\n\t\tresult += \"-------------------------------\\n\";\n\t}\n}\n\nvoid changeLogDirectory(const std::string &dir)\n{\n\tif (fd == NULL)return;\n\tLogPath = CPath::standardizePath(dir);\n\tstring p = LogPath + \"log.log\";\n\tfd->setParam(p);\n}\n\nstd::string getLogDirectory()\n{\n\treturn LogPath;\n}\n\n// You should not call this, unless you know what you're trying to do (it kills debug/log)!\n// Destroys debug environment, to clear up the memleak log.\n// NeL context must be deleted immediately after debug destroyed,\n// or there will be various issues when static destructors call nldebug etc...\nvoid destroyDebug()\n{\n\tdelete sd; sd = NULL;\n\tdelete DefaultMsgBoxDisplayer; DefaultMsgBoxDisplayer = NULL;\n\tdelete fd; fd = NULL;\n\tdelete DefaultMemDisplayer; DefaultMemDisplayer = NULL;\n\tif (INelContext::isContextInitialised())\n\t{\n\t\tCLog *log;\n\t\tINelContext &context = INelContext::getInstance();\n\t\tlog = context.getErrorLog(); context.setErrorLog(NULL); delete log; log = NULL;\n\t\tlog = context.getWarningLog(); context.setWarningLog(NULL); delete log; log = NULL;\n\t\tlog = context.getInfoLog(); context.setInfoLog(NULL); delete log; log = NULL;\n\t\tlog = context.getDebugLog(); context.setDebugLog(NULL); delete log; log = NULL;\n\t\tlog = context.getAssertLog(); context.setAssertLog(NULL); delete log; log = NULL;\n\t\tINelContext::getInstance().setAlreadyCreateSharedAmongThreads(false);\n\t}\n}\n\nvoid createDebug (const char *logPath, bool logInFile, bool eraseLastLog)\n{\n\t// Do some basic compiler time check on type size\n\tnlctassert(sizeof(char) == 1);\n\n//\tstatic bool alreadyCreateSharedAmongThreads = false;\n//\tif ( !alreadyCreateSharedAmongThreads )\n\tif (!INelContext::getInstance().getAlreadyCreateSharedAmongThreads())\n\t{\n\t\t// Debug Info for mutexes\n#ifdef MUTEX_DEBUG\n\t\tinitAcquireTimeMap();\n#endif\n\n#ifndef NL_COMP_MINGW\n#\tifdef NL_OS_WINDOWS\n//\t\tif (!IsDebuggerPresent ())\n\t\t{\n\t\t\t// Use an environment variable to share the value among the EXE and its child DLLs\n\t\t\t// (otherwise there would be one distinct bool by module, and the last\n\t\t\t// _set_se_translator would overwrite the previous ones)\n\t\t\tconst TCHAR *SE_TRANSLATOR_IN_MAIN_MODULE = _T(\"NEL_SE_TRANS\");\n\t\t\tTCHAR envBuf [2];\n\t\t\tif ( GetEnvironmentVariable( SE_TRANSLATOR_IN_MAIN_MODULE, envBuf, 2 ) == 0)\n\t\t\t{\n\t\t\t\t_set_se_translator(exceptionTranslator);\n\t\t\t\tSetEnvironmentVariable( SE_TRANSLATOR_IN_MAIN_MODULE, _T(\"1\") );\n\t\t\t}\n\t\t}\n#\tendif // NL_OS_WINDOWS\n#endif //!NL_COMP_MINGW\n\n\t\tINelContext::getInstance().setErrorLog(new CLog (CLog::LOG_ERROR));\n\t\tINelContext::getInstance().setWarningLog(new CLog (CLog::LOG_WARNING));\n\t\tINelContext::getInstance().setInfoLog(new CLog (CLog::LOG_INFO));\n\t\tINelContext::getInstance().setDebugLog(new CLog (CLog::LOG_DEBUG));\n\t\tINelContext::getInstance().setAssertLog(new CLog (CLog::LOG_ASSERT));\n\n\t\tsd = new CStdDisplayer (\"DEFAULT_SD\");\n\n#ifdef NL_OS_WINDOWS\n\t\tif (TrapCrashInDebugger || !IsDebuggerPresent ())\n\t\t{\n\t\t\tDefaultMsgBoxDisplayer = new CMsgBoxDisplayer (\"DEFAULT_MBD\");\n\t\t}\n#endif\n\n#if LOG_IN_FILE\n\t\tif (logInFile)\n\t\t{\n\t\t\tstring fn;\n\t\t\tif (logPath != NULL)\n\t\t\t{\n\t\t\t\tLogPath = CPath::standardizePath(logPath);\n\t\t\t\tfn += LogPath;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n// we want the log.log to be in the current directory\n//\t\t\t\tchar\ttmpPath[1024];\n//\t\t\t\tfn += getcwd(tmpPath, 1024);\n//\t\t\t\tfn += \"/\";\n\t\t\t}\n\t\t\tfn += \"log.log\";\n#if FINAL_VERSION\n\t\t\tfd = new CFileDisplayer (fn, true, \"DEFAULT_FD\");\n#else // FINAL_VERSION\n\t\t\tfd = new CFileDisplayer (fn, eraseLastLog, \"DEFAULT_FD\");\n#endif // FINAL_VERSION\n\t\t}\n#endif // LOG_IN_FILE\n\t\tDefaultMemDisplayer = new CMemDisplayer (\"DEFAULT_MD\");\n\n#ifdef NL_OS_WINDOWS\n\t\tif (GetConsoleWindow() == NULL)\n\t\t\tINelContext::getInstance().setWindowedApplication(true);\n#endif\n\n\t\tinitDebug2(logInFile);\n\n\t\tINelContext::getInstance().setAlreadyCreateSharedAmongThreads(true);\n//\t\talreadyCreateSharedAmongThreads = true;\n\t}\n}\n\n\n/*\n * Beep (Windows only, no effect elsewhere)\n */\nvoid beep( uint freq, uint duration )\n{\n#ifdef NL_OS_WINDOWS\n\tBeep( freq, duration );\n#endif\n}\n\n\n//\n// Instance counter\n//\n\nNLMISC_SAFE_SINGLETON_IMPL(CInstanceCounterManager);\n\nCInstanceCounterLocalManager *CInstanceCounterLocalManager::_Instance = NULL;\n\nTInstanceCounterData::TInstanceCounterData(const char *className)\n:\t_InstanceCounter(0),\n\t_DeltaCounter(0),\n\t_ClassName(className),\n\t_Touched(false)\n{\n\tCInstanceCounterLocalManager::getInstance().registerInstanceCounter(this);\n}\n\nTInstanceCounterData::~TInstanceCounterData()\n{\n\tCInstanceCounterLocalManager::getInstance().unregisterInstanceCounter(this);\n}\n\n\nvoid CInstanceCounterManager::registerInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr)\n{\n\t_InstanceCounterMgrs.insert(localMgr);\n}\n\nvoid CInstanceCounterManager::unregisterInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr)\n{\n\t_InstanceCounterMgrs.erase(localMgr);\n}\n\n\nstd::string CInstanceCounterManager::displayCounters() const\n{\n\tmap<string, TInstanceCounterData> counters;\n\n\t{\n\t\t// gather counter information\n\t\tstd::set<CInstanceCounterLocalManager*>::const_iterator first2(_InstanceCounterMgrs.begin()), last2(_InstanceCounterMgrs.end());\n\t\tfor (; first2 != last2; ++first2)\n\t\t{\n\t\t\t// iterate over managers\n\t\t\tconst CInstanceCounterLocalManager *mgr = *first2;\n\t\t\t{\n\t\t\t\tstd::set<TInstanceCounterData*>::const_iterator first(mgr->_InstanceCounters.begin()), last(mgr->_InstanceCounters.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tconst TInstanceCounterData *icd = *first;\n\n\t\t\t\t\tif (!icd->_Touched)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif( counters.find(icd->_ClassName) == counters.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// insert a new item\n\t\t\t\t\t\tcounters.insert(make_pair(string(icd->_ClassName), TInstanceCounterData(*icd)));\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// accumulate the counter with the existing counter\n\t\t\t\t\t\tTInstanceCounterData &icddest = counters.find(icd->_ClassName)->second;\n\n\n\t\t\t\t\t\ticddest._DeltaCounter += icd->_DeltaCounter;\n\t\t\t\t\t\ticddest._InstanceCounter += icd->_InstanceCounter;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\tstring ret = toString(\"Listing %u Instance counters :\\n\", counters.size());\n\tmap<string, TInstanceCounterData>::iterator first(counters.begin()), last(counters.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tTInstanceCounterData &icd = first->second;\n\t\tret += toString(\"  Class '%-20s', \\t%10d instances, \\t%10d delta\\n\",\n\t\t\ticd._ClassName,\n\t\t\ticd._InstanceCounter,\n\t\t\ticd._InstanceCounter - icd._DeltaCounter);\n\t}\n\n\treturn ret;\n}\n\nvoid CInstanceCounterManager::resetDeltaCounter()\n{\n\tstd::set<CInstanceCounterLocalManager*>::iterator first2(_InstanceCounterMgrs.begin()), last2(_InstanceCounterMgrs.end());\n\tfor (; first2 != last2; ++first2)\n\t{\n\t\t// iterate over managers\n\t\tCInstanceCounterLocalManager *mgr = *first2;\n\t\t{\n\t\t\tstd::set<TInstanceCounterData*>::iterator first(mgr->_InstanceCounters.begin()), last(mgr->_InstanceCounters.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTInstanceCounterData *icd = *first;\n\n\t\t\t\ticd->_DeltaCounter = icd->_InstanceCounter;\n\t\t\t}\n\t\t}\n\t}\n}\n\nuint32 CInstanceCounterManager::getInstanceCounter(const std::string &className) const\n{\n\tuint32 result = 0;\n\tstd::set<CInstanceCounterLocalManager*>::const_iterator first2(_InstanceCounterMgrs.begin()), last2(_InstanceCounterMgrs.end());\n\tfor (; first2 != last2; ++first2)\n\t{\n\t\t// iterate over managers\n\t\tconst CInstanceCounterLocalManager *mgr = *first2;\n\t\t{\n\t\t\tstd::set<TInstanceCounterData*>::const_iterator first(mgr->_InstanceCounters.begin()), last(mgr->_InstanceCounters.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst TInstanceCounterData *icd = *first;\n\n\t\t\t\tif (icd->_ClassName == className)\n\t\t\t\t{\n\t\t\t\t\tresult += icd->_InstanceCounter;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nsint32 CInstanceCounterManager::getInstanceCounterDelta(const std::string &className) const\n{\n\tsint32 result = 0;\n\tstd::set<CInstanceCounterLocalManager*>::const_iterator first2(_InstanceCounterMgrs.begin()), last2(_InstanceCounterMgrs.end());\n\tfor (; first2 != last2; ++first2)\n\t{\n\t\t// iterate over managers\n\t\tconst CInstanceCounterLocalManager *mgr = *first2;\n\t\t{\n\t\t\tstd::set<TInstanceCounterData*>::const_iterator first(mgr->_InstanceCounters.begin()), last(mgr->_InstanceCounters.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst TInstanceCounterData *icd = *first;\n\n\t\t\t\tif (icd->_ClassName == className)\n\t\t\t\t{\n\t\t\t\t\tresult += icd->_InstanceCounter - icd->_DeltaCounter;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nvoid CInstanceCounterLocalManager::unregisterInstanceCounter(TInstanceCounterData *counter)\n{\n\t_InstanceCounters.erase(counter);\n\n\tif (_InstanceCounters.empty())\n\t{\n\t\t// no more need for the singleton\n\t\treleaseInstance();\n\t}\n}\n\n\n/// Return the last error code generated by a system call\nint getLastError()\n{\n#ifdef NL_OS_WINDOWS\n\treturn GetLastError();\n#else\n\treturn errno;\n#endif\n}\n\n/// Return a readable text according to the error code submited\nstd::string formatErrorMessage(int errorCode)\n{\n#ifdef NL_OS_WINDOWS\n\tLPVOID lpMsgBuf;\n\tFormatMessage(\n\t\tFORMAT_MESSAGE_ALLOCATE_BUFFER |\n\t\tFORMAT_MESSAGE_FROM_SYSTEM |\n\t\tFORMAT_MESSAGE_IGNORE_INSERTS,\n\t\tNULL,\n\t\terrorCode,\n\t\tMAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\n\t\t(LPTSTR) &lpMsgBuf,\n\t\t0,\n\t\tNULL\n\t);\n\n\tstring ret = (char*)lpMsgBuf;\n\t// Free the buffer.\n\tLocalFree( lpMsgBuf );\n\n\treturn ret;\n#else\n\treturn strerror(errorCode);\n#endif\n}\n\n\n\n//\n// Commands\n//\n\nNLMISC_CATEGORISED_COMMAND(nel, displayInstanceCounter, \"display the instance counters\", \"[<filter>]\")\n{\n\tstring className;\n\tif (args.size() == 1)\n\t\tclassName = args[0];\n\tif (args.size() > 1)\n\t\treturn false;\n\n\tstring list = CInstanceCounterManager::getInstance().displayCounters();\n\n\tvector<string> lines;\n\texplode(list, string(\"\\n\"), lines);\n\n\n\tfor (uint i=0; i<lines.size(); ++i)\n\t{\n\t\tif (!className.empty())\n\t\t{\n\t\t\tif (lines[i].find(className) == string::npos)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tlog.displayNL(lines[i].c_str());\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, resetInstanceCounterDelta, \"reset the delta value for instance counter\", \"\")\n{\n\tCInstanceCounterManager::getInstance().resetDeltaCounter();\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, displayMemlog, \"displays the last N line of the log in memory\", \"[<NbLines>]\")\n{\n\tuint nbLines;\n\n\tif (args.size() == 0) nbLines = 100;\n\telse if (args.size() == 1) NLMISC::fromString(args[0], nbLines);\n\telse return false;\n\n\tif (DefaultMemDisplayer == NULL) return false;\n\n\tdeque<string>::const_iterator it;\n\n\tconst deque<string> &str = DefaultMemDisplayer->lockStrings ();\n\n\tif (nbLines >= str.size())\n\t\tit = str.begin();\n\telse\n\t\tit = str.end() - nbLines;\n\n\tDefaultMemDisplayer->write (&log);\n\n\tDefaultMemDisplayer->unlockStrings ();\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, resetFilters, \"disable all filters on Nel loggers\", \"[debug|info|warning|error|assert]\")\n{\n\tif(args.size() == 0)\n\t{\n\t\tDebugLog->resetFilters();\n\t\tInfoLog->resetFilters();\n\t\tWarningLog->resetFilters();\n\t\tErrorLog->resetFilters();\n\t\tAssertLog->resetFilters();\n\t}\n\telse if (args.size() == 1)\n\t{\n\t\tif (args[0] == \"debug\") DebugLog->resetFilters();\n\t\telse if (args[0] == \"info\") InfoLog->resetFilters();\n\t\telse if (args[0] == \"warning\") WarningLog->resetFilters();\n\t\telse if (args[0] == \"error\") ErrorLog->resetFilters();\n\t\telse if (args[0] == \"assert\") AssertLog->resetFilters();\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addPositiveFilterDebug, \"add a positive filter on DebugLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tDebugLog->addPositiveFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addNegativeFilterDebug, \"add a negative filter on DebugLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tDebugLog->addNegativeFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, removeFilterDebug, \"remove a filter on DebugLog\", \"[<filterstr>]\")\n{\n\tif(args.size() == 0)\n\t\tDebugLog->removeFilter();\n\telse if(args.size() == 1)\n\t\tDebugLog->removeFilter( args[0].c_str() );\n\telse return false;\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, displayFilterDebug, \"display filter on DebugLog\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tDebugLog->displayFilter(log);\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addPositiveFilterInfo, \"add a positive filter on InfoLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tInfoLog->addPositiveFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addNegativeFilterInfo, \"add a negative filter on InfoLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tInfoLog->addNegativeFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, removeFilterInfo, \"remove a filter on InfoLog\", \"[<filterstr>]\")\n{\n\tif(args.size() == 0)\n\t\tInfoLog->removeFilter();\n\telse if(args.size() == 1)\n\t\tInfoLog->removeFilter( args[0].c_str() );\n\telse return false;\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, displayFilterInfo, \"display filter on InfoLog\", \"[d|i|w|e]\")\n{\n\tif(args.size() > 1) return false;\n\tif ( args.size() == 1 )\n\t{\n\t\tif ( strcmp( args[0].c_str(), \"d\" ) == 0 )\n\t\t\tInfoLog->displayFilter(*DebugLog);\n\t\telse if ( strcmp( args[0].c_str(), \"i\" ) == 0 )\n\t\t\tInfoLog->displayFilter(*InfoLog);\n\t\telse if ( strcmp( args[0].c_str(), \"w\" ) == 0 )\n\t\t\tInfoLog->displayFilter(*WarningLog);\n\t\telse if ( strcmp( args[0].c_str(), \"e\" ) == 0 )\n\t\t\tInfoLog->displayFilter(*ErrorLog);\n\t\telse\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\tInfoLog->displayFilter(log);\n\t}\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addPositiveFilterWarning, \"add a positive filter on WarningLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tWarningLog->addPositiveFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, addNegativeFilterWarning, \"add a negative filter on WarningLog\", \"<filterstr>\")\n{\n\tif(args.size() != 1) return false;\n\tWarningLog->addNegativeFilter( args[0].c_str() );\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, removeFilterWarning, \"remove a filter on WarningLog\", \"[<filterstr>]\")\n{\n\tif(args.size() == 0)\n\t\tWarningLog->removeFilter();\n\telse if(args.size() == 1)\n\t\tWarningLog->removeFilter( args[0].c_str() );\n\telse return false;\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, displayFilterWarning, \"display filter on WarningLog\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tWarningLog->displayFilter(log);\n\treturn true;\n}\n\n\n#if !FINAL_VERSION\n\n// commands to generate different \"crash\"\n\nNLMISC_CATEGORISED_COMMAND(nel, assert, \"generate a failed nlassert()\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tnlassertex (false, (\"Assert generated by the assert command\"));\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, stop, \"generate a nlstop()\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tnlstopex ((\"Stop generated by the stop command\"));\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, abort, \"generate a abort()\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tabort();\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, divbyzero, \"generate a divide by zero\", \"\")\n{\n\tif(args.size() != 0) return false;\n\tfloat a=10,b=0;\n\ta /= b;\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, writeaccess, \"write a uint8 value in an invalid address\", \"[<adr> [<value>]]\")\n{\n\tuint8 val = 123;\n\tuint8 *adr = (uint8*)0;\n\tif(args.size() >= 1)\n\t{\n#ifdef HAVE_X86_64\n\t\tuint64 addr64;\n\t\tNLMISC::fromString(args[0], addr64);\n\t\tadr = (uint8*)addr64;\n#else\n\t\tuint32 addr32;\n\t\tNLMISC::fromString(args[0], addr32);\n\t\tadr = (uint8*)addr32;\n#endif\n\t}\n\tif(args.size() >= 2) NLMISC::fromString(args[1], val);\n\t*adr = val;\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, readaccess, \"read a uint8 value in an invalid address\", \"[<adr>]\")\n{\n\tuint8 val;\n\tuint8 *adr = (uint8*)0;\n\tif(args.size() == 1)\n\t{\n#ifdef HAVE_X86_64\n\t\tuint64 addr64;\n\t\tNLMISC::fromString(args[0], addr64);\n\t\tadr = (uint8*)addr64;\n#else\n\t\tuint32 addr32;\n\t\tNLMISC::fromString(args[0], addr32);\n\t\tadr = (uint8*)addr32;\n#endif\n\t}\n\tval = *adr;\n\tlog.displayNL(\"value is %hu\", (uint16)val);\n\treturn true;\n}\n\n#endif // FINAL_VERSION\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/diff_tool.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/diff_tool.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace STRING_MANAGER\n{\n\nuint64 makePhraseHash(const TPhrase &phrase)\n{\n\tucstring text;\n\ttext = phrase.Parameters;\n\tfor (uint i=0; i<phrase.Clauses.size(); ++i)\n\t{\n\t\ttext += phrase.Clauses[i].Conditions;\n\t\ttext += phrase.Clauses[i].Identifier;\n\t\ttext += phrase.Clauses[i].Text;\n\t}\n\n\treturn CI18N::makeHash(text);\n}\n\n\n\n\nbool parseHashFromComment(const ucstring &comments, uint64 &hashValue)\n{\n\tstring str = comments.toString();\n\n\tstring::size_type pos = str.find(\"HASH_VALUE \");\n\tif (pos == string::npos)\n\t\treturn false;\n\n\tstring hashStr = str.substr(pos + 11, 16);\n\n\thashValue = CI18N::stringToHash(hashStr);\n\treturn true;\n}\n\n\nuint32 countLine(const ucstring &text, const ucstring::const_iterator upTo)\n{\n\tuint32 ret = 1;\n\tucstring::const_iterator first(text.begin());\n\n\tfor (; first != upTo; ++first)\n\t{\n\t\tif (*first == '\\n')\n\t\t\tret++;\n\t}\n\n\treturn ret;\n}\n\nbool loadStringFile(const std::string filename, vector<TStringInfo> &stringInfos, bool forceRehash, ucchar openMark, ucchar closeMark, bool specialCase)\n{\n/*\tuint8 *buffer = 0;\n\tuint\tsize;\n\n\ttry\n\t{\n\t\tCIFile fp(filename);\n\t\tsize = fp.getFileSize();\n\t\tbuffer = new uint8[size];\n\t\tfp.serialBuffer(buffer, size);\n\t}\n\tcatch(const Exception &e)\n\t{\n\t\tnlinfo(\"Can't open file [%s] (%s)\\n\", filename.c_str(), e.what());\n\t\treturn true;\n\t}\n*/\n/*\tFILE *fp = fopen(filename.c_str(), \"rb\");\n\n\tif (fp == NULL)\n\t{\n\t\tnlinfo(\"Can't open file [%s]\\n\", filename.c_str());\n\t\tif (buffer != 0)\n\t\t\tdelete [] buffer;\n\t\treturn true;\n\t}\n\n\t// move to end of file\n\tfseek(fp, 0, SEEK_END);\n\n\tfpos_t\tpos;\n\tfgetpos(fp, &pos);\n\n\tuint8 *buffer = new uint8[uint(pos)];\n\n\trewind(fp);\n\tuint size = fread(buffer, 1, uint(pos), fp);\n\tfclose (fp);\n*/\n\tucstring text;\n\n\tCI18N::readTextFile(filename, text, false, false, true, CI18N::LINE_FMT_CRLF);\n//\tCI18N::readTextBuffer(buffer, size, text);\n//\tdelete [] buffer;\n\n\t// ok, parse the file now.\n\tucstring::const_iterator first(text.begin()), last(text.end());\n\tstd::string lastLabel(\"nothing\");\n\n\twhile (first != last)\n\t{\n\t\tTStringInfo si;\n\t\tCI18N::skipWhiteSpace(first, last, &si.Comments);\n\n\t\tif (first == last)\n\t\t{\n\t\t\t// check if there is only swap command remaining in comment\n\t\t\tif (si.Comments.find(ucstring(\"// DIFF SWAP \")) != ucstring::npos)\n\t\t\t{\n\t\t\t\tstringInfos.push_back(si);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// try to read a #fileline preprocessor command\n\t\tif (CI18N::matchToken(\"#fileline\", first, last))\n\t\t{\n\t\t\t// for now, just skip\n\t\t\tuint32 lineCounter =0;\t// we count line another way\n\t\t\tCI18N::skipLine(first, last, lineCounter);\n\n\t\t\t// begin parse of next line\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!CI18N::parseLabel(first, last, si.Identifier))\n\t\t{\n\t\t\tuint32 line = countLine(text, first);\n\t\t\tnlwarning(\"DT: Fatal : In '%s', line %u: Invalid label after '%s'\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tlastLabel.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tlastLabel = si.Identifier;\n\n\t\tCI18N::skipWhiteSpace(first, last, &si.Comments);\n\n\t\tif (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text))\n\t\t{\n\t\t\tuint32 line = countLine(text, first);\n\t\t\tnlwarning(\"DT: Fatal : In '%s', line %u: Invalid text value for label %s\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tlastLabel.c_str());\n\t\t\treturn false;\n\t\t}\n\n\t\tif (specialCase)\n\t\t{\n\t\t\tCI18N::skipWhiteSpace(first, last, &si.Comments);\n\n\t\t\tif (!CI18N::parseMarkedString(openMark, closeMark, first, last, si.Text2))\n\t\t\t{\n\t\t\t\tuint32 line = countLine(text, first);\n\t\t\t\tnlwarning(\"DT: Fatal: In '%s' line %u: Invalid text2 value label %s\\n\",\n\t\t\t\t\tfilename.c_str(),\n\t\t\t\t\tline,\n\t\t\t\t\tlastLabel.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t}\n\n\t\tif (forceRehash || !parseHashFromComment(si.Comments, si.HashValue))\n\t\t{\n\t\t\t// compute the hash value from text.\n\t\t\tsi.HashValue = CI18N::makeHash(si.Text);\n//\t\t\tnldebug(\"Generating hash for %s as %s\", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str());\n\t\t}\n\t\telse\n\t\t{\n//\t\t\tnldebug(\"Comment = [%s]\", si.Comments.toString().c_str());\n//\t\t\tnldebug(\"Retrieving hash for %s as %s\", si.Identifier.c_str(), CI18N::hashToString(si.HashValue).c_str());\n\t\t}\n\t\tstringInfos.push_back(si);\n\t}\n\n\n\t// check identifier uniqueness\n\t{\n\t\tbool error = false;\n\t\tset<string>\tunik;\n\t\tset<string>::iterator it;\n\t\tfor (uint i=0; i<stringInfos.size(); ++i)\n\t\t{\n\t\t\tit = unik.find(stringInfos[i].Identifier);\n\t\t\tif (it != unik.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"DT: loadStringFile : identifier '%s' exist twice\", stringInfos[i].Identifier.c_str() );\n\t\t\t\terror = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tunik.insert(stringInfos[i].Identifier);\n\n\t\t}\n\t\tif (error)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n\nucstring prepareStringFile(const vector<TStringInfo> &strings, bool removeDiffComments, bool noDiffInfo)\n{\n\tucstring diff;\n\n\tvector<TStringInfo>::const_iterator first(strings.begin()), last(strings.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tucstring str;\n\t\tconst TStringInfo &si = *first;\n\t\tstring comment = si.Comments.toString();\n\t\tvector<string>\tlines;\n\t\texplode(comment, string(\"\\n\"), lines, true);\n\n\t\tuint i;\n\t\tfor (i=0; i<lines.size(); ++i)\n\t\t{\n\t\t\tif (removeDiffComments)\n\t\t\t{\n\t\t\t\tif (lines[i].find(\"// DIFF \") != string::npos)\n\t\t\t\t{\n\t\t\t\t\tlines.erase(lines.begin()+i);\n\t\t\t\t\t--i;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (lines[i].find(\"// INDEX \") != string::npos)\n\t\t\t{\n\t\t\t\tlines.erase(lines.begin()+i);\n\t\t\t\t--i;\n\t\t\t}\n\t\t\telse if (lines[i].find(\"// HASH_VALUE \") != string::npos)\n\t\t\t{\n\t\t\t\tlines.erase(lines.begin()+i);\n\t\t\t\t--i;\n\t\t\t}\n\t\t}\n\n\t\tcomment.erase();\n\t\tfor (i=0; i<lines.size(); ++i)\n\t\t{\n\t\t\tcomment += lines[i] + \"\\n\";\n\t\t}\n\t\tsi.Comments = ucstring(comment);\n\n\t\tstr = si.Comments;\n\t\tif (!si.Identifier.empty() || !si.Text.empty())\n\t\t{\n\t\t\t// add hash value comment if needed\n//\t\t\tif (si.Comments.find(ucstring(\"// HASH_VALUE \")) == ucstring::npos)\n\t\t\tif (!noDiffInfo)\n\t\t\t{\n\t\t\tstr += ucstring(\"// HASH_VALUE \") + CI18N::hashToString(si.HashValue)+ nl;\n\t\t\tstr += ucstring(\"// INDEX \") + NLMISC::toString(\"%u\", first-strings.begin())+ nl;\n\t\t\t}\n\t\t\tstr += si.Identifier + '\\t';\n\n\t\t\tucstring text = CI18N::makeMarkedString('[', ']', si.Text);;\n\t\t\tucstring text2;\n\t\t\t// add new line and tab after each \\n tag\n\t\t\tucstring::size_type pos;\n\t\t\tconst ucstring nlTag(\"\\\\n\");\n\t\t\twhile ((pos = text.find(nlTag)) != ucstring::npos)\n\t\t\t{\n\t\t\t\ttext2 += text.substr(0, pos+2) + nl + \"\\t\";\n\t\t\t\ttext = text.substr(pos+2);\n\t\t\t}\n\t\t\ttext2 += text;//.substr(0, pos+2);\n\t\t\tstr += text2 + nl + nl;\n//\t\t\tstr += CI18N::makeMarkedString('[', ']', si.Text) + nl + nl;\n\t\t}\n\n//\t\tnldebug(\"Adding string [%s]\", str.toString().c_str());\n\t\tdiff += str;\n\t}\n\n\treturn diff;\n}\n\n\nbool readPhraseFile(const std::string &filename, vector<TPhrase> &phrases, bool forceRehash)\n{\n\tucstring doc;\n\n\tCI18N::readTextFile(filename, doc, false, false, true, CI18N::LINE_FMT_CRLF);\n\n\treturn readPhraseFileFromString(doc, filename, phrases, forceRehash);\n}\n\nbool readPhraseFileFromString(ucstring const& doc, const std::string &filename, vector<TPhrase> &phrases, bool forceRehash)\n{\n\tstd::string lastRead(\"nothing\");\n\n\tucstring::const_iterator first(doc.begin()), last(doc.end());\n\twhile (first != last)\n\t{\n\t\tTPhrase\tphrase;\n\t\t// parse the phrase\n\t\tCI18N::skipWhiteSpace(first, last, &phrase.Comments);\n\n\t\tif (first == last)\n\t\t{\n\t\t\tif (!phrase.Comments.empty())\n\t\t\t{\n\t\t\t\t// push the resulting comment\n\t\t\t\tphrases.push_back(phrase);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// try to read a #fileline preprocessor command\n\t\tif (CI18N::matchToken(\"#fileline\", first, last))\n\t\t{\n\t\t\t// for now, just skip\n\t\t\tuint32 lineCounter =0;\t// we count line another way\n\t\t\tCI18N::skipLine(first, last, lineCounter);\n\n\t\t\t// begin parse of next line\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!CI18N::parseLabel(first, last, phrase.Identifier))\n\t\t{\n\t\t\tuint32 line = countLine(doc, first);\n\t\t\tnlwarning(\"DT: In '%s' line %u: Error parsing phrase identifier after %s\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tlastRead.c_str());\n\t\t\treturn false;\n\t\t}\n//\t\tnldebug(\"DT: parsing phrase '%s'\", phrase.Identifier.c_str());\n\t\tlastRead = phrase.Identifier;\n\t\tCI18N::skipWhiteSpace(first, last, &phrase.Comments);\n\t\tif (!CI18N::parseMarkedString('(', ')', first, last, phrase.Parameters))\n\t\t{\n\t\t\tuint32 line = countLine(doc, first);\n\t\t\tnlwarning(\"DT: in '%s', line %u: Error parsing parameter list for phrase %s\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tphrase.Identifier.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tCI18N::skipWhiteSpace(first, last, &phrase.Comments);\n\t\tif (first == last || *first != '{')\n\t\t{\n\t\t\tuint32 line = countLine(doc, first);\n\t\t\tnlwarning(\"DT: In '%s', line %u: Error parsing block opening '{' in phase %s\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tphrase.Identifier.c_str());\n\t\t\treturn false;\n\t\t}\n\t\t++first;\n\n\t\tucstring temp;\n\n\t\twhile (first != last && *first != '}')\n\t\t{\n\t\t\tTClause\tclause;\n\t\t\t// append the comment preread at previous pass\n\t\t\tclause.Comments = temp;\n\t\t\ttemp.erase();\n\t\t\t// parse the clauses\n\t\t\tCI18N::skipWhiteSpace(first, last, &clause.Comments);\n\t\t\tif (first == last)\n\t\t\t{\n\t\t\t\tnlwarning(\"DT: Found end of file in non closed block for phrase %s\\n\", phrase.Identifier.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (*first == '}')\n\t\t\t\tbreak;\n\n\t\t\t// skip the conditional expression\n\t\t\tucstring cond;\n\t\t\twhile (first != last && *first == '(')\n\t\t\t{\n\t\t\t\tif (!CI18N::parseMarkedString('(', ')', first, last, cond))\n\t\t\t\t{\n\t\t\t\t\tuint32 line = countLine(doc, first);\n\t\t\t\t\tnlwarning(\"DT: In '%s' line %u: Error parsing conditional expression in phrase %s, clause %u\\n\",\n\t\t\t\t\t\tfilename.c_str(),\n\t\t\t\t\t\tline,\n\t\t\t\t\t\tphrase.Identifier.c_str(),\n\t\t\t\t\t\tphrase.Clauses.size()+1);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tclause.Conditions += \"(\" + cond + \") \";\n\t\t\t\tCI18N::skipWhiteSpace(first, last, &clause.Comments);\n\t\t\t}\n\t\t\tif (first == last)\n\t\t\t{\n\t\t\t\tnlwarning(\"DT: in '%s': Found end of file in non closed block for phrase %s\\n\",\n\t\t\t\t\tfilename.c_str(),\n\t\t\t\t\tphrase.Identifier.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// read the idnetifier (if any)\n\t\t\tCI18N::parseLabel(first, last, clause.Identifier);\n\t\t\tCI18N::skipWhiteSpace(first, last, &temp);\n\t\t\t// read the text\n\t\t\tif (CI18N::parseMarkedString('[', ']', first, last, clause.Text))\n\t\t\t{\n\t\t\t\t// the last read comment is for this clause.\n\t\t\t\tclause.Comments += temp;\n\t\t\t\ttemp.erase();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint32 line = countLine(doc, first);\n\t\t\t\tnlwarning(\"DT: in '%s' line %u: Error reading text for clause %u (%s) in  phrase %s\\n\",\n\t\t\t\t\tfilename.c_str(),\n\t\t\t\t\tline,\n\t\t\t\t\tphrase.Clauses.size()+1,\n\t\t\t\t\tclause.Identifier.c_str(),\n\t\t\t\t\tphrase.Identifier.c_str());\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t\tphrase.Clauses.push_back(clause);\n\t\t}\n\t\tCI18N::skipWhiteSpace(first, last);\n\t\tif (first == last || *first != '}')\n\t\t{\n\t\t\tuint32 line = countLine(doc, first);\n\t\t\tnlwarning(\"DT: in '%s' line %u: Missing block closing tag '}' in phrase %s\\n\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tline,\n\t\t\t\tphrase.Identifier.c_str());\n\t\t\treturn false;\n\t\t}\n\t\t++first;\n\n\t\t// handle hash value.\n\t\tif (forceRehash || !parseHashFromComment(phrase.Comments, phrase.HashValue))\n\t\t{\n\t\t\t// the hash is not in the comment, compute it.\n\t\t\tphrase.HashValue = makePhraseHash(phrase);\n\t\t\tif (forceRehash)\n\t\t\t{\n\t\t\t\t// the has is perhaps in the comment\n\t\t\t\tucstring::size_type pos = phrase.Comments.find(ucstring(\"// HASH_VALUE\"));\n\t\t\t\tif (pos != ucstring::npos)\n\t\t\t\t{\n\t\t\t\t\tphrase.Comments = phrase.Comments.substr(0, pos);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n//\t\tnldebug(\"DT : storing phrase '%s'\", phrase.Identifier.c_str());\n\t\tphrases.push_back(phrase);\n\t}\n\n\t// check identifier uniqueness\n\t{\n\t\tbool error = false;\n\t\tset<string>\tunik;\n\t\tset<string>::iterator it;\n\t\tfor (uint i=0; i<phrases.size(); ++i)\n\t\t{\n\t\t\tit = unik.find(phrases[i].Identifier);\n\t\t\tif (it != unik.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"DT: readPhraseFile : identifier '%s' exist twice\", phrases[i].Identifier.c_str() );\n\t\t\t\terror = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tunik.insert(phrases[i].Identifier);\n\t\t}\n\t\tif (error)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\nucstring tabLines(uint nbTab, const ucstring &str)\n{\n\tucstring ret;\n\tucstring tabs;\n\n\tfor (uint i =0; i<nbTab; ++i)\n\t\ttabs.push_back('\\t');\n\n\tret = tabs;\n\tucstring::const_iterator first(str.begin()), last(str.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tret += *first;\n\t\tif (*first == '\\n')\n\t\t\tret += tabs;\n\t}\n\n\twhile (ret[ret.size()-1] == '\\t')\n\t\tret = ret.substr(0, ret.size()-1);\n\n\treturn ret;\n}\n\nucstring preparePhraseFile(const vector<TPhrase> &phrases, bool removeDiffComments)\n{\n\tucstring ret;\n\tvector<TPhrase>::const_iterator first(phrases.begin()), last(phrases.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tconst TPhrase &p = *first;\n\n\t\tif (removeDiffComments)\n\t\t{\n\t\t\tstring comment = p.Comments.toString();\n\t\t\tvector<string>\tlines;\n\t\t\texplode(comment, string(\"\\n\"), lines, true);\n\n\t\t\tuint i;\n\t\t\tfor (i=0; i<lines.size(); ++i)\n\t\t\t{\n\t\t\t\tif (lines[i].find(\"// DIFF \") != string::npos)\n\t\t\t\t{\n\t\t\t\t\tlines.erase(lines.begin()+i);\n\t\t\t\t\t--i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcomment.erase();\n\t\t\tfor (i=0; i<lines.size(); ++i)\n\t\t\t{\n\t\t\t\tcomment += lines[i] + \"\\n\";\n\t\t\t}\n\t\t\tp.Comments = ucstring(comment);\n\t\t}\n\t\tret += p.Comments;\n\n\t\tif (!p.Identifier.empty() || !p.Clauses.empty())\n\t\t{\n\t\t\tif (p.Comments.find(ucstring(\"// HASH_VALUE \")) == ucstring::npos)\n\t\t\t{\n\t\t\t\t// add the hash value.\n\t\t\t\tret += ucstring(\"// HASH_VALUE \")+CI18N::hashToString(p.HashValue) + nl;\n\t\t\t}\n\t\t\tret += p.Identifier + \" (\"+p.Parameters + \")\" + nl;\n\t\t\tret += '{';\n\t\t\tret += nl;\n\t\t\tfor (uint i=0; i<p.Clauses.size(); ++i)\n\t\t\t{\n\t\t\t\tconst TClause &c = p.Clauses[i];\n\t\t\t\tif (!c.Comments.empty())\n\t\t\t\t{\n\t\t\t\t\tucstring comment = tabLines(1, c.Comments);\n\t\t\t\t\tret += comment; // + '\\r'+'\\n';\n\t\t\t\t}\n\t\t\t\tif (!c.Conditions.empty())\n\t\t\t\t{\n\t\t\t\t\tucstring cond = tabLines(1, c.Conditions);\n\t\t\t\t\tret += cond + nl;\n\t\t\t\t}\n\t\t\t\tret += '\\t';\n//\t\t\t\tucstring text = CI18N::makeMarkedString('[', ']', c.Text);\n\n\t\t\t\tucstring text = CI18N::makeMarkedString('[', ']', c.Text);;\n\t\t\t\tucstring text2;\n\t\t\t\t// add new line and tab after each \\n tag\n\t\t\t\tucstring::size_type pos;\n\t\t\t\tconst ucstring nlTag(\"\\\\n\");\n\t\t\t\twhile ((pos = text.find(nlTag)) != ucstring::npos)\n\t\t\t\t{\n\t\t\t\t\ttext2 += text.substr(0, pos+2) + nl;\n\t\t\t\t\ttext = text.substr(pos+2);\n\t\t\t\t}\n\t\t\t\ttext2 += text;//.substr(0, pos+2);\n\n\t\t\t\ttext.swap(text2);\n\n\t\t\t\ttext = tabLines(3, text);\n\t\t\t\t// remove begin tabs\n\t\t\t\ttext = text.substr(3);\n\t\t\t\tret += '\\t' + c.Identifier + '\\t' + text + nl + nl;\n\t\t\t}\n\t\t\tret += '}';\n\t\t}\n\t\tret += nl + nl;\n\t}\n\n\treturn ret;\n}\n\nbool loadExcelSheet(const string filename, TWorksheet &worksheet, bool checkUnique)\n{\n\t// Yoyo: must test with CIFile because can be packed into a .bnp on client...\n\tCIFile\tfp;\n\tif(!fp.open(filename))\n\t{\n\t\tnldebug(\"DT: Can't open file [%s]\\n\", filename.c_str());\n\t\treturn true;\n\t}\n\tfp.close();\n\n\tucstring str;\n\tCI18N::readTextFile(filename, str, false, false, false, CI18N::LINE_FMT_CRLF);\n\n\tif (!readExcelSheet(str, worksheet, checkUnique))\n\t\treturn false;\n\n\treturn true;\n}\n\nbool readExcelSheet(const ucstring &str, TWorksheet &worksheet, bool checkUnique)\n{\n\tif(str.empty())\n\t\treturn true;\n\n\t// copy the str to a big ucchar array => Avoid allocation / free\n\tvector<ucchar>\tstrArray;\n\t// append a '\\0'\n\tstrArray.resize(str.size()+1);\n\tstrArray[strArray.size()-1]= 0;\n\tmemcpy(&strArray[0], &str[0], str.size()*sizeof(ucchar));\n\n\n\t// **** Build array of lines. just point to strArray, and fill 0 where appropriated\n\tvector<ucchar*> lines;\n\tlines.reserve(500);\n\tucstring::size_type pos = 0;\n\tucstring::size_type lastPos = 0;\n\twhile ((pos = str.find(nl, lastPos)) != ucstring::npos)\n\t{\n\t\tif (pos>lastPos)\n\t\t{\n\t\t\tstrArray[pos]= 0;\n//\t\t\tnldebug(\"Found line : [%s]\", ucstring(&strArray[lastPos]).toString().c_str());\n\t\t\tlines.push_back(&strArray[lastPos]);\n\t\t}\n\t\tlastPos = pos + 2;\n\t}\n\n\t// Must add last line if no \\r\\n ending\n\tif (lastPos < str.size())\n\t{\n\t\tpos= str.size();\n\t\tstrArray[pos]= 0;\n//\t\tnldebug(\"Found line : [%s]\", ucstring(&strArray[lastPos]).toString().c_str());\n\t\tlines.push_back(&strArray[lastPos]);\n\t}\n\n//\tnldebug(\"Found %u lines\", lines.size());\n\n\t// **** Do 2 pass.1st count the cell number, then fill. => avoid reallocation\n\tuint\t\tnewColCount= 0;\n\tuint\t\ti;\n\tfor (i=0; i<lines.size(); ++i)\n\t{\n\t\tuint\tnumCells;\n\t\tnumCells= 0;\n\n\t\tucchar\t*first= lines[i];\n\t\tfor (; *first != 0; ++first)\n\t\t{\n\t\t\tif (*first == '\\t')\n\t\t\t{\n\t\t\t\tnumCells++;\n\t\t\t}\n\t\t\telse if (*first == '\"' && first==lines[i])\n\t\t\t{\n\t\t\t\t// read a quoted field.\n\t\t\t\tfirst++;\n\t\t\t\twhile (*first != 0 && *first != '\"' && *(first+1) != 0 && *(first+1) != '\"')\n\t\t\t\t{\n\t\t\t\t\tfirst++;\n\t\t\t\t\tif (*first != 0 && *first == '\"')\n\t\t\t\t\t{\n\t\t\t\t\t\t// skip this\n\t\t\t\t\t\tfirst++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// last cell\n\t\tnumCells++;\n\n\t\t// take max cell of all lines\n\t\tif (newColCount != max(newColCount, numCells))\n\t\t{\n\t\t\tnewColCount = max(newColCount, numCells);\n\t\t\tnldebug(\"At line %u, numCol changed to %u\",\n\t\t\t\ti, newColCount);\n\t\t}\n\t}\n\n\n\t// **** alloc / enlarge worksheet\n\t// enlarge Worksheet column size, as needed\n\twhile (worksheet.ColCount < newColCount)\n\t\tworksheet.insertColumn(worksheet.ColCount);\n\n\t// enlarge Worksheet row size, as needed\n\tuint\tstartLine= worksheet.size();\n\tworksheet.resize(startLine + (uint)lines.size());\n\n\n\t// **** fill worksheet\n\tucstring\tcell;\n\tfor (i=0; i<lines.size(); ++i)\n\t{\n\t\tuint\tnumCells;\n\t\tnumCells= 0;\n\t\tcell.erase();\n\n\t\tucchar\t*first= lines[i];\n\t\tfor (; *first != 0; ++first)\n\t\t{\n\t\t\tif (*first == '\\t')\n\t\t\t{\n//\t\t\t\tnldebug(\"Found cell [%s]\", cell.toString().c_str());\n\t\t\t\tworksheet.setData(startLine + i, numCells, cell);\n\t\t\t\tnumCells++;\n\t\t\t\tcell.erase();\n\t\t\t}\n\t\t\telse if (*first == '\"' && first==lines[i])\n\t\t\t{\n\t\t\t\t// read a quoted field.\n\t\t\t\tfirst++;\n\t\t\t\twhile (*first != 0 && *first != '\"' && *(first+1) != 0 && *(first+1) != '\"')\n\t\t\t\t{\n\t\t\t\t\tcell += *first;\n\t\t\t\t\tfirst++;\n\t\t\t\t\tif (*first != 0 && *first == '\"')\n\t\t\t\t\t{\n\t\t\t\t\t\t// skip this\n\t\t\t\t\t\tfirst++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tcell += *first;\n\t\t\t}\n\t\t}\n//\t\tnldebug(\"Found cell [%s]\", cell.toString().c_str());\n\t\t/// append last cell\n\t\tworksheet.setData(startLine + i, numCells, cell);\n\t\tnumCells++;\n\t\tnlassertex(numCells<=newColCount, (\"readExcelSheet: bad row format: at line %u, the row has %u cell, max is %u\", i, numCells, newColCount));\n//\t\tnldebug(\"Found %u cells in line %u\", numCells, i);\n\t}\n\n\n\t// **** identifier uniqueness checking.\n\tif (checkUnique)\n\t{\n\t\tif (worksheet.size() > 0)\n\t\t{\n\t\t\t// look for the first non '* tagged' or 'DIFF_CMD' column\n\t\t\tuint nameCol = 0;\n\t\t\twhile (nameCol < worksheet.ColCount && (*worksheet.getData(0, nameCol).begin() == uint16('*') || worksheet.getData(0, nameCol) == ucstring(\"DIFF_CMD\")))\n\t\t\t\t++nameCol;\n\n\t\t\tif (nameCol < worksheet.ColCount )\n\t\t\t{\n\t\t\t\t// ok we can check unikness\n\t\t\t\tbool error = false;\n\t\t\t\tset<ucstring>\tunik;\n\t\t\t\tset<ucstring>::iterator it;\n\t\t\t\tfor (uint j=0; j<worksheet.size(); ++j)\n\t\t\t\t{\n\t\t\t\t\tit = unik.find(worksheet.getData(j, nameCol));\n\t\t\t\t\tif (it != unik.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning(\"DT: readExcelSheet : identifier '%s' exist twice\", worksheet.getData(j, nameCol).toString().c_str() );\n\t\t\t\t\t\terror = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tunik.insert(worksheet.getData(j, nameCol));\n\t\t\t\t}\n\t\t\t\tif (error)\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid makeHashCode(TWorksheet &sheet, bool forceRehash)\n{\n\tif (!sheet.Data.empty())\n\t{\n\t\tTWorksheet::TRow::iterator it = find(sheet.Data[0].begin(), sheet.Data[0].end(), ucstring(\"*HASH_VALUE\"));\n\t\tif (forceRehash || it == sheet.Data[0].end())\n\t\t{\n\t\t\t// we need to generate HASH_VALUE column !\n\t\t\tif (it == sheet.Data[0].end())\n\t\t\t{\n\t\t\t\tsheet.insertColumn(0);\n\t\t\t\tsheet.Data[0][0] = ucstring(\"*HASH_VALUE\");\n\t\t\t}\n\n\t\t\t// Check columns\n\t\t\tvector<bool>\tcolumnOk;\n\t\t\tcolumnOk.resize(sheet.ColCount, false);\n\t\t\tfor (uint k=1; k<sheet.ColCount; ++k)\n\t\t\t{\n\t\t\t\tif (sheet.Data[0][k].find(ucstring(\"*\")) != 0 && sheet.Data[0][k].find(ucstring(\"DIFF \")) != 0)\n\t\t\t\t{\n\t\t\t\t\tcolumnOk[k]= true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// make hash for each line\n\t\t\tucstring str;\n\t\t\tfor (uint j=1; j<sheet.Data.size(); ++j)\n\t\t\t{\n\t\t\t\tstr.erase();\n\t\t\t\tfor (uint k=1; k<sheet.ColCount; ++k)\n\t\t\t\t{\n\t\t\t\t\tif (columnOk[k])\n\t\t\t\t\t{\n\t\t\t\t\t\tstr += sheet.Data[j][k];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tuint64 hash = CI18N::makeHash(str);\n\t\t\t\tCI18N::hashToUCString(hash, sheet.Data[j][0]);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuint index = (uint)(it - sheet.Data[0].begin());\n\t\t\tfor (uint j=1; j<sheet.Data.size(); ++j)\n\t\t\t{\n\t\t\t\tucstring &field = sheet.Data[j][index];\n\n\t\t\t\tif (!field.empty() && field[0] == '_')\n\t\t\t\t\tfield = field.substr(1);\n\t\t\t}\n\t\t}\n\t}\n}\n\nucstring prepareExcelSheet(const TWorksheet &worksheet)\n{\n\tif(worksheet.Data.empty())\n\t\treturn ucstring();\n\n\t// **** First pass: count approx the size\n\tuint\tapproxSize= 0;\n\tfor (uint i=0; i<worksheet.Data.size(); ++i)\n\t{\n\t\tfor (uint j=0; j<worksheet.Data[i].size(); ++j)\n\t\t{\n\t\t\tapproxSize+= (uint)worksheet.Data[i][j].size() + 1;\n\t\t}\n\t\tapproxSize++;\n\t}\n\n\t// Hash value for each column?\n\tvector<bool>\thashValue;\n\thashValue.resize(worksheet.Data[0].size());\n\tfor (uint j=0; j<worksheet.Data[0].size(); ++j)\n\t{\n\t\thashValue[j]= worksheet.Data[0][j] == ucstring(\"*HASH_VALUE\");\n\t}\n\n\t// **** Second pass: fill\n\tucstring text;\n\ttext.reserve(approxSize*2);\n\tfor (uint i=0; i<worksheet.Data.size(); ++i)\n\t{\n\t\tfor (uint j=0; j<worksheet.Data[i].size(); ++j)\n\t\t{\n\t\t\tif (i > 0 && hashValue[j] && (!worksheet.Data[i][j].empty() && worksheet.Data[i][j][0] != '_'))\n\t\t\t\ttext += \"_\";\n\t\t\ttext += worksheet.Data[i][j];\n\t\t\tif (j != worksheet.Data[i].size()-1)\n\t\t\t\ttext += '\\t';\n\t\t}\n\t\ttext += nl;\n\t}\n\n\treturn text;\n}\n\n\n\n\n\n\n\n}\t// namespace STRING_MANAGER\n\n"
  },
  {
    "path": "code/nel/src/misc/displayer.cpp",
    "content": "﻿// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n\n#ifndef NL_OS_WINDOWS\n#\tdefine IsDebuggerPresent() false\n#endif\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <io.h>\n#\tinclude <fcntl.h>\n#\tinclude <sys/types.h>\n#\tinclude <sys/stat.h>\n#else\n#\tinclude <cerrno>\n#endif // NL_OS_WINDOWS\n\n#include \"nel/misc/path.h\"\n#include \"nel/misc/mutex.h\"\n#include \"nel/misc/report.h\"\n#include \"nel/misc/system_utils.h\"\n#include \"nel/misc/variable.h\"\n\n#include \"nel/misc/debug.h\"\n\n#include \"nel/misc/displayer.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nCVariable<bool> StdDisplayerColor(\"nel\", \"StdDisplayerColor\", \"Enable colors in std displayer\", true, 0, true);\n\nstatic const char *LogTypeToString[][8] = {\n\t{ \"\", \"ERR\", \"WRN\", \"INF\", \"DBG\", \"STT\", \"AST\", \"UKN\" },\n\t{ \"\", \"Error\", \"Warning\", \"Information\", \"Debug\", \"Statistic\", \"Assert\", \"Unknown\" },\n\t{ \"\", \"A fatal error occurs. The program must quit\", \"\", \"\", \"\", \"\", \"A failed assertion occurs\", \"\" },\n};\n\nconst char *IDisplayer::logTypeToString (CLog::TLogType logType, bool longFormat)\n{\n\tif (logType < CLog::LOG_NO || logType > CLog::LOG_UNKNOWN)\n\t\treturn \"<NotDefined>\";\n\n\treturn LogTypeToString[longFormat?1:0][logType];\n}\n\nconst char *IDisplayer::dateToHumanString ()\n{\n\ttime_t date;\n\ttime (&date);\n\treturn dateToHumanString (date);\n}\n\nconst char *IDisplayer::dateToHumanString (time_t date)\n{\n\tstatic char cstime[25];\n\tstruct tm *tms = localtime(&date);\n\tif (tms)\n\t\tstrftime (cstime, 25, \"%Y/%m/%d %H:%M:%S\", tms);\n\telse\n\t\tsprintf(cstime, \"bad date %d\", (uint32)date);\n\treturn cstime;\n}\n\nconst char *IDisplayer::dateToComputerString (time_t date)\n{\n\tstatic char cstime[25];\n\tsmprintf (cstime, 25, \"%ld\", &date);\n\treturn cstime;\n}\n\nconst char *IDisplayer::HeaderString ()\n{\n\tstatic char header[1024];\n\tsmprintf(header, 1024, \"\\nLog Starting [%s]\\n\", dateToHumanString());\n\treturn header;\n}\n\n\nIDisplayer::IDisplayer(const char *displayerName)\n{\n\t_Mutex = new CMutex (string(displayerName)+\"DISP\");\n\tDisplayerName = displayerName;\n}\n\nIDisplayer::~IDisplayer()\n{\n\tdelete _Mutex;\n}\n\n/*\n * Display the string where it does.\n */\nvoid IDisplayer::display ( const CLog::TDisplayInfo& args, const char *message )\n{\n\t_Mutex->enter();\n\ttry\n\t{\n\t\tdoDisplay( args, message );\n\t}\n\tcatch (const Exception &)\n\t{\n\t\t// silence\n\t}\n\t_Mutex->leave();\n}\n\n\n// Log format : \"<LogType> <ThreadNo> <FileName> <Line> <ProcessName> : <Msg>\"\nvoid CStdDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message )\n{\n\tbool needSpace = false;\n\t//stringstream ss;\n\tstring str;\n#ifdef NL_OS_UNIX\n\tbool colorSet = false;\n#endif\n\n\tif (args.LogType != CLog::LOG_NO)\n\t{\n#ifdef NL_OS_UNIX\n\t\tif (StdDisplayerColor.get())\n\t\t{\n\t\t\tif (args.LogType == CLog::LOG_ERROR || args.LogType == CLog::LOG_ASSERT) { str += \"\\e[0;30m\\e[41m\"; colorSet = true; } // black text, red background\n\t\t\telse if (args.LogType == CLog::LOG_WARNING) { str += \"\\e[0;91m\"; colorSet = true; } // bright red text\n\t\t\t//else if (args.LogType == CLog::LOG_DEBUG) { str += \"\\e[0;34m\"; colorSet = true; } // blue text\n            else if (args.LogType == CLog::LOG_DEBUG) { str += \"\\e[0;32m\"; colorSet = true; } // 暗绿\n\t\t}\n#endif\n\t\t//ss << logTypeToString(args.LogType);\n\t\tstr += logTypeToString(args.LogType);\n\t\tneedSpace = true;\n\t}\n\n\t// Write thread identifier\n\tif ( args.ThreadId != 0 )\n\t{\n\t\t//ss << setw(5) << args.ThreadId;\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n#ifdef NL_OS_WINDOWS\n\t\tstr += NLMISC::toString(\"%5x\", args.ThreadId);\n#else\n\t\tstr += NLMISC::toString(\"%08x\", args.ThreadId);\n#endif\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t//ss << CFile::getFilename(args.FileName);\n\t\tstr += CFile::getFilename(args.FileName);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t//ss << args.Line;\n\t\tstr += NLMISC::toString(args.Line);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FuncName != NULL)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t//ss << args.FuncName;\n\t\tstr += args.FuncName;\n\t\tneedSpace = true;\n\t}\n\n\tif (!args.ProcessName.empty())\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t//ss << args.ProcessName;\n\t\tstr += args.ProcessName;\n\t\tneedSpace = true;\n\t}\n\n\t//if (needSpace) { ss << \" : \"; needSpace = false; }\n\tif (needSpace) { str += \" : \"; needSpace = false; }\n\n\t//ss << message;\n\tstr += message;\n\n//\tstring s = ss.str();\n\n\tstatic bool consoleMode = true;\n\n#if defined(NL_OS_WINDOWS)\n\tstatic bool consoleModeTest = false;\n\tif (!consoleModeTest)\n\t{\n\t\tHANDLE handle = CreateFile (\"CONOUT$\", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);\n\t\tconsoleMode = handle != INVALID_HANDLE_VALUE;\n\t\tif (consoleMode)\n\t\t\tCloseHandle (handle);\n\t\tconsoleModeTest = true;\n\t}\n#endif // NL_OS_WINDOWS\n\n#ifdef NL_OS_UNIX\n\tif (colorSet)\n\t{\n\t\tstr += \"\\e[0m\";\n\t}\n#endif\n\n\t// Printf ?\n\tif (consoleMode)\n\t{\n\t\t// we don't use cout because sometimes, it crashs because cout isn't already init, printf doesn t crash.\n\t\tif (!str.empty())\n\t\t\tprintf (\"%s\", str.c_str());\n\n\t\tif (!args.CallstackAndLog.empty())\n\t\t\tprintf (\"%s\", args.CallstackAndLog.c_str());\n\n\t\tfflush(stdout);\n\t}\n\n#ifdef NL_OS_WINDOWS\n\t// display the string in the debugger is the application is started with the debugger\n\tif (IsDebuggerPresent ())\n\t{\n\t\t//stringstream ss2;\n\t\tstring str2;\n\t\tneedSpace = false;\n\n\t\tif (args.FileName != NULL) str2 += args.FileName;\n\n\t\tif (args.Line != -1)\n\t\t{\n\t\t\tstr2 += \"(\" + NLMISC::toString(args.Line) + \")\";\n\t\t\tneedSpace = true;\n\t\t}\n\n\t\tif (needSpace) { str2 += \" : \"; needSpace = false; }\n\n\t\tif (args.FuncName != NULL) str2 += string(args.FuncName) + \" \";\n\n\t\tif (args.LogType != CLog::LOG_NO)\n\t\t{\n\t\t\tstr2 += logTypeToString(args.LogType);\n\t\t\tneedSpace = true;\n\t\t}\n\n\t\t// Write thread identifier\n\t\tif ( args.ThreadId != 0 )\n\t\t{\n\t\t\tstr2 += NLMISC::toString(\"%5x: \", args.ThreadId);\n\t\t}\n\n\t\tstr2 += message;\n\n\t\tconst sint maxOutString = 2*1024;\n\n\t\tif(str2.size() < maxOutString)\n\t\t{\n\t\t\t//////////////////////////////////////////////////////////////////\n\t\t\t// WARNING: READ THIS !!!!!!!!!!!!!!!! ///////////////////////////\n\t\t\t// If at the release time, it freezes here, it's a microsoft bug:\n\t\t\t// http://support.microsoft.com/support/kb/articles/q173/2/60.asp\n\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(str2).c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/*OutputDebugString(ss2.str().c_str());\n\t\t\tOutputDebugString(\"\\n\\t\\t\\t\");\n\t\t\tOutputDebugString(\"message end: \");\n\t\t\tOutputDebugString(&message[strlen(message) - 1024]);\n\t\t\tOutputDebugString(\"\\n\");*/\n\n\t\t\tsint count = 0;\n\t\t\tuint n = (uint)strlen(message);\n\t\t\tstd::string s(&str2.c_str()[0], (str2.size() - n));\n\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(s).c_str());\n\n\t\t\tfor(;;)\n\t\t\t{\n\n\t\t\t\tif((n - count) < maxOutString )\n\t\t\t\t{\n\t\t\t\t\ts = std::string(&message[count], (n - count));\n\t\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(s).c_str());\n\t\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(\"\\n\").c_str());\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ts = std::string(&message[count] , count + maxOutString);\n\t\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(s).c_str());\n\t\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(\"\\n\\t\\t\\t\").c_str());\n\t\t\t\t\tcount += maxOutString;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// OutputDebugString is a big shit, we can't display big string in one time, we need to split\n\t\tuint32 pos = 0;\n\t\tstring splited;\n\t\tfor(;;)\n\t\t{\n\t\t\tif (pos+1000 < args.CallstackAndLog.size ())\n\t\t\t{\n\t\t\t\tsplited = args.CallstackAndLog.substr (pos, 1000);\n\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(splited).c_str());\n\t\t\t\tpos += 1000;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsplited = args.CallstackAndLog.substr (pos);\n\t\t\t\tOutputDebugStringW((LPCWSTR)ucstring::makeFromUtf8(splited).c_str());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\nCFileDisplayer::CFileDisplayer (const std::string &filename, bool eraseLastLog, const char *displayerName, bool raw) :\n\tIDisplayer (displayerName), _NeedHeader(true), _LastLogSizeChecked(0), _Raw(raw)\n{\n\t_FilePointer = (FILE*)1;\n\tsetParam (filename, eraseLastLog);\n}\n\nCFileDisplayer::CFileDisplayer () :\n\tIDisplayer (\"\"), _NeedHeader(true), _LastLogSizeChecked(0), _Raw(false)\n{\n\t_FilePointer = (FILE*)1;\n}\n\nCFileDisplayer::~CFileDisplayer ()\n{\n\tif (_FilePointer > (FILE*)1)\n\t{\n\t\tfclose(_FilePointer);\n\t\t_FilePointer = NULL;\n\t}\n}\n\nvoid CFileDisplayer::setParam (const std::string &filename, bool eraseLastLog)\n{\n\t_FileName = filename;\n\n\tif (filename.empty())\n\t{\n\t\t// can't do nlwarning or infinite recurs\n\t\tprintf (\"CFileDisplayer::setParam(): Can't create file with empty filename\\n\");\n\t\treturn;\n\t}\n\n\tif (eraseLastLog)\n\t{\n/*\t\tofstream ofs (filename.c_str(), ios::out | ios::trunc);\n\t\tif (!ofs.is_open())\n\t\t{\n\t\t\t// can't do nlwarning or infinite recurs\n\t\t\tprintf (\"CFileDisplayer::setParam(): Can't open and clear the log file '%s'\\n\", filename.c_str());\n\t\t}*/\n\n\t\t// Erase all the derived log files\n\t\tint i = 0;\n\t\tbool fileExist = true;\n\t\twhile (fileExist)\n\t\t{\n\t\t\tstring fileToDelete = CFile::getPath (filename) + CFile::getFilenameWithoutExtension (filename) +\n\t\t\t\ttoString (\"%03d.\", i) + CFile::getExtension (filename);\n\t\t\tfileExist = CFile::isExists (fileToDelete);\n\t\t\tif (fileExist)\n\t\t\t\tCFile::deleteFile (fileToDelete);\n\t\t\ti++;\n\t\t}\n\t}\n\n\tif (_FilePointer > (FILE*)1)\n\t{\n\t\tfclose (_FilePointer);\n\t\t_FilePointer = (FILE*)1;\n\t}\n}\n\n// Log format: \"2000/01/15 12:05:30 <ProcessName> <LogType> <ThreadId> <FileName> <Line> : <Msg>\"\nvoid CFileDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message )\n{\n\tbool needSpace = false;\n\t//stringstream ss;\n\tstring str;\n\n\t// if the filename is not set, don't log\n\tif (_FileName.empty()) return;\n\n\tif (args.Date != 0 && !_Raw)\n\t{\n\t\tstr += dateToHumanString(args.Date);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.LogType != CLog::LOG_NO && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += logTypeToString(args.LogType);\n\t\tneedSpace = true;\n\t}\n\n\t// Write thread identifier\n\tif ( args.ThreadId != 0 && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n#ifdef NL_OS_WINDOWS\n\t\tstr += NLMISC::toString(\"%4x\", args.ThreadId);\n#else\n\t\tstr += NLMISC::toString(\"%4u\", args.ThreadId);\n#endif\n\t\tneedSpace = true;\n\t}\n\n\tif (!args.ProcessName.empty() && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += args.ProcessName;\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += CFile::getFilename(args.FileName);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1 && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(args.Line);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FuncName != NULL && !_Raw)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += args.FuncName;\n\t\tneedSpace = true;\n\t}\n\n\tif (needSpace) { str += \" : \"; needSpace = false; }\n\n\tstr += message;\n\n\tif (_FilePointer > (FILE*)1)\n\t{\n\t\t// if the file is too big (>5mb), rename it and create another one (check only after 20 lines to speed up)\n\t\tif (_LastLogSizeChecked++ > 20)\n\t\t{\n\t\t  int res = ftell (_FilePointer);\n\t\t  if (res > 5*1024*1024)\n\t\t    {\n\t\t\tfclose (_FilePointer);\n\t\t\trename (_FileName.c_str(), CFile::findNewFile (_FileName).c_str());\n\t\t\t_FilePointer = (FILE*) 1;\n\t\t\t_LastLogSizeChecked = 0;\n\t\t    }\n\t\t}\n\t}\n\n\tif (_FilePointer == (FILE*)1)\n\t{\n\t\t_FilePointer = fopen (_FileName.c_str(), \"at\");\n\t\tif (_FilePointer == NULL)\n\t\t\tprintf (\"Can't open log file '%s': %s\\n\", _FileName.c_str(), strerror (errno));\n\t}\n\n\tif (_FilePointer != 0)\n\t{\n\t\tif (_NeedHeader)\n\t\t{\n\t\t\tconst char *hs = HeaderString();\n\t\t\tfwrite (hs, strlen (hs), 1, _FilePointer);\n\t\t\t_NeedHeader = false;\n\t\t}\n\n\t\tif(!str.empty())\n\t\t\tfwrite (str.c_str(), str.size(), 1, _FilePointer);\n\n\t\tif(!args.CallstackAndLog.empty())\n\t\t\tfwrite (args.CallstackAndLog.c_str(), args.CallstackAndLog.size (), 1, _FilePointer);\n\n\t\tfflush (_FilePointer);\n\t}\n}\n\n// Log format in clipboard: \"2000/01/15 12:05:30 <LogType> <ProcessName> <FileName> <Line>: <Msg>\"\n// Log format on the screen: in debug   \"<ProcessName> <FileName> <Line>: <Msg>\"\n//                           in release \"<Msg>\"\nvoid CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message)\n{\n#ifdef NL_OS_WINDOWS\n\n\tbool needSpace = false;\n//\tstringstream ss;\n\tstring str;\n\n\t// create the string for the clipboard\n\n\tif (args.Date != 0)\n\t{\n\t\tstr += dateToHumanString(args.Date);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.LogType != CLog::LOG_NO)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += logTypeToString(args.LogType);\n\t\tneedSpace = true;\n\t}\n\n\tif (!args.ProcessName.empty())\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += args.ProcessName;\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += CFile::getFilename(args.FileName);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(args.Line);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FuncName != NULL)\n\t{\n\t\t//if (needSpace) { ss << \" \"; needSpace = false; }\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += args.FuncName;\n\t\tneedSpace = true;\n\t}\n\n\tif (needSpace) { str += \": \"; needSpace = false; }\n\n\tstr += message;\n\n\tCSystemUtils::copyTextToClipboard(str);\n\n\t// create the string on the screen\n\tneedSpace = false;\n//\tstringstream ss2;\n\tstring str2;\n\n#ifdef NL_DEBUG\n\tif (!args.ProcessName.empty())\n\t{\n\t\tif (needSpace) { str2 += \" \"; needSpace = false; }\n\t\tstr2 += args.ProcessName;\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL)\n\t{\n\t\tif (needSpace) { str2 += \" \"; needSpace = false; }\n\t\tstr2 += CFile::getFilename(args.FileName);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1)\n\t{\n\t\tif (needSpace) { str2 += \" \"; needSpace = false; }\n\t\tstr2 += NLMISC::toString(args.Line);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FuncName != NULL)\n\t{\n\t\tif (needSpace) { str2 += \" \"; needSpace = false; }\n\t\tstr2 += args.FuncName;\n\t\tneedSpace = true;\n\t}\n\n\tif (needSpace) { str2 += \": \"; needSpace = false; }\n\n#endif // NL_DEBUG\n\n\tstr2 += message;\n\tstr2 += \"\\n\\n(this message was copied in the clipboard)\";\n\n/*\tif (IsDebuggerPresent ())\n\t{\n\t\t// Must break in assert call\n\t\tDebugNeedAssert = true;\n\t}\n\telse\n*/\t{\n\n\t\t// Display the report\n\n\t\tstring body;\n\n\t\tbody += toString(LogTypeToString[2][args.LogType]) + \"\\n\";\n\t\tbody += \"ProcName: \" + args.ProcessName + \"\\n\";\n\t\tbody += \"Date: \" + string(dateToHumanString(args.Date)) + \"\\n\";\n\t\tif(args.FileName == NULL)\n\t\t\tbody += \"File: <Unknown>\\n\";\n\t\telse\n\t\t\tbody += \"File: \" + string(args.FileName) + \"\\n\";\n\t\tbody += \"Line: \" + toString(args.Line) + \"\\n\";\n\t\tif (args.FuncName == NULL)\n\t\t\tbody += \"FuncName: <Unknown>\\n\";\n\t\telse\n\t\t\tbody += \"FuncName: \" + string(args.FuncName) + \"\\n\";\n\t\tbody += \"Reason: \" + toString(message);\n\n\t\tbody += args.CallstackAndLog;\n\n\t\tstring subject;\n\n\t\t// procname is host/service_name-sid we only want the service_name to avoid redondant mail\n\t\tstring procname;\n\t\tstring::size_type pos = args.ProcessName.find (\"/\");\n\t\tif (pos == string::npos)\n\t\t{\n\t\t\tprocname =  args.ProcessName;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstring::size_type pos2 = args.ProcessName.find (\"-\", pos+1);\n\t\t\tif (pos2 == string::npos)\n\t\t\t{\n\t\t\t\tprocname =  args.ProcessName.substr (pos+1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tprocname =  args.ProcessName.substr (pos+1, pos2-pos-1);\n\t\t\t}\n\t\t}\n\n\t\tsubject += procname + \" NeL \" + toString(LogTypeToString[0][args.LogType]) + \" \" + (args.FileName?string(args.FileName):\"\") + \" \" + toString(args.Line) + \" \" + (args.FuncName?string(args.FuncName):\"\");\n\n\t\t// Check the envvar NEL_IGNORE_ASSERT\n\t\tif (getenv (\"NEL_IGNORE_ASSERT\") == NULL)\n\t\t{\n\t\t\t// yoyo: allow only to send the crash report once. Because users usually click ignore,\n\t\t\t// which create noise into list of bugs (once a player crash, it will surely continues to do it).\n\t\t\tstd::string filename = getLogDirectory() + NL_CRASH_DUMP_FILE;\n\n\t\t\tif  (ReportDebug == report (args.ProcessName + \" NeL \" + toString(logTypeToString(args.LogType, true)), \"\", subject, body, true, 2, true, 1, !isCrashAlreadyReported(), IgnoreNextTime, filename.c_str()))\n\t\t\t{\n\t\t\t\tINelContext::getInstance().setDebugNeedAssert(true);\n\t\t\t}\n\n\t\t\t// no more sent mail for crash\n\t\t\tsetCrashAlreadyReported(true);\n\t\t}\n\n/*\t\t// Check the envvar NEL_IGNORE_ASSERT\n\t\tif (getenv (\"NEL_IGNORE_ASSERT\") == NULL)\n\t\t{\n\t\t\t// Ask the user to continue, debug or ignore\n\t\t\tint result = MessageBox (NULL, ss2.str().c_str (), logTypeToString(args.LogType, true), MB_ABORTRETRYIGNORE | MB_ICONSTOP);\n\t\t\tif (result == IDABORT)\n\t\t\t{\n\t\t\t\t// Exit the program now\n\t\t\t\texit (EXIT_FAILURE);\n\t\t\t}\n\t\t\telse if (result == IDRETRY)\n\t\t\t{\n\t\t\t\t// Give the debugger a try\n\t\t\t\tDebugNeedAssert = true;\n \t\t\t}\n\t\t\telse if (result == IDIGNORE)\n\t\t\t{\n\t\t\t\t// Continue, do nothing\n\t\t\t}\n\t\t}\n*/\t}\n\n#endif\n}\n\n\n\n/***************************************************************/\n/******************* THE FOLLOWING CODE IS COMMENTED OUT *******/\n/***************************************************************\nvoid CStdDisplayer::display (const std::string& str)\n{\n//\tprintf(\"%s\", str.c_str ());\n\tcout << str;\n\n#ifdef NL_OS_WINDOWS\n\t// display the string in the debugger is the application is started with the debugger\n\tif (IsDebuggerPresent ())\n\t\tOutputDebugString(str.c_str ());\n#endif\n}\n\n\nvoid CFileDisplayer::display (const std::string& str)\n{\n\tif (_FileName.size () == 0) return;\n\n\tofstream ofs (_FileName.c_str (), ios::out | ios::app);\n\tif (ofs.is_open ())\n\t{\n\t\tofs << str;\n\t\tofs.close();\n\t}\n\n\n//\tFILE *fp = fopen (_FileName.c_str (), \"a\");\n//\tif (fp == NULL) return;\n\n//\tfprintf (fp, \"%s\", str.c_str ());\n\n//\tfclose (fp);\n}\n\n\n\nvoid CMsgBoxDisplayer::display (const std::string& str)\n{\n#ifdef NL_OS_WINDOWS\n\n\tCSystemUtils::copyTextToClipboard(str);\n\n\tstring strf = str;\n\tstrf += \"\\n\\n(this message was copied in the clipboard)\";\n\tMessageBox (NULL, strf.c_str (), \"\", MB_OK | MB_ICONEXCLAMATION);\n#endif\n}\n**************************************************************************/\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/dummy_window.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n#include \"nel/misc/dummy_window.h\"\n\n\n#ifdef NL_OS_WINDOWS\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\nstatic LRESULT CALLBACK nlDefaultWinProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n{\n\treturn DefWindowProc(hwnd, uMsg, wParam, lParam);\n}\n\n\n// ***************************************************************\nCDummyWindow::CDummyWindow() : _HWnd(NULL)\n{\n}\n\n// ***************************************************************\nbool CDummyWindow::init(HINSTANCE hInstance, WNDPROC winProc)\n{\n\trelease();\n\tstatic const char *INVISIBLE_WINDOW_CLASS = \"nl_invisible_wnd_class\";\n\tWNDCLASSEX wc;\n\twc.cbSize = sizeof(WNDCLASSEX);\n\tif (!GetClassInfoEx(hInstance, INVISIBLE_WINDOW_CLASS, &wc))\n\t{\n\t\twc.cbSize = sizeof(WNDCLASSEX);\n\t\twc.style\t\t\t= CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;\n\t\twc.lpfnWndProc\t\t= nlDefaultWinProc;\n\t\twc.cbClsExtra\t\t= 0;\n\t\twc.cbWndExtra\t\t= 0;\n\t\twc.hInstance\t\t= hInstance;\n\t\twc.hIcon\t\t\t= 0;\n\t\twc.hCursor\t\t\t= 0;\n\t\twc.hbrBackground\t= 0;\n\t\twc.lpszMenuName\t\t= 0;\n\t\twc.lpszClassName\t= INVISIBLE_WINDOW_CLASS;\n\t\twc.hIconSm\t\t\t= 0;\n\t\tRegisterClassEx(&wc);\n\t}\n    _HWnd = CreateWindow(INVISIBLE_WINDOW_CLASS, \"\", WS_POPUP,\n                         CW_USEDEFAULT,CW_USEDEFAULT,\n                         CW_USEDEFAULT,CW_USEDEFAULT,\n                         NULL, 0,\n                         hInstance, 0);\n\tif (_HWnd)\n\t{\n\t\tif (winProc) SetWindowLongPtr(_HWnd, GWLP_WNDPROC, (LONG_PTR) winProc);\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************\nvoid CDummyWindow::release()\n{\n\tif (_HWnd)\n\t{\n\t\tDestroyWindow(_HWnd);\n\t\t_HWnd = NULL;\n\t}\n}\n\n// ***************************************************************\nCDummyWindow::~CDummyWindow()\n{\n\trelease();\n}\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n"
  },
  {
    "path": "code/nel/src/misc/dynloadlib.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/dynloadlib.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nNL_LIB_HANDLE nlLoadLibrary(const std::string &libName)\n{\n\tNL_LIB_HANDLE res = 0;\n#ifdef NL_OS_WINDOWS\n\tres = LoadLibrary(libName.c_str());\n#elif defined(NL_OS_UNIX)\n\tres = dlopen(libName.c_str(), RTLD_NOW);\n#else\n#\terror \"You must code nlLoadLibrary() for your platform\"\n#endif\n\tif(res == 0) nlwarning(\"Load library '%s' failed: %s\", libName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\treturn res;\n}\n\nbool nlFreeLibrary(NL_LIB_HANDLE libHandle)\n{\n#ifdef NL_OS_WINDOWS\n\treturn FreeLibrary(libHandle) > 0;\n#elif defined(NL_OS_UNIX)\n\treturn dlclose(libHandle) == 0;\n#else\n#\terror \"You must code nlFreeLibrary() for your platform\"\n#endif\n}\n\nvoid *nlGetSymbolAddress(NL_LIB_HANDLE libHandle, const std::string &procName)\n{\n\tvoid *res = 0;\n#ifdef NL_OS_WINDOWS\n\tres = (void *)GetProcAddress(libHandle, procName.c_str());\n#elif defined(NL_OS_UNIX)\n\tres = dlsym(libHandle, procName.c_str());\n#else\n#\terror \"You must code nlGetProcAddress() for your platform\"\n#endif\n\tif(res == 0) nlwarning(\"Getting symbol address of '%s' failed: %s\", procName.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\treturn res;\n}\n\n// Again some OS specifics stuff\n#ifdef NL_OS_WINDOWS\n  const string\tnlLibPrefix;\t// empty\n  const string\tnlLibExt(\".dll\");\n#elif defined(NL_OS_UNIX)\n  const string\tnlLibPrefix(\"lib\");\n  const string\tnlLibExt(\".so\");\n#else\n#\terror \"You must define the default dynamic lib extention\"\n#endif\n\nstd::vector<std::string>\tCLibrary::_LibPaths;\n\n\nCLibrary::CLibrary (const CLibrary &/* other */)\n{\n\t// Nothing to do has it is forbidden.\n\t// Allowing copy require to manage reference count from CLibrary to the module resource.\n\tnlassert(false);\n}\n\nCLibrary &CLibrary::operator =(const CLibrary &/* other */)\n{\n\t// Nothing to do has it is forbidden.\n\t// Allowing assignment require to manage reference count from CLibrary to the module resource.\n\tnlassert(false);\n\treturn *this;\n}\n\nstd::string CLibrary::makeLibName(const std::string &baseName)\n{\n\treturn nlLibPrefix+baseName+nlLibSuffix+nlLibExt;\n}\n\nstd::string CLibrary::cleanLibName(const std::string &decoratedName)\n{\n\t// remove path and extension\n\tstring ret = CFile::getFilenameWithoutExtension(decoratedName);\n\n\tif (!nlLibPrefix.empty())\n\t{\n\t\t// remove prefix\n\t\tif (ret.find(nlLibPrefix) == 0)\n\t\t\tret = ret.substr(nlLibPrefix.size());\n\t}\n\tif (!nlLibSuffix.empty())\n\t{\n\t\t// remove suffix\n\t\tif (ret.substr(ret.size()-nlLibSuffix.size()) == nlLibSuffix)\n\t\t\tret = ret.substr(0, ret.size() - nlLibSuffix.size());\n\t}\n\n\treturn ret;\n}\n\nvoid CLibrary::addLibPaths(const std::vector<std::string> &paths)\n{\n\tfor (uint i=0; i<paths.size(); ++i)\n\t{\n\t\tstring newPath = CPath::standardizePath(paths[i]);\n\n\t\t// only add new path\n\t\tif (std::find(_LibPaths.begin(), _LibPaths.end(), newPath) == _LibPaths.end())\n\t\t{\n\t\t\t_LibPaths.push_back(newPath);\n\t\t}\n\t}\n}\n\nvoid CLibrary::addLibPath(const std::string &path)\n{\n\tstring newPath = CPath::standardizePath(path);\n\n\t// only add new path\n\tif (std::find(_LibPaths.begin(), _LibPaths.end(), newPath) == _LibPaths.end())\n\t{\n\t\t_LibPaths.push_back(newPath);\n\t}\n}\n\nCLibrary::CLibrary()\n:\t_LibHandle(NULL),\n\t_Ownership(true),\n\t_PureNelLibrary(NULL)\n{\n}\n\nCLibrary::CLibrary(NL_LIB_HANDLE libHandle, bool ownership)\n: _PureNelLibrary(NULL)\n{\n\t_LibHandle = libHandle;\n\t_Ownership = ownership;\n\t_LibFileName = \"unknown\";\n}\n\nCLibrary::CLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership)\n: _PureNelLibrary(NULL)\n{\n\tloadLibrary(libName, addNelDecoration, tryLibPath, ownership);\n\t// Assert here !\n\tnlassert(_LibHandle != NULL);\n}\n\n\nCLibrary::~CLibrary()\n{\n\tif (_LibHandle != NULL && _Ownership)\n\t{\n\t\tnlFreeLibrary(_LibHandle);\n\t}\n}\n\nbool CLibrary::loadLibrary(const std::string &libName, bool addNelDecoration, bool tryLibPath, bool ownership)\n{\n\t_Ownership = ownership;\n\tstring libPath = libName;\n\n\tif (addNelDecoration)\n\t\tlibPath = makeLibName(libPath);\n\n\tif (tryLibPath)\n\t{\n\t\t// remove any directory spec\n\t\tstring filename = CFile::getFilename(libPath);\n\n\t\tfor (uint i=0; i<_LibPaths.size(); ++i)\n\t\t{\n\t\t\tstring pathname = _LibPaths[i]+filename;\n\t\t\tif (CFile::isExists(pathname))\n\t\t\t{\n\t\t\t\t// we found it, replace libPath\n\t\t\t\tlibPath = pathname;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tnldebug(\"Loading dynamic library '%s'\", libPath.c_str());\n\t// load the lib now\n\t_LibHandle = nlLoadLibrary(libPath);\n\t_LibFileName = libPath;\n\t// MTR: some new error handling. Just logs if it couldn't load the handle.\n\tif(_LibHandle == NULL)\n\t{\n#ifdef NL_OS_UNIX\n\t\tconst char *errormsg = dlerror();\n#else\n\t\tconst char *errormsg = \"Verify DLL existence\";\n#endif\n\t\tnlwarning(\"Loading library %s failed: %s\", libPath.c_str(), errormsg);\n\t}\n\telse\n\t{\n\t\t// check for 'pure' NeL library\n\t\tvoid *entryPoint = getSymbolAddress( NL_MACRO_TO_STR(NLMISC_PURE_LIB_ENTRY_POINT) );\n\t\tif (entryPoint != NULL)\n\t\t{\n\t\t\t// rebuild the interface pointer\n\t\t\t_PureNelLibrary = *(reinterpret_cast<INelLibrary**>(entryPoint));\n\t\t\t// call the private initialization method.\n\t\t\t_PureNelLibrary->_onLibraryLoaded(INelContext::getInstance());\n\t\t}\n\t}\n\n\treturn _LibHandle != NULL;\n}\n\nvoid CLibrary::freeLibrary()\n{\n\tif (_LibHandle)\n\t{\n\t\tnlassert(_Ownership);\n\n\t\tif (_PureNelLibrary)\n\t\t{\n\t\t\t// call the private finalization method.\n\t\t\t_PureNelLibrary->_onLibraryUnloaded();\n\t\t}\n\n\t\tnldebug(\"Freeing dynamic library '%s'\", _LibFileName.c_str());\n\t\tnlFreeLibrary(_LibHandle);\n\n\t\t_PureNelLibrary = NULL;\n\t\t_LibHandle = NULL;\n\t\t_Ownership = false;\n\t\t_LibFileName = \"\";\n\t}\n}\n\nvoid *CLibrary::getSymbolAddress(const std::string &symbolName)\n{\n\tnlassert(_LibHandle != NULL);\n\n\treturn nlGetSymbolAddress(_LibHandle, symbolName);\n}\n\nbool CLibrary::isLibraryLoaded()\n{\n\treturn _LibHandle != NULL;\n}\n\nbool CLibrary::isLibraryPure()\n{\n\treturn _LibHandle != NULL && _PureNelLibrary != NULL;\n}\n\nINelLibrary *CLibrary::getNelLibraryInterface()\n{\n\tif (!isLibraryPure())\n\t\treturn NULL;\n\n\treturn _PureNelLibrary;\n}\n\nINelLibrary::~INelLibrary()\n{\n\t// cleanup ram\n\tif (_LibContext != NULL)\n\t\tdelete _LibContext;\n}\n\nvoid INelLibrary::_onLibraryLoaded(INelContext &nelContext)\n{\n\t++_LoadingCounter;\n\n\tif (_LoadingCounter == 1)\n\t{\n\t\t// Linux relocates all symbols, so this is unnecessary.\n#ifdef NL_OS_WINDOWS\n\t\t// initialize NeL context\n\t\tnlassert(!NLMISC::INelContext::isContextInitialised());\n#endif // NL_OS_WINDOWS\n\n\t\t_LibContext = new CLibraryContext(nelContext);\n\t}\n\telse\n\t{\n\t\tnlassert(NLMISC::INelContext::isContextInitialised());\n\t}\n\n\tonLibraryLoaded(_LoadingCounter==1);\n}\n\nvoid INelLibrary::_onLibraryUnloaded()\n{\n\tnlassert(_LoadingCounter > 0);\n\n\tonLibraryUnloaded(_LoadingCounter == 1);\n\n\t--_LoadingCounter;\n}\n\nuint32\tINelLibrary::getLoadingCounter()\n{\n\treturn _LoadingCounter;\n}\n\n\n}\t// namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/eid_translator.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/algo.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/eid_translator.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n//\n// Variables\n//\n\n//CEntityIdTranslator *CEntityIdTranslator::Instance = NULL;\nNLMISC_SAFE_SINGLETON_IMPL(CEntityIdTranslator);\n\n// don't forget to increment the number when you change the file format\nconst uint CEntityIdTranslator::Version = 1;\n\n//\n// Functions\n//\n\nvoid CEntityIdTranslator::CEntity::serial (NLMISC::IStream &s)\n{\n\tH_AUTO(EIdTrans_serial);\n\ts.serial (EntityName);\n\n\tif (CEntityIdTranslator::getInstance()->FileVersion >= 1)\n\t\ts.serial (EntitySlot);\n\telse\n\t{\n\t\tif(s.isReading())\n\t\t{\n\t\t\tEntitySlot = -1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsint8 slot = -1;\n\t\t\ts.serial (slot);\n\t\t}\n\t}\n\ts.serial (UId);\n\ts.serial (UserName);\n}\n\n//CEntityIdTranslator *CEntityIdTranslator::getInstance ()\n//{\n//\tif(Instance == NULL)\n//\t{\n//\t\tInstance = new CEntityIdTranslator;\n//\t}\n//\treturn Instance;\n//}\n\nvoid CEntityIdTranslator::getByUser (uint32 uid, vector<CEntityId> &res)\n{\n\tH_AUTO(EIdTrans_getByUser);\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != RegisteredEntities.end(); it++)\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (entity.UId == uid)\n\t\t{\n\t\t\tres.push_back(it->first);\n\t\t}\n\t}\n}\n\nvoid CEntityIdTranslator::getByUser (const string &userName, vector<CEntityId> &res, bool exact)\n{\n\tH_AUTO(EIdTrans_getByUser2);\n\tstring lowerName = toLower(userName);\n\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != RegisteredEntities.end(); it++)\n\t{\n\t\tif (exact)\n\t\t{\n\t\t\tCEntity &entity = it->second;\n\t\t\tif (toLower(entity.UserName) == lowerName)\n\t\t\t{\n\t\t\t\tres.push_back(it->first);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCEntity &entity = it->second;\n\t\t\tif (toLower(entity.UserName).find(lowerName) != string::npos)\n\t\t\t{\n\t\t\t\tres.push_back(it->first);\n\t\t\t}\n\t\t}\n\t}\n}\n\nconst ucstring &CEntityIdTranslator::getByEntity (const CEntityId &eid)\n{\n\tH_AUTO(EIdTrans_getByEntity);\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tstatic ucstring emptyString;\n\t\treturn emptyString;\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\treturn entity.EntityName;\n\t}\n}\n\nCEntityId CEntityIdTranslator::getByEntity (const ucstring &entityName)\n{\n\tH_AUTO(EIdTrans_getByEntity2);\n\tvector<CEntityId> res;\n\tgetByEntity (entityName, res, true);\n\tif (res.empty())\n\t\treturn CEntityId::Unknown;\n\telse\n\t\treturn res[0];\n}\n\nvoid CEntityIdTranslator::getByEntity (const ucstring &entityName, vector<CEntityId> &res, bool exact)\n{\n\tH_AUTO(EIdTrans_getByEntity3);\n\tstring lowerName = toLower(entityName.toString());\n\n\tif (exact)\n\t{\n\t\t// use the reverse index to speed up search\n\t\tTNameIndexCont::iterator it(NameIndex.find(lowerName));\n\t\tif (it != NameIndex.end())\n\t\t\tres.push_back(it->second);\n\n\t\treturn;\n\t}\n\t// parse the entire container to match all entities\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != RegisteredEntities.end(); ++it)\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (toLower(entity.EntityName.toString()).find(lowerName) != string::npos)\n\t\t{\n\t\t\tres.push_back(it->first);\n\t\t}\n\t}\n}\n\nbool CEntityIdTranslator::isValidEntityName (const ucstring &entityName,CLog *log)\n{\n\tH_AUTO(EIdTrans_isValidEntityName);\n\t// 3 char at least\n\tif (entityName.size() < 3)\n\t{\n\t\tlog->displayNL(\"Bad entity name '%s' (less than 3 char)\", entityName.toString().c_str());\n\t\treturn false;\n\t}\n\n\tif (entityName.size() > 15)\n\t{\n\t\t// if a parenthesis is found before 15 chars, the name is valid\n\t\tif (entityName.find(ucstring(\"(\")) > 15 || entityName[entityName.size()-1] != ucchar(')'))\n\t\t{\n\t\t\tlog->displayNL(\"EIT: Bad entity name '%s' (more than 15 char)\", entityName.toString().c_str());\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tbool allowNumeric = false;\n\tfor (uint i = 0; i < entityName.size(); i++)\n\t{\n\t\tif (entityName[i] == '(')\n\t\t{\n\t\t\t// starting from shard name, allow alphanumeric character\n\t\t\tallowNumeric = true;\n\t\t}\n\t\t// only accept name with alphabetic and numeric value [a-zA-Z] and parenthesis\n\t\tif (!allowNumeric && !isalpha (entityName[i]) && entityName[i] != '(' && entityName[i] != ')')\n\t\t{\n\t\t\tlog->displayNL(\"Bad entity name '%s' (only char and num)\", entityName.toString().c_str());\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// now check with the invalid name list\n\tstring en = getRegisterableString( entityName );\n\n\tfor (uint i = 0; i < InvalidEntityNames.size(); i++)\n\t{\n\t\tif(testWildCard(en, InvalidEntityNames[i]))\n\t\t{\n\t\t\tlog->displayNL(\"Bad entity name '%s' (match the invalid entity name pattern '%s')\", entityName.toString().c_str(), InvalidEntityNames[i].c_str());\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid CEntityIdTranslator::clear()\n{\n\tNameIndex.clear();\n\tRegisteredEntities.clear();\n}\n\n\nbool CEntityIdTranslator::checkEntityName (const ucstring &entityName )\n{\n\tH_AUTO(EIdTrans_entityNameExists);\n\t// if bad name, don't accept it\n\tif (!isValidEntityName (entityName,NLMISC::InfoLog)) return false;\n\treturn !entityNameExists( entityName );\n}\n\nbool CEntityIdTranslator::entityNameExists (const ucstring &entityName )\n{\n\t// Names are stored in case dependant, so we have to test them without case.\n\tucstring registerable = getRegisterableString (entityName);\n\n\treturn NameIndex.find(registerable) !=NameIndex.end();\n/*\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != RegisteredEntities.end(); it++)\n\t{\n\t\tif (getRegisterableString ((*it).second.EntityName) == registerable)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n*/\n}\n\nvoid CEntityIdTranslator::registerEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const string &userName, uint32 shardId)\n{\n\tH_AUTO(EIdTrans_registerEntity);\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tif (RegisteredEntities.find (reid) != RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: Can't register EId %s EntityName '%s' UId %d UserName '%s' because EId is already in the map\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\treturn;\n\t}\n\n\tif (!checkEntityName(entityName))\n\t{\n\t\tif (isValidEntityName(entityName))\n\t\t\tnlwarning (\"EIT: Can't register EId %s EntityName '%s' UId %d UserName '%s' because EntityName is already in the map\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\telse\n\t\t\tnlwarning (\"EIT: Can't register EId %s EntityName '%s' UId %d UserName '%s' because EntityName is invalid\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\treturn;\n\t}\n\n\tnlinfo (\"EIT: Register EId %s EntityName '%s' UId %d UserName '%s'\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\tRegisteredEntities.insert (make_pair(reid, CEntityIdTranslator::CEntity(entityName, uid, userName, entitySlot, shardId)));\n\tNameIndex.insert(make_pair(toLower(entityName), reid));\n}\n\nvoid CEntityIdTranslator::updateEntity (const CEntityId &eid, const ucstring &entityName, sint8 entitySlot, uint32 uid, const std::string &userName, uint32 shardId)\n{\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\n\tif (it == RegisteredEntities.end())\n\t{\n\t\t// just register\n\t\tregisterEntity(eid, entityName, entitySlot, uid, userName, shardId);\n\t}\n\telse\n\t{\n\t\t// update entity entry and name index\n\t\tCEntity &entity = it->second;\n\t\tif (entity.EntityName != entityName)\n\t\t{\n\t\t\tif (!checkEntityName(entityName))\n\t\t\t{\n\t\t\t\tnlwarning (\"EIT: Can't update EId %s EntityName '%s' UId %d UserName '%s' with new name '%s' because EntityName is already in the map\",\n\t\t\t\t\treid.toString().c_str(),\n\t\t\t\t\tentity.EntityName.toString().c_str(),\n\t\t\t\t\tuid,\n\t\t\t\t\tuserName.c_str(),\n\t\t\t\t\tentityName.toString().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// update the name and name index\n\t\t\tNameIndex.erase(toLower(entity.EntityName));\n\t\t\tNameIndex.insert(make_pair(toLower(entityName), reid));\n\t\t\tentity.EntityName = entityName;\n\t\t\tentity.EntityNameStringId = 0;\n\t\t}\n\t\tentity.EntitySlot = entitySlot;\n\t\tentity.UId = uid;\n\t\tentity.UserName = userName;\n\t\tentity.ShardId = shardId;\n\t}\n}\n\n\nvoid CEntityIdTranslator::unregisterEntity (const CEntityId &eid)\n{\n\tH_AUTO(EIdTrans_unregisterEntity);\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: Can't unregister EId %s because EId is not in the map\", reid.toString().c_str());\n\t\treturn;\n\t}\n\n\tCEntity &entity = it->second;\n\n\tnldebug (\"EIT: Unregister EId %s EntityName '%s' UId %d UserName '%s'\", reid.toString().c_str(), entity.EntityName.toString().c_str(), entity.UId, entity.UserName.c_str());\n\tNameIndex.erase(toLower(entity.EntityName));\n\tRegisteredEntities.erase (reid);\n}\n\nbool CEntityIdTranslator::isEntityRegistered(const CEntityId &eid)\n{\n\tH_AUTO(EIdTrans_unregisterEntity);\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\n\treturn it != RegisteredEntities.end ();\n}\n\n\nvoid CEntityIdTranslator::checkEntity (const CEntityId &eid, const ucstring &entityName, uint32 uid, const string &userName)\n{\n\tH_AUTO(EIdTrans_checkEntity);\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tmap<CEntityId, CEntityIdTranslator::CEntity>::iterator it = RegisteredEntities.find (reid);\n\n\tnlinfo (\"EIT: Checking EId %s EntityName '%s' UId %d UserName '%s'\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: Check failed because EId is not in the CEntityIdTranslator map for EId %s EntityName '%s' UId %d UserName '%s'\", reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\n\t\tif (checkEntityName(entityName))\n\t\t{\n\t\t\tnlwarning (\"EIT: Check failed because entity name already exist '%s' for EId %s EntityName '%s' UId %d UserName '%s'\", getByEntity(entityName).toString().c_str(), reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\t}\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (entity.EntityName != entityName)\n\t\t{\n\t\t\tnlwarning (\"EIT: Check failed because entity name not identical '%s' in the CEntityIdTranslator map for EId %s EntityName '%s' UId %d UserName '%s'\", entity.EntityName.toString().c_str(), reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\t\tif(!entityName.empty())\n\t\t\t{\n\t\t\t\tentity.EntityName = entityName;\n\t\t\t}\n\t\t}\n\t\tif (entity.UId != uid)\n\t\t{\n\t\t\tnlwarning (\"EIT: Check failed because uid not identical (%d) in the CEntityIdTranslator map for EId %s EntityName '%s' UId %d UserName '%s'\", entity.UId, reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\t\tif (uid != 0)\n\t\t\t{\n\t\t\t\tentity.UId = uid;\n\t\t\t}\n\t\t}\n\t\tif (entity.UserName != userName)\n\t\t{\n\t\t\tnlwarning (\"EIT: Check failed because user name not identical '%s' in the CEntityIdTranslator map for EId %s EntityName '%s' UId %d UserName '%s'\", entity.UserName.c_str(), reid.toString().c_str(), entityName.toString().c_str(), uid, userName.c_str());\n\t\t\tif(!userName.empty())\n\t\t\t{\n\t\t\t\tentity.UserName = userName;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CEntityIdTranslator::removeShardFromName(ucstring& name)\n{\n\t// The string must contain a '(' and a ')'\n\tucstring::size_type\tp0= name.find('(');\n\tucstring::size_type\tp1= name.find(')');\n\tif (p0 == ucstring::npos || p1 == ucstring::npos || p1 <= p0)\n\t\treturn;\n\n\tname = name.substr(0, p0) + name.substr(p1 + 1);\n}\n\n// this callback is call when the file is changed\nvoid cbInvalidEntityNamesFilename(const std::string &invalidEntityNamesFilename)\n{\n\tCEntityIdTranslator::getInstance()->InvalidEntityNames.clear ();\n\n\tstring fn = CPath::lookup(invalidEntityNamesFilename, false);\n\n\tif (fn.empty())\n\t{\n\t\tnlwarning (\"EIT: Can't load filename '%s' for invalid entity names filename (not found)\", invalidEntityNamesFilename.c_str());\n\t\treturn;\n\t}\n\n\tFILE *fp = fopen (fn.c_str(), \"r\");\n\tif (fp == NULL)\n\t{\n\t\tnlwarning (\"EIT: Can't load filename '%s' for invalid entity names filename\", fn.c_str());\n\t\treturn;\n\t}\n\n\tfor(;;)\n\t{\n\t\tchar str[512];\n\t\tif (!fgets(str, 511, fp))\n\t\t\tbreak;\n\t\tif(feof(fp))\n\t\t\tbreak;\n\t\tif (strlen(str) > 0)\n\t\t{\n\t\t\tstr[strlen(str)-1] = '\\0';\n\t\t\tCEntityIdTranslator::getInstance()->InvalidEntityNames.push_back(str);\n\t\t}\n\t}\n\n\tfclose (fp);\n}\n\nvoid CEntityIdTranslator::load (const string &fileName, const string &invalidEntityNamesFilename)\n{\n\tH_AUTO(EIdTrans_load);\n\tif (fileName.empty())\n\t{\n\t\tnlwarning (\"EIT: Can't load empty filename for EntityIdTranslator\");\n\t\treturn;\n\t}\n\n\tif (!FileName.empty())\n\t{\n\t\tnlwarning (\"EIT: Can't load file '%s' for EntityIdTranslator because we already load the file '%s'\", fileName.c_str(), FileName.c_str());\n\t\treturn;\n\t}\n\n\tnlinfo (\"EIT: CEntityIdTranslator: load '%s'\", fileName.c_str());\n\n\tFileName = fileName;\n\n\tif(CFile::fileExists(FileName))\n\t{\n\t\tCIFile ifile;\n\t\tif( ifile.open(FileName) )\n\t\t{\n\t\t\tFileVersion = Version;\n\t\t\tifile.serialVersion (FileVersion);\n\t\t\tifile.serialCont (RegisteredEntities);\n\n\t\t\tifile.close ();\n\n\t\t\t// fill the entity name index container\n\t\t\tNameIndex.clear();\n\t\t\tTEntityCont::iterator first(RegisteredEntities.begin()), last(RegisteredEntities.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tNameIndex.insert(make_pair(toLower(first->second.EntityName), first->first));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"EIT: Can't load filename '%s' for EntityIdTranslator\", FileName.c_str());\n\t\t}\n\t}\n\n\tcbInvalidEntityNamesFilename (invalidEntityNamesFilename);\n\n\tNLMISC::CFile::addFileChangeCallback (invalidEntityNamesFilename, cbInvalidEntityNamesFilename);\n}\n\nvoid CEntityIdTranslator::save ()\n{\n\tH_AUTO(EIdTrans_save);\n\n\tif (FileName.empty())\n\t{\n\t\tnlwarning (\"EIT: Can't save empty filename for EntityIdTranslator (you forgot to load() it before?)\");\n\t\treturn;\n\t}\n\n\tnlinfo (\"EIT: CEntityIdTranslator: save\");\n\n\tCOFile ofile;\n\tif( ofile.open(FileName) )\n\t{\n\t\tofile.serialVersion (Version);\n\t\tFileVersion = Version;\n\t\tofile.serialCont (RegisteredEntities);\n\n\t\tofile.close ();\n\t}\n\telse\n\t{\n\t\tnlwarning (\"EIT: Can't save filename '%s' for EntityIdTranslator\", FileName.c_str());\n\t}\n}\n\nuint32 CEntityIdTranslator::getUId (const string &userName)\n{\n\tconst TEntityCont::iterator itEnd = RegisteredEntities.end();\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != itEnd ; ++it)\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (entity.UserName == userName)\n\t\t{\n\t\t\treturn entity.UId;\n\t\t}\n\t}\n\treturn 0;\n}\n\nstring CEntityIdTranslator::getUserName (uint32 uid)\n{\n\tconst TEntityCont::iterator itEnd = RegisteredEntities.end();\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != itEnd ; ++it)\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (entity.UId == uid)\n\t\t{\n\t\t\treturn entity.UserName;\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid CEntityIdTranslator::getEntityIdInfo (const CEntityId &eid, ucstring &entityName, sint8 &entitySlot, uint32 &uid, string &userName, bool &online, std::string* additional)\n{\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tif (additional != NULL)\n\t\tadditional->clear();\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: %s is not registered in CEntityIdTranslator\", reid.toString().c_str());\n\t\tentityName = \"\";\n\t\tentitySlot = -1;\n\t\tuid = std::numeric_limits<uint32>::max();\n\t\tuserName = \"\";\n\t\tonline = false;\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\tentityName = entity.EntityName;\n\t\tentitySlot = entity.EntitySlot;\n\t\tuid = entity.UId;\n\t\tuserName = entity.UserName;\n\t\tonline = entity.Online;\n\n\t\tif (EntityInfoCallback != NULL && additional != NULL)\n\t\t\t*additional = EntityInfoCallback(eid);\n\t}\n}\n\nbool CEntityIdTranslator::setEntityNameStringId(const ucstring &entityName, uint32 stringId)\n{\n\tconst TEntityCont::iterator itEnd = RegisteredEntities.end();\n\tfor (TEntityCont::iterator it = RegisteredEntities.begin(); it != itEnd ; ++it)\n\t{\n\t\tCEntity &entity = it->second;\n\t\tif (entity.EntityName == entityName)\n\t\t{\n\t\t\tentity.EntityNameStringId = stringId;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nbool CEntityIdTranslator::setEntityNameStringId(const CEntityId &eid, uint32 stringId)\n{\n\tTEntityCont::iterator it (RegisteredEntities.find(eid));\n\tif (it == RegisteredEntities.end())\n\t{\n\t\t// there is nothing we can do !\n\t\treturn false;\n\t}\n\n\tCEntity &entity = it->second;\n\tentity.EntityNameStringId = stringId;\n\n\treturn true;\n}\n\nuint32 CEntityIdTranslator::getEntityNameStringId(const CEntityId &eid)\n{\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tconst TEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\treturn entity.EntityNameStringId;\n\t}\n}\n\n// get the shard id of an entity\nuint32\tCEntityIdTranslator::getEntityShardId(const CEntityId &eid)\n{\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tconst TEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\treturn entity.ShardId;\n\t}\n}\n\n\nvoid CEntityIdTranslator::setEntityOnline (const CEntityId &eid, bool online)\n{\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: %s is not registered in CEntityIdTranslator\", reid.toString().c_str());\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\tentity.Online = online;\n\t}\n}\n\nbool CEntityIdTranslator::isEntityOnline (const CEntityId &eid)\n{\n\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\tCEntityId reid(eid);\n\treid.setCreatorId(0);\n\treid.setDynamicId(0);\n\n\tTEntityCont::iterator it = RegisteredEntities.find (reid);\n\tif (it == RegisteredEntities.end ())\n\t{\n\t\tnlwarning (\"EIT: %s is not registered in CEntityIdTranslator\", reid.toString().c_str());\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\tCEntity &entity = it->second;\n\t\treturn entity.Online;\n\t}\n}\n\nstd::string CEntityIdTranslator::getRegisterableString( const ucstring & entityName )\n{\n\tstring ret = toLower( entityName.toString() );\n\tstring::size_type pos = ret.find( 0x20 );\n\twhile( pos != string::npos )\n\t{\n\t\tret.erase( pos,1 );\n\t\tpos = ret.find( 0x20 );\n\t}\n\treturn ret;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel,findEIdByUser,\"Find entity ids using the user name\",\"<username>|<uid>\")\n{\n\tif (args.size () != 1)\n\t\treturn false;\n\n\tvector<CEntityId> res;\n\n\tstring userName = args[0];\n\tuint32 uid = atoi (userName.c_str());\n\n\tif (uid != 0)\n\t{\n\t\tCEntityIdTranslator::getInstance()->getByUser(uid, res);\n\t\tuserName = CEntityIdTranslator::getInstance()->getUserName(uid);\n\t}\n\telse\n\t{\n\t\tCEntityIdTranslator::getInstance()->getByUser(userName, res);\n\t\tCEntityIdTranslator::getInstance()->getUId(userName);\n\t}\n\n\tlog.displayNL(\"User Name '%s' (uid=%d) has %d entities:\", userName.c_str(), uid, res.size());\n\tfor (uint i = 0 ; i < res.size(); i++)\n\t{\n\t\tlog.displayNL(\">  %s '%s'\", res[i].toString().c_str(), CEntityIdTranslator::getInstance()->getByEntity (res[i]).c_str());\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel,findEIdByEntity,\"Find entity id using the entity name\",\"<entityname>|<eid>\")\n{\n\tif (args.size () != 1)\n\t\treturn false;\n\n\tCEntityId eid (args[0].c_str());\n\n\tif (eid == CEntityId::Unknown)\n\t{\n\t\teid = CEntityIdTranslator::getInstance()->getByEntity(args[0]);\n\t}\n\n\tif (eid == CEntityId::Unknown)\n\t{\n\t\tlog.displayNL(\"'%s' is not an eid or an entity name\", args[0].c_str());\n\t\treturn false;\n\t}\n\n\tucstring entityName;\n\tsint8 entitySlot;\n\tuint32 uid;\n\tstring userName;\n\tbool online;\n\tstd::string\textinf;\n\n\tCEntityIdTranslator::getInstance()->getEntityIdInfo(eid, entityName, entitySlot, uid, userName, online, &extinf);\n\n\tlog.displayNL(\"UId %d UserName '%s' EId %s EntityName '%s' EntitySlot %hd %s%s%s\", uid, userName.c_str(), eid.toString().c_str(), entityName.toString().c_str(), (sint16)entitySlot, (extinf.c_str()), (extinf.empty() ? \"\" : \" \"), (online?\"Online\":\"Offline\"));\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel,entityNameValid,\"Tell if an entity name is valid or not using CEntityIdTranslator validation rulez\",\"<entityname>\")\n{\n\tif (args.size () != 1) return false;\n\n\tif(!CEntityIdTranslator::getInstance()->isValidEntityName(args[0], &log))\n\t{\n\t\tlog.displayNL(\"Entity name '%s' is not valid\", args[0].c_str());\n\t}\n\telse\n\t{\n\t\tif (CEntityIdTranslator::getInstance()->checkEntityName(args[0]))\n\t\t{\n\t\t\tlog.displayNL(\"Entity name '%s' is already used by another player\", args[0].c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog.displayNL(\"Entity name '%s' is available\", args[0].c_str());\n\t\t}\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel,playerInfo,\"Get information about a player or all players in CEntityIdTranslator\",\"[<entityname>|<eid>|<username>|<uid>]\")\n{\n\tif (args.size () == 0)\n\t{\n\t\tconst map<CEntityId, CEntityIdTranslator::CEntity>\t&res = CEntityIdTranslator::getInstance()->getRegisteredEntities ();\n\t\tlog.displayNL(\"%d result(s) for 'all players information'\", res.size());\n\t\tfor (map<CEntityId, CEntityIdTranslator::CEntity>::const_iterator it = res.begin(); it != res.end(); it++)\n\t\t{\n\t\t\tconst CEntityIdTranslator::CEntity &entity = it->second;\n\t\t\tlog.displayNL(\"UId %d UserName '%s' EId %s EntityName '%s' EntitySlot %hd %s\", entity.UId, entity.UserName.c_str(), it->first.toString().c_str(), entity.EntityName.toString().c_str(), (sint16)(entity.EntitySlot), (entity.Online?\"Online\":\"Offline\"));\n\t\t}\n\n\t\treturn true;\n\t}\n\telse if (args.size () == 1)\n\t{\n\t\tvector<CEntityId> res;\n\n\t\tCEntityId eid (args[0].c_str());\n\t\tuint32 uid = atoi (args[0].c_str());\n\n\t\tif (eid != CEntityId::Unknown)\n\t\t{\n\t\t\t// we have to remove the crea and dyna because it can changed dynamically and will not be found in the storage array\n\t\t\teid.setCreatorId(0);\n\t\t\teid.setDynamicId(0);\n\n\t\t\tres.push_back(eid);\n\t\t}\n\t\telse if (uid != 0)\n\t\t{\n\t\t\t// the parameter is an uid\n\t\t\tCEntityIdTranslator::getInstance()->getByUser (uid, res);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCEntityIdTranslator::getInstance()->getByUser (args[0], res, false);\n\n\t\t\tCEntityIdTranslator::getInstance()->getByEntity (args[0], res, false);\n\t\t}\n\n\t\tlog.displayNL(\"%d result(s) for '%s'\", res.size(), args[0].c_str());\n\t\tfor (uint i = 0; i < res.size(); i++)\n\t\t{\n\t\t\tucstring entityName;\n\t\t\tsint8 entitySlot;\n\t\t\tuint32 uid2;\n\t\t\tstring userName;\n\t\t\tbool online;\n\t\t\tstd::string\textinf;\n\t\t\tCEntityIdTranslator::getInstance()->getEntityIdInfo (res[i], entityName, entitySlot, uid2, userName, online, &extinf);\n\n\t\t\tlog.displayNL(\"UId %d UserName '%s' EId %s EntityName '%s' EntitySlot %hd %s%s%s\", uid2, userName.c_str(), res[i].toString().c_str(), entityName.toString().c_str(), (sint16)entitySlot, (extinf.c_str()), (extinf.empty() ? \"\" : \" \"), (online?\"Online\":\"Offline\"));\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/entity_id.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/entity_id.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\tconst uint64 CEntityId::MaxEntityId = ((uint64)1 << (CEntityId::ID_SIZE + 1)) - (uint64)1;\n\n\tCEntityId CEntityId::_NextEntityId;\n\n\tuint8 CEntityId::_ServerId = 0;\n\n\tconst CEntityId CEntityId::Unknown (CEntityId::UNKNOWN_TYPE, 0, 0, 0);\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/eval_num_expr.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/eval_num_expr.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nusing namespace std;\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::readDecimal (double &value)\n{\n\t// Read first integer value\n\treadIntegerNumberDecimal (value);\n\n\t// Dot ?\n\tchar currentChar = *_ExprPtr;\n\tif (currentChar == '.')\n\t{\n\t\t// Next char\n\t\t_ExprPtr++;\n\t\tcurrentChar = *_ExprPtr;\n\t\tif (currentChar < '0' || currentChar > '9')\n\t\t\treturn NumberSyntaxError;\n\n\t\t// Read the decimal part\n\t\tconst char *start = _ExprPtr;\n\t\tdouble fract;\n\t\treadIntegerNumberDecimal (fract);\n\t\tfract /= (double)pow (10.0,(sint)(_ExprPtr-start));\n\t\tvalue += fract;\n\t}\n\n\treturn NoError;\n}\n\n// ***************************************************************************\n\nvoid CEvalNumExpr::readIntegerNumberDecimal (double &value)\n{\n\t// Registered values\n\tregister double regValue = 0;\n\n\t// Read the first value\n\tchar currentChar = *_ExprPtr;\n\tif ((currentChar >= '0') && (currentChar <= '9'))\n\t{\n\t\tregValue += (currentChar - '0');\n\t\t_ExprPtr++;\n\t\tcurrentChar = *_ExprPtr;\n\n\t\t// For each values\n\t\twhile ((currentChar >= '0') && (currentChar <= '9'))\n\t\t{\n\t\t\tregValue *= 10;\n\t\t\tregValue += (currentChar - '0');\n\n\t\t\t// Next char\n\t\t\t_ExprPtr++;\n\t\t\tcurrentChar = *_ExprPtr;\n\t\t}\n\t}\n\n\t// Store value\n\tvalue = regValue;\n}\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::getNextToken (TToken &token)\n{\n\t// Get the current char\n\tuint8 currentChar = *_ExprPtr;\n\n\t// Skip space\n\twhile ((currentChar!=0) && (currentChar<=0x20))\n\t{\n\t\t_ExprPtr++;\n\t\tcurrentChar = *_ExprPtr;\n\t}\n\n\t// Can be an operator ?\n\tif (currentChar <= 128)\n\t{\n\t\t// Get the operator\n\t\t_Op = _OperatorArray[currentChar];\n\n\t\t// Is an operator ?\n\t\tif (_Op != NotOperator)\n\t\t{\n\t\t\t// It is an operator\n\t\t\ttoken = Operator;\n\n\t\t\t// Is a 2 characters operator ?\n\t\t\tif (_Op != ExtOperator)\n\t\t\t{\n\t\t\t\t// Return next character\n\t\t\t\t_ExprPtr++;\n\t\t\t\treturn NoError;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Have a second character ?\n\t\t\t\tchar secondChar = *(_ExprPtr+1);\n\n\t\t\t\t// What kind of 1st character\n\t\t\t\tswitch (currentChar)\n\t\t\t\t{\n\t\t\t\tcase '!':\n\t\t\t\t\tif (secondChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = NotEqual;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Not;\n\t\t\t\t\t\t_ExprPtr++;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '&':\n\t\t\t\t\tif (secondChar == '&')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = LogicalAnd;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = And;\n\t\t\t\t\t\t_ExprPtr+=1;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '-':\n\t\t\t\t\tif (secondChar == '>')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = SRightShift;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Minus;\n\t\t\t\t\t\t_ExprPtr++;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '<':\n\t\t\t\t\tif (secondChar == '<')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = ULeftShift;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse if (secondChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = InferiorEqual;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse if (secondChar == '-')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = SLeftShift;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Inferior;\n\t\t\t\t\t\t_ExprPtr+=1;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '=':\n\t\t\t\t\tif (secondChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Equal;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '>':\n\t\t\t\t\tif (secondChar == '>')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = URightShift;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse if (secondChar == '=')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = SuperiorEqual;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Superior;\n\t\t\t\t\t\t_ExprPtr+=1;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '^':\n\t\t\t\t\tif (secondChar == '^')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = LogicalXor;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Xor;\n\t\t\t\t\t\t_ExprPtr+=1;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\tcase '|':\n\t\t\t\t\tif (secondChar == '|')\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = LogicalOr;\n\t\t\t\t\t\t_ExprPtr+=2;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_Op = Or;\n\t\t\t\t\t\t_ExprPtr+=1;\n\t\t\t\t\t\treturn NoError;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Can't found the operator\n\t\t\t\treturn UnknownOperator;\n\t\t\t}\n\t\t}\n\t\t// Is End, '(', ')', '.' ?\n\t\telse if (currentChar == 0)\n\t\t{\n\t\t\ttoken = End;\n\t\t\treturn NoError;\n\t\t}\n\t\telse if (currentChar == '(')\n\t\t{\n\t\t\t_ExprPtr++;\n\t\t\ttoken = Open;\n\t\t\treturn NoError;\n\t\t}\n\t\telse if (currentChar == ')')\n\t\t{\n\t\t\t_ExprPtr++;\n\t\t\ttoken = Close;\n\t\t\treturn NoError;\n\t\t}\n\t\telse if (currentChar == ',')\n\t\t{\n\t\t\t_ExprPtr++;\n\t\t\ttoken = Coma;\n\t\t\treturn NoError;\n\t\t}\n\t\t// Is a number ?\n\t\telse if (((currentChar >= '0') && (currentChar <= '9')) || (currentChar == '.'))\n\t\t{\n\t\t\t// This is a number\n\t\t\ttoken = Number;\n\n\t\t\t// Have a second character ?\n\t\t\tchar secondChar = *(_ExprPtr+1);\n\n\t\t\t// Is an hexadecimal value ?\n\t\t\tif ((currentChar == '0') && (secondChar == 'x'))\n\t\t\t{\n\t\t\t\t// Go to the number\n\t\t\t\t_ExprPtr +=2;\n\t\t\t\tcurrentChar = *_ExprPtr;\n\n\t\t\t\t// Registered values\n\t\t\t\tregister double regValue = 0;\n\t\t\t\tif ((currentChar >= '0') && (currentChar <= '9'))\n\t\t\t\t{\n\t\t\t\t\tregValue += (currentChar - '0');\n\t\t\t\t}\n\t\t\t\telse if ((currentChar >= 'a') && (currentChar <= 'f'))\n\t\t\t\t{\n\t\t\t\t\tregValue += (currentChar - 'a' + 10);\n\t\t\t\t}\n\t\t\t\telse if ((currentChar >= 'A') && (currentChar <= 'F'))\n\t\t\t\t{\n\t\t\t\t\tregValue += (currentChar - 'A' + 10);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Number syntax error\n\t\t\t\t\treturn NumberSyntaxError;\n\t\t\t\t}\n\t\t\t\t_ExprPtr++;\n\t\t\t\tcurrentChar = *_ExprPtr;\n\n\t\t\t\t// For each values\n\t\t\t\tfor(;;)\n\t\t\t\t{\n\t\t\t\t\tif ((currentChar >= '0') && (currentChar <= '9'))\n\t\t\t\t\t{\n\t\t\t\t\t\tregValue *= 16;\n\t\t\t\t\t\tregValue += (currentChar - '0');\n\t\t\t\t\t}\n\t\t\t\t\telse if ((currentChar >= 'a') && (currentChar <= 'f'))\n\t\t\t\t\t{\n\t\t\t\t\t\tregValue *= 16;\n\t\t\t\t\t\tregValue += (currentChar - 'a' + 10);\n\t\t\t\t\t}\n\t\t\t\t\telse if ((currentChar >= 'A') && (currentChar <= 'F'))\n\t\t\t\t\t{\n\t\t\t\t\t\tregValue *= 16;\n\t\t\t\t\t\tregValue += (currentChar - 'A' + 10);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Stop\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Next char\n\t\t\t\t\t_ExprPtr++;\n\t\t\t\t\tcurrentChar = *_ExprPtr;\n\t\t\t\t}\n\n\t\t\t\t// Store value\n\t\t\t\t_Value = regValue;\n\n\t\t\t\t// Number ok\n\t\t\t\treturn NoError;\n\t\t\t}\n\t\t\t// Is an octal value ?\n\t\t\telse if ((currentChar == '0') && (secondChar >= '0') && (secondChar <= '9'))\n\t\t\t{\n\t\t\t\t// Go to the number\n\t\t\t\t_ExprPtr ++;\n\t\t\t\tcurrentChar = *_ExprPtr;\n\n\t\t\t\t// Registered values\n\t\t\t\tregister double regValue = 0;\n\n\t\t\t\t// Check octal number\n\t\t\t\tif (currentChar > '7')\n\t\t\t\t\treturn NumberSyntaxError;\n\n\t\t\t\t// Read the first value\n\t\t\t\tregValue += (currentChar - '0');\n\t\t\t\t_ExprPtr++;\n\t\t\t\tcurrentChar = *_ExprPtr;\n\n\t\t\t\t// For each values\n\t\t\t\twhile ((currentChar >= '0') && (currentChar <= '9'))\n\t\t\t\t{\n\t\t\t\t\t// Check octal number\n\t\t\t\t\tif (currentChar > '7')\n\t\t\t\t\t\treturn NumberSyntaxError;\n\n\t\t\t\t\tregValue *= 8;\n\t\t\t\t\tregValue += (currentChar - '0');\n\n\t\t\t\t\t// Next char\n\t\t\t\t\t_ExprPtr++;\n\t\t\t\t\tcurrentChar = *_ExprPtr;\n\t\t\t\t}\n\n\t\t\t\t// Store value\n\t\t\t\t_Value = regValue;\n\n\t\t\t\t// Number ok\n\t\t\t\treturn NoError;\n\t\t\t}\n\t\t\t// It is a decimal value\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Read value\n\t\t\t\tTReturnState state = readDecimal (_Value);\n\t\t\t\tif (state == NoError)\n\t\t\t\t{\n\t\t\t\t\t// Exponent ?\n\t\t\t\t\tcurrentChar = *_ExprPtr;\n\t\t\t\t\tif ( (currentChar == 'e') || (currentChar == 'E') )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Next char\n\t\t\t\t\t\t_ExprPtr++;\n\n\t\t\t\t\t\t// Minus ?\n\t\t\t\t\t\tbool negative = false;\n\t\t\t\t\t\tif (*_ExprPtr == '-')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnegative = true;\n\t\t\t\t\t\t\t_ExprPtr++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Read value\n\t\t\t\t\t\tdouble exponent;\n\t\t\t\t\t\tstate = readDecimal (exponent);\n\t\t\t\t\t\tif (state == NoError)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Negative value ?\n\t\t\t\t\t\t\tif (negative)\n\t\t\t\t\t\t\t\texponent = -exponent;\n\n\t\t\t\t\t\t\t// Raise 10 at the power of\n\t\t\t\t\t\t\t_Value *= pow (10.0, exponent);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn state;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Number ok\n\t\t\t\t\treturn NoError;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn state;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Is a string ?\n\t\telse if (currentChar == '\"')\n\t\t{\n\t\t\t// Look for the end of the string\n\t\t\t_ExprPtr++;\n\t\t\tcurrentChar = *_ExprPtr;\n\t\t\tconst char *start = _ExprPtr;\n\t\t\twhile ( (currentChar != 0) && (currentChar != '\"') )\n\t\t\t{\n\t\t\t\t_ExprPtr++;\n\t\t\t\tcurrentChar = *_ExprPtr;\n\t\t\t}\n\n\t\t\t// End reached ?\n\t\t\tif (currentChar == 0)\n\t\t\t\treturn MustBeDoubleQuote;\n\n\t\t\t// This is a user string, copy the string\n\t\t\tuint size = (uint)(_ExprPtr - start);\n\t\t\tif (size >= (InternalStringLen-1))\n\t\t\t{\n\t\t\t\t_InternalStlString.resize (size);\n\t\t\t\tuint i;\n\t\t\t\tfor (i=0; i<size; i++)\n\t\t\t\t\t_InternalStlString[i] = start[i];\n\t\t\t\t_InternalStringPtr = _InternalStlString.c_str ();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tmemcpy (_InternalString, start, size);\n\t\t\t\t_InternalString[size] = 0;\n\t\t\t\t_InternalStringPtr = _InternalString;\n\t\t\t}\n\n\t\t\t// Token\n\t\t\t_ExprPtr++;\n\t\t\ttoken = String;\n\t\t\treturn NoError;\n\t\t}\n\t}\n\n\t// Read a string\n\tconst char *start = _ExprPtr;\n\twhile ( (currentChar >= 128) || _StringChar[currentChar] )\n\t{\n\t\t_ExprPtr++;\n\t\tcurrentChar = *_ExprPtr;\n\t}\n\n\t// Is pi ?\n\tif (((_ExprPtr - start) == 2) && (start[0] == 'p') && (start[1] == 'i'))\n\t{\n\t\ttoken = Number;\n\t\t_Value = 3.1415926535897932384626433832795;\n\t\treturn NoError;\n\t}\n\t// Is e ?\n\telse if (((_ExprPtr - start) == 1) && (start[0] == 'e'))\n\t{\n\t\ttoken = Number;\n\t\t_Value = 2.7182818284590452353602874713527;\n\t\treturn NoError;\n\t}\n\n\t// This is a user string, copy the string\n\tuint size = (uint)(_ExprPtr - start);\n\tif (size >= (InternalStringLen-1))\n\t{\n\t\t_InternalStlString.resize (size);\n\t\tuint i;\n\t\tfor (i=0; i<size; i++)\n\t\t\t_InternalStlString[i] = start[i];\n\t\t_InternalStringPtr = _InternalStlString.c_str ();\n\t}\n\telse\n\t{\n\t\tmemcpy (_InternalString, start, size);\n\t\t_InternalString[size] = 0;\n\t\t_InternalStringPtr = _InternalString;\n\t}\n\n\t// Search for a reserved word ?\n\tuint begin = 0;\n\tuint end = ReservedWordCount-1;\n\tsint result = strcmp (_InternalStringPtr, _ReservedWord[begin]);\n\tif ( result >= 0 )\n\t{\n\t\t// The first is the good ?\n\t\tif ( result == 0 )\n\t\t{\n\t\t\tend = begin;\n\t\t}\n\n\t\tresult = strcmp (_InternalStringPtr, _ReservedWord[end]);\n\t\tif (result <= 0)\n\t\t{\n\t\t\t// The last is the good ?\n\t\t\tif ( result == 0 )\n\t\t\t{\n\t\t\t\tbegin = end;\n\t\t\t}\n\n\t\t\t// While there is a middle..\n\t\t\twhile ((end - begin) > 1)\n\t\t\t{\n\t\t\t\tuint middle = begin + (end - begin) / 2;\n\t\t\t\tresult = strcmp (_InternalStringPtr, _ReservedWord[middle]);\n\t\t\t\tif (result == 0)\n\t\t\t\t{\n\t\t\t\t\tbegin = middle;\n\t\t\t\t\tend = middle;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if (result < 0)\n\t\t\t\t{\n\t\t\t\t\tend = middle;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tbegin = middle;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Found ?\n\t\tif (end == begin)\n\t\t{\n\t\t\t// Return the token\n\t\t\t_ReservedWordFound = (TReservedWord)begin;\n\t\t\ttoken = _ReservedWordToken[begin];\n\n\t\t\t// Ok\n\t\t\treturn NoError;\n\t\t}\n\t}\n\n\t// Token\n\ttoken = String;\n\treturn NoError;\n}\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::evalExpression (const char *expression, double &result,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t int *errorIndex, uint32 userData)\n{\n\t// Init the ptr\n\t_ExprPtr = expression;\n\n\tTToken nextToken;\n\tTReturnState error = evalExpression (result, nextToken, userData);\n\tif (error == NoError)\n\t{\n\t\t// The end ?\n\t\tif (nextToken == End)\n\t\t\treturn NoError;\n\t\telse\n\t\t{\n\t\t\tif (errorIndex)\n\t\t\t\t*errorIndex = (int)(_ExprPtr - expression);\n\t\t\treturn MustBeEnd;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (errorIndex)\n\t\t\t*errorIndex = (int)(_ExprPtr - expression);\n\t\treturn error;\n\t}\n}\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::evalExpression (double &finalResult, TToken &nextToken, uint32 userData)\n{\n\t// Array of result\n\n\tuint exprCount = 0;\n\tdouble result[InternalOperator];\n\tvector<double> resultSup;\n\n\tuint opCount = 0;\n\tTOperator resultOp[InternalOperator];\n\tvector<TOperator> resultOpSup;\n\n\t// Read a token\n\tTReturnState error = getNextToken (nextToken);\n\tif (error != NoError)\n\t\treturn error;\n\tfor(;;)\n\t{\n\t\t// Unary opertor\n\t\tuint unaryOpCount = 0;\n\t\tTOperator resultUnaryOp[InternalOperator];\n\t\tvector<TOperator> resultUnaryOpSup;\n\n\t\t// Current value\n\t\tdouble value;\n\n\t\t// Unary operator ?\n\t\tif ( (nextToken == Operator) && ( (_Op == Minus) || (_Op == Not) || (_Op == Tilde) ) )\n\t\t{\n\t\t\t// Push the unary operator\n\t\t\tif (unaryOpCount<InternalOperator)\n\t\t\t\tresultUnaryOp[unaryOpCount] = _Op;\n\t\t\telse\n\t\t\t\tresultUnaryOpSup.push_back (_Op);\n\t\t\tunaryOpCount++;\n\n\t\t\t// Read next token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error != NoError)\n\t\t\t\treturn error;\n\t\t}\n\n\t\t// Parenthesis ?\n\t\tif (nextToken == Open)\n\t\t{\n\t\t\t// Eval sub expression\n\t\t\terror = evalExpression (value, nextToken, userData);\n\t\t\tif (error == NoError)\n\t\t\t{\n\t\t\t\tif (nextToken != Close)\n\t\t\t\t\treturn MustBeClose;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn error;\n\n\t\t\t// Get next token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error != NoError)\n\t\t\t\treturn error;\n\t\t}\n\t\t// This is a function ?\n\t\telse if ( (nextToken == Function1) || (nextToken == Function2) )\n\t\t{\n\t\t\tTToken backupedToken = nextToken;\n\n\t\t\t// Get the function\n\t\t\tTReservedWord reservedWord = _ReservedWordFound;\n\n\t\t\t// Read a token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error == NoError)\n\t\t\t{\n\t\t\t\t// Open ?\n\t\t\t\tif (nextToken != Open)\n\t\t\t\t{\n\t\t\t\t\treturn MustBeOpen;\n\t\t\t\t}\n\n\t\t\t\t// Eval an expression\n\t\t\t\tdouble arg0;\n\t\t\t\terror = evalExpression (arg0, nextToken, userData);\n\t\t\t\tif (error == NoError)\n\t\t\t\t{\n\t\t\t\t\t// 2 arg ?\n\t\t\t\t\tif (backupedToken == Function2)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nextToken == Coma)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Second argument\n\t\t\t\t\t\t\tdouble arg1;\n\t\t\t\t\t\t\terror = evalExpression (arg1, nextToken, userData);\n\t\t\t\t\t\t\tif (error == NoError)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Final with close ?\n\t\t\t\t\t\t\t\tif (nextToken == Close)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tswitch (reservedWord)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase Atan2:\n\t\t\t\t\t\t\t\t\t\tvalue = atan2 (arg0, arg1);\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Max:\n\t\t\t\t\t\t\t\t\t\tvalue = (arg0>arg1) ? arg0 : arg1;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Min:\n\t\t\t\t\t\t\t\t\t\tvalue = (arg0<arg1) ? arg0 : arg1;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Pow:\n\t\t\t\t\t\t\t\t\t\tvalue = pow (arg0, arg1);\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase Rand:\n\t\t\t\t\t\t\t\t\t\tvalue = arg0 + (arg1-arg0) * (double)rand () / ((double)RAND_MAX+1.0);\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\t\t// Can't be here after getToken\n\t\t\t\t\t\t\t\t\t\tnlstop;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\treturn MustBeClose;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\treturn error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn MustBeComa;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nextToken == Close)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Eval the function\n\t\t\t\t\t\t\tswitch (reservedWord)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase Abs:\n\t\t\t\t\t\t\t\tvalue = fabs (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Acos:\n\t\t\t\t\t\t\t\tvalue = acos (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Asin:\n\t\t\t\t\t\t\t\tvalue = asin (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Atan:\n\t\t\t\t\t\t\t\tvalue = atan (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Ceil:\n\t\t\t\t\t\t\t\tvalue = ceil (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Cosh:\n\t\t\t\t\t\t\t\tvalue = cosh (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Cos:\n\t\t\t\t\t\t\t\tvalue = cos (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Exponent:\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tint exponent;\n\t\t\t\t\t\t\t\t\tfrexp( arg0, &exponent);\n\t\t\t\t\t\t\t\t\tvalue = (double)exponent;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Exp:\n\t\t\t\t\t\t\t\tvalue = exp (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Floor:\n\t\t\t\t\t\t\t\tvalue = floor (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Int:\n\t\t\t\t\t\t\t\tvalue = (double)(int)(arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Log10:\n\t\t\t\t\t\t\t\tvalue = log10 (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Log:\n\t\t\t\t\t\t\t\tvalue = log (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Mantissa:\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tint exponent;\n\t\t\t\t\t\t\t\t\tvalue = frexp( arg0, &exponent);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Round:\n\t\t\t\t\t\t\t\tvalue = floor (arg0 + 0.5);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Sinh:\n\t\t\t\t\t\t\t\tvalue = sinh (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Sin:\n\t\t\t\t\t\t\t\tvalue = sin (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Sqrt:\n\t\t\t\t\t\t\t\tvalue = sqrt (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Sq:\n\t\t\t\t\t\t\t\tvalue = arg0 * arg0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Tanh:\n\t\t\t\t\t\t\t\tvalue = tanh (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase Tan:\n\t\t\t\t\t\t\t\tvalue = tan (arg0);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t// Can't be hear after getToken\n\t\t\t\t\t\t\t\tnlstop;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\treturn MustBeClose;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\treturn error;\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn error;\n\n\t\t\t// Get next token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error != NoError)\n\t\t\t\treturn error;\n\t\t}\n\t\telse if (nextToken == Number)\n\t\t{\n\t\t\t// Save the internal value\n\t\t\tvalue = _Value;\n\n\t\t\t// Get next token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error != NoError)\n\t\t\t\treturn error;\n\t\t}\n\t\telse if (nextToken == String)\n\t\t{\n\t\t\t// Copy the string\n\t\t\tchar\t\t\tinternalString[InternalStringLen];\n\t\t\tstd::string\t\tinternalStlString;\n\t\t\tconst char\t\t*internalStringPtr;\n\t\t\tif (strlen (_InternalStringPtr) >= InternalStringLen-1)\n\t\t\t{\n\t\t\t\tinternalStlString = _InternalStringPtr;\n\t\t\t\tinternalStringPtr = internalStlString.c_str ();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstrcpy (internalString ,_InternalStringPtr);\n\t\t\t\tinternalStringPtr = internalString;\n\t\t\t}\n\n\t\t\t// Read a token\n\t\t\terror = getNextToken (nextToken);\n\t\t\tif (error == NoError)\n\t\t\t{\n\t\t\t\t// Open ?\n\t\t\t\tif (nextToken == Open)\n\t\t\t\t{\n\t\t\t\t\t// Eval an expression\n\t\t\t\t\tdouble arg0;\n\t\t\t\t\terror = evalExpression (arg0, nextToken, userData);\n\t\t\t\t\tif (error == NoError)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (nextToken == Coma)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Second argument\n\t\t\t\t\t\t\tdouble arg1;\n\t\t\t\t\t\t\terror = evalExpression (arg1, nextToken, userData);\n\t\t\t\t\t\t\tif (error == NoError)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Final with close ?\n\t\t\t\t\t\t\t\tif (nextToken == Close)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Eval the function\n\t\t\t\t\t\t\t\t\terror = evalFunction (internalStringPtr, arg0, arg1, value);\n\t\t\t\t\t\t\t\t\tif (error != NoError)\n\t\t\t\t\t\t\t\t\t\treturn error;\n\n\t\t\t\t\t\t\t\t\t// Get next token\n\t\t\t\t\t\t\t\t\terror = getNextToken (nextToken);\n\t\t\t\t\t\t\t\t\tif (error != NoError)\n\t\t\t\t\t\t\t\t\t\treturn error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\treturn MustBeClose;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\treturn error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (nextToken == Close)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Eval the function\n\t\t\t\t\t\t\t\terror = evalFunction (internalStringPtr, arg0, value);\n\t\t\t\t\t\t\t\tif (error != NoError)\n\t\t\t\t\t\t\t\t\treturn error;\n\n\t\t\t\t\t\t\t\t// Get next token\n\t\t\t\t\t\t\t\terror = getNextToken (nextToken);\n\t\t\t\t\t\t\t\tif (error != NoError)\n\t\t\t\t\t\t\t\t\treturn error;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\treturn MustBeClose;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\treturn error;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// This is a user value\n\t\t\t\t\terror = evalValue (internalStringPtr, value, userData);\n\t\t\t\t\tif (error != NoError)\n\t\t\t\t\t\treturn error;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn error;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn MustBeExpression;\n\t\t}\n\n\t\t// Eval unary operator\n\t\tsint i;\n\t\tfor (i=unaryOpCount-1; i>=0; i--)\n\t\t{\n\t\t\tswitch ((i<InternalOperator)?resultUnaryOp[i]:resultUnaryOpSup[i-InternalOperator])\n\t\t\t{\n\t\t\tcase Not:\n\t\t\t\tvalue = (double)(uint)((floor (value+0.5)==0.0));\n\t\t\t\tbreak;\n\t\t\tcase Tilde:\n\t\t\t\tvalue = (double)~((uint)floor (value+0.5));\n\t\t\t\tbreak;\n\t\t\tcase Minus:\n\t\t\t\tvalue = -value;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Can't be hear after getToken\n\t\t\t\tnlstop;\n\t\t\t}\n\t\t}\n\n\t\t// Push the value\n\t\tif (exprCount < InternalOperator)\n\t\t\tresult[exprCount] = value;\n\t\telse\n\t\t\tresultSup.push_back (value);\n\t\texprCount++;\n\n\t\t// Look for an operator\n\t\t// Operator ?\n\t\tif (nextToken == Operator)\n\t\t{\n\t\t\t// Yes, push it\n\t\t\tif (opCount < InternalOperator)\n\t\t\t\tresultOp[opCount] = _Op;\n\t\t\telse\n\t\t\t\tresultOpSup.push_back (_Op);\n\t\t\topCount++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Exit the evaluate loop\n\t\t\tbreak;\n\t\t}\n\n\t\t// Next token\n\t\terror = getNextToken (nextToken);\n\t}\n\n\t// Reduce the expression\n\tuint index = 1;\n\twhile (exprCount != 1)\n\t{\n\t\t// Reduct ?\n\t\tTOperator before = (((index-1)<InternalOperator)?resultOp[index-1]:resultOpSup[index-1-InternalOperator]);\n\t\tTOperator after = (index < opCount)?(((index)<InternalOperator)?resultOp[index]:resultOpSup[index-InternalOperator]):NotOperator;\n\t\tif ((index == opCount) || (_OperatorPrecedence[before] <= _OperatorPrecedence[after]))\n\t\t{\n\t\t\t// Eval the value\n\t\t\tdouble &v0 = ((index-1)<InternalOperator)?result[index-1]:resultSup[index-1-InternalOperator];\n\t\t\tdouble &v1 = ((index)<InternalOperator)?result[index]:resultSup[index-InternalOperator];\n\n\t\t\t// Choose the operator\n\t\t\tswitch (before)\n\t\t\t{\n\t\t\tcase Not:\n\t\t\tcase Tilde:\n\t\t\t\treturn NotUnaryOperator;\n\t\t\tcase Mul:\n\t\t\t\tv0 *= v1;\n\t\t\t\tbreak;\n\t\t\tcase Div:\n\t\t\t\tif (v1 == 0)\n\t\t\t\t{\n\t\t\t\t\treturn DividByZero;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tv0 /= v1;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase Remainder:\n\t\t\t\tv0 = fmod (v0, v1);\n\t\t\t\tbreak;\n\t\t\tcase Plus:\n\t\t\t\tv0 += v1;\n\t\t\t\tbreak;\n\t\t\tcase Minus:\n\t\t\t\tv0 -= v1;\n\t\t\t\tbreak;\n\t\t\tcase ULeftShift:\n\t\t\t\tv0 = (double)(((uint)floor (v0 + 0.5))<<((uint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase URightShift:\n\t\t\t\tv0 = (double)(((uint)floor (v0 + 0.5))>>((uint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase SLeftShift:\n\t\t\t\tv0 = (double)(((sint)floor (v0 + 0.5))<<((sint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase SRightShift:\n\t\t\t\tv0 = (double)(((sint)floor (v0 + 0.5))>>((sint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase Inferior:\n\t\t\t\tv0 = (v0<v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase InferiorEqual:\n\t\t\t\tv0 = (v0<=v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase Superior:\n\t\t\t\tv0 = (v0>v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase SuperiorEqual:\n\t\t\t\tv0 = (v0>=v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase Equal:\n\t\t\t\tv0 = (v0==v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase NotEqual:\n\t\t\t\tv0 = (v0!=v1)?1.0:0.0;\n\t\t\t\tbreak;\n\t\t\tcase And:\n\t\t\t\tv0 = (double)(((uint)floor (v0 + 0.5)) & ((uint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase Or:\n\t\t\t\tv0 = (double)(((uint)floor (v0 + 0.5)) | ((uint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase Xor:\n\t\t\t\tv0 = (double)(((uint)floor (v0 + 0.5)) ^ ((uint)floor (v1 + 0.5)));\n\t\t\t\tbreak;\n\t\t\tcase LogicalAnd:\n\t\t\t\tv0 = (double)(uint)((floor (v0 + 0.5) != 0.0) && (floor (v1 + 0.5) != 0.0));\n\t\t\t\tbreak;\n\t\t\tcase LogicalOr:\n\t\t\t\tv0 = (double)(uint)((floor (v0 + 0.5) != 0.0) || (floor (v1 + 0.5) != 0.0));\n\t\t\t\tbreak;\n\t\t\tcase LogicalXor:\n\t\t\t\t{\n\t\t\t\t\tbool b0 = floor (v0 + 0.5) != 0.0;\n\t\t\t\t\tbool b1 = floor (v1 + 0.5) != 0.0;\n\t\t\t\t\tv0 = (double)(uint)((b0&&!b1) || ((!b0)&&b1));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tnlstop;\n\t\t\t}\n\n\t\t\t// Decal others values\n\t\t\tuint i = index;\n\t\t\tfor (; i<exprCount-1; i++)\n\t\t\t{\n\t\t\t\t// Copy\n\t\t\t\tif (i<InternalOperator)\n\t\t\t\t\tresult[i] = (i+1<InternalOperator)?result[i+1]:resultSup[i+1-InternalOperator];\n\t\t\t\telse\n\t\t\t\t\tresultSup[i-InternalOperator] = (i+1<InternalOperator)?result[i+1]:resultSup[i+1-InternalOperator];\n\t\t\t}\n\t\t\texprCount--;\n\n\t\t\t// Decal operators\n\t\t\ti = index-1;\n\t\t\tfor (; i<opCount-1; i++)\n\t\t\t{\n\t\t\t\t// Copy\n\t\t\t\tif (i<InternalOperator)\n\t\t\t\t\tresultOp[i] = (i+1<InternalOperator)?resultOp[i+1]:resultOpSup[i+1-InternalOperator];\n\t\t\t\telse\n\t\t\t\t\tresultOpSup[i-InternalOperator] = (i+1<InternalOperator)?resultOp[i+1]:resultOpSup[i+1-InternalOperator];\n\n\t\t\t}\n\t\t\topCount--;\n\n\t\t\t// Last one ?\n\t\t\tif (index > 1)\n\t\t\t\tindex--;\n\t\t}\n\t\telse\n\t\t\tindex++;\n\t}\n\n\tfinalResult = result[0];\n\treturn NoError;\n}\n\n// ***************************************************************************\n\nbool CEvalNumExpr::internalCheck ()\n{\n\tfor (uint i=0; i<ReservedWordCount-1; i++)\n\t\tif (strcmp (_ReservedWord[i], _ReservedWord[i+1]) >= 0)\n\t\t{\n\t\t\tnlstop;\n\t\t\treturn false;\n\t\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\n// ASCII TABLE\n\n/*\n0 NUL\tSOH\t\tSTX\t\tETX\t\tEOT\t\tENQ\t\tACK\t\tBEL\t\tBS\t\tTAB\t\tLF\t\tVT\t\tFF\t\tCR\t\tSO\t\tSI\n1 DLE\tDC1\t\tDC2\t\tDC3\t\tDC4\t\tNAK\t\tSYN\t\tETB\t\tCAN\t\tEM\t\tSUB\t\tESC\t\tFS\t\tGS\t\tRS\t\tUS\n2\t\t!\t\t\"\t\t#\t\t$\t\t%\t\t&\t\t'\t\t(\t\t)\t\t*\t\t+\t\t,\t\t-\t\t.\t\t/\n3 0\t\t1\t\t2\t\t3\t\t4\t\t5\t\t6\t\t7\t\t8\t\t9\t\t:\t\t;\t\t<\t\t=\t\t>\t\t?\n4 @\t\tA\t\tB\t\tC\t\tD\t\tE\t\tF\t\tG\t\tH\t\tI\t\tJ\t\tK\t\tL\t\tM\t\tN\t\tO\n5 P\t\tQ\t\tR\t\tS\t\tT\t\tU\t\tV\t\tW\t\tX\t\tY\t\tZ\t\t[\t\t\\\t\t]\t\t^\t\t_\n6 `\t\ta\t\tb\t\tc\t\td\t\te\t\tf\t\tg\t\th\t\ti\t\tj\t\tk\t\tl\t\tm\t\tn\t\to\n7 p\t\tq\t\tr\t\ts\t\tt\t\tu\t\tv\t\tw\t\tx\t\ty\t\tz\t\t{\t\t|\t\t}\t\t~\n*/\n\n// ***************************************************************************\n\nconst CEvalNumExpr::TOperator\tCEvalNumExpr::_OperatorArray[128] =\n{\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator,\n\tNotOperator, ExtOperator, NotOperator, NotOperator, NotOperator, Remainder,   ExtOperator, NotOperator, NotOperator, NotOperator, Mul,\t\t   Plus,\t\tNotOperator, ExtOperator, NotOperator, Div,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, ExtOperator, ExtOperator, ExtOperator, NotOperator,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, ExtOperator, NotOperator,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator,\n\tNotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, NotOperator, ExtOperator, NotOperator, Tilde,\t   NotOperator,\n};\n\n// ***************************************************************************\n\nconst bool CEvalNumExpr::_StringChar[128] =\n{\n\tfalse, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,\n\tfalse, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,\n\tfalse, false, true,  true,  true,  false, false, true,  false, false, false, false, false, false, false, false,\n\ttrue,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  false, false, false, true,\n\ttrue,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,\n\ttrue,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  false,  true,\n\ttrue,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,\n\ttrue,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  true,  false, true,  false, true,\n};\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::evalValue (const char *value, double &result, uint32 userData)\n{\n\treturn UnknownValue;\n}\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::evalFunction (const char *funcName, double arg0, double &result)\n{\n\treturn UnknownFunction;\n}\n\n// ***************************************************************************\n\nCEvalNumExpr::TReturnState CEvalNumExpr::evalFunction (const char *funcName, double arg0, double arg1, double &result)\n{\n\treturn UnknownFunction;\n}\n\n// ***************************************************************************\n\nconst char *CEvalNumExpr::_ReservedWord[ReservedWordCount] =\n{\n\t\"abs\", // Abs\n\t\"acos\", // Acos\n\t\"asin\", // Asin\n\t\"atan\", // Atan\n\t\"atan2\", // Atan2\n\t\"ceil\", // Ceil\n\t\"cos\",\t// Cos\n\t\"cosh\", // Cosh\n\t\"exp\", // Exp\n\t\"exponent\", // Exponent\n\t\"floor\", // Floor\n\t\"int\", // Int\n\t\"log\", // Log\n\t\"log10\", // Log10\n\t\"mantissa\", // Mantissa\n\t\"max\", // Max\n\t\"min\", // Min\n\t\"pow\", // Pow\n\t\"rand\", // Rand\n\t\"round\", // Round\n\t\"sin\", // Sin\n\t\"sinh\", // Sinh\n\t\"sq\", // Sq\n\t\"sqrt\", // Sqrt\n\t\"tan\", // Tan\n\t\"tanh\", // Tanh\n};\n\n// ***************************************************************************\n\nconst CEvalNumExpr::TToken CEvalNumExpr::_ReservedWordToken[ReservedWordCount] =\n{\n\tFunction1, // Abs\n\tFunction1, // Acos\n\tFunction1, // Asin\n\tFunction1, // Atan\n\tFunction2, // Atan2\n\tFunction1, // Ceil\n\tFunction1, // Cos\n\tFunction1, // Cosh\n\tFunction1, // Exp\n\tFunction1, // Exponent\n\tFunction1, // Floor\n\tFunction1, // Int\n\tFunction1, // Log\n\tFunction1, // Log10\n\tFunction1, // Mantissa\n\tFunction2, // Max\n\tFunction2, // Min\n\tFunction2, // Pow\n\tFunction2, // Rand\n\tFunction1, // Round\n\tFunction1, // Sin\n\tFunction1, // Sinh\n\tFunction1, // Sq\n\tFunction1, // Sqrt\n\tFunction1, // Tan\n\tFunction1, // Tanh\n};\n\n// ***************************************************************************\n\nconst char *CEvalNumExpr::_ErrorString[ReturnValueCount]=\n{\n\t\"No error\",\n\t\"Unknown value\",\n\t\"Error during user defined value evaluation\",\n\t\"Unknown function\",\n\t\"Error during user defined function evaluation\",\n\t\"Syntax error in a number expression\",\n\t\"Unknown operator\",\n\t\"Should be a open parentesis\",\n\t\"Should be a close parentesis\",\n\t\"Should be a coma character\",\n\t\"Should be an expression\",\n\t\"Should not be an unary operator\",\n\t\"Should be the end of the expression\",\n\t\"Should be a double quote\",\n\t\"Divid by zero\",\n};\n\n// ***************************************************************************\n\nconst char* CEvalNumExpr::getErrorString (TReturnState state) const\n{\n\treturn _ErrorString[state];\n}\n\n// ***************************************************************************\n\nconst int CEvalNumExpr::_OperatorPrecedence[]=\n{\n\t0,\t// Not\n\t0,\t// Tilde\n\t1,\t// Mul\n\t1,\t// Div\n\t1,\t// Remainder\n\t2,\t// Plus\n\t2,\t// Minus\n\t3,\t// ULeftShift\n\t3,\t// URightShift\n\t3,\t// SLeftShift\n\t3,\t// SRightShift\n\t4,\t// Inferior\n\t4,\t// InferiorEqual\n\t4,\t// Superior\n\t4,\t// SuperiorEqual\n\t5,\t// Equal\n\t5,\t// NotEqual\n\t6,\t// And\n\t7,\t// Or\n\t8,\t// Xor\n\t9,\t// LogicalAnd\n\t10,\t// LogicalOr\n\t11,\t// LogicalXor\n\t-1,\t// OperatorCount\n\t20,\t// NotOperator\n};\n\n// ***************************************************************************\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/event_emitter.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n// remove stupid VC6 warnings\nvoid foo_event_emitter_cpp() {}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/event_emitter_multi.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/event_emitter_multi.h\"\n#include \"nel/misc/system_utils.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// a predicate to find an emitter in a list\nstruct EmitterEqualPred\n{\n\tEmitterEqualPred(IEventEmitter *e) : E(e) {}\n\tIEventEmitter *E;\n\tbool operator()(const std::pair<IEventEmitter *, bool> &el)\n\t{\n\t\treturn el.first == E;\n\t}\n};\n\n///============================================================\nCEventEmitterMulti::~CEventEmitterMulti()\n{\n\tfor (TEmitterCont::iterator it = _Emitters.begin(); it != _Emitters.end(); ++it)\n\t{\n\t\tif (it->second) // asked \"must Delete' ?\n\t\t{\n\t\t\tdelete it->first;\n\t\t}\n\t}\n}\n\n///============================================================\nvoid\tCEventEmitterMulti::addEmitter(IEventEmitter *e, bool mustDelete)\n{\n\tnlassert(e != this); // avoid infinite recursion\n\tnlassert(!isEmitter(e));\n\t_Emitters.push_back(std::make_pair(e, mustDelete));\n}\n\n///============================================================\nvoid\tCEventEmitterMulti::removeEmitter(IEventEmitter *e)\n{\n\tTEmitterCont::iterator it = std::find_if(_Emitters.begin(), _Emitters.end(), EmitterEqualPred(e));\n\tnlassert(it!= _Emitters.end());\n\tif (it->second)\n\t{\n\t\tdelete it->first;\n\t}\n\t_Emitters.erase(it);\n}\n\n///============================================================\nbool\tCEventEmitterMulti::isEmitter(IEventEmitter *e) const\n{\n\tTEmitterCont::const_iterator it = std::find_if(_Emitters.begin(), _Emitters.end(), EmitterEqualPred(e));\n\treturn it != _Emitters.end();\n}\n\n///============================================================\nvoid CEventEmitterMulti::submitEvents(CEventServer &server, bool allWindows)\n{\n\tfor (TEmitterCont::iterator it = _Emitters.begin(); it != _Emitters.end(); ++it)\n\t{\n\t\tit->first->submitEvents(server, allWindows);\n\t}\n}\n\n///============================================================\nIEventEmitter *CEventEmitterMulti::getEmitter(uint index)\n{\n\tnlassert(index < _Emitters.size());\n\treturn _Emitters[index].first;\n}\n\n///============================================================\nconst IEventEmitter *CEventEmitterMulti::getEmitter(uint index) const\n{\n\tnlassert(index < _Emitters.size());\n\treturn _Emitters[index].first;\n}\n\nbool CEventEmitterMulti::copyTextToClipboard(const ucstring &text)\n{\n\t// Naush: wrapped to old API to avoid duplicate code\n\treturn CSystemUtils::copyTextToClipboard(text);\n}\n\nbool CEventEmitterMulti::pasteTextFromClipboard(ucstring &text)\n{\n\t// Naush: wrapped to old API to avoid duplicate code\n\treturn CSystemUtils::pasteTextFromClipboard(text);\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/event_listener.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/event_listener.h\"\n#include \"nel/misc/event_server.h\"\n#include \"nel/misc/events.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n/*\n * Constructor\n */\nIEventListener::IEventListener() : _Hook(NULL)\n{\n}\n\n// ***************************************************************************\n// ***************************************************************************\n// CEventListenerAsync\n// ***************************************************************************\n// ***************************************************************************\n\n// ***************************************************************************\nCEventListenerAsync::CEventListenerAsync()\n{\n\t_KeyArray.resize (KeyCount);\n\t_KeyDownArray.resize (KeyCount);\n\t_KeyReleaseArray.resize (KeyCount);\n\treset ();\n}\n// ***************************************************************************\nvoid CEventListenerAsync::addToServer (CEventServer& server)\n{\n\tserver.addListener (EventKeyDownId, this);\n\tserver.addListener (EventSetFocusId, this);\n\tserver.addListener (EventKeyUpId, this);\n}\n// ***************************************************************************\nvoid CEventListenerAsync::removeFromServer (CEventServer& server)\n{\n\tserver.removeListener (EventKeyUpId, this);\n\tserver.removeListener (EventKeyDownId, this);\n\tserver.removeListener (EventSetFocusId, this);\n}\n// ***************************************************************************\nbool CEventListenerAsync::isKeyDown (TKey key) const\n{\n\treturn _KeyArray.get(key);\n}\n\n// ***************************************************************************\nbool CEventListenerAsync::isKeyPushed (TKey key, bool release)\n{\n\tbool\tret= _KeyDownArray.get(key) && !(_KeyReleaseArray.get(key));\n\tif(ret && release)\n\t{\n\t\t_KeyReleaseArray.set(key, true);\n\t}\n\treturn ret;\n}\n\n// ***************************************************************************\nvoid CEventListenerAsync::operator ()(const CEvent& event)\n{\n\t// Key down ?\n\tif (event==EventKeyDownId)\n\t{\n\t\tCEventKeyDown *pEvent=(CEventKeyDown*)&event;\n\t\t_KeyArray.set (pEvent->Key);\n\t\t_KeyDownArray.set (pEvent->Key);\n\t\tswitch(pEvent->Key)\n\t\t{\n\t\t\tcase KeyRCONTROL:\n\t\t\tcase KeyLCONTROL:\n\t\t\t\t_KeyArray.set (KeyCONTROL);\n\t\t\t\t_KeyDownArray.set (KeyCONTROL);\n\t\t\tbreak;\n\t\t\tcase KeyRSHIFT:\n\t\t\tcase KeyLSHIFT:\n\t\t\t\t_KeyArray.set (KeySHIFT);\n\t\t\t\t_KeyDownArray.set (KeySHIFT);\n\t\t\tbreak;\n\t\t\tcase KeyRMENU:\n\t\t\tcase KeyLMENU:\n\t\t\t\t_KeyArray.set (KeyMENU);\n\t\t\t\t_KeyDownArray.set (KeyMENU);\n\t\t\tbreak;\n\t\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\t// Key up ?\n\tif (event==EventKeyUpId)\n\t{\n\t\tCEventKeyUp *pEvent=(CEventKeyUp*)&event;\n\n\t\t_KeyArray.clear (pEvent->Key);\n\n\t\tswitch(pEvent->Key)\n\t\t{\n\t\t\tcase KeyRCONTROL:\n\t\t\tcase KeyLCONTROL:\n\t\t\t\t// Do not \"raise up\" the key, until someone has get the state of this key.\n\t\t\t\tif (!_KeyArray[KeyLCONTROL] && !_KeyArray[KeyRCONTROL])\n\t\t\t\t{\n\t\t\t\t\t_KeyArray.clear(KeyCONTROL);\n\n\t\t\t\t\tif(_KeyReleaseArray.get(KeyCONTROL))\n\t\t\t\t\t{\n\t\t\t\t\t\t_KeyDownArray.clear (KeyCONTROL);\n\t\t\t\t\t\t_KeyReleaseArray.clear (KeyCONTROL);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\t\t\tcase KeyRSHIFT:\n\t\t\tcase KeyLSHIFT:\n\t\t\t\tif (!_KeyArray[KeyLSHIFT] && !_KeyArray[KeyRSHIFT])\n\t\t\t\t{\n\t\t\t\t\t_KeyArray.clear(KeySHIFT);\n\n\t\t\t\t\tif(_KeyReleaseArray.get(KeySHIFT))\n\t\t\t\t\t{\n\t\t\t\t\t\t_KeyDownArray.clear (KeySHIFT);\n\t\t\t\t\t\t_KeyReleaseArray.clear (KeySHIFT);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\t\t\tcase KeyRMENU:\n\t\t\tcase KeyLMENU:\n\t\t\t\tif (!_KeyArray[KeyLMENU] && !_KeyArray[KeyRMENU])\n\t\t\t\t{\n\t\t\t\t\t_KeyArray.clear(KeyMENU);\n\n\t\t\t\t\tif(_KeyReleaseArray.get(KeyMENU))\n\t\t\t\t\t{\n\t\t\t\t\t\t_KeyDownArray.clear (KeyMENU);\n\t\t\t\t\t\t_KeyReleaseArray.clear (KeyMENU);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\tbreak;\n\t\t\tdefault: break;\n\t\t}\n\n\n\t\t// Do not \"raise up\" the key, until someone has get the state of this key.\n\t\tif(_KeyReleaseArray.get(pEvent->Key))\n\t\t{\n\t\t\t_KeyDownArray.clear (pEvent->Key);\n\t\t\t_KeyReleaseArray.clear (pEvent->Key);\n\t\t}\n\n\t}\n\t// Activate false ?\n\tif (event==EventSetFocusId)\n\t{\n\t\tCEventSetFocus *pEvent=(CEventSetFocus *)&event;\n\t\tif (!pEvent->Get)\n\t\t{\n\t\t\t// Disactive all keys\n\t\t\t_KeyArray.clearAll ();\n\t\t\t_KeyDownArray.clearAll ();\n\t\t\t_KeyReleaseArray.clearAll ();\n\t\t}\n\t}\n}\n\n\n// ***************************************************************************\nvoid CEventListenerAsync::reset ()\n{\n\t_KeyArray.clearAll ();\n\t_KeyDownArray.clearAll ();\n\t_KeyReleaseArray.clearAll ();\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/event_server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/event_server.h\"\n#include \"nel/misc/event_listener.h\"\n#include \"nel/misc/event_emitter.h\"\n#include \"nel/misc/events.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tCEventServer()\n\\*------------------------------------------------------------------*/\nCEventServer::CEventServer()\n{\n\t_Pumping= false;\n}\n\nCEventServer::~CEventServer()\n{\n\tstd::list<CEvent*>::iterator itev = _Events.begin();\n\twhile(itev!=_Events.end())\n\t{\n\t\tdelete *itev;\n\t\titev=_Events.erase (itev);\n\t}\n}\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tpostEvent()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::postEvent(CEvent * event)\n{\n\t_Events.push_back(event);\n}\n\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tpump()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::pump(bool allWindows)\n{\n\t// Avoid recurse (can arise if the process of an event decide to pump the server again....)\n\tnlassert(!_Pumping);\n\t_Pumping= true;\n\n\t// **** submit emitters events\n\tstd::list<IEventEmitter*>::iterator item = _Emitters.begin();\n\n\t// getting events from emitters\n\twhile(item!=_Emitters.end())\n\t{\n\t\t// ask emitters to submit their events to server\n\t\t(*item)->submitEvents(*this, allWindows);\n\t\titem++;\n\t}\n\n\t// **** process to listeners\n\tstd::list<CEvent*>::iterator itev = _Events.begin();\n\twhile(itev!=_Events.end())\n\t{\n\t\t// pump event\n\t\tbool bDelete=pumpEvent(*itev);\n\t\tif (bDelete)\n\t\t\tdelete *itev;\n\t\titev=_Events.erase (itev);\n\t}\n\n\t// end of pumping\n\t_Pumping= false;\n}\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tpumpEvent()\n\\*------------------------------------------------------------------*/\nbool CEventServer::pumpEvent(CEvent* event)\n{\n\t// taking id\n\tuint64 id = (uint64) *event;\n\n\t// looking for the first occurence of id\n\tmapListener::iterator it = _Listeners.find(id);\n\n\t// calling every callbacks\n\twhile(it!=_Listeners.end() && (uint64)(*it).first == id)\n\t{\n\t\tIEventListener *a = (IEventListener *)((*it).second);\n\t\ta->process(*event);\n\t\tit++;\n\t}\n\n\t// delete the pointer\n\treturn true;\n}\n\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\taddListener()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::addListener(CClassId id, IEventListener* listener )\n{\n\t_Listeners.insert( mapListener::value_type(id, listener));\n}\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tremoveListener()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::removeListener(CClassId id, IEventListener* listener )\n{\n\t// looking for the first occurence of id\n\tmapListener::iterator it = _Listeners.find(id);\n\n\t// looking for occurence with the right callback\n\twhile(it!=_Listeners.end() && (*it).first == id)\n\t{\n\t\tif((*it).second==listener)\n\t\t{\n\t\t\t// erasing pair\n\t\t\t_Listeners.erase(it);\n\t\t\treturn;\n\t\t}\n\t\tit++;\n\t}\n}\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\taddEmitter()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::addEmitter(IEventEmitter * emitter)\n{\n\t_Emitters.push_back(emitter);\n}\n\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tremoveEmitter()\n\\*------------------------------------------------------------------*/\nvoid CEventServer::removeEmitter(IEventEmitter * emitter)\n{\n\t_Emitters.remove(emitter);\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/events.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/events.h\"\n#include \"nel/misc/string_conversion.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n// ***************************************************************************\n// The conversion table\nstatic const CStringConversion<TKey>::CPair stringTable [] =\n{\n\t// BUFFER\n\t{ \"Key0\", Key0 },\n\t{ \"Key1\", Key1 },\n\t{ \"Key2\", Key2 },\n\t{ \"Key3\", Key3 },\n\t{ \"Key4\", Key4 },\n\t{ \"Key5\", Key5 },\n\t{ \"Key6\", Key6 },\n\t{ \"Key7\", Key7 },\n\t{ \"Key8\", Key8 },\n\t{ \"Key9\", Key9 },\n\t{ \"KeyA\", KeyA },\n\t{ \"KeyB\", KeyB },\n\t{ \"KeyC\", KeyC },\n\t{ \"KeyD\", KeyD },\n\t{ \"KeyE\", KeyE },\n\t{ \"KeyF\", KeyF },\n\t{ \"KeyG\", KeyG },\n\t{ \"KeyH\", KeyH },\n\t{ \"KeyI\", KeyI },\n\t{ \"KeyJ\", KeyJ },\n\t{ \"KeyK\", KeyK },\n\t{ \"KeyL\", KeyL },\n\t{ \"KeyM\", KeyM },\n\t{ \"KeyN\", KeyN },\n\t{ \"KeyO\", KeyO },\n\t{ \"KeyP\", KeyP },\n\t{ \"KeyQ\", KeyQ },\n\t{ \"KeyR\", KeyR },\n\t{ \"KeyS\", KeyS },\n\t{ \"KeyT\", KeyT },\n\t{ \"KeyU\", KeyU },\n\t{ \"KeyV\", KeyV },\n\t{ \"KeyW\", KeyW },\n\t{ \"KeyX\", KeyX },\n\t{ \"KeyY\", KeyY },\n\t{ \"KeyZ\", KeyZ },\n\t{ \"KeyLBUTTON\", KeyLBUTTON },\n\t{ \"KeyRBUTTON\", KeyRBUTTON },\n\t{ \"KeyCANCEL\", KeyCANCEL },\n\t{ \"KeyMBUTTON\", KeyMBUTTON },\n\t{ \"KeyBACK\", KeyBACK },\n\t{ \"KeyTAB\", KeyTAB },\n\t{ \"KeyCLEAR\", KeyCLEAR },\n\t{ \"KeyRETURN\", KeyRETURN },\n\t{ \"KeySHIFT\", KeySHIFT },\n\t{ \"KeyCONTROL\", KeyCONTROL },\n\t{ \"KeyMENU\", KeyMENU },\n\t{ \"KeyPAUSE\", KeyPAUSE },\n\t{ \"KeyCAPITAL\", KeyCAPITAL },\n\t{ \"KeyKANA\", KeyKANA },\n\t{ \"KeyHANGEUL\", KeyHANGEUL },\n\t{ \"KeyHANGUL\", KeyHANGUL },\n\t{ \"KeyJUNJA\", KeyJUNJA },\n\t{ \"KeyFINAL\", KeyFINAL },\n\t{ \"KeyHANJA\", KeyHANJA },\n\t{ \"KeyKANJI\", KeyKANJI },\n\t{ \"KeyESCAPE\", KeyESCAPE },\n\t{ \"KeyCONVERT\", KeyCONVERT },\n\t{ \"KeyNONCONVERT\", KeyNONCONVERT },\n\t{ \"KeyACCEPT\", KeyACCEPT },\n\t{ \"KeyMODECHANGE\", KeyMODECHANGE },\n\t{ \"KeySPACE\", KeySPACE },\n\t{ \"KeyPRIOR\", KeyPRIOR },\n\t{ \"KeyNEXT\", KeyNEXT },\n\t{ \"KeyEND\", KeyEND },\n\t{ \"KeyHOME\", KeyHOME },\n\t{ \"KeyLEFT\", KeyLEFT },\n\t{ \"KeyUP\", KeyUP },\n\t{ \"KeyRIGHT\", KeyRIGHT },\n\t{ \"KeyDOWN\", KeyDOWN },\n\t{ \"KeySELECT\", KeySELECT },\n\t{ \"KeyPRINT\", KeyPRINT },\n\t{ \"KeyEXECUTE\", KeyEXECUTE },\n\t{ \"KeySNAPSHOT\", KeySNAPSHOT },\n\t{ \"KeyINSERT\", KeyINSERT },\n\t{ \"KeyDELETE\", KeyDELETE },\n\t{ \"KeyHELP\", KeyHELP },\n\t{ \"KeyLWIN\", KeyLWIN },\n\t{ \"KeyRWIN\", KeyRWIN },\n\t{ \"KeyAPPS\", KeyAPPS },\n\t{ \"KeyNUMPAD0\", KeyNUMPAD0 },\n\t{ \"KeyNUMPAD1\", KeyNUMPAD1 },\n\t{ \"KeyNUMPAD2\", KeyNUMPAD2 },\n\t{ \"KeyNUMPAD3\", KeyNUMPAD3 },\n\t{ \"KeyNUMPAD4\", KeyNUMPAD4 },\n\t{ \"KeyNUMPAD5\", KeyNUMPAD5 },\n\t{ \"KeyNUMPAD6\", KeyNUMPAD6 },\n\t{ \"KeyNUMPAD7\", KeyNUMPAD7 },\n\t{ \"KeyNUMPAD8\", KeyNUMPAD8 },\n\t{ \"KeyNUMPAD9\", KeyNUMPAD9 },\n\t{ \"KeyMULTIPLY\", KeyMULTIPLY },\n\t{ \"KeyADD\", KeyADD },\n\t{ \"KeySEPARATOR\", KeySEPARATOR },\n\t{ \"KeySUBTRACT\", KeySUBTRACT },\n\t{ \"KeyDECIMAL\", KeyDECIMAL },\n\t{ \"KeyDIVIDE\", KeyDIVIDE },\n\t{ \"KeyF1\", KeyF1 },\n\t{ \"KeyF2\", KeyF2 },\n\t{ \"KeyF3\", KeyF3 },\n\t{ \"KeyF4\", KeyF4 },\n\t{ \"KeyF5\", KeyF5 },\n\t{ \"KeyF6\", KeyF6 },\n\t{ \"KeyF7\", KeyF7 },\n\t{ \"KeyF8\", KeyF8 },\n\t{ \"KeyF9\", KeyF9 },\n\t{ \"KeyF10\", KeyF10 },\n\t{ \"KeyF11\", KeyF11 },\n\t{ \"KeyF12\", KeyF12 },\n\t{ \"KeyF13\", KeyF13 },\n\t{ \"KeyF14\", KeyF14 },\n\t{ \"KeyF15\", KeyF15 },\n\t{ \"KeyF16\", KeyF16 },\n\t{ \"KeyF17\", KeyF17 },\n\t{ \"KeyF18\", KeyF18 },\n\t{ \"KeyF19\", KeyF19 },\n\t{ \"KeyF20\", KeyF20 },\n\t{ \"KeyF21\", KeyF21 },\n\t{ \"KeyF22\", KeyF22 },\n\t{ \"KeyF23\", KeyF23 },\n\t{ \"KeyF24\", KeyF24 },\n\t{ \"KeyNUMLOCK\", KeyNUMLOCK },\n\t{ \"KeySCROLL\", KeySCROLL },\n\t{ \"KeyLSHIFT\", KeyLSHIFT },\n\t{ \"KeyRSHIFT\", KeyRSHIFT },\n\t{ \"KeyLCONTROL\", KeyLCONTROL },\n\t{ \"KeyRCONTROL\", KeyRCONTROL },\n\t{ \"KeyLMENU\", KeyLMENU },\n\t{ \"KeyRMENU\", KeyRMENU },\n\t{ \"KeySEMICOLON\", KeySEMICOLON },\n\t{ \"KeyEQUALS\", KeyEQUALS },\n\t{ \"KeyCOMMA\", KeyCOMMA },\n\t{ \"KeyDASH\", KeyDASH },\n\t{ \"KeyPERIOD\", KeyPERIOD },\n\t{ \"KeySLASH\", KeySLASH },\n\t{ \"KeyTILDE\", KeyTILDE },\n\t{ \"KeyLBRACKET\", KeyLBRACKET },\n\t{ \"KeyBACKSLASH\", KeyBACKSLASH },\n\t{ \"KeyRBRACKET\", KeyRBRACKET },\n\t{ \"KeyAPOSTROPHE\", KeyAPOSTROPHE },\n\t{ \"KeyPARAGRAPH\", KeyPARAGRAPH },\n\t{ \"KeyOEM_102\", KeyOEM_102 },\n\t{ \"KeyPROCESSKEY\", KeyPROCESSKEY },\n\t{ \"KeyATTN\", KeyATTN },\n\t{ \"KeyCRSEL\", KeyCRSEL },\n\t{ \"KeyEXSEL\", KeyEXSEL },\n\t{ \"KeyEREOF\", KeyEREOF },\n\t{ \"KeyPLAY\", KeyPLAY },\n\t{ \"KeyZOOM\", KeyZOOM },\n\t{ \"KeyNONAME\", KeyNONAME },\n\t{ \"KeyPA1\", KeyPA1 },\n\t{ \"KeyOEM_CLEAR\", KeyOEM_CLEAR }\n};\n\n\nstatic\tCStringConversion<TKey> KeyConversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]),  KeyCount);\n\n\n// ***************************************************************************\nTKey\t\t\t\tCEventKey::getKeyFromString(const std::string &str)\n{\n\treturn KeyConversion.fromString(str);\n}\n\n// ***************************************************************************\nconst std::string\t&CEventKey::getStringFromKey(TKey k)\n{\n\treturn KeyConversion.toString(k);\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/fast_floor.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/fast_floor.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nint\t\tOptFastFloorCWStack[OptFastFloorCWStackSize];\nint\t\t*OptFastFloorCWStackEnd = OptFastFloorCWStack + OptFastFloorCWStackSize;\nint\t\t*OptFastFloorCWStackPtr = OptFastFloorCWStack;\n\n#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM) && defined(NL_USE_FASTFLOOR)\n\ndouble\tOptFastFloorMagicConst = pow(2.0,52) + pow(2.0,51);\nfloat\tOptFastFloorMagicConst24 = (float)pow(2.0,23);\n\n#endif\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/fast_id_map.cpp",
    "content": "/**\n * \\file fast_id_map.cpp\n * \\brief CFastIdMap\n * \\date 2012-04-10 19:28GMT\n * \\author Jan Boon (Kaetemi)\n * CFastIdMap\n */\n\n/* \n * Copyright (C) 2012  by authors\n * \n * This file is part of RYZOM CORE.\n * RYZOM CORE is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n * \n * RYZOM CORE is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Affero General Public License for more details.\n * \n * You should have received a copy of the GNU Affero General Public\n * License along with RYZOM CORE.  If not, see\n * <http://www.gnu.org/licenses/>.\n */\n\n#include <nel/misc/types_nl.h>\n#include <nel/misc/fast_id_map.h>\n\n// STL includes\n\n// NeL includes\n// #include <nel/misc/debug.h>\n\n// Project includes\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nvoid dummytoavoidthecompilerwarningfastidmap() { }\n\n} /* namespace NLMISC */\n\n/* end of file */\n"
  },
  {
    "path": "code/nel/src/misc/fast_mem.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/fast_mem.h\"\n#include \"nel/misc/system_info.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)\n\n\n// ***************************************************************************\nvoid\t\t*CFastMem::memcpySSE(void *dest, const void *src, size_t nbytes)\n{\n\t_asm\n\t{\n\t\t\tmov esi, src\n\t\t\tmov edi, dest\n\t\t\tmov ebx, nbytes\n\n\t\t\t// edx takes number of bytes%64\n\t\t\tmov\tedx, ebx\n\t\t\tand edx, 63\n\n\t\t\t// ebx takes number of bytes/64\n\t\t\tshr\tebx, 6\n\t\t\tjz\tbyteCopy\n\n\n\tloop4k: // flush 4k into temporary buffer\n\t\t\tpush esi\n\t\t\tmov ecx, ebx\n\t\t\t// copy per block of 64 bytes. Must not override 64*64= 4096 bytes.\n\t\t\tcmp ecx, 64\n\t\t\tjle\tskipMiniMize\n\t\t\tmov\tecx, 64\n\tskipMiniMize:\n\t\t\t// eax takes the number of 64bytes packet for this block.\n\t\t\tmov eax, ecx\n\n\tloopMemToL1:\n\t\t\tprefetchnta 64[ESI] // Prefetch next loop, non-temporal\n\t\t\tprefetchnta 96[ESI]\n\n\t\t\tmovq mm1,  0[ESI] // Read in source data\n\t\t\tmovq mm2,  8[ESI]\n\t\t\tmovq mm3, 16[ESI]\n\t\t\tmovq mm4, 24[ESI]\n\t\t\tmovq mm5, 32[ESI]\n\t\t\tmovq mm6, 40[ESI]\n\t\t\tmovq mm7, 48[ESI]\n\t\t\tmovq mm0, 56[ESI]\n\n\t\t\tadd esi, 64\n\t\t\tdec ecx\n\t\t\tjnz loopMemToL1\n\n\t\t\tpop esi // Now copy from L1 to system memory\n\t\t\tmov ecx, eax\n\n\tloopL1ToMem:\n\t\t\tmovq mm1, 0[ESI] // Read in source data from L1\n\t\t\tmovq mm2, 8[ESI]\n\t\t\tmovq mm3, 16[ESI]\n\t\t\tmovq mm4, 24[ESI]\n\t\t\tmovq mm5, 32[ESI]\n\t\t\tmovq mm6, 40[ESI]\n\t\t\tmovq mm7, 48[ESI]\n\t\t\tmovq mm0, 56[ESI]\n\n\t\t\tmovntq 0[EDI], mm1 // Non-temporal stores\n\t\t\tmovntq 8[EDI], mm2\n\t\t\tmovntq 16[EDI], mm3\n\t\t\tmovntq 24[EDI], mm4\n\t\t\tmovntq 32[EDI], mm5\n\t\t\tmovntq 40[EDI], mm6\n\t\t\tmovntq 48[EDI], mm7\n\t\t\tmovntq 56[EDI], mm0\n\n\t\t\tadd esi, 64\n\t\t\tadd edi, 64\n\t\t\tdec ecx\n\t\t\tjnz loopL1ToMem\n\n\t\t\t// Do next 4k block\n\t\t\tsub ebx, eax\n\t\t\tjnz loop4k\n\n\t\t\temms\n\n\tbyteCopy:\n\t\t\t// Do last bytes with std cpy\n\t\t\tmov\tecx, edx\n\t\t\trep movsb\n\t}\n\treturn dest;\n}\n\n// ***************************************************************************\nvoid\t\tCFastMem::precacheSSE(const void *src, uint nbytes)\n{\n\t_asm\n\t{\n\t\t\tmov esi, src\n\t\t\tmov ecx, nbytes\n\t\t\t// 64 bytes per pass\n\t\t\tshr ecx, 6\n\t\t\tjz endLabel\n\n\tloopMemToL1:\n\t\t\tprefetchnta 64[ESI] // Prefetch next loop, non-temporal\n\t\t\tprefetchnta 96[ESI]\n\n\t\t\tmovq mm1,  0[ESI] // Read in source data\n\t\t\tmovq mm2,  8[ESI]\n\t\t\tmovq mm3, 16[ESI]\n\t\t\tmovq mm4, 24[ESI]\n\t\t\tmovq mm5, 32[ESI]\n\t\t\tmovq mm6, 40[ESI]\n\t\t\tmovq mm7, 48[ESI]\n\t\t\tmovq mm0, 56[ESI]\n\n\t\t\tadd esi, 64\n\t\t\tdec ecx\n\t\t\tjnz loopMemToL1\n\n\t\t\temms\n\n\tendLabel:\n\t}\n}\n\n// ***************************************************************************\nvoid\t\tCFastMem::precacheMMX(const void *src, uint nbytes)\n{\n\t_asm\n\t{\n\t\t\tmov esi, src\n\t\t\tmov ecx, nbytes\n\t\t\t// 64 bytes per pass\n\t\t\tshr ecx, 6\n\t\t\tjz endLabel\n\n\tloopMemToL1:\n\t\t\tmovq mm1,  0[ESI] // Read in source data\n\t\t\tmovq mm2,  8[ESI]\n\t\t\tmovq mm3, 16[ESI]\n\t\t\tmovq mm4, 24[ESI]\n\t\t\tmovq mm5, 32[ESI]\n\t\t\tmovq mm6, 40[ESI]\n\t\t\tmovq mm7, 48[ESI]\n\t\t\tmovq mm0, 56[ESI]\n\n\t\t\tadd esi, 64\n\t\t\tdec ecx\n\t\t\tjnz loopMemToL1\n\n\t\t\temms\n\n\tendLabel:\n\t}\n}\n\n\n// ***************************************************************************\nvoid\t\tCFastMem::precache(const void *src, uint nbytes)\n{\n\tif(NLMISC::CSystemInfo::hasSSE())\n\t\tprecacheSSE(src, nbytes);\n\telse if(NLMISC::CSystemInfo::hasMMX())\n\t\tprecacheMMX(src, nbytes);\n}\n\n\n#else\n\n\n// ***************************************************************************\nvoid\t\t*CFastMem::memcpySSE(void *dst, const void *src, size_t nbytes)\n{\n\t// Use std memcpy.\n\treturn memcpy(dst, src, nbytes);\n}\nvoid\t\tCFastMem::precacheSSE(const void *src, uint nbytes)\n{\n\t// no-op.\n}\nvoid\t\tCFastMem::precacheMMX(const void *src, uint nbytes)\n{\n\t// no-op.\n}\nvoid\t\tCFastMem::precache(const void *src, uint nbytes)\n{\n\t// no-op.\n}\n\n#endif\n\ntypedef void  *(*memcpyPtr)(void *dts, const void *src, size_t nbytes);\n\nstatic memcpyPtr findBestmemcpy ()\n{\n#if defined(NL_OS_WINDOWS) && !defined(NL_NO_ASM)\n\tif (CSystemInfo::hasSSE ())\n\t\treturn CFastMem::memcpySSE;\n\telse\n\t\treturn ::memcpy;\n#else // NL_OS_WINDOWS\n\treturn ::memcpy;\n#endif // NL_OS_WINDOWS\n}\n\nvoid  *(*CFastMem::memcpy)(void *dts, const void *src, size_t nbytes) = findBestmemcpy ();\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/file.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/file.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/big_file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/misc/xml_pack.h\"\n\n#ifndef NL_OS_WINDOWS\n#include <errno.h>\n#endif\n\nusing namespace std;\n\n#define NLMISC_DONE_FILE_OPENED 40\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\ntypedef std::list<uint64> TFileAccessTimes;\t\t\t\t\t// list of times at which a given file is opened for reading\ntypedef CHashMap<std::string,TFileAccessTimes> TFileAccessLog;\t// map from file name to read access times\ntypedef NLMISC::CSynchronized<TFileAccessLog> TSynchronizedFileAccessLog;\n\nstatic TSynchronizedFileAccessLog IFileAccessLog(\"IFileAccessLog\");\nstatic bool IFileAccessLoggingEnabled= false;\nstatic uint64 IFileAccessLogStartTime= 0;\n\nuint32 CIFile::_NbBytesSerialized = 0;\nuint32 CIFile::_NbBytesLoaded = 0;\nuint32 CIFile::_ReadFromFile = 0;\nuint32 CIFile::_ReadingFromFile = 0;\nuint32 CIFile::_FileOpened = 0;\nuint32 CIFile::_FileRead = 0;\nCSynchronized<std::deque<std::string> > CIFile::_OpenedFiles(\"\");\n\n// ======================================================================================================\nCIFile::CIFile() : IStream(true)\n{\n\t_F = NULL;\n\t_Cache = NULL;\n\t_ReadPos = 0;\n\t_FileSize = 0;\n\t_BigFileOffset = 0;\n\t_IsInBigFile = false;\n\t_IsInXMLPackFile = false;\n\t_CacheFileOnOpen = false;\n\t_IsAsyncLoading = false;\n\t_AllowBNPCacheFileOnOpen= true;\n}\n\n// ======================================================================================================\nCIFile::CIFile(const std::string &path, bool text) : IStream(true)\n{\n\t_F=NULL;\n\t_Cache = NULL;\n\t_ReadPos = 0;\n\t_FileSize = 0;\n\t_BigFileOffset = 0;\n\t_IsInBigFile = false;\n\t_IsInXMLPackFile = false;\n\t_CacheFileOnOpen = false;\n\t_IsAsyncLoading = false;\n\t_AllowBNPCacheFileOnOpen= true;\n\topen(path, text);\n}\n\n// ======================================================================================================\nCIFile::~CIFile()\n{\n\tclose();\n}\n\n\n// ======================================================================================================\nvoid\t\tCIFile::loadIntoCache()\n{\n\tconst uint32 READPACKETSIZE = 64 * 1024;\n\tconst uint32 INTERPACKETSLEEP = 5;\n\n\t_Cache = new uint8[_FileSize];\n\tif(!_IsAsyncLoading)\n\t{\n\t\t_ReadingFromFile += _FileSize;\n\t\tint read = (int)fread (_Cache, _FileSize, 1, _F);\n\t\t_FileRead++;\n\t\t_ReadingFromFile -= _FileSize;\n\t\t_ReadFromFile += read * _FileSize;\n\t}\n\telse\n\t{\n\t\tuint\tindex= 0;\n\t\twhile(index<_FileSize)\n\t\t{\n\t\t\tif( _NbBytesLoaded + (_FileSize-index) > READPACKETSIZE )\n\t\t\t{\n\t\t\t\tsint\tn= READPACKETSIZE-_NbBytesLoaded;\n\t\t\t\tn= max(n, 1);\n\t\t\t\t_ReadingFromFile += n;\n\t\t\t\tint read = (int)fread (_Cache+index, n, 1, _F);\n\t\t\t\t_FileRead++;\n\t\t\t\t_ReadingFromFile -= n;\n\t\t\t\t_ReadFromFile += read * n;\n\t\t\t\tindex+= n;\n\n\t\t\t\tnlSleep (INTERPACKETSLEEP);\n\t\t\t\t_NbBytesLoaded= 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint\tn= _FileSize-index;\n\t\t\t\t_ReadingFromFile += n;\n\t\t\t\tint read = (int)fread (_Cache+index, n, 1, _F);\n\t\t\t\t_FileRead++;\n\t\t\t\t_ReadingFromFile -= n;\n\t\t\t\t_ReadFromFile += read * n;\n\t\t\t\t_NbBytesLoaded+= n;\n\t\t\t\tindex+= n;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n// ======================================================================================================\nbool\t\tCIFile::open(const std::string &path, bool text)\n{\n\t// Log opened files\n\t{\n\t\tCSynchronized<deque<string> >::CAccessor fileOpened(&_OpenedFiles);\n\t\tfileOpened.value().push_front (path);\n\t\tif (fileOpened.value().size () > NLMISC_DONE_FILE_OPENED)\n\t\t\tfileOpened.value().resize (NLMISC_DONE_FILE_OPENED);\n\t\t_FileOpened++;\n\t}\n\n\tclose();\n\n\t// can't open empty filename\n\tif(path.empty ())\n\t\treturn false;\n\n\t// IFile Access Log management\n\tif (IFileAccessLoggingEnabled)\n\t{\n\t\t// get the current time\n\t\tuint64 timeNow = NLMISC::CTime::getPerformanceTime();\n\n\t\t// get a handle for the container\n\t\tTSynchronizedFileAccessLog::CAccessor synchronizedFileAccesLog(&IFileAccessLog);\n\t\tTFileAccessLog& fileAccessLog= synchronizedFileAccesLog.value();\n\n\t\t// add the current time to the container entry for the given path (creating a new container entry if required)\n\t\tfileAccessLog[path].push_back(timeNow);\n\t}\n\n\tchar mode[3];\n\tmode[0] = 'r';\n\tmode[1] = 'b'; // No more reading in text mode\n\tmode[2] = '\\0';\n\n\t_FileName = path;\n\t_ReadPos = 0;\n\n\t// Bigfile or xml pack access requested ?\n\tstring::size_type pos;\n\tif ((pos = path.find('@')) != string::npos)\n\t{\n\t\t// check for a double @ to identify XML pack file\n\t\tif (pos+1 < path.size() && path[pos+1] == '@')\n\t\t{\n\t\t\t// xml pack file\n\t\t\t_IsInXMLPackFile = true;\n\n\t\t\tif(_AllowBNPCacheFileOnOpen)\n\t\t\t{\n\t\t\t\t_F = CXMLPack::getInstance().getFile(path, _FileSize, _BigFileOffset, _CacheFileOnOpen, _AlwaysOpened);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbool\tdummy;\n\t\t\t\t_F = CXMLPack::getInstance().getFile (path, _FileSize, _BigFileOffset, dummy, _AlwaysOpened);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// bnp file\n\t\t\t_IsInBigFile = true;\n\t\t\tif(_AllowBNPCacheFileOnOpen)\n\t\t\t{\n\t\t\t\t_F = CBigFile::getInstance().getFile (path, _FileSize, _BigFileOffset, _CacheFileOnOpen, _AlwaysOpened);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbool\tdummy;\n\t\t\t\t_F = CBigFile::getInstance().getFile (path, _FileSize, _BigFileOffset, dummy, _AlwaysOpened);\n\t\t\t}\n\t\t}\n\t\tif(_F != NULL)\n\t\t{\n\t\t\t// Start to load the bigfile or xml file at the file offset.\n\t\t\tnlfseek64 (_F, _BigFileOffset, SEEK_SET);\n\n\t\t\t// Load into cache ?\n\t\t\tif (_CacheFileOnOpen)\n\t\t\t{\n\t\t\t\t// load file in the cache\n\t\t\t\tloadIntoCache();\n\n\t\t\t\tif (!_AlwaysOpened)\n\t\t\t\t{\n\t\t\t\t\tfclose (_F);\n\t\t\t\t\t_F = NULL;\n\t\t\t\t}\n\t\t\t\treturn (_Cache != NULL);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t_IsInBigFile = false;\n\t\t_IsInXMLPackFile = false;\n\t\t_BigFileOffset = 0;\n\t\t_AlwaysOpened = false;\n\t\t_F = fopen (path.c_str(), mode);\n\t\tif (_F != NULL)\n\t\t{\n\t\t\t/*\n\t\t\tTHIS CODE REPLACED BY SADGE BECAUSE SOMETIMES\n\t\t\tftell() RETRUNS 0 FOR NO GOOD REASON - LEADING TO CLIENT CRASH\n\n\t\t\tnlfseek64 (_F, 0, SEEK_END);\n\t\t\t_FileSize = ftell(_F);\n\t\t\tnlfseek64 (_F, 0, SEEK_SET);\n\t\t\tnlassert(_FileSize==filelength(fileno(_F)));\n\n\t\t\tTHE FOLLOWING WORKS BUT IS NOT PORTABLE\n\t\t\t_FileSize=filelength(fileno(_F));\n\t\t\t*/\n\t\t\t_FileSize=CFile::getFileSize (_F);\n\t\t\tif (_FileSize == 0)\n\t\t\t{\n\t\t\t\tnlwarning (\"FILE: Size of file '%s' is 0\", path.c_str());\n\t\t\t\tfclose (_F);\n\t\t\t\t_F = NULL;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"Failed to open file '%s', error %u : %s\", path.c_str(), errno, strerror(errno));\n\t\t\t_FileSize = 0;\n\t\t}\n\n\t\tif ((_CacheFileOnOpen) && (_F != NULL))\n\t\t{\n\t\t\t// load file in the cache\n\t\t\tloadIntoCache();\n\n\t\t\tfclose (_F);\n\t\t\t_F = NULL;\n\t\t\treturn (_Cache != NULL);\n\t\t}\n\t}\n\n\treturn (_F != NULL);\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::setCacheFileOnOpen (bool newState)\n{\n\t_CacheFileOnOpen = newState;\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::setAsyncLoading (bool newState)\n{\n\t_IsAsyncLoading = true;\n}\n\n\n// ======================================================================================================\nvoid\t\tCIFile::close()\n{\n\tif (_CacheFileOnOpen)\n\t{\n\t\tif (_Cache)\n\t\t{\n\t\t\tdelete[] _Cache;\n\t\t\t_Cache = NULL;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (_IsInBigFile || _IsInXMLPackFile)\n\t\t{\n\t\t\tif (!_AlwaysOpened)\n\t\t\t{\n\t\t\t\tif (_F)\n\t\t\t\t{\n\t\t\t\t\tfclose (_F);\n\t\t\t\t\t_F = NULL;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (_F)\n\t\t\t{\n\t\t\t\tfclose (_F);\n\t\t\t\t_F = NULL;\n\t\t\t}\n\t\t}\n\t}\n\tnlassert(_Cache == NULL);\n\tresetPtrTable();\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::flush()\n{\n\tif (_CacheFileOnOpen)\n\t{\n\t}\n\telse\n\t{\n\t\tif (_F)\n\t\t{\n\t\t\tfflush (_F);\n\t\t}\n\t}\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::getline (char *buffer, uint32 bufferSize)\n{\n\tif (bufferSize == 0)\n\t\treturn;\n\n\tuint read = 0;\n\tfor(;;)\n\t{\n\t\tif (read == bufferSize - 1)\n\t\t{\n\t\t\t*buffer = '\\0';\n\t\t\treturn;\n\t\t}\n\n\t\ttry\n\t\t{\n\t\t\t// read one byte\n\t\t\tserialBuffer ((uint8 *)buffer, 1);\n\t\t}\n\t\tcatch (const EFile &)\n\t\t{\n\t\t\t*buffer = '\\0';\n\t\t\treturn;\n\t\t}\n\n\t\tif (*buffer == '\\n')\n\t\t{\n\t\t\t*buffer = '\\0';\n\t\t\treturn;\n\t\t}\n\n\t\t// skip '\\r' char\n\t\tif (*buffer != '\\r')\n\t\t{\n\t\t\tbuffer++;\n\t\t\tread++;\n\t\t}\n\t}\n\n}\n\n\n// ======================================================================================================\nbool\t\tCIFile::eof ()\n{\n\treturn _ReadPos >= (sint32)_FileSize;\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::serialBuffer(uint8 *buf, uint len) throw(EReadError)\n{\n\tif (len == 0)\n\t\treturn;\n\t// Check the read pos\n\tif ((_ReadPos < 0) || ((_ReadPos+len) > _FileSize))\n\t\tthrow EReadError (_FileName);\n\tif ((_CacheFileOnOpen) && (_Cache == NULL))\n\t\tthrow EFileNotOpened (_FileName);\n\tif ((!_CacheFileOnOpen) && (_F == NULL))\n\t\tthrow EFileNotOpened (_FileName);\n\n\tif (_IsAsyncLoading)\n\t{\n\t\t_NbBytesSerialized += len;\n\t\tif (_NbBytesSerialized > 64 * 1024)\n\t\t{\n\t\t\t// give up time slice\n\t\t\tnlSleep (0);\n\t\t\t_NbBytesSerialized = 0;\n\t\t}\n\t}\n\n\tif (_CacheFileOnOpen)\n\t{\n\t\tmemcpy (buf, _Cache + _ReadPos, len);\n\t\t_ReadPos += len;\n\t}\n\telse\n\t{\n\t\tint read;\n\t\t_ReadingFromFile += len;\n\t\tread=(int)fread(buf, len, 1, _F);\n\t\t_FileRead++;\n\t\t_ReadingFromFile -= len;\n\t\t_ReadFromFile += /*read **/ len;\n\t\tif (read != 1 /*< (int)len*/)\n\t\t\tthrow EReadError(_FileName);\n\t\t_ReadPos += len;\n\t}\n}\n\n// ======================================================================================================\nvoid\t\tCIFile::serialBit(bool &bit) throw(EReadError)\n{\n\t// Simple for now.\n\tuint8\tv=bit;\n\tserialBuffer(&v, 1);\n\tbit=(v!=0);\n}\n\n// ======================================================================================================\nbool\t\tCIFile::seek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream)\n{\n\tif ((_CacheFileOnOpen) && (_Cache == NULL))\n\t\treturn false;\n\tif ((!_CacheFileOnOpen) && (_F == NULL))\n\t\treturn false;\n\n\tswitch (origin)\n\t{\n\t\tcase IStream::begin:\n\t\t\t_ReadPos = offset;\n\t\tbreak;\n\t\tcase IStream::current:\n\t\t\t_ReadPos = _ReadPos + offset;\n\t\tbreak;\n\t\tcase IStream::end:\n\t\t\t_ReadPos = _FileSize + offset;\n\t\tbreak;\n\t\tdefault:\n\t\t\tnlstop;\n\t}\n\n\tif (_CacheFileOnOpen)\n\t\treturn true;\n\n\t// seek in the file. NB: if not in bigfile, _BigFileOffset==0.\n\tif (nlfseek64(_F, _BigFileOffset+_ReadPos, SEEK_SET) != 0)\n\t\treturn false;\n\treturn true;\n}\n\n// ======================================================================================================\nsint32\t\tCIFile::getPos () const throw(EStream)\n{\n\treturn _ReadPos;\n}\n\n\n// ======================================================================================================\nstd::string\tCIFile::getStreamName() const\n{\n\treturn _FileName;\n}\n\n\n// ======================================================================================================\nvoid\tCIFile::allowBNPCacheFileOnOpen(bool newState)\n{\n\t_AllowBNPCacheFileOnOpen= newState;\n}\n\n\n// ======================================================================================================\nvoid\tCIFile::dump (std::vector<std::string> &result)\n{\n\tCSynchronized<deque<string> >::CAccessor acces(&_OpenedFiles);\n\n\tconst deque<string> &openedFile = acces.value();\n\n\t// Resize the destination array\n\tresult.clear ();\n\tresult.reserve (openedFile.size ());\n\n\t// Add the waiting strings\n\tdeque<string>::const_reverse_iterator ite = openedFile.rbegin ();\n\twhile (ite != openedFile.rend ())\n\t{\n\t\tresult.push_back (*ite);\n\n\t\t// Next task\n\t\tite++;\n\t}\n}\n\n// ======================================================================================================\nvoid\tCIFile::clearDump ()\n{\n\tCSynchronized<deque<string> >::CAccessor acces(&_OpenedFiles);\n\tacces.value().clear();\n}\n\n// ======================================================================================================\nuint\tCIFile::getDbgStreamSize() const\n{\n\treturn getFileSize();\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nCOFile::COFile() : IStream(false)\n{\n\t_F=NULL;\n\t_FileName = \"\";\n}\n\n// ======================================================================================================\nCOFile::COFile(const std::string &path, bool append, bool text, bool useTempFile) : IStream(false)\n{\n\t_F=NULL;\n\topen(path, append, text, useTempFile);\n}\n\n// ======================================================================================================\nCOFile::~COFile()\n{\n\tinternalClose(false);\n}\n// ======================================================================================================\nbool\tCOFile::open(const std::string &path, bool append, bool text, bool useTempFile)\n{\n\tclose();\n\n\t// can't open empty filename\n\tif(path.empty ())\n\t\treturn false;\n\n\t_FileName = path;\n\t_TempFileName.clear();\n\n\tchar mode[3];\n\tmode[0] = (append)?'a':'w';\n// ACE: NEVER SAVE IN TEXT MODE!!!\tmode[1] = (text)?'\\0':'b';\n\tmode[1] = 'b';\n\tmode[2] = '\\0';\n\n\tstring fileToOpen = path;\n\tif (useTempFile)\n\t{\n\t\tCFile::getTemporaryOutputFilename (path, _TempFileName);\n\t\tfileToOpen = _TempFileName;\n\t}\n\n\t// if appending to file and using a temporary file, copycat temporary file from original...\n\tif (append && useTempFile && CFile::fileExists(_FileName))\n\t{\n\t\t// open fails if can't copy original content\n\t\tif (!CFile::copyFile(_TempFileName, _FileName))\n\t\t\treturn false;\n\t}\n\n\t_F=fopen(fileToOpen.c_str(), mode);\n\n\treturn _F!=NULL;\n}\n// ======================================================================================================\nvoid\tCOFile::close()\n{\n\tinternalClose(true);\n}\n// ======================================================================================================\nvoid\tCOFile::internalClose(bool success)\n{\n\tif(_F)\n\t{\n\t\tfclose(_F);\n\n\t\t// Temporary filename ?\n\t\tif (!_TempFileName.empty())\n\t\t{\n\t\t\t// Delete old\n\t\t\tif (success)\n\t\t\t{\n\t\t\t\t// Bug under windows, sometimes the file is not deleted\n\t\t\t\tuint retry = 1000;\n\t\t\t\twhile (--retry)\n\t\t\t\t{\n\t\t\t\t\tif (CFile::fileExists(_FileName))\n\t\t\t\t\t\tCFile::deleteFile (_FileName);\n\n\t\t\t\t\tif (CFile::moveFile (_FileName.c_str(), _TempFileName.c_str()))\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tnlSleep (0);\n\t\t\t\t}\n\t\t\t\tif (!retry)\n\t\t\t\t\tthrow ERenameError (_FileName, _TempFileName);\n\t\t\t}\n\t\t\telse\n\t\t\t\tCFile::deleteFile (_TempFileName);\n\t\t}\n\n\t\t_F=NULL;\n\t}\n\tresetPtrTable();\n}\n// ======================================================================================================\nvoid\tCOFile::flush()\n{\n\tif(_F)\n\t{\n\t\tfflush(_F);\n\t}\n}\n\n\n// ======================================================================================================\nvoid\t\tCOFile::serialBuffer(uint8 *buf, uint len) throw(EWriteError)\n{\n\tif(!_F)\n\t\tthrow\tEFileNotOpened(_FileName);\n\tif(fwrite(buf, len, 1, _F) != 1)\n//\tif(fwrite(buf, 1, len, _F) != len)\n\t{\n\t\tif (ferror(_F) && errno == 28 /*ENOSPC*/)\n\t\t{\n\t\t\tthrow EDiskFullError(_FileName);\n\t\t}\n\t\tthrow\tEWriteError(_FileName);\n\t}\n}\n// ======================================================================================================\nvoid\t\tCOFile::serialBit(bool &bit) throw(EWriteError)\n{\n\t// Simple for now.\n\tuint8\tv=bit;\n\tserialBuffer(&v, 1);\n}\n// ======================================================================================================\nbool\t\tCOFile::seek (sint32 offset, IStream::TSeekOrigin origin) const throw(EStream)\n{\n\tif (_F)\n\t{\n\t\tint origin_c = SEEK_SET;\n\t\tswitch (origin)\n\t\t{\n\t\tcase IStream::begin:\n\t\t\torigin_c=SEEK_SET;\n\t\t\tbreak;\n\t\tcase IStream::current:\n\t\t\torigin_c=SEEK_CUR;\n\t\t\tbreak;\n\t\tcase IStream::end:\n\t\t\torigin_c=SEEK_END;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tnlstop;\n\t\t}\n\n\t\tif (nlfseek64 (_F, offset, origin_c)!=0)\n\t\t\treturn false;\n\t\treturn true;\n\t}\n\treturn false;\n}\n// ======================================================================================================\nsint32\t\tCOFile::getPos () const throw(EStream)\n{\n\tif (_F)\n\t{\n\t\treturn ftell (_F);\n\t}\n\treturn 0;\n}\n\n// ======================================================================================================\nstd::string\t\tCOFile::getStreamName() const\n{\n\treturn _FileName;\n}\n\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nNLMISC_CATEGORISED_COMMAND(nel, iFileAccessLogStart, \"Start file access logging\", \"\")\n{\n\tif (!args.empty())\n\t\treturn false;\n\n\tIFileAccessLoggingEnabled= true;\n\tif (IFileAccessLogStartTime==0)\n\t{\n\t\tuint64 timeNow = NLMISC::CTime::getPerformanceTime();\n\t\tIFileAccessLogStartTime= timeNow;\n\t}\n\n\treturn true;\n}\n\n// ======================================================================================================\nNLMISC_CATEGORISED_COMMAND(nel, iFileAccessLogStop, \"Stop file access logging\", \"\")\n{\n\tif (!args.empty())\n\t\treturn false;\n\n\tIFileAccessLoggingEnabled= false;\n\n\treturn true;\n}\n\n// ======================================================================================================\nNLMISC_CATEGORISED_COMMAND(nel, iFileAccessLogClear, \"Clear file access logs\", \"\")\n{\n\tif (!args.empty())\n\t\treturn false;\n\n\tTSynchronizedFileAccessLog::CAccessor(&IFileAccessLog).value().clear();\n\n\treturn true;\n}\n\n// ======================================================================================================\nNLMISC_CATEGORISED_COMMAND(nel, iFileAccessLogDisplay, \"Display file access logs\", \"\")\n{\n\tif (!args.empty())\n\t\treturn false;\n\n\tlog.displayNL(\"-- FILE ACCESS LOG BEGIN --\");\n\n\tTSynchronizedFileAccessLog::CAccessor fileAccesLog(&IFileAccessLog);\n\tTFileAccessLog::const_iterator it= fileAccesLog.value().begin();\n\tTFileAccessLog::const_iterator itEnd= fileAccesLog.value().end();\n\tuint32 count=0;\n\twhile (it!=itEnd)\n\t{\n\t\tuint32 numTimes= (uint32)it->second.size();\n\t\tCSString fileName= it->first;\n\t\tif (fileName.contains(\"@\"))\n\t\t{\n\t\t\tlog.display(\"%d,%s,%s,\",numTimes,fileName.splitTo(\"@\").c_str(),fileName.splitFrom(\"@\").c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tlog.display(\"%d,,%s,\",numTimes,fileName.c_str());\n\t\t}\n\t\tTFileAccessTimes::const_iterator atIt= it->second.begin();\n\t\tTFileAccessTimes::const_iterator atItEnd=it->second.end();\n\t\twhile (atIt!=atItEnd)\n\t\t{\n\t\t\tuint64 delta= (*atIt-IFileAccessLogStartTime);\n\t\t\tlog.display(\"%\" NL_I64 \"u,\",delta);\n\t\t\t++atIt;\n\t\t}\n\t\tlog.displayNL(\"\");\n\t\t++count;\n\t\t++it;\n\t}\n\n\tlog.displayNL(\"-- FILE ACCESS LOG END (%d Unique Files Accessed) --\",count);\n\n\treturn true;\n}\n\n}\n\n\n"
  },
  {
    "path": "code/nel/src/misc/fixed_size_allocator.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/fixed_size_allocator.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// *****************************************************************************************************************\nCFixedSizeAllocator::CFixedSizeAllocator(uint numBytesPerBlock, uint numBlockPerChunk)\n{\n\t_FreeSpace = NULL;\n\t_NumChunks = 0;\n\tnlassert(numBytesPerBlock > 1);\n\t_NumBytesPerBlock = numBytesPerBlock;\n\tconst uint mask = NL_DEFAULT_MEMORY_ALIGNMENT - 1;\n\t_NumBytesPerBlock = (_NumBytesPerBlock + mask) & ~mask;\n\tnlassert(_NumBytesPerBlock >= numBytesPerBlock);\n\t_NumBlockPerChunk = std::max(numBlockPerChunk, (uint) 3);\n\t_NumAlloc = 0;\n}\n\n// *****************************************************************************************************************\nCFixedSizeAllocator::~CFixedSizeAllocator()\n{\n\tif (_NumAlloc != 0)\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\tnlwarning(\"%d blocks were not freed\", (int) _NumAlloc);\n\t\t#endif\n\t\treturn;\n\t}\n\tif (_NumChunks > 0)\n\t{\n\t\tnlassert(_NumChunks == 1);\n\t\t// delete the left chunk. This should force all the left nodes to be removed from the empty list\n\t\tdelete _FreeSpace->Chunk;\n\t}\n}\n\n// *****************************************************************************************************************\nvoid *CFixedSizeAllocator::alloc()\n{\n\tif (!_FreeSpace)\n\t{\n\t\tCChunk *chunk = new CChunk; // link a new chunk to that object\n\t\tchunk->init(this);\n\t}\n\t++ _NumAlloc;\n\treturn _FreeSpace->unlink();\n}\n\n#define aligned_offsetof(s, m) ((offsetof(s, m) + (NL_DEFAULT_MEMORY_ALIGNMENT - 1)) & ~(NL_DEFAULT_MEMORY_ALIGNMENT - 1))\n\n// *****************************************************************************************************************\nvoid CFixedSizeAllocator::free(void *block)\n{\n\tif (!block) return;\n\t/// get the node from the object\n\tCNode *node = (CNode *) ((uint8 *) block - aligned_offsetof(CNode, Next));\n\t//\n\tnlassert(node->Chunk != NULL);\n\tnlassert(node->Chunk->Allocator == this);\n\t//\n\t--_NumAlloc;\n\tnode->link();\n}\n\n// *****************************************************************************************************************\nuint CFixedSizeAllocator::CChunk::getBlockSizeWithOverhead() const\n{\n\tnlctassert((sizeof(CNode) % NL_DEFAULT_MEMORY_ALIGNMENT) == 0);\n\treturn std::max((uint)(sizeof(CNode) - aligned_offsetof(CNode, Next)),\n\t\t(uint)(Allocator->getNumBytesPerBlock())) + aligned_offsetof(CNode, Next);\n}\n\n// *****************************************************************************************************************\nCFixedSizeAllocator::CChunk::CChunk()\n{\n\tNumFreeObjs = 0;\n\tAllocator = NULL;\n}\n\n// *****************************************************************************************************************\nCFixedSizeAllocator::CChunk::~CChunk()\n{\n\tnlassert(Allocator != NULL);\n\tfor (uint k = 0; k < Allocator->getNumBlockPerChunk(); ++k)\n\t{\n\t\tgetNode(k).unlink();\n\t}\n\tnlassert(NumFreeObjs == 0);\n\tnlassert(Allocator->_NumChunks > 0);\n\t-- (Allocator->_NumChunks);\n\taligned_free(Mem); //delete[] Mem;\n}\n\n// *****************************************************************************************************************\nvoid CFixedSizeAllocator::CChunk::init(CFixedSizeAllocator *alloc)\n{\n\tnlassert(!Allocator);\n\tnlassert(alloc != NULL);\n\tAllocator = alloc;\n\t//\n\tMem = (uint8 *)aligned_malloc(getBlockSizeWithOverhead() * alloc->getNumBlockPerChunk(), NL_DEFAULT_MEMORY_ALIGNMENT); // new uint8[getBlockSizeWithOverhead() * alloc->getNumBlockPerChunk()];\n\t//\n\tgetNode(0).Chunk = this;\n\tgetNode(0).Next = &getNode(1);\n\tgetNode(0).Prev = &alloc->_FreeSpace;\n\t//\n\tNumFreeObjs = alloc->getNumBlockPerChunk();\n\t/// init all the element as a linked list\n\tfor (uint k = 1; k < (NumFreeObjs - 1); ++k)\n\t{\n\t\tgetNode(k).Chunk = this;\n\t\tgetNode(k).Next = &getNode(k + 1);\n\t\tgetNode(k).Prev = &getNode(k - 1).Next;\n\t}\n\n\tgetNode(NumFreeObjs - 1).Chunk = this;\n\tgetNode(NumFreeObjs - 1).Next  = alloc->_FreeSpace;\n\tgetNode(NumFreeObjs - 1).Prev = &(getNode(NumFreeObjs - 2).Next);\n\n\tif (alloc->_FreeSpace) { alloc->_FreeSpace->Prev = &getNode(NumFreeObjs - 1).Next; }\n\talloc->_FreeSpace = &getNode(0);\n\t++(alloc->_NumChunks);\n}\n\n// *****************************************************************************************************************\nCFixedSizeAllocator::CNode &CFixedSizeAllocator::CChunk::getNode(uint index)\n{\n\tnlassert(Allocator != NULL);\n\tnlassert(index < Allocator->getNumBlockPerChunk());\n\treturn *(CNode *) ((uint8 *) Mem + index * getBlockSizeWithOverhead());\n}\n\n// *****************************************************************************************************************\nvoid CFixedSizeAllocator::CChunk::add()\n{\n\tnlassert(Allocator);\n\t// a node of this chunk has been given back\n\tnlassert(NumFreeObjs < Allocator->getNumBlockPerChunk());\n\t++ NumFreeObjs;\n\tif (NumFreeObjs == Allocator->getNumBlockPerChunk()) // all objects back ?\n\t{\n\t\tif (Allocator->_NumChunks > 1) // we want to have at least one chunk left\n\t\t{\n\t\t\tdelete this; // kill that object\n\t\t}\n\t}\n}\n\n// *****************************************************************************************************************\nvoid CFixedSizeAllocator::CChunk::grab()\n{\n\t// a node of this chunk has been given back\n\tnlassert(NumFreeObjs > 0);\n\t-- NumFreeObjs;\n}\n\n// *****************************************************************************************************************\nvoid *CFixedSizeAllocator::CNode::unlink()\n{\n\tnlassert(Prev != NULL);\n\tif (Next) { Next->Prev = Prev;}\n\t*Prev = Next;\n\tnlassert(Chunk->NumFreeObjs > 0);\n\tChunk->grab(); // tells the containing chunk that a node has been allocated\n\treturn (void *)((uintptr_t)(this) + aligned_offsetof(CNode, Next)); //(void *) &Next;\n}\n\n// *****************************************************************************************************************\nvoid CFixedSizeAllocator::CNode::link()\n{\n\t// destroy the obj to get back uninitialized memory\n\tnlassert(Chunk);\n\tnlassert(Chunk->Allocator);\n\n\tCNode *&head = Chunk->Allocator->_FreeSpace;\n\tNext = head;\n\tPrev = &head;\n\tif (Next)\n\t{\n\t\tnlassert(Next->Prev = &head);\n\t\tNext->Prev = &Next;\n\t}\n\tChunk->Allocator->_FreeSpace = this;\n\tChunk->add();\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/game_device.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/game_device.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/game_device_events.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/game_device_events.h\"\n\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nvoid dummyToAvoidStupidCompilerWarning_game_device_events_cpp()\n{\n\t\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/geom_ext.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/geom_ext.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_geom_ext_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/grid_traversal.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n#include \"nel/misc/grid_traversal.h\"\n#include \"nel/misc/vector_2f.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// ********************************************************************************************************************************\nvoid\tCGridTraversal::startTraverse(const NLMISC::CVector2f &start, sint &nextX, sint &nextY)\n{\n\tnextX = (sint) floorf(start.x);\n\tnextY = (sint) floorf(start.y);\n}\n\n// ********************************************************************************************************************************\nbool\tCGridTraversal::traverse(const NLMISC::CVector2f &start, const NLMISC::CVector2f &dir, sint &x, sint &y)\n{\n\tif (dir.x > 0.f)\n\t{\n\t\tfloat lambdaX = (x + 1.f - start.x) / dir.x;\n\t\tif (dir.y > 0.f)\n\t\t{\n\t\t\tfloat lambdaY = (y + 1 - start.y) / dir.y;\n\t\t\tif (lambdaX < lambdaY)\n\t\t\t{\n\t\t\t\tif (lambdaX > 1.f) return false;\n\t\t\t\t++ x;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lambdaY > 1.f) return false;\n\t\t\t\t++ y;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse if (dir.y < 0.f)\n\t\t{\n\t\t\tfloat lambdaY = (y - start.y) / dir.y;\n\t\t\tif (lambdaX < lambdaY)\n\t\t\t{\n\t\t\t\tif (lambdaX > 1.f) return false;\n\t\t\t\t++ x;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lambdaY > 1.f) return false;\n\t\t\t\t-- y;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t++ x;\n\t\treturn x <= (sint) floorf(start.x + dir.x);\n\t}\n\telse if (dir.x < 0.f)\n\t{\n\t\tfloat lambdaX = (x - start.x) / dir.x;\n\t\tif (dir.y > 0.f)\n\t\t{\n\t\t\tfloat lambdaY = (y + 1.f - start.y) / dir.y;\n\t\t\tif (lambdaX < lambdaY)\n\t\t\t{\n\t\t\t\tif (lambdaX > 1.f) return false;\n\t\t\t\t-- x;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lambdaY > 1.f) return false;\n\t\t\t\t++ y;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse if (dir.y < 0.f)\n\t\t{\n\t\t\tfloat lambdaY = (y - start.y) / dir.y;\n\t\t\tif (lambdaX < lambdaY)\n\t\t\t{\n\t\t\t\tif (lambdaX > 1.f) return false;\n\t\t\t\t-- x;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (lambdaY > 1.f) return false;\n\t\t\t\t-- y;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t-- x;\n\t\treturn x >= (sint) floorf(start.x + dir.x);\n\t}\n\n\tif (dir.y > 0.f)\n\t{\n\t\t++ y;\n\t\treturn y <= (sint) floorf(start.y + dir.y);\n\n\t}\n\telse if (dir.y < 0.f)\n\t{\n\t\t-- y;\n\t\treturn y >= (sint) floorf(start.y + dir.y);\n\t}\n\treturn false;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/gtk_displayer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/gtk_displayer.h\"\n\n#ifdef NL_USE_GTK\n\n#include <gtk/gtk.h>\n#include <gdk/gdk.h>\n//#include <gobject/gobject.h>\n#include <gdk/gdkkeysyms.h>\n\n#ifdef NL_OS_WINDOWS\n// automatically add gtk library\n#pragma comment(lib, \"gtk-1.3.lib\")\n#pragma comment(lib, \"gdk-1.3.lib\")\n#pragma comment(lib, \"glib-1.3.lib\")\n#pragma comment(lib, \"gthread-1.3.lib\")\n#endif\n\n#include \"nel/misc/app_context.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/thread.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n//\n// Variables\n//\n\nstatic vector<string> CommandHistory;\nstatic uint32 CommandHistoryPos = 0;\nstatic CLog *Log = 0;\n\nstatic GtkWidget *RootWindow = NULL, *OutputText = NULL, *InputText = NULL;\nstatic GtkWidget *hrootbox = NULL, *scrolled_win2 = NULL;\n\n//\n// Functions\n//\n\nCGtkDisplayer (const char *displayerName) : CWindowDisplayer(displayerName)\n{\n\tneedSlashR = false;\n\tcreateLabel (\"@Clear|CLEAR\");\n\n\tINelContext::getInstance().setWindowedApplication(true);\n}\n\nCGtkDisplayer::~CGtkDisplayer ()\n{\n\tif (_Init)\n\t{\n\t}\n}\n\ngint ButtonClicked(GtkWidget *Widget, gpointer *Data)\n{\n\tCGtkDisplayer *disp = (CGtkDisplayer *) Data;\n\n\t// find the button and execute the command\n\tCSynchronized<std::vector<CGtkDisplayer::CLabelEntry> >::CAccessor access (&(disp->_Labels));\n\tfor (uint i = 0; i < access.value().size(); i++)\n\t{\n\t\tif (access.value()[i].Hwnd == Widget)\n\t\t{\n\t\t\tif(access.value()[i].Value == \"@Clear|CLEAR\")\n\t\t\t{\n\t\t\t\t// special commands because the clear must be called by the display thread and not main thread\n\t\t\t\tdisp->clear ();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the button was found, add the command in the command stack\n\t\t\t\tCSynchronized<std::vector<std::string> >::CAccessor accessCommands (&disp->_CommandsToExecute);\n\t\t\t\tstring str;\n\t\t\t\tnlassert (!access.value()[i].Value.empty());\n\t\t\t\tnlassert (access.value()[i].Value[0] == '@');\n\n\t\t\t\tstring::size_type pos = access.value()[i].Value.find (\"|\");\n\t\t\t\tif (pos != string::npos)\n\t\t\t\t{\n\t\t\t\t\tstr = access.value()[i].Value.substr(pos+1);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstr = access.value()[i].Value.substr(1);\n\t\t\t\t}\n\t\t\t\tif (!str.empty())\n\t\t\t\t\taccessCommands.value().push_back(str);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn TRUE;\n}\n\n\nvoid CGtkDisplayer::updateLabels ()\n{\n\t{\n\t\tCSynchronized<std::vector<CLabelEntry> >::CAccessor access (&_Labels);\n\t\tfor (uint i = 0; i < access.value().size(); i++)\n\t\t{\n\t\t\tif (access.value()[i].NeedUpdate && !access.value()[i].Value.empty())\n\t\t\t{\n\t\t\t\tstring n;\n\n\t\t\t\tif (access.value()[i].Value[0] != '@')\n\t\t\t\t\tn = access.value()[i].Value;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstring::size_type pos = access.value()[i].Value.find ('|');\n\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tn = access.value()[i].Value.substr (1, pos - 1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tn = access.value()[i].Value.substr (1);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (access.value()[i].Hwnd == NULL)\n\t\t\t\t{\n\t\t\t\t\t// create a button for command and label for variables\n\t\t\t\t\tif (access.value()[i].Value[0] == '@')\n\t\t\t\t\t{\n\t\t\t\t\t\taccess.value()[i].Hwnd = gtk_button_new_with_label (n.c_str());\n\t\t\t\t\t\tnlassert (access.value()[i].Hwnd != NULL);\n\t\t\t\t\t\tgtk_signal_connect (GTK_OBJECT (access.value()[i].Hwnd), \"clicked\", GTK_SIGNAL_FUNC (ButtonClicked), (gpointer) this);\n\t\t\t\t\t\tGtkLabel *label = GTK_LABEL(gtk_bin_get_child(GTK_BIN(access.value()[i].Hwnd)));\n\t\t\t\t\t\tgtk_label_set_justify (label, GTK_JUSTIFY_LEFT);\n\t\t\t\t\t\tgtk_label_set_line_wrap (label, FALSE);\n\t\t\t\t\t\tgtk_widget_show (GTK_WIDGET (access.value()[i].Hwnd));\n\t\t\t\t\t\tgtk_box_pack_start (GTK_BOX (hrootbox), GTK_WIDGET (access.value()[i].Hwnd), TRUE, TRUE, 0);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\taccess.value()[i].Hwnd = gtk_label_new (\"\");\n\t\t\t\t\t\tgtk_label_set_justify (GTK_LABEL (access.value()[i].Hwnd), GTK_JUSTIFY_LEFT);\n\t\t\t\t\t\tgtk_label_set_line_wrap (GTK_LABEL (access.value()[i].Hwnd), FALSE);\n\t\t\t\t\t\tgtk_widget_show (GTK_WIDGET (access.value()[i].Hwnd));\n\t\t\t\t\t\tgtk_box_pack_start (GTK_BOX (hrootbox), GTK_WIDGET (access.value()[i].Hwnd), TRUE, TRUE, 0);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (access.value()[i].Value[0] != '@')\n\t\t\t\t\tgtk_label_set_text (GTK_LABEL (access.value()[i].Hwnd), n.c_str());\n\n\t\t\t\taccess.value()[i].NeedUpdate = false;\n\t\t\t}\n\t\t}\n\t}\n}\n\n// windows delete event => quit\ngint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)\n{\n\tgtk_main_quit();\n\n\texit(1);\n\treturn FALSE;\n}\n\ngint KeyIn(GtkWidget *Widget, GdkEventKey *Event, gpointer *Data)\n{\n\tswitch (Event->keyval)\n\t{\n\tcase GDK_Escape :\n\t\tgtk_entry_set_text (GTK_ENTRY(Widget), \"\");\n\t\tbreak;\n\tcase GDK_Up :\n\t\tif (CommandHistoryPos > 0) {\n\t\t\tCommandHistoryPos--;\n\t\t\tgtk_entry_set_text (GTK_ENTRY(Widget), CommandHistory[CommandHistoryPos].c_str());\n\t\t}\n\t\tbreak;\n\tcase GDK_Down :\n\t\tif (CommandHistoryPos + 1 < CommandHistory.size())\n\t\t{\n\t\t\tCommandHistoryPos++;\n\t\t\tgtk_entry_set_text (GTK_ENTRY(Widget), CommandHistory[CommandHistoryPos].c_str());\n\t\t}\n\t\tbreak;\n\tcase GDK_KP_Enter :\n\t\tgtk_signal_emit_by_name(GTK_OBJECT(Widget),\"activate\");\n\tdefault :\n\t\treturn FALSE;\n\t}\n\tgtk_signal_emit_stop_by_name(GTK_OBJECT(Widget),\"key_press_event\");\n\treturn TRUE;\n}\n\nvoid updateInput ()\n{\n\tgtk_widget_grab_focus (InputText);\n}\n\ngint KeyOut(GtkWidget *Widget, GdkEventKey *Event, gpointer *Data)\n{\n\tupdateInput();\n\tgtk_signal_emit_stop_by_name(GTK_OBJECT(Widget),\"key_press_event\");\n\treturn TRUE;\n}\n\n\n/*gint ButtonClear(GtkWidget *Widget, GdkEventKey *Event, gpointer *Data)\n{\n\tCGtkDisplayer *disp = (CGtkDisplayer *) Data;\n\n\tdisp->clear ();\n\treturn TRUE;\n}\n*/\n\n\n// the user typed  command, execute it\ngint cbValidateCommand (GtkWidget *widget, GdkEvent *event, gpointer data)\n{\n\tstring cmd = gtk_entry_get_text (GTK_ENTRY(widget));\n\tCommandHistory.push_back (cmd);\n\t// execute the command\n\tif(Log == NULL)\n\t\tLog = InfoLog;\n\tICommand::execute (cmd, *Log);\n\t// clear the input text\n\tgtk_entry_set_text (GTK_ENTRY(widget), \"\");\n\tCommandHistoryPos = CommandHistory.size();\n\treturn TRUE;\n}\n\n\nvoid CGtkDisplayer::setTitleBar (const string &titleBar)\n{\n\tstring wn;\n\tif (!titleBar.empty())\n\t{\n\t\twn += titleBar;\n\t\twn += \": \";\n\t}\n\twn += \"Nel Service Console (compiled \" __DATE__ \" \" __TIME__ \" in \" + nlMode + \" mode)\";\n\n\t//nlassert (RootWindow != NULL);\n\tgtk_window_set_title (GTK_WINDOW (RootWindow), wn.c_str());\n}\n\nvoid CGtkDisplayer::open (std::string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log)\n{\n\t_HistorySize = hs;\n\n\tif (w == -1)\n\t\tw = 700;\n\tif (h == -1)\n\t\th = 300;\n\tif (hs == -1)\n\t\ths = 10000;\n\n\tgtk_init (NULL, NULL);\n\n\tLog = log;\n\n\t// Root window\n\tRootWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);\n\tgtk_window_set_default_size (GTK_WINDOW (RootWindow), w, h);\n\tgtk_signal_connect (GTK_OBJECT (RootWindow), \"delete_event\", GTK_SIGNAL_FUNC (delete_event), NULL);\n\n\t// Vertical box\n\tGtkWidget *vrootbox = gtk_vbox_new (FALSE, 0);\n\tnlassert (vrootbox != NULL);\n\tgtk_container_add (GTK_CONTAINER (RootWindow), vrootbox);\n\n\t// Horizontal box (for labels)\n\throotbox = gtk_hbox_new (FALSE, 0);\n\tnlassert (hrootbox != NULL);\n\tgtk_box_pack_start (GTK_BOX (vrootbox), hrootbox, FALSE, FALSE, 0);\n\n/*\t// Clear button\n    GtkWidget *button = gtk_button_new_with_label (\"Clear\");\n\tnlassert (button != NULL);\n    gtk_signal_connect (GTK_OBJECT (button), \"clicked\", GTK_SIGNAL_FUNC (ButtonClear), (gpointer) this);\n\tgtk_box_pack_start (GTK_BOX (hrootbox), button, FALSE, FALSE, 0);\n*/\n\t// Output text\n\tscrolled_win2 = gtk_scrolled_window_new (NULL, NULL);\n\tnlassert (scrolled_win2 != NULL);\n\tgtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);\n\tgtk_widget_show (scrolled_win2);\n\tgtk_container_add (GTK_CONTAINER (vrootbox), scrolled_win2);\n\n\tOutputText = gtk_text_view_new();\n\tnlassert (OutputText != NULL);\n\n\tPangoFontDescription *fontDesc = pango_font_description_from_string(\"Monospace 10\");\n  \tgtk_widget_modify_font(OutputText, fontDesc);\n  \tpango_font_description_free(fontDesc);\n\n\tGtkTextBuffer *textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText));\n\tGtkTextIter endIter;\n\tgtk_text_buffer_get_end_iter(textBuffer, &endIter);\n\tgtk_text_buffer_create_mark(textBuffer, \"endmark\", &endIter, false);\n\tgtk_signal_connect(GTK_OBJECT(OutputText),\"key_press_event\",GTK_SIGNAL_FUNC(KeyOut),NULL);\n\tgtk_text_view_set_editable (GTK_TEXT_VIEW(OutputText), FALSE);\n\tgtk_container_add (GTK_CONTAINER (scrolled_win2), OutputText);\n\n\t// Input text\n\tInputText = gtk_entry_new ();\n\tnlassert (InputText != NULL);\n\tgtk_signal_connect (GTK_OBJECT(InputText), \"activate\", GTK_SIGNAL_FUNC(cbValidateCommand), NULL);\n\tgtk_signal_connect(GTK_OBJECT(InputText),\"key_press_event\",GTK_SIGNAL_FUNC(KeyIn),NULL);\n\tgtk_box_pack_start (GTK_BOX (vrootbox), InputText, FALSE, FALSE, 0);\n\n//\tgtk_widget_show (button);\n\tgtk_widget_show (OutputText);\n\tgtk_widget_show (InputText);\n\n\tgtk_widget_show (hrootbox);\n\tgtk_widget_show (vrootbox);\n    gtk_widget_show (RootWindow);\n\n\tsetTitleBar (titleBar);\n\n\t_Init = true;\n}\n\nvoid CGtkDisplayer::clear ()\n{\n\tGtkTextBuffer *buffer;\n\tGtkTextIter    start, end;\n\n\t// who is taking care of the iterators?\n\tbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText));\n\tgtk_text_buffer_get_bounds(buffer, &start, &end);\n\tgtk_text_buffer_delete(buffer, &start, &end);\n}\n\ngint updateInterf (gpointer data)\n{\n\tCGtkDisplayer *disp = (CGtkDisplayer *)data;\n\n\t//\n\t// Update labels\n\t//\n\n\tdisp->updateLabels ();\n\n\t//\n\t// Display the bufferized string\n\t//\n\tGtkAdjustment *Adj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_win2));\n\tbool Bottom = (Adj->value >= Adj->upper - Adj->page_size - Adj->step_increment);\n\tbool textChanged = false;\n\n\tGtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText));\n\tGtkTextIter    end_iter;\n\tgtk_text_buffer_get_end_iter(buffer, &end_iter);\n\n\tstd::list<std::pair<uint32, std::string> >::iterator it;\n\t{\n\t\tCSynchronized<std::list<std::pair<uint32, std::string> > >::CAccessor access (&disp->_Buffer);\n\n\t\tfor (it = access.value().begin(); it != access.value().end(); it++)\n\t\t{\n\t\t\tuint32 col = (*it).first;\n\t\t\tGtkTextTag *tag = NULL;\n\t\t\tif ((col>>24) == 0)\n\t\t\t{\n\t\t\t\tGdkColor color;\n\t\t\t\tcolor.red = (col >> 8) & 0xFF00;\n\t\t\t\tcolor.green = col & 0xFF00;\n\t\t\t\tcolor.blue = (col << 8) & 0xFF00;\n\t\t\t\ttag = gtk_text_buffer_create_tag(buffer, NULL, \"foreground-gdk\", &color, \"foreground-set\", TRUE, NULL);\n\t\t\t}\n\t\t\tgtk_text_buffer_insert_with_tags(buffer, &end_iter, (*it).second.c_str(), -1, tag, NULL);\n\t\t\ttextChanged = true;\n\t\t}\n\n\t\taccess.value().clear ();\n\t}\n\n\tif (Bottom && textChanged)\n\t{\n\t\tGtkTextMark *mark = gtk_text_buffer_get_mark(buffer, \"endmark\");\n\t\tgtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(OutputText), mark, 0.0, true, 0.0, 1.0);\n\t}\n\n\treturn TRUE;\n}\n\nvoid CGtkDisplayer::display_main ()\n{\n\t//\n\t// Manage windows message\n\t//\n\n\tgtk_timeout_add (10, updateInterf, this);\n\tgtk_main ();\n}\n\n\nvoid CGtkDisplayer::getWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h)\n{\n// todo\n\tx = y = w = h = 0;\n}\n\n\n\n} // NLMISC\n\n#else // NL_USE_GTK\n\n// remove stupid VC6 warnings\nvoid foo_gtk_displayer_cpp() {}\n\n#endif // NL_USE_GTK\n"
  },
  {
    "path": "code/nel/src/misc/heap_memory.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/heap_memory.h\"\n#include \"nel/misc/debug.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n// ***************************************************************************\nCHeapMemory::CHeapMemory()\n{\n\treset();\n\t// For allocate to work even if the heap is not initialized.\n\t_Alignment= 4;\n}\n// ***************************************************************************\nCHeapMemory::~CHeapMemory()\n{\n\treset();\n}\n\n\n// ***************************************************************************\nvoid\t\t\tCHeapMemory::reset()\n{\n\t_EmptySpaces.clear();\n\t_EmptySpaceMap.clear();\n\t_AllocatedSpaceMap.clear();\n\t_HeapPtr= NULL;\n\t_HeapSize= 0;\n\t_HeapSizeUsed= 0;\n}\n\n\n// ***************************************************************************\nvoid\t\t\tCHeapMemory::initHeap(void *heap, uint size, uint align)\n{\n\t// setup alignement.\n\tif(align!=4 && align!=8 && align!=16 && align!=32)\n\t{\n\t\tnlstop;\n\t\talign= 4;\n\t}\n\t_Alignment= align;\n\n\t// Manage alignement.\n\tsize= (size) & (~(_Alignment-1));\n\n\t// clear container.\n\treset();\n\tif(heap==0 || size==0)\n\t\treturn;\n\n\t_HeapPtr= (uint8*)heap;\n\t_HeapSize= size;\n\t_HeapSizeUsed= 0;\n\n\t// Add the only one empty space.\n\tCEmptySpace\t\tspace;\n\tspace.Ptr= _HeapPtr;\n\tspace.Size= _HeapSize;\n\n\taddEmptySpace(space);\n}\n\n\n// ***************************************************************************\nvoid\t\tCHeapMemory::removeEmptySpace(CEmptySpace &space)\n{\n\t// remove the iterator on the spaceMap.\n\t_EmptySpaceMap.erase( space.SizeIt );\n\n\t// remove from the list of EmptySpaces. NB: must fo it after all, because \"space\" may be deleted.\n\t_EmptySpaces.erase( space.Ptr );\n}\n\n\n// ***************************************************************************\nvoid\t\tCHeapMemory::addEmptySpace(CEmptySpace &space)\n{\n\t// insert and get the iterator on the spaceMap.\n\tspace.SizeIt= _EmptySpaceMap.insert( make_pair(space.Size, space.Ptr));\n\n\t// insert into the list of EmptySpaces.\n\t_EmptySpaces.insert( make_pair(space.Ptr, space) );\n}\n\n\n// ***************************************************************************\nvoid\t\t\t*CHeapMemory::allocate(uint size)\n{\n\tif(size==0)\n\t\treturn NULL;\n\n\t// Manage alignement.\n\tsize= (size + (_Alignment-1)) & (~(_Alignment-1));\n\n\n\t// retrieve the best block.\n\t//=========================\n\tCEmptySpace\t\tbestSpace;\n\t// NB: do a copy, because of removeEmptySpace() which delete the space.\n\n\t// Find the smaller space which is >= than size.\n\tItEmptySpaceSizeMap\t\tit;\n\tit= _EmptySpaceMap.lower_bound(size);\n\n\t// if not found, alloc fails.\n\tif(it == _EmptySpaceMap.end())\n\t\treturn NULL;\n\telse\n\t{\n\t\t// NB: this space must exist in the \"array\".\n\t\tbestSpace= _EmptySpaces[it->second];\n\t}\n\n\n\t// remove this empty space from list.\n\t//=========================\n\tremoveEmptySpace(bestSpace);\n\n\n\t// if any, add the space unused to the list.\n\t//=========================\n\tif(bestSpace.Size > size)\n\t{\n\t\tCEmptySpace\t\tspace;\n\t\tspace.Ptr= bestSpace.Ptr + size;\n\t\tspace.Size= bestSpace.Size - size;\n\n\t\taddEmptySpace(space);\n\t}\n\n\n\t// return / insert the allocated space.\n\t//=========================\n\t_AllocatedSpaceMap.insert(make_pair(bestSpace.Ptr, size));\n\t_HeapSizeUsed+= size;\n\n\t// return the ptr of start of this empty space.\n\treturn bestSpace.Ptr;\n}\n\n// ***************************************************************************\nvoid\t\t\tCHeapMemory::free(void *ptr)\n{\n\tif(ptr==NULL)\n\t\treturn;\n\n\t// Must find the array in allocated spaces.\n\t//==========================\n\tItAllocatedSpaceMap\t\titAlloc= _AllocatedSpaceMap.find((uint8*)ptr);\n\tif(itAlloc == _AllocatedSpaceMap.end())\n\t{\n\t\tnlstop;\n\t\treturn;\n\t}\n\tuint\tsize= itAlloc->second;\n\n\t// free this space from allocated Spaces.\n\t_AllocatedSpaceMap.erase(itAlloc);\n\t_HeapSizeUsed-= size;\n\n\n\t// Must find previous or/and next empty space, if any.\n\t//==========================\n\tItEmptySpacePtrMap\t\titPrevious, itNext;\n\n\t// find the empty space which is immediately >= than ptr.\n\titNext= _EmptySpaces.lower_bound((uint8*)ptr);\n\t// NB: it may be end(), if it is the last block (very rare).\n\n\t// some check. next empty space ptr must be after ptr.\n\tif(itNext!=_EmptySpaces.end())\n\t{\n\t\tnlassert(itNext->second.Ptr >= (uint8*)ptr + size);\n\t}\n\n\t// if itNext is not the first empty space, there is an empty space before us.\n\tif( itNext!= _EmptySpaces.begin() )\n\t{\n\t\t// NB: work even if itNext==end().\n\t\titPrevious= itNext;\n\t\titPrevious--;\n\t\t// some check. previous empty space ptr must be before ptr.\n\t\tnlassert(itPrevious!=_EmptySpaces.end());\n\t\tnlassert(itPrevious->second.Ptr + itPrevious->second.Size <= (uint8*)ptr );\n\t}\n\telse\n\t\titPrevious= _EmptySpaces.end();\n\n\n\t// if next exist.\n\tif(itNext!=_EmptySpaces.end())\n\t{\n\t\t// If Previous is not just after allocated ptr, it means that there is some allocated blocks beetween,\n\t\t// so it is not a valid empty space to concat.\n\t\tif(itNext->second.Ptr != (uint8*)ptr + size)\n\t\t\titNext= _EmptySpaces.end();\n\t}\n\t// if previous exist.\n\tif(itPrevious!=_EmptySpaces.end())\n\t{\n\t\t// If Previous is not just before allocated ptr, it means that there is some allocated blocks beetween,\n\t\t// so it is not a valid empty space to concat.\n\t\tif(itPrevious->second.Ptr + itPrevious->second.Size != (uint8*)ptr )\n\t\t\titPrevious=_EmptySpaces.end();\n\t}\n\n\n\n\t// According to configuration, build the new empty space, mreging previous and next, and remove old ones.\n\t//==========================\n\tCEmptySpace\t\tnewSpace;\n\n\t// if no previous empty space, then newSpace start at ptr.\n\tif(itPrevious == _EmptySpaces.end())\n\t{\n\t\t// Start with old allocated block.\n\t\tnewSpace.Ptr= (uint8*)ptr;\n\t\tnewSpace.Size= size;\n\t}\n\t// else, start at previous Ptr.\n\telse\n\t{\n\t\t// Start with previous block. size is previous size + allocated block size.\n\t\tnewSpace.Ptr= itPrevious->second.Ptr;\n\t\tnewSpace.Size= itPrevious->second.Size + size;\n\t}\n\n\t// if next empty space, must inc size.\n\tif(itNext != _EmptySpaces.end())\n\t{\n\t\tnewSpace.Size+= itNext->second.Size;\n\t}\n\n\n\t// remove old empty space, and add new one.\n\t//==========================\n\n\t// remove old empty spaces.\n\tif(itPrevious != _EmptySpaces.end())\n\t\tremoveEmptySpace(itPrevious->second);\n\tif(itNext != _EmptySpaces.end())\n\t\tremoveEmptySpace(itNext->second);\n\n\n\t// Add the new concatenated empty space.\n\taddEmptySpace(newSpace);\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/hierarchical_timer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/system_info.h\"\n\n#ifdef NL_CPU_INTEL\n#include \"nel/misc/time_nl.h\"\n#endif\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nbool   CSimpleClock::_InitDone = false;\nuint64 CSimpleClock::_StartStopNumTicks = 0;\n\n\n// root node for all execution paths\nCHTimer::CNode  CHTimer::_RootNode;\nCHTimer::CNode *CHTimer::_CurrNode = &_RootNode;\nCSimpleClock\tCHTimer::_PreambuleClock;\nCHTimer\t\t\tCHTimer::_RootTimer(\"root\", true);\nbool\t\t\tCHTimer::_Benching = false;\nbool\t\t\tCHTimer::_BenchStartedOnce = false;\ndouble\t\t\tCHTimer::_MsPerTick;\nbool\t\t\tCHTimer::_WantStandardDeviation = false;\nCHTimer\t\t   *CHTimer::_CurrTimer = &_RootTimer;\nsint64\t\t\tCHTimer::_AfterStopEstimateTime= 0;\nbool\t\t\tCHTimer::_AfterStopEstimateTimeDone= false;\n\n\n\n\n\n\n\n//=================================================================\nvoid CSimpleClock::init()\n{\n\tif (_InitDone) return;\n\tconst uint numSamples = 10000;\n\n\tCSimpleClock observedClock;\n\tCSimpleClock measuringClock;\n\n\tmeasuringClock.start();\n\tfor(uint l = 0; l < numSamples; ++l)\n\t{\n\t\tobservedClock.start();\n\t\tobservedClock.stop();\n\t}\n\tmeasuringClock.stop();\n\n\t_StartStopNumTicks = (measuringClock.getNumTicks() >> 1) / numSamples;\n\t_InitDone = true;\n}\n\n\n\n//=================================================================\n/** Do simple statistics on a list of values (mean value, standard deviation)\n  */\n/*static void PerformStatistics(const std::vector<double> &values, double &standardDeviation)\n{\n\tnlassert(!values.empty());\n\tdouble total = 0;\n\tdouble variance = 0;\n\tuint k;\n\tfor(k = 0; k < values.size(); ++k)\n\t{\n\t\ttotal += (double) values[k];\n\t}\n\tmeanValue = total / values.size();\n\tif (values.size() <= 1)\n\t{\n\t\tstandardDeviation = 0.f;\n\t\treturn;\n\t}\n\tfor(k = 0; k < values.size(); ++k)\n\t{\n\t\tvariance += NLMISC::sqr((values[k] - meanValue));\n\t}\n\tstandardDeviation = ::sqrt(variance / values.size() - 1);\n}*/\n\n\n\n//=================================================================\nCHTimer::CNode::~CNode()\n{\n\treleaseSons();\n\tfor(uint k = 0; k < Sons.size(); ++k)\n\t\tdelete Sons[k];\n}\n\n//=================================================================\nvoid CHTimer::CNode::releaseSons()\n{\n\tfor(uint k = 0; k < Sons.size(); ++k)\n\t\tdelete Sons[k];\n\tSons.clear();\n}\n\n//=================================================================\nvoid CHTimer::CNode::displayPath(CLog *log) const\n{\n\tstd::string path;\n\tgetPath(path);\n\tlog->displayRawNL((\"HTIMER: \" + path).c_str());\n}\n\n//=================================================================\nvoid CHTimer::CNode::getPath(std::string &path) const\n{\n\tpath.clear();\n\tconst CNode *currNode = this;\n\tdo\n\t{\n\t\tpath = path.empty() ? currNode->Owner->getName()\n\t\t\t: currNode->Owner->getName() + std::string(\"::\") + path;\n\t\tcurrNode = currNode->Parent;\n\t}\n\twhile (currNode);\n}\n\n\n//=================================================================\nuint CHTimer::CNode::getNumNodes() const\n{\n\tuint sum = 1;\n\tfor(uint k = 0; k < Sons.size(); ++k)\n\t{\n\t\tsum += Sons[k]->getNumNodes();\n\t}\n\treturn sum;\n}\n\n\n//=================================================================\nvoid CHTimer::walkTreeToCurrent()\n{\n\tif (_IsRoot) return;\n\tbool found = false;\n\tfor(uint k = 0; k < _CurrNode->Sons.size(); ++k)\n\t{\n\t\tif (_CurrNode->Sons[k]->Owner == this)\n\t\t{\n\t\t\t_CurrNode = _CurrNode->Sons[k];\n\t\t\tfound = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!found)\n\t{\n\t\t// no node for this execution path : create a new one\n\t\t_CurrNode->Sons.push_back(new CNode(this, _CurrNode));\n\t\t_CurrNode->Sons.back()->Parent = _CurrNode;\n\t\t_CurrNode = _CurrNode->Sons.back();\n\t}\n}\n\n\n\n//=================================================================\nvoid\tCHTimer::estimateAfterStopTime()\n{\n\tif(_AfterStopEstimateTimeDone)\n\t\treturn;\n\tconst uint numSamples = 1000;\n\n\t// Do as in startBench, reset and init\n\tclear();\n\n\t{\n#ifdef NL_CPU_INTEL\n\t\tdouble freq = (double) CSystemInfo::getProcessorFrequency(false);\n\t\t_MsPerTick = 1000 / (double) freq;\n#else\n\t\t_MsPerTick = CTime::ticksToSecond(1000);\n#endif\n\t\tCSimpleClock::init();\n\t}\n\n\t// start\n\t_Benching = true;\n\t_BenchStartedOnce = true;\n\t_RootNode.Owner = &_RootTimer;\n\t_WantStandardDeviation = false;\n\t_RootTimer.before();\n\n\tfor(uint i=0;i<numSamples;i++)\n\t{\n\t\tstatic NLMISC::CHTimer\t\testimateSampleTimer(\"sampleTimer\");\n\t\testimateSampleTimer.before();\n\t\testimateSampleTimer.after();\n\t}\n\n\t_RootTimer.after();\n\t_Benching = false;\n\n\t// Then the After Stop time is the rootTimer time / numSamples\n\t_AfterStopEstimateTime= (_RootNode.TotalTime-_RootNode.SonsTotalTime) / numSamples;\n\n\t_AfterStopEstimateTimeDone= true;\n\n\t// must re-clear.\n\tclear();\n}\n\n\n//=================================================================\nvoid\tCHTimer::startBench(bool wantStandardDeviation /*= false*/, bool quick, bool reset)\n{\n\tnlassert(!_Benching);\n\n\t// if not done, estimate the AfterStopTime\n\testimateAfterStopTime();\n\n\tif(reset)\n\t\tclear();\n\n\tif(reset)\n\t{\n#ifdef NL_CPU_INTEL\n\t\tdouble freq = (double) CSystemInfo::getProcessorFrequency(quick);\n\t\t_MsPerTick = 1000 / (double) freq;\n#else\n\t\t_MsPerTick = CTime::ticksToSecond(1000);\n#endif\n\t\tCSimpleClock::init();\n\t}\n\n\t// if reset needed, clearup all\n\tif (reset)\n\t\tclearSessionStats();\n\n\t// clear current for session\n\tclearSessionCurrent();\n\n\t// Launch\n\t_Benching = true;\n\t_BenchStartedOnce = true;\n\t_RootNode.Owner = &_RootTimer;\n\t_WantStandardDeviation = wantStandardDeviation;\n\t_RootTimer.before();\n}\n\n//=================================================================\nvoid\tCHTimer::endBench()\n{\n\tif (!_Benching)\n\t\treturn;\n\n\tif (_CurrNode == &_RootNode)\n\t{\n\t\t_RootTimer.after();\n\t}\n\telse\n\t{\n\t\tnlwarning(\"HTIMER: Stopping the bench inside a benched functions !\");\n\t}\n\t_Benching = false;\n\n\t// spread session stats if root node is greater\n\tupdateSessionStats();\n}\n\n//=================================================================\nvoid\tCHTimer::display(CLog *log, TSortCriterion criterion, bool displayInline /*= true*/, bool displayEx)\n{\n\tCSimpleClock\tbenchClock;\n\tbenchClock.start();\n\tif(!_BenchStartedOnce) // should have done at least one bench\n\t{\n\t\tbenchClock.stop();\n\t\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n\t\treturn;\n\t}\n\tlog->displayNL(\"HTIMER: =========================================================================\");\n\tlog->displayRawNL(\"HTIMER: Bench cumuled results\");\n\ttypedef std::map<CHTimer *, TNodeVect> TNodeMap;\n\tTNodeMap nodeMap;\n\tTNodeVect nodeLeft;\n\tnodeLeft.push_back(&_RootNode);\n\n\t/// 1 ) walk the tree to build the node map (well, in a not very optimal way..)\n\twhile (!nodeLeft.empty())\n\t{\n\t\tCNode *currNode = nodeLeft.back();\n\t\tnodeMap[currNode->Owner].push_back(currNode);\n\t\tnodeLeft.pop_back();\n\t\tnodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());\n\t}\n\n\t// 2 ) build statistics\n\ttypedef std::vector<CTimerStat> TTimerStatVect;\n\ttypedef std::vector<CTimerStat *> TTimerStatPtrVect;\n\tTTimerStatVect\t\tstats(nodeMap.size());\n\tTTimerStatPtrVect\tstatsPtr(stats.size());\n\t//\n\tuint k = 0;\n\tfor(TNodeMap::iterator it = nodeMap.begin(); it != nodeMap.end(); ++it)\n\t{\n\t\tstatsPtr[k] = &stats[k];\n\t\tstats[k].Timer = it->first;\n\t\tstats[k].buildFromNodes(&(it->second[0]), (uint)it->second.size(), _MsPerTick);\n\t\t++k;\n\t}\n\n\t// 3 ) sort statistics\n\tif (criterion != NoSort)\n\t{\n\t\tCStatSorter sorter(criterion);\n\t\tstd::sort(statsPtr.begin(), statsPtr.end(), sorter);\n\t}\n\n\t// 4 ) get root total time.\n\tCStats\trootStats;\n\trootStats.buildFromNode( &_RootNode, _MsPerTick);\n\n\t// 5 ) display statistics\n\tuint maxNodeLength = 0;\n\tstd::string format;\n\tif (displayInline)\n\t{\n\t\tfor(TTimerStatPtrVect::iterator statIt = statsPtr.begin(); statIt != statsPtr.end(); ++statIt)\n\t\t{\n\t\t\tmaxNodeLength = std::max(maxNodeLength, (uint)strlen((*statIt)->Timer->_Name));\n\t\t}\n\t\tformat = \"HTIMER: %-\" + NLMISC::toString(maxNodeLength + 1) + \"s %s\";\n\t}\n\tstd::string statsInline;\n\n\tlog->displayRawNL(format.c_str(), \"\", \" |      total |      local |       visits |  loc%/ glb% | sessn max |       min |       max |      mean\");\n\n\tfor(TTimerStatPtrVect::iterator statIt = statsPtr.begin(); statIt != statsPtr.end(); ++statIt)\n\t{\n\t\tif (!displayInline)\n\t\t{\n\t\t\tlog->displayRawNL(\"HTIMER: =================================\");\n\t\t\tlog->displayRawNL(\"HTIMER: Node %s\", (*statIt)->Timer->_Name);\n\t\t\t(*statIt)->display(log, displayEx, _WantStandardDeviation);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t(*statIt)->getStats(statsInline, displayEx, rootStats.TotalTime, _WantStandardDeviation);\n\t\t\tchar out[2048];\n\t\t\tNLMISC::smprintf(out, 2048, format.c_str(), (*statIt)->Timer->_Name, statsInline.c_str());\n\t\t\tlog->displayRawNL(out);\n\t\t}\n\t}\n\tbenchClock.stop();\n\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n}\n\n//================================================================================================\nvoid\t\tCHTimer::displayByExecutionPath(CLog *log, TSortCriterion criterion, bool displayInline, bool alignPaths, bool displayEx)\n{\n\tCSimpleClock\tbenchClock;\n\tbenchClock.start();\n\tlog->displayRawNL(\"HTIMER: =========================================================================\");\n\tlog->displayRawNL(\"HTIMER: Bench by execution path\");\n\tnlassert(_BenchStartedOnce); // should have done at least one bench\n\t//\n\ttypedef std::vector<CNodeStat>   TNodeStatVect;\n\ttypedef std::vector<CNodeStat *> TNodeStatPtrVect;\n\n\tTNodeStatVect nodeStats;\n\tnodeStats.reserve(_RootNode.getNumNodes());\n\tTNodeVect nodeLeft;\n\tnodeLeft.push_back(&_RootNode);\n\t/// 1 ) walk the tree to build the node map (well, in a not very optimal way..)\n\twhile (!nodeLeft.empty())\n\t{\n\t\tCNode *currNode = nodeLeft.back();\n\n\t\tnodeStats.push_back(CNodeStat());\n\t\tnodeStats.back().buildFromNode(currNode, _MsPerTick);\n\t\tnodeStats.back().Node = currNode;\n\n\t\tnodeLeft.pop_back();\n\t\tnodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());\n\n\t}\n\n\t/// 2 ) sort statistics\n\t// create a pointer list\n\tTNodeStatPtrVect nodeStatsPtrs(nodeStats.size());\n\tfor(uint k = 0; k < nodeStats.size(); ++k)\n\t{\n\t\tnodeStatsPtrs[k] = &nodeStats[k];\n\t}\n\n\t// 3 ) sort statistics\n\tif (criterion != NoSort)\n\t{\n\t\tCStatSorter sorter(criterion);\n\t\tstd::sort(nodeStatsPtrs.begin(), nodeStatsPtrs.end(), sorter);\n\t}\n\n\t// 4 ) get root total time.\n\tCStats\trootStats;\n\trootStats.buildFromNode(&_RootNode, _MsPerTick);\n\n\t// 5 ) display statistics\n\tstd::string statsInline;\n\tstd::string nodePath;\n\n\tstd::string format;\n\tif (displayInline)\n\t{\n\t\tif (alignPaths)\n\t\t{\n\t\t\tuint maxSize = 0;\n\t\t\tstd::string np;\n\t\t\tfor(TNodeStatPtrVect::iterator it = nodeStatsPtrs.begin(); it != nodeStatsPtrs.end(); ++it)\n\t\t\t{\n\t\t\t\t(*it)->Node->getPath(np);\n\t\t\t\tmaxSize = std::max(maxSize, (uint)np.size());\n\t\t\t}\n\t\t\tformat = \"HTIMER: %-\" + NLMISC::toString(maxSize) +\"s %s\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tformat = \"HTIMER: %s %s\";\n\t\t}\n\t}\n\n\tlog->displayRawNL(format.c_str(), \"\", \" |      total |      local |       visits |  loc%/ glb% | sessn max |       min |       max |      mean\");\n\n\tfor(TNodeStatPtrVect::iterator it = nodeStatsPtrs.begin(); it != nodeStatsPtrs.end(); ++it)\n\t{\n\t\tif (!displayInline)\n\t\t{\n\t\t\tlog->displayRawNL(\"HTIMER: =================================\");\n\t\t\t(*it)->Node->displayPath(log);\n\t\t\t(*it)->display(log, displayEx, _WantStandardDeviation);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t(*it)->getStats(statsInline, displayEx, rootStats.TotalTime, _WantStandardDeviation);\n\t\t\t(*it)->Node->getPath(nodePath);\n\n\t\t\tchar out[2048];\n\t\t\tNLMISC::smprintf(out, 2048, format.c_str(), nodePath.c_str(), statsInline.c_str());\n\t\t\tlog->displayRawNL(out);\n\t\t}\n\t}\n\tbenchClock.stop();\n\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n}\n\n//=================================================================\n/*static*/ void CHTimer::displayHierarchical(CLog *log, bool displayEx /*=true*/,uint labelNumChar /*=32*/, uint indentationStep /*= 2*/)\n{\n\tCSimpleClock\tbenchClock;\n\tbenchClock.start();\n\tlog->displayNL(\"HTIMER: =========================================================================\");\n\tlog->displayRawNL(\"HTIMER: Hierarchical display of bench\");\n\tnlassert(_BenchStartedOnce); // should have done at least one bench\n\ttypedef std::map<CHTimer *, TNodeVect> TNodeMap;\n\tTNodeMap nodeMap;\n\tTNodeVect nodeLeft;\n\tnodeLeft.push_back(&_RootNode);\n\t/// 1 ) walk the execution tree to build the node map (well, in a not very optimal way..)\n\twhile (!nodeLeft.empty())\n\t{\n\t\tCNode *currNode = nodeLeft.back();\n\t\tnodeMap[currNode->Owner].push_back(currNode);\n\t\tnodeLeft.pop_back();\n\t\tnodeLeft.insert(nodeLeft.end(), currNode->Sons.begin(), currNode->Sons.end());\n\n\t}\n\tlog->displayRawNL(\"HTIMER: %*s |      total |      local |       visits |  loc%%/ glb%% | sessn max |       min |       max |      mean\", labelNumChar, \"\");\n\n\t/// 2 ) get root total time.\n\tCStats\trootStats;\n\trootStats.buildFromNode(&_RootNode, _MsPerTick);\n\n\t/// 3 ) walk the timers tree and display infos (cumulate infos of nodes of each execution path)\n\tCStats\tcurrNodeStats;\n\tstd::vector<uint> sonsIndex;\n\tuint depth = 0;\n\tCHTimer *currTimer = &_RootTimer;\n\tsonsIndex.push_back(0);\n\tbool displayStat = true;\n\tstd::string resultName;\n\tstd::string resultStats;\n\twhile (!sonsIndex.empty())\n\t{\n\t\tif (displayStat)\n\t\t{\n\t\t\tresultName.resize(labelNumChar);\n\t\t\tstd::fill(resultName.begin(), resultName.end(), '.');\n\t\t\tuint startIndex = depth * indentationStep;\n\t\t\tuint endIndex = std::min(startIndex + (uint)::strlen(currTimer->_Name), labelNumChar);\n\t\t\tif ((sint) (endIndex - startIndex) >= 1)\n\t\t\t{\n\t\t\t\tstd::copy(currTimer->_Name, currTimer->_Name + (endIndex - startIndex), resultName.begin() + startIndex);\n\t\t\t}\n\t\t\tTNodeVect &execNodes = nodeMap[currTimer];\n\t\t\tif (execNodes.size() > 0)\n\t\t\t{\n\t\t\t\tcurrNodeStats.buildFromNodes(&execNodes[0], (uint)execNodes.size(), _MsPerTick);\n\t\t\t\tcurrNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);\n\t\t\t\tlog->displayRawNL(\"HTIMER: %s\", (resultName + resultStats).c_str());\n\t\t\t}\n\t\t}\n\t\tif (sonsIndex.back() == currTimer->_Sons.size())\n\t\t{\n\t\t\tsonsIndex.pop_back();\n\t\t\tcurrTimer = currTimer->_Parent;\n\t\t\tdisplayStat = false;\n\t\t\t-- depth;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcurrTimer = currTimer->_Sons[sonsIndex.back()];\n\t\t\t++ sonsIndex.back();\n\t\t\tsonsIndex.push_back(0);\n\t\t\tdisplayStat = true;\n\t\t\t++ depth;\n\t\t}\n\t}\n\tbenchClock.stop();\n\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n}\n\n\n//=================================================================\n/*static*/ void\t\tCHTimer::displayHierarchicalByExecutionPath(CLog *log, bool displayEx, uint labelNumChar, uint indentationStep)\n{\n\tdisplayHierarchicalByExecutionPathSorted(log, NoSort, displayEx, labelNumChar, indentationStep);\n}\n\n\n//=================================================================\n/*static*/ void\t\tCHTimer::displayHierarchicalByExecutionPathSorted(CLog *log, TSortCriterion criterion, bool displayEx, uint labelNumChar, uint indentationStep)\n{\n\n\tCSimpleClock\tbenchClock;\n\tbenchClock.start();\n\tnlassert(_BenchStartedOnce); // should have done at least one bench\n\n\t// get root total time.\n\tCStats\trootStats;\n\trootStats.buildFromNode(&_RootNode, _MsPerTick);\n\n\n\t// display header.\n\tCLog::TDisplayInfo\tdummyDspInfo;\n\tlog->displayRawNL(\"HTIMER: =========================================================================\");\n\tlog->displayRawNL(\"HTIMER: Hierarchical display of bench by execution path\");\n\tlog->displayRawNL(\"HTIMER: %*s |      total |      local |       visits |  loc%%/ glb%% | sessn max |       min |       max |      mean\", labelNumChar, \"\");\n\n\n\t// use list because vector of vector is bad.\n\tstd::list< CExamStackEntry >\texamStack;\n\n\t// Add the root to the stack.\n\texamStack.push_back( CExamStackEntry( &_RootNode ) );\n\tCStats\t\tcurrNodeStats;\n\tstd::string resultName;\n\tstd::string resultStats;\n\n\twhile (!examStack.empty())\n\t{\n\t\tCNode\t\t\t\t*node = examStack.back().Node;\n\t\tstd::vector<CNode*>\t&children= examStack.back().Children;\n\t\tuint\t\t\t\tchild = examStack.back().CurrentChild;\n\n\t\t// If child 0, then must first build children info and display me.\n\t\tif (child == 0)\n\t\t{\n\t\t\t// Build Sons Infos.\n\t\t\t// ==============\n\n\t\t\t// resize array\n\t\t\tchildren.resize(node->Sons.size());\n\n\t\t\t// If no sort, easy.\n\t\t\tif(criterion == NoSort)\n\t\t\t{\n\t\t\t\tchildren= node->Sons;\n\t\t\t}\n\t\t\t// else, Sort them with criterion.\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::vector<CNodeStat>\t\tstats;\n\t\t\t\tstd::vector<CNodeStat *>\tptrStats;\n\t\t\t\tstats.resize(children.size());\n\t\t\t\tptrStats.resize(children.size());\n\n\t\t\t\t// build stats.\n\t\t\t\tuint\ti;\n\t\t\t\tfor(i=0; i<children.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tCNode\t*childNode= node->Sons[i];\n\t\t\t\t\tstats[i].buildFromNode(childNode, _MsPerTick);\n\t\t\t\t\tstats[i].Node = childNode;\n\t\t\t\t\tptrStats[i]= &stats[i];\n\t\t\t\t}\n\n\t\t\t\t// sort.\n\t\t\t\tCStatSorter\tsorter;\n\t\t\t\tsorter.Criterion= criterion;\n\t\t\t\tstd::sort(ptrStats.begin(), ptrStats.end(), sorter);\n\n\t\t\t\t// fill children.\n\t\t\t\tfor(i=0; i<children.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tchildren[i]= ptrStats[i]->Node;\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\t// Display our infos\n\t\t\t// ==============\n\t\t\t// build the indented node name.\n\t\t\tresultName.resize(labelNumChar);\n\t\t\tstd::fill(resultName.begin(), resultName.end(), '.');\n\t\t\tuint startIndex = (uint)(examStack.size()-1) * indentationStep;\n\t\t\tuint endIndex = std::min(startIndex + (uint)::strlen(node->Owner->_Name), labelNumChar);\n\t\t\tif ((sint) (endIndex - startIndex) >= 1)\n\t\t\t{\n\t\t\t\tstd::copy(node->Owner->_Name, node->Owner->_Name + (endIndex - startIndex), resultName.begin() + startIndex);\n\t\t\t}\n\n\t\t\t// build the stats string.\n\t\t\tcurrNodeStats.buildFromNode(node, _MsPerTick);\n\t\t\tcurrNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);\n\n\t\t\t// display\n\t\t\tlog->displayRawNL(\"HTIMER: %s\", (resultName + resultStats).c_str());\n\t\t}\n\n\t\t// End of sons?? stop.\n\t\tif (child >= children.size())\n\t\t{\n\t\t\texamStack.pop_back();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// next son.\n\t\t++(examStack.back().CurrentChild);\n\n\t\t// process the current son.\n\t\texamStack.push_back( CExamStackEntry( children[child] ) );\n\t}\n\n\t//\n\tbenchClock.stop();\n\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n}\n\n//=================================================================\n/*static*/ void\t\tCHTimer::displaySummary(CLog *log, TSortCriterion criterion, bool displayEx, uint labelNumChar, uint indentationStep, uint maxDepth)\n{\n\n\tCSimpleClock\tbenchClock;\n\tbenchClock.start();\n\tnlassert(_BenchStartedOnce); // should have done at least one bench\n\n\t// get root total time.\n\tCStats\trootStats;\n\trootStats.buildFromNode(&_RootNode, _MsPerTick);\n\n\n\t// display header.\n\tCLog::TDisplayInfo\tdummyDspInfo;\n\tlog->displayRawNL(\"HTIMER: =========================================================================\");\n\tlog->displayRawNL(\"HTIMER: Hierarchical display of bench by execution path\");\n\tlog->displayRawNL(\"HTIMER: %*s |      total |      local |       visits |  loc%%/ glb%% | sessn max |       min |       max |      mean\", labelNumChar, \"\");\n\n\n\t// use list because vector of vector is bad.\n\tstd::list< CExamStackEntry >\texamStack;\n\n\t// Add the root to the stack.\n\texamStack.push_back( CExamStackEntry( &_RootNode ) );\n\tCStats\t\tcurrNodeStats;\n\tstd::string resultName;\n\tstd::string resultStats;\n\n\twhile (!examStack.empty())\n\t{\n\t\tCNode\t\t\t\t*node = examStack.back().Node;\n\t\tstd::vector<CNode*>\t&children= examStack.back().Children;\n\t\tuint\t\t\t\tchild = examStack.back().CurrentChild;\n\t\tuint\t\t\t\tdepth = examStack.back().Depth;\n\n\t\t// If child 0, then must first build children info and display me.\n\t\tif (child == 0)\n\t\t{\n\t\t\t// Build Sons Infos.\n\t\t\t// ==============\n\n\t\t\t// resize array\n\t\t\tchildren.resize(node->Sons.size());\n\n\t\t\t// If no sort, easy.\n\t\t\tif(criterion == NoSort)\n\t\t\t{\n\t\t\t\tchildren= node->Sons;\n\t\t\t}\n\t\t\t// else, Sort them with criterion.\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::vector<CNodeStat>\t\tstats;\n\t\t\t\tstd::vector<CNodeStat *>\tptrStats;\n\t\t\t\tstats.resize(children.size());\n\t\t\t\tptrStats.resize(children.size());\n\n\t\t\t\t// build stats.\n\t\t\t\tuint\ti;\n\t\t\t\tfor(i=0; i<children.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tCNode\t*childNode= node->Sons[i];\n\t\t\t\t\tstats[i].buildFromNode(childNode, _MsPerTick);\n\t\t\t\t\tstats[i].Node = childNode;\n\t\t\t\t\tptrStats[i]= &stats[i];\n\t\t\t\t}\n\n\t\t\t\t// sort.\n\t\t\t\tCStatSorter\tsorter;\n\t\t\t\tsorter.Criterion= criterion;\n\t\t\t\tstd::sort(ptrStats.begin(), ptrStats.end(), sorter);\n\n\t\t\t\t// fill children.\n\t\t\t\tfor(i=0; i<children.size(); i++)\n\t\t\t\t{\n\t\t\t\t\tchildren[i]= ptrStats[i]->Node;\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\t// Display our infos\n\t\t\t// ==============\n\t\t\t// build the indented node name.\n\t\t\tresultName.resize(labelNumChar);\n\t\t\tstd::fill(resultName.begin(), resultName.end(), '.');\n\t\t\tuint startIndex = (uint)(examStack.size()-1) * indentationStep;\n\t\t\tuint endIndex = std::min(startIndex + (uint)::strlen(node->Owner->_Name), labelNumChar);\n\t\t\tif ((sint) (endIndex - startIndex) >= 1)\n\t\t\t{\n\t\t\t\tstd::copy(node->Owner->_Name, node->Owner->_Name + (endIndex - startIndex), resultName.begin() + startIndex);\n\t\t\t}\n\n\t\t\t// build the stats string.\n\t\t\tcurrNodeStats.buildFromNode(node, _MsPerTick);\n\t\t\tcurrNodeStats.getStats(resultStats, displayEx, rootStats.TotalTime, _WantStandardDeviation);\n\n\t\t\t// display\n\t\t\tlog->displayRawNL(\"HTIMER: %s\", (resultName + resultStats).c_str());\n\t\t}\n\n\t\t// End of sons?? stop.\n\t\tif (child >= children.size())\n\t\t{\n\t\t\texamStack.pop_back();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// next son.\n\t\t++(examStack.back().CurrentChild);\n\n\t\t// process the current son.\n\t\tif (depth+1 < maxDepth)\n\t\t\texamStack.push_back( CExamStackEntry( children[child], depth+1 ) );\n\t}\n\n\t//\n\tbenchClock.stop();\n\t_CurrNode->SonsPreambule += benchClock.getNumTicks();\n}\n\n//=================================================================\nvoid\tCHTimer::clear()\n{\n\t// should not be benching !\n\tnlassert(_CurrNode == &_RootNode);\n\t_RootNode.releaseSons();\n\t_CurrNode = &_RootNode;\n\t_RootNode.reset();\n}\n\n//=================================================================\nvoid CHTimer::CStats::buildFromNode(CNode *node, double msPerTick)\n{\n\tbuildFromNodes(&node, 1, msPerTick);\n}\n\n//=================================================================\nvoid CHTimer::CStats::buildFromNodes(CNode **nodes, uint numNodes, double msPerTick)\n{\n\tTotalTime = 0;\n\tTotalTimeWithoutSons = 0;\n\tNumVisits = 0;\n\n\tuint64 minTime = (uint64) -1;\n\tuint64 maxTime = 0;\n\tuint64 sessionMaxTime = 0;\n\n\tuint k, l;\n\tfor(k = 0; k < numNodes; ++k)\n\t{\n\t\tTotalTime += nodes[k]->TotalTime * msPerTick;\n\t\tTotalTimeWithoutSons += (nodes[k]->TotalTime -  nodes[k]->LastSonsTotalTime) * msPerTick;\n\t\tNumVisits += nodes[k]->NumVisits;\n\t\tminTime = std::min(minTime, nodes[k]->MinTime);\n\t\tmaxTime = std::max(maxTime, nodes[k]->MaxTime);\n\t\tsessionMaxTime = std::max(sessionMaxTime, nodes[k]->SessionMax);\n\t}\n\tif (minTime == (uint64) -1)\n\t{\n\t\tminTime = 0;\n\t}\n\tMinTime  = minTime * msPerTick;\n\tMaxTime  = maxTime * msPerTick;\n\tSessionMaxTime = sessionMaxTime * msPerTick;\n\n\tif (NumVisits > 0)\n\t\tMeanTime = TotalTime / NumVisits;\n\telse\n\t\tMeanTime = 0.0;\n\n\t// compute standard deviation\n\tdouble varianceSum = 0;\n\tuint   numMeasures = 0;\n\tfor(k = 0; k < numNodes; ++k)\n\t{\n\t\tnumMeasures += (uint)nodes[k]->Measures.size();\n\t\tfor(l = 0; l < nodes[k]->Measures.size(); ++l)\n\t\t{\n\t\t\tvarianceSum += NLMISC::sqr(nodes[k]->Measures[l] - MeanTime);\n\t\t}\n\t}\n\tTimeStandardDeviation = numMeasures == 0 ? 0\n\t\t\t\t\t\t\t\t\t\t\t : ::sqrt(varianceSum / (numMeasures +1));\n}\n\n//=================================================================\nvoid CHTimer::CStats::display(CLog *log, bool displayEx, bool wantStandardDeviation /* = false*/)\n{\n\tlog->displayRawNL(\"HTIMER: Total time                = %.3f ms\", (float) TotalTime);\n\tlog->displayRawNL(\"HTIMER: Total time without sons   = %.3f ms\", (float) TotalTimeWithoutSons);\n\tlog->displayRawNL((\"HTIMER: Num visits                = \" + NLMISC::toString(NumVisits)).c_str());\n\tif (displayEx)\n\t{\n\t\t\tlog->displayRawNL(\"HTIMER: Min time                  = %.3f ms\", (float) MinTime);\n\t\t\tlog->displayRawNL(\"HTIMER: Max time                  = %.3f ms\", (float) MaxTime);\n\t\t\tlog->displayRawNL(\"HTIMER: Mean time                 = %.3f ms\", (float) MeanTime);\n\t\t\tif (wantStandardDeviation)\n\t\t\t{\n\t\t\tlog->displayRawNL(\"HTIMER: Standard deviation        = %.3f ms\", (float) TimeStandardDeviation);\n\t\t\t}\n\t\t\tlog->displayRawNL(\"HTIMER: Session Max time          = %.3f ms\", (float) SessionMaxTime);\n\t\t\t//log->displayRawNL(\"Time standard deviation\t= %.3f ms\", (float) TimeStandardDeviation);\n\t}\n}\n\n\n//=================================================================\nvoid CHTimer::CStats::getStats(std::string &dest, bool statEx, double rootTotalTime, bool wantStandardDeviation /*= false*/)\n{\n\tchar buf[1024];\n\tif (!wantStandardDeviation)\n\t{\n\t\tif (!statEx)\n\t\t{\n\t\t\tNLMISC::smprintf(buf, 1024, \" | %10.3f | %10.3f | %12s \", (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNLMISC::smprintf(buf, 1024, \" | %10.3f | %10.3f | %12s | %5.1f/%5.1f | %9.3f | %9.3f | %9.3f | %9.3f\",\n\t\t\t\t\t  (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(),\n\t\t\t\t\t  float(100*TotalTimeWithoutSons/rootTotalTime), float(100*TotalTime/rootTotalTime),\n\t\t\t\t\t  (float) SessionMaxTime,\n\t\t\t\t\t  (float) MinTime, (float) MaxTime, (float) MeanTime\n\t\t\t\t\t );\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (!statEx)\n\t\t{\n\t\t\tNLMISC::smprintf(buf, 1024, \" | %10.3f | %10.3f | %12s | std deviation %9.3f\", (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(), (float) TimeStandardDeviation);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNLMISC::smprintf(buf, 1024, \" | %10.3f | %10.3f | %12s | %5.1f/%5.1f | %9.3f | %9.3f | %9.3f | %9.3f | std deviation %9.3f\",\n\t\t\t\t\t\t\t  (float) TotalTime, (float) TotalTimeWithoutSons, toString(NumVisits).c_str(),\n\t\t\t\t\t\t\t  float(100*TotalTimeWithoutSons/rootTotalTime), float(100*TotalTime/rootTotalTime),\n\t\t\t\t\t\t\t  (float) SessionMaxTime,\n\t\t\t\t\t\t\t  (float) MinTime, (float) MaxTime, (float) MeanTime,\n\t\t\t\t\t\t\t  (float) TimeStandardDeviation\n\t\t\t\t\t\t\t);\n\t\t}\n\t}\n\tdest = buf;\n}\n\n\n//=================================================================\nbool CHTimer::CStatSorter::operator()(const CHTimer::CStats *lhs, const CHTimer::CStats *rhs)\n{\n\tswitch(Criterion)\n\t{\n\t\tcase CHTimer::TotalTime:\t\t\t\treturn lhs->TotalTime >= rhs->TotalTime;\n\t\tcase CHTimer::TotalTimeWithoutSons:\t\treturn lhs->TotalTimeWithoutSons >= rhs->TotalTimeWithoutSons;\n\t\tcase CHTimer::MeanTime:\t\t\t\t\treturn lhs->MeanTime >= rhs->MeanTime;\n\t\tcase CHTimer::NumVisits:\t\t\t\treturn lhs->NumVisits >= rhs->NumVisits;\n\t\tcase CHTimer::MaxTime:\t\t\t\t\treturn lhs->MaxTime >= rhs->MaxTime;\n\t\tcase CHTimer::MinTime:\t\t\t\t\treturn lhs->MinTime < rhs->MinTime;\n\t\tcase CHTimer::MaxSession:\t\t\t\treturn lhs->SessionMaxTime > rhs->SessionMaxTime;\n\t\tdefault:\n\t\t\tnlassert(0); // not a valid criterion\n\t\tbreak;\n\t}\n\treturn false;\n}\n\n\n//===============================================\nvoid\tCHTimer::doBefore()\n{\n\t_PreambuleClock.start();\n\twalkTreeToCurrent();\n\t++ _CurrNode->NumVisits;\n\t_CurrNode->SonsPreambule = 0;\n\tif (!_Parent && _CurrTimer != this)\n\t{\n\t\t_Parent = _CurrTimer;\n\t\t// register as a son of the parent\n\t\t_Parent->_Sons.push_back(this);\n\t}\n\t_CurrTimer = this;\n\t_PreambuleClock.stop();\n\tif (_CurrNode->Parent)\n\t{\n\t\t_CurrNode->Parent->SonsPreambule += _PreambuleClock.getNumTicks();\n\t}\n\t_CurrNode->Clock.start();\n}\n\n//===============================================\nvoid\tCHTimer::doAfter(bool displayAfter)\n{\n\t_CurrNode->Clock.stop();\n\t_PreambuleClock.start();\n\t/* Remove my Son preambule, and remove only ONE StartStop\n\t\tIt is because between the start and the end, only ONE rdtsc time is counted:\n\t*/\n\tsint64 numTicks = _CurrNode->Clock.getNumTicks()  - _CurrNode->SonsPreambule - (CSimpleClock::getStartStopNumTicks());\n\t// Case where the SonPreambule is overestimated,\n\tnumTicks= std::max((sint64)0, numTicks);\n\t// In case where the SonPreambule is overestimated, the TotalTime must not be < of the SonTime\n\tif(_CurrNode->TotalTime + numTicks < _CurrNode->SonsTotalTime)\n\t\tnumTicks= _CurrNode->SonsTotalTime - _CurrNode->TotalTime;\n\n\t_CurrNode->TotalTime += numTicks;\n\t_CurrNode->MinTime = std::min(_CurrNode->MinTime, (uint64)numTicks);\n\t_CurrNode->MaxTime = std::max(_CurrNode->MaxTime, (uint64)numTicks);\n\t_CurrNode->LastSonsTotalTime = _CurrNode->SonsTotalTime;\n\n\t_CurrNode->SessionCurrent += (uint64)numTicks;\n\n\tif (displayAfter)\n\t{\n\t\tnlinfo(\"HTIMER: %s %.3fms loop number %d\", _Name, numTicks * _MsPerTick, _CurrNode->NumVisits);\n\t}\n\t//\n\tif (_WantStandardDeviation)\n\t{\n\t\t_CurrNode->Measures.push_back(numTicks * _MsPerTick);\n\t}\n\t//\n\tif (_Parent)\n\t{\n\t\t_CurrTimer = _Parent;\n\t}\n\t//\n\tif (_CurrNode->Parent)\n\t{\n\t\tCNode\t*curNode= _CurrNode;\n\t\tCNode\t*parent= _CurrNode->Parent;\n\t\tparent->SonsTotalTime += numTicks;\n\t\t_PreambuleClock.stop();\n\t\t/*\n\t\t\tThe SonPreambule of my parent is\n\t\t\t\t+ my BeforePreambule (counted in doBefore)\n\t\t\t\t+ my Afterpreambule (see below)\n\t\t\t\t+ my Sons Preambule\n\t\t\t\t+ some constant time due to the Start/Stop of the _CurrNode->Clock, the 2* Start/Stop\n\t\t\t\t\tof the PreabmuleClock, the function call time of doBefore and doAfter\n\t\t*/\n\t\tparent->SonsPreambule += _PreambuleClock.getNumTicks() + curNode->SonsPreambule + _AfterStopEstimateTime;\n\t\t// walk to parent\n\t\t_CurrNode= parent;\n\t}\n\telse\n\t{\n\t\t_PreambuleClock.stop();\n\t}\n}\n\n\n\n\n/*\n * Clears SessionMax current stats (only current value)\n */\nvoid\tCHTimer::clearSessionCurrent()\n{\n\t_RootNode.resetSessionCurrent();\n}\n\n/*\n * Clears all SessionMax stats (max and current values)\n */\nvoid\tCHTimer::clearSessionStats()\n{\n\t_RootNode.resetSessionStats();\n}\n\n/*\n * Update session stats\n */\nvoid\tCHTimer::updateSessionStats()\n{\n\tif (_RootNode.SessionCurrent > _RootNode.SessionMax)\n\t\t_RootNode.spreadSession();\n}\n\n\n\n\n//\n// Commands\n//\n\n#define\tCASE_DISPLAYMEASURES(crit, alternative)\t\\\n\tif (args[0] == #crit || depth == alternative)\t\\\n\t{\t\\\n\t\tCHTimer::TSortCriterion\tcriterion = CHTimer::crit;\t\\\n\t\tif (hasDepth && depth != alternative)\t\\\n\t\t\tCHTimer::displaySummary(&log, criterion, true, 64, 2, depth);\t\\\n\t\telse\t\\\n\t\t\tCHTimer::display(&log, criterion);\t\\\n\t}\t\\\n\telse\n\nNLMISC_CATEGORISED_COMMAND(nel,displayMeasures, \"display hierarchical timer\", \"[TotalTime(=-2)|NoSort(=-3)|TotalTimeWithoutSons(=-4)|MeanTime(=-5)|NumVisits(=-6)|MaxTime(=-7)|MinTime(=-8)|MaxSession(=-9)] [depth]\")\n{\n\tif (args.size() < 1)\n\t{\n\t\tCHTimer::display(&log);\n\t\tCHTimer::displayHierarchicalByExecutionPathSorted (&log, CHTimer::TotalTime, true, 64);\n\t\treturn true;\n\t}\n\n\tsint\tdepth = 0;\n\tbool\thasDepth = (sscanf(args[0].c_str(), \"%d\", &depth) == 1 || (args.size() > 1 && sscanf(args[1].c_str(), \"%d\", &depth) == 1));\n\n\tCASE_DISPLAYMEASURES(NoSort, -3)\n\tCASE_DISPLAYMEASURES(TotalTime, -2)\n\tCASE_DISPLAYMEASURES(TotalTimeWithoutSons, -4)\n\tCASE_DISPLAYMEASURES(MeanTime, -5)\n\tCASE_DISPLAYMEASURES(NumVisits, -6)\n\tCASE_DISPLAYMEASURES(MaxTime, -7)\n\tCASE_DISPLAYMEASURES(MinTime, -8)\n\tCASE_DISPLAYMEASURES(MaxSession, -9)\n\t{\n\t\tif (hasDepth)\n\t\t\tCHTimer::displaySummary(&log, CHTimer::TotalTime, true, 64, 2, depth);\n\t\telse\n\t\t\tCHTimer::display(&log, CHTimer::TotalTime);\n\t}\n\n\treturn true;\n}\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/i18n.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/path.h\"\n#include \"nel/misc/i18n.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nCI18N::StrMapContainer\tCI18N::_StrMap;\nCI18N::StrMapContainer\tCI18N::_StrMapFallback;\nbool\t\t\t\t\tCI18N::_StrMapLoaded = false;\nconst ucstring\t\t\tCI18N::_NotTranslatedValue(\"<Not Translated>\");\nbool\t\t\t\t\tCI18N::_LanguagesNamesLoaded = false;\nstring\t\t\t\t\tCI18N::_SelectedLanguageCode;\nCI18N::ILoadProxy\t\t*CI18N::_LoadProxy = 0;\nvector<string>\t\t\tCI18N::_LanguageCodes;\nvector<ucstring>\t\tCI18N::_LanguageNames;\nbool CI18N::noResolution = false;\n\nvoid CI18N::setLoadProxy(ILoadProxy *loadProxy)\n{\n\t_LoadProxy = loadProxy;\n}\n\nvoid CI18N::initLanguages()\n{\n\tif (!_LanguagesNamesLoaded)\n\t{\n\t\t_LanguageCodes.push_back(\"en\");\n\t\t_LanguageCodes.push_back(\"fr\");\n\t\t_LanguageCodes.push_back(\"de\");\n\t\t_LanguageCodes.push_back(\"ru\");\n\n\t\t_LanguageNames.push_back(ucstring(\"English\"));\n\t\t_LanguageNames.push_back(ucstring(\"French\"));\n\t\t_LanguageNames.push_back(ucstring(\"German\"));\n\t\t_LanguageNames.push_back(ucstring(\"Russian\"));\n\n\t\t_LanguagesNamesLoaded = true;\n\t}\n}\n\nconst std::vector<ucstring> &CI18N::getLanguageNames()\n{\n\tinitLanguages();\n\n\treturn _LanguageNames;\n}\n\nconst std::vector<std::string> &CI18N::getLanguageCodes()\n{\n\tinitLanguages();\n\n\treturn _LanguageCodes;\n}\n\nvoid CI18N::load (const string &languageCode, const string &fallbackLanguageCode)\n{\n\tif (_StrMapLoaded)\t_StrMap.clear ();\n\telse\t\t\t\t_StrMapLoaded = true;\n\t_SelectedLanguageCode = languageCode;\n\tloadFileIntoMap(languageCode + \".uxt\", _StrMap);\n\n\t_StrMapFallback.clear();\n\tif(!fallbackLanguageCode.empty())\n\t{\n\t\tloadFileIntoMap(fallbackLanguageCode + \".uxt\", _StrMapFallback);\n\t}\n}\n\nbool CI18N::loadFileIntoMap(const string &fileName, StrMapContainer &destMap)\n{\n\tucstring text;\n\t// read in the text\n\tif (_LoadProxy)\n\t\t_LoadProxy->loadStringFile(fileName, text);\n\telse\n\t\treadTextFile(fileName, text);\n\n\t// remove any comment\n\tremoveCComment(text);\n\n\tucstring::const_iterator first(text.begin()), last(text.end());\n\tstring lastReadLabel(\"nothing\");\n\n\twhile (first != last)\n\t{\n\t\tskipWhiteSpace(first, last);\n\t\tstring label;\n\t\tucstring ucs;\n\t\tif (!parseLabel(first, last, label))\n\t\t{\n\t\t\tnlwarning(\"I18N: Error reading label field in %s. Stop reading after %s.\", fileName.c_str(), lastReadLabel.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tlastReadLabel = label;\n\t\tskipWhiteSpace(first, last);\n\t\tif (!parseMarkedString('[', ']', first, last, ucs))\n\t\t{\n\t\t\tnlwarning(\"I18N: Error reading text for label %s in %s. Stop reading.\", label.c_str(), fileName.c_str());\n\t\t\treturn false;\n\t\t}\n\n\t\t// ok, a line read.\n\t\tpair<map<string, ucstring>::iterator, bool> ret;\n\t\tret = destMap.insert(make_pair(label, ucs));\n\t\tif (!ret.second)\n\t\t{\n\t\t\tnlwarning(\"I18N: Error in %s, the label %s exists twice !\", fileName.c_str(), label.c_str());\n\t\t}\n\t\tskipWhiteSpace(first, last);\n\t}\n\n\t// a little check to ensure that the lang name has been set.\n\tStrMapContainer::iterator it(destMap.find(\"LanguageName\"));\n\tif (it == destMap.end())\n\t{\n\t\tnlwarning(\"I18N: In file %s, missing LanguageName translation (should be first in file)\", fileName.c_str());\n\t}\n\treturn true;\n}\n\nvoid CI18N::loadFromFilename(const string &filename, bool reload)\n{\n\tStrMapContainer destMap;\n\tif (!loadFileIntoMap(filename, destMap))\n\t{\n\t\treturn;\n\t}\n\t// merge with existing map\n\tfor(StrMapContainer::iterator it = destMap.begin(); it != destMap.end(); ++it)\n\t{\n\t\tif (!reload)\n\t\t{\n\t\t\tif (_StrMap.count(it->first))\n\t\t\t{\n\t\t\t\tnlwarning(\"I18N: Error in %s, the label %s exist twice !\", filename.c_str(), it->first.c_str());\n\t\t\t}\n\t\t}\n\t\t_StrMap[it->first] = it->second;\n\t}\n}\n\nconst ucstring &CI18N::get (const string &label)\n{\n\tif( noResolution )\n\t{\n\t\tstatic ucstring labelString;\n\t\tlabelString = label;\n\t\treturn labelString;\n\t}\n\n\tif (label.empty())\n\t{\n\t\tstatic ucstring\temptyString;\n\t\treturn emptyString;\n\t}\n\n\tStrMapContainer::iterator it(_StrMap.find(label));\n\n\tif (it != _StrMap.end())\n\t\treturn it->second;\n\n\tstatic CHashSet<string>\tmissingStrings;\n\tif (missingStrings.find(label) == missingStrings.end())\n\t{\n\t\tnlwarning(\"I18N: The string %s did not exist in language %s (display once)\", label.c_str(), _SelectedLanguageCode.c_str());\n\t\tmissingStrings.insert(label);\n\t}\n\n\t// use the fall back language if it exists\n\tit = _StrMapFallback.find(label);\n\tif (it != _StrMapFallback.end())\n\t\treturn it->second;\n\n\tstatic ucstring\tbadString;\n\n\tbadString = ucstring(string(\"<NotExist:\")+label+\">\");\n\n\treturn badString;\n}\n\nbool CI18N::hasTranslation(const string &label)\n{\n\tif (label.empty()) return true;\n\n\tif(_StrMap.find(label) != _StrMap.end())\n\t\t\treturn true;\n\n\t// use the fall back language if it exists\n\tif (_StrMapFallback.find(label) != _StrMapFallback.end())\n\t\treturn true;\n\n\treturn false;\n}\n\nucstring CI18N::getCurrentLanguageName ()\n{\n\treturn get(\"LanguageName\");\n}\n\nstring CI18N::getCurrentLanguageCode ()\n{\n\treturn _SelectedLanguageCode;\n}\n\nvoid CI18N::removeCComment(ucstring &commentedString)\n{\n\tucstring temp;\n\ttemp.reserve(commentedString.size());\n\tucstring::const_iterator first(commentedString.begin()), last(commentedString.end());\n\tfor (;first != last; ++first)\n\t{\n\t\ttemp.push_back(*first);\n\t\tif (*first == '[')\n\t\t{\n\t\t\t// no comment inside string literal\n\t\t\twhile (++first != last)\n\t\t\t{\n\t\t\t\ttemp.push_back(*first);\n\t\t\t\tif (*first == ']')\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if (*first == '/')\n\t\t{\n\t\t\t// start of comment ?\n\t\t\t++first;\n\t\t\tif (first != last && *first == '/')\n\t\t\t{\n\t\t\t\ttemp.resize(temp.size()-1);\n\t\t\t\t// one line comment, skip until end of line\n\t\t\t\twhile (first != last && *first != '\\n')\n\t\t\t\t\t++first;\n\t\t\t}\n\t\t\telse if (first != last && *first == '*')\n\t\t\t{\n\t\t\t\ttemp.resize(temp.size()-1);\n\t\t\t\t// start of multi line comment, skip until we found '*/'\n\t\t\t\twhile (first != last && !(*first == '*' && (first+1) != last && *(first+1) == '/'))\n\t\t\t\t\t++first;\n\t\t\t\t// skip the closing '/'\n\t\t\t\tif (first != last)\n\t\t\t\t\t++first;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttemp.push_back(*first);\n\t\t\t}\n\t\t}\n\t}\n\tcommentedString.swap(temp);\n}\n\nvoid CI18N::skipWhiteSpace(ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring *storeComments, bool newLineAsWhiteSpace)\n{\n\twhile (it != last &&\n\t\t\t(\n\t\t\t\t\t(*it == 0xa && newLineAsWhiteSpace)\n\t\t\t\t||\t(*it == 0xd && newLineAsWhiteSpace)\n\t\t\t\t||\t*it == ' '\n\t\t\t\t||\t*it == '\\t'\n\t\t\t\t||\t(storeComments && *it == '/' && it+1 != last && *(it+1) == '/')\n\t\t\t\t||\t(storeComments && *it == '/' && it+1 != last && *(it+1) == '*')\n\t\t\t))\n\t{\n\t\tif (storeComments && *it == '/' && it+1 != last && *(it+1) == '/')\n\t\t{\n\t\t\t// found a one line C comment. Store it until end of line.\n\t\t\twhile (it != last && *it != '\\n')\n\t\t\t\tstoreComments->push_back(*it++);\n\t\t\t// store the final '\\n'\n\t\t\tif (it != last)\n\t\t\t\tstoreComments->push_back(*it++);\n\t\t}\n\t\telse if (storeComments && *it == '/' && it+1 != last && *(it+1) == '*')\n\t\t{\n\t\t\t// found a multi line C++ comment. store until we found the closing '*/'\n\t\t\twhile (it != last && !(*it == '*' && it+1 != last && *(it+1) == '/'))\n\t\t\t\tstoreComments->push_back(*it++);\n\t\t\t// store the final '*'\n\t\t\tif (it != last)\n\t\t\t\tstoreComments->push_back(*it++);\n\t\t\t// store the final '/'\n\t\t\tif (it != last)\n\t\t\t\tstoreComments->push_back(*it++);\n\t\t\t// and a new line.\n\t\t\tstoreComments->push_back('\\r');\n\t\t\tstoreComments->push_back('\\n');\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// just skip white space or don't store comments\n\t\t\t++it;\n\t\t}\n\t}\n}\n\nbool CI18N::parseLabel(ucstring::const_iterator &it, ucstring::const_iterator &last, string &label)\n{\n\tucstring::const_iterator rewind = it;\n\tlabel.erase();\n\n\t// first char must be A-Za-z@_\n\tif (it != last &&\n\t\t\t(\n\t\t\t\t(*it >= '0' && *it <= '9')\n\t\t\t||\t(*it >= 'A' && *it <= 'Z')\n\t\t\t||\t(*it >= 'a' && *it <= 'z')\n\t\t\t||\t(*it == '_')\n\t\t\t||\t(*it == '@')\n\t\t\t)\n\t\t)\n\t\tlabel.push_back(char(*it++));\n\telse\n\t{\n\t\tit = rewind;\n\t\treturn false;\n\t}\n\n\t// other char must be [0-9A-Za-z@_]*\n\twhile (it != last &&\n\t\t\t(\n\t\t\t\t(*it >= '0' && *it <= '9')\n\t\t\t||\t(*it >= 'A' && *it <= 'Z')\n\t\t\t||\t(*it >= 'a' && *it <= 'z')\n\t\t\t||\t(*it == '_')\n\t\t\t||\t(*it == '@')\n\t\t\t)\n\t\t)\n\t\tlabel.push_back(char(*it++));\n\n\treturn true;\n}\n\nbool CI18N::parseMarkedString(ucchar openMark, ucchar closeMark, ucstring::const_iterator &it, ucstring::const_iterator &last, ucstring &result, uint32 *lineCounter, bool allowNewline)\n{\n\tresult.erase();\n\n\t// parse a string delimited by the specified opening and closing mark\n\tif (it != last && *it == openMark)\n\t{\n\t\t++it;\n\n\t\twhile (it != last && *it != closeMark && (allowNewline || *it != '\\n'))\n\t\t{\n\t\t\t// ignore tab, new lines and line feed\n\t\t\tif (*it == openMark)\n\t\t\t{\n\t\t\t\tnlwarning(\"I18N: Found a non escaped openmark %c in a delimited string (Delimiters : '%c' - '%c')\", char(openMark), char(openMark), char(closeMark));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (*it == '\\t'\n\t\t\t\t|| (*it == '\\n' && allowNewline)\n\t\t\t\t|| *it == '\\r')\n\t\t\t\t++it;\n\t\t\telse if (*it == '\\\\' && it+1 != last && *(it+1) != '\\\\')\n\t\t\t{\n\t\t\t\t++it;\n\t\t\t\t// this is an escape sequence !\n\t\t\t\tswitch(*it)\n\t\t\t\t{\n\t\t\t\tcase 't':\n\t\t\t\t\tresult.push_back('\\t');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'n':\n\t\t\t\t\tresult.push_back('\\n');\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'd':\n\t\t\t\t\t// insert a delete\n\t\t\t\t\tresult.push_back(8);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// escape the close mark ?\n\t\t\t\t\tif(*it == closeMark)\n\t\t\t\t\t\tresult.push_back(closeMark);\n\t\t\t\t\t// escape the open mark ?\n\t\t\t\t\telse if(*it == openMark)\n\t\t\t\t\t\tresult.push_back(openMark);\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning(\"I18N: Ignoring unknown escape code \\\\%c (char value : %u)\", char(*it), *it);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t++it;\n\t\t\t}\n\t\t\telse if (*it == '\\\\' && it+1 != last && *(it+1) == '\\\\')\n\t\t\t{\n\t\t\t\t// escape the \\ char\n\t\t\t\t++it;\n\t\t\t\tresult.push_back(*it);\n\t\t\t\t++it;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (*it == '\\n' && lineCounter != NULL)\n\t\t\t\t\t// update line counter\n\t\t\t\t\t++(*lineCounter);\n\n\t\t\t\tresult.push_back(*it++);\n\t\t\t}\n\t\t}\n\n\t\tif (it == last || *it != closeMark)\n\t\t{\n\t\t\tnlwarning(\"I18N: Missing end of delimited string (Delimiters : '%c' - '%c')\", char(openMark), char(closeMark));\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\t++it;\n\t}\n\telse\n\t{\n\t\tnlwarning(\"I18N: Malformed or non existent delimited string (Delimiters : '%c' - '%c')\", char(openMark), char(closeMark));\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid CI18N::readTextFile(const string &filename,\n\t\t\t\t\t\t ucstring &result,\n\t\t\t\t\t\t bool forceUtf8,\n\t\t\t\t\t\t bool fileLookup,\n\t\t\t\t\t\t bool preprocess,\n\t\t\t\t\t\t TLineFormat lineFmt,\n\t\t\t\t\t\t bool warnIfIncludesNotFound)\n{\n\t// create the read context\n\tTReadContext readContext;\n\n\t// call the inner function\n\t_readTextFile(filename, result, forceUtf8, fileLookup, preprocess, lineFmt, warnIfIncludesNotFound, readContext);\n\n\tif (!readContext.IfStack.empty())\n\t{\n\t\tnlwarning(\"Preprocess: Missing %u closing #endif after parsing %s\", readContext.IfStack.size(), filename.c_str() );\n\t}\n}\n\nbool CI18N::matchToken(const char* token, ucstring::const_iterator &it, ucstring::const_iterator end)\n{\n\tucstring::const_iterator rewind = it;\n\tskipWhiteSpace(it, end, NULL, false);\n\twhile (it != end && *token != 0 && *it == *token)\n\t{\n\t\t++it;\n\t\t++token;\n\t}\n\n\tif (*token == 0)\n\t{\n\t\t// we fund the token\n\t\treturn true;\n\t}\n\n\t// not found\n\tit = rewind;\n\treturn false;\n}\n\nvoid CI18N::skipLine(ucstring::const_iterator &it, ucstring::const_iterator end, uint32 &lineCounter)\n{\n\twhile (it != end && *it != '\\n')\n\t\t++it;\n\n\tif (it != end)\n\t{\n\t\t++lineCounter;\n\t\t++it;\n\t}\n}\n\nvoid CI18N::_readTextFile(const string &filename,\n\t\t\t\t\t\t ucstring &result,\n\t\t\t\t\t\t bool forceUtf8,\n\t\t\t\t\t\t bool fileLookup,\n\t\t\t\t\t\t bool preprocess,\n\t\t\t\t\t\t TLineFormat lineFmt,\n\t\t\t\t\t\t bool warnIfIncludesNotFound,\n\t\t\t\t\t\t TReadContext &readContext)\n{\n\tstring fullName;\n\tif (fileLookup)\n\t\tfullName = CPath::lookup(filename, false,warnIfIncludesNotFound);\n\telse\n\t\tfullName = filename;\n\n\tif (fullName.empty())\n\t\treturn;\n\n\t// If ::lookup is used, the file can be in a bnp and CFile::fileExists fails.\n\tbool isInBnp = fullName.find('@') != string::npos;\n\tif (!isInBnp && !CFile::fileExists(fullName))\n\t{\n\t\tnlwarning(\"CI18N::readTextFile : file '%s' does not exist, returning empty string\", fullName.c_str());\n\t\treturn;\n\t}\n\n\tNLMISC::CIFile\tfile(fullName);\n\n\t// Fast read all the text in binary mode.\n\tstring text;\n\ttext.resize(file.getFileSize());\n\tif (file.getFileSize() > 0)\n\t\tfile.serialBuffer((uint8*)(&text[0]), (uint)text.size());\n\n\t// Transform the string in ucstring according to format header\n\tif (!text.empty())\n\t\treadTextBuffer((uint8*)&text[0], (uint)text.size(), result, forceUtf8);\n\n\tif (preprocess)\n\t{\n\t\t// a string to old the result of the preprocess\n\t\tucstring final;\n\t\t// make rooms to reduce allocation cost\n\t\tfinal.reserve(raiseToNextPowerOf2((uint)result.size()));\n\n\t\t// parse the file, looking for preprocessor command.\n\t\tucstring::const_iterator it(result.begin()), end(result.end());\n\n\t\t// input line counter\n\t\tuint32 currentLine = 1;\n\n\t\t// set the current file and line info\n\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\n\t\twhile (it != end)\n\t\t{\n\t\t\t// remember the begin of the line\n\t\t\tucstring::const_iterator beginOfLine = it;\n\n\t\t\t// advance in the line, looking for a preprocessor command\n\t\t\tskipWhiteSpace(it, end, NULL, false);\n\n\t\t\tif (it != end && *it == '#')\n\t\t\t{\n\t\t\t\t// skip the '#' symbol\n\t\t\t\t++it;\n\t\t\t\t// we found a preprocessor command !\n\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\n\t\t\t\tif (matchToken(\"include\", it, end))\n\t\t\t\t{\n\t\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t\t{\n\t\t\t\t\t\t// we have an include command\n\t\t\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\n\t\t\t\t\t\t// read the file name between quote\n\t\t\t\t\t\tucstring str;\n\t\t\t\t\t\tbreakable\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!parseMarkedString(ucchar('\\\"'), ucchar('\\\"'), it, end, str, &currentLine, false))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error parsing include file command\", filename.c_str(), currentLine);\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// ok, read the subfile\n\t\t\t\t\t\t\t\tstring subFilename = str.toString();\n\n\t\t\t\t\t\t\t\t// check is file exist\n\t\t\t\t\t\t\t\tif (!CFile::fileExists(subFilename))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// look for the file relative to current file\n\t\t\t\t\t\t\t\t\tsubFilename = CFile::getPath(filename)+subFilename;\n\t\t\t\t\t\t\t\t\tif (!CFile::fileExists(subFilename))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// the include file is not found, issue a warning\n\t\t\t\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Cannot include file '%s'\",\n\t\t\t\t\t\t\t\t\t\t\tfilename.c_str(), currentLine,\n\t\t\t\t\t\t\t\t\t\t\tstr.toString().c_str());\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tnlinfo(\"Preprocess: In file %s(%u) : Including '%s'\",\n\t\t\t\t\t\t\t\t\tfilename.c_str(), currentLine,\n\t\t\t\t\t\t\t\t\tsubFilename.c_str());\n\n\t\t\t\t\t\t\t\tucstring inserted;\n\t\t\t\t\t\t\t\t_readTextFile(subFilename, inserted, forceUtf8, fileLookup, preprocess, lineFmt, warnIfIncludesNotFound, readContext);\n\t\t\t\t\t\t\t\tfinal += inserted;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// advance to next line\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t\t// reset filename and line counter\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (matchToken(\"optional\", it, end))\n\t\t\t\t{\n\t\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t\t{\n\t\t\t\t\t\t// we have an optional include command\n\t\t\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\n\t\t\t\t\t\t// read the file name between quote\n\t\t\t\t\t\tucstring str;\n\t\t\t\t\t\tbreakable\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (!parseMarkedString('\\\"', '\\\"', it, end, str, &currentLine, false))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error parsing optional file command\", filename.c_str(), currentLine);\n\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// ok, read the subfile\n\t\t\t\t\t\t\t\tstring subFilename = str.toString();\n\n\t\t\t\t\t\t\t\t// check is file exist\n\t\t\t\t\t\t\t\tif (!CFile::fileExists(subFilename))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// look for the file relative to current file\n\t\t\t\t\t\t\t\t\tsubFilename = CFile::getPath(filename)+subFilename;\n\t\t\t\t\t\t\t\t\tif (!CFile::fileExists(subFilename))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// not found but optional, only emit a debug log\n\t\t\t\t\t\t\t\t\t\t// the include file is not found, issue a warning\n\t\t\t\t\t\t\t\t\t\tnldebug(\"Preprocess: In file %s(%u) : Cannot include optional file '%s'\",\n\t\t\t\t\t\t\t\t\t\t\tfilename.c_str(), currentLine,\n\t\t\t\t\t\t\t\t\t\t\tstr.toString().c_str());\n\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tnlinfo(\"Preprocess: In file %s(%u) : Including optional '%s'\",\n\t\t\t\t\t\t\t\t\tfilename.c_str(), currentLine,\n\t\t\t\t\t\t\t\t\tsubFilename.c_str());\n\n\t\t\t\t\t\t\t\tucstring inserted;\n\t\t\t\t\t\t\t\t_readTextFile(subFilename, inserted, forceUtf8, fileLookup, preprocess, lineFmt, warnIfIncludesNotFound, readContext);\n\t\t\t\t\t\t\t\tfinal += inserted;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// advance to next line\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t\t// reset filename and line counter\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (matchToken(\"define\", it, end))\n\t\t\t\t{\n\t\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t\t{\n\t\t\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\n\t\t\t\t\t\tstring label;\n\t\t\t\t\t\tif (parseLabel(it, end, label))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (readContext.Defines.find(label) != readContext.Defines.end())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnlinfo(\"Preprocess: In file %s(%u) : symbol '%s' already defined\",\n\t\t\t\t\t\t\t\t\tfilename.c_str(), currentLine,\n\t\t\t\t\t\t\t\t\tlabel.c_str());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\treadContext.Defines.insert(label);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error parsing #define command\", filename.c_str(), currentLine);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// advance to next line\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t\t// update filename and line number\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (matchToken(\"ifdef\", it, end))\n\t\t\t\t{\n\t\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t\t{\n\t\t\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\t\t\t\t\t\tstring label;\n\t\t\t\t\t\tif (parseLabel(it, end, label))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (readContext.Defines.find(label) != \treadContext.Defines.end())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// symbol defined, push a true\n\t\t\t\t\t\t\t\treadContext.IfStack.push_back(true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// symbol not defines, push a false\n\t\t\t\t\t\t\t\treadContext.IfStack.push_back(false);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error parsing #ifdef command\", filename.c_str(), currentLine);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// advance to next line\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t\t// update filename and line number\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// just push to false\n\t\t\t\t\t\treadContext.IfStack.push_back(false);\n\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (matchToken(\"ifndef\", it, end))\n\t\t\t\t{\n\t\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t\t{\n\t\t\t\t\t\tskipWhiteSpace(it, end, NULL, false);\n\t\t\t\t\t\tstring label;\n\t\t\t\t\t\tif (parseLabel(it, end, label))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (readContext.Defines.find(label) == \treadContext.Defines.end())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// symbol defined, push a true\n\t\t\t\t\t\t\t\treadContext.IfStack.push_back(true);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// symbol not defines, push a false\n\t\t\t\t\t\t\t\treadContext.IfStack.push_back(false);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error parsing #ifndef command\", filename.c_str(), currentLine);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// advance to next line\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t\t// update filename and line number\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// just push to false\n\t\t\t\t\t\treadContext.IfStack.push_back(false);\n\n\t\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (matchToken(\"endif\", it, end))\n\t\t\t\t{\n\t\t\t\t\tbool previous = false;\n\t\t\t\t\tif (readContext.IfStack.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error found '#endif' without matching #if\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tprevious = readContext.IfStack.back();\n\n\t\t\t\t\t\treadContext.IfStack.pop_back();\n\t\t\t\t\t}\n\t\t\t\t\tskipLine(it, end, currentLine);\n\n\t\t\t\t\tif (!previous && (readContext.IfStack.empty() || readContext.IfStack.back()))\n\t\t\t\t\t{\n\t\t\t\t\t\t// end of ignored file part, restore the file and line number\n\t\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t\t}\n\t\t\t\t\t// update filename and line number\n//\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// unrecognized command, ignore line\n\t\t\t\t\tnlwarning(\"Preprocess: In file %s(%u) : Error unrecognized preprocessor command\",\n\t\t\t\t\t\tfilename.c_str(), currentLine);\n\n\t\t\t\t\tskipLine(it, end, currentLine);\n\t\t\t\t\t// update filename and line number\n\t\t\t\t\tfinal += toString(\"#fileline \\\"%s\\\" %u\\n\", filename.c_str(), currentLine);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// normal line\n\t\t\t\tskipLine(it, end, currentLine);\n\n\t\t\t\tif (readContext.IfStack.empty() || readContext.IfStack.back())\n\t\t\t\t{\n\t\t\t\t\t// copy the line to the final string\n\t\t\t\t\tfinal.append(beginOfLine, it);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// set the result with the preprocessed content\n\t\tresult.swap(final);\n\t}\n\n\t// apply line delimiter conversion if needed\n\tif (lineFmt != LINE_FMT_NO_CARE)\n\t{\n\t\tif (lineFmt == LINE_FMT_LF)\n\t\t{\n\t\t\t// we only want \\n\n\t\t\t// easy, just remove or replace any \\r code\n\t\t\tstring::size_type pos;\n\t\t\tstring::size_type lastPos = 0;\n\t\t\tucstring temp;\n\t\t\t// reserve some place to reduce re-allocation\n\t\t\ttemp.reserve(result.size() +result.size()/10);\n\n\t\t\t// look for the first \\r\n\t\t\tpos = result.find('\\r');\n\t\t\twhile (pos != string::npos)\n\t\t\t{\n\t\t\t\tif (pos < result.size()-1 && result[pos+1] == '\\n')\n\t\t\t\t{\n\t\t\t\t\ttemp.append(result.begin()+lastPos, result.begin()+pos);\n\t\t\t\t\tpos += 1;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\ttemp.append(result.begin()+lastPos, result.begin()+pos);\n\t\t\t\t\ttemp[temp.size()-1] = '\\n';\n\t\t\t\t}\n\n\t\t\t\tlastPos = pos;\n\t\t\t\t// look for next \\r\n\t\t\t\tpos = result.find('\\r', pos);\n\t\t\t}\n\n\t\t\t// copy the rest\n\t\t\ttemp.append(result.begin()+lastPos, result.end());\n\n\t\t\tresult.swap(temp);\n\t\t}\n\t\telse if (lineFmt == LINE_FMT_CRLF)\n\t\t{\n\t\t\t// need to replace simple '\\n' or '\\r' with a '\\r\\n' double\n\t\t\tstring::size_type pos = 0;\n\t\t\tstring::size_type lastPos = 0;\n\n\t\t\tucstring temp;\n\t\t\t// reserve some place to reduce re-allocation\n\t\t\ttemp.reserve(result.size() +result.size()/10);\n\n\n\t\t\t// first loop with the '\\r'\n\t\t\tpos = result.find('\\r', pos);\n\t\t\twhile (pos != string::npos)\n\t\t\t{\n\t\t\t\tif (pos >= result.size()-1 || result[pos+1] != '\\n')\n\t\t\t\t{\n\t\t\t\t\ttemp.append(result.begin()+lastPos, result.begin()+pos+1);\n\t\t\t\t\ttemp += '\\n';\n\t\t\t\t\tlastPos = pos+1;\n\t\t\t\t}\n\t\t\t\t// skip this char\n\t\t\t\tpos++;\n\n\t\t\t\t// look the next '\\r'\n\t\t\t\tpos = result.find('\\r', pos);\n\t\t\t}\n\n\t\t\t// copy the rest\n\t\t\ttemp.append(result.begin()+lastPos, result.end());\n\t\t\tresult.swap(temp);\n\n\t\t\ttemp = \"\";\n\n\t\t\t// second loop with the '\\n'\n\t\t\tpos = 0;\n\t\t\tlastPos = 0;\n\t\t\tpos = result.find('\\n', pos);\n\t\t\twhile (pos != string::npos)\n\t\t\t{\n\t\t\t\tif (pos == 0 || result[pos-1] != '\\r')\n\t\t\t\t{\n\t\t\t\t\ttemp.append(result.begin()+lastPos, result.begin()+pos);\n\t\t\t\t\ttemp += '\\r';\n\t\t\t\t\ttemp += '\\n';\n\t\t\t\t\tlastPos = pos+1;\n\t\t\t\t}\n\t\t\t\t// skip this char\n\t\t\t\tpos++;\n\n\t\t\t\tpos = result.find('\\n', pos);\n\t\t\t}\n\n\t\t\t// copy the rest\n\t\t\ttemp.append(result.begin()+lastPos, result.end());\n\t\t\tresult.swap(temp);\n\t\t}\n\t}\n}\n\nvoid CI18N::readTextBuffer(uint8 *buffer, uint size, ucstring &result, bool forceUtf8)\n{\n\tstatic uint8 utf16Header[] = { 0xffu, 0xfeu };\n\tstatic uint8 utf16RevHeader[] = { 0xfeu, 0xffu };\n\tstatic uint8 utf8Header[] = { 0xefu, 0xbbu, 0xbfu };\n\n\tif (forceUtf8)\n\t{\n\t\tif (size>=3 &&\n\t\t\tbuffer[0]==utf8Header[0] &&\n\t\t\tbuffer[1]==utf8Header[1] &&\n\t\t\tbuffer[2]==utf8Header[2]\n\t\t\t)\n\t\t{\n\t\t\t// remove utf8 header\n\t\t\tbuffer+= 3;\n\t\t\tsize-=3;\n\t\t}\n\t\tstring text((char*)buffer, size);\n\t\tresult.fromUtf8(text);\n\t}\n\telse if (size>=3 &&\n\t\t\t buffer[0]==utf8Header[0] &&\n\t\t\t buffer[1]==utf8Header[1] &&\n\t\t\t buffer[2]==utf8Header[2]\n\t\t\t)\n\t{\n\t\t// remove utf8 header\n\t\tbuffer+= 3;\n\t\tsize-=3;\n\t\tstring text((char*)buffer, size);\n\t\tresult.fromUtf8(text);\n\t}\n\telse if (size>=2 &&\n\t\t\t buffer[0]==utf16Header[0] &&\n\t\t\t buffer[1]==utf16Header[1]\n\t\t\t)\n\t{\n\t\t// remove utf16 header\n\t\tbuffer+= 2;\n\t\tsize-= 2;\n\t\t// check pair number of bytes\n\t\tnlassert((size & 1) == 0);\n\t\t// and do manual conversion\n\t\tuint16 *src = (uint16*)(buffer);\n\t\tresult.resize(size/2);\n\t\tfor (uint j=0; j<result.size(); j++)\n\t\t\tresult[j]= *src++;\n\t}\n\telse if (size>=2 &&\n\t\t\t buffer[0]==utf16RevHeader[0] &&\n\t\t\t buffer[1]==utf16RevHeader[1]\n\t\t\t)\n\t{\n\t\t// remove utf16 header\n\t\tbuffer+= 2;\n\t\tsize-= 2;\n\t\t// check pair number of bytes\n\t\tnlassert((size & 1) == 0);\n\t\t// and do manual conversion\n\t\tuint16 *src = (uint16*)(buffer);\n\t\tresult.resize(size/2);\n\t\tuint j;\n\t\tfor (j=0; j<result.size(); j++)\n\t\t\tresult[j]= *src++;\n\t\t//  Reverse byte order\n\t\tfor (j=0; j<result.size(); j++)\n\t\t{\n\t\t\tuint8 *pc = (uint8*) &result[j];\n\t\t\tswap(pc[0], pc[1]);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// hum.. ascii read ?\n\t\t// so, just do a direct conversion\n\t\tstring text((char*)buffer, size);\n\t\tresult = text;\n\t}\n}\n\nvoid CI18N::writeTextFile(const string filename, const ucstring &content, bool utf8)\n{\n\tCOFile file(filename);\n\n\tif (!utf8)\n\t{\n\t\t// write the Unicode 16 bits tag\n\t\tuint16 unicodeTag = 0xfeff;\n\t\tfile.serial(unicodeTag);\n\n\t\tuint i;\n\t\tfor (i=0; i<content.size(); ++i)\n\t\t{\n\t\t\tuint16 c = content[i];\n\t\t\tfile.serial(c);\n\t\t}\n\t}\n\telse\n\t{\n\t\tstatic char utf8Header[] = {char(0xef), char(0xbb), char(0xbf), 0};\n\n\t\tstring str = encodeUTF8(content);\n\t\t// add the UTF-8 'not official' header\n\t\tstr = utf8Header + str;\n\n\t\tuint i;\n\t\tfor (i=0; i<str.size(); ++i)\n\t\t{\n\t\t\tfile.serial(str[i]);\n\t\t}\n\t}\n}\n\nucstring CI18N::makeMarkedString(ucchar openMark, ucchar closeMark, const ucstring &text)\n{\n\tucstring ret;\n\n\tret.push_back(openMark);\n\n\tucstring::const_iterator first(text.begin()), last(text.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tif (*first == '\\n')\n\t\t{\n\t\t\tret += '\\\\';\n\t\t\tret += 'n';\n\t\t}\n\t\telse if (*first == '\\t')\n\t\t{\n\t\t\tret += '\\\\';\n\t\t\tret += 't';\n\t\t}\n\t\telse if (*first == closeMark)\n\t\t{\n\t\t\t// escape the embedded closing mark\n\t\t\tret += '\\\\';\n\t\t\tret += closeMark;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tret += *first;\n\t\t}\n\t}\n\n\tret += closeMark;\n\n\treturn ret;\n}\n\nstring CI18N::encodeUTF8(const ucstring &str)\n{\n\treturn str.toUtf8();\n}\n\n/* UTF-8 conversion table\nU-00000000 - U-0000007F:  0xxxxxxx\nU-00000080 - U-000007FF:  110xxxxx 10xxxxxx\nU-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx\n// not used as we convert from 16 bits unicode\nU-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\nU-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\nU-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx\n*/\n\nuint64\tCI18N::makeHash(const ucstring &str)\n{\n\t// we do at least 8 pass on each result byte\n\tif (str.empty())\n\t\treturn 0;\n\tconst\tuint32\tMIN_TURN = 8*8;\n\tuint64\thash = 0;\n\tuint8\t*ph = (uint8*)&hash;\n\tuint8\t*pc = (uint8*)str.data();\n\n\tuint nbLoop = max(uint32(str.size()*2), MIN_TURN);\n\tuint roll = 0;\n\n\tfor (uint i=0; i<nbLoop; ++i)\n\t{\n\t\tph[(i/2) & 0x7] = uint8((ph[(i/2) & 0x7] + (pc[i%(str.size()*2)] << roll)) & 0xff);\n\t\tph[(i/2) & 0x7] = uint8((ph[(i/2) & 0x7] + (pc[i%(str.size()*2)] >> (8-roll))) & 0xff);\n\n\t\troll++;\n\t\troll &= 0x7;\n\t}\n\n\treturn hash;\n}\n\n// convert a hash value to a readable string\nstring CI18N::hashToString(uint64 hash)\n{\n\tchar temp[] = \"0011223344556677\";\n\tsprintf(temp, \"%08X%08X\", (uint32)(hash & 0xffffffff), (uint32)(hash >> 32));\n\n\treturn string(temp);\n}\n\n// fast convert a hash value to a ucstring\nvoid\tCI18N::hashToUCString(uint64 hash, ucstring &dst)\n{\n\tstatic ucchar\tcvtTable[]= {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\n\n\tdst.resize(16);\n\tfor(sint i=15;i>=0;i--)\n\t{\n\t\t// Must decal dest of 8, cause of hashToString code (Little Endian)\n\t\tdst[(i+8)&15]= cvtTable[hash&15];\n\t\thash>>=4;\n\t}\n}\n\n// convert a readable string into a hash value.\nuint64 CI18N::stringToHash(const string &str)\n{\n\tnlassert(str.size() == 16);\n\tuint32\tlow, high;\n\n\tstring sl, sh;\n\tsh = str.substr(0, 8);\n\tsl = str.substr(8, 8);\n\n\tsscanf(sh.c_str(), \"%08X\", &high);\n\tsscanf(sl.c_str(), \"%08X\", &low);\n\n\tuint64 hash;\n\n\tmemcpy(&hash, &high, sizeof(high));\n\tmemcpy((uint32*)&hash + 1, &low, sizeof(low));\n\n\treturn hash;\n}\n\n} // namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/i_xml.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/algo.h\"\n#include \"nel/misc/i_xml.h\"\n#include \"nel/misc/sstring.h\"\n\n#ifndef NL_DONT_USE_EXTERNAL_CODE\n\n// Include from libxml2\n#include <libxml/xmlerror.h>\n\n#if defined(NL_OS_WINDOWS) && defined(NL_COMP_VC_VERSION) && NL_COMP_VC_VERSION >= 80\n#define USE_LOCALE_ATOF\n#include <locale.h>\n#endif\n\nusing namespace std;\n\n#define NLMISC_READ_BUFFER_SIZE 1024\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// *********************************************************\n\nconst char SEPARATOR = ' ';\n\n// ***************************************************************************\n\n#define readnumber(dest,thetype,digits,convfunc) \\\n\tstring number_as_string; \\\n\tserialSeparatedBufferIn( number_as_string ); \\\n\tdest = (thetype)convfunc( number_as_string.c_str() );\n\n#ifdef USE_LOCALE_ATOF\n\n#define readnumberlocale(dest,thetype,digits,convfunc) \\\n\tstring number_as_string; \\\n\tserialSeparatedBufferIn( number_as_string ); \\\n\tdest = (thetype)convfunc( number_as_string.c_str(), (_locale_t)_Locale );\n\n#define nl_atof _atof_l\n\n#else\n\n#define readnumberlocale(dest,thetype,digits,convfunc) readnumber(dest,thetype,digits,convfunc)\n#define nl_atof atof\n\n#endif\n\n// ***************************************************************************\n\ninline void CIXml::flushContentString ()\n{\n\t// String size\n\t_ContentString.erase ();\n\n\t// Reset\n\t_ContentStringIndex = 0;\n}\n\n// ***************************************************************************\n\nCIXml::CIXml () : IStream (true /* Input mode */)\n{\n\t// Not initialized\n\t_Parser = NULL;\n\t_CurrentElement = NULL;\n\t_CurrentNode = NULL;\n\t_PushBegin = false;\n\t_AttribPresent = false;\n\t_ErrorString = \"\";\n\t_TryBinaryMode = false;\n\t_BinaryStream = NULL;\n\n#ifdef USE_LOCALE_ATOF\n\t// create C numeric locale\n\t_Locale = _create_locale(LC_NUMERIC, \"C\");\n#else\n\t_Locale = NULL;\n#endif\n}\n\n// ***************************************************************************\n\nCIXml::CIXml (bool tryBinaryMode) : IStream (true /* Input mode */)\n{\n\t// Not initialized\n\t_Parser = NULL;\n\t_CurrentElement = NULL;\n\t_CurrentNode = NULL;\n\t_PushBegin = false;\n\t_AttribPresent = false;\n\t_ErrorString = \"\";\n\t_TryBinaryMode = tryBinaryMode;\n\t_BinaryStream = NULL;\n\n#ifdef USE_LOCALE_ATOF\n\t// create C numeric locale\n\t_Locale = _create_locale(LC_NUMERIC, \"C\");\n#else\n\t_Locale = NULL;\n#endif\n}\n\n// ***************************************************************************\n\nCIXml::~CIXml ()\n{\n\t// Release\n\trelease ();\n\n#ifdef USE_LOCALE_ATOF\n\tif (_Locale) _free_locale((_locale_t)_Locale);\n#endif\n}\n\n// ***************************************************************************\n\nvoid CIXml::release ()\n{\n\t// Release the parser\n\tif (_Parser)\n\t{\n\t\t// Free it\n\t\txmlClearParserCtxt (_Parser);\n\t\txmlFreeParserCtxt (_Parser);\n\t\t// commented due to the bug #857 xmlCleanupParser ();\n\n\t\t_Parser = NULL;\n\t}\n\n\t// Not initialized\n\t_Parser = NULL;\n\t_CurrentElement = NULL;\n\t_CurrentNode = NULL;\n\t_PushBegin = false;\n\t_AttribPresent = false;\n\t_ErrorString = \"\";\n\n\tresetPtrTable();\n}\n\n// ***************************************************************************\n\nvoid xmlGenericErrorFuncRead (void *ctx, const char *msg, ...)\n{\n\t// Get the error string\n\tstring str;\n\tNLMISC_CONVERT_VARGS (str, msg, NLMISC::MaxCStringSize);\n\t((CIXml*)ctx)->_ErrorString += str;\n}\n\n// ***************************************************************************\n\nbool CIXml::init (IStream &stream)\n{\n\t// Release\n\trelease ();\n\n\txmlInitParser();\n\n\t// Default : XML mode\n\t_BinaryStream = NULL;\n\n\t// Input stream ?\n\tif (stream.isReading())\n\t{\n\t\t// Set XML mode\n\t\tsetXMLMode (true);\n\n\t\t// Get current position\n\t\tsint32 pos = stream.getPos ();\n\n\t\t// Go to end\n\t\tbool seekGood = stream.seek (0, end);\n\t\tnlassert (seekGood);\n\n\t\t// Get input stream length\n\t\tsint32 length = stream.getPos () - pos;\n\n\t\t// Go to start\n\t\tstream.seek (pos, begin);\n\n\t\t// The read buffer\n        char buffer[NLMISC_READ_BUFFER_SIZE];\n\n\t\t// Fill the buffer\n\t\tstream.serialBuffer ((uint8*)buffer, 4);\n\t\tlength -= 4;\n\n\t\t// Try binary mode\n\t\tif (_TryBinaryMode)\n\t\t{\n\t\t\tstring header;\n\t\t\theader.resize(4);\n\t\t\theader[0] = buffer[0];\n\t\t\theader[1] = buffer[1];\n\t\t\theader[2] = buffer[2];\n\t\t\theader[3] = buffer[3];\n\t\t\ttoLower(header);\n\n\t\t\t// Does it a xml stream ?\n\t\t\tif (header != \"<?xm\")\n\t\t\t{\n\t\t\t\t// NO ! Go in binary mode\n\t\t\t\t_BinaryStream = &stream;\n\n\t\t\t\t// Seek back to the start\n\t\t\t\tstream.seek (pos, begin);\n\n\t\t\t\t// Done\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// Set error handler\n\t\t_ErrorString = \"\";\n\t\txmlSetGenericErrorFunc\t(this, xmlGenericErrorFuncRead);\n\n\t\t// Ask to get debug info\n\t\txmlLineNumbersDefault(1);\n\n\t\t// The parser context\n        _Parser = xmlCreatePushParserCtxt(NULL, NULL, buffer, 4, NULL);\n\t\tnlassert (_Parser);\n\n\t\t// For all the file\n        while (length>=NLMISC_READ_BUFFER_SIZE)\n\t\t{\n\t\t\t// Fill the buffer\n\t\t\tstream.serialBuffer ((uint8*)buffer, NLMISC_READ_BUFFER_SIZE);\n\n\t\t\t// Read a buffer\n            int res = xmlParseChunk(_Parser, buffer, NLMISC_READ_BUFFER_SIZE, 0);\n\n\t\t\t// Error code ?\n\t\t\tif (res)\n\t\t\t{\n\t\t\t\tthrow EXmlParsingError (_ErrorString);\n\t\t\t}\n\n\t\t\t// Length left\n\t\t\tlength -= NLMISC_READ_BUFFER_SIZE;\n        }\n\n\t\t// Fill the buffer\n\t\tstream.serialBuffer ((uint8*)buffer, length);\n\n\t\t// Parse the last buffer\n\t\tint res = xmlParseChunk(_Parser, buffer, length, 1);\n\n\t\t// Error code ?\n\t\tif (res)\n\t\t{\n\t\t\tthrow EXmlParsingError (_ErrorString);\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\tnlwarning (\"XML: The stream is not an input stream.\");\n\t}\n\n\t// Error\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CIXml::serialSeparatedBufferIn ( string &value, bool checkSeparator )\n{\n\tnlassert( isReading() );\n\n\t// Output stream has been initialized ?\n\tif ( _Parser )\n\t{\n\t\t// Current node presents ?\n\t\tif (_CurrentElement)\n\t\t{\n\t\t\t// Write a push attribute ?\n\t\t\tif (_PushBegin)\n\t\t\t{\n\t\t\t\t// Current attrib is set ?\n\t\t\t\tif (_AttribPresent)\n\t\t\t\t{\n\t\t\t\t\t// Should have a current element\n\t\t\t\t\tnlassert (_CurrentElement);\n\n\t\t\t\t\t// Get the attribute\n\t\t\t\t\txmlChar *attributeValue = xmlGetProp (_CurrentElement, (const xmlChar*)_AttribName.c_str());\n\n\t\t\t\t\t// Attribute is here ?\n\t\t\t\t\tif (attributeValue)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Copy the value\n\t\t\t\t\t\tvalue = (const char*)attributeValue;\n\n\t\t\t\t\t\t// Delete the value\n\t\t\t\t\t\txmlFree ((void*)attributeValue);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Node name must not be NULL\n\t\t\t\t\t\tnlassert (_CurrentElement->name);\n\n\t\t\t\t\t\t// Make an error message\n\t\t\t\t\t\tchar tmp[512];\n\t\t\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error in block line %d\\nAttribute \\\"%s\\\" is missing in node \\\"%s\\\"\",\n\t\t\t\t\t\t\t(int)_CurrentElement->line, _AttribName.c_str(), _CurrentElement->name);\n\t\t\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t\t\t}\n\n\t\t\t\t\t// The attribute has been used\n\t\t\t\t\t_AttribPresent = false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// * Error, the stream don't use XML streaming properly\n\t\t\t\t\t// * You must take care of this in your last serial call:\n\t\t\t\t\t// * - Between xmlPushBegin() and xmlPushEnd(), before each serial, you must set the attribute name with xmlSetAttrib.\n\t\t\t\t\t// * - Between xmlPushBegin() and xmlPushEnd(), you must serial only basic objects (numbers and strings).\n\t\t\t\t\tnlerror ( \"Error, the stream don't use XML streaming properly\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Content length\n\t\t\t\tuint length = (uint)_ContentString.length();\n\n\t\t\t\t// String empty ?\n\t\t\t\tif (length==0)\n\t\t\t\t{\n\t\t\t\t\t// Try to open the node\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t// If no more node, empty string\n\t\t\t\t\t\tif (_CurrentNode == NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvalue = \"\";\n\t\t\t\t\t\t\t_ContentStringIndex = 0;\n\t\t\t\t\t\t\t_ContentString.erase ();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Node with the good name\n\t\t\t\t\t\tif (_CurrentNode->type == XML_TEXT_NODE)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Stop searching\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t// Get next\n\t\t\t\t\t\t\t_CurrentNode = _CurrentNode->next;\n\t\t\t\t\t}\n\t\t\t\t\twhile (_CurrentNode);\n\n\t\t\t\t\t// Not found ?\n\t\t\t\t\tif (_CurrentNode != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Read the content\n\t\t\t\t\t\tconst char *content = (const char*)xmlNodeGetContent (_CurrentNode);\n\t\t\t\t\t\tif (content)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_ContentString = content;\n\n\t\t\t\t\t\t\t// Delete the value\n\t\t\t\t\t\t\txmlFree ((void*)content);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t_ContentString.erase ();\n\n\t\t\t\t\t\t// Set the current index\n\t\t\t\t\t\t_ContentStringIndex = 0;\n\n\t\t\t\t\t\t// New length\n\t\t\t\t\t\tlength = (uint)_ContentString.length();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Keyword in the buffer ?\n\t\t\t\tif (_ContentStringIndex < length)\n\t\t\t\t{\n\t\t\t\t\t// First index\n\t\t\t\t\tuint first = _ContentStringIndex;\n\n\t\t\t\t\t// Have to take care of separators ?\n\t\t\t\t\tif (checkSeparator)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Scan to the end\n\t\t\t\t\t\twhile (_ContentStringIndex < length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Not a separator ?\n\t\t\t\t\t\t\tif ( (_ContentString[_ContentStringIndex]==SEPARATOR) || (_ContentString[_ContentStringIndex]=='\\n') )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t_ContentStringIndex++;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Next char\n\t\t\t\t\t\t\t_ContentStringIndex++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Copy all the string\n\t\t\t\t\t\t_ContentStringIndex = length;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Make a string\n\t\t\t\t\tvalue.assign (_ContentString, first, _ContentStringIndex-first);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Should have a name\n\t\t\t\t\tnlassert (_CurrentElement->name);\n\n\t\t\t\t\t// Make an error message\n\t\t\t\t\tchar tmp[512];\n\t\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error in block line %d \\nMissing keywords in text child node in the node %s\",\n\t\t\t\t\t\t(int)_CurrentElement->line, _CurrentElement->name);\n\t\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// * Error, no current node present.\n\t\t\t// * Check that your serial is initialy made between a xmlPushBegin and xmlPushEnd calls.\n\t\t\tnlerror ( \"Error, the stream don't use XML streaming properly\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlerror ( \"Output stream has not been initialized\" );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(uint8 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\t// Read the number\n\t\treadnumber( b, uint8, 3, atoi );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(sint8 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, sint8, 4, atoi );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(uint16 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, uint16, 5, atoi );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(sint16 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, sint16, 6, atoi );\n\t}\n}\n\n// ***************************************************************************\n\ninline uint32 atoui( const char *ident)\n{\n\treturn (uint32) strtoul (ident, NULL, 10);\n}\n\nvoid CIXml::serial(uint32 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, uint32, 10, atoui );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(sint32 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, sint32, 11, atoi );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(uint64 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, uint64, 20, atoiInt64 );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(sint64 &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumber( b, sint64, 20, atoiInt64 );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(float &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumberlocale( b, float, 128, nl_atof );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(double &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\treadnumberlocale( b, double, 128, nl_atof );\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(bool &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\tserialBit(b);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serialBit(bool &bit)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serialBit(bit);\n\t}\n\telse\n\t{\n\t\tuint8 u;\n\t\tserial (u);\n\t\tbit = (u!=0);\n\t}\n}\n\n// ***************************************************************************\n\n#ifndef NL_OS_CYGWIN\nvoid CIXml::serial(char &b)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\tstring toto;\n\t\tserialSeparatedBufferIn ( toto );\n\n\t\t// Good value ?\n\t\tif (toto.length()!=1)\n\t\t{\n\t\t\t// Protect error\n\t\t\tif (_Parser)\n\t\t\t{\n\t\t\t\t// Should have a name\n\t\t\t\tnlassert (_CurrentElement->name);\n\n\t\t\t\t// Make an error message\n\t\t\t\tchar tmp[512];\n\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error in block line %d \\nValue is not a char in the node named %s\",\n\t\t\t\t\t(int)_CurrentElement->line, _CurrentElement->name);\n\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlerror ( \"Output stream has not been initialized\" );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tb=toto[0];\n\t}\n}\n#endif // NL_OS_CYGWIN\n\n// ***************************************************************************\n\nvoid CIXml::serial(std::string &b)\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\t// Attibute ?\n\t\tif (_PushBegin)\n\t\t{\n\t\t\t// Only serial the string\n\t\t\tserialSeparatedBufferIn ( b, false );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Open a string node\n\t\t\txmlPush (\"S\");\n\n\t\t\t// Serial the string\n\t\t\tserialSeparatedBufferIn ( b, false );\n\n\t\t\t// Close the node\n\t\t\txmlPop ();\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serial(ucstring &b)\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serial(b);\n\t}\n\telse\n\t{\n\t\t// Serial a simple string\n\t\tstring tmp;\n\n\t\t// Serial this string\n\t\tserial (tmp);\n\n\t\t// Return a ucstring\n\t\tb.fromUtf8(tmp);\n\t}\n}\n\n// ***************************************************************************\n\nvoid CIXml::serialBuffer(uint8 *buf, uint len)\n{\n\tif (_BinaryStream)\n\t{\n\t\t_BinaryStream->serialBuffer(buf, len);\n\t}\n\telse\n\t{\n\t\t// Open a node\n\t\txmlPush (\"BUFFER\");\n\n\t\t// Serialize the buffer\n\t\tfor (uint i=0; i<len; i++)\n\t\t{\n\t\t\txmlPush (\"ELM\");\n\n\t\t\tserial (buf[i]);\n\n\t\t\txmlPop ();\n\t\t}\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlPushBeginInternal (const char *nodeName)\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Check _Parser\n\t\tif ( _Parser )\n\t\t{\n\t\t\t// Can make a xmlPushBegin ?\n\t\t\tif ( ! _PushBegin )\n\t\t\t{\n\t\t\t\t// Current node exist ?\n\t\t\t\tif (_CurrentNode==NULL)\n\t\t\t\t{\n\t\t\t\t\t// Get the first node\n\t\t\t\t\t_CurrentNode = xmlDocGetRootElement (_Parser->myDoc);\n\n\t\t\t\t\t// Has a root node ?\n\t\t\t\t\tif (_CurrentNode)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Node name must not be NULL\n\t\t\t\t\t\tnlassert (_CurrentNode->name);\n\n\t\t\t\t\t\t// Node element with the good name ?\n\t\t\t\t\t\tif ( (_CurrentNode->type != XML_ELEMENT_NODE) || ( (const char*)_CurrentNode->name != string(nodeName)) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Make an error message\n\t\t\t\t\t\t\tchar tmp[512];\n\t\t\t\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error : root node has the wrong name : \\\"%s\\\" should have \\\"%s\\\"\",\n\t\t\t\t\t\t\t\t_CurrentNode->name, nodeName);\n\t\t\t\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Make an error message\n\t\t\t\t\t\tchar tmp[512];\n\t\t\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error : no root node found.\");\n\t\t\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Try to open the node\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\t// Node name must not be NULL\n\t\t\t\t\tnlassert (_CurrentNode->name);\n\n\t\t\t\t\t// Node with the good name\n\t\t\t\t\tif ( (_CurrentNode->type == XML_ELEMENT_NODE) && ( (const char*)_CurrentNode->name == string(nodeName)) )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Save current element\n\t\t\t\t\t\t_CurrentElement = _CurrentNode;\n\n\t\t\t\t\t\t// Stop searching\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\t// Get next\n\t\t\t\t\t\t_CurrentNode = _CurrentNode->next;\n\t\t\t\t}\n\t\t\t\twhile (_CurrentNode);\n\n\t\t\t\t// Not found ?\n\t\t\t\tif (_CurrentNode == NULL)\n\t\t\t\t{\n\t\t\t\t\t// Make an error message\n\t\t\t\t\tchar tmp[512];\n\t\t\t\t\tsmprintf (tmp, 512, \"NeL XML Syntax error in block line %d \\nCan't open the node named %s in node named %s\",\n\t\t\t\t\t\t(int)_CurrentElement->line, nodeName, _CurrentElement->name);\n\t\t\t\t\tthrow EXmlParsingError (tmp);\n\t\t\t\t}\n\n\t\t\t\t// Get first child\n\t\t\t\t_CurrentNode = _CurrentNode->children;\n\n\t\t\t\t// Push begun\n\t\t\t\t_PushBegin = true;\n\n\t\t\t\t// Flush current string\n\t\t\t\tflushContentString ();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlerror ( \"You must close your xmlPushBegin - xmlPushEnd before calling a new xmlPushBegin.\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror ( \"Output stream has not been initialized.\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlPushEndInternal ()\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Check _Parser\n\t\tif ( _Parser )\n\t\t{\n\t\t\t// Can make a xmlPushEnd ?\n\t\t\tif ( _PushBegin )\n\t\t\t{\n\t\t\t\t// Push begun\n\t\t\t\t_PushBegin = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlerror ( \"You must call xmlPushBegin before calling xmlPushEnd.\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror ( \"Output stream has not been initialized.\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlPopInternal ()\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Check _Parser\n\t\tif ( _Parser )\n\t\t{\n\t\t\t// Not in the push mode ?\n\t\t\tif ( ! _PushBegin )\n\t\t\t{\n\t\t\t\t// Some content to write ?\n\t\t\t\tflushContentString ();\n\n\t\t\t\t// Get parents\n\t\t\t\t_CurrentNode = _CurrentElement;\n\t\t\t\t_CurrentElement = _CurrentElement->parent;\n\t\t\t\t_CurrentNode = _CurrentNode->next;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlerror ( \"You must call xmlPop after xmlPushEnd.\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror ( \"Output stream has not been initialized.\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlSetAttribInternal (const char *attribName)\n{\n\tnlassert( isReading() );\n\n\tif (_BinaryStream)\n\t{\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\t// Check _Parser\n\t\tif ( _Parser )\n\t\t{\n\t\t\t// Can make a xmlPushEnd ?\n\t\t\tif ( _PushBegin )\n\t\t\t{\n\t\t\t\t// Set attribute name\n\t\t\t\t_AttribName = attribName;\n\n\t\t\t\t// Attribute name is present\n\t\t\t\t_AttribPresent = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlerror ( \"You must call xmlSetAttrib between xmlPushBegin and xmlPushEnd calls.\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlerror ( \"Output stream has not been initialized.\");\n\t\t\treturn false;\n\t\t}\n\n\t\t// Ok\n\t\treturn true;\n\t}\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlBreakLineInternal ()\n{\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool CIXml::xmlCommentInternal (const char * /* comment */)\n{\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CIXml::getFirstChildNode (xmlNodePtr parent, const char *childName)\n{\n\txmlNodePtr child = parent->children;\n\twhile (child)\n\t{\n\t\tif (strcmp ((const char*)child->name, childName) == 0)\n\t\t\treturn child;\n\t\tchild = child->next;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CIXml::getNextChildNode (xmlNodePtr last, const char *childName)\n{\n\tlast = last->next;\n\twhile (last)\n\t{\n\t\tif (strcmp ((const char*)last->name, childName) == 0)\n\t\t\treturn last;\n\t\tlast = last->next;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CIXml::getFirstChildNode (xmlNodePtr parent, xmlElementType type)\n{\n\txmlNodePtr child = parent->children;\n\twhile (child)\n\t{\n\t\tif (child->type == type)\n\t\t\treturn child;\n\t\tchild = child->next;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CIXml::getNextChildNode (xmlNodePtr last, xmlElementType type)\n{\n\tlast = last->next;\n\twhile (last)\n\t{\n\t\tif (last->type == type)\n\t\t\treturn last;\n\t\tlast = last->next;\n\t}\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nuint CIXml::countChildren (xmlNodePtr node, const char *childName)\n{\n\tuint count=0;\n\txmlNodePtr child = getFirstChildNode (node, childName);\n\twhile (child)\n\t{\n\t\tcount++;\n\t\tchild = getNextChildNode (child, childName);\n\t}\n\treturn count;\n}\n\n// ***************************************************************************\n\nuint CIXml::countChildren (xmlNodePtr node, xmlElementType type)\n{\n\tuint count=0;\n\txmlNodePtr child = getFirstChildNode (node, type);\n\twhile (child)\n\t{\n\t\tcount++;\n\t\tchild = getNextChildNode (child, type);\n\t}\n\treturn count;\n}\n\n// ***************************************************************************\n\nxmlNodePtr CIXml::getRootNode () const\n{\n\tif (_Parser)\n\t\tif (_Parser->myDoc)\n\t\t\treturn xmlDocGetRootElement (_Parser->myDoc);\n\treturn NULL;\n}\n\n// ***************************************************************************\n\nbool CIXml::getPropertyString (std::string &result, xmlNodePtr node, const char *property)\n{\n\t// Get the value\n\tconst char *value = (const char*)xmlGetProp (node, (xmlChar*)property);\n\tif (value)\n\t{\n\t\t// Active value\n\t\tresult = value;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)value);\n\n\t\t// Found\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nint CIXml::getIntProperty(xmlNodePtr node, const char *property, int defaultValue)\n{\n\tCSString s;\n\tbool b;\n\n\tb=getPropertyString(s,node,property);\n\tif (b==false)\n\t\treturn defaultValue;\n\n\ts=s.strip();\n\tsint val=s.atoi();\n\tif (val==0 && s!=\"0\")\n\t{\n\t\tnlwarning(\"bad integer value: %s\",s.c_str());\n\t\treturn defaultValue;\n\t}\n\n\treturn val;\n}\n\n// ***************************************************************************\n\ndouble CIXml::getFloatProperty(xmlNodePtr node, const char *property, float defaultValue)\n{\n\tCSString s;\n\tbool b;\n\n\tb=getPropertyString(s,node,property);\n\tif (b==false)\n\t\treturn defaultValue;\n\n    //sint64 tmp = (s.strip().atof() + 0.000005) * 10000;\n\treturn DoubleRound(s.strip().atof(), 6);\n}\n\n// ***************************************************************************\n\nstd::string CIXml::getStringProperty(xmlNodePtr node, const char *property, const std::string& defaultValue)\n{\n\tstd::string s;\n\tbool b;\n\n\tb=getPropertyString(s,node,property);\n\tif (b==false)\n\t\treturn defaultValue;\n\n\treturn s;\n}\n\n// ***************************************************************************\n\nbool CIXml::getContentString (std::string &result, xmlNodePtr node)\n{\n\tconst char *valueText = (const char*)xmlNodeGetContent (node);\n\tif (valueText)\n\t{\n\t\tresult = valueText;\n\n\t\t// Delete the value\n\t\txmlFree ((void*)valueText);\n\n\t\t// Found\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\n} // NLMISC\n\n#endif // NL_DONT_USE_EXTERNAL_CODE\n"
  },
  {
    "path": "code/nel/src/misc/input_device.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/input_device.h\"\n\n// remove stupid VC6 warnings\nvoid foo_input_device_cpp() {}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/input_device_server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/input_device_server.h\"\n#include \"nel/misc/input_device.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n//=======================================================================\nvoid\tCInputDeviceServer::registerDevice(IInputDevice *device)\n{\n\tnlassert(!isDevice(device));\n\t_Devices.push_back(device);\n}\n\n//=======================================================================\nvoid\tCInputDeviceServer::removeDevice(IInputDevice *device)\n{\n\tTDeviceCont::iterator it = std::find(_Devices.begin(), _Devices.end(), device);\n\tnlassert(it != _Devices.end());\n\t_Devices.erase(it);\n}\n\n//=======================================================================\nbool\tCInputDeviceServer::isDevice(IInputDevice *device) const\n{\n\tTDeviceCont::const_iterator it = std::find(_Devices.begin(), _Devices.end(), device);\n\treturn it != _Devices.end();\n}\n\n//=======================================================================\n// Predicate to compare vents dates\nstruct CInputDeviceEventLess\n{\n\tbool operator()(const IInputDeviceEvent *lhs, const IInputDeviceEvent *rhs) const\n\t{\n\t\treturn *lhs < *rhs;\n\t}\n};\n\n//=======================================================================\nvoid\tCInputDeviceServer::poll(CEventServer *server)\n{\n\tnlassert(_Events.empty());\n\tTDeviceCont::iterator deviceIt;\n\tfor (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt)\n\t{\n\t\t(*deviceIt)->begin(server);\n\t\t(*deviceIt)->poll(this);\n\t}\n\t// Sort the messages to get the right dates.\n\tstd::sort(_Events.begin(), _Events.end(), CInputDeviceEventLess());\n\t// submit the result to the server\n\tIInputDevice *lastVisitedDevice = NULL;\n\tTEventCont::iterator eventIt;\n\tfor (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt)\n\t{\n\t\t// see if this message is from a previous device then the last we visited.\n\t\tif (lastVisitedDevice && (*eventIt)->Emitter != lastVisitedDevice)\n\t\t{\n\t\t\t// yes, tells that a transition occured\n\t\t\tlastVisitedDevice->transitionOccured(server, *eventIt);\n\t\t\tlastVisitedDevice = (*eventIt)->Emitter;\n\t\t}\n\t\tnlassert((*eventIt)->Emitter != NULL);\n\t\t(*eventIt)->Emitter->submit(*eventIt, server);\n\t}\n\t//\n\tfor (deviceIt = _Devices.begin(); deviceIt != _Devices.end(); ++deviceIt)\n\t{\n\t\t(*deviceIt)->transitionOccured(server, NULL);\n\t}\n\t// delete the messages\n\tfor (eventIt = _Events.begin(); eventIt != _Events.end(); ++eventIt)\n\t{\n\t\tdelete *eventIt;\n\t}\n\t//\n\t_Events.clear();\n}\n\n//=======================================================================\nvoid\tCInputDeviceServer::submitEvent(IInputDeviceEvent *deviceEvent)\n{\n\t_Events.push_back(deviceEvent);\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/inter_window_msg_queue.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/inter_window_msg_queue.h\"\n\n#ifdef NL_OS_WINDOWS\n#include \"nel/misc/mem_stream.h\"\n#include \"nel/misc/shared_memory.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n\tCSynchronized<CInterWindowMsgQueue::TMessageQueueMap> CInterWindowMsgQueue::_MessageQueueMap(\"CInterWindowMsgQueue::_MessageQueueMap\");\n\tconst uint CInterWindowMsgQueue::_CurrentVersion = 0;\n\tCInterWindowMsgQueue::TOldWinProcMap CInterWindowMsgQueue::_OldWinProcMap;\n\n\n\n\n\t// **************************************************************************************************\n\n\t////////////////////////////////////////\n\t// CInterWindowMsgQueue::CProtagonist //\n\t////////////////////////////////////////\n\n\t// **************************************************************************************************\n\tCInterWindowMsgQueue::CProtagonist::CProtagonist() : _Id(0),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t _Wnd(0),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t _SharedMemMutex(0),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t _SharedWndHandle(NULL)\n\t{\n\t}\n\n\n\t// **************************************************************************************************\n\tCInterWindowMsgQueue::CProtagonist::~CProtagonist()\n\t{\n\t\trelease();\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CProtagonist::release()\n\t{\n\t\tCloseHandle(_SharedMemMutex);\n\t\t_SharedMemMutex = 0;\n\t\tif (_SharedWndHandle)\n\t\t{\n\t\t\tCSharedMemory::closeSharedMemory(_SharedWndHandle);\n\t\t\t_SharedWndHandle = NULL;\n\t\t}\n\t\t_Wnd = 0;\n\t\t_Id = 0;\n\t\t// unhook window\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CProtagonist::acquireSMMutex()\n\t{\n\t\tnlassert(_SharedMemMutex);\n\t\tDWORD result = WaitForSingleObject(_SharedMemMutex, INFINITE);\n\t\tnlassert(result != WAIT_FAILED);\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CProtagonist::releaseSMMutex()\n\t{\n\t\tnlassert(_SharedMemMutex);\n\t\tReleaseMutex(_SharedMemMutex);\n\t}\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::CProtagonist::init(uint32 id)\n\t{\n\t\tnlassert(id != 0);\n\t\tnlassert(id != 0x3a732235); // cf doc of NLMISC::CSharedMemory : this id is reserved\n\t\tnlassert(_Id == 0); // init done twice\n\t\trelease();\n\t\t// create a system wide mutex\n\t\t_SharedMemMutex = CreateMutex(NULL, FALSE, toString(\"NL_MUTEX_%d\", (int) id).c_str());\n\t\tif (!_SharedMemMutex) return false;\n\t\t_Id = id;\n\t\treturn true;\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CProtagonist::setWnd(HWND wnd)\n\t{\n\t\tnlassert(wnd != 0);\n\t\tnlassert(_SharedWndHandle == NULL); // setWnd was called before ?\n\t\t\t\t\t\t\t\t\t\t\t// setWnd should be called once for the 'local' window at beginning\n\t\tacquireSMMutex();\n\t\t_SharedWndHandle = CSharedMemory::createSharedMemory(toSharedMemId((int) _Id), sizeof(HWND));\n\t\tif (_SharedWndHandle)\n\t\t{\n\t\t\t*(HWND *) _SharedWndHandle = wnd;\n\t\t}\n\t\treleaseSMMutex();\n\t\t_Wnd = wnd;\n\t}\n\n\t// **************************************************************************************************\n\tHWND CInterWindowMsgQueue::CProtagonist::getWnd()\n\t{\n\t\tif (!_SharedMemMutex)\n\t\t{\n\t\t\tnlassert(_Wnd == 0);\n\t\t\tnlassert(!_SharedWndHandle);\n\t\t\treturn 0;\n\t\t}\n\t\tif (_Wnd != 0)\n\t\t{\n\t\t\t// local window case\n\t\t\treturn _Wnd;\n\t\t}\n\t\t// this is the foreign window\n\t\t// access shared memory just for the time of the query \t(this allow to see if foreign window is still alive)\n\t\tnlassert(!_SharedWndHandle);\n\t\tHWND result = 0;\n\t\tacquireSMMutex();\n\t\tvoid *sharedMem = CSharedMemory::accessSharedMemory(toSharedMemId((int) _Id));\n\t\tif (sharedMem)\n\t\t{\n\t\t\tresult = *(HWND *) sharedMem;\n\t\t\tCSharedMemory::closeSharedMemory(sharedMem);\n\t\t}\n\t\treleaseSMMutex();\n\t\treturn result;\n\n\t}\n\n\n\t// **************************************************************************************************\n\n\t/////////////////////////////////////\n\t// CInterWindowMsgQueue::CSendTask //\n\t/////////////////////////////////////\n\n\t// **************************************************************************************************\n\tCInterWindowMsgQueue::CSendTask::CSendTask(CInterWindowMsgQueue *parent) : _StopAsked(false)\n\t{\n\t\tnlassert(parent);\n\t\t_Parent = parent;\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CSendTask::run()\n\t{\n\t\twhile(!_StopAsked)\n\t\t{\n\t\t\tnlassert(_Parent);\n\t\t\tHWND targetWindow = _Parent->_ForeignWindow.getWnd();\n\t\t\tif (targetWindow == 0)\n\t\t\t{\n\t\t\t\t// there is no receiver, so message queue has become irrelevant, so just clear it\n\t\t\t\t_Parent->clearOutQueue();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tTMsgList nestedMsgs;\n\t\t\t\tCMemStream outMsg;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<TMsgList>::CAccessor outMessageQueue(&_Parent->_OutMessageQueue);\n\t\t\t\t\tnestedMsgs.swap(outMessageQueue.value());\n\t\t\t\t}\n\t\t\t\tif (!nestedMsgs.empty())\n\t\t\t\t{\n\t\t\t\t\tCMemStream msgOut(false);\n\t\t\t\t\tmsgOut.serialVersion(CInterWindowMsgQueue::_CurrentVersion);\n\t\t\t\t\tuint32 fromId(_Parent->_LocalWindow.getId());\n\t\t\t\t\tuint32 toId(_Parent->_ForeignWindow.getId());\n\t\t\t\t\tmsgOut.serial(fromId);\n\t\t\t\t\tmsgOut.serial(toId);\n\t\t\t\t\tmsgOut.serialCont(nestedMsgs);\n\t\t\t\t\tCOPYDATASTRUCT cds;\n\t\t\t\t\tcds.dwData = 0;\n\t\t\t\t\tcds.cbData = msgOut.length();\n\t\t\t\t\tcds.lpData = (PVOID) msgOut.buffer();\n\t\t\t\t\tfor(;;)\n\t\t\t\t\t{\n\t\t\t\t\t\tLRESULT result = ::SendMessage(targetWindow, WM_COPYDATA, (WPARAM) _Parent->_LocalWindow.getWnd(), (LPARAM) &cds);\n\t\t\t\t\t\tif (result) break;\n\t\t\t\t\t\t// retry ...\n\t\t\t\t\t\tSleep(30);\n\t\t\t\t\t\tif (!_Parent->_ForeignWindow.getWnd())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning(\"CInterWindowMsgQueue : tried to send message, but destination window has been closed\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tSleep(30);\n\t\t}\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::CSendTask::stop()\n\t{\n\t\t_StopAsked = true;\n\t}\n\n\n\t// **************************************************************************************************\n\n\t//////////////////////////\n\t// CInterWindowMsgQueue //\n\t//////////////////////////\n\n\t// **************************************************************************************************\n\tCInterWindowMsgQueue::CInterWindowMsgQueue() : _SendTask(NULL),\n\t\t\t\t\t\t\t\t\t\t\t\t   _SendThread(NULL),\n\t\t\t\t\t\t\t\t\t\t\t\t   _OutMessageQueue(\"CInterWindowMsgQueue::_OutMessageQueue\")\n\t{\n\t}\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::init(HWND ownerWindow, uint32 localId, uint32 foreignId)\n\t{\n\t\treturn initInternal(NULL, ownerWindow, localId, foreignId);\n\t}\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::init(HINSTANCE hInstance, uint32 localId, uint32 foreignId)\n\t{\n\t\treturn initInternal(hInstance, NULL, localId, foreignId);\n\t}\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::initInternal(HINSTANCE hInstance, HWND ownerWindow, uint32 localId, uint32 foreignId)\n\t{\n\t\tif (!ownerWindow)\n\t\t{\n\t\t\t// see if\n\t\t\tnlassert(hInstance);\n\t\t\tbool ok = _DummyWindow.init(hInstance, invisibleWindowListenerProc);\n\t\t\tif (!ok) return false;\n\t\t\townerWindow = _DummyWindow.getWnd();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlassert(ownerWindow);\n\t\t\tnlassert(!hInstance);\n\t\t}\n\t\tnlassert(localId != 0);\n\t\tnlassert(foreignId != 0);\n\t\tnlassert(localId != foreignId);\n\t\t{\n\t\t\ttypedef CSynchronized<TMessageQueueMap>::CAccessor TAccessor;\n\t\t\t// NB : use a 'new' instead of an automatic object here, because I got an 'INTERNAL COMPILER ERROR' compiler file 'msc1.cpp', line 1794\n\t\t\t// else, this is one of the way recommended by microsoft to solve the problem.\n\t\t\tstd::auto_ptr<TAccessor> messageQueueMap(new TAccessor(&_MessageQueueMap));\n\t\t\tCMsgQueueIdent msgQueueIdent(ownerWindow, localId, foreignId);\n\t\t\tif (messageQueueMap->value().count(msgQueueIdent))\n\t\t\t{\n\t\t\t\tnlassert(!_DummyWindow.getWnd()); // invisible window has just been created, it can't be in the map now!\n\t\t\t\t// message queue already exists\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (ownerWindow != _DummyWindow.getWnd())\n\t\t\t{\n\t\t\t\t// subclass window\n\t\t\t\tWNDPROC oldWinProc = (WNDPROC) GetWindowLongPtr(ownerWindow, GWLP_WNDPROC);\n\t\t\t\tuint &refCount = _OldWinProcMap[ownerWindow].RefCount;\n\t\t\t\t++ refCount;\n\t\t\t\tif (refCount == 1)\n\t\t\t\t{\n\t\t\t\t\tnlassert(oldWinProc != listenerProc); // first registration so the winproc must be different\n\t\t\t\t\tSetWindowLongPtr(ownerWindow, GWLP_WNDPROC, (LONG_PTR) listenerProc);\n\t\t\t\t\t_OldWinProcMap[ownerWindow].OldWinProc = oldWinProc;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnlassert(oldWinProc == listenerProc);\n\t\t\t\t}\n\t\t\t}\n\t\t\t//\n\t\t\tmessageQueueMap->value()[msgQueueIdent] = this;\n\t\t\t_SendTask = new CSendTask(this);\n\t\t\t_SendThread = IThread::create(_SendTask);\n\t\t\t_SendThread->start();\n\t\t\t// init the window handle in shared memory last,\n\t\t\t// this way we are sure that the new win proc has been installed, and can start received messages\n\t\t\tbool ok = _LocalWindow.init(localId) && _ForeignWindow.init(foreignId);\n\t\t\tif (!ok)\n\t\t\t{\n\t\t\t\trelease();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t_LocalWindow.setWnd(ownerWindow);\n\t\t}\n\t\treturn true;\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::release()\n\t{\n\t\tif (_LocalWindow.getWnd() != 0)\n\t\t{\n\t\t\tif (IsWindow(_LocalWindow.getWnd())) // handle gracefully case where the window has been destroyed before\n\t\t\t\t\t\t\t\t\t\t\t\t // this manager\n\t\t\t{\n\n\t\t\t\tif (_LocalWindow.getWnd() != _DummyWindow.getWnd())\n\t\t\t\t{\n\t\t\t\t\tWNDPROC currWinProc = (WNDPROC) GetWindowLongPtr(_LocalWindow.getWnd(), GWLP_WNDPROC);\n\t\t\t\t\tif (currWinProc != listenerProc)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlassert(0); // IF THIS ASSERT FIRES :\n\t\t\t\t\t\t\t\t\t // either :\n\t\t\t\t\t\t\t\t\t // - The window handle has been removed, and recreated\n\t\t\t\t\t\t\t\t\t // - The window has been hooked by someone else\n\t\t\t\t\t\t\t\t\t // in the application, but not unhooked properly.\n\t\t\t\t\t\t\t\t\t // Hook (performed at init) and unhook (performed here at release) should be\n\t\t\t\t\t\t\t\t\t // done in reverse order ! We got no way to unhook correclty, else.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (_LocalWindow.getWnd() != _DummyWindow.getWnd())\n\t\t\t{\n\t\t\t\tTOldWinProcMap::iterator it = _OldWinProcMap.find(_LocalWindow.getWnd());\n\t\t\t\tnlassert(it != _OldWinProcMap.end());\n\t\t\t\tnlassert(it->second.RefCount > 0);\n\t\t\t\t-- it->second.RefCount;\n\t\t\t\tif (it->second.RefCount == 0)\n\t\t\t\t{\n\t\t\t\t\tif (IsWindow(_LocalWindow.getWnd()))\n\t\t\t\t\t{\n\t\t\t\t\t\tSetWindowLongPtr(_LocalWindow.getWnd(), GWLP_WNDPROC, (LONG_PTR) it->second.OldWinProc);\n\t\t\t\t\t}\n\t\t\t\t\t_OldWinProcMap.erase(it);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (_SendThread)\n\t\t{\n\t\t\tif (_SendTask)\n\t\t\t{\n\t\t\t\t_SendTask->stop();\n\t\t\t\t_SendThread->wait();\n\t\t\t}\n\t\t\tdelete _SendTask;\n\t\t\tdelete _SendThread;\n\t\t\t_SendTask = NULL;\n\t\t\t_SendThread = NULL;\n\t\t}\n\t\tif (_LocalWindow.getId() != 0)\n\t\t{\n\t\t\ttypedef CSynchronized<TMessageQueueMap>::CAccessor TAccessor;\n\t\t\t// NB : use a 'new' instead of an automatic object here, because I got an 'INTERNAL COMPILER ERROR' compiler file 'msc1.cpp', line 1794\n\t\t\t// else, this is one of the way recommended by microsoft to solve the problem.\n\t\t\tstd::auto_ptr<TAccessor> messageQueueMap(new TAccessor(&_MessageQueueMap));\n\t\t\tTMessageQueueMap::iterator it = messageQueueMap->value().find(CMsgQueueIdent(_LocalWindow.getWnd(), _LocalWindow.getId(), _ForeignWindow.getId()));\n\t\t\tnlassert(it != messageQueueMap->value().end());\n\t\t\tmessageQueueMap->value().erase(it);\n\t\t}\n\t\tclearOutQueue();\n\t\t_LocalWindow.release();\n\t\t_ForeignWindow.release();\n\t\t_DummyWindow.release();\n\t}\n\n\n\t//=====================================================\n\tLRESULT CInterWindowMsgQueue::handleWMCopyData(HWND hwnd, COPYDATASTRUCT *cds)\n\t{\n\t\t// ctruct a write stream\n\t\tCMemStream msgIn;\n\t\tif (cds->lpData)\n\t\t{\n\t\t\tuint32 fromId;\n\t\t\tuint32 toId;\n\t\t\tTMsgList nestedMsgs;\n\t\t\ttry\n\t\t\t{\n\n\t\t\t\tmsgIn.serialBuffer((uint8 *) cds->lpData, cds->cbData);\n\t\t\t\t// make it a read stream\n\t\t\t\tmsgIn.resetPtrTable();\n\t\t\t\tmsgIn.invert();\n\t\t\t\tnlassert(msgIn.isReading());\n\t\t\t\tmsgIn.serialVersion(_CurrentVersion);\n\t\t\t\tmsgIn.serial(fromId);\n\t\t\t\tmsgIn.serial(toId);\n\t\t\t\tmsgIn.serialCont(nestedMsgs);\n\n\t\t\t\tCInterWindowMsgQueue messageQueue;\n\t\t\t\t{\n\t\t\t\t\ttypedef CSynchronized<TMessageQueueMap>::CAccessor TAccessor;\n\t\t\t\t\t// NB : use a 'new' instead of an automatic object here, because I got an 'INTERNAL COMPILER ERROR' compiler file 'msc1.cpp', line 1794\n\t\t\t\t\t// else, this is one of the way recommended by microsoft to solve the problem.\n\t\t\t\t\tstd::auto_ptr<TAccessor> messageQueueMap(new TAccessor(&_MessageQueueMap));\n\t\t\t\t\tTMessageQueueMap::iterator it = messageQueueMap->value().find(CMsgQueueIdent(hwnd, toId, fromId));\n\t\t\t\t\tif (it != messageQueueMap->value().end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// no mutex stuff here, we're in the main thread\n\t\t\t\t\t\tTMsgList &targetList = it->second->_InMessageQueue;\n\t\t\t\t\t\ttargetList.splice(targetList.end(), nestedMsgs); // append\n\t\t\t\t\t\treturn TRUE;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning(\"CInterWindowMsgQueue : Received inter window message from '%x' to '%x', but there's no associated message queue\", (int) fromId, (int) toId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch(const EStream &)\n\t\t\t{\n\t\t\t\tnlwarning(\"CInterWindowMsgQueue : Bad message format in inter window communication\");\n\t\t\t}\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// msg received with NULL content\n\t\t\tnlwarning(\"CInterWindowMsgQueue : NULL message received\");\n\t\t}\n\t\treturn FALSE;\n\t}\n\n\t//=====================================================\n\tLRESULT CALLBACK CInterWindowMsgQueue::listenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tif (uMsg == WM_COPYDATA) // WM_COPYDATA messages are sent by the other window to communicate with the client\n\t\t{\n\t\t\treturn handleWMCopyData(hwnd, (COPYDATASTRUCT *) lParam);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTOldWinProcMap::iterator it = _OldWinProcMap.find(hwnd);\n\t\t\tnlassert(it != _OldWinProcMap.end());\n\t\t\treturn CallWindowProc(it->second.OldWinProc, hwnd, uMsg, wParam, lParam);\n\t\t}\n\t}\n\n\t//=====================================================\n\tLRESULT CALLBACK CInterWindowMsgQueue::invisibleWindowListenerProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\n\t{\n\t\tif (uMsg == WM_COPYDATA) // WM_COPYDATA messages are sent by the other window to communicate with the client\n\t\t{\n\t\t\treturn handleWMCopyData(hwnd, (COPYDATASTRUCT *) lParam);\n\t\t}\n\t\treturn DefWindowProc(hwnd, uMsg, wParam, lParam);\n\t}\n\n\t// **************************************************************************************************\n\tCInterWindowMsgQueue::~CInterWindowMsgQueue()\n\t{\n\t\trelease();\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::clearOutQueue()\n\t{\n\t\tCSynchronized<TMsgList>::CAccessor  outMessageQueue(&_OutMessageQueue);\n\t\tif (!outMessageQueue.value().empty())\n\t\t{\n\t\t\toutMessageQueue.value().clear();\n\t\t}\n\t}\n\n\t// **************************************************************************************************\n\tvoid CInterWindowMsgQueue::sendMessage(CMemStream &msg)\n\t{\n\t\tif (!msg.isReading())\n\t\t{\n\t\t\tmsg.invert();\n\t\t}\n\t\tmsg.resetPtrTable();\n\t\t{\n\t\t\tCSynchronized<TMsgList>::CAccessor outMessageQueue(&_OutMessageQueue);\n\t\t\tstd::vector<uint8> sentMsg(msg.buffer(), msg.buffer() + msg.length());\n\t\t\toutMessageQueue.value().push_back(CMsg());\n\t\t\toutMessageQueue.value().back().Msg.swap(sentMsg);\n\t\t}\n\t}\n\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::pumpMessage(CMemStream &dest)\n\t{\n\t\tif (_InMessageQueue.empty()) return false;\n\t\tif (dest.isReading())\n\t\t{\n\t\t\tdest.invert();\n\t\t\tdest.clear();\n\t\t}\n\t\tstd::vector<uint8> &msgIn = _InMessageQueue.front().Msg;\n\t\tdest.serialBuffer(&(msgIn[0]), (uint)msgIn.size());\n\t\t_InMessageQueue.pop_front();\n\t\t// make dest a read stream\n\t\tdest.invert();\n\t\tdest.resetPtrTable();\n\t\treturn true;\n\t}\n\n\t// **************************************************************************************************\n\tbool CInterWindowMsgQueue::connected() const\n\t{\n\t\treturn const_cast<CProtagonist &>(_ForeignWindow).getWnd() != NULL;\n\t}\n\n\t// **************************************************************************************************\n\tuint CInterWindowMsgQueue::getSendQueueSize() const\n\t{\n\t\tCSynchronized<TMsgList>::CAccessor outMessageQueue(&const_cast<CSynchronized<TMsgList> &>(_OutMessageQueue));\n\t\treturn (uint)outMessageQueue.value().size();\n\t}\n\n\t// **************************************************************************************************\n\tuint CInterWindowMsgQueue::getReceiveQueueSize() const\n\t{\n\t\treturn (uint)_InMessageQueue.size();\n\t}\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n\n"
  },
  {
    "path": "code/nel/src/misc/keyboard_device.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n//#include \"nel/3d/u_keyboard_device.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NL3D {\n\n\n/*\n * Constructor\n */\n/*UKeyboardDevice::UKeyboardDevice()\n{\n}*/\n\n\n} // NL3D\n"
  },
  {
    "path": "code/nel/src/misc/line.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/line.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nvoid CLine::project(const CVector &inV,CVector &outV)\n{\n\tCVector seg = V1 - V0;\n\tfloat n = seg.sqrnorm();\n\tif (n == 0.f)\n\t{\n\t\toutV = V0;\n\t}\n\telse\n\t{\n\t\tfloat dp = (inV - V0) * seg;\n\t\toutV = V0 + (dp /  n) * seg;\n\t}\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/log.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/log.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <process.h>\n#else\n#\tinclude <unistd.h>\n#endif\n\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/log.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/path.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nstring *CLog::_ProcessName = NULL;\n\nCLog::CLog( TLogType logType) : _LogType (logType), _FileName(NULL), _Line(-1), _FuncName(NULL), _Mutex(\"LOG\"+toString((uint)logType)), _PosSet(false)\n{\n}\n\nvoid CLog::setDefaultProcessName ()\n{\n\tif (_ProcessName == NULL)\n\t{\n\t\t_ProcessName = (string *)INelContext::getInstance().getSingletonPointer(\"NLMISC::CLog::_ProcessName\");\n\t\tif (_ProcessName == NULL)\n\t\t{\n\t\t\t_ProcessName = new string;\n\t\t\tINelContext::getInstance().setSingletonPointer(\"NLMISC::CLog::_ProcessName\", _ProcessName);\n\t\t}\n\t}\n\n#ifdef NL_OS_WINDOWS\n\tif ((*_ProcessName).empty())\n\t{\n\t\tchar name[1024];\n\t\tGetModuleFileName (NULL, name, 1023);\n\t\t(*_ProcessName) = CFile::getFilename(name);\n\t}\n#else\n\tif ((*_ProcessName).empty())\n\t{\n\t\t*_ProcessName = \"<Unknown>\";\n\t}\n#endif\n}\n\nvoid CLog::setProcessName (const std::string &processName)\n{\n\tif (_ProcessName == NULL)\n\t{\n\t\t_ProcessName = (string *)INelContext::getInstance().getSingletonPointer(\"NLMISC::CLog::_ProcessName\");\n\t\tif (_ProcessName == NULL)\n\t\t{\n\t\t\t_ProcessName = new string;\n\t\t\tINelContext::getInstance().setSingletonPointer(\"NLMISC::CLog::_ProcessName\", _ProcessName);\n\t\t}\n\t}\n\n\t*_ProcessName = processName;\n}\n\nvoid CLog::setPosition (sint line, const char *fileName, const char *funcName)\n{\n\tif ( !noDisplayer() )\n\t{\n\t\t_Mutex.enter();\n\t\t_PosSet++;\n\t\t_FileName = fileName;\n\t\t_Line = line;\n\t\t_FuncName = funcName;\n\t}\n}\n\n/// Symetric to setPosition(). Automatically called by display...(). Do not call if noDisplayer().\nvoid CLog::unsetPosition()\n{\n\tnlassert( !noDisplayer() );\n\n\tif ( _PosSet > 0 )\n\t{\n\t\t_FileName = NULL;\n\t\t_Line = -1;\n\t\t_FuncName = NULL;\n\t\t_PosSet--;\n\t\t_Mutex.leave(); // needs setPosition() to have been called\n\t}\n}\n\n\nvoid CLog::addDisplayer (IDisplayer *displayer, bool bypassFilter)\n{\n\tif (displayer == NULL)\n\t{\n\t\t// Can't nlwarning because recursive call\n\t\tprintf (\"Trying to add a NULL displayer\\n\");\n\t\treturn;\n\t}\n\n\tif (bypassFilter)\n\t{\n\t\tCDisplayers::iterator idi = std::find (_BypassFilterDisplayers.begin (), _BypassFilterDisplayers.end (), displayer);\n\t\tif (idi == _BypassFilterDisplayers.end ())\n\t\t{\n\t\t\t_BypassFilterDisplayers.push_back (displayer);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"LOG: Couldn't add the displayer, it was already added\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tCDisplayers::iterator idi = std::find (_Displayers.begin (), _Displayers.end (), displayer);\n\t\tif (idi == _Displayers.end ())\n\t\t{\n\t\t\t_Displayers.push_back (displayer);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"LOG: Couldn't add the displayer, it was already added\");\n\t\t}\n\t}\n}\n\nvoid CLog::removeDisplayer (IDisplayer *displayer)\n{\n\tif (displayer == NULL)\n\t{\n\t\tnlwarning (\"LOG: Trying to remove a NULL displayer\");\n\t\treturn;\n\t}\n\n\tCDisplayers::iterator idi = std::find (_Displayers.begin (), _Displayers.end (), displayer);\n\tif (idi != _Displayers.end ())\n\t{\n\t\t_Displayers.erase (idi);\n\t}\n\n\tidi = std::find (_BypassFilterDisplayers.begin (), _BypassFilterDisplayers.end (), displayer);\n\tif (idi != _BypassFilterDisplayers.end ())\n\t{\n\t\t_BypassFilterDisplayers.erase (idi);\n\t}\n\n}\n\nvoid CLog::removeDisplayer (const char *displayerName)\n{\n\tif (displayerName == NULL || displayerName[0] == '\\0')\n\t{\n\t\tnlwarning (\"LOG: Trying to remove an empty displayer name\");\n\t\treturn;\n\t}\n\n\tCDisplayers::iterator idi;\n\tfor (idi = _Displayers.begin (); idi != _Displayers.end ();)\n\t{\n\t\tif ((*idi)->DisplayerName == displayerName)\n\t\t{\n\t\t\tidi = _Displayers.erase (idi);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tidi++;\n\t\t}\n\t}\n\n\tfor (idi = _BypassFilterDisplayers.begin (); idi != _BypassFilterDisplayers.end ();)\n\t{\n\t\tif ((*idi)->DisplayerName == displayerName)\n\t\t{\n\t\t\tidi = _BypassFilterDisplayers.erase (idi);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tidi++;\n\t\t}\n\t}\n}\n\nIDisplayer *CLog::getDisplayer (const char *displayerName)\n{\n\tif (displayerName == NULL || displayerName[0] == '\\0')\n\t{\n\t\tnlwarning (\"LOG: Trying to get an empty displayer name\");\n\t\treturn NULL;\n\t}\n\n\tCDisplayers::iterator idi;\n\tfor (idi = _Displayers.begin (); idi != _Displayers.end (); idi++)\n\t{\n\t\tif ((*idi)->DisplayerName == displayerName)\n\t\t{\n\t\t\treturn *idi;\n\t\t}\n\t}\n\tfor (idi = _BypassFilterDisplayers.begin (); idi != _BypassFilterDisplayers.end (); idi++)\n\t{\n\t\tif ((*idi)->DisplayerName == displayerName)\n\t\t{\n\t\t\treturn *idi;\n\t\t}\n\t}\n\treturn NULL;\n}\n\n/*\n * Returns true if the specified displayer is attached to the log object\n */\nbool CLog::attached(IDisplayer *displayer) const\n{\n\treturn (find( _Displayers.begin(), _Displayers.end(), displayer ) != _Displayers.end()) ||\n\t\t\t(find( _BypassFilterDisplayers.begin(), _BypassFilterDisplayers.end(), displayer ) != _BypassFilterDisplayers.end());\n}\n\n\nvoid CLog::displayString (const char *str)\n{\n\tconst char *disp = NULL;\n\tTDisplayInfo localargs, *args = NULL;\n\n\tsetDefaultProcessName ();\n\n\tif(strchr(str,'\\n') == NULL)\n\t{\n\t\tif (TempString.empty())\n\t\t{\n\t\t\ttime (&TempArgs.Date);\n\t\t\tTempArgs.LogType = _LogType;\n\t\t\tTempArgs.ProcessName = *_ProcessName;\n\t\t\tTempArgs.ThreadId = getThreadId();\n\t\t\tTempArgs.FileName = _FileName;\n\t\t\tTempArgs.Line = _Line;\n\t\t\tTempArgs.FuncName = _FuncName;\n\t\t\tTempArgs.CallstackAndLog = \"\";\n\n\t\t\tTempString = str;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTempString += str;\n\t\t}\n\t\treturn;\n\t}\n\telse\n\t{\n\t\tif (TempString.empty())\n\t\t{\n\t\t\ttime (&localargs.Date);\n\t\t\tlocalargs.LogType = _LogType;\n\t\t\tlocalargs.ProcessName = *_ProcessName;\n\t\t\tlocalargs.ThreadId = getThreadId();\n\t\t\tlocalargs.FileName = _FileName;\n\t\t\tlocalargs.Line = _Line;\n\t\t\tlocalargs.FuncName = _FuncName;\n\t\t\tlocalargs.CallstackAndLog = \"\";\n\n\t\t\tdisp = str;\n\t\t\targs = &localargs;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTempString += str;\n\t\t\tdisp = TempString.c_str();\n\t\t\targs = &TempArgs;\n\t\t}\n\t}\n\n\t// send to all bypass filter displayers\n\tfor (CDisplayers::iterator idi=_BypassFilterDisplayers.begin(); idi!=_BypassFilterDisplayers.end(); idi++ )\n\t{\n\t\t(*idi)->display( *args, disp );\n\t}\n\n\t// get the log at the last minute to be sure to have everything\n\tif(args->LogType == LOG_ERROR || args->LogType == LOG_ASSERT)\n\t{\n\t\tgetCallStackAndLog (args->CallstackAndLog, 4);\n\t}\n\n\tif (passFilter (disp))\n\t{\n\t\t// Send to the attached displayers\n\t\tfor (CDisplayers::iterator idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )\n\t\t{\n\t\t\t(*idi)->display( *args, disp );\n\t\t}\n\t}\n\tTempString = \"\";\n\tunsetPosition();\n}\n\n\n/*\n * Display the string with decoration and final new line to all attached displayers\n */\n#ifdef NL_OS_WINDOWS\nvoid CLog::_displayNL (const char *format, ...)\n#else\nvoid CLog::displayNL (const char *format, ...)\n#endif\n{\n\tif ( noDisplayer() )\n\t{\n\t\treturn;\n\t}\n\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tif (strlen(str)<NLMISC::MaxCStringSize-1)\n\t\tstrcat (str, \"\\n\");\n\telse\n\t\tstr[NLMISC::MaxCStringSize-2] = '\\n';\n\n\tdisplayString (str);\n}\n\n/*\n * Display the string with decoration to all attached displayers\n */\n#ifdef NL_OS_WINDOWS\nvoid CLog::_display (const char *format, ...)\n#else\nvoid CLog::display (const char *format, ...)\n#endif\n{\n\tif ( noDisplayer() )\n\t{\n\t\treturn;\n\t}\n\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tdisplayString (str);\n}\n\nvoid CLog::displayRawString (const char *str)\n{\n\tconst char *disp = NULL;\n\tTDisplayInfo localargs, *args = NULL;\n\n\tsetDefaultProcessName ();\n\n\tif(strchr(str,'\\n') == NULL)\n\t{\n\t\tif (TempString.empty())\n\t\t{\n\t\t\tlocalargs.Date = 0;\n\t\t\tlocalargs.LogType = CLog::LOG_NO;\n\t\t\tlocalargs.ProcessName = \"\";\n\t\t\tlocalargs.ThreadId = 0;\n\t\t\tlocalargs.FileName = NULL;\n\t\t\tlocalargs.Line = -1;\n\t\t\tlocalargs.CallstackAndLog = \"\";\n\n\t\t\tTempString = str;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTempString += str;\n\t\t}\n\t\treturn;\n\t}\n\telse\n\t{\n\t\tif (TempString.empty())\n\t\t{\n\t\t\tlocalargs.Date = 0;\n\t\t\tlocalargs.LogType = CLog::LOG_NO;\n\t\t\tlocalargs.ProcessName = \"\";\n\t\t\tlocalargs.ThreadId = 0;\n\t\t\tlocalargs.FileName = NULL;\n\t\t\tlocalargs.Line = -1;\n\t\t\tlocalargs.CallstackAndLog = \"\";\n\n\t\t\tdisp = str;\n\t\t\targs = &localargs;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTempString += str;\n\t\t\tdisp = TempString.c_str();\n\t\t\targs = &TempArgs;\n\t\t}\n\t}\n\n\t// send to all bypass filter displayers\n\tfor (CDisplayers::iterator idi=_BypassFilterDisplayers.begin(); idi!=_BypassFilterDisplayers.end(); idi++ )\n\t{\n\t\t(*idi)->display( *args, disp );\n\t}\n\n\t// get the log at the last minute to be sure to have everything\n\tif(args->LogType == LOG_ERROR || args->LogType == LOG_ASSERT)\n\t{\n\t\tgetCallStackAndLog (args->CallstackAndLog, 4);\n\t}\n\n\tif ( passFilter( disp ) )\n\t{\n\t\t// Send to the attached displayers\n\t\tfor ( CDisplayers::iterator idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )\n\t\t{\n\t\t\t(*idi)->display( *args, disp );\n\t\t}\n\t}\n\tTempString.clear();\n\tunsetPosition();\n}\n\n/*\n * Display a string (and nothing more) to all attached displayers\n */\n#ifdef NL_OS_WINDOWS\nvoid CLog::_displayRawNL( const char *format, ... )\n#else\nvoid CLog::displayRawNL( const char *format, ... )\n#endif\n{\n\tif ( noDisplayer() )\n\t{\n\t\treturn;\n\t}\n\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tif (strlen(str)<NLMISC::MaxCStringSize-1)\n\t\tstrcat (str, \"\\n\");\n\telse\n\t\tstr[NLMISC::MaxCStringSize-2] = '\\n';\n\n\tdisplayRawString(str);\n}\n\n/*\n * Display a string (and nothing more) to all attached displayers\n */\n#ifdef NL_OS_WINDOWS\nvoid CLog::_displayRaw( const char *format, ... )\n#else\nvoid CLog::displayRaw( const char *format, ... )\n#endif\n{\n\tif ( noDisplayer() )\n\t{\n\t\treturn;\n\t}\n\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tdisplayRawString(str);\n}\n\n\n#ifdef NL_OS_WINDOWS\nvoid CLog::_forceDisplayRaw (const char *format, ...)\n#else\nvoid CLog::forceDisplayRaw (const char *format, ...)\n#endif\n{\n\tif ( noDisplayer() )\n\t{\n\t\treturn;\n\t}\n\n\tchar *str;\n\tNLMISC_CONVERT_VARGS (str, format, NLMISC::MaxCStringSize);\n\n\tTDisplayInfo args;\n\tCDisplayers::iterator idi;\n\n\t// send to all bypass filter displayers\n\tfor (idi=_BypassFilterDisplayers.begin(); idi!=_BypassFilterDisplayers.end(); idi++ )\n\t{\n\t\t(*idi)->display( args, str );\n\t}\n\n\t// Send to the attached displayers\n\tfor ( idi=_Displayers.begin(); idi!=_Displayers.end(); idi++ )\n\t{\n\t\t(*idi)->display( args, str );\n\t}\n}\n\n\n\n/*\n * Returns true if the string must be logged, according to the current filter\n */\nbool CLog::passFilter( const char *filter )\n{\n\tbool yes = _PositiveFilter.empty();\n\n\tbool found;\n\tlist<string>::iterator ilf;\n\n\t// 1. Positive filter\n\tfor ( ilf=_PositiveFilter.begin(); ilf!=_PositiveFilter.end(); ++ilf )\n\t{\n\t\tfound = ( strstr( filter, (*ilf).c_str() ) != NULL );\n\t\tif ( found )\n\t\t{\n\t\t\tyes = true; // positive filter passed (no need to check another one)\n\t\t\tbreak;\n\t\t}\n\t\t// else try the next one\n\t}\n\tif ( ! yes )\n\t{\n\t\treturn false; // positive filter not passed\n\t}\n\n\t// 2. Negative filter\n\tfor ( ilf=_NegativeFilter.begin(); ilf!=_NegativeFilter.end(); ++ilf )\n\t{\n\t\tfound = ( strstr( filter, (*ilf).c_str() ) != NULL );\n\t\tif ( found )\n\t\t{\n\t\t\treturn false; // negative filter not passed (no need to check another one)\n\t\t}\n\t}\n\treturn true; // negative filter passed\n}\n\n\n/*\n * Removes a filter by name. Returns true if it was found.\n */\nvoid CLog::removeFilter( const char *filterstr )\n{\n\tif (filterstr == NULL)\n\t{\n\t\t_PositiveFilter.clear();\n\t\t_NegativeFilter.clear();\n\t\t//displayNL (\"CLog::addNegativeFilter('%s')\", filterstr);\n\t}\n\telse\n\t{\n\t\t_PositiveFilter.remove( filterstr );\n\t\t_NegativeFilter.remove( filterstr );\n\t\t//displayNL (\"CLog::removeFilter('%s')\", filterstr);\n\t}\n}\n\nvoid CLog::displayFilter( CLog &log )\n{\n\tstd::list<std::string>::iterator it;\n\tlog.displayNL (\"Positive Filter(s):\");\n\tfor (it = _PositiveFilter.begin (); it != _PositiveFilter.end (); it++)\n\t{\n\t\tlog.displayNL (\"'%s'\", (*it).c_str());\n\t}\n\tlog.displayNL (\"Negative Filter(s):\");\n\tfor (it = _NegativeFilter.begin (); it != _NegativeFilter.end (); it++)\n\t{\n\t\tlog.displayNL (\"'%s'\", (*it).c_str());\n\t}\n}\n\nvoid CLog::addPositiveFilter( const char *filterstr )\n{\n\t//displayNL (\"CLog::addPositiveFilter('%s')\", filterstr);\n\t_PositiveFilter.push_back( filterstr );\n}\n\nvoid CLog::addNegativeFilter( const char *filterstr )\n{\n\t//displayNL (\"CLog::addNegativeFilter('%s')\", filterstr);\n\t_NegativeFilter.push_back( filterstr );\n}\n\nvoid CLog::resetFilters()\n{\n\t//displayNL (\"CLog::resetFilter()\");\n\t_PositiveFilter.clear();\n\t_NegativeFilter.clear();\n}\n\n/// Do not call this unless you know why you're doing it, it kills the debug/log system!\nvoid CLog::releaseProcessName()\n{\n\tif (INelContext::isContextInitialised())\n\t{\n\t\tINelContext::getInstance().releaseSingletonPointer(\"NLMISC::CLog::_ProcessName\", _ProcessName);\n\t}\n\tdelete _ProcessName;\n\t_ProcessName = NULL;\n}\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/matrix.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/matrix.h\"\n#include \"nel/misc/plane.h\"\n#include \"nel/misc/debug.h\"\n\nusing namespace std;\n\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n\n// ======================================================================================================\nconst CMatrix\tCMatrix::Identity;\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// State Bits.\n#define\tMAT_TRANS\t\t1\n#define\tMAT_ROT\t\t\t2\n#define\tMAT_SCALEUNI\t4\n#define\tMAT_SCALEANY\t8\n#define\tMAT_PROJ\t\t16\n// Validity bits. These means that the part may be yet identity, but is valid in the floats.\n// NB: MAT_VALIDTRANS no more used for faster Pos access\n#define\tMAT_VALIDROT\t64\n#define\tMAT_VALIDPROJ\t128\n#define\tMAT_VALIDALL\t(MAT_VALIDROT | MAT_VALIDPROJ)\n// The identity is nothing.\n#define\tMAT_IDENTITY\t0\n\n\n\n// Matrix elements.\n#define\ta11\t\tM[0]\n#define\ta21\t\tM[1]\n#define\ta31\t\tM[2]\n#define\ta41\t\tM[3]\n#define\ta12\t\tM[4]\n#define\ta22\t\tM[5]\n#define\ta32\t\tM[6]\n#define\ta42\t\tM[7]\n#define\ta13\t\tM[8]\n#define\ta23\t\tM[9]\n#define\ta33\t\tM[10]\n#define\ta43\t\tM[11]\n#define\ta14\t\tM[12]\n#define\ta24\t\tM[13]\n#define\ta34\t\tM[14]\n#define\ta44\t\tM[15]\n\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n\n// ======================================================================================================\nbool\t\tCMatrix::hasScalePart() const\n{\n\treturn (StateBit&(MAT_SCALEUNI|MAT_SCALEANY))!=0;\n}\nbool\t\tCMatrix::hasProjectionPart() const\n{\n\treturn (StateBit&MAT_PROJ)!=0;\n}\n\n\nbool\t\tCMatrix::hasScaleUniform() const\n{\n\treturn (StateBit & (MAT_SCALEUNI|MAT_SCALEANY))== MAT_SCALEUNI;\n}\nfloat\t\tCMatrix::getScaleUniform() const\n{\n\tif(hasScaleUniform())\n\t\treturn Scale33;\n\telse\n\t\treturn 1;\n}\n\n\n\n// ======================================================================================================\ninline bool\tCMatrix::hasRot() const\n{\n\treturn (StateBit&(MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY))!=0;\n}\ninline bool\tCMatrix::hasTrans() const\n{\n\treturn (StateBit&MAT_TRANS)!=0;\n}\ninline bool\tCMatrix::hasProj() const\n{\n\treturn (StateBit&MAT_PROJ)!=0;\n}\ninline bool\tCMatrix::hasAll() const\n{\n\treturn (hasRot() && hasTrans() && hasProj());\n}\n\n\ninline void CMatrix::testExpandRot() const\n{\n\tif(hasRot())\n\t\treturn;\n\tif(!(StateBit&MAT_VALIDROT))\n\t{\n\t\tCMatrix\t*self= const_cast<CMatrix*>(this);\n\t\tself->StateBit|=MAT_VALIDROT;\n\t\tself->a11= 1; self->a12=0; self->a13=0;\n\t\tself->a21= 0; self->a22=1; self->a23=0;\n\t\tself->a31= 0; self->a32=0; self->a33=1;\n\t\tself->Scale33= 1;\n\t}\n}\n\ninline void CMatrix::testExpandProj() const\n{\n\tif(hasProj())\n\t\treturn;\n\tif(!(StateBit&MAT_VALIDPROJ))\n\t{\n\t\tCMatrix\t*self= const_cast<CMatrix*>(this);\n\t\tself->StateBit|=MAT_VALIDPROJ;\n\t\tself->a41=0; self->a42=0; self->a43=0; self->a44=1;\n\t}\n}\n\n\n// ======================================================================================================\nCMatrix::CMatrix(const CMatrix &m)\n{\n\t(*this)= m;\n}\n// ======================================================================================================\nCMatrix\t\t&CMatrix::operator=(const CMatrix &m)\n{\n\tStateBit= m.StateBit & ~MAT_VALIDALL;\n\tif(hasAll())\n\t{\n\t\tmemcpy(M, m.M, 16*sizeof(float));\n\t\tScale33= m.Scale33;\n\t}\n\telse\n\t{\n\t\tif(hasRot())\n\t\t{\n\t\t\tmemcpy(&a11, &m.a11, 3*sizeof(float));\n\t\t\tmemcpy(&a12, &m.a12, 3*sizeof(float));\n\t\t\tmemcpy(&a13, &m.a13, 3*sizeof(float));\n\t\t\tScale33= m.Scale33;\n\t\t}\n\t\tif(hasProj())\n\t\t{\n\t\t\ta41= m.a41;\n\t\t\ta42= m.a42;\n\t\t\ta43= m.a43;\n\t\t\ta44= m.a44;\n\t\t}\n\t\t// Must always copy Trans part.\n\t\tmemcpy(&a14, &m.a14, 3*sizeof(float));\n\t}\n\treturn *this;\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::identity()\n{\n\tStateBit= MAT_IDENTITY;\n\t// Reset just Pos because must always be valid for faster getPos()\n\ta14= a24= a34= 0;\n\t// For optimisation it would be useful to keep MAT_VALID states.\n\t// But this slows identity(), and this may not be interesting...\n}\n// ======================================================================================================\nvoid\t\tCMatrix::setRot(const CVector &i, const CVector &j, const CVector &k, bool hintNoScale)\n{\n\tStateBit|= MAT_ROT | MAT_SCALEANY;\n\tif(hintNoScale)\n\t\tStateBit&= ~(MAT_SCALEANY|MAT_SCALEUNI);\n\ta11= i.x; a12= j.x; a13= k.x;\n\ta21= i.y; a22= j.y; a23= k.y;\n\ta31= i.z; a32= j.z; a33= k.z;\n\tScale33= 1.0f;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::setRot(const float m33[9], bool hintNoScale)\n{\n\tStateBit|= MAT_ROT | MAT_SCALEANY;\n\tif(hintNoScale)\n\t\tStateBit&= ~(MAT_SCALEANY|MAT_SCALEUNI);\n\ta11= m33[0]; a12= m33[3]; a13= m33[6];\n\ta21= m33[1]; a22= m33[4]; a23= m33[7];\n\ta31= m33[2]; a32= m33[5]; a33= m33[8];\n\tScale33= 1.0f;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::setRot(const CVector &v, TRotOrder ro)\n{\n\tCMatrix\t\trot;\n\trot.identity();\n\trot.rotate(v, ro);\n\tfloat\tm33[9];\n\trot.getRot(m33);\n\tsetRot(m33, true);\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::setRot(const CMatrix &matrix)\n{\n\t// copy rotpart statebit from other.\n\tStateBit&= ~(MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY);\n\tStateBit|= matrix.StateBit & (MAT_ROT | MAT_SCALEUNI | MAT_SCALEANY);\n\t// copy values.\n\tif(hasRot())\n\t{\n\t\ta11= matrix.a11; a12= matrix.a12; a13= matrix.a13;\n\t\ta21= matrix.a21; a22= matrix.a22; a23= matrix.a23;\n\t\ta31= matrix.a31; a32= matrix.a32; a33= matrix.a33;\n\t\t// if has scale uniform, copy from matrix.\n\t\tif(hasScaleUniform())\n\t\t\tScale33= matrix.Scale33;\n\t}\n\telse\n\t{\n\t\t// we are rot identity, with undefined values.\n\t\tStateBit&= ~MAT_VALIDROT;\n\t}\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::setPos(const CVector &v)\n{\n\ta14= v.x;\n\ta24= v.y;\n\ta34= v.z;\n\tif(a14!=0 || a24!=0 || a34!=0)\n\t\tStateBit|= MAT_TRANS;\n\telse\n\t\t// The trans is identity\n\t\tStateBit&= ~MAT_TRANS;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::movePos(const CVector &v)\n{\n\ta14+= v.x;\n\ta24+= v.y;\n\ta34+= v.z;\n\tif(a14!=0 || a24!=0 || a34!=0)\n\t\tStateBit|= MAT_TRANS;\n\telse\n\t\t// The trans is identity\n\t\tStateBit&= ~MAT_TRANS;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::setProj(const float proj[4])\n{\n\ta41= proj[0];\n\ta42= proj[1];\n\ta43= proj[2];\n\ta44= proj[3];\n\n\t// Check Proj state.\n\tif(a41!=0 || a42!=0 || a43!=0 || a44!=1)\n\t\tStateBit|= MAT_PROJ;\n\telse\n\t{\n\t\t// The proj is identity, and is correcly setup!\n\t\tStateBit&= ~MAT_PROJ;\n\t\tStateBit|= MAT_VALIDPROJ;\n\t}\n}\n// ======================================================================================================\nvoid\t\tCMatrix::resetProj()\n{\n\ta41= 0;\n\ta42= 0;\n\ta43= 0;\n\ta44= 1;\n\t// The proj is identity, and is correcly setup!\n\tStateBit&= ~MAT_PROJ;\n\tStateBit|= MAT_VALIDPROJ;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::set(const float m44[16])\n{\n\tStateBit= MAT_IDENTITY;\n\n\tStateBit|= MAT_ROT | MAT_SCALEANY;\n\tmemcpy(M, m44, 16*sizeof(float));\n\tScale33= 1.0f;\n\n\t// Check Trans state.\n\tif(a14!=0 || a24!=0 || a34!=0)\n\t\tStateBit|= MAT_TRANS;\n\telse\n\t\t// The trans is identity\n\t\tStateBit&= ~MAT_TRANS;\n\n\t// Check Proj state.\n\tif(a41!=0 || a42!=0 || a43!=0 || a44!=1)\n\t\tStateBit|= MAT_PROJ;\n\telse\n\t{\n\t\t// The proj is identity, and is correcly setup!\n\t\tStateBit&= ~MAT_PROJ;\n\t\tStateBit|= MAT_VALIDPROJ;\n\t}\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::getRot(CVector &i, CVector &j, CVector &k) const\n{\n\tif(hasRot())\n\t{\n\t\ti.set(a11, a21, a31);\n\t\tj.set(a12, a22, a32);\n\t\tk.set(a13, a23, a33);\n\t}\n\telse\n\t{\n\t\ti.set(1, 0, 0);\n\t\tj.set(0, 1, 0);\n\t\tk.set(0, 0, 1);\n\t}\n}\n// ======================================================================================================\nvoid\t\tCMatrix::getRot(float m33[9]) const\n{\n\tif(hasRot())\n\t{\n\t\tm33[0]= a11;\n\t\tm33[1]= a21;\n\t\tm33[2]= a31;\n\n\t\tm33[3]= a12;\n\t\tm33[4]= a22;\n\t\tm33[5]= a32;\n\n\t\tm33[6]= a13;\n\t\tm33[7]= a23;\n\t\tm33[8]= a33;\n\t}\n\telse\n\t{\n\t\tm33[0]= 1;\n\t\tm33[1]= 0;\n\t\tm33[2]= 0;\n\n\t\tm33[3]= 0;\n\t\tm33[4]= 1;\n\t\tm33[5]= 0;\n\n\t\tm33[6]= 0;\n\t\tm33[7]= 0;\n\t\tm33[8]= 1;\n\t}\n}\n// ======================================================================================================\nvoid\t\tCMatrix::getProj(float proj[4]) const\n{\n\tif(hasProj())\n\t{\n\t\tproj[0]= a41;\n\t\tproj[1]= a42;\n\t\tproj[2]= a43;\n\t\tproj[3]= a44;\n\t}\n\telse\n\t{\n\t\tproj[0]= 0;\n\t\tproj[1]= 0;\n\t\tproj[2]= 0;\n\t\tproj[3]= 1;\n\t}\n}\n// ======================================================================================================\nCVector\t\tCMatrix::getI() const\n{\n\tif(hasRot())\n\t\treturn CVector(a11, a21, a31);\n\telse\n\t\treturn CVector(1, 0, 0);\n}\n// ======================================================================================================\nCVector\t\tCMatrix::getJ() const\n{\n\tif(hasRot())\n\t\treturn CVector(a12, a22, a32);\n\telse\n\t\treturn CVector(0, 1, 0);\n}\n// ======================================================================================================\nCVector\t\tCMatrix::getK() const\n{\n\tif(hasRot())\n\t\treturn CVector(a13, a23, a33);\n\telse\n\t\treturn CVector(0, 0, 1);\n}\n// ======================================================================================================\nvoid\t\tCMatrix::get(float m44[16]) const\n{\n\ttestExpandRot();\n\ttestExpandProj();\n\tmemcpy(m44, M, 16*sizeof(float));\n}\n// ======================================================================================================\nconst float *CMatrix::get() const\n{\n\ttestExpandRot();\n\ttestExpandProj();\n\treturn M;\n}\n/*// ======================================================================================================\nCVector\t\tCMatrix::toEuler(TRotOrder ro) const\n{\n\n}*/\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::translate(const CVector &v)\n{\n\t// SetTrans.\n\tif( hasRot() )\n\t{\n\t\ta14+= a11*v.x + a12*v.y + a13*v.z;\n\t\ta24+= a21*v.x + a22*v.y + a23*v.z;\n\t\ta34+= a31*v.x + a32*v.y + a33*v.z;\n\t}\n\telse\n\t{\n\t\ta14+= v.x;\n\t\ta24+= v.y;\n\t\ta34+= v.z;\n\t}\n\n\t// SetProj.\n\tif( hasProj() )\n\t\ta44+= a41*v.x + a42*v.y + a43*v.z;\n\n\t// Check Trans.\n\tif(a14!=0 || a24!=0 || a34!=0)\n\t\tStateBit|= MAT_TRANS;\n\telse\n\t\t// The trans is identity, and is correcly setup!\n\t\tStateBit&= ~MAT_TRANS;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::rotateX(float a)\n{\n\n\tif(a==0)\n\t\treturn;\n\tdouble\tca,sa;\n\tca=cos(a);\n\tsa=sin(a);\n\n\t// SetRot.\n\tif( hasRot() )\n\t{\n\t\tfloat\tb12=a12, b22=a22, b32=a32;\n\t\tfloat\tb13=a13, b23=a23, b33=a33;\n\t\ta12= (float)(b12*ca + b13*sa);\n\t\ta22= (float)(b22*ca + b23*sa);\n\t\ta32= (float)(b32*ca + b33*sa);\n\t\ta13= (float)(b13*ca - b12*sa);\n\t\ta23= (float)(b23*ca - b22*sa);\n\t\ta33= (float)(b33*ca - b32*sa);\n\t}\n\telse\n\t{\n\t\ttestExpandRot();\n\t\ta12= 0.0f; a22= (float)ca; a32= (float)sa;\n\t\ta13= 0.0f; a23= (float)-sa; a33= (float)ca;\n\t}\n\n\t// SetProj.\n\tif( hasProj() )\n\t{\n\t\tfloat\tb42=a42, b43=a43;\n\t\ta42= (float)(b42*ca + b43*sa);\n\t\ta43= (float)(b43*ca - b42*sa);\n\t}\n\n\t// set Rot.\n\tStateBit|= MAT_ROT;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::rotateY(float a)\n{\n\n\tif(a==0)\n\t\treturn;\n\tdouble\tca,sa;\n\tca=cos(a);\n\tsa=sin(a);\n\n\t// SetRot.\n\tif( hasRot() )\n\t{\n\t\tfloat\tb11=a11, b21=a21, b31=a31;\n\t\tfloat\tb13=a13, b23=a23, b33=a33;\n\t\ta11= (float)(b11*ca - b13*sa);\n\t\ta21= (float)(b21*ca - b23*sa);\n\t\ta31= (float)(b31*ca - b33*sa);\n\t\ta13= (float)(b13*ca + b11*sa);\n\t\ta23= (float)(b23*ca + b21*sa);\n\t\ta33= (float)(b33*ca + b31*sa);\n\t}\n\telse\n\t{\n\t\ttestExpandRot();\n\t\ta11= (float)ca; a21=0.0f; a31= (float)-sa;\n\t\ta13= (float)sa; a23=0.0f; a33= (float)ca;\n\t}\n\n\t// SetProj.\n\tif( hasProj() )\n\t{\n\t\tfloat\tb41=a41, b43=a43;\n\t\ta41= (float)(b41*ca - b43*sa);\n\t\ta43= (float)(b43*ca + b41*sa);\n\t}\n\n\t// set Rot.\n\tStateBit|= MAT_ROT;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::rotateZ(float a)\n{\n\n\tif(a==0)\n\t\treturn;\n\tdouble\tca,sa;\n\tca=cos(a);\n\tsa=sin(a);\n\n\t// SetRot.\n\tif( StateBit & (MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY) )\n\t{\n\t\tfloat\tb11=a11, b21=a21, b31=a31;\n\t\tfloat\tb12=a12, b22=a22, b32=a32;\n\t\ta11= (float)(b11*ca + b12*sa);\n\t\ta21= (float)(b21*ca + b22*sa);\n\t\ta31= (float)(b31*ca + b32*sa);\n\t\ta12= (float)(b12*ca - b11*sa);\n\t\ta22= (float)(b22*ca - b21*sa);\n\t\ta32= (float)(b32*ca - b31*sa);\n\t}\n\telse\n\t{\n\t\ttestExpandRot();\n\t\ta11= (float)ca; a21= (float)sa; a31=0.0f;\n\t\ta12= (float)-sa; a22= (float)ca; a32=0.0f;\n\t}\n\n\t// SetProj.\n\tif( hasProj() )\n\t{\n\t\tfloat\tb41=a41, b42=a42;\n\t\ta41= (float)(b41*ca + b42*sa);\n\t\ta42= (float)(b42*ca - b41*sa);\n\t}\n\n\t// set Rot.\n\tStateBit|= MAT_ROT;\n}\n// ======================================================================================================\nvoid\t\tCMatrix::rotate(const CVector &v, TRotOrder ro)\n{\n\tCMatrix\t\trot;\n\trot.identity();\n\tswitch(ro)\n\t{\n\t\tcase XYZ: rot.rotateX(v.x); rot.rotateY(v.y); rot.rotateZ(v.z); break;\n\t\tcase XZY: rot.rotateX(v.x); rot.rotateZ(v.z); rot.rotateY(v.y); break;\n\t\tcase YXZ: rot.rotateY(v.y); rot.rotateX(v.x); rot.rotateZ(v.z); break;\n\t\tcase YZX: rot.rotateY(v.y); rot.rotateZ(v.z); rot.rotateX(v.x); break;\n\t\tcase ZXY: rot.rotateZ(v.z); rot.rotateX(v.x); rot.rotateY(v.y); break;\n\t\tcase ZYX: rot.rotateZ(v.z); rot.rotateY(v.y); rot.rotateX(v.x); break;\n\t}\n\n\t(*this)*= rot;\n}\n\n// ======================================================================================================\nvoid\t\tCMatrix::rotate(const CQuat &quat)\n{\n\tCMatrix\t\trot;\n\trot.setRot(quat);\n\t(*this)*= rot;\n}\n\n// ======================================================================================================\nvoid\t\tCMatrix::scale(float f)\n{\n\n\tif(f==1.0f) return;\n\tif(StateBit & MAT_SCALEANY)\n\t{\n\t\tscale(CVector(f,f,f));\n\t}\n\telse\n\t{\n\t\ttestExpandRot();\n\t\tStateBit|= MAT_SCALEUNI;\n\t\tScale33*=f;\n\t\ta11*= f; a12*=f; a13*=f;\n\t\ta21*= f; a22*=f; a23*=f;\n\t\ta31*= f; a32*=f; a33*=f;\n\n\t\t// SetProj.\n\t\tif( hasProj() )\n\t\t{\n\t\t\ta41*=f; a42*=f; a43*=f;\n\t\t}\n\t}\n}\n// ======================================================================================================\nvoid\t\tCMatrix::scale(const CVector &v)\n{\n\n\tif( v==CVector(1,1,1) ) return;\n\tif( !(StateBit & MAT_SCALEANY) && v.x==v.y && v.x==v.z)\n\t{\n\t\tscale(v.x);\n\t}\n\telse\n\t{\n\t\ttestExpandRot();\n\t\tStateBit|=MAT_SCALEANY;\n\t\ta11*= v.x; a12*=v.y; a13*=v.z;\n\t\ta21*= v.x; a22*=v.y; a23*=v.z;\n\t\ta31*= v.x; a32*=v.y; a33*=v.z;\n\n\t\t// SetProj.\n\t\tif( hasProj() )\n\t\t{\n\t\t\ta41*=v.x;\n\t\t\ta42*=v.y;\n\t\t\ta43*=v.z;\n\t\t}\n\t}\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ***************************************************************************\nvoid\t\tCMatrix::setMulMatrixNoProj(const CMatrix &m1, const CMatrix &m2)\n{\n\t/*\n\tFor a fast MulMatrix, it appears to be better to not take State bits into account (no test/if() overhead)\n\tJust do heavy mul all the time (common case, and not so slow)\n\t*/\n\n\t// Ensure the src matrix have correct values in rot part\n\tm1.testExpandRot();\n\tm2.testExpandRot();\n\n\t// Rot Mul\n\ta11= m1.a11*m2.a11 + m1.a12*m2.a21 + m1.a13*m2.a31;\n\ta12= m1.a11*m2.a12 + m1.a12*m2.a22 + m1.a13*m2.a32;\n\ta13= m1.a11*m2.a13 + m1.a12*m2.a23 + m1.a13*m2.a33;\n\n\ta21= m1.a21*m2.a11 + m1.a22*m2.a21 + m1.a23*m2.a31;\n\ta22= m1.a21*m2.a12 + m1.a22*m2.a22 + m1.a23*m2.a32;\n\ta23= m1.a21*m2.a13 + m1.a22*m2.a23 + m1.a23*m2.a33;\n\n\ta31= m1.a31*m2.a11 + m1.a32*m2.a21 + m1.a33*m2.a31;\n\ta32= m1.a31*m2.a12 + m1.a32*m2.a22 + m1.a33*m2.a32;\n\ta33= m1.a31*m2.a13 + m1.a32*m2.a23 + m1.a33*m2.a33;\n\n\t// Trans mul\n\ta14= m1.a11*m2.a14 + m1.a12*m2.a24 + m1.a13*m2.a34 + m1.a14;\n\ta24= m1.a21*m2.a14 + m1.a22*m2.a24 + m1.a23*m2.a34 + m1.a24;\n\ta34= m1.a31*m2.a14 + m1.a32*m2.a24 + m1.a33*m2.a34 + m1.a34;\n\n\t// Setup no proj at all, and force valid rot (still may be identity, but 0/1 are filled)\n\tStateBit= (m1.StateBit | m2.StateBit | MAT_VALIDROT) & ~(MAT_PROJ|MAT_VALIDPROJ);\n\n\t// Modify Scale. This test is important because Scale33 may be a #NAN if SCALEANY => avoid very slow mul.\n\tif( hasScaleUniform() )\n\t\tScale33= m1.Scale33*m2.Scale33;\n\telse\n\t\tScale33=1;\n\n}\n\n\n// ***************************************************************************\nvoid\t\tCMatrix::setMulMatrix(const CMatrix &m1, const CMatrix &m2)\n{\n\t// Do *this= m1*m2\n\tidentity();\n\tStateBit= m1.StateBit | m2.StateBit;\n\tStateBit&= ~MAT_VALIDALL;\n\n\t// Build Rot part.\n\t//===============\n\tbool\tM1Identity= ! m1.hasRot();\n\tbool\tM2Identity= ! m2.hasRot();\n\tbool\tM1ScaleOnly= ! (m1.StateBit & MAT_ROT);\n\tbool\tM2ScaleOnly= ! (m2.StateBit & MAT_ROT);\n\tbool\tMGeneralCase= !M1Identity && !M2Identity && !M1ScaleOnly && !M2ScaleOnly;\n\n\n\t// Manage the most common general case first (optim the if ): blending of two rotations.\n\tif( MGeneralCase )\n\t{\n\t\ta11= m1.a11*m2.a11 + m1.a12*m2.a21 + m1.a13*m2.a31;\n\t\ta12= m1.a11*m2.a12 + m1.a12*m2.a22 + m1.a13*m2.a32;\n\t\ta13= m1.a11*m2.a13 + m1.a12*m2.a23 + m1.a13*m2.a33;\n\n\t\ta21= m1.a21*m2.a11 + m1.a22*m2.a21 + m1.a23*m2.a31;\n\t\ta22= m1.a21*m2.a12 + m1.a22*m2.a22 + m1.a23*m2.a32;\n\t\ta23= m1.a21*m2.a13 + m1.a22*m2.a23 + m1.a23*m2.a33;\n\n\t\ta31= m1.a31*m2.a11 + m1.a32*m2.a21 + m1.a33*m2.a31;\n\t\ta32= m1.a31*m2.a12 + m1.a32*m2.a22 + m1.a33*m2.a32;\n\t\ta33= m1.a31*m2.a13 + m1.a32*m2.a23 + m1.a33*m2.a33;\n\t}\n\t// If one of the 3x3 matrix is an identity, just do a copy\n\telse if( M1Identity || M2Identity )\n\t{\n\t\t// If both identity, then me too.\n\t\tif( M1Identity && M2Identity )\n\t\t{\n\t\t\t// just expand me (important because validated below)\n\t\t\ttestExpandRot();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Copy the non identity matrix.\n\t\t\tconst CMatrix\t*c= M2Identity? &m1 : &m2;\n\t\t\ta11= c->a11; a12= c->a12; a13= c->a13;\n\t\t\ta21= c->a21; a22= c->a22; a23= c->a23;\n\t\t\ta31= c->a31; a32= c->a32; a33= c->a33;\n\t\t}\n\t}\n\t// If two 3x3 matrix are just scaleOnly matrix, do a scaleFact.\n\telse if( M1ScaleOnly && M2ScaleOnly )\n\t{\n\t\t// same process for scaleUni or scaleAny.\n\t\ta11= m1.a11*m2.a11; a12= 0; a13= 0;\n\t\ta21= 0; a22= m1.a22*m2.a22; a23= 0;\n\t\ta31= 0; a32= 0; a33= m1.a33*m2.a33;\n\t}\n\t// If one of the matrix is a scaleOnly matrix, do a scale*Rot.\n\telse if( M1ScaleOnly && !M2ScaleOnly )\n\t{\n\t\ta11= m1.a11*m2.a11; a12= m1.a11*m2.a12; a13= m1.a11*m2.a13;\n\t\ta21= m1.a22*m2.a21; a22= m1.a22*m2.a22; a23= m1.a22*m2.a23;\n\t\ta31= m1.a33*m2.a31; a32= m1.a33*m2.a32; a33= m1.a33*m2.a33;\n\t}\n\telse\n\t{\n\t\t// This must be this case\n\t\tnlassert(!M1ScaleOnly && M2ScaleOnly);\n\t\ta11= m1.a11*m2.a11; a12= m1.a12*m2.a22; a13= m1.a13*m2.a33;\n\t\ta21= m1.a21*m2.a11; a22= m1.a22*m2.a22; a23= m1.a23*m2.a33;\n\t\ta31= m1.a31*m2.a11; a32= m1.a32*m2.a22; a33= m1.a33*m2.a33;\n\t}\n\n\t// If M1 has translate and M2 has projective, rotation is modified.\n\tif( m1.hasTrans() && m2.hasProj())\n\t{\n\t\tStateBit|= MAT_ROT|MAT_SCALEANY;\n\n\t\ta11+= m1.a14*m2.a41;\n\t\ta12+= m1.a14*m2.a42;\n\t\ta13+= m1.a14*m2.a43;\n\n\t\ta21+= m1.a24*m2.a41;\n\t\ta22+= m1.a24*m2.a42;\n\t\ta23+= m1.a24*m2.a43;\n\n\t\ta31+= m1.a34*m2.a41;\n\t\ta32+= m1.a34*m2.a42;\n\t\ta33+= m1.a34*m2.a43;\n\t}\n\n\t// Modify Scale.\n\tif( (StateBit & MAT_SCALEUNI) && !(StateBit & MAT_SCALEANY) )\n\t{\n\t\t// Must have correct Scale33\n\t\tm1.testExpandRot();\n\t\tm2.testExpandRot();\n\t\tScale33= m1.Scale33*m2.Scale33;\n\t}\n\telse\n\t\tScale33=1;\n\n\t// In every case, I am valid now!\n\tStateBit|=MAT_VALIDROT;\n\n\n\t// Build Trans part.\n\t//=================\n\tif( StateBit & MAT_TRANS )\n\t{\n\t\t// Compose M2 part.\n\t\tif( M1Identity )\n\t\t{\n\t\t\ta14= m2.a14;\n\t\t\ta24= m2.a24;\n\t\t\ta34= m2.a34;\n\t\t}\n\t\telse if (M1ScaleOnly )\n\t\t{\n\t\t\ta14= m1.a11*m2.a14;\n\t\t\ta24= m1.a22*m2.a24;\n\t\t\ta34= m1.a33*m2.a34;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ta14= m1.a11*m2.a14 + m1.a12*m2.a24 + m1.a13*m2.a34;\n\t\t\ta24= m1.a21*m2.a14 + m1.a22*m2.a24 + m1.a23*m2.a34;\n\t\t\ta34= m1.a31*m2.a14 + m1.a32*m2.a24 + m1.a33*m2.a34;\n\t\t}\n\t\t// Compose M1 part.\n\t\tif(m1.StateBit & MAT_TRANS)\n\t\t{\n\t\t\tif(m2.StateBit & MAT_PROJ)\n\t\t\t{\n\t\t\t\ta14+= m1.a14*m2.a44;\n\t\t\t\ta24+= m1.a24*m2.a44;\n\t\t\t\ta34+= m1.a34*m2.a44;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ta14+= m1.a14;\n\t\t\t\ta24+= m1.a24;\n\t\t\t\ta34+= m1.a34;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t// Build Proj part.\n\t//=================\n\tif( StateBit & MAT_PROJ )\n\t{\n\t\t// optimize nothing... (projection matrix are rare).\n\t\tm1.testExpandRot();\n\t\tm1.testExpandProj();\n\t\tm2.testExpandRot();\n\t\tm2.testExpandProj();\n\t\ta41= m1.a41*m2.a11 + m1.a42*m2.a21 + m1.a43*m2.a31 + m1.a44*m2.a41;\n\t\ta42= m1.a41*m2.a12 + m1.a42*m2.a22 + m1.a43*m2.a32 + m1.a44*m2.a42;\n\t\ta43= m1.a41*m2.a13 + m1.a42*m2.a23 + m1.a43*m2.a33 + m1.a44*m2.a43;\n\t\ta44= m1.a41*m2.a14 + m1.a42*m2.a24 + m1.a43*m2.a34 + m1.a44*m2.a44;\n\t\t// The proj is valid now\n\t\tStateBit|= MAT_VALIDPROJ;\n\t}\n\telse\n\t{\n\t\t// Don't copy proj part, and leave MAT_VALIDPROJ not set\n\t}\n}\n// ======================================================================================================\nvoid\t\tCMatrix::invert()\n{\n\n\t*this= inverted();\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::transpose3x3()\n{\n\tif(hasRot())\n\t{\n\t\t// swap values.\n\t\tswap(a12, a21);\n\t\tswap(a13, a31);\n\t\tswap(a32, a23);\n\t\t// Scale mode (none, uni, or any) is conserved. Scale33 too...\n\t}\n}\n\n// ======================================================================================================\nvoid\t\tCMatrix::transpose()\n{\n\ttranspose3x3();\n\tif(hasTrans() || hasProj())\n\t{\n\t\t// if necessary, Get valid 0 on proj part.\n\t\ttestExpandProj();\n\t\t// swap values\n\t\tswap(a41, a14);\n\t\tswap(a42, a24);\n\t\tswap(a43, a34);\n\t\t// swap StateBit flags, if not both were sets...\n\t\tif(!hasTrans() || !hasProj())\n\t\t{\n\t\t\t// swap StateBit flags (swap trans with proj).\n\t\t\tif(hasTrans())\n\t\t\t{\n\t\t\t\tStateBit&= ~MAT_TRANS;\n\t\t\t\tStateBit|= MAT_PROJ;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tStateBit&= ~MAT_PROJ;\n\t\t\t\tStateBit|= MAT_TRANS;\n\t\t\t}\n\t\t}\n\t\t// reset validity. NB, maybe not useful, but simpler, and bugfree.\n\t\tStateBit&= ~(MAT_VALIDPROJ);\n\t}\n\t// NB: if no Trans or no Proj, do nothing, so don't need to modify VALIDTRANS and VALIDPROJ too.\n}\n\n\n// ======================================================================================================\nbool\tCMatrix::fastInvert33(CMatrix &ret) const\n{\n\t// Fast invert of 3x3 rot matrix.\n\t// Work if no scale and if MAT_SCALEUNI. doesn't work if MAT_SCALEANY.\n\n\tif(StateBit & MAT_SCALEUNI)\n\t{\n\t\tif (Scale33 == 0.f) return false;\n\t\tdouble\ts,S;\t// important for precision.\n\t\t// Must divide the matrix by 1/Scale 2 times, to set unit, and to have a Scale=1/Scale.\n\t\tS=1.0/Scale33;\n\t\tret.Scale33= (float)S;\n\t\ts=S*S;\n\t\t// The matrix is a base, so just transpose it.\n\t\tret.a11= (float)(a11*s); ret.a12= (float)(a21*s); ret.a13= (float)(a31*s);\n\t\tret.a21= (float)(a12*s); ret.a22= (float)(a22*s); ret.a23= (float)(a32*s);\n\t\tret.a31= (float)(a13*s); ret.a32= (float)(a23*s); ret.a33= (float)(a33*s);\n\t}\n\telse\n\t{\n\t\tret.Scale33=1;\n\t\t// The matrix is a base, so just transpose it.\n\t\tret.a11= a11; ret.a12= a21; ret.a13=a31;\n\t\tret.a21= a12; ret.a22= a22; ret.a23=a32;\n\t\tret.a31= a13; ret.a32= a23; ret.a33=a33;\n\t}\n\treturn true;\n\t// 15 cycles if no scale.\n\t// 35 cycles if scale.\n}\n// ======================================================================================================\nbool\tCMatrix::slowInvert33(CMatrix &ret) const\n{\n\tCVector\tinvi,invj,invk;\n\tCVector\ti,j,k;\n\tdouble\ts;\n\n\ti= getI();\n\tj= getJ();\n\tk= getK();\n\t// Compute cofactors (minors *(-1)^(i+j)).\n\tinvi.x= j.y*k.z - k.y*j.z;\n\tinvi.y= j.z*k.x - k.z*j.x;\n\tinvi.z= j.x*k.y - k.x*j.y;\n\tinvj.x= k.y*i.z - i.y*k.z;\n\tinvj.y= k.z*i.x - i.z*k.x;\n\tinvj.z= k.x*i.y - i.x*k.y;\n\tinvk.x= i.y*j.z - j.y*i.z;\n\tinvk.y= i.z*j.x - j.z*i.x;\n\tinvk.z= i.x*j.y - j.x*i.y;\n\t// compute determinant.\n\ts= invi.x*i.x + invj.x*j.x + invk.x*k.x;\n\tif(s==0)\n\t\treturn false;\n\t// Transpose the Comatrice, and divide by determinant.\n\ts=1.0/s;\n\tret.a11= (float)(invi.x*s); ret.a12= (float)(invi.y*s); ret.a13= (float)(invi.z*s);\n\tret.a21= (float)(invj.x*s); ret.a22= (float)(invj.y*s); ret.a23= (float)(invj.z*s);\n\tret.a31= (float)(invk.x*s); ret.a32= (float)(invk.y*s); ret.a33= (float)(invk.z*s);\n\n\treturn true;\n\t// Roundly 82 cycles. (1Div=10 cycles).\n}\n// ======================================================================================================\nbool\tCMatrix::slowInvert44(CMatrix &ret) const\n{\n\tsint\ti,j;\n\tdouble\ts;\n\n\t// Compute Cofactors\n\t//==================\n\tfor(i=0;i<=3;i++)\n\t{\n\t\tfor(j=0;j<=3;j++)\n\t\t{\n\t\t\tsint\tl1=0,l2=0,l3=0;\n\t\t\tsint\tc1,c2,c3;\n\t\t\tgetCofactIndex(i,l1,l2,l3);\n\t\t\tgetCofactIndex(j,c1,c2,c3);\n\n\t\t\tret.mat(i,j)= 0;\n\t\t\tret.mat(i,j)+= mat(l1,c1) * mat(l2,c2) * mat(l3,c3);\n\t\t\tret.mat(i,j)+= mat(l1,c2) * mat(l2,c3) * mat(l3,c1);\n\t\t\tret.mat(i,j)+= mat(l1,c3) * mat(l2,c1) * mat(l3,c2);\n\n\t\t\tret.mat(i,j)-= mat(l1,c1) * mat(l2,c3) * mat(l3,c2);\n\t\t\tret.mat(i,j)-= mat(l1,c2) * mat(l2,c1) * mat(l3,c3);\n\t\t\tret.mat(i,j)-= mat(l1,c3) * mat(l2,c2) * mat(l3,c1);\n\n\t\t\tif( (i+j)&1 )\n\t\t\t\tret.mat(i,j)=-ret.mat(i,j);\n\t\t}\n\t}\n\n\t// Compute determinant.\n\t//=====================\n\ts= ret.mat(0,0) * mat(0,0) + ret.mat(0,1) * mat(0,1) + ret.mat(0,2) * mat(0,2) + ret.mat(0,3) * mat(0,3);\n\tif(s==0)\n\t\treturn false;\n\n\t// Divide by determinant.\n\t//=======================\n\ts=1.0/s;\n\tfor(i=0;i<=3;i++)\n\t{\n\t\tfor(j=0;j<=3;j++)\n\t\t\tret.mat(i,j)= (float)(ret.mat(i,j)*s);\n\t}\n\n\t// Transpose the comatrice.\n\t//=========================\n\tfor(i=0;i<=3;i++)\n\t{\n\t\tfor(j=i+1;j<=3;j++)\n\t\t{\n\t\t\tswap(ret.mat(i,j), ret.mat(j,i));\n\t\t}\n\t}\n\n\treturn true;\n}\n// ======================================================================================================\nCMatrix\t\tCMatrix::inverted() const\n{\n\n\tCMatrix\tret;\n\n\ttestExpandRot();\n\ttestExpandProj();\n\n\t// Do a conventionnal 44 inversion.\n\t//=================================\n\tif(StateBit & MAT_PROJ)\n\t{\n\t\tif(!slowInvert44(ret))\n\t\t{\n\t\t\tret.identity();\n\t\t\treturn ret;\n\t\t}\n\n\t\t// Well, don't know what happens to matrix, so set all StateBit :).\n\t\tret.StateBit= MAT_TRANS|MAT_ROT|MAT_SCALEANY|MAT_PROJ;\n\n\t\t// Check Trans state.\n\t\tif(ret.a14!=0 || ret.a24!=0 || ret.a34!=0)\n\t\t\tret.StateBit|= MAT_TRANS;\n\t\telse\n\t\t\tret.StateBit&= ~MAT_TRANS;\n\n\t\t// Check Proj state.\n\t\tif(ret.a41!=0 || ret.a42!=0 || ret.a43!=0 || ret.a44!=1)\n\t\t\tret.StateBit|= MAT_PROJ;\n\t\telse\n\t\t\tret.StateBit&= ~MAT_PROJ;\n\t}\n\n\t// Do a speed 34 inversion.\n\t//=========================\n\telse\n\t{\n\t\t// Invert the rotation part.\n\t\tif(StateBit & MAT_SCALEANY)\n\t\t{\n\t\t\tif(!slowInvert33(ret))\n\t\t\t{\n\t\t\t\tret.identity();\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (!fastInvert33(ret))\n\t\t\t{\n\t\t\t\tret.identity();\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t}\n\t\t// Scale33 is updated in fastInvert33().\n\n\t\t// Invert the translation part.\n\t\tif(StateBit & MAT_TRANS)\n\t\t{\n\t\t\t// Invert the translation part.\n\t\t\t// This can only work if 4th line is 0 0 0 1.\n\t\t\t// formula: InvVp= InvVi*(-Vp.x) + InvVj*(-Vp.y) + InvVk*(-Vp.z)\n\t\t\tret.a14= ret.a11*(-a14) + ret.a12*(-a24) + ret.a13*(-a34);\n\t\t\tret.a24= ret.a21*(-a14) + ret.a22*(-a24) + ret.a23*(-a34);\n\t\t\tret.a34= ret.a31*(-a14) + ret.a32*(-a24) + ret.a33*(-a34);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tret.a14= 0;\n\t\t\tret.a24= 0;\n\t\t\tret.a34= 0;\n\t\t}\n\n\t\t// The projection part is unmodified.\n\t\tret.a41= 0; ret.a42= 0; ret.a43= 0; ret.a44= 1;\n\n\t\t// The matrix inverted keep the same state bits.\n\t\tret.StateBit= StateBit;\n\t}\n\n\n\treturn ret;\n}\n// ======================================================================================================\nbool\t\tCMatrix::normalize(TRotOrder ro)\n{\n\n\tCVector\tti,tj,tk;\n\tti= getI();\n\ttj= getJ();\n\ttk= getK();\n\n\ttestExpandRot();\n\n\t// Normalize with help of ro\n\tswitch(ro)\n\t{\n\t\tcase XYZ:\n\t\t\tti.normalize();\n\t\t\ttk= ti^tj;\n\t\t\ttk.normalize();\n\t\t\ttj= tk^ti;\n\t\t\tbreak;\n\t\tcase XZY:\n\t\t\tti.normalize();\n\t\t\ttj= tk^ti;\n\t\t\ttj.normalize();\n\t\t\ttk= ti^tj;\n\t\t\tbreak;\n\t\tcase YXZ:\n\t\t\ttj.normalize();\n\t\t\ttk= ti^tj;\n\t\t\ttk.normalize();\n\t\t\tti= tj^tk;\n\t\t\tbreak;\n\t\tcase YZX:\n\t\t\ttj.normalize();\n\t\t\tti= tj^tk;\n\t\t\tti.normalize();\n\t\t\ttk= ti^tj;\n\t\t\tbreak;\n\t\tcase ZXY:\n\t\t\ttk.normalize();\n\t\t\ttj= tk^ti;\n\t\t\ttj.normalize();\n\t\t\tti= tj^tk;\n\t\t\tbreak;\n\t\tcase ZYX:\n\t\t\ttk.normalize();\n\t\t\tti= tj^tk;\n\t\t\tti.normalize();\n\t\t\ttj= tk^ti;\n\t\t\tbreak;\n\t}\n\n\t// Check, and set result.\n\tif( ti.isNull() || tj.isNull() || tk.isNull() )\n\t\treturn false;\n\ta11= ti.x; a12= tj.x; a13= tk.x;\n\ta21= ti.y; a22= tj.y; a23= tk.y;\n\ta31= ti.z; a32= tj.z; a33= tk.z;\n\t// Scale is reseted.\n\tStateBit&= ~(MAT_SCALEUNI|MAT_SCALEANY);\n\t// Rot is setup...\n\tStateBit|= MAT_ROT;\n\tScale33=1;\n\n\treturn true;\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nCVector\t\tCMatrix::mulVector(const CVector &v) const\n{\n\n\tCVector\tret;\n\n\tif( hasRot() )\n\t{\n\t\tret.x= a11*v.x + a12*v.y + a13*v.z;\n\t\tret.y= a21*v.x + a22*v.y + a23*v.z;\n\t\tret.z= a31*v.x + a32*v.y + a33*v.z;\n\t\treturn ret;\n\t}\n\telse\n\t\treturn v;\n}\n\n// ======================================================================================================\nCVector\t\tCMatrix::mulPoint(const CVector &v) const\n{\n\n\tCVector\tret;\n\n\tif( hasRot() )\n\t{\n\t\tret.x= a11*v.x + a12*v.y + a13*v.z;\n\t\tret.y= a21*v.x + a22*v.y + a23*v.z;\n\t\tret.z= a31*v.x + a32*v.y + a33*v.z;\n\t}\n\telse\n\t{\n\t\tret= v;\n\t}\n\tif( hasTrans() )\n\t{\n\t\tret.x+= a14;\n\t\tret.y+= a24;\n\t\tret.z+= a34;\n\t}\n\n\treturn ret;\n}\n\n\n/*\n * Multiply\n */\nCVectorH\tCMatrix::operator*(const CVectorH& v) const\n{\n\n\tCVectorH ret;\n\n\ttestExpandRot();\n\ttestExpandProj();\n\n\tret.x= a11*v.x + a12*v.y + a13*v.z + a14*v.w;\n\tret.y= a21*v.x + a22*v.y + a23*v.z + a24*v.w;\n\tret.z= a31*v.x + a32*v.y + a33*v.z + a34*v.w;\n\tret.w= a41*v.x + a42*v.y + a43*v.z + a44*v.w;\n\treturn ret;\n}\n\n\n// ======================================================================================================\nCPlane\t\toperator*(const CPlane &p, const CMatrix &m)\n{\n\tm.testExpandRot();\n\tm.testExpandProj();\n\n\tCPlane\tret;\n\n\tif( m.StateBit & (MAT_ROT|MAT_SCALEUNI|MAT_SCALEANY|MAT_PROJ) )\n\t{\n\t\t// Compose with translation too.\n\t\tret.a= p.a*m.a11 + p.b*m.a21 + p.c*m.a31 + p.d*m.a41;\n\t\tret.b= p.a*m.a12 + p.b*m.a22 + p.c*m.a32 + p.d*m.a42;\n\t\tret.c= p.a*m.a13 + p.b*m.a23 + p.c*m.a33 + p.d*m.a43;\n\t\tret.d= p.a*m.a14 + p.b*m.a24 + p.c*m.a34 + p.d*m.a44;\n\t\treturn ret;\n\t}\n\telse if( m.StateBit & MAT_TRANS )\n\t{\n\n\t\t// Compose just with a translation.\n\t\tret.a= p.a;\n\t\tret.b= p.b;\n\t\tret.c= p.c;\n\t\tret.d= p.a*m.a14 + p.b*m.a24 + p.c*m.a34 + p.d*m.a44;\n\t\treturn ret;\n\t}\n\telse\t// Identity!!\n\t\treturn p;\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::setRot(const CQuat &quat)\n{\n\t// A quaternion do not have scale.\n\tStateBit&= ~(MAT_ROT | MAT_SCALEANY|MAT_SCALEUNI);\n\tScale33= 1.0f;\n\tif(quat.isIdentity())\n\t{\n\t\ta11= 1; a12= 0; a13= 0;\n\t\ta21= 0; a22= 1; a23= 0;\n\t\ta31= 0; a32= 0; a33= 1;\n\t}\n\telse\n\t{\n\t\tStateBit|= MAT_ROT;\n\t\tfloat wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;\n\n\t\t// calculate coefficients\n\t\tx2 = quat.x + quat.x; y2 = quat.y + quat.y;\n\t\tz2 = quat.z + quat.z;\n\t\txx = quat.x * x2;   xy = quat.x * y2;   xz = quat.x * z2;\n\t\tyy = quat.y * y2;   yz = quat.y * z2;   zz = quat.z * z2;\n\t\twx = quat.w * x2;   wy = quat.w * y2;   wz = quat.w * z2;\n\n\t\ta11 = 1.0f - (yy + zz);\n\t\ta12 = xy - wz;\n\t\ta13 = xz + wy;\n\n\t\ta21 = xy + wz;\n\t\ta22 = 1.0f - (xx + zz);\n\t\ta23 = yz - wx;\n\n\t\ta31 = xz - wy;\n\t\ta32 = yz + wx;\n\t\ta33 = 1.0f - (xx + yy);\n\t}\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::getRot(CQuat &quat) const\n{\n\tconst CMatrix\t*pmat= this;\n\tCMatrix\t\t\tMatNormed;\n\n\n\t// Rot Indentity?\n\tif(! (StateBit & MAT_ROT))\n\t{\n\t\tquat= CQuat::Identity;\n\t\treturn;\n\t}\n\n\t// Must normalize the matrix??\n\tif(StateBit & (MAT_SCALEUNI | MAT_SCALEANY) )\n\t{\n\t\tMatNormed= *this;\n\t\tMatNormed.normalize(ZYX);\n\t\tpmat= &MatNormed;\n\t}\n\n\t// Compute quaternion.\n\tfloat  tr, s, q[4];\n\n\ttr = pmat->a11 + pmat->a22 + pmat->a33;\n\n\t// check the diagonal\n\tif (tr > 0.0)\n\t{\n\t\ts = (float)sqrt (tr + 1.0f);\n\t\tquat.w = s / 2.0f;\n\t\ts = 0.5f / s;\n\t\tquat.x = (pmat->a32 - pmat->a23) * s;\n\t\tquat.y = (pmat->a13 - pmat->a31) * s;\n\t\tquat.z = (pmat->a21 - pmat->a12) * s;\n\t}\n\telse\n\t{\n\t\tsint    i, j, k;\n\t\tsint\tnxt[3] = {1, 2, 0};\n\n\t\t// diagonal is negative\n\t\ti = 0;\n\t\tif (pmat->a22 > pmat->a11) i = 1;\n\t\tif (pmat->a33 > pmat->mat(i,i) ) i = 2;\n\t\tj = nxt[i];\n\t\tk = nxt[j];\n\n\t\ts = (float) sqrt (  (pmat->mat(i,i) - (pmat->mat(j,j) + pmat->mat(k,k)) )   + 1.0);\n\n\t\tq[i] = s * 0.5f;\n\n\t\tif (s != 0.0f) s = 0.5f / s;\n\n\t\tq[j] = (pmat->mat(j,i) + pmat->mat(i,j)) * s;\n\t\tq[k] = (pmat->mat(k,i) + pmat->mat(i,k)) * s;\n\t\tq[3] =\t (pmat->mat(k,j) - pmat->mat(j,k)) * s;\n\n\t\tquat.x = q[0];\n\t\tquat.y = q[1];\n\t\tquat.z = q[2];\n\t\tquat.w = q[3];\n\t}\n\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\ninline\tvoid\tCMatrix::setScaleUni(float scale)\n{\n\t// A Scale matrix do not have rotation.\n\tStateBit&= ~(MAT_ROT | MAT_SCALEANY | MAT_SCALEUNI);\n\tStateBit|= MAT_SCALEUNI | MAT_VALIDROT;\n\tScale33= scale;\n\ta11= scale; a12= 0; a13= 0;\n\ta21= 0; a22= scale; a23= 0;\n\ta31= 0; a32= 0; a33= scale;\n}\n\n// ======================================================================================================\nvoid\t\tCMatrix::setScale(float scale)\n{\n\tsetScaleUni(scale);\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::setScale(const CVector &v)\n{\n\t// actually a scale uniform?\n\tif(v.x==v.y && v.x==v.z)\n\t\tsetScaleUni(v.x);\n\n\t// A Scale matrix do not have rotation.\n\tStateBit&= ~(MAT_ROT | MAT_SCALEANY | MAT_SCALEUNI);\n\tStateBit|= MAT_SCALEANY | MAT_VALIDROT;\n\ta11= v.x; a12= 0; a13= 0;\n\ta21= 0; a22= v.y; a23= 0;\n\ta31= 0; a32= 0; a33= v.z;\n\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::serial(IStream &f)\n{\n\t// Use versionning, maybe for futur improvement.\n\t(void)f.serialVersion(0);\n\n\tif(f.isReading())\n\t\tidentity();\n\tf.serial(StateBit);\n\t// avoid serial of random data\n\tif(!f.isReading() && !hasScaleUniform())\n\t{\n\t\tfloat\tfs= 1.f;\n\t\tf.serial(fs);\n\t}\n\telse\n\t\tf.serial(Scale33);\n\tif( hasRot() )\n\t{\n\t\tf.serial(a11, a12, a13);\n\t\tf.serial(a21, a22, a23);\n\t\tf.serial(a31, a32, a33);\n\t}\n\tif( hasTrans() )\n\t{\n\t\tf.serial(a14, a24, a34);\n\t}\n\telse if(f.isReading())\n\t{\n\t\t// must reset because Pos must always be valid\n\t\ta14= a24= a34= 0;\n\t}\n\tif( hasProj() )\n\t{\n\t\tf.serial(a41, a42, a43, a44);\n\t}\n}\n\n\n// ======================================================================================================\nvoid\t\tCMatrix::setArbitraryRotI(const CVector &idir)\n{\n\t// avoid gimbal lock. if idir == nearly K, use another second lead vector\n\tif( fabs(idir.z)<0.9f )\n\t\tsetRot(idir, CVector::J, CVector::K);\n\telse\n\t\tsetRot(idir, CVector::J, CVector::I);\n\tnormalize(CMatrix::XZY);\n}\n\nvoid\t\tCMatrix::setArbitraryRotJ(const CVector &jdir)\n{\n\t// avoid gimbal lock. if jdir == nearly K, use another second lead vector\n\tif(fabs(jdir.z)<0.9f)\n\t\tsetRot(CVector::I, jdir, CVector::K);\n\telse\n\t\tsetRot(CVector::I, jdir, CVector::J);\n\tnormalize(CMatrix::YZX);\n}\n\nvoid\t\tCMatrix::setArbitraryRotK(const CVector &kdir)\n{\n\t// avoid gimbal lock. if kdir == nearly I, use another second lead vector\n\tif( fabs(kdir.y)<0.9f )\n\t\tsetRot(CVector::I, CVector::J, kdir);\n\telse\n\t\tsetRot(CVector::I, CVector::K, kdir);\n\tnormalize(CMatrix::ZYX);\n}\n\n\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/md5.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm\n */\n\n/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All\n   rights reserved.\n\n   License to copy and use this software is granted provided that it\n   is identified as the \"RSA Data Security, Inc. MD5 Message-Digest\nAlgorithm\" in all material mentioning or referencing this software\nor this function.\n\nLicense is also granted to make and use derivative works provided\nthat such works are identified as \"derived from the RSA Data\nSecurity, Inc. MD5 Message-Digest Algorithm\" in all material\nmentioning or referencing the derived work.\n\nRSA Data Security, Inc. makes no representations concerning either\nthe merchantability of this software or the suitability of this\nsoftware for any particular purpose. It is provided \"as is\"\nwithout express or implied warranty of any kind.\n\nThese notices must be retained in any copies of any part of this\ndocumentation and/or software.\n*/\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/md5.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/stream.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n// ****************************************************************************\n// ****************************************************************************\n// High Level Routines\n// ****************************************************************************\n// ****************************************************************************\n\n// ****************************************************************************\nCHashKeyMD5 getMD5(const std::string &filename)\n{\n    CMD5Context\tmd5ctx;\n    CHashKeyMD5 Message_Digest;\n\tMessage_Digest.clear();\n\n\tCIFile ifile;\n\tif (!ifile.open(CPath::lookup(filename)))\n\t{\n\t\tnlwarning (\"MD5: Can't open the file '%s'\", filename.c_str());\n\t\treturn Message_Digest;\n\t}\n\n\tmd5ctx.init();\n\n\tuint8 buffer[1024];\n\tint bufferSize = 1024;\n\tsint fs = ifile.getFileSize();\n\tsint n, read = 0;\n\tdo\n\t{\n\t\t//bs = (int)fread (buffer, 1, bufferSize, fp);\n\t\tn = std::min (bufferSize, fs-read);\n\t\t//nlinfo (\"read %d bytes\", n);\n\t\tifile.serialBuffer((uint8 *)buffer, n);\n\n\t\tmd5ctx.update(buffer, n);\n\n\t\tread += n;\n\t}\n\twhile (!ifile.eof());\n\n\tifile.close\t();\n\n\tmd5ctx.final(Message_Digest);\n\n\treturn Message_Digest;\n}\n\n// ****************************************************************************\nCHashKeyMD5 getMD5(const uint8 *buffer, uint32 size)\n{\n    CMD5Context\tmd5ctx;\n    CHashKeyMD5 Message_Digest;\n\tMessage_Digest.clear();\n\n\tmd5ctx.init();\n\tmd5ctx.update(buffer, size);\n\tmd5ctx.final(Message_Digest);\n\n\treturn Message_Digest;\n}\n\n// ****************************************************************************\n// Helper\n// ****************************************************************************\nstatic bool fromHex(char c, uint8 &x)\n{\n\tif (c >= '0' && c <= '9')\n\t{\n\t\tx = c - '0';\n\t\treturn true;\n\t}\n\telse if (c >= 'A' && c <= 'F')\n\t{\n\t\tx = c - 'A' + 10;\n\t\treturn true;\n\t}\n\telse if (c >= 'a' && c <= 'f')\n\t{\n\t\tx = c - 'a' + 10;\n\t\treturn true;\n\t}\n\n\tnlwarning(\"cannot convert to hexa\");\n\treturn false;\n}\n\n// ****************************************************************************\n// ****************************************************************************\n// CHashKeyMD5\n// ****************************************************************************\n// ****************************************************************************\n\n// ****************************************************************************\nvoid CHashKeyMD5::clear()\n{\n\tfor (uint32 i = 0; i < 16; ++i)\n\t\tData[i] = 0;\n}\n\n// ****************************************************************************\nstring CHashKeyMD5::toString() const\n{\n\tstring sTmp;\n\tfor (uint32 i = 0; i < 16; ++i)\n\t\tsTmp += NLMISC::toString(\"%02x\", Data[i]);\n\treturn sTmp;\n}\n\n// ****************************************************************************\nbool CHashKeyMD5::fromString(const std::string &in)\n{\n\tif (in.size() != 32)\n\t{\n\t\tnlwarning(\"bad string size\");\n\t\treturn false;\n\t}\n\n\tfor (uint32 i = 0; i < 16; ++i)\n\t{\n\t\tchar c1 = in[2*i];\n\t\tchar c2 = in[2*i+1];\n\t\tuint8 x1, x2;\n\t\tif (!fromHex(c1, x1)) return false;\n\t\tif (!fromHex(c2, x2)) return false;\n\t\tData[i] = (x1 << 4) | x2;\n\t}\n\treturn true;\n}\n\n// ****************************************************************************\nbool CHashKeyMD5::operator!=(const CHashKeyMD5 &in) const\n{\n\tfor (uint32 i = 0; i < 16; ++i)\n\t\tif (Data[i] != in.Data[i])\n\t\t\treturn true;\n\treturn false;\n}\n\n// ****************************************************************************\nbool CHashKeyMD5::operator==(const CHashKeyMD5 &in) const\n{\n\treturn !operator!=(in);\n}\n\n// ****************************************************************************\nbool CHashKeyMD5::operator<(const CHashKeyMD5 &in) const\n{\n\tfor (uint32 i = 0; i < 16; ++i)\n\t\tif (Data[i] >= in.Data[i])\n\t\t\treturn false;\n\treturn true;\n}\n\n// ****************************************************************************\nvoid CHashKeyMD5::serial (NLMISC::IStream &s)\n{\n\ts.serialBuffer(Data,16);\n}\n\n\n// ****************************************************************************\n// ****************************************************************************\n// CMD5Context\n// ****************************************************************************\n// ****************************************************************************\n\nuint8 CMD5Context::Padding[64] = {\n    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n};\n\n// ****************************************************************************\nvoid CMD5Context::init()\n{\n    Count[0] = Count[1] = 0;\n    // Load magic initialization constants.\n    State[0] = 0x67452301;\n    State[1] = 0xefcdab89;\n    State[2] = 0x98badcfe;\n    State[3] = 0x10325476;\n}\n\n// ****************************************************************************\nvoid CMD5Context::update (const uint8 *pBufIn, uint32 nBufLength)\n{\n    uint i, index, partLen;\n\n    // Compute number of bytes mod 64\n    index = (uint)((Count[0] >> 3) & 0x3F);\n\n    // Update number of bits\n    if ((Count[0] += (nBufLength << 3)) < (nBufLength << 3))\n\tCount[1]++;\n    Count[1] += (nBufLength >> 29);\n\n    partLen = 64 - index;\n\n    // Transform as many times as possible.\n    if (nBufLength >= partLen)\n\t{\n\t\tmemcpy((uint8*)&Buffer[index], pBufIn, partLen);\n\t\ttransform (State, Buffer);\n\n\t\tfor (i = partLen; i + 63 < nBufLength; i += 64)\n\t\t\ttransform (State, &pBufIn[i]);\n\n\t\tindex = 0;\n    }\n\telse\n\t{\n\t\ti = 0;\n\t}\n\n    // Buffer remaining input\n    memcpy((uint8*)&Buffer[index], &pBufIn[i], nBufLength-i);\n}\n\n// ****************************************************************************\nvoid CMD5Context::final (CHashKeyMD5 &out)\n{\n\tuint8 bits[8];\n\tuint index, padLen;\n\n\t// Save number of bits\n\tencode (&bits[0], Count, 8);\n\n\t// Pad out to 56 mod 64.\n\tindex = (unsigned int)((Count[0] >> 3) & 0x3f);\n\tpadLen = (index < 56) ? (56 - index) : (120 - index);\n\tupdate (Padding, padLen);\n\n\t// Append length (before padding)\n\tupdate (&bits[0], 8);\n\t// Store state in digest\n\tencode (out.Data, State, 16);\n\n\t// Zeroize sensitive information.\n\tuint i;\n\tfor (i = 0; i < 4; ++i) State[i] = 0;\n    for (i = 0; i < 2; ++i) Count[i] = 0;\n    for (i = 0; i < 64; ++i) Buffer[i] = 0;\n}\n\n// Constants for MD5Transform routine.\n// ****************************************************************************\n#define S11 7\n#define S12 12\n#define S13 17\n#define S14 22\n#define S21 5\n#define S22 9\n#define S23 14\n#define S24 20\n#define S31 4\n#define S32 11\n#define S33 16\n#define S34 23\n#define S41 6\n#define S42 10\n#define S43 15\n#define S44 21\n\n// F, G, H and I are basic MD5 functions.\n#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\n#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\n#define H(x, y, z) ((x) ^ (y) ^ (z))\n#define I(x, y, z) ((y) ^ ((x) | (~z)))\n\n// ROTATE_LEFT rotates x left n bits.\n#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\n\n// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.\n// Rotation is separate from addition to prevent recomputation.\n#define FF(a, b, c, d, x, s, ac) { \\\n      (a) += F ((b), (c), (d)) + (x) + (uint32)(ac); \\\n      (a) = ROTATE_LEFT ((a), (s)); \\\n      (a) += (b); \\\n\t\t\t       }\n#define GG(a, b, c, d, x, s, ac) { \\\n      (a) += G ((b), (c), (d)) + (x) + (uint32)(ac); \\\n      (a) = ROTATE_LEFT ((a), (s)); \\\n      (a) += (b); \\\n     }\n#define HH(a, b, c, d, x, s, ac) { \\\n      (a) += H ((b), (c), (d)) + (x) + (uint32)(ac); \\\n      (a) = ROTATE_LEFT ((a), (s)); \\\n      (a) += (b); \\\n     }\n#define II(a, b, c, d, x, s, ac) { \\\n      (a) += I ((b), (c), (d)) + (x) + (uint32)(ac); \\\n      (a) = ROTATE_LEFT ((a), (s)); \\\n      (a) += (b); \\\n     }\n\n\n// MD5 basic transformation. Transforms state based on block.\n// ****************************************************************************\nvoid CMD5Context::transform (uint32 state[4], const uint8 block[64])\n{\n    uint32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];\n\n    decode (&x[0], &block[0], 64);\n\n    // Round 1\n    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1\n    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2\n    FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3\n    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4\n    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5\n    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6\n    FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7\n    FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8\n    FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9\n    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10\n    FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11\n    FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12\n    FF (a, b, c, d, x[12], S11, 0x6b901122); // 13\n    FF (d, a, b, c, x[13], S12, 0xfd987193); // 14\n    FF (c, d, a, b, x[14], S13, 0xa679438e); // 15\n    FF (b, c, d, a, x[15], S14, 0x49b40821); // 16\n\n    // Round 2\n    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17\n    GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18\n    GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19\n    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20\n    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21\n    GG (d, a, b, c, x[10], S22,  0x2441453); // 22\n    GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23\n    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24\n    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25\n    GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26\n    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27\n    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28\n    GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29\n    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30\n    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31\n    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32\n\n    // Round 3\n    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33\n    HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34\n    HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35\n    HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36\n    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37\n    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38\n    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39\n    HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40\n    HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41\n    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42\n    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43\n    HH (b, c, d, a, x[ 6], S34,  0x4881d05); // 44\n    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45\n    HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46\n    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47\n    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48\n\n    // Round 4\n    II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49\n    II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50\n    II (c, d, a, b, x[14], S43, 0xab9423a7); // 51\n    II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52\n    II (a, b, c, d, x[12], S41, 0x655b59c3); // 53\n    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54\n    II (c, d, a, b, x[10], S43, 0xffeff47d); // 55\n    II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56\n    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57\n    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58\n    II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59\n    II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60\n    II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61\n    II (d, a, b, c, x[11], S42, 0xbd3af235); // 62\n    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63\n    II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64\n\n    state[0] += a;\n    state[1] += b;\n    state[2] += c;\n    state[3] += d;\n}\n\n// Encodes input (guint32) into output (unsigned char). Assumes len is a multiple of 4.\n// ****************************************************************************\nvoid CMD5Context::encode (uint8 *output, const uint32 *input, uint len)\n{\n\tuint i, j;\n\n\tfor (i = 0, j = 0; j < len; i++, j += 4)\n\t{\n\t\toutput[j] = (uint8)(input[i] & 0xff);\n\t\toutput[j+1] = (uint8)((input[i] >> 8) & 0xff);\n\t\toutput[j+2] = (uint8)((input[i] >> 16) & 0xff);\n\t\toutput[j+3] = (uint8)((input[i] >> 24) & 0xff);\n\t}\n}\n\n// Decodes input (unsigned char) into output (guint32). Assumes len is a multiple of 4.\n// ****************************************************************************\nvoid CMD5Context::decode (uint32 *output, const uint8 *input, uint len)\n{\n\tuint i, j;\n\n\tfor (i = 0, j = 0; j < len; i++, j += 4)\n\t\toutput[i] = ((uint32)input[j]) | (((uint32)input[j+1]) << 8) |\n\t\t\t\t\t(((uint32)input[j+2]) << 16) | (((uint32)input[j+3]) << 24);\n}\n\n\n} // namespace NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/mem_displayer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/mem_displayer.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <imagehlp.h>\n#\tpragma comment(lib, \"imagehlp.lib\")\n#\tifdef NL_OS_WIN64\n#\t\tdefine DWORD_TYPE DWORD64\n#\telse\n#\t\tdefine DWORD_TYPE DWORD\n#\tendif // NL_OS_WIN64\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n//  UNTIL we found who to walk in the call stack wihtout error, we disactive this feature\n\n\n#ifdef NL_OS_WINDOWS\n\nstatic const uint32 stringSize = 1024;\n\nstatic string getFuncInfo (DWORD_TYPE funcAddr, DWORD_TYPE stackAddr)\n{\n\tstring str (\"NoSymbol\");\n\n\tDWORD symSize = 10000;\n\tPIMAGEHLP_SYMBOL  sym = (PIMAGEHLP_SYMBOL) GlobalAlloc (GMEM_FIXED, symSize);\n\t::ZeroMemory (sym, symSize);\n\tsym->SizeOfStruct = symSize;\n\tsym->MaxNameLength = symSize - sizeof(IMAGEHLP_SYMBOL);\n\n\tDWORD_TYPE disp = 0;\n\tif (SymGetSymFromAddr (GetCurrentProcess(), funcAddr, &disp, sym) == FALSE)\n\t{\n\t\treturn str;\n\t}\n\n\tCHAR undecSymbol[stringSize];\n\tif (UnDecorateSymbolName (sym->Name, undecSymbol, stringSize, UNDNAME_COMPLETE | UNDNAME_NO_THISTYPE | UNDNAME_NO_SPECIAL_SYMS | UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS ) > 0)\n\t{\n\t\tstr = undecSymbol;\n\t}\n\telse if (SymUnDName (sym, undecSymbol, stringSize) == TRUE)\n\t{\n\t\tstr = undecSymbol;\n\t}\n\n\tif (disp != 0)\n\t{\n\t\tstr += \" + \";\n\t\tstr += toString ((uint32)disp);\n\t\tstr += \" bytes\";\n\t}\n\n\t// replace param with the value of the stack for this param\n\n\tstring parse = str;\n\tstr = \"\";\n\tuint pos = 0;\n\tsint stop = 0;\n\n\tfor (uint i = 0; i < parse.size (); i++)\n\t{\n\t\tif (parse[i] == '<')\n\t\t\t stop++;\n\t\tif (parse[i] == '>')\n\t\t\t stop--;\n\n\t\tif (stop==0 && (parse[i] == ',' || parse[i] == ')'))\n\t\t{\n\t\t\tchar tmp[32];\n\t\t\tsprintf(tmp, \"=0x%p\", *((DWORD_TYPE*)(stackAddr) + 2 + pos++));\n\t\t\tstr += tmp;\n\t\t}\n\t\tstr += parse[i];\n\t}\n\tGlobalFree (sym);\n\n\treturn str;\n}\n\nstatic string getSourceInfo (DWORD_TYPE addr)\n{\n\tstring str;\n\n\tIMAGEHLP_LINE  line;\n\t::ZeroMemory (&line, sizeof (line));\n\tline.SizeOfStruct = sizeof(line);\n\n// It doesn't work in windows 98\n/*\tDWORD disp;\n\tif (SymGetLineFromAddr (GetCurrentProcess(), addr, &disp, &line))\n\t{\n\t\tstr = line.FileName;\n\t\tstr += \"(\" + toString (line.LineNumber) + \")\";\n\t}\n\telse\n*/\t{\n\t\tIMAGEHLP_MODULE module;\n\t\t::ZeroMemory (&module, sizeof(module));\n\t\tmodule.SizeOfStruct = sizeof(module);\n\n\t\tif (SymGetModuleInfo (GetCurrentProcess(), addr, &module))\n\t\t{\n\t\t\tstr = module.ModuleName;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstr = \"<NoModule>\";\n\t\t}\n\t\tchar tmp[32];\n\t\tsprintf (tmp, \"!0x%X\", addr);\n\t\tstr += tmp;\n\t}\n\n\treturn str;\n}\n\n#ifdef NL_OS_WIN64\nstatic DWORD64 __stdcall GetModuleBase(HANDLE hProcess, DWORD64 dwReturnAddress)\n#else\nstatic DWORD __stdcall GetModuleBase(HANDLE hProcess, DWORD dwReturnAddress)\n#endif\n{\n\tIMAGEHLP_MODULE moduleInfo;\n\n\tif (SymGetModuleInfo(hProcess, dwReturnAddress, &moduleInfo))\n\t\treturn moduleInfo.BaseOfImage;\n\telse\n\t{\n\t\tMEMORY_BASIC_INFORMATION memoryBasicInfo;\n\n\t\tif (::VirtualQueryEx(hProcess, (LPVOID) dwReturnAddress,\n\t\t\t&memoryBasicInfo, sizeof(memoryBasicInfo)))\n\t\t{\n\t\t\tDWORD cch = 0;\n\t\t\tchar szFile[MAX_PATH] = { 0 };\n\n\t\t cch = GetModuleFileNameA((HINSTANCE)memoryBasicInfo.AllocationBase,\n\t\t\t\t\t\t\t\t szFile, MAX_PATH);\n\n\t\tif (cch && (lstrcmp(szFile, \"DBFN\")== 0))\n\t\t{\n\t\t\tchar mn[] = { 'M', 'N', 0x00 };\n#ifdef NL_OS_WIN64\n\t\t\tif (!SymLoadModule64(\n#else\n\t\t\tif (!SymLoadModule(\n#endif\n\t\t\t\t\thProcess,\n\t\t\t\t\tNULL, mn,\n\t\t\t\t\tNULL, (uintptr_t)memoryBasicInfo.AllocationBase, 0))\n\t\t\t\t{\n//\t\t\t\t\tDWORD dwError = GetLastError();\n//\t\t\t\t\tnlinfo(\"Error: %d\", dwError);\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n#ifdef NL_OS_WIN64\n\t\t\tif (!SymLoadModule64(\n#else\n\t\t\tif (!SymLoadModule(\n#endif\n\t\t\t\thProcess,\n\t\t\t\tNULL, ((cch) ? szFile : NULL),\n\t\t\t\tNULL, (uintptr_t)memoryBasicInfo.AllocationBase, 0))\n\t\t\t{\n//\t\t\t\tDWORD dwError = GetLastError();\n//\t\t\t\tnlinfo(\"Error: %d\", dwError);\n\t\t\t }\n\n\n\t\t}\n\n\t\t return (uintptr_t)memoryBasicInfo.AllocationBase;\n\t  }\n//\t\telse\n//\t\t\tnlinfo(\"Error is %d\", GetLastError());\n\t}\n\n\treturn 0;\n}\n\n\nstatic void displayCallStack (CLog *log)\n{\n\tstatic string symbolPath;\n\n\tDWORD symOptions = SymGetOptions();\n\tsymOptions |= SYMOPT_LOAD_LINES;\n\tsymOptions &= ~SYMOPT_UNDNAME;\n\tSymSetOptions (symOptions);\n\n\t//\n\t// Create the path where to find the symbol\n\t//\n\n\tif (symbolPath.empty())\n\t{\n\t\tCHAR tmpPath[stringSize];\n\n\t\tsymbolPath = \".\";\n\n\t\tif (GetEnvironmentVariable (\"_NT_SYMBOL_PATH\", tmpPath, stringSize))\n\t\t{\n\t\t\tsymbolPath += \";\";\n\t\t\tsymbolPath += tmpPath;\n\t\t}\n\n\t\tif (GetEnvironmentVariable (\"_NT_ALTERNATE_SYMBOL_PATH\", tmpPath, stringSize))\n\t\t{\n\t\t\tsymbolPath += \";\";\n\t\t\tsymbolPath += tmpPath;\n\t\t}\n\n\t\tif (GetEnvironmentVariable (\"SYSTEMROOT\", tmpPath, stringSize))\n\t\t{\n\t\t\tsymbolPath += \";\";\n\t\t\tsymbolPath += tmpPath;\n\t\t\tsymbolPath += \";\";\n\t\t\tsymbolPath += tmpPath;\n\t\t\tsymbolPath += \"\\\\system32\";\n\t\t}\n\t}\n\n\t//\n\t// Initialize\n\t//\n\n\tif (SymInitialize (GetCurrentProcess(), NULL, FALSE) == FALSE)\n\t{\n\t\tnlwarning (\"DISP: SymInitialize(%p, '%s') failed\", GetCurrentProcess(), symbolPath.c_str());\n\t\treturn;\n\t}\n\n\t// FIXME: Implement this for MinGW\n#ifndef NL_COMP_MINGW\n\tCONTEXT context;\n\t::ZeroMemory (&context, sizeof(context));\n\tcontext.ContextFlags = CONTEXT_FULL;\n\n\tif (GetThreadContext (GetCurrentThread(), &context) == FALSE)\n\t{\n\t\tnlwarning (\"DISP: GetThreadContext(%p) failed\", GetCurrentThread());\n\t\treturn;\n\t}\n\n\tSTACKFRAME callStack;\n\t::ZeroMemory (&callStack, sizeof(callStack));\n\n#ifdef NL_OS_WIN64\n\tcallStack.AddrPC.Offset    = context.Rip;\n\tcallStack.AddrStack.Offset = context.Rsp;\n\tcallStack.AddrFrame.Offset = context.Rbp;\n#else\n\tcallStack.AddrPC.Offset    = context.Eip;\n\tcallStack.AddrStack.Offset = context.Esp;\n\tcallStack.AddrFrame.Offset = context.Ebp;\n#endif\n\n\tcallStack.AddrPC.Mode      = AddrModeFlat;\n\tcallStack.AddrStack.Mode   = AddrModeFlat;\n\tcallStack.AddrFrame.Mode   = AddrModeFlat;\n\n\tfor (uint32 i = 0; ; i++)\n\t{\n\t\tDWORD MachineType;\n\n#ifdef NL_OS_WIN64\n\t\tMachineType = IMAGE_FILE_MACHINE_AMD64;\n\t\tBOOL res = StackWalk64(MachineType, GetCurrentProcess(), GetCurrentThread(), &callStack,\n\t\t\tNULL, NULL, SymFunctionTableAccess, GetModuleBase, NULL);\n#else\n\t\tMachineType = IMAGE_FILE_MACHINE_I386;\n\t\tBOOL res = StackWalk(MachineType, GetCurrentProcess(), GetCurrentThread(), &callStack,\n\t\t\tNULL, NULL, SymFunctionTableAccess, GetModuleBase, NULL);\n#endif\n\n/*\t\tif (res == FALSE)\n\t\t{\n\t\t\tDWORD r = GetLastError ();\n\t\t\tnlinfo (\"%d\",r);\n\t\t}\n*/\n\t\tif (i == 0)\n\t\t   continue;\n\n\t\tif (res == FALSE || callStack.AddrFrame.Offset == 0)\n\t\t\tbreak;\n\n\t\tstring symInfo, srcInfo;\n\n\t\tsymInfo = getFuncInfo (callStack.AddrPC.Offset, callStack.AddrFrame.Offset);\n\t\tsrcInfo = getSourceInfo (callStack.AddrPC.Offset);\n\n\t\tlog->displayNL (\"   %s : %s\", srcInfo.c_str(), symInfo.c_str());\n\t}\n#endif\n}\n\n#else // NL_OS_WINDOWS\n\nstatic void displayCallStack (CLog *log)\n{\n\tlog->displayNL (\"no call stack info available\");\n}\n\n#endif // NL_OS_WINDOWS\n\n\n/*\n * Constructor\n */\nCMemDisplayer::CMemDisplayer (const char *displayerName) : IDisplayer (displayerName), _NeedHeader(true), _MaxStrings(50), _CanUseStrings(true)\n{\n\tsetParam (50);\n}\n\nvoid CMemDisplayer::setParam (uint32 maxStrings)\n{\n\t_MaxStrings = maxStrings;\n}\n\n\n// Log format: \"2000/01/15 12:05:30 <ProcessName> <LogType> <ThreadId> <FileName> <Line> : <Msg>\"\nvoid CMemDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message )\n{\n//\tstringstream\tss;\n\tstring str;\n\tbool\t\t\tneedSpace = false;\n\n\tif (!_CanUseStrings) return;\n\n\tif (_NeedHeader)\n\t{\n\t\tstr += HeaderString();\n\t\t_NeedHeader = false;\n\t}\n\n\tif (args.Date != 0)\n\t{\n\t\tstr += dateToHumanString(args.Date);\n\t\tneedSpace = true;\n\t}\n\n\tif (!args.ProcessName.empty())\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += args.ProcessName;\n\t\tneedSpace = true;\n\t}\n\n\tif (args.LogType != CLog::LOG_NO)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += logTypeToString(args.LogType);\n\t\tneedSpace = true;\n\t}\n\n\t// Write thread identifier\n\tif ( args.ThreadId != 0 )\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n#ifdef NL_OS_WINDOWS\n\t\tstr += NLMISC::toString(\"%5x\", args.ThreadId);\n#else\n\t\tstr += NLMISC::toString(\"%08x\", args.ThreadId);\n#endif\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += CFile::getFilename(args.FileName);\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(args.Line);\n\t\tneedSpace = true;\n\t}\n\n\tif (needSpace) { str += \" : \"; needSpace = false; }\n\n\tstr += message;\n\n\t// clear old line\n\twhile (_Strings.size () > _MaxStrings)\n\t{\n\t\t_Strings.pop_front ();\n\t}\n\n\t_Strings.push_back (str);\n}\n\nvoid CMemDisplayer::write (CLog *log, bool quiet)\n{\n\tif (log == NULL)\n\t\tlog = InfoLog;\n\n\tif ( ! quiet )\n\t{\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t\tlog->forceDisplayRaw (\"----------------------------------------- display MemDisplayer history -------\\n\");\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t}\n\tfor (deque<string>::iterator it = _Strings.begin(); it != _Strings.end(); it++)\n\t{\n\t\tlog->forceDisplayRaw ((*it).c_str());\n\t}\n\tif ( ! quiet )\n\t{\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t\tlog->forceDisplayRaw (\"----------------------------------------- display MemDisplayer callstack -----\\n\");\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t\tdisplayCallStack(log);\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t\tlog->forceDisplayRaw (\"----------------------------------------- end of MemDisplayer display --------\\n\");\n\t\tlog->forceDisplayRaw (\"------------------------------------------------------------------------------\\n\");\n\t}\n}\n\nvoid CMemDisplayer::write (string &str, bool crLf)\n{\n\tfor (deque<string>::iterator it = _Strings.begin(); it != _Strings.end(); it++)\n\t{\n\t\tstr += (*it);\n\t\tif ( crLf )\n\t\t{\n\t\t\tif ( (!str.empty()) && (str[str.size()-1] == '\\n') )\n\t\t\t{\n\t\t\t\tstr[str.size()-1] = '\\r';\n\t\t\t\tstr += '\\n';\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nvoid\tCLightMemDisplayer::doDisplay ( const CLog::TDisplayInfo& /* args */, const char *message )\n{\n\t//stringstream\tss;\n\tstring str;\n\t//bool\t\t\tneedSpace = false;\n\n\tif (!_CanUseStrings) return;\n\n\tstr += message;\n\n\t// clear old line\n\twhile (_Strings.size () >= _MaxStrings)\n\t{\n\t\t_Strings.pop_front ();\n\t}\n\n\t_Strings.push_back (str);\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/mem_stream.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/mem_stream.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nvoid CMemStream::swap(CMemStream &other)\n{\n\tIStream::swap(other);\n\t_Buffer.swap(other._Buffer);\n\tstd::swap(_StringMode, other._StringMode);\n\tstd::swap(_DefaultCapacity, other._DefaultCapacity);\n}\n\n\n/*\n * serial (inherited from IStream)\n */\nvoid CMemStream::serialBuffer(uint8 *buf, uint len)\n{\n\t// commented for optimum performance\n//\tnlassert (len > 0);\n\n\tif (len == 0)\n\t\treturn;\n\n\tnlassert (buf != NULL);\n\n\tif ( isReading() )\n\t{\n\t\t// Check that we don't read more than there is to read\n\t\t//checkStreamSize(len);\n\n\t\tuint32 pos = lengthS();\n\t\tuint32 total = length();\n\t\tif ( pos+len > total ) // calls virtual length (cf. sub messages)\n\t\t{\n\t\t\tthrow EStreamOverflow( \"CMemStream serialBuffer overflow: Read past %u bytes\", total );\n\t\t}\n\n\t\t// Serialize in\n\t\tCFastMem::memcpy( buf, _Buffer.getBuffer().getPtr()+_Buffer.Pos, len );\n\t\t_Buffer.Pos += len;\n\t}\n\telse\n\t{\n\t\t// Serialize out\n\n\t\tincreaseBufferIfNecessary (len);\n\t\tCFastMem::memcpy( _Buffer.getBufferWrite().getPtr()+_Buffer.Pos, buf, len );\n\t\t_Buffer.Pos += len;\n\n\t}\n}\n\n/*\n * serialBit (inherited from IStream)\n */\nvoid CMemStream::serialBit(bool &bit)\n{\n\tuint8 u;\n\tif ( isReading() )\n\t{\n\t\tserial( u );\n\t\tbit = (u!=0);\n\t}\n\telse\n\t{\n\t\tu = (uint8)bit;\n\t\tserial( u );\n\t}\n}\n\n\n/*\n * seek (inherited from IStream)\n *\n * Warning: in output mode, seek(end) does not point to the end of the serialized data,\n * but on the end of the whole allocated buffer (see size()).\n * If you seek back and want to return to the end of the serialized data, you have to\n * store the position (a better way is to use reserve()/poke()).\n *\n * Possible enhancement:\n * In output mode, keep another pointer to track the end of serialized data.\n * When serializing, increment the pointer if its value exceeds its previous value\n * (to prevent from an \"inside serial\" to increment it).\n * Then a seek(end) would get back to the pointer.\n */\nbool CMemStream::seek (sint32 offset, TSeekOrigin origin) const throw(EStream)\n{\n\tswitch (origin)\n\t{\n\tcase begin:\n\t\tif (offset > (sint)length())\n\t\t\treturn false;\n\t\tif (offset < 0)\n\t\t\treturn false;\n\t\t_Buffer.Pos = offset;\n\t\tbreak;\n\tcase current:\n\t\tif (getPos ()+offset > (sint)length())\n\t\t\treturn false;\n\t\tif (getPos ()+offset < 0)\n\t\t\treturn false;\n\t\t_Buffer.Pos += offset;\n\t\tbreak;\n\tcase end:\n\t\tif (offset < -(sint)length())\n\t\t\treturn false;\n\t\tif (offset > 0)\n\t\t\treturn false;\n\t\t_Buffer.Pos = _Buffer.getBuffer().size()+offset;\n\t\tbreak;\n\t}\n\treturn true;\n}\n\n\n/*\n * Resize the buffer.\n * Warning: the position is unchanged, only the size is changed.\n */\nvoid CMemStream::resize (uint32 size)\n{\n\tif (size == length()) return;\n\t// need to increase the buffer size\n\t_Buffer.getBufferWrite().resize(size);\n}\n\n\n/*\n * Input: read from the stream until the next separator, and return the number of bytes read. The separator is then skipped.\n */\nuint CMemStream::serialSeparatedBufferIn( uint8 *buf, uint len )\n{\n\tnlassert( _StringMode && isReading() );\n\n\t// Check that we don't read more than there is to read\n\tif ( ( _Buffer.Pos == _Buffer.getBuffer().size() ) || // we are at the end\n\t\t ( ( lengthS()+len+SEP_SIZE > length() ) && (_Buffer.getBuffer()[_Buffer.getBuffer().size()-1] != SEPARATOR ) ) ) // we are before the end // calls virtual length (cf. sub messages)\n\t{\n\t\tthrow EStreamOverflow();\n\t}\n\t// Serialize in\n\tuint32 i = 0;\n\tconst uint8\t*pos = _Buffer.getBuffer().getPtr()+_Buffer.Pos;\n\twhile ( (i<len) && (*pos) != SEPARATOR )\n\t{\n\t\t*(buf+i) = *pos;\n\t\ti++;\n\t\t++pos;\n\t\t++_Buffer.Pos;\n\t}\n\t// Exceeds len\n\tif ( (*pos) != SEPARATOR )\n\t{\n\t\tthrow EStreamOverflow();\n\t}\n\t_Buffer.Pos += SEP_SIZE;\n\n\treturn i;\n}\n\n\n/*\n * Output: writes len bytes from buf into the stream\n */\nvoid CMemStream::serialSeparatedBufferOut( uint8 *buf, uint len )\n{\n\tnlassert( _StringMode && (!isReading()) );\n\n\t// Serialize out\n\tuint32 oldBufferSize = _Buffer.getBuffer().size();\n\tif (_Buffer.Pos + (len + SEP_SIZE) > oldBufferSize)\n\t{\n\t\t// need to increase the buffer size\n\t\t_Buffer.getBufferWrite().resize(oldBufferSize*2 + len + SEP_SIZE);\n\t}\n\n\tCFastMem::memcpy( _Buffer.getBufferWrite().getPtr()+_Buffer.Pos, buf, len );\n\t_Buffer.Pos += len;\n\t*(_Buffer.getBufferWrite().getPtr()+_Buffer.Pos) = SEPARATOR;\n\t_Buffer.Pos += SEP_SIZE;\n\n}\n\n/* Returns a readable string to display it to the screen. It's only for debugging purpose!\n * Don't use it for anything else than to debugging, the string format could change in the future.\n * \\param hexFormat If true, display all bytes in hexadecimal, else display as chars (above 31, otherwise '.')\n */\nstd::string\t\tCMemStream::toString( bool hexFormat ) const\n{\n\tstd::string s;\n\tuint32 len = length();\n\tif ( hexFormat )\n\t{\n\t\tfor ( uint i=0; i!=len; ++i )\n\t\t\ts += NLMISC::toString( \"%2X \", buffer()[i] );\n\t}\n\telse\n\t{\n\t\tfor ( uint i=0; i!=len; ++i )\n\t\t\ts += NLMISC::toString( \"%c\", (buffer()[i]>31) ? buffer()[i] : '.' );\n\t}\n\treturn s;\n}\n\n\n// ***************************************************************************\nuint\t\t\tCMemStream::getDbgStreamSize() const\n{\n\tif(isReading())\n\t\treturn length();\n\telse\n\t\treturn 0;\n}\n\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/mouse_smoother.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/mouse_smoother.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// *******************************************************************************************\n/// build some hermite spline value, with the given points and tangents\nstatic inline void BuildHermiteVector(const NLMISC::CVector2f &P0,\n\t\t\t\t\t\t\t\t\t  const NLMISC::CVector2f &P1,\n\t\t\t\t\t\t\t\t\t  const NLMISC::CVector2f &T0,\n\t\t\t\t\t\t\t\t\t  const NLMISC::CVector2f &T1,\n\t\t\t\t\t\t\t\t\t  NLMISC::CVector2f &dest,\n\t\t\t\t\t\t\t\t\t  float lambda\n\t\t\t\t\t\t\t\t\t  )\n{\n\tconst float lambda2 = lambda * lambda;\n\tconst float lambda3 = lambda2 * lambda;\n\tconst float h1 = 2 * lambda3 - 3 * lambda2 + 1;\n\tconst float h2 = - 2 * lambda3 + 3 * lambda2;\n\tconst float h3 = lambda3 - 2 * lambda2 + lambda;\n\tconst float h4 = lambda3 - lambda2;\n\t/// just avoid some ctor calls here...\n\tdest.set(h1 * P0.x + h2 * P1.x + h3 * T0.x + h4 * T1.x,\n\t\th1 * P0.y + h2 * P1.y + h3 * T0.y + h4 * T1.y);\n}\n\n// *******************************************************************************************\nCMouseSmoother::CMouseSmoother(double samplingPeriod /*=0.2f*/)\n{\n\tnlassert(samplingPeriod > 0);\n\t_SamplingPeriod = samplingPeriod;\n\t_Init = false;\n}\n\n\n// *******************************************************************************************\nvoid CMouseSmoother::setSamplingPeriod(double period)\n{\n\tif (period == _SamplingPeriod) return;\n\treset();\n\tnlassert(_SamplingPeriod > 0);\n\t_SamplingPeriod = period;\n}\n\n\n// *******************************************************************************************\nNLMISC::CVector2f CMouseSmoother::samplePos(const CVector2f &wantedPos, double date)\n{\n\tif (!_Init)\n\t{\n\t\t_Sample[0] = _Sample[1] = _Sample[2] = _Sample[3] = CSample(date, wantedPos);\n\t\t_Init = true;\n\t}\n\telse\n\t{\n\t\t// see if enough time has elapsed since last sample\n\t\tif (date - _Sample[3].Date >= _SamplingPeriod)\n\t\t{\n\t\t\tuint numSamples = (uint) floor((date - _Sample[3].Date) / _SamplingPeriod);\n\t\t\tnumSamples = std::min(numSamples, (uint) 4);\n\t\t\tfor(uint k = 0; k < numSamples; ++k)\n\t\t\t{\n\t\t\t\t// add a new sample\n\t\t\t\t_Sample[0] = _Sample[1];\n\t\t\t\t_Sample[1] = _Sample[2];\n\t\t\t\t_Sample[2] = _Sample[3];\n\t\t\t\t_Sample[3] = CSample(date, wantedPos);\n\t\t\t}\n\t\t}\n\t\telse if (date == _Sample[3].Date)\n\t\t{\n\t\t\t// update cur pos\n\t\t\t_Sample[3] = CSample(date, wantedPos);\n\t\t}\n\t}\n\tif (_Sample[1].Pos.x == _Sample[2].Pos.x &&\n\t\t_Sample[1].Pos.y == _Sample[2].Pos.y\n\t   )\n\t{\n\t\t// special case : if pointer hasn't moved, allow a discontinuity of speed\n\t\treturn _Sample[2].Pos;\n\t}\n\tdouble evalDate = date - 2 * _SamplingPeriod;\n\tclamp(evalDate, _Sample[1].Date, _Sample[2].Date);\n\tCVector2f t0;\n\tdouble dt = _Sample[2].Date - _Sample[1].Date;\n\tif (_Sample[2].Date != _Sample[0].Date)\n\t{\n\t\tt0 = (float) dt * (_Sample[2].Pos - _Sample[0].Pos) / (float) (_Sample[2].Date - _Sample[0].Date);\n\t}\n\telse\n\t{\n\t\tt0= NLMISC::CVector::Null;\n\t}\n\tCVector2f t1;\n\tif (_Sample[3].Date != _Sample[1].Date)\n\t{\n\t\tt1 = (float) dt * (_Sample[3].Pos - _Sample[1].Pos) / (float) (_Sample[3].Date - _Sample[1].Date);\n\t}\n\telse\n\t{\n\t\tt1= NLMISC::CVector::Null;\n\t}\n\tNLMISC::CVector2f result;\n\tif (dt == 0) return _Sample[2].Pos;\n\tBuildHermiteVector(_Sample[1].Pos, _Sample[2].Pos, t0, t1, result, (float) ((evalDate - _Sample[1].Date) / dt));\n\treturn result;\n}\n\n// *******************************************************************************************\nvoid CMouseSmoother::reset()\n{\n\t_Init = false;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/mutex.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#ifndef _GNU_SOURCE\n#define _GNU_SOURCE\n#endif // _GNU_SOURCE\n\n#include \"nel/misc/mutex.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/debug.h\"\n\nusing namespace std;\n\n#ifndef MUTEX_DEBUG\n#define debugCreateMutex() ;\n#define debugBeginEnter() ;\n#define debugEndEnter() ;\n#define debugLeave() ;\n#define debugDeleteMutex() ;\n#endif\n\n\n/****************\n * Windows code *\n ****************/\n\n#ifdef NL_OS_WINDOWS\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n\ninline void EnterMutex( void *handle )\n{\n#ifdef NL_DEBUG\n\tDWORD timeout;\n\tif ( IsDebuggerPresent() )\n\t\ttimeout = INFINITE;\n\telse\n\t\ttimeout = 10000;\n\n    // Request ownership of mutex\n\tDWORD dwWaitResult = WaitForSingleObject (handle, timeout);\n#else\n    // Request ownership of mutex during 10s\n\tDWORD dwWaitResult = WaitForSingleObject (handle, 10000);\n#endif // NL_DEBUG\n\tswitch (dwWaitResult)\n\t{\n\t// The thread got mutex ownership.\n\tcase WAIT_OBJECT_0:\t\tbreak;\n\t// Cannot get mutex ownership due to time-out.\n\tcase WAIT_TIMEOUT:\t\tnlerror (\"Dead lock in a mutex (or more that 10s for the critical section\");\n\t// Got ownership of the abandoned mutex object.\n\tcase WAIT_ABANDONED:\tnlerror (\"A thread forgot to release the mutex\");\n\tdefault:\t\t\t\tnlerror (\"EnterMutex failed\");\n    }\n}\n\n\ninline void LeaveMutex( void *handle )\n{\n\tif (ReleaseMutex(handle) == 0)\n\t{\n\t\t//LPVOID lpMsgBuf;\n\t\t//FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n\t\t//\t\t\t\t NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL );*/\n\t\tnlerror (\"error while releasing the mutex (0x%x %d), %p\", GetLastError(), GetLastError(), handle);\n\t\t//LocalFree( lpMsgBuf );\n\t}\n}\n\n\n/////////////////////////// CUnfairMutex\n\n\n/*\n * Windows version\n */\n\nCUnfairMutex::CUnfairMutex()\n{\n\t// Create a mutex with no initial owner.\n\t_Mutex = (void *) CreateMutex( NULL, FALSE, NULL );\n\tnlassert( _Mutex != NULL );\n}\n\n\nCUnfairMutex::CUnfairMutex( const std::string & /* name */ )\n{\n\t// Create a mutex with no initial owner.\n\t_Mutex = (void *) CreateMutex( NULL, FALSE, NULL );\n\tnlassert( _Mutex != NULL );\n\n\t// (Does not use name, only provided for debug compatibility with CFairMutex)\n}\n\n\n/*\n * Windows version\n */\nCUnfairMutex::~CUnfairMutex()\n{\n\tCloseHandle( _Mutex );\n}\n\n\n/*\n * Windows version\n */\nvoid CUnfairMutex::enter()\n{\n\tEnterMutex( _Mutex );\n}\n\n\n/*\n * Windows version\n */\nvoid CUnfairMutex::leave()\n{\n\tLeaveMutex( _Mutex );\n}\n\n\n/////////////////////////// CSharedMutexW\n\n\n/*\n *\n */\nCSharedMutex::CSharedMutex()\n{\n\t_Mutex = NULL;\n}\n\n\n/*\n * Create or use an existing mutex (created by another process) with a specific object name (createNow must be false in the constructor)\n * Returns false if it failed.\n */\nbool\tCSharedMutex::createByName( const char *objectName )\n{\n#ifdef NL_DEBUG\n\tnlassert( _Mutex == NULL );\n#endif\n\t_Mutex = (void *) CreateMutex( NULL, FALSE, objectName );\n\t//nldebug( \"Creating mutex %s: handle %p\", objectName, _Mutex );\n\treturn ( _Mutex != NULL );\n}\n\n\n/*\n *\n */\nvoid CSharedMutex::destroy()\n{\n\tCloseHandle( _Mutex );\n\t_Mutex = NULL;\n}\n\n/*\n *\n */\nvoid CSharedMutex::enter()\n{\n\tEnterMutex( _Mutex );\n}\n\n\n/*\n *\n */\nvoid CSharedMutex::leave()\n{\n\tLeaveMutex( _Mutex );\n}\n\n\n/////////////////////////// CFairMutex\n\n\n/*\n * Windows version\n */\nCFairMutex::CFairMutex()\n{\n#ifdef STORE_MUTEX_NAME\n\tName = \"unset mutex name\";\n#endif\n\n\tdebugCreateMutex();\n\n\t// Check that the CRITICAL_SECTION structure has not changed\n\tnlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );\n\n#if (_WIN32_WINNT >= 0x0500)\n\tDWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation\n\tif ( ! InitializeCriticalSectionAndSpinCount( (CRITICAL_SECTION*)&_Cs, dwSpinCount ) )\n\t{\n\t\tnlerror( \"Error entering critical section\" );\n\t}\n#else\n\tInitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );\n#endif\n}\n\n\nCFairMutex::CFairMutex(const string &name)\n{\n#ifdef STORE_MUTEX_NAME\n\tName = name;\n#endif\n\n#ifdef MUTEX_DEBUG\n\tdebugCreateMutex();\n#endif\n\n\t// Check that the CRITICAL_SECTION structure has not changed\n\tnlassert( sizeof(TNelRtlCriticalSection)==sizeof(CRITICAL_SECTION) );\n\n#if (_WIN32_WINNT >= 0x0500)\n\tDWORD dwSpinCount = 0x80000000; // set high-order bit to use preallocation\n\tif ( ! InitializeCriticalSectionAndSpinCount( (CRITICAL_SECTION*)&_Cs, dwSpinCount ) )\n\t{\n\t\tnlerror( \"Error entering critical section\" );\n\t}\n#else\n\tInitializeCriticalSection( (CRITICAL_SECTION*)&_Cs );\n#endif\n}\n\n\n\n/*\n * Windows version\n */\nCFairMutex::~CFairMutex()\n{\n\tDeleteCriticalSection( (CRITICAL_SECTION*)&_Cs );\n\n\tdebugDeleteMutex();\n}\n\n\n/*\n * Windows version\n */\nvoid CFairMutex::enter()\n{\n\tdebugBeginEnter();\n\n\tEnterCriticalSection( (CRITICAL_SECTION*)&_Cs );\n\n\tdebugEndEnter();\n}\n\n\n/*\n * Windows version\n */\nvoid CFairMutex::leave()\n{\n\tLeaveCriticalSection( (CRITICAL_SECTION*)&_Cs );\n\n\tdebugLeave();\n}\n\n/*************\n * Unix code *\n *************/\n\n#elif defined NL_OS_UNIX\n\n#include <pthread.h>\n#include <cerrno>\n#include <unistd.h>\n\n#include <sys/types.h>\n#include <sys/ipc.h>\n#include <sys/sem.h> // System V semaphores\n\n\n\n/*\n * Clanlib authors say: \"We need to do this because the posix threads library\n * under linux obviously suck:\"\n */\nextern \"C\"\n{\n\tint pthread_mutexattr_setkind_np( pthread_mutexattr_t *attr, int kind );\n}\n\n\nnamespace NLMISC {\n\n\nCUnfairMutex::CUnfairMutex()\n{\n    pthread_mutexattr_t attr;\n\tpthread_mutexattr_init( &attr );\n\t// Fast mutex. Note: on Windows all mutexes are recursive\n\tpthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );\n\tpthread_mutex_init( &mutex, &attr );\n\tpthread_mutexattr_destroy( &attr );\n}\n\n\n/*\n * Unix version\n */\nCUnfairMutex::CUnfairMutex(const std::string &name)\n{\n\tpthread_mutexattr_t attr;\n\tpthread_mutexattr_init( &attr );\n\t// Fast mutex. Note: on Windows all mutexes are recursive\n\tpthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );\n\tpthread_mutex_init( &mutex, &attr );\n\tpthread_mutexattr_destroy( &attr );\n}\n\n\n/*\n * Unix version\n */\nCUnfairMutex::~CUnfairMutex()\n{\n\tpthread_mutex_destroy( &mutex );\n}\n\n\n/*\n * Unix version\n */\nvoid CUnfairMutex::enter()\n{\n\t//cout << getpid() << \": Locking \" << &mutex << endl;\n\tif ( pthread_mutex_lock( &mutex ) != 0 )\n\t{\n\t  //cout << \"Error locking a mutex \" << endl;\n\t\tnlerror( \"Error locking a mutex\" );\n\t}\n\t/*else\n\t{\n\t  cout << getpid() << \": Owning \" << &mutex << endl;\n\t}*/\n}\n\n\n/*\n * Unix version\n */\nvoid CUnfairMutex::leave()\n{\n\t//int errcode;\n\t//cout << getpid() << \": Unlocking \" << &mutex << endl;\n\tif ( (/*errcode=*/pthread_mutex_unlock( &mutex )) != 0 )\n\t{\n\t /* switch ( errcode )\n\t    {\n\t    case EINVAL: cout << \"INVAL\" << endl; break;\n\t    case EPERM: cout << \"PERM\" << endl; break;\n\t    default: cout << \"OTHER\" << endl;\n\t    }\n\t  */\n\t  //cout << \"Error unlocking a mutex \" /*<< &mutex*/ << endl;\n\t\tnlerror( \"Error unlocking a mutex\" );\n\t}\n\t/*else\n\t{\n\t  cout << getpid() << \": Released \" << &mutex << endl;\n\t}*/\n}\n\n\n/*\n * Unix version\n */\nCFairMutex::CFairMutex()\n{\n#ifdef NL_OS_MAC\n\t_Sem = dispatch_semaphore_create(1);\n#else\n\tsem_init( const_cast<sem_t*>(&_Sem), 0, 1 );\n#endif\n}\n\n\nCFairMutex::CFairMutex(\tconst std::string &name )\n{\n#ifdef NL_OS_MAC\n\t_Sem = dispatch_semaphore_create(1);\n#else\n\tsem_init( const_cast<sem_t*>(&_Sem), 0, 1 );\n#endif\n}\n\n\n/*\n * Unix version\n */\nCFairMutex::~CFairMutex()\n{\n#ifdef NL_OS_MAC\n\tdispatch_release(_Sem);\n#else\n\tsem_destroy( const_cast<sem_t*>(&_Sem) ); // needs that no thread is waiting on the semaphore\n#endif\n}\n\n\n/*\n * Unix version\n */\nvoid CFairMutex::enter()\n{\n#ifdef NL_OS_MAC\n\tdispatch_semaphore_wait(_Sem, DISPATCH_TIME_FOREVER);\n#else\n\tsem_wait( const_cast<sem_t*>(&_Sem) );\n#endif\n}\n\n\n/*\n * Unix version\n */\nvoid CFairMutex::leave()\n{\n#ifdef NL_OS_MAC\n\tdispatch_semaphore_signal(_Sem);\n#else\n\tsem_post( const_cast<sem_t*>(&_Sem) );\n#endif\n}\n\n\n///////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/*\n *\n */\nCSharedMutex::CSharedMutex() : _SemId(-1)\n{}\n\n\n\n#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)\n/* union semun is defined by including <sys/sem.h> */\n#else\n/* according to X/OPEN we have to define it ourselves */\nunion semun {\n        int val;                    /* value for SETVAL */\n        struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */\n        unsigned short int *array;  /* array for GETALL, SETALL */\n        struct seminfo *__buf;      /* buffer for IPC_INFO */\n};\n#endif\n\n\n/*\n *\n */\nbool\tCSharedMutex::createByKey( int key, bool createNew )\n{\n\t// Create a semaphore set containing one semaphore\n    /*key_t mykey = ftok(\".\", 'n');\n\t_SemId = semget( mykey, 1, IPC_CREAT | IPC_EXCL | 0666 );*/\n\n\tif ( createNew )\n\t\t_SemId = semget( key, 1, IPC_CREAT | IPC_EXCL | 0666 );\n\telse\n\t\t_SemId = semget( key, 1, 0666 );\n\tnldebug( \"Got semid %d\", _SemId );\n\tif( _SemId == -1 )\n\t\treturn false;\n\n\t// Initialise the semaphore to 1\n\tunion semun arg;\n\targ.val = 1;\n\tif ( semctl( _SemId, 0, SETVAL, arg ) == -1 )\n\t{\n\t\tnlwarning( \"semid=%d, err=%s\", _SemId, strerror(errno) );\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n\n/*\n *\n */\nvoid\tCSharedMutex::destroy()\n{\n\t// Destroy the semaphore\n\tunion semun arg;\n\tnlverifyex( semctl( _SemId, 0, IPC_RMID, arg ) != -1, (\"semid=%d, err=%s\", _SemId, strerror(errno) ) );\n\t_SemId = -1;\n}\n\n\n/*\n *\n */\nvoid\tCSharedMutex::enter()\n{\n\t// Decrement the semaphore\n\tsembuf buf;\n\tbuf.sem_num = 0;\n\tbuf.sem_op = -1;\n\tnlverify( semop( _SemId, &buf, 1 ) != -1);\n}\n\n\n/*\n *\n */\nvoid\tCSharedMutex::leave()\n{\n\t// Increment the semaphore\n\tsembuf buf;\n\tbuf.sem_num = 0;\n\tbuf.sem_op = 1;\n\tnlverify( semop( _SemId, &buf, 1 ) != -1);\n}\n\n\n#endif // NL_OS_WINDOWS/NL_OS_UNIX\n\n\n\n\n\n\n\n/******************\n * Debugging code *\n ******************/\n\n#ifdef MUTEX_DEBUG\n\nmap<CFairMutex*,TMutexLocks>\t*AcquireTime = NULL;\nuint32\t\t\t\t\t\tNbMutexes = 0;\nCFairMutex\t\t\t\t\t\t*ATMutex = NULL;\nbool\t\t\t\t\t\tInitAT = true;\n\n\n/// Inits the \"mutex debugging info system\"\nvoid initAcquireTimeMap()\n{\n\tif ( InitAT )\n\t{\n\t\tATMutex = new CFairMutex(\"ATMutex\");\n\t\tAcquireTime = new map<CFairMutex*,TMutexLocks>;\n\t\tInitAT = false;\n\t}\n}\n\n\n/// Gets the debugging info for all mutexes (call it evenly, e.g. once per second)\nmap<CFairMutex*,TMutexLocks>\tgetNewAcquireTimes()\n{\n\tmap<CMutex*,TMutexLocks>\tm;\n\tATMutex->enter();\n\n\t// Copy map\n\tm = *AcquireTime;\n\n\t// Reset map\n/*\tmap<CMutex*,TMutexLocks>::iterator im;\n\tfor ( im=AcquireTime->begin(); im!=AcquireTime->end(); ++im )\n\t{\n\t\t(*im).second.Time = 0;\n\t\t(*im).second.Nb = 0;\n\t\t(*im).second.Locked = false;\n\t}\n*/\n\tATMutex->leave();\n\treturn m;\n}\n\n\n////////////////////////\n////////////////////////\n\nvoid CFairMutex::debugCreateMutex()\n{\n/*\tif ( ! InitAT )\n\t{\n\t\tATMutex->enter();\n\t\tAcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes) ) );\n\t\tNbMutexes++;\n\t\tATMutex->leave();\n\t\tchar dbgstr [256];\n#ifdef STORE_MUTEX_NAME\n\t\tsmprintf( dbgstr, 256, \"MUTEX: Creating mutex %p %s (number %u)\\n\", this, Name.c_str(), NbMutexes-1 );\n#else\n\t\tsmprintf( dbgstr, 256, \"MUTEX: Creating mutex %p (number %u)\\n\", this, NbMutexes-1 );\n#endif\n#ifdef NL_OS_WINDOWS\n\t\tif ( IsDebuggerPresent() )\n\t\t\tOutputDebugString( dbgstr );\n#endif\n\t\tcout << dbgstr << endl;\n\t}\n*/}\n\nvoid CFairMutex::debugDeleteMutex()\n{\n\tif ( (this!=ATMutex ) && (ATMutex!=NULL) )\n\t{\n\t\tATMutex->enter();\n\t\t(*AcquireTime)[this].Dead = true;\n\t\tATMutex->leave();\n\t}\n}\n\nvoid CFairMutex::debugBeginEnter()\n{\n\tif ( (this!=ATMutex ) && (ATMutex!=NULL) )\n\t{\n\t\tTTicks t = CTime::getPerformanceTime();\n\n\t\tATMutex->enter();\n\t\tstd::map<CMutex*,TMutexLocks>::iterator it = (*AcquireTime).find (this);\n\t\tif (it == (*AcquireTime).end())\n\t\t{\n\t\t\tAcquireTime->insert( make_pair( this, TMutexLocks(NbMutexes++) ) );\n\t\t\tchar dbgstr [256];\n#ifdef STORE_MUTEX_NAME\n\t\t\tsmprintf( dbgstr, 256, \"MUTEX: Creating mutex %p %s (number %u)\\n\", this, Name.c_str(), NbMutexes-1 );\n#else\n\t\t\tsmprintf( dbgstr, 256, \"MUTEX: Creating mutex %p (number %u)\\n\", this, NbMutexes-1 );\n#endif\n\n#ifdef NL_OS_WINDOWS\n\t\t\tif ( IsDebuggerPresent() ) OutputDebugString( dbgstr );\n#endif\n\t\t\tcout << dbgstr << endl;\n\n\t\t\tit = (*AcquireTime).find (this);\n#ifdef STORE_MUTEX_NAME\n\t\t\t(*it).second.MutexName = Name;\n#endif\n\t\t}\n\t\t(*it).second.WaitingMutex++;\n\t\t(*it).second.BeginEnter = t;\n\t\tATMutex->leave();\n\t}\n}\n\n\nvoid CFairMutex::debugEndEnter()\n{\n//\tprintf(\"1\");\n/*\tchar str[1024];\n\tsprintf(str, \"enter %8p %8p %8p\\n\", this, _Mutex, getThreadId ());\n\tif (_Mutex == (void*)0x88)\n\t{\n\t\tOutputDebugString (str);\n\t\tif (entered) __asm int 3;\n\t\tentered = true;\n\t}\n*/\n\tif ( ( this != ATMutex ) && ( ATMutex != NULL ) )\n\t{\n\t\tTTicks t = CTime::getPerformanceTime();\n\t\tATMutex->enter();\n\t\tif ((uint32)(t-(*AcquireTime)[this].BeginEnter) > (*AcquireTime)[this].TimeToEnter)\n\t\t\t(*AcquireTime)[this].TimeToEnter = (uint32)(t-(*AcquireTime)[this].BeginEnter);\n\t\t(*AcquireTime)[this].Nb += 1;\n\t\t(*AcquireTime)[this].WaitingMutex--;\n\t\t(*AcquireTime)[this].ThreadHavingTheMutex = getThreadId();\n\t\t(*AcquireTime)[this].EndEnter = t;\n\t\tATMutex->leave();\n\t}\n}\n\n\nvoid CFairMutex::debugLeave()\n{\n//\tprintf( \"0\" );\n/*\tchar str[1024];\n\tsprintf(str, \"leave %8p %8p %8p\\n\", this, _Mutex, getThreadId ());\n\tif (_Mutex == (void*)0x88)\n\t{\n\t\tOutputDebugString (str);\n\t\tif (!entered) __asm int 3;\n\t\tentered = false;\n\t}\n*/\n\n\tif ( ( this != ATMutex ) && ( ATMutex != NULL ) )\n\t{\n\t\tTTicks Leave = CTime::getPerformanceTime();\n\t\tATMutex->enter();\n\t\tif ((uint32)(Leave-(*AcquireTime)[this].EndEnter) > (*AcquireTime)[this].TimeInMutex)\n\t\t\t(*AcquireTime)[this].TimeInMutex = (uint32)(Leave-(*AcquireTime)[this].EndEnter);\n\t\t(*AcquireTime)[this].Nb += 1;\n\t\t(*AcquireTime)[this].WaitingMutex = false;\n\t\t(*AcquireTime)[this].ThreadHavingTheMutex = 0xFFFFFFFF;\n\t\tATMutex->leave();\n\t}\n\n}\n\n#endif // MUTEX_DEBUG\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/nel-misc.pc",
    "content": "prefix=/usr\nexec_prefix=${prefix}\nlibdir=${exec_prefix}/lib\nincludedir=${prefix}/include\n\nName: nel-misc\nVersion: 0.5.0\nDescription: NeL 0.5.0\nRequires:\nLibs: -L${libdir}\nLibs.private: -ldl -lpthread  -lxml2 -lc -lpthread -lrt -ldl\nCflags: -I${includedir} -lc -lpthread -lrt -ldl\n"
  },
  {
    "path": "code/nel/src/misc/nel-misc.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: nel-misc\nVersion: @NL_VERSION@\nDescription: NeL @NL_VERSION@\nRequires:\nLibs: -L${libdir}\nLibs.private: @LIBS@ -lc -lpthread -lrt -ldl\nCflags: -I${includedir} -lc -lpthread -lrt -ldl\n"
  },
  {
    "path": "code/nel/src/misc/noise_value.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/noise_value.h\"\n#include \"nel/misc/fast_floor.h\"\n\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n// 3 level: best quality/speed ratio.\n#define\tNL3D_NOISE_LEVEL\t\t\t3\n#define\tNL3D_NOISE_GRID_SIZE_SHIFT\t5\n#define\tNL3D_NOISE_GRID_SIZE\t\t(1<<NL3D_NOISE_GRID_SIZE_SHIFT)\nstatic\tconst float NL3D_OO255= 1.0f / 255;\n\n// ***************************************************************************\n// ***************************************************************************\n// ***************************************************************************\n\n// ***************************************************************************\n/// A static 3D array of random value + other infos for noise\nclass\tCRandomGrid3D\n{\npublic:\n\n\t// generate a random grid, with same seed.\n\tCRandomGrid3D()\n\t{\n\t\t//seed\n\t\tsrand(0);\n\n\t\t// init the grid\n\t\tfor(uint z=0; z<NL3D_NOISE_GRID_SIZE; z++)\n\t\t{\n\t\t\tfor(uint y=0; y<NL3D_NOISE_GRID_SIZE; y++)\n\t\t\t{\n\t\t\t\tfor(uint x=0; x<NL3D_NOISE_GRID_SIZE; x++)\n\t\t\t\t{\n\t\t\t\t\tuint\tid= x + (y<<NL3D_NOISE_GRID_SIZE_SHIFT) + (z<<(NL3D_NOISE_GRID_SIZE_SHIFT*2));\n\t\t\t\t\t// take higher bits of rand gives better result.\n\t\t\t\t\tuint\tv= rand() >> 5;\n\t\t\t\t\t_Texture3d[id]= v&255;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// init sizes.\n\t\tuint\ti;\n\t\t// sum of sizes must be 1, and each level must be /2.\n\t\tfloat\tsizeSum=0;\n\t\tfor(i=0; i<NL3D_NOISE_LEVEL; i++)\n\t\t{\n\t\t\t_Sizes[i]= 1.0f / (1<<i);\n\t\t\tsizeSum+= _Sizes[i];\n\t\t}\n\t\t// normalize\n\t\tfor(i=0; i<NL3D_NOISE_LEVEL; i++)\n\t\t{\n\t\t\t_Sizes[i]/= sizeSum;\n\t\t}\n\n\t\t// init LevelPhases.\n\t\tfor(i=0; i<NL3D_NOISE_LEVEL; i++)\n\t\t{\n\t\t\t_LevelPhase[i].x= frand(NL3D_NOISE_GRID_SIZE);\n\t\t\t_LevelPhase[i].y= frand(NL3D_NOISE_GRID_SIZE);\n\t\t\t_LevelPhase[i].z= frand(NL3D_NOISE_GRID_SIZE);\n\t\t}\n\t\t// not for level 0.\n\t\t_LevelPhase[0]= CVector::Null;\n\t}\n\n\t// x/y/z are use to lookup directly in the grid 3D.\n\tstatic inline float\tevalNearest(const CVector &pos)\n\t{\n\t\t// compute integer part.\n\t\tsint\tx= OptFastFloor(pos.x);\n\t\tsint\ty= OptFastFloor(pos.y);\n\t\tsint\tz= OptFastFloor(pos.z);\n\t\t// index in texture.\n\t\tuint\tux= x& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuy= y& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuz= z& (NL3D_NOISE_GRID_SIZE-1);\n\n\t\t// read the texture.\n\t\tfloat\tturb= lookup(ux,uy,uz);\n\n\t\treturn turb*NL3D_OO255;\n\t}\n\n\t// x/y/z are use to lookup directly in the grid 3D.\n\tstatic inline float\tevalBiLinear(const CVector &pos)\n\t{\n\t\t// compute integer part.\n\t\tsint\tx= OptFastFloor(pos.x);\n\t\tsint\ty= OptFastFloor(pos.y);\n\t\tsint\tz= OptFastFloor(pos.z);\n\t\t// index in texture.\n\t\tuint\tux= x& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuy= y& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuz= z& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tux2= (x+1)& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuy2= (y+1)& (NL3D_NOISE_GRID_SIZE-1);\n\t\tuint\tuz2= (z+1)& (NL3D_NOISE_GRID_SIZE-1);\n\t\t// delta.\n\t\tfloat\tdx2;\n\t\tfloat\tdy2;\n\t\tfloat\tdz2;\n\t\teaseInEaseOut(dx2, pos.x-x);\n\t\teaseInEaseOut(dy2, pos.y-y);\n\t\teaseInEaseOut(dz2, pos.z-z);\n\t\tfloat\tdx= 1-dx2;\n\t\tfloat\tdy= 1-dy2;\n\t\tfloat\tdz= 1-dz2;\n\t\t// TriLinear in texture3D.\n\t\tfloat\tturb=0;\n\t\tfloat\tdxdy= dx*dy;\n\t\tturb+= lookup(ux,uy,uz)* dxdy*dz;\n\t\tturb+= lookup(ux,uy,uz2)* dxdy*dz2;\n\t\tfloat\tdxdy2= dx*dy2;\n\t\tturb+= lookup(ux,uy2,uz)* dxdy2*dz;\n\t\tturb+= lookup(ux,uy2,uz2)* dxdy2*dz2;\n\t\tfloat\tdx2dy= dx2*dy;\n\t\tturb+= lookup(ux2,uy,uz)* dx2dy*dz;\n\t\tturb+= lookup(ux2,uy,uz2)* dx2dy*dz2;\n\t\tfloat\tdx2dy2= dx2*dy2;\n\t\tturb+= lookup(ux2,uy2,uz)* dx2dy2*dz;\n\t\tturb+= lookup(ux2,uy2,uz2)* dx2dy2*dz2;\n\n\t\t// End!\n\t\treturn turb*NL3D_OO255;\n\t}\n\n\n\t// get size according to level\n\tstatic inline float\tgetLevelSize(uint level)\n\t{\n\t\treturn _Sizes[level];\n\t}\n\n\t// get an additional level phase.\n\tstatic inline const CVector\t&getLevelPhase(uint level)\n\t{\n\t\treturn _LevelPhase[level];\n\t}\n\n\n// **************\nprivate:\n\n\tstatic\tuint8\t\t_Texture3d[NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE];\n\tstatic\tfloat\t\t_Sizes[NL3D_NOISE_LEVEL];\n\tstatic\tCVector\t\t_LevelPhase[NL3D_NOISE_LEVEL];\n\n\n\t// lookup with no mod.\n\tstatic inline float\tlookup(uint ux, uint uy, uint uz)\n\t{\n\t\tuint\tid= ux + (uy<<NL3D_NOISE_GRID_SIZE_SHIFT) + (uz<<(NL3D_NOISE_GRID_SIZE_SHIFT*2));\n\t\treturn\t_Texture3d[id];\n\t}\n\n\t// easineasout\n\tstatic inline void\teaseInEaseOut(float &y, float x)\n\t{\n\t\t// cubic such that f(0)=0, f'(0)=0, f(1)=1, f'(1)=0.\n\t\tfloat\tx2=x*x;\n\t\tfloat\tx3=x2*x;\n\t\ty= -2*x3 + 3*x2;\n\t}\n\n};\n\n\nuint8\t\tCRandomGrid3D::_Texture3d[NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE];\nfloat\t\tCRandomGrid3D::_Sizes[NL3D_NOISE_LEVEL];\nCVector\t\tCRandomGrid3D::_LevelPhase[NL3D_NOISE_LEVEL];\n\n// just to init the static arrays.\nstatic\tCRandomGrid3D\tNL3D_RandomGrid3D;\n\n\n// ***************************************************************************\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\nfloat\tCNoiseValue::evalRandom(const CVector &pos) const\n{\n\treturn CRandomGrid3D::evalNearest(pos);\n}\n\n\n// ***************************************************************************\nfloat\tCNoiseValue::noise(const CVector &pos) const\n{\n\t// eval \"fractaly\".\n\tfloat\t\tturb;\n\n#if (NL3D_NOISE_LEVEL != 3)\n\tCVector\t\tvd= pos;\n\tturb=0;\n\tfor(uint level=0;level<NL3D_NOISE_LEVEL;level++)\n\t{\n\t\t// Add the influence of the ith level.\n\t\tturb+= CRandomGrid3D::getLevelSize(level) *\n\t\t\tCRandomGrid3D::evalBiLinear(vd + CRandomGrid3D::getLevelPhase(level) );\n\t\t// Next level at higher frequency\n\t\tvd*= 2;\n\t}\n#else\n\t// special case. unrolled loop.\n\t// level 0 has no phase.\n\tturb= CRandomGrid3D::getLevelSize(0) *\n\t\tCRandomGrid3D::evalBiLinear(pos);\n\t// level 1\n\tturb+= CRandomGrid3D::getLevelSize(1) *\n\t\tCRandomGrid3D::evalBiLinear(pos*2 + CRandomGrid3D::getLevelPhase(1) );\n\t// level 2\n\tturb+= CRandomGrid3D::getLevelSize(2) *\n\t\tCRandomGrid3D::evalBiLinear(pos*4 + CRandomGrid3D::getLevelPhase(2) );\n#endif\n\n\treturn turb;\n}\n\n\n\n// ***************************************************************************\nCNoiseValue::CNoiseValue()\n{\n\tAbs= 0;\n\tRand= 1;\n\tFrequency= 1;\n}\n\n\n// ***************************************************************************\nCNoiseValue::CNoiseValue(float abs, float rand, float freq)\n{\n\tAbs= abs;\n\tRand= rand;\n\tFrequency= freq;\n}\n\n\n// ***************************************************************************\nfloat\tCNoiseValue::eval(const CVector &posInWorld) const\n{\n\t// A single cube in the Grid3d correspond to Frequency==1.\n\t// So enlarging size of the grid3d do not affect the frequency aspect.\n\treturn Abs + Rand * noise(posInWorld*Frequency);\n}\n\n\n// ***************************************************************************\nfloat\tCNoiseValue::evalOneLevelRandom(const CVector &posInWorld) const\n{\n\t// A single cube in the Grid3d correspond to Frequency==1.\n\t// So enlarging size of the grid3d do not affect the frequency aspect.\n\treturn Abs + Rand * evalRandom(posInWorld*Frequency);\n}\n\n\n// ***************************************************************************\nvoid\tCNoiseValue::serial(IStream &f)\n{\n\t(void)f.serialVersion(0);\n\tf.serial(Abs);\n\tf.serial(Rand);\n\tf.serial(Frequency);\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\nvoid\tCNoiseColorGradient::eval(const CVector &posInWorld, CRGBAF &result) const\n{\n\t// test if not null grads.\n\tuint\tnGrads= (uint)Gradients.size();\n\tif(nGrads==0)\n\t\treturn;\n\t// if only one color, easy\n\tif(nGrads==1)\n\t{\n\t\tresult= Gradients[0];\n\t}\n\telse\n\t{\n\t\t// eval noise\n\t\tfloat\tf= NoiseValue.eval(posInWorld) * (nGrads-1);\n\t\tclamp(f, 0.f, (float)(nGrads-1));\n\t\t// look up in table of gradients.\n\t\tuint\tid= OptFastFloor(f);\n\t\tclamp(id, 0U, nGrads-2);\n\t\t// fractionnal part.\n\t\tf= f-id;\n\t\tclamp(f, 0, 1);\n\t\t// interpolate the gradient.\n\t\tresult= Gradients[id]*(1-f) + Gradients[id+1]*f;\n\t}\n}\n\n// ***************************************************************************\nvoid\tCNoiseColorGradient::serial(IStream &f)\n{\n\t(void)f.serialVersion(0);\n\tf.serial(NoiseValue);\n\tf.serialCont(Gradients);\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/o_xml.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/o_xml.h\"\n\n#ifndef NL_DONT_USE_EXTERNAL_CODE\n\n// Include from libxml2\n#include <libxml/xmlerror.h>\n\n#if defined(NL_OS_WINDOWS) && defined(NL_COMP_VC_VERSION) && NL_COMP_VC_VERSION >= 80\n#define USE_LOCALE_SPRINTF\n#include <locale.h>\n#endif\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// ***************************************************************************\n\nconst char SEPARATOR = ' ';\n\n// ***************************************************************************\n\n#ifdef USE_LOCALE_SPRINTF\n\n#define writenumber(src,format,digits) \\\n\tchar number_as_cstring [digits+1]; \\\n\t_sprintf_l( number_as_cstring, format, (_locale_t)_Locale, src ); \\\n\tserialSeparatedBufferOut( number_as_cstring );\n\n#else\n\n#define writenumber(src,format,digits) \\\n\tchar number_as_cstring [digits+1]; \\\n\tsprintf( number_as_cstring, format, src ); \\\n\tserialSeparatedBufferOut( number_as_cstring );\n\n#endif\n\n// ***************************************************************************\n// XML callbacks\n// ***************************************************************************\n\nint xmlOutputWriteCallbackForNeL ( void *context, const char *buffer, int len)\n{\n\t// no need to save empty buffer\n\tif(len == 0) return 0;\n\n\t// Get the object\n\tCOXml *object = (COXml*) context;\n\n\t// Serialise the buffer\n\tobject->_InternalStream->serialBuffer ((uint8*)buffer, len);\n\n\t// Return the value\n\treturn len;\n}\n\n// ***************************************************************************\n\nint xmlOutputCloseCallbackForNeL ( void * /* context */ )\n{\n\t// Get the object\n\t// COXml *object = (COXml*) context;\n\n\t// Does nothing\n\treturn 1;\n}\n\n// ***************************************************************************\n\nxmlDocPtr COXml::getDocument ()\n{\n\tif (_Document)\n\t\treturn _Document;\n\n\t// Initialise the document\n\t_Document = xmlNewDoc ((const xmlChar *)_Version.c_str());\n\n\treturn _Document;\n}\n\n\n// ***************************************************************************\n\ninline void COXml::flushContentString ()\n{\n\t// Current node must exist here\n\tnlassert (_CurrentNode);\n\n\t// String size\n\tuint size=(uint)_ContentString.length();\n\n\t// Some content to write ?\n\tif (size)\n\t{\n\t\t// Write it in the current node\n\t\txmlNodePtr textNode = xmlNewText ((const xmlChar *)_ContentString.c_str());\n\t\txmlAddChild (_CurrentNode, textNode);\n\n\t\t// Empty the string\n\t\t_ContentString.erase ();\n\t}\n}\n\n// ***************************************************************************\n\nCOXml::COXml () : IStream (false /* Output mode */)\n{\n\t// Set XML mode\n\tsetXMLMode (true);\n\n\t// Set the stream\n\t_InternalStream = NULL;\n\n\t// Set the version\n\t_Version = \"1.0\";\n\n\t// Initialise the document\n\t_Document = NULL;\n\n\t// Current node\n\t_CurrentNode = NULL;\n\n\t// Content string\n\t_ContentString = \"\";\n\n\t// Push begin\n\t_PushBegin = false;\n\n#ifdef USE_LOCALE_SPRINTF\n\t// create C numeric locale\n\t_Locale = _create_locale(LC_NUMERIC, \"C\");\n#else\n\t_Locale = NULL;\n#endif\n}\n\n// ***************************************************************************\n\nvoid xmlGenericErrorFuncWrite (void *ctx, const char *msg, ...)\n{\n\t// Get the error string\n\tstring str;\n\tNLMISC_CONVERT_VARGS (str, msg, NLMISC::MaxCStringSize);\n\t((COXml*)ctx)->_ErrorString += str;\n}\n\n// ***************************************************************************\n\nbool COXml::init (IStream *stream, const char *version)\n{\n\tresetPtrTable();\n\n\t// Output stream ?\n\tif (!stream->isReading())\n\t{\n\t\t// Set error handler\n\t\t_ErrorString = \"\";\n\t\txmlSetGenericErrorFunc\t(this, xmlGenericErrorFuncWrite);\n\n\t\t// Set XML mode\n\t\tsetXMLMode (true);\n\n\t\t// Set the stream\n\t\t_InternalStream = stream;\n\n\t\t// Set the version\n\t\t_Version = version;\n\n\t\t// Initialise the document\n\t\t_Document = NULL;\n\n\t\t// Current node\n\t\t_CurrentNode = NULL;\n\n\t\t// Content string\n\t\t_ContentString = \"\";\n\n\t\t// Push begin\n\t\t_PushBegin = false;\n\n\t\t// Ok\n\t\treturn true;\n\t}\n\telse\n\t\treturn false;\n}\n\n// ***************************************************************************\n\nCOXml::~COXml ()\n{\n\t// Flush document to the internal stream\n\tflush ();\n\n#ifdef USE_LOCALE_SPRINTF\n\tif (_Locale) _free_locale((_locale_t)_Locale);\n#endif\n}\n\n// ***************************************************************************\n\nvoid COXml::serialSeparatedBufferOut( const char *value )\n{\n\tnlassert( ! isReading() );\n\n\t// Output stream has been setuped ?\n\tif ( _InternalStream )\n\t{\n\t\t// Current node presents ?\n\t\tif (_CurrentNode)\n\t\t{\n\t\t\t// Write a push attribute ?\n\t\t\tif (_PushBegin)\n\t\t\t{\n\t\t\t\t// Current attrib is set ?\n\t\t\t\tif (_AttribPresent)\n\t\t\t\t{\n\t\t\t\t\t// Set the attribute\n\t\t\t\t\txmlSetProp (_CurrentNode, (const xmlChar*)_AttribName.c_str(), (const xmlChar*)value);\n\n\t\t\t\t\t// The attribute has been used\n\t\t\t\t\t_AttribPresent = false;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// * Error, the stream don't use XML streaming properly\n\t\t\t\t\t// * You must take care of this in your last serial call:\n\t\t\t\t\t// * - Between xmlPushBegin() and xmlPushEnd(), before each serial, you must set the attribute name with xmlSetAttrib.\n\t\t\t\t\t// * - Between xmlPushBegin() and xmlPushEnd(), you must serial only basic objects (numbers and strings).\n\t\t\t\t\tnlerror ( \"Error, the stream don't use XML streaming properly\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Get the content buffer size\n\t\t\t\tuint size=(uint)_ContentString.length();\n\n\t\t\t\t// Add a separator\n\t\t\t\tif ((size) && (_ContentString[size-1]!='\\n'))\n\t\t\t\t\t_ContentString += SEPARATOR;\n\n\t\t\t\t// Concat the strings\n\t\t\t\t_ContentString += value;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// * Error, no current node present.\n\t\t\t// * Check that your serial is initialy made between a xmlPushBegin and xmlPushEnd calls.\n\t\t\tnlerror ( \"Error, the stream don't use XML streaming properly\" );\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlerror ( \"Output stream has not been setuped\" );\n\t}\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(uint8 &b)\n{\n\t// Write the number\n\twritenumber( (uint16)b,\"%hu\", 3 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(sint8 &b)\n{\n\twritenumber( (sint16)b, \"%hd\", 4 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(uint16 &b)\n{\n\twritenumber( b, \"%hu\", 5 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(sint16 &b)\n{\n\twritenumber( b, \"%hd\", 6 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(uint32 &b)\n{\n\twritenumber( b, \"%u\", 10 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(sint32 &b)\n{\n\twritenumber( b, \"%d\", 11 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(uint64 &b)\n{\n\twritenumber( b, \"%\" NL_I64 \"u\", 20 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(sint64 &b)\n{\n\twritenumber( b, \"%\" NL_I64 \"d\", 20 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(float &b)\n{\n\twritenumber( (double)b, \"%f\", 128 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(double &b)\n{\n\twritenumber( b, \"%f\", 128 );\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(bool &b)\n{\n\tserialBit(b);\n}\n\n// ***************************************************************************\n\nvoid COXml::serialBit(bool &bit)\n{\n\tuint8 u = (uint8)bit;\n\tserial( u );\n}\n\n// ***************************************************************************\n\n#ifndef NL_OS_CYGWIN\nvoid COXml::serial(char &b)\n{\n\tchar tmp[2] = {b , 0};\n\tserialSeparatedBufferOut( tmp );\n}\n#endif // NL_OS_CYGWIN\n\n// ***************************************************************************\n\nvoid COXml::serial(std::string &b)\n{\n\tnlassert( ! isReading() );\n\n\t// Attibute ?\n\tif (_PushBegin)\n\t{\n\t\t// Only serial the string\n\t\tserialSeparatedBufferOut( b.c_str() );\n\t}\n\telse\n\t{\n\t\t// Open a string node\n\t\txmlPush (\"S\");\n\n\t\t// Serial the string\n\t\tserialSeparatedBufferOut( b.c_str() );\n\n\t\t// Close the node\n\t\txmlPop ();\n\t}\n}\n\n// ***************************************************************************\n\nvoid COXml::serial(ucstring &b)\n{\n\tnlassert( ! isReading() );\n\n\t// convert ucstring to utf-8 std::string\n\tstd::string output = b.toUtf8();\n\n\t// Serial this string\n\tserial (output);\n}\n\n// ***************************************************************************\n\nvoid COXml::serialBuffer(uint8 *buf, uint len)\n{\n\t// Open a node\n\txmlPush (\"BUFFER\");\n\n\t// Serialize the buffer\n\tfor (uint i=0; i<len; i++)\n\t{\n\t\txmlPush (\"ELM\");\n\n\t\tserial (buf[i]);\n\n\t\txmlPop ();\n\t}\n\n\t// Close the node\n\txmlPop ();\n}\n\n// ***************************************************************************\n\nbool COXml::xmlPushBeginInternal (const char *nodeName)\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Can make a xmlPushBegin ?\n\t\tif ( ! _PushBegin )\n\t\t{\n\t\t\t// Current node exist ?\n\t\t\tif (_CurrentNode==NULL)\n\t\t\t{\n\t\t\t\t// No document ?\n\t\t\t\tif (_Document == NULL)\n\t\t\t\t{\n\t\t\t\t\t// Initialise the document\n\t\t\t\t\t_Document = xmlNewDoc ((const xmlChar *)_Version.c_str());\n\n\t\t\t\t\t// Return NULL if error\n\t\t\t\t\tnlassert (_Document);\n\t\t\t\t}\n\n\t\t\t\t// Create the first node\n\t\t\t\t_CurrentNode=xmlNewDocNode (_Document, NULL, (const xmlChar*)nodeName, NULL);\n\t\t\t\txmlDocSetRootElement (_Document, _CurrentNode);\n\n\t\t\t\t// Return NULL if error\n\t\t\t\tnlassert (_CurrentNode);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Flush current content string ?\n\t\t\t\tflushContentString ();\n\n\t\t\t\t// Create a new node\n\t\t\t\t_CurrentNode=xmlNewChild (_CurrentNode, NULL, (const xmlChar*)nodeName, NULL);\n\n\t\t\t\t// Return NULL if error\n\t\t\t\tnlassert (_CurrentNode);\n\t\t\t}\n\n\t\t\t// Push begun\n\t\t\t_PushBegin = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must close your xmlPushBegin - xmlPushEnd before calling a new xmlPushBegin.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool COXml::xmlPushEndInternal ()\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Can make a xmlPushEnd ?\n\t\tif ( _PushBegin )\n\t\t{\n\t\t\t// Push begun\n\t\t\t_PushBegin = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must call xmlPushBegin before calling xmlPushEnd.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool COXml::xmlPopInternal ()\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Not in the push mode ?\n\t\tif ( ! _PushBegin )\n\t\t{\n\t\t\t// Some content to write ?\n\t\t\tflushContentString ();\n\n\t\t\t// Get parent\n\t\t\t_CurrentNode=_CurrentNode->parent;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must call xmlPop after xmlPushEnd.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool COXml::xmlSetAttribInternal (const char *attribName)\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Can make a xmlPushEnd ?\n\t\tif ( _PushBegin )\n\t\t{\n\t\t\t// Set attribute name\n\t\t\t_AttribName = attribName;\n\n\t\t\t// Attribute name is present\n\t\t\t_AttribPresent = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must call xmlSetAttrib between xmlPushBegin and xmlPushEnd calls.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool COXml::xmlBreakLineInternal ()\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Not in the push mode ?\n\t\tif ( ! _PushBegin )\n\t\t{\n\t\t\t// Add a break line\n\t\t\t_ContentString += '\\n';\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must call xmlNBreakLine after xmlPushEnd.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nbool COXml::xmlCommentInternal (const char *comment)\n{\n\tnlassert( ! isReading() );\n\n\t// Check _InternalStream\n\tif ( _InternalStream )\n\t{\n\t\t// Not in the push mode ?\n\t\tif ( _CurrentNode != NULL)\n\t\t{\n\t\t\t// Add a comment node\n\t\t\txmlNodePtr commentPtr = xmlNewComment ((const xmlChar *)comment);\n\n\t\t\t// Add the node\n\t\t\txmlAddChild (_CurrentNode, commentPtr);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning ( \"XML: You must call xmlCommentInternal between xmlPushBegin and xmlPushEnd.\");\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning ( \"XML: Output stream has not been setuped.\");\n\t\treturn false;\n\t}\n\t// Ok\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid COXml::flush ()\n{\n\tif (_Document)\n\t{\n\t\t// Generate indentation\n\t\txmlKeepBlanksDefault (0);\n\n\t\t// Create a output context\n\t\txmlOutputBufferPtr outputBuffer = xmlOutputBufferCreateIO  ( xmlOutputWriteCallbackForNeL, xmlOutputCloseCallbackForNeL, this, NULL );\n\n\t\t// Save the file\n\t\tint res = xmlSaveFormatFileTo (outputBuffer, _Document, NULL, 1);\n\n\t\t// No error should be returned because, exception should be raised by the internal stream\n\t\tnlassert (res!=-1);\n\n\t\t// Free the document\n\t\txmlFreeDoc (_Document);\n\t\t_Document = NULL;\n\t}\n}\n\n// ***************************************************************************\n\nbool COXml::isStringValidForProperties (const char *str)\n{\n\twhile (*str)\n\t{\n\t\tif (*str == '\\n')\n\t\t\treturn false;\n\t\tstr++;\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nconst char *COXml::getErrorString () const\n{\n\treturn _ErrorString.c_str ();\n}\n\n} // NLMISC\n\n#endif // NL_DONT_USE_EXTERNAL_CODE\n"
  },
  {
    "path": "code/nel/src/misc/object_arena_allocator.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/object_arena_allocator.h\"\n#include \"nel/misc/fixed_size_allocator.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\nCObjectArenaAllocator *CObjectArenaAllocator::_DefaultAllocator = NULL;\n\n\n// *****************************************************************************************************************\nCObjectArenaAllocator::CObjectArenaAllocator(uint maxAllocSize, uint granularity /* = 4*/)\n{\n\tnlassert(granularity > 0);\n\tnlassert(maxAllocSize > 0);\n\t_MaxAllocSize = granularity * ((maxAllocSize + (granularity - 1)) / granularity);\n\t_ObjectSizeToAllocator.resize(_MaxAllocSize / granularity, NULL);\n\t_Granularity = granularity;\n\t#ifdef NL_DEBUG\n\t\t_AllocID = 0;\n\t\t_WantBreakOnAlloc = false;\n\t\t_BreakAllocID = 0;\n\t#endif\n}\n\n// *****************************************************************************************************************\nCObjectArenaAllocator::~CObjectArenaAllocator()\n{\n\tfor(uint k = 0; k < _ObjectSizeToAllocator.size(); ++k)\n\t{\n\t\tdelete _ObjectSizeToAllocator[k];\n\t}\n}\n\n// *****************************************************************************************************************\nvoid *CObjectArenaAllocator::alloc(uint size)\n{\n\t#ifdef NL_DEBUG\n\t\tif (_WantBreakOnAlloc)\n\t\t{\n\t\t\tif (_AllocID == _BreakAllocID)\n\t\t\t{\n\t\t\t\tnlassert(0);\n\t\t\t}\n\t\t}\n\t#endif\n\tif (size >= _MaxAllocSize)\n\t{\n\t\t// use standard allocator\n\t\tnlctassert(NL_DEFAULT_MEMORY_ALIGNMENT >= sizeof(uint));\n\t\tuint8 *block = (uint8 *)aligned_malloc(NL_DEFAULT_MEMORY_ALIGNMENT + size, NL_DEFAULT_MEMORY_ALIGNMENT); //new uint8[size + sizeof(uint)]; // an additionnal uint is needed to store size of block\n\t\tif (!block) return NULL;\n\t\t#ifdef NL_DEBUG\n\t\t\t_MemBlockToAllocID[block] = _AllocID;\n\t\t#endif\n\t\t*(uint *) block = size;\n\t\treturn block + NL_DEFAULT_MEMORY_ALIGNMENT;\n\t}\n\tuint entry = ((size + (_Granularity - 1)) / _Granularity) ;\n\tnlassert(entry < _ObjectSizeToAllocator.size());\n\tif (!_ObjectSizeToAllocator[entry])\n\t{\n\t\t_ObjectSizeToAllocator[entry] = new CFixedSizeAllocator(entry * _Granularity + NL_DEFAULT_MEMORY_ALIGNMENT, _MaxAllocSize / size); // an additionnal uint is needed to store size of block\n\t}\n\tvoid *block = _ObjectSizeToAllocator[entry]->alloc();\n\tnlassert(((uintptr_t)block % NL_DEFAULT_MEMORY_ALIGNMENT) == 0);\n\t#ifdef NL_DEBUG\n\t\tif (block)\n\t\t{\n\t\t\t_MemBlockToAllocID[block] = _AllocID;\n\t\t}\n\t\t++_AllocID;\n\t#endif\n\t*(uint *) block = size;\n\treturn (void *) ((uint8 *) block + NL_DEFAULT_MEMORY_ALIGNMENT);\n}\n\n// *****************************************************************************************************************\nvoid CObjectArenaAllocator::free(void *block)\n{\n\tif (!block) return;\n\tuint8 *realBlock = (uint8 *) block - NL_DEFAULT_MEMORY_ALIGNMENT; // sizeof(uint); // a uint is used at start of block to give its size\n\tuint size = *(uint *) realBlock;\n\tif (size >= _MaxAllocSize)\n\t{\n\t\t#ifdef NL_DEBUG\n\t\t\t\tstd::map<void *, uint>::iterator it = _MemBlockToAllocID.find(realBlock);\n\t\t\t\tnlassert(it != _MemBlockToAllocID.end());\n\t\t\t\t_MemBlockToAllocID.erase(it);\n\t\t#endif\n\t\taligned_free(realBlock);\n\t\treturn;\n\t}\n\tuint entry = ((size + (_Granularity - 1)) / _Granularity);\n\tnlassert(entry < _ObjectSizeToAllocator.size());\n\t_ObjectSizeToAllocator[entry]->free(realBlock);\n\t#ifdef NL_DEBUG\n\t\tstd::map<void *, uint>::iterator it = _MemBlockToAllocID.find(realBlock);\n\t\tnlassert(it != _MemBlockToAllocID.end());\n\t\t/*\n\t\t#ifdef NL_DEBUG\n\t\t\t\tif (_WantBreakOnAlloc)\n\t\t\t\t{\n\t\t\t\t\tif (it->second == _BreakAllocID)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlassert(0);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t#endif\n\t\t*/\n\t\t_MemBlockToAllocID.erase(it);\n\t#endif\n}\n\n// *****************************************************************************************************************\nuint CObjectArenaAllocator::getNumAllocatedBlocks() const\n{\n\tuint numObjs = 0;\n\tfor(uint k = 0; k < _ObjectSizeToAllocator.size(); ++k)\n\t{\n\t\tif (_ObjectSizeToAllocator[k]) numObjs += _ObjectSizeToAllocator[k]->getNumAllocatedBlocks();\n\t}\n\treturn numObjs;\n}\n\n// *****************************************************************************************************************\nCObjectArenaAllocator &CObjectArenaAllocator::getDefaultAllocator()\n{\n\tif (!_DefaultAllocator)\n\t{\n\t\t_DefaultAllocator = new CObjectArenaAllocator(32768);\n\t}\n\treturn *_DefaultAllocator;\n}\n\n\n#ifdef NL_DEBUG\n\n// *****************************************************************************************************************\nvoid CObjectArenaAllocator::dumpUnreleasedBlocks()\n{\n\tfor(std::map<void *, uint>::iterator it = _MemBlockToAllocID.begin(); it != _MemBlockToAllocID.end(); ++it)\n\t{\n\t  nlinfo(\"block %u at adress %p remains\", it->second, (static_cast<uint8 *>(it->first) + sizeof(uint)));\n\t}\n}\n\n// *****************************************************************************************************************\nvoid CObjectArenaAllocator::setBreakForAllocID(bool enabled, uint id)\n{\n\t_WantBreakOnAlloc = enabled;\n\t_BreakAllocID = id;\n}\n\n#endif // NL_DEBUG\n\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/object_vector.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/object_vector.h\"\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_object_vector_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/p_thread.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n\n#ifdef NL_OS_UNIX\n\n#include \"nel/misc/p_thread.h\"\n#include \"nel/misc/debug.h\"\n\n#include <sched.h>\n#include <pwd.h>\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n/* Key for thread specific storage holding IThread pointer. */\nstatic pthread_key_t threadSpecificKey;\n\n/* Special thread type representing the main thread. */\nstruct CPMainThread : public CPThread\n{\n\tCPMainThread() : CPThread(NULL, 0)\n\t{\n\t\tif(pthread_key_create(&threadSpecificKey, NULL) != 0)\n\t\t\tthrow EThread(\"cannot create thread specific storage key.\");\n\n\t\tif(pthread_setspecific(threadSpecificKey, this) != 0)\n\t\t\tthrow EThread(\"cannot set main thread ptr in thread specific storage.\");\n\t}\n\n\t~CPMainThread()\n\t{\n\t\tif(pthread_key_delete(threadSpecificKey) != 0)\n\t\t\tthrow EThread(\"cannot delete thread specific storage key.\");\n\t}\n};\n\n/* Holds the thread instance representing the main thread. */\nstatic CPMainThread mainThread = CPMainThread();\n\n/*\n * The IThread static creator\n */\nIThread *IThread::create( IRunnable *runnable, uint32 stackSize)\n{\n\treturn new CPThread( runnable, stackSize );\n}\n\n/*\n * Get the current thread\n */\nIThread *IThread::getCurrentThread ()\n{\n\treturn (IThread *)pthread_getspecific(threadSpecificKey);\n}\n\n/*\n * Thread beginning\n */\nstatic void *ProxyFunc( void *arg )\n{\n\tCPThread *parent = (CPThread*)arg;\n\n\t// Set this thread's thread specific storage to IThread instance pointer\n\tif(pthread_setspecific(threadSpecificKey, parent) != 0)\n\t\tthrow EThread(\"cannot set thread ptr in thread specific storage.\");\n\n\t// Allow to terminate the thread without cancellation point\n\tpthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);\n\n\t// Run the code of the thread\n\tparent->Runnable->run();\n\n\t{\n\t\tpthread_t thread_self = pthread_self();\n\t\t// Make sure the parent still cares\n\t\t// If this thread was replaced with a new thread (which should not happen),\n\t\t// and the IThread object has been deleted, this will likely crash.\n\t\tif (parent->_ThreadHandle == thread_self)\n\t\t\tparent->_State = CPThread::ThreadStateFinished;\n\t\telse\n\t\t\tthrow EThread(\"Thread ended after being detached, this should not happen\");\n\t}\n\n\t// Allow some clean\n//\tpthread_exit(0);\n\treturn NULL;\n}\n\n\n\n/*\n * Constructor\n */\nCPThread::CPThread(IRunnable *runnable, uint32 stackSize)\n\t:\tRunnable(runnable),\n\t\t_State(ThreadStateNone),\n\t\t_StackSize(stackSize)\n{}\n\n\n/*\n * Destructor\n */\nCPThread::~CPThread()\n{\n\tterminate(); // force the end of the thread if not already ended\n\n\tif (_State != ThreadStateNone)\n\t\tpthread_detach(_ThreadHandle); // free allocated resources only if it was created\n}\n\n/*\n * start\n */\nvoid CPThread::start()\n{\n\tpthread_attr_t tattr;\n\tint ret;\n\n\tif (_StackSize != 0)\n\t{\n\t\t/* initialized with default attributes */\n\t\tret = pthread_attr_init(&tattr);\n\n\t\t/* setting the size of the stack also */\n\t\tret = pthread_attr_setstacksize(&tattr, _StackSize);\n\t}\n\n\tbool detach_old_thread = false;\n\tpthread_t old_thread_handle;\n\tif (_State != ThreadStateNone)\n\t{\n\t\tif (_State == ThreadStateRunning)\n\t\t{\n\t\t\t// I don't know if this behaviour is allowed, but neither thread implementations\n\t\t\t// check the start function, and both simply let the existing running thread for what it is...\n\t\t\t// From now on, this is not allowed.\n\t\t\tthrow EThread(\"Starting a thread that is already started, existing thread will continue running, this should not happen\");\n\t\t}\n\t\tdetach_old_thread = true;\n\t\told_thread_handle = _ThreadHandle;\n\t}\n\n    sigset_t new_mask, old_mask; \n    sigemptyset(&new_mask); \n    sigaddset(&new_mask, SIGINT); \n    sigaddset(&new_mask, SIGQUIT); \n    sigaddset(&new_mask, SIGTERM); \n    pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask); \n\n\tif (pthread_create(&_ThreadHandle, _StackSize != 0 ? &tattr : NULL, ProxyFunc, this) != 0)\n\t{\n        pthread_sigmask(SIG_SETMASK, &old_mask, NULL);\n\t\tthrow EThread(\"Cannot start new thread\");\n\t}\n    pthread_sigmask(SIG_SETMASK, &old_mask, NULL);\n\t_State = ThreadStateRunning;\n\n    if (_StackSize != 0)\n    {\n        pthread_attr_destroy(&tattr);\n    }\n\n\tif (detach_old_thread)\n\t{\n\t\t// Docs don't say anything about what happens when pthread_create is called with existing handle referenced.\n\t\tif (old_thread_handle == _ThreadHandle)\n\t\t\tthrow EThread(\"Thread handle did not change, this should not happen\");\n\t\t// Don't care about old thread, free resources when it terminates.\n\t\tpthread_detach(old_thread_handle);\n\t}\n}\n\nbool CPThread::isRunning()\n{\n\treturn _State == ThreadStateRunning;\n}\n\n/*\n * terminate\n */\nvoid CPThread::terminate()\n{\n\tif (_State == ThreadStateRunning)\n\t{\n\t\t// cancel only if started\n\t\tpthread_cancel(_ThreadHandle);\n\t\t_State = ThreadStateFinished; // set to finished\n\t}\n}\n\n/*\n * wait\n */\nvoid CPThread::wait ()\n{\n\tif (_State == ThreadStateRunning)\n\t{\n\t\tint error = pthread_join(_ThreadHandle, 0);\n\t\tswitch (error)\n\t\t{\n\t\tcase 0:\n\t\t\tbreak;\n\t\tcase EINVAL:\n\t\t\tthrow EThread(\"Thread is not joinable\");\n\t\tcase ESRCH:\n\t\t\tthrow EThread(\"No thread found with this id\");\n\t\tcase EDEADLK:\n\t\t\tthrow EThread(\"Deadlock detected or calling thread waits for itself\");\n\t\tdefault:\n\t\t\tthrow EThread(\"Unknown thread join error\");\n\t\t}\n\t\tif(_State != ThreadStateFinished)\n\t\t\tthrow EThread(\"Thread did not finish, this should not happen\");\n\t}\n}\n\n/*\n * setCPUMask\n */\nbool CPThread::setCPUMask(uint64 cpuMask)\n{\n#ifdef __USE_GNU\n\n\tnlwarning(\"This code does not work. May cause a segmentation fault...\");\n\n\tsint res = pthread_setaffinity_np(_ThreadHandle, sizeof(uint64), (const cpu_set_t*)&cpuMask);\n\n\tif (res)\n\t{\n\t\tnlwarning(\"pthread_setaffinity_np() returned %d\", res);\n\t\treturn false;\n\t}\n\n\treturn true;\n\n#else // __USE_GNU\n\n\treturn false;\n\n#endif // __USE_GNU\n}\n\n/*\n * getCPUMask\n */\nuint64 CPThread::getCPUMask()\n{\n#ifdef __USE_GNU\n\n\tnlwarning(\"This code does not work. May cause a segmentation fault...\");\n\n\tuint64 cpuMask = 0;\n\n\tsint res = pthread_getaffinity_np(_ThreadHandle, sizeof(uint64), (cpu_set_t*)&cpuMask);\n\n\tif (res)\n\t{\n\t\tnlwarning(\"pthread_getaffinity_np() returned %d\", res);\n\t\treturn 0;\n\t}\n\n\treturn cpuMask;\n\n#else // __USE_GNU\n\n\treturn 0;\n\n#endif // __USE_GNU\n}\n\nvoid CPThread::setPriority(TThreadPriority priority)\n{\n\t// TODO: Test this\n\tsched_param sp;\n\tswitch (priority)\n\t{\n\tcase ThreadPriorityHigh:\n\t{\n\t\tint minPrio = sched_get_priority_min(SCHED_FIFO);\n\t\tint maxPrio = sched_get_priority_max(SCHED_FIFO);\n\t\tsp.sched_priority = ((maxPrio - minPrio) / 4) + minPrio;\n\t\tpthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);\n\t\tbreak;\n\t}\n\tcase ThreadPriorityHighest:\n\t{\n\t\tint minPrio = sched_get_priority_min(SCHED_FIFO);\n\t\tint maxPrio = sched_get_priority_max(SCHED_FIFO);\n\t\tsp.sched_priority = ((maxPrio - minPrio) / 2) + minPrio;\n\t\tpthread_setschedparam(_ThreadHandle, SCHED_FIFO, &sp);\n\t\tbreak;\n\t}\n\tdefault:\n\t\tsp.sched_priority = 0;\n\t\tpthread_setschedparam(_ThreadHandle, SCHED_OTHER, &sp);\n\t}\n}\n\n/*\n * getUserName\n */\nstd::string CPThread::getUserName()\n{\n\tstruct passwd *pw = getpwuid(getuid());\n\n\tif (!pw)\n\t\treturn \"\";\n\n\treturn pw->pw_name;\n}\n\n\n// **** Process\n\n// The current process\nCPProcess CurrentProcess;\n\n// Get the current process\nIProcess *IProcess::getCurrentProcess ()\n{\n\treturn &CurrentProcess;\n}\n\n/*\n * getCPUMask\n */\nuint64 CPProcess::getCPUMask()\n{\n#ifdef __USE_GNU\n\n\tuint64 cpuMask = 0;\n\tsint res = sched_getaffinity(getpid(), sizeof(uint64), (cpu_set_t*)&cpuMask);\n\n\tif (res)\n\t{\n\t\tnlwarning(\"sched_getaffinity() returned %d, errno = %d: %s\", res, errno, strerror(errno));\n\t\treturn 0;\n\t}\n\n\treturn cpuMask;\n\n#else // __USE_GNU\n\n\treturn 0;\n\n#endif // __USE_GNU\n}\n\n/// set the CPU mask\nbool CPProcess::setCPUMask(uint64 cpuMask)\n{\n#ifdef __USE_GNU\n\n\tsint res = sched_setaffinity(getpid(), sizeof(uint64), (const cpu_set_t*)&cpuMask);\n\n\tif (res)\n\t{\n\t\tnlwarning(\"sched_setaffinity() returned %d, errno = %d: %s\", res, errno, strerror(errno));\n\t\treturn false;\n\t}\n\n\treturn true;\n\n#else // __USE_GNU\n\n\treturn false;\n\n#endif // __USE_GNU\n}\n\n\n} // NLMISC\n\n#else // NL_OS_UNIX\n\n// remove stupid VC6 warnings\nvoid foo_p_thread_cpp() {}\n\n#endif // NL_OS_UNIX\n"
  },
  {
    "path": "code/nel/src/misc/path.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/path.h\"\n#include \"nel/misc/big_file.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/progress_callback.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/xml_pack.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <sys/types.h>\n#\tinclude <sys/stat.h>\n#\tinclude <direct.h>\n#\tinclude <io.h>\n#\tinclude <fcntl.h>\n#\tinclude <sys/types.h>\n#\tinclude <sys/stat.h>\n#\tinclude <shlobj.h>\n#else\n#   include <sys/types.h>\n#   include <sys/stat.h>\n#\tinclude <dirent.h>\n#   include <unistd.h>\n#\tinclude <cstdio>\n#   include <cerrno>\n#   include <sys/types.h>\n#   include <utime.h>\n#endif // NL_OS_WINDOWS\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n//\n// Macros\n//\n\n// Use this define if you want to display info about the CPath.\n//#define\tNL_DEBUG_PATH\n\n#ifdef\tNL_DEBUG_PATH\n#\tdefine\tNL_DISPLAY_PATH\tnlinfo\n#else\n#\tifdef __GNUC__\n#\t\tdefine\tNL_DISPLAY_PATH(format, args...)\n#\telse // __GNUC__\n#\t\tdefine\tNL_DISPLAY_PATH if(false)\n#\tendif // __GNUC__\n#endif\n\n\n//\n// Variables\n//\n\nNLMISC_SAFE_SINGLETON_IMPL(CPath);\n\n\n//\n// Functions\n//\n\nCFileContainer::~CFileContainer()\n{\n\tif( _AllFileNames )\n\t{\n\t\tdelete[] _AllFileNames;\n\t\t_AllFileNames = NULL;\n\t}\n}\n\nvoid CPath::releaseInstance()\n{\n\tif (_Instance)\n\t{\n\t\tNLMISC::INelContext::getInstance().releaseSingletonPointer(\"CPath\", _Instance);\n\t\tdelete _Instance;\n\t\t_Instance = NULL;\n\t}\n}\n\n\nvoid CPath::getFileList(const std::string &extension, std::vector<std::string> &filenames)\n{\n\tgetInstance()->_FileContainer.getFileList(extension, filenames);\n}\n\nvoid CFileContainer::getFileList(const std::string &extension, std::vector<std::string> &filenames)\n{\n\tif (!_MemoryCompressed)\n\t{\n\t\tTFiles::iterator first(_Files.begin()), last(_Files.end());\n\n\t\tif( !extension.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->second.idExt);\n\t\t\t\tif (ext == extension)\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->first);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tfilenames.push_back(first->first);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// compressed memory version\n\t\tstd::vector<CFileContainer::CMCFileEntry>::iterator first(_MCFiles.begin()), last(_MCFiles.end());\n\n\t\tif( !extension.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->idExt);\n\t\t\t\tif (ext == extension)\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CPath::getFileListByName(const std::string &extension, const std::string &name, std::vector<std::string> &filenames)\n{\n\tgetInstance()->_FileContainer.getFileListByName(extension, name, filenames);\n}\n\nvoid CFileContainer::getFileListByName(const std::string &extension, const std::string &name, std::vector<std::string> &filenames)\n{\n\tif (!_MemoryCompressed)\n\t{\n\t\tTFiles::iterator first(_Files.begin()), last(_Files.end());\n\n\t\tif( !name.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->second.idExt);\n\t\t\t\tif (first->first.find(name) != string::npos && (ext == extension || extension.empty()))\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->first);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tfilenames.push_back(first->first);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// compressed memory version\n\t\tstd::vector<CFileContainer::CMCFileEntry>::iterator first(_MCFiles.begin()), last(_MCFiles.end());\n\n\t\tif( !name.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->idExt);\n\t\t\t\tif (strstr(first->Name, name.c_str()) != NULL && (ext == extension || extension.empty()))\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t{\n\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CPath::getFileListByPath(const std::string &extension, const std::string &path, std::vector<std::string> &filenames)\n{\n\tgetInstance()->_FileContainer.getFileListByPath(extension, path, filenames);\n}\n\nvoid CFileContainer::getFileListByPath(const std::string &extension, const std::string &path, std::vector<std::string> &filenames)\n{\n\tif (!_MemoryCompressed)\n\t{\n\t\tTFiles::iterator first(_Files.begin()), last(_Files.end());\n\n\t\tif( !path.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->second.idExt);\n\t\t\t\tstring p = SSMpath.get(first->second.idPath);\n\t\t\t\tif (p.find(path) != string::npos && (ext == extension || extension.empty()))\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->first);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tfilenames.push_back(first->first);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\t// compressed memory version\n\t\tstd::vector<CFileContainer::CMCFileEntry>::iterator first(_MCFiles.begin()), last(_MCFiles.end());\n\n\t\tif( !path.empty() )\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t\t{\n\t\t\t\tstring ext = SSMext.get(first->idExt);\n\t\t\t\tstring p = SSMpath.get(first->idPath);\n\t\t\t\t\n\t\t\t\tif (strstr(p.c_str(), path.c_str()) != NULL && (ext == extension || extension.empty()))\n\t\t\t\t{\n\t\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// if extension is empty we keep all files\n\t\telse\n\t\t{\n\t\t\tfor (; first != last; ++ first)\n\t\t{\n\t\t\t\tfilenames.push_back(first->Name);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CPath::clearMap ()\n{\n\tgetInstance()->_FileContainer.clearMap();\n}\n\nvoid CFileContainer::clearMap ()\n{\n\tnlassert(!_MemoryCompressed);\n\t_Files.clear ();\n\tCBigFile::getInstance().removeAll ();\n\tNL_DISPLAY_PATH(\"PATH: CPath::clearMap(): map directory cleared\");\n}\n\nCFileContainer::CMCFileEntry *CFileContainer::MCfind (const std::string &filename)\n{\n\tnlassert(_MemoryCompressed);\n\tvector<CMCFileEntry>::iterator it;\n\tCMCFileEntry temp_cmc_file;\n\ttemp_cmc_file.Name = (char*)filename.c_str();\n\tit = lower_bound(_MCFiles.begin(), _MCFiles.end(), temp_cmc_file, CMCFileComp());\n\tif (it != _MCFiles.end())\n\t{\n\t\tCMCFileComp FileComp;\n\t\tif (FileComp.specialCompare(*it, filename.c_str()) == 0)\n\t\t\treturn &(*it);\n\t}\n\treturn NULL;\n}\n\nsint CFileContainer::findExtension (const string &ext1, const string &ext2)\n{\n\tfor (uint i = 0; i < _Extensions.size (); i++)\n\t{\n\t\tif (_Extensions[i].first == ext1 && _Extensions[i].second == ext2)\n\t\t{\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\nvoid CPath::remapExtension (const string &ext1, const string &ext2, bool substitute)\n{\n\tgetInstance()->_FileContainer.remapExtension(ext1, ext2, substitute);\n}\n\nvoid CFileContainer::remapExtension (const string &ext1, const string &ext2, bool substitute)\n{\n\tnlassert(!_MemoryCompressed);\n\n\tstring ext1lwr = toLower(ext1);\n\tstring ext2lwr = toLower(ext2);\n\n\tif (ext1lwr.empty() || ext2lwr.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::remapExtension(%s, %s, %d): can't remap empty extension\", ext1lwr.c_str(), ext2lwr.c_str(), substitute);\n\t}\n\n\tif (ext1lwr == \"bnp\" || ext2lwr == \"bnp\")\n\t{\n\t\tnlwarning (\"PATH: CPath::remapExtension(%s, %s, %d): you can't remap a big file\", ext1lwr.c_str(), ext2lwr.c_str(), substitute);\n\t}\n\n\tif (!substitute)\n\t{\n\t\t// remove the mapping from the mapping list\n\t\tsint n = findExtension (ext1lwr, ext2lwr);\n\t\tnlassert (n != -1);\n\t\t_Extensions.erase (_Extensions.begin() + n);\n\n\t\t// remove mapping in the map\n\t\tTFiles::iterator it = _Files.begin();\n\t\tTFiles::iterator nit = it;\n\t\twhile (it != _Files.end ())\n\t\t{\n\t\t\tnit++;\n\t\t\tstring ext = SSMext.get((*it).second.idExt);\n\t\t\tif ((*it).second.Remapped && ext == ext2lwr)\n\t\t\t{\n\t\t\t\t_Files.erase (it);\n\t\t\t}\n\t\t\tit = nit;\n\t\t}\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::remapExtension(%s, %s, %d): extension removed\", ext1lwr.c_str(), ext2lwr.c_str(), substitute);\n\t}\n\telse\n\t{\n\t\tsint n = findExtension (ext1lwr, ext2lwr);\n\t\tif (n != -1)\n\t\t{\n\t\t\tnlwarning (\"PATH: CPath::remapExtension(%s, %s, %d): remapping already set\", ext1lwr.c_str(), ext2lwr.c_str(), substitute);\n\t\t\treturn;\n\t\t}\n\n\t\t// adding mapping into the mapping list\n\t\t_Extensions.push_back (make_pair (ext1lwr, ext2lwr));\n\n\t\t// adding mapping into the map\n\t\tvector<string> newFiles;\n\t\tTFiles::iterator it = _Files.begin();\n\t\twhile (it != _Files.end ())\n\t\t{\n\t\t\tstring ext = SSMext.get((*it).second.idExt);\n\t\t\tif (!(*it).second.Remapped && ext == ext1lwr)\n\t\t\t{\n\t\t\t\t// find if already exist\n\t\t\t\tstring::size_type pos = (*it).first.find_last_of (\".\");\n\t\t\t\tif (pos != string::npos)\n\t\t\t\t{\n\t\t\t\t\tstring file = (*it).first.substr (0, pos + 1);\n\t\t\t\t\tfile += ext2lwr;\n\n// TODO perhaps a problem because I insert in the current map that I process\n\t\t\t\t\tstring path = SSMpath.get((*it).second.idPath);\n\t\t\t\t\tinsertFileInMap (file, path+file, true, ext1lwr);\n\t\t\t\t}\n\t\t\t}\n\t\t\tit++;\n\t\t}\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::remapExtension(%s, %s, %d): extension added\", ext1lwr.c_str(), ext2lwr.c_str(), substitute);\n\t}\n}\n\n// ***************************************************************************\nvoid CPath::remapFile (const std::string &file1, const std::string &file2)\n{\n\tgetInstance()->_FileContainer.remapFile(file1, file2);\n}\n\nvoid CFileContainer::remapFile (const std::string &file1, const std::string &file2)\n{\n\tif (file1.empty()) return;\n\tif (file2.empty()) return;\n\t_RemappedFiles[toLower(file1)] = toLower(file2);\n}\n\n// ***************************************************************************\nstatic void removeAllUnusedChar(string &str)\n{\n\tuint32 i = 0;\n\twhile (!str.empty() && (i != str.size()))\n\t{\n\t\tif ((str[i] == ' ' || str[i] == '\\t' || str[i] == '\\r' || str[i] == '\\n'))\n\t\t\tstr.erase(str.begin()+i);\n\t\telse\n\t\t\ti++;\n\t}\n}\n\n// ***************************************************************************\nvoid CPath::loadRemappedFiles (const std::string &file)\n{\n\tgetInstance()->_FileContainer.loadRemappedFiles(file);\n}\n\nvoid CFileContainer::loadRemappedFiles (const std::string &file)\n{\n\tstring fullName = lookup(file, false, true, true);\n\tCIFile f;\n\tf.setCacheFileOnOpen (true);\n\n\tif (!f.open (fullName))\n\t\treturn;\n\n\tchar sTmp[514];\n\tstring str;\n\n\twhile (!f.eof())\n\t{\n\t\tf.getline(sTmp, 512);\n\t\tstr = sTmp;\n\t\tstd::string::size_type pos = str.find(',');\n\t\tif (pos != string::npos)\n\t\t{\n\t\t\tremoveAllUnusedChar(str);\n\t\t\tif (!str.empty())\n\t\t\t{\n\t\t\t\tpos = str.find(',');\n\t\t\t\tremapFile( str.substr(0,pos), str.substr(pos+1, str.size()) );\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n// ***************************************************************************\nstring CPath::lookup (const string &filename, bool throwException, bool displayWarning, bool lookupInLocalDirectory)\n{\n\treturn getInstance()->_FileContainer.lookup(filename, throwException, displayWarning, lookupInLocalDirectory);\n}\n\nstring CFileContainer::lookup (const string &filename, bool throwException, bool displayWarning, bool lookupInLocalDirectory)\n{\n\t/* ***********************************************\n\t *\tWARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance\n\t *\tIt can be loaded/called through CAsyncFileManager for instance\n\t * ***********************************************/\n\t/*\n\t\tNB: CPath access static instance getInstance() of course, so user must ensure\n\t\tthat no mutator is called while async loading\n\t*/\n\n\n\t// If the file already contains a @, it means that a lookup already proceed and returning a big file, do nothing\n\tif (filename.find (\"@\") != string::npos)\n\t{\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s):\talready found\", filename.c_str());\n\t\treturn filename;\n\t}\n\n\t// Try to find in the map directories\n\n\t// If filename contains a path, we get only the filename to look inside paths\n\tstring str = CFile::getFilename(toLower(filename));\n\n\t// Remove end spaces\n\twhile ((!str.empty()) && (str[str.size()-1] == ' '))\n\t{\n\t\tstr.resize (str.size()-1);\n\t}\n\n\tmap<string, string>::iterator itss = _RemappedFiles.find(str);\n\tif (itss != _RemappedFiles.end())\n\t\tstr = itss->second;\n\n\tif (_MemoryCompressed)\n\t{\n\t\tCMCFileEntry *pMCFE = MCfind(str);\n\t\t// If found in the map, returns it\n\t\tif (pMCFE != NULL)\n\t\t{\n\t\t\tstring fname, path = SSMpath.get(pMCFE->idPath);\n\t\t\tif (pMCFE->Remapped)\n\t\t\t\tfname = CFile::getFilenameWithoutExtension(pMCFE->Name) + \".\" + SSMext.get(pMCFE->idExt);\n\t\t\telse\n\t\t\t\tfname = pMCFE->Name;\n\n\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s): found in the map directory: '%s'\", fname.c_str(), path.c_str());\n\t\t\treturn path + fname;\n\t\t}\n\t}\n\telse // NOT memory compressed\n\t{\n\n\t\tTFiles::iterator it = _Files.find (str);\n\t\t// If found in the map, returns it\n\t\tif (it != _Files.end())\n\t\t{\n\t\t\tstring fname, path = SSMpath.get((*it).second.idPath);\n\t\t\tif (it->second.Remapped)\n\t\t\t\tfname = CFile::getFilenameWithoutExtension((*it).second.Name) + \".\" + SSMext.get((*it).second.idExt);\n\t\t\telse\n\t\t\t\tfname = (*it).second.Name;\n\n\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s): found in the map directory: '%s'\", fname.c_str(), path.c_str());\n\t\t\treturn path + fname;\n\t\t}\n\t}\n\n\n\t// Try to find in the alternative directories\n\tfor (uint i = 0; i < _AlternativePaths.size(); i++)\n\t{\n\t\tstring s = _AlternativePaths[i] + str;\n\t\tif ( CFile::fileExists(s) )\n\t\t{\n\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s): found in the alternative directory: '%s'\", str.c_str(), s.c_str());\n\t\t\treturn s;\n\t\t}\n\n\t\t// try with the remapping\n\t\tfor (uint j = 0; j < _Extensions.size(); j++)\n\t\t{\n\t\t\tif (toLower(CFile::getExtension (str)) == _Extensions[j].second)\n\t\t\t{\n\t\t\t\tstring rs = _AlternativePaths[i] + CFile::getFilenameWithoutExtension (filename) + \".\" + _Extensions[j].first;\n\t\t\t\tif ( CFile::fileExists(rs) )\n\t\t\t\t{\n\t\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s): found in the alternative directory: '%s'\", str.c_str(), rs.c_str());\n\t\t\t\t\treturn rs;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Try to find in the current directory\n\tif ( lookupInLocalDirectory && CFile::fileExists(filename) )\n\t{\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::lookup(%s): found in the current directory: '%s'\", str.c_str(), filename.c_str());\n\t\treturn filename;\n\t}\n\n\t// Not found\n\tif (displayWarning)\n\t{\n\t\tif(filename.empty())\n\t\t\tnlwarning (\"PATH: Try to lookup for an empty filename. TODO: check why.\");\n\t\telse\n\t\t\tnlwarning (\"PATH: File (%s) not found (%s)\", str.c_str(), filename.c_str());\n\t}\n\n\tif (throwException)\n\t\tthrow EPathNotFound (filename);\n\n\treturn \"\";\n}\n\nbool CPath::exists (const std::string &filename)\n{\n\treturn getInstance()->_FileContainer.exists(filename);\n}\n\nbool CFileContainer::exists (const std::string &filename)\n{\n\t// Try to find in the map directories\n\tstring str = toLower(filename);\n\n\t// Remove end spaces\n\twhile ((!str.empty()) && (str[str.size()-1] == ' '))\n\t{\n\t\tstr.resize (str.size()-1);\n\t}\n\n\tif (_MemoryCompressed)\n\t{\n\t\tCMCFileEntry *pMCFE = MCfind(str);\n\t\t// If found in the vector, returns it\n\t\tif (pMCFE != NULL)\n\t\t\treturn true;\n\t}\n\telse\n\t{\n\t\tTFiles::iterator it = _Files.find (str);\n\t\t// If found in the map, returns it\n\t\tif (it != _Files.end())\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nstring CPath::standardizePath (const string &path, bool addFinalSlash)\n{\n\treturn getInstance()->_FileContainer.standardizePath(path, addFinalSlash);\n}\n\nstring CFileContainer::standardizePath (const string &path, bool addFinalSlash)\n{\n\t// check empty path\n\tif (path.empty())\n\t\treturn \"\";\n\n\tstring newPath(path);\n\n\tfor (uint i = 0; i < path.size(); i++)\n\t{\n\t\t// don't transform the first \\\\ for windows network path\n\t\tif (path[i] == '\\\\')\n\t\t\tnewPath[i] = '/';\n\t}\n\n\t// add terminal slash\n\tif (addFinalSlash && newPath[path.size()-1] != '/')\n\t\tnewPath += '/';\n\n\treturn newPath;\n}\n\n// replace / with backslash\nstd::string\tCPath::standardizeDosPath (const std::string &path)\n{\n\treturn getInstance()->_FileContainer.standardizeDosPath(path);\n}\n\nstd::string\tCFileContainer::standardizeDosPath (const std::string &path)\n{\n\tstring newPath;\n\n\tfor (uint i = 0; i < path.size(); i++)\n\t{\n\t\tif (path[i] == '/')\n\t\t\tnewPath += '\\\\';\n\t\t// Yoyo: supress toLower. Not useful!?!\n\t\t/*else if (isupper(path[i]))\n\t\t\tnewPath += tolower(path[i]);*/\n\t\telse\n\t\t\tnewPath += path[i];\n\t}\n\n\tif (CFile::isExists(path) && CFile::isDirectory(path) && newPath[newPath.size()-1] != '\\\\')\n\t\tnewPath += '\\\\';\n\n\treturn newPath;\n}\n\n\nstd::string CPath::getCurrentPath ()\n{\n\treturn getInstance()->_FileContainer.getCurrentPath();\n}\n\nstd::string CFileContainer::getCurrentPath ()\n{\n\tchar buffer [1024];\n\n#ifdef NL_OS_WINDOWS\n\treturn standardizePath(_getcwd(buffer, 1024), false);\n#else\n\treturn standardizePath(getcwd(buffer, 1024), false);\n#endif\n}\n\nbool CPath::setCurrentPath (const std::string &path)\n{\n\treturn getInstance()->_FileContainer.setCurrentPath(path);\n}\n\nbool CFileContainer::setCurrentPath (const std::string &path)\n{\n\tint res;\n\t//nldebug(\"Change current path to '%s' (current path is '%s')\", path.c_str(), getCurrentPath().c_str());\n#ifdef NL_OS_WINDOWS\n\tres = _chdir(path.c_str());\n#else\n\tres = chdir(path.c_str());\n#endif\n\tif(res != 0) nlwarning(\"Cannot change current path to '%s' (current path is '%s') res: %d errno: %d (%s)\", path.c_str(), getCurrentPath().c_str(), res, errno, strerror(errno));\n\treturn res == 0;\n}\n\nstd::string CPath::getFullPath (const std::string &path, bool addFinalSlash)\n{\n\treturn getInstance()->_FileContainer.getFullPath(path, addFinalSlash);\n}\n\nstd::string CFileContainer::getFullPath (const std::string &path, bool addFinalSlash)\n{\n\tstring currentPath = standardizePath (getCurrentPath ());\n\tstring sPath = standardizePath (path, addFinalSlash);\n\n\t// current path\n\tif (path.empty() || sPath == \".\" || sPath == \"./\")\n\t{\n\t\treturn currentPath;\n\t}\n\n\t// windows full path\n\tif (path.size() >= 2 && path[1] == ':')\n\t{\n\t\treturn sPath;\n\t}\n\n\tif (path.size() >= 2 && (path[0] == '/' || path[0] == '\\\\') && (path[1] == '/' || path[1] == '\\\\'))\n\t{\n\t\treturn sPath;\n\t}\n\n\n\t// from root\n\tif (path [0] == '/' || path[0] == '\\\\')\n\t{\n\t\tif (currentPath.size() > 2 && currentPath[1] == ':')\n\t\t{\n\t\t\treturn currentPath.substr(0,3) + sPath.substr(1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn sPath;\n\t\t}\n\t}\n\n\t// default case\n\treturn currentPath + sPath;\n}\n\n\n\n#ifdef NL_OS_WINDOWS\n#\tdefine dirent\tWIN32_FIND_DATA\n#\tdefine DIR\t\tvoid\n\nstatic string sDir;\nstatic WIN32_FIND_DATA findData;\nstatic HANDLE hFind;\n\nDIR *opendir (const char *path)\n{\n\tnlassert (path != NULL);\n\tnlassert (path[0] != '\\0');\n\n\tif (!CFile::isDirectory(path))\n\t\treturn NULL;\n\n\tsDir = path;\n\n\thFind = NULL;\n\n\treturn (void *)1;\n}\n\nint closedir (DIR *dir)\n{\n\tFindClose(hFind);\n\treturn 0;\n}\n\ndirent *readdir (DIR *dir)\n{\n\t// FIX : call to SetCurrentDirectory() and SetCurrentDirectory() removed to improve speed\n\tnlassert (!sDir.empty());\n\n\t// first visit in this directory : FindFirstFile()\n\tif (hFind == NULL)\n\t{\n\t\tstring fullPath = CPath::standardizePath(sDir) + \"*\";\n\t\thFind = FindFirstFileA (fullPath.c_str(), &findData);\n\t}\n\t// directory already visited : FindNextFile()\n\telse\n\t{\n\t\tif (!FindNextFileA (hFind, &findData))\n\t\t\treturn NULL;\n\t}\n\n\treturn &findData;\n}\n\n\n#endif // NL_OS_WINDOWS\n\n#ifndef NL_OS_WINDOWS\nstring BasePathgetPathContent;\n#endif\n\nbool isdirectory (dirent *de)\n{\n\tnlassert (de != NULL);\n#ifdef NL_OS_WINDOWS\n\treturn ((de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && ((de->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0);\n#else\n\t//nlinfo (\"isdirectory filename %s -> 0x%08x\", de->d_name, de->d_type);\n\t// we can't use \"de->d_type & DT_DIR\" because it s always NULL on libc2.1\n\t//return (de->d_type & DT_DIR) != 0;\n\n\treturn CFile::isDirectory (BasePathgetPathContent + de->d_name);\n\n#endif // NL_OS_WINDOWS\n}\n\nbool isfile (dirent *de)\n{\n\tnlassert (de != NULL);\n#ifdef NL_OS_WINDOWS\n\treturn ((de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) && ((de->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0);\n#else\n\t// we can't use \"de->d_type & DT_DIR\" because it s always NULL on libc2.1\n\t//return (de->d_type & DT_DIR) == 0;\n\n\treturn !CFile::isDirectory (BasePathgetPathContent + de->d_name);\n\n#endif // NL_OS_WINDOWS\n}\n\nstring getname (dirent *de)\n{\n\tnlassert (de != NULL);\n#ifdef NL_OS_WINDOWS\n\treturn de->cFileName;\n#else\n\treturn de->d_name;\n#endif // NL_OS_WINDOWS\n}\n\nvoid CPath::getPathContent (const string &path, bool recurse, bool wantDir, bool wantFile, vector<string> &result, class IProgressCallback *progressCallBack, bool showEverything)\n{\n\tgetInstance()->_FileContainer.getPathContent(path, recurse, wantDir, wantFile, result, progressCallBack, showEverything);\n\n\tsort(result.begin(), result.end());\n}\n\nvoid CFileContainer::getPathContent (const string &path, bool recurse, bool wantDir, bool wantFile, vector<string> &result, class IProgressCallback *progressCallBack, bool showEverything)\n{\n\tif(\tpath.empty() )\n\t{\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(): Empty input Path\");\n\t\treturn;\n\t}\n\n#ifndef NL_OS_WINDOWS\n\tBasePathgetPathContent = CPath::standardizePath (path);\n#endif\n\n\tDIR *dir = opendir (path.c_str());\n\n\tif (dir == NULL)\n\t{\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): could not open the directory\", path.c_str(), recurse, wantDir, wantFile);\n\t\treturn;\n\t}\n\n\t// contains path that we have to recurs into\n\tvector<string> recursPath;\n\n\tfor(;;)\n\t{\n\t\tdirent *de = readdir(dir);\n\t\tif (de == NULL)\n\t\t{\n\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): end of directory\", path.c_str(), recurse, wantDir, wantFile);\n\t\t\tbreak;\n\t\t}\n\n\t\tstring fn = getname (de);\n\n\t\t// skip . and ..\n\t\tif (fn == \".\" || fn == \"..\")\n\t\t\tcontinue;\n\n\t\tif (isdirectory(de))\n\t\t{\n\t\t\t// skip CVS, .svn and .hg directory\n\t\t\tif ((!showEverything) && (fn == \"CVS\" || fn == \".svn\" || fn == \".hg\"))\n\t\t\t{\n\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): skip CVS, .svn and .hg directory\", path.c_str(), recurse, wantDir, wantFile);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tstring stdName = standardizePath(standardizePath(path) + fn);\n\t\t\tif (recurse)\n\t\t\t{\n\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): need to recurse into '%s'\", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());\n\t\t\t\trecursPath.push_back (stdName);\n\t\t\t}\n\n\t\t\tif (wantDir)\n\t\t\t{\n\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): adding path '%s'\", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());\n\t\t\t\tresult.push_back (stdName);\n\t\t\t}\n\t\t}\n\n\t\tif (wantFile && isfile(de))\n\t\t{\n\t\t\tif ( (!showEverything) && (fn.size() >= 4 && fn.substr (fn.size()-4) == \".log\"))\n\t\t\t{\n\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): skip *.log files (%s)\", path.c_str(), recurse, wantDir, wantFile, fn.c_str());\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tstring stdName = standardizePath(path) + getname(de);\n\n\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::getPathContent(%s, %d, %d, %d): adding file '%s'\", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());\n\t\t\tresult.push_back (stdName);\n\t\t}\n\t}\n\n\tclosedir (dir);\n\n#ifndef NL_OS_WINDOWS\n\tBasePathgetPathContent.clear();\n#endif\n\n\t// let's recurse\n\tfor (uint i = 0; i < recursPath.size (); i++)\n\t{\n\t\t// Progress bar\n\t\tif (progressCallBack)\n\t\t{\n\t\t\tprogressCallBack->progress ((float)i/(float)recursPath.size ());\n\t\t\tprogressCallBack->pushCropedValues ((float)i/(float)recursPath.size (), (float)(i+1)/(float)recursPath.size ());\n\t\t}\n\n\t\tgetPathContent (recursPath[i], recurse, wantDir, wantFile, result, progressCallBack, showEverything);\n\n\t\t// Progress bar\n\t\tif (progressCallBack)\n\t\t{\n\t\t\tprogressCallBack->popCropedValues ();\n\t\t}\n\t}\n}\n\nvoid CPath::removeAllAlternativeSearchPath ()\n{\n\tgetInstance()->_FileContainer.removeAllAlternativeSearchPath();\n}\n\nvoid CFileContainer::removeAllAlternativeSearchPath ()\n{\n\t_AlternativePaths.clear ();\n\tNL_DISPLAY_PATH(\"PATH: CPath::RemoveAllAternativeSearchPath(): removed\");\n}\n\n\nvoid CPath::addSearchPath (const string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack)\n{\n\tgetInstance()->_FileContainer.addSearchPath(path, recurse, alternative, progressCallBack);\n}\n\nvoid CFileContainer::addSearchPath (const string &path, bool recurse, bool alternative, class IProgressCallback *progressCallBack)\n{\n\t//H_AUTO_INST(addSearchPath);\n\n\tnlassert(!_MemoryCompressed);\n\n\t// check empty directory\n\tif (path.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchPath(%s, %s, %s): can't add empty directory, skip it\",\n\t\t\tpath.c_str(),\n\t\t\trecurse ? \"recursive\" : \"not recursive\",\n\t\t\talternative ? \"alternative\" : \"not alternative\");\n\t\treturn;\n\t}\n\n\t// check if it s a directory\n\tif (!CFile::isDirectory (path))\n\t{\n\t\tnlinfo (\"PATH: CPath::addSearchPath(%s, %s, %s): '%s' is not a directory, I'll call addSearchFile()\",\n\t\t\tpath.c_str(),\n\t\t\trecurse ? \"recursive\" : \"not recursive\",\n\t\t\talternative ? \"alternative\" : \"not alternative\",\n\t\t\tpath.c_str());\n\t\taddSearchFile (path, false, \"\", progressCallBack);\n\t\treturn;\n\t}\n\n\tstring newPath = standardizePath(path);\n\n\t// check if it s a directory\n\tif (!CFile::isExists (newPath))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchPath(%s, %s, %s): '%s' is not found, skip it\",\n\t\t\tpath.c_str(),\n\t\t\trecurse ? \"recursive\" : \"not recursive\",\n\t\t\talternative ? \"alternative\" : \"not alternative\",\n\t\t\tnewPath.c_str());\n\t\treturn;\n\t}\n\n\tnlinfo (\"PATH: CPath::addSearchPath(%s, %d, %d): adding the path '%s'\", path.c_str(), recurse, alternative, newPath.c_str());\n\n\tNL_DISPLAY_PATH(\"PATH: CPath::addSearchPath(%s, %d, %d): try to add '%s'\", path.c_str(), recurse, alternative, newPath.c_str());\n\n\tif (alternative)\n\t{\n\t\tvector<string> pathsToProcess;\n\n\t\t// add the current path\n\t\tpathsToProcess.push_back (newPath);\n\n\t\tif (recurse)\n\t\t{\n\t\t\t// find all path and subpath\n\t\t\tgetPathContent (newPath, recurse, true, false, pathsToProcess, progressCallBack);\n\n\t\t\t// sort files\n\t\t\tsort(pathsToProcess.begin(), pathsToProcess.end());\n\t\t}\n\n\t\tfor (uint p = 0; p < pathsToProcess.size(); p++)\n\t\t{\n\t\t\t// check if the path not already in the vector\n\t\t\tuint i;\n\t\t\tfor (i = 0; i < _AlternativePaths.size(); i++)\n\t\t\t{\n\t\t\t\tif (_AlternativePaths[i] == pathsToProcess[p])\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (i == _AlternativePaths.size())\n\t\t\t{\n\t\t\t\t// add them in the alternative directory\n\t\t\t\t_AlternativePaths.push_back (pathsToProcess[p]);\n\t\t\t\tNL_DISPLAY_PATH(\"PATH: CPath::addSearchPath(%s, %s, %s): path '%s' added\",\n\t\t\t\t\tnewPath.c_str(),\n\t\t\t\t\trecurse ? \"recursive\" : \"not recursive\",\n\t\t\t\t\talternative ? \"alternative\" : \"not alternative\",\n\t\t\t\t\tpathsToProcess[p].c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning (\"PATH: CPath::addSearchPath(%s, %s, %s): path '%s' already added\",\n\t\t\t\t\tnewPath.c_str(),\n\t\t\t\t\trecurse ? \"recursive\" : \"not recursive\",\n\t\t\t\t\talternative ? \"alternative\" : \"not alternative\",\n\t\t\t\t\tpathsToProcess[p].c_str());\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tvector<string> filesToProcess;\n\n\t\t// Progress bar\n\t\tif (progressCallBack)\n\t\t{\n\t\t\tprogressCallBack->progress (0);\n\t\t\tprogressCallBack->pushCropedValues (0, 0.5f);\n\t\t}\n\n\t\t// find all files in the path and subpaths\n\t\tgetPathContent (newPath, recurse, false, true, filesToProcess, progressCallBack);\n\n\t\t// sort files\n\t\tsort(filesToProcess.begin(), filesToProcess.end());\n\n\t\t// Progress bar\n\t\tif (progressCallBack)\n\t\t{\n\t\t\tprogressCallBack->popCropedValues ();\n\t\t\tprogressCallBack->progress (0.5);\n\t\t\tprogressCallBack->pushCropedValues (0.5f, 1);\n\t\t}\n\n\t\t// add them in the map\n\t\tfor (uint f = 0; f < filesToProcess.size(); f++)\n\t\t{\n\t\t\t// Progree bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->progress ((float)f/(float)filesToProcess.size());\n\t\t\t\tprogressCallBack->pushCropedValues ((float)f/(float)filesToProcess.size(), (float)(f+1)/(float)filesToProcess.size());\n\t\t\t}\n\n\t\t\tstring filename = CFile::getFilename (filesToProcess[f]);\n\t\t\tstring filepath = CFile::getPath (filesToProcess[f]);\n//\t\t\tinsertFileInMap (filename, filepath, false, CFile::getExtension(filename));\n\t\t\taddSearchFile (filesToProcess[f], false, \"\", progressCallBack);\n\n\t\t\t// Progress bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->popCropedValues ();\n\t\t\t}\n\t\t}\n\n\t\t// Progress bar\n\t\tif (progressCallBack)\n\t\t{\n\t\t\tprogressCallBack->popCropedValues ();\n\t\t}\n\t}\n}\n\nvoid CPath::addSearchFile (const string &file, bool remap, const string &virtual_ext, NLMISC::IProgressCallback *progressCallBack)\n{\n\tgetInstance()->_FileContainer.addSearchFile(file, remap, virtual_ext, progressCallBack);\n}\n\nvoid CFileContainer::addSearchFile (const string &file, bool remap, const string &virtual_ext, NLMISC::IProgressCallback *progressCallBack)\n{\n\tnlassert(!_MemoryCompressed);\n\n\tstring newFile = standardizePath(file, false);\n\n\t// check empty file\n\tif (newFile.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchFile(%s, %d, '%s'): can't add empty file, skip it\", file.c_str(), remap, virtual_ext.c_str());\n\t\treturn;\n\t}\n\n\t// check if the file exists\n\tif (!CFile::isExists (newFile))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchFile(%s, %d, '%s'): '%s' is not found, skip it (current dir is '%s'\",\n\t\t\tfile.c_str(),\n\t\t\tremap,\n\t\t\tvirtual_ext.c_str(),\n\t\t\tnewFile.c_str(),\n\t\t\tCPath::getCurrentPath().c_str());\n\t\treturn;\n\t}\n\n\t// check if it s a file\n\tif (CFile::isDirectory (newFile))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchFile(%s, %d, '%s'): '%s' is not a file, skip it\",\n\t\t\tfile.c_str(),\n\t\t\tremap,\n\t\t\tvirtual_ext.c_str(),\n\t\t\tnewFile.c_str());\n\t\treturn;\n\t}\n\n\t// check if it s a big file\n\tif (CFile::getExtension(newFile) == \"bnp\")\n\t{\n\t\tNL_DISPLAY_PATH (\"PATH: CPath::addSearchFile(%s, %d, '%s'): '%s' is a big file, add it\", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());\n\t\taddSearchBigFile(file, false, false, progressCallBack);\n\t\treturn;\n\t}\n\n\t// check if it s an xml pack file\n\tif (CFile::getExtension(newFile) == \"xml_pack\")\n\t{\n\t\tNL_DISPLAY_PATH (\"PATH: CPath::addSearchFile(%s, %d, '%s'): '%s' is an xml pack file, add it\", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());\n\t\taddSearchXmlpackFile(file, false, false, progressCallBack);\n\t\treturn;\n\t}\n\n\tstring filenamewoext = CFile::getFilenameWithoutExtension (newFile);\n\tstring filename, ext;\n\n\tif (virtual_ext.empty())\n\t{\n\t\tfilename = CFile::getFilename (newFile);\n\t\text = CFile::getExtension (filename);\n\t}\n\telse\n\t{\n\t\tfilename = filenamewoext + \".\" + virtual_ext;\n\t\text = CFile::getExtension (newFile);\n\t}\n\n\tinsertFileInMap (filename, newFile, remap, ext);\n\n\tif (!remap && !ext.empty())\n\t{\n\t\t// now, we have to see extension and insert in the map the remapped files\n\t\tfor (uint i = 0; i < _Extensions.size (); i++)\n\t\t{\n\t\t\tif (_Extensions[i].first == toLower(ext))\n\t\t\t{\n\t\t\t\t// need to remap\n\t\t\t\taddSearchFile (newFile, true, _Extensions[i].second, progressCallBack);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CPath::addSearchListFile (const string &filename, bool recurse, bool alternative)\n{\n\tgetInstance()->_FileContainer.addSearchListFile(filename, recurse, alternative);\n}\n\nvoid CFileContainer::addSearchListFile (const string &filename, bool recurse, bool alternative)\n{\n\t// check empty file\n\tif (filename.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchListFile(%s, %d, %d): can't add empty file, skip it\", filename.c_str(), recurse, alternative);\n\t\treturn;\n\t}\n\n\t// check if the file exists\n\tif (!CFile::isExists (filename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchListFile(%s, %d, %d): '%s' is not found, skip it\", filename.c_str(), recurse, alternative, filename.c_str());\n\t\treturn;\n\t}\n\n\t// check if it s a file\n\tif (CFile::isDirectory (filename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchListFile(%s, %d, %d): '%s' is not a file, skip it\", filename.c_str(), recurse, alternative, filename.c_str());\n\t\treturn;\n\t}\n\n\t// TODO read the file and add files that are inside\n}\n\n// WARNING : recurse is not used\nvoid CPath::addSearchBigFile (const string &sBigFilename, bool recurse, bool alternative, NLMISC::IProgressCallback *progressCallBack)\n{\n\tgetInstance()->_FileContainer.addSearchBigFile(sBigFilename, recurse, alternative, progressCallBack);\n}\n\nvoid CFileContainer::addSearchBigFile (const string &sBigFilename, bool recurse, bool alternative, NLMISC::IProgressCallback *progressCallBack)\n{\n\t// Check if filename is not empty\n\tif (sBigFilename.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): can't add empty file, skip it\", sBigFilename.c_str(), recurse, alternative);\n\t\treturn;\n\t}\n\t// Check if the file exists\n\tif (!CFile::isExists (sBigFilename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): '%s' is not found, skip it\", sBigFilename.c_str(), recurse, alternative, sBigFilename.c_str());\n\t\treturn;\n\t}\n\t// Check if it s a file\n\tif (CFile::isDirectory (sBigFilename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): '%s' is not a file, skip it\", sBigFilename.c_str(), recurse, alternative, sBigFilename.c_str());\n\t\treturn;\n\t}\n\t// Open and read the big file header\n\tnlassert(!_MemoryCompressed);\n\n\tFILE *Handle = fopen (sBigFilename.c_str(), \"rb\");\n\tif (Handle == NULL)\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): can't open file, skip it\", sBigFilename.c_str(), recurse, alternative);\n\t\treturn;\n\t}\n\n\t// add the link with the CBigFile singleton\n\tif (CBigFile::getInstance().add (sBigFilename, BF_ALWAYS_OPENED | BF_CACHE_FILE_ON_OPEN))\n\t{\n\t\t// also add the bigfile name in the map to retrieve the full path of a .bnp when we want modification date of the bnp for example\n\t\tinsertFileInMap (CFile::getFilename (sBigFilename), sBigFilename, false, CFile::getExtension(sBigFilename));\n\n\t\t// parse the big file to add file in the map\n\t\tuint32 nFileSize=CFile::getFileSize (Handle);\n\t\t//nlfseek64 (Handle, 0, SEEK_END);\n\t\t//uint32 nFileSize = ftell (Handle);\n\t\tnlfseek64 (Handle, nFileSize-4, SEEK_SET);\n\t\tuint32 nOffsetFromBeginning;\n\t\tif (fread (&nOffsetFromBeginning, sizeof(uint32), 1, Handle) != 1)\n\t\t{\n\t\t\tfclose(Handle);\n\t\t\treturn;\n\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\tNLMISC_BSWAP32(nOffsetFromBeginning);\n#endif\n\n\t\tnlfseek64 (Handle, nOffsetFromBeginning, SEEK_SET);\n\t\tuint32 nNbFile;\n\t\tif (fread (&nNbFile, sizeof(uint32), 1, Handle) != 1)\n\t\t{\n\t\t\tfclose(Handle);\n\t\t\treturn;\n\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\tNLMISC_BSWAP32(nNbFile);\n#endif\n\n\t\tfor (uint32 i = 0; i < nNbFile; ++i)\n\t\t{\n\t\t\t// Progress bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->progress ((float)i/(float)nNbFile);\n\t\t\t\tprogressCallBack->pushCropedValues ((float)i/(float)nNbFile, (float)(i+1)/(float)nNbFile);\n\t\t\t}\n\n\t\t\tchar FileName[256];\n\t\t\tuint8 nStringSize;\n\t\t\tif (fread (&nStringSize, 1, 1, Handle) != 1)\n\t\t\t{\n\t\t\t\tfclose(Handle);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (fread (FileName, 1, nStringSize, Handle) != nStringSize)\n\t\t\t{\n\t\t\t\tfclose(Handle);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tFileName[nStringSize] = 0;\n\t\t\tuint32 nFileSize2;\n\t\t\tif (fread (&nFileSize2, sizeof(uint32), 1, Handle) != 1)\n\t\t\t{\n\t\t\t\tfclose(Handle);\n\t\t\t\treturn;\n\t\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\t\tNLMISC_BSWAP32(nFileSize2);\n#endif\n\n\t\t\tuint32 nFilePos;\n\t\t\tif (fread (&nFilePos, sizeof(uint32), 1, Handle) != 1)\n\t\t\t{\n\t\t\t\tfclose(Handle);\n\t\t\t\treturn;\n\t\t\t}\n\n#ifdef NL_BIG_ENDIAN\n\t\t\tNLMISC_BSWAP32(nFilePos);\n#endif\n\n\t\t\tstring sTmp = toLower(string(FileName));\n\t\t\tif (sTmp.empty())\n\t\t\t{\n\t\t\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): can't add empty file, skip it\", sBigFilename.c_str(), recurse, alternative);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tstring bigfilenamealone = CFile::getFilename (sBigFilename);\n\t\t\tstring filenamewoext = CFile::getFilenameWithoutExtension (sTmp);\n\t\t\tstring ext = toLower(CFile::getExtension(sTmp));\n\n\t\t\tinsertFileInMap (sTmp, bigfilenamealone + \"@\" + sTmp, false, ext);\n\n\t\t\tfor (uint j = 0; j < _Extensions.size (); j++)\n\t\t\t{\n\t\t\t\tif (_Extensions[j].first == ext)\n\t\t\t\t{\n\t\t\t\t\t// need to remap\n\t\t\t\t\tinsertFileInMap (filenamewoext+\".\"+_Extensions[j].second,\n\t\t\t\t\t\t\t\t\tbigfilenamealone + \"@\" + sTmp,\n\t\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\t_Extensions[j].first);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Progress bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->popCropedValues ();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchBigFile(%s, %d, %d): can't add the big file\", sBigFilename.c_str(), recurse, alternative);\n\t}\n\n\tfclose (Handle);\n}\n\n// WARNING : recurse is not used\nvoid CPath::addSearchXmlpackFile (const string &sXmlpackFilename, bool recurse, bool alternative, NLMISC::IProgressCallback *progressCallBack)\n{\n\tgetInstance()->_FileContainer.addSearchXmlpackFile(sXmlpackFilename, recurse, alternative, progressCallBack);\n}\n\nvoid CFileContainer::addSearchXmlpackFile (const string &sXmlpackFilename, bool recurse, bool alternative, NLMISC::IProgressCallback *progressCallBack)\n{\n\t// Check if filename is not empty\n\tif (sXmlpackFilename.empty())\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchXmlpackFile(%s, %d, %d): can't add empty file, skip it\", sXmlpackFilename.c_str(), recurse, alternative);\n\t\treturn;\n\t}\n\t// Check if the file exists\n\tif (!CFile::isExists (sXmlpackFilename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchXmlpackFile(%s, %d, %d): '%s' is not found, skip it\", sXmlpackFilename.c_str(), recurse, alternative, sXmlpackFilename.c_str());\n\t\treturn;\n\t}\n\t// Check if it s a file\n\tif (CFile::isDirectory (sXmlpackFilename))\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchXmlpackFile(%s, %d, %d): '%s' is not a file, skip it\", sXmlpackFilename.c_str(), recurse, alternative, sXmlpackFilename.c_str());\n\t\treturn;\n\t}\n\t// Open and read the xmlpack file header\n\n\tFILE *Handle = fopen (sXmlpackFilename.c_str(), \"rb\");\n\tif (Handle == NULL)\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchXmlpackFile(%s, %d, %d): can't open file, skip it\", sXmlpackFilename.c_str(), recurse, alternative);\n\t\treturn;\n\t}\n\n\t// add the link with the CXMLPack singleton\n\tif (CXMLPack::getInstance().add (sXmlpackFilename))\n\t{\n\t\t// also add the xmlpack file name in the map to retrieve the full path of a .xml_pack when we want modification date of the xml_pack for example\n\t\tinsertFileInMap (sXmlpackFilename, sXmlpackFilename, false, CFile::getExtension(sXmlpackFilename));\n\n\n\t\tvector<string>\tfilenames;\n\t\tCXMLPack::getInstance().list(sXmlpackFilename, filenames);\n\n\t\tfor (uint i=0; i<filenames.size(); ++i)\n\t\t{\n\t\t\t// Progress bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->progress ((float)i/(float)filenames.size());\n\t\t\t\tprogressCallBack->pushCropedValues ((float)i/(float)filenames.size(), (float)(i+1)/(float)filenames.size());\n\t\t\t}\n\n\t\t\tstring packfilenamealone = sXmlpackFilename;\n\t\t\tstring filenamewoext = CFile::getFilenameWithoutExtension (filenames[i]);\n\t\t\tstring ext = toLower(CFile::getExtension(filenames[i]));\n\n\t\t\tinsertFileInMap (filenames[i], packfilenamealone + \"@@\" + filenames[i], false, ext);\n\n\t\t\tfor (uint j = 0; j < _Extensions.size (); j++)\n\t\t\t{\n\t\t\t\tif (_Extensions[j].first == ext)\n\t\t\t\t{\n\t\t\t\t\t// need to remap\n\t\t\t\t\tinsertFileInMap (filenamewoext+\".\"+_Extensions[j].second,\n\t\t\t\t\t\t\t\t\tpackfilenamealone + \"@@\" + filenames[i],\n\t\t\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\t\t\t_Extensions[j].first);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Progress bar\n\t\t\tif (progressCallBack)\n\t\t\t{\n\t\t\t\tprogressCallBack->popCropedValues ();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlwarning (\"PATH: CPath::addSearchXmlpackFile(%s, %d, %d): can't add the xml pack file\", sXmlpackFilename.c_str(), recurse, alternative);\n\t}\n\n\tfclose (Handle);\n}\n\nvoid CPath::addIgnoredDoubleFile(const std::string &ignoredFile)\n{\n\tgetInstance()->_FileContainer.addIgnoredDoubleFile(ignoredFile);\n}\n\nvoid CFileContainer::addIgnoredDoubleFile(const std::string &ignoredFile)\n{\n\tIgnoredFiles.push_back(ignoredFile);\n}\n\nvoid CFileContainer::insertFileInMap (const string &filename, const string &filepath, bool remap, const string &extension)\n{\n\tnlassert(!_MemoryCompressed);\n\t// find if the file already exist\n\tTFiles::iterator it = _Files.find (toLower(filename));\n\tif (it != _Files.end ())\n\t{\n\t\tstring path = SSMpath.get((*it).second.idPath);\n\t\tif (path.find(\"@\") != string::npos && filepath.find(\"@\") == string::npos)\n\t\t{\n\t\t\t// if there's a file in a big file and a file in a path, the file in path wins\n\t\t\t// replace with the new one\n\t\t\tnlinfo (\"PATH: CPath::insertFileInMap(%s, %s, %d, %s): already inserted from '%s' but special case so override it\", filename.c_str(), filepath.c_str(), remap, extension.c_str(), path.c_str());\n\t\t\tstring sTmp = filepath.substr(0,filepath.rfind('/')+1);\n\t\t\t(*it).second.idPath = SSMpath.add(sTmp);\n\t\t\t(*it).second.Remapped = remap;\n\t\t\t(*it).second.idExt = SSMext.add(extension);\n\t\t\t(*it).second.Name = filename;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfor(uint i = 0; i < IgnoredFiles.size(); i++)\n\t\t\t{\n\t\t\t\t// if we don't want to display a warning, skip it\n\t\t\t\tif(filename == IgnoredFiles[i])\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t\t// if the path is the same, don't warn\n\t\t\tstring path2 = SSMpath.get((*it).second.idPath);\n\t\t\tstring sPathOnly;\n\t\t\tif(filepath.rfind(\"@@\") != string::npos)\n\t\t\t\tsPathOnly = filepath.substr(0,filepath.rfind(\"@@\")+2);\n\t\t\telse if(filepath.rfind('@') != string::npos)\n\t\t\t\tsPathOnly = filepath.substr(0,filepath.rfind('@')+1);\n\t\t\telse\n\t\t\t\tsPathOnly = CFile::getPath(filepath);\n\n\t\t\tif (path2 == sPathOnly)\n\t\t\t\treturn;\n\t\t\tnlwarning (\"PATH: CPath::insertFileInMap(%s, %s, %d, %s): already inserted from '%s', skip it\",\n\t\t\t\tfilename.c_str(),\n\t\t\t\tfilepath.c_str(),\n\t\t\t\tremap,\n\t\t\t\textension.c_str(),\n\t\t\t\tpath2.c_str());\n\t\t}\n\t}\n\telse\n\t{\n\t\tCFileEntry fe;\n\t\tfe.idExt = SSMext.add(extension);\n\t\tfe.Remapped = remap;\n\t\tstring sTmp;\n\t\tif (filepath.find(\"@\") == string::npos)\n\t\t\tsTmp = filepath.substr(0,filepath.rfind('/')+1);\n\t\telse if (filepath.find(\"@@\") != string::npos)\n\t\t\tsTmp = filepath.substr(0,filepath.rfind(\"@@\")+2);\n\t\telse\n\t\t\tsTmp = filepath.substr(0,filepath.rfind('@')+1);\n\n\t\tfe.idPath = SSMpath.add(sTmp);\n\t\tfe.Name = filename;\n\n\t\t_Files.insert (make_pair(toLower(filename), fe));\n\t\tNL_DISPLAY_PATH(\"PATH: CPath::insertFileInMap(%s, %s, %d, %s): added\", toLower(filename).c_str(), filepath.c_str(), remap, toLower(extension).c_str());\n\t}\n}\n\nvoid CPath::display ()\n{\n\tgetInstance()->_FileContainer.display();\n}\n\nvoid CFileContainer::display ()\n{\n\tnlinfo (\"PATH: Contents of the map:\");\n\tnlinfo (\"PATH: %-25s %-5s %-5s %s\", \"filename\", \"ext\", \"remap\", \"full path\");\n\tnlinfo (\"PATH: ----------------------------------------------------\");\n\tif (_MemoryCompressed)\n\t{\n\t\tfor (uint i = 0; i < _MCFiles.size(); ++i)\n\t\t{\n\t\t\tconst CMCFileEntry &fe = _MCFiles[i];\n\t\t\tstring ext = SSMext.get(fe.idExt);\n\t\t\tstring path = SSMpath.get(fe.idPath);\n\t\t\tnlinfo (\"PATH: %-25s %-5s %-5d %s\", fe.Name, ext.c_str(), fe.Remapped, path.c_str());\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (TFiles::iterator it = _Files.begin(); it != _Files.end (); it++)\n\t\t{\n\t\t\tstring ext = SSMext.get((*it).second.idExt);\n\t\t\tstring path = SSMpath.get((*it).second.idPath);\n\t\t\tnlinfo (\"PATH: %-25s %-5s %-5d %s\", (*it).first.c_str(), ext.c_str(), (*it).second.Remapped, path.c_str());\n\t\t}\n\t}\n\tnlinfo (\"PATH: \");\n\tnlinfo (\"PATH: Contents of the alternative directory:\");\n\tfor (uint i = 0; i < _AlternativePaths.size(); i++)\n\t{\n\t\tnlinfo (\"PATH: '%s'\", _AlternativePaths[i].c_str ());\n\t}\n\tnlinfo (\"PATH: \");\n\tnlinfo (\"PATH: Contents of the remapped entension table:\");\n\tfor (uint j = 0; j < _Extensions.size(); j++)\n\t{\n\t\tnlinfo (\"PATH: '%s' -> '%s'\", _Extensions[j].first.c_str (), _Extensions[j].second.c_str ());\n\t}\n\tnlinfo (\"PATH: End of display\");\n}\n\nvoid CPath::removeBigFiles(const std::vector<std::string> &bnpFilenames)\n{\n\tgetInstance()->_FileContainer.removeBigFiles(bnpFilenames);\n}\n\nvoid CFileContainer::removeBigFiles(const std::vector<std::string> &bnpFilenames)\n{\n\tnlassert(!isMemoryCompressed());\n\tCHashSet<TSStringId> bnpStrIds;\n\tTFiles::iterator fileIt, fileCurrIt;\n\tfor (uint k = 0; k < bnpFilenames.size(); ++k)\n\t{\n\t\tstd::string completeBNPName = toLower(bnpFilenames[k]) + \"@\";\n\t\tif (SSMpath.isAdded(completeBNPName))\n\t\t{\n\t\t\tbnpStrIds.insert(SSMpath.add(completeBNPName));\n\t\t}\n\t\tCBigFile::getInstance().remove(bnpFilenames[k]);\n\t\tfileIt = _Files.find(toLower(bnpFilenames[k]));\n\t\tif (fileIt != _Files.end())\n\t\t{\n\t\t\t_Files.erase(fileIt);\n\t\t}\n\t}\n\tif (bnpStrIds.empty()) return;\n\t//\tremove remapped files\n\tstd::map<std::string, std::string>::iterator remapIt, remapCurrIt;\n\tfor(remapIt = _RemappedFiles.begin(); remapIt != _RemappedFiles.end();)\n\t{\n\t\tremapCurrIt = remapIt;\n\t\t++ remapIt;\n\t\tconst std::string &filename = remapCurrIt->second;\n\t\tfileIt = _Files.find(filename);\n\t\tif (fileIt != _Files.end())\n\t\t{\n\t\t\tif (bnpStrIds.count(fileIt->second.idPath))\n\t\t\t{\n\t\t\t\t_Files.erase(fileIt);\n\t\t\t\t_RemappedFiles.erase(remapCurrIt);\n\t\t\t}\n\t\t}\n\t}\n\t//\tremove file entries\n\tfor(fileIt = _Files.begin(); fileIt != _Files.end();)\n\t{\n\t\tfileCurrIt = fileIt;\n\t\t++ fileIt;\n\t\tif (bnpStrIds.count(fileCurrIt->second.idPath))\n\t\t{\n\t\t\t_Files.erase(fileCurrIt);\n\t\t}\n\t}\n\n\n}\n\n\nvoid CPath::memoryCompress()\n{\n\tgetInstance()->_FileContainer.memoryCompress();\n}\n\nvoid CFileContainer::memoryCompress()\n{\n\n\tSSMext.memoryCompress();\n\tSSMpath.memoryCompress();\n\tuint nDbg = (uint)_Files.size();\n\tuint nDbg2 = SSMext.getCount();\n\tuint nDbg3 = SSMpath.getCount();\n\tnlinfo (\"PATH: Number of file: %d, extension: %d, path: %d\", nDbg, nDbg2, nDbg3);\n\n\t// Convert from _Files to _MCFiles\n\tuint nSize = 0, nNb = 0;\n\tTFiles::iterator it = _Files.begin();\n\twhile (it != _Files.end())\n\t{\n\t\tstring sTmp = SSMpath.get(it->second.idPath);\n\t\tif ((sTmp.find(\"@@\") == string::npos) && (sTmp.find('@') != string::npos) && !it->second.Remapped)\n\t\t{\n\t\t\t// This is a file included in a bigfile (so the name is in the bigfile manager)\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnSize += (uint)it->second.Name.size() + 1;\n\t\t}\n\t\tnNb++;\n\t\tit++;\n\t}\n\n\t_AllFileNames = new char[nSize];\n\tmemset(_AllFileNames, 0, nSize);\n\t_MCFiles.resize(nNb);\n\n\tit = _Files.begin();\n\tnSize = 0;\n\tnNb = 0;\n\twhile (it != _Files.end())\n\t{\n\t\tCFileEntry &rFE = it->second;\n\t\tstring sTmp = SSMpath.get(rFE.idPath);\n\t\tif (sTmp.find(\"@\") == string::npos || sTmp.find(\"@@\") != string::npos || rFE.Remapped)\n\t\t{\n\t\t\tstrcpy(_AllFileNames+nSize, rFE.Name.c_str());\n\t\t\t_MCFiles[nNb].Name = _AllFileNames+nSize;\n\t\t\tnSize += (uint)rFE.Name.size() + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// This is a file included in a bigfile (so the name is in the bigfile manager)\n\t\t\tsTmp = sTmp.substr(0, sTmp.size()-1);\n\t\t\t_MCFiles[nNb].Name = CBigFile::getInstance().getFileNamePtr(rFE.Name, sTmp);\n\t\t\tif (_MCFiles[nNb].Name == NULL)\n\t\t\t{\n\t\t\t\tnlerror(\"memoryCompress: failed to find named file in big file: %s\",SSMpath.get(rFE.idPath));\n\t\t\t}\n\t\t}\n\n\t\t_MCFiles[nNb].idExt = rFE.idExt;\n\t\t_MCFiles[nNb].idPath = rFE.idPath;\n\t\t_MCFiles[nNb].Remapped = rFE.Remapped;\n\n\t\tnNb++;\n\t\tit++;\n\t}\n\n\tcontReset(_Files);\n\t_MemoryCompressed = true;\n}\n\nvoid CPath::memoryUncompress()\n{\n\tgetInstance()->_FileContainer.memoryUncompress();\n}\n\nvoid CFileContainer::memoryUncompress()\n{\n\tSSMext.memoryUncompress();\n\tSSMpath.memoryUncompress();\n\tfor(std::vector<CMCFileEntry>::iterator it = _MCFiles.begin(); it != _MCFiles.end(); ++it)\n\t{\n\t\tCFileEntry fe;\n\t\tfe.Name = it->Name;\n\t\tfe.idExt = it->idExt;\n\t\tfe.idPath = it->idPath;\n\t\tfe.Remapped = it->Remapped;\n\n\t\t_Files[toLower(CFile::getFilename(fe.Name))] = fe;\n\t}\n\tcontReset(_MCFiles);\n\t_MemoryCompressed = false;\n}\n\nstd::string CPath::getWindowsDirectory()\n{\n\treturn getInstance()->_FileContainer.getWindowsDirectory();\n}\n\nstd::string CFileContainer::getWindowsDirectory()\n{\n#ifndef NL_OS_WINDOWS\n\tnlwarning(\"not a ms windows platform\");\n\treturn \"\";\n#else\n\tchar winDir[MAX_PATH];\n\tUINT numChar = ::GetWindowsDirectory(winDir, MAX_PATH);\n\tif (numChar > MAX_PATH || numChar == 0)\n\t{\n\t\tnlwarning(\"Couldn't retrieve windows directory\");\n\t\treturn \"\";\n\t}\n\treturn CPath::standardizePath(winDir);\n#endif\n}\n\nstd::string CPath::getApplicationDirectory(const std::string &appName)\n{\n\treturn getInstance()->_FileContainer.getApplicationDirectory(appName);\n}\n\nstd::string CFileContainer::getApplicationDirectory(const std::string &appName)\n{\n\tstatic std::string appPath;\n\tif (appPath.empty())\n\t{\n#ifdef NL_OS_WINDOWS\n\t\twchar_t buffer[MAX_PATH];\n\t\tSHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, TRUE);\n\t\tappPath = CPath::standardizePath(ucstring((ucchar*)buffer).toUtf8());\n#elif defined(NL_OS_MAC)\n\t\tappPath = CPath::standardizePath(getenv(\"HOME\"));\n\t\tappPath += \"/Library/Application Support/\";\n#else\n\t\tappPath = CPath::standardizePath(getenv(\"HOME\"));\n#endif\n\t}\n\n\tstd::string path = appPath;\n#ifdef NL_OS_WINDOWS\n\tif (!appName.empty())\n\t\tpath = CPath::standardizePath(path + appName);\n#elif defined(NL_OS_MAC)\n\tpath = CPath::standardizePath(path + appName);\n#else\n\tif (!appName.empty())\n\t\tpath = CPath::standardizePath(path + \".\" + toLower(appName));\n#endif\n\n\treturn path;\n}\n\nstd::string CPath::getTemporaryDirectory()\n{\n\treturn getInstance()->_FileContainer.getTemporaryDirectory();\n}\n\nstd::string CFileContainer::getTemporaryDirectory()\n{\n\tstatic std::string path;\n\tif (path.empty())\n\t{\n\t\tconst char *temp = getenv(\"TEMP\");\n\t\tconst char *tmp = getenv(\"TMP\");\n\n\t\tstd::string tempDir;\n\n\t\tif (temp)\n\t\t\ttempDir = temp;\n\n\t\tif (tempDir.empty() && tmp)\n\t\t\ttempDir = tmp;\n\n#ifdef NL_OS_UNIX\n\t\tif (tempDir.empty())\n\t\t\ttempDir = \"/tmp\";\n#else\n\t\tif (tempDir.empty())\n\t\t\ttempDir = \".\";\n#endif\n\n\t\tpath = CPath::standardizePath(tempDir);\n\t}\n\n\treturn path;\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////////\n\nint CFile::getLastSeparator (const string &filename)\n{\n\tstring::size_type pos = filename.find_last_of ('/');\n\tif (pos == string::npos)\n\t{\n\t\tpos = filename.find_last_of ('\\\\');\n\t\tif (pos == string::npos)\n\t\t{\n\t\t\tpos = filename.find_last_of ('@');\n\t\t}\n\t}\n\treturn (int)pos;\n}\n\nstring CFile::getFilename (const string &filename)\n{\n\tstring::size_type pos = CFile::getLastSeparator(filename);\n\tif (pos != string::npos)\n\t\treturn filename.substr (pos + 1);\n\telse\n\t\treturn filename;\n}\n\nstring CFile::getFilenameWithoutExtension (const string &filename)\n{\n\tstring filename2 = getFilename (filename);\n\tstring::size_type pos = filename2.find_last_of ('.');\n\tif (pos == string::npos)\n\t\treturn filename2;\n\telse\n\t\treturn filename2.substr (0, pos);\n}\n\nstring CFile::getExtension (const string &filename)\n{\n\tstring::size_type pos = filename.find_last_of ('.');\n\tif (pos == string::npos)\n\t\treturn \"\";\n\telse\n\t\treturn filename.substr (pos + 1);\n}\n\nstring CFile::getPath (const string &filename)\n{\n\tstring::size_type pos = CFile::getLastSeparator(filename);\n\tif (pos != string::npos)\n\t\treturn filename.substr (0, pos + 1);\n\telse\n\t\treturn \"\";\n}\n\nbool CFile::isDirectory (const string &filename)\n{\n#ifdef NL_OS_WINDOWS\n\tDWORD res = GetFileAttributes(filename.c_str());\n\tif (res == INVALID_FILE_ATTRIBUTES)\n\t{\n\t\t// nlwarning (\"PATH: '%s' is not a valid file or directory name\", filename.c_str ());\n\t\treturn false;\n\t}\n\treturn (res & FILE_ATTRIBUTE_DIRECTORY) != 0;\n#else // NL_OS_WINDOWS\n\tstruct stat buf;\n\tint res = stat (filename.c_str (), &buf);\n\tif (res == -1)\n\t{\n\t\t// There was previously a warning message here but that was incorrect as it is defined that isDirectory returns false if the directory doesn't exist\n\t\t// nlwarning (\"PATH: can't stat '%s' error %d '%s'\", filename.c_str(), errno, strerror(errno));\n\t\treturn false;\n\t}\n\treturn (buf.st_mode & S_IFDIR) != 0;\n#endif // NL_OS_WINDOWS\n}\n\nbool CFile::isExists (const string &filename)\n{\n#ifdef NL_OS_WINDOWS\n\treturn (GetFileAttributes(filename.c_str()) != INVALID_FILE_ATTRIBUTES);\n#else // NL_OS_WINDOWS\n\tstruct stat buf;\n\treturn stat (filename.c_str (), &buf) == 0;\n#endif // NL_OS_WINDOWS\n}\n\nbool CFile::createEmptyFile (const std::string& filename)\n{\n\tFILE *file = fopen (filename.c_str(), \"wb\");\n\n\tif (file)\n\t{\n\t\tfclose (file);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool CFile::fileExists (const string& filename)\n{\n\t//H_AUTO(FileExists);\n\treturn ! ! fstream( filename.c_str(), ios::in );\n}\n\n\nstring CFile::findNewFile (const string &filename)\n{\n\tstring::size_type pos = filename.find_last_of ('.');\n\tif (pos == string::npos)\n\t\treturn filename;\n\n\tstring start = filename.substr (0, pos);\n\tstring end = filename.substr (pos);\n\n\tuint num = 0;\n\tchar numchar[4];\n\tstring npath;\n\tdo\n\t{\n\t\tnpath = start;\n\t\tsmprintf(numchar,4,\"%03d\",num++);\n\t\tnpath += numchar;\n\t\tnpath += end;\n\t\tif (!CFile::fileExists(npath)) break;\n\t}\n\twhile (num<999);\n\treturn npath;\n}\n\n// \\warning doesn't work with big file\nuint32\tCFile::getFileSize (const std::string &filename)\n{\n\tif (filename.find(\"@@\") != string::npos)\n\t{\n\t\tuint32 fs = 0, bfo;\n\t\tbool c, d;\n\t\tCXMLPack::getInstance().getFile (filename, fs, bfo, c, d);\n\t\treturn fs;\n\t}\n\telse if (filename.find('@') != string::npos)\n\t{\n\t\tuint32 fs = 0, bfo;\n\t\tbool c, d;\n\t\tCBigFile::getInstance().getFile (filename, fs, bfo, c, d);\n\t\treturn fs;\n\t}\n\telse\n\t{\n#if defined (NL_OS_WINDOWS)\n\t\tstruct _stat buf;\n\t\tint result = _stat (filename.c_str (), &buf);\n#elif defined (NL_OS_UNIX)\n\t\tstruct stat buf;\n\t\tint result = stat (filename.c_str (), &buf);\n#endif\n\t\tif (result != 0) return 0;\n\t\telse return buf.st_size;\n\t}\n}\n\nuint32\tCFile::getFileSize (FILE *f)\n{\n#if defined (NL_OS_WINDOWS)\n\tstruct _stat buf;\n\tint result = _fstat (fileno(f), &buf);\n#elif defined (NL_OS_UNIX)\n\tstruct stat buf;\n\tint result = fstat (fileno(f), &buf);\n#endif\n\tif (result != 0) return 0;\n\telse return buf.st_size;\n}\n\nuint32\tCFile::getFileModificationDate(const std::string &filename)\n{\n\tstring::size_type pos;\n\tstring fn;\n\tif ((pos=filename.find(\"@@\")) != string::npos)\n\t{\n\t\tfn = filename.substr (0, pos);\n\t}\n\telse if ((pos=filename.find('@')) != string::npos)\n\t{\n\t\tfn = CPath::lookup(filename.substr (0, pos));\n\t}\n\telse\n\t{\n\t\tfn = filename;\n\t}\n\n#if defined (NL_OS_WINDOWS)\n//\tstruct _stat buf;\n//\tint result = _stat (fn.c_str (), &buf);\n\t// Changed 06-06-2007 : boris : _stat have an incoherent and hard to reproduce\n\t// on windows : if the system clock is adjusted according to daylight saving\n\t// time, the file date reported by _stat may (not always!) be adjusted by 3600s\n\t// This is a bad behavior because file time should always be reported as UTC time value\n\n\t// Use the WIN32 API to read the file times in UTC\n\n\t// create a file handle (this does not open the file)\n\tHANDLE h = CreateFile(fn.c_str(), 0, 0, NULL, OPEN_EXISTING, 0, 0);\n\tif (h == INVALID_HANDLE_VALUE)\n\t{\n\t\tnlwarning(\"Can't get modification date on file '%s' : %s\", fn.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\t\treturn 0;\n\t}\n\tFILETIME creationTime;\n\tFILETIME accesstime;\n\tFILETIME modTime;\n\n\t// get the files times\n\tBOOL res = GetFileTime(h, &creationTime, &accesstime, &modTime);\n\tif (res == 0)\n\t{\n\t\tnlwarning(\"Can't get modification date on file '%s' : %s\", fn.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\t\tCloseHandle(h);\n\t\treturn 0;\n\t}\n\t// close the handle\n\tCloseHandle(h);\n\n\t// win32 file times are in 10th of micro sec (100ns resolution), starting at jan 1, 1601\n\t// hey Mr Gates, why 1601 ?\n\n\t// first, convert it into second since jan1, 1601\n\tuint64 t = modTime.dwLowDateTime | (uint64(modTime.dwHighDateTime)<<32);\n\n\t// adjust time base to unix epoch base\n\tt -= CTime::getWindowsToUnixBaseTimeOffset();\n\n\t// convert the resulting time into seconds\n\tt /= 10;\t// microsec\n\tt /= 1000;\t// millisec\n\tt /= 1000;\t// sec\n\n\t// return the resulting time\n\treturn uint32(t);\n\n#elif defined (NL_OS_UNIX)\n\tstruct stat buf;\n\tint result = stat (fn.c_str (), &buf);\n\tif (result != 0)\n\t{\n\t\tnlwarning(\"Can't get modification date on file '%s' : %s\", fn.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\t\treturn 0;\n\t}\n\telse\n\t\treturn (uint32)buf.st_mtime;\n#endif\n\n}\n\nbool\tCFile::setFileModificationDate(const std::string &filename, uint32 modTime)\n{\n\tstring::size_type pos;\n\tstring fn;\n\tif ((pos=filename.find('@')) != string::npos)\n\t{\n\t\tfn = CPath::lookup(filename.substr (0, pos));\n\t}\n\telse\n\t{\n\t\tfn = filename;\n\t}\n\n#if defined (NL_OS_WINDOWS)\n\n\t// Use the WIN32 API to set the file times in UTC\n\n\t// create a file handle (this does not open the file)\n\tHANDLE h = CreateFile(fn.c_str(), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);\n\tif (h == INVALID_HANDLE_VALUE)\n\t{\n\t\tnlwarning(\"Can't set modification date on file '%s' (error accessing file) : %s\", fn.c_str(), NLMISC::formatErrorMessage(NLMISC::getLastError()).c_str());\n\t\treturn false;\n\t}\n\tFILETIME creationFileTime;\n\tFILETIME accessFileTime;\n\tFILETIME modFileTime;\n\n\t// read the current the files times\n\tif (GetFileTime(h, &creationFileTime, &accessFileTime, &modFileTime) == 0)\n\t{\n\t\tnlwarning(\"Can't set modification date on file '%s' : %s\", fn.c_str(), formatErrorMessage(getLastError()).c_str());\n\t\tCloseHandle(h);\n\t\treturn false;\n\t}\n\n\t// win32 file times are in 10th of micro sec (100ns resolution), starting at jan 1, 1601\n\t// hey Mr Gates, why 1601 ?\n\n\t// convert the unix time into a windows file time\n\tuint64 t = modTime;\n\t// convert to 10th of microsec\n\tt *= 1000;\t// millisec\n\tt *= 1000;\t// microsec\n\tt *= 10;\t// 10th of micro sec (rez of windows file time is 100ns <=> 1/10 us\n\n\t// apply the windows to unix base time offset\n\tt += CTime::getWindowsToUnixBaseTimeOffset();\n\n\t// update the windows modTime structure\n\tmodFileTime.dwLowDateTime = uint32(t & 0xffffffff);\n\tmodFileTime.dwHighDateTime = uint32(t >> 32);\n\n\t// update the file time on disk\n\tBOOL rez = SetFileTime(h, &creationFileTime, &accessFileTime, &modFileTime);\n\tif (rez == 0)\n\t{\n\t\tnlwarning(\"Can't set modification date on file '%s': %s\", fn.c_str(), formatErrorMessage(getLastError()).c_str());\n\n\t\tCloseHandle(h);\n\t\treturn false;\n\t}\n\n\t// close the handle\n\tCloseHandle(h);\n\n\treturn true;\n\n#elif defined (NL_OS_UNIX)\n\t// first, read the current time of the file\n\tstruct stat buf;\n\tint result = stat (fn.c_str (), &buf);\n\tif (result != 0)\n\t\treturn false;\n\n\t// prepare the new time to apply\n\tutimbuf tb;\n\ttb.actime = buf.st_atime;\n\ttb.modtime = modTime;\n\t// set eh new time\n\tint res = utime(fn.c_str(), &tb);\n\tif (res == -1)\n\t\tnlwarning(\"Can't set modification date on file '%s': %s\", fn.c_str(), formatErrorMessage(getLastError()).c_str());\n\treturn res != -1;\n#endif\n\n}\n\nuint32\tCFile::getFileCreationDate(const std::string &filename)\n{\n\tstring::size_type pos;\n\tstring fn;\n\tif ((pos=filename.find('@')) != string::npos)\n\t{\n\t\tfn = CPath::lookup(filename.substr (0, pos));\n\t}\n\telse\n\t{\n\t\tfn = filename;\n\t}\n\n#if defined (NL_OS_WINDOWS)\n\tstruct _stat buf;\n\tint result = _stat (fn.c_str (), &buf);\n#elif defined (NL_OS_UNIX)\n\tstruct stat buf;\n\tint result = stat (fn.c_str (), &buf);\n#endif\n\n\tif (result != 0) return 0;\n\telse return (uint32)buf.st_ctime;\n}\n\nstruct CFileEntry\n{\n\tCFileEntry (const string &filename, void (*callback)(const string &filename)) : FileName (filename), Callback (callback)\n\t{\n\t\tLastModified = CFile::getFileModificationDate(filename);\n\t}\n\tstring FileName;\n\tvoid (*Callback)(const string &filename);\n\tuint32 LastModified;\n};\n\nstatic vector <CFileEntry> FileToCheck;\n\nvoid CFile::removeFileChangeCallback (const std::string &filename)\n{\n\tstring fn = CPath::lookup(filename, false, false);\n\tif (fn.empty())\n\t{\n\t\tfn = filename;\n\t}\n\tfor (uint i = 0; i < FileToCheck.size(); i++)\n\t{\n\t\tif(FileToCheck[i].FileName == fn)\n\t\t{\n\t\t\tnlinfo (\"PATH: CFile::removeFileChangeCallback: '%s' is removed from checked files modification\", fn.c_str());\n\t\t\tFileToCheck.erase(FileToCheck.begin()+i);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid CFile::addFileChangeCallback (const std::string &filename, void (*cb)(const string &filename))\n{\n\tstring fn = CPath::lookup(filename, false, false);\n\tif (fn.empty())\n\t{\n\t\tfn = filename;\n\t}\n\tnlinfo (\"PATH: CFile::addFileChangeCallback: I'll check the modification date for this file '%s'\", fn.c_str());\n\tFileToCheck.push_back(CFileEntry(fn, cb));\n}\n\nvoid CFile::checkFileChange (TTime frequency)\n{\n\tstatic TTime lastChecked = CTime::getLocalTime();\n\n\tif (CTime::getLocalTime() > lastChecked + frequency)\n\t{\n\t\tfor (uint i = 0; i < FileToCheck.size(); i++)\n\t\t{\n\t\t\tif(CFile::getFileModificationDate(FileToCheck[i].FileName) != FileToCheck[i].LastModified)\n\t\t\t{\n\t\t\t\t// need to reload it\n\t\t\t\tif(FileToCheck[i].Callback != NULL)\n\t\t\t\t\tFileToCheck[i].Callback(FileToCheck[i].FileName);\n\n\t\t\t\tFileToCheck[i].LastModified = CFile::getFileModificationDate(FileToCheck[i].FileName);\n\t\t\t}\n\t\t}\n\n\t\tlastChecked = CTime::getLocalTime();\n\t}\n}\n\nstatic bool CopyMoveFile(const std::string &dest, const std::string &src, bool copyFile, bool failIfExists = false, IProgressCallback *progress = NULL)\n{\n\tif (dest.empty() || src.empty()) return false;\n\tstd::string sdest = CPath::standardizePath(dest,false);\n\tstd::string ssrc = CPath::standardizePath(src,false);\n\n//\treturn copyFile  ? CopyFile(dossrc.c_str(), dosdest.c_str(), failIfExists) != FALSE\n//\t\t\t\t\t : MoveFile(dossrc.c_str(), dosdest.c_str()) != FALSE;\n\n\tif (progress) progress->progress(0.f);\n\tif(copyFile)\n\t{\n\t\tuint32 totalSize = 0;\n\t\tuint32 readSize = 0;\n\t\tif (progress)\n\t\t{\n\t\t\ttotalSize = CFile::getFileSize(ssrc);\n\t\t}\n\t\tFILE *fp1 = fopen(ssrc.c_str(), \"rb\");\n\t\tif (fp1 == NULL)\n\t\t{\n\t\t\tnlwarning (\"PATH: CopyMoveFile error: can't fopen in read mode '%s'\", ssrc.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tFILE *fp2 = fopen(sdest.c_str(), \"wb\");\n\t\tif (fp2 == NULL)\n\t\t{\n\t\t\tnlwarning (\"PATH: CopyMoveFile error: can't fopen in read write mode '%s'\", sdest.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tstatic char buffer [1000];\n\t\tsize_t s;\n\n\t\ts = fread(buffer, 1, sizeof(buffer), fp1);\n\t\twhile (s != 0)\n\t\t{\n\t\t\tif (progress)\n\t\t\t{\n\t\t\t\treadSize += (uint32)s;\n\t\t\t\tprogress->progress((float) readSize / totalSize);\n\t\t\t}\n\t\t\tsize_t ws = fwrite(buffer, s, 1, fp2);\n\t\t\tif (ws != 1)\n\t\t\t{\n\t\t\t\tnlwarning(\"Error copying '%s' to '%s', trying to write %u bytes failed.\",\n\t\t\t\t\tssrc.c_str(),\n\t\t\t\t\tsdest.c_str(),\n\t\t\t\t\ts);\n\t\t\t\tfclose(fp1);\n\t\t\t\tfclose(fp2);\n\t\t\t\tnlwarning(\"Errno = %d\", errno);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ts = fread(buffer, 1, sizeof(buffer), fp1);\n\t\t}\n\n\t\tfclose(fp1);\n\t\tfclose(fp2);\n\t\tif (progress) progress->progress(1.f);\n\t}\n\telse\n\t{\n#ifdef NL_OS_WINDOWS\n\t\tif (MoveFile(ssrc.c_str(), sdest.c_str()) == 0)\n\t\t{\n\t\t\tLPVOID lpMsgBuf;\n\t\t\tFormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |\n\t\t\t\t\t    FORMAT_MESSAGE_FROM_SYSTEM |\n\t\t\t\t\t\tFORMAT_MESSAGE_IGNORE_INSERTS,\n\t\t\t\t\t\tNULL,\n\t\t\t\t\t\tGetLastError(),\n\t\t\t\t\t\tMAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language\n\t\t\t\t\t\t(LPTSTR) &lpMsgBuf,\n\t\t\t\t\t\t0,\n\t\t\t\t\t\tNULL );\n\t\t\tnlwarning (\"PATH: CopyMoveFile error: can't link/move '%s' into '%s', error %u (%s)\",\n\t\t\t\tssrc.c_str(),\n\t\t\t\tsdest.c_str(),\n\t\t\t\tGetLastError(),\n\t\t\t\tlpMsgBuf);\n\n\t\t\tLocalFree(lpMsgBuf);\n\t\t\treturn false;\n\t\t}\n#else\n\t\tif (rename (ssrc.c_str(), sdest.c_str()) == -1)\n\t\t{\n\t\t\tnlwarning (\"PATH: CopyMoveFile error: can't rename '%s' into '%s', error %u\",\n\t\t\t\tssrc.c_str(),\n\t\t\t\tsdest.c_str(),\n\t\t\t\terrno);\n\t\t\treturn false;\n\t\t}\n#endif\n\t}\n\tif (progress) progress->progress(1.f);\n\treturn true;\n}\n\nbool CFile::copyFile(const std::string &dest, const std::string &src, bool failIfExists /*=false*/, IProgressCallback *progress)\n{\n\treturn CopyMoveFile(dest, src, true, failIfExists, progress);\n}\n\nbool CFile::quickFileCompare(const std::string &fileName0, const std::string &fileName1)\n{\n\t// make sure the files both exist\n\tif (!fileExists(fileName0.c_str()) || !fileExists(fileName1.c_str()))\n\t\treturn false;\n\n\t// compare time stamps\n\tif (getFileModificationDate(fileName0.c_str()) != getFileModificationDate(fileName1.c_str()))\n\t\treturn false;\n\n\t// compare file sizes\n\tif (getFileSize(fileName0.c_str()) != getFileSize(fileName1.c_str()))\n\t\treturn false;\n\n\t// everything matched so return true\n\treturn true;\n}\n\nbool CFile::thoroughFileCompare(const std::string &fileName0, const std::string &fileName1,uint32 maxBufSize)\n{\n\t// make sure the files both exist\n\tif (!fileExists(fileName0.c_str()) || !fileExists(fileName1.c_str()))\n\t\treturn false;\n\n\t// setup the size variable from file length of first file\n\tuint32 fileSize=getFileSize(fileName0.c_str());\n\n\t// compare file sizes\n\tif (fileSize != getFileSize(fileName1.c_str()))\n\t\treturn false;\n\n\t// allocate a couple of data buffers for our 2 files\n\tuint32 bufSize= maxBufSize/2;\n\tnlassert(sint32(bufSize)>0);\n\tstd::vector<uint8> buf0(bufSize);\n\tstd::vector<uint8> buf1(bufSize);\n\n\t// open the two files for input\n\tCIFile file0(fileName0);\n\tCIFile file1(fileName1);\n\n\tfor (uint32 i=0;i<fileSize;i+=bufSize)\n\t{\n\t\t// for the last block in the file reduce buf size to represent the amount of data left in file\n\t\tif (i+bufSize>fileSize)\n\t\t{\n\t\t\tbufSize= fileSize-i;\n\t\t\tbuf0.resize(bufSize);\n\t\t\tbuf1.resize(bufSize);\n\t\t}\n\n\t\t// read in the next data block from disk\n\t\tfile0.serialBuffer(&buf0[0], bufSize);\n\t\tfile1.serialBuffer(&buf1[0], bufSize);\n\n\t\t// compare the contents of the 2 data buffers\n\t\tif (buf0!=buf1)\n\t\t\treturn false;\n\t}\n\n\t// everything matched so return true\n\treturn true;\n}\n\nbool CFile::moveFile(const char *dest,const char *src)\n{\n\treturn CopyMoveFile(dest, src, false);\n}\n\nbool CFile::createDirectory(const std::string &filename)\n{\n#ifdef NL_OS_WINDOWS\n\treturn _mkdir(filename.c_str())==0;\n#else\n\t// Set full permissions....\n\treturn mkdir(filename.c_str(), 0xFFFF)==0;\n#endif\n}\n\nbool CFile::createDirectoryTree(const std::string &filename)\n{\n\tbool lastResult=true;\n\tuint32 i=0;\n\n\t// skip dos drive name eg \"a:\"\n\tif (filename.size()>1 && filename[1]==':')\n\t\ti=2;\n\n\t// iterate over the set of directories in the routine's argument\n\twhile (i<filename.size())\n\t{\n\t\t// skip passed leading slashes\n\t\tfor (;i<filename.size();++i)\n\t\t\tif (filename[i]!='\\\\' && filename[i]!='/')\n\t\t\t\tbreak;\n\n\t\t// if the file name ended with a '/' then there's no extra directory to create\n\t\tif (i==filename.size())\n\t\t\tbreak;\n\n\t\t// skip forwards to next slash\n\t\tfor (;i<filename.size();++i)\n\t\t\tif (filename[i]=='\\\\' || filename[i]=='/')\n\t\t\t\tbreak;\n\n\t\t// try to create directory\n\t\tstd::string s= filename.substr(0,i);\n\t\tlastResult= createDirectory(s);\n\t}\n\n\treturn lastResult;\n}\n\nbool CPath::makePathRelative (const char *basePath, std::string &relativePath)\n{\n\t// Standard path with final slash\n\tstring tmp = standardizePath (basePath, true);\n\tstring src = standardizePath (relativePath, true);\n\tstring prefix;\n\n\tfor(;;)\n\t{\n\t\t// Compare with relativePath\n\t\tif (strncmp (tmp.c_str (), src.c_str (), tmp.length ()) == 0)\n\t\t{\n\t\t\t// Truncate\n\t\t\tuint size = (uint)tmp.length ();\n\n\t\t\t// Same path ?\n\t\t\tif (size == src.length ())\n\t\t\t{\n\t\t\t\trelativePath = \".\";\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\trelativePath = prefix+relativePath.substr (size, relativePath.length () - size);\n\t\t\treturn true;\n\t\t}\n\n\t\t// Too small ?\n\t\tif (tmp.length ()<2)\n\t\t\tbreak;\n\n\t\t// Remove last directory\n\t\tstring::size_type lastPos = tmp.rfind ('/', tmp.length ()-2);\n\t\tstring::size_type previousPos = tmp.find ('/');\n\t\tif ((lastPos == previousPos) || (lastPos == string::npos))\n\t\t\tbreak;\n\n\t\t// Troncate\n\t\ttmp = tmp.substr (0, lastPos+1);\n\n\t\t// New prefix\n\t\tprefix += \"../\";\n\t}\n\n\treturn false;\n}\n\nstd::string CPath::makePathAbsolute( const std::string &relativePath, const std::string &directory )\n{\n\tif( relativePath.empty() )\n\t\treturn \"\";\n\tif( directory.empty() )\n\t\treturn \"\";\n\n#ifdef NL_OS_WINDOWS\n\t// Windows network address. Eg.: \\\\someshare\\path\n\tif( ( relativePath[ 0 ] == '\\\\' ) && ( relativePath[ 1 ] == '\\\\' ) )\n\t\treturn relativePath;\n\n\t// Normal Windows absolute path. Eg.: C:\\something\n\t//\n\tif( isalpha( relativePath[ 0 ] ) && ( relativePath[ 1 ] == ':' ) && ( ( relativePath[ 2 ] == '\\\\' ) || ( relativePath[ 2 ] == '/' ) ) )\n\t\treturn relativePath;\n#else\n\t// Unix filesystem absolute path\n\tif( relativePath[ 0 ] == '/' )\n\t\treturn relativePath;\n\n#endif\n\n\t// Add a slash to the directory if necessary.\n\t// If the relative path starts with dots we need a slash.\n\t// If the relative path starts with a slash we don't.\n\t// If it starts with neither, we need a slash.\n\tbool needSlash = true;\n\tchar c = relativePath[ 0 ];\n\tif( ( c == '\\\\' ) || ( c == '/' ) )\n\t\tneedSlash = false;\n\t\n\tbool hasSlash = false;\n\tstd::string npath = directory;\n\tc = npath[ npath.size() - 1 ];\n\tif( ( c == '\\\\' ) || ( c == '/' ) )\n\t\thasSlash = true;\n\n\tif( needSlash && !hasSlash )\n\t\tnpath += '/';\n\telse\n\tif( hasSlash && !needSlash )\n\t\tnpath.resize( npath.size() - 1 );\n\t\n\t// Now build the new absolute path\n\tnpath += relativePath;\n\tnpath = standardizePath( npath, false );\n\n\treturn npath;\n}\n\nbool CFile::setRWAccess(const std::string &filename)\n{\n#ifdef NL_OS_WINDOWS\n\t// if the file exists and there's no write access\n\tif (_access (filename.c_str(), 00) == 0 && _access (filename.c_str(), 06) == -1)\n\t{\n\t\t// try to set the read/write access\n\t\tif (_chmod (filename.c_str(), _S_IREAD | _S_IWRITE) == -1)\n\t\t{\n\t\t\tif (INelContext::getInstance().getAlreadyCreateSharedAmongThreads())\n\t\t\t{\n\t\t\t\tnlwarning (\"PATH: Can't set RW access to file '%s': %d %s\", filename.c_str(), errno, strerror(errno));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n#else\n\t// if the file exists and there's no write access\n\tif (access (filename.c_str(), F_OK) == 0)\n\t{\n\t\t// try to set the read/write access\n\t\tif (chmod (filename.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH) == -1)\n\t\t{\n\t\t\tif (INelContext::getInstance().getAlreadyCreateSharedAmongThreads())\n\t\t\t{\n\t\t\t\tnlwarning (\"PATH: Can't set RW access to file '%s': %d %s\", filename.c_str(), errno, strerror(errno));\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (INelContext::getInstance().getAlreadyCreateSharedAmongThreads())\n\t\t{\n\t\t\tnlwarning(\"PATH: Can't access to file '%s'\", filename.c_str());\n\t\t}\n//\t\treturn false;\n\t}\n#endif\n\treturn true;\n}\n\n\n#ifdef NL_OS_WINDOWS\n#define unlink _unlink\n#endif\n\nbool CFile::deleteFile(const std::string &filename)\n{\n\tsetRWAccess(filename);\n\tint res = unlink (filename.c_str());\n\tif (res == -1)\n\t{\n\t\tif (INelContext::getInstance().getAlreadyCreateSharedAmongThreads())\n\t\t{\n\t\t\tnlwarning (\"PATH: Can't delete file '%s': (errno %d) %s\", filename.c_str(), errno, strerror(errno));\n\t\t}\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n#ifdef NL_OS_WINDOWS\n#define rmdir _rmdir\n#endif\n\nbool CFile::deleteDirectory(const std::string &filename)\n{\n\tsetRWAccess(filename);\n\tint res = rmdir (filename.c_str());\n\tif (res == -1)\n\t{\n\t\tnlwarning (\"PATH: Can't delete directory '%s': (errno %d) %s\", filename.c_str(), errno, strerror(errno));\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid CFile::getTemporaryOutputFilename (const std::string &originalFilename, std::string &tempFilename)\n{\n\tuint i = 0;\n\tdo\n\t\ttempFilename = originalFilename+\".tmp\"+toString (i++);\n\twhile (CFile::isExists(tempFilename));\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/plane.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/plane.h\"\n#include \"nel/misc/uv.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n\n//============================================================\nvoid\tCPlane::make(const CVector &normal, const CVector &p)\n{\n\tCVector\tv= normal.normed();\n\ta= v.x;\n\tb= v.y;\n\tc= v.z;\n\td=-(v*p);\t\t// d=- (ax+by+cz).\n}\nvoid\tCPlane::make(const CVector &p0, const CVector &p1, const CVector &p2)\n{\n\tCVector v;\n\n\tv=(p1-p0)^(p2-p1);\n\tmake(v,p1);\n}\n\n\n//============================================================\nbool\tCPlane::clipSegmentBack(CVector &p0, CVector &p1) const\n{\n\tfloat\td0,d1,decal;\n\tCVector\tproj;\n\n\td0= (*this)*p0;\n\td1= (*this)*p1;\n\tif(d0<0 && d1<0)\n\t\treturn true;\n\tif(d0>=0 && d1>=0)\n\t\treturn false;\n\t// Clip line.\n\tdecal= (0-d0) / (d1-d0);\n\tproj= p0+ (p1-p0)*decal;\n\tif(d0>=0)\n\t\tp0=proj;\n\telse\n\t\tp1=proj;\n\treturn true;\n}\nbool\tCPlane::clipSegmentFront(CVector &p0, CVector &p1) const\n{\n\tfloat\td0,d1,decal;\n\tCVector\tproj;\n\n\td0= (*this)*p0;\n\td1= (*this)*p1;\n\tif(d0>=0 && d1>=0)\n\t\treturn true;\n\tif(d0<0 && d1<0)\n\t\treturn false;\n\t// Clip line.\n\tdecal= (0-d0) / (d1-d0);\n\tproj= p0+ (p1-p0)*decal;\n\tif(d0<0)\n\t\tp0=proj;\n\telse\n\t\tp1=proj;\n\treturn true;\n}\n\n//============================================================\nsint\tCPlane::clipPolygonBack(CVector in[], CVector out[], sint nIn) const\n{\n\tsint nOut=0,s,p,i;\n\tif(nIn<=2) return 0;\n\n\ts=nIn-1;\n\n\tfor (i=0;i<nIn;i++)\n\t{\n\t\tp=i;\n\t\tif ( (*this)*in[p] < 0 )\n\t\t{\n\t\t\tif ( (*this)*in[s] >= 0 )\n\t\t\t\tout[nOut++]= intersect(in[s],in[p]);\n\t\t\tout[nOut++]=in[p];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( (*this)*in[s] < 0 )\n\t\t\t\tout[nOut++]= intersect(in[s],in[p]);\n\t\t}\n\t\ts=p;\n\t}\n\n\treturn nOut;\n}\n\n//============================================================\nsint CPlane::clipPolygonBack(const CVector in[], const CUV inUV[], CVector out[], CUV outUV[], sint nIn) const\n{\n\tsint nOut=0,s,p,i;\n\tif(nIn<=2) return 0;\n\n\ts=nIn-1;\n\n\tfor (i=0;i<nIn;i++)\n\t{\n\t\tp=i;\n\t\tfloat dp3Curr = (*this)*in[p];\n\t\tfloat dp3Prev = (*this)*in[s];\n\t\tif ( dp3Curr < 0 )\n\t\t{\n\t\t\tif (dp3Prev >= 0 )\n\t\t\t{\n\t\t\t\tfloat lambda = favoid0((float) ((double) dp3Prev / ((double) dp3Prev - (double) dp3Curr)));\n\t\t\t\tout[nOut] = blend(in[s], in[p], lambda);\n\t\t\t\toutUV[nOut++] = blend(inUV[s], inUV[p], lambda);\n\t\t\t}\n\t\t\tout[nOut]=in[p];\n\t\t\toutUV[nOut++]=inUV[p];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dp3Prev < 0 )\n\t\t\t{\n\t\t\t\tfloat lambda = favoid0((float) ((double) dp3Prev / ((double) dp3Prev - (double) dp3Curr)));\n\t\t\t\tout[nOut] = blend(in[s], in[p], lambda);\n\t\t\t\toutUV[nOut++] = blend(inUV[s], inUV[p], lambda);\n\t\t\t}\n\t\t}\n\t\ts=p;\n\t}\n\n\treturn nOut;\n}\n\n//============================================================\nsint\tCPlane::clipPolygonFront(CVector in[], CVector out[], sint nIn) const\n{\n\tsint nOut=0,s,p,i;\n\tif(nIn<=2) return 0;\n\n\ts=nIn-1;\n\n\tfor (i=0;i<nIn;i++)\n\t{\n\t\tp=i;\n\t\tif ( (*this)*in[p] > 0 )\n\t\t{\n\t\t\tif ( (*this)*in[s] <= 0 )\n\t\t\t\tout[nOut++]= intersect(in[s],in[p]);\n\t\t\tout[nOut++]=in[p];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( (*this)*in[s] > 0 )\n\t\t\t\tout[nOut++]= intersect(in[s],in[p]);\n\t\t}\n\t\ts=p;\n\t}\n\n\treturn nOut;\n}\n\n\n//============================================================\nCPlane  CPlane::inverted() const\n{\n\treturn CPlane(-a, -b, -c, -d);\n}\n\n//============================================================\nvoid\tCPlane::invert()\n{\n\ta = -a;\n\tb = -b;\n\tc = -c;\n\td = -d;\n}\n\n\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/polygon.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/polygon.h\"\n#include \"nel/misc/plane.h\"\n#include \"nel/misc/triangle.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n//==================================//\n//\t\tCPolygon implementation     //\n//==================================//\n\n// ***************************************************************************\nCPolygon::CPolygon(const CVector &a, const CVector &b, const CVector &c)\n{\n\tVertices.reserve(3);\n\tVertices.push_back(a);\n\tVertices.push_back(b);\n\tVertices.push_back(c);\n}\n\n// ***************************************************************************\nvoid CPolygon::toTriFan(std::vector<NLMISC::CTriangle> &dest) const\n{\n\tsint count = (sint) Vertices.size() - 2;\n\tfor(sint k = 0; k < count; ++k)\n\t{\n\t\tdest.push_back(CTriangle(Vertices[0], Vertices[k + 1], Vertices[k + 2]));\n\t}\n}\n\n// ***************************************************************************\nfloat CPolygon::computeArea() const\n{\n\tfloat area = 0.f;\n\tsint numVerts = (sint) Vertices.size();\n\tfor(sint k = 0; k < numVerts - 2; ++k)\n\t{\n\t\tCVector v0 = Vertices[k + 1] - Vertices[0];\n\t\tCVector v1 = Vertices[k + 2] - Vertices[0];\n\t\tarea += (v0 ^ v1).norm();\n\t}\n\treturn 0.5f * fabsf(area);\n}\n\n// ***************************************************************************\nvoid\t\t\tCPolygon::clip(const CPlane\t *planes, uint nPlanes)\n{\n\tif(nPlanes==0 || getNumVertices()==0)\n\t\treturn;\n\n\t// The final polygon has at maximum currentVertices+number of clipping planes.\n\t// For performance, the vectors are static, so reallocation rarely occurs.\n\tstatic\tvector<CVector>\t\ttab0, tab1;\n\ttab0.resize(getNumVertices()+nPlanes);\n\ttab1.resize(getNumVertices()+nPlanes);\n\t// Init tab0 with Vertices.\n\tcopy(Vertices.begin(), Vertices.end(), tab0.begin());\n\tCVector\t\t\t\t*in=&(*tab0.begin()), *out= &(*tab1.begin());\n\tsint\t\t\t\tnin= getNumVertices(), nout;\n\tfor(sint i=0;i<(sint)nPlanes;i++)\n\t{\n\t\tnout= planes[i].clipPolygonBack(in, out, nin);\n\t\tswap(in, out);\n\t\tnin= nout;\n\t\tif(nin==0)\n\t\t\tbreak;\n\t}\n\n\t// Final result in \"in\".\n\tVertices.resize(nin);\n\tif(nin>0)\n\t{\n\t\tmemcpy(&(*Vertices.begin()), in, nin*sizeof(CVector));\n\t}\n}\n\n\n// ***************************************************************************\nvoid\t\t\tCPolygon::clip(const std::vector<CPlane> &planes)\n{\n\tif(planes.size()==0)\n\t\treturn;\n\tclip(&(*planes.begin()), (uint)planes.size());\n}\n\n\n\n// ***************************************************************************\nvoid CPolygon::serial(NLMISC::IStream &f) throw(NLMISC::EStream)\n{\n\tf.serialVersion(0);\n\tf.serialCont(Vertices);\n}\n\n// ***************************************************************************\nvoid CPolygon::getBestTriplet(uint &index0,uint &index1,uint &index2)\n{\n\tnlassert(Vertices.size() >= 3);\n\tuint i, j, k;\n\tfloat bestArea = 0.f;\n\tconst uint numVerts = (uint)Vertices.size();\n\tfor (i = 0; i < numVerts; ++i)\n\t{\n\t\tfor (j = 0; j < numVerts; ++j)\n\t\t{\n\t\t\tif (i != j)\n\t\t\t{\n\t\t\t\tfor (k = 0; k < numVerts; ++k)\n\t\t\t\t{\n\t\t\t\t\tif (k != i && k != j)\n\t\t\t\t\t{\n\t\t\t\t\t\tCVector v0 = Vertices[j] - Vertices[i];\n\t\t\t\t\t\tCVector v1 = Vertices[k] - Vertices[i];\n\t\t\t\t\t\tfloat area = (v0 ^ v1).norm();\n\t\t\t\t\t\tif (area > bestArea)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbestArea = area;\n\t\t\t\t\t\t\tindex0 = i;\n\t\t\t\t\t\t\tindex1 = j;\n\t\t\t\t\t\t\tindex2 = k;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n// ***************************************************************************\nvoid CPolygon::buildBasis(CMatrix &dest)\n{\n\tnlassert(Vertices.size() > 3);\n\tuint i1, i2, i3;\n\tgetBestTriplet(i1, i2, i3);\n\tCVector v1 = (Vertices[i2] - Vertices[i1]).normed();\n\tCVector v2 = (Vertices[i3] - Vertices[i1]).normed();\n\tCVector K = v2 ^ v1;\n\tCVector I = v1 - (v1 * K) * v1;\n\tCVector J = K ^ I;\n\tdest.setRot(I, J, K);\n\tdest.setPos(Vertices[i1]);\n}\n\n// ***************************************************************************\n\nclass CConcavePolygonsVertexDesc\n{\npublic:\n\n\tCConcavePolygonsVertexDesc (float length, uint index)\n\t{\n\t\tLength = length;\n\t\tIndex = index;\n\t}\n\n\t// Length > 0\n\tfloat\tLength;\n\n\t// First vertex index\n\tuint\tIndex;\n};\ntypedef std::map<float, CConcavePolygonsVertexDesc> TCConcavePolygonsVertexMap;\n\n\n// ***************************************************************************\nbool CPolygon::toConvexPolygonsEdgeIntersect (const CVector2f& a0, const CVector2f& a1, const CVector2f& b0, const CVector2f& b1)\n{\n\t// both vertical?\n\tif( a0.x-a1.x==0 && b0.x-b1.x==0 )\n\t\treturn false;\n\n\t// compute intersection of both lines\n\tCVector2f intersection;\n\n\t// first edge vertical?\n\tif(a0.x - a1.x==0)\n\t{\n\t\tfloat Ab = (b0.y - b1.y) / (b0.x - b1.x);\n\n\t\t// Intersection\n\t\tintersection.x = a0.x;\n\t\tintersection.y = b0.y + (a0.x-b0.x) * Ab;\n\t}\n\t// second edge vertical?\n\telse if(b0.x - b1.x==0)\n\t{\n\t\tfloat Aa = (a0.y - a1.y) / (a0.x - a1.x);\n\n\t\t// Intersection\n\t\tintersection.x = b0.x;\n\t\tintersection.y = a0.y + (b0.x-a0.x) * Aa;\n\t}\n\t// standard case\n\telse\n\t{\n\t\tfloat Aa = (a0.y - a1.y) / (a0.x - a1.x);\n\t\tfloat Ba = a0.y - a0.x * Aa;\n\t\tfloat Ab = (b0.y - b1.y) / (b0.x - b1.x);\n\t\tfloat Bb = b0.y - b0.x * Ab;\n\n\t\t// colinear?\n\t\tif(Aa==Ab)\n\t\t\treturn false;\n\n\t\t// Intersection\n\t\tintersection.x = (Bb - Ba) / (Aa - Ab);\n\t\tintersection.y = Aa * intersection.x + Ba;\n\t}\n\n\t// In it ?\n\treturn ( ( (a0-intersection)*(a1-intersection) < 0 ) && ( (b0-intersection)*(b1-intersection) < 0 ) );\n}\n\n// ***************************************************************************\n\nclass CBSPNode2v\n{\npublic:\n\tCBSPNode2v ()\n\t{\n\t\tBack = NULL;\n\t\tFront = NULL;\n\t}\n\tCBSPNode2v ( const CPlane &plane, CVector p0, CVector p1, uint v0, uint v1 ) : Plane (plane), P0 (p0), P1 (p1)\n\t{\n\t\tBack = NULL;\n\t\tFront = NULL;\n\t\tParent = NULL;\n\t\tV0 = v0;\n\t\tV1 = v1;\n\t}\n\t~CBSPNode2v ()\n\t{\n\t\tif (Front)\n\t\t\tdelete Front;\n\t\tif (Back)\n\t\t\tdelete Back;\n\t}\n\n\tvoid insert (CBSPNode2v *node)\n\t{\n\t\t// Front ?\n\t\tbool p0Front = (Plane * node->P0) > 0;\n\t\tbool p1Front = (Plane * node->P1) > 0;\n\t\tif (p0Front && p1Front)\n\t\t{\n\t\t\t// Front child ?\n\t\t\tif (Front)\n\t\t\t\tFront->insert (node);\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Link left\n\t\t\t\tFront = node;\n\t\t\t\tnode->Parent = this;\n\t\t\t}\n\t\t}\n\t\telse if ((!p0Front) && (!p1Front))\n\t\t{\n\t\t\t// Back child ?\n\t\t\tif (Back)\n\t\t\t\tBack->insert (node);\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Link left\n\t\t\t\tBack = node;\n\t\t\t\tnode->Parent = this;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Split vertex\n\t\t\tCVector newVertex = Plane.intersect (node->P0, node->P1);\n\n\t\t\t// New node\n\t\t\tCBSPNode2v *newNode = new CBSPNode2v (node->Plane, node->P0, newVertex, node->V0, node->V1);\n\n\t\t\t// Old node\n\t\t\tnode->P0 = newVertex;\n\n\t\t\t// Insert child\n\t\t\tCBSPNode2v **p0Parent;\n\t\t\tCBSPNode2v **p1Parent;\n\n\t\t\t// Get insertion pointer\n\t\t\tif (p0Front)\n\t\t\t{\n\t\t\t\tp0Parent = &Front;\n\t\t\t\tp1Parent = &Back;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tp0Parent = &Back;\n\t\t\t\tp1Parent = &Front;\n\t\t\t}\n\n\t\t\t// Insert children\n\t\t\tif (*p0Parent)\n\t\t\t{\n\t\t\t\t(*p0Parent)->insert (newNode);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*p0Parent = newNode;\n\t\t\t\tnewNode->Parent = this;\n\t\t\t}\n\n\t\t\t// Insert children\n\t\t\tif (*p1Parent)\n\t\t\t{\n\t\t\t\t(*p1Parent)->insert (node);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t*p1Parent = node;\n\t\t\t\tnode->Parent = this;\n\t\t\t}\n\t\t}\n\t}\n\n\tbool intersect (const CVector &p0, const CVector &p1, uint v0, uint v1) const\n\t{\n\t\t// Front ?\n\t\tbool p0Front = (Plane * p0) > 0;\n\t\tbool p1Front = (Plane * p1) > 0;\n\n\t\tif (p0Front != p1Front)\n\t\t\tif ( (v0 != V0) && (v0 != V1) && (v1 != V0) && (v1 != V1) )\n\t\t\t\tif (CPolygon::toConvexPolygonsEdgeIntersect ((CVector2f) P0, (CVector2f) P1, (CVector2f) p0, (CVector2f) p1))\n\t\t\t\t\treturn true;\n\n\t\tif (p0Front || p1Front)\n\t\t{\n\t\t\tif (Front)\n\t\t\t\tif (Front->intersect (p0, p1, v0, v1))\n\t\t\t\t\treturn true;\n\t\t}\n\n\t\tif ((!p0Front) || (!p1Front))\n\t\t{\n\t\t\tif (Back)\n\t\t\t\tif (Back->intersect (p0, p1, v0, v1))\n\t\t\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tCBSPNode2v\t*Back, *Front, *Parent;\n\tCPlane\t\tPlane;\n\tCVector\t\tP0;\n\tCVector\t\tP1;\n\tuint\t\tV0;\n\tuint\t\tV1;\n};\n\n// ***************************************************************************\n\nbool CPolygon::toConvexPolygonsLeft (const std::vector<CVector> &vertex, uint a, uint b, uint c)\n{\n\treturn ( (vertex[b].x - vertex[a].x) * (vertex[c].y - vertex[a].y) - (vertex[c].x - vertex[a].x) * (vertex[b].y - vertex[a].y) ) < 0;\n}\n\n// ***************************************************************************\n\nbool CPolygon::toConvexPolygonsLeftOn (const std::vector<CVector> &vertex, uint a, uint b, uint c)\n{\n\treturn ( (vertex[b].x - vertex[a].x) * (vertex[c].y - vertex[a].y) - (vertex[c].x - vertex[a].x) * (vertex[b].y - vertex[a].y) ) <= 0;\n}\n\n// ***************************************************************************\n\nbool CPolygon::toConvexPolygonsInCone (const std::vector<CVector> &vertex, uint a, uint b)\n{\n\t// Prev and next\n\tuint a0 = a+1;\n\tif (a0==vertex.size())\n\t\ta0=0;\n\tuint a1;\n\tif (a==0)\n\t\ta1= (uint)vertex.size()-1;\n\telse\n\t\ta1= a-1;\n\n\tif (toConvexPolygonsLeftOn (vertex, a, a1, a0) )\n\t{\n\t\treturn toConvexPolygonsLeft ( vertex, a, b, a0) && toConvexPolygonsLeft ( vertex, b, a, a1);\n\t}\n\telse\n\t{\n\t\treturn !( toConvexPolygonsLeft ( vertex, a, b, a1) && toConvexPolygonsLeft ( vertex, b, a, a0) );\n\t}\n}\n\n// ***************************************************************************\n\nbool CPolygon::toConvexPolygonsDiagonal (const std::vector<CVector> &vertex, const CBSPNode2v &bsp, uint a, uint b)\n{\n\t// Check it is a border\n\tif ( ( (b - a) == 1) || ( (a - b) == 1) || ( (a==0) && (b ==(vertex.size()-1))) || ( (b==0) && (a ==(vertex.size()-1))) )\n\t\treturn true;\n\n\t// Check visibility\n\tif (toConvexPolygonsInCone (vertex, a, b) && toConvexPolygonsInCone (vertex, b, a))\n\t{\n\t\t// Intersection ?\n\t\treturn !bsp.intersect (vertex[a], vertex[b], a, b);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nvoid CPolygon::toConvexPolygonsLocalAndBSP (std::vector<CVector> &localVertices, CBSPNode2v &root, const CMatrix &basis) const\n{\n\t// Invert matrix\n\tCMatrix invert = basis;\n\tinvert.invert ();\n\n\t// Insert vertices in an ordered table\n\tuint vertexCount = (uint)Vertices.size();\n\tTCConcavePolygonsVertexMap vertexMap;\n\tlocalVertices.resize (vertexCount);\n\tuint i, j;\n\n\t// Transform the vertex\n\tfor (i=0; i<vertexCount; i++)\n\t{\n\t\tCVector local = invert*Vertices[i];\n\t\tlocalVertices[i] = CVector (local.x, local.y, 0);\n\t}\n\n\t// Plane direction\n\ti=0;\n\tj=(uint)Vertices.size()-1;\n\tCVector normal = localVertices[i] - localVertices[j];\n\tnormal = normal ^ CVector::K;\n\tCPlane clipPlane;\n\tclipPlane.make(normal, localVertices[i]);\n\n\t// Build the BSP root\n\troot = CBSPNode2v (clipPlane, localVertices[i], localVertices[j], i, j);\n\n\t// Insert all others edges\n\tj=i++;\n\tfor (; i<Vertices.size(); i++)\n\t{\n\t\t// Plane direction\n\t\tnormal = localVertices[i] - localVertices[j];\n\t\tnormal = normal ^ CVector::K;\n\t\tclipPlane.make(normal, localVertices[i]);\n\n\t\t// Build the BSP root\n\t\troot.insert ( new CBSPNode2v (clipPlane, localVertices[i], localVertices[j], i, j) );\n\n\t\tj=i;\n\t}\n}\n\n\n// ***************************************************************************\nbool CPolygon::toConvexPolygons (std::list<CPolygon>& outputPolygons, const CMatrix& basis) const\n{\n\t// Some vertices ?\n\tif (Vertices.size()>2)\n\t{\n\t\t// Local vertices\n\t\tstd::vector<CVector>\tlocalVertices;\n\n\t\t// Build the BSP root\n\t\tCBSPNode2v root;\n\n\t\t// Build the local array and the BSP\n\t\ttoConvexPolygonsLocalAndBSP (localVertices, root, basis);\n\n\t\t// Build a vertex list\n\t\tstd::list<uint> vertexList;\n\t\tuint i;\n\t\tfor (i=0; i<Vertices.size(); i++)\n\t\t\tvertexList.push_back (i);\n\n\t\t// Clip ears while there is some polygons\n\t\tstd::list<uint>::iterator current=vertexList.begin();\n\t\tstd::list<uint>::iterator begin=vertexList.begin();\n\t\tdo\n\t\t{\nagain:;\n\t\t\t// Search for a diagonal\n\t\t\tbool found = false;\n\n\t\t\t// Get next vertex\n\t\t\tstd::list<uint>::iterator first = current;\n\t\t\tstd::list<uint>::iterator lastPreviousPrevious=current;\n\t\t\tstd::list<uint>::iterator lastPrevious=current;\n\t\t\tlastPrevious++;\n\t\t\tif (lastPrevious==vertexList.end())\n\t\t\t\tlastPrevious = vertexList.begin();\n\t\t\tstd::list<uint>::iterator currentNext = lastPrevious;\n\t\t\tstd::list<uint>::iterator last = lastPrevious;\n\t\t\tlast++;\n\t\t\tif (last==vertexList.end())\n\t\t\t\tlast = vertexList.begin();\n\t\t\twhile (last != current)\n\t\t\t{\n\t\t\t\t// Is a diagonal ?\n\t\t\t\tif (\n\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *lastPreviousPrevious, *last)) &&\n\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *currentNext, *last)) &&\n\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *last, *current))\n\t\t\t\t\t)\n\t\t\t\t{\n\t\t\t\t\t// Find one\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Come back\n\t\t\t\t\tlast = lastPrevious;\n\t\t\t\t\tlastPrevious = lastPreviousPrevious;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// Next vertex\n\t\t\t\tlastPreviousPrevious = lastPrevious;\n\t\t\t\tlastPrevious = last++;\n\t\t\t\tif (last==vertexList.end())\n\t\t\t\t\tlast = vertexList.begin();\n\t\t\t}\n\n\t\t\t// Last polygon ?\n\t\t\tif (last==current)\n\t\t\t{\n\t\t\t\t// Add a polygon\n\t\t\t\toutputPolygons.push_back (CPolygon());\n\t\t\t\tCPolygon &back = outputPolygons.back ();\n\t\t\t\tback.Vertices.reserve (vertexList.size());\n\n\t\t\t\t// Add each vertex in the new polygon\n\t\t\t\tcurrent=vertexList.begin();\n\t\t\t\twhile (current!=vertexList.end())\n\t\t\t\t{\n\t\t\t\t\tback.Vertices.push_back (Vertices[*current]);\n\t\t\t\t\tcurrent++;\n\t\t\t\t}\n\n\t\t\t\t// Exit\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstd::list<uint>::iterator firstNext = current;\n\t\t\t\tstd::list<uint>::iterator firstNextNext = currentNext;\n\t\t\t\tif (first != vertexList.begin())\n\t\t\t\t\tfirst--;\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfirst = vertexList.end();\n\t\t\t\t\tfirst--;\n\t\t\t\t}\n\n\t\t\t\twhile (current != first)\n\t\t\t\t{\n\t\t\t\t\t// Is a diagonal ?\n\t\t\t\t\tif (\n\t\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *firstNextNext, *first)) &&\n\t\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *lastPrevious, *first)) &&\n\t\t\t\t\t\t(toConvexPolygonsDiagonal (localVertices, root, *last, *first))\n\t\t\t\t\t\t)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Find one\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// Come back\n\t\t\t\t\t\tfirst = firstNext;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Next vertex\n\t\t\t\t\tfirstNextNext = firstNext;\n\t\t\t\t\tfirstNext = first;\n\t\t\t\t\tif (first==vertexList.begin())\n\t\t\t\t\t{\n\t\t\t\t\t\tfirst = vertexList.end();\n\t\t\t\t\t\tfirst--;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tfirst--;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Found ?\n\t\t\tif (found)\n\t\t\t{\n\t\t\t\t// Count vertex\n\t\t\t\toutputPolygons.push_back (CPolygon());\n\t\t\t\tCPolygon &back = outputPolygons.back ();\n\n\t\t\t\t// Vertex count\n\t\t\t\tuint vertexCount = 1;\n\t\t\t\tcurrent = first;\n\t\t\t\twhile (current != last)\n\t\t\t\t{\n\t\t\t\t\tvertexCount++;\n\t\t\t\t\tcurrent++;\n\t\t\t\t\tif (current == vertexList.end())\n\t\t\t\t\t\tcurrent = vertexList.begin();\n\t\t\t\t}\n\n\t\t\t\t// Alloc vertices\n\t\t\t\tback.Vertices.reserve (vertexCount);\n\n\t\t\t\t// Copy and remove vertices\n\t\t\t\tback.Vertices.push_back (Vertices[*first]);\n\t\t\t\tfirst++;\n\t\t\t\tif (first == vertexList.end())\n\t\t\t\t\tfirst = vertexList.begin();\n\t\t\t\twhile (first != last)\n\t\t\t\t{\n\t\t\t\t\tback.Vertices.push_back (Vertices[*first]);\n\n\t\t\t\t\t// Remove from list\n\t\t\t\t\tfirst = vertexList.erase (first);\n\t\t\t\t\tif (first == vertexList.end())\n\t\t\t\t\t\tfirst = vertexList.begin();\n\t\t\t\t\tnlassert (first != vertexList.end());\n\t\t\t\t}\n\t\t\t\tback.Vertices.push_back (Vertices[*first]);\n\t\t\t\tcurrent = begin = last;\n\t\t\t\tgoto again;\n\t\t\t}\n\n\t\t\t// Next current\n\t\t\tcurrent++;\n\t\t\tif (current == vertexList.end())\n\t\t\t\tcurrent = vertexList.begin ();\n\t\t}\n\t\twhile (current != begin);\n\t}\n\treturn false;\n}\n\n// ***************************************************************************\n\nbool CPolygon::chain (const std::vector<CPolygon> &other, const CMatrix& basis)\n{\n\t// Local vertices\n\tstd::vector<CVector>\tlocalVertices;\n\n\t// Build the BSP root\n\tCBSPNode2v root;\n\n\t// Build the local array and the BSP\n\ttoConvexPolygonsLocalAndBSP (localVertices, root, basis);\n\n\t// Local vertices\n\tstd::vector<std::vector<CVector> >\tlocalVerticesOther (other.size());\n\n\t// Build the BSP root\n\tstd::vector<CBSPNode2v> rootOther (other.size());\n\n\t// Build a copy of the polygons\n\tstd::vector<CPolygon> copy = other;\n\n\t// Main copy\n\tCPolygon mainCopy = *this;\n\n\t// For each other polygons\n\tuint o;\n\tfor (o=0; o<other.size(); o++)\n\t{\n\t\t// Build the local array and the BSP\n\t\tother[o].toConvexPolygonsLocalAndBSP (localVerticesOther[o], rootOther[o], basis);\n\t}\n\n\t// Look for a couple..\n\tuint thisCount = (uint)Vertices.size();\n\tuint i, j;\n\tfor (o=0; o<other.size(); o++)\n\t{\n\t\tuint otherCount = (uint)other[o].Vertices.size();\n\n\t\t// Try to link in the main polygon\n\t\tfor (i=0; i<thisCount; i++)\n\t\t{\n\t\t\tfor (j=0; j<otherCount; j++)\n\t\t\t{\n\t\t\t\t// Test this segement\n\t\t\t\tif (!root.intersect (localVertices[i], localVerticesOther[o][j], i, 0xffffffff))\n\t\t\t\t{\n\t\t\t\t\t// Test each other polygons\n\t\t\t\t\tuint otherO;\n\t\t\t\t\tfor (otherO=0; otherO<other.size(); otherO++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Intersect ?\n\t\t\t\t\t\tif (rootOther[otherO].intersect (localVertices[i], localVerticesOther[o][j], 0xffffffff, (otherO == o)?j:0xffffffff))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Continue ?\n\t\t\t\t\tif (otherO==other.size())\n\t\t\t\t\t{\n\t\t\t\t\t\t// Insert new vertices\n\t\t\t\t\t\tmainCopy.Vertices.insert (mainCopy.Vertices.begin()+i, 2+otherCount, CVector());\n\n\t\t\t\t\t\t// Copy the first vertex\n\t\t\t\t\t\tmainCopy.Vertices[i] = mainCopy.Vertices[i+otherCount+2];\n\n\t\t\t\t\t\t// Copy the new vertices\n\t\t\t\t\t\tuint k;\n\t\t\t\t\t\tfor (k=0; k<otherCount; k++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint index = j+k;\n\t\t\t\t\t\t\tif (index>=otherCount)\n\t\t\t\t\t\t\t\tindex -= otherCount;\n\t\t\t\t\t\t\tmainCopy.Vertices[i+k+1] = copy[o].Vertices[index];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Copy the last one\n\t\t\t\t\t\tmainCopy.Vertices[i+otherCount+1] = copy[o].Vertices[j];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (j!=otherCount)\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// Not found ?\n\t\tif (i==thisCount)\n\t\t{\n\t\t\t// Try to link in the sub polygons\n\t\t\tuint otherToCheck;\n\t\t\tfor (otherToCheck=o+1; otherToCheck<other.size(); otherToCheck++)\n\t\t\t{\n\t\t\t\tuint otherToCheckCount = (uint)other[otherToCheck].Vertices.size();\n\t\t\t\tfor (i=0; i<otherToCheckCount; i++)\n\t\t\t\t{\n\t\t\t\t\tfor (j=0; j<otherCount; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Test this segement\n\t\t\t\t\t\tif (!rootOther[otherToCheck].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j], i, 0xffffffff))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Test each other polygons\n\t\t\t\t\t\t\tuint otherO;\n\t\t\t\t\t\t\tfor (otherO=0; otherO<other.size(); otherO++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Intersect ?\n\t\t\t\t\t\t\t\tif (rootOther[otherO].intersect (localVerticesOther[otherToCheck][i], localVerticesOther[o][j],  (otherToCheck == otherO)?i:0xffffffff,  (otherO == o)?j:0xffffffff))\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Continue ?\n\t\t\t\t\t\t\tif (otherO==other.size())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// Insert new vertices\n\t\t\t\t\t\t\t\tcopy[otherToCheck].Vertices.insert (copy[otherToCheck].Vertices.begin()+i, 2+otherCount, CVector());\n\n\t\t\t\t\t\t\t\t// Copy the first vertex\n\t\t\t\t\t\t\t\tcopy[otherToCheck].Vertices[i] = copy[otherToCheck].Vertices[i+otherCount+2];\n\n\t\t\t\t\t\t\t\t// Copy the new vertices\n\t\t\t\t\t\t\t\tuint k;\n\t\t\t\t\t\t\t\tfor (k=0; k<otherCount; k++)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuint index = j+k;\n\t\t\t\t\t\t\t\t\tif (index>=otherCount)\n\t\t\t\t\t\t\t\t\t\tindex -= otherCount;\n\t\t\t\t\t\t\t\t\tcopy[otherToCheck].Vertices[i+k+1] = copy[otherO].Vertices[index];\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Copy the last one\n\t\t\t\t\t\t\t\tcopy[otherToCheck].Vertices[i+otherCount+1] = copy[otherO].Vertices[j];\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (j!=otherCount)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (i!=otherToCheckCount)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (otherToCheck==other.size())\n\t\t\t{\n\t\t\t\t// Not ok\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Ok\n\t*this = mainCopy;\n\treturn true;\n}\n\n// ***************************************************************************\n\n\n//====================================//\n//\t\tCPolygon2d implementation     //\n//====================================//\n\n\n\n// ***************************************************************************\nCPolygon2D::CPolygon2D(const CPolygon &src, const CMatrix &projMat)\n{\n\tfromPolygon(src, projMat);\n}\n\n// ***************************************************************************\nvoid CPolygon2D::fromPolygon(const CPolygon &src, const CMatrix &projMat /*=CMatrix::Identity*/)\n{\n\tuint size = (uint)src.Vertices.size();\n\tVertices.resize(size);\n\tfor (uint k = 0; k < size; ++k)\n\t{\n\t\tCVector proj = projMat * src.Vertices[k];\n\t\tVertices[k].set(proj.x, proj.y);\n\t}\n}\n\n// ***************************************************************************\nbool\t\tCPolygon2D::isConvex()\n{\n\tbool Front  = true, Back = false;\n\t// we apply a dummy algo for now : check whether every vertex is in the same side\n\t// of every plane defined by a segment of this poly\n\tuint numVerts = (uint)Vertices.size();\n\tif (numVerts < 3) return true;\n\tCVector\t\tsegStart, segEnd;\n\tCPlane\t\tclipPlane;\n\tfor (TVec2fVect::const_iterator it = Vertices.begin(); it != Vertices.end(); ++it)\n\t{\n\t\tsegStart.set(it->x, it->y, 0);\t          // segment start\n\t\tsegEnd.set((it + 1)->x, (it + 1)->y, 0);  // segment end\n\t\tfloat n = (segStart - segEnd).norm();     // segment norm\n\t\tif (n != 0)\n\t\t{\n\t\t\tclipPlane.make(segStart, segEnd, (n > 10 ? n : 10) * CVector::K + segStart); // make a plane, with this segment and the poly normal\n\t\t\t// check each other vertices against this plane\n\t\t\tfor (TVec2fVect::const_iterator it2 = Vertices.begin(); it2 != Vertices.end(); ++it2)\n\t\t\t{\n\t\t\t\tif (it2 != it && it2 != (it + 1)) // the vertices must not be part of the test plane (because of imprecision)\n\t\t\t\t{\n\n\t\t\t\t\tfloat dist  = clipPlane * CVector(it2->x, it2-> y, 0);\n\t\t\t\t\tif (dist != 0) // midlle pos\n\t\t\t\t\t{\n\t\t\t\t\t\tif (dist > 0) Front = true; else Back = true;\n\t\t\t\t\t\tif (Front && Back) return false; // there are both front end back vertices -> failure\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n// ***************************************************************************\n\nvoid\t\tCPolygon2D::buildConvexHull(CPolygon2D &dest) const\n{\n\tnlassert(&dest != this);\n\n\tif (this->Vertices.size() == 3) // with 3 points it is always convex\n\t{\n\t\tdest = *this;\n\t\treturn;\n\t}\n\tuint k, l;\n\tuint numVerts = (uint)Vertices.size();\n\tCVector2f p, curr, prev;\n\tuint      pIndex, p1Index, p2Index, pCurr, pPrev;\n\t// this is not optimized, but not used in realtime.. =)\n\tnlassert(numVerts >= 3);\n\tdest.Vertices.clear();\n\n\ttypedef std::set<uint> TIndexSet;\n\tTIndexSet leftIndex;\n\tfor (k = 0; k < Vertices.size(); ++k)\n\t{\n\t\tleftIndex.insert(k);\n\t}\n\n\n\t// 1) find the highest point p of the set. We are sure it belongs to the hull\n\tpIndex = 0;\n\tp = Vertices[0];\n\tfor (k = 1; k < numVerts; ++k)\n\t{\n\t\tif (Vertices[k].y < p.y)\n\t\t{\n\t\t\tpIndex = k;\n\t\t\tp = Vertices[k];\n\t\t}\n\t}\n\n\tleftIndex.erase(pIndex);\n\n\n\tfloat bestCP = 1.1f;\n\tp1Index = p2Index = pIndex;\n\n\tfor (k = 0; k < numVerts; ++k)\n\t{\n\t\tif (k != pIndex)\n\t\t{\n\t\t\tfor (l = 0; l < numVerts; ++l)\n\t\t\t{\n\t\t\t\tif (l != pIndex && l != k)\n\t\t\t\t{\n\t\t\t\t\tCVector2f seg1 = (Vertices[l] - p).normed();\n\t\t\t\t\tCVector2f seg2 = (Vertices[k] - p).normed();\n\n\t\t\t\t\t//CVector cp = CVector(seg1.x, seg1.y, 0) ^ CVector(seg2.x, seg2.y, 0);\n\t\t\t\t\t//float n = fabsf(cp.z);\n\t\t\t\t\tfloat n = seg1 * seg2;\n\t\t\t\t\tif (n < bestCP)\n\t\t\t\t\t{\n\t\t\t\t\t\tp1Index = l;\n\t\t\t\t\t\tp2Index = k;\n\t\t\t\t\t\tbestCP  = n;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\tleftIndex.erase(p2Index);\n\n\n\n\t// start from the given triplet, and complete the poly until we reach the first point\n\tpCurr = p2Index;\n\tpPrev = pIndex;\n\n\tcurr = Vertices[pCurr];\n\tprev = Vertices[pPrev];\n\n\t// create the first triplet vertices\n\tdest.Vertices.push_back(Vertices[p1Index]);\n\tdest.Vertices.push_back(prev);\n\tdest.Vertices.push_back(curr);\n\n\tuint step = 0;\n\n\tfor(;;)\n\t{\n\t\tbestCP = 1.1f;\n\t\tCVector2f seg2 = (prev - curr).normed();\n\t\tTIndexSet::iterator bestIt = leftIndex.end();\n\t\tfor (TIndexSet::iterator it =  leftIndex.begin(); it != leftIndex.end(); ++it)\n\t\t{\n\t\t\tif (step == 0 && *it == p1Index) continue;\n\t\t\tCVector2f seg1 = (Vertices[*it] - curr).normed();\n\t\t\tfloat n = seg1 * seg2;\n\t\t\tif (n < bestCP)\n\t\t\t{\n\t\t\t\tbestCP = n;\n\t\t\t\tbestIt = it;\n\t\t\t}\n\t\t}\n\n\t\tnlassert(bestIt != leftIndex.end());\n\t\tif (*bestIt == p1Index)\n\t\t{\n\t\t\treturn; // if we reach the start point we have finished\n\t\t}\n\t\tprev = curr;\n\t\tcurr = Vertices[*bestIt];\n\t\tpPrev = pCurr;\n\t\tpCurr = *bestIt;\n\t\t// add new point to the destination\n\t\tdest.Vertices.push_back(curr);\n\t\t++step;\n\t\tleftIndex.erase(bestIt);\n\t}\n}\n\n// ***************************************************************************\n\n\nvoid CPolygon2D::serial(NLMISC::IStream &f) throw(NLMISC::EStream)\n{\n\t(void)f.serialVersion(0);\n\tf.serialCont(Vertices);\n}\n\n// ***************************************************************************\n/// get the best triplet of vector. e.g the triplet that has the best surface\nvoid\t\tCPolygon2D::getBestTriplet(uint &index0, uint &index1, uint &index2)\n{\n\tnlassert(Vertices.size() >= 3);\n\tuint i, j, k;\n\tfloat bestArea = 0.f;\n\tconst uint numVerts = (uint)Vertices.size();\n\tfor (i = 0; i < numVerts; ++i)\n\t{\n\t\tfor (j = 0; j < numVerts; ++j)\n\t\t{\n\t\t\tif (i != j)\n\t\t\t{\n\t\t\t\tfor (k = 0; k < numVerts; ++k)\n\t\t\t\t{\n\t\t\t\t\tif (k != i && k != j)\n\t\t\t\t\t{\n\t\t\t\t\t\tCVector2f v0 = Vertices[j] - Vertices[i];\n\t\t\t\t\t\tCVector2f v1 = Vertices[k] - Vertices[i];\n\t\t\t\t\t\tfloat area = fabsf((CVector(v0.x, v0.y, 0) ^ CVector(v1.x, v1.y, 0)).norm());\n\t\t\t\t\t\tif (area > bestArea)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tbestArea = area;\n\t\t\t\t\t\t\tindex0 = i;\n\t\t\t\t\t\t\tindex1 = j;\n\t\t\t\t\t\t\tindex2 = k;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/// ***************************************************************************************\n// scan a an edge of a poly and write it into a table\nstatic void ScanEdge(CPolygon2D::TRasterVect &outputVect, sint topY, const CVector2f &v1, const CVector2f &v2, bool rightEdge = true)\n{\n\t const uint rol16 = 65536;\n\t sint ceilY1 = (sint) ceilf(v1.y);\n\t sint height;\n\t float deltaX, deltaY;\n\t float fInverseSlope;\n\t sint  iInverseSlope, iPosX;\n\n\t // check whether this segment gives a contribution to the final poly\n\t height = (sint) (ceilf(v2.y) - ceilY1);\n\t if (height <= 0) return;\n\n\t // compute slope\n\t deltaY = v2.y - v1.y;\n\t deltaX = v2.x - v1.x;\n\t fInverseSlope = deltaX / deltaY;\n\n\n\t CPolygon2D::TRasterVect::iterator  outputIt = outputVect.begin() + (ceilY1 - topY);\n\n\t // slope with ints\n\t iInverseSlope = (sint) (rol16 * fInverseSlope);\n\n\t // sub-pixel accuracy\n\t iPosX = (int) (rol16 * (v1.x + fInverseSlope * (ceilY1 - v1.y)));\n\n\t const CPolygon2D::TRasterVect::iterator endIt = outputIt + height;\n\t if (rightEdge)\n\t {\n\t\t do\n\t\t {\n\t\t   outputIt->second =  iPosX >> 16;\n\t\t   iPosX += iInverseSlope;\n\t\t   ++outputIt;\n\t\t }\n\t\t while (outputIt != endIt);\n\t }\n\t else\n\t {\n\t\t iPosX += (rol16 - 1);\n\t\t do\n\t\t {\n\t\t   outputIt->first =  iPosX >> 16;\n\t\t   iPosX += iInverseSlope;\n\t\t   ++outputIt;\n\t\t }\n\t\t while (outputIt != endIt);\n\t }\n}\n\n\n// *******************************************************************************\n// This function alow to cycle forward through a vertex vector like if it was a circular list\nstatic inline CPolygon2D::TVec2fVect::const_iterator Next(const CPolygon2D::TVec2fVect::const_iterator &it, const CPolygon2D::TVec2fVect &cont)\n{\n\tnlassert(cont.size() != 0);\n\tif ((it + 1) == cont.end()) return cont.begin();\n\treturn (it + 1);\n}\n\n\n// *******************************************************************************\n// This function alow to cycle backward through a (non null) vertex vector like if it was a circular list\nstatic inline CPolygon2D::TVec2fVect::const_iterator Prev(const CPolygon2D::TVec2fVect::const_iterator &it, const CPolygon2D::TVec2fVect &cont)\n{\n\tnlassert(cont.size() != 0);\n\tif (it == cont.begin()) return cont.end() - 1;\n\treturn (it - 1);\n}\n\n\n// *******************************************************************************\nbool CPolygon2D::isCCWOriented() const\n{\n\tconst TVec2fVect &V = Vertices;\n\tnlassert(Vertices.size() >= 3);\n\t// compute highest and lowest pos of the poly\n\tfloat fHighest = V[0].y;\n\tfloat fLowest = fHighest;\n\t// iterators to the highest and lowest vertex\n\tTVec2fVect::const_iterator it = V.begin() ;\n\tconst TVec2fVect::const_iterator endIt = V.end();\n\tTVec2fVect::const_iterator pHighest = V.begin();\n\tdo\n\t{\n\t\tif (it->y < fHighest)\n\t\t{\n\t\t\tfHighest = it->y;\n\t\t\tpHighest = it;\n\t\t}\n\t\tfLowest = std::max(fLowest, it->y);\n\t\t++it;\n\t}\n\twhile (it != endIt);\n\t// we seek this vertex\n\tTVec2fVect::const_iterator pHighestRight = pHighest;\n\tif (fLowest == fHighest)\n\t{\n\t\t// special case : degenerate poly\n\t\twhile (pHighestRight->x == pHighest->x)\n\t\t{\n\t\t\tpHighestRight = Next(pHighestRight, V);\n\t\t\tif (pHighestRight == pHighest) return false; // the poly is reduced to a point, returns an abritrary value\n\t\t}\n\t\treturn pHighest->x <= pHighestRight->x;\n\t}\n\t// iterator to the first vertex that has an y different from the top vertex\n\twhile (Next(pHighestRight, V)->y == fHighest)\n\t{\n\t\tpHighestRight = Next(pHighestRight, V);\n\t}\n\n\t// iterator to the first vertex after pHighestRight, that has the same y than the highest vertex\n\tTVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);\n\t// seek the vertex\n\twhile (pHighestLeft->y != fHighest)\n\t{\n\t\tpHighestLeft = Next(pHighestLeft, V);\n\t}\n\tTVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);\n\t// we need to get the orientation of the polygon\n\t// There are 2 case : flat, and non-flat top\n\t// check for flat top\n\tif (pHighestLeft->x != pHighestRight->x)\n\t{\n\t\t// compare right and left side\n\t\treturn pHighestLeft->x <= pHighestRight->x;\n\t}\n\t// The top of the poly is sharp\n\t// We perform a cross product of the 2 highest vect to get its orientation\n\t float deltaXN = Next(pHighestRight, V)->x - pHighestRight->x;\n\t float deltaYN = Next(pHighestRight, V)->y - pHighestRight->y;\n\t float deltaXP = pPrevHighestLeft->x - pHighestLeft->x;\n\t float deltaYP = pPrevHighestLeft->y - pHighestLeft->y;\n\t return (deltaXN * deltaYP - deltaYN * deltaXP) >= 0;\n}\n\n// *******************************************************************************\nvoid\tCPolygon2D::computeBorders(TRasterVect &borders, sint &highestY) const\n{\n\t#ifdef NL_DEBUG\n\t\tcheckValidBorders();\n\t#endif\n\t// an 'alias' to the vertices\n\tconst TVec2fVect &V = Vertices;\n\tif (Vertices.size() < 3)\n\t{\n\t\tborders.clear();\n\t\treturn;\n\t}\n\tbool    ccw;  // set to true when it has a counter clock wise orientation\n\n\t// compute highest and lowest pos of the poly\n\tfloat fHighest = V[0].y;\n\tfloat fLowest  = fHighest;\n\n\t// iterators to the thighest and lowest vertex\n\tTVec2fVect::const_iterator pLowest = V.begin(), pHighest = V.begin();\n\tTVec2fVect::const_iterator it = V.begin() ;\n\tconst TVec2fVect::const_iterator endIt = V.end();\n\tdo\n\t{\n\t\tif (it->y > fLowest)\n\t\t{\n\t\t\tfLowest = it->y;\n\t\t\tpLowest = it;\n\t\t}\n\t\telse\n\t\tif (it->y < fHighest)\n\t\t{\n\t\t\tfHighest = it->y;\n\t\t\tpHighest = it;\n\t\t}\n\t\t++it;\n\t}\n\twhile (it != endIt);\n\n\n\tsint iHighest = (sint) ceilf(fHighest) ;\n\tsint iLowest  = (sint) ceilf(fLowest) ;\n\n\thighestY = iHighest;\n\n\n\t/// check poly height, and discard null height\n\tuint polyHeight = iLowest - iHighest;\n\tif (polyHeight <= 0)\n\t{\n\t\tborders.clear();\n\t\treturn;\n\t}\n\n\tborders.resize(polyHeight);\n\n\t// iterator to the first vertex that has an y different from the top vertex\n\tTVec2fVect::const_iterator pHighestRight = pHighest;\n\t// we seek this vertex\n\twhile (Next(pHighestRight, V)->y == fHighest)\n\t{\n\t\tpHighestRight = Next(pHighestRight, V);\n\t}\n\n\t// iterator to the first vertex after pHighestRight, that has the same y than the highest vertex\n\tTVec2fVect::const_iterator pHighestLeft = Next(pHighestRight, V);\n\t// seek the vertex\n\twhile (pHighestLeft->y != fHighest)\n\t{\n\t\tpHighestLeft = Next(pHighestLeft, V);\n\t}\n\n\tTVec2fVect::const_iterator pPrevHighestLeft = Prev(pHighestLeft, V);\n\n\t// we need to get the orientation of the polygon\n\t// There are 2 case : flat, and non-flat top\n\n\t// check for flat top\n\tif (pHighestLeft->x != pHighestRight->x)\n\t{\n\t\t// compare right and left side\n\t\tif (pHighestLeft->x > pHighestRight->x)\n\t\t{\n\t\t\tccw = true;  // the list is CCW oriented\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tccw = false; // the list is CW oriented\n\t\t}\n\t}\n\telse\n\t{\n\t\t// The top of the poly is sharp\n\t\t// We perform a cross product of the 2 highest vect to get its orientation\n\n\t\t const float deltaXN = Next(pHighestRight, V)->x - pHighestRight->x;\n\t\t const float deltaYN = Next(pHighestRight, V)->y - pHighestRight->y;\n\t\t const float deltaXP = pPrevHighestLeft->x - pHighestLeft->x;\n\t\t const float deltaYP = pPrevHighestLeft->y - pHighestLeft->y;\n\t\t if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)\n\t\t {\n\t\t\tccw = true;  // the list is CCW oriented\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t }\n\t\t else\n\t\t {\n\t\t\tccw = false; // the list is CW oriented\n\t\t }\n\t}\n\n\n\t// compute borders\n\tTVec2fVect::const_iterator currV, nextV; // current and next vertex\n\tif (!ccw) // clock wise order ?\n\t{\n\t\tcurrV = pHighestRight ;\n\t\t// compute right edge from top to bottom\n\t\tdo\n\t\t{\n\t\t\tnextV = Next(currV, V);\n\t\t\tScanEdge(borders, iHighest, *currV, *nextV, true);\n            currV = nextV;\n\t\t}\n\t\twhile (currV != pLowest); // repeat until we reach the bottom vertex\n\n\t\t// compute left edge from bottom to top\n\t\tdo\n\t\t{\n   \t\t\tnextV = Next(currV, V);\n\t\t\tScanEdge(borders, iHighest, *nextV, *currV, false);\n\t\t\tcurrV = nextV;\n\t\t}\n\t\twhile (currV != pHighestLeft);\n\t}\n\telse // ccw order\n\t{\n\t\tcurrV = pHighestLeft;\n\t\t// compute left edge from top to bottom\n\t\tdo\n\t\t{\n\t\t\tnextV = Next(currV, V);\n\t\t\tScanEdge(borders, iHighest, *currV, *nextV, false) ;\n\t\t\tcurrV = nextV;\n\t\t}\n\t\twhile (currV != pLowest) ;\n\n\t\t// compute right edge from bottom to top\n\t\tdo\n\t\t{\n\t\t\tnextV = Next(currV, V);\n\t\t\tScanEdge(borders, iHighest, *nextV, *currV, true);\n\t\t\tcurrV = nextV;\n\t\t}\n\t\twhile (currV != pHighestRight)  ;\n\t}\n}\n\n//=========================================================================\n// scan outer right edge of a poly\nstatic void ScanOuterEdgeRight(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY)\n{\n\tCPolygon2D::TRaster *currRaster;\n\tfloat deltaX, deltaY;\n\tfloat inverseSlope;\n\tsint32  iInverseSlope, iposx;\n\tsint  height;\n\tdeltaX = x2 - x1;\n\theight = (sint) (ceilf(y2) - floorf(y1)) ;\n\tif (height <= 0) return;\n\tif (deltaX >= 0.f)\n\t{\n\t\tif (height == 1)\n\t\t{\n\t\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\t\tcurrRaster->second = std::max((sint) floorf(x2), currRaster->second);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdeltaY = y2 - y1;\n\t\t\tif(deltaY)\n\t\t\t\tinverseSlope = deltaX / deltaY;\n\t\t\telse\n\t\t\t\tinverseSlope = 0;\n\t\t\tiInverseSlope = (sint32) (65536.0 * inverseSlope);\n\t\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\t\tiposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy\n\t\t\tif (ceilf(y1) == y1)\n\t\t\t{\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t}\n\t\t\tdo\n\t\t\t{\n\t\t\t\tcurrRaster->second = std::max((sint) (iposx >> 16), currRaster->second);\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t}\n\t\t\twhile (height != 1);\n\t\t\t// correction for last line\n\t\t\tcurrRaster->second = std::max((sint) floorf(x2), currRaster->second);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdeltaY = y2 - y1;\n\t\tif(deltaY)\n\t\t\tinverseSlope = deltaX / deltaY;\n\t\telse\n\t\t\tinverseSlope = 0;\n\t\tiInverseSlope = (sint32) (65536.0 * inverseSlope);\n\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\tcurrRaster->second = std::max((sint) floorf(x1), currRaster->second);\n\t\t++ currRaster;\n\t\tiposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy\n\t\tif (ceilf(y1) == y1)\n\t\t{\n\t\t\tiposx += iInverseSlope;\n\t\t}\n\t\twhile (--height)\n\t\t{\n\t\t\tcurrRaster->second = std::max((sint) (iposx >> 16), currRaster->second);\n\t\t\tiposx += iInverseSlope;\n\t\t\t++ currRaster;\n\t\t}\n\t}\n}\n\n//=========================================================================\n// scan outer left edge of a poly\nstatic void ScanOuterEdgeLeft(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY)\n{\n\tCPolygon2D::TRaster *currRaster;\n\tfloat deltaX, deltaY;\n\tfloat inverseSlope;\n\tsint32   iInverseSlope, iposx;\n\tsint  height;\n\tdeltaX = x2 - x1;\n\theight = (sint) (ceilf(y2) - floorf(y1)) ;\n\tif (height <= 0) return;\n\tif (deltaX < 0.f)\n\t{\n\t\tif (height == 1)\n\t\t{\n\t\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\t\tcurrRaster->first = std::min((sint) floorf(x2), currRaster->first);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tdeltaY = y2 - y1;\n\t\t\tif(deltaY)\n\t\t\t\tinverseSlope = deltaX / deltaY;\n\t\t\telse\n\t\t\t\tinverseSlope = 0;\n\t\t\tiInverseSlope = (sint32) (65536.0 * inverseSlope);\n\t\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\t\tiposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy\n\t\t\tif (ceilf(y1) == y1)\n\t\t\t{\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t}\n\t\t\tdo\n\t\t\t{\n\t\t\t\tcurrRaster->first = std::min((sint) (iposx >> 16), currRaster->first);\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t}\n\t\t\twhile (height != 1);\n\t\t\t// correction for last line\n\t\t\tcurrRaster->first = std::min((sint) floorf(x2), currRaster->first);\n\t\t}\n\t}\n\telse\n\t{\n\t\tdeltaY = y2 - y1;\n\t\tif(deltaY)\n\t\t\tinverseSlope = deltaX / deltaY;\n\t\telse\n\t\t\tinverseSlope = 0;\n\t\tiInverseSlope = (sint32) (65536.0 * inverseSlope);\n\t\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t\tcurrRaster->first = std::min((sint) floorf(x1), currRaster->first);\n\t\t++ currRaster;\n\t\tiposx = (sint32) (65536.0 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy\n\t\tif (ceilf(y1) == y1)\n\t\t{\n\t\t\tiposx += iInverseSlope;\n\t\t}\n\t\twhile (--height)\n\t\t{\n\t\t\tcurrRaster->first = std::min((sint) (iposx >> 16), currRaster->first);\n\t\t\tiposx += iInverseSlope;\n\t\t\t++ currRaster;\n\t\t}\n\t}\n}\n\n\n// *******************************************************************************\nvoid CPolygon2D::computeOuterBorders(TRasterVect &borders, sint &minimumY) const\n{\n\t#ifdef NL_DEBUG\n\t\tcheckValidBorders();\n\t#endif\n\tborders.clear();\n\t// NB : this version is not much optimized, because of the min/max test\n\t// during rasterization.\n\t// TODO : optimize if needed ...\n\n\tif (Vertices.empty())\n\t{\n\t\tminimumY = -1;\n\t\treturn;\n\t}\n\tconst CVector2f *first = &Vertices[0];\n\tconst CVector2f *last  = first + Vertices.size();\n\n\tconst CVector2f *curr = first, *next, *plowest ,*phighest;\n\tconst CVector2f *pHighestRight, *pHighestRightNext, *pHighestLeft;\n\tconst CVector2f *pPrevHighestLeft;\n\tdouble\t\t    deltaXN, deltaYN, deltaXP, deltaYP;\n\tbool\t\t    ccw;  // true if CCW oriented\n\tsint            polyHeight;\n\tsint            highest, lowest;\n\n\tfloat fright   = curr->x;\n\tfloat fleft    = curr->x;\n\tfloat fhighest = curr->y;\n\tfloat flowest  = curr->y;\n\tplowest = phighest = curr;\n\n\t// compute highest and lowest pos of the poly\n\tdo\n\t{\n\t\tfright = std::max(fright, curr->x);\n\t\tfleft  = std::min(fleft, curr->x);\n\t\tif (curr->y > flowest)\n\t\t{\n\t\t\tflowest = curr->y;\n\t\t\tplowest = curr;\n\t\t}\n\t\tif (curr->y < fhighest)\n\t\t{\n\t\t\tfhighest = curr->y;\n\t\t\tphighest = curr;\n\t\t}\n\t\t++curr;\n\t}\n\twhile (curr != last);\n\n\n\thighest = (sint) floorf(fhighest);\n\tlowest = (sint) floorf(flowest);\n\n\tpolyHeight = lowest - highest + 1;\n\tnlassert(polyHeight > 0);\n\n\t// make room for rasters\n\tborders.resize(polyHeight);\n\t// fill with xmin / xman\n\tsint ileft = (sint) floorf(fleft);\n\tsint iright = (sint) ceilf(fright);\n\tminimumY = highest;\n\tif (flowest == fhighest) // special case : degenerate poly\n\t{\n\n\t\tborders.resize(1);\n\t\tborders.front().first =  ileft;\n\t\tborders.front().second =  ileft;\n\t\treturn;\n\t}\n\t//\n\tfor(TRasterVect::iterator it = borders.begin(); it != borders.end(); ++it)\n\t{\n\t\tit->second = ileft;\n\t\tit->first = iright;\n\t}\n\n\n\n\tpHighestRight = phighest;\n\tfor (;;)\n\t{\n\t\tpHighestRightNext  = pHighestRight + 1;\n\t\tif (pHighestRightNext == last) pHighestRightNext = first;\n\t\tif (pHighestRightNext->y != pHighestRight->y) break;\n\t\tpHighestRight = pHighestRightNext;\n\t}\n\n\tpPrevHighestLeft = pHighestRight;\n\tpHighestLeft = pHighestRight;\n\t++pHighestLeft;\n\tif (pHighestLeft == last) pHighestLeft = first;\n\n\twhile (pHighestLeft->y != fhighest)\n\t{\n\t\tpPrevHighestLeft = pHighestLeft;\n\t\t++pHighestLeft;\n\t\tif (pHighestLeft == last) pHighestLeft = first;\n\t}\n\n\n\t// we need to get the orientation of the polygon\n\t// There are 2 case : flat, and non-flat top\n\n\t// check for flat top\n\tif (pHighestLeft->x != pHighestRight->x)\n\t{\n\t\t// compare right and left side\n\t\tif (pHighestLeft->x > pHighestRight->x)\n\t\t{\n\t\t\tccw = true;  // the list is CCW oriented\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tccw = false; // the list is CW oriented\n\t\t}\n\t}\n\telse\n\t{\n\t\tpHighestRightNext = pHighestRight + 1;\n\t\tif (pHighestRightNext == last) pHighestRightNext = first;\n\t\t deltaXN = pHighestRightNext->x - pHighestRight->x;\n\t\t deltaYN = pHighestRightNext->y - pHighestRight->y;\n\t\t deltaXP = pPrevHighestLeft->x - pHighestLeft->x;\n\t\t deltaYP = pPrevHighestLeft->y - pHighestLeft->y;\n\t\t if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)\n\t\t {\n\t\t\tccw = true;\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t }\n\t\t else\n\t\t {\n\t\t\tccw = false;\n\t\t }\n\t}\n\n\tif (!ccw)\n\t{\n\t\t// clock wise oriented list\n\t\tcurr = pHighestRight;\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanOuterEdgeRight(&borders[0], curr->x, curr->y, next->x, next->y, minimumY);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != plowest);\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanOuterEdgeLeft(&borders[0], next->x, next->y, curr->x, curr->y, minimumY);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != pHighestLeft);\n\t}\n\telse\n\t{\n\t\t// ccw oriented\n\t\tcurr = pHighestLeft;\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanOuterEdgeLeft(&borders[0], curr->x, curr->y, next->x, next->y, minimumY);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != plowest);\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanOuterEdgeRight(&borders[0], next->x, next->y, curr->x, curr->y, minimumY);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != pHighestRight);\n\t}\n}\n\n\n//=========================================================================\n// scan inner right edge of a poly\nstatic void ScanInnerEdge(CPolygon2D::TRaster *r, float x1, float y1, float x2, float y2, sint minY, bool rightEdge)\n{\n\tconst uint rol16 = 65536;\n\tCPolygon2D::TRaster *currRaster;\n\tfloat deltaX, deltaY;\n\tfloat inverseSlope;\n\tsint32  iInverseSlope, iposx;\n\tsint  height;\n\tdeltaX = x2 - x1;\n\theight = (sint) (ceilf(y2) - floorf(y1));\n\tif (height <= 0) return;\n\tdeltaY = y2 - y1;\n\tif(deltaY)\n\t\tinverseSlope = deltaX / deltaY;\n\telse\n\t\tinverseSlope = 0;\n\tiInverseSlope = (sint32) (rol16 * inverseSlope);\n\tcurrRaster = r + ((sint) floorf(y1) - minY);\n\t//\n\tiposx = (sint32) (rol16 * (x1 + inverseSlope * (ceilf(y1) - y1))); // sub-pixel accuracy\n\tif (rightEdge)\n\t{\n\t\tiposx -= rol16 - 1;\n\t\tif (deltaX >= 0.f)\n\t\t{\n\t\t\t// start of segment\n\t\t\tif (floorf(y1) != y1)\n\t\t\t{\n\t\t\t\tcurrRaster->second = std::min((sint) floorf(x1) - 1, currRaster->second);\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t\tif (height == 0) return;\n\t\t\t}\n\t\t\tdo\n\t\t\t{\n\t\t\t\tcurrRaster->second = std::min((sint) (iposx >> 16), currRaster->second);\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\t++ currRaster;\n\t\t\t}\n\t\t\twhile (--height);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// start of segment\n\t\t\tif (floorf(y1) != y1)\n\t\t\t{\n\t\t\t\tcurrRaster->second = std::min((sint) (iposx >> 16), currRaster->second);\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t\tif (height == 0) return;\n\t\t\t}\n\t\t\twhile (--height)\n\t\t\t{\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\tcurrRaster->second = std::min((sint) (iposx >> 16), currRaster->second);\n\t\t\t\t++ currRaster;\n\t\t\t}\n\t\t\t// fill bottom of segment\n\t\t\tcurrRaster->second = std::min((sint) floorf(x2) - 1, currRaster->second);\n\t\t}\n\t}\n\telse\n\t{\n\t\tiposx += rol16 - 1;\n\t\tif (deltaX < 0.f)\n\t\t{\n\t\t\t// start of segment\n\t\t\tif (floorf(y1) != y1)\n\t\t\t{\n\t\t\t\tcurrRaster->first = std::max((sint) ceilf(x1), currRaster->first);\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t\tif (height == 0) return;\n\t\t\t}\n\t\t\tdo\n\t\t\t{\n\t\t\t\tcurrRaster->first = std::max((sint) (iposx >> 16), currRaster->first);\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\t++ currRaster;\n\t\t\t}\n\t\t\twhile (--height);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// start of segment\n\t\t\tif (floorf(y1) != y1)\n\t\t\t{\n\t\t\t\tcurrRaster->first = std::max((sint) (iposx >> 16), currRaster->first);\n\t\t\t\t++ currRaster;\n\t\t\t\t-- height;\n\t\t\t\tif (height == 0) return;\n\t\t\t}\n\t\t\twhile (--height)\n\t\t\t{\n\t\t\t\tiposx += iInverseSlope;\n\t\t\t\tcurrRaster->first = std::max((sint) (iposx >> 16), currRaster->first);\n\t\t\t\t++ currRaster;\n\t\t\t}\n\t\t\t// fill bottom of segment\n\t\t\tcurrRaster->first = std::max((sint) ceilf(x2), currRaster->first);\n\t\t}\n\t}\n}\n\n// *******************************************************************************\nvoid CPolygon2D::computeInnerBorders(TRasterVect &borders, sint &minimumY) const\n{\n\t#ifdef NL_DEBUG\n\t\tcheckValidBorders();\n\t#endif\n\tborders.clear();\n\tif (Vertices.empty())\n\t{\n\t\tminimumY = -1;\n\t\treturn;\n\t}\n\tconst CVector2f *first = &Vertices[0];\n\tconst CVector2f *last  = first + Vertices.size();\n\n\tconst CVector2f *curr = first, *next, *plowest ,*phighest;\n\tconst CVector2f *pHighestRight, *pHighestRightNext, *pHighestLeft;\n\tconst CVector2f *pPrevHighestLeft;\n\tdouble\t\t    deltaXN, deltaYN, deltaXP, deltaYP;\n\tbool\t\t    ccw;  // true if CCW oriented\n\tsint            polyHeight;\n\tsint            highest, lowest;\n\n\tfloat fright   = curr->x;\n\tfloat fleft    = curr->x;\n\tfloat fhighest = curr->y;\n\tfloat flowest  = curr->y;\n\tplowest = phighest = curr;\n\n\t// compute highest (with lowest y) and lowest (with highest y) points of the poly\n\tdo\n\t{\n\t\tfright = std::max(fright, curr->x);\n\t\tfleft  = std::min(fleft, curr->x);\n\t\tif (curr->y > flowest)\n\t\t{\n\t\t\tflowest = curr->y;\n\t\t\tplowest = curr;\n\t\t}\n\t\tif (curr->y < fhighest)\n\t\t{\n\t\t\tfhighest = curr->y;\n\t\t\tphighest = curr;\n\t\t}\n\t\t++curr;\n\t}\n\twhile (curr != last);\n\tif (flowest == fhighest)\n\t{\n\t\tminimumY = -1;\n\t\treturn;\n\t}\n\thighest = (sint) floorf(fhighest);\n\tlowest = (sint) ceilf(flowest);\n\n\tpolyHeight = lowest - highest;\n\tminimumY = highest;\n\tif (polyHeight == 0)\n\t{\n\t\tminimumY = -1;\n\t\treturn;\n\t}\n\t// make room for rasters\n\tborders.resize(polyHeight);\n\t// fill with xmin / xman\n\tsint ileft = (sint) floorf(fleft) - 1;\n\tsint iright = (sint) ceilf(fright);\n\tfor(TRasterVect::iterator it = borders.begin(); it != borders.end(); ++it)\n\t{\n\t\tit->second = iright;\n\t\tit->first = ileft;\n\t}\n\tpHighestRight = phighest;\n\tfor (;;)\n\t{\n\t\tpHighestRightNext  = pHighestRight + 1;\n\t\tif (pHighestRightNext == last) pHighestRightNext = first;\n\t\tif (pHighestRightNext->y != pHighestRight->y) break;\n\t\tpHighestRight = pHighestRightNext;\n\t}\n\n\tpPrevHighestLeft = pHighestRight;\n\tpHighestLeft = pHighestRight;\n\t++pHighestLeft;\n\tif (pHighestLeft == last) pHighestLeft = first;\n\n\twhile (pHighestLeft->y != fhighest)\n\t{\n\t\tpPrevHighestLeft = pHighestLeft;\n\t\t++pHighestLeft;\n\t\tif (pHighestLeft == last) pHighestLeft = first;\n\t}\n\n\n\t// we need to get the orientation of the polygon\n\t// There are 2 case : flat, and non-flat top\n\n\t// check for flat top\n\tif (pHighestLeft->x != pHighestRight->x)\n\t{\n\t\t// compare right and left side\n\t\tif (pHighestLeft->x > pHighestRight->x)\n\t\t{\n\t\t\tccw = true;  // the list is CCW oriented\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tccw = false; // the list is CW oriented\n\t\t}\n\t}\n\telse\n\t{\n\t\tpHighestRightNext = pHighestRight + 1;\n\t\tif (pHighestRightNext == last) pHighestRightNext = first;\n\t\t deltaXN = pHighestRightNext->x - pHighestRight->x;\n\t\t deltaYN = pHighestRightNext->y - pHighestRight->y;\n\t\t deltaXP = pPrevHighestLeft->x - pHighestLeft->x;\n\t\t deltaYP = pPrevHighestLeft->y - pHighestLeft->y;\n\t\t if ((deltaXN * deltaYP - deltaYN * deltaXP) < 0)\n\t\t {\n\t\t\tccw = true;\n\t\t\tstd::swap(pHighestLeft, pHighestRight);\n\t\t }\n\t\t else\n\t\t {\n\t\t\tccw = false;\n\t\t }\n\t}\n\n\tif (!ccw)\n\t{\n\t\t// cw oriented\n\t\tcurr = pHighestRight;\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanInnerEdge(&borders[0], curr->x, curr->y, next->x, next->y, minimumY, true);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != plowest);\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanInnerEdge(&borders[0], next->x, next->y, curr->x, curr->y, minimumY, false);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != pHighestLeft);\n\t}\n\telse\n\t{\n\t\t// ccw oriented\n\t\tcurr = pHighestLeft;\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanInnerEdge(&borders[0], curr->x, curr->y, next->x, next->y, minimumY, false);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != plowest);\n\t\tdo\n\t\t{\n\t\t\tnext = curr + 1;\n\t\t\tif (next == last) next = first;\n\t\t\tScanInnerEdge(&borders[0], next->x, next->y, curr->x, curr->y, minimumY, true);\n\t\t\tcurr = next;\n\t\t}\n\t\twhile (curr != pHighestRight);\n\t}\n\t// fix for top\n\tif (floorf(fhighest) != fhighest)\n\t{\n\t\tborders[0].first = 1;\n\t\tborders[0].second = 0;\n\t}\n\t// fix for bottom\n\tif (floorf(flowest) != flowest)\n\t{\n\t\tborders.back().first = 1;\n\t\tborders.back().second = 0;\n\t}\n}\n\n// *******************************************************************************\nvoid CPolygon2D::checkValidBorders() const\n{\n\tfor (uint k = 0; k < Vertices.size(); ++k)\n\t{\n\t\tnlassert(Vertices[k].x >= -32000.f); // coordinate too big !\n\t\tnlassert(Vertices[k].x < 32000.f);   // coordinate too big !\n\t\tnlassert(Vertices[k].y >= -32000.f); // coordinate too big !\n\t\tnlassert(Vertices[k].y < 32000.f);   // coordinate too big !\n\t}\n}\n\n// *******************************************************************************\n/// Sum the dot product of this poly vertices against a plane\nfloat\t\tCPolygon2D::sumDPAgainstLine(float a, float b, float c) const\n{\n\tfloat sum = 0.f;\n\tfor (uint k = 0; k < Vertices.size(); ++k)\n\t{\n\t\tconst CVector2f &p = Vertices[k];\n\t\tsum += a * p.x + b * p.y + c;\n\t}\n\treturn sum;\n}\n\n\n// *******************************************************************************\nbool  CPolygon2D::getNonNullSeg(uint &index) const\n{\n\tnlassert(Vertices.size() > 0);\n\tfloat bestLength = 0.f;\n\tsint  bestIndex = -1;\n\tfor (uint k = 0; k < Vertices.size() - 1; ++k)\n\t{\n\t\tfloat norm2 = (Vertices[k + 1] - Vertices[k]).sqrnorm();\n\t\tif ( norm2 > bestLength)\n\t\t{\n\t\t\tbestLength = norm2;\n\t\t\tbestIndex = (int) k;\n\t\t}\n\t}\n\tfloat norm2 = (Vertices[Vertices.size() - 1] - Vertices[0]).sqrnorm();\n\tif ( norm2 > bestLength)\n\t{\n\t\tindex = (uint)Vertices.size() - 1;\n\t\treturn true;\n\t}\n\n\tif (bestIndex != -1)\n\t{\n\t\tindex = bestIndex;\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n}\n\n\n// *******************************************************************************\nvoid  CPolygon2D::getLineEquation(uint index, float &a, float &b, float &c) const\n{\n\tnlassert(index < Vertices.size());\n\tconst CVector2f &v0 = getSegRef0(index);\n\tconst CVector2f &v1 = getSegRef1(index);\n\n\tNLMISC::CVector2f seg = v0 - v1;\n\ta = seg.y;\n\tb = - seg.x;\n\tc = - v0.x * a - v0.y * b;\n}\n\n// *******************************************************************************\nbool        CPolygon2D::intersect(const CPolygon2D &other) const\n{\n\tnlassert(other.Vertices.size() > 0);\n\tuint nonNullSegIndex;\n\t/// get the orientation of this poly\n\tif (getNonNullSeg(nonNullSegIndex))\n\t{\n\t\tfloat a0, b0, c0; /// contains the seg 2d equation\n\t\tgetLineEquation(nonNullSegIndex, a0, b0, c0);\n\t\tfloat orient = sumDPAgainstLine(a0, b0, c0);\n\n\t\tfor (uint k = 0; k < Vertices.size(); ++k)\n\t\t{\n\t\t\t/// don't check against a null segment\n\t\t    if ( (getSegRef0(k) - getSegRef1(k)).sqrnorm() == 0.f) continue;\n\n\t\t\t/// get the line equation of the current segment\n\t\t\tfloat a, b, c; /// contains the seg 2d equation\n\t\t\tgetLineEquation(k, a, b, c);\n\t\t\tuint l;\n\t\t\tfor (l = 0; l < other.Vertices.size(); ++l)\n\t\t\t{\n\t\t\t\tconst CVector2f &ov = other.Vertices[l];\n\t\t\t\tif ( orient * (ov.x * a + ov.y * b +c) > 0.f) break;\n\t\t\t}\n\t\t\tif (l == other.Vertices.size()) // all point on the outside\n\t\t\t{\n\t\t\t\treturn false; // outside\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\telse // this poly is just a point\n\t{\n\t\treturn other.contains(Vertices[0]);\n\t}\n}\n\n// *******************************************************************************\nbool\t\tCPolygon2D::contains(const CVector2f &p, bool hintIsConvex /*= true*/) const\n{\n\tif (hintIsConvex)\n\t{\n\t\tuint numVerts = (uint)Vertices.size();\n\t\tnlassert(numVerts >= 0.f);\n\t\tfor (uint k = 0; k < numVerts; ++k)\n\t\t{\n\t\t\tif (getSegRef0(k) != getSegRef1(k))\n\t\t\t{\n\t\t\t\tfloat a, b, c; /// contains the seg 2d equation\n\t\t\t\tgetLineEquation(k, a, b, c);\n\t\t\t\tfloat orient = a * p.x + b * p.y + c;\n\t\t\t\tfor(uint l = k + 1; l < numVerts; ++l)\n\t\t\t\t{\n\t\t\t\t\tgetLineEquation(l, a, b, c);\n\t\t\t\t\tfloat newOrient = a * p.x + b * p.y + c;\n\t\t\t\t\tif (newOrient * orient < 0.f) return false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t// the poly reduces to a point\n\t\treturn p == Vertices[0];\n\t}\n\telse\n\t{\n\t\t// concave case\n\t\tstatic std::vector<float> xInter;\n\t\txInter.clear();\n\t\tfor(uint k = 0; k < Vertices.size(); ++k)\n\t\t{\n\t\t\tconst CVector2f &p0 = getSegRef0(k);\n\t\t\tconst CVector2f &p1 = getSegRef1(k);\n\t\t\tif (p0.y == p1.y)\n\t\t\t{\n\t\t\t\tif (p.y == p0.y)\n\t\t\t\t{\n\t\t\t\t\tif ((p.x >= p0.x && p.x <= p1.x)\n\t\t\t\t\t\t|| (p.x >= p1.x && p.x <= p0.x))\n\t\t\t\t\t{\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ((p.y >= p0.y && p.y < p1.y) ||\n\t\t\t\t(p.y >= p1.y && p.y < p0.y)\n\t\t\t   )\n\t\t\t{\n\n\t\t\t\tfloat inter = p0.x + (p.y - p0.y) * (p1.x - p0.x) / (p1.y- p0.y);\n\t\t\t\txInter.push_back(inter);\n\t\t\t}\n\t\t}\n\t\tif (xInter.size() < 2) return false;\n\t\tstd::sort(xInter.begin(), xInter.end());\n\t\tfor(uint k = 0; k < xInter.size() - 1; ++k)\n\t\t{\n\t\t\tif (p.x >= xInter[k] && p.x <= xInter[k + 1])\n\t\t\t{\n\t\t\t\treturn (k & 1) == 0;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n}\n\n\n// *******************************************************************************\nCPolygon2D::CPolygon2D(const CTriangle &tri, const CMatrix &projMat)\n{\n\tVertices.resize(3);\n\tNLMISC::CVector proj[3] = { projMat * tri.V0, projMat * tri.V1, projMat * tri.V2 };\n\tVertices[0].set(proj[0].x, proj[0].y);\n\tVertices[1].set(proj[1].x, proj[1].y);\n\tVertices[2].set(proj[2].x, proj[2].y);\n}\n\n// *******************************************************************************\nvoid CPolygon2D::getBoundingRect(CVector2f &minCorner, CVector2f &maxCorner) const\n{\n\tnlassert(!Vertices.empty());\n\tminCorner = maxCorner = Vertices[0];\n\tuint numVertices = (uint)Vertices.size();\n\tfor(uint k = 0; k < numVertices; ++k)\n\t{\n\t\tminCorner.minof(minCorner, Vertices[k]);\n\t\tmaxCorner.maxof(minCorner, Vertices[k]);\n\t}\n}\n\n// *******************************************************************************\nbool operator ==(const CPolygon2D &lhs,const CPolygon2D &rhs)\n{\n\tif (lhs.Vertices.size() != rhs.Vertices.size()) return false;\n\treturn std::equal(lhs.Vertices.begin(), lhs.Vertices.end(), rhs.Vertices.begin());\n}\n\n// *******************************************************************************\nbool operator < (const CPolygon2D &lhs, const CPolygon2D &rhs)\n{\n\tif (lhs.Vertices.size() != rhs.Vertices.size()) return lhs.Vertices.size() < rhs.Vertices.size();\n\tfor(uint k = 0; k < lhs.Vertices.size(); ++k)\n\t{\n\t\tif (lhs.Vertices[k] != rhs.Vertices[k]) return lhs.Vertices[k] < rhs.Vertices[k];\n\t}\n\treturn false;\n}\n\n\n// *******************************************************************************\nstatic inline bool testSegmentIntersection(const CVector2f &a, const CVector2f &b,\n\t\t\t\t\t\t\t\t\t\t   const CVector2f &c, const CVector2f &d)\n{\n\tdouble denom = a.x * double(d.y - c.y) +\n\t\t\tb.x * double(c.y - d.y) +\n\t\t\td.x * double(b.y - a.y) +\n\t\t\tc.x * double(a.y - b.y);\n\n\tif (denom == 0) return false;\n\t//\n\tdouble num = a.x * double(d.y - c.y) +\n\t\t\t\t c.x * double(a.y - d.y) +\n\t\t\t\t d.x * double(c.y - a.y);\n\n\tif (num == 0 || (num == denom)) return false;\n\tdouble lambda = num / denom;\n\tif (lambda <= 0 || lambda >= 1) return false;\n\t//\n\tnum = - (a.x * double(c.y - b.y) +\n\t\t  b.x * double(a.y - c.y) +\n\t\t  c.x * double(b.y - a.y));\n\n\tif (num == 0 || (num == denom)) return false;\n\tlambda = num / denom;\n\tif (lambda <= 0 || lambda >= 1) return false;\n\treturn true;\n}\n\n\n// *******************************************************************************\nbool CPolygon2D::selfIntersect() const\n{\n\tif (Vertices.size() < 3) return false;\n\tuint numEdges = (uint)Vertices.size();\n\tfor(uint k = 0; k < numEdges; ++k)\n\t{\n\t\t// test intersection with all other edges that don't share a vertex with this one\n\t\tconst CVector2f &p0 = getSegRef0(k);\n\t\tconst CVector2f &p1 = getSegRef1(k);\n\t\tfor(uint l = 0; l < k; ++l)\n\t\t{\n\t\t\tconst CVector2f &v0 = getSegRef0(l);\n\t\t\tconst CVector2f &v1 = getSegRef1(l);\n\t\t\tif (v0 == p0 || v0 == p1 || v1 == p0 || v1 == p1) continue;\n\t\t\t//\n\t\t\tif (testSegmentIntersection(p0, p1, v0, v1)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\n\n} // NLMISC\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "code/nel/src/misc/progress_callback.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/progress_callback.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nfloat IProgressCallback::getCropedValue (float value) const\n{\n\tnlassert (_CropedValues.size ()>0);\n\tconst CCropedValues &values = _CropedValues.back ();\n\treturn value*(values.Max-values.Min)+values.Min;\n}\n\nIProgressCallback::IProgressCallback ()\n{\n\t_CropedValues.push_back (CCropedValues (0, 1));\n}\n\nvoid IProgressCallback::pushCropedValues (float min, float max)\n{\n\tnlassert (_CropedValues.size ()>0);\n\t//const CCropedValues &values = _CropedValues.back ();\n\t_CropedValues.push_back (CCropedValues (getCropedValue (min), getCropedValue (max)));\n}\n\nvoid IProgressCallback::popCropedValues ()\n{\n\tnlassert (_CropedValues.size ()>1);\n\t_CropedValues.pop_back ();\n}\n\nvoid IProgressCallback::progress (float /* progressValue */)\n{\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/quad.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/quad.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_quad_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/quat.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/quat.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n\nconst CQuat\t\tCQuat::Identity;\nconst CQuatD\tCQuatD::Identity;\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/reader_writer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/reader_writer.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nCReaderWriter::CReaderWriter()\n{\n\t_ReadersLevel = 0;\n}\n\nCReaderWriter::~CReaderWriter()\n{\n\t// here some checks to avoid a reader/writer still working while we flush the mutexes...\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/rect.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/rect.h\"\n#include \"nel/misc/vector_2f.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n// *********************************************************************\nvoid CRect::extend (sint32 x, sint32 y)\n{\n\tif (x<X)\n\t{\n\t\tWidth+=(uint32)(X-x);\n\t\tx=X;\n\t}\n\telse if (x>=(X+(sint32)Width))\n\t\tWidth=(uint32)(x-X+1);\n\tif (y<Y)\n\t{\n\t\tHeight+=(uint32)(Y-y);\n\t\ty=Y;\n\t}\n\telse if (y>=(Y+(sint32)Height))\n\t\tHeight=(uint32)(y-Y+1);\n}\n\n\n// *********************************************************************\nvoid CRect::setWH(sint32 x, sint32 y, uint32 width, uint32 height)\n{\n\tX=x;\n\tY=y;\n\tWidth=width;\n\tHeight=height;\n}\n\n\n// *********************************************************************\nvoid CRect::set(sint32 x0, sint32 y0, sint32 x1, sint32 y1)\n{\n\tif (x0 < x1)\n\t{\n\t\tX = x0;\n\t\tWidth = x1 - x0;\n\t}\n\telse\n\t{\n\t\tX = x1;\n\t\tWidth = y0 - y1;\n\t}\n\n\tif (y0 < y1)\n\t{\n\t\tY = y0;\n\t\tHeight = y1 - y0;\n\t}\n\telse\n\t{\n\t\tY = y1;\n\t\tHeight = y0 - y1;\n\t}\n}\n\n// *********************************************************************\nCRect::CRect (sint32 x, sint32 y, uint32 width, uint32 height)\n{\n\tsetWH(x, y, width, height);\n}\n\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/report.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/ucstring.h\"\n\n#include \"nel/misc/report.h\"\n#include \"nel/misc/path.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <windowsx.h>\n#\tinclude <winuser.h>\n#endif // NL_OS_WINDOWS\n\n#define NL_NO_DEBUG_FILES 1\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n#ifdef NL_OS_WINDOWS\nstatic HWND sendReport=NULL;\n#endif\n\n//old doesn't work on visual c++ 7.1 due to default parameter typedef bool (*TEmailFunction) (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile = \"\", bool onlyCheck = false);\ntypedef bool (*TEmailFunction) (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile, bool onlyCheck);\n\n#define DELETE_OBJECT(a) if((a)!=NULL) { DeleteObject (a); a = NULL; }\n\nstatic TEmailFunction EmailFunction = NULL;\n\nvoid setReportEmailFunction (void *emailFunction)\n{\n\tEmailFunction = (TEmailFunction)emailFunction;\n\n#ifdef NL_OS_WINDOWS\n\tif (sendReport)\n\t\tEnableWindow(sendReport, FALSE);\n#endif\n}\n\n#ifndef NL_OS_WINDOWS\n\n// GNU/Linux, do nothing\n\nvoid report ()\n{\n}\n\n#else\n\n// Windows specific version\n\nstatic string Body;\nstatic string Subject;\nstatic string AttachedFile;\n\nstatic HWND checkIgnore=NULL;\nstatic HWND debug=NULL;\nstatic HWND ignore=NULL;\nstatic HWND quit=NULL;\nstatic HWND dialog=NULL;\n\nstatic bool NeedExit;\nstatic TReportResult Result;\nstatic bool IgnoreNextTime;\nstatic bool CanSendMailReport= false;\n\nstatic bool DebugDefaultBehavior, QuitDefaultBehavior;\n\nstatic void sendEmail()\n{\n\tif (CanSendMailReport && SendMessage(sendReport, BM_GETCHECK, 0, 0) != BST_CHECKED)\n\t{\n\t\tbool res = EmailFunction (\"\", \"\", \"\", Subject, Body, AttachedFile, false);\n\t\tif (res)\n\t\t{\n\t\t\t// EnableWindow(sendReport, FALSE);\n\t\t\t// MessageBox (dialog, \"The email was successfully sent\", \"email\", MB_OK);\n#ifndef NL_NO_DEBUG_FILES\n\t\t\tCFile::createEmptyFile(getLogDirectory() + \"report_sent\");\n#endif\n\t\t}\n\t\telse\n\t\t{\n#ifndef NL_NO_DEBUG_FILES\n\t\t\tCFile::createEmptyFile(getLogDirectory() + \"report_failed\");\n#endif\n\t\t\t// MessageBox (dialog, \"Failed to send the email\", \"email\", MB_OK | MB_ICONERROR);\n\t\t}\n\t}\n\telse\n\t{\n#ifndef NL_NO_DEBUG_FILES\n\t\tCFile::createEmptyFile(getLogDirectory() + \"report_refused\");\n#endif\n\t}\n}\n\nstatic LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n{\n\t//MSGFILTER *pmf;\n\n\tif (message == WM_COMMAND && HIWORD(wParam) == BN_CLICKED)\n\t{\n\t\tif ((HWND) lParam == checkIgnore)\n\t\t{\n\t\t\tIgnoreNextTime = !IgnoreNextTime;\n\t\t}\n\t\telse if ((HWND) lParam == debug)\n\t\t{\n\t\t\tsendEmail();\n\t\t\tNeedExit = true;\n\t\t\tResult = ReportDebug;\n\t\t\tif (DebugDefaultBehavior)\n\t\t\t{\n\t\t\t\tNLMISC_BREAKPOINT;\n\t\t\t}\n\t\t}\n\t\telse if ((HWND) lParam == ignore)\n\t\t{\n\t\t\tsendEmail();\n\t\t\tNeedExit = true;\n\t\t\tResult = ReportIgnore;\n\t\t}\n\t\telse if ((HWND) lParam == quit)\n\t\t{\n\t\t\tsendEmail();\n\t\t\tNeedExit = true;\n\t\t\tResult = ReportQuit;\n\n\t\t\tif (QuitDefaultBehavior)\n\t\t\t{\n\t\t\t\t// ace: we cannot call exit() because it's call the static object dtor and can crash the application\n\t\t\t\t// if the dtor call order is not good.\n\t\t\t\t//exit(EXIT_SUCCESS);\n#ifdef NL_OS_WINDOWS\n#ifndef NL_COMP_MINGW\n\t\t\t\t// disable the Windows popup telling that the application aborted and disable the dr watson report.\n\t\t\t\t_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\n#endif\n#endif\n\t\t\t\t// quit without calling atexit or static object dtors.\n\t\t\t\tabort();\n\t\t\t}\n\t\t}\n\t\t/*else if ((HWND) lParam == sendReport)\n\t\t{\n\t\t\tif (EmailFunction != NULL)\n\t\t\t{\n\t\t\t\tbool res = EmailFunction (\"\", \"\", \"\", Subject, Body, AttachedFile, false);\n\t\t\t\tif (res)\n\t\t\t\t{\n\t\t\t\t\tEnableWindow(sendReport, FALSE);\n\t\t\t\t\tMessageBox (dialog, \"The email was successfully sent\", \"email\", MB_OK);\n\t\t\t\t\tCFile::createEmptyFile(getLogDirectory() + \"report_sent\");\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tMessageBox (dialog, \"Failed to send the email\", \"email\", MB_OK | MB_ICONERROR);\n\t\t\t\t}\n\t\t\t}\n\t\t}*/\n\t}\n\telse if (message == WM_CHAR)\n\t{\n\t\tif (wParam == 27)\n\t\t{\n\t\t\t// ESC -> ignore\n\t\t\tsendEmail();\n\t\t\tNeedExit = true;\n\t\t\tResult = ReportIgnore;\n\t\t}\n\t}\n\n\treturn DefWindowProc (hWnd, message, wParam, lParam);\n}\n\nTReportResult report (const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const string &attachedFile)\n{\n\t// register the window\n\tstatic bool AlreadyRegister = false;\n\tif(!AlreadyRegister)\n\t{\n\t\tWNDCLASSW wc;\n\t\tmemset (&wc,0,sizeof(wc));\n\t\twc.style\t\t\t= CS_HREDRAW | CS_VREDRAW;\n\t\twc.lpfnWndProc\t\t= (WNDPROC)WndProc;\n\t\twc.cbClsExtra\t\t= 0;\n\t\twc.cbWndExtra\t\t= 0;\n\t\twc.hInstance\t\t= GetModuleHandle(NULL);\n\t\twc.hIcon\t\t\t= NULL;\n\t\twc.hCursor\t\t\t= LoadCursor(NULL,IDC_ARROW);\n\t\twc.hbrBackground\t= (HBRUSH)COLOR_WINDOW;\n\t\twc.lpszClassName\t= L\"NLReportWindow\";\n\t\twc.lpszMenuName\t\t= NULL;\n\t\tif (!RegisterClassW(&wc)) return ReportError;\n\t\tAlreadyRegister = true;\n\t}\n\n\tucstring formatedTitle = title.empty() ? ucstring(\"NeL report\") : ucstring(title);\n\n\n\t// create the window\n\tdialog = CreateWindowW (L\"NLReportWindow\", (LPCWSTR)formatedTitle.c_str(), WS_DLGFRAME | WS_CAPTION /*| WS_THICKFRAME*/, CW_USEDEFAULT, CW_USEDEFAULT, 456, 400,  NULL, NULL, GetModuleHandle(NULL), NULL);\n\n\t// create the font\n\tHFONT font = CreateFont (-12, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, \"Arial\");\n\n\tSubject = subject;\n\tAttachedFile = attachedFile;\n\n\t// create the edit control\n\tHWND edit = CreateWindowW (L\"EDIT\", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_READONLY | ES_LEFT | ES_MULTILINE, 7, 70, 429, 212, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (edit, WM_SETFONT, (WPARAM) font, TRUE);\n\n\t// set the edit text limit to lot of :)\n\tSendMessage (edit, EM_LIMITTEXT, ~0U, 0);\n\n\tBody = addSlashR (body);\n\n\t// set the message in the edit text\n\tSendMessage (edit, WM_SETTEXT, (WPARAM)0, (LPARAM)Body.c_str());\n\n\tif (enableCheckIgnore)\n\t{\n\t\t// create the combo box control\n\t\tcheckIgnore = CreateWindowW (L\"BUTTON\", L\"Don't display this report again\", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_CHECKBOX, 7, 290, 429, 18, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\t\tSendMessage (checkIgnore, WM_SETFONT, (WPARAM) font, TRUE);\n\n\t\tif(ignoreNextTime)\n\t\t{\n\t\t\tSendMessage (checkIgnore, BM_SETCHECK, BST_CHECKED, 0);\n\t\t}\n\t}\n\n\t// create the debug button control\n\tdebug = CreateWindowW (L\"BUTTON\", L\"Debug\", WS_CHILD | WS_VISIBLE, 7, 315, 75, 25, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (debug, WM_SETFONT, (WPARAM) font, TRUE);\n\n\tif (debugButton == 0)\n\t\tEnableWindow(debug, FALSE);\n\n\t// create the ignore button control\n\tignore = CreateWindowW (L\"BUTTON\", L\"Ignore\", WS_CHILD | WS_VISIBLE, 75+7+7, 315, 75, 25, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (ignore, WM_SETFONT, (WPARAM) font, TRUE);\n\n\tif (ignoreButton == 0)\n\t\tEnableWindow(ignore, FALSE);\n\n\t// create the quit button control\n\tquit = CreateWindowW (L\"BUTTON\", L\"Quit\", WS_CHILD | WS_VISIBLE, 75+75+7+7+7, 315, 75, 25, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (quit, WM_SETFONT, (WPARAM) font, TRUE);\n\n\tif (quitButton == 0)\n\t\tEnableWindow(quit, FALSE);\n\n\t// create the debug button control\n\tsendReport = CreateWindowW (L\"BUTTON\", L\"Don't send the report\", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 7, 315+32, 429, 18, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (sendReport, WM_SETFONT, (WPARAM) font, TRUE);\n\n\tstring formatedHeader;\n\tif (header.empty())\n\t{\n\t\tformatedHeader = \"This application stopped to display this report.\";\n\t}\n\telse\n\t{\n\t\tformatedHeader = header;\n\t}\n\n\t// ace don't do that because it s slow to try to send a mail\n\t//CanSendMailReport  = sendReportButton && EmailFunction != NULL && EmailFunction(\"\", \"\", \"\", \"\", \"\", true);\n\tCanSendMailReport  = sendReportButton && EmailFunction != NULL;\n\n\tif (CanSendMailReport)\n\t\tformatedHeader += \" Send report will only email the contents of the box below. Please, send it to help us (it could take few minutes to send the email, be patient).\";\n\telse\n\t\tEnableWindow(sendReport, FALSE);\n\n\tucstring uc = ucstring::makeFromUtf8(formatedHeader);\n\n\t// create the label control\n\tHWND label = CreateWindowW (L\"STATIC\", (LPCWSTR)uc.c_str(), WS_CHILD | WS_VISIBLE /*| SS_WHITERECT*/, 7, 7, 429, 51, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);\n\tSendMessage (label, WM_SETFONT, (WPARAM) font, TRUE);\n\n\n\tDebugDefaultBehavior = debugButton==1;\n\tQuitDefaultBehavior = quitButton==1;\n\n\tIgnoreNextTime = ignoreNextTime;\n\n\t// show until the cursor really show :)\n\twhile (ShowCursor(TRUE) < 0)\n\t\t;\n\n\tSetWindowPos (dialog, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);\n\n\tSetFocus(dialog);\n\tSetForegroundWindow(dialog);\n\n\tNeedExit = false;\n\n\twhile(!NeedExit)\n\t{\n\t\tMSG\tmsg;\n\t\twhile (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))\n\t\t{\n\t\t\tTranslateMessage(&msg);\n\t\t\tDispatchMessageW(&msg);\n\t\t}\n\t\tnlSleep (1);\n\t}\n\n\t// set the user result\n\tignoreNextTime = IgnoreNextTime;\n\n\tShowWindow(dialog, SW_HIDE);\n\n\n\n\tDELETE_OBJECT(sendReport)\n\tDELETE_OBJECT(quit)\n\tDELETE_OBJECT(ignore)\n\tDELETE_OBJECT(debug)\n\tDELETE_OBJECT(checkIgnore)\n\tDELETE_OBJECT(edit)\n\tDELETE_OBJECT(label)\n\tDELETE_OBJECT(dialog)\n\n\treturn Result;\n}\n\n#endif\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/rgba.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/rgba.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/system_info.h\"\n#include \"nel/misc/common.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n#ifdef NL_NO_ASM\n\t#define DISABLE_MMX_OPTIM\n#endif\n\n// ***************************************************************************\n// ***************************************************************************\n// CRGBA\n// ***************************************************************************\n// ***************************************************************************\n\n// predifined colors\n\n/// some colors\nconst CRGBA CRGBA::Black(0, 0, 0) ;\nconst CRGBA CRGBA::Red(255, 0, 0) ;\nconst CRGBA CRGBA::Green(0, 255, 0) ;\nconst CRGBA CRGBA::Yellow(255, 255, 0) ;\nconst CRGBA CRGBA::Blue(0, 0, 255) ;\nconst CRGBA CRGBA::Magenta(255, 0, 255) ;\nconst CRGBA CRGBA::Cyan(0, 255, 255) ;\nconst CRGBA CRGBA::White(255, 255, 255) ;\n\n// ***************************************************************************\nvoid CRGBA::serial(class NLMISC::IStream &f)\n{\n\tf.serial (R);\n\tf.serial (G);\n\tf.serial (B);\n\tf.serial (A);\n}\n// ***************************************************************************\nvoid CRGBA::set(uint8 r, uint8 g, uint8 b, uint8 a)\n{\n\tR = r;\n\tG = g;\n\tB = b;\n\tA = a;\n}\n// ***************************************************************************\nuint8 CRGBA::toGray() const\n{\n\treturn (R*11+G*16+B*5)/32;\n}\n\n#ifdef \tNL_OS_WINDOWS\n\t#pragma warning(disable : 4731) /* frame pointer register 'ebp' modified by inline assembly code */\n#endif\n\n// ***************************************************************************\nvoid CRGBA::addColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride, uint destStride, uint dup)\n{\n\tif (numColors == 0) return;\n#if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\tif (!CSystemInfo::hasMMX())\n#endif\n\t{   // unoptimized version\n\t\tif (dup == 1)\n\t\t{\n\t\t\twhile (numColors--)\n\t\t\t{\n\t\t\t\tdest->add(*src1, *src2);\n\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4) // optimisation for the 4 case\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->add(*src1, *src2);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + (destStride << 1));\n\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->add(*src1, *src2);\n\n\t\t\t\t\tuint k = dup - 1;\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t}\n\t\t\t\t\twhile (--k);\n\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\telse // optimized mmx version\n\t{\n\t\t/// well, this could be further optimized when stride is 4 (2 at once)\n\t\tif (dup == 1)\n\t\t{\n\t\t\t__asm\n\t\t\t{\n\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\t\tsub         edi, edx\n\t\t\t\tmyLoop:\n\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\tadd         edi, edx\n\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\tpaddusb     mm0, mm1\n\t\t\t\t\t\tmovd        [edi], mm0\n\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\tdec\t\t\tecx\n\t\t\t\t\t\tjne         myLoop\n\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\temms\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4)\n\t\t\t{\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\tmyLoop4:\n\t\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\t\tpaddusb     mm0, mm1\n\t\t\t\t\t\t\tmovd        eax, mm0\n\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tmov         [edi + 2 * edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi + edx * 2]\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi + edx * 2]\n\t\t\t\t\t\t\tadd         esi, ebp\n\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoop4\n\t\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         eax, dup\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\t\t\tpush        eax\n\t\t\t\t\tmyLoopN:\n\t\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\t\tpush        ecx\n\t\t\t\t\t\t\tpaddusb     mm0, mm1\n\t\t\t\t\t\t\tmov         ecx, 4[esp]\n\t\t\t\t\t\t\tmovd        eax, mm0\n\t\t\t\t\tdupLoopN:\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tlea         edi, [edi + edx]\n\t\t\t\t\t\t\tjne\t\t    dupLoopN\n\t\t\t\t\t\t\tpop         ecx\t\t\t; get back the loop counter\n\t\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoopN\n\t\t\t\t\t\t\tpop eax\n\t\t\t\t\t\t\tpop\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n// ***************************************************************************\nvoid CRGBA::modulateColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride, uint destStride, uint dup)\n{\n#if \tdefined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\tif (!CSystemInfo::hasMMX())\n#endif\n\t{   // unoptimized version\n\t\tif (dup == 1)\n\t\t{\n\t\t\twhile (numColors--)\n\t\t\t{\n\t\t\t\tdest->modulateFromColor(*src1, *src2);\n\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4) // optimisation for the 4 case\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->modulateFromColor(*src1, *src2);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + (destStride << 1));\n\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->modulateFromColor(*src1, *src2);\n\n\t\t\t\t\tuint k = dup - 1;\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t}\n\t\t\t\t\twhile (--k);\n\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#if \tdefined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\telse // optimized mmx version\n\t{\n\t\tuint64 blank = 0;\n\t\t/// well, this could be further optimized when stride is 4\n\t\tif (dup == 1)\n\t\t{\t__asm\n\t\t\t{\n\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\tmovq        mm2, blank\n\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\tmyLoop:\n\t\t\t\t\t\tmovd\t\t\tmm0, [esi]\n\t\t\t\t\t\tmovd\t\t\tmm1, [esi + ebx]\n\t\t\t\t\t\tpunpcklbw\tmm0, mm2\n\t\t\t\t\t\tpunpcklbw\tmm1, mm2\n\t\t\t\t\t\tpmullw\t\tmm0, mm1\n\t\t\t\t\t\tpsrlw       mm0, 8\n\t\t\t\t\t\tpackuswb    mm0, mm0\n\t\t\t\t\t\tmovd        [edi], mm0\n\t\t\t\t\t\tadd         edi, edx\n\t\t\t\t\t\tadd         esi, ebp\n\n\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\tjne         myLoop\n\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\temms\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4)\n\t\t\t{\n\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmovq        mm2, blank\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\tmyLoop4:\n\t\t\t\t\t\t\tmovd\t\tmm0, [esi]\n\t\t\t\t\t\t\tmovd\t\tmm1, [esi + ebx]\n\t\t\t\t\t\t\tpunpcklbw\tmm0, mm2\n\t\t\t\t\t\t\tpunpcklbw\tmm1, mm2\n\t\t\t\t\t\t\tpmullw\t\tmm0, mm1\n\t\t\t\t\t\t\tpsrlw       mm0, 8\n\t\t\t\t\t\t\tpackuswb    mm0, mm0\n\t\t\t\t\t\t\tmovd        eax, mm0\n\t\t\t\t\t\t\t; duplicate the result 4 times\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tmov         [edi + 2 * edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi +  2 * edx]\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi + 2 * edx]\n\t\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoop4\n\t\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmovq        mm2, blank\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         eax, dup\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\t\t\tpush        eax\n\t\t\t\t\tmyLoopN:\n\t\t\t\t\t\t\tmovd\t\tmm0, [esi]\n\t\t\t\t\t\t\tmovd\t\tmm1, [esi + ebx]\n\t\t\t\t\t\t\tpunpcklbw\tmm0, mm2\n\t\t\t\t\t\t\tpunpcklbw\tmm1, mm2\n\t\t\t\t\t\t\tpmullw\t\tmm0, mm1\n\t\t\t\t\t\t\tpush        ecx\n\t\t\t\t\t\t\tpsrlw       mm0, 8\n\t\t\t\t\t\t\tmov         ecx, 4[esp]\n\t\t\t\t\t\t\tpackuswb    mm0, mm0\n\t\t\t\t\t\t\tmovd        eax, mm0\n\t\t\t\t\tdupLoopN:\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tlea         edi, [edi + edx]\n\t\t\t\t\t\t\tjne\t\t    dupLoopN\n\t\t\t\t\t\t\tpop         ecx\t\t\t; get back the loop counter\n\t\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoopN\n\t\t\t\t\t\t\tpop eax\n\t\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n// ***************************************************************************\nvoid CRGBA::subtractColors(CRGBA *dest, const CRGBA *src1, const CRGBA *src2, uint numColors, uint srcStride, uint destStride, uint dup)\n{\n\tif (numColors == 0) return;\n#if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\tif (!CSystemInfo::hasMMX())\n#endif\n\t{   // unoptimized version\n\t\tif (dup == 1)\n\t\t{\n\t\t\twhile (numColors--)\n\t\t\t{\n\t\t\t\tdest->sub(*src1, *src2);\n\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4) // optimisation for the 4 case\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->sub(*src1, *src2);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + (destStride << 1));\n\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile (numColors--)\n\t\t\t\t{\n\t\t\t\t\tdest->sub(*src1, *src2);\n\n\t\t\t\t\tuint k = dup - 1;\n\t\t\t\t\tdo\n\t\t\t\t\t{\n\t\t\t\t\t\t* (CRGBA *) ((uint8 *) dest + destStride) = *dest;\n\t\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\t}\n\t\t\t\t\twhile (--k);\n\n\t\t\t\t\tdest = (CRGBA *) ((uint8 *) dest + destStride);\n\t\t\t\t\tsrc1 = (CRGBA *) ((uint8 *) src1 + srcStride);\n\t\t\t\t\tsrc2 = (CRGBA *) ((uint8 *) src2 + srcStride);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#if defined(NL_OS_WINDOWS) && !defined(DISABLE_MMX_OPTIM)\n\telse // optimized mmx version\n\t{\n\t\t/// well, this could be further optimized when stride is 4 (2 at once)\n\t\tif (dup == 1)\n\t\t{\n\t\t\t__asm\n\t\t\t{\n\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\t\tsub         edi, edx\n\t\t\t\tmyLoop:\n\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\tadd         edi, edx\n\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\tpsubusb     mm0, mm1\n\t\t\t\t\t\tmovd        [edi], mm0\n\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\tdec\t\t\tecx\n\t\t\t\t\t\tjne         myLoop\n\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\temms\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (dup == 4)\n\t\t\t{\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\tmyLoop4:\n\t\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\t\tpsubusb     mm0, mm1\n\t\t\t\t\t\t\tmovd        eax, mm0\n\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tmov         [edi + 2 * edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi + edx * 2]\n\t\t\t\t\t\t\tmov         [edi + edx], eax\n\t\t\t\t\t\t\tlea         edi, [edi + edx * 2]\n\t\t\t\t\t\t\tadd         esi, ebp\n\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoop4\n\t\t\t\t\t\t\tpop\t\t\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\t\t\tpush        ebp\n\t\t\t\t\t\t\tmov\t\t\tedi, dest\n\t\t\t\t\t\t\tmov\t\t\tesi, src1\n\t\t\t\t\t\t\tmov\t\t\tebx, src2\n\t\t\t\t\t\t\tsub\t\t\tebx, esi  ; offset to source 2\n\t\t\t\t\t\t\tmov\t\t\tecx, numColors\n\t\t\t\t\t\t\tmov         edx, destStride\n\t\t\t\t\t\t\tmov         eax, dup\n\t\t\t\t\t\t\tmov         ebp, srcStride\n\t\t\t\t\t\t\tpush        eax\n\t\t\t\t\tmyLoopN:\n\t\t\t\t\t\t\tmovd        mm0, [esi]\n\t\t\t\t\t\t\tmovd        mm1, [esi + ebx]\n\t\t\t\t\t\t\tpush        ecx\n\t\t\t\t\t\t\tpsubusb     mm0, mm1\n\t\t\t\t\t\t\tmov         ecx, 4[esp]\n\t\t\t\t\t\t\tmovd        eax, mm0\n\t\t\t\t\tdupLoopN:\n\t\t\t\t\t\t\tmov         [edi], eax\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tlea         edi, [edi + edx]\n\t\t\t\t\t\t\tjne\t\t    dupLoopN\n\t\t\t\t\t\t\tpop         ecx\t\t\t; get back the loop counter\n\t\t\t\t\t\t\tadd         esi, ebp\n\t\t\t\t\t\t\tdec         ecx\n\t\t\t\t\t\t\tjne         myLoopN\n\t\t\t\t\t\t\tpop eax\n\t\t\t\t\t\t\tpop\tebp\n\t\t\t\t\t\t\temms\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n\n// ***************************************************************************\n// ***************************************************************************\n// CBGRA\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\nvoid CBGRA::serial(class NLMISC::IStream &f)\n{\n\tf.serial (B);\n\tf.serial (G);\n\tf.serial (R);\n\tf.serial (A);\n}\n\n// ***************************************************************************\nvoid CBGRA::set(uint8 r, uint8 g, uint8 b, uint8 a)\n{\n\tR = r;\n\tG = g;\n\tB = b;\n\tA = a;\n}\n\n// ***************************************************************************\nvoid CBGRA::blendFromui(CBGRA &c0, CBGRA &c1, uint coef) // coef must be in [0,256]\n{\n\tsint\ta1 = coef;\n\tsint\ta2 = 256-a1;\n\tR = (c0.R*a2 + c1.R*a1) >>8;\n\tG = (c0.G*a2 + c1.G*a1) >>8;\n\tB = (c0.B*a2 + c1.B*a1) >>8;\n\tA = (c0.A*a2 + c1.A*a1) >>8;\n}\n\n// ***************************************************************************\nbool CRGBA::convertToHLS(float &h, float &l, float &s) const\n{\n\tfloat r = R / 255.f;\n\tfloat g = G / 255.f;\n\tfloat b = B / 255.f;\n\n\tfloat maxV = NLMISC::maxof(r, g, b);\n\tfloat minV = NLMISC::minof(r, g, b);\n\n\t// all composants are equals -> achromatique\n\tif (minV == maxV)\n\t{\n\t\th = 0.f;\n\t\tl = minV;\n\t\ts = 0.f;\n\t\treturn true;\n\t}\n\n\t// get lightness\n\tl = 0.5f * (maxV + minV);\n\n\tfloat diff = maxV - minV;\n\n\t// get saturation\n\ts  = l > 0.5f ?   /*are we in the top of the double-hexcone ? */\n\t\tdiff / (2.f - maxV - minV)  :\n\t\tdiff / (maxV + minV);\n\n\t// get hue\n\tif (maxV == r)\n\t{\n\t\th = (g - b) / diff;\n\t}\n\telse if (maxV == g)\n\t{\n\t\th = 2.f + (b - r) / diff;\n\t}\n#if defined(GCC_VERSION) && (GCC_VERSION == 40204)\n\t// use the fix only if using the specific GCC version\n\telse if (maxV == b)\n\t{\n\t\th = 4.f + (r - g) / diff;\n\t}\n\telse\n\t{\n\t\t// this case is to fix a compiler bug\n\t\th = (g - b) / diff;\n\t}\n#else\n\telse\n\t{\n\t\th = 4.f + (r - g) / diff;\n\t}\n#endif\n\n\th *= 60.f; // scale to [0..360]\n\n\tif (h < 0.f) h += 360.f;\n\n\treturn false;\n}\n\n// ***************************************************************************\n/// Used by buildFromHLS\nstatic float HLSValue(float h, float v1, float v2)\n{\n\t/* get hue in the [0, 360] interval */\n\t// h -= 360.f * ::floorf(h / 360.f);\n\n\tif (h > 360.f) h -= 360.f;\n\telse if (h < 0) h += 360.f;\n\n\tif (h < 60.f)\n\t{\n\t\treturn v1 + (v2 - v1) * h / 60.f;\n\t}\n\telse if (h < 180.f)\n\t{\n\t\treturn v2;\n\t}\n\telse if (h < 240.f)\n\t{\n\t\treturn v1 + (v2 - v1) * (240.f - h) / 60.f;\n\t}\n\telse\n\t{\n\t\treturn v1;\n\t}\n}\n\n\n// ***************************************************************************\nvoid CRGBA::buildFromHLS(float h, float l, float s)\n{\n\tclamp(l, 0.f, 1.f);\n\tclamp(s, 0.f, 1.f);\n\n\tfloat v2 = (l <= 0.5f) ? (l * (1.f + s)) : (l + s - l * s);\n\tfloat v1 = 2.f * l - v2;\n\n\tif (s == 0) // achromatic ?\n\t{\n\t\tR = G = B = (uint8) (255.f * l);\n\t}\n\telse // chromatic case\n\t{\n\t\tfloat v;\n\t\t//\n\t\tv = HLSValue(h + 120.f, v1, v2);\n\t\tclamp(v, 0.f, 1.f);\n\t\tR = (uint8) (255.f * v);\n\t\t//\n\t\tv = HLSValue(h, v1, v2);\n\t\tclamp(v, 0.f, 1.f);\n\t\tG = (uint8) (255.f * v);\n\t\t//\n\t\tv = HLSValue(h - 120.f, v1, v2);\n\t\tclamp(v, 0.f, 1.f);\n\t\tB = (uint8) (255.f * v);\n\t}\n}\n\nCRGBA CRGBA::stringToRGBA( const char *ptr )\n{\n\tif (!ptr)\n\t\treturn NLMISC::CRGBA::White;\n\t\n\tint r = 255, g = 255, b = 255, a = 255;\n\tsscanf( ptr, \"%d %d %d %d\", &r, &g, &b, &a );\n\tclamp( r, 0, 255 );\n\tclamp( g, 0, 255 );\n\tclamp( b, 0, 255 );\n\tclamp( a, 0, 255 );\n\t\n\treturn CRGBA( r,g,b,a );\n}\n\nstd::string CRGBA::toString() const\n{\n\tstd::string s;\n\ts =  NLMISC::toString( R );\n\ts += \" \";\n\ts += NLMISC::toString( G );\n\ts += \" \";\n\ts += NLMISC::toString( B );\n\ts += \" \";\n\ts += NLMISC::toString( A );\n\treturn s;\n}\n\nbool CRGBA::fromString( const std::string &s )\n{\n\t*this = stringToRGBA( s.c_str() );\n\treturn true;\n}\n\n\n// ***************************************************************************\n// ***************************************************************************\n// CRGBAF\n// ***************************************************************************\n// ***************************************************************************\n\n\n// ***************************************************************************\nvoid CRGBAF::serial(class NLMISC::IStream &f)\n{\n\tf.serial (R);\n\tf.serial (G);\n\tf.serial (B);\n\tf.serial (A);\n}\n// ***************************************************************************\nvoid CRGBAF::set(float r, float g, float b, float a)\n{\n\tR = r;\n\tG = g;\n\tB = b;\n\tA = a;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/sha1.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/sha1.h\"\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\n//\n// Types\n//\n\n/*\n * If you do not have the ISO standard stdint.h header file, then you\n * must typedef the following:\n *    name              meaning\n *  uint32_t         unsigned 32 bit integer\n *  uint8_t          unsigned 8 bit integer (i.e., unsigned char)\n *  int_least16_t    integer of >= 16 bits\n *\n */\n\ntypedef unsigned int uint32_t;\ntypedef unsigned char uint8_t;\ntypedef short int_least16_t;\n\n//\n// Constantes\n//\n\nstatic const int bufferSize = 100000;\nstatic uint8_t buffer[bufferSize];\n\nenum\n{\n    shaSuccess = 0,\n    shaNull,            /* Null pointer parameter */\n    shaInputTooLong,    /* input data too long */\n    shaStateError       /* called Input after Result */\n};\n\n#define SHA1HashSize 20\n\n/*\n *  This structure will hold context information for the SHA-1\n *  hashing operation\n */\ntypedef struct SHA1Context\n{\n    uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest  */\n\n    uint32_t Length_Low;            /* Message length in bits      */\n    uint32_t Length_High;           /* Message length in bits      */\n\n                               /* Index into message block array   */\n    int_least16_t Message_Block_Index;\n    uint8_t Message_Block[64];      /* 512-bit message blocks      */\n\n    int Computed;               /* Is the digest computed?         */\n    int Corrupted;             /* Is the message digest corrupted? */\n} SHA1Context;\n\n//\n//  Function Prototypes\n//\n\nint SHA1Reset (SHA1Context *);\nint SHA1Input (SHA1Context *, const uint8_t *, unsigned int);\nint SHA1Result (SHA1Context *, uint8_t Message_Digest[SHA1HashSize]);\n\n//\n// Functions\n//\n\nCHashKey getSHA1(const uint8 *buffer, uint32 size)\n{\n    SHA1Context sha;\n    int err;\n    uint8_t Message_Digest[20];\n\n\terr = SHA1Reset(&sha);\n\tif (err)\n\t{\n\t\tnlwarning(\"SHA: SHA1Reset Error %d.\\n\", err );\n\t\treturn CHashKey();\n\t}\n\n\terr = SHA1Input(&sha, (const uint8_t*)buffer, size);\n\tif (err)\n\t{\n\t\tnlwarning (\"SHA: SHA1Input Error %d.\\n\", err);\n\t\treturn CHashKey();\n\t}\n\n\terr = SHA1Result(&sha, Message_Digest);\n\tif (err)\n\t{\n\t\tnlwarning(\"SHA: SHA1Result Error %d, could not compute message digest.\\n\", err );\n\t\treturn CHashKey();\n\t}\n\n\tCHashKey hk (Message_Digest);\n\treturn hk;\n}\n\nCHashKey getSHA1(const string &filename, bool forcePath)\n{\n    SHA1Context sha;\n    int err;\n    uint8_t Message_Digest[20];\n\n\t//printf(\"reading '%s'\\n\", findData.cFileName);\n\tCIFile ifile;\n\tifile.setCacheFileOnOpen(true);\n\tif (!ifile.open(forcePath ? filename:CPath::lookup(filename)))\n\t{\n\t\tnlwarning (\"SHA: Can't open the file '%s'\", filename.c_str());\n\t\treturn CHashKey();\n\t}\n\n\t//FILE *fp = fopen (filename.c_str(), \"rb\");\n\t//if (fp == NULL) return CHashKey();\n\n\terr = SHA1Reset(&sha);\n\tif (err)\n\t{\n\t\tnlwarning(\"SHA: SHA1Reset Error %d.\\n\", err );\n\t\tifile.close ();\n\t\treturn CHashKey();\n\t}\n\n\tsint fs = ifile.getFileSize();\n\tsint n, read = 0;\n\tdo\n\t{\n\t\t//bs = (int)fread (buffer, 1, bufferSize, fp);\n\t\tn = std::min (bufferSize, fs-read);\n\t\t//nlinfo (\"read %d bytes\", n);\n\t\tifile.serialBuffer((uint8 *)buffer, n);\n\n\t\terr = SHA1Input(&sha, buffer, n);\n\t\tif (err)\n\t\t{\n\t\t\tnlwarning (\"SHA: SHA1Input Error %d.\\n\", err);\n\t\t\tifile.close();\n\t\t\treturn CHashKey();\n\t\t}\n\t\tread += n;\n\t}\n\twhile (!ifile.eof());\n\n\tifile.close\t();\n\n\terr = SHA1Result(&sha, Message_Digest);\n\tif (err)\n\t{\n\t\tnlwarning(\"SHA: SHA1Result Error %d, could not compute message digest.\\n\", err );\n\t\treturn CHashKey();\n\t}\n\n\tCHashKey hk (Message_Digest);\n\treturn hk;\n}\n\n/*\n*\n* HMAC = hash( (Key ^ 0x5c) .. hash( (Key ^0x36) .. Message ) )\n*\n*/\n\nCHashKey getHMacSHA1(const uint8 *text, uint32 text_len, const uint8 *key, uint32 key_len)\n{\n\tSHA1Context sha;\n\n\tuint8_t SHA1_Key[64];\n\tuint8_t SHA1_Key1[20];\n\tuint8_t SHA1_Key2[20];\n\n\tstring buffer1;\n\tstring buffer2;\n\n\t// Init some vars\n\tfor (uint i = 0; i <  64; i++)\n\t\tSHA1_Key[i] = 0;\n\n\t// If lenght of key > 64 use sha1 hash\n\tif (key_len > 64) {\n\t\tuint8_t SHA1_Key0[20];\n\t\tSHA1Reset(&sha);\n\t\tSHA1Input(&sha, (const uint8_t*)key, key_len);\n\t\tSHA1Result(&sha, SHA1_Key0);\n\t\tCHashKey hk0 (SHA1_Key0);\n\t\tfor (uint i = 0; i <  20; i++)\n\t\t\tSHA1_Key[i] = hk0.HashKeyString[i];\n\t} else {\n\t\tfor (uint i = 0; i < key_len; i++)\n\t\t\tSHA1_Key[i] = key[i];\n\t}\n\n\t// Do 0x36 XOR Key\n\tfor (uint i = 0; i < 64; i++)\n\t\tbuffer1 += 0x36 ^ SHA1_Key[i];\n\n\t// Append text\n\tfor (uint i = 0; i < text_len; i++)\n\t\tbuffer1 += text[i];\n\n\t// Get hash\n\tSHA1Reset(&sha);\n\tSHA1Input(&sha, (const uint8_t*)buffer1.c_str(), (uint)buffer1.size());\n\tSHA1Result(&sha, SHA1_Key1);\n\tCHashKey hk1 (SHA1_Key1);\n\n\t// Do 0x5c XOR Key\n\tfor (uint i = 0; i < 64; i++)\n\t\tbuffer2 += 0x5c ^ SHA1_Key[i];\n\n\t// Append previous hash\n\tfor (uint i = 0; i < 20; i++)\n\t\tbuffer2 += hk1.HashKeyString[i];\n\n\t// Get new hash\n\tSHA1Reset(&sha);\n\tSHA1Input(&sha, (const uint8_t*)buffer2.c_str(), (uint)buffer2.size());\n\tSHA1Result(&sha, SHA1_Key2);\n\tCHashKey hk (SHA1_Key2);\n\n\treturn hk;\n}\n\n\n#ifdef _MFC_VER\n\t#pragma runtime_checks( \"\", off )\n#endif\n\n/*\n *  Define the SHA1 circular left shift macro\n */\n#define SHA1CircularShift(bits,word) \\\n                (((word) << (bits)) | ((word) >> (32-(bits))))\n\n/* Local Function Prototypes */\nvoid SHA1PadMessage(SHA1Context *);\nvoid SHA1ProcessMessageBlock(SHA1Context *);\n\n/*\n *  SHA1Reset\n *\n *  Description:\n *      This function will initialize the SHA1Context in preparation\n *      for computing a new SHA1 message digest.\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to reset.\n *\n *  Returns:\n *      sha Error Code.\n *\n */\nint SHA1Reset(SHA1Context *context)\n{\n    if (!context)\n    {\n        return shaNull;\n    }\n\n    context->Length_Low             = 0;\n    context->Length_High            = 0;\n    context->Message_Block_Index    = 0;\n\n    context->Intermediate_Hash[0]   = 0x67452301;\n    context->Intermediate_Hash[1]   = 0xEFCDAB89;\n    context->Intermediate_Hash[2]   = 0x98BADCFE;\n    context->Intermediate_Hash[3]   = 0x10325476;\n    context->Intermediate_Hash[4]   = 0xC3D2E1F0;\n\n    context->Computed   = 0;\n    context->Corrupted  = 0;\n\n    return shaSuccess;\n}\n\n/*\n *  SHA1Result\n *\n *  Description:\n *      This function will return the 160-bit message digest into the\n *      Message_Digest array  provided by the caller.\n *      NOTE: The first octet of hash is stored in the 0th element,\n *            the last octet of hash in the 19th element.\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to use to calculate the SHA-1 hash.\n *      Message_Digest: [out]\n *          Where the digest is returned.\n *\n *  Returns:\n *      sha Error Code.\n *\n */\nint SHA1Result( SHA1Context *context,\n                uint8_t Message_Digest[SHA1HashSize])\n{\n    int i;\n\n    if (!context || !Message_Digest)\n    {\n        return shaNull;\n    }\n\n    if (context->Corrupted)\n    {\n        return context->Corrupted;\n    }\n\n    if (!context->Computed)\n    {\n        SHA1PadMessage(context);\n        for(i=0; i<64; ++i)\n        {\n            /* message may be sensitive, clear it out */\n            context->Message_Block[i] = 0;\n        }\n        context->Length_Low = 0;    /* and clear length */\n        context->Length_High = 0;\n        context->Computed = 1;\n\n    }\n\n    for(i = 0; i < SHA1HashSize; ++i)\n    {\n        Message_Digest[i] = uint8_t((context->Intermediate_Hash[i>>2]\n                            >> 8 * ( 3 - ( i & 0x03 ) ) ) & 0xff );\n    }\n\n    return shaSuccess;\n}\n\n/*\n *  SHA1Input\n *\n *  Description:\n *      This function accepts an array of octets as the next portion\n *      of the message.\n *\n *  Parameters:\n *      context: [in/out]\n *          The SHA context to update\n *      message_array: [in]\n *          An array of characters representing the next portion of\n *          the message.\n *      length: [in]\n *          The length of the message in message_array\n *\n *  Returns:\n *      sha Error Code.\n *\n */\nint SHA1Input(    SHA1Context    *context,\n                  const uint8_t  *message_array,\n                  unsigned       length)\n{\n    if (!length)\n    {\n        return shaSuccess;\n    }\n\n    if (!context || !message_array)\n    {\n        return shaNull;\n    }\n\n    if (context->Computed)\n    {\n        context->Corrupted = shaStateError;\n\n        return shaStateError;\n    }\n\n    if (context->Corrupted)\n    {\n         return context->Corrupted;\n    }\n    while(length-- && !context->Corrupted)\n    {\n    context->Message_Block[context->Message_Block_Index++] =\n                    (*message_array & 0xFF);\n\n    context->Length_Low += 8;\n    if (context->Length_Low == 0)\n    {\n        context->Length_High++;\n        if (context->Length_High == 0)\n        {\n            /* Message is too long */\n            context->Corrupted = 1;\n        }\n    }\n\n    if (context->Message_Block_Index == 64)\n    {\n        SHA1ProcessMessageBlock(context);\n    }\n\n    message_array++;\n    }\n\n    return shaSuccess;\n}\n\n/*\n *  SHA1ProcessMessageBlock\n *\n *  Description:\n *      This function will process the next 512 bits of the message\n *      stored in the Message_Block array.\n *\n *  Parameters:\n *      None.\n *\n *  Returns:\n *      Nothing.\n *\n *  Comments:\n\n *      Many of the variable names in this code, especially the\n *      single character names, were used because those were the\n *      names used in the publication.\n *\n *\n */\nvoid SHA1ProcessMessageBlock(SHA1Context *context)\n{\n    const uint32_t K[] =    {       /* Constants defined in SHA-1   */\n                            0x5A827999,\n                            0x6ED9EBA1,\n                            0x8F1BBCDC,\n                            0xCA62C1D6\n                            };\n    int           t;                 /* Loop counter                */\n    uint32_t      temp;              /* Temporary word value        */\n    uint32_t      W[80];             /* Word sequence               */\n    uint32_t      A, B, C, D, E;     /* Word buffers                */\n\n    /*\n     *  Initialize the first 16 words in the array W\n     */\n    for(t = 0; t < 16; t++)\n    {\n        W[t] = context->Message_Block[t * 4] << 24;\n        W[t] |= context->Message_Block[t * 4 + 1] << 16;\n        W[t] |= context->Message_Block[t * 4 + 2] << 8;\n        W[t] |= context->Message_Block[t * 4 + 3];\n    }\n\n    for(t = 16; t < 80; t++)\n    {\n       W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);\n    }\n\n    A = context->Intermediate_Hash[0];\n    B = context->Intermediate_Hash[1];\n    C = context->Intermediate_Hash[2];\n    D = context->Intermediate_Hash[3];\n    E = context->Intermediate_Hash[4];\n\n    for(t = 0; t < 20; t++)\n    {\n        temp =  SHA1CircularShift(5,A) +\n                ((B & C) | ((~B) & D)) + E + W[t] + K[0];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n\n        B = A;\n        A = temp;\n    }\n\n    for(t = 20; t < 40; t++)\n    {\n        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    for(t = 40; t < 60; t++)\n    {\n        temp = SHA1CircularShift(5,A) +\n               ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    for(t = 60; t < 80; t++)\n    {\n        temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];\n        E = D;\n        D = C;\n        C = SHA1CircularShift(30,B);\n        B = A;\n        A = temp;\n    }\n\n    context->Intermediate_Hash[0] += A;\n    context->Intermediate_Hash[1] += B;\n    context->Intermediate_Hash[2] += C;\n    context->Intermediate_Hash[3] += D;\n    context->Intermediate_Hash[4] += E;\n\n    context->Message_Block_Index = 0;\n}\n\n/*\n *  SHA1PadMessage\n *\n\n *  Description:\n *      According to the standard, the message must be padded to an even\n *      512 bits.  The first padding bit must be a '1'.  The last 64\n *      bits represent the length of the original message.  All bits in\n *      between should be 0.  This function will pad the message\n *      according to those rules by filling the Message_Block array\n *      accordingly.  It will also call the ProcessMessageBlock function\n *      provided appropriately.  When it returns, it can be assumed that\n *      the message digest has been computed.\n *\n *  Parameters:\n *      context: [in/out]\n *          The context to pad\n *      ProcessMessageBlock: [in]\n *          The appropriate SHA*ProcessMessageBlock function\n *  Returns:\n *      Nothing.\n *\n */\n\nvoid SHA1PadMessage(SHA1Context *context)\n{\n    /*\n     *  Check to see if the current message block is too small to hold\n     *  the initial padding bits and length.  If so, we will pad the\n     *  block, process it, and then continue padding into a second\n     *  block.\n     */\n    if (context->Message_Block_Index > 55)\n    {\n        context->Message_Block[context->Message_Block_Index++] = 0x80;\n        while(context->Message_Block_Index < 64)\n        {\n            context->Message_Block[context->Message_Block_Index++] = 0;\n        }\n\n        SHA1ProcessMessageBlock(context);\n\n        while(context->Message_Block_Index < 56)\n        {\n            context->Message_Block[context->Message_Block_Index++] = 0;\n        }\n    }\n    else\n    {\n        context->Message_Block[context->Message_Block_Index++] = 0x80;\n        while(context->Message_Block_Index < 56)\n        {\n\n            context->Message_Block[context->Message_Block_Index++] = 0;\n        }\n    }\n\n\t/*\n\t*  Store the message length as the last 8 octets\n\t*/\n\tcontext->Message_Block[56] = uint8_t((context->Length_High >> 24)&0xff);\n\tcontext->Message_Block[57] = uint8_t((context->Length_High >> 16)&0xff);\n\tcontext->Message_Block[58] = uint8_t((context->Length_High >> 8)&0xff);\n\tcontext->Message_Block[59] = uint8_t((context->Length_High)&0xff);\n\tcontext->Message_Block[60] = uint8_t((context->Length_Low >> 24)&0xff);\n\tcontext->Message_Block[61] = uint8_t((context->Length_Low >> 16)&0xff);\n\tcontext->Message_Block[62] = uint8_t((context->Length_Low >> 8)&0xff);\n\tcontext->Message_Block[63] = uint8_t((context->Length_Low)&0xff);\n\n\tSHA1ProcessMessageBlock(context);\n}\n"
  },
  {
    "path": "code/nel/src/misc/shared_memory.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/shared_memory.h\"\n#include \"nel/misc/debug.h\"\n\n#ifndef NL_OS_WINDOWS\n#\tinclude <sys/types.h>\n#\tinclude <sys/ipc.h>\n#\tinclude <sys/shm.h>\n#endif\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n#ifdef NL_OS_WINDOWS\n\t// Storage for file handles, necessary to close the handles\n\tmap<void*,HANDLE>\tAccessAddressesToHandles;\n#else\n\t// Storage for shmid, necessary to destroy the segments\n\tmap<TSharedMemId, sint>   SharedMemIdsToShmids;\n#endif\n\n\n/*\n * Create a shared memory segment\n */\nvoid\t\t\t*CSharedMemory::createSharedMemory( TSharedMemId sharedMemId, uint32 size )\n{\n#ifdef NL_OS_WINDOWS\n\n\t// Create a file mapping backed by the virtual memory swap file (not a data file)\n\tHANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, sharedMemId );\n\tif ( (hMapFile == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS) )\n\t{\n\t\tnlwarning( \"SHDMEM: Cannot create file mapping for smid %s: error %u%s, mapFile %p\", sharedMemId, GetLastError(), (GetLastError()==ERROR_ALREADY_EXISTS) ? \" (already exists) \": \"\", hMapFile );\n\t\treturn NULL;\n\t}\n\t//else\n\t//\tnldebug( \"SHDMEM: Creating smid %s --> mapFile %p\", sharedMemId, hMapFile );\n\n\n\t// Map the file into memory address space\n\tvoid *accessAddress = MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );\n\tAccessAddressesToHandles.insert( make_pair( accessAddress, hMapFile ) );\n\t/*if ( accessAddress == NULL )\n\t{\n\t\tnlwarning( \"SHDMEM: Cannot map view of file: error %u\", GetLastError() );\n\t}*/\n\treturn accessAddress;\n\n#else\n\n\t// Create a shared memory segment\n\tsint shmid = shmget( sharedMemId, size, IPC_CREAT | IPC_EXCL | 0666 );\n\tif ( shmid == -1 )\n\t\treturn NULL;\n\tSharedMemIdsToShmids.insert( make_pair( sharedMemId, shmid ) );\n\n\t// Map the segment into memory address space\n\tvoid *accessAddress = (void*)shmat( shmid, 0, 0 );\n\tif ( accessAddress == (void*)-1 )\n\t\treturn NULL;\n\telse\n\t\treturn accessAddress;\n\n#endif\n}\n\n\n/*\n * Get access to an existing shared memory segment\n */\nvoid\t\t\t*CSharedMemory::accessSharedMemory( TSharedMemId sharedMemId )\n{\n#ifdef NL_OS_WINDOWS\n\n\t// Open the existing file mapping by name\n\tHANDLE hMapFile = OpenFileMapping( FILE_MAP_ALL_ACCESS, false, sharedMemId );\n\tif ( hMapFile == NULL )\n\t\treturn NULL;\n\t//nldebug( \"SHDMEM: Opening smid %s --> mapFile %p\", sharedMemId, hMapFile );\n\n\t// Map the file into memory address space\n\tvoid *accessAddress = MapViewOfFile( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0 );\n\tAccessAddressesToHandles.insert( make_pair( accessAddress, hMapFile ) );\n\treturn accessAddress;\n\n#else\n\n\t// Open an existing shared memory segment\n\tint shmid = shmget( sharedMemId, 0, 0666 );\n\tif ( shmid == -1 )\n\t\treturn NULL;\n\n\t// Map the segment into memory address space\n\tvoid *accessAddress = (void*)shmat( shmid, 0, 0 );\n\tif ( accessAddress == (void*)-1 )\n\t\treturn NULL;\n\telse\n\t\treturn accessAddress;\n\n#endif\n}\n\n\n/*\n * Close (detach) a shared memory segment\n */\nbool\t\t\tCSharedMemory::closeSharedMemory( void *accessAddress )\n{\n#ifdef NL_OS_WINDOWS\n\n\tbool result = true;\n\n\t// Unmap the file from memory address space\n\tif ( UnmapViewOfFile( accessAddress ) == 0 )\n\t{\n\t\tnlwarning( \"SHDMEM: UnmapViewOfFile failed: error %u\", GetLastError() );\n\t\tresult = false;\n\t}\n\n\t// Close the corresponding handle\n\tmap<void*,HANDLE>::iterator im = AccessAddressesToHandles.find( accessAddress );\n\tif ( im != AccessAddressesToHandles.end() )\n\t{\n\t\t//nldebug( \"SHDMEM: CloseHandle mapFile %u\", (*im).second );\n\t\tif ( ! CloseHandle( (*im).second ) )\n\t\t\tnlwarning( \"SHDMEM: CloseHandle failed: error %u, mapFile %u\", GetLastError(), (*im).second );\n\t\tAccessAddressesToHandles.erase( im );\n\t\treturn result;\n\t}\n\telse\n\t{\n\t\treturn false;\n\t}\n\n#else\n\n\t// Detach the shared memory segment\n\treturn ( shmdt( accessAddress ) != -1 );\n\n#endif\n}\n\n\n/*\n * Destroy a shared memory segment (to call only by the process that created the segment)\n * Note: does nothing under Windows, it is automatic.\n * \"Rescue feature\": set \"force\" to true if a segment was created and left out of\n * control (meaning a new createSharedMemory() with the same sharedMemId fails), but\n * before, make sure the segment really belongs to you!\n *\n * Note: this method does nothing under Windows, destroying is automatic.\n * Under Unix, the segment will actually be destroyed after the last detach\n * (quoting shmctl man page). It means after calling destroySharedMemory(), the\n * segment is still accessible by another process until it calls closeSharedMemory().\n */\nvoid        CSharedMemory::destroySharedMemory( TSharedMemId sharedMemId, bool force )\n{\n#ifndef NL_OS_WINDOWS\n  // Set the segment to auto-destroying (when the last process detaches)\n  map<TSharedMemId,int>::iterator im = SharedMemIdsToShmids.find( sharedMemId );\n  if ( im != SharedMemIdsToShmids.end() )\n\t{\n\t  // Destroy the segment created before\n\t  shmctl( (*im).second, IPC_RMID, 0 );\n\t  SharedMemIdsToShmids.erase( im );\n\t}\n  else if ( force )\n\t{\n\t  // Open and destroy the segment\n\t  int shmid = shmget( sharedMemId, 0, 0666 );\n\t  if ( shmid != -1 )\n\t\t{\n\t\t  // Destroy the segment\n\t\t  shmctl( shmid, IPC_RMID, 0 );\n\t\t}\n\t}\n#endif\n}\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/sheet_id.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/* This class is case unsensitive. It means that you can call build() and\n * buildIdVector() with string with anycase, it'll work.\n */\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/file.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/misc/sheet_id.h\"\n#include \"nel/misc/common.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nCSheetId::CChar CSheetId::_AllStrings;\nCStaticMap<uint32,CSheetId::CChar> CSheetId::_SheetIdToName;\nCStaticMap<CSheetId::CChar,uint32, CSheetId::CCharComp> CSheetId::_SheetNameToId;\n//map<uint32,std::string> CSheetId::_SheetIdToName;\n//map<std::string,uint32> CSheetId::_SheetNameToId;\nvector<std::string> CSheetId::_FileExtensions;\nbool CSheetId::_Initialised=false;\nbool CSheetId::_RemoveUnknownSheet=true;\nbool CSheetId::_DontHaveSheetKnowledge = false;\nstd::map<std::string, uint32> CSheetId::_DevTypeNameToId;\nstd::vector<std::vector<std::string> > CSheetId::_DevSheetIdToName;\nstd::map<std::string, uint32> CSheetId::_DevSheetNameToId;\n\n#define NL_TEMP_YUBO_NO_SOUND_SHEET_ID\n\n#ifdef NL_TEMP_YUBO_NO_SOUND_SHEET_ID\nnamespace { bool a_NoSoundSheetId = false; const uint32 a_NoSoundSheetType = 80; }\n#endif\n\nconst CSheetId CSheetId::Unknown(0);\n\nvoid CSheetId::cbFileChange (const std::string &filename)\n{\n\tnlinfo (\"SHEETID: %s changed, reload it\", filename.c_str());\n\n\tloadSheetId();\n}\n\n//-----------------------------------------------\n//\tCSheetId\n//\n//-----------------------------------------------\nCSheetId::CSheetId( uint32 sheetRef)\n{\n\t_Id.Id = sheetRef;\n\n#ifdef NL_DEBUG_SHEET_ID\n\t// Yoyo: don't access the static map, because of order of static ctor call.\n\t// For now, all static CSheetId are 0 (eg: CSheetId::Unknown)\n\tif(sheetRef)\n\t{\n\t\tCStaticMap<uint32, CChar>::iterator it(_SheetIdToName.find(sheetRef));\n\t\tif (it != _SheetIdToName.end())\n\t\t{\n\t\t\t_DebugSheetName = it->second.Ptr;\n\t\t}\n\t\telse\n\t\t\t_DebugSheetName = NULL;\n\t}\n\telse\n\t{\n\t\t_DebugSheetName = NULL;\n\t}\n#endif\n}\n\n\n//-----------------------------------------------\n//\tCSheetId\n//\n//-----------------------------------------------\nCSheetId::CSheetId( const string& sheetName )\n{\n\tif (!buildSheetId(sheetName))\n\t{\n\t\tif(sheetName.empty())\n\t\t\tnlwarning(\"SHEETID: Try to create an CSheetId with empty name. TODO: check why.\");\n\t\telse\n\t\t\tnlwarning(\"SHEETID: The sheet '%s' is not in sheet_id.bin, setting it to Unknown\",sheetName.c_str());\n\t\t//std::string stack;\n\t\t//NLMISC::getCallStack(stack);\n\t\t//std::vector<std::string> contexts;\n\t\t//NLMISC::explode(stack, string(\"\\n\"), contexts);\n\t\t//nldebug(\"Dumping callstack :\");\n\t\t//for (uint i=0; i<contexts.size(); ++i)\n\t\t//\tnldebug(\"  %3u : %s\", i, contexts[i].c_str());\n\t\t*this = Unknown;\n\t}\n\n\t// nldebug(\"LIST_SHEET_ID: %s (%s)\", toString().c_str(), sheetName.c_str());\n\n} // CSheetId //\n\nCSheetId::CSheetId( const std::string& sheetName, const std::string &defaultType )\n{\n\t// Don't use this function without defaultType, use the one above.\n\tnlassert(defaultType.size() != 0);\n\t\n\tif (sheetName.rfind('.') == std::string::npos)\n\t{\n\t\tstd::string withType = sheetName + \".\" + defaultType;\n\t\t*this = CSheetId(withType);\n\t\t// nldebug(\"SHEETID: Constructing CSheetId from name '%s' without explicit type, defaulting as '%s' to '%s'\", sheetName.c_str(), defaultType.c_str(), withType.c_str());\n\t}\n\telse\n\t{\n\t\t*this = CSheetId(sheetName);\n\t}\n}\n\n\n//-----------------------------------------------\n//\tBuild\n//\n//-----------------------------------------------\nbool CSheetId::buildSheetId(const std::string& sheetName)\n{\n\tnlassert(_Initialised);\n\t\n\t// When no sheet_id.bin is loaded, use dynamically assigned IDs.\n\tif (_DontHaveSheetKnowledge)\n\t{\n\t\tstd::string sheetNameLc = toLower(sheetName);\n\t\tstd::map<std::string, uint32>::iterator it = _DevSheetNameToId.find(sheetNameLc);\n\t\tif (it == _DevSheetNameToId.end())\n\t\t{\n\t\t\t// Create a new dynamic sheet ID.\n\t\t\t// nldebug(\"SHEETID: Creating a dynamic sheet id for '%s'\", sheetName.c_str());\n\t\t\tstd::string sheetType = CFile::getExtension(sheetNameLc);\n\t\t\tstd::string sheetName = CFile::getFilenameWithoutExtension(sheetNameLc);\n\t\t\tstd::map<std::string, uint32>::iterator tit = _DevTypeNameToId.find(sheetType);\n\t\t\tuint32 typeId;\n\t\t\tif (tit == _DevTypeNameToId.end())\n\t\t\t{\n\t\t\t\t_FileExtensions.push_back(sheetType);\n\t\t\t\t_DevSheetIdToName.push_back(std::vector<std::string>());\n\t\t\t\ttypeId = (uint32)_FileExtensions.size() - 1;\n\t\t\t\t_DevTypeNameToId[sheetType] = typeId;\n\t\t\t\tstd::string unknownNewType = std::string(\"unknown.\" + sheetType);\n\t\t\t\t_DevSheetIdToName[typeId].push_back(unknownNewType);\n\t\t\t\t_Id.IdInfos.Type = typeId;\n\t\t\t\t_Id.IdInfos.Id = _DevSheetIdToName[typeId].size() - 1;\n\t\t\t\t_DevSheetNameToId[unknownNewType] = _Id.Id;\n\t\t\t\tif (sheetName == \"unknown\")\n\t\t\t\t\treturn true; // Return with the unknown sheet id of this type\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttypeId = tit->second;\n\t\t\t\t_Id.IdInfos.Type = typeId;\n\t\t\t}\n\t\t\t// Add a new sheet name to the type\n\t\t\t_DevSheetIdToName[typeId].push_back(sheetNameLc);\n\t\t\t_Id.IdInfos.Id = _DevSheetIdToName[typeId].size() - 1;\n\t\t\t// nldebug(\"SHEETID: Type %i, id %i, sheetid %i\", _Id.IdInfos.Type, _Id.IdInfos.Id, _Id.Id);\n\t\t\t_DevSheetNameToId[sheetNameLc] = _Id.Id;\n\t\t\treturn true;\n\t\t}\n\t\t_Id.Id = it->second;\n\t\treturn true;\n\t}\n\n\t// try looking up the sheet name in _SheetNameToId\n\tCStaticMap<CChar,uint32,CCharComp>::const_iterator itId;\n\tCChar c;\n\tc.Ptr = new char [sheetName.size()+1];\n\tstrcpy(c.Ptr, sheetName.c_str());\n\ttoLower(c.Ptr);\n\n\titId = _SheetNameToId.find (c);\n\tdelete [] c.Ptr;\n\tif( itId != _SheetNameToId.end() )\n\t{\n\t\t_Id.Id = itId->second;\n#ifdef NL_DEBUG_SHEET_ID\n\t\t// store debug info\n\t\t_DebugSheetName = itId->first.Ptr;\n#endif\n\t\treturn true;\n\t}\n\n\t// we failed to find the sheet name in the sheetname map so see if the string is numeric\n\tif (sheetName.size()>1 && sheetName[0]=='#')\n\t{\n\t\tuint32 numericId;\n\t\tNLMISC::fromString((const char*)(sheetName.c_str()+1), numericId);\n\t\tif (NLMISC::toString(\"#%u\",numericId)==sheetName)\n\t\t{\n\t\t\t_Id.Id= numericId;\n\t\t\treturn true;\n\t\t}\n\t}\n\n#ifdef NL_TEMP_YUBO_NO_SOUND_SHEET_ID\n\tif (a_NoSoundSheetId && sheetName.find(\".sound\") != std::string::npos)\n\t{\n\t\tstd::string sheetNameLc = toLower(sheetName);\n\t\tstd::map<std::string, uint32>::iterator it = _DevSheetNameToId.find(sheetNameLc);\n\t\tif (it == _DevSheetNameToId.end())\n\t\t{\n\t\t\t// nldebug(\"SHEETID: Creating a temporary sheet id for '%s'\", sheetName.c_str());\n\t\t\t_DevSheetIdToName[0].push_back(sheetName);\n\t\t\t_Id.IdInfos.Type = a_NoSoundSheetType;\n\t\t\t_Id.IdInfos.Id = _DevSheetIdToName[0].size() - 1;\n\t\t\t_DevSheetNameToId[sheetNameLc] = _Id.Id;\n\t\t\treturn true;\n\t\t}\n\t\t_Id.Id = it->second;\n\t\treturn true;\n\t}\n#endif\n\n\treturn false;\n}\n\nvoid CSheetId::loadSheetId ()\n{\n\tH_AUTO(CSheetIdInit);\n\t//nldebug(\"Loading sheet_id.bin\");\n\n\t// Open the sheet id to sheet file name association\n\tCIFile file;\n\tstd::string path = CPath::lookup(\"sheet_id.bin\", false, false);\n\tif(!path.empty() && file.open(path))\n\t{\n\t\t// clear entries\n\t\t_FileExtensions.clear ();\n\t\t_SheetIdToName.clear ();\n\t\t_SheetNameToId.clear ();\n\n\t\t// reserve space for the vector of file extensions\n\t\t_FileExtensions.resize(1 << (NL_SHEET_ID_TYPE_BITS));\n\n\t\t// Get the map from the file\n\t\tmap<uint32,string> tempMap;\n\t\tcontReset(tempMap);\n\t\tfile.serialCont(tempMap);\n\t\tfile.close();\n\n\t\tif (_RemoveUnknownSheet)\n\t\t{\n\t\t\tuint32 removednbfiles = 0;\n\t\t\tuint32 nbfiles = (uint32)tempMap.size();\n\n\t\t\t// now we remove all files that not available\n\t\t\tmap<uint32,string>::iterator itStr2;\n\t\t\tfor( itStr2 = tempMap.begin(); itStr2 != tempMap.end(); )\n\t\t\t{\n\t\t\t\tif (CPath::exists ((*itStr2).second))\n\t\t\t\t{\n\t\t\t\t\t++itStr2;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmap<uint32,string>::iterator olditStr = itStr2;\n\t\t\t\t\t//nldebug (\"Removing file '%s' from CSheetId because the file not exists\", (*olditStr).second.c_str ());\n\t\t\t\t\titStr2++;\n\t\t\t\t\ttempMap.erase (olditStr);\n\t\t\t\t\tremovednbfiles++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnlinfo (\"SHEETID: Removed %d files on %d from CSheetId because these files don't exist\", removednbfiles, nbfiles);\n\t\t}\n\n\t\t// Convert the map to one big string and 1 static map (id to name)\n\t\t{\n\t\t\t// Get the number and size of all strings\n\t\t\tvector<CChar> tempVec; // Used to initialise the first map\n\t\t\tuint32 nNb = 0;\n\t\t\tuint32 nSize = 0;\n\t\t\tmap<uint32,string>::const_iterator it = tempMap.begin();\n\t\t\twhile (it != tempMap.end())\n\t\t\t{\n\t\t\t\tnSize += (uint32)it->second.size()+1;\n\t\t\t\tnNb++;\n\t\t\t\tit++;\n\t\t\t}\n\n\t\t\t// Make the big string (composed of all strings) and a vector referencing each string\n\t\t\ttempVec.resize(nNb);\n\t\t\t_AllStrings.Ptr = new char[nSize];\n\t\t\tit = tempMap.begin();\n\t\t\tnSize = 0;\n\t\t\tnNb = 0;\n\t\t\twhile (it != tempMap.end())\n\t\t\t{\n\t\t\t\ttempVec[nNb].Ptr = _AllStrings.Ptr+nSize;\n\t\t\t\tstrcpy(_AllStrings.Ptr+nSize, it->second.c_str());\n\t\t\t\ttoLower(_AllStrings.Ptr+nSize);\n\t\t\t\tnSize += (uint32)it->second.size()+1;\n\t\t\t\tnNb++;\n\t\t\t\tit++;\n\t\t\t}\n\n\t\t\t// Finally build the static map (id to name)\n\t\t\t_SheetIdToName.reserve(tempVec.size());\n\t\t\tit = tempMap.begin();\n\t\t\tnNb = 0;\n\t\t\twhile (it != tempMap.end())\n\t\t\t{\n\t\t\t\t_SheetIdToName.add(pair<uint32, CChar>(it->first, CChar(tempVec[nNb])));\n\n\t\t\t\tnNb++;\n\t\t\t\tit++;\n\t\t\t}\n\n\t\t\t// The vector of all small string is not needed anymore we have all the info in\n\t\t\t// the static map and with the pointer AllStrings referencing the beginning.\n\t\t}\n\n\t\t// Build the invert map (Name to Id) & file extension vector\n\t\t{\n\t\t\tuint32 nSize = (uint32)_SheetIdToName.size();\n\t\t\t_SheetNameToId.reserve(nSize);\n\t\t\tCStaticMap<uint32,CChar>::iterator itStr;\n\t\t\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t\t\t{\n\t\t\t\t// add entry to the inverse map\n\t\t\t\t_SheetNameToId.add( make_pair((*itStr).second, (*itStr).first) );\n\n\t\t\t\t// work out the type value for this entry in the map\n\t\t\t\tTSheetId sheetId;\n\t\t\t\tsheetId.Id=(*itStr).first;\n\t\t\t\tuint32 type = sheetId.IdInfos.Type;\n\n\t\t\t\t// check whether we need to add an entry to the file extensions vector\n\t\t\t\tif (_FileExtensions[type].empty())\n\t\t\t\t{\n\t\t\t\t\t// find the file extension part of the given file name\n\t\t\t\t\t_FileExtensions[type] = toLower(CFile::getExtension((*itStr).second.Ptr));\n\t\t\t\t}\n\t\t\t\tnSize--;\n\t\t\t}\n\t\t\t_SheetNameToId.endAdd();\n\t\t}\n\t}\n\telse\n\t{\n\t\tnlerror(\"<CSheetId::init> Can't open the file sheet_id.bin\");\n\t}\n\tnldebug(\"Finished loading sheet_id.bin: %u entries read\",_SheetIdToName.size());\n}\n\n\n//-----------------------------------------------\n//\tinit\n//\n//-----------------------------------------------\nvoid CSheetId::init(bool removeUnknownSheet)\n{\n\t// allow multiple calls to init in case libraries depending on sheetid call this init from their own\n\tif (_Initialised)\n\t{\n\t\tif (_DontHaveSheetKnowledge)\n\t\t\tnlinfo(\"SHEETID: CSheetId is already initialized without sheet_id.bin\");\n\t\treturn;\n\t}\n\n//\tCFile::addFileChangeCallback (\"sheet_id.bin\", cbFileChange);\n\n\t_RemoveUnknownSheet = removeUnknownSheet;\n\n\tloadSheetId ();\n\t_Initialised=true;\n\n#ifdef NL_TEMP_YUBO_NO_SOUND_SHEET_ID\n\tif (typeFromFileExtension(\"sound\") == std::numeric_limits<uint32>::max())\n\t{\n\t\tnlwarning(\"SHEETID: Loading without known sound sheet id, please update sheet_id.bin with .sound sheets\");\n\t\tnlassert(_FileExtensions.size() == 1 << (NL_SHEET_ID_TYPE_BITS));\n\t\tnlassert(_FileExtensions[a_NoSoundSheetType].empty());\n\t\t_FileExtensions[a_NoSoundSheetType] = \"sound\";\n\t\t_DevSheetIdToName.push_back(std::vector<std::string>());\n\t\t_DevSheetIdToName[0].push_back(\"unknown.sound\");\n\t\tTSheetId id;\n\t\tid.IdInfos.Type = a_NoSoundSheetType;\n\t\tid.IdInfos.Id = _DevSheetIdToName[0].size() - 1;\n\t\tnlassert(id.IdInfos.Id == 0);\n\t\t_DevSheetNameToId[\"unknown.sound\"] = id.Id;\n\t\ta_NoSoundSheetId = true;\n\t}\n#endif\n\n} // init //\n\nvoid CSheetId::initWithoutSheet()\n{\n\tif (_Initialised)\n\t{\n\t\tnlassert(_DontHaveSheetKnowledge);\n\t\treturn;\n\t}\n\n\t_Initialised = true;\n\t_DontHaveSheetKnowledge = true;\n\n\t// Initialize id 0,0 as unknown.unknown\n\tCSheetId unknownunknown = CSheetId(\"unknown.unknown\");\n\tnlassert(unknownunknown == CSheetId::Unknown);\n}\n\n\n\n//-----------------------------------------------\n//\tuninit\n//\n//-----------------------------------------------\nvoid CSheetId::uninit()\n{\n\tdelete [] _AllStrings.Ptr;\n\t_FileExtensions.clear();\n\t_DevTypeNameToId.clear();\n\t_DevSheetIdToName.clear();\n\t_DevSheetNameToId.clear();\n} // uninit //\n\n//-----------------------------------------------\n//\toperator=\n//\n//-----------------------------------------------\nCSheetId& CSheetId::operator=( const CSheetId& sheetId )\n{\n\tif (!_Initialised) init(false);\n\n\tif(this == &sheetId)\n\t{\n\t\treturn *this;\n\t}\n\n\t_Id.Id = sheetId.asInt();\n\n#ifdef NL_DEBUG_SHEET_ID\n\t_DebugSheetName = sheetId._DebugSheetName;\n#endif\n\n    return *this;\n\n\n} // operator= //\n\n\n//-----------------------------------------------\n//\toperator=\n//\n//-----------------------------------------------\nCSheetId& CSheetId::operator=( const string& sheetName )\n{\n\n\tif (!buildSheetId(sheetName))\n\t\t*this = Unknown;\n\n\t// nldebug(\"LIST_SHEET_ID: %s (%s)\", toString().c_str(), sheetName.c_str());\n\n\treturn *this;\n\n} // operator= //\n\n\n//-----------------------------------------------\n//\toperator=\n//\n//-----------------------------------------------\nCSheetId& CSheetId::operator=( uint32 sheetRef )\n{\n\tif (!_Initialised) init(false);\n\n\t_Id.Id = sheetRef;\n\n\treturn *this;\n\n} // operator= //\n\n\n\n//-----------------------------------------------\n//\toperator<\n//\n//-----------------------------------------------\nbool CSheetId::operator < (const CSheetId& sheetRef ) const\n{\n\tif (!_Initialised) init(false);\n\n\tif (_Id.Id < sheetRef.asInt())\n\t{\n\t\treturn true;\n\t}\n\n\treturn false;\n\n} // operator< //\n\n\n\n//-----------------------------------------------\n//\ttoString\n//\n//-----------------------------------------------\nstring CSheetId::toString(bool ifNotFoundUseNumericId) const\n{\n\tif (!_Initialised) init(false);\n\n\tif (_DontHaveSheetKnowledge)\n\t{\n\t\t// FIXME: When someone punches in a fake sheet id this will \n\t\t// fail.\n\t\treturn _DevSheetIdToName[_Id.IdInfos.Type][_Id.IdInfos.Id];\n\t}\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr = _SheetIdToName.find (_Id.Id);\n\tif( itStr != _SheetIdToName.end() )\n\t{\n\t\treturn string((*itStr).second.Ptr);\n\t}\n\telse\n\t{\n#ifdef NL_TEMP_YUBO_NO_SOUND_SHEET_ID\n\t\tif (a_NoSoundSheetId && _Id.IdInfos.Type == a_NoSoundSheetType)\n\t\t{\n\t\t\treturn _DevSheetIdToName[0][_Id.IdInfos.Id];\n\t\t}\n#endif\n\t\t// This nlwarning is commented out because the loggers are mutexed, therefore\n\t\t// you couldn't use toString() within a nlwarning().\n\t\t//nlwarning(\"<CSheetId::toString> The sheet %08x is not in sheet_id.bin\",_Id.Id);\n\t\tif (ifNotFoundUseNumericId)\n\t\t{\n\t\t\treturn NLMISC::toString( \"#%u\", _Id.Id );\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn NLMISC::toString( \"<Sheet %d not found in sheet_id.bin>\", _Id.Id );\n\t\t}\n\t}\n\n} // toString //\n\nvoid CSheetId::serial(NLMISC::IStream\t&f) throw(NLMISC::EStream)\n{\n\tnlassert(!_DontHaveSheetKnowledge);\n\n\tf.serial( _Id.Id );\n\n#ifdef NL_DEBUG_SHEET_ID\n\tCStaticMap<uint32, CChar>::iterator it(_SheetIdToName.find(_Id.Id));\n\tif (it != _SheetIdToName.end())\n\t\t_DebugSheetName = it->second.Ptr;\n\telse\n\t\t_DebugSheetName = NULL;\n#endif\n}\n\nvoid CSheetId::serialString(NLMISC::IStream &f, const std::string &defaultType) throw(NLMISC::EStream)\n{\n\tnlassert(_Initialised);\n\t\n\tif (f.isReading())\n\t{\n\t\tstd::string sheetName;\n\t\tf.serial(sheetName);\n\t\t*this = CSheetId(sheetName, defaultType);\n\t}\n\telse\n\t{\n\t\t// if this assert fails, you may be using an outdated id bin\n\t\tnlassert(*this != CSheetId::Unknown);\n\t\tstd::string sheetName = toString();\n\t\tf.serial(sheetName);\n\t}\n}\n\n\n//-----------------------------------------------\n//\tdisplay\n//\n//-----------------------------------------------\nvoid CSheetId::display()\n{\n\tif (!_Initialised) init(false);\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr;\n\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t{\n\t\t//nlinfo(\"%d %s\",(*itStr).first,(*itStr).second.c_str());\n\t\tnlinfo(\"SHEETID: (%08x %d) %s\",(*itStr).first,(*itStr).first,(*itStr).second.Ptr);\n\t}\n\n} // display //\n\n\n\n//-----------------------------------------------\n//\tdisplay\n//\n//-----------------------------------------------\nvoid CSheetId::display(uint32 type)\n{\n\tif (!_Initialised) init(false);\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr;\n\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t{\n\t\t// work out the type value for this entry in the map\n\t\tTSheetId sheetId;\n\t\tsheetId.Id=(*itStr).first;\n\n\t\t// decide whether or not to display the entry\n\t\tif (type==sheetId.IdInfos.Type)\n\t\t{\n\t\t\t//nlinfo(\"%d %s\",(*itStr).first,(*itStr).second.c_str());\n\t\t\tnlinfo(\"SHEETID: (%08x %d) %s\",(*itStr).first,(*itStr).first,(*itStr).second.Ptr);\n\t\t}\n\t}\n\n} // display //\n\n\n\n//-----------------------------------------------\n//\tbuildIdVector\n//\n//-----------------------------------------------\nvoid CSheetId::buildIdVector(std::vector <CSheetId> &result)\n{\n\tif (!_Initialised) init(false);\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr;\n\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t{\n\t\tresult.push_back( (CSheetId)(*itStr).first );\n\t}\n\n} // buildIdVector //\n\n\n//-----------------------------------------------\n//\tbuildIdVector\n//\n//-----------------------------------------------\nvoid CSheetId::buildIdVector(std::vector <CSheetId> &result, uint32 type)\n{\n\tif (!_Initialised) init(false);\n\tnlassert(type < (1 << (NL_SHEET_ID_TYPE_BITS)));\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr;\n\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t{\n\t\t// work out the type value for this entry in the map\n\t\tTSheetId sheetId;\n\t\tsheetId.Id=(*itStr).first;\n\n\t\t// decide whether or not to use the entry\n\t\tif (type==sheetId.IdInfos.Type)\n\t\t{\n\t\t\tresult.push_back( (CSheetId)sheetId.Id );\n\t\t}\n\t}\n\n} // buildIdVector //\n\n//-----------------------------------------------\n//\tbuildIdVector\n//\n//-----------------------------------------------\nvoid CSheetId::buildIdVector(std::vector <CSheetId> &result, std::vector <std::string> &resultFilenames,uint32 type)\n{\n\tif (!_Initialised) init(false);\n\tnlassert(type < (1 << (NL_SHEET_ID_TYPE_BITS)));\n\n\tCStaticMap<uint32,CChar>::const_iterator itStr;\n\tfor( itStr = _SheetIdToName.begin(); itStr != _SheetIdToName.end(); ++itStr )\n\t{\n\t\t// work out the type value for this entry in the map\n\t\tTSheetId sheetId;\n\t\tsheetId.Id=(*itStr).first;\n\n\t\t// decide whether or not to use the entry\n\t\tif (type==sheetId.IdInfos.Type)\n\t\t{\n\t\t\tresult.push_back( (CSheetId)sheetId.Id );\n\t\t\tresultFilenames.push_back( (*itStr).second.Ptr );\n\t\t}\n\t}\n\n} // buildIdVector //\n\n//-----------------------------------------------\n//\tbuildIdVector\n//\n//-----------------------------------------------\nvoid CSheetId::buildIdVector(std::vector <CSheetId> &result,const std::string &fileExtension)\n{\n\tuint32 type=typeFromFileExtension(fileExtension);\n\tif (type != std::numeric_limits<uint32>::max())\n\t\tbuildIdVector(result, type);\n\n} // buildIdVector //\n\n//-----------------------------------------------\n//\tbuildIdVector\n//\n//-----------------------------------------------\nvoid CSheetId::buildIdVector(std::vector <CSheetId> &result, std::vector <std::string> &resultFilenames,const std::string &fileExtension)\n{\n\tuint32 type=typeFromFileExtension(fileExtension);\n\tif (type != std::numeric_limits<uint32>::max())\n\t\tbuildIdVector(result,resultFilenames, type);\n\n} // buildIdVector //\n\n\n//-----------------------------------------------\n//\ttypeFromFileExtension\n//\n//-----------------------------------------------\nuint32 CSheetId::typeFromFileExtension(const std::string &fileExtension)\n{\n\tif (!_Initialised) init(false);\n\n\tuint i;\n\tfor (i=0;i<_FileExtensions.size();i++)\n\t\tif (toLower(fileExtension)==_FileExtensions[i])\n\t\t\treturn i;\n\n\treturn std::numeric_limits<uint32>::max();\n} // typeFromFileExtension //\n\n\n//-----------------------------------------------\n//\tfileExtensionFromType\n//\n//-----------------------------------------------\nconst std::string &CSheetId::fileExtensionFromType(uint32 type)\n{\n\tif (!_Initialised) init(false);\n\tnlassert(type < (1<<(NL_SHEET_ID_TYPE_BITS)));\n\n\treturn _FileExtensions[type];\n\n} // fileExtensionFromType //\n\n//-----------------------------------------------\n//\tbuild\n//\n//-----------------------------------------------\nvoid\tCSheetId::buildSheetId(uint32 shortId, uint32 type)\n{\n\tnlassert(shortId < (1<<NL_SHEET_ID_ID_BITS));\n\tnlassert(type < (1<<(NL_SHEET_ID_TYPE_BITS)));\n\n\t_Id.IdInfos.Id= shortId;\n\t_Id.IdInfos.Type= type;\n\n#ifdef NL_DEBUG_SHEET_ID\n\tCStaticMap<uint32, CChar>::iterator it(_SheetIdToName.find(_Id.Id));\n\tif (it != _SheetIdToName.end())\n\t{\n\t\t_DebugSheetName = it->second.Ptr;\n\t}\n\telse\n\t\t_DebugSheetName = NULL;\n#endif\n\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/smart_ptr.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/smart_ptr.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// Use a Raw structure, to be sure it is initialized before any constructor calls...\n//CPtrInfo() {Ptr=NULL; RefCount=0x7FFFFFFF; IsNullPtrInfo=true;}\nCRefCount::CPtrInfoBase\t\tCRefCount::NullPtrInfo= {NULL, 0x7FFFFFFF, true};\n\n\n// must not be static\nvoid\tdummy_to_avoid_stupid_4768_smart_ptr_cpp()\n{\n}\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/sstring.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/sstring.h\"\n\nnamespace NLMISC\n{\n\n\tCSString CSString::strtok(\tconst char *separators,\n\t\t\t\t\t\t\t\t\t\tbool useSmartExtensions,\t\t\t// if true then match brackets etc (and refine with following args)\n\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t// - treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// - treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape)\t// - treat \"\"\"\" as '\"')\n\t{\n\t\tif (useSmartExtensions)\n\t\t{\n\t\t\tCSString token;\n\n\t\t\t// split to the first non empty token, or until the this string is empty\n\t\t\twhile (!empty() && token.empty())\n\t\t\t\ttoken = splitToOneOfSeparators(separators,true,useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,true);\n\n\t\t\treturn token;\n\t\t}\n\n\t\tuint i, j;\n\t\tCSString result;\n\n\t\t// skip leading junk\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\t// look for the next character in the 'separator' character list supplied\n\t\t\tfor (j=0;separators[j] && (*this)[i]!=separators[j];++j)\n\t\t\t{}\n\t\t\t// if not found then we're at end of leading junk\n\t\t\tif (!separators[j])\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// copy out everything up to the next separator character\n\t\tfor (;i<size();++i)\n\t\t{\n\t\t\t// look for the next character in the 'separator' character list supplied\n\t\t\tfor (j=0;separators[j] && (*this)[i]!=separators[j];++j)\n\t\t\t{}\n\t\t\t// if not found then we're at end of text chunk\n\t\t\tif (separators[j])\n\t\t\t\tbreak;\n\t\t\tresult+=(*this)[i];\n\t\t}\n\n\t\t// skip trailing junk\n\t\tfor (;i<size();++i)\n\t\t{\n\t\t\t// look for the next character in the 'separator' character list supplied\n\t\t\tfor (j=0;separators[j] && (*this)[i]!=separators[j];++j)\n\t\t\t{}\n\t\t\t// if not found then we're at end of leading junk\n\t\t\tif (!separators[j])\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// delete the treated bit from this string\n\t\t(*this)=substr(i);\n\n\t\treturn result;\n\t}\n\n\n\tCSString CSString::splitToOneOfSeparators(\tconst CSString& separators,\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool truncateThis,\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter,\t// if true tail begins after separator char\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool splitStringAtBrackets)\n\t{\n\t\t// iterate over our string\n\t\tuint32 i;\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\tchar thisChar=(*this)[i];\n\n\t\t\t// if we've found the separator character then all's cool so break out of the loop\n\t\t\tif (separators.contains(thisChar))\n\t\t\t\tbreak;\n\n\t\t\t// if we have a bracket or quote of any type then match to it's matching bracket, quote or whatever\n\t\t\tif (isOpeningDelimiter(thisChar,useAngleBrace) || isStringDelimiter(thisChar))\n\t\t\t{\n\t\t\t\tif (i != 0)\n\t\t\t\t{\n\t\t\t\t\t// we are not at beginning of the string, delimiter is considered as separator\n\t\t\t\t\tif (splitStringAtBrackets)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tuint32 j=i;\n\t\t\t\ti=findMatchingDelimiterPos(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,i);\n\t\t\t\t// if there was a problem then break here\n\t\t\t\tif (j==i)\n\t\t\t\t\tbreak;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// build the return string\n\t\tCSString result=left(i);\n\n\t\t// if need be truncate '*this' before returning\n\t\tif (truncateThis)\n\t\t{\n\t\t\tif (truncateSeparatorCharacter && separators.contains((*this)[i]))\n\t\t\t\t++i;\n\t\t\t*this=leftCrop(i);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitToLineComment(bool truncateThis, bool useSlashStringEscape)\n\t{\n\t\tbool quoteOpen= false;\n\t\tbool escape= false;\n\t\tfor (uint32 i=0;i<size();++i)\n\t\t{\n\t\t\t// if we're escaped then accept the next character blindly\n\t\t\tif (escape)\n\t\t\t{\n\t\t\t\tescape= false;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// do we have an escape?\n\t\t\tif (useSlashStringEscape && operator[](i)=='\\\\')\n\t\t\t{\n\t\t\t\tescape= true;\n\t\t\t}\n\t\t\t// do we have a quote (it is not escaped by definition here)\n\t\t\telse if (operator[](i)=='\\\"')\n\t\t\t{\n\t\t\t\tquoteOpen= !quoteOpen;\n\t\t\t}\n\t\t\t// do we have a comment (not in quotes)\n\t\t\telse if (!quoteOpen && i<size()-1 && operator[](i)=='/' && operator[](i+1)=='/')\n\t\t\t{\n\t\t\t\t// we found a comment so strip string down here\n\t\t\t\tif (truncateThis)\n\t\t\t\t{\n\t\t\t\t\tCSString result= left(i);\n\t\t\t\t\t*this= leftCrop(i);\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\treturn left(i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (truncateThis)\n\t\t{\n\t\t\tCSString result= *this;\n\t\t\tclear();\n\t\t\treturn result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\t}\n\n\tbool CSString::isValidText()\n\t{\n\t\t// setup a handy static lookup table for differentiating valid and invalid text characters\n\t\tstatic bool* tbl=NULL;\n\t\tif (tbl==NULL)\n\t\t{\n\t\t\ttbl= new bool[256];\n\t\t\tfor (uint32 i=0;i<256;++i)\n\t\t\t{\n\t\t\t\ttbl[i]= ((i>32) || isWhiteSpace((char)i));\n\t\t\t}\n\t\t}\n\n\t\t// scan the string for binary characters\n\t\tuint32 i=(uint32)size();\n\t//\twhile (i && !tbl[i-1])\n\t//\t{\n\t//\t\ti--;\n\t//\t}\n\t\twhile (i--)\n\t\t{\n\t\t\tif (!tbl[(uint8)operator[](i)])\n\t\t\t{\n\t\t\t\tnldebug(\"string is not valid text due to character: %u at index: %u\",(uint8)operator[](i),i);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// no binary characters found so return true\n\t\treturn true;\n\t}\n\n\tbool CSString::isValidFileName() const\n\t{\n\t\tif (empty())\n\t\t\treturn false;\n\n\t\tif ((*this)[0]=='\"')\n\t\t{\n\t\t\tif (!isDelimitedMonoBlock(false,false,false))\n\t\t\t\treturn false;\n\n\t\t\t// iterate from size-2 to 1\n\t\t\tfor (uint32 i=(uint32)size()-1; --i;)\n\t\t\t\tif (!isValidFileNameChar((*this)[i]) && (*this)[i]!=' ')\n\t\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// iterate from size-1 to 0\n\t\t\tfor (uint32 i=(uint32)size(); i--;)\n\t\t\t\tif (!isValidFileNameChar((*this)[i]))\n\t\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::isValidUnquotedFileName() const\n\t{\n\t\treturn (CSString('\\\"'+*this+'\\\"')).isValidFileName();\n\t}\n\n\tbool CSString::isValidKeyword() const\n\t{\n\t\tif (empty())\n\t\t\treturn false;\n\n\t\tif (!isValidKeywordFirstChar((*this)[0]))\n\t\t\treturn false;\n\n\t\t// iterate from size-1 to 1\n\t\tfor (uint32 i=(uint32)size(); --i;)\n\t\t\tif (!isValidKeywordChar((*this)[i]))\n\t\t\t\treturn false;\n\n\t\treturn true;\n\t}\n\n\tuint32 CSString::findMatchingDelimiterPos(\tbool useAngleBrace,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tuint32 startPos ) const\n\t{\n\t\tuint32 i=startPos;\n\t\tchar openingDelimiter= (*this)[i];\n\t\tif (isOpeningDelimiter(openingDelimiter,useAngleBrace))\n\t\t{\n\t\t\t// deal with (), [], {} or <> type delimiters\n\t\t\twhile (i<size())\n\t\t\t{\n\t\t\t\t++i;\n\t\t\t\tif(isMatchingDelimiter(openingDelimiter,(*this)[i]))\n\t\t\t\t{\n\t\t\t\t\t// this is it! we've found the matching quote so we're done\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (isOpeningDelimiter((*this)[i],useAngleBrace) || isStringDelimiter((*this)[i]))\n\t\t\t\t{\n\t\t\t\t\tuint32 j=i;\n\t\t\t\t\ti=findMatchingDelimiterPos(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,i);\n\t\t\t\t\tif (j==i)\n\t\t\t\t\t\treturn startPos;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (isClosingDelimiter((*this)[i],useAngleBrace))\n\t\t\t\t{\n\t\t\t\t\t// we've found a closing delimiter that doesn't match our opening delimiter so give up\n\t\t\t\t\treturn startPos;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (isStringDelimiter(openingDelimiter))\n\t\t{\n\t\t\t// deal with \"...\" or '...' type delimiters\n\t\t\twhile (i<size())\n\t\t\t{\n\t\t\t\t++i;\n\t\t\t\tif ((*this)[i]==openingDelimiter)\n\t\t\t\t{\n\t\t\t\t\tif (useRepeatQuoteStringEscape && (*this)[i+1]==openingDelimiter)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we've found a \"\" pair and we're treating it as \\\" equivalent so skip an extra character\n\t\t\t\t\t\t++i;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// this is it! we've found the matching quote so we're done\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (useSlashStringEscape && (*this)[i]=='\\\\')\n\t\t\t\t{\n\t\t\t\t\t// we've found a '\\' character so skip the next character, whatever it is\n\t\t\t\t\t++i;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn i;\n\t}\n\n\tCSString CSString::matchDelimiters(\tbool truncateThis,\n\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape)\t// treat \"\"\"\" as '\"'\n\t{\n\t\t// skip white space\n\t\tuint32 startPos;\n\t\tfor (startPos=0;startPos<size() && isWhiteSpace((*this)[startPos]);++startPos) {}\n\n\t\t// locate the matching brace\n\t\tuint32 matchPos=findMatchingDelimiterPos(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,startPos);\n\n\t\t// if not found give up\n\t\tif (matchPos>=size())\n\t\t{\n\t\t\treturn CSString();\n\t\t}\n\n\t\t// build the return string\n\t\tCSString result=left(matchPos+1);\n\n\t\t// if need be truncate '*this' before returning\n\t\tif (truncateThis)\n\t\t{\n\t\t\t*this=leftCrop(matchPos+1);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitToStringSeparator(\n\t\t\t\t\t\t\t\t\t\t\t\tchar separator,\n\t\t\t\t\t\t\t\t\t\t\t\tbool truncateThis,\n\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter)\t// if true tail begins after separator char\n\t{\n\t\t// iterate over our string\n\t\tuint32 i;\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\tchar thisChar=(*this)[i];\n\n\t\t\t// if we've found the separator character then all's cool so break out of the loop\n\t\t\tif (thisChar==separator)\n\t\t\t\tbreak;\n\n\t\t\t// if we have a bracket or quote of any type then match to it's matching bracket, quote or whatever\n\t\t\tif (isStringDelimiter(thisChar))\n\t\t\t{\n\t\t\t\tuint32 j=i;\n\t\t\t\ti=findMatchingDelimiterPos(false,useSlashStringEscape,useRepeatQuoteStringEscape,i);\n\t\t\t\t// if there was a problem then break here\n\t\t\t\tif (j==i)\n\t\t\t\t\tbreak;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// build the return string\n\t\tCSString result=left(i);\n\n\t\t// if need be truncate '*this' before returning\n\t\tif (truncateThis)\n\t\t{\n\t\t\tif (truncateSeparatorCharacter && separator==(*this)[i])\n\t\t\t\t++i;\n\t\t\t*this=leftCrop(i);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitToSeparator(\tchar separator,\n\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape) const\t// treat \"\"\"\" as '\"'\n\t{\n\t\treturn const_cast<CSString*>(this)->splitToSeparator(separator,false,useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,false);\n\t}\n\n\tCSString CSString::splitToSeparator(\tchar separator,\n\t\t\t\t\t\t\t\t\t\t\t\tbool truncateThis,\n\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool truncateSeparatorCharacter)\t// if true tail begins after separator char\n\t{\n\t\t// iterate over our string\n\t\tuint32 i;\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\tchar thisChar=(*this)[i];\n\n\t\t\t// if we've found the separator character then all's cool so break out of the loop\n\t\t\tif (thisChar==separator)\n\t\t\t\tbreak;\n\n\t\t\t// if we have a bracket or quote of any type then match to it's matching bracket, quote or whatever\n\t\t\tif (isOpeningDelimiter(thisChar,useAngleBrace) || isStringDelimiter(thisChar))\n\t\t\t{\n\t\t\t\tuint32 j=i;\n\t\t\t\ti=findMatchingDelimiterPos(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,i);\n\t\t\t\t// if there was a problem then break here\n\t\t\t\tif (j==i)\n\t\t\t\t\tbreak;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// build the return string\n\t\tCSString result=left(i);\n\n\t\t// if need be truncate '*this' before returning\n\t\tif (truncateThis)\n\t\t{\n\t\t\tif (truncateSeparatorCharacter && separator==(*this)[i])\n\t\t\t\t++i;\n\t\t\t*this=leftCrop(i);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitToOneOfSeparators(\tconst CSString& separators,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape) const\t// treat \"\"\"\" as '\"'\n\t{\n\t\treturn const_cast<CSString*>(this)->splitToOneOfSeparators(separators,false,useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape,false);\n\t}\n\n\n\tbool CSString::isDelimitedMonoBlock(\tbool useAngleBrace,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t ) const\n\t{\n\t\tif (empty())\n\t\t\treturn false;\n\t\tuint32 matchPos=findMatchingDelimiterPos(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape);\n\t\treturn (matchPos==size()-1 && isMatchingDelimiter((*this)[0],(*this)[matchPos]));\n\t}\n\n\tCSString CSString::stripBlockDelimiters(\tbool useAngleBrace,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t ) const\n\t{\n\t\tif (isDelimitedMonoBlock(useAngleBrace,useSlashStringEscape,useRepeatQuoteStringEscape))\n\t\t{\n\t\t\treturn substr(1,size()-2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn *this;\n\t\t}\n\t}\n\n\tbool CSString::splitWords(CVectorSString& result) const\n\t{\n\t\tCSString s=strip();\n\t\twhile(!s.empty())\n\t\t{\n\t\t\tuint32 pre=(uint32)s.size();\n\t\t\tresult.push_back(s.firstWord(true));\n\t\t\tuint32 post=(uint32)s.size();\n\t\t\tif (post>=pre)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::splitWordOrWords(CVectorSString& result,bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tCSString s=*this;\n\t\twhile(!s.empty())\n\t\t{\n\t\t\tuint32 pre=(uint32)s.size();\n\t\t\tresult.push_back(s.firstWordOrWords(true,useSlashStringEscape,useRepeatQuoteStringEscape));\n\t\t\tuint32 post=(uint32)s.size();\n\t\t\tif (post>=pre)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::splitLines(CVectorSString& result) const\n\t{\n\t\tCSString s=*this;\n\n\t\t// make sure we deal with '\\n\\r' style carriage returns cleanly\n\t\tif (s.contains('\\r'))\n\t\t\ts=s.replace(\"\\r\",\"\");\n\n\t\tuint32 it=0;\n\t\tuint32 len= (uint32)s.size();\n\t\twhile(it<len)\n\t\t{\n\t\t\t// extract the text up to the next '\\n'character\n\t\t\tresult.push_back(s.splitToWithIterator('\\n',it));\n\t\t\t// skip the '\\n' character\n\t\t\t++it;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::splitBySeparator(\tchar separator, CVectorSString& result,\n\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,\t// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\tbool skipBlankEntries\t\t\t\t// dont add blank entries to the result vector\n\t\t\t\t\t\t\t\t\t\t ) const\n\t{\n\t\tCSString s=*this;\n\t\twhile(!s.empty())\n\t\t{\n\t\t\tuint32 pre=(uint32)s.size();\n\t\t\tresult.push_back(s.splitToSeparator(separator,true,useAngleBrace,useSlashStringEscape,\n\t\t\t\t\t\t\t\t\t\t\t\tuseRepeatQuoteStringEscape,true));\n\t\t\tif (skipBlankEntries && result.back().empty())\n\t\t\t\tresult.pop_back();\n\t\t\tuint32 post=(uint32)s.size();\n\t\t\tif (post>=pre)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::splitByOneOfSeparators(\tconst CSString& separators, CVectorSString& result,\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useAngleBrace,\t\t\t\t// treat '<' and '>' as brackets\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useSlashStringEscape,\t\t// treat '\\' as escape char so \"\\\"\" == '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool useRepeatQuoteStringEscape,// treat \"\"\"\" as '\"'\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool retainSeparators,\t\t\t// have the separators turn up in the result vector\n\t\t\t\t\t\t\t\t\t\t\t\t\tbool skipBlankEntries\t\t\t// dont add blank entries to the result vector\n\t\t\t\t\t\t\t\t\t\t\t\t ) const\n\t{\n\t\tCSString s=*this;\n\t\twhile (!s.empty() && skipBlankEntries && !retainSeparators && separators.contains(s[0]))\n\t\t\ts= s.leftCrop(1);\n\n\t\twhile(!s.empty())\n\t\t{\n\t\t\tuint32 pre=(uint32)s.size();\n\t\t\tresult.push_back(s.splitToOneOfSeparators(\tseparators,true,useAngleBrace,useSlashStringEscape,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tuseRepeatQuoteStringEscape,!retainSeparators ));\n\n\t\t\t// if we failed to extract a string segment then we must be looking at a separator\n\t\t\tif (result.back().empty())\n\t\t\t{\n\t\t\t\tif (skipBlankEntries && result.back().empty())\n\t\t\t\t\tresult.pop_back();\n\n\t\t\t\tif (!s.empty())\n\t\t\t\t{\n\t\t\t\t\tif (retainSeparators)\n\t\t\t\t\t\tresult.back()=s[0];\n\t\t\t\t\ts=s.leftCrop(1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuint32 post=(uint32)s.size();\n\t\t\tif (post>=pre)\n\t\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tconst CSString& CSString::join(const std::vector<CSString>& strings, const CSString& separator)\n\t{\n\t\tfor (uint32 i=0;i<strings.size();++i)\n\t\t{\n\t\t\t// add in separators before all but the first string\n\t\t\tif (!empty())\n\t\t\t\toperator+=(separator);\n\t\t\t// append next string\n\t\t\toperator+=(strings[i]);\n\t\t}\n\n\t\t// return a ref to ourselves\n\t\treturn *this;\n\t}\n\n\tconst CSString& CSString::join(const std::vector<CSString>& strings, char separator)\n\t{\n\t\tfor (uint32 i=0;i<strings.size();++i)\n\t\t{\n\t\t\t// add in separators before all but the first string\n\t\t\tif (!empty())\n\t\t\t\toperator+=(separator);\n\t\t\t// append next string\n\t\t\toperator+=(strings[i]);\n\t\t}\n\n\t\t// return a ref to ourselves\n\t\treturn *this;\n\t}\n\n\tCSString CSString::strip() const\n\t{\n\t\tCSString result;\n\t\tint i,j;\n\t\tfor (j=(int)size()-1; j>=0 && isWhiteSpace((*this)[j]); --j) {}\n\t\tfor (i=0;\t\t i<j  && isWhiteSpace((*this)[i]); ++i) {}\n\t\tresult=substr(i,j-i+1);\n\t\treturn result;\n\t}\n\n\tCSString CSString::leftStrip() const\n\t{\n\t\tCSString result;\n\t\tint i,j=(int)size()-1;\n\t\tfor (i=0; i<j  && isWhiteSpace((*this)[i]); ++i) {}\n\t\tresult=substr(i,j-i+1);\n\t\treturn result;\n\t}\n\n\tCSString CSString::rightStrip() const\n\t{\n\t\tCSString result;\n\t\tint i=0,j;\n\t\tfor (j=(int)size()-1; j>=0 && isWhiteSpace((*this)[j]); --j) {}\n\t\tresult=substr(i,j-i+1);\n\t\treturn result;\n\t}\n\n\tCSString CSString::toUpper() const\n\t{\n\t\tCSString result;\n\t\tstd::string::const_iterator it;\n\t\tfor (it=begin();it!=end();++it)\n\t\t{\n\t\t\tchar c=(*it);\n\t\t\tif (c>='a' && c<='z')\n\t\t\t\tc^=('a'^'A');\n\t\t\tresult+=c;\n\t\t}\n\t\treturn result;\n\t}\n\n\tCSString CSString::toLower() const\n\t{\n\t\tCSString result;\n\t\tstd::string::const_iterator it;\n\t\tfor (it=begin();it!=end();++it)\n\t\t{\n\t\t\tchar c=(*it);\n\t\t\tif (c>='A' && c<='Z')\n\t\t\t\tc^=('a'^'A');\n\t\t\tresult+=c;\n\t\t}\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitTo(char c) const\n\t{\n\t\tuint i;\n\t\tCSString result;\n\t\tfor (i=0;i<size() && (*this)[i]!=c;++i)\n\t\t\tresult+=(*this)[i];\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitTo(char c,bool truncateThis,bool absorbSeparator)\n\t{\n\t\tuint i;\n\t\tCSString result;\n\t\tfor (i=0;i<size() && (*this)[i]!=c;++i)\n\t\t\tresult+=(*this)[i];\n\n\t\t// remove the result string from the input string if so desired\n\t\tif (truncateThis)\n\t\t{\n\t\t\tif (absorbSeparator)\n\t\t\t\t++i;\n\t\t\tif (i<size())\n\t\t\t\t(*this)=substr(i);\n\t\t\telse\n\t\t\t\tclear();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitTo(const char *s,bool truncateThis)\n\t{\n\t\tuint i;\n\t\tCSString result;\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\t// perform a quick string compare\n\t\t\tint j;\n\t\t\tfor (j=0;s[j]!=0 && s[j]==(&((*this)[i]))[j];++j)\n\t\t\t{\n\t\t\t}\n\t\t\t// if string compare matched then return result so far\n\t\t\tif (s[j]==0)\n\t\t\t{\n\t\t\t\t// remove the result string from the input string if so desired\n\t\t\t\tif (truncateThis)\n\t\t\t\t{\n\t\t\t\t\tif (i+1<size())\n\t\t\t\t\t\t(*this)=substr(i+1);\t// +1 to skip the separator character\n\t\t\t\t\telse\n\t\t\t\t\t\tclear();\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tresult+=(*this)[i];\n\t\t}\n\t\t// we didn't find the separator string so we're returning a copy of the whole string\n\t\tif (truncateThis)\n\t\t\tclear();\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitFrom(char c) const\n\t{\n\t\tCSString result;\n\t\tstd::string::const_iterator it;\n\t\tfor (it=begin();it!=end() && *it!=c;++it)\n\t\t{}\n\t\tif (it!=end())\n\t\t{\n\t\t\t++it;\n\t\t\tfor (;it!=end();++it)\n\t\t\t\tresult+=*it;\n\t\t}\n\t\treturn result;\n\t}\n\n\tCSString CSString::splitFrom(const char *s) const\n\t{\n\t\tuint i;\n\t\tCSString result;\n\t\tfor (i=0;i<size();++i)\n\t\t{\n\t\t\t// perform a quick string compare\n\t\t\tuint j;\n\t\t\tfor (j=0;i+j<size() && s[j]!=0 && s[j]==(*this)[i+j];++j)\n\t\t\t{\n\t\t\t}\n\t\t\t// if string compare matched then build and return a result\n\t\t\tif (s[j]==0)\n\t\t\t{\n\t\t\t\tresult=substr(i+j);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\n\tCSString CSString::firstWord(bool truncateThis)\n\t{\n\t\t// idiot test to avoid accessing index 0 in empty strings\n\t\tif (empty())\n\t\t\treturn CSString();\n\n\t\tCSString result;\n\t\tuint i=0;\n\t\t// skip white space\n\t\tfor (i=0;i<size() && isWhiteSpace((*this)[i]);++i)\n\t\t{}\n\n\t\tif ( ((*this)[i]>='A' && (*this)[i]<='Z') || ((*this)[i]>='a' && (*this)[i]<='z') ||\n\t\t\t ((*this)[i]>='0' && (*this)[i]<='9') || (*this)[i]=='_')\n\t\t{\n\t\t\t// copy out an alpha-numeric string\n\t\t\tfor (;i<(*this).size() &&\n\t\t\t\t( ((*this)[i]>='A' && (*this)[i]<='Z') || ((*this)[i]>='a' && (*this)[i]<='z') ||\n\t\t\t\t  ((*this)[i]>='0' && (*this)[i]<='9') || (*this)[i]=='_')\n\t\t\t\t;++i)\n\t\t\t\tresult+=(*this)[i];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// just take the first character of the input\n\t\t\tresult=(*this)[i];\n\t\t\t++i;\n\t\t}\n\n\t\t// remove the result string from the input string if so desired\n\t\tif (truncateThis)\n\t\t{\n\t\t\tif (i<size())\n\t\t\t\t(*this)=substr(i);\n\t\t\telse\n\t\t\t\tclear();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::firstWordConst() const\n\t{\n\t\treturn const_cast<CSString *>(this)->firstWord();\n\t}\n\n\tCSString CSString::tailFromFirstWord() const\n\t{\n\t\tCSString hold=*this;\n\t\thold.firstWord(true);\n\t\treturn hold;\n\t}\n\n\tunsigned CSString::countWords() const\n\t{\n\t\tunsigned count=0;\n\t\tCSString hold=strip();\n\t\twhile (!hold.empty())\n\t\t{\n\t\t\thold=hold.tailFromFirstWord().strip();\n\t\t\t++count;\n\t\t}\n\t\treturn count;\n\t}\n\n\tCSString CSString::word(uint32 idx) const\n\t{\n\t\tCSString hold=strip();\n\n\t\tfor (unsigned count=0;count<idx;++count)\n\t\t\thold=hold.tailFromFirstWord().strip();\n\n\t\treturn hold.firstWord();\n\t}\n\n\tCSString CSString::firstWordOrWords(bool truncateThis,bool useSlashStringEscape,bool useRepeatQuoteStringEscape)\n\t{\n\t\tuint32 startPos;\n\t\tfor (startPos=0;startPos<size();++startPos)\n\t\t\tif (!isWhiteSpace((*this)[startPos]))\n\t\t\t\tbreak;\n\n\t\tif (isStringDelimiter((*this)[startPos]))\n\t\t{\n\t\t\tuint32 endPos= findMatchingDelimiterPos(false,useSlashStringEscape,useRepeatQuoteStringEscape,startPos);\n\t\t\tCSString result=substr(startPos,endPos-startPos+1);\n\t\t\tresult=result.unquote(useSlashStringEscape,useRepeatQuoteStringEscape);\n\t\t\tif (truncateThis)\n\t\t\t\t*this=leftCrop(endPos+1);\n\t\t\treturn result;\n\t\t}\n\t\telse\n\t\t\treturn firstWord(truncateThis);\n\t}\n\n\tCSString CSString::firstWordOrWordsConst(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\treturn const_cast<CSString *>(this)->firstWordOrWords(useSlashStringEscape,useRepeatQuoteStringEscape);\n\t}\n\n\tCSString CSString::tailFromFirstWordOrWords(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tCSString hold=*this;\n\t\thold.firstWordOrWords(true,useSlashStringEscape,useRepeatQuoteStringEscape);\n\t\treturn hold;\n\t}\n\n\tunsigned CSString::countWordOrWords(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tunsigned count=0;\n\t\tCSString hold=strip();\n\t\twhile (!hold.empty())\n\t\t{\n\t\t\thold=hold.tailFromFirstWordOrWords(useSlashStringEscape,useRepeatQuoteStringEscape).strip();\n\t\t\t++count;\n\t\t}\n\t\treturn count;\n\t}\n\n\tCSString CSString::wordOrWords(uint32 idx,bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tCSString hold=strip();\n\n\t\tfor (unsigned count=0;count<idx;++count)\n\t\t\thold=hold.tailFromFirstWordOrWords(useSlashStringEscape,useRepeatQuoteStringEscape).strip();\n\n\t\treturn hold.firstWordOrWords(useSlashStringEscape,useRepeatQuoteStringEscape);\n\t}\n\n\n\tCSString CSString::firstLine(bool truncateThis)\n\t{\n\t\treturn splitTo('\\n',truncateThis);\n\t}\n\n\tCSString CSString::firstLineConst() const\n\t{\n\t\treturn const_cast<CSString *>(this)->firstLine();\n\t}\n\n\tCSString CSString::tailFromFirstLine() const\n\t{\n\t\tCSString hold=*this;\n\t\thold.firstLine(true);\n\t\treturn hold;\n\t}\n\n\tunsigned CSString::countLines() const\n\t{\n\t\tunsigned count=0;\n\t\tCSString hold=strip();\n\t\twhile (!hold.empty())\n\t\t{\n\t\t\thold=hold.tailFromFirstLine().strip();\n\t\t\t++count;\n\t\t}\n\t\treturn count;\n\t}\n\n\tCSString CSString::line(uint32 idx) const\n\t{\n\t\tCSString hold=strip();\n\n\t\tfor (unsigned count=0;count<idx;++count)\n\t\t\thold= hold.tailFromFirstLine().strip();\n\n\t\treturn hold.firstLine();\n\t}\n\n\n\tCSString CSString::quote(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tCSString result;\n\n\t\tresult+='\\\"';\n\t\tfor (uint32 i=0;i<size();++i)\n\t\t{\n\t\t\tswitch ((*this)[i])\n\t\t\t{\n\t\t\tcase '\\\"':\n\t\t\t\tif (useSlashStringEscape)\n\t\t\t\t{\n\t\t\t\t\tresult+=\"\\\\\\\"\";\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telse if (useRepeatQuoteStringEscape)\n\t\t\t\t{\n\t\t\t\t\tresult+=\"\\\"\\\"\";\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '\\\\':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\\\\\\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\a':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\a\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\b':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\b\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\f':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\f\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\n':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\n\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\r':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\r\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\t':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\t\";\tcontinue;\t}\tbreak;\n\t\t\tcase '\\v':\tif (useSlashStringEscape)\t{\tresult+=\"\\\\v\";\tcontinue;\t}\tbreak;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif ((signed char)(*this)[i]<32 && useSlashStringEscape)\n\t\t\t\t{\n\t\t\t\t\tresult+=NLMISC::toString(\"\\\\x%02x\",(unsigned char)(*this)[i]);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tresult+=(*this)[i];\n\t\t}\n\t\tresult+='\\\"';\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::quoteIfNotQuoted(\tbool useSlashStringEscape, bool useRepeatQuoteStringEscape ) const\n\t{\n\t\tif (empty()||(*this)[0]!='\\\"'||!isDelimitedMonoBlock(false,useSlashStringEscape,useRepeatQuoteStringEscape))\n\t\t\treturn quote(useSlashStringEscape,useRepeatQuoteStringEscape);\n\n\t\treturn *this;\n\t}\n\n\tCSString CSString::quoteIfNotAtomic(\tbool useSlashStringEscape, bool useRepeatQuoteStringEscape ) const\n\t{\n\t\tif (empty())\n\t\t\treturn \"\\\"\\\"\";\n\n\t\tuint32 i=1;\n\t\tif (((*this)[0]>='0' && (*this)[0]<='9')||(*this)[0]=='-')\n\t\t{\n\t\t\tfor (i=1;i<size();++i)\n\t\t\t\tif ((*this)[i]<'0' || (*this)[i]>'9')\n\t\t\t\t\tbreak;\n\t\t}\n\t\telse if ( CSString::isValidKeywordFirstChar((*this)[0]) )\n\t\t{\n\t\t\tfor (i=1;i<size();++i)\n\t\t\t\tif (!CSString::isValidFileNameChar((*this)[i]))\n\t\t\t\t\tbreak;\n\t\t}\n\t\telse if ((*this)[0]=='\\\"' && isDelimitedMonoBlock(false,useSlashStringEscape,useRepeatQuoteStringEscape))\n\t\t{\n\t\t\ti=(uint32)size();\n\t\t}\n\t\tif (i!=size())\n\t\t\treturn quote(useSlashStringEscape,useRepeatQuoteStringEscape);\n\n\t\treturn *this;\n\t}\n\n\tCSString CSString::unquote(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tCSString result=stripBlockDelimiters(false,useSlashStringEscape,useRepeatQuoteStringEscape);\n\t\tuint32 i,j;\n\t\tfor (i=0,j=0;i<result.size();++i,++j)\n\t\t{\n\t\t\tif (useSlashStringEscape && result[i]=='\\\\')\n\t\t\t{\n\t\t\t\t++i;\n\t\t\t\tif (i<result.size())\n\t\t\t\t{\n\t\t\t\t\tswitch(result[i])\n\t\t\t\t\t{\n\t\t\t\t\tcase 'a': result[i]='\\a'; break;\n\t\t\t\t\tcase 'b': result[i]='\\b'; break;\n\t\t\t\t\tcase 'f': result[i]='\\f'; break;\n\t\t\t\t\tcase 'n': result[i]='\\n'; break;\n\t\t\t\t\tcase 'r': result[i]='\\r'; break;\n\t\t\t\t\tcase 't': result[i]='\\t'; break;\n\t\t\t\t\tcase 'v': result[i]='\\v'; break;\n\n\t\t\t\t\tcase '0':\n\t\t\t\t\tcase '1':\n\t\t\t\t\tcase '2':\n\t\t\t\t\tcase '3':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchar hold=result[i]-'0';\n\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\tif (i<result.size() && result[i]>='0' && result[i]<='7')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thold=8*hold+(result[i]-'0');\n\t\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\t\tif (i<result.size() && result[i]>='0' && result[i]<='7')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\thold=8*hold+(result[i]-'0');\n\t\t\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult[j]=hold;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase '4':\n\t\t\t\t\tcase '5':\n\t\t\t\t\tcase '6':\n\t\t\t\t\tcase '7':\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchar hold=result[i]-'0';\n\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\tif (i<result.size() && result[i]>='0' && result[i]<='7')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thold=8*hold+(result[i]-'0');\n\t\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult[j]=hold;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'x':\n\t\t\t\t\t\tif (i+1<result.size() && isHexDigit(result[i+1]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tchar hold=convertHexDigit(result[i+1]);\n\t\t\t\t\t\t\ti+=2;\n\t\t\t\t\t\t\tif (i<result.size() && isHexDigit(result[i]))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\thold=16*hold+convertHexDigit(result[i]);\n\t\t\t\t\t\t\t\t++i;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tresult[j]=hold;\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (useRepeatQuoteStringEscape && (i+1<result.size()) && result[i]=='\\\"' && result[i+1]=='\\\"')\n\t\t\t\t++i;\n\t\t\tif (i<result.size())\n\t\t\t\tresult[j]=result[i];\n\t\t}\n\t\tif (i!=j)\n\t\t\tresult.resize(j);\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::unquoteIfQuoted(bool useSlashStringEscape,bool useRepeatQuoteStringEscape) const\n\t{\n\t\tif (isQuoted())\n\t\t\treturn unquote(useSlashStringEscape,useRepeatQuoteStringEscape);\n\t\telse\n\t\t\treturn *this;\n\t}\n\n\tCSString CSString::encodeXML(bool isParameter) const\n\t{\n\t\tCSString result;\n\n\t\tfor (uint32 i=0;i<size();++i)\n\t\t{\n\t\t\tunsigned char c= (*this)[i];\n\t\t\tswitch(c)\n\t\t\t{\n\t\t\t// special xml characters\n\t\t\tcase '\\\"':\tresult+=\"&quot;\";\tcontinue;\n\t\t\tcase '&':\tresult+=\"&amp;\";\tcontinue;\n\t\t\tcase '<':\tresult+=\"&lt;\";\t\tcontinue;\n\t\t\tcase '>':\tresult+=\"&gt;\";\t\tcontinue;\n\n\t\t\t// characters that are not allowed inside a parameter block\n\t\t\tcase '\\n':\n\t\t\tcase '\\r':\n\t\t\tcase '\\t':\n\t\t\t\tif (!isParameter) { result+=c; continue; }\n\t\t\t}\n\n\t\t\t// hex coding for extended characters\n\t\t\tif (c<32 || c>127)\n\t\t\t{\n\t\t\t\tresult+=\"&#x\";\n\t\t\t\tresult+= ((c>>4)>=10? 'A'+(c>>4)-10: '0'+(c>>4));\n\t\t\t\tresult+= ((c&15)>=10? 'A'+(c&15)-10: '0'+(c&15));\n\t\t\t\tresult+=\";\";\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// all the special cases are catered for... treat this as a normal character\n\t\t\tresult+=c;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tCSString CSString::decodeXML() const\n\t{\n\t\tCSString result;\n\n\t\tfor (uint32 i=0;i<size();++i)\n\t\t{\n\t\t\tbreakable\n\t\t\t{\n\t\t\t\tif((*this)[i]=='&')\n\t\t\t\t{\n\t\t\t\t\t// special xml characters\n\t\t\t\t\tif (substr(i+1,5)==\"quot;\")\t{ i+=5; result+='\\\"'; continue; }\n\t\t\t\t\tif (substr(i+1,4)==\"amp;\")\t{ i+=4; result+='&'; continue; }\n\t\t\t\t\tif (substr(i+1,3)==\"lt;\")\t{ i+=3; result+='<'; continue; }\n\t\t\t\t\tif (substr(i+1,3)==\"gt;\")\t{ i+=3; result+='>'; continue; }\n\n\t\t\t\t\t// hex coding for extended characters\n\t\t\t\t\tif ((size()-i)>=5)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ((*this)[i+1]!='#') break;\n\t\t\t\t\t\tif (((*this)[i+2]|('a'-'A'))!='x') break;\n\t\t\t\t\t\t// setup j to point at the first character following \"&#x\"[0-9|a-f]*\n\t\t\t\t\t\tuint32 j; for (j=i+3;j<size();++j) if (!isHexDigit((*this)[j])) break;\n\t\t\t\t\t\t// make sure that at least 1 hex character was found\n\t\t\t\t\t\tif (j==i+3) break;\n\t\t\t\t\t\t// make sure have the terminating ';' to complete the token: \"&#x\"[0-9|a-f]*\";\"\n\t\t\t\t\t\tif (j>=size() || (*this)[j]!=';') break;\n\t\t\t\t\t\t// make sure that the value we have is only one or 2 hex digits\n\t\t\t\t\t\tif (j>=i+6) nlwarning(\"Truncating extended char code '%s\",(substr(i,j-i+1)+\"' => using \"+substr(j-2,2)).c_str());\n\n\t\t\t\t\t\t// convert the 1 or 2 last hex digits to a char value\n\t\t\t\t\t\tchar c=0;\n\t\t\t\t\t\tif (j>=i+5)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// if we have 2 or more digits then grab the high digit\n\t\t\t\t\t\t\tc+= convertHexDigit( (*this)[j-2] )*16;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tc+= convertHexDigit( (*this)[j-1] );\n\n\t\t\t\t\t\t// append our new character to the result string\n\t\t\t\t\t\tresult+=c;\n\t\t\t\t\t\t// move 'i' forward to point at the ';' .. the for(...) will increment i to point to next char\n\t\t\t\t\t\ti=j;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// all the special cases are catered for... treat this as a normal character\n\t\t\tresult+=(*this)[i];\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tbool CSString::isEncodedXML() const\n\t{\n\t\tbool foundToken= false;\n\n\t\tfor (uint32 i=(uint32)size();i--;)\n\t\t{\n\t\t\tswitch((*this)[i])\n\t\t\t{\n\t\t\t// decoded special xml characters\n\t\t\tcase '\\\"':\n\t\t\tcase '<':\n\t\t\tcase '>':\n\t\t\tcase '&':\n\t\t\t\treturn false;\n\n\t\t\tcase ';':\n\t\t\t\t// encoded special xml characters\n\t\t\t\tif (i>=5 && substr(i-5,5)==\"&quot\")\t{ foundToken= true; i-=5; break; }\n\t\t\t\tif (i>=4 && substr(i-4,4)==\"&amp\")\t{ foundToken= true; i-=4; break; }\n\t\t\t\tif (i>=3 && substr(i-3,3)==\"&lt\")\t{ foundToken= true; i-=3; break; }\n\t\t\t\tif (i>=3 && substr(i-3,3)==\"&gt\")\t{ foundToken= true; i-=3; break; }\n\n\t\t\t\t// hex coding for extended characters\n\t\t\t\tif (i>=3 && isHexDigit((*this)[i-1]))\n\t\t\t\t{\n\t\t\t\t\tuint32 j,k;\n\t\t\t\t\t// locate the start of a potential hex string\n\t\t\t\t\tfor (j=i;j--;)\n\t\t\t\t\t\tif ((*this)[j]=='&')\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t// make sure that at least 5 chars were found for: &#x0;\n\t\t\t\t\tif (i-j<4) continue;\n\t\t\t\t\t// make sure we have '&#x' at the start\n\t\t\t\t\tif ((*this)[j]!='&') continue;\n\t\t\t\t\tif ((*this)[j+1]!='#') continue;\n\t\t\t\t\tif ((*this)[j+2]!='x') continue;\n\t\t\t\t\t// ensure that the remainder between the leading '&#x' and trailing ';' are hex digits\n\t\t\t\t\tfor (k=j+3;k<i;++k)\n\t\t\t\t\t\tif (!isHexDigit((*this)[k]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (k!=i) continue;\n\t\t\t\t\t// skip the characters that were matched - i now refs the opening '&'\n\t\t\t\t\ti=j;\n\t\t\t\t\tfoundToken= true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn foundToken;\n\t}\n\n\tbool CSString::isXMLCompatible(bool isParameter) const\n\t{\n\t\tfor (uint32 i=(uint32)size();i--;)\n\t\t{\n\t\t\tswitch((*this)[i])\n\t\t\t{\n\t\t\t// decoded special xml characters\n\t\t\tcase '\\\"':\n\t\t\tcase '<':\n\t\t\tcase '>':\n\t\t\tcase '&':\n\t\t\t\treturn false;\n\n\t\t\tcase ';':\n\t\t\t\t// encoded special xml characters\n\t\t\t\tif (i>=5 && substr(i-5,5)==\"&quot\")\t{ i-=5; continue; }\n\t\t\t\tif (i>=4 && substr(i-4,4)==\"&amp\")\t{ i-=4; continue; }\n\t\t\t\tif (i>=3 && substr(i-3,3)==\"&lt\")\t{ i-=3; continue; }\n\t\t\t\tif (i>=3 && substr(i-3,3)==\"&gt\")\t{ i-=3; continue; }\n\n\t\t\t\t// hex coding for extended characters\n\t\t\t\tif (i>=3 && isHexDigit((*this)[i-1]))\n\t\t\t\t{\n\t\t\t\t\tuint32 j,k;\n\t\t\t\t\t// locate the start of a potential hex string\n\t\t\t\t\tfor (j=i;j--;)\n\t\t\t\t\t\tif ((*this)[j]=='&')\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t// make sure that at least 5 chars were found for: &#x0;\n\t\t\t\t\tif (i-j<4) continue;\n\t\t\t\t\t// make sure we have '&#x' at the start\n\t\t\t\t\tif ((*this)[j]!='&') continue;\n\t\t\t\t\tif ((*this)[j+1]!='#') continue;\n\t\t\t\t\tif ((*this)[j+2]!='x') continue;\n\t\t\t\t\t// ensure that the remainder between the leading '&#x' and trailing ';' are hex digits\n\t\t\t\t\tfor (k=j+3;k<i;++k)\n\t\t\t\t\t\tif (!isHexDigit((*this)[k]))\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\tif (k!=i) continue;\n\t\t\t\t\t// skip the characters that were matched - i now refs the opening '&'\n\t\t\t\t\ti=j;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t// characters that are not allowed inside a parameter block\n\t\t\tcase '\\n':\n\t\t\tcase '\\r':\n\t\t\tcase '\\t':\n\t\t\t\tif (!isParameter) continue;\n\t\t\t}\n\n\t\t\tif ((uint8)((*this)[i])>127 || (uint8)((*this))[i]<32)\n\t\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tCSString CSString::replace(const char *toFind,const char *replacement) const\n\t{\n\t\t// just bypass the problems that can cause a crash...\n\t\tif (toFind==NULL || *toFind==0)\n\t\t\treturn *this;\n\n\t\tstd::string::size_type i,j;\n\t\tCSString result;\n\t\tfor (i=0;i<size();)\n\t\t{\n\t\t\t// string compare toFind against (*this)+i ...\n\t\t\tfor (j=0;toFind[j];++j)\n\t\t\t\tif ((*this)[i+j]!=toFind[j])\n\t\t\t\t\tbreak;\n\t\t\t// if strings were identical then j reffers to ASCIIZ terminator at end of 'toFind'\n\t\t\tif (toFind[j]==0)\n\t\t\t{\n\t\t\t\tif (replacement!=NULL)\n\t\t\t\t\tresult+=replacement;\n\t\t\t\ti+=j;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tresult+=(*this)[i];\n\t\t\t\t++i;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tstd::string::size_type CSString::find(const char *toFind, std::string::size_type startLocation) const\n\t{\n\t//\tconst char *constStr = c_str();\n\n\t\t// just bypass the problems that can cause a crash...\n\t\tif (toFind==NULL || *toFind==0 || startLocation>=size())\n\t\t\treturn std::string::npos;\n\n\t\tstd::string::size_type i,j;\n\t\tfor (i=startLocation;i<size();++i)\n\t\t{\n\t\t\t// string compare toFind against (*this)+i ...\n\t\t\tfor (j=0;toFind[j];++j)\n\t\t\t\tif ((i+j>=size()) || (*this)[i+j]!=toFind[j])\n\t\t\t\t\tbreak;\n\t\t\t// if strings were identical then we're done\n\t\t\tif (toFind[j]==0)\n\t\t\t\treturn i;\n\t\t}\n\t\treturn std::string::npos;\n\t}\n\n\t/// Find index at which a sub-string starts (case NOT sensitive) - if sub-string not found then returns string::npos\n\tstd::string::size_type CSString::findNS(const char *toFind, std::string::size_type startLocation) const\n\t{\n\t\tconst char *constStr = c_str();\n\n\t\t// just bypass the problems that can cause a crash...\n\t\tif (toFind==NULL || *toFind==0 || startLocation>=size())\n\t\t\treturn std::string::npos;\n\n\t\tstd::string::size_type i,j;\n\t\tfor (i=startLocation;i<size();++i)\n\t\t{\n\t\t\t// string compare toFind against (*this)+i ...\n\t\t\tfor (j=0;toFind[j];++j)\n\t\t\t\tif ((i+j>=size()) || tolower(constStr[i+j])!=tolower(toFind[j]))\n\t\t\t\t\tbreak;\n\t\t\t// if strings were identical then we're done\n\t\t\tif (toFind[j]==0)\n\t\t\t\treturn i;\n\t\t}\n\t\treturn std::string::npos;\n\t}\n\n\tbool CSString::contains(const char *toFind) const\n\t{\n\t\treturn find(toFind)!=std::string::npos;\n\t}\n\n\tbool CSString::contains(int character) const\n\t{\n\t\tfor (const_iterator it=begin();it!=end();++it)\n\t\t\tif ((*it)==character)\n\t\t\t\treturn true;\n\n\t\treturn false;\n\t}\n\n\tstatic const uint32 MaxUint32= ~0u;\n\tstatic const uint32 MaxUint32LastDigit= MaxUint32-(MaxUint32/10)*10;\n\tstatic const uint32 MaxUint32PreLastDigit= (MaxUint32/10);\n\n\tstatic const uint32 MaxNegSint32= ~0u/2+1;\n\tstatic const uint32 MaxNegSint32LastDigit= MaxNegSint32-(MaxNegSint32/10)*10;\n\tstatic const uint32 MaxNegSint32PreLastDigit= (MaxNegSint32/10);\n\n\tstatic const uint32 MaxPosSint32= ~0u/2;\n\tstatic const uint32 MaxPosSint32LastDigit= MaxPosSint32-(MaxPosSint32/10)*10;\n\tstatic const uint32 MaxPosSint32PreLastDigit= (MaxPosSint32/10);\n\n\tint CSString::atoi() const\n\t{\n\t\tif (empty())\n\t\t\treturn 0;\n\n\t\tbool neg= false;\n\t\tuint32 result;\n\t\tswitch (*begin())\n\t\t{\n\t\t\tcase '+':\tresult=0; break;\n\t\t\tcase '-':\tresult=0; neg=true; break;\n\t\t\tcase '0':\tresult=0; break;\n\t\t\tcase '1':\tresult=1; break;\n\t\t\tcase '2':\tresult=2; break;\n\t\t\tcase '3':\tresult=3; break;\n\t\t\tcase '4':\tresult=4; break;\n\t\t\tcase '5':\tresult=5; break;\n\t\t\tcase '6':\tresult=6; break;\n\t\t\tcase '7':\tresult=7; break;\n\t\t\tcase '8':\tresult=8; break;\n\t\t\tcase '9':\tresult=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t}\n\n\t\tfor (const_iterator it=begin()+1;it!=end();++it)\n\t\t{\n\t\t\tuint32 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\t\tcase '0':\toffset=0; break;\n\t\t\t\tcase '1':\toffset=1; break;\n\t\t\t\tcase '2':\toffset=2; break;\n\t\t\t\tcase '3':\toffset=3; break;\n\t\t\t\tcase '4':\toffset=4; break;\n\t\t\t\tcase '5':\toffset=5; break;\n\t\t\t\tcase '6':\toffset=6; break;\n\t\t\t\tcase '7':\toffset=7; break;\n\t\t\t\tcase '8':\toffset=8; break;\n\t\t\t\tcase '9':\toffset=9; break;\n\t\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (!neg)\n\t\t\t{\n\t\t\t\tif (result>=MaxUint32PreLastDigit/*~0u/10*/)\n\t\t\t\t{\n\t\t\t\t\tif (result>MaxUint32PreLastDigit || offset>MaxUint32LastDigit)\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (result>=MaxNegSint32PreLastDigit /*~0u/20+1*/)\n\t\t\t\t{\n\t\t\t\t\tif (result>MaxNegSint32PreLastDigit || offset>MaxNegSint32LastDigit)\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn neg? -(sint32)result: (sint32)result;\n\t}\n\n\tsint32 CSString::atosi() const\n\t{\n\t\tif (empty())\n\t\t\treturn 0;\n\n\t\tbool neg= false;\n\t\tuint32 result;\n\t\tswitch (*begin())\n\t\t{\n\t\t\tcase '+':\tresult=0; break;\n\t\t\tcase '-':\tresult=0; neg=true; break;\n\t\t\tcase '0':\tresult=0; break;\n\t\t\tcase '1':\tresult=1; break;\n\t\t\tcase '2':\tresult=2; break;\n\t\t\tcase '3':\tresult=3; break;\n\t\t\tcase '4':\tresult=4; break;\n\t\t\tcase '5':\tresult=5; break;\n\t\t\tcase '6':\tresult=6; break;\n\t\t\tcase '7':\tresult=7; break;\n\t\t\tcase '8':\tresult=8; break;\n\t\t\tcase '9':\tresult=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t}\n\n\t\tfor (const_iterator it=begin()+1;it!=end();++it)\n\t\t{\n\t\t\tuint32 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\t\tcase '0':\toffset=0; break;\n\t\t\t\tcase '1':\toffset=1; break;\n\t\t\t\tcase '2':\toffset=2; break;\n\t\t\t\tcase '3':\toffset=3; break;\n\t\t\t\tcase '4':\toffset=4; break;\n\t\t\t\tcase '5':\toffset=5; break;\n\t\t\t\tcase '6':\toffset=6; break;\n\t\t\t\tcase '7':\toffset=7; break;\n\t\t\t\tcase '8':\toffset=8; break;\n\t\t\t\tcase '9':\toffset=9; break;\n\t\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (result>=MaxPosSint32PreLastDigit /*~0u/20*/)\n\t\t\t{\n\t\t\t\tif (result>MaxPosSint32PreLastDigit || offset>(neg?MaxNegSint32LastDigit:MaxPosSint32LastDigit))\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn neg? -(sint32)result: (sint32)result;\n\t}\n\n\tuint32 CSString::atoui() const\n\t{\n\t\tuint32 result=0;\n\t\tfor (const_iterator it=begin();it!=end();++it)\n\t\t{\n\t\t\tuint32 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\tcase '0':\toffset=0; break;\n\t\t\tcase '1':\toffset=1; break;\n\t\t\tcase '2':\toffset=2; break;\n\t\t\tcase '3':\toffset=3; break;\n\t\t\tcase '4':\toffset=4; break;\n\t\t\tcase '5':\toffset=5; break;\n\t\t\tcase '6':\toffset=6; break;\n\t\t\tcase '7':\toffset=7; break;\n\t\t\tcase '8':\toffset=8; break;\n\t\t\tcase '9':\toffset=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (result>=MaxUint32PreLastDigit/*~0u/10*/)\n\t\t\t{\n\t\t\t\tif (result>MaxUint32PreLastDigit || offset>MaxUint32LastDigit)\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn result;\n\t}\n\n\tstatic const uint64 MaxUint64= (uint64)0-(uint64)1;\n\tstatic const uint64 MaxUint64LastDigit= MaxUint64-(MaxUint64/10)*10;\n\tstatic const uint64 MaxUint64PreLastDigit= (MaxUint64/10);\n\n\tstatic const uint64 MaxNegSint64= ((uint64)0-(uint64)1)/2+1;\n\tstatic const uint64 MaxNegSint64LastDigit= MaxNegSint64-(MaxNegSint64/10)*10;\n\tstatic const uint64 MaxNegSint64PreLastDigit= (MaxNegSint64/10);\n\n\tstatic const uint64 MaxPosSint64= ((uint64)0-(uint64)1)/2;\n\tstatic const uint64 MaxPosSint64LastDigit= MaxPosSint64-(MaxPosSint64/10)*10;\n\tstatic const uint64 MaxPosSint64PreLastDigit= (MaxPosSint64/10);\n\n\tsint64 CSString::atoi64() const\n\t{\n\t\tif (empty())\n\t\t\treturn 0;\n\n\t\tbool neg= false;\n\t\tuint64 result;\n\t\tswitch (*begin())\n\t\t{\n\t\t\tcase '+':\tresult=0; break;\n\t\t\tcase '-':\tresult=0; neg=true; break;\n\t\t\tcase '0':\tresult=0; break;\n\t\t\tcase '1':\tresult=1; break;\n\t\t\tcase '2':\tresult=2; break;\n\t\t\tcase '3':\tresult=3; break;\n\t\t\tcase '4':\tresult=4; break;\n\t\t\tcase '5':\tresult=5; break;\n\t\t\tcase '6':\tresult=6; break;\n\t\t\tcase '7':\tresult=7; break;\n\t\t\tcase '8':\tresult=8; break;\n\t\t\tcase '9':\tresult=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t}\n\n\t\tfor (const_iterator it=begin()+1;it!=end();++it)\n\t\t{\n\t\t\tuint64 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\t\tcase '0':\toffset=0; break;\n\t\t\t\tcase '1':\toffset=1; break;\n\t\t\t\tcase '2':\toffset=2; break;\n\t\t\t\tcase '3':\toffset=3; break;\n\t\t\t\tcase '4':\toffset=4; break;\n\t\t\t\tcase '5':\toffset=5; break;\n\t\t\t\tcase '6':\toffset=6; break;\n\t\t\t\tcase '7':\toffset=7; break;\n\t\t\t\tcase '8':\toffset=8; break;\n\t\t\t\tcase '9':\toffset=9; break;\n\t\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (!neg)\n\t\t\t{\n\t\t\t\tif (result>=MaxUint64PreLastDigit/*~0u/10*/)\n\t\t\t\t{\n\t\t\t\t\tif (result>MaxUint64PreLastDigit || offset>MaxUint64LastDigit)\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (result>=MaxNegSint64PreLastDigit /*~0u/20+1*/)\n\t\t\t\t{\n\t\t\t\t\tif (result>MaxNegSint64PreLastDigit || offset>MaxNegSint64LastDigit)\n\t\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn neg? -(sint64)result: (sint64)result;\n\t}\n\n\tsint64 CSString::atosi64() const\n\t{\n\t\tif (empty())\n\t\t\treturn 0;\n\n\t\tbool neg= false;\n\t\tuint64 result;\n\t\tswitch (*begin())\n\t\t{\n\t\t\tcase '+':\tresult=0; break;\n\t\t\tcase '-':\tresult=0; neg=true; break;\n\t\t\tcase '0':\tresult=0; break;\n\t\t\tcase '1':\tresult=1; break;\n\t\t\tcase '2':\tresult=2; break;\n\t\t\tcase '3':\tresult=3; break;\n\t\t\tcase '4':\tresult=4; break;\n\t\t\tcase '5':\tresult=5; break;\n\t\t\tcase '6':\tresult=6; break;\n\t\t\tcase '7':\tresult=7; break;\n\t\t\tcase '8':\tresult=8; break;\n\t\t\tcase '9':\tresult=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t}\n\n\t\tfor (const_iterator it=begin()+1;it!=end();++it)\n\t\t{\n\t\t\tuint64 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\t\tcase '0':\toffset=0; break;\n\t\t\t\tcase '1':\toffset=1; break;\n\t\t\t\tcase '2':\toffset=2; break;\n\t\t\t\tcase '3':\toffset=3; break;\n\t\t\t\tcase '4':\toffset=4; break;\n\t\t\t\tcase '5':\toffset=5; break;\n\t\t\t\tcase '6':\toffset=6; break;\n\t\t\t\tcase '7':\toffset=7; break;\n\t\t\t\tcase '8':\toffset=8; break;\n\t\t\t\tcase '9':\toffset=9; break;\n\t\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (result>=MaxPosSint64PreLastDigit /*~0u/20*/)\n\t\t\t{\n\t\t\t\tif (result>MaxPosSint64PreLastDigit || offset>(neg?MaxNegSint64LastDigit:MaxPosSint64LastDigit))\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn neg? -(sint64)result: (sint64)result;\n\t}\n\n\tuint64 CSString::atoui64() const\n\t{\n\t\tuint64 result=0;\n\t\tfor (const_iterator it=begin();it!=end();++it)\n\t\t{\n\t\t\tuint64 offset;\n\t\t\tswitch (*it)\n\t\t\t{\n\t\t\tcase '0':\toffset=0; break;\n\t\t\tcase '1':\toffset=1; break;\n\t\t\tcase '2':\toffset=2; break;\n\t\t\tcase '3':\toffset=3; break;\n\t\t\tcase '4':\toffset=4; break;\n\t\t\tcase '5':\toffset=5; break;\n\t\t\tcase '6':\toffset=6; break;\n\t\t\tcase '7':\toffset=7; break;\n\t\t\tcase '8':\toffset=8; break;\n\t\t\tcase '9':\toffset=9; break;\n\t\t\tdefault:\treturn 0;\n\t\t\t}\n\t\t\tif (result>=MaxUint64PreLastDigit/*~0u/10*/)\n\t\t\t{\n\t\t\t\tif (result>MaxUint64PreLastDigit || offset>MaxUint64LastDigit)\n\t\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tresult=10*result+offset;\n\t\t}\n\t\treturn result;\n\t}\n\n\tdouble CSString::atof() const\n\t{\n\t\tdouble val;\n\t\tNLMISC::fromString(*this, val);\n\t\treturn val;\n\t}\n\n\tbool CSString::readFromFile(const CSString& fileName)\n\t{\n\t\tFILE* file;\n\t\tfile=fopen(fileName.c_str(),\"rb\");\n\t\tif (file==NULL)\n\t\t{\n\t\t\tclear();\n\t\t\t// There was previously a warning displayed here but that was incorrect as it is defined that refaFromFile returns an empty result if the file is not found\n\t\t\t// nlwarning(\"Failed to open file for reading: %s\",fileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tresize(NLMISC::CFile::getFileSize(file));\n\t\tuint32 bytesRead=(uint32)fread(const_cast<char*>(data()),1,size(),file);\n\t\tfclose(file);\n\t\tif (bytesRead!=size())\n\t\t{\n\t\t\tresize(bytesRead);\n\t\t\tnlwarning(\"Failed to read file contents (requested %u bytes but fread returned %u) for file:%s\",size(),bytesRead,fileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tbool CSString::writeToFile(const CSString& fileName) const\n\t{\n\t\tFILE* file;\n\t\tfile=fopen(fileName.c_str(),\"wb\");\n\t\tif (file==NULL)\n\t\t{\n\t\t\tnlwarning(\"Failed to open file for writing: %s\",fileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tuint32 recordsWritten=(uint32)fwrite(const_cast<char*>(data()),size(),1,file);\n\t\tfclose(file);\n\t\tif (recordsWritten!=1)\n\t\t{\n\t\t\tnlwarning(\"Failed to write file contents (requested %u bytes but fwrite returned %u) for file:%s\",size(),recordsWritten,fileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tnldebug(\"CSSWTF Wrote %u bytes to file %s\",size(),fileName.c_str());\n\t\treturn true;\n\t}\n\n\tbool CSString::writeToFileIfDifferent(const CSString& fileName) const\n\t{\n\t\t// if the file exists...\n\t\tif (NLMISC::CFile::fileExists(fileName))\n\t\t{\n\t\t\t// the file exists so check it's the right size\n\t\t\tif (NLMISC::CFile::getFileSize(fileName)==size())\n\t\t\t{\n\t\t\t\t// the file is the right size so read its data from disk...\n\t\t\t\tCSString hold;\n\t\t\t\thold.readFromFile(fileName);\n\t\t\t\t// check whether data read from file and our own data are identical\n\t\t\t\tif (hold.size()==size() && memcmp(&hold[0],&(*this)[0],size())==0)\n\t\t\t\t{\n\t\t\t\t\t// data is identical so drop out\n\t\t\t\t\tnldebug(\"CSSWTF Request to write data to file %s IGNORED because file already contains correct data\",fileName.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// the file didn't already exist or content\n\t\treturn writeToFile(fileName);\n\t}\n\n} // namespace NLMISC\n\n\n\n"
  },
  {
    "path": "code/nel/src/misc/stdmisc.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n"
  },
  {
    "path": "code/nel/src/misc/stdmisc.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef NL_STDMISC_H\n#define NL_STDMISC_H\n\n#include <algorithm>\n#include <cmath>\n#include <csignal>\n#include <cstdarg>\n#include <cstddef>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <ctime>\n#include <deque>\n#include <exception>\n#include <fstream>\n#include <iomanip>\n#include <iostream>\n#include <limits>\n#include <list>\n#include <map>\n#include <memory>\n#include <numeric>\n#include <set>\n#include <string>\n#include <typeinfo>\n#include <utility>\n#include <vector>\n\n#include <nel/misc/types_nl.h>\n\n#ifdef NL_OS_WINDOWS\n#\tdefine WIN32_LEAN_AND_MEAN\n#\tdefine _WIN32_WINDOWS 0x0410\n#\tifndef _WIN32_WINNT\n#\t\tdefine _WIN32_WINNT 0x0400\n#\tendif\n#\tifndef NL_COMP_MINGW\n#\t\tdefine WINVER 0x0400\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <WinSock2.h>\n#\tinclude <Windows.h>\n#endif\n\n#endif // NL_STDMISC_H\n"
  },
  {
    "path": "code/nel/src/misc/stl_block_allocator.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/stl_block_allocator.h\"\n\n// remove stupid VC6 warnings\nvoid foo_stl_block_allocator_cpp() {}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/stl_block_list.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/stl_block_list.h\"\n\n// remove stupid VC6 warnings\nvoid foo_stl_block_list_cpp() {}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/stop_watch.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/stop_watch.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n/*\n * Constructor\n */\nCStopWatch::CStopWatch( uint queueLength ) :\n\t_BeginTime( 0 ),\n\t_ElapsedTicks( 0 ),\n\t_SumTicks( 0 ),\n\t_MeasurementNumber( 0 ),\n\t_Queue(),\n\t_QLength( queueLength )\n{}\n\n\n/*\n * Begin measurement\n */\nvoid\tCStopWatch::start()\n{\n\t_BeginTime = CTime::getPerformanceTime();\n\t_ElapsedTicks = 0;\n}\n\n\n/*\n * Pause\n */\nvoid\tCStopWatch::pause()\n{\n\t_ElapsedTicks += (TTickDuration)(CTime::getPerformanceTime() - _BeginTime);\n}\n\n\n/*\n * Resume\n */\nvoid\tCStopWatch::resume()\n{\n\t_BeginTime = CTime::getPerformanceTime();\n}\n\n\n/*\n * Add time (in TTicks unit) to the current measurement\n */\nvoid\tCStopWatch::addTime( TTickDuration t )\n{\n\t_ElapsedTicks += t;\n}\n\n\n/*\n * End measurement\n */\nvoid\tCStopWatch::stop()\n{\n\t_ElapsedTicks += (TTickDuration)(CTime::getPerformanceTime() - _BeginTime);\n\n\t// Setup average\n\t_SumTicks += _ElapsedTicks;\n\t++_MeasurementNumber;\n\n\t// Setup partial average\n\tif ( _QLength != 0 )\n\t{\n\t\t_Queue.push_back( _ElapsedTicks );\n\t\tif ( _Queue.size() > _QLength )\n\t\t{\n\t\t\t_Queue.pop_front();\n\t\t}\n\t}\n}\n\n\n/*\n * Add an external duration (in TTicks unit) to the average queue\n */\nvoid\tCStopWatch::addMeasurement( TTickDuration t )\n{\n\t// Setup average\n\t_SumTicks += t;\n\t++_MeasurementNumber;\n\n\t// Setup partial average\n\tif ( _QLength != 0 )\n\t{\n\t\t_Queue.push_back( t );\n\t\tif ( _Queue.size() > _QLength )\n\t\t{\n\t\t\t_Queue.pop_front();\n\t\t}\n\t}\n\n}\n\n\n/*\n * Elapsed time in millisecond (call it after stop())\n */\nTMsDuration\tCStopWatch::getDuration() const\n{\n\treturn (TMsDuration)(CTime::ticksToSecond( _ElapsedTicks ) * 1000.0);\n}\n\n\n/*\n * Average of the queueLength last durations (using the queueLength argument specified in the constructor)\n */\nTMsDuration\tCStopWatch::getPartialAverage() const\n{\n\tif (_Queue.size() == 0)\n\t\treturn (TMsDuration)0;\n\telse\n\t\treturn (TMsDuration)(CTime::ticksToSecond( accumulate( _Queue.begin(), _Queue.end(), 0 ) / _Queue.size() ) * 1000.0);\n}\n\n\n/*\n * Average of the duration\n */\nTMsDuration\tCStopWatch::getAverageDuration() const\n{\n\treturn (TMsDuration)(CTime::ticksToSecond( _SumTicks / _MeasurementNumber ) * 1000.0);\n}\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/stream.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/mem_stream.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n// ======================================================================================================\n// ======================================================================================================\n// EStream.\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nEStream::EStream( const IStream &f ) : Exception( \"In Stream: \" + f.getStreamName() + string(\": Stream Error\") )\n{\n\tStreamName= f.getStreamName();\n}\n\nEStream::EStream( const IStream &f, const std::string& str )\n : Exception( \"In Stream: \" + f.getStreamName() + \": \" + str )\n{\n\tStreamName= f.getStreamName();\n}\n\nEInvalidDataStream::EInvalidDataStream(const char *msg, uint size)\n: EStream( NLMISC::toString( msg, size ) )\n{}\n\n\nEStreamOverflow::EStreamOverflow( const char *msg, uint size )\n : EStream( NLMISC::toString( msg, size ) )\n{}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// IStream.\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nbool\tIStream::_ThrowOnOlder=false;\nbool\tIStream::_ThrowOnNewer=true;\n\n\n// ======================================================================================================\nvoid\tIStream::setVersionException(bool throwOnOlder, bool throwOnNewer)\n{\n\t_ThrowOnOlder=throwOnOlder;\n\t_ThrowOnNewer=throwOnNewer;\n}\n\n// ======================================================================================================\nvoid\tIStream::getVersionException(bool &throwOnOlder, bool &throwOnNewer)\n{\n\tthrowOnOlder=_ThrowOnOlder;\n\tthrowOnNewer=_ThrowOnNewer;\n}\n\n\n\n/*\n * Copy constructor\n */\nIStream::IStream( const IStream& other )\n{\n\toperator=( other );\n\n\t// By default, mode _XML is off\n\t_XML = false;\n}\n\n\n/*\n * Assignment operator\n */\nIStream& IStream::operator=( const IStream& other )\n{\n\t_InputStream = other._InputStream;\n\tresetPtrTable();\n\treturn *this;\n}\n\nvoid IStream::swap(IStream &other)\n{\n\tstd::swap(_InputStream, other._InputStream);\n\tstd::swap(_NextSerialPtrId, other._NextSerialPtrId);\n\t_IdMap.swap(other._IdMap);\n\tstd::swap(_XML, other._XML);\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nvoid\t\t\tIStream::serialIStreamable(IStreamable* &ptr)\n{\n\tuint64\tnode=0;\n\n\t// Open a node\n\txmlPushBegin (\"POLYPTR\");\n\n\tif(isReading())\n\t{\n\t\t// First attribute name\n\t\txmlSetAttrib (\"id\");\n\n\t\tserial(node);\n\n\t\tif(node==0)\n\t\t{\n\t\t\tptr=NULL;\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tItIdMap\tit;\n\t\t\tit= _IdMap.find(node);\n\n\t\t\t// Test if object already created/read.\n\t\t\tif( it==_IdMap.end() )\n\t\t\t{\n\t\t\t\t// Read the class name.\n\t\t\t\tstring\tclassName;\n\n\t\t\t\t// Second attribute name\n\t\t\t\txmlSetAttrib (\"class\");\n\n\t\t\t\tserial(className);\n\n\t\t\t\t// Close the node header\n\t\t\t\txmlPushEnd ();\n\n\t\t\t\t// Construct object.\n\t\t\t\tptr= dynamic_cast<IStreamable*> (CClassRegistry::create(className));\n\t\t\t\tif(ptr==NULL)\n\t\t\t\t#ifdef NL_DEBUG\n\t\t\t\t\tthrow EUnregisteredClass(className);\n\t\t\t\t#else\n\t\t\t\t\tthrow EUnregisteredClass();\n\t\t\t\t#endif\n\n\n\t\t\t\t#ifdef NL_DEBUG\n\t\t\t\t\tnlassert(CClassRegistry::checkObject(ptr));\n\t\t\t\t#endif\n\n\t\t\t\t// Insert the node.\n\t\t\t\t_IdMap.insert( ValueIdMap(node, ptr) );\n\n\t\t\t\t// Read the object!\n\t\t\t\tptr->serial(*this);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tptr= static_cast<IStreamable*>(it->second);\n\n\t\t\t\t// Close the node header\n\t\t\t\txmlPushEnd ();\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tif(ptr==NULL)\n\t\t{\n\t\t\tnode= 0;\n\n\t\t\t// First attribute name\n\t\t\txmlSetAttrib (\"id\");\n\n\t\t\tserial(node);\n\n\t\t\t// Close the node header\n\t\t\txmlPushEnd ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Assume that prt size is an int size\n\t\t\t//#ifdef NL_DEBUG\n\t\t\t//\tnlassert(sizeof(uint) == sizeof(void *));\n\t\t\t//#endif\n\n\t\t\tItIdMap\tit;\n\t\t\tit = _IdMap.find((uint64)/*(uint)*/ptr);\n\n\t\t\t// Test if object has been already written\n\t\t\tif( it==_IdMap.end() )\n\t\t\t{\n\t\t\t\t// Not yet written\n\n\t\t\t\t// Get the next available ID\n\t\t\t\tnode = _NextSerialPtrId++;\n\n\t\t\t\t// Serial the id\n\t\t\t\txmlSetAttrib (\"id\");\n\t\t\t\tserial(node);\n\n\t\t\t\t// Insert the pointer in the map with the id\n\t\t\t\t_IdMap.insert( ValueIdMap((uint64)/*(uint)*/ptr, (void*)/*(uint)*/node) );\n\n\t\t\t\t#ifdef NL_DEBUG\n\t\t\t\t\tnlassert(CClassRegistry::checkObject(ptr));\n\t\t\t\t#endif\n\n\t\t\t\t// Write the class name.\n\t\t\t\tstring\tclassName=ptr->getClassName();\n\n\t\t\t\t// Second attribute name\n\t\t\t\txmlSetAttrib (\"class\");\n\t\t\t\tserial(className);\n\n\t\t\t\t// Close the node header\n\t\t\t\txmlPushEnd ();\n\n\t\t\t\t// Write the object!\n\t\t\t\tptr->serial(*this);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Write only the object id\n\t\t\t\txmlSetAttrib (\"id\");\n\t\t\t\tnode = (uint64)/*(uint)*/(it->second);\n\t\t\t\tserial(node);\n\t\t\t\txmlPushEnd ();\n\t\t\t}\n\t\t}\n\t}\n\n\t// Close the node\n\txmlPop ();\n}\n// ======================================================================================================\nvoid\t\t\tIStream::resetPtrTable()\n{\n\t_IdMap.clear();\n\t_NextSerialPtrId = 1;\t\t// Start at 1 because 0 is the NULL pointer\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n\n// ======================================================================================================\nuint IStream::serialVersion(uint currentVersion)\n{\n\tuint8\tb=0;\n\tuint32\tv=0;\n\tuint\tstreamVersion;\n\n\t// Open the node\n\txmlPush (\"VERSION\");\n\n\tif(isReading())\n\t{\n\t\tserial(b);\n\t\tif(b==0xFF)\n\t\t\tserial(v);\n\t\telse\n\t\t\tv=b;\n\t\tstreamVersion=v;\n\n\t\t// Exception test.\n\t\tif(_ThrowOnOlder && streamVersion < currentVersion)\n\t\t\tthrow EOlderStream(*this);\n\t\tif(_ThrowOnNewer && streamVersion > currentVersion)\n\t\t\tthrow ENewerStream(*this);\n\t}\n\telse\n\t{\n\t\tv= streamVersion=currentVersion;\n\t\tif(v>=0xFF)\n\t\t{\n\t\t\tb=0xFF;\n\t\t\tserial(b);\n\t\t\tserial(v);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tb= (uint8)v;\n\t\t\tserial(b);\n\t\t}\n\t}\n\n\t// Close the node\n\txmlPop ();\n\n\treturn streamVersion;\n}\n\n\n// ======================================================================================================\n// ======================================================================================================\n// ======================================================================================================\n\n// ======================================================================================================\nvoid\t\t\tIStream::serialCont(vector<uint8> &cont)\n{\n\tsint32\tlen=0;\n\tif(isReading())\n\t{\n\t\tserial(len);\n\n\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\tcheckStreamSize(len);\n\n\t\t// one block serial\n\t\tcont.resize(len);\n\t\tif (len != 0)\n\t\t\tserialBuffer( (uint8*)&(*cont.begin()) , len);\n\t}\n\telse\n\t{\n\t\tlen= (sint32)cont.size();\n\t\tserial(len);\n\t\tif (len != 0)\n\t\t\tserialBuffer( (uint8*)&(*cont.begin()) ,  len);\n\t}\n}\n// ======================================================================================================\nvoid\t\t\tIStream::serialCont(vector<sint8> &cont)\n{\n\tsint32\tlen=0;\n\tif(isReading())\n\t{\n\t\tserial(len);\n\n\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\tcheckStreamSize(len);\n\n\t\t// one block serial\n\t\tcont.resize(len);\n\t\tif (len != 0)\n\t\t\tserialBuffer( (uint8*)&(*cont.begin()) , len);\n\t}\n\telse\n\t{\n\t\tlen= (sint32)cont.size();\n\t\tserial(len);\n\t\tif (len != 0)\n\t\t\tserialBuffer( (uint8*)&(*cont.begin()) ,  len);\n\t}\n}\n// ======================================================================================================\nvoid\t\t\tIStream::serialCont(vector<bool> &cont)\n{\n\tsint32\tlen=0;\n\tvector<uint8>\tvec;\n\n\tif(isReading())\n\t{\n\t\tserial(len);\n\n\t\t// check stream holds enough bytes (avoid STL to crash on resize)\n\t\tcheckStreamSize(len/8);\n\n\t\t// One Block Serial\n\t\tcont.resize(len);\n\n\t\tif (len != 0)\n\t\t{\n\t\t\t// read as uint8*.\n\t\t\tsint\tlb= (len+7)/8;\n\t\t\tvec.resize(lb);\n\t\t\tserialBuffer( (uint8*)&(*vec.begin()) ,  lb);\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\tuint\tbit= (vec[i>>3]>>(i&7)) & 1;\n\t\t\t\tcont[i]= bit?true:false;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tlen= (sint32)cont.size();\n\t\tserial(len);\n\n\t\tif (len != 0)\n\t\t{\n\t\t\t// write as uint8*.\n\t\t\tsint\tlb= (len+7)/8;\n\t\t\tvec.resize(lb);\n\t\t\tfill_n(vec.begin(), lb, 0);\n\t\t\tfor(sint i=0;i<len;i++)\n\t\t\t{\n\t\t\t\tuint\tbit= cont[i]?1:0;\n\t\t\t\tvec[i>>3]|= bit<<(i&7);\n\t\t\t}\n\t\t\tserialBuffer( (uint8*)&(*vec.begin()) ,  lb);\n\t\t}\n\t}\n\n}\n// ======================================================================================================\nbool\t\t\tIStream::seek (sint32 offset, TSeekOrigin origin) const\n{\n\tthrow ESeekNotSupported(*this);\n}\n// ======================================================================================================\nsint32\t\t\tIStream::getPos () const\n{\n\tthrow ESeekNotSupported(*this);\n}\n\n// ======================================================================================================\nvoid\t\t\tIStream::setInOut(bool inputStream)\n{\n\t_InputStream= inputStream;\n}\n\n\n// ======================================================================================================\nstring\t\t\tIStream::getStreamName() const\n{\n\treturn \"\";\n}\n\n\n// ======================================================================================================\nvoid\t\t\tIStream::setXMLMode (bool on)\n{\n\t_XML = on;\n}\n\n\n/*\n * Serial memstream, bitmemstream...\n */\nvoid\tIStream::serialMemStream( CMemStream &b )\n{\n\tuint32 len=0;\n\n\t// Serialize length\n\tif ( isReading() )\n\t{\n\t\t// fill b with data from this\n\t\tserial (len);\n\t\tserialBuffer (b.bufferToFill (len), len);\n\t\tb.resetBufPos ();\n\t}\n\telse\n\t{\n\t\t// fill this with data from b\n\t\tlen = b.length();\n\n\t\tserial( len );\n\t\tserialBuffer( (uint8*) b.buffer (), len );\n\t}\n}\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/string_common.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/string_common.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nstring addSlashR (string str)\n{\n\tstring formatedStr;\n\t// replace \\n with \\r\\n\n\tfor (uint i = 0; i < str.size(); i++)\n\t{\n\t\tif (str[i] == '\\n' && i > 0 && str[i-1] != '\\r')\n\t\t{\n\t\t\tformatedStr += '\\r';\n\t\t}\n\t\tformatedStr += str[i];\n\t}\n\treturn formatedStr;\n}\n\nstring removeSlashR (string str)\n{\n\tstring formatedStr;\n\t// replace \\n with \\r\\n\n\tfor (uint i = 0; i < str.size(); i++)\n\t{\n\t\tif (str[i] != '\\r')\n\t\t\tformatedStr += str[i];\n\t}\n\treturn formatedStr;\n}\n\n}\n"
  },
  {
    "path": "code/nel/src/misc/string_id_array.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/string_id_array.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_string_id_array_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/string_mapper.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/string_mapper.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nCStringMapper\tCStringMapper::_GlobalMapper;\n\n\n// ****************************************************************************\nCStringMapper::CStringMapper()\n{\n\t_EmptyId = new string;\n\t*_EmptyId = \"\";\n}\n\n// ****************************************************************************\nCStringMapper *CStringMapper::createLocalMapper()\n{\n\treturn new CStringMapper;\n}\n\n// ****************************************************************************\nTStringId CStringMapper::localMap(const std::string &str)\n{\n\tif (str.size() == 0)\n\t\treturn 0;\n\n\tCAutoFastMutex\tautomutex(&_Mutex);\n\n\tstring *pStr = new string;\n\t*pStr = str;\n\n\tstd::set<string*,CCharComp>::iterator it = _StringTable.find(pStr);\n\n\tif (it == _StringTable.end())\n\t{\n\t\t_StringTable.insert(pStr);\n\t}\n\telse\n\t{\n\t\tdelete pStr;\n\t\tpStr = (*it);\n\t}\n\treturn (TStringId)pStr;\n}\n\n// ***************************************************************************\nvoid CStringMapper::localSerialString(NLMISC::IStream &f, TStringId &id)\n{\n\tstd::string\tstr;\n\tif(f.isReading())\n\t{\n\t\tf.serial(str);\n\t\tid= localMap(str);\n\t}\n\telse\n\t{\n\t\tstr= localUnmap(id);\n\t\tf.serial(str);\n\t}\n}\n\n// ****************************************************************************\nvoid CStringMapper::localClear()\n{\n\tCAutoFastMutex\tautomutex(&_Mutex);\n\n\tstd::set<string*,CCharComp>::iterator it = _StringTable.begin();\n\twhile (it != _StringTable.end())\n\t{\n\t\tstring *ptrTmp = (*it);\n\t\tdelete ptrTmp;\n\t\tit++;\n\t}\n\t_StringTable.clear();\n\tdelete _EmptyId;\n}\n\n// ****************************************************************************\n// CStaticStringMapper\n// ****************************************************************************\n\n// ****************************************************************************\nTSStringId CStaticStringMapper::add(const std::string &str)\n{\n\tnlassert(!_MemoryCompressed);\n\tstd::map<std::string, TSStringId>::iterator it = _TempStringTable.find(str);\n\tif (it == _TempStringTable.end())\n\t{\n\t\t_TempStringTable.insert(pair<string,TSStringId>(str,_IdCounter));\n\t\t_TempIdTable.insert(pair<TSStringId,string>(_IdCounter,str));\n\t\t_IdCounter++;\n\t\treturn _IdCounter-1;\n\t}\n\telse\n\t{\n\t\treturn it->second;\n\t}\n}\n\n// ****************************************************************************\nbool CStaticStringMapper::isAdded(const std::string &str) const\n{\n\tnlassert(!_MemoryCompressed);\n\treturn _TempStringTable.count(str) != 0;\n}\n\n// ****************************************************************************\nvoid CStaticStringMapper::memoryUncompress()\n{\n\tstd::map<std::string, TSStringId>\ttempStringTable;\n\tstd::map<TSStringId, std::string>\ttempIdTable;\n\tfor(uint k = 0; k < _IdToStr.size(); ++k)\n\t{\n\t\ttempStringTable[_IdToStr[k]] = (TSStringId) k;\n\t\ttempIdTable[(TSStringId) k] = _IdToStr[k];\n\t}\n\tdelete [] _AllStrings;\n\t_AllStrings = NULL;\n\tcontReset(_IdToStr);\n\t_TempStringTable.swap(tempStringTable);\n\t_TempIdTable.swap(tempIdTable);\n\t_MemoryCompressed = false;\n}\n\n// ****************************************************************************\nvoid CStaticStringMapper::memoryCompress()\n{\n\t_MemoryCompressed = true;\n\tstd::map<TSStringId, std::string>::iterator it = _TempIdTable.begin();\n\n\tuint nTotalSize = 0;\n\tuint32 nNbStrings = 0;\n\twhile (it != _TempIdTable.end())\n\t{\n\t\tnTotalSize += (uint)it->second.size() + 1;\n\t\tnNbStrings++;\n\t\tit++;\n\t}\n\n\t_AllStrings = new char[nTotalSize];\n\t_IdToStr.resize(nNbStrings);\n\tnNbStrings = 0;\n\tnTotalSize = 0;\n\tit = _TempIdTable.begin();\n\twhile (it != _TempIdTable.end())\n\t{\n\t\tstrcpy(_AllStrings + nTotalSize, it->second.c_str());\n\t\t_IdToStr[nNbStrings] = _AllStrings + nTotalSize;\n\t\tnTotalSize += (uint)it->second.size() + 1;\n\t\tnNbStrings++;\n\t\tit++;\n\t}\n\tcontReset(_TempStringTable);\n\tcontReset(_TempIdTable);\n}\n\n// ****************************************************************************\nconst char *CStaticStringMapper::get(TSStringId stringId)\n{\n\tif (_MemoryCompressed)\n\t{\n\t\tnlassert(stringId < _IdToStr.size());\n\t\treturn _IdToStr[stringId];\n\t}\n\telse\n\t{\n\t\tstd::map<TSStringId, std::string>::iterator it = _TempIdTable.find(stringId);\n\t\tif (it != _TempIdTable.end())\n\t\t\treturn it->second.c_str();\n\t\telse\n\t\t\treturn NULL;\n\t}\n}\n\n// ****************************************************************************\nvoid CStaticStringMapper::clear()\n{\n\tcontReset(_TempStringTable);\n\tcontReset(_TempIdTable);\n\tdelete [] _AllStrings;\n\tcontReset(_IdToStr);\n\n\t_IdCounter = 0;\n\t_AllStrings = NULL;\n\t_MemoryCompressed = false;\n\tadd(\"\");\n}\n\n// ****************************************************************************\nvoid CStaticStringMapper::serial(IStream &f, TSStringId &strId) throw(EStream)\n{\n\tstd::string tmp;\n\tif (f.isReading())\n\t{\n\t\tf.serial(tmp);\n\t\tstrId = add(tmp);\n\t}\n\telse\n\t{\n\t\ttmp = get(strId);\n\t\tf.serial(tmp);\n\t}\n}\n\n// ****************************************************************************\nvoid CStaticStringMapper::serial(IStream &f, std::vector<TSStringId> &strIdVect) throw(EStream)\n{\n\tstd::vector<std::string> vsTmp;\n\tstd::string sTmp;\n\t// Serialize class components.\n\tif (f.isReading())\n\t{\n\t\tf.serialCont(vsTmp);\n\t\tstrIdVect.resize(vsTmp.size());\n\t\tfor(uint i = 0; i < vsTmp.size(); ++i)\n\t\t\tstrIdVect[i] = add(vsTmp[i]);\n\t\t\t}\n\telse\n\t{\n\t\tvsTmp.resize(strIdVect.size());\n\t\tfor (uint i = 0; i < vsTmp.size(); ++i)\n\t\t\tvsTmp[i] = get(strIdVect[i]);\n\t\tf.serialCont(vsTmp);\n\n\t}\n}\n\n\n\n} // namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/system_info.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/system_info.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <WinNT.h>\n#\tinclude <tchar.h>\n#\tinclude <intrin.h>\n#\tdefine nlcpuid(regs, idx) __cpuid(regs, idx)\n#else\n#\tinclude <sys/types.h>\n#\tinclude <sys/stat.h>\n#\tinclude <sys/sysctl.h>\n#\tinclude <fcntl.h>\n#\tinclude <unistd.h>\n#\tinclude <cerrno>\n#\tifdef NL_CPU_INTEL\n#\t\tinclude <cpuid.h>\n#\t\tdefine nlcpuid(regs, idx) __cpuid(idx, regs[0], regs[1], regs[2], regs[3])\n#\tendif // NL_CPU_INTEL\n#endif // NL_OS_WINDOWS\n\n#include \"nel/misc/system_info.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/variable.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n#ifdef NL_OS_FREEBSD\n#define PROC_BASE_PATH \"/usr/compat/linux/proc\"\n#elif defined(NL_OS_UNIX)\n#define PROC_BASE_PATH \"/proc\"\n#endif\n\n#ifdef NL_OS_UNIX\n\tstatic string getCpuInfo(const string &colname)\n\t{\n\t\tif (colname.empty())\n\t\t\treturn \"\";\n\n\t\tint fd = open(PROC_BASE_PATH\"/cpuinfo\", O_RDONLY);\n\t\tif (fd == -1)\n\t\t{\n\t\t\tnlwarning (\"SI: Can't open \" PROC_BASE_PATH \"/cpuinfo: %s\", strerror (errno));\n\t\t\treturn \"\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tchar buffer[4096+1];\n\t\t\tuint32 len = read(fd, buffer, sizeof(buffer)-1);\n\t\t\tclose(fd);\n\t\t\tbuffer[len] = '\\0';\n\n\t\t\tvector<string> splitted;\n\t\t\texplode(string(buffer), string(\"\\n\"), splitted, true);\n\n\t\t\tstd::string value;\n\n\t\t\tfor(uint32 i = 0; i < splitted.size(); i++)\n\t\t\t{\n\t\t\t\tvector<string> sline;\n\t\t\t\texplode(splitted[i], string(\":\"), sline, true);\n\t\t\t\tif(sline.size() == 2 && trim(sline[0]) == colname)\n\t\t\t\t{\n\t\t\t\t\tvalue = sline[1];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!value.empty())\n\t\t\t\treturn trim(value);\n\t\t}\n\t\tnlwarning (\"SI: Can't find the colname '%s' in \" PROC_BASE_PATH \"/cpuinfo\", colname.c_str());\n\t\treturn \"\";\n\t}\n\n\t// return the value of the colname in bytes from /proc/meminfo\n\tstatic uint64 getSystemMemory (const string &colname)\n\t{\n\t\tif (colname.empty())\n\t\t\treturn 0;\n\n\t\tint fd = open(PROC_BASE_PATH\"/meminfo\", O_RDONLY);\n\t\tif (fd == -1)\n\t\t{\n\t\t\tnlwarning (\"SI: Can't open \" PROC_BASE_PATH \"/meminfo: %s\", strerror (errno));\n\t\t\treturn 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tchar buffer[4096+1];\n\t\t\tuint32 len = read(fd, buffer, sizeof(buffer)-1);\n\t\t\tclose(fd);\n\t\t\tbuffer[len] = '\\0';\n\n\t\t\tvector<string> splitted;\n\t\t\texplode(string(buffer), string(\"\\n\"), splitted, true);\n\n\t\t\tfor(uint32 i = 0; i < splitted.size(); i++)\n\t\t\t{\n\t\t\t\tvector<string> sline;\n\t\t\t\texplode(splitted[i], string(\" \"), sline, true);\n\t\t\t\tif(sline.size() == 3 && sline[0] == colname)\n\t\t\t\t{\n\t\t\t\t\tuint64 val = atoiInt64(sline[1].c_str());\n\t\t\t\t\tif(sline[2] == \"kB\") val *= 1024;\n\t\t\t\t\treturn val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tnlwarning (\"SI: Can't find the colname '%s' in \" PROC_BASE_PATH \"/meminfo\", colname.c_str());\n\t\treturn 0;\n\t}\n#endif // NL_OS_UNIX\n\n#if defined(NL_OS_MAC) || defined(NL_OS_FREEBSD)\nstatic sint32 getsysctlnum(const string &name)\n{\n\tsint32 value = 0;\n\tsize_t len = sizeof(value);\n\tif(sysctlbyname(name.c_str(), &value, &len, NULL, 0) != 0)\n\t{\n\t\tnlwarning(\"SI: Can't get '%s' from sysctl: %s\", name.c_str(), strerror (errno));\n\t}\n\treturn value;\n}\n\nstatic sint64 getsysctlnum64(const string &name)\n{\n\tsint64 value = 0;\n\tsize_t len = sizeof(value);\n\tif(sysctlbyname(name.c_str(), &value, &len, NULL, 0) != 0)\n\t{\n\t\tnlwarning(\"SI: Can't get '%s' from sysctl: %s\", name.c_str(), strerror (errno));\n\t}\n\treturn value;\n}\n\nstatic string getsysctlstr(const string &name)\n{\n\tstring value(\"Unknown\");\n\tsize_t len;\n\tchar *p;\n\tif(sysctlbyname(name.c_str(), NULL, &len, NULL, 0) == 0)\n\t{\n\t\tp = (char*)malloc(len);\n\t\tif(sysctlbyname(name.c_str(), p, &len, NULL, 0) == 0)\n\t\t{\n\t\t\tvalue = p;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"SI: Can't get '%s' from sysctl: %s\", name.c_str(), strerror (errno));\n\t\t}\n\t\tfree(p);\n\t}\n\telse\n\t{\n\t\tnlwarning(\"SI: Can't get '%s' from sysctl: %s\", name.c_str(), strerror (errno));\n\t}\n\treturn value;\n}\n#endif // NL_OS_MAC || NL_OS_FREEBSD\n\nstring CSystemInfo::getOS()\n{\n\tstring OSString = \"Unknown\";\n\n#ifdef NL_OS_WINDOWS\n\n\ttypedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);\n\ttypedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);\n\n\tSYSTEM_INFO si;\n\tPGNSI pGNSI;\n\tPGPI pGPI;\n\tOSVERSIONINFOEX osvi;\n\tBOOL bOsVersionInfoEx;\n\tconst int BUFSIZE = 80;\n\n\t// Try calling GetVersionEx using the OSVERSIONINFOEX structure.\n\t// If that fails, try using the OSVERSIONINFO structure.\n\n\tZeroMemory(&si, sizeof(SYSTEM_INFO));\n\tZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));\n\tosvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\n\n\tbOsVersionInfoEx = GetVersionExA ((OSVERSIONINFO *) &osvi);\n\n\tif(!bOsVersionInfoEx)\n\t{\n\t\tosvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);\n\t\tif (! GetVersionExA ( (OSVERSIONINFO *) &osvi) )\n\t\t\treturn OSString+\" Can't GetVersionEx()\";\n\t}\n\n\t// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.\n\n\tpGNSI = (PGNSI) GetProcAddress(GetModuleHandleA(\"kernel32.dll\"), \"GetNativeSystemInfo\");\n\n\tif (NULL != pGNSI)\n\t\tpGNSI(&si);\n\telse\n\t\tGetSystemInfo(&si);\n\n\t// Test for the Windows NT product family.\n\tif ( VER_PLATFORM_WIN32_NT == osvi.dwPlatformId && osvi.dwMajorVersion > 4 )\n\t{\n\t\tOSString = \"Microsoft\";\n\n\t\tif ( osvi.dwMajorVersion > 6 )\n\t\t{\n\t\t\tOSString += \" Windows (not released)\";\n\t\t}\n\t\telse if ( osvi.dwMajorVersion == 6 )\n\t\t{\n\t\t\tif ( osvi.dwMinorVersion == 2 )\n\t\t\t{\n\t\t\t\tif( osvi.wProductType == VER_NT_WORKSTATION )\n\t\t\t\t\tOSString += \" Windows 8\";\n\t\t\t\telse\n\t\t\t\t\tOSString += \" Windows Server 2012\";\n\t\t\t}\n\t\t\telse if ( osvi.dwMinorVersion == 1 )\n\t\t\t{\n\t\t\t\tif( osvi.wProductType == VER_NT_WORKSTATION )\n\t\t\t\t\tOSString += \" Windows 7\";\n\t\t\t\telse\n\t\t\t\t\tOSString += \" Windows Server 2008 R2\";\n\t\t\t}\n\t\t\telse if ( osvi.dwMinorVersion == 0 )\n\t\t\t{\n\t\t\t\tif( osvi.wProductType == VER_NT_WORKSTATION )\n\t\t\t\t\tOSString += \" Windows Vista\";\n\t\t\t\telse\n\t\t\t\t\tOSString += \" Windows Server 2008\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tOSString += \" Windows (not released)\";\n\t\t\t}\n\n\t\t\tpGPI = (PGPI) GetProcAddress(GetModuleHandleA(\"kernel32.dll\"), \"GetProductInfo\");\n\n\t\t\tDWORD dwType;\n\t\t\tpGPI( osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.wServicePackMinor, &dwType);\n\n\t\t\t// Test for the specific product family.\n\t\t\tswitch( dwType )\n\t\t\t{\n#ifdef PRODUCT_UNLICENSED\n\t\t\tcase PRODUCT_UNLICENSED:\n\t\t\t\tOSString += \" Unlicensed\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ULTIMATE\n\t\t\tcase PRODUCT_ULTIMATE:\n\t\t\t\tOSString += \" Ultimate Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_BASIC\n\t\t\tcase PRODUCT_HOME_BASIC:\n\t\t\t\tOSString += \" Home Basic Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_PREMIUM\n\t\t\tcase PRODUCT_HOME_PREMIUM:\n\t\t\t\tOSString += \" Home Premium Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE\n\t\t\tcase PRODUCT_ENTERPRISE:\n\t\t\t\tOSString += \" Enterprise Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_BASIC_N\n\t\t\tcase PRODUCT_HOME_BASIC_N:\n\t\t\t\tOSString += \" Home Basic N Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_BUSINESS\n\t\t\tcase PRODUCT_BUSINESS:\n\t\t\t\tOSString += \" Business Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STANDARD_SERVER\n\t\t\tcase PRODUCT_STANDARD_SERVER:\n\t\t\t\tOSString += \" Standard Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_DATACENTER_SERVER\n\t\t\tcase PRODUCT_DATACENTER_SERVER:\n\t\t\t\tOSString += \" Datacenter Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_SMALLBUSINESS_SERVER\n\t\t\tcase PRODUCT_SMALLBUSINESS_SERVER:\n\t\t\t\tOSString += \" Small Business Server\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_SERVER\n\t\t\tcase PRODUCT_ENTERPRISE_SERVER:\n\t\t\t\tOSString += \" Enterprise Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STARTER\n\t\t\tcase PRODUCT_STARTER:\n\t\t\t\tOSString += \" Starter Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_DATACENTER_SERVER_CORE\n\t\t\tcase PRODUCT_DATACENTER_SERVER_CORE:\n\t\t\t\tOSString += \" Datacenter Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STANDARD_SERVER_CORE\n\t\t\tcase PRODUCT_STANDARD_SERVER_CORE:\n\t\t\t\tOSString += \" Standard Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_SERVER_CORE\n\t\t\tcase PRODUCT_ENTERPRISE_SERVER_CORE:\n\t\t\t\tOSString += \" Enterprise Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_SERVER_IA64\n\t\t\tcase PRODUCT_ENTERPRISE_SERVER_IA64:\n\t\t\t\tOSString += \" Enterprise Edition for Itanium-based Systems\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_BUSINESS_N\n\t\t\tcase PRODUCT_BUSINESS_N:\n\t\t\t\tOSString += \" Business N Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_WEB_SERVER\n\t\t\tcase PRODUCT_WEB_SERVER:\n\t\t\t\tOSString += \" Web Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_CLUSTER_SERVER\n\t\t\tcase PRODUCT_CLUSTER_SERVER:\n\t\t\t\tOSString += \" Cluster Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_SERVER\n\t\t\tcase PRODUCT_HOME_SERVER:\n\t\t\t\tOSString += \" Home Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STORAGE_EXPRESS_SERVER\n\t\t\tcase PRODUCT_STORAGE_EXPRESS_SERVER:\n\t\t\t\tOSString += \" Storage Server Express Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STORAGE_STANDARD_SERVER\n\t\t\tcase PRODUCT_STORAGE_STANDARD_SERVER:\n\t\t\t\tOSString += \" Storage Server Standard Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STORAGE_WORKGROUP_SERVER\n\t\t\tcase PRODUCT_STORAGE_WORKGROUP_SERVER:\n\t\t\t\tOSString += \" Storage Server Workgroup Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STORAGE_ENTERPRISE_SERVER\n\t\t\tcase PRODUCT_STORAGE_ENTERPRISE_SERVER:\n\t\t\t\tOSString += \" Storage Server Enterprise Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_SERVER_FOR_SMALLBUSINESS\n\t\t\tcase PRODUCT_SERVER_FOR_SMALLBUSINESS:\n\t\t\t\tOSString += \" Essential Server Solutions Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_SMALLBUSINESS_SERVER_PREMIUM\n\t\t\tcase PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:\n\t\t\t\tOSString += \" Small Business Server Premium Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_PREMIUM_N\n\t\t\tcase PRODUCT_HOME_PREMIUM_N:\n\t\t\t\tOSString += \" Home Premium N Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_N\n\t\t\tcase PRODUCT_ENTERPRISE_N:\n\t\t\t\tOSString += \" Enterprise N Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ULTIMATE_N\n\t\t\tcase PRODUCT_ULTIMATE_N:\n\t\t\t\tOSString += \" Ultimate N Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_WEB_SERVER_CORE\n\t\t\tcase PRODUCT_WEB_SERVER_CORE:\n\t\t\t\tOSString += \" Web Server Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT\n\t\t\tcase PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:\n\t\t\t\tOSString += \" Essential Business Server Management Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY\n\t\t\tcase PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:\n\t\t\t\tOSString += \" Essential Business Server Security Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING\n\t\t\tcase PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:\n\t\t\t\tOSString += \" Essential Business Server Messaging Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_SMALLBUSINESS_SERVER_PRIME\n\t\t\tcase PRODUCT_SMALLBUSINESS_SERVER_PRIME:\n\t\t\t\tOSString += \" Small Business Server Prime Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HOME_PREMIUM_SERVER\n\t\t\tcase PRODUCT_HOME_PREMIUM_SERVER:\n\t\t\t\tOSString += \" Home Premium Server Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_SERVER_FOR_SMALLBUSINESS_V\n\t\t\tcase PRODUCT_SERVER_FOR_SMALLBUSINESS_V:\n\t\t\t\tOSString += \" Essential Server Solutions without Hyper-V Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STANDARD_SERVER_V\n\t\t\tcase PRODUCT_STANDARD_SERVER_V:\n\t\t\t\tOSString += \" Standard without Hyper-V Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_DATACENTER_SERVER_V\n\t\t\tcase PRODUCT_DATACENTER_SERVER_V:\n\t\t\t\tOSString += \" Datacenter without Hyper-V Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_SERVER_V\n\t\t\tcase PRODUCT_ENTERPRISE_SERVER_V:\n\t\t\t\tOSString += \" Enterprise without Hyper-V Edition\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_DATACENTER_SERVER_CORE_V\n\t\t\tcase PRODUCT_DATACENTER_SERVER_CORE_V:\n\t\t\t\tOSString += \" Datacenter without Hyper-V Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_STANDARD_SERVER_CORE_V\n\t\t\tcase PRODUCT_STANDARD_SERVER_CORE_V:\n\t\t\t\tOSString += \" Standard without Hyper-V Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_ENTERPRISE_SERVER_CORE_V\n\t\t\tcase PRODUCT_ENTERPRISE_SERVER_CORE_V:\n\t\t\t\tOSString += \" Enterprise without Hyper-V Edition (core installation)\";\n\t\t\t\tbreak;\n#endif\n#ifdef PRODUCT_HYPERV\n\t\t\tcase PRODUCT_HYPERV:\n\t\t\t\tOSString += \" Hyper-V Server Edition\";\n\t\t\t\tbreak;\n#endif\n\t\t\tdefault:\n\t\t\t\tOSString += toString(\" Unknown Edition (0x%04x)\", dwType);\n\t\t\t}\n\n\t\t\tif ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )\n\t\t\t\tOSString += \" 64-bit\";\n\t\t\telse if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL )\n\t\t\t\tOSString += \" 32-bit\";\n\t\t}\n\t\telse if ( osvi.dwMajorVersion == 5 )\n\t\t{\n\t\t\tif ( osvi.dwMinorVersion == 2 )\n\t\t\t{\n\t\t\t\tif( GetSystemMetrics(89 /* SM_SERVERR2 */) )\n\t\t\t\t\tOSString += \" Windows Server 2003 R2\";\n#ifdef VER_SUITE_STORAGE_SERVER\n\t\t\t\telse if ( osvi.wSuiteMask == VER_SUITE_STORAGE_SERVER )\n\t\t\t\t\tOSString += \" Windows Storage Server 2003\";\n#endif\n#ifdef VER_SUITE_WH_SERVER\n\t\t\t\telse if ( osvi.wSuiteMask == VER_SUITE_WH_SERVER )\n\t\t\t\t\tOSString += \" Windows Home Server\";\n#endif\n\t\t\t\telse if( osvi.wProductType == VER_NT_WORKSTATION &&\n\t\t\t\t\tsi.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)\n\t\t\t\t\tOSString += \" Windows XP Professional x64 Edition\";\n\t\t\t\telse\n\t\t\t\t\tOSString += \" Windows Server 2003\";\n\n\t\t\t\t// Test for the server type.\n\t\t\t\tif ( osvi.wProductType != VER_NT_WORKSTATION )\n\t\t\t\t{\n\t\t\t\t\tif ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )\n\t\t\t\t\t{\n\t\t\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_DATACENTER )\n\t\t\t\t\t\t\tOSString += \" Datacenter Edition for Itanium-based Systems\";\n\t\t\t\t\t\telse if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\n\t\t\t\t\t\t\tOSString += \" Enterprise Edition for Itanium-based Systems\";\n\t\t\t\t\t}\n\n\t\t\t\t\telse if ( si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )\n\t\t\t\t\t{\n\t\t\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_DATACENTER )\n\t\t\t\t\t\t\tOSString += \" Datacenter x64 Edition\";\n\t\t\t\t\t\telse if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\n\t\t\t\t\t\t\tOSString += \" Enterprise x64 Edition\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tOSString += \" Standard x64 Edition\";\n\t\t\t\t\t}\n\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\n\t\t\t\t\t\t\tOSString += \" Enterprise Edition\";\n#ifdef VER_SUITE_DATACENTER\n\t\t\t\t\t\telse if( osvi.wSuiteMask & VER_SUITE_DATACENTER )\n\t\t\t\t\t\t\tOSString += \" Datacenter Edition\";\n#endif\n#ifdef VER_SUITE_BLADE\n\t\t\t\t\t\telse if ( osvi.wSuiteMask & VER_SUITE_BLADE )\n\t\t\t\t\t\t\tOSString += \" Web Edition\";\n#endif\n#ifdef VER_SUITE_COMPUTE_SERVER\n\t\t\t\t\t\telse if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )\n\t\t\t\t\t\t\tOSString += \" Compute Cluster Edition\";\n#endif\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tOSString += \" Standard Edition\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( osvi.dwMinorVersion == 1 )\n\t\t\t{\n\t\t\t\tOSString += \" Windows XP\";\n\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_PERSONAL )\n\t\t\t\t\tOSString += \" Home Edition\";\n\t\t\t\telse\n\t\t\t\t\tOSString += \" Professional\";\n\t\t\t}\n\t\t\telse if ( osvi.dwMinorVersion == 0 )\n\t\t\t{\n\t\t\t\tOSString += \" Windows 2000\";\n\n\t\t\t\tif ( osvi.wProductType == VER_NT_WORKSTATION )\n\t\t\t\t{\n\t\t\t\t\tOSString += \" Professional\";\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_DATACENTER )\n\t\t\t\t\t\tOSString += \" Datacenter Server\";\n\t\t\t\t\telse if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\n\t\t\t\t\t\tOSString += \" Advanced Server\";\n\t\t\t\t\telse\n\t\t\t\t\t\tOSString += \" Server\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tOSString += \" Unknown Windows\";\n\t\t\t}\n\t\t}\n\t\telse if ( osvi.dwMajorVersion <= 4 )\n\t\t{\n\t\t\tOSString += \" Windows NT\";\n\n\t\t\t// Test for specific product on Windows NT 4.0 SP6 and later.\n\t\t\tif( bOsVersionInfoEx )\n\t\t\t{\n\t\t\t\t// Test for the workstation type.\n\t\t\t\tif ( osvi.wProductType == VER_NT_WORKSTATION )\n\t\t\t\t{\n\t\t\t\t\tif( osvi.dwMajorVersion == 4 )\n\t\t\t\t\t\tOSString += \" Workstation 4.0\";\n\t\t\t\t\telse if( osvi.wSuiteMask & VER_SUITE_PERSONAL )\n\t\t\t\t\t\tOSString += \" Home Edition\";\n\t\t\t\t\telse\n\t\t\t\t\t\tOSString += \" Professional\";\n\t\t\t\t}\n\n\t\t\t\t// Test for the server type.\n\t\t\t\telse if ( osvi.wProductType == VER_NT_SERVER )\n\t\t\t\t{\n\t\t\t\t\tif( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\n\t\t\t\t\t\tOSString += \" Server 4.0 Enterprise Edition\";\n\t\t\t\t\telse\n\t\t\t\t\t\tOSString += \" Server 4.0\";\n\t\t\t\t}\n\t\t\t}\n\t\t\telse  // Test for specific product on Windows NT 4.0 SP5 and earlier\n\t\t\t{\n\t\t\t\tHKEY hKey;\n\t\t\t\tTCHAR szProductType[BUFSIZE];\n\t\t\t\tDWORD dwBufLen=BUFSIZE;\n\t\t\t\tLONG lRet;\n\n\t\t\t\tlRet = RegOpenKeyExA( HKEY_LOCAL_MACHINE, \"SYSTEM\\\\CurrentControlSet\\\\Control\\\\ProductOptions\", 0, KEY_QUERY_VALUE, &hKey );\n\t\t\t\tif( lRet != ERROR_SUCCESS )\n\t\t\t\t\treturn OSString + \" Can't RegOpenKeyEx\";\n\n\t\t\t\tlRet = RegQueryValueExA( hKey, \"ProductType\", NULL, NULL, (LPBYTE) szProductType, &dwBufLen);\n\t\t\t\tif( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )\n\t\t\t\t\treturn OSString + \" Can't ReQueryValueEx\";\n\n\t\t\t\tRegCloseKey( hKey );\n\n\t\t\t\tif ( lstrcmpi( _T(\"WINNT\"), szProductType) == 0 )\n\t\t\t\t\tOSString += \" Workstation\";\n\t\t\t\tif ( lstrcmpi( _T(\"LANMANNT\"), szProductType) == 0 )\n\t\t\t\t\tOSString += \" Server\";\n\t\t\t\tif ( lstrcmpi( _T(\"SERVERNT\"), szProductType) == 0 )\n\t\t\t\t\tOSString += \" Advanced Server\";\n\t\t\t}\n\t\t}\n\n\t\tstd::string servicePack;\n\n\t\tif( osvi.dwMajorVersion == 4 && lstrcmpi( osvi.szCSDVersion, _T(\"Service Pack 6\") ) == 0 )\n\t\t{\n\t\t\tHKEY hKey;\n\t\t\tLONG lRet;\n\n\t\t\t// Test for SP6 versus SP6a.\n\t\t\tlRet = RegOpenKeyExA( HKEY_LOCAL_MACHINE, \"SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Hotfix\\\\Q246009\", 0, KEY_QUERY_VALUE, &hKey );\n\t\t\tif( lRet == ERROR_SUCCESS )\n\t\t\t\tservicePack = \"Service Pack 6a\";\n\t\t\telse // Windows NT 4.0 prior to SP6a\n\t\t\t{\n\t\t\t\tservicePack = osvi.szCSDVersion;\n\t\t\t}\n\n\t\t\tRegCloseKey( hKey );\n\t\t}\n\t\telse // Windows NT 3.51 and earlier or Windows 2000 and later\n\t\t{\n\t\t\tservicePack = osvi.szCSDVersion;\n\t\t}\n\n\t\t// Include service pack (if any)\n\t\tif (!servicePack.empty()) OSString += \" \" + servicePack;\n\n\t\t// Include build number\n\t\tOSString += toString(\" (Build %d)\", osvi.dwBuildNumber & 0xFFFF);\n\t}\n\telse if ( VER_PLATFORM_WIN32_WINDOWS == osvi.dwPlatformId )\n\t{\n\t\tOSString = \"Microsoft\";\n\n\t\tif (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)\n\t\t{\n\t\t\tOSString += \" Windows 95\";\n\t\t\tif ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )\n\t\t\t\tOSString += \" OSR2\";\n\t\t}\n\t\telse if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)\n\t\t{\n\t\t\tOSString += \" Windows 98\";\n\t\t\tif ( osvi.szCSDVersion[1] == 'A' )\n\t\t\t\tOSString += \" SE\";\n\t\t}\n\t\telse if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)\n\t\t{\n\t\t\tOSString += \" Windows Millennium Edition\";\n\t\t}\n\t\telse\n\t\t\tOSString += \" Windows 9x\";\n\t}\n\telse if ( VER_PLATFORM_WIN32s == osvi.dwPlatformId )\n\t{\n\t\tOSString = toString(\"Microsoft Windows %d.%d + Win32s\", osvi.dwMajorVersion, osvi.dwMinorVersion);\n\t}\n\telse\n\t{\n\t\tOSString = toString(\"Microsoft Windows %d.%d\", osvi.dwMajorVersion, osvi.dwMinorVersion);\n\t}\n\n\tOSString += toString( \" (%d.%d %d)\", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);\n\n#elif defined(NL_OS_MAC) || defined(NL_OS_FREEBSD)\n\n\tOSString = getsysctlstr(\"kern.version\");\n\n#elif defined NL_OS_UNIX\n\n\tint fd = open(PROC_BASE_PATH\"/version\", O_RDONLY);\n\tif (fd == -1)\n\t{\n\t\tnlwarning (\"SI: Can't get OS from \" PROC_BASE_PATH \"/version: %s\", strerror (errno));\n\t}\n\telse\n\t{\n\t\tchar buffer[4096+1];\n\t\tint len = read(fd, buffer, sizeof(buffer)-1);\n\t\tclose(fd);\n\n\t\t// remove the \\n and set \\0\n\t\tbuffer[len-1] = '\\0';\n\n\t\tOSString = buffer;\n\t}\n\n#endif\t// NL_OS_UNIX\n\n\treturn OSString;\n}\n\nstring CSystemInfo::getProc ()\n{\n\tstring ProcString = \"Unknown\";\n\n#ifdef NL_OS_WINDOWS\n\n\tLONG result;\n\tchar value[1024];\n\tDWORD valueSize;\n\tHKEY hKey;\n\n\tresult = ::RegOpenKeyExA (HKEY_LOCAL_MACHINE, \"Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\0\", 0, KEY_QUERY_VALUE, &hKey);\n\tif (result == ERROR_SUCCESS)\n\t{\n\t\t// get processor name\n\t\tvalueSize = 1024;\n\t\tresult = ::RegQueryValueEx (hKey, _T(\"ProcessorNameString\"), NULL, NULL, (LPBYTE)value, &valueSize);\n\t\tif (result == ERROR_SUCCESS)\n\t\t\tProcString = value;\n\t\telse\n\t\t\tProcString = \"UnknownProc\";\n\n\t\tProcString += \" / \";\n\n\t\t// get processor identifier\n\t\tvalueSize = 1024;\n\t\tresult = ::RegQueryValueEx (hKey, _T(\"Identifier\"), NULL, NULL, (LPBYTE)value, &valueSize);\n\t\tif (result == ERROR_SUCCESS)\n\t\t\tProcString += value;\n\t\telse\n\t\t\tProcString += \"UnknownIdentifier\";\n\n\t\tProcString += \" / \";\n\n\t\t// get processor vendor\n\t\tvalueSize = 1024;\n\t\tresult = ::RegQueryValueEx (hKey, _T(\"VendorIdentifier\"), NULL, NULL, (LPBYTE)value, &valueSize);\n\t\tif (result == ERROR_SUCCESS)\n\t\t\tProcString += value;\n\t\telse\n\t\t\tProcString += \"UnknownVendor\";\n\n\t\tProcString += \" / \";\n\n\t\t// get processor frequency\n\t\tresult = ::RegQueryValueEx (hKey, _T(\"~MHz\"), NULL, NULL, (LPBYTE)value, &valueSize);\n\t\tif (result == ERROR_SUCCESS)\n\t\t{\n\t\t\tuint32 freq = *(int *)value;\n\t\t\t// discard the low value (not enough significant)\n\t\t\tfreq /= 10;\n\t\t\tfreq *= 10;\n\t\t\tProcString += toString(\"%uMHz\", freq);\n\t\t}\n\t\telse\n\t\t\tProcString += \"UnknownFreq\";\n\t}\n\n\t// Make sure to close the reg key\n\tRegCloseKey (hKey);\n\n\t// count the number of processor (max 8, in case this code don't work well)\n\tuint\tnumProc= 1;\n\tfor(uint i=1;i<8;i++)\n\t{\n\t\tstring\ttmp= string(\"Hardware\\\\Description\\\\System\\\\CentralProcessor\\\\\") + toString(i);\n\n\t\t// try to open the key\n\t\tresult = ::RegOpenKeyExA (HKEY_LOCAL_MACHINE, tmp.c_str(), 0, KEY_QUERY_VALUE, &hKey);\n\t\t// Make sure to close the reg key\n\t\tRegCloseKey (hKey);\n\n\t\tif(result == ERROR_SUCCESS)\n\t\t\tnumProc++;\n\t\telse\n\t\t\tbreak;\n\t}\n\tProcString += \" / \";\n\tProcString += toString(numProc) + \" Processors found\";\n\n#elif defined NL_OS_MAC\n\n\tProcString = getsysctlstr(\"machdep.cpu.brand_string\");\n\tProcString += \" / \";\n\tProcString += getsysctlstr(\"hw.machine\");\n\tProcString += \" Family \" + toString(getsysctlnum(\"machdep.cpu.family\"));\n\tProcString += \" Model \" + toString(getsysctlnum(\"machdep.cpu.model\"));\n\tProcString += \" Stepping \" + toString(getsysctlnum(\"machdep.cpu.stepping\"));\n\tProcString += \" / \";\n\tProcString += getsysctlstr(\"machdep.cpu.vendor\");\n\tProcString += \" / \";\n\tProcString += toString(getsysctlnum64(\"hw.cpufrequency\")/1000000)+\"MHz\";\n\tProcString += \" / \";\n\tProcString += toString(getsysctlnum(\"hw.ncpu\")) + \" Processors found\";\n#elif defined NL_OS_FREEBSD\n\n    ProcString = getsysctlstr(\"hw.model\");\n    ProcString += \" / \";\n    ProcString += getsysctlstr(\"hw.machine\");\n    ProcString += \" Family 0\";\n    ProcString += \" Model 0\";\n    ProcString += \" Stepping 0\";\n    ProcString += \" / \";\n    ProcString += \"cpu.vendor\";\n    ProcString += \" / \";\n    ProcString += toString(getsysctlnum64(\"machdep.tsc_freq\")/1000000)+\"MHz\";\n    ProcString += \" / \";\n    ProcString += toString(getsysctlnum(\"hw.ncpu\")) + \" Processors found\";\n#elif defined NL_OS_UNIX\n\n\tuint processors = 0;\n\tif (fromString(getCpuInfo(\"processor\"), processors)) ++processors;\n\n\tProcString = getCpuInfo(\"model name\");\n\tProcString += \" / ?\";\n\tProcString += \" Family \" + getCpuInfo(\"cpu family\");\n\tProcString += \" Model \" + getCpuInfo(\"model\");\n\tProcString += \" Stepping \" + getCpuInfo(\"stepping\");\n\tProcString += \" / \";\n\tProcString += getCpuInfo(\"vendor_id\");\n\tProcString += \" / \";\n\tProcString += getCpuInfo(\"cpu MHz\")+\"MHz\";\n\tProcString += \" / \";\n\tProcString += toString(\"%u Processors found\", processors);\n\n#endif\n\n\t// Remove beginning spaces\n\tProcString = ProcString.substr (ProcString.find_first_not_of (\" \"));\n\n\treturn ProcString;\n}\n\nuint64 CSystemInfo::getProcessorFrequency(bool quick)\n{\n\tstatic uint64 freq = 0;\n#ifdef\tNL_CPU_INTEL\n\tstatic bool freqComputed = false;\n\tif (freqComputed) return freq;\n\n\tif (!quick)\n\t{\n\t\tTTicks bestNumTicks   = 0;\n\t\tuint64 bestNumCycles  = 0;\n\t\tuint64 numCycles;\n\t\tconst uint numSamples = 5;\n\t\tconst uint numLoops   = 50000000;\n\n\t\tvolatile uint k; // prevent optimization for the loop\n\t\tfor(uint l = 0; l < numSamples; ++l)\n\t\t{\n\t\t\tTTicks startTick = NLMISC::CTime::getPerformanceTime();\n\t\t\tuint64 startCycle = rdtsc();\n\t\t\tvolatile uint dummy = 0;\n\t\t\tfor(k = 0; k < numLoops; ++k)\n\t\t\t{\n\t\t\t\t++ dummy;\n\t\t\t}\n\t\t\tnumCycles = rdtsc() - startCycle;\n\t\t\tTTicks numTicks = NLMISC::CTime::getPerformanceTime() - startTick;\n\t\t\tif (numTicks > bestNumTicks)\n\t\t\t{\n\t\t\t\tbestNumTicks  = numTicks;\n\t\t\t\tbestNumCycles = numCycles;\n\t\t\t}\n\t\t}\n\t\tfreq = (uint64) ((double) bestNumCycles * 1 / CTime::ticksToSecond(bestNumTicks));\n\t}\n\telse\n\t{\n\t\tTTicks timeBefore = NLMISC::CTime::getPerformanceTime();\n\t\tuint64 tickBefore = rdtsc();\n\t\tnlSleep (100);\n\t\tTTicks timeAfter = NLMISC::CTime::getPerformanceTime();\n\t\tTTicks tickAfter = rdtsc();\n\n\t\tdouble timeDelta = CTime::ticksToSecond(timeAfter - timeBefore);\n\t\tTTicks tickDelta = tickAfter - tickBefore;\n\n\t\tfreq = (uint64) ((double)tickDelta / timeDelta);\n\t}\n\n\tnlinfo (\"SI: CSystemInfo: Processor frequency is %.0f MHz\", (float)freq/1000000.0);\n\tfreqComputed = true;\n#endif // NL_CPU_INTEL\n\treturn freq;\n}\n\nstatic bool DetectMMX()\n{\n\t#ifdef NL_CPU_INTEL\n\t\tif (!CSystemInfo::hasCPUID()) return false; // cpuid not supported ...\n\n\t\tsint32 CPUInfo[4];\n\t\tnlcpuid(CPUInfo, 1);\n\t\t// check for bit 23 = MMX instruction set\n\t\tif (CPUInfo[3] & 0x800000) return true;\n\t#endif // NL_CPU_INTEL\n\n\treturn false;\n}\n\n\nstatic bool DetectSSE()\n{\n\t#ifdef NL_CPU_INTEL\n\t\tif (!CSystemInfo::hasCPUID()) return false; // cpuid not supported ...\n\n\t\tsint32 CPUInfo[4];\n\t\tnlcpuid(CPUInfo, 1);\n\n\t\tif (CPUInfo[3]  & 0x2000000)\n\t\t{\n\t\t\t// check OS support for SSE\n\t\t\ttry\n\t\t\t{\n\t\t\t\t#ifdef NL_OS_WINDOWS\n\t\t\t\t#ifdef NL_NO_ASM\n\t\t\t\tunsigned int tmp = _mm_getcsr();\n\t\t\t\tnlunreferenced(tmp);\n\t\t\t\t#else\n\t\t\t\t__asm\n\t\t\t\t{\n\t\t\t\t\txorps xmm0, xmm0  // Streaming SIMD Extension\n\t\t\t\t}\n\t\t\t\t#endif // NL_NO_ASM\n\t\t\t\t#elif NL_OS_UNIX\n\t\t\t\t\t__asm__ __volatile__ (\"xorps %xmm0, %xmm0;\");\n\t\t\t\t#endif // NL_OS_UNIX\n\t\t\t}\n\t\t\tcatch(...)\n\t\t\t{\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// printf(\"sse detected\\n\");\n\n\t\t\treturn true;\n\t\t}\n\t#endif // NL_CPU_INTEL\n\n\treturn false;\n}\n\nbool CSystemInfo::_HaveMMX = DetectMMX ();\nbool CSystemInfo::_HaveSSE = DetectSSE ();\n\nbool CSystemInfo::hasCPUID ()\n{\n\t#ifdef NL_CPU_INTEL\n\t\t uint32 result = 0;\n\t\t#ifdef NL_OS_WINDOWS\n\t\t#ifdef NL_NO_ASM\n\t\t\tsint32 CPUInfo[4] = {-1};\n\t\t\tnlcpuid(CPUInfo, 0);\n\t\t\tif (CPUInfo[3] != -1) result = 1;\n\t\t#else\n\t\t __asm\n\t\t {\n\t\t\t pushad\n\t\t\t pushfd\n\t\t\t //\t If ID bit of EFLAGS can change, then cpuid is available\n\t\t\t pushfd\n\t\t\t pop  eax\t\t\t\t\t// Get EFLAG\n\t\t\t mov  ecx,eax\n\t\t\t xor  eax,0x200000\t\t\t// Flip ID bit\n\t\t\t push eax\n\t\t\t popfd\t\t\t\t\t\t// Write EFLAGS\n\t\t\t pushfd\n\t\t\t pop  eax\t\t\t\t\t// read back EFLAG\n\t\t\t xor  eax,ecx\n\t\t\t je   noCpuid\t\t\t\t// no flip -> no CPUID instr.\n\n\t\t\t popfd\t\t\t\t\t\t// restore state\n\t\t\t popad\n\t\t\t mov  result, 1\n\t\t\t jmp  CPUIDPresent\n\n\t\t\tnoCpuid:\n\t\t\t popfd\t\t\t\t\t    // restore state\n\t\t\t popad\n\t\t\t mov result, 0\n\t\t\tCPUIDPresent:\n\t\t }\n\t\t#endif // NL_NO_ASM\n\t\t#elif NL_OS_UNIX // NL_OS_WINDOWS\n\t\t\t__asm__ __volatile__ (\n\t\t\t\t/* Save Register */\n\t\t\t\t\"pushl  %%ebp;\"\n\t\t\t\t\"pushl  %%ebx;\"\n\t\t\t\t\"pushl  %%edx;\"\n\n\t\t\t\t/* Check if this CPU supports cpuid */\n\t\t\t\t\"pushf;\"\n\t\t\t\t\"pushf;\"\n\t\t\t\t\"popl   %%eax;\"\n\t\t\t\t\"movl   %%eax, %%ebx;\"\n\t\t\t\t\"xorl   $(1 << 21), %%eax;\"\t// CPUID bit\n\t\t\t\t\"pushl  %%eax;\"\n\t\t\t\t\"popf;\"\n\t\t\t\t\"pushf;\"\n\t\t\t\t\"popl   %%eax;\"\n\t\t\t\t\"popf;\"                  \t// Restore flags\n\t\t\t\t\"xorl   %%ebx, %%eax;\"\n\t\t\t\t\"jz     NoCPUID;\"\n\t\t\t\t\"movl   $1, %0;\"\n\t\t\t\t\"jmp    CPUID;\"\n\n\t\t\t\"NoCPUID:;\"\n\t\t\t\t\"movl   $0, %0;\"\n              \t\t\"CPUID:;\"\n\t\t\t\t\"popl   %%edx;\"\n\t\t\t\t\"popl   %%ebx;\"\n\t\t\t\t\"popl   %%ebp;\"\n\n\t\t\t\t:\"=a\"(result)\n                \t);\n\t\t#endif // NL_OS_UNIX\n\t\treturn result == 1;\n\t#else\n\t\treturn false;\n\t#endif\n}\n\n\nuint32 CSystemInfo::getCPUID()\n{\n#ifdef NL_CPU_INTEL\n\tif(hasCPUID())\n\t{\n\t\tuint32 result = 0;\n\t\tsint32 CPUInfo[4];\n\t\tnlcpuid(CPUInfo, 1);\n\t\treturn CPUInfo[3];\n\t}\n#endif // NL_CPU_INTEL\n\n\treturn 0;\n}\n\n/*\n *\tNote: Not used in NeL probably in Ryzom closed source. Not translated in AT&T asm, I don't understand the aim of this method\n *\t      Returns true if the CPU has HT,  even if it is disabled. Maybe shoud count how many (virtual) core there is.\n */\nbool CSystemInfo::hasHyperThreading()\n{\n#ifdef NL_OS_WINDOWS\n\tif(hasCPUID())\n\t{\n\t\tsint32 CPUInfo[4];\n\n\t\t// get vendor string from cpuid\n\t\tchar vendor_id[32];\n\t\tmemset(vendor_id, 0, sizeof(vendor_id));\n\t\tnlcpuid(CPUInfo, 0);\n\t\tmemcpy(vendor_id, &CPUInfo[1], sizeof(sint32));\n\t\tmemcpy(vendor_id+4, &CPUInfo[3], sizeof(sint32));\n\t\tmemcpy(vendor_id+8, &CPUInfo[2], sizeof(sint32));\n\n\t\t// get cpuid flags\n\t\tnlcpuid(CPUInfo, 1);\n\n\t\t// pentium 4 or later processor?\n\t\tif ((((CPUInfo[0] & 0xf00) == 0xf00) || (CPUInfo[0] & 0xf00000)) &&\n\t\t\tstrcmp(vendor_id, \"GenuineIntel\") == 0)\n\t\t\treturn (CPUInfo[3] & 0x10000000)!=0; // Intel Processor Hyper-Threading\n\t}\n#endif\n\n\treturn false;\n}\n\nbool CSystemInfo::isNT()\n{\n#ifdef NL_OS_WINDOWS\n\tOSVERSIONINFO ver;\n\tver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\n\tGetVersionEx(&ver);\n\treturn ver.dwPlatformId == VER_PLATFORM_WIN32_NT;\n#else\n\treturn false;\n#endif\n}\n\nstring CSystemInfo::availableHDSpace (const string &filename)\n{\n#ifdef NL_OS_UNIX\n\tstring cmd = \"df \";\n\tif(filename.empty())\n\t\tcmd += \".\";\n\telse\n\t\tcmd += filename;\n\tcmd += \" >/tmp/nelhdfs\";\n\tsint error = system (cmd.c_str());\n\tif (error)\n\t\tnlwarning(\"'%s' failed with error code %d\", cmd.c_str(), error);\n\n\tint fd = open(\"/tmp/nelhdfs\", O_RDONLY);\n\tif (fd == -1)\n\t{\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\tchar buffer[4096+1];\n\t\tint len = read(fd, buffer, sizeof(buffer)-1);\n\t\tclose(fd);\n\t\tbuffer[len] = '\\0';\n\n\t\tvector<string> splitted;\n\t\texplode(string(buffer), string(\"\\n\"), splitted, true);\n\n\t\tif(splitted.size() < 2)\n\t\t\treturn \"NoInfo\";\n\n\t\tvector<string> sline;\n\t\texplode(splitted[1], string(\" \"), sline, true);\n\n\t\tif(sline.size() < 5)\n\t\t\treturn splitted[1];\n\n\t\tstring space = sline[3] + \"000\";\n\t\treturn bytesToHumanReadable(space);\n\t}\n#else\n\tnlunreferenced(filename);\n\treturn \"NoInfo\";\n#endif\n}\n\nuint64 CSystemInfo::availablePhysicalMemory ()\n{\n#ifdef NL_OS_WINDOWS\n\tMEMORYSTATUS ms;\n\tGlobalMemoryStatus (&ms);\n\treturn uint64(ms.dwAvailPhys);\n#elif defined(NL_OS_MAC) || defined(NL_OS_FREEBSD)\n\treturn uint64(getsysctlnum64(\"hw.usermem\"));\n#elif defined NL_OS_UNIX\n\treturn getSystemMemory(\"MemFree:\")+getSystemMemory(\"Buffers:\")+getSystemMemory(\"Cached:\");\n#else\n\treturn 0;\n#endif\n}\n\nuint64 CSystemInfo::totalPhysicalMemory ()\n{\n#ifdef NL_OS_WINDOWS\n\tMEMORYSTATUS ms;\n\tGlobalMemoryStatus (&ms);\n\treturn uint64(ms.dwTotalPhys);\n#elif defined NL_OS_MAC || defined(NL_OS_FREEBSD)\n\treturn uint64(getsysctlnum64(\"hw.physmem\"));\n#elif defined NL_OS_UNIX\n\treturn getSystemMemory(\"MemTotal:\");\n#else\n\treturn 0;\n#endif\n}\n\n#ifndef NL_OS_WINDOWS\nstatic inline char *skipWS(const char *p)\n{\n    while (isspace(*p)) p++;\n    return (char *)p;\n}\n\nstatic inline char *skipToken(const char *p)\n{\n    while (isspace(*p)) p++;\n    while (*p && !isspace(*p)) p++;\n    return (char *)p;\n}\n#endif\n\nuint64 CSystemInfo::getAllocatedSystemMemory ()\n{\n\tuint64 systemMemory = 0;\n    return systemMemory;\n\n#ifdef NL_OS_WINDOWS\n\t// Get system memory information\n\tHANDLE hHeap[100];\n\tDWORD heapCount = GetProcessHeaps (100, hHeap);\n\n\tuint heap;\n\tfor (heap = 0; heap < heapCount; heap++)\n\t{\n        PROCESS_HEAP_ENTRY entry;\n        entry.lpData = NULL;\n\n        HeapLock( hHeap[ heap ] );\n\n        while (HeapWalk (hHeap[heap], &entry))\n        {\n            if (entry.wFlags & PROCESS_HEAP_ENTRY_BUSY)\n            {\n                systemMemory += entry.cbData + entry.cbOverhead;\n            }\n        }\n\n        HeapUnlock( hHeap[ heap ] );\n\t}\n\n#elif defined(NL_OS_UNIX)\n    \n\tint fd = open(PROC_BASE_PATH\"/self/stat\", O_RDONLY);\n\tif (fd == -1)\n\t{\n\t\tnlwarning (\"HA: Can't get OS from \" PROC_BASE_PATH \"/self/stat: %s\", strerror (errno));\n\t}\n\telse\n\t{\n\t\tchar buffer[4096], *p;\n\t\tint len = read(fd, buffer, sizeof(buffer)-1);\n\t\tclose(fd);\n\n\t\tbuffer[len] = '\\0';\n\n\t\tp = buffer;\n\t\tp = strchr(p, ')')+1;\t\t\t/* skip pid */\n\t\tp = skipWS(p);\n\t\tp++;\n\n\t\tp = skipToken(p);\t\t\t\t/* skip ppid */\n\t\tp = skipToken(p);\t\t\t\t/* skip pgrp */\n\t\tp = skipToken(p);\t\t\t\t/* skip session */\n\t\tp = skipToken(p);\t\t\t\t/* skip tty */\n\t\tp = skipToken(p);\t\t\t\t/* skip tty pgrp */\n\t\tp = skipToken(p);\t\t\t\t/* skip flags */\n\t\tp = skipToken(p);\t\t\t\t/* skip min flt */\n\t\tp = skipToken(p);\t\t\t\t/* skip cmin flt */\n\t\tp = skipToken(p);\t\t\t\t/* skip maj flt */\n\t\tp = skipToken(p);\t\t\t\t/* skip cmaj flt */\n\t\tp = skipToken(p);\t\t\t\t/* utime */\n\t\tp = skipToken(p);\t\t\t\t/* stime */\n\t\tp = skipToken(p);\t\t\t\t/* skip cutime */\n\t\tp = skipToken(p);\t\t\t\t/* skip cstime */\n\t\tp = skipToken(p);\t\t\t\t/* priority */\n\t\tp = skipToken(p);\t\t\t\t/* nice */\n\t\tp = skipToken(p);\t\t\t\t/* skip timeout */\n\t\tp = skipToken(p);\t\t\t\t/* skip it_real_val */\n\t\tp = skipToken(p);\t\t\t\t/* skip start_time */\n\n\t\tsystemMemory = strtoul(p, &p, 10);\t/* vsize in bytes */\n\t}\n\n#endif // NL_OS_WINDOWS\n\treturn systemMemory;\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, AvailableHDSpace, \"Hard drive space left in bytes\")\n{\n\t// ace: it's a little bit tricky, if you don't understand how it works, don't touch!\n\tstatic string location;\n\tif (get)\n\t{\n\t\t*pointer = (CSystemInfo::availableHDSpace(location));\n\t\tlocation = \"\";\n\t}\n\telse\n\t{\n\t\tlocation = *pointer;\n\t}\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, AvailablePhysicalMemory, \"Physical memory available on this computer in bytes\")\n{\n\tif (get) *pointer = bytesToHumanReadable(CSystemInfo::availablePhysicalMemory ());\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, TotalPhysicalMemory, \"Total physical memory on this computer in bytes\")\n{\n\tif (get) *pointer = bytesToHumanReadable(CSystemInfo::totalPhysicalMemory ());\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, ProcessUsedMemory, \"Memory used by this process in bytes\")\n{\n\tif (get) *pointer = bytesToHumanReadable(CSystemInfo::getAllocatedSystemMemory ());\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, OS, \"OS used\")\n{\n\tif (get) *pointer = CSystemInfo::getOS();\n}\n\n#ifdef NL_OS_WINDOWS\nstruct DISPLAY_DEVICE_EX\n{\n    DWORD  cb;\n    CHAR  DeviceName[32];\n    CHAR  DeviceString[128];\n    DWORD  StateFlags;\n    CHAR  DeviceID[128];\n    CHAR  DeviceKey[128];\n};\n#endif // NL_OS_WINDOWS\n\nbool CSystemInfo::getVideoInfo (std::string &deviceName, uint64 &driverVersion)\n{\n#ifdef NL_OS_WINDOWS\n\t/* Get the device name with EnumDisplayDevices (doesn't work under win95).\n\t * Look for driver information for this device in the registry\n\t *\n\t * Follow the recommendations in the news group comp.os.ms-windows.programmer.nt.kernel-mode : \"Get Video Driver ... Need Version\"\n\t */\n\n\tHMODULE hm = GetModuleHandle(TEXT(\"USER32\"));\n\tif (hm)\n\t{\n\t\tBOOL (WINAPI* EnumDisplayDevices)(LPCTSTR lpDevice, DWORD iDevNum, PDISPLAY_DEVICE lpDisplayDevice, DWORD dwFlags) = NULL;\n\t\t*(FARPROC*)&EnumDisplayDevices = GetProcAddress(hm, \"EnumDisplayDevicesA\");\n\t\tif (EnumDisplayDevices)\n\t\t{\n\t\t\tDISPLAY_DEVICE_EX DisplayDevice;\n\t\t\tuint device = 0;\n\t\t\tDisplayDevice.cb = sizeof (DISPLAY_DEVICE_EX);\n\t\t\tbool found = false;\n\t\t\twhile (EnumDisplayDevices(NULL, device, (DISPLAY_DEVICE*)&DisplayDevice, 0))\n\t\t\t{\n\t\t\t\t// Main board ?\n\t\t\t\tif ((DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) &&\n\t\t\t\t\t(DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) &&\n\t\t\t\t\t((DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0) &&\n\t\t\t\t\t(DisplayDevice.DeviceKey[0] != 0))\n\t\t\t\t{\n\t\t\t\t\tfound = true;\n\n\t\t\t\t\t// The device name\n\t\t\t\t\tdeviceName = DisplayDevice.DeviceString;\n\n\t\t\t\t\tstring keyPath = DisplayDevice.DeviceKey;\n\t\t\t\t\tstring keyName;\n\n\t\t\t\t\t// Get the window version\n\t\t\t\t\tOSVERSIONINFO ver;\n\t\t\t\t\tver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\n\t\t\t\t\tGetVersionEx(&ver);\n\t\t\t\t\tbool atleastNT4 = (ver.dwMajorVersion  > 3) && (ver.dwPlatformId == VER_PLATFORM_WIN32_NT);\n\t\t\t\t\tbool winXP = ((ver.dwMajorVersion == 5) && (ver.dwMinorVersion == 1)) || (ver.dwMajorVersion > 5);\n\n\t\t\t\t\t// * Get the registry entry for driver\n\n\t\t\t\t\t// OSversion >= osWin2k\n\t\t\t\t\tif (atleastNT4)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (winXP)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring::size_type pos = keyPath.rfind ('\\\\');\n\t\t\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t\t\t\tkeyPath = keyPath.substr (0, pos+1);\n\t\t\t\t\t\t\tkeyPath += \"Video\";\n\t\t\t\t\t\t\tkeyName = \"Service\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstring::size_type pos = toLower(keyPath).find (\"\\\\device\");\n\t\t\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t\t\t\tkeyPath = keyPath.substr (0, pos+1);\n\t\t\t\t\t\t\tkeyName = \"ImagePath\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse // Win 9x\n\t\t\t\t\t{\n\t\t\t\t\t\tkeyPath += \"\\\\default\";\n\t\t\t\t\t\tkeyName = \"drv\";\n\t\t\t\t\t}\n\n\t\t\t\t\t// Format the key path\n\t\t\t\t\tif (toLower(keyPath).find (\"\\\\registry\\\\machine\") == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tkeyPath = \"HKEY_LOCAL_MACHINE\" + keyPath.substr (strlen (\"\\\\registry\\\\machine\"));\n\t\t\t\t\t}\n\n\t\t\t\t\t// Get the root key\n\t\t\t\t\tstatic const char *rootKeys[]=\n\t\t\t\t\t{\n\t\t\t\t\t\t\"HKEY_CLASSES_ROOT\\\\\",\n\t\t\t\t\t\t\"HKEY_CURRENT_CONFIG\\\\\",\n\t\t\t\t\t\t\"HKEY_CURRENT_USER\\\\\",\n\t\t\t\t\t\t\"HKEY_LOCAL_MACHINE\\\\\",\n\t\t\t\t\t\t\"HKEY_USERS\\\\\",\n\t\t\t\t\t\t\"HKEY_PERFORMANCE_DATA\\\\\",\n\t\t\t\t\t\t\"HKEY_DYN_DATA\\\\\"\n\t\t\t\t\t};\n\t\t\t\t\tstatic const HKEY rootKeysH[]=\n\t\t\t\t\t{\n\t\t\t\t\t\tHKEY_CLASSES_ROOT,\n\t\t\t\t\t\tHKEY_CURRENT_CONFIG,\n\t\t\t\t\t\tHKEY_CURRENT_USER,\n\t\t\t\t\t\tHKEY_LOCAL_MACHINE,\n\t\t\t\t\t\tHKEY_USERS,\n\t\t\t\t\t\tHKEY_PERFORMANCE_DATA,\n\t\t\t\t\t\tHKEY_DYN_DATA,\n\t\t\t\t\t};\n\t\t\t\t\tuint i;\n\t\t\t\t\tHKEY keyRoot = HKEY_LOCAL_MACHINE;\n\t\t\t\t\tfor (i=0; i<sizeof(rootKeysH)/sizeof(HKEY); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (toUpper(keyPath).find (rootKeys[i]) == 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tkeyPath = keyPath.substr (strlen (rootKeys[i]));\n\t\t\t\t\t\t\tkeyRoot = rootKeysH[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// * Read the registry\n\t\t\t\t\tHKEY baseKey;\n\t\t\t\t\tif (RegOpenKeyExA(keyRoot, keyPath.c_str(), 0, KEY_READ, &baseKey) == ERROR_SUCCESS)\n\t\t\t\t\t{\n\t\t\t\t\t\tDWORD valueType;\n\t\t\t\t\t\tchar value[512];\n\t\t\t\t\t\tDWORD size = 512;\n\t\t\t\t\t\tif (RegQueryValueExA(baseKey, keyName.c_str(), NULL, &valueType, (unsigned char *)value, &size) == ERROR_SUCCESS)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Null ?\n\t\t\t\t\t\t\tif (value[0] != 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tbool ok = !winXP;\n\t\t\t\t\t\t\t\tif (winXP)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// In Windows'XP we got service name -> not real driver name, so\n\t\t\t\t\t\t\t\t\tstring xpKey = string (\"System\\\\CurrentControlSet\\\\Services\\\\\")+value;\n\t\t\t\t\t\t\t\t\tif (RegOpenKeyExA(HKEY_LOCAL_MACHINE, xpKey.c_str(), 0, KEY_READ, &baseKey) == ERROR_SUCCESS)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tsize = 512;\n\t\t\t\t\t\t\t\t\t\tif (RegQueryValueExA(baseKey, \"ImagePath\", NULL, &valueType, (unsigned char *)value, &size) == ERROR_SUCCESS)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif (value[0] != 0)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : empty value ImagePath in key %s\", xpKey.c_str());\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : can't query ImagePath in key %s\", xpKey.c_str());\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : can't open key %s\", xpKey.c_str());\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Version dll link\n\t\t\t\t\t\t\t\tHMODULE hmVersion = LoadLibrary (_T(\"version\"));\n\t\t\t\t\t\t\t\tif (hmVersion)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tBOOL (WINAPI* _GetFileVersionInfo)(LPTSTR, DWORD, DWORD, LPVOID) = NULL;\n\t\t\t\t\t\t\t\t\tDWORD (WINAPI* _GetFileVersionInfoSize)(LPTSTR, LPDWORD) = NULL;\n\t\t\t\t\t\t\t\t\tBOOL (WINAPI* _VerQueryValue)(const LPVOID, LPTSTR, LPVOID*, PUINT) = NULL;\n\t\t\t\t\t\t\t\t\t*(FARPROC*)&_GetFileVersionInfo = GetProcAddress(hmVersion, \"GetFileVersionInfoA\");\n\t\t\t\t\t\t\t\t\t*(FARPROC*)&_GetFileVersionInfoSize = GetProcAddress(hmVersion, \"GetFileVersionInfoSizeA\");\n\t\t\t\t\t\t\t\t\t*(FARPROC*)&_VerQueryValue = GetProcAddress(hmVersion, \"VerQueryValueA\");\n\t\t\t\t\t\t\t\t\tif (_VerQueryValue && _GetFileVersionInfoSize && _GetFileVersionInfo)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// value got the path to the driver\n\t\t\t\t\t\t\t\t\t\tstring driverName = value;\n\t\t\t\t\t\t\t\t\t\tif (atleastNT4)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnlverify (GetWindowsDirectoryA(value, 512) != 0);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnlverify (GetSystemDirectoryA(value, 512) != 0);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tdriverName = string (value) + \"\\\\\" + driverName;\n\n\t\t\t\t\t\t\t\t\t\tDWORD dwHandle;\n\t\t\t\t\t\t\t\t\t\tDWORD size = _GetFileVersionInfoSize ((char*)driverName.c_str(), &dwHandle);\n\t\t\t\t\t\t\t\t\t\tif (size)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tvector<uint8> buffer;\n\t\t\t\t\t\t\t\t\t\t\tbuffer.resize (size);\n\t\t\t\t\t\t\t\t\t\t\tif (_GetFileVersionInfo((char*)driverName.c_str(), dwHandle, size, &buffer[0]))\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tVS_FIXEDFILEINFO *info;\n\t\t\t\t\t\t\t\t\t\t\t\tUINT len;\n\t\t\t\t\t\t\t\t\t\t\t\tchar bslash[] = { '\\\\', 0x00 };\n\t\t\t\t\t\t\t\t\t\t\t\tif (_VerQueryValue(&buffer[0], bslash, (VOID**)&info, &len))\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tdriverVersion = (((uint64)info->dwFileVersionMS)<<32)|info->dwFileVersionLS;\n\t\t\t\t\t\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : VerQueryValue fails (%s)\", driverName.c_str());\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : GetFileVersionInfo fails (%s)\", driverName.c_str());\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : GetFileVersionInfoSize == 0 (%s)\", driverName.c_str());\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : No VerQuery, GetFileVersionInfoSize, GetFileVersionInfo functions\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : No version dll\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : empty value %s in key %s\", keyName.c_str(), keyPath.c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : can't query value %s in key %s\", keyName.c_str(), keyPath.c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : can't open key %s\", keyPath.c_str());\n\t\t\t\t}\n\t\t\t\tdevice++;\n\t\t\t}\n\t\t\tif (!found)\n\t\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : No primary display device found\");\n\t\t}\n\t\telse\n\t\t\tnlwarning (\"CSystemInfo::getVideoInfo : No EnumDisplayDevices function\");\n\t}\n\telse\n\t\tnlwarning (\"CSystemInfo::getVideoInfo : No user32 dll\");\n\n#endif // NL_OS_WINDOWS\n\n\t// Fails\n\treturn false;\n}\n\nuint64 CSystemInfo::virtualMemory ()\n{\n#ifdef NL_OS_WINDOWS\n\tMEMORYSTATUS ms;\n\tGlobalMemoryStatus (&ms);\n\treturn uint64(ms.dwTotalVirtual - ms.dwAvailVirtual);\n#else\n\treturn 0;\n#endif\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/system_utils.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/system_utils.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <ObjBase.h>\n#\tifdef _WIN32_WINNT_WIN7\n\t\t// only supported by Windows 7 Platform SDK\n#\t\tinclude <ShObjIdl.h>\n#\t\tdefine TASKBAR_PROGRESS 1\n#\tendif\n#endif\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nusing namespace std;\n\n// Key in registry\nstatic string RootKey;\nstatic const uint32 KeyMaxLength = 1024;\n\nnamespace NLMISC {\n\nnlWindow CSystemUtils::s_window = EmptyWindow;\n\nbool CSystemUtils::init()\n{\n#ifdef NL_OS_WINDOWS\n\t// initialize COM\n\tHRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);\n\tif (FAILED(hr)) return false;\n#endif\n\n\treturn true;\n}\n\nbool CSystemUtils::uninit()\n{\n#ifdef NL_OS_WINDOWS\n\t// uninitialize COM\n\tCoUninitialize();\n#endif\n\n\treturn true;\n}\n\nvoid CSystemUtils::setWindow(nlWindow window)\n{\n\ts_window = window;\n}\n\nbool CSystemUtils::updateProgressBar(uint value, uint total)\n{\n#ifdef TASKBAR_PROGRESS\n\tif (s_window == NULL)\n\t{\n\t\tnlwarning(\"No window has be set with CSystemUtils::setWindow(), progress bar can't be displayed\");\n\t\treturn false;\n\t}\n\n\tITaskbarList3 *pTaskbarList = NULL;\n\n\t// instanciate the taskbar control COM object\n\tHRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pTaskbarList));\n\t// error can be ignored because Windows versions before Windows 7 doesn't support it\n\tif (FAILED(hr) || !pTaskbarList) return false;\n\n\tif (total)\n\t{\n\t\t// update the taskbar progress\n\t\thr = pTaskbarList->SetProgressValue(s_window, (ULONGLONG)value, (ULONGLONG)total);\n\t}\n\telse\n\t{\n\t\t// don't update anymore the progress\n\t\thr = pTaskbarList->SetProgressState(s_window, value == 0 ? TBPF_INDETERMINATE:TBPF_NOPROGRESS);\n\t}\n\n\t// release the interface\n\tpTaskbarList->Release();\n\n#endif // TASKBAR_PROGRESS\n\n\treturn true;\n}\n\nbool CSystemUtils::copyTextToClipboard(const ucstring &text)\n{\n\tif (!text.size()) return false;\n\n\tbool res = false;\n\n#ifdef NL_OS_WINDOWS\n\tif (OpenClipboard(NULL))\n\t{\n\t\t// check if unicode format is supported by clipboard\n\t\tbool isUnicode = (IsClipboardFormatAvailable(CF_UNICODETEXT) == TRUE);\n\n\t\t// allocates a buffer to copy text in global memory\n\t\tHGLOBAL mem = GlobalAlloc(GHND|GMEM_DDESHARE, (text.size()+1) * (isUnicode ? 2:1));\n\n\t\tif (mem)\n\t\t{\n\t\t\t// create a lock on this buffer\n\t\t\tvoid *hLock = GlobalLock(mem);\n\n\t\t\t// copy text to this buffer\n\t\t\tif (isUnicode)\n\t\t\t\twcscpy((wchar_t*)hLock, (const wchar_t*)text.c_str());\n\t\t\telse\n\t\t\t\tstrcpy((char*)hLock, text.toString().c_str());\n\n\t\t\t// unlock buffer\n\t\t\tGlobalUnlock(mem);\n\n\t\t\t// empty clipboard\n\t\t\tEmptyClipboard();\n\n\t\t\t// set new data to clipboard in the right format\n\t\t\tSetClipboardData(isUnicode ? CF_UNICODETEXT:CF_TEXT, mem);\n\n\t\t\tres = true;\n\t\t}\n\n\t\tCloseClipboard();\n\t}\n#endif\n\n\treturn res;\n}\n\nbool CSystemUtils::pasteTextFromClipboard(ucstring &text)\n{\n\tbool res = false;\n\n#ifdef NL_OS_WINDOWS\n\tif (OpenClipboard(NULL))\n\t{\n\t\t// check if unicode format is supported by clipboard\n\t\tbool isUnicode = (IsClipboardFormatAvailable(CF_UNICODETEXT) == TRUE);\n\n\t\t// get data from clipboard (if not of this type, they are converted)\n\t\t// warning, this code can't be debuggued in VC++ IDE, hObj will be always NULL\n\t\tHANDLE hObj = GetClipboardData(isUnicode ? CF_UNICODETEXT:CF_TEXT);\n\n\t\tif (hObj)\n\t\t{\n\t\t\t// create a lock on clipboard data\n\t\t\tvoid *hLock = GlobalLock(hObj);\n\n\t\t\tif (hLock != NULL)\n\t\t\t{\n\t\t\t\t// retrieve clipboard data\n\t\t\t\tif (isUnicode)\n\t\t\t\t\ttext = (const ucchar*)hLock;\n\t\t\t\telse\n\t\t\t\t\ttext = (const char*)hLock;\n\n\t\t\t\t// unlock data\n\t\t\t\tGlobalUnlock(hObj);\n\n\t\t\t\tres = true;\n\t\t\t}\n\t\t}\n\n\t\tCloseClipboard();\n\t}\n#endif\n\n\treturn res;\n}\n\nbool CSystemUtils::supportUnicode()\n{\n\tstatic bool init = false;\n\tstatic bool unicodeSupported = false;\n\tif (!init)\n\t{\n\t\tinit = true;\n#ifdef NL_OS_WINDOWS\n\t\tOSVERSIONINFO osvi;\n\t\tosvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\n\n\t\t// get Windows version\n\t\tif (GetVersionEx(&osvi))\n\t\t{\n\t\t\tif (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)\n\t\t\t{\n\t\t\t\t// unicode is supported since Windows NT 4.0\n\t\t\t\tif (osvi.dwMajorVersion >= 4)\n\t\t\t\t{\n\t\t\t\t\tunicodeSupported = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n#else\n\t\tunicodeSupported = true;\n#endif\n\t}\n\treturn unicodeSupported;\n}\n\nbool CSystemUtils::isAzertyKeyboard()\n{\n#ifdef NL_OS_WINDOWS\n\tuint16 klId = uint16((uintptr_t)GetKeyboardLayout(0) & 0xFFFF);\n\t// 0x040c is French, 0x080c is Belgian\n\tif (klId == 0x040c || klId == 0x080c)\n\t\treturn true;\n#endif\n\treturn false;\n}\n\nbool CSystemUtils::isScreensaverEnabled()\n{\n\tbool res = false;\n#ifdef NL_OS_WINDOWS\n//\told code, is not working anymore\n//\tBOOL bRetValue;\n//\tSystemParametersInfoA(SPI_GETSCREENSAVEACTIVE, 0, &bRetValue, 0);\n//\tres = (bRetValue == TRUE);\n\tHKEY hKeyScreenSaver = NULL;\n//\tLSTATUS lReturn = RegOpenKeyExA(HKEY_CURRENT_USER, TEXT(\"Control Panel\\\\Desktop\"), 0, KEY_QUERY_VALUE, &hKeyScreenSaver);\n\tunsigned long lReturn = RegOpenKeyExA(HKEY_CURRENT_USER, TEXT(\"Control Panel\\\\Desktop\"), 0, KEY_QUERY_VALUE, &hKeyScreenSaver);\n\tif (lReturn == ERROR_SUCCESS)\n\t{\n\t\tDWORD dwType = 0L;\n\t\tDWORD dwSize = KeyMaxLength;\n\t\tunsigned char Buffer[KeyMaxLength] = {0};\n\n\t\tlReturn = RegQueryValueExA(hKeyScreenSaver, TEXT(\"SCRNSAVE.EXE\"), NULL, &dwType, NULL, &dwSize);\n\t\t// if SCRNSAVE.EXE is present, check also if it's empty\n\t\tif (lReturn == ERROR_SUCCESS)\n\t\t\tres = (Buffer[0] != '\\0');\n\t}\n\tRegCloseKey(hKeyScreenSaver);\n#endif\n\treturn res;\n}\n\nbool CSystemUtils::enableScreensaver(bool screensaver)\n{\n\tbool res = false;\n#ifdef NL_OS_WINDOWS\n\tres = (SystemParametersInfoA(SPI_SETSCREENSAVEACTIVE, screensaver ? TRUE:FALSE, NULL, 0) == TRUE);\n#endif\n\treturn res;\n}\n\nstd::string CSystemUtils::getRootKey()\n{\n\treturn RootKey;\n}\n\nvoid CSystemUtils::setRootKey(const std::string &root)\n{\n\tRootKey = root;\n}\n\nstring CSystemUtils::getRegKey(const string &Entry)\n{\n\tstring ret;\n#ifdef NL_OS_WINDOWS\n\tHKEY hkey;\n\n\tif(RegOpenKeyEx(HKEY_CURRENT_USER, RootKey.c_str(), 0, KEY_READ, &hkey) == ERROR_SUCCESS)\n\t{\n\t\tDWORD\tdwType\t= 0L;\n\t\tDWORD\tdwSize\t= KeyMaxLength;\n\t\tunsigned char\tBuffer[KeyMaxLength];\n\n\t\tif(RegQueryValueEx(hkey, Entry.c_str(), NULL, &dwType, Buffer, &dwSize) != ERROR_SUCCESS)\n\t\t{\n\t\t\tnlwarning(\"Can't get the reg key '%s'\", Entry.c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tret = (char*)Buffer;\n\t\t}\n\t\tRegCloseKey(hkey);\n\t}\n\telse\n\t{\n\t\tnlwarning(\"Can't get the reg key '%s'\", Entry.c_str());\n\t}\n#endif\n\treturn ret;\n}\n\nbool CSystemUtils::setRegKey(const string &ValueName, const string &Value)\n{\n\tbool res = false;\n#ifdef NL_OS_WINDOWS\n\tHKEY hkey;\n\tDWORD dwDisp;\n\n\tchar nstr[] = { 0x00 };\n\tif (RegCreateKeyExA(HKEY_CURRENT_USER, RootKey.c_str(), 0, nstr, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp) == ERROR_SUCCESS)\n\t{\n\t\tif (RegSetValueExA(hkey, ValueName.c_str(), 0L, REG_SZ, (const BYTE *)Value.c_str(), (DWORD)(Value.size())+1) == ERROR_SUCCESS)\n\t\t\tres = true;\n\t\tRegCloseKey(hkey);\n\t}\n\telse\n\t{\n\t\tnlwarning(\"Can't set the reg key '%s' '%s'\", ValueName.c_str(), Value.c_str());\n\t}\n#endif\n\n\treturn res;\n}\n\nuint CSystemUtils::getCurrentColorDepth()\n{\n\tuint depth = 0;\n\n#ifdef NL_OS_WINDOWS\n\tHWND desktopWnd = GetDesktopWindow();\n\tif (desktopWnd)\n\t{\n\t\tHDC desktopDC = GetWindowDC(desktopWnd);\n\t\tif (desktopDC)\n\t\t{\n\t\t\tdepth = (uint) GetDeviceCaps(desktopDC, BITSPIXEL);\n\t\t\tReleaseDC(desktopWnd, desktopDC);\n\t\t}\n\t}\n#else\n\tdepth = 24; // temporary fix for compilation under Linux\n/*\n\tDisplay *display = XOpenDisplay(NULL);\n\tif (display)\n\t{\n\t\tdepth = (uint) DefaultDepth(display, DefaultScreen(display));\n\t\tXCloseDisplay(display);\n\t}\n*/\n#endif\n\treturn depth;\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/task_manager.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/task_manager.h\"\n#include \"nel/misc/big_file.h\"\n\nusing namespace std;\n\n#define NLMISC_DONE_TASK_SIZE 20\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n/*\n * Constructor\n */\nCTaskManager::CTaskManager() : _RunningTask (\"\"), _TaskQueue (\"\"), _DoneTaskQueue (\"\")\n{\n\t_IsTaskRunning = false;\n\t_ThreadRunning = true;\n\tCSynchronized<string>::CAccessor currentTask(&_RunningTask);\n\tcurrentTask.value () = \"\";\n\t_Thread = IThread::create(this);\n\t_Thread->start();\n\t_ChangePriorityCallback = NULL;\n}\n\n/*\n * Destructeur\n */\nCTaskManager::~CTaskManager()\n{\n\t_ThreadRunning = false;\n\twhile(!_ThreadRunning)\n\t\tnlSleep(10);\n\n\t// There should be no remaining Tasks\n\tCSynchronized<std::list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tnlassert(acces.value().empty());\n\t_Thread->wait();\n\tdelete _Thread;\n\t_Thread = NULL;\n\n}\n\n// Manage TaskQueue\nvoid CTaskManager::run(void)\n{\n\tIRunnable *runnableTask;\n\tfloat priorityTask = 0.f;\n\twhile(_ThreadRunning)\n\t{\n\t\t{\n\t\t\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\t\t\tif(acces.value().empty())\n\t\t\t{\n\t\t\t\trunnableTask = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Update task priorities\n\t\t\t\tchangeTaskPriority ();\n\n\t\t\t\t// Get the best task\n\t\t\t\tlist<CWaitingTask> &taskList = acces.value();\n\t\t\t\tlist<CWaitingTask>::iterator ite = taskList.begin();\n\t\t\t\tlist<CWaitingTask>::iterator bestIte = ite;\n\t\t\t\twhile (ite != taskList.end())\n\t\t\t\t{\n\t\t\t\t\tif (ite->Priority < bestIte->Priority)\n\t\t\t\t\t\tbestIte = ite;\n\n\t\t\t\t\t// Next task;\n\t\t\t\t\tite++;\n\t\t\t\t}\n\n\t\t\t\t_IsTaskRunning = true;\n\t\t\t\trunnableTask = bestIte->Task;\n\t\t\t\tpriorityTask = bestIte->Priority;\n\t\t\t\ttaskList.erase (bestIte);\n\t\t\t}\n\t\t}\n\t\tif(runnableTask)\n\t\t{\n\t\t\t{\n\t\t\t\tCSynchronized<string>::CAccessor currentTask(&_RunningTask);\n\t\t\t\tstring temp;\n\t\t\t\trunnableTask->getName(temp);\n\t\t\t\tcurrentTask.value () = temp + \" \" + toString (priorityTask);\n\t\t\t}\n\t\t\trunnableTask->run();\n\t\t\t{\n\t\t\t\tCSynchronized<string>::CAccessor currentTask(&_RunningTask);\n\t\t\t\tCSynchronized<deque<string> >::CAccessor doneTask(&_DoneTaskQueue);\n\t\t\t\tdoneTask.value().push_front (currentTask.value ());\n\t\t\t\tcurrentTask.value () = \"\";\n\t\t\t\tif (doneTask.value().size () > NLMISC_DONE_TASK_SIZE)\n\t\t\t\t\tdoneTask.value().resize (NLMISC_DONE_TASK_SIZE);\n\t\t\t}\n\n\t\t\t_IsTaskRunning = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsleepTask();\n\t\t}\n\t}\n\tCBigFile::getInstance().currentThreadFinished();\n\t_ThreadRunning = true;\n}\n\n// Add a task to TaskManager\nvoid CTaskManager::addTask(IRunnable *r, float priority)\n{\n\tCSynchronized<std::list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tacces.value().push_back(CWaitingTask(r, priority));\n}\n\n/// Delete a task, only if task is not running, return true if found and deleted\nbool CTaskManager::deleteTask(IRunnable *r)\n{\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tfor(list<CWaitingTask>::iterator it = acces.value().begin(); it != acces.value().end(); it++)\n\t{\n\t\tif(it->Task == r)\n\t\t{\n\t\t\tacces.value().erase(it);\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/// Task list size\nuint CTaskManager::taskListSize(void)\n{\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\treturn (uint)acces.value().size();\n}\n\n\nvoid\tCTaskManager::waitCurrentTaskToComplete ()\n{\n\twhile (_IsTaskRunning)\n\t\tsleepTask();\n}\n\n// ***************************************************************************\n\nvoid CTaskManager::dump (std::vector<std::string> &result)\n{\n\tCSynchronized<string>::CAccessor accesCurrent(&_RunningTask);\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\tCSynchronized<deque<string> >::CAccessor accesDone(&_DoneTaskQueue);\n\n\tconst list<CWaitingTask> &taskList = acces.value();\n\tconst deque<string> &taskDone = accesDone.value();\n\tconst string &taskCurrent = accesCurrent.value();\n\n\t// Resize the destination array\n\tresult.clear ();\n\tresult.reserve (taskList.size () + taskDone.size () + 1);\n\n\t// Add the done strings\n\tdeque<string>::const_reverse_iterator iteDone = taskDone.rbegin ();\n\twhile (iteDone != taskDone.rend ())\n\t{\n\t\tresult.push_back (\"Done : \" + *iteDone);\n\n\t\t// Next task\n\t\titeDone++;\n\t}\n\n\t// Add the current string\n\tif (!taskCurrent.empty())\n\t{\n\t\tresult.push_back (\"Current : \" + taskCurrent);\n\t}\n\n\t// Add the waiting strings\n\tlist<CWaitingTask>::const_iterator ite = taskList.begin ();\n\twhile (ite != taskList.end ())\n\t{\n\t\tstring name;\n\t\tite->Task->getName (name);\n\t\tresult.push_back (\"Waiting : \" + name + \" \" + toString(ite->Priority));\n\n\t\t// Next task\n\t\tite++;\n\t}\n}\n\n// ***************************************************************************\nvoid CTaskManager::clearDump()\n{\n\tCSynchronized<deque<string> >::CAccessor accesDone(&_DoneTaskQueue);\n\taccesDone.value().clear();\n}\n\n// ***************************************************************************\n\nuint CTaskManager::getNumWaitingTasks()\n{\n\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\treturn (uint)acces.value().size();\n}\n\n// ***************************************************************************\n\nvoid CTaskManager::changeTaskPriority ()\n{\n\tif (_ChangePriorityCallback)\n\t{\n\t\tCSynchronized<list<CWaitingTask> >::CAccessor acces(&_TaskQueue);\n\t\tlist<CWaitingTask> &taskList = acces.value();\n\n\t\tlist<CWaitingTask>::iterator ite = taskList.begin();\n\t\twhile(ite != taskList.end())\n\t\t{\n\t\t\t// Get the new priority\n\t\t\tite->Priority = _ChangePriorityCallback->getTaskPriority(*(ite->Task));\n\n\t\t\t// Next task\n\t\t\tite++;\n\t\t}\n\t}\n}\n\n// ***************************************************************************\n\nvoid CTaskManager::registerTaskPriorityCallback (IChangeTaskPriority *callback)\n{\n\t_ChangePriorityCallback = callback;\n}\n\n// ***************************************************************************\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/tds.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/tds.h\"\n#include \"nel/misc/debug.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n// *********************************************************\n\nCTDS::CTDS ()\n{\n\t/* Please no assert in the constructor because it is called by the NeL memory allocator constructor */\n#ifdef NL_OS_WINDOWS\n\t_Handle = TlsAlloc ();\n\tTlsSetValue (_Handle, NULL);\n#else // NL_OS_WINDOWS\n//\tnldebug(\"CTDS::CTDS...\");\n\tnlverify(pthread_key_create (&_Key, NULL) == 0);\n//\tnldebug(\"CTDS::CTDS : create a new key %u\", _Key);\n\tpthread_setspecific(_Key, NULL);\n#endif // NL_OS_WINDOWS\n}\n\n// *********************************************************\n\nCTDS::~CTDS ()\n{\n#ifdef NL_OS_WINDOWS\n\tnlverify (TlsFree (_Handle) != 0);\n#else // NL_OS_WINDOWS\n//\tnldebug(\"CTDS::~CTDS : deleting key %u\", _Key);\n\tnlverify (pthread_key_delete (_Key) == 0);\n#endif // NL_OS_WINDOWS\n}\n\n// *********************************************************\n\nvoid *CTDS::getPointer () const\n{\n#ifdef NL_OS_WINDOWS\n\treturn TlsGetValue (_Handle);\n#else // NL_OS_WINDOWS\n//\tnldebug(\"CTDS::getPointer for key %u...\", _Key);\n\tvoid *ret = pthread_getspecific (_Key);\n//\tnldebug(\"CTDS::getPointer returing value %p\", ret);\n\treturn ret;\n#endif // NL_OS_WINDOWS\n}\n\n// *********************************************************\n\nvoid CTDS::setPointer (void* pointer)\n{\n#ifdef NL_OS_WINDOWS\n\tnlverify (TlsSetValue (_Handle, pointer) != 0);\n#else // NL_OS_WINDOWS\n//\tnldebug(\"CTDS::setPointer for key %u to value %p\", _Key, pointer);\n\tnlverify (pthread_setspecific (_Key, pointer) == 0);\n#endif // NL_OS_WINDOWS\n}\n\n// *********************************************************\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/time_nl.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/misc/thread.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <MMSystem.h>\n#elif defined (NL_OS_UNIX)\n#\tinclude <sys/time.h>\n#\tinclude <unistd.h>\n#endif\n\n#ifdef NL_OS_MAC\n#include <mach/mach.h>\n#include <mach/mach_time.h>\n#endif\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nnamespace {\n#ifdef NL_OS_WINDOWS\nbool a_HaveQueryPerformance = false;\nLARGE_INTEGER a_QueryPerformanceFrequency;\n#endif\n#ifdef NL_OS_UNIX\n#\tif defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)\n#\tif defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK >= 0)\n#\t\tdefine NL_MONOTONIC_CLOCK\n#\tendif\n#\tendif\n#\tifdef NL_MONOTONIC_CLOCK\nbool a_CheckedMonotonicClock = false;\nbool a_HasMonotonicClock = false;\nuint64 a_MonotonicClockFrequency = 0;\nuint64 a_MonotonicClockResolutionNs = 0;\nbool hasMonotonicClock()\n{\n\tif (!a_CheckedMonotonicClock)\n\t{\n\t\t/* Initialize the local time engine.\n\t\t* On Unix, this method will find out if the Monotonic Clock is supported\n\t\t* (seems supported by kernel 2.6, not by kernel 2.4). See getLocalTime().\n\t\t*/\n\t\tstruct timespec tv;\n\t\tif ((clock_gettime( CLOCK_MONOTONIC, &tv ) == 0) &&\n\t\t\t (clock_getres( CLOCK_MONOTONIC, &tv ) == 0))\n\t\t{\n//\t\t\tnldebug( \"Monotonic local time supported (resolution %.6f ms)\", ((float)tv.tv_sec)*1000.0f + ((float)tv.tv_nsec)/1000000.0f );\n\n\t\t\tif (tv.tv_sec > 0)\n\t\t\t{\n\t\t\t\tnlwarning(\"Monotonic clock not ok, resolution > 1s\");\n\t\t\t\ta_HasMonotonicClock = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tuint64 nsPerTick = tv.tv_nsec;\n\t\t\t\tuint64 nsPerSec = 1000000000L;\n\t\t\t\tuint64 tickPerSec = nsPerSec / nsPerTick;\n\t\t\t\ta_MonotonicClockFrequency = tickPerSec;\n\t\t\t\ta_MonotonicClockResolutionNs = nsPerTick;\n\t\t\t\ta_HasMonotonicClock = true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\ta_HasMonotonicClock = false;\n\t\t}\n\t\ta_CheckedMonotonicClock = true;\n\t}\n\treturn a_HasMonotonicClock;\n}\n#\tendif\n#endif\n}\n\nvoid CTime::probeTimerInfo(CTime::CTimerInfo &result)\n{\n\tbreakable\n\t{\n#ifdef NL_OS_WINDOWS\n\t\tLARGE_INTEGER winPerfFreq;\n\t\tLARGE_INTEGER winPerfCount;\n\t\tDWORD lowResTime;\n\t\tif (!QueryPerformanceFrequency(&winPerfFreq))\n\t\t{\n\t\t\tnldebug(\"Cannot query performance frequency\");\n\t\t\tresult.IsHighPrecisionAvailable = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tresult.HighPrecisionResolution = winPerfFreq.QuadPart;\n\t\t}\n\t\tif (winPerfFreq.QuadPart == 1000)\n\t\t{\n\t\t\tnldebug(\"Higher precision timer not available, OS defaulted to GetTickCount\");\n\t\t\tresult.IsHighPrecisionAvailable = false;\n\t\t}\n\t\tif (!QueryPerformanceCounter(&winPerfCount))\n\t\t{\n\t\t\tnldebug(\"Cannot query performance counter\");\n\t\t\tresult.IsHighPrecisionAvailable = false;\n\t\t\tresult.HighPrecisionResolution = 1000;\n\t\t}\n\t\ta_HaveQueryPerformance = result.IsHighPrecisionAvailable;\n\t\ta_QueryPerformanceFrequency.QuadPart = winPerfFreq.QuadPart;\n\t\tif (!result.IsHighPrecisionAvailable)\n\t\t{\n\t\t\tlowResTime = timeGetTime();\n\t\t}\n#else\n\n\t\t// Other platforms are awesome. Generic implementation for now.\n\t\tTTime localTime = getLocalTime();\n\t\tresult.IsHighPrecisionAvailable = true;\n\t\tresult.HighPrecisionResolution = 0;\n\n#\tifdef NL_MONOTONIC_CLOCK\n\t\ttimespec monoClock;\n\t\tif (hasMonotonicClock())\n\t\t{\n\t\t\tclock_gettime(CLOCK_MONOTONIC, &monoClock);\n\t\t\tresult.HighPrecisionResolution = a_MonotonicClockFrequency;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnldebug(\"Monotonic clock not available\");\n\t\t}\n#\tendif\n\n#endif\n\n\t\tuint64 cpuMask = IProcess::getCurrentProcess()->getCPUMask();\n#ifdef NL_OS_WINDOWS\n\t\tuint64 threadMask = IThread::getCurrentThread()->getCPUMask(); // broken on linux, don't expect it to work anywhere\n#else\n\t\tuint64 threadMask = cpuMask;\n#endif\n\n\t\tuint identical = 0; // Identical stamps may indicate the os handling backwards glitches.\n\t\tuint backwards = 0; // Happens when the timers are not always in sync and the implementation is faulty.\n\t\tuint regular = 0; // How many times the number advanced normally.\n\t\tuint skipping = 0; // Does not really mean anything necessarily.\n\t\tuint frequencybug = 0; // Should never happen.\n\t\t// uint badcore = 0; // Affinity does not work.\n\n\t\t// Cycle 32 times trough all cores, and verify if the timing remains consistent.\n\t\tfor (uint i = 32; i; --i)\n\t\t{\n\t\t\tuint64 currentBit = 1;\n\t\t\tfor (uint j = 64; j; --j)\n\t\t\t{\n\t\t\t\tif (cpuMask & currentBit)\n\t\t\t\t{\n#ifdef NL_OS_WINDOWS\n\t\t\t\t\tif (!IThread::getCurrentThread()->setCPUMask(currentBit))\n#else\n\t\t\t\t\tif (!IProcess::getCurrentProcess()->setCPUMask(currentBit))\n#endif\n\t\t\t\t\t\tbreak; // Thread was set to last cpu.\n#ifdef NL_OS_WINDOWS\n\t\t\t\t\t// Make sure the thread is rescheduled.\n\t\t\t\t\tSwitchToThread();\n\t\t\t\t\tSleep(0);\n\t\t\t\t\t// Verify the core\n\t\t\t\t\t/* Can only verify on 2003, Vista and higher.\n\t\t\t\t\tif (1 << GetCurrentProcessorNumber() != currentBit)\n\t\t\t\t\t\t++badcore;\n\t\t\t\t\t*/\n\t\t\t\t\t// Check if the timer is still sane.\n\t\t\t\t\tif (result.IsHighPrecisionAvailable)\n\t\t\t\t\t{\n\t\t\t\t\t\tLARGE_INTEGER winPerfFreqN;\n\t\t\t\t\t\tLARGE_INTEGER winPerfCountN;\n\t\t\t\t\t\tQueryPerformanceFrequency(&winPerfFreqN);\n\t\t\t\t\t\tif (winPerfFreqN.QuadPart != winPerfFreq.QuadPart)\n\t\t\t\t\t\t\t++frequencybug;\n\t\t\t\t\t\tQueryPerformanceCounter(&winPerfCountN);\n\t\t\t\t\t\tif (winPerfCountN.QuadPart == winPerfCount.QuadPart)\n\t\t\t\t\t\t\t++identical;\n\t\t\t\t\t\tif (winPerfCountN.QuadPart < winPerfCount.QuadPart || winPerfCountN.QuadPart - winPerfCount.QuadPart < 0)\n\t\t\t\t\t\t\t++backwards;\n\t\t\t\t\t\tif (winPerfCountN.QuadPart - winPerfCount.QuadPart > winPerfFreq.QuadPart / 20) // 50ms skipping check\n\t\t\t\t\t\t\t++skipping;\n\t\t\t\t\t\telse if (winPerfCountN.QuadPart > winPerfCount.QuadPart)\n\t\t\t\t\t\t\t++regular;\n\t\t\t\t\t\twinPerfCount.QuadPart = winPerfCountN.QuadPart;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tDWORD lowResTimeN;\n\t\t\t\t\t\tlowResTimeN = timeGetTime();\n\t\t\t\t\t\tif (lowResTimeN == lowResTime)\n\t\t\t\t\t\t\t++identical;\n\t\t\t\t\t\tif (lowResTimeN < lowResTime || lowResTimeN - lowResTime < 0)\n\t\t\t\t\t\t\t++backwards;\n\t\t\t\t\t\tif (lowResTimeN - lowResTime > 50)\n\t\t\t\t\t\t\t++skipping;\n\t\t\t\t\t\telse if (lowResTimeN > lowResTime)\n\t\t\t\t\t\t\t++regular;\n\t\t\t\t\t\tlowResTime = lowResTimeN;\n\t\t\t\t\t}\n#else\n#ifdef NL_OS_UNIX\n\t\t\t\t\tsched_yield();\n#else\n\t\t\t\t\tnlSleep(0);\n#endif\n#\tifdef NL_MONOTONIC_CLOCK\n\t\t\t\t\tif (hasMonotonicClock())\n\t\t\t\t\t{\n\t\t\t\t\t\ttimespec monoClockN;\n\t\t\t\t\t\tclock_gettime(CLOCK_MONOTONIC, &monoClockN);\n\t\t\t\t\t\tif (monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec == monoClockN.tv_nsec)\n\t\t\t\t\t\t\t++identical;\n\t\t\t\t\t\tif (monoClockN.tv_sec < monoClock.tv_sec || (monoClock.tv_sec == monoClockN.tv_sec && monoClockN.tv_nsec < monoClock.tv_nsec))\n\t\t\t\t\t\t\t++backwards;\n\t\t\t\t\t\tif (monoClock.tv_sec == monoClockN.tv_sec && (monoClockN.tv_nsec - monoClock.tv_nsec > 50000000L))\n\t\t\t\t\t\t\t++skipping;\n\t\t\t\t\t\telse if ((monoClock.tv_sec == monoClockN.tv_sec && monoClock.tv_nsec < monoClockN.tv_nsec) || monoClock.tv_sec < monoClockN.tv_sec)\n\t\t\t\t\t\t\t++regular;\n\t\t\t\t\t\tmonoClock.tv_sec = monoClockN.tv_sec;\n\t\t\t\t\t\tmonoClock.tv_nsec = monoClockN.tv_nsec;\n\t\t\t\t\t}\n\t\t\t\t\telse\n#\tendif\n\t\t\t\t\t{\n\t\t\t\t\t\tTTime localTimeN = getLocalTime();\n\t\t\t\t\t\tif (localTimeN == localTime)\n\t\t\t\t\t\t\t++identical;\n\t\t\t\t\t\tif (localTimeN < localTime || localTimeN - localTime < 0)\n\t\t\t\t\t\t\t++backwards;\n\t\t\t\t\t\tif (localTimeN - localTime > 50)\n\t\t\t\t\t\t\t++skipping;\n\t\t\t\t\t\telse if (localTimeN > localTime)\n\t\t\t\t\t\t\t++regular;\n\t\t\t\t\t\tlocalTime = localTimeN;\n\t\t\t\t\t}\n#endif\n\t\t\t\t}\n\t\t\t\tcurrentBit <<= 1;\n\t\t\t}\n\t\t}\n\n#ifdef NL_OS_WINDOWS\n\t\tIThread::getCurrentThread()->setCPUMask(threadMask);\n#else\n\t\tIProcess::getCurrentProcess()->setCPUMask(threadMask);\n#endif\n\n\t\tnldebug(\"Timer resolution: %i Hz\", (int)(result.HighPrecisionResolution));\n\t\tnldebug(\"Time identical: %i, backwards: %i, regular: %i, skipping: %i, frequency bug: %i\", identical, backwards, regular, skipping, frequencybug);\n\t\tif (identical > regular)\n\t\t\tnlwarning(\"The system timer is of relatively low resolution, you may experience issues\");\n\t\tif (backwards > 0 || frequencybug > 0)\n\t\t{\n\t\t\tnlwarning(\"The current system timer is not reliable across multiple cpu cores\");\n\t\t\tresult.RequiresSingleCore = true;\n\t\t}\n\t\telse result.RequiresSingleCore = false;\n\n\t\tif (result.HighPrecisionResolution == 14318180)\n\t\t{\n\t\t\tnldebug(\"Detected known HPET era timer frequency\");\n\t\t}\n\t\tif (result.HighPrecisionResolution == 3579545)\n\t\t{\n\t\t\tnldebug(\"Detected known AHCI era timer frequency\");\n\t\t}\n\t\tif (result.HighPrecisionResolution == 1193182)\n\t\t{\n\t\t\tnldebug(\"Detected known i8253/i8254 era timer frequency\");\n\t\t}\n\t}\n}\n\n/* Return the number of second since midnight (00:00:00), January 1, 1970,\n * coordinated universal time, according to the system clock.\n * This values is the same on all computer if computers are synchronized (with NTP for example).\n */\nuint32 CTime::getSecondsSince1970 ()\n{\n\treturn uint32(time(NULL));\n}\n\n/** Return the number of second since midnight (00:00:00), January 1, 1970,\n * coordinated universal time, according to the system clock.\n * The time returned is UTC (aka GMT+0), ie it does not have the local time ajustement\n * nor it have the daylight saving ajustement.\n * This values is the same on all computer if computers are synchronized (with NTP for example).\n */\n//uint32\tCTime::getSecondsSince1970UTC ()\n//{\n//\t// get the local time\n//\ttime_t nowLocal = time(NULL);\n//\t// convert it to GMT time (UTC)\n//\tstruct tm * timeinfo;\n//\ttimeinfo = gmtime(&nowLocal);\n//\treturn nl_mktime(timeinfo);\n//}\n\n/* Return the local time in milliseconds.\n * Use it only to measure time difference, the absolute value does not mean anything.\n * On Unix, getLocalTime() will try to use the Monotonic Clock if available, otherwise\n * the value can jump backwards if the system time is changed by a user or a NTP time sync process.\n * The value is different on 2 different computers; use the CUniTime class to get a universal\n * time that is the same on all computers.\n * \\warning On Win32, the value is on 32 bits only. It wraps around to 0 every about 49.71 days.\n */\nTTime CTime::getLocalTime ()\n{\n\n#ifdef NL_OS_WINDOWS\n\n\t//static bool initdone = false;\n\t//static bool byperfcounter;\n\t// Initialization\n\t//if ( ! initdone )\n\t//{\n\t\t//byperfcounter = (getPerformanceTime() != 0);\n\t\t//initdone = true;\n\t//}\n\n\t/* Retrieve time is ms\n     * Why do we prefer getPerformanceTime() to timeGetTime() ? Because on one dual-processor Win2k\n\t * PC, we have noticed that timeGetTime() slows down when the client is running !!!\n\t */\n\t/* Now we have noticed that on all WinNT4 PC the getPerformanceTime can give us value that\n\t * are less than previous\n\t */\n\n\t//if ( byperfcounter )\n\t//{\n\t//\treturn (TTime)(ticksToSecond(getPerformanceTime()) * 1000.0f);\n\t//}\n\t//else\n\t//{\n\t\t// This is not affected by system time changes. But it cycles every 49 days.\n\t\t// return timeGetTime(); // Only this was left active before it was commented.\n\t//}\n\n\t/*\n\t * The above is no longer relevant.\n\t */\n\n\tif (a_HaveQueryPerformance)\n\t{\n\t\t// On a (fast) 15MHz timer this rolls over after 7000 days.\n\t\t// If my calculations are right.\n\t\tLARGE_INTEGER counter;\n\t\tQueryPerformanceCounter(&counter);\n\t\tcounter.QuadPart *= (LONGLONG)1000L;\n\t\tcounter.QuadPart /= a_QueryPerformanceFrequency.QuadPart;\n\t\treturn counter.QuadPart;\n\t}\n\telse\n\t{\n\t\t// Use default reliable low resolution timer.\n\t\treturn timeGetTime();\n\t}\n\n#elif defined (NL_OS_UNIX)\n\n#ifdef NL_MONOTONIC_CLOCK\n\n\tif (hasMonotonicClock())\n\t{\n\t\ttimespec tv;\n\t\t// This is not affected by system time changes.\n\t\tif ( clock_gettime( CLOCK_MONOTONIC, &tv ) != 0 )\n\t\t\tnlerror (\"Can't get clock time again\");\n\t    return (TTime)tv.tv_sec * (TTime)1000 + (TTime)((tv.tv_nsec/*+500*/) / 1000000);\n\t}\n\n#endif\n\n\t// This is affected by system time changes.\n\tstruct timeval tv;\n\tif ( gettimeofday( &tv, NULL) != 0 )\n\t\tnlerror (\"Can't get time of day\");\n\treturn (TTime)tv.tv_sec * (TTime)1000 + (TTime)tv.tv_usec / (TTime)1000;\n\n#endif\n}\n\n/* Return the time in processor ticks. Use it for profile purpose.\n * If the performance time is not supported on this hardware, it returns 0.\n * \\warning On a multiprocessor system, the value returned by each processor may\n * be different. The only way to workaround this is to set a processor affinity\n * to the measured thread.\n * \\warning The speed of tick increase can vary (especially on laptops or CPUs with\n * power management), so profiling several times and computing the average could be\n * a wise choice.\n */\nTTicks CTime::getPerformanceTime ()\n{\n#ifdef NL_OS_WINDOWS\n\tLARGE_INTEGER ret;\n\tif (QueryPerformanceCounter (&ret))\n\t\treturn ret.QuadPart;\n\telse\n\t\treturn 0;\n#elif defined(NL_OS_MAC)\n\treturn mach_absolute_time();\n#else\n#if defined(HAVE_X86_64)\n\tuint64 hi, lo;\n\t__asm__ volatile (\".byte 0x0f, 0x31\" : \"=a\" (lo), \"=d\" (hi));\n\treturn (hi << 32) | (lo & 0xffffffff);\n#elif defined(HAVE_X86) and !defined(NL_OS_MAC)\n\tuint64 x;\n\t// RDTSC - Read time-stamp counter into EDX:EAX.\n\t__asm__ volatile (\".byte 0x0f, 0x31\" : \"=A\" (x));\n\treturn x;\n#else // HAVE_X86\n\tstatic bool firstWarn = true;\n\tif (firstWarn)\n\t{\n\t\tnlwarning (\"TTicks CTime::getPerformanceTime () is not implemented for your processor, returning 0\");\n\t\tfirstWarn = false;\n\t}\n\treturn 0;\n#endif // HAVE_X86\n\n#endif // NL_OS_WINDOWS\n}\n/*\n#define GETTICKS(t) asm volatile (\"push %%esi\\n\\t\" \"mov %0, %%esi\" : : \"r\" (t)); \\\n                      asm volatile (\"push %eax\\n\\t\" \"push %edx\"); \\\n                      asm volatile (\"rdtsc\"); \\\n                      asm volatile (\"movl %eax, (%esi)\\n\\t\" \"movl %edx, 4(%esi)\"); \\\n                      asm volatile (\"pop %edx\\n\\t\" \"pop %eax\\n\\t\" \"pop %esi\");\n*/\n\n\n/* Convert a ticks count into second. If the performance time is not supported on this\n * hardware, it returns 0.0.\n */\ndouble CTime::ticksToSecond (TTicks ticks)\n{\n#ifdef NL_OS_WINDOWS\n\tLARGE_INTEGER ret;\n\tif (QueryPerformanceFrequency(&ret))\n\t{\n\t\treturn (double)(sint64)ticks/(double)ret.QuadPart;\n\t}\n\telse\n#elif defined(NL_OS_MAC)\n\t{\n\t\tstatic double factor = 0.0;\n\t\tif (factor == 0.0)\n\t\t{\n\t\t\tmach_timebase_info_data_t tbInfo;\n\t\t\tmach_timebase_info(&tbInfo);\n\t\t\tfactor = 1000000000.0 * (double)tbInfo.numer / (double)tbInfo.denom;\n\t\t}\n\t\treturn double(ticks / factor);\n\t}\n#endif // NL_OS_WINDOWS\n\t{\n\t\tstatic bool benchFrequency = true;\n\t\tstatic sint64 freq = 0;\n\t\tif (benchFrequency)\n\t\t{\n\t\t\t// try to have an estimation of the cpu frequency\n\n\t\t\tTTicks tickBefore = getPerformanceTime ();\n\t\t\tTTicks tickAfter = tickBefore;\n\t\t\tTTime timeBefore = getLocalTime ();\n\t\t\tTTime timeAfter = timeBefore;\n\t\t\tfor(;;)\n\t\t\t{\n\t\t\t\tif (timeAfter - timeBefore > 1000)\n\t\t\t\t\tbreak;\n\t\t\t\ttimeAfter = getLocalTime ();\n\t\t\t\ttickAfter = getPerformanceTime ();\n\t\t\t}\n\n\t\t\tTTime timeDelta = timeAfter - timeBefore;\n\t\t\tTTicks tickDelta = tickAfter - tickBefore;\n\n\t\t\tfreq = 1000 * tickDelta / timeDelta;\n\t\t\tbenchFrequency = false;\n\t\t}\n\n\t\treturn (double)(sint64)ticks/(double)freq;\n\t}\n}\n\n\nstd::string\tCTime::getHumanRelativeTime(sint32 nbSeconds)\n{\n\tsint32 delta = nbSeconds;\n\tif (delta < 0)\n\t\tdelta = -delta;\n\n\t// some constants of time duration in seconds\n\tconst sint32 oneMinute = 60;\n\tconst sint32 oneHour = oneMinute * 60;\n\tconst sint32 oneDay = oneHour * 24;\n\tconst sint32 oneWeek = oneDay * 7;\n\tconst sint32 oneMonth = oneDay * 30; // aprox, a more precise value is 30.416666... but no matter\n\tconst sint32 oneYear = oneDay * 365; // aprox, a more precise value is 365.26.. who care?\n\n\tsint32 year, month, week, day, hour, minute;\n\tyear = month = week = day = hour = minute = 0;\n\n\t/// compute the different parts\n\tyear = delta / oneYear;\n\tdelta %= oneYear;\n\n\tmonth = delta / oneMonth;\n\tdelta %= oneMonth;\n\n\tweek = delta / oneWeek;\n\tdelta %= oneWeek;\n\n\tday = delta / oneDay;\n\tdelta %= oneDay;\n\n\thour = delta / oneHour;\n\tdelta %= oneHour;\n\n\tminute = delta / oneMinute;\n\tdelta %= oneMinute;\n\n\t// compute the string\n\tCSString ret;\n\n\tif (year)\n\t\tret << year << \" years \";\n\tif (month)\n\t\tret << month << \" months \";\n\tif (week)\n\t\tret << week << \" weeks \";\n\tif (day)\n\t\tret << day << \" days \";\n\tif (hour)\n\t\tret << hour << \" hours \";\n\tif (minute)\n\t\tret << minute << \" minutes \";\n\tif (delta || ret.empty())\n\t\tret << delta << \" seconds \";\n\n\treturn ret;\n}\n\n#ifdef NL_OS_WINDOWS\n\t/** Return the offset in 10th of micro sec between the windows base time (\n\t *\t01-01-1601 0:0:0 UTC) and the unix base time (01-01-1970 0:0:0 UTC).\n\t *\tThis value is used to convert windows system and file time back and\n\t *\tforth to unix time (aka epoch)\n\t */\n\tuint64 CTime::getWindowsToUnixBaseTimeOffset()\n\t{\n\t\tstatic bool init = false;\n\n\t\tstatic uint64 offset = 0;\n\n\t\tif (! init)\n\t\t{\n\t\t\t// compute the offset to convert windows base time into unix time (aka epoch)\n\t\t\t// build a WIN32 system time for jan 1, 1970\n\t\t\tSYSTEMTIME baseTime;\n\t\t\tbaseTime.wYear = 1970;\n\t\t\tbaseTime.wMonth = 1;\n\t\t\tbaseTime.wDayOfWeek = 0;\n\t\t\tbaseTime.wDay = 1;\n\t\t\tbaseTime.wHour = 0;\n\t\t\tbaseTime.wMinute = 0;\n\t\t\tbaseTime.wSecond = 0;\n\t\t\tbaseTime.wMilliseconds = 0;\n\n\t\t\tFILETIME baseFileTime = {0,0};\n\t\t\t// convert it into a FILETIME value\n\t\t\tSystemTimeToFileTime(&baseTime, &baseFileTime);\n\t\t\toffset = baseFileTime.dwLowDateTime | (uint64(baseFileTime.dwHighDateTime)<<32);\n\n\t\t\tinit = true;\n\t\t}\n\n\t\treturn offset;\n\t}\n#endif\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/triangle.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/triangle.h\"\n#include \"nel/misc/plane.h\"\n#include \"nel/misc/matrix.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n#define EPSILON 0.0001f\n// ***************************************************************************\nbool CTriangle::intersect (const CVector& p0, const CVector& p1, CVector& hit, const CPlane& plane) const\n{\n\tCVector\tnormal = plane.getNormal();\n\n\tfloat\tnp1 = normal*p1;\n\tfloat\tnp2 = np1-normal*p0;\n\n\tif (np2 == 0.0f)\n\t\treturn false;\n\n\tfloat\tlambda = (plane.d+np1)/np2;\n\n\t// Checks the intersection belongs to the segment\n\tif (lambda < -EPSILON || lambda > 1.0f+EPSILON)\n\t\treturn false;\n\n\t// The intersection on the plane\n\thit = p0*lambda+p1*(1.0f-lambda);\n\n\tfloat\td0 = ((V1-V0)^normal)*(hit-V0);\n\tfloat\td1 = ((V2-V1)^normal)*(hit-V1);\n\tfloat\td2 = ((V0-V2)^normal)*(hit-V2);\n\n\treturn (d0 < +EPSILON && d1 < +EPSILON && d2 < +EPSILON) ||\n\t\t   (d0 > -EPSILON && d1 > -EPSILON && d2 > -EPSILON);\n}\n\n\n\n// ***************************************************************************\nvoid\tCTriangle::computeGradient(float c0, float c1, float c2, CVector &grad) const\n{\n\t// Compute basis for 2D triangle.\n\tCVector\t\tlocI, locJ, locK;\n\tlocI= V1-V0;\n\tlocJ= V2-V0;\n\tlocK= locI^locJ;\n\tlocK.normalize();\n\tlocI.normalize();\n\tlocJ= locK^locI;\n\n\t// compute triangle in 2D.\n\tCTriangle\ttri2D;\n\ttri2D.V0.set(0,0,0);\n\ttri2D.V1.x= (V1-V0)*locI;\n\ttri2D.V1.y= (V1-V0)*locJ;\n\ttri2D.V1.z= 0;\n\ttri2D.V2.x= (V2-V0)*locI;\n\ttri2D.V2.y= (V2-V0)*locJ;\n\ttri2D.V2.z= 0;\n\n\t// Compute 2 2D Gradients.\n\tfloat\tdx01= tri2D.V0.x - tri2D.V2.x;\n\tfloat\tdx02= tri2D.V1.x - tri2D.V2.x;\n\tfloat\tdy01= tri2D.V0.y - tri2D.V2.y;\n\tfloat\tdy02= tri2D.V1.y - tri2D.V2.y;\n\tfloat\tdc01= c0 - c2;\n\tfloat\tdc02= c1 - c2;\n\tfloat\tgd= dx02*dy01 - dx01*dy02;\n\n\tfloat\tOOgd;\n\tif(gd!=0)\n\t\tOOgd= 1.0f/gd;\n\telse\n\t\tOOgd= 1;\t// for now, do not manage correctly this case.\n\tfloat\tgx, gy;\n\tgx= (dc02*dy01 - dc01*dy02) * OOgd;\n\tgy= (dc01*dx02 - dc02*dx01) * OOgd;\n\n\t// transform in 3D.\n\tgrad= locI*gx + locJ*gy;\n}\n\n// ***************************************************************************\nvoid CTriangle::applyMatrix(const CMatrix &m, CTriangle &dest) const\n{\n\tdest.V0 = m * V0;\n\tdest.V1 = m * V1;\n\tdest.V2 = m * V2;\n}\n\n\n\n} // NLMISC\n\n"
  },
  {
    "path": "code/nel/src/misc/unicode.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/ucstring.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\n// Uppercase to lowercase 16 bits unicode. This table must be sorted. First entry must be unique.\nstatic const ucchar UnicodeUpperToLower[]=\n{\n\t0x0041, 0x0061,\t// LATIN CAPITAL LETTER A\n\t0x0042, 0x0062,\t// LATIN CAPITAL LETTER B\n\t0x0043, 0x0063,\t// LATIN CAPITAL LETTER C\n\t0x0044, 0x0064,\t// LATIN CAPITAL LETTER D\n\t0x0045, 0x0065,\t// LATIN CAPITAL LETTER E\n\t0x0046, 0x0066,\t// LATIN CAPITAL LETTER F\n\t0x0047, 0x0067,\t// LATIN CAPITAL LETTER G\n\t0x0048, 0x0068, // LATIN CAPITAL LETTER H\n\t0x0049, 0x0069, // LATIN CAPITAL LETTER I\n\t0x004A, 0x006A, // LATIN CAPITAL LETTER J\n\t0x004B, 0x006B, // LATIN CAPITAL LETTER K\n\t0x004C, 0x006C, // LATIN CAPITAL LETTER L\n\t0x004D, 0x006D, // LATIN CAPITAL LETTER M\n\t0x004E, 0x006E, // LATIN CAPITAL LETTER N\n\t0x004F, 0x006F, // LATIN CAPITAL LETTER O\n\t0x0050, 0x0070, // LATIN CAPITAL LETTER P\n\t0x0051, 0x0071, // LATIN CAPITAL LETTER Q\n\t0x0052, 0x0072, // LATIN CAPITAL LETTER R\n\t0x0053, 0x0073, // LATIN CAPITAL LETTER S\n\t0x0054, 0x0074, // LATIN CAPITAL LETTER T\n\t0x0055, 0x0075, // LATIN CAPITAL LETTER U\n\t0x0056, 0x0076, // LATIN CAPITAL LETTER V\n\t0x0057, 0x0077, // LATIN CAPITAL LETTER W\n\t0x0058, 0x0078, // LATIN CAPITAL LETTER X\n\t0x0059, 0x0079, // LATIN CAPITAL LETTER Y\n\t0x005A, 0x007A, // LATIN CAPITAL LETTER Z\n\t0x00B5, 0x03BC, // MICRO SIGN\n\t0x00C0, 0x00E0, // LATIN CAPITAL LETTER A WITH GRAVE\n\t0x00C1, 0x00E1, // LATIN CAPITAL LETTER A WITH ACUTE\n\t0x00C2, 0x00E2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX\n\t0x00C3, 0x00E3, // LATIN CAPITAL LETTER A WITH TILDE\n\t0x00C4, 0x00E4, // LATIN CAPITAL LETTER A WITH DIAERESIS\n\t0x00C5, 0x00E5, // LATIN CAPITAL LETTER A WITH RING ABOVE\n\t0x00C6, 0x00E6, // LATIN CAPITAL LETTER AE\n\t0x00C7, 0x00E7, // LATIN CAPITAL LETTER C WITH CEDILLA\n\t0x00C8, 0x00E8, // LATIN CAPITAL LETTER E WITH GRAVE\n\t0x00C9, 0x00E9, // LATIN CAPITAL LETTER E WITH ACUTE\n\t0x00CA, 0x00EA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX\n\t0x00CB, 0x00EB, // LATIN CAPITAL LETTER E WITH DIAERESIS\n\t0x00CC, 0x00EC, // LATIN CAPITAL LETTER I WITH GRAVE\n\t0x00CD, 0x00ED, // LATIN CAPITAL LETTER I WITH ACUTE\n\t0x00CE, 0x00EE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX\n\t0x00CF, 0x00EF, // LATIN CAPITAL LETTER I WITH DIAERESIS\n\t0x00D0, 0x00F0, // LATIN CAPITAL LETTER ETH\n\t0x00D1, 0x00F1, // LATIN CAPITAL LETTER N WITH TILDE\n\t0x00D2, 0x00F2, // LATIN CAPITAL LETTER O WITH GRAVE\n\t0x00D3, 0x00F3, // LATIN CAPITAL LETTER O WITH ACUTE\n\t0x00D4, 0x00F4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX\n\t0x00D5, 0x00F5, // LATIN CAPITAL LETTER O WITH TILDE\n\t0x00D6, 0x00F6, // LATIN CAPITAL LETTER O WITH DIAERESIS\n\t0x00D8, 0x00F8, // LATIN CAPITAL LETTER O WITH STROKE\n\t0x00D9, 0x00F9, // LATIN CAPITAL LETTER U WITH GRAVE\n\t0x00DA, 0x00FA, // LATIN CAPITAL LETTER U WITH ACUTE\n\t0x00DB, 0x00FB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX\n\t0x00DC, 0x00FC, // LATIN CAPITAL LETTER U WITH DIAERESIS\n\t0x00DD, 0x00FD, // LATIN CAPITAL LETTER Y WITH ACUTE\n\t0x00DE, 0x00FE, // LATIN CAPITAL LETTER THORN\n\t0x00DF, 0x0073 , // # LATIN SMALL LETTER SHARP S\n\t0x0100, 0x0101, // LATIN CAPITAL LETTER A WITH MACRON\n\t0x0102, 0x0103, // LATIN CAPITAL LETTER A WITH BREVE\n\t0x0104, 0x0105, // LATIN CAPITAL LETTER A WITH OGONEK\n\t0x0106, 0x0107, // LATIN CAPITAL LETTER C WITH ACUTE\n\t0x0108, 0x0109, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX\n\t0x010A, 0x010B, // LATIN CAPITAL LETTER C WITH DOT ABOVE\n\t0x010C, 0x010D, // LATIN CAPITAL LETTER C WITH CARON\n\t0x010E, 0x010F, // LATIN CAPITAL LETTER D WITH CARON\n\t0x0110, 0x0111, // LATIN CAPITAL LETTER D WITH STROKE\n\t0x0112, 0x0113, // LATIN CAPITAL LETTER E WITH MACRON\n\t0x0114, 0x0115, // LATIN CAPITAL LETTER E WITH BREVE\n\t0x0116, 0x0117, // LATIN CAPITAL LETTER E WITH DOT ABOVE\n\t0x0118, 0x0119, // LATIN CAPITAL LETTER E WITH OGONEK\n\t0x011A, 0x011B, // LATIN CAPITAL LETTER E WITH CARON\n\t0x011C, 0x011D, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX\n\t0x011E, 0x011F, // LATIN CAPITAL LETTER G WITH BREVE\n\t0x0120, 0x0121, // LATIN CAPITAL LETTER G WITH DOT ABOVE\n\t0x0122, 0x0123, // LATIN CAPITAL LETTER G WITH CEDILLA\n\t0x0124, 0x0125, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX\n\t0x0126, 0x0127, // LATIN CAPITAL LETTER H WITH STROKE\n\t0x0128, 0x0129, // LATIN CAPITAL LETTER I WITH TILDE\n\t0x012A, 0x012B, // LATIN CAPITAL LETTER I WITH MACRON\n\t0x012C, 0x012D, // LATIN CAPITAL LETTER I WITH BREVE\n\t0x012E, 0x012F, // LATIN CAPITAL LETTER I WITH OGONEK\n\t0x0130, 0x0069, // LATIN CAPITAL LETTER I WITH DOT ABOVE\n\t0x0132, 0x0133, // LATIN CAPITAL LIGATURE IJ\n\t0x0134, 0x0135, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX\n\t0x0136, 0x0137, // LATIN CAPITAL LETTER K WITH CEDILLA\n\t0x0139, 0x013A, // LATIN CAPITAL LETTER L WITH ACUTE\n\t0x013B, 0x013C, // LATIN CAPITAL LETTER L WITH CEDILLA\n\t0x013D, 0x013E, // LATIN CAPITAL LETTER L WITH CARON\n\t0x013F, 0x0140, // LATIN CAPITAL LETTER L WITH MIDDLE DOT\n\t0x0141, 0x0142, // LATIN CAPITAL LETTER L WITH STROKE\n\t0x0143, 0x0144, // LATIN CAPITAL LETTER N WITH ACUTE\n\t0x0145, 0x0146, // LATIN CAPITAL LETTER N WITH CEDILLA\n\t0x0147, 0x0148, // LATIN CAPITAL LETTER N WITH CARON\n\t0x0149, 0x02BC , // # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE\n\t0x014A, 0x014B, // LATIN CAPITAL LETTER ENG\n\t0x014C, 0x014D, // LATIN CAPITAL LETTER O WITH MACRON\n\t0x014E, 0x014F, // LATIN CAPITAL LETTER O WITH BREVE\n\t0x0150, 0x0151, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE\n\t0x0152, 0x0153, // LATIN CAPITAL LIGATURE OE\n\t0x0154, 0x0155, // LATIN CAPITAL LETTER R WITH ACUTE\n\t0x0156, 0x0157, // LATIN CAPITAL LETTER R WITH CEDILLA\n\t0x0158, 0x0159, // LATIN CAPITAL LETTER R WITH CARON\n\t0x015A, 0x015B, // LATIN CAPITAL LETTER S WITH ACUTE\n\t0x015C, 0x015D, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX\n\t0x015E, 0x015F, // LATIN CAPITAL LETTER S WITH CEDILLA\n\t0x0160, 0x0161, // LATIN CAPITAL LETTER S WITH CARON\n\t0x0162, 0x0163, // LATIN CAPITAL LETTER T WITH CEDILLA\n\t0x0164, 0x0165, // LATIN CAPITAL LETTER T WITH CARON\n\t0x0166, 0x0167, // LATIN CAPITAL LETTER T WITH STROKE\n\t0x0168, 0x0169, // LATIN CAPITAL LETTER U WITH TILDE\n\t0x016A, 0x016B, // LATIN CAPITAL LETTER U WITH MACRON\n\t0x016C, 0x016D, // LATIN CAPITAL LETTER U WITH BREVE\n\t0x016E, 0x016F, // LATIN CAPITAL LETTER U WITH RING ABOVE\n\t0x0170, 0x0171, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE\n\t0x0172, 0x0173, // LATIN CAPITAL LETTER U WITH OGONEK\n\t0x0174, 0x0175, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX\n\t0x0176, 0x0177, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX\n\t0x0178, 0x00FF, // LATIN CAPITAL LETTER Y WITH DIAERESIS\n\t0x0179, 0x017A, // LATIN CAPITAL LETTER Z WITH ACUTE\n\t0x017B, 0x017C, // LATIN CAPITAL LETTER Z WITH DOT ABOVE\n\t0x017D, 0x017E, // LATIN CAPITAL LETTER Z WITH CARON\n\t0x017F, 0x0073, // LATIN SMALL LETTER LONG S\n\t0x0181, 0x0253, // LATIN CAPITAL LETTER B WITH HOOK\n\t0x0182, 0x0183, // LATIN CAPITAL LETTER B WITH TOPBAR\n\t0x0184, 0x0185, // LATIN CAPITAL LETTER TONE SIX\n\t0x0186, 0x0254, // LATIN CAPITAL LETTER OPEN O\n\t0x0187, 0x0188, // LATIN CAPITAL LETTER C WITH HOOK\n\t0x0189, 0x0256, // LATIN CAPITAL LETTER AFRICAN D\n\t0x018A, 0x0257, // LATIN CAPITAL LETTER D WITH HOOK\n\t0x018B, 0x018C, // LATIN CAPITAL LETTER D WITH TOPBAR\n\t0x018E, 0x01DD, // LATIN CAPITAL LETTER REVERSED E\n\t0x018F, 0x0259, // LATIN CAPITAL LETTER SCHWA\n\t0x0190, 0x025B, // LATIN CAPITAL LETTER OPEN E\n\t0x0191, 0x0192, // LATIN CAPITAL LETTER F WITH HOOK\n\t0x0193, 0x0260, // LATIN CAPITAL LETTER G WITH HOOK\n\t0x0194, 0x0263, // LATIN CAPITAL LETTER GAMMA\n\t0x0196, 0x0269, // LATIN CAPITAL LETTER IOTA\n\t0x0197, 0x0268, // LATIN CAPITAL LETTER I WITH STROKE\n\t0x0198, 0x0199, // LATIN CAPITAL LETTER K WITH HOOK\n\t0x019C, 0x026F, // LATIN CAPITAL LETTER TURNED M\n\t0x019D, 0x0272, // LATIN CAPITAL LETTER N WITH LEFT HOOK\n\t0x019F, 0x0275, // LATIN CAPITAL LETTER O WITH MIDDLE TILDE\n\t0x01A0, 0x01A1, // LATIN CAPITAL LETTER O WITH HORN\n\t0x01A2, 0x01A3, // LATIN CAPITAL LETTER OI\n\t0x01A4, 0x01A5, // LATIN CAPITAL LETTER P WITH HOOK\n\t0x01A6, 0x0280, // LATIN LETTER YR\n\t0x01A7, 0x01A8, // LATIN CAPITAL LETTER TONE TWO\n\t0x01A9, 0x0283, // LATIN CAPITAL LETTER ESH\n\t0x01AC, 0x01AD, // LATIN CAPITAL LETTER T WITH HOOK\n\t0x01AE, 0x0288, // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\n\t0x01AF, 0x01B0, // LATIN CAPITAL LETTER U WITH HORN\n\t0x01B1, 0x028A, // LATIN CAPITAL LETTER UPSILON\n\t0x01B2, 0x028B, // LATIN CAPITAL LETTER V WITH HOOK\n\t0x01B3, 0x01B4, // LATIN CAPITAL LETTER Y WITH HOOK\n\t0x01B5, 0x01B6, // LATIN CAPITAL LETTER Z WITH STROKE\n\t0x01B7, 0x0292, // LATIN CAPITAL LETTER EZH\n\t0x01B8, 0x01B9, // LATIN CAPITAL LETTER EZH REVERSED\n\t0x01BC, 0x01BD, // LATIN CAPITAL LETTER TONE FIVE\n\t0x01C4, 0x01C6, // LATIN CAPITAL LETTER DZ WITH CARON\n\t0x01C5, 0x01C6, // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON\n\t0x01C7, 0x01C9, // LATIN CAPITAL LETTER LJ\n\t0x01C8, 0x01C9, // LATIN CAPITAL LETTER L WITH SMALL LETTER J\n\t0x01CA, 0x01CC, // LATIN CAPITAL LETTER NJ\n\t0x01CB, 0x01CC, // LATIN CAPITAL LETTER N WITH SMALL LETTER J\n\t0x01CD, 0x01CE, // LATIN CAPITAL LETTER A WITH CARON\n\t0x01CF, 0x01D0, // LATIN CAPITAL LETTER I WITH CARON\n\t0x01D1, 0x01D2, // LATIN CAPITAL LETTER O WITH CARON\n\t0x01D3, 0x01D4, // LATIN CAPITAL LETTER U WITH CARON\n\t0x01D5, 0x01D6, // LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON\n\t0x01D7, 0x01D8, // LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE\n\t0x01D9, 0x01DA, // LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON\n\t0x01DB, 0x01DC, // LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE\n\t0x01DE, 0x01DF, // LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON\n\t0x01E0, 0x01E1, // LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON\n\t0x01E2, 0x01E3, // LATIN CAPITAL LETTER AE WITH MACRON\n\t0x01E4, 0x01E5, // LATIN CAPITAL LETTER G WITH STROKE\n\t0x01E6, 0x01E7, // LATIN CAPITAL LETTER G WITH CARON\n\t0x01E8, 0x01E9, // LATIN CAPITAL LETTER K WITH CARON\n\t0x01EA, 0x01EB, // LATIN CAPITAL LETTER O WITH OGONEK\n\t0x01EC, 0x01ED, // LATIN CAPITAL LETTER O WITH OGONEK AND MACRON\n\t0x01EE, 0x01EF, // LATIN CAPITAL LETTER EZH WITH CARON\n\t0x01F0, 0x006A , // # LATIN SMALL LETTER J WITH CARON\n\t0x01F1, 0x01F3, // LATIN CAPITAL LETTER DZ\n\t0x01F2, 0x01F3, // LATIN CAPITAL LETTER D WITH SMALL LETTER Z\n\t0x01F4, 0x01F5, // LATIN CAPITAL LETTER G WITH ACUTE\n\t0x01F6, 0x0195, // LATIN CAPITAL LETTER HWAIR\n\t0x01F7, 0x01BF, // LATIN CAPITAL LETTER WYNN\n\t0x01F8, 0x01F9, // LATIN CAPITAL LETTER N WITH GRAVE\n\t0x01FA, 0x01FB, // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE\n\t0x01FC, 0x01FD, // LATIN CAPITAL LETTER AE WITH ACUTE\n\t0x01FE, 0x01FF, // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE\n\t0x0200, 0x0201, // LATIN CAPITAL LETTER A WITH DOUBLE GRAVE\n\t0x0202, 0x0203, // LATIN CAPITAL LETTER A WITH INVERTED BREVE\n\t0x0204, 0x0205, // LATIN CAPITAL LETTER E WITH DOUBLE GRAVE\n\t0x0206, 0x0207, // LATIN CAPITAL LETTER E WITH INVERTED BREVE\n\t0x0208, 0x0209, // LATIN CAPITAL LETTER I WITH DOUBLE GRAVE\n\t0x020A, 0x020B, // LATIN CAPITAL LETTER I WITH INVERTED BREVE\n\t0x020C, 0x020D, // LATIN CAPITAL LETTER O WITH DOUBLE GRAVE\n\t0x020E, 0x020F, // LATIN CAPITAL LETTER O WITH INVERTED BREVE\n\t0x0210, 0x0211, // LATIN CAPITAL LETTER R WITH DOUBLE GRAVE\n\t0x0212, 0x0213, // LATIN CAPITAL LETTER R WITH INVERTED BREVE\n\t0x0214, 0x0215, // LATIN CAPITAL LETTER U WITH DOUBLE GRAVE\n\t0x0216, 0x0217, // LATIN CAPITAL LETTER U WITH INVERTED BREVE\n\t0x0218, 0x0219, // LATIN CAPITAL LETTER S WITH COMMA BELOW\n\t0x021A, 0x021B, // LATIN CAPITAL LETTER T WITH COMMA BELOW\n\t0x021C, 0x021D, // LATIN CAPITAL LETTER YOGH\n\t0x021E, 0x021F, // LATIN CAPITAL LETTER H WITH CARON\n\t0x0220, 0x019E, // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG\n\t0x0222, 0x0223, // LATIN CAPITAL LETTER OU\n\t0x0224, 0x0225, // LATIN CAPITAL LETTER Z WITH HOOK\n\t0x0226, 0x0227, // LATIN CAPITAL LETTER A WITH DOT ABOVE\n\t0x0228, 0x0229, // LATIN CAPITAL LETTER E WITH CEDILLA\n\t0x022A, 0x022B, // LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON\n\t0x022C, 0x022D, // LATIN CAPITAL LETTER O WITH TILDE AND MACRON\n\t0x022E, 0x022F, // LATIN CAPITAL LETTER O WITH DOT ABOVE\n\t0x0230, 0x0231, // LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON\n\t0x0232, 0x0233, // LATIN CAPITAL LETTER Y WITH MACRON\n\t0x0345, 0x03B9, // COMBINING GREEK YPOGEGRAMMENI\n\t0x0386, 0x03AC, // GREEK CAPITAL LETTER ALPHA WITH TONOS\n\t0x0388, 0x03AD, // GREEK CAPITAL LETTER EPSILON WITH TONOS\n\t0x0389, 0x03AE, // GREEK CAPITAL LETTER ETA WITH TONOS\n\t0x038A, 0x03AF, // GREEK CAPITAL LETTER IOTA WITH TONOS\n\t0x038C, 0x03CC, // GREEK CAPITAL LETTER OMICRON WITH TONOS\n\t0x038E, 0x03CD, // GREEK CAPITAL LETTER UPSILON WITH TONOS\n\t0x038F, 0x03CE, // GREEK CAPITAL LETTER OMEGA WITH TONOS\n\t0x0390, 0x03B9 , // ; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS\n\t0x0391, 0x03B1, // GREEK CAPITAL LETTER ALPHA\n\t0x0392, 0x03B2, // GREEK CAPITAL LETTER BETA\n\t0x0393, 0x03B3, // GREEK CAPITAL LETTER GAMMA\n\t0x0394, 0x03B4, // GREEK CAPITAL LETTER DELTA\n\t0x0395, 0x03B5, // GREEK CAPITAL LETTER EPSILON\n\t0x0396, 0x03B6, // GREEK CAPITAL LETTER ZETA\n\t0x0397, 0x03B7, // GREEK CAPITAL LETTER ETA\n\t0x0398, 0x03B8, // GREEK CAPITAL LETTER THETA\n\t0x0399, 0x03B9, // GREEK CAPITAL LETTER IOTA\n\t0x039A, 0x03BA, // GREEK CAPITAL LETTER KAPPA\n\t0x039B, 0x03BB, // GREEK CAPITAL LETTER LAMDA\n\t0x039C, 0x03BC, // GREEK CAPITAL LETTER MU\n\t0x039D, 0x03BD, // GREEK CAPITAL LETTER NU\n\t0x039E, 0x03BE, // GREEK CAPITAL LETTER XI\n\t0x039F, 0x03BF, // GREEK CAPITAL LETTER OMICRON\n\t0x03A0, 0x03C0, // GREEK CAPITAL LETTER PI\n\t0x03A1, 0x03C1, // GREEK CAPITAL LETTER RHO\n\t0x03A3, 0x03C3, // GREEK CAPITAL LETTER SIGMA\n\t0x03A4, 0x03C4, // GREEK CAPITAL LETTER TAU\n\t0x03A5, 0x03C5, // GREEK CAPITAL LETTER UPSILON\n\t0x03A6, 0x03C6, // GREEK CAPITAL LETTER PHI\n\t0x03A7, 0x03C7, // GREEK CAPITAL LETTER CHI\n\t0x03A8, 0x03C8, // GREEK CAPITAL LETTER PSI\n\t0x03A9, 0x03C9, // GREEK CAPITAL LETTER OMEGA\n\t0x03AA, 0x03CA, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA\n\t0x03AB, 0x03CB, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA\n\t0x03B0, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS\n\t0x03C2, 0x03C3, // GREEK SMALL LETTER FINAL SIGMA\n\t0x03D0, 0x03B2, // GREEK BETA SYMBOL\n\t0x03D1, 0x03B8, // GREEK THETA SYMBOL\n\t0x03D5, 0x03C6, // GREEK PHI SYMBOL\n\t0x03D6, 0x03C0, // GREEK PI SYMBOL\n\t0x03D8, 0x03D9, // GREEK LETTER ARCHAIC KOPPA\n\t0x03DA, 0x03DB, // GREEK LETTER STIGMA\n\t0x03DC, 0x03DD, // GREEK LETTER DIGAMMA\n\t0x03DE, 0x03DF, // GREEK LETTER KOPPA\n\t0x03E0, 0x03E1, // GREEK LETTER SAMPI\n\t0x03E2, 0x03E3, // COPTIC CAPITAL LETTER SHEI\n\t0x03E4, 0x03E5, // COPTIC CAPITAL LETTER FEI\n\t0x03E6, 0x03E7, // COPTIC CAPITAL LETTER KHEI\n\t0x03E8, 0x03E9, // COPTIC CAPITAL LETTER HORI\n\t0x03EA, 0x03EB, // COPTIC CAPITAL LETTER GANGIA\n\t0x03EC, 0x03ED, // COPTIC CAPITAL LETTER SHIMA\n\t0x03EE, 0x03EF, // COPTIC CAPITAL LETTER DEI\n\t0x03F0, 0x03BA, // GREEK KAPPA SYMBOL\n\t0x03F1, 0x03C1, // GREEK RHO SYMBOL\n\t0x03F4, 0x03B8, // GREEK CAPITAL THETA SYMBOL\n\t0x03F5, 0x03B5, // GREEK LUNATE EPSILON SYMBOL\n\t0x03F7, 0x03F8, // GREEK CAPITAL LETTER SHO\n\t0x03F9, 0x03F2, // GREEK CAPITAL LUNATE SIGMA SYMBOL\n\t0x03FA, 0x03FB, // GREEK CAPITAL LETTER SAN\n\t0x0400, 0x0450, // CYRILLIC CAPITAL LETTER IE WITH GRAVE\n\t0x0401, 0x0451, // CYRILLIC CAPITAL LETTER IO\n\t0x0402, 0x0452, // CYRILLIC CAPITAL LETTER DJE\n\t0x0403, 0x0453, // CYRILLIC CAPITAL LETTER GJE\n\t0x0404, 0x0454, // CYRILLIC CAPITAL LETTER UKRAINIAN IE\n\t0x0405, 0x0455, // CYRILLIC CAPITAL LETTER DZE\n\t0x0406, 0x0456, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I\n\t0x0407, 0x0457, // CYRILLIC CAPITAL LETTER YI\n\t0x0408, 0x0458, // CYRILLIC CAPITAL LETTER JE\n\t0x0409, 0x0459, // CYRILLIC CAPITAL LETTER LJE\n\t0x040A, 0x045A, // CYRILLIC CAPITAL LETTER NJE\n\t0x040B, 0x045B, // CYRILLIC CAPITAL LETTER TSHE\n\t0x040C, 0x045C, // CYRILLIC CAPITAL LETTER KJE\n\t0x040D, 0x045D, // CYRILLIC CAPITAL LETTER I WITH GRAVE\n\t0x040E, 0x045E, // CYRILLIC CAPITAL LETTER SHORT U\n\t0x040F, 0x045F, // CYRILLIC CAPITAL LETTER DZHE\n\t0x0410, 0x0430, // CYRILLIC CAPITAL LETTER A\n\t0x0411, 0x0431, // CYRILLIC CAPITAL LETTER BE\n\t0x0412, 0x0432, // CYRILLIC CAPITAL LETTER VE\n\t0x0413, 0x0433, // CYRILLIC CAPITAL LETTER GHE\n\t0x0414, 0x0434, // CYRILLIC CAPITAL LETTER DE\n\t0x0415, 0x0435, // CYRILLIC CAPITAL LETTER IE\n\t0x0416, 0x0436, // CYRILLIC CAPITAL LETTER ZHE\n\t0x0417, 0x0437, // CYRILLIC CAPITAL LETTER ZE\n\t0x0418, 0x0438, // CYRILLIC CAPITAL LETTER I\n\t0x0419, 0x0439, // CYRILLIC CAPITAL LETTER SHORT I\n\t0x041A, 0x043A, // CYRILLIC CAPITAL LETTER KA\n\t0x041B, 0x043B, // CYRILLIC CAPITAL LETTER EL\n\t0x041C, 0x043C, // CYRILLIC CAPITAL LETTER EM\n\t0x041D, 0x043D, // CYRILLIC CAPITAL LETTER EN\n\t0x041E, 0x043E, // CYRILLIC CAPITAL LETTER O\n\t0x041F, 0x043F, // CYRILLIC CAPITAL LETTER PE\n\t0x0420, 0x0440, // CYRILLIC CAPITAL LETTER ER\n\t0x0421, 0x0441, // CYRILLIC CAPITAL LETTER ES\n\t0x0422, 0x0442, // CYRILLIC CAPITAL LETTER TE\n\t0x0423, 0x0443, // CYRILLIC CAPITAL LETTER U\n\t0x0424, 0x0444, // CYRILLIC CAPITAL LETTER EF\n\t0x0425, 0x0445, // CYRILLIC CAPITAL LETTER HA\n\t0x0426, 0x0446, // CYRILLIC CAPITAL LETTER TSE\n\t0x0427, 0x0447, // CYRILLIC CAPITAL LETTER CHE\n\t0x0428, 0x0448, // CYRILLIC CAPITAL LETTER SHA\n\t0x0429, 0x0449, // CYRILLIC CAPITAL LETTER SHCHA\n\t0x042A, 0x044A, // CYRILLIC CAPITAL LETTER HARD SIGN\n\t0x042B, 0x044B, // CYRILLIC CAPITAL LETTER YERU\n\t0x042C, 0x044C, // CYRILLIC CAPITAL LETTER SOFT SIGN\n\t0x042D, 0x044D, // CYRILLIC CAPITAL LETTER E\n\t0x042E, 0x044E, // CYRILLIC CAPITAL LETTER YU\n\t0x042F, 0x044F, // CYRILLIC CAPITAL LETTER YA\n\t0x0460, 0x0461, // CYRILLIC CAPITAL LETTER OMEGA\n\t0x0462, 0x0463, // CYRILLIC CAPITAL LETTER YAT\n\t0x0464, 0x0465, // CYRILLIC CAPITAL LETTER IOTIFIED E\n\t0x0466, 0x0467, // CYRILLIC CAPITAL LETTER LITTLE YUS\n\t0x0468, 0x0469, // CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS\n\t0x046A, 0x046B, // CYRILLIC CAPITAL LETTER BIG YUS\n\t0x046C, 0x046D, // CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS\n\t0x046E, 0x046F, // CYRILLIC CAPITAL LETTER KSI\n\t0x0470, 0x0471, // CYRILLIC CAPITAL LETTER PSI\n\t0x0472, 0x0473, // CYRILLIC CAPITAL LETTER FITA\n\t0x0474, 0x0475, // CYRILLIC CAPITAL LETTER IZHITSA\n\t0x0476, 0x0477, // CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT\n\t0x0478, 0x0479, // CYRILLIC CAPITAL LETTER UK\n\t0x047A, 0x047B, // CYRILLIC CAPITAL LETTER ROUND OMEGA\n\t0x047C, 0x047D, // CYRILLIC CAPITAL LETTER OMEGA WITH TITLO\n\t0x047E, 0x047F, // CYRILLIC CAPITAL LETTER OT\n\t0x0480, 0x0481, // CYRILLIC CAPITAL LETTER KOPPA\n\t0x048A, 0x048B, // CYRILLIC CAPITAL LETTER SHORT I WITH TAIL\n\t0x048C, 0x048D, // CYRILLIC CAPITAL LETTER SEMISOFT SIGN\n\t0x048E, 0x048F, // CYRILLIC CAPITAL LETTER ER WITH TICK\n\t0x0490, 0x0491, // CYRILLIC CAPITAL LETTER GHE WITH UPTURN\n\t0x0492, 0x0493, // CYRILLIC CAPITAL LETTER GHE WITH STROKE\n\t0x0494, 0x0495, // CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK\n\t0x0496, 0x0497, // CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER\n\t0x0498, 0x0499, // CYRILLIC CAPITAL LETTER ZE WITH DESCENDER\n\t0x049A, 0x049B, // CYRILLIC CAPITAL LETTER KA WITH DESCENDER\n\t0x049C, 0x049D, // CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE\n\t0x049E, 0x049F, // CYRILLIC CAPITAL LETTER KA WITH STROKE\n\t0x04A0, 0x04A1, // CYRILLIC CAPITAL LETTER BASHKIR KA\n\t0x04A2, 0x04A3, // CYRILLIC CAPITAL LETTER EN WITH DESCENDER\n\t0x04A4, 0x04A5, // CYRILLIC CAPITAL LIGATURE EN GHE\n\t0x04A6, 0x04A7, // CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK\n\t0x04A8, 0x04A9, // CYRILLIC CAPITAL LETTER ABKHASIAN HA\n\t0x04AA, 0x04AB, // CYRILLIC CAPITAL LETTER ES WITH DESCENDER\n\t0x04AC, 0x04AD, // CYRILLIC CAPITAL LETTER TE WITH DESCENDER\n\t0x04AE, 0x04AF, // CYRILLIC CAPITAL LETTER STRAIGHT U\n\t0x04B0, 0x04B1, // CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE\n\t0x04B2, 0x04B3, // CYRILLIC CAPITAL LETTER HA WITH DESCENDER\n\t0x04B4, 0x04B5, // CYRILLIC CAPITAL LIGATURE TE TSE\n\t0x04B6, 0x04B7, // CYRILLIC CAPITAL LETTER CHE WITH DESCENDER\n\t0x04B8, 0x04B9, // CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE\n\t0x04BA, 0x04BB, // CYRILLIC CAPITAL LETTER SHHA\n\t0x04BC, 0x04BD, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE\n\t0x04BE, 0x04BF, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER\n\t0x04C1, 0x04C2, // CYRILLIC CAPITAL LETTER ZHE WITH BREVE\n\t0x04C3, 0x04C4, // CYRILLIC CAPITAL LETTER KA WITH HOOK\n\t0x04C5, 0x04C6, // CYRILLIC CAPITAL LETTER EL WITH TAIL\n\t0x04C7, 0x04C8, // CYRILLIC CAPITAL LETTER EN WITH HOOK\n\t0x04C9, 0x04CA, // CYRILLIC CAPITAL LETTER EN WITH TAIL\n\t0x04CB, 0x04CC, // CYRILLIC CAPITAL LETTER KHAKASSIAN CHE\n\t0x04CD, 0x04CE, // CYRILLIC CAPITAL LETTER EM WITH TAIL\n\t0x04D0, 0x04D1, // CYRILLIC CAPITAL LETTER A WITH BREVE\n\t0x04D2, 0x04D3, // CYRILLIC CAPITAL LETTER A WITH DIAERESIS\n\t0x04D4, 0x04D5, // CYRILLIC CAPITAL LIGATURE A IE\n\t0x04D6, 0x04D7, // CYRILLIC CAPITAL LETTER IE WITH BREVE\n\t0x04D8, 0x04D9, // CYRILLIC CAPITAL LETTER SCHWA\n\t0x04DA, 0x04DB, // CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS\n\t0x04DC, 0x04DD, // CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS\n\t0x04DE, 0x04DF, // CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS\n\t0x04E0, 0x04E1, // CYRILLIC CAPITAL LETTER ABKHASIAN DZE\n\t0x04E2, 0x04E3, // CYRILLIC CAPITAL LETTER I WITH MACRON\n\t0x04E4, 0x04E5, // CYRILLIC CAPITAL LETTER I WITH DIAERESIS\n\t0x04E6, 0x04E7, // CYRILLIC CAPITAL LETTER O WITH DIAERESIS\n\t0x04E8, 0x04E9, // CYRILLIC CAPITAL LETTER BARRED O\n\t0x04EA, 0x04EB, // CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS\n\t0x04EC, 0x04ED, // CYRILLIC CAPITAL LETTER E WITH DIAERESIS\n\t0x04EE, 0x04EF, // CYRILLIC CAPITAL LETTER U WITH MACRON\n\t0x04F0, 0x04F1, // CYRILLIC CAPITAL LETTER U WITH DIAERESIS\n\t0x04F2, 0x04F3, // CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE\n\t0x04F4, 0x04F5, // CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS\n\t0x04F8, 0x04F9, // CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS\n\t0x0500, 0x0501, // CYRILLIC CAPITAL LETTER KOMI DE\n\t0x0502, 0x0503, // CYRILLIC CAPITAL LETTER KOMI DJE\n\t0x0504, 0x0505, // CYRILLIC CAPITAL LETTER KOMI ZJE\n\t0x0506, 0x0507, // CYRILLIC CAPITAL LETTER KOMI DZJE\n\t0x0508, 0x0509, // CYRILLIC CAPITAL LETTER KOMI LJE\n\t0x050A, 0x050B, // CYRILLIC CAPITAL LETTER KOMI NJE\n\t0x050C, 0x050D, // CYRILLIC CAPITAL LETTER KOMI SJE\n\t0x050E, 0x050F, // CYRILLIC CAPITAL LETTER KOMI TJE\n\t0x0531, 0x0561, // ARMENIAN CAPITAL LETTER AYB\n\t0x0532, 0x0562, // ARMENIAN CAPITAL LETTER BEN\n\t0x0533, 0x0563, // ARMENIAN CAPITAL LETTER GIM\n\t0x0534, 0x0564, // ARMENIAN CAPITAL LETTER DA\n\t0x0535, 0x0565, // ARMENIAN CAPITAL LETTER ECH\n\t0x0536, 0x0566, // ARMENIAN CAPITAL LETTER ZA\n\t0x0537, 0x0567, // ARMENIAN CAPITAL LETTER EH\n\t0x0538, 0x0568, // ARMENIAN CAPITAL LETTER ET\n\t0x0539, 0x0569, // ARMENIAN CAPITAL LETTER TO\n\t0x053A, 0x056A, // ARMENIAN CAPITAL LETTER ZHE\n\t0x053B, 0x056B, // ARMENIAN CAPITAL LETTER INI\n\t0x053C, 0x056C, // ARMENIAN CAPITAL LETTER LIWN\n\t0x053D, 0x056D, // ARMENIAN CAPITAL LETTER XEH\n\t0x053E, 0x056E, // ARMENIAN CAPITAL LETTER CA\n\t0x053F, 0x056F, // ARMENIAN CAPITAL LETTER KEN\n\t0x0540, 0x0570, // ARMENIAN CAPITAL LETTER HO\n\t0x0541, 0x0571, // ARMENIAN CAPITAL LETTER JA\n\t0x0542, 0x0572, // ARMENIAN CAPITAL LETTER GHAD\n\t0x0543, 0x0573, // ARMENIAN CAPITAL LETTER CHEH\n\t0x0544, 0x0574, // ARMENIAN CAPITAL LETTER MEN\n\t0x0545, 0x0575, // ARMENIAN CAPITAL LETTER YI\n\t0x0546, 0x0576, // ARMENIAN CAPITAL LETTER NOW\n\t0x0547, 0x0577, // ARMENIAN CAPITAL LETTER SHA\n\t0x0548, 0x0578, // ARMENIAN CAPITAL LETTER VO\n\t0x0549, 0x0579, // ARMENIAN CAPITAL LETTER CHA\n\t0x054A, 0x057A, // ARMENIAN CAPITAL LETTER PEH\n\t0x054B, 0x057B, // ARMENIAN CAPITAL LETTER JHEH\n\t0x054C, 0x057C, // ARMENIAN CAPITAL LETTER RA\n\t0x054D, 0x057D, // ARMENIAN CAPITAL LETTER SEH\n\t0x054E, 0x057E, // ARMENIAN CAPITAL LETTER VEW\n\t0x054F, 0x057F, // ARMENIAN CAPITAL LETTER TIWN\n\t0x0550, 0x0580, // ARMENIAN CAPITAL LETTER REH\n\t0x0551, 0x0581, // ARMENIAN CAPITAL LETTER CO\n\t0x0552, 0x0582, // ARMENIAN CAPITAL LETTER YIWN\n\t0x0553, 0x0583, // ARMENIAN CAPITAL LETTER PIWR\n\t0x0554, 0x0584, // ARMENIAN CAPITAL LETTER KEH\n\t0x0555, 0x0585, // ARMENIAN CAPITAL LETTER OH\n\t0x0556, 0x0586, // ARMENIAN CAPITAL LETTER FEH\n\t0x0587, 0x0565 , // # ARMENIAN SMALL LIGATURE ECH YIWN\n\t0x1E00, 0x1E01, // LATIN CAPITAL LETTER A WITH RING BELOW\n\t0x1E02, 0x1E03, // LATIN CAPITAL LETTER B WITH DOT ABOVE\n\t0x1E04, 0x1E05, // LATIN CAPITAL LETTER B WITH DOT BELOW\n\t0x1E06, 0x1E07, // LATIN CAPITAL LETTER B WITH LINE BELOW\n\t0x1E08, 0x1E09, // LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE\n\t0x1E0A, 0x1E0B, // LATIN CAPITAL LETTER D WITH DOT ABOVE\n\t0x1E0C, 0x1E0D, // LATIN CAPITAL LETTER D WITH DOT BELOW\n\t0x1E0E, 0x1E0F, // LATIN CAPITAL LETTER D WITH LINE BELOW\n\t0x1E10, 0x1E11, // LATIN CAPITAL LETTER D WITH CEDILLA\n\t0x1E12, 0x1E13, // LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW\n\t0x1E14, 0x1E15, // LATIN CAPITAL LETTER E WITH MACRON AND GRAVE\n\t0x1E16, 0x1E17, // LATIN CAPITAL LETTER E WITH MACRON AND ACUTE\n\t0x1E18, 0x1E19, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW\n\t0x1E1A, 0x1E1B, // LATIN CAPITAL LETTER E WITH TILDE BELOW\n\t0x1E1C, 0x1E1D, // LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE\n\t0x1E1E, 0x1E1F, // LATIN CAPITAL LETTER F WITH DOT ABOVE\n\t0x1E20, 0x1E21, // LATIN CAPITAL LETTER G WITH MACRON\n\t0x1E22, 0x1E23, // LATIN CAPITAL LETTER H WITH DOT ABOVE\n\t0x1E24, 0x1E25, // LATIN CAPITAL LETTER H WITH DOT BELOW\n\t0x1E26, 0x1E27, // LATIN CAPITAL LETTER H WITH DIAERESIS\n\t0x1E28, 0x1E29, // LATIN CAPITAL LETTER H WITH CEDILLA\n\t0x1E2A, 0x1E2B, // LATIN CAPITAL LETTER H WITH BREVE BELOW\n\t0x1E2C, 0x1E2D, // LATIN CAPITAL LETTER I WITH TILDE BELOW\n\t0x1E2E, 0x1E2F, // LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE\n\t0x1E30, 0x1E31, // LATIN CAPITAL LETTER K WITH ACUTE\n\t0x1E32, 0x1E33, // LATIN CAPITAL LETTER K WITH DOT BELOW\n\t0x1E34, 0x1E35, // LATIN CAPITAL LETTER K WITH LINE BELOW\n\t0x1E36, 0x1E37, // LATIN CAPITAL LETTER L WITH DOT BELOW\n\t0x1E38, 0x1E39, // LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON\n\t0x1E3A, 0x1E3B, // LATIN CAPITAL LETTER L WITH LINE BELOW\n\t0x1E3C, 0x1E3D, // LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW\n\t0x1E3E, 0x1E3F, // LATIN CAPITAL LETTER M WITH ACUTE\n\t0x1E40, 0x1E41, // LATIN CAPITAL LETTER M WITH DOT ABOVE\n\t0x1E42, 0x1E43, // LATIN CAPITAL LETTER M WITH DOT BELOW\n\t0x1E44, 0x1E45, // LATIN CAPITAL LETTER N WITH DOT ABOVE\n\t0x1E46, 0x1E47, // LATIN CAPITAL LETTER N WITH DOT BELOW\n\t0x1E48, 0x1E49, // LATIN CAPITAL LETTER N WITH LINE BELOW\n\t0x1E4A, 0x1E4B, // LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW\n\t0x1E4C, 0x1E4D, // LATIN CAPITAL LETTER O WITH TILDE AND ACUTE\n\t0x1E4E, 0x1E4F, // LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS\n\t0x1E50, 0x1E51, // LATIN CAPITAL LETTER O WITH MACRON AND GRAVE\n\t0x1E52, 0x1E53, // LATIN CAPITAL LETTER O WITH MACRON AND ACUTE\n\t0x1E54, 0x1E55, // LATIN CAPITAL LETTER P WITH ACUTE\n\t0x1E56, 0x1E57, // LATIN CAPITAL LETTER P WITH DOT ABOVE\n\t0x1E58, 0x1E59, // LATIN CAPITAL LETTER R WITH DOT ABOVE\n\t0x1E5A, 0x1E5B, // LATIN CAPITAL LETTER R WITH DOT BELOW\n\t0x1E5C, 0x1E5D, // LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON\n\t0x1E5E, 0x1E5F, // LATIN CAPITAL LETTER R WITH LINE BELOW\n\t0x1E60, 0x1E61, // LATIN CAPITAL LETTER S WITH DOT ABOVE\n\t0x1E62, 0x1E63, // LATIN CAPITAL LETTER S WITH DOT BELOW\n\t0x1E64, 0x1E65, // LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE\n\t0x1E66, 0x1E67, // LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE\n\t0x1E68, 0x1E69, // LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE\n\t0x1E6A, 0x1E6B, // LATIN CAPITAL LETTER T WITH DOT ABOVE\n\t0x1E6C, 0x1E6D, // LATIN CAPITAL LETTER T WITH DOT BELOW\n\t0x1E6E, 0x1E6F, // LATIN CAPITAL LETTER T WITH LINE BELOW\n\t0x1E70, 0x1E71, // LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW\n\t0x1E72, 0x1E73, // LATIN CAPITAL LETTER U WITH DIAERESIS BELOW\n\t0x1E74, 0x1E75, // LATIN CAPITAL LETTER U WITH TILDE BELOW\n\t0x1E76, 0x1E77, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW\n\t0x1E78, 0x1E79, // LATIN CAPITAL LETTER U WITH TILDE AND ACUTE\n\t0x1E7A, 0x1E7B, // LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS\n\t0x1E7C, 0x1E7D, // LATIN CAPITAL LETTER V WITH TILDE\n\t0x1E7E, 0x1E7F, // LATIN CAPITAL LETTER V WITH DOT BELOW\n\t0x1E80, 0x1E81, // LATIN CAPITAL LETTER W WITH GRAVE\n\t0x1E82, 0x1E83, // LATIN CAPITAL LETTER W WITH ACUTE\n\t0x1E84, 0x1E85, // LATIN CAPITAL LETTER W WITH DIAERESIS\n\t0x1E86, 0x1E87, // LATIN CAPITAL LETTER W WITH DOT ABOVE\n\t0x1E88, 0x1E89, // LATIN CAPITAL LETTER W WITH DOT BELOW\n\t0x1E8A, 0x1E8B, // LATIN CAPITAL LETTER X WITH DOT ABOVE\n\t0x1E8C, 0x1E8D, // LATIN CAPITAL LETTER X WITH DIAERESIS\n\t0x1E8E, 0x1E8F, // LATIN CAPITAL LETTER Y WITH DOT ABOVE\n\t0x1E90, 0x1E91, // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX\n\t0x1E92, 0x1E93, // LATIN CAPITAL LETTER Z WITH DOT BELOW\n\t0x1E94, 0x1E95, // LATIN CAPITAL LETTER Z WITH LINE BELOW\n\t0x1E96, 0x0068 , // # LATIN SMALL LETTER H WITH LINE BELOW\n\t0x1E97, 0x0074 , // # LATIN SMALL LETTER T WITH DIAERESIS\n\t0x1E98, 0x0077 , // # LATIN SMALL LETTER W WITH RING ABOVE\n\t0x1E99, 0x0079 , // # LATIN SMALL LETTER Y WITH RING ABOVE\n\t0x1E9A, 0x0061 , // # LATIN SMALL LETTER A WITH RIGHT HALF RING\n\t0x1E9B, 0x1E61, // LATIN SMALL LETTER LONG S WITH DOT ABOVE\n\t0x1EA0, 0x1EA1, // LATIN CAPITAL LETTER A WITH DOT BELOW\n\t0x1EA2, 0x1EA3, // LATIN CAPITAL LETTER A WITH HOOK ABOVE\n\t0x1EA4, 0x1EA5, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE\n\t0x1EA6, 0x1EA7, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE\n\t0x1EA8, 0x1EA9, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1EAA, 0x1EAB, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE\n\t0x1EAC, 0x1EAD, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW\n\t0x1EAE, 0x1EAF, // LATIN CAPITAL LETTER A WITH BREVE AND ACUTE\n\t0x1EB0, 0x1EB1, // LATIN CAPITAL LETTER A WITH BREVE AND GRAVE\n\t0x1EB2, 0x1EB3, // LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE\n\t0x1EB4, 0x1EB5, // LATIN CAPITAL LETTER A WITH BREVE AND TILDE\n\t0x1EB6, 0x1EB7, // LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW\n\t0x1EB8, 0x1EB9, // LATIN CAPITAL LETTER E WITH DOT BELOW\n\t0x1EBA, 0x1EBB, // LATIN CAPITAL LETTER E WITH HOOK ABOVE\n\t0x1EBC, 0x1EBD, // LATIN CAPITAL LETTER E WITH TILDE\n\t0x1EBE, 0x1EBF, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE\n\t0x1EC0, 0x1EC1, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE\n\t0x1EC2, 0x1EC3, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1EC4, 0x1EC5, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE\n\t0x1EC6, 0x1EC7, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW\n\t0x1EC8, 0x1EC9, // LATIN CAPITAL LETTER I WITH HOOK ABOVE\n\t0x1ECA, 0x1ECB, // LATIN CAPITAL LETTER I WITH DOT BELOW\n\t0x1ECC, 0x1ECD, // LATIN CAPITAL LETTER O WITH DOT BELOW\n\t0x1ECE, 0x1ECF, // LATIN CAPITAL LETTER O WITH HOOK ABOVE\n\t0x1ED0, 0x1ED1, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE\n\t0x1ED2, 0x1ED3, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE\n\t0x1ED4, 0x1ED5, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1ED6, 0x1ED7, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE\n\t0x1ED8, 0x1ED9, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW\n\t0x1EDA, 0x1EDB, // LATIN CAPITAL LETTER O WITH HORN AND ACUTE\n\t0x1EDC, 0x1EDD, // LATIN CAPITAL LETTER O WITH HORN AND GRAVE\n\t0x1EDE, 0x1EDF, // LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE\n\t0x1EE0, 0x1EE1, // LATIN CAPITAL LETTER O WITH HORN AND TILDE\n\t0x1EE2, 0x1EE3, // LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW\n\t0x1EE4, 0x1EE5, // LATIN CAPITAL LETTER U WITH DOT BELOW\n\t0x1EE6, 0x1EE7, // LATIN CAPITAL LETTER U WITH HOOK ABOVE\n\t0x1EE8, 0x1EE9, // LATIN CAPITAL LETTER U WITH HORN AND ACUTE\n\t0x1EEA, 0x1EEB, // LATIN CAPITAL LETTER U WITH HORN AND GRAVE\n\t0x1EEC, 0x1EED, // LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE\n\t0x1EEE, 0x1EEF, // LATIN CAPITAL LETTER U WITH HORN AND TILDE\n\t0x1EF0, 0x1EF1, // LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW\n\t0x1EF2, 0x1EF3, // LATIN CAPITAL LETTER Y WITH GRAVE\n\t0x1EF4, 0x1EF5, // LATIN CAPITAL LETTER Y WITH DOT BELOW\n\t0x1EF6, 0x1EF7, // LATIN CAPITAL LETTER Y WITH HOOK ABOVE\n\t0x1EF8, 0x1EF9, // LATIN CAPITAL LETTER Y WITH TILDE\n\t0x1F08, 0x1F00, // GREEK CAPITAL LETTER ALPHA WITH PSILI\n\t0x1F09, 0x1F01, // GREEK CAPITAL LETTER ALPHA WITH DASIA\n\t0x1F0A, 0x1F02, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA\n\t0x1F0B, 0x1F03, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA\n\t0x1F0C, 0x1F04, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA\n\t0x1F0D, 0x1F05, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA\n\t0x1F0E, 0x1F06, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI\n\t0x1F0F, 0x1F07, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI\n\t0x1F18, 0x1F10, // GREEK CAPITAL LETTER EPSILON WITH PSILI\n\t0x1F19, 0x1F11, // GREEK CAPITAL LETTER EPSILON WITH DASIA\n\t0x1F1A, 0x1F12, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA\n\t0x1F1B, 0x1F13, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA\n\t0x1F1C, 0x1F14, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA\n\t0x1F1D, 0x1F15, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA\n\t0x1F28, 0x1F20, // GREEK CAPITAL LETTER ETA WITH PSILI\n\t0x1F29, 0x1F21, // GREEK CAPITAL LETTER ETA WITH DASIA\n\t0x1F2A, 0x1F22, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA\n\t0x1F2B, 0x1F23, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA\n\t0x1F2C, 0x1F24, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA\n\t0x1F2D, 0x1F25, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA\n\t0x1F2E, 0x1F26, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI\n\t0x1F2F, 0x1F27, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI\n\t0x1F38, 0x1F30, // GREEK CAPITAL LETTER IOTA WITH PSILI\n\t0x1F39, 0x1F31, // GREEK CAPITAL LETTER IOTA WITH DASIA\n\t0x1F3A, 0x1F32, // GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA\n\t0x1F3B, 0x1F33, // GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA\n\t0x1F3C, 0x1F34, // GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA\n\t0x1F3D, 0x1F35, // GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA\n\t0x1F3E, 0x1F36, // GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI\n\t0x1F3F, 0x1F37, // GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI\n\t0x1F48, 0x1F40, // GREEK CAPITAL LETTER OMICRON WITH PSILI\n\t0x1F49, 0x1F41, // GREEK CAPITAL LETTER OMICRON WITH DASIA\n\t0x1F4A, 0x1F42, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA\n\t0x1F4B, 0x1F43, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA\n\t0x1F4C, 0x1F44, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA\n\t0x1F4D, 0x1F45, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA\n\t0x1F50, 0x03C5 , // # GREEK SMALL LETTER UPSILON WITH PSILI\n\t0x1F52, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA\n\t0x1F54, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA\n\t0x1F56, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI\n\t0x1F59, 0x1F51, // GREEK CAPITAL LETTER UPSILON WITH DASIA\n\t0x1F5B, 0x1F53, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA\n\t0x1F5D, 0x1F55, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA\n\t0x1F5F, 0x1F57, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI\n\t0x1F68, 0x1F60, // GREEK CAPITAL LETTER OMEGA WITH PSILI\n\t0x1F69, 0x1F61, // GREEK CAPITAL LETTER OMEGA WITH DASIA\n\t0x1F6A, 0x1F62, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA\n\t0x1F6B, 0x1F63, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA\n\t0x1F6C, 0x1F64, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA\n\t0x1F6D, 0x1F65, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA\n\t0x1F6E, 0x1F66, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI\n\t0x1F6F, 0x1F67, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI\n\t0x1F80, 0x1F00 , // # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI\n\t0x1F81, 0x1F01 , // # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI\n\t0x1F82, 0x1F02 , // # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n\t0x1F83, 0x1F03 , // # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n\t0x1F84, 0x1F04 , // # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n\t0x1F85, 0x1F05 , // # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n\t0x1F86, 0x1F06 , // # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1F87, 0x1F07 , // # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1F88, 0x1F80, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI\n\t0x1F89, 0x1F81, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI\n\t0x1F8A, 0x1F82, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1F8B, 0x1F83, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1F8C, 0x1F84, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1F8D, 0x1F85, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1F8E, 0x1F86, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F8F, 0x1F87, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F90, 0x1F20 , // # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI\n\t0x1F91, 0x1F21 , // # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI\n\t0x1F92, 0x1F22 , // # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n\t0x1F93, 0x1F23 , // # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n\t0x1F94, 0x1F24 , // # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n\t0x1F95, 0x1F25 , // # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n\t0x1F96, 0x1F26 , // # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1F97, 0x1F27 , // # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1F98, 0x1F90, // GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI\n\t0x1F99, 0x1F91, // GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI\n\t0x1F9A, 0x1F92, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1F9B, 0x1F93, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1F9C, 0x1F94, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1F9D, 0x1F95, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1F9E, 0x1F96, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F9F, 0x1F97, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FA0, 0x1F60 , // # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI\n\t0x1FA1, 0x1F61 , // # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI\n\t0x1FA2, 0x1F62 , // # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI\n\t0x1FA3, 0x1F63 , // # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI\n\t0x1FA4, 0x1F64 , // # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI\n\t0x1FA5, 0x1F65 , // # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI\n\t0x1FA6, 0x1F66 , // # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1FA7, 0x1F67 , // # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI\n\t0x1FA8, 0x1FA0, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI\n\t0x1FA9, 0x1FA1, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI\n\t0x1FAA, 0x1FA2, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1FAB, 0x1FA3, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1FAC, 0x1FA4, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1FAD, 0x1FA5, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1FAE, 0x1FA6, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FAF, 0x1FA7, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FB2, 0x1F70 , // # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI\n\t0x1FB3, 0x03B1 , // # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI\n\t0x1FB4, 0x03AC , // # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI\n\t0x1FB6, 0x03B1 , // # GREEK SMALL LETTER ALPHA WITH PERISPOMENI\n\t0x1FB7, 0x03B1 , // ; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI\n\t0x1FB8, 0x1FB0, // GREEK CAPITAL LETTER ALPHA WITH VRACHY\n\t0x1FB9, 0x1FB1, // GREEK CAPITAL LETTER ALPHA WITH MACRON\n\t0x1FBA, 0x1F70, // GREEK CAPITAL LETTER ALPHA WITH VARIA\n\t0x1FBB, 0x1F71, // GREEK CAPITAL LETTER ALPHA WITH OXIA\n\t0x1FBC, 0x1FB3, // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI\n\t0x1FBE, 0x03B9, // GREEK PROSGEGRAMMENI\n\t0x1FC2, 0x1F74 , // # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI\n\t0x1FC3, 0x03B7 , // # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI\n\t0x1FC4, 0x03AE , // # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI\n\t0x1FC6, 0x03B7 , // # GREEK SMALL LETTER ETA WITH PERISPOMENI\n\t0x1FC7, 0x03B7 , // ; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI\n\t0x1FC8, 0x1F72, // GREEK CAPITAL LETTER EPSILON WITH VARIA\n\t0x1FC9, 0x1F73, // GREEK CAPITAL LETTER EPSILON WITH OXIA\n\t0x1FCA, 0x1F74, // GREEK CAPITAL LETTER ETA WITH VARIA\n\t0x1FCB, 0x1F75, // GREEK CAPITAL LETTER ETA WITH OXIA\n\t0x1FCC, 0x1FC3, // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI\n\t0x1FD2, 0x03B9 , // ; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA\n\t0x1FD3, 0x03B9 , // ; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA\n\t0x1FD6, 0x03B9 , // # GREEK SMALL LETTER IOTA WITH PERISPOMENI\n\t0x1FD7, 0x03B9 , // ; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI\n\t0x1FD8, 0x1FD0, // GREEK CAPITAL LETTER IOTA WITH VRACHY\n\t0x1FD9, 0x1FD1, // GREEK CAPITAL LETTER IOTA WITH MACRON\n\t0x1FDA, 0x1F76, // GREEK CAPITAL LETTER IOTA WITH VARIA\n\t0x1FDB, 0x1F77, // GREEK CAPITAL LETTER IOTA WITH OXIA\n\t0x1FE2, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA\n\t0x1FE3, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA\n\t0x1FE4, 0x03C1 , // # GREEK SMALL LETTER RHO WITH PSILI\n\t0x1FE6, 0x03C5 , // # GREEK SMALL LETTER UPSILON WITH PERISPOMENI\n\t0x1FE7, 0x03C5 , // ; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI\n\t0x1FE8, 0x1FE0, // GREEK CAPITAL LETTER UPSILON WITH VRACHY\n\t0x1FE9, 0x1FE1, // GREEK CAPITAL LETTER UPSILON WITH MACRON\n\t0x1FEA, 0x1F7A, // GREEK CAPITAL LETTER UPSILON WITH VARIA\n\t0x1FEB, 0x1F7B, // GREEK CAPITAL LETTER UPSILON WITH OXIA\n\t0x1FEC, 0x1FE5, // GREEK CAPITAL LETTER RHO WITH DASIA\n\t0x1FF2, 0x1F7C , // # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI\n\t0x1FF3, 0x03C9 , // # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI\n\t0x1FF4, 0x03CE , // # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI\n\t0x1FF6, 0x03C9 , // # GREEK SMALL LETTER OMEGA WITH PERISPOMENI\n\t0x1FF7, 0x03C9 , // ; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI\n\t0x1FF8, 0x1F78, // GREEK CAPITAL LETTER OMICRON WITH VARIA\n\t0x1FF9, 0x1F79, // GREEK CAPITAL LETTER OMICRON WITH OXIA\n\t0x1FFA, 0x1F7C, // GREEK CAPITAL LETTER OMEGA WITH VARIA\n\t0x1FFB, 0x1F7D, // GREEK CAPITAL LETTER OMEGA WITH OXIA\n\t0x1FFC, 0x1FF3, // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI\n\t0x2126, 0x03C9, // OHM SIGN\n\t0x212A, 0x006B, // KELVIN SIGN\n\t0x212B, 0x00E5, // ANGSTROM SIGN\n\t0x2160, 0x2170, // ROMAN NUMERAL ONE\n\t0x2161, 0x2171, // ROMAN NUMERAL TWO\n\t0x2162, 0x2172, // ROMAN NUMERAL THREE\n\t0x2163, 0x2173, // ROMAN NUMERAL FOUR\n\t0x2164, 0x2174, // ROMAN NUMERAL FIVE\n\t0x2165, 0x2175, // ROMAN NUMERAL SIX\n\t0x2166, 0x2176, // ROMAN NUMERAL SEVEN\n\t0x2167, 0x2177, // ROMAN NUMERAL EIGHT\n\t0x2168, 0x2178, // ROMAN NUMERAL NINE\n\t0x2169, 0x2179, // ROMAN NUMERAL TEN\n\t0x216A, 0x217A, // ROMAN NUMERAL ELEVEN\n\t0x216B, 0x217B, // ROMAN NUMERAL TWELVE\n\t0x216C, 0x217C, // ROMAN NUMERAL FIFTY\n\t0x216D, 0x217D, // ROMAN NUMERAL ONE HUNDRED\n\t0x216E, 0x217E, // ROMAN NUMERAL FIVE HUNDRED\n\t0x216F, 0x217F, // ROMAN NUMERAL ONE THOUSAND\n\t0x24B6, 0x24D0, // CIRCLED LATIN CAPITAL LETTER A\n\t0x24B7, 0x24D1, // CIRCLED LATIN CAPITAL LETTER B\n\t0x24B8, 0x24D2, // CIRCLED LATIN CAPITAL LETTER C\n\t0x24B9, 0x24D3, // CIRCLED LATIN CAPITAL LETTER D\n\t0x24BA, 0x24D4, // CIRCLED LATIN CAPITAL LETTER E\n\t0x24BB, 0x24D5, // CIRCLED LATIN CAPITAL LETTER F\n\t0x24BC, 0x24D6, // CIRCLED LATIN CAPITAL LETTER G\n\t0x24BD, 0x24D7, // CIRCLED LATIN CAPITAL LETTER H\n\t0x24BE, 0x24D8, // CIRCLED LATIN CAPITAL LETTER I\n\t0x24BF, 0x24D9, // CIRCLED LATIN CAPITAL LETTER J\n\t0x24C0, 0x24DA, // CIRCLED LATIN CAPITAL LETTER K\n\t0x24C1, 0x24DB, // CIRCLED LATIN CAPITAL LETTER L\n\t0x24C2, 0x24DC, // CIRCLED LATIN CAPITAL LETTER M\n\t0x24C3, 0x24DD, // CIRCLED LATIN CAPITAL LETTER N\n\t0x24C4, 0x24DE, // CIRCLED LATIN CAPITAL LETTER O\n\t0x24C5, 0x24DF, // CIRCLED LATIN CAPITAL LETTER P\n\t0x24C6, 0x24E0, // CIRCLED LATIN CAPITAL LETTER Q\n\t0x24C7, 0x24E1, // CIRCLED LATIN CAPITAL LETTER R\n\t0x24C8, 0x24E2, // CIRCLED LATIN CAPITAL LETTER S\n\t0x24C9, 0x24E3, // CIRCLED LATIN CAPITAL LETTER T\n\t0x24CA, 0x24E4, // CIRCLED LATIN CAPITAL LETTER U\n\t0x24CB, 0x24E5, // CIRCLED LATIN CAPITAL LETTER V\n\t0x24CC, 0x24E6, // CIRCLED LATIN CAPITAL LETTER W\n\t0x24CD, 0x24E7, // CIRCLED LATIN CAPITAL LETTER X\n\t0x24CE, 0x24E8, // CIRCLED LATIN CAPITAL LETTER Y\n\t0x24CF, 0x24E9, // CIRCLED LATIN CAPITAL LETTER Z\n\t0xFB00, 0x0066 , // # LATIN SMALL LIGATURE FF\n\t0xFB01, 0x0066 , // # LATIN SMALL LIGATURE FI\n\t0xFB02, 0x0066 , // # LATIN SMALL LIGATURE FL\n\t0xFB03, 0x0066 , // ; # LATIN SMALL LIGATURE FFI\n\t0xFB04, 0x0066 , // ; # LATIN SMALL LIGATURE FFL\n\t0xFB05, 0x0073 , // # LATIN SMALL LIGATURE LONG S T\n\t0xFB06, 0x0073 , // # LATIN SMALL LIGATURE ST\n\t0xFB13, 0x0574 , // # ARMENIAN SMALL LIGATURE MEN NOW\n\t0xFB14, 0x0574 , // # ARMENIAN SMALL LIGATURE MEN ECH\n\t0xFB15, 0x0574 , // # ARMENIAN SMALL LIGATURE MEN INI\n\t0xFB16, 0x057E , // # ARMENIAN SMALL LIGATURE VEW NOW\n\t0xFB17, 0x0574 , // # ARMENIAN SMALL LIGATURE MEN XEH\n\t0xFF21, 0xFF41, // FULLWIDTH LATIN CAPITAL LETTER A\n\t0xFF22, 0xFF42, // FULLWIDTH LATIN CAPITAL LETTER B\n\t0xFF23, 0xFF43, // FULLWIDTH LATIN CAPITAL LETTER C\n\t0xFF24, 0xFF44, // FULLWIDTH LATIN CAPITAL LETTER D\n\t0xFF25, 0xFF45, // FULLWIDTH LATIN CAPITAL LETTER E\n\t0xFF26, 0xFF46, // FULLWIDTH LATIN CAPITAL LETTER F\n\t0xFF27, 0xFF47, // FULLWIDTH LATIN CAPITAL LETTER G\n\t0xFF28, 0xFF48, // FULLWIDTH LATIN CAPITAL LETTER H\n\t0xFF29, 0xFF49, // FULLWIDTH LATIN CAPITAL LETTER I\n\t0xFF2A, 0xFF4A, // FULLWIDTH LATIN CAPITAL LETTER J\n\t0xFF2B, 0xFF4B, // FULLWIDTH LATIN CAPITAL LETTER K\n\t0xFF2C, 0xFF4C, // FULLWIDTH LATIN CAPITAL LETTER L\n\t0xFF2D, 0xFF4D, // FULLWIDTH LATIN CAPITAL LETTER M\n\t0xFF2E, 0xFF4E, // FULLWIDTH LATIN CAPITAL LETTER N\n\t0xFF2F, 0xFF4F, // FULLWIDTH LATIN CAPITAL LETTER O\n\t0xFF30, 0xFF50, // FULLWIDTH LATIN CAPITAL LETTER P\n\t0xFF31, 0xFF51, // FULLWIDTH LATIN CAPITAL LETTER Q\n\t0xFF32, 0xFF52, // FULLWIDTH LATIN CAPITAL LETTER R\n\t0xFF33, 0xFF53, // FULLWIDTH LATIN CAPITAL LETTER S\n\t0xFF34, 0xFF54, // FULLWIDTH LATIN CAPITAL LETTER T\n\t0xFF35, 0xFF55, // FULLWIDTH LATIN CAPITAL LETTER U\n\t0xFF36, 0xFF56, // FULLWIDTH LATIN CAPITAL LETTER V\n\t0xFF37, 0xFF57, // FULLWIDTH LATIN CAPITAL LETTER W\n\t0xFF38, 0xFF58, // FULLWIDTH LATIN CAPITAL LETTER X\n\t0xFF39, 0xFF59, // FULLWIDTH LATIN CAPITAL LETTER Y\n\t0xFF3A, 0xFF5A, // FULLWIDTH LATIN CAPITAL LETTER Z\n};\n\n// ***************************************************************************\n\n// Lowercase to uppercase 16 bits unicode. This table must be sorted. First entry must be unique.\nstatic const ucchar UnicodeLowerToUpper[]=\n{\n\t// 0x0061, 0x0041, // LATIN CAPITAL LETTER A\n\t0x0061, 'A', // LATIN CAPITAL LETTER A\n\t// 0x0062, 0x0042, // LATIN CAPITAL LETTER B\n\t0x0062, 'B', // LATIN CAPITAL LETTER B\n\t// 0x0063, 0x0043, // LATIN CAPITAL LETTER C\n\t0x0063, 'C', // LATIN CAPITAL LETTER C\n\t// 0x0064, 0x0044, // LATIN CAPITAL LETTER D\n\t0x0064, 'D', // LATIN CAPITAL LETTER D\n\t// 0x0065, 0x0045, // LATIN CAPITAL LETTER E\n\t0x0065, 'E', // LATIN CAPITAL LETTER E\n\t// 0x0066, 0x0046, // LATIN CAPITAL LETTER F\n\t0x0066, 'F', // LATIN CAPITAL LETTER F\n\t// 0x0067, 0x0047, // LATIN CAPITAL LETTER G\n\t0x0067, 'G', // LATIN CAPITAL LETTER G\n\t// 0x0068, 0x0048, // LATIN CAPITAL LETTER H\n\t0x0068, 'H', // LATIN CAPITAL LETTER H\n\t// 0x0069, 0x0049, // LATIN CAPITAL LETTER I\n\t0x0069, 'I', // LATIN CAPITAL LETTER I\n\t// 0x006A, 0x004A, // LATIN CAPITAL LETTER J\n\t0x006A, 'J', // LATIN CAPITAL LETTER J\n\t// 0x006B, 0x004B, // LATIN CAPITAL LETTER K\n\t0x006B, 'K', // LATIN CAPITAL LETTER K\n\t// 0x006C, 0x004C, // LATIN CAPITAL LETTER L\n\t0x006C, 'L', // LATIN CAPITAL LETTER L\n\t// 0x006D, 0x004D, // LATIN CAPITAL LETTER M\n\t0x006D, 'M', // LATIN CAPITAL LETTER M\n\t// 0x006E, 0x004E, // LATIN CAPITAL LETTER N\n\t0x006E, 'N', // LATIN CAPITAL LETTER N\n\t// 0x006F, 0x004F, // LATIN CAPITAL LETTER O\n\t0x006F, 'O', // LATIN CAPITAL LETTER O\n\t// 0x0070, 0x0050, // LATIN CAPITAL LETTER P\n\t0x0070, 'P', // LATIN CAPITAL LETTER P\n\t// 0x0071, 0x0051, // LATIN CAPITAL LETTER Q\n\t0x0071, 'Q', // LATIN CAPITAL LETTER Q\n\t// 0x0072, 0x0052, // LATIN CAPITAL LETTER R\n\t0x0072, 'R', // LATIN CAPITAL LETTER R\n\t// 0x0073, 0x0053, // LATIN CAPITAL LETTER S\n\t0x0073, 'S', // LATIN CAPITAL LETTER S\n\t// 0x0074, 0x0054, // LATIN CAPITAL LETTER T\n\t0x0074, 'T', // LATIN CAPITAL LETTER T\n\t// 0x0075, 0x0055, // LATIN CAPITAL LETTER U\n\t0x0075, 'U', // LATIN CAPITAL LETTER U\n\t// 0x0076, 0x0056, // LATIN CAPITAL LETTER V\n\t0x0076, 'V', // LATIN CAPITAL LETTER V\n\t// 0x0077, 0x0057, // LATIN CAPITAL LETTER W\n\t0x0077, 'W', // LATIN CAPITAL LETTER W\n\t// 0x0078, 0x0058, // LATIN CAPITAL LETTER X\n\t0x0078, 'X', // LATIN CAPITAL LETTER X\n\t// 0x0079, 0x0059, // LATIN CAPITAL LETTER Y\n\t0x0079, 'Y', // LATIN CAPITAL LETTER Y\n\t// 0x007A, 0x005A, // LATIN CAPITAL LETTER Z\n\t0x007A, 'Z', // LATIN CAPITAL LETTER Z\n\t// 0x00E0, 0x00C0, // LATIN CAPITAL LETTER A WITH GRAVE\n\t0x00E0, 'A', // LATIN CAPITAL LETTER A WITH GRAVE\n\t// 0x00E1, 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE\n\t0x00E1, 'A', // LATIN CAPITAL LETTER A WITH ACUTE\n\t// 0x00E2, 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX\n\t0x00E2, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX\n\t// 0x00E3, 0x00C3, // LATIN CAPITAL LETTER A WITH TILDE\n\t0x00E3, 'A', // LATIN CAPITAL LETTER A WITH TILDE\n\t// 0x00E4, 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS\n\t0x00E4, 'A', // LATIN CAPITAL LETTER A WITH DIAERESIS\n\t// 0x00E5, 0x00C5, // LATIN CAPITAL LETTER A WITH RING ABOVE\n\t0x00E5, 'A', // LATIN CAPITAL LETTER A WITH RING ABOVE\n\t0x00E6, 0x00C6, // LATIN CAPITAL LETTER AE\n\t// 0x00E7, 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA\n\t0x00E7, 'C', // LATIN CAPITAL LETTER C WITH CEDILLA\n\t// 0x00E8, 0x00C8, // LATIN CAPITAL LETTER E WITH GRAVE\n\t0x00E8, 'E', // LATIN CAPITAL LETTER E WITH GRAVE\n\t// 0x00E9, 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE\n\t0x00E9, 'E', // LATIN CAPITAL LETTER E WITH ACUTE\n\t// 0x00EA, 0x00CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX\n\t0x00EA, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX\n\t// 0x00EB, 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS\n\t0x00EB, 'E', // LATIN CAPITAL LETTER E WITH DIAERESIS\n\t// 0x00EC, 0x00CC, // LATIN CAPITAL LETTER I WITH GRAVE\n\t0x00EC, 'I', // LATIN CAPITAL LETTER I WITH GRAVE\n\t// 0x00ED, 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE\n\t0x00ED, 'I', // LATIN CAPITAL LETTER I WITH ACUTE\n\t// 0x00EE, 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX\n\t0x00EE, 'I', // LATIN CAPITAL LETTER I WITH CIRCUMFLEX\n\t// 0x00EF, 0x00CF, // LATIN CAPITAL LETTER I WITH DIAERESIS\n\t0x00EF, 'I', // LATIN CAPITAL LETTER I WITH DIAERESIS\n\t0x00F0, 0x00D0, // LATIN CAPITAL LETTER ETH\n\t// 0x00F1, 0x00D1, // LATIN CAPITAL LETTER N WITH TILDE\n\t0x00F1, 'N', // LATIN CAPITAL LETTER N WITH TILDE\n\t// 0x00F2, 0x00D2, // LATIN CAPITAL LETTER O WITH GRAVE\n\t0x00F2, 'O', // LATIN CAPITAL LETTER O WITH GRAVE\n\t// 0x00F3, 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE\n\t0x00F3, 'O', // LATIN CAPITAL LETTER O WITH ACUTE\n\t// 0x00F4, 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX\n\t0x00F4, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX\n\t// 0x00F5, 0x00D5, // LATIN CAPITAL LETTER O WITH TILDE\n\t0x00F5, 'O', // LATIN CAPITAL LETTER O WITH TILDE\n\t// 0x00F6, 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS\n\t0x00F6, 'O', // LATIN CAPITAL LETTER O WITH DIAERESIS\n\t// 0x00F8, 0x00D8, // LATIN CAPITAL LETTER O WITH STROKE\n\t0x00F8, 'O', // LATIN CAPITAL LETTER O WITH STROKE\n\t// 0x00F9, 0x00D9, // LATIN CAPITAL LETTER U WITH GRAVE\n\t0x00F9, 'U', // LATIN CAPITAL LETTER U WITH GRAVE\n\t// 0x00FA, 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE\n\t0x00FA, 'U', // LATIN CAPITAL LETTER U WITH ACUTE\n\t// 0x00FB, 0x00DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX\n\t0x00FB, 'U', // LATIN CAPITAL LETTER U WITH CIRCUMFLEX\n\t// 0x00FC, 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS\n\t0x00FC, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS\n\t// 0x00FD, 0x00DD, // LATIN CAPITAL LETTER Y WITH ACUTE\n\t0x00FD, 'Y', // LATIN CAPITAL LETTER Y WITH ACUTE\n\t0x00FE, 0x00DE, // LATIN CAPITAL LETTER THORN\n\t// 0x00FF, 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS\n\t0x00FF, 'Y', // LATIN CAPITAL LETTER Y WITH DIAERESIS\n\t// 0x0101, 0x0100, // LATIN CAPITAL LETTER A WITH MACRON\n\t0x0101, 'A', // LATIN CAPITAL LETTER A WITH MACRON\n\t// 0x0103, 0x0102, // LATIN CAPITAL LETTER A WITH BREVE\n\t0x0103, 'A', // LATIN CAPITAL LETTER A WITH BREVE\n\t// 0x0105, 0x0104, // LATIN CAPITAL LETTER A WITH OGONEK\n\t0x0105, 'A', // LATIN CAPITAL LETTER A WITH OGONEK\n\t// 0x0107, 0x0106, // LATIN CAPITAL LETTER C WITH ACUTE\n\t0x0107, 'C', // LATIN CAPITAL LETTER C WITH ACUTE\n\t// 0x0109, 0x0108, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX\n\t0x0109, 'C', // LATIN CAPITAL LETTER C WITH CIRCUMFLEX\n\t// 0x010B, 0x010A, // LATIN CAPITAL LETTER C WITH DOT ABOVE\n\t0x010B, 'C', // LATIN CAPITAL LETTER C WITH DOT ABOVE\n\t// 0x010D, 0x010C, // LATIN CAPITAL LETTER C WITH CARON\n\t0x010D, 'C', // LATIN CAPITAL LETTER C WITH CARON\n\t// 0x010F, 0x010E, // LATIN CAPITAL LETTER D WITH CARON\n\t0x010F, 'D', // LATIN CAPITAL LETTER D WITH CARON\n\t// 0x0111, 0x0110, // LATIN CAPITAL LETTER D WITH STROKE\n\t0x0111, 'D', // LATIN CAPITAL LETTER D WITH STROKE\n\t// 0x0113, 0x0112, // LATIN CAPITAL LETTER E WITH MACRON\n\t0x0113, 'E', // LATIN CAPITAL LETTER E WITH MACRON\n\t// 0x0115, 0x0114, // LATIN CAPITAL LETTER E WITH BREVE\n\t0x0115, 'E', // LATIN CAPITAL LETTER E WITH BREVE\n\t// 0x0117, 0x0116, // LATIN CAPITAL LETTER E WITH DOT ABOVE\n\t0x0117, 'E', // LATIN CAPITAL LETTER E WITH DOT ABOVE\n\t// 0x0119, 0x0118, // LATIN CAPITAL LETTER E WITH OGONEK\n\t0x0119, 'E', // LATIN CAPITAL LETTER E WITH OGONEK\n\t// 0x011B, 0x011A, // LATIN CAPITAL LETTER E WITH CARON\n\t0x011B, 'E', // LATIN CAPITAL LETTER E WITH CARON\n\t// 0x011D, 0x011C, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX\n\t0x011D, 'G', // LATIN CAPITAL LETTER G WITH CIRCUMFLEX\n\t// 0x011F, 0x011E, // LATIN CAPITAL LETTER G WITH BREVE\n\t0x011F, 'G', // LATIN CAPITAL LETTER G WITH BREVE\n\t// 0x0121, 0x0120, // LATIN CAPITAL LETTER G WITH DOT ABOVE\n\t0x0121, 'G', // LATIN CAPITAL LETTER G WITH DOT ABOVE\n\t// 0x0123, 0x0122, // LATIN CAPITAL LETTER G WITH CEDILLA\n\t0x0123, 'G', // LATIN CAPITAL LETTER G WITH CEDILLA\n\t// 0x0125, 0x0124, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX\n\t0x0125, 'H', // LATIN CAPITAL LETTER H WITH CIRCUMFLEX\n\t// 0x0127, 0x0126, // LATIN CAPITAL LETTER H WITH STROKE\n\t0x0127, 'H', // LATIN CAPITAL LETTER H WITH STROKE\n\t// 0x0129, 0x0128, // LATIN CAPITAL LETTER I WITH TILDE\n\t0x0129, 'I', // LATIN CAPITAL LETTER I WITH TILDE\n\t// 0x012B, 0x012A, // LATIN CAPITAL LETTER I WITH MACRON\n\t0x012B, 'I', // LATIN CAPITAL LETTER I WITH MACRON\n\t// 0x012D, 0x012C, // LATIN CAPITAL LETTER I WITH BREVE\n\t0x012D, 'I', // LATIN CAPITAL LETTER I WITH BREVE\n\t// 0x012F, 0x012E, // LATIN CAPITAL LETTER I WITH OGONEK\n\t0x012F, 'I', // LATIN CAPITAL LETTER I WITH OGONEK\n\t// 0x0131, 0x0049, // LATIN CAPITAL LETTER I\n\t0x0131, 'I', // LATIN CAPITAL LETTER I\n\t0x0133, 0x0132, // LATIN CAPITAL LIGATURE IJ\n\t// 0x0135, 0x0134, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX\n\t0x0135, 'J', // LATIN CAPITAL LETTER J WITH CIRCUMFLEX\n\t// 0x0137, 0x0136, // LATIN CAPITAL LETTER K WITH CEDILLA\n\t0x0137, 'K', // LATIN CAPITAL LETTER K WITH CEDILLA\n\t// 0x013A, 0x0139, // LATIN CAPITAL LETTER L WITH ACUTE\n\t0x013A, 'L', // LATIN CAPITAL LETTER L WITH ACUTE\n\t// 0x013C, 0x013B, // LATIN CAPITAL LETTER L WITH CEDILLA\n\t0x013C, 'L', // LATIN CAPITAL LETTER L WITH CEDILLA\n\t// 0x013E, 0x013D, // LATIN CAPITAL LETTER L WITH CARON\n\t0x013E, 'L', // LATIN CAPITAL LETTER L WITH CARON\n\t// 0x0140, 0x013F, // LATIN CAPITAL LETTER L WITH MIDDLE DOT\n\t0x0140, 'L', // LATIN CAPITAL LETTER L WITH MIDDLE DOT\n\t// 0x0142, 0x0141, // LATIN CAPITAL LETTER L WITH STROKE\n\t0x0142, 'L', // LATIN CAPITAL LETTER L WITH STROKE\n\t// 0x0144, 0x0143, // LATIN CAPITAL LETTER N WITH ACUTE\n\t0x0144, 'N', // LATIN CAPITAL LETTER N WITH ACUTE\n\t// 0x0146, 0x0145, // LATIN CAPITAL LETTER N WITH CEDILLA\n\t0x0146, 'N', // LATIN CAPITAL LETTER N WITH CEDILLA\n\t// 0x0148, 0x0147, // LATIN CAPITAL LETTER N WITH CARON\n\t0x0148, 'N', // LATIN CAPITAL LETTER N WITH CARON\n\t0x014B, 0x014A, // LATIN CAPITAL LETTER ENG\n\t// 0x014D, 0x014C, // LATIN CAPITAL LETTER O WITH MACRON\n\t0x014D, 'O', // LATIN CAPITAL LETTER O WITH MACRON\n\t// 0x014F, 0x014E, // LATIN CAPITAL LETTER O WITH BREVE\n\t0x014F, 'O', // LATIN CAPITAL LETTER O WITH BREVE\n\t// 0x0151, 0x0150, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE\n\t0x0151, 'O', // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE\n\t0x0153, 0x0152, // LATIN CAPITAL LIGATURE OE\n\t// 0x0155, 0x0154, // LATIN CAPITAL LETTER R WITH ACUTE\n\t0x0155, 'R', // LATIN CAPITAL LETTER R WITH ACUTE\n\t// 0x0157, 0x0156, // LATIN CAPITAL LETTER R WITH CEDILLA\n\t0x0157, 'R', // LATIN CAPITAL LETTER R WITH CEDILLA\n\t// 0x0159, 0x0158, // LATIN CAPITAL LETTER R WITH CARON\n\t0x0159, 'R', // LATIN CAPITAL LETTER R WITH CARON\n\t// 0x015B, 0x015A, // LATIN CAPITAL LETTER S WITH ACUTE\n\t0x015B, 'S', // LATIN CAPITAL LETTER S WITH ACUTE\n\t// 0x015D, 0x015C, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX\n\t0x015D, 'S', // LATIN CAPITAL LETTER S WITH CIRCUMFLEX\n\t// 0x015F, 0x015E, // LATIN CAPITAL LETTER S WITH CEDILLA\n\t0x015F, 'S', // LATIN CAPITAL LETTER S WITH CEDILLA\n\t// 0x0161, 0x0160, // LATIN CAPITAL LETTER S WITH CARON\n\t0x0161, 'S', // LATIN CAPITAL LETTER S WITH CARON\n\t// 0x0163, 0x0162, // LATIN CAPITAL LETTER T WITH CEDILLA\n\t0x0163, 'T', // LATIN CAPITAL LETTER T WITH CEDILLA\n\t// 0x0165, 0x0164, // LATIN CAPITAL LETTER T WITH CARON\n\t0x0165, 'T', // LATIN CAPITAL LETTER T WITH CARON\n\t// 0x0167, 0x0166, // LATIN CAPITAL LETTER T WITH STROKE\n\t0x0167, 'T', // LATIN CAPITAL LETTER T WITH STROKE\n\t// 0x0169, 0x0168, // LATIN CAPITAL LETTER U WITH TILDE\n\t0x0169, 'U', // LATIN CAPITAL LETTER U WITH TILDE\n\t// 0x016B, 0x016A, // LATIN CAPITAL LETTER U WITH MACRON\n\t0x016B, 'U', // LATIN CAPITAL LETTER U WITH MACRON\n\t// 0x016D, 0x016C, // LATIN CAPITAL LETTER U WITH BREVE\n\t0x016D, 'U', // LATIN CAPITAL LETTER U WITH BREVE\n\t// 0x016F, 0x016E, // LATIN CAPITAL LETTER U WITH RING ABOVE\n\t0x016F, 'U', // LATIN CAPITAL LETTER U WITH RING ABOVE\n\t// 0x0171, 0x0170, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE\n\t0x0171, 'U', // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE\n\t// 0x0173, 0x0172, // LATIN CAPITAL LETTER U WITH OGONEK\n\t0x0173, 'U', // LATIN CAPITAL LETTER U WITH OGONEK\n\t// 0x0175, 0x0174, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX\n\t0x0175, 'W', // LATIN CAPITAL LETTER W WITH CIRCUMFLEX\n\t// 0x0177, 0x0176, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX\n\t0x0177, 'Y', // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX\n\t// 0x017A, 0x0179, // LATIN CAPITAL LETTER Z WITH ACUTE\n\t0x017A, 'Z', // LATIN CAPITAL LETTER Z WITH ACUTE\n\t// 0x017C, 0x017B, // LATIN CAPITAL LETTER Z WITH DOT ABOVE\n\t0x017C, 'Z', // LATIN CAPITAL LETTER Z WITH DOT ABOVE\n\t// 0x017E, 0x017D, // LATIN CAPITAL LETTER Z WITH CARON\n\t0x017E, 'Z', // LATIN CAPITAL LETTER Z WITH CARON\n\t// 0x0183, 0x0182, // LATIN CAPITAL LETTER B WITH TOPBAR\n\t0x0183, 'B', // LATIN CAPITAL LETTER B WITH TOPBAR\n\t0x0185, 0x0184, // LATIN CAPITAL LETTER TONE SIX\n\t// 0x0188, 0x0187, // LATIN CAPITAL LETTER C WITH HOOK\n\t0x0188, 'C', // LATIN CAPITAL LETTER C WITH HOOK\n\t// 0x018C, 0x018B, // LATIN CAPITAL LETTER D WITH TOPBAR\n\t0x018C, 'D', // LATIN CAPITAL LETTER D WITH TOPBAR\n\t// 0x0192, 0x0191, // LATIN CAPITAL LETTER F WITH HOOK\n\t0x0192, 'F', // LATIN CAPITAL LETTER F WITH HOOK\n\t0x0195, 0x01F6, // LATIN CAPITAL LETTER HWAIR\n\t// 0x0199, 0x0198, // LATIN CAPITAL LETTER K WITH HOOK\n\t0x0199, 'K', // LATIN CAPITAL LETTER K WITH HOOK\n\t// 0x019E, 0x0220, // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG\n\t0x019E, 'N', // LATIN CAPITAL LETTER N WITH LONG RIGHT LEG\n\t// 0x01A1, 0x01A0, // LATIN CAPITAL LETTER O WITH HORN\n\t0x01A1, 'O', // LATIN CAPITAL LETTER O WITH HORN\n\t0x01A3, 0x01A2, // LATIN CAPITAL LETTER OI\n\t// 0x01A5, 0x01A4, // LATIN CAPITAL LETTER P WITH HOOK\n\t0x01A5, 'P', // LATIN CAPITAL LETTER P WITH HOOK\n\t0x01A8, 0x01A7, // LATIN CAPITAL LETTER TONE TWO\n\t// 0x01AD, 0x01AC, // LATIN CAPITAL LETTER T WITH HOOK\n\t0x01AD, 'T', // LATIN CAPITAL LETTER T WITH HOOK\n\t// 0x01B0, 0x01AF, // LATIN CAPITAL LETTER U WITH HORN\n\t0x01B0, 'U', // LATIN CAPITAL LETTER U WITH HORN\n\t// 0x01B4, 0x01B3, // LATIN CAPITAL LETTER Y WITH HOOK\n\t0x01B4, 'Y', // LATIN CAPITAL LETTER Y WITH HOOK\n\t// 0x01B6, 0x01B5, // LATIN CAPITAL LETTER Z WITH STROKE\n\t0x01B6, 'Z', // LATIN CAPITAL LETTER Z WITH STROKE\n\t0x01B9, 0x01B8, // LATIN CAPITAL LETTER EZH REVERSED\n\t0x01BD, 0x01BC, // LATIN CAPITAL LETTER TONE FIVE\n\t0x01BF, 0x01F7, // LATIN CAPITAL LETTER WYNN\n\t0x01C6, 0x01C4, // LATIN CAPITAL LETTER DZ WITH CARON\n\t0x01C9, 0x01C7, // LATIN CAPITAL LETTER LJ\n\t0x01CC, 0x01CA, // LATIN CAPITAL LETTER NJ\n\t// 0x01CE, 0x01CD, // LATIN CAPITAL LETTER A WITH CARON\n\t0x01CE, 'A', // LATIN CAPITAL LETTER A WITH CARON\n\t// 0x01D0, 0x01CF, // LATIN CAPITAL LETTER I WITH CARON\n\t0x01D0, 'I', // LATIN CAPITAL LETTER I WITH CARON\n\t// 0x01D2, 0x01D1, // LATIN CAPITAL LETTER O WITH CARON\n\t0x01D2, 'O', // LATIN CAPITAL LETTER O WITH CARON\n\t// 0x01D4, 0x01D3, // LATIN CAPITAL LETTER U WITH CARON\n\t0x01D4, 'U', // LATIN CAPITAL LETTER U WITH CARON\n\t// 0x01D6, 0x01D5, // LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON\n\t0x01D6, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON\n\t// 0x01D8, 0x01D7, // LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE\n\t0x01D8, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE\n\t// 0x01DA, 0x01D9, // LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON\n\t0x01DA, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON\n\t// 0x01DC, 0x01DB, // LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE\n\t0x01DC, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE\n\t0x01DD, 0x018E, // LATIN CAPITAL LETTER REVERSED E\n\t// 0x01DF, 0x01DE, // LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON\n\t0x01DF, 'A', // LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON\n\t// 0x01E1, 0x01E0, // LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON\n\t0x01E1, 'A', // LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON\n\t0x01E3, 0x01E2, // LATIN CAPITAL LETTER AE WITH MACRON\n\t// 0x01E5, 0x01E4, // LATIN CAPITAL LETTER G WITH STROKE\n\t0x01E5, 'G', // LATIN CAPITAL LETTER G WITH STROKE\n\t// 0x01E7, 0x01E6, // LATIN CAPITAL LETTER G WITH CARON\n\t0x01E7, 'G', // LATIN CAPITAL LETTER G WITH CARON\n\t// 0x01E9, 0x01E8, // LATIN CAPITAL LETTER K WITH CARON\n\t0x01E9, 'K', // LATIN CAPITAL LETTER K WITH CARON\n\t// 0x01EB, 0x01EA, // LATIN CAPITAL LETTER O WITH OGONEK\n\t0x01EB, 'O', // LATIN CAPITAL LETTER O WITH OGONEK\n\t// 0x01ED, 0x01EC, // LATIN CAPITAL LETTER O WITH OGONEK AND MACRON\n\t0x01ED, 'O', // LATIN CAPITAL LETTER O WITH OGONEK AND MACRON\n\t0x01EF, 0x01EE, // LATIN CAPITAL LETTER EZH WITH CARON\n\t0x01F3, 0x01F1, // LATIN CAPITAL LETTER DZ\n\t// 0x01F5, 0x01F4, // LATIN CAPITAL LETTER G WITH ACUTE\n\t0x01F5, 'G', // LATIN CAPITAL LETTER G WITH ACUTE\n\t// 0x01F9, 0x01F8, // LATIN CAPITAL LETTER N WITH GRAVE\n\t0x01F9, 'N', // LATIN CAPITAL LETTER N WITH GRAVE\n\t// 0x01FB, 0x01FA, // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE\n\t0x01FB, 'A', // LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE\n\t0x01FD, 0x01FC, // LATIN CAPITAL LETTER AE WITH ACUTE\n\t// 0x01FF, 0x01FE, // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE\n\t0x01FF, 'O', // LATIN CAPITAL LETTER O WITH STROKE AND ACUTE\n\t// 0x0201, 0x0200, // LATIN CAPITAL LETTER A WITH DOUBLE GRAVE\n\t0x0201, 'A', // LATIN CAPITAL LETTER A WITH DOUBLE GRAVE\n\t// 0x0203, 0x0202, // LATIN CAPITAL LETTER A WITH INVERTED BREVE\n\t0x0203, 'A', // LATIN CAPITAL LETTER A WITH INVERTED BREVE\n\t// 0x0205, 0x0204, // LATIN CAPITAL LETTER E WITH DOUBLE GRAVE\n\t0x0205, 'E', // LATIN CAPITAL LETTER E WITH DOUBLE GRAVE\n\t// 0x0207, 0x0206, // LATIN CAPITAL LETTER E WITH INVERTED BREVE\n\t0x0207, 'E', // LATIN CAPITAL LETTER E WITH INVERTED BREVE\n\t// 0x0209, 0x0208, // LATIN CAPITAL LETTER I WITH DOUBLE GRAVE\n\t0x0209, 'I', // LATIN CAPITAL LETTER I WITH DOUBLE GRAVE\n\t// 0x020B, 0x020A, // LATIN CAPITAL LETTER I WITH INVERTED BREVE\n\t0x020B, 'I', // LATIN CAPITAL LETTER I WITH INVERTED BREVE\n\t// 0x020D, 0x020C, // LATIN CAPITAL LETTER O WITH DOUBLE GRAVE\n\t0x020D, 'O', // LATIN CAPITAL LETTER O WITH DOUBLE GRAVE\n\t// 0x020F, 0x020E, // LATIN CAPITAL LETTER O WITH INVERTED BREVE\n\t0x020F, 'O', // LATIN CAPITAL LETTER O WITH INVERTED BREVE\n\t// 0x0211, 0x0210, // LATIN CAPITAL LETTER R WITH DOUBLE GRAVE\n\t0x0211, 'R', // LATIN CAPITAL LETTER R WITH DOUBLE GRAVE\n\t// 0x0213, 0x0212, // LATIN CAPITAL LETTER R WITH INVERTED BREVE\n\t0x0213, 'R', // LATIN CAPITAL LETTER R WITH INVERTED BREVE\n\t// 0x0215, 0x0214, // LATIN CAPITAL LETTER U WITH DOUBLE GRAVE\n\t0x0215, 'U', // LATIN CAPITAL LETTER U WITH DOUBLE GRAVE\n\t// 0x0217, 0x0216, // LATIN CAPITAL LETTER U WITH INVERTED BREVE\n\t0x0217, 'U', // LATIN CAPITAL LETTER U WITH INVERTED BREVE\n\t// 0x0219, 0x0218, // LATIN CAPITAL LETTER S WITH COMMA BELOW\n\t0x0219, 'S', // LATIN CAPITAL LETTER S WITH COMMA BELOW\n\t// 0x021B, 0x021A, // LATIN CAPITAL LETTER T WITH COMMA BELOW\n\t0x021B, 'T', // LATIN CAPITAL LETTER T WITH COMMA BELOW\n\t0x021D, 0x021C, // LATIN CAPITAL LETTER YOGH\n\t// 0x021F, 0x021E, // LATIN CAPITAL LETTER H WITH CARON\n\t0x021F, 'H', // LATIN CAPITAL LETTER H WITH CARON\n\t0x0223, 0x0222, // LATIN CAPITAL LETTER OU\n\t// 0x0225, 0x0224, // LATIN CAPITAL LETTER Z WITH HOOK\n\t0x0225, 'Z', // LATIN CAPITAL LETTER Z WITH HOOK\n\t// 0x0227, 0x0226, // LATIN CAPITAL LETTER A WITH DOT ABOVE\n\t0x0227, 'A', // LATIN CAPITAL LETTER A WITH DOT ABOVE\n\t// 0x0229, 0x0228, // LATIN CAPITAL LETTER E WITH CEDILLA\n\t0x0229, 'E', // LATIN CAPITAL LETTER E WITH CEDILLA\n\t// 0x022B, 0x022A, // LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON\n\t0x022B, 'O', // LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON\n\t// 0x022D, 0x022C, // LATIN CAPITAL LETTER O WITH TILDE AND MACRON\n\t0x022D, 'O', // LATIN CAPITAL LETTER O WITH TILDE AND MACRON\n\t// 0x022F, 0x022E, // LATIN CAPITAL LETTER O WITH DOT ABOVE\n\t0x022F, 'O', // LATIN CAPITAL LETTER O WITH DOT ABOVE\n\t// 0x0231, 0x0230, // LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON\n\t0x0231, 'O', // LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON\n\t// 0x0233, 0x0232, // LATIN CAPITAL LETTER Y WITH MACRON\n\t0x0233, 'Y', // LATIN CAPITAL LETTER Y WITH MACRON\n\t// 0x0253, 0x0181, // LATIN CAPITAL LETTER B WITH HOOK\n\t0x0253, 'B', // LATIN CAPITAL LETTER B WITH HOOK\n\t0x0254, 0x0186, // LATIN CAPITAL LETTER OPEN O\n\t0x0256, 0x0189, // LATIN CAPITAL LETTER AFRICAN D\n\t// 0x0257, 0x018A, // LATIN CAPITAL LETTER D WITH HOOK\n\t0x0257, 'D', // LATIN CAPITAL LETTER D WITH HOOK\n\t0x0259, 0x018F, // LATIN CAPITAL LETTER SCHWA\n\t0x025B, 0x0190, // LATIN CAPITAL LETTER OPEN E\n\t// 0x0260, 0x0193, // LATIN CAPITAL LETTER G WITH HOOK\n\t0x0260, 'G', // LATIN CAPITAL LETTER G WITH HOOK\n\t0x0263, 0x0194, // LATIN CAPITAL LETTER GAMMA\n\t// 0x0268, 0x0197, // LATIN CAPITAL LETTER I WITH STROKE\n\t0x0268, 'I', // LATIN CAPITAL LETTER I WITH STROKE\n\t0x0269, 0x0196, // LATIN CAPITAL LETTER IOTA\n\t0x026F, 0x019C, // LATIN CAPITAL LETTER TURNED M\n\t// 0x0272, 0x019D, // LATIN CAPITAL LETTER N WITH LEFT HOOK\n\t0x0272, 'N', // LATIN CAPITAL LETTER N WITH LEFT HOOK\n\t// 0x0275, 0x019F, // LATIN CAPITAL LETTER O WITH MIDDLE TILDE\n\t0x0275, 'O', // LATIN CAPITAL LETTER O WITH MIDDLE TILDE\n\t0x0280, 0x01A6, // LATIN LETTER YR\n\t0x0283, 0x01A9, // LATIN CAPITAL LETTER ESH\n\t// 0x0288, 0x01AE, // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\n\t0x0288, 'T', // LATIN CAPITAL LETTER T WITH RETROFLEX HOOK\n\t0x028A, 0x01B1, // LATIN CAPITAL LETTER UPSILON\n\t// 0x028B, 0x01B2, // LATIN CAPITAL LETTER V WITH HOOK\n\t0x028B, 'V', // LATIN CAPITAL LETTER V WITH HOOK\n\t0x0292, 0x01B7, // LATIN CAPITAL LETTER EZH\n\t0x03AC, 0x0386, // GREEK CAPITAL LETTER ALPHA WITH TONOS\n\t0x03AD, 0x0388, // GREEK CAPITAL LETTER EPSILON WITH TONOS\n\t0x03AE, 0x0389, // GREEK CAPITAL LETTER ETA WITH TONOS\n\t0x03AF, 0x038A, // GREEK CAPITAL LETTER IOTA WITH TONOS\n\t0x03B1, 0x0391, // GREEK CAPITAL LETTER ALPHA\n\t0x03B2, 0x0392, // GREEK CAPITAL LETTER BETA\n\t0x03B3, 0x0393, // GREEK CAPITAL LETTER GAMMA\n\t0x03B4, 0x0394, // GREEK CAPITAL LETTER DELTA\n\t0x03B5, 0x0395, // GREEK CAPITAL LETTER EPSILON\n\t0x03B6, 0x0396, // GREEK CAPITAL LETTER ZETA\n\t0x03B7, 0x0397, // GREEK CAPITAL LETTER ETA\n\t0x03B8, 0x0398, // GREEK CAPITAL LETTER THETA\n\t0x03B9, 0x0345, // COMBINING GREEK YPOGEGRAMMENI\n\t0x03BA, 0x039A, // GREEK CAPITAL LETTER KAPPA\n\t0x03BB, 0x039B, // GREEK CAPITAL LETTER LAMDA\n\t0x03BC, 0x039C, // GREEK CAPITAL LETTER MU\n\t0x03BD, 0x039D, // GREEK CAPITAL LETTER NU\n\t0x03BE, 0x039E, // GREEK CAPITAL LETTER XI\n\t0x03BF, 0x039F, // GREEK CAPITAL LETTER OMICRON\n\t0x03C0, 0x03A0, // GREEK CAPITAL LETTER PI\n\t0x03C1, 0x03A1, // GREEK CAPITAL LETTER RHO\n\t0x03C3, 0x03A3, // GREEK CAPITAL LETTER SIGMA\n\t0x03C4, 0x03A4, // GREEK CAPITAL LETTER TAU\n\t0x03C5, 0x03A5, // GREEK CAPITAL LETTER UPSILON\n\t0x03C6, 0x03A6, // GREEK CAPITAL LETTER PHI\n\t0x03C7, 0x03A7, // GREEK CAPITAL LETTER CHI\n\t0x03C8, 0x03A8, // GREEK CAPITAL LETTER PSI\n\t0x03C9, 0x03A9, // GREEK CAPITAL LETTER OMEGA\n\t0x03CA, 0x03AA, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA\n\t0x03CB, 0x03AB, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA\n\t0x03CC, 0x038C, // GREEK CAPITAL LETTER OMICRON WITH TONOS\n\t0x03CD, 0x038E, // GREEK CAPITAL LETTER UPSILON WITH TONOS\n\t0x03CE, 0x038F, // GREEK CAPITAL LETTER OMEGA WITH TONOS\n\t0x03D9, 0x03D8, // GREEK LETTER ARCHAIC KOPPA\n\t0x03DB, 0x03DA, // GREEK LETTER STIGMA\n\t0x03DD, 0x03DC, // GREEK LETTER DIGAMMA\n\t0x03DF, 0x03DE, // GREEK LETTER KOPPA\n\t0x03E1, 0x03E0, // GREEK LETTER SAMPI\n\t0x03E3, 0x03E2, // COPTIC CAPITAL LETTER SHEI\n\t0x03E5, 0x03E4, // COPTIC CAPITAL LETTER FEI\n\t0x03E7, 0x03E6, // COPTIC CAPITAL LETTER KHEI\n\t0x03E9, 0x03E8, // COPTIC CAPITAL LETTER HORI\n\t0x03EB, 0x03EA, // COPTIC CAPITAL LETTER GANGIA\n\t0x03ED, 0x03EC, // COPTIC CAPITAL LETTER SHIMA\n\t0x03EF, 0x03EE, // COPTIC CAPITAL LETTER DEI\n\t0x03F2, 0x03F9, // GREEK CAPITAL LUNATE SIGMA SYMBOL\n\t0x03F8, 0x03F7, // GREEK CAPITAL LETTER SHO\n\t0x03FB, 0x03FA, // GREEK CAPITAL LETTER SAN\n\t0x0430, 0x0410, // CYRILLIC CAPITAL LETTER A\n\t0x0431, 0x0411, // CYRILLIC CAPITAL LETTER BE\n\t0x0432, 0x0412, // CYRILLIC CAPITAL LETTER VE\n\t0x0433, 0x0413, // CYRILLIC CAPITAL LETTER GHE\n\t0x0434, 0x0414, // CYRILLIC CAPITAL LETTER DE\n\t0x0435, 0x0415, // CYRILLIC CAPITAL LETTER IE\n\t0x0436, 0x0416, // CYRILLIC CAPITAL LETTER ZHE\n\t0x0437, 0x0417, // CYRILLIC CAPITAL LETTER ZE\n\t0x0438, 0x0418, // CYRILLIC CAPITAL LETTER I\n\t0x0439, 0x0419, // CYRILLIC CAPITAL LETTER SHORT I\n\t0x043A, 0x041A, // CYRILLIC CAPITAL LETTER KA\n\t0x043B, 0x041B, // CYRILLIC CAPITAL LETTER EL\n\t0x043C, 0x041C, // CYRILLIC CAPITAL LETTER EM\n\t0x043D, 0x041D, // CYRILLIC CAPITAL LETTER EN\n\t0x043E, 0x041E, // CYRILLIC CAPITAL LETTER O\n\t0x043F, 0x041F, // CYRILLIC CAPITAL LETTER PE\n\t0x0440, 0x0420, // CYRILLIC CAPITAL LETTER ER\n\t0x0441, 0x0421, // CYRILLIC CAPITAL LETTER ES\n\t0x0442, 0x0422, // CYRILLIC CAPITAL LETTER TE\n\t0x0443, 0x0423, // CYRILLIC CAPITAL LETTER U\n\t0x0444, 0x0424, // CYRILLIC CAPITAL LETTER EF\n\t0x0445, 0x0425, // CYRILLIC CAPITAL LETTER HA\n\t0x0446, 0x0426, // CYRILLIC CAPITAL LETTER TSE\n\t0x0447, 0x0427, // CYRILLIC CAPITAL LETTER CHE\n\t0x0448, 0x0428, // CYRILLIC CAPITAL LETTER SHA\n\t0x0449, 0x0429, // CYRILLIC CAPITAL LETTER SHCHA\n\t0x044A, 0x042A, // CYRILLIC CAPITAL LETTER HARD SIGN\n\t0x044B, 0x042B, // CYRILLIC CAPITAL LETTER YERU\n\t0x044C, 0x042C, // CYRILLIC CAPITAL LETTER SOFT SIGN\n\t0x044D, 0x042D, // CYRILLIC CAPITAL LETTER E\n\t0x044E, 0x042E, // CYRILLIC CAPITAL LETTER YU\n\t0x044F, 0x042F, // CYRILLIC CAPITAL LETTER YA\n\t0x0450, 0x0400, // CYRILLIC CAPITAL LETTER IE WITH GRAVE\n\t0x0451, 0x0401, // CYRILLIC CAPITAL LETTER IO\n\t0x0452, 0x0402, // CYRILLIC CAPITAL LETTER DJE\n\t0x0453, 0x0403, // CYRILLIC CAPITAL LETTER GJE\n\t0x0454, 0x0404, // CYRILLIC CAPITAL LETTER UKRAINIAN IE\n\t0x0455, 0x0405, // CYRILLIC CAPITAL LETTER DZE\n\t0x0456, 0x0406, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I\n\t0x0457, 0x0407, // CYRILLIC CAPITAL LETTER YI\n\t0x0458, 0x0408, // CYRILLIC CAPITAL LETTER JE\n\t0x0459, 0x0409, // CYRILLIC CAPITAL LETTER LJE\n\t0x045A, 0x040A, // CYRILLIC CAPITAL LETTER NJE\n\t0x045B, 0x040B, // CYRILLIC CAPITAL LETTER TSHE\n\t0x045C, 0x040C, // CYRILLIC CAPITAL LETTER KJE\n\t0x045D, 0x040D, // CYRILLIC CAPITAL LETTER I WITH GRAVE\n\t0x045E, 0x040E, // CYRILLIC CAPITAL LETTER SHORT U\n\t0x045F, 0x040F, // CYRILLIC CAPITAL LETTER DZHE\n\t0x0461, 0x0460, // CYRILLIC CAPITAL LETTER OMEGA\n\t0x0463, 0x0462, // CYRILLIC CAPITAL LETTER YAT\n\t0x0465, 0x0464, // CYRILLIC CAPITAL LETTER IOTIFIED E\n\t0x0467, 0x0466, // CYRILLIC CAPITAL LETTER LITTLE YUS\n\t0x0469, 0x0468, // CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS\n\t0x046B, 0x046A, // CYRILLIC CAPITAL LETTER BIG YUS\n\t0x046D, 0x046C, // CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS\n\t0x046F, 0x046E, // CYRILLIC CAPITAL LETTER KSI\n\t0x0471, 0x0470, // CYRILLIC CAPITAL LETTER PSI\n\t0x0473, 0x0472, // CYRILLIC CAPITAL LETTER FITA\n\t0x0475, 0x0474, // CYRILLIC CAPITAL LETTER IZHITSA\n\t0x0477, 0x0476, // CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT\n\t0x0479, 0x0478, // CYRILLIC CAPITAL LETTER UK\n\t0x047B, 0x047A, // CYRILLIC CAPITAL LETTER ROUND OMEGA\n\t0x047D, 0x047C, // CYRILLIC CAPITAL LETTER OMEGA WITH TITLO\n\t0x047F, 0x047E, // CYRILLIC CAPITAL LETTER OT\n\t0x0481, 0x0480, // CYRILLIC CAPITAL LETTER KOPPA\n\t0x048B, 0x048A, // CYRILLIC CAPITAL LETTER SHORT I WITH TAIL\n\t0x048D, 0x048C, // CYRILLIC CAPITAL LETTER SEMISOFT SIGN\n\t0x048F, 0x048E, // CYRILLIC CAPITAL LETTER ER WITH TICK\n\t0x0491, 0x0490, // CYRILLIC CAPITAL LETTER GHE WITH UPTURN\n\t0x0493, 0x0492, // CYRILLIC CAPITAL LETTER GHE WITH STROKE\n\t0x0495, 0x0494, // CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK\n\t0x0497, 0x0496, // CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER\n\t0x0499, 0x0498, // CYRILLIC CAPITAL LETTER ZE WITH DESCENDER\n\t0x049B, 0x049A, // CYRILLIC CAPITAL LETTER KA WITH DESCENDER\n\t0x049D, 0x049C, // CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE\n\t0x049F, 0x049E, // CYRILLIC CAPITAL LETTER KA WITH STROKE\n\t0x04A1, 0x04A0, // CYRILLIC CAPITAL LETTER BASHKIR KA\n\t0x04A3, 0x04A2, // CYRILLIC CAPITAL LETTER EN WITH DESCENDER\n\t0x04A5, 0x04A4, // CYRILLIC CAPITAL LIGATURE EN GHE\n\t0x04A7, 0x04A6, // CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK\n\t0x04A9, 0x04A8, // CYRILLIC CAPITAL LETTER ABKHASIAN HA\n\t0x04AB, 0x04AA, // CYRILLIC CAPITAL LETTER ES WITH DESCENDER\n\t0x04AD, 0x04AC, // CYRILLIC CAPITAL LETTER TE WITH DESCENDER\n\t0x04AF, 0x04AE, // CYRILLIC CAPITAL LETTER STRAIGHT U\n\t0x04B1, 0x04B0, // CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE\n\t0x04B3, 0x04B2, // CYRILLIC CAPITAL LETTER HA WITH DESCENDER\n\t0x04B5, 0x04B4, // CYRILLIC CAPITAL LIGATURE TE TSE\n\t0x04B7, 0x04B6, // CYRILLIC CAPITAL LETTER CHE WITH DESCENDER\n\t0x04B9, 0x04B8, // CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE\n\t0x04BB, 0x04BA, // CYRILLIC CAPITAL LETTER SHHA\n\t0x04BD, 0x04BC, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE\n\t0x04BF, 0x04BE, // CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER\n\t0x04C2, 0x04C1, // CYRILLIC CAPITAL LETTER ZHE WITH BREVE\n\t0x04C4, 0x04C3, // CYRILLIC CAPITAL LETTER KA WITH HOOK\n\t0x04C6, 0x04C5, // CYRILLIC CAPITAL LETTER EL WITH TAIL\n\t0x04C8, 0x04C7, // CYRILLIC CAPITAL LETTER EN WITH HOOK\n\t0x04CA, 0x04C9, // CYRILLIC CAPITAL LETTER EN WITH TAIL\n\t0x04CC, 0x04CB, // CYRILLIC CAPITAL LETTER KHAKASSIAN CHE\n\t0x04CE, 0x04CD, // CYRILLIC CAPITAL LETTER EM WITH TAIL\n\t0x04D1, 0x04D0, // CYRILLIC CAPITAL LETTER A WITH BREVE\n\t0x04D3, 0x04D2, // CYRILLIC CAPITAL LETTER A WITH DIAERESIS\n\t0x04D5, 0x04D4, // CYRILLIC CAPITAL LIGATURE A IE\n\t0x04D7, 0x04D6, // CYRILLIC CAPITAL LETTER IE WITH BREVE\n\t0x04D9, 0x04D8, // CYRILLIC CAPITAL LETTER SCHWA\n\t0x04DB, 0x04DA, // CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS\n\t0x04DD, 0x04DC, // CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS\n\t0x04DF, 0x04DE, // CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS\n\t0x04E1, 0x04E0, // CYRILLIC CAPITAL LETTER ABKHASIAN DZE\n\t0x04E3, 0x04E2, // CYRILLIC CAPITAL LETTER I WITH MACRON\n\t0x04E5, 0x04E4, // CYRILLIC CAPITAL LETTER I WITH DIAERESIS\n\t0x04E7, 0x04E6, // CYRILLIC CAPITAL LETTER O WITH DIAERESIS\n\t0x04E9, 0x04E8, // CYRILLIC CAPITAL LETTER BARRED O\n\t0x04EB, 0x04EA, // CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS\n\t0x04ED, 0x04EC, // CYRILLIC CAPITAL LETTER E WITH DIAERESIS\n\t0x04EF, 0x04EE, // CYRILLIC CAPITAL LETTER U WITH MACRON\n\t0x04F1, 0x04F0, // CYRILLIC CAPITAL LETTER U WITH DIAERESIS\n\t0x04F3, 0x04F2, // CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE\n\t0x04F5, 0x04F4, // CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS\n\t0x04F9, 0x04F8, // CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS\n\t0x0501, 0x0500, // CYRILLIC CAPITAL LETTER KOMI DE\n\t0x0503, 0x0502, // CYRILLIC CAPITAL LETTER KOMI DJE\n\t0x0505, 0x0504, // CYRILLIC CAPITAL LETTER KOMI ZJE\n\t0x0507, 0x0506, // CYRILLIC CAPITAL LETTER KOMI DZJE\n\t0x0509, 0x0508, // CYRILLIC CAPITAL LETTER KOMI LJE\n\t0x050B, 0x050A, // CYRILLIC CAPITAL LETTER KOMI NJE\n\t0x050D, 0x050C, // CYRILLIC CAPITAL LETTER KOMI SJE\n\t0x050F, 0x050E, // CYRILLIC CAPITAL LETTER KOMI TJE\n\t0x0561, 0x0531, // ARMENIAN CAPITAL LETTER AYB\n\t0x0562, 0x0532, // ARMENIAN CAPITAL LETTER BEN\n\t0x0563, 0x0533, // ARMENIAN CAPITAL LETTER GIM\n\t0x0564, 0x0534, // ARMENIAN CAPITAL LETTER DA\n\t0x0565, 0x0535, // ARMENIAN CAPITAL LETTER ECH\n\t0x0566, 0x0536, // ARMENIAN CAPITAL LETTER ZA\n\t0x0567, 0x0537, // ARMENIAN CAPITAL LETTER EH\n\t0x0568, 0x0538, // ARMENIAN CAPITAL LETTER ET\n\t0x0569, 0x0539, // ARMENIAN CAPITAL LETTER TO\n\t0x056A, 0x053A, // ARMENIAN CAPITAL LETTER ZHE\n\t0x056B, 0x053B, // ARMENIAN CAPITAL LETTER INI\n\t0x056C, 0x053C, // ARMENIAN CAPITAL LETTER LIWN\n\t0x056D, 0x053D, // ARMENIAN CAPITAL LETTER XEH\n\t0x056E, 0x053E, // ARMENIAN CAPITAL LETTER CA\n\t0x056F, 0x053F, // ARMENIAN CAPITAL LETTER KEN\n\t0x0570, 0x0540, // ARMENIAN CAPITAL LETTER HO\n\t0x0571, 0x0541, // ARMENIAN CAPITAL LETTER JA\n\t0x0572, 0x0542, // ARMENIAN CAPITAL LETTER GHAD\n\t0x0573, 0x0543, // ARMENIAN CAPITAL LETTER CHEH\n\t0x0574, 0x0544, // ARMENIAN CAPITAL LETTER MEN\n\t0x0575, 0x0545, // ARMENIAN CAPITAL LETTER YI\n\t0x0576, 0x0546, // ARMENIAN CAPITAL LETTER NOW\n\t0x0577, 0x0547, // ARMENIAN CAPITAL LETTER SHA\n\t0x0578, 0x0548, // ARMENIAN CAPITAL LETTER VO\n\t0x0579, 0x0549, // ARMENIAN CAPITAL LETTER CHA\n\t0x057A, 0x054A, // ARMENIAN CAPITAL LETTER PEH\n\t0x057B, 0x054B, // ARMENIAN CAPITAL LETTER JHEH\n\t0x057C, 0x054C, // ARMENIAN CAPITAL LETTER RA\n\t0x057D, 0x054D, // ARMENIAN CAPITAL LETTER SEH\n\t0x057E, 0x054E, // ARMENIAN CAPITAL LETTER VEW\n\t0x057F, 0x054F, // ARMENIAN CAPITAL LETTER TIWN\n\t0x0580, 0x0550, // ARMENIAN CAPITAL LETTER REH\n\t0x0581, 0x0551, // ARMENIAN CAPITAL LETTER CO\n\t0x0582, 0x0552, // ARMENIAN CAPITAL LETTER YIWN\n\t0x0583, 0x0553, // ARMENIAN CAPITAL LETTER PIWR\n\t0x0584, 0x0554, // ARMENIAN CAPITAL LETTER KEH\n\t0x0585, 0x0555, // ARMENIAN CAPITAL LETTER OH\n\t0x0586, 0x0556, // ARMENIAN CAPITAL LETTER FEH\n\t// 0x1E01, 0x1E00, // LATIN CAPITAL LETTER A WITH RING BELOW\n\t0x1E01, 'A', // LATIN CAPITAL LETTER A WITH RING BELOW\n\t// 0x1E03, 0x1E02, // LATIN CAPITAL LETTER B WITH DOT ABOVE\n\t0x1E03, 'B', // LATIN CAPITAL LETTER B WITH DOT ABOVE\n\t// 0x1E05, 0x1E04, // LATIN CAPITAL LETTER B WITH DOT BELOW\n\t0x1E05, 'B', // LATIN CAPITAL LETTER B WITH DOT BELOW\n\t// 0x1E07, 0x1E06, // LATIN CAPITAL LETTER B WITH LINE BELOW\n\t0x1E07, 'B', // LATIN CAPITAL LETTER B WITH LINE BELOW\n\t// 0x1E09, 0x1E08, // LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE\n\t0x1E09, 'C', // LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE\n\t// 0x1E0B, 0x1E0A, // LATIN CAPITAL LETTER D WITH DOT ABOVE\n\t0x1E0B, 'D', // LATIN CAPITAL LETTER D WITH DOT ABOVE\n\t// 0x1E0D, 0x1E0C, // LATIN CAPITAL LETTER D WITH DOT BELOW\n\t0x1E0D, 'D', // LATIN CAPITAL LETTER D WITH DOT BELOW\n\t// 0x1E0F, 0x1E0E, // LATIN CAPITAL LETTER D WITH LINE BELOW\n\t0x1E0F, 'D', // LATIN CAPITAL LETTER D WITH LINE BELOW\n\t// 0x1E11, 0x1E10, // LATIN CAPITAL LETTER D WITH CEDILLA\n\t0x1E11, 'D', // LATIN CAPITAL LETTER D WITH CEDILLA\n\t// 0x1E13, 0x1E12, // LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW\n\t0x1E13, 'D', // LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW\n\t// 0x1E15, 0x1E14, // LATIN CAPITAL LETTER E WITH MACRON AND GRAVE\n\t0x1E15, 'E', // LATIN CAPITAL LETTER E WITH MACRON AND GRAVE\n\t// 0x1E17, 0x1E16, // LATIN CAPITAL LETTER E WITH MACRON AND ACUTE\n\t0x1E17, 'E', // LATIN CAPITAL LETTER E WITH MACRON AND ACUTE\n\t// 0x1E19, 0x1E18, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW\n\t0x1E19, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW\n\t// 0x1E1B, 0x1E1A, // LATIN CAPITAL LETTER E WITH TILDE BELOW\n\t0x1E1B, 'E', // LATIN CAPITAL LETTER E WITH TILDE BELOW\n\t// 0x1E1D, 0x1E1C, // LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE\n\t0x1E1D, 'E', // LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE\n\t// 0x1E1F, 0x1E1E, // LATIN CAPITAL LETTER F WITH DOT ABOVE\n\t0x1E1F, 'F', // LATIN CAPITAL LETTER F WITH DOT ABOVE\n\t// 0x1E21, 0x1E20, // LATIN CAPITAL LETTER G WITH MACRON\n\t0x1E21, 'G', // LATIN CAPITAL LETTER G WITH MACRON\n\t// 0x1E23, 0x1E22, // LATIN CAPITAL LETTER H WITH DOT ABOVE\n\t0x1E23, 'H', // LATIN CAPITAL LETTER H WITH DOT ABOVE\n\t// 0x1E25, 0x1E24, // LATIN CAPITAL LETTER H WITH DOT BELOW\n\t0x1E25, 'H', // LATIN CAPITAL LETTER H WITH DOT BELOW\n\t// 0x1E27, 0x1E26, // LATIN CAPITAL LETTER H WITH DIAERESIS\n\t0x1E27, 'H', // LATIN CAPITAL LETTER H WITH DIAERESIS\n\t// 0x1E29, 0x1E28, // LATIN CAPITAL LETTER H WITH CEDILLA\n\t0x1E29, 'H', // LATIN CAPITAL LETTER H WITH CEDILLA\n\t// 0x1E2B, 0x1E2A, // LATIN CAPITAL LETTER H WITH BREVE BELOW\n\t0x1E2B, 'H', // LATIN CAPITAL LETTER H WITH BREVE BELOW\n\t// 0x1E2D, 0x1E2C, // LATIN CAPITAL LETTER I WITH TILDE BELOW\n\t0x1E2D, 'I', // LATIN CAPITAL LETTER I WITH TILDE BELOW\n\t// 0x1E2F, 0x1E2E, // LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE\n\t0x1E2F, 'I', // LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE\n\t// 0x1E31, 0x1E30, // LATIN CAPITAL LETTER K WITH ACUTE\n\t0x1E31, 'K', // LATIN CAPITAL LETTER K WITH ACUTE\n\t// 0x1E33, 0x1E32, // LATIN CAPITAL LETTER K WITH DOT BELOW\n\t0x1E33, 'K', // LATIN CAPITAL LETTER K WITH DOT BELOW\n\t// 0x1E35, 0x1E34, // LATIN CAPITAL LETTER K WITH LINE BELOW\n\t0x1E35, 'K', // LATIN CAPITAL LETTER K WITH LINE BELOW\n\t// 0x1E37, 0x1E36, // LATIN CAPITAL LETTER L WITH DOT BELOW\n\t0x1E37, 'L', // LATIN CAPITAL LETTER L WITH DOT BELOW\n\t// 0x1E39, 0x1E38, // LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON\n\t0x1E39, 'L', // LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON\n\t// 0x1E3B, 0x1E3A, // LATIN CAPITAL LETTER L WITH LINE BELOW\n\t0x1E3B, 'L', // LATIN CAPITAL LETTER L WITH LINE BELOW\n\t// 0x1E3D, 0x1E3C, // LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW\n\t0x1E3D, 'L', // LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW\n\t// 0x1E3F, 0x1E3E, // LATIN CAPITAL LETTER M WITH ACUTE\n\t0x1E3F, 'M', // LATIN CAPITAL LETTER M WITH ACUTE\n\t// 0x1E41, 0x1E40, // LATIN CAPITAL LETTER M WITH DOT ABOVE\n\t0x1E41, 'M', // LATIN CAPITAL LETTER M WITH DOT ABOVE\n\t// 0x1E43, 0x1E42, // LATIN CAPITAL LETTER M WITH DOT BELOW\n\t0x1E43, 'M', // LATIN CAPITAL LETTER M WITH DOT BELOW\n\t// 0x1E45, 0x1E44, // LATIN CAPITAL LETTER N WITH DOT ABOVE\n\t0x1E45, 'N', // LATIN CAPITAL LETTER N WITH DOT ABOVE\n\t// 0x1E47, 0x1E46, // LATIN CAPITAL LETTER N WITH DOT BELOW\n\t0x1E47, 'N', // LATIN CAPITAL LETTER N WITH DOT BELOW\n\t// 0x1E49, 0x1E48, // LATIN CAPITAL LETTER N WITH LINE BELOW\n\t0x1E49, 'N', // LATIN CAPITAL LETTER N WITH LINE BELOW\n\t// 0x1E4B, 0x1E4A, // LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW\n\t0x1E4B, 'N', // LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW\n\t// 0x1E4D, 0x1E4C, // LATIN CAPITAL LETTER O WITH TILDE AND ACUTE\n\t0x1E4D, 'O', // LATIN CAPITAL LETTER O WITH TILDE AND ACUTE\n\t// 0x1E4F, 0x1E4E, // LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS\n\t0x1E4F, 'O', // LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS\n\t// 0x1E51, 0x1E50, // LATIN CAPITAL LETTER O WITH MACRON AND GRAVE\n\t0x1E51, 'O', // LATIN CAPITAL LETTER O WITH MACRON AND GRAVE\n\t// 0x1E53, 0x1E52, // LATIN CAPITAL LETTER O WITH MACRON AND ACUTE\n\t0x1E53, 'O', // LATIN CAPITAL LETTER O WITH MACRON AND ACUTE\n\t// 0x1E55, 0x1E54, // LATIN CAPITAL LETTER P WITH ACUTE\n\t0x1E55, 'P', // LATIN CAPITAL LETTER P WITH ACUTE\n\t// 0x1E57, 0x1E56, // LATIN CAPITAL LETTER P WITH DOT ABOVE\n\t0x1E57, 'P', // LATIN CAPITAL LETTER P WITH DOT ABOVE\n\t// 0x1E59, 0x1E58, // LATIN CAPITAL LETTER R WITH DOT ABOVE\n\t0x1E59, 'R', // LATIN CAPITAL LETTER R WITH DOT ABOVE\n\t// 0x1E5B, 0x1E5A, // LATIN CAPITAL LETTER R WITH DOT BELOW\n\t0x1E5B, 'R', // LATIN CAPITAL LETTER R WITH DOT BELOW\n\t// 0x1E5D, 0x1E5C, // LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON\n\t0x1E5D, 'R', // LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON\n\t// 0x1E5F, 0x1E5E, // LATIN CAPITAL LETTER R WITH LINE BELOW\n\t0x1E5F, 'R', // LATIN CAPITAL LETTER R WITH LINE BELOW\n\t// 0x1E61, 0x1E60, // LATIN CAPITAL LETTER S WITH DOT ABOVE\n\t0x1E61, 'S', // LATIN CAPITAL LETTER S WITH DOT ABOVE\n\t// 0x1E63, 0x1E62, // LATIN CAPITAL LETTER S WITH DOT BELOW\n\t0x1E63, 'S', // LATIN CAPITAL LETTER S WITH DOT BELOW\n\t// 0x1E65, 0x1E64, // LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE\n\t0x1E65, 'S', // LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE\n\t// 0x1E67, 0x1E66, // LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE\n\t0x1E67, 'S', // LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE\n\t// 0x1E69, 0x1E68, // LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE\n\t0x1E69, 'S', // LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE\n\t// 0x1E6B, 0x1E6A, // LATIN CAPITAL LETTER T WITH DOT ABOVE\n\t0x1E6B, 'T', // LATIN CAPITAL LETTER T WITH DOT ABOVE\n\t// 0x1E6D, 0x1E6C, // LATIN CAPITAL LETTER T WITH DOT BELOW\n\t0x1E6D, 'T', // LATIN CAPITAL LETTER T WITH DOT BELOW\n\t// 0x1E6F, 0x1E6E, // LATIN CAPITAL LETTER T WITH LINE BELOW\n\t0x1E6F, 'T', // LATIN CAPITAL LETTER T WITH LINE BELOW\n\t// 0x1E71, 0x1E70, // LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW\n\t0x1E71, 'T', // LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW\n\t// 0x1E73, 0x1E72, // LATIN CAPITAL LETTER U WITH DIAERESIS BELOW\n\t0x1E73, 'U', // LATIN CAPITAL LETTER U WITH DIAERESIS BELOW\n\t// 0x1E75, 0x1E74, // LATIN CAPITAL LETTER U WITH TILDE BELOW\n\t0x1E75, 'U', // LATIN CAPITAL LETTER U WITH TILDE BELOW\n\t// 0x1E77, 0x1E76, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW\n\t0x1E77, 'U', // LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW\n\t// 0x1E79, 0x1E78, // LATIN CAPITAL LETTER U WITH TILDE AND ACUTE\n\t0x1E79, 'U', // LATIN CAPITAL LETTER U WITH TILDE AND ACUTE\n\t// 0x1E7B, 0x1E7A, // LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS\n\t0x1E7B, 'U', // LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS\n\t// 0x1E7D, 0x1E7C, // LATIN CAPITAL LETTER V WITH TILDE\n\t0x1E7D, 'V', // LATIN CAPITAL LETTER V WITH TILDE\n\t// 0x1E7F, 0x1E7E, // LATIN CAPITAL LETTER V WITH DOT BELOW\n\t0x1E7F, 'V', // LATIN CAPITAL LETTER V WITH DOT BELOW\n\t// 0x1E81, 0x1E80, // LATIN CAPITAL LETTER W WITH GRAVE\n\t0x1E81, 'W', // LATIN CAPITAL LETTER W WITH GRAVE\n\t// 0x1E83, 0x1E82, // LATIN CAPITAL LETTER W WITH ACUTE\n\t0x1E83, 'W', // LATIN CAPITAL LETTER W WITH ACUTE\n\t// 0x1E85, 0x1E84, // LATIN CAPITAL LETTER W WITH DIAERESIS\n\t0x1E85, 'W', // LATIN CAPITAL LETTER W WITH DIAERESIS\n\t// 0x1E87, 0x1E86, // LATIN CAPITAL LETTER W WITH DOT ABOVE\n\t0x1E87, 'W', // LATIN CAPITAL LETTER W WITH DOT ABOVE\n\t// 0x1E89, 0x1E88, // LATIN CAPITAL LETTER W WITH DOT BELOW\n\t0x1E89, 'W', // LATIN CAPITAL LETTER W WITH DOT BELOW\n\t// 0x1E8B, 0x1E8A, // LATIN CAPITAL LETTER X WITH DOT ABOVE\n\t0x1E8B, 'X', // LATIN CAPITAL LETTER X WITH DOT ABOVE\n\t// 0x1E8D, 0x1E8C, // LATIN CAPITAL LETTER X WITH DIAERESIS\n\t0x1E8D, 'X', // LATIN CAPITAL LETTER X WITH DIAERESIS\n\t// 0x1E8F, 0x1E8E, // LATIN CAPITAL LETTER Y WITH DOT ABOVE\n\t0x1E8F, 'Y', // LATIN CAPITAL LETTER Y WITH DOT ABOVE\n\t// 0x1E91, 0x1E90, // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX\n\t0x1E91, 'Z', // LATIN CAPITAL LETTER Z WITH CIRCUMFLEX\n\t// 0x1E93, 0x1E92, // LATIN CAPITAL LETTER Z WITH DOT BELOW\n\t0x1E93, 'Z', // LATIN CAPITAL LETTER Z WITH DOT BELOW\n\t// 0x1E95, 0x1E94, // LATIN CAPITAL LETTER Z WITH LINE BELOW\n\t0x1E95, 'Z', // LATIN CAPITAL LETTER Z WITH LINE BELOW\n\t// 0x1EA1, 0x1EA0, // LATIN CAPITAL LETTER A WITH DOT BELOW\n\t0x1EA1, 'A', // LATIN CAPITAL LETTER A WITH DOT BELOW\n\t// 0x1EA3, 0x1EA2, // LATIN CAPITAL LETTER A WITH HOOK ABOVE\n\t0x1EA3, 'A', // LATIN CAPITAL LETTER A WITH HOOK ABOVE\n\t// 0x1EA5, 0x1EA4, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE\n\t0x1EA5, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE\n\t// 0x1EA7, 0x1EA6, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE\n\t0x1EA7, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE\n\t// 0x1EA9, 0x1EA8, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1EA9, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE\n\t// 0x1EAB, 0x1EAA, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE\n\t0x1EAB, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE\n\t// 0x1EAD, 0x1EAC, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW\n\t0x1EAD, 'A', // LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW\n\t// 0x1EAF, 0x1EAE, // LATIN CAPITAL LETTER A WITH BREVE AND ACUTE\n\t0x1EAF, 'A', // LATIN CAPITAL LETTER A WITH BREVE AND ACUTE\n\t// 0x1EB1, 0x1EB0, // LATIN CAPITAL LETTER A WITH BREVE AND GRAVE\n\t0x1EB1, 'A', // LATIN CAPITAL LETTER A WITH BREVE AND GRAVE\n\t// 0x1EB3, 0x1EB2, // LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE\n\t0x1EB3, 'A', // LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE\n\t// 0x1EB5, 0x1EB4, // LATIN CAPITAL LETTER A WITH BREVE AND TILDE\n\t0x1EB5, 'A', // LATIN CAPITAL LETTER A WITH BREVE AND TILDE\n\t// 0x1EB7, 0x1EB6, // LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW\n\t0x1EB7, 'A', // LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW\n\t// 0x1EB9, 0x1EB8, // LATIN CAPITAL LETTER E WITH DOT BELOW\n\t0x1EB9, 'E', // LATIN CAPITAL LETTER E WITH DOT BELOW\n\t// 0x1EBB, 0x1EBA, // LATIN CAPITAL LETTER E WITH HOOK ABOVE\n\t0x1EBB, 'E', // LATIN CAPITAL LETTER E WITH HOOK ABOVE\n\t// 0x1EBD, 0x1EBC, // LATIN CAPITAL LETTER E WITH TILDE\n\t0x1EBD, 'E', // LATIN CAPITAL LETTER E WITH TILDE\n\t// 0x1EBF, 0x1EBE, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE\n\t0x1EBF, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE\n\t// 0x1EC1, 0x1EC0, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE\n\t0x1EC1, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE\n\t// 0x1EC3, 0x1EC2, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1EC3, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE\n\t// 0x1EC5, 0x1EC4, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE\n\t0x1EC5, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE\n\t// 0x1EC7, 0x1EC6, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW\n\t0x1EC7, 'E', // LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW\n\t// 0x1EC9, 0x1EC8, // LATIN CAPITAL LETTER I WITH HOOK ABOVE\n\t0x1EC9, 'I', // LATIN CAPITAL LETTER I WITH HOOK ABOVE\n\t// 0x1ECB, 0x1ECA, // LATIN CAPITAL LETTER I WITH DOT BELOW\n\t0x1ECB, 'I', // LATIN CAPITAL LETTER I WITH DOT BELOW\n\t// 0x1ECD, 0x1ECC, // LATIN CAPITAL LETTER O WITH DOT BELOW\n\t0x1ECD, 'O', // LATIN CAPITAL LETTER O WITH DOT BELOW\n\t// 0x1ECF, 0x1ECE, // LATIN CAPITAL LETTER O WITH HOOK ABOVE\n\t0x1ECF, 'O', // LATIN CAPITAL LETTER O WITH HOOK ABOVE\n\t// 0x1ED1, 0x1ED0, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE\n\t0x1ED1, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE\n\t// 0x1ED3, 0x1ED2, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE\n\t0x1ED3, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE\n\t// 0x1ED5, 0x1ED4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE\n\t0x1ED5, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE\n\t// 0x1ED7, 0x1ED6, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE\n\t0x1ED7, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE\n\t// 0x1ED9, 0x1ED8, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW\n\t0x1ED9, 'O', // LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW\n\t// 0x1EDB, 0x1EDA, // LATIN CAPITAL LETTER O WITH HORN AND ACUTE\n\t0x1EDB, 'O', // LATIN CAPITAL LETTER O WITH HORN AND ACUTE\n\t// 0x1EDD, 0x1EDC, // LATIN CAPITAL LETTER O WITH HORN AND GRAVE\n\t0x1EDD, 'O', // LATIN CAPITAL LETTER O WITH HORN AND GRAVE\n\t// 0x1EDF, 0x1EDE, // LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE\n\t0x1EDF, 'O', // LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE\n\t// 0x1EE1, 0x1EE0, // LATIN CAPITAL LETTER O WITH HORN AND TILDE\n\t0x1EE1, 'O', // LATIN CAPITAL LETTER O WITH HORN AND TILDE\n\t// 0x1EE3, 0x1EE2, // LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW\n\t0x1EE3, 'O', // LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW\n\t// 0x1EE5, 0x1EE4, // LATIN CAPITAL LETTER U WITH DOT BELOW\n\t0x1EE5, 'U', // LATIN CAPITAL LETTER U WITH DOT BELOW\n\t// 0x1EE7, 0x1EE6, // LATIN CAPITAL LETTER U WITH HOOK ABOVE\n\t0x1EE7, 'U', // LATIN CAPITAL LETTER U WITH HOOK ABOVE\n\t// 0x1EE9, 0x1EE8, // LATIN CAPITAL LETTER U WITH HORN AND ACUTE\n\t0x1EE9, 'U', // LATIN CAPITAL LETTER U WITH HORN AND ACUTE\n\t// 0x1EEB, 0x1EEA, // LATIN CAPITAL LETTER U WITH HORN AND GRAVE\n\t0x1EEB, 'U', // LATIN CAPITAL LETTER U WITH HORN AND GRAVE\n\t// 0x1EED, 0x1EEC, // LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE\n\t0x1EED, 'U', // LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE\n\t// 0x1EEF, 0x1EEE, // LATIN CAPITAL LETTER U WITH HORN AND TILDE\n\t0x1EEF, 'U', // LATIN CAPITAL LETTER U WITH HORN AND TILDE\n\t// 0x1EF1, 0x1EF0, // LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW\n\t0x1EF1, 'U', // LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW\n\t// 0x1EF3, 0x1EF2, // LATIN CAPITAL LETTER Y WITH GRAVE\n\t0x1EF3, 'Y', // LATIN CAPITAL LETTER Y WITH GRAVE\n\t// 0x1EF5, 0x1EF4, // LATIN CAPITAL LETTER Y WITH DOT BELOW\n\t0x1EF5, 'Y', // LATIN CAPITAL LETTER Y WITH DOT BELOW\n\t// 0x1EF7, 0x1EF6, // LATIN CAPITAL LETTER Y WITH HOOK ABOVE\n\t0x1EF7, 'Y', // LATIN CAPITAL LETTER Y WITH HOOK ABOVE\n\t// 0x1EF9, 0x1EF8, // LATIN CAPITAL LETTER Y WITH TILDE\n\t0x1EF9, 'Y', // LATIN CAPITAL LETTER Y WITH TILDE\n\t0x1F00, 0x1F08, // GREEK CAPITAL LETTER ALPHA WITH PSILI\n\t0x1F01, 0x1F09, // GREEK CAPITAL LETTER ALPHA WITH DASIA\n\t0x1F02, 0x1F0A, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA\n\t0x1F03, 0x1F0B, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA\n\t0x1F04, 0x1F0C, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA\n\t0x1F05, 0x1F0D, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA\n\t0x1F06, 0x1F0E, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI\n\t0x1F07, 0x1F0F, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI\n\t0x1F10, 0x1F18, // GREEK CAPITAL LETTER EPSILON WITH PSILI\n\t0x1F11, 0x1F19, // GREEK CAPITAL LETTER EPSILON WITH DASIA\n\t0x1F12, 0x1F1A, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA\n\t0x1F13, 0x1F1B, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA\n\t0x1F14, 0x1F1C, // GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA\n\t0x1F15, 0x1F1D, // GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA\n\t0x1F20, 0x1F28, // GREEK CAPITAL LETTER ETA WITH PSILI\n\t0x1F21, 0x1F29, // GREEK CAPITAL LETTER ETA WITH DASIA\n\t0x1F22, 0x1F2A, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA\n\t0x1F23, 0x1F2B, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA\n\t0x1F24, 0x1F2C, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA\n\t0x1F25, 0x1F2D, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA\n\t0x1F26, 0x1F2E, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI\n\t0x1F27, 0x1F2F, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI\n\t0x1F30, 0x1F38, // GREEK CAPITAL LETTER IOTA WITH PSILI\n\t0x1F31, 0x1F39, // GREEK CAPITAL LETTER IOTA WITH DASIA\n\t0x1F32, 0x1F3A, // GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA\n\t0x1F33, 0x1F3B, // GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA\n\t0x1F34, 0x1F3C, // GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA\n\t0x1F35, 0x1F3D, // GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA\n\t0x1F36, 0x1F3E, // GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI\n\t0x1F37, 0x1F3F, // GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI\n\t0x1F40, 0x1F48, // GREEK CAPITAL LETTER OMICRON WITH PSILI\n\t0x1F41, 0x1F49, // GREEK CAPITAL LETTER OMICRON WITH DASIA\n\t0x1F42, 0x1F4A, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA\n\t0x1F43, 0x1F4B, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA\n\t0x1F44, 0x1F4C, // GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA\n\t0x1F45, 0x1F4D, // GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA\n\t0x1F51, 0x1F59, // GREEK CAPITAL LETTER UPSILON WITH DASIA\n\t0x1F53, 0x1F5B, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA\n\t0x1F55, 0x1F5D, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA\n\t0x1F57, 0x1F5F, // GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI\n\t0x1F60, 0x1F68, // GREEK CAPITAL LETTER OMEGA WITH PSILI\n\t0x1F61, 0x1F69, // GREEK CAPITAL LETTER OMEGA WITH DASIA\n\t0x1F62, 0x1F6A, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA\n\t0x1F63, 0x1F6B, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA\n\t0x1F64, 0x1F6C, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA\n\t0x1F65, 0x1F6D, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA\n\t0x1F66, 0x1F6E, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI\n\t0x1F67, 0x1F6F, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI\n\t0x1F70, 0x1FBA, // GREEK CAPITAL LETTER ALPHA WITH VARIA\n\t0x1F71, 0x1FBB, // GREEK CAPITAL LETTER ALPHA WITH OXIA\n\t0x1F72, 0x1FC8, // GREEK CAPITAL LETTER EPSILON WITH VARIA\n\t0x1F73, 0x1FC9, // GREEK CAPITAL LETTER EPSILON WITH OXIA\n\t0x1F74, 0x1FCA, // GREEK CAPITAL LETTER ETA WITH VARIA\n\t0x1F75, 0x1FCB, // GREEK CAPITAL LETTER ETA WITH OXIA\n\t0x1F76, 0x1FDA, // GREEK CAPITAL LETTER IOTA WITH VARIA\n\t0x1F77, 0x1FDB, // GREEK CAPITAL LETTER IOTA WITH OXIA\n\t0x1F78, 0x1FF8, // GREEK CAPITAL LETTER OMICRON WITH VARIA\n\t0x1F79, 0x1FF9, // GREEK CAPITAL LETTER OMICRON WITH OXIA\n\t0x1F7A, 0x1FEA, // GREEK CAPITAL LETTER UPSILON WITH VARIA\n\t0x1F7B, 0x1FEB, // GREEK CAPITAL LETTER UPSILON WITH OXIA\n\t0x1F7C, 0x1FFA, // GREEK CAPITAL LETTER OMEGA WITH VARIA\n\t0x1F7D, 0x1FFB, // GREEK CAPITAL LETTER OMEGA WITH OXIA\n\t0x1F80, 0x1F88, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI\n\t0x1F81, 0x1F89, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI\n\t0x1F82, 0x1F8A, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1F83, 0x1F8B, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1F84, 0x1F8C, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1F85, 0x1F8D, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1F86, 0x1F8E, // GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F87, 0x1F8F, // GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F90, 0x1F98, // GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI\n\t0x1F91, 0x1F99, // GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI\n\t0x1F92, 0x1F9A, // GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1F93, 0x1F9B, // GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1F94, 0x1F9C, // GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1F95, 0x1F9D, // GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1F96, 0x1F9E, // GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1F97, 0x1F9F, // GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FA0, 0x1FA8, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI\n\t0x1FA1, 0x1FA9, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI\n\t0x1FA2, 0x1FAA, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI\n\t0x1FA3, 0x1FAB, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI\n\t0x1FA4, 0x1FAC, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI\n\t0x1FA5, 0x1FAD, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI\n\t0x1FA6, 0x1FAE, // GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FA7, 0x1FAF, // GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI\n\t0x1FB0, 0x1FB8, // GREEK CAPITAL LETTER ALPHA WITH VRACHY\n\t0x1FB1, 0x1FB9, // GREEK CAPITAL LETTER ALPHA WITH MACRON\n\t0x1FB3, 0x1FBC, // GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI\n\t0x1FC3, 0x1FCC, // GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI\n\t0x1FD0, 0x1FD8, // GREEK CAPITAL LETTER IOTA WITH VRACHY\n\t0x1FD1, 0x1FD9, // GREEK CAPITAL LETTER IOTA WITH MACRON\n\t0x1FE0, 0x1FE8, // GREEK CAPITAL LETTER UPSILON WITH VRACHY\n\t0x1FE1, 0x1FE9, // GREEK CAPITAL LETTER UPSILON WITH MACRON\n\t0x1FE5, 0x1FEC, // GREEK CAPITAL LETTER RHO WITH DASIA\n\t0x1FF3, 0x1FFC, // GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI\n\t0x2170, 0x2160, // ROMAN NUMERAL ONE\n\t0x2171, 0x2161, // ROMAN NUMERAL TWO\n\t0x2172, 0x2162, // ROMAN NUMERAL THREE\n\t0x2173, 0x2163, // ROMAN NUMERAL FOUR\n\t0x2174, 0x2164, // ROMAN NUMERAL FIVE\n\t0x2175, 0x2165, // ROMAN NUMERAL SIX\n\t0x2176, 0x2166, // ROMAN NUMERAL SEVEN\n\t0x2177, 0x2167, // ROMAN NUMERAL EIGHT\n\t0x2178, 0x2168, // ROMAN NUMERAL NINE\n\t0x2179, 0x2169, // ROMAN NUMERAL TEN\n\t0x217A, 0x216A, // ROMAN NUMERAL ELEVEN\n\t0x217B, 0x216B, // ROMAN NUMERAL TWELVE\n\t0x217C, 0x216C, // ROMAN NUMERAL FIFTY\n\t0x217D, 0x216D, // ROMAN NUMERAL ONE HUNDRED\n\t0x217E, 0x216E, // ROMAN NUMERAL FIVE HUNDRED\n\t0x217F, 0x216F, // ROMAN NUMERAL ONE THOUSAND\n\t// 0x24D0, 0x24B6, // CIRCLED LATIN CAPITAL LETTER A\n\t0x24D0, 'A', // CIRCLED LATIN CAPITAL LETTER A\n\t// 0x24D1, 0x24B7, // CIRCLED LATIN CAPITAL LETTER B\n\t0x24D1, 'B', // CIRCLED LATIN CAPITAL LETTER B\n\t// 0x24D2, 0x24B8, // CIRCLED LATIN CAPITAL LETTER C\n\t0x24D2, 'C', // CIRCLED LATIN CAPITAL LETTER C\n\t// 0x24D3, 0x24B9, // CIRCLED LATIN CAPITAL LETTER D\n\t0x24D3, 'D', // CIRCLED LATIN CAPITAL LETTER D\n\t// 0x24D4, 0x24BA, // CIRCLED LATIN CAPITAL LETTER E\n\t0x24D4, 'E', // CIRCLED LATIN CAPITAL LETTER E\n\t// 0x24D5, 0x24BB, // CIRCLED LATIN CAPITAL LETTER F\n\t0x24D5, 'F', // CIRCLED LATIN CAPITAL LETTER F\n\t// 0x24D6, 0x24BC, // CIRCLED LATIN CAPITAL LETTER G\n\t0x24D6, 'G', // CIRCLED LATIN CAPITAL LETTER G\n\t// 0x24D7, 0x24BD, // CIRCLED LATIN CAPITAL LETTER H\n\t0x24D7, 'H', // CIRCLED LATIN CAPITAL LETTER H\n\t// 0x24D8, 0x24BE, // CIRCLED LATIN CAPITAL LETTER I\n\t0x24D8, 'I', // CIRCLED LATIN CAPITAL LETTER I\n\t// 0x24D9, 0x24BF, // CIRCLED LATIN CAPITAL LETTER J\n\t0x24D9, 'J', // CIRCLED LATIN CAPITAL LETTER J\n\t// 0x24DA, 0x24C0, // CIRCLED LATIN CAPITAL LETTER K\n\t0x24DA, 'K', // CIRCLED LATIN CAPITAL LETTER K\n\t// 0x24DB, 0x24C1, // CIRCLED LATIN CAPITAL LETTER L\n\t0x24DB, 'L', // CIRCLED LATIN CAPITAL LETTER L\n\t// 0x24DC, 0x24C2, // CIRCLED LATIN CAPITAL LETTER M\n\t0x24DC, 'M', // CIRCLED LATIN CAPITAL LETTER M\n\t// 0x24DD, 0x24C3, // CIRCLED LATIN CAPITAL LETTER N\n\t0x24DD, 'N', // CIRCLED LATIN CAPITAL LETTER N\n\t// 0x24DE, 0x24C4, // CIRCLED LATIN CAPITAL LETTER O\n\t0x24DE, 'O', // CIRCLED LATIN CAPITAL LETTER O\n\t// 0x24DF, 0x24C5, // CIRCLED LATIN CAPITAL LETTER P\n\t0x24DF, 'P', // CIRCLED LATIN CAPITAL LETTER P\n\t// 0x24E0, 0x24C6, // CIRCLED LATIN CAPITAL LETTER Q\n\t0x24E0, 'Q', // CIRCLED LATIN CAPITAL LETTER Q\n\t// 0x24E1, 0x24C7, // CIRCLED LATIN CAPITAL LETTER R\n\t0x24E1, 'R', // CIRCLED LATIN CAPITAL LETTER R\n\t// 0x24E2, 0x24C8, // CIRCLED LATIN CAPITAL LETTER S\n\t0x24E2, 'S', // CIRCLED LATIN CAPITAL LETTER S\n\t// 0x24E3, 0x24C9, // CIRCLED LATIN CAPITAL LETTER T\n\t0x24E3, 'T', // CIRCLED LATIN CAPITAL LETTER T\n\t// 0x24E4, 0x24CA, // CIRCLED LATIN CAPITAL LETTER U\n\t0x24E4, 'U', // CIRCLED LATIN CAPITAL LETTER U\n\t// 0x24E5, 0x24CB, // CIRCLED LATIN CAPITAL LETTER V\n\t0x24E5, 'V', // CIRCLED LATIN CAPITAL LETTER V\n\t// 0x24E6, 0x24CC, // CIRCLED LATIN CAPITAL LETTER W\n\t0x24E6, 'W', // CIRCLED LATIN CAPITAL LETTER W\n\t// 0x24E7, 0x24CD, // CIRCLED LATIN CAPITAL LETTER X\n\t0x24E7, 'X', // CIRCLED LATIN CAPITAL LETTER X\n\t// 0x24E8, 0x24CE, // CIRCLED LATIN CAPITAL LETTER Y\n\t0x24E8, 'Y', // CIRCLED LATIN CAPITAL LETTER Y\n\t// 0x24E9, 0x24CF, // CIRCLED LATIN CAPITAL LETTER Z\n\t0x24E9, 'Z', // CIRCLED LATIN CAPITAL LETTER Z\n\t// 0xFF41, 0xFF21, // FULLWIDTH LATIN CAPITAL LETTER A\n\t0xFF41, 'A', // FULLWIDTH LATIN CAPITAL LETTER A\n\t// 0xFF42, 0xFF22, // FULLWIDTH LATIN CAPITAL LETTER B\n\t0xFF42, 'B', // FULLWIDTH LATIN CAPITAL LETTER B\n\t// 0xFF43, 0xFF23, // FULLWIDTH LATIN CAPITAL LETTER C\n\t0xFF43, 'C', // FULLWIDTH LATIN CAPITAL LETTER C\n\t// 0xFF44, 0xFF24, // FULLWIDTH LATIN CAPITAL LETTER D\n\t0xFF44, 'D', // FULLWIDTH LATIN CAPITAL LETTER D\n\t// 0xFF45, 0xFF25, // FULLWIDTH LATIN CAPITAL LETTER E\n\t0xFF45, 'E', // FULLWIDTH LATIN CAPITAL LETTER E\n\t// 0xFF46, 0xFF26, // FULLWIDTH LATIN CAPITAL LETTER F\n\t0xFF46, 'F', // FULLWIDTH LATIN CAPITAL LETTER F\n\t// 0xFF47, 0xFF27, // FULLWIDTH LATIN CAPITAL LETTER G\n\t0xFF47, 'G', // FULLWIDTH LATIN CAPITAL LETTER G\n\t// 0xFF48, 0xFF28, // FULLWIDTH LATIN CAPITAL LETTER H\n\t0xFF48, 'H', // FULLWIDTH LATIN CAPITAL LETTER H\n\t// 0xFF49, 0xFF29, // FULLWIDTH LATIN CAPITAL LETTER I\n\t0xFF49, 'I', // FULLWIDTH LATIN CAPITAL LETTER I\n\t// 0xFF4A, 0xFF2A, // FULLWIDTH LATIN CAPITAL LETTER J\n\t0xFF4A, 'J', // FULLWIDTH LATIN CAPITAL LETTER J\n\t// 0xFF4B, 0xFF2B, // FULLWIDTH LATIN CAPITAL LETTER K\n\t0xFF4B, 'K', // FULLWIDTH LATIN CAPITAL LETTER K\n\t// 0xFF4C, 0xFF2C, // FULLWIDTH LATIN CAPITAL LETTER L\n\t0xFF4C, 'L', // FULLWIDTH LATIN CAPITAL LETTER L\n\t// 0xFF4D, 0xFF2D, // FULLWIDTH LATIN CAPITAL LETTER M\n\t0xFF4D, 'M', // FULLWIDTH LATIN CAPITAL LETTER M\n\t// 0xFF4E, 0xFF2E, // FULLWIDTH LATIN CAPITAL LETTER N\n\t0xFF4E, 'N', // FULLWIDTH LATIN CAPITAL LETTER N\n\t// 0xFF4F, 0xFF2F, // FULLWIDTH LATIN CAPITAL LETTER O\n\t0xFF4F, 'O', // FULLWIDTH LATIN CAPITAL LETTER O\n\t// 0xFF50, 0xFF30, // FULLWIDTH LATIN CAPITAL LETTER P\n\t0xFF50, 'P', // FULLWIDTH LATIN CAPITAL LETTER P\n\t// 0xFF51, 0xFF31, // FULLWIDTH LATIN CAPITAL LETTER Q\n\t0xFF51, 'Q', // FULLWIDTH LATIN CAPITAL LETTER Q\n\t// 0xFF52, 0xFF32, // FULLWIDTH LATIN CAPITAL LETTER R\n\t0xFF52, 'R', // FULLWIDTH LATIN CAPITAL LETTER R\n\t// 0xFF53, 0xFF33, // FULLWIDTH LATIN CAPITAL LETTER S\n\t0xFF53, 'S', // FULLWIDTH LATIN CAPITAL LETTER S\n\t// 0xFF54, 0xFF34, // FULLWIDTH LATIN CAPITAL LETTER T\n\t0xFF54, 'T', // FULLWIDTH LATIN CAPITAL LETTER T\n\t// 0xFF55, 0xFF35, // FULLWIDTH LATIN CAPITAL LETTER U\n\t0xFF55, 'U', // FULLWIDTH LATIN CAPITAL LETTER U\n\t// 0xFF56, 0xFF36, // FULLWIDTH LATIN CAPITAL LETTER V\n\t0xFF56, 'V', // FULLWIDTH LATIN CAPITAL LETTER V\n\t// 0xFF57, 0xFF37, // FULLWIDTH LATIN CAPITAL LETTER W\n\t0xFF57, 'W', // FULLWIDTH LATIN CAPITAL LETTER W\n\t// 0xFF58, 0xFF38, // FULLWIDTH LATIN CAPITAL LETTER X\n\t0xFF58, 'X', // FULLWIDTH LATIN CAPITAL LETTER X\n\t// 0xFF59, 0xFF39, // FULLWIDTH LATIN CAPITAL LETTER Y\n\t0xFF59, 'Y', // FULLWIDTH LATIN CAPITAL LETTER Y\n\t// 0xFF5A, 0xFF3A, // FULLWIDTH LATIN CAPITAL LETTER Z\n\t0xFF5A, 'Z', // FULLWIDTH LATIN CAPITAL LETTER Z\n};\n\n// ***************************************************************************\n\nint toLowerUpperCompare(const void *arg1, const void *arg2)\n{\n\tucchar uc1 = *(ucchar *)arg1;\n\tucchar uc2 = *(ucchar *)arg2;\n\treturn (uc1<uc2)?-1:(uc1 > uc2)?1:0;\n}\n\n// ***************************************************************************\n\n/* This macro uses bsearch, it can be slow. If it is, a template (inline) version of bsearch working with pointers should be written */\n#define toLowerUpperSearch(value, table) ((ucchar *)bsearch( value, table, sizeof(table)/(2*sizeof(ucchar)), 2*sizeof(ucchar), toLowerUpperCompare))\n\n// ***************************************************************************\n\nucstring\ttoLower (const ucstring &str)\n{\n\tuint i;\n\tucstring temp = str;\n\tconst uint size = (uint)temp.size();\n\tfor (i=0; i<(uint)size; i++)\n\t{\n\t\t// Search the key in the table\n\t\tucchar *result = toLowerUpperSearch (&(temp[i]), UnicodeUpperToLower);\n\t\tif (result)\n\t\t\ttemp[i] = result[1];\n\t}\n\treturn temp;\n}\n\n// ***************************************************************************\n\nvoid\t\ttoLower (ucchar *str)\n{\n\twhile (*str)\n\t{\n\t\t// Search the key in the table\n\t\tucchar *result = toLowerUpperSearch (str, UnicodeUpperToLower);\n\t\tif (result)\n\t\t\t*str = result[1];\n\t\tstr++;\n\t}\n}\n\n// ***************************************************************************\n\nucchar\t\ttoLower (ucchar c)\n{\n\t// Search the key in the table\n\tucchar *result = toLowerUpperSearch (&c, UnicodeUpperToLower);\n\tif (result)\n\t\treturn result[1];\n\treturn c;\n}\n\n// ***************************************************************************\n\nucstring\ttoUpper (const ucstring &str)\n{\n\tuint i;\n\tucstring temp = str;\n\tconst uint size = (uint)temp.size();\n\tfor (i=0; i<size; i++)\n\t{\n\t\t// Search the key in the table\n\t\tucchar *result = toLowerUpperSearch (&(temp[i]), UnicodeLowerToUpper);\n\t\tif (result)\n\t\t\ttemp[i] = result[1];\n\t}\n\treturn temp;\n}\n\n// ***************************************************************************\n\nvoid\t\ttoUpper (ucchar *str)\n{\n\twhile (*str)\n\t{\n\t\t// Search the key in the table\n\t\tucchar *result = toLowerUpperSearch (str, UnicodeLowerToUpper);\n\t\tif (result)\n\t\t\t*str = result[1];\n\t\tstr++;\n\t}\n}\n\n// ***************************************************************************\n\nucchar\t\ttoUpper (ucchar c)\n{\n\t// Search the key in the table\n\tucchar *result = toLowerUpperSearch (&c, UnicodeLowerToUpper);\n\tif (result)\n\t\treturn result[1];\n\treturn c;\n}\n\n// ***************************************************************************\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/uv.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/uv.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_uv_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/value_smoother.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/value_smoother.h\"\n\n// remove stupid VC6 warnings\nvoid foo_value_smoother_cpp() {}\n"
  },
  {
    "path": "code/nel/src/misc/variable.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/variable.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\nvoid cbVarChanged (CConfigFile::CVar &cvar)\n{\n\tCCommandRegistry &cr = CCommandRegistry::getInstance();\n\tfor (CCommandRegistry::TCommand::iterator comm = cr._Commands.begin(); comm != cr._Commands.end(); comm++)\n\t{\n\t\tif (comm->second->Type == ICommand::Variable && comm->second->getName() == cvar.Name)\n\t\t{\n\t\t\tIVariable *var = static_cast<IVariable*>(comm->second);\n\t\t\tstring val = cvar.asString();\n\t\t\tnlinfo (\"VAR: Setting variable '%s' with value '%s' from config file\", cvar.Name.c_str(), val.c_str());\n\t\t\tvar->fromString(val, true);\n\t\t}\n\t}\n}\n\n\nvoid IVariable::init (NLMISC::CConfigFile &configFile)\n{\n\tCCommandRegistry::getInstance().initVariables(configFile);\n}\n\nvoid CCommandRegistry::initVariables(NLMISC::CConfigFile &configFile)\n{\n\tfor (TCommand::iterator comm = _Commands.begin(); comm != _Commands.end(); comm++)\n\t{\n\t\tif (comm->second->Type == ICommand::Variable)\n\t\t{\n\t\t\tIVariable *var = static_cast<IVariable *>(comm->second);\n\t\t\tif (var->_UseConfigFile)\n\t\t\t{\n\t\t\t\tconfigFile.setCallback(var->_CommandName, cbVarChanged);\n\t\t\t\tCConfigFile::CVar *cvar = configFile.getVarPtr(var->_CommandName);\n\t\t\t\tif (cvar != 0)\n\t\t\t\t{\n\t\t\t\t\tstring val = cvar->asString();\n\t\t\t\t\t//nldebug(\"VAR: Setting variable '%s' with value '%s' from config file '%s'\", var->_CommandName.c_str(), val.c_str(), configFile.getFilename().c_str());\n\t\t\t\t\tvar->fromString(val, true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t//nldebug(\"VAR: No variable '%s' in config file '%s'\", var->_CommandName.c_str(), configFile.getFilename().c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/vector.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include\t\"nel/misc/vector.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\nconst CVector\tCVector::Null(0,0,0);\nconst CVector\tCVector::I(1,0,0);\nconst CVector\tCVector::J(0,1,0);\nconst CVector\tCVector::K(0,0,1);\n\n\n/*\n * Returns the contents as a printable string \"x y z\"\n */\nstring CVector::toString() const\n{\n\tstring str;\n\tstr = NLMISC::toString(x) + \" \" + NLMISC::toString(y) + \" \" + NLMISC::toString(z);\n\treturn str;\n}\n\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/vector_2d.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/vector_2d.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_vector_2d_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/vector_2f.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/vector_2f.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\nconst CVector2f CVector2f::Null(0, 0);\n\n} // NLMISC\n\n\n"
  },
  {
    "path": "code/nel/src/misc/vector_h.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/vector_h.h\"\n\n\n// leave not static else this workaround don't work\nvoid\tdummyToAvoidStupidCompilerWarning_misc_vector_h_cpp()\n{\n}\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/vectord.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include\t\"nel/misc/vectord.h\"\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace\tNLMISC\n{\n\nconst CVectorD\tCVectorD::Null(0,0,0);\nconst CVectorD\tCVectorD::I(1,0,0);\nconst CVectorD\tCVectorD::J(0,1,0);\nconst CVectorD\tCVectorD::K(0,0,1);\n\n}\n\n"
  },
  {
    "path": "code/nel/src/misc/win32_util.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/win32_util.h\"\n#include \"nel/misc/i18n.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\n//*************************************************************************************\nvoid CWin32Util::localizeWindow(HWND wnd)\n{\n\tif (!wnd) return;\n\tint textLength = GetWindowTextLength(wnd);\n\tif (textLength > 0)\n\t{\n\t\tstd::vector<char> str(textLength + 1);\n\t\tGetWindowText(wnd, &str[0], textLength + 1);\n\t\tstd::string winText(str.begin(), str.end() - 1);\n\t\tif (CI18N::hasTranslation(winText))\n\t\t{\n\t\t\tSetWindowTextW(wnd, (const WCHAR *) CI18N::get(winText).c_str());\n\t\t}\n\t}\n\tHWND currSon = GetWindow(wnd, GW_CHILD);\n\tif (currSon)\n\t{\n\t\tHWND lastSon = GetWindow(currSon, GW_HWNDLAST);\n\t\tfor(;;)\n\t\t{\n\t\t\tlocalizeWindow(currSon);\n\t\t\tif (currSon == lastSon) break;\n\t\t\tcurrSon = GetWindow(currSon, GW_HWNDNEXT);\n\t\t}\n\t}\n}\n\n//*************************************************************************************\nvoid CWin32Util::appendChildWindows(HWND parentWnd, std::vector<HWND> &childWindows)\n{\n\tif (!parentWnd) return;\n\tHWND currSon = GetWindow(parentWnd, GW_CHILD);\n\tif (currSon)\n\t{\n\t\tHWND lastSon = GetWindow(currSon, GW_HWNDLAST);\n\t\tfor(;;)\n\t\t{\n\t\t\tchildWindows.push_back(currSon);\n\t\t\tappendChildWindows(currSon, childWindows);\n\t\t\tif (currSon == lastSon) break;\n\t\t\tcurrSon = GetWindow(currSon, GW_HWNDNEXT);\n\t\t}\n\t}\n}\n\n\n\n\n\n} // NLMISC\n\n\n#endif\n"
  },
  {
    "path": "code/nel/src/misc/win_displayer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/win_displayer.h\"\n\n#ifdef NL_OS_WINDOWS\n#include <windowsx.h>\n#include <winuser.h>\n#include <cstring>\n#include <cstdlib>\n#include <richedit.h>\n#include <commctrl.h>\n#include <ctime>\n\n#include \"nel/misc/app_context.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/ucstring.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nstatic CHARFORMAT2 CharFormat;\n\nCWinDisplayer::CWinDisplayer(const char *displayerName) : CWindowDisplayer(displayerName), Exit(false)\n{\n\tneedSlashR = true;\n\tcreateLabel(\"@Clear|CLEAR\");\n\n\tINelContext::getInstance().setWindowedApplication(true);\n}\n\nCWinDisplayer::~CWinDisplayer ()\n{\n}\n\nLRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\n{\n\tMSGFILTER *pmf;\n\n\tswitch (message)\n\t{\n\tcase WM_ACTIVATE:\n\t\t{\n\t\t\tif (LOWORD(wParam) != WA_INACTIVE)\n\t\t\t{\n\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\t\t\t\tif (cwd != NULL)\n\t\t\t\t\tSetFocus(cwd->_HInputEdit);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase WM_SIZE:\n\t\t{\n\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\t\t\tif (cwd != NULL)\n\t\t\t{\n\t\t\t\tint w = lParam & 0xFFFF;\n\t\t\t\tint h = (lParam >> 16) & 0xFFFF;\n\n//\t\t\t\tSetWindowPos (cwd->_HEdit, NULL, 0, cwd->_ToolBarHeight, w, h-cwd->_ToolBarHeight-cwd->_InputEditHeight, SWP_NOZORDER | SWP_NOACTIVATE );\n\t\t\t\tSetWindowPos (cwd->_HInputEdit, NULL, 0, h-cwd->_InputEditHeight, w, cwd->_InputEditHeight, SWP_NOZORDER | SWP_NOACTIVATE );\n\t\t\t\tcwd->resizeLabels ();\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase WM_DESTROY:\tPostQuitMessage (0); break;\n\tcase WM_CLOSE:\n\t\t{\n\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\t\t\tif (cwd != NULL)\n\t\t\t\tcwd->_Continue = false;\n\t\t}\n\t\tbreak;\n\tcase WM_COMMAND:\n\t\t{\n\t\t\tif (HIWORD(wParam) == BN_CLICKED)\n\t\t\t{\n\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\t\t\t\t// find the button and execute the command\n\t\t\t\tCSynchronized<std::vector<CWindowDisplayer::CLabelEntry> >::CAccessor access (&cwd->_Labels);\n\t\t\t\tfor (uint i = 0; i < access.value().size(); i++)\n\t\t\t\t{\n\t\t\t\t\tif (access.value()[i].Hwnd == (HWND)lParam)\n\t\t\t\t\t{\n\t\t\t\t\t\tif(access.value()[i].Value == \"@Clear|CLEAR\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// special commands because the clear must be called by the display thread and not main thread\n\t\t\t\t\t\t\tcwd->clear ();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// the button was found, add the command in the command stack\n\t\t\t\t\t\t\tCSynchronized<std::vector<std::string> >::CAccessor accessCommands (&cwd->_CommandsToExecute);\n\t\t\t\t\t\t\tstring str;\n\t\t\t\t\t\t\tnlassert (!access.value()[i].Value.empty());\n\t\t\t\t\t\t\tnlassert (access.value()[i].Value[0] == '@');\n\n\t\t\t\t\t\t\tstring::size_type pos = access.value()[i].Value.find (\"|\");\n\t\t\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstr = access.value()[i].Value.substr(pos+1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstr = access.value()[i].Value.substr(1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!str.empty())\n\t\t\t\t\t\t\t\taccessCommands.value().push_back(str);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\tcase WM_NOTIFY:\n\t\tswitch (((NMHDR*)lParam)->code)\n\t\t{\n\t\tcase EN_MSGFILTER:\n\t\t\tpmf = (MSGFILTER *)lParam;\n\t\t\tif (pmf->msg == WM_CHAR)\n\t\t\t{\n\t\t\t\tif (pmf->wParam == VK_RETURN)\n\t\t\t\t{\n\t\t\t\t\tWCHAR\twText[20000];\n\t\t\t\t\tstring\tTextSend;\n\t\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtr (hWnd, GWLP_USERDATA);\n\t\t\t\t\t// get the text as unicode string\n\t\t\t\t\tGetWindowTextW(cwd->_HInputEdit, wText, 20000);\n\t\t\t\t\tucstring ucs((ucchar*)wText);\n\t\t\t\t\t// and convert it to UTF-8 encoding.\n\t\t\t\t\tTextSend = ucs.toUtf8();\n\t\t\t\t\tSendMessage (cwd->_HInputEdit, WM_SETTEXT, (WPARAM)0, (LPARAM)\"\");\n\t\t\t\t\tconst char *pos2 = TextSend.c_str();\n\t\t\t\t\tstring str;\n\t\t\t\t\twhile (*pos2 != '\\0')\n\t\t\t\t\t{\n\t\t\t\t\t\tstr = \"\";\n\n\t\t\t\t\t\t// get the string\n\t\t\t\t\t\twhile (*pos2 != '\\0' && *pos2 != '\\n')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (*pos2 != '\\r')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tstr += *pos2;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t*pos2++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// eat the \\n\n\t\t\t\t\t\tif (*pos2 == '\\n')\n\t\t\t\t\t\t\t*pos2++;\n\n\t\t\t\t\t\tif (!str.empty())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tCSynchronized<std::vector<std::string> >::CAccessor access (&cwd->_CommandsToExecute);\n\t\t\t\t\t\t\t\taccess.value().push_back(str);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcwd->_History.push_back(str);\n\t\t\t\t\t\t\tcwd->_PosInHistory = (uint)cwd->_History.size();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (pmf->wParam == VK_TAB)\n\t\t\t\t{\n\t\t\t\t\tWCHAR\twText[20000];\n\n\n\t\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\n\t\t\t\t\t// get the text as unicode string\n\t\t\t\t\tGetWindowTextW(cwd->_HInputEdit, wText, 20000);\n\t\t\t\t\tucstring ucs((ucchar*)wText);\n\t\t\t\t\t// and convert it to UTF-8 encoding\n\t\t\t\t\tstring str = ucs.toUtf8();\n\t\t\t\t\tnlassert (cwd->Log != NULL);\n\t\t\t\t\tICommand::expand (str, *cwd->Log);\n\t\t\t\t\tSendMessage (cwd->_HInputEdit, WM_SETTEXT, (WPARAM)0, (LPARAM)str.c_str());\n\n\t\t\t\t\tSendMessage (cwd->_HInputEdit, EM_SETSEL, str.size(), str.size());\n\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (pmf->msg == WM_KEYUP)\n\t\t\t{\n\t\t\t\tif (pmf->wParam == VK_UP)\n\t\t\t\t{\n\t\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\n\t\t\t\t\tif (cwd->_PosInHistory > 0)\n\t\t\t\t\t\tcwd->_PosInHistory--;\n\n\t\t\t\t\tif (!cwd->_History.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tucstring ucs;\n\t\t\t\t\t\t// convert the text from UTF-8 to unicode\n\t\t\t\t\t\tucs.fromUtf8(cwd->_History[cwd->_PosInHistory]);\n\t\t\t\t\t\t// set the text as unicode string\n\t\t\t\t\t\tSetWindowTextW(cwd->_HInputEdit, (LPCWSTR)ucs.c_str());\n\t\t\t\t\t\tSendMessage (cwd->_HInputEdit, EM_SETSEL, (WPARAM)ucs.size(), (LPARAM)ucs.size());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (pmf->wParam == VK_DOWN)\n\t\t\t\t{\n\t\t\t\t\tCWinDisplayer *cwd=(CWinDisplayer *)GetWindowLongPtrW (hWnd, GWLP_USERDATA);\n\n\t\t\t\t\tif (cwd->_PosInHistory < cwd->_History.size()-1)\n\t\t\t\t\t\tcwd->_PosInHistory++;\n\n\t\t\t\t\tif (!cwd->_History.empty() && cwd->_PosInHistory < cwd->_History.size())\n\t\t\t\t\t{\n\t\t\t\t\t\tucstring ucs;\n\t\t\t\t\t\t// convert the text from UTF-8 to unicode\n\t\t\t\t\t\tucs.fromUtf8(cwd->_History[cwd->_PosInHistory]);\n\t\t\t\t\t\t// set the text as unicode string\n\t\t\t\t\t\tSetWindowTextW(cwd->_HInputEdit, (LPCWSTR)ucs.c_str());\n\t\t\t\t\t\tSendMessage (cwd->_HInputEdit, EM_SETSEL, (WPARAM)ucs.size(), (LPARAM)ucs.size());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn DefWindowProcW (hWnd, message, wParam, lParam);\n}\n\nvoid CWinDisplayer::updateLabels ()\n{\n\tbool needResize = false;\n\t{\n\t\tCSynchronized<std::vector<CLabelEntry> >::CAccessor access (&_Labels);\n\t\tfor (uint i = 0; i < access.value().size(); i++)\n\t\t{\n\t\t\tif (access.value()[i].NeedUpdate && !access.value()[i].Value.empty())\n\t\t\t{\n\t\t\t\tif (access.value()[i].Hwnd == NULL)\n\t\t\t\t{\n\t\t\t\t\t// create a button for command and label for variables\n\t\t\t\t\tif (access.value()[i].Value[0] == '@')\n\t\t\t\t\t{\n\t\t\t\t\t\taccess.value()[i].Hwnd = CreateWindowW (L\"BUTTON\", L\"\", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 0, 0, _HWnd, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(_HWnd, GWLP_HINSTANCE), NULL);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\taccess.value()[i].Hwnd = CreateWindowW (L\"STATIC\", L\"\", WS_CHILD | WS_VISIBLE | SS_SIMPLE, 0, 0, 0, 0, _HWnd, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(_HWnd, GWLP_HINSTANCE), NULL);\n\t\t\t\t\t}\n\t\t\t\t\tSendMessage ((HWND)access.value()[i].Hwnd, WM_SETFONT, (WPARAM)_HFont, TRUE);\n\t\t\t\t\tneedResize = true;\n\t\t\t\t}\n\n\t\t\t\tstring n;\n\n\t\t\t\t// do this tricks to be sure that windows will clear what is after the number\n\t\t\t\tif (access.value()[i].Value[0] != '@')\n\t\t\t\t\tn = access.value()[i].Value + \"                                                 \";\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstring::size_type pos = access.value()[i].Value.find ('|');\n\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tn = access.value()[i].Value.substr (1, pos - 1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tn = access.value()[i].Value.substr (1);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tSendMessage ((HWND)access.value()[i].Hwnd, WM_SETTEXT, 0, (LPARAM) n.c_str());\n\t\t\t\taccess.value()[i].NeedUpdate = false;\n\t\t\t}\n\t\t}\n\t}\n\tif (needResize)\n\t\tresizeLabels();\n}\n\nvoid CWinDisplayer::resizeLabels ()\n{\n\t{\n\t\tCSynchronized<std::vector<CLabelEntry> >::CAccessor access (&_Labels);\n\n\t\tRECT Rect;\n\t\tGetClientRect (_HWnd, &Rect);\n\n\t\tuint i = 0, nb;\n\t\tuint y = 0, nby = 1;\n\n\t\tfor (i = 0; i < access.value().size (); i++)\n\t\t\tif (access.value()[i].Value.empty())\n\t\t\t\tnby++;\n\n\t\ti = 0;\n\n\t\tfor(;;)\n\t\t{\n\t\t\tnb = 0;\n\t\t\twhile (i+nb != access.value().size () && !access.value()[i+nb].Value.empty()) nb++;\n\n\t\t\tsint delta;\n\t\t\tif (nb == 0)\n\t\t\t\tdelta = 0;\n\t\t\telse\n\t\t\t\tdelta = Rect.right / nb;\n\n\t\t\tfor (uint j = 0; j< nb; j++)\n\t\t\t{\n\t\t\t\tif ((HWND)access.value()[i+j].Hwnd != NULL)\n\t\t\t\t\tSetWindowPos ((HWND)access.value()[i+j].Hwnd, NULL, j*delta, y*_ToolBarHeight, delta, _ToolBarHeight, SWP_NOZORDER | SWP_NOACTIVATE );\n\t\t\t}\n\t\t\ti += nb + 1;\n\t\t\ty++;\n\t\t\tif (i >= access.value().size())\n\t\t\t\tbreak;\n\t\t}\n\n\t\tSetWindowPos (_HEdit, NULL, 0, nby*_ToolBarHeight, Rect.right, Rect.bottom-nby*_ToolBarHeight-_InputEditHeight, SWP_NOZORDER | SWP_NOACTIVATE );\n\t}\n}\n\nvoid CWinDisplayer::setTitleBar (const string &titleBar)\n{\n\tstring wn;\n\tif (!titleBar.empty())\n\t{\n\t\twn += titleBar;\n\t\twn += \": \";\n\t}\n\twn += \"Nel Service Console (compiled \" __DATE__ \" \" __TIME__ \" in \" + nlMode + \" mode)\";\n\n\tnldebug(\"SERVICE: Set title bar to '%s'\", wn.c_str());\n\n\tSetWindowTextW (_HWnd, (LPWSTR)ucstring::makeFromUtf8(wn).c_str());\n}\n\nvoid CWinDisplayer::open (string titleBar, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log)\n{\n\tif (w == -1)\n\t\tw = 700;\n\tif (h == -1)\n\t\th = 300;\n\tif (hs == -1)\n\t\ths = 1000;\n\n\tLog = log;\n\n\t_HistorySize = hs;\n\n\tWNDCLASSW wc;\n\tmemset (&wc,0,sizeof(wc));\n\twc.style\t\t\t= CS_HREDRAW | CS_VREDRAW ;//| CS_DBLCLKS;\n\twc.lpfnWndProc\t\t= (WNDPROC)WndProc;\n\twc.cbClsExtra\t\t= 0;\n\twc.cbWndExtra\t\t= 0;\n\twc.hInstance\t\t= GetModuleHandleW(NULL);\n\twc.hIcon\t\t\t= NULL;\n\twc.hCursor\t\t\t= LoadCursorW(NULL,(LPWSTR)IDC_ARROW);\n\twc.hbrBackground\t= (HBRUSH)COLOR_WINDOW;\n\twc.lpszClassName\t= L\"NLDisplayerClass\";\n\twc.lpszMenuName\t\t= NULL;\n\tif ( !RegisterClassW(&wc) ) return;\n\n\tULONG\tWndFlags;\n\tRECT\tWndRect;\n\tWndFlags = WS_OVERLAPPEDWINDOW /*| WS_CLIPCHILDREN | WS_CLIPSIBLINGS*/;\n\tWndRect.left = 0;\n\tWndRect.top = 0;\n\tWndRect.right = w;\n\tWndRect.bottom = h;\n\tAdjustWindowRect(&WndRect,WndFlags,FALSE);\n\n\t// create the window\n\t_HWnd = CreateWindowW (L\"NLDisplayerClass\", L\"\", WndFlags, CW_USEDEFAULT,CW_USEDEFAULT, WndRect.right,WndRect.bottom, NULL, NULL, GetModuleHandle(NULL), NULL);\n\tSetWindowLongPtrW (_HWnd, GWLP_USERDATA, (LONG_PTR)this);\n\n\t_HLibModule = LoadLibraryW(L\"RICHED20.DLL\");\n\tif (_HLibModule == NULL)\n\t{\n\t\tnlerror (\"RichEdit 2.0 library not found!\");\n\t}\n\n\tstring rfn;\n\tif (fn.empty())\n\t\trfn = \"courier\";\n\telse\n\t\trfn = fn;\n\n\tsint rfs;\n\tif (fs == 0)\n\t\trfs = 10;\n\telse\n\t\trfs = fs;\n\n\t_HFont = CreateFontW (-MulDiv(rfs, GetDeviceCaps(GetDC(0),LOGPIXELSY), 72), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, (LPCWSTR)ucstring::makeFromUtf8(rfn).c_str());\n\n\n\t// create the edit control\n\tDWORD dwStyle = WS_HSCROLL | WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_LEFT | ES_MULTILINE /*| ES_AUTOVSCROLL*/;\n\n\tif(ww)\n\t\tdwStyle &= ~WS_HSCROLL;\n\telse\n\t\tdwStyle |= WS_HSCROLL;\n\n\t_HEdit = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, RICHEDIT_CLASSW, L\"\", dwStyle, 0, _ToolBarHeight, w, h-_ToolBarHeight-_InputEditHeight, _HWnd, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(_HWnd, GWLP_HINSTANCE), NULL);\n\tSendMessage (_HEdit, WM_SETFONT, (WPARAM)_HFont, TRUE);\n\n\t// set the edit text limit to lot of :)\n\tSendMessage (_HEdit, EM_LIMITTEXT, -1, 0);\n\n\tCharFormat.cbSize = sizeof(CharFormat);\n\tCharFormat.dwMask = CFM_COLOR;\n\tSendMessage(_HEdit,EM_GETCHARFORMAT,(WPARAM)0,(LPARAM)&CharFormat);\n\tCharFormat.dwEffects &= ~CFE_AUTOCOLOR;\n\n\t// create the input edit control\n\t_HInputEdit = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, RICHEDIT_CLASSW, L\"\", WS_CHILD | WS_VISIBLE\n\t\t/*| ES_MULTILINE*/ | ES_WANTRETURN | ES_NOHIDESEL | ES_AUTOHSCROLL, 0, h-_InputEditHeight, w, _InputEditHeight,\n\t\t_HWnd, NULL, (HINSTANCE) GetWindowLongPtr(_HWnd, GWLP_HINSTANCE), NULL);\n\tSendMessageW (_HInputEdit, WM_SETFONT, (WPARAM)_HFont, TRUE);\n\n\tLRESULT dwEvent = SendMessageW(_HInputEdit, EM_GETEVENTMASK, (WPARAM)0, (LPARAM)0);\n\tdwEvent |= ENM_MOUSEEVENTS | ENM_KEYEVENTS | ENM_CHANGE;\n\tSendMessage(_HInputEdit, EM_SETEVENTMASK, (WPARAM)0, (LPARAM)dwEvent);\n\n\t// resize the window\n\tRECT rc;\n\tSetRect (&rc, 0, 0, w, h);\n\tAdjustWindowRectEx (&rc, GetWindowStyle (_HWnd), GetMenu (_HWnd) != NULL, GetWindowExStyle (_HWnd));\n\n\tLONG flag = SWP_NOZORDER | SWP_NOACTIVATE;\n\n\tif (x == -1 && y == -1) flag |= SWP_NOMOVE;\n\tif (w == -1 && h == -1) flag |= SWP_NOSIZE;\n\n\tSetWindowPos (_HWnd, NULL, x, y, w, h, flag);\n\tSetWindowPos (_HWnd, NULL, x, y, rc.right - rc.left, rc.bottom - rc.top, flag);\n\n\tsetTitleBar (titleBar);\n\n\tif (iconified)\n\t\tShowWindow(_HWnd,SW_MINIMIZE);\n\telse\n\t\tShowWindow(_HWnd,SW_SHOW);\n\n\tSetFocus (_HInputEdit);\n\n\t_Init = true;\n}\n\nvoid CWinDisplayer::clear ()\n{\n\tbool focus = (GetFocus() == _HEdit);\n\tif (focus)\n\t{\n\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_AND,(LPARAM)~ECO_AUTOVSCROLL);\n\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_AND,(LPARAM)~ECO_AUTOHSCROLL);\n\t}\n\n\t// get number of line\n\tLRESULT nLine = SendMessageW (_HEdit, EM_GETLINECOUNT, 0, 0) - 1;\n\n\t// get size of the last line\n\tLRESULT nIndex = SendMessageW (_HEdit, EM_LINEINDEX, nLine, 0);\n\n\t// select all the text\n\tSendMessageW (_HEdit, EM_SETSEL, 0, nIndex);\n\n\t// clear all the text\n\tSendMessageW (_HEdit, EM_REPLACESEL, FALSE, (LPARAM) \"\");\n\n\tSendMessageW(_HEdit,EM_SETMODIFY,(WPARAM)TRUE,(LPARAM)0);\n\n\tif ( focus )\n\t{\n\t\tSendMessageW(_HEdit,EM_SETOPTIONS,ECOOP_OR,(LPARAM)ECO_AUTOVSCROLL);\n\t\tSendMessageW(_HEdit,EM_SETOPTIONS,ECOOP_OR,(LPARAM)ECO_AUTOHSCROLL);\n\t}\n}\n\nvoid CWinDisplayer::display_main ()\n{\n\tnlassert (_Init);\n\n\twhile (_Continue)\n\t{\n\t\t//\n\t\t// Display the bufferized string\n\t\t//\n\n\t\t{\n\t\t\tCSynchronized<std::list<std::pair<uint32, std::string> > >::CAccessor access (&_Buffer);\n\t\t\tstd::list<std::pair<uint32, std::string> >::iterator it;\n\n\t\t\tsint vecSize = (sint)access.value().size();\n\t\t\t//nlassert (vecSize <= _HistorySize);\n\n\t\t\tif (vecSize > 0)\n\t\t\t{\n\t\t\t\t// look if we are at the bottom of the edit\n\t\t\t\tSCROLLINFO\tinfo;\n\t\t\t\tinfo.cbSize = sizeof(info);\n\t\t\t\tinfo.fMask = SIF_ALL;\n\n\t\t\t\tbool bottom = true;\n\t\t\t\tif (GetScrollInfo(_HEdit,SB_VERT,&info) != 0)\n\t\t\t\t\tbottom = (info.nPage == 0) || (info.nMax<=(info.nPos+(int)info.nPage));\n\n\t\t\t\t// look if we have the focus\n\t\t\t\tbool focus = (GetFocus() == _HEdit);\n\t\t\t\tif (focus)\n\t\t\t\t{\n\t\t\t\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_AND,(LPARAM)~ECO_AUTOVSCROLL);\n\t\t\t\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_AND,(LPARAM)~ECO_AUTOHSCROLL);\n\t\t\t\t}\n\n\t\t\t\t// store old selection\n\t\t\t\tDWORD startSel, endSel;\n\t\t\t\tSendMessage (_HEdit, EM_GETSEL, (WPARAM)&startSel, (LPARAM)&endSel);\n\n\t\t\t\t// find how many lines we have to remove in the current output to add new lines\n\n\t\t\t\t// get number of line\n\t\t\t\tLRESULT nLine = SendMessageW (_HEdit, EM_GETLINECOUNT, 0, 0) - 1;\n\n\t\t\t\tif (_HistorySize > 0 && nLine+vecSize > _HistorySize)\n\t\t\t\t{\n\t\t\t\t\tint nblineremove = vecSize;\n\t\t\t\t\t//nlassert (nblineremove>0 && nblineremove <= _HistorySize);\n\n\t\t\t\t\tif (nblineremove == _HistorySize)\n\t\t\t\t\t{\n\t\t\t\t\t\tSendMessage (_HEdit, WM_SETTEXT, 0, (LPARAM) \"\");\n\t\t\t\t\t\tstartSel = endSel = -1;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tLRESULT oldIndex1 = SendMessageW (_HEdit, EM_LINEINDEX, 0, 0);\n\t\t\t\t\t\t//nlassert (oldIndex1 != -1);\n\t\t\t\t\t\tLRESULT oldIndex2 = SendMessageW (_HEdit, EM_LINEINDEX, nblineremove, 0);\n\t\t\t\t\t\t//nlassert (oldIndex2 != -1);\n\t\t\t\t\t\tSendMessageW (_HEdit, EM_SETSEL, oldIndex1, oldIndex2);\n\t\t\t\t\t\tSendMessageW (_HEdit, EM_REPLACESEL, FALSE, (LPARAM) \"\");\n\n\t\t\t\t\t\t// update the selection due to the erasing\n\t\t\t\t\t\tsint dt = (sint)(oldIndex2 - oldIndex1);\n\t\t\t\t\t\tif (startSel < 65000)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((sint)startSel-dt < 0) startSel = -1;\n\t\t\t\t\t\t\telse startSel -= dt;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse startSel = -1;\n\t\t\t\t\t\tif(endSel < 65000)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ((sint)endSel-dt < 0) startSel = endSel = -1;\n\t\t\t\t\t\t\telse endSel -= dt;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse startSel = endSel = -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (it = access.value().begin(); it != access.value().end(); )\n\t\t\t\t{\n\t\t\t\t\tucstring str = ucstring::makeFromUtf8((*it).second);\n\t\t\t\t\tuint32 col = (*it).first;\n\n\t\t\t\t\t// get all string that have the same color\n\t\t\t\t\tfor (it++; it != access.value().end() && (*it).first == col; it++)\n\t\t\t\t\t{\n\t\t\t\t\t\tstr += ucstring::makeFromUtf8((*it).second);\n\t\t\t\t\t}\n\n\t\t\t\t\tSendMessage (_HEdit, EM_SETSEL, -1, -1);\n\n\t\t\t\t\tif ((col>>24) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// there s a specific color\n\t\t\t\t\t\tCharFormat.crTextColor = RGB ((col>>16)&0xFF, (col>>8)&0xFF, col&0xFF);\n\t\t\t\t\t\tSendMessage((HWND) _HEdit, EM_SETCHARFORMAT, (WPARAM) SCF_SELECTION, (LPARAM) &CharFormat);\n\t\t\t\t\t}\n\n\t\t\t\t\t// add the string to the edit control\n\t\t\t\t\tSendMessageW (_HEdit, EM_REPLACESEL, FALSE, (LPARAM) str.c_str());\n\t\t\t\t}\n\n\t\t\t\t// restore old selection\n\t\t\t\tSendMessage (_HEdit, EM_SETSEL, startSel, endSel);\n\n\t\t\t\tSendMessage(_HEdit,EM_SETMODIFY,(WPARAM)TRUE,(LPARAM)0);\n\n\t\t\t\tif (bottom)\n\t\t\t\t\tSendMessage(_HEdit,WM_VSCROLL,(WPARAM)SB_BOTTOM,(LPARAM)0L);\n\n\t\t\t\tif (focus)\n\t\t\t\t{\n\t\t\t\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_OR,(LPARAM)ECO_AUTOVSCROLL);\n\t\t\t\t\tSendMessage(_HEdit,EM_SETOPTIONS,ECOOP_OR,(LPARAM)ECO_AUTOHSCROLL);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// clear the log\n\t\t\taccess.value().clear ();\n\t\t}\n\n\t\t//\n\t\t// Update labels\n\t\t//\n\n\t\tupdateLabels ();\n\n\t\t//\n\t\t// Manage windows message\n\t\t//\n\n\t\tMSG\tmsg;\n\t\twhile (PeekMessageW(&msg,NULL,0,0,PM_REMOVE))\n\t\t{\n\t\t\tTranslateMessage(&msg);\n\t\t\tDispatchMessageW(&msg);\n\t\t}\n\n\t\t//\n\t\t// Wait\n\t\t//\n\n\t\t//////////////////////////////////////////////////////////////////\n\t\t// WARNING: READ THIS !!!!!!!!!!!!!!!! ///////////////////////////\n\t\t// If at the release time, it freezes here, it's a microsoft bug:\n\t\t// http://support.microsoft.com/support/kb/articles/q173/2/60.asp\n\t\tnlSleep (1);\n\t}\n\n\tDeleteObject (_HFont);\n\t_HFont = NULL;\n\tDestroyWindow (_HWnd);\n\t_HWnd = NULL;\n\tDestroyWindow (_HEdit);\n\t_HEdit = NULL;\n\tFreeLibrary (_HLibModule);\n\t_HLibModule = NULL;\n}\n\nvoid CWinDisplayer::getWindowPos (uint32 &x, uint32 &y, uint32 &w, uint32 &h)\n{\n\tRECT rect;\n\t// get the w and h of the client array\n\tGetClientRect (_HWnd, &rect);\n\tw = rect.right - rect.left;\n\th = rect.bottom - rect.top;\n\n\t// get the x and y of the window (not the client array)\n\tGetWindowRect (_HWnd, &rect);\n\tx = rect.left;\n\ty = rect.top;\n}\n\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n"
  },
  {
    "path": "code/nel/src/misc/win_event_emitter.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/events.h\"\n#include \"nel/misc/event_emitter.h\"\n#include \"nel/misc/win_event_emitter.h\"\n#include \"nel/misc/event_server.h\"\n\n#ifdef NL_OS_WINDOWS\n#include <windowsx.h>\n\n/**\n  * Needed for definition of WM_MOUSEWHEEL. It should be in winuser.h\n  * but not under win98.. strange..\n  */\n#include <zmouse.h>\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tsubmitEvents()\n\\*------------------------------------------------------------------*/\nvoid CWinEventEmitter::submitEvents(CEventServer & server, bool allWindows)\n{\n\tMSG\tmsg;\n\twhile ( PeekMessageW(&msg,allWindows?NULL:_HWnd,0,0,PM_REMOVE) )\n\t{\n\t\tTranslateMessage(&msg);\n\t\tDispatchMessageW(&msg);\n\t}\n\n\t// Dispatch sent messages\n\t_InternalServer.setServer (&server);\n\t_InternalServer.pump (allWindows);\n}\n\n/*------------------------------------------------------------------*\\\n\t\t\t\t\t\t\tprocessMessage()\n\\*------------------------------------------------------------------*/\n\n\nTKeyButton getKeyButton (bool _altButton, bool _shiftButton, bool _ctrlButton)\n{\n\tTKeyButton button=noKeyButton;\n\tif (_altButton)\n\t\t(int&)button|=altKeyButton;\n\tif (_shiftButton)\n\t\t(int&)button|=shiftKeyButton;\n\tif (_ctrlButton)\n\t\t(int&)button|=ctrlKeyButton;\n\n\treturn button;\n}\n\n/*TMouseButton getMouseButton (uint32 wParam, bool _altButton)\n{\n\tTMouseButton button=noButton;\n\tif (wParam&MK_CONTROL)\n\t\t(int&)button|=ctrlButton;\n\tif (wParam&MK_LBUTTON)\n\t\t(int&)button|=leftButton;\n\tif (wParam&MK_RBUTTON)\n\t\t(int&)button|=rightButton;\n\tif (wParam&MK_MBUTTON)\n\t\t(int&)button|=middleButton;\n\tif (wParam&MK_SHIFT)\n\t\t(int&)button|=shiftButton;\n\tif (_altButton)\n\t\t(int&)button|=altButton;\n}*/\n\n\nTMouseButton CWinEventEmitter::getButtons() const\n{\n\tuint result = (_CtrlButton ? ctrlButton : 0)\n\t\t\t\t | (_AltButton ? altButton : 0)\n\t\t\t\t | (_ShiftButton ? shiftButton : 0)\n\t\t\t\t | (_CtrlButton ? ctrlButton : 0)\n\t\t\t\t | (_MouseButtons[0] ? leftButton : 0)\n\t\t\t\t | (_MouseButtons[1] ? rightButton : 0)\n\t\t\t\t | (_MouseButtons[2] ? middleButton : 0);\n\treturn (TMouseButton) result;\n}\n\n\nbool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPARAM lParam, CEventServer *server)\n{\n\tif (!server)\n\t\tserver=&_InternalServer;\n\n\t/// Process IME messages\n\t/*if ( _IMEEventsEnabled && (ImmIsUIMessage( ImmGetDefaultIMEWnd((HWND)_HWnd), msg, wParam, lParam) == TRUE) )\n\t{\n\t\tserver->postEvent( new CEventIME(msg, wParam, lParam, this) );\n\t\treturn true; // trap message (however DefWindowProc will still be called in some instances by the event listener)\n\t}*/\n\n\tswitch (msg)\n\t{\n\tcase WM_KEYDOWN:\n\tcase WM_SYSKEYDOWN:\n\t\tif (_KeyboardEventsEnabled)\n\t\t{\n\t\t\t// Ctrl, shit or alt ?\n\t\t\tif ((sint)wParam==VK_MENU)\n\t\t\t\t_AltButton=true;\n\t\t\tif ((sint)wParam==VK_CONTROL)\n\t\t\t\t_CtrlButton=true;\n\t\t\tif ((sint)wParam==VK_SHIFT)\n\t\t\t\t_ShiftButton=true;\n\n\t\t\t// Post the message\n\t\t\tif (wParam < KeyCount)\n\t\t\t\tserver->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), (((int) lParam)&(1<<30))==0, this));\n\t\t}\n\t\tbreak;\n\n\tcase WM_SYSKEYUP:\n\tcase WM_KEYUP:\n\t\tif (_KeyboardEventsEnabled)\n\t\t{\n\t\t\t// Ctrl, shit or alt ?\n\t\t\tif ((int)wParam==VK_MENU)\n\t\t\t\t_AltButton=false;\n\t\t\tif ((int)wParam==VK_CONTROL)\n\t\t\t\t_CtrlButton=false;\n\t\t\tif ((int)wParam==VK_SHIFT)\n\t\t\t\t_ShiftButton=false;\n\n\t\t\t// As Print Screen button does not trigger a WM_KEYDOWN msg, simulate it here\n\t\t\tif ((int)wParam==VK_SNAPSHOT)\n\t\t\t{\n\t\t\t\tif (wParam < KeyCount)\n\t\t\t\t\tserver->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), true, this));\n\t\t\t}\n\n\t\t\t// Post the message\n\t\t\tif (wParam < KeyCount)\n\t\t\t\tserver->postEvent (new CEventKeyUp ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));\n\t\t}\n\t\tbreak;\n\tcase WM_CHAR:\n\t\tif (_KeyboardEventsEnabled)\n\t\t{\n\t\t\t//if (wParam < KeyCount)\n\t\t\t//nlinfo(\"WM_CHAR with %u\", wParam);\n\t\t\tserver->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));\n\t\t}\n\t\tbreak;\n\t/*case WM_IME_CHAR:\n\t\tif (_KeyboardEventsEnabled && _IMEEventsEnabled)\n\t\t{\n\t\t\tserver->postEvent (new CEventChar ((ucchar)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this));\n\t\t}\n\t\tbreak;*/\n\tcase WM_ACTIVATE:\n\t\tif (WA_INACTIVE==LOWORD(wParam))\n\t\t\tserver->postEvent (new CEventActivate (false, this));\n\t\telse\n\t\t{\n\t\t\t// Reset flags state\n\t\t\tresetButtonFlagState ();\n\n\t\t\t// Post the message\n\t\t\tserver->postEvent (new CEventActivate (true, this));\n\t\t}\n\t\tbreak;\n\tcase WM_KILLFOCUS:\n\t\tserver->postEvent (new CEventSetFocus (false, this));\n\t\tbreak;\n\tcase WM_SETFOCUS:\n\t\t// Reset flags state\n\t\tresetButtonFlagState ();\n\n\t\t// Post the message\n\t\tserver->postEvent (new CEventSetFocus (true, this));\n\t\tbreak;\n\tcase WM_MOUSEMOVE:\n\tcase WM_RBUTTONDOWN:\n\tcase WM_LBUTTONDOWN:\n\tcase WM_MBUTTONDOWN:\n\tcase WM_RBUTTONUP:\n\tcase WM_LBUTTONUP:\n\tcase WM_MBUTTONUP:\n\tcase WM_RBUTTONDBLCLK:\n\tcase WM_MBUTTONDBLCLK:\n\tcase WM_LBUTTONDBLCLK:\n\t\t{\n\t\t\tif (_MouseEventsEnabled)\n\t\t\t{\n\t\t\t\t// MSWindows coordinates to NeL window coordinate\n\t\t\t\tfloat fX, fY;\n\t\t\t\tRECT client;\n\n\t\t\t\tfloat xPos = (float)GET_X_LPARAM(lParam);\n\t\t\t\tfloat yPos = (float)GET_Y_LPARAM(lParam);\n\n\t\t\t\tGetClientRect (hWnd, &client);\n\t\t\t\tfX=xPos/(float)(client.right-client.left);\n\t\t\t\tfY=1.f-yPos/(float)(client.bottom-client.top);\n\n\t\t\t\t// buttons\n\t\t\t\tTMouseButton button=getButtons();\n\n\t\t\t\t// Reswitch\n\t\t\t\tswitch (msg)\n\t\t\t\t{\n\t\t\t\tcase WM_MOUSEMOVE:\n\t\t\t\t\tserver->postEvent (new CEventMouseMove (fX, fY, button, this));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WM_RBUTTONDOWN:\n\t\t\t\t\t_MouseButtons[1] = true;\n\t\t\t\t\tserver->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_MBUTTONDOWN:\n\t\t\t\t\t_MouseButtons[2] = true;\n\t\t\t\t\tserver->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_LBUTTONDOWN:\n\t\t\t\t\t_MouseButtons[0] = true;\n\t\t\t\t\tserver->postEvent (new CEventMouseDown (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WM_RBUTTONUP:\n\t\t\t\t\t_MouseButtons[1] = false;\n\t\t\t\t\tserver->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_MBUTTONUP:\n\t\t\t\t\t_MouseButtons[2] = false;\n\t\t\t\t\tserver->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_LBUTTONUP:\n\t\t\t\t\t_MouseButtons[0] = false;\n\t\t\t\t\tserver->postEvent (new CEventMouseUp (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WM_RBUTTONDBLCLK:\n\t\t\t\t\tserver->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(rightButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_MBUTTONDBLCLK:\n\t\t\t\t\tserver->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(middleButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_LBUTTONDBLCLK:\n\t\t\t\t\tserver->postEvent (new CEventMouseDblClk (fX, fY, (TMouseButton)(leftButton|(button&~(leftButton|middleButton|rightButton))), this));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\tcase WM_DESTROY:\n\t\tserver->postEvent (new CEventDestroyWindow (this));\n\t\tbreak;\n\tcase WM_CLOSE:\n\t\tserver->postEvent (new CEventCloseWindow (this));\n\t\treturn true;\n\tcase WM_DISPLAYCHANGE:\n\t\tserver->postEvent (new CEventDisplayChange (LOWORD(lParam), HIWORD(lParam), (uint)wParam, this));\n\t\tbreak;\n\tcase WM_MOUSEWHEEL:\n\t\tif (_MouseEventsEnabled)\n\t\t{\n\t\t\t// MSWindows coordinates to NeL window coordinate\n\t\t\tfloat fX, fY;\n\t\t\tRECT client;\n\t\t\tGetClientRect (hWnd, &client);\n\t\t\tif (client.right-client.left > 0)\n\t\t\t\tfX=(float)LOWORD(lParam)/(float)(client.right-client.left);\n\t\t\telse\n\t\t\t\tfX=0;\n\t\t\tif (client.bottom-client.top > 0)\n\t\t\t\tfY=1.f-(float)HIWORD(lParam)/(float)(client.bottom-client.top);\n\t\t\telse\n\t\t\t\tfY=0;\n\n\t\t\t// buttons\n\t\t\tTMouseButton button=getButtons();\n\n\t\t\tserver->postEvent (new CEventMouseWheel (fX, fY, button, (short) HIWORD(wParam)>=0, this));\n\t\t\tbreak;\n\t\t}\n\tcase WM_IME_SETCONTEXT:\n\tcase WM_IME_STARTCOMPOSITION:\n\tcase WM_IME_COMPOSITION:\n\tcase WM_IME_ENDCOMPOSITION:\n\tcase WM_IME_NOTIFY:\n\t//case WM_INPUTLANGCHANGEREQUEST:\n\tcase WM_INPUTLANGCHANGE:\n\t\tif ( _IMEEventsEnabled )\n\t\t{\n\t\t\t// wParam = Specifies the character set of the new locale.\n\t\t\t// lParam = Input locale identifier.\n\t\t\tserver->postEvent( new CEventIME( msg, (uint32)wParam, (uint32)lParam, this ) );\n\t\t\treturn true; // trap message\n\t\t}\n\t\tbreak;\n\t}\n\treturn false;\n}\n\n//==========================================================\nvoid CWinEventEmitter::resetButtonFlagState ()\n{\n\t_CtrlButton=( (GetAsyncKeyState(VK_CONTROL)&0x8000) != 0);\n\t_ShiftButton=( (GetAsyncKeyState(VK_SHIFT)&0x8000) != 0);\n\t_AltButton=( (GetAsyncKeyState(VK_MENU)&0x8000) != 0);\n\t//\n\t_MouseButtons[0]=( (GetAsyncKeyState(VK_LBUTTON)&0x8000) != 0);\n\t_MouseButtons[1]=( (GetAsyncKeyState(VK_RBUTTON)&0x8000) != 0);\n\t_MouseButtons[2]=( (GetAsyncKeyState(VK_MBUTTON)&0x8000) != 0);\n\n\n\n}\n\n//==========================================================\nTMouseButton CWinEventEmitter::buildFlags() const\n{\n\tuint flags = (_CtrlButton ? ctrlButton : 0)\n\t\t\t\t | (_ShiftButton ? shiftButton : 0)\n\t\t\t\t | (_AltButton   ? altButton : 0)\n\t\t\t\t | (_MouseButtons[0] ? leftButton : 0)\n\t\t\t\t | (_MouseButtons[1] ? rightButton : 0)\n\t\t\t\t | (_MouseButtons[2] ? middleButton : 0);\n\treturn (TMouseButton) flags;\n}\n\n\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n"
  },
  {
    "path": "code/nel/src/misc/win_thread.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/win_thread.h\"\n\n#ifdef NL_OS_WINDOWS\n\n#include \"nel/misc/path.h\"\n#ifndef NL_COMP_MINGW\n#define NOMINMAX\n#endif\n#include <windows.h>\n\n#include <typeinfo>\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nCWinThread MainThread ((void*)GetCurrentThread (), GetCurrentThreadId());\nDWORD TLSThreadPointer = 0xFFFFFFFF;\n\n// the IThread static creator\nIThread *IThread::create (IRunnable *runnable, uint32 stackSize)\n{\n\treturn new CWinThread (runnable, stackSize);\n}\n\nIThread *IThread::getCurrentThread ()\n{\n\t// TLS alloc must have been done\n\tnlassert (TLSThreadPointer != 0xffffffff);\n\n\t// Get the thread pointer\n\tIThread *thread = (IThread*)TlsGetValue (TLSThreadPointer);\n\n\t// Return current thread\n\treturn thread;\n}\n\nstatic unsigned long __stdcall ProxyFunc (void *arg)\n{\n\tCWinThread *parent = (CWinThread *) arg;\n\n\t// TLS alloc must have been done\n\tnlassert (TLSThreadPointer != 0xffffffff);\n\n\t// Set the thread pointer in TLS memory\n\tnlverify (TlsSetValue (TLSThreadPointer, (void*)parent) != 0);\n\n\t// Run the thread\n\tparent->Runnable->run();\n\n\treturn 0;\n}\n\nCWinThread::CWinThread (IRunnable *runnable, uint32 stackSize)\n{\n\t_StackSize = stackSize;\n\tthis->Runnable = runnable;\n\tThreadHandle = NULL;\n\t_SuspendCount = -1;\n\t_MainThread = false;\n}\n\nnamespace {\nclass CWinCriticalSection\n{\nprivate:\n\tCRITICAL_SECTION cs;\npublic:\n\tCWinCriticalSection() { InitializeCriticalSection(&cs); }\n\t~CWinCriticalSection() { DeleteCriticalSection(&cs); }\n\tinline void enter() { EnterCriticalSection(&cs); }\n\tinline void leave() { LeaveCriticalSection(&cs); }\n};\nCWinCriticalSection s_CS;\n}/* anonymous namespace */\n\nCWinThread::CWinThread (void* threadHandle, uint32 threadId)\n{\n\t// Main thread\n\t_MainThread = true;\n\tthis->Runnable = NULL;\n\tThreadHandle = threadHandle;\n\tThreadId = threadId;\n\n\t// TLS alloc must have been done\n\tTLSThreadPointer = TlsAlloc ();\n\tnlassert (TLSThreadPointer!=0xffffffff);\n\n\t// Set the thread pointer in TLS memory\n\tnlverify (TlsSetValue (TLSThreadPointer, (void*)this) != 0);\n\n\tif (GetCurrentThreadId() == threadId)\n\t{\n\t\t_SuspendCount = 0; // is calling thread call this itself, well, if we reach this place\n\t\t\t\t\t\t   // there are chances that it is not suspended ...\n\t}\n\telse\n\t{\n\t\t// initialized from another thread (very unlikely ...)\n\t\tnlassert(0); // WARNING: following code has not tested! don't know if it work fo real ...\n\t\t\t\t\t // This is just a suggestion of a possible solution, should this situation one day occur ...\n\t\t// Ensure that this thread don't get deleted, or we could suspend the main thread\n\t\ts_CS.enter();\n\t\t// the 2 following statement must be executed atomicaly among the threads of the current process !\n\t\tSuspendThread(threadHandle);\n\t\t_SuspendCount = ResumeThread(threadHandle);\n\t\ts_CS.leave();\n\t}\n}\n\n\nvoid CWinThread::incSuspendCount()\n{\n\tnlassert(ThreadHandle); // start was not called !!\n\tint newSuspendCount = ::SuspendThread(ThreadHandle) + 1;\n\tnlassert(newSuspendCount != 0xffffffff); // more infos with 'GetLastError'\n\tnlassert(newSuspendCount == _SuspendCount + 1); // is this assert fire , then 'SuspendThread' or 'ResumeThread'\n\t\t\t\t\t\t\t\t\t\t\t\t\t// have been called outside of this object interface! (on this thread handle ...)\n\t_SuspendCount = newSuspendCount;\n}\n\nvoid CWinThread::decSuspendCount()\n{\n\tnlassert(ThreadHandle); // 'start' was not called !!\n\tnlassert(_SuspendCount > 0);\n\tint newSuspendCount = ::ResumeThread(ThreadHandle) - 1;\n\tnlassert(newSuspendCount != 0xffffffff); // more infos with 'GetLastError'\n\tnlassert(newSuspendCount == _SuspendCount - 1); // is this assert fire , then 'SuspendThread' or 'ResumeThread'\n\t\t\t\t\t\t\t\t\t\t\t\t\t// have been called outside of this object interface! (on this thread handle ...)\n\t_SuspendCount = newSuspendCount;\n}\n\nvoid CWinThread::suspend()\n{\n\tif (getSuspendCount() == 0)\n\t{\n\t\tincSuspendCount();\n\t}\n}\n\nvoid CWinThread::resume()\n{\n\twhile (getSuspendCount() != 0)\n\t{\n\t\tdecSuspendCount();\n\t}\n}\n\nvoid CWinThread::setPriority(TThreadPriority priority)\n{\n\tnlassert(ThreadHandle); // 'start' was not called !!\n\tBOOL result = SetThreadPriority(ThreadHandle, (int)priority);\n\tnlassert(result);\n}\n\nvoid CWinThread::enablePriorityBoost(bool enabled)\n{\n\tnlassert(ThreadHandle); // 'start' was not called !!\n\tSetThreadPriorityBoost(ThreadHandle, enabled ? TRUE : FALSE);\n}\n\n\nCWinThread::~CWinThread ()\n{\n\t// If not the main thread\n\tif (_MainThread)\n\t{\n\t\t// Free TLS memory\n\t\tnlassert (TLSThreadPointer!=0xffffffff);\n\t\tTlsFree (TLSThreadPointer);\n\t}\n\telse\n\t{\n\t\tif (ThreadHandle != NULL) terminate();\n\t}\n}\n\nvoid CWinThread::start ()\n{\n\tif (isRunning())\n\t\tthrow EThread(\"Starting a thread that is already started, existing thread will continue running, this should not happen\");\t\n\n//\tThreadHandle = (void *) ::CreateThread (NULL, _StackSize, ProxyFunc, this, 0, (DWORD *)&ThreadId);\n\tThreadHandle = (void *) ::CreateThread (NULL, 0, ProxyFunc, this, 0, (DWORD *)&ThreadId);\n//\tnldebug(\"NLMISC: thread %x started for runnable '%x'\", typeid( Runnable ).name());\n//\tOutputDebugString(toString(NL_LOC_MSG \" NLMISC: thread %x started for runnable '%s'\\n\", ThreadId, typeid( *Runnable ).name()).c_str());\n\tSetThreadPriorityBoost (ThreadHandle, TRUE); // FALSE == Enable Priority Boost\n\tif (ThreadHandle == NULL)\n\t{\n\t\tthrow EThread ( \"Cannot create new thread\" );\n\t}\n\n\t_SuspendCount = 0;\n}\n\nbool CWinThread::isRunning()\n{\n\tif (ThreadHandle == NULL)\n\t\treturn false;\n\n\tDWORD exitCode;\n\tif (!GetExitCodeThread(ThreadHandle, &exitCode))\n\t\treturn false;\n\n\treturn exitCode == STILL_ACTIVE;\n}\n\n\nvoid CWinThread::terminate ()\n{\n\tTerminateThread((HANDLE)ThreadHandle, 0);\n\tCloseHandle((HANDLE)ThreadHandle);\n\tThreadHandle = NULL;\n\t_SuspendCount = -1;\n}\n\nvoid CWinThread::wait ()\n{\n\tif (ThreadHandle == NULL) return;\n\n\tWaitForSingleObject(ThreadHandle, INFINITE);\n\tCloseHandle(ThreadHandle);\n\tThreadHandle = NULL;\n\t_SuspendCount = -1;\n}\n\nbool CWinThread::setCPUMask(uint64 cpuMask)\n{\n\t// Thread must exist\n\tif (ThreadHandle == NULL)\n\t\treturn false;\n\n\t// Ask the system for number of processor available for this process\n\treturn SetThreadAffinityMask ((HANDLE)ThreadHandle, (DWORD_PTR)cpuMask) != 0;\n}\n\nuint64 CWinThread::getCPUMask()\n{\n\t// Thread must exist\n\tif (ThreadHandle == NULL)\n\t\treturn 1;\n\n\t// Get the current process mask\n\tuint64 mask=IProcess::getCurrentProcess ()->getCPUMask ();\n\n\t// Get thread affinity mask\n\tDWORD_PTR old = SetThreadAffinityMask ((HANDLE)ThreadHandle, (DWORD_PTR)mask);\n\tnlassert (old != 0);\n\tif (old == 0)\n\t\treturn 1;\n\n\t// Reset it\n\tSetThreadAffinityMask ((HANDLE)ThreadHandle, old);\n\n\t// Return the mask\n\treturn (uint64)old;\n}\n\nstd::string CWinThread::getUserName()\n{\n\tchar userName[512];\n\tDWORD size = 512;\n\tGetUserName (userName, &size);\n\treturn (const char*)userName;\n}\n\n// **** Process\n\n// The current process\nCWinProcess CurrentProcess ((void*)GetCurrentProcess());\n\n// Get the current process\nIProcess *IProcess::getCurrentProcess ()\n{\n\treturn &CurrentProcess;\n}\n\nCWinProcess::CWinProcess (void *handle)\n{\n\t// Get the current process handle\n\t_ProcessHandle = handle;\n}\n\nuint64 CWinProcess::getCPUMask()\n{\n\t// Ask the system for number of processor available for this process\n\tDWORD_PTR processAffinityMask;\n\tDWORD_PTR systemAffinityMask;\n\tif (GetProcessAffinityMask((HANDLE)_ProcessHandle, &processAffinityMask, &systemAffinityMask))\n\t{\n\t\t// Return the CPU mask\n\t\treturn (uint64)processAffinityMask;\n\t}\n\telse\n\t\treturn 1;\n}\n\nbool CWinProcess::setCPUMask(uint64 mask)\n{\n\t// Ask the system for number of processor available for this process\n\tDWORD_PTR processAffinityMask= (DWORD_PTR)mask;\n\treturn SetProcessAffinityMask((HANDLE)_ProcessHandle, processAffinityMask)!=0;\n}\n\n// ****************************************************************************************************************\n/**\n * Simple wrapper around the PSAPI library\n * \\author Nicolas Vizerie\n * \\author GameForge\n * \\date 2007\n */\n\nclass CPSAPILib\n{\npublic:\n\ttypedef BOOL  (WINAPI *EnumProcessesFunPtr)(DWORD *lpidProcess, DWORD cb, DWORD *cbNeeded);\n\ttypedef DWORD (WINAPI *GetModuleFileNameExAFunPtr)(HANDLE hProcess, HMODULE hModule, LPTSTR lpFilename, DWORD nSize);\n\ttypedef BOOL  (WINAPI *EnumProcessModulesFunPtr)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);\n\tEnumProcessesFunPtr\t\t  EnumProcesses;\n\tGetModuleFileNameExAFunPtr GetModuleFileNameExA;\n\tEnumProcessModulesFunPtr  EnumProcessModules;\npublic:\n\tCPSAPILib();\n\t~CPSAPILib();\n\tbool init();\nprivate:\n\tHINSTANCE _PSAPILibHandle;\n\tbool\t  _LoadFailed;\n};\n\n// ****************************************************************************************************************\nCPSAPILib::CPSAPILib()\n{\n\t_LoadFailed = false;\n\t_PSAPILibHandle     = NULL;\n\tEnumProcesses       = NULL;\n\tGetModuleFileNameExA = NULL;\n\tEnumProcessModules  = NULL;\n}\n\n// ****************************************************************************************************************\nCPSAPILib::~CPSAPILib()\n{\n\tif (_PSAPILibHandle)\n\t{\n\t\tFreeLibrary(_PSAPILibHandle);\n\t}\n}\n\n// ****************************************************************************************************************\nbool CPSAPILib::init()\n{\n\t//\n\tif (_LoadFailed) return false;\n\tif (!_PSAPILibHandle)\n\t{\n\t\t_PSAPILibHandle = LoadLibrary(\"psapi.dll\");\n\t\tif (!_PSAPILibHandle)\n\t\t{\n\t\t\tnlwarning(\"couldn't load psapi.dll, possibly not supported by os\");\n\t\t\t_LoadFailed = true;\n\t\t\treturn false;\n\t\t}\n\t\tEnumProcesses\t\t= (EnumProcessesFunPtr)\t\t  GetProcAddress(_PSAPILibHandle, \"EnumProcesses\");\n\t\tGetModuleFileNameExA = (GetModuleFileNameExAFunPtr) GetProcAddress(_PSAPILibHandle, \"GetModuleFileNameExA\");\n\t\tEnumProcessModules  = (EnumProcessModulesFunPtr)  GetProcAddress(_PSAPILibHandle, \"EnumProcessModules\");\n\t\tif (!EnumProcesses ||\n\t\t\t!GetModuleFileNameExA ||\n\t\t\t!EnumProcessModules\n\t\t   )\n\t\t{\n\t\t\tnlwarning(\"Failed to import functions from psapi.dll!\");\n\t\t\t_LoadFailed = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n\nstatic CPSAPILib PSAPILib;\n\n\n\n// ****************************************************************************************************************\nbool CWinProcess::enumProcessesId(std::vector<uint32> &processesId)\n{\n\tif (!PSAPILib.init()) return false;\n\t// list of processes\n\tstd::vector<uint32> prcIds(16);\n\tfor (;;)\n\t{\n\t\tDWORD cbNeeded;\n\t\tif (!PSAPILib.EnumProcesses((DWORD *) &prcIds[0], (DWORD)(prcIds.size() * sizeof(DWORD)), &cbNeeded))\n\t\t{\n\t\t\tnlwarning(\"Processes enumeration failed!\");\n\t\t\treturn false;\n\t\t}\n\t\tif (cbNeeded < prcIds.size() * sizeof(DWORD))\n\t\t{\n\t\t\tprcIds.resize(cbNeeded / sizeof(DWORD));\n\t\t\tbreak;\n\t\t}\n\t\t// make some more room\n\t\tprcIds.resize(prcIds.size() * 2);\n\t}\n\tprocessesId.swap(prcIds);\n\treturn true;\n}\n\n// ****************************************************************************************************************\nbool CWinProcess::enumProcessModules(uint32 processId, std::vector<std::string> &moduleNames)\n{\n\tif (!PSAPILib.init()) return false;\n\tHANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, (DWORD) processId);\n\tif (!hProcess) return false;\n\t// list of modules\n\tstd::vector<HMODULE> prcModules(2);\n\tfor (;;)\n\t{\n\t\tDWORD cbNeeded;\n\t\tif (!PSAPILib.EnumProcessModules(hProcess, (HMODULE *) &prcModules[0], (DWORD)(prcModules.size() * sizeof(HMODULE)), &cbNeeded))\n\t\t{\n\t\t\t//nlwarning(\"Processe modules enumeration failed!\");\n\t\t\treturn false;\n\t\t}\n\t\tif (cbNeeded < prcModules.size() * sizeof(HMODULE))\n\t\t{\n\t\t\tprcModules.resize(cbNeeded / sizeof(HMODULE));\n\t\t\tbreak;\n\t\t}\n\t\t// make some more room\n\t\tprcModules.resize(prcModules.size() * 2);\n\t}\n\tmoduleNames.clear();\n\tstd::vector<std::string> resultModuleNames;\n\tchar moduleName[MAX_PATH + 1];\n\tfor (uint m = 0; m < prcModules.size(); ++m)\n\t{\n\t\tif (PSAPILib.GetModuleFileNameExA(hProcess, prcModules[m], moduleName, MAX_PATH))\n\t\t{\n\t\t\tmoduleNames.push_back(moduleName);\n\t\t}\n\t}\n\tCloseHandle(hProcess);\n\treturn true;\n}\n\n// ****************************************************************************************************************\nuint32 CWinProcess::getProcessIdFromModuleFilename(const std::string &moduleFileName)\n{\n\tstd::vector<uint32> processesId;\n\tif (!enumProcessesId(processesId)) return false;\n\tstd::vector<std::string> moduleNames;\n\tfor (uint prc = 0; prc < processesId.size(); ++prc)\n\t{\n\t\tif (enumProcessModules(processesId[prc], moduleNames))\n\t\t{\n\t\t\tfor (uint m = 0; m < moduleNames.size(); ++m)\n\t\t\t{\n\t\t\t\tif (nlstricmp(CFile::getFilename(moduleNames[m]), moduleFileName) == 0)\n\t\t\t\t{\n\t\t\t\t\treturn processesId[prc];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\n// ****************************************************************************************************************\nbool CWinProcess::terminateProcess(uint32 processId, uint exitCode)\n{\n\tif (!processId) return false;\n\tHANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, (DWORD) processId);\n\tif (!hProcess) return false;\n\tBOOL ok = TerminateProcess(hProcess, (UINT) exitCode);\n\tCloseHandle(hProcess);\n\treturn ok != FALSE;\n}\n\n// ****************************************************************************************************************\nbool CWinProcess::terminateProcessFromModuleName(const std::string &moduleName, uint exitCode)\n{\n\treturn terminateProcess(getProcessIdFromModuleFilename(moduleName), exitCode);\n}\n\n\n///////////////////\n// CProcessWatch //\n///////////////////\n\n\n/*\n\n//  I didn't use and test that code, eventually, but maybe useful in the future\n\nclass CProcessWatchTask : public IRunnable\n{\npublic:\n\tHANDLE HProcess;\npublic:\n\tCProcessWatchTask(HANDLE hProcess) : HProcess(hProcess)\n\t{\n\t}\n\tvirtual void run()\n\t{\n\t\tWaitForSingleObject(HProcess, INFINITE);\n\t}\n};\n\nclass CProcessWatchImpl\n{\npublic:\n\tbool Launched;\n\tIThread\t\t\t\t*WatchThread;\n\tCProcessWatchTask\t*WatchTask;\npublic:\n\tCProcessWatchImpl() : Launched(false), WatchThread(NULL), WatchTask(NULL)\n\t{\n\t}\n\t~CProcessWatchImpl()\n\t{\n\t\treset();\n\t}\n\tvoid reset()\n\t{\n\t\tif (WatchThread)\n\t\t{\n\t\t\tif (WatchThread->isRunning())\n\t\t\t{\n\t\t\t\tWatchThread->terminate();\n\t\t\t}\n\t\t\tdelete WatchTask;\n\t\t\tdelete WatchThread;\n\t\t\tWatchTask = NULL;\n\t\t\tWatchThread = NULL;\n\t\t\tLaunched = false;\n\t\t}\n\t}\n\tbool launch(const std::string &programName, const std::string &arguments)\n\t{\n\t\tif (isRunning()) return false;\n\t\tPROCESS_INFORMATION processInfo;\n\t\tSTARTUPINFO startupInfo = {0};\n\t\tstartupInfo.cb = sizeof(STARTUPINFO);\n\t\tif (CreateProcess(programName.c_str(), const_cast<LPTSTR>(arguments.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))\n\t\t{\n\t\t\tWatchTask = new CProcessWatchTask(processInfo.hProcess);\n\t\t\tWatchThread = IThread::create(WatchTask);\n\t\t\tWatchThread->start();\n\t\t\tLaunched = true;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\tbool isRunning()\n\t{\n\t\tif (!Launched) return false;\n\t\tnlassert(WatchThread);\n\t\tnlassert(WatchTask);\n\t\tif (WatchThread->isRunning()) return true;\n\t\treset();\n\t\treturn false;\n\t}\n};\n\n\nCProcessWatch::CProcessWatch()\n{\n\t_PImpl = new CProcessWatchImpl;\n}\n\nCProcessWatch::~CProcessWatch()\n{\n\tdelete _PImpl;\n}\n\nbool CProcessWatch::launch(const std::string &programName, const std::string &arguments)\n{\n\treturn _PImpl->launch(programName, arguments);\n}\n\nbool CProcessWatch::isRunning() const\n{\n\treturn _PImpl->isRunning();\n}\n\n*/\n} // NLMISC\n\n#endif // NL_OS_WINDOWS\n"
  },
  {
    "path": "code/nel/src/misc/win_tray.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n"
  },
  {
    "path": "code/nel/src/misc/window_displayer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/path.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/thread.h\"\n\n#include \"nel/misc/window_displayer.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nclass CUpdateThread : public IRunnable\n{\n\tCWindowDisplayer *Disp;\n\tstring WindowNameEx;\n\tsint X, Y, W, H, HS;\n\tbool Iconified;\n\tuint32 FS;\n\tstring FN;\n\tbool WW;\n\tCLog *Log;\n\npublic:\n\tCUpdateThread (CWindowDisplayer *disp, string windowNameEx, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log) :\n\t  Disp(disp), WindowNameEx(windowNameEx), X(x), Y(y), W(w), H(h), HS(hs), Iconified(iconified), FS(fs), FN(fn), WW(ww), Log(log)\n\t{\n\t}\n\n\tvoid run()\n\t{\n\t\tDisp->open (WindowNameEx, Iconified, X, Y, W, H, HS, FS, FN, WW, Log);\n\t\tDisp->display_main ();\n\t}\n};\n\nCWindowDisplayer::~CWindowDisplayer ()\n{\n\t// we have to wait the exit of the thread\n\t_Continue = false;\n\tnlassert (_Thread != NULL);\n\t_Thread->wait();\n\tdelete _Thread;\n}\n\nbool CWindowDisplayer::update ()\n{\n\tvector<string> copy;\n\t{\n\t\tCSynchronized<std::vector<std::string> >::CAccessor access (&_CommandsToExecute);\n\t\tcopy = access.value();\n\t\taccess.value().clear ();\n\t}\n\n\t// execute all commands in the main thread\n\tfor (uint i = 0; i < copy.size(); i++)\n\t{\n\t\tnlassert (Log != NULL);\n\t\tICommand::execute (copy[i], *Log);\n\t}\n\n\treturn _Continue;\n}\n\nuint CWindowDisplayer::createLabel (const char *value)\n{\n\tuint pos;\n\t{\n\t\tCSynchronized<std::vector<CLabelEntry> >::CAccessor access (&_Labels);\n\t\taccess.value().push_back (CLabelEntry(value));\n\t\tpos = (uint)access.value().size()-1;\n\t}\n\treturn pos;\n}\n\nvoid CWindowDisplayer::setLabel (uint label, const string &value)\n{\n\t{\n\t\tCSynchronized<std::vector<CLabelEntry> >::CAccessor access (&_Labels);\n\t\tnlassert (label < access.value().size());\n\t\tif (access.value()[label].Value != value)\n\t\t{\n\t\t\taccess.value()[label].Value = value;\n\t\t\taccess.value()[label].NeedUpdate = true;\n\t\t}\n\t}\n}\n\nvoid CWindowDisplayer::create (string windowNameEx, bool iconified, sint x, sint y, sint w, sint h, sint hs, sint fs, const std::string &fn, bool ww, CLog *log)\n{\n\tnlassert (_Thread == NULL);\n\t_Thread = IThread::create (new CUpdateThread(this, windowNameEx, iconified, x, y, w, h, hs, fs, fn, ww, log));\n\n\tLog = log;\n\n\t_Thread->start ();\n}\n\nvoid CWindowDisplayer::doDisplay (const NLMISC::CLog::TDisplayInfo &args, const char *message)\n{\n\tbool needSpace = false;\n\t//stringstream ss;\n\tstring str;\n\n\tuint32 color = 0xFF000000;\n\n\tif (args.LogType != CLog::LOG_NO)\n\t{\n\t\tstr += logTypeToString(args.LogType);\n\t\tif (args.LogType == CLog::LOG_ERROR || args.LogType == CLog::LOG_ASSERT) color = 0x00FF0000;\n\t\telse if (args.LogType == CLog::LOG_WARNING) color = 0x00800000;\n\t\telse if (args.LogType == CLog::LOG_DEBUG) color = 0x00808080;\n\t\telse color = 0;\n\t\tneedSpace = true;\n\t}\n\n\t// Write thread identifier\n\tif ( args.ThreadId != 0 )\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n#ifdef NL_OS_WINDOWS\n\t\tstr += NLMISC::toString(\"%4x\", args.ThreadId);\n#else\n\t\tstr += NLMISC::toString(\"%08x\", args.ThreadId);\n#endif\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FileName != NULL)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(\"%20s\", CFile::getFilename(args.FileName).c_str());\n\t\tneedSpace = true;\n\t}\n\n\tif (args.Line != -1)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(\"%4u\", args.Line);\n\t\t//ss << setw(4) << args.Line;\n\t\tneedSpace = true;\n\t}\n\n\tif (args.FuncName != NULL)\n\t{\n\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\tstr += NLMISC::toString(\"%20s\", args.FuncName);\n\t\tneedSpace = true;\n\t}\n\n\tif (needSpace) { str += \": \"; needSpace = false; }\n\n\tuint nbl = 1;\n\n\tchar *npos, *pos = const_cast<char *>(message);\n\twhile ((npos = strchr (pos, '\\n')))\n\t{\n\t\t*npos = '\\0';\n\t\tstr += pos;\n\t\tif (needSlashR)\n\t\t\tstr += \"\\r\";\n\t\tstr += \"\\n\";\n\t\t*npos = '\\n';\n\t\tpos = npos+1;\n\t\tnbl++;\n\t}\n\tstr += pos;\n\n\tpos = const_cast<char *>(args.CallstackAndLog.c_str());\n\twhile ((npos = strchr (pos, '\\n')))\n\t{\n\t\t*npos = '\\0';\n\t\tstr += pos;\n\t\tif (needSlashR)\n\t\t\tstr += \"\\r\";\n\t\tstr += \"\\n\";\n\t\t*npos = '\\n';\n\t\tpos = npos+1;\n\t\tnbl++;\n\t}\n\tstr += pos;\n\n\t{\n\t\tCSynchronized<std::list<std::pair<uint32, std::string> > >::CAccessor access (&_Buffer);\n\t\tif (_HistorySize > 0 && access.value().size() >= (uint)_HistorySize)\n\t\t{\n\t\t\taccess.value().erase (access.value().begin());\n\t\t}\n\t\taccess.value().push_back (make_pair (color, str));\n\t}\n}\n\n} // NLMISC\n"
  },
  {
    "path": "code/nel/src/misc/words_dictionary.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n\n#include \"nel/misc/words_dictionary.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/diff_tool.h\"\n\nusing namespace std;\n\nconst string DefaultColTitle = \"name\";\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC {\n\nNL_INSTANCE_COUNTER_IMPL(CWordsDictionary);\n\n/*\n * Constructor\n */\nCWordsDictionary::CWordsDictionary()\n{\n}\n\n\n/* Load the config file and the related words files. Return false in case of failure.\n * Config file variables:\n * - WordsPath: where to find <filter>_words_<languageCode>.txt\n * - LanguageCode: language code (ex: en for English)\n * - Utf8: results are in UTF8, otherwise in ANSI string\n * - Filter: \"*\" for all files (default) or a name (ex: \"item\").\n * - AdditionalFiles/AdditionalFileColumnTitles\n */\nbool CWordsDictionary::init( const string& configFileName )\n{\n\t// Read config file\n\tbool cfFound = false;\n\tCConfigFile cf;\n\ttry\n\t{\n\t\tcf.load( configFileName );\n\t\tcfFound = true;\n\t}\n\tcatch (const EConfigFile &e)\n\t{\n\t\tnlwarning( \"WD: %s\", e.what() );\n\t}\n\tstring wordsPath, languageCode, filter = \"*\";\n\tvector<string> additionalFiles, additionalFileColumnTitles;\n\tbool filterAll = true, utf8 = false;\n\tif ( cfFound )\n\t{\n\t\tCConfigFile::CVar *v = cf.getVarPtr( \"WordsPath\" );\n\t\tif ( v )\n\t\t{\n\t\t\twordsPath = v->asString();\n\t\t\t/*if ( (!wordsPath.empty()) && (wordsPath[wordsPath.size()-1]!='/') )\n\t\t\t\twordsPath += '/';*/\n\t\t}\n\t\tv = cf.getVarPtr( \"LanguageCode\" );\n\t\tif ( v )\n\t\t\tlanguageCode = v->asString();\n\t\tv = cf.getVarPtr( \"Utf8\" );\n\t\tif ( v )\n\t\t\tutf8 = (v->asInt() == 1);\n\t\tv = cf.getVarPtr( \"Filter\" );\n\t\tif ( v )\n\t\t{\n\t\t\tfilter = v->asString();\n\t\t\tfilterAll = (filter == \"*\");\n\t\t}\n\t\tv = cf.getVarPtr( \"AdditionalFiles\" );\n\t\tif ( v )\n\t\t{\n\t\t\tfor ( uint i=0; i!=v->size(); ++i )\n\t\t\t\tadditionalFiles.push_back( v->asString( i ) );\n\t\t\tv = cf.getVarPtr( \"AdditionalFileColumnTitles\" );\n\t\t\tif ( v->size() != additionalFiles.size() )\n\t\t\t{\n\t\t\t\tnlwarning( \"AdditionalFiles and AdditionalFileColumnTitles have different size, ignoring second one\" );\n\t\t\t\tadditionalFileColumnTitles.resize( v->size(), DefaultColTitle );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor ( uint i=0; i!=v->size(); ++i )\n\t\t\t\t\tadditionalFileColumnTitles.push_back( v->asString( i ) );\n\t\t\t}\n\t\t}\n\n\t}\n\tif ( languageCode.empty() )\n\t\tlanguageCode = \"en\";\n\n\t// Load all found words files\n\tconst string ext = \".txt\";\n\tvector<string> fileList;\n\tCPath::getPathContent( wordsPath, false, false, true, fileList );\n\tfor ( vector<string>::const_iterator ifl=fileList.begin(); ifl!=fileList.end(); ++ifl )\n\t{\n\t\tconst string& filename = (*ifl);\n\t\tstring::size_type p = string::npos;\n\t\tbool isAdditionalFile = false;\n\n\t\t// Test if filename is in additional file list\n\t\tuint iAdditionalFile;\n\t\tfor ( iAdditionalFile=0; iAdditionalFile!=additionalFiles.size(); ++iAdditionalFile )\n\t\t{\n\t\t\tif ( (p = filename.find( additionalFiles[iAdditionalFile] )) != string::npos )\n\t\t\t{\n\t\t\t\tisAdditionalFile = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Or test if filename is a words_*.txt file\n\t\tstring pattern = string(\"_words_\") + languageCode + ext;\n\t\tif ( isAdditionalFile ||\n\t\t\t ((p = filename.find( pattern )) != string::npos) )\n\t\t{\n\t\t\t// Skip if a filter is specified and does not match the current file\n\t\t\tif ( (!filterAll) && (filename.find( filter+pattern ) == string::npos) )\n\t\t\t\tcontinue;\n\n\t\t\t// Load file\n\t\t\tnldebug( \"WD: Loading %s\", filename.c_str() );\n\t\t\t_FileList.push_back( filename );\n\t\t\tstring::size_type origSize = filename.size() - ext.size();\n\t\t\tconst string truncFilename = CFile::getFilenameWithoutExtension( filename );\n\t\t\tconst string wordType = isAdditionalFile ? \"\" : truncFilename.substr( 0, p - (origSize - truncFilename.size()) );\n\t\t\tconst string colTitle = isAdditionalFile ? additionalFileColumnTitles[iAdditionalFile] : DefaultColTitle;\n\n\t\t\t// Load Unicode Excel words file\n\t\t\tSTRING_MANAGER::TWorksheet worksheet;\n\t\t\tSTRING_MANAGER::loadExcelSheet( filename, worksheet );\n\t\t\tuint ck, cw = 0;\n\t\t\tif ( worksheet.findId( ck ) && worksheet.findCol( ucstring(colTitle), cw ) ) // =>\n\t\t\t{\n\t\t\t\tfor ( std::vector<STRING_MANAGER::TWorksheet::TRow>::iterator ip = worksheet.begin(); ip!=worksheet.end(); ++ip )\n\t\t\t\t{\n\t\t\t\t\tif ( ip == worksheet.begin() ) // skip first row\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tSTRING_MANAGER::TWorksheet::TRow& row = *ip;\n\t\t\t\t\t_Keys.push_back( row[ck].toString() );\n\t\t\t\t\tstring word = utf8 ? row[cw].toUtf8() : row[cw].toString();\n\t\t\t\t\t_Words.push_back( word );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\tnlwarning( \"WD: %s ID or %s not found in %s\", wordType.c_str(), colTitle.c_str(), filename.c_str() );\n\t\t}\n\t}\n\n\tif ( _Keys.empty() )\n\t{\n\t\tif ( wordsPath.empty() )\n\t\t\tnlwarning( \"WD: WordsPath missing in config file %s\", configFileName.c_str() );\n\t\tnlwarning( \"WD: %s_words_%s.txt not found\", filter.c_str(), languageCode.c_str() );\n\t\treturn false;\n\t}\n\telse\n\t\treturn true;\n}\n\n\n/*\n * Set the result vector with strings corresponding to the input string:\n * - If inputStr is partially or completely found in the keys, all the matching <key,words> are returned;\n * - If inputStr is partially or completely in the words, all the matching <key, words> are returned.\n * The following tags can modify the behaviour of the search algorithm:\n * - ^mystring returns mystring only if it is at the beginning of a key or word\n * - mystring$ returns mystring only if it is at the end of a key or word\n * All returned words are in UTF8.\n */\nvoid CWordsDictionary::lookup( const CSString& inputStr, CVectorSString& resultVec ) const\n{\n\t// Prepare search string\n\tif ( inputStr.empty() )\n\t\treturn;\n\n\tCSString searchStr = inputStr;\n\tbool findAtBeginning = false, findAtEnd = false;\n\tif ( searchStr[0] == '^' )\n\t{\n\t\tsearchStr = searchStr.substr( 1 );\n\t\tfindAtBeginning = true;\n\t}\n\tif ( searchStr[searchStr.size()-1] == '$' )\n\t{\n\t\tsearchStr = searchStr.rightCrop( 1 );\n\t\tfindAtEnd = true;\n\t}\n\n\t// Search\n\tfor ( CVectorSString::const_iterator ivs=_Keys.begin(); ivs!=_Keys.end(); ++ivs )\n\t{\n\t\tconst CSString& key = *ivs;\n\t\tstring::size_type p;\n\t\tif ( (p = key.findNS( searchStr.c_str() )) != string::npos )\n\t\t{\n\t\t\tif ( ((!findAtBeginning) || (p==0)) && ((!findAtEnd) || (p==key.size()-searchStr.size())) )\n\t\t\t\tresultVec.push_back( makeResult( key, _Words[ivs-_Keys.begin()] ) );\n\t\t}\n\t}\n\tfor ( CVectorSString::const_iterator ivs=_Words.begin(); ivs!=_Words.end(); ++ivs )\n\t{\n\t\tconst CSString& word = *ivs;\n\t\tstring::size_type p;\n\t\tif ( (p = word.findNS( searchStr.c_str() )) != string::npos )\n\t\t{\n\t\t\tif ( ((!findAtBeginning) || (p==0)) && ((!findAtEnd) || (p==word.size()-searchStr.size())) )\n\t\t\t\tresultVec.push_back( makeResult( _Keys[ivs-_Words.begin()], word ) );\n\t\t}\n\t}\n}\n\n\n/*\n * Set the result vector with the word(s) corresponding to the key\n */\nvoid CWordsDictionary::exactLookupByKey( const CSString& key, CVectorSString& resultVec )\n{\n\t// Search\n\tfor ( CVectorSString::const_iterator ivs=_Keys.begin(); ivs!=_Keys.end(); ++ivs )\n\t{\n\t\tif ( key == *ivs )\n\t\t\tresultVec.push_back( _Words[ivs-_Keys.begin()] );\n\t}\n}\n\n\n/*\n * Make a result string\n */\ninline CSString CWordsDictionary::makeResult( const CSString &key, const CSString &word )\n{\n\treturn key + \": \" + word.c_str();\n}\n\n\n/*\n * Return the key contained in the provided string returned by lookup() (without extension)\n */\nCSString CWordsDictionary::getWordsKey( const CSString& resultStr )\n{\n\treturn resultStr.splitTo( ':' );\n}\n\n} // NLMISC\n\n\n\n\n"
  },
  {
    "path": "code/nel/src/misc/xml_pack.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdmisc.h\"\n#include \"nel/misc/xml_pack.h\"\n#include \"nel/misc/file.h\"\n\nusing namespace std;\n\n#ifdef DEBUG_NEW\n\t#define new DEBUG_NEW\n#endif\n\nnamespace NLMISC\n{\n\n\tNLMISC_SAFE_SINGLETON_IMPL(CXMLPack);\n\n\n\t// For a simple parser, we read by line, with a limit to 1Ko\n\tconst uint32 MaxLineSize = 1*1024;\n\n\t/// Consume space and tab characters (but NOT newlines)\n\tvoid CXMLPack::skipWS(string::iterator &it, string::iterator end)\n\t{\n\t\twhile (it != end && (*it == ' ' || *it == '\\t'))\n\t\t\t++it;\n\t}\n\t/// Try to match the specified text at current position. Return false of no match\n\tbool CXMLPack::matchString(string::iterator &it, string::iterator end, const char *text)\n\t{\n\t\tstring::iterator rewind = it;\n\t\t// skip leading WS\n\t\tskipWS(it, end);\n\n\t\twhile (it != end && *text && *text == *it)\n\t\t{\n\t\t\t++it;\n\t\t\t++text;\n\t\t}\n\t\tif (*text == 0)\n\t\t{\n\t\t\t// we have advanced up to the end of text, so the match is OK\n\t\t\treturn true;\n\t\t}\n\t\t// no match !\n\t\t// rewind\n\t\tit = rewind;\n\t\treturn false;\n\t}\n\n\t/// Advance up to the beginning of the next line, incrementing the in/out param lineCount\n\tvoid CXMLPack::skipLine(string::iterator &it, string::iterator end, uint32 &lineCount)\n\t{\n\t\t// advance up to end of string or newline char\n\t\twhile (it != end && *it != '\\n')\n\t\t{\n\t\t\t++it;\n\t\t}\n\t\t// skip the new line char\n\t\tif (it != end && *it == '\\n')\n\t\t{\n\t\t\t++it;\n\t\t\t++lineCount;\n\t\t}\n\t}\n\n\n\t// Add an xml pack to the manager\n\tbool CXMLPack::add (const std::string &xmlPackFileName)\n\t{\n\t\t// prepare the container to store this pack file\n\t\tTStringId packId = CStringMapper::map(xmlPackFileName);\n\t\tTPackList::iterator packIt(_XMLPacks.find(packId));\n\t\tif (packIt != _XMLPacks.end())\n\t\t{\n\t\t\tnlwarning(\"CXMLPack::add : can't add xml_pack file '%s' because already added\", xmlPackFileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\tTXMLPackInfo &packInfo = _XMLPacks[packId];\n\n\t\t// open the xml pack for later access\n//\t\tpackInfo.FileHandler = fopen(xmlPackFileName.c_str(), \"rb\");\n\n\t\t// open the xml pack for parsing\n\t\tCIFile packFile;\n\t\tpackFile.open(xmlPackFileName);\n\n\t\tuint32 packSize = packFile.getFileSize();\n\t\tstring buffer;\n\t\tbuffer.resize(packSize);\n\n\t\t// read the file in memory for parsing\n\t\tpackFile.serialBuffer((uint8*)buffer.data(), packSize);\n\n\t\tstring::iterator it=buffer.begin(), end(buffer.end());\n\t\tuint32 lineCount = 0;\n\n\t\t// check the xml pack header element\n\t\tif (!matchString(it, end, \"<nel:packed_xml>\"))\n\t\t{\n\t\t\tnlwarning(\"Error : invalid pack file '%s', invalid header\", xmlPackFileName.c_str());\n\t\t\treturn false;\n\t\t}\n\t\t// advance to next line\n\t\tskipLine(it, end, lineCount);\n\n\t\t// now enter the sub file loop\n\t\tfor(;;)\n\t\t{\n\t\t\tTXMLFileInfo fileInfo;\n\t\t\t// match a sub file header\n\t\t\tif (!matchString(it, end, \"<nel:xml_file\"))\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid pack file content at line %u in '%s'\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// ok, extract the file name from the header, match 'name' then '=' then '\"'\n\t\t\tif (!matchString(it, end, \"name\") || !matchString(it, end, \"=\") || !matchString(it, end, \"\\\"\"))\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid pack file sub header at line %u in '%s', can't found attribute 'name'\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstring::iterator nameBegin = it;\n\t\t\t// advance up to closing quote\n\t\t\twhile (it != end && *it != '\\\"')\n\t\t\t\t++it;\n\t\t\tif (it == end)\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid pack file sub header at line %u in '%s', can't found attribute closing quote for name\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tstring subFileName(buffer, nameBegin-buffer.begin(), it-nameBegin);\n\t\t\tif (subFileName.empty())\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid pack file sub header at line %u in '%s', empty filename\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// advance to the closing '>'\n\t\t\twhile (it != end && *it != '>')\n\t\t\t\t++it;\n\t\t\tif (it == end)\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid pack file sub header at line %u in '%s', can't found element closing '>'\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// advance to next line (beginning of sub file)\n\t\t\tskipLine(it, end, lineCount);\n\n\t\t\tstring::iterator beginOfFile = it;\n\t\t\tstring::iterator endOfFile = it;\n\n\t\t\t// now, advance up to the end of file\n\t\t\twhile (it != end && !matchString(it, end, \"</nel:xml_file>\"))\n\t\t\t{\n\t\t\t\tskipLine(it, end, lineCount);\n\t\t\t\tendOfFile = it;\n\t\t\t}\n\n\t\t\t// we must not be at end of file\n\t\t\tif (it == end)\n\t\t\t{\n\t\t\t\tnlwarning(\"Error : invalid sub file at line %u in '%s', reach end of file without closing file and pack elements\", lineCount, xmlPackFileName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// ok, the file is parsed, store it\n\t\t\tfileInfo.FileName = CStringMapper::map(subFileName);\n\t\t\tfileInfo.FileOffset = (uint32)(beginOfFile - buffer.begin());\n\t\t\tfileInfo.FileSize = (uint32)(endOfFile - beginOfFile);\n//\t\t\tfileInfo.FileHandler = fopen(xmlPackFileName.c_str(), \"rb\");\n\t\t\tpackInfo._XMLFiles.insert(make_pair(fileInfo.FileName, fileInfo));\n\n\t\t\t// advance to next line\n\t\t\tskipLine(it, end, lineCount);\n\n\t\t\t// check for end of pack\n\t\t\tif (matchString(it, end, \"</nel:packed_xml>\"))\n\t\t\t{\n\t\t\t\t// ok, the parse is over\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// continue to next file in pack\n\t\t}\n\n\t\tnldebug(\"XMLPack : xml_pack '%s' added to the collection with %u files\", xmlPackFileName.c_str(), packInfo._XMLFiles.size());\n\t\t// ok, parsing ended\n\t\treturn true;\n\t}\n\n\t// List all files in an xml_pack file\n\tvoid CXMLPack::list (const std::string &xmlPackFileName, std::vector<std::string> &allFiles)\n\t{\n\t\tTStringId key = CStringMapper::map(xmlPackFileName);\n\n\t\tTPackList::const_iterator it(_XMLPacks.find(key));\n\t\tif (it != _XMLPacks.end())\n\t\t{\n\t\t\tconst TXMLPackInfo &packInfo = it->second;\n\t\t\t// we found it, fill the out vector\n\t\t\tTXMLPackInfo::TFileList::const_iterator first(packInfo._XMLFiles.begin()), last(packInfo._XMLFiles.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst TXMLFileInfo &fileInfo = first->second;\n\t\t\t\tallFiles.push_back(CStringMapper::unmap(fileInfo.FileName));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Used by CIFile to get information about the files within the xml pack\n\tFILE* CXMLPack::getFile (const std::string &sFileName, uint32 &rFileSize, uint32 &rFileOffset,\n\t\t\t\t\t\tbool &rCacheFileOnOpen, bool &rAlwaysOpened)\n\t{\n\t\t// split the name appart from the '@@' separator to get the pack file name\n\t\t// and subfile name\n\t\tvector<string>\tparts;\n\t\texplode(sFileName, string(\"@@\"), parts, true);\n\t\tif (parts.size() != 2)\n\t\t{\n\t\t\tnlwarning(\"CXMLPack::getFile : Can't extract pack and filename from '%s', found %u part instead of 2 when spliting apart from '@@'\",\n\t\t\t\tsFileName.c_str(),\n\t\t\t\tparts.size());\n\t\t\treturn NULL;\n\t\t}\n\n\t\tTStringId packId = CStringMapper::map(parts[0]);\n\t\tTStringId fileId = CStringMapper::map(parts[1]);\n\n\t\tTPackList::iterator packIt(_XMLPacks.find(packId));\n\t\tif (packIt == _XMLPacks.end())\n\t\t{\n\t\t\tnlwarning(\"CXMLPack::getFile : Can't find xml pack file named '%s' to open '%s'\", parts[0].c_str(), sFileName.c_str());\n\t\t\treturn NULL;\n\t\t}\n\t\tTXMLPackInfo &packInfo = packIt->second;\n\t\tTXMLPackInfo::TFileList::iterator fileIt = packInfo._XMLFiles.find(fileId);\n\t\tif (fileIt == packInfo._XMLFiles.end())\n\t\t{\n\t\t\tnlwarning(\"CXMLPack::getFile : Can't find xml file named '%s' in pack '%s'\",\n\t\t\t\tparts[1].c_str(), parts[0].c_str());\n\t\t\treturn NULL;\n\t\t}\n\n\t\t// ok, we have found it !\n\t\tTXMLFileInfo &fileInfo = fileIt->second;\n\n\t\t// fill the return value\n\t\trFileSize = fileInfo.FileSize;\n\t\trFileOffset = fileInfo.FileOffset;\n\t\trCacheFileOnOpen = false;\n\t\trAlwaysOpened = false;\n\t\tFILE *fp = fopen(parts[0].c_str(), \"rb\");\n\t\treturn fp;\n\t}\n\n\n} // namespace NLMISC\n\n"
  },
  {
    "path": "code/nel/src/net/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\nFILE(GLOB HEADERS ../../include/nel/net/*.h)\nFILE(GLOB NET_MANAGER \"net_manager.*\")\nLIST(REMOVE_ITEM SRC ${NET_MANAGER})\n\nNL_TARGET_LIB(nelnet ${HEADERS} ${SRC})\n\nINCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR} ${LIBEVENT_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})\n\nIF(WITH_GTK)\n  IF(GTK2_FOUND)\n    INCLUDE_DIRECTORIES(${GTK2_INCLUDE_DIRS})\n    ADD_DEFINITIONS(-DNL_USE_GTK)\n  ENDIF(GTK2_FOUND)\nENDIF(WITH_GTK)\n\nIF(WIN32)\n  TARGET_LINK_LIBRARIES(nelnet crypt32)\nENDIF(WIN32)\n\nTARGET_LINK_LIBRARIES(nelnet nelmisc ${OPENSSL_LIBRARIES} ${PROTOBUF_LIBRARIES} ${LIBEVENT_LIBRARY} ${LIBEVENT_OPENSSL_LIBRARY})\n\n\nSET_TARGET_PROPERTIES(nelnet PROPERTIES LINK_INTERFACE_LIBRARIES \"\")\nNL_DEFAULT_PROPS(nelnet \"NeL, Library: NeL Net\")\nNL_ADD_RUNTIME_FLAGS(nelnet)\n\nNL_ADD_LIB_SUFFIX(nelnet)\n\nIF(WITH_PCH)\n  ADD_NATIVE_PRECOMPILED_HEADER(nelnet ${CMAKE_CURRENT_SOURCE_DIR}/stdnet.h ${CMAKE_CURRENT_SOURCE_DIR}/stdnet.cpp)\nENDIF(WITH_PCH)\n\nNL_GEN_PC(nel-net.pc)\n\nIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n  INSTALL(TARGETS nelnet LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries)\nENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)\n"
  },
  {
    "path": "code/nel/src/net/admin.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n//\n// Includes\n//\n\n#include \"stdnet.h\"\n\n#include \"nel/net/service.h\"\n#include \"nel/net/admin.h\"\n#include \"nel/net/varpath.h\"\n\n\n//\n// Namspaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n\nnamespace NLNET {\n\n\n//\n// Structures\n//\n\nstruct CRequest\n{\n\tCRequest (uint32 id, TServiceId sid) : Id(id), NbWaiting(0), NbReceived(0), SId(sid)\n\t{\n\t\tnldebug (\"ADMIN: ++ NbWaiting %d NbReceived %d\", NbWaiting, NbReceived);\n\t\tTime = CTime::getSecondsSince1970 ();\n\t}\n\n\tuint32\t\t\tId;\n\tuint\t\t\tNbWaiting;\n\tuint32\t\t\tNbReceived;\n\tTServiceId\t\t\tSId;\n\tuint32\t\t\tTime;\t// when the request was ask\n\n\tTAdminViewResult Answers;\n};\n\n\n//\n// Variables\n//\n\nTRemoteClientCallback RemoteClientCallback = 0;\n\nvector<CAlarm> Alarms;\n\nvector<CGraphUpdate> GraphUpdates;\n\n// check alarms every 5 seconds\nconst uint32 AlarmCheckDelay = 5;\n\nvector<CRequest> Requests;\n\nuint32 RequestTimeout = 4;\t// in second\n\n\n//\n// Callbacks\n//\n\nstatic void cbInfo (CMessage &msgin, const std::string &/* serviceName */, TServiceId /* sid */)\n{\n\tnlinfo (\"ADMIN: Updating admin information\");\n\n\tvector<string> alarms;\n\tmsgin.serialCont (alarms);\n\tvector<string> graphupdate;\n\tmsgin.serialCont (graphupdate);\n\n\tsetInformation (alarms, graphupdate);\n}\n\nstatic void cbServGetView (CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)\n{\n\tuint32 rid;\n\tstring rawvarpath;\n\n\tmsgin.serial (rid);\n\tmsgin.serial (rawvarpath);\n\n\tRequests.push_back (CRequest(rid, sid));\n\n\tTAdminViewResult answer;\n\t// just send the view in async mode, don't retrieve the answer\n\tserviceGetView (rid, rawvarpath, answer, true);\n\tnlassert (answer.empty());\n}\n\nstatic void cbExecCommand (CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)\n{\n\t// create a displayer to gather the output of the command\n\tclass CStringDisplayer: public IDisplayer\n\t{\n\tpublic:\n\t\tvoid serial(NLMISC::IStream &stream)\n\t\t{\n\t\t\tstream.serial(_Data);\n\t\t}\n\n\tprotected:\n\t\tvirtual void doDisplay( const CLog::TDisplayInfo& /* args */, const char *message)\n\t\t{\n\t\t\t_Data += message;\n\t\t}\n\n\t\tstd::string _Data;\n\t};\n\tCStringDisplayer stringDisplayer;\n\tIService::getInstance()->CommandLog.addDisplayer(&stringDisplayer);\n\n\t// retreive the command from the input message and execute it\n\tstring command;\n\tmsgin.serial (command);\n\tnlinfo (\"ADMIN: Executing command from network : '%s'\", command.c_str());\n\tICommand::execute (command, IService::getInstance()->CommandLog);\n\n\t// unhook our displayer as it's work is now done\n\tIService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer);\n\n\t// send a reply message to the originating service\n\tCMessage msgout(\"EXEC_COMMAND_RESULT\");\n\tstringDisplayer.serial(msgout);\n\tCUnifiedNetwork::getInstance()->send(sid, msgout);\n}\n\n\n// AES wants to know if i'm not dead, I have to answer faster as possible or i'll be killed\nstatic void cbAdminPing (CMessage &/* msgin */, const std::string &/* serviceName */, TServiceId sid)\n{\n\t// Send back a pong to say to the AES that I'm alive\n\tCMessage msgout(\"ADMIN_PONG\");\n\tCUnifiedNetwork::getInstance()->send(sid, msgout);\n}\n\nstatic void cbStopService (CMessage &/* msgin */, const std::string &serviceName, TServiceId sid)\n{\n\tnlinfo (\"ADMIN: Receive a stop from service %s-%hu, need to quit\", serviceName.c_str(), sid.get());\n\tIService::getInstance()->exit (0xFFFF);\n}\n\n\nvoid cbAESConnection (const string &/* serviceName */, TServiceId /* sid */, void * /* arg */)\n{\n\t// established a connection to the AES, identify myself\n\n\t//\n\t// Sends the identification message with the name of the service and all commands available on this service\n\t//\n\n\tnlinfo(\"cbAESConnection: Identifying self as: AliasName='%s' LongName='%s' PId=%u\",\n\t\tIService::getInstance()->_AliasName.c_str(),\n\t\tIService::getInstance()->_LongName.c_str(),\n\t\tgetpid ());\n\tCMessage msgout (\"SID\");\n\tuint32 pid = getpid ();\n\tmsgout.serial (IService::getInstance()->_AliasName, IService::getInstance()->_LongName, pid);\n\tICommand::serialCommands (msgout);\n\tCUnifiedNetwork::getInstance()->send(\"AES\", msgout);\n\n\tif (IService::getInstance()->_Initialized)\n\t{\n\t\tCMessage msgout2 (\"SR\");\n\t\tCUnifiedNetwork::getInstance()->send(\"AES\", msgout2);\n\t}\n}\n\n\nstatic void cbAESDisconnection (const std::string &serviceName, TServiceId sid, void * /* arg */)\n{\n\tnlinfo(\"Lost connection to the %s-%hu\", serviceName.c_str(), sid.get());\n}\n\n\nstatic TUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"INFO\",\t\t\tcbInfo },\n\t{ \"GET_VIEW\",\t\tcbServGetView },\n\t{ \"STOPS\",\t\t\tcbStopService },\n\t{ \"EXEC_COMMAND\",\tcbExecCommand },\n\t{ \"ADMIN_PING\",\t\tcbAdminPing },\n};\n\n\n//\n// Functions\n//\n\nvoid setRemoteClientCallback (TRemoteClientCallback cb)\n{\n\tRemoteClientCallback = cb;\n}\n\n\n//\n// Request functions\n//\n\nstatic void addRequestWaitingNb (uint32 rid)\n{\n\tfor (uint i = 0 ; i < Requests.size (); i++)\n\t{\n\t\tif (Requests[i].Id == rid)\n\t\t{\n\t\t\tRequests[i].NbWaiting++;\n\t\t\tnldebug (\"ADMIN: ++ i %d rid %d NbWaiting+ %d NbReceived %d\", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);\n\t\t\t// if we add a waiting, reset the timer\n\t\t\tRequests[i].Time = CTime::getSecondsSince1970 ();\n\t\t\treturn;\n\t\t}\n\t}\n\tnlwarning (\"ADMIN: addRequestWaitingNb: can't find the rid %d\", rid);\n}\n\n/*\nstatic void subRequestWaitingNb (uint32 rid)\n{\n\tfor (uint i = 0 ; i < Requests.size (); i++)\n\t{\n\t\tif (Requests[i].Id == rid)\n\t\t{\n\t\t\tRequests[i].NbWaiting--;\n\t\t\tnldebug (\"ADMIN: ++ i %d rid %d NbWaiting- %d NbReceived %d\", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);\n\t\t\treturn;\n\t\t}\n\t}\n\tnlwarning (\"ADMIN: subRequestWaitingNb: can't find the rid %d\", rid);\n}\n*/\n\nvoid addRequestAnswer (uint32 rid, const TAdminViewVarNames& varNames, const TAdminViewValues& values)\n{\n\tif (!varNames.empty() && varNames[0] == \"__log\")\n\t{\tnlassert (varNames.size() == 1); }\n\telse\n\t{\tnlassert (varNames.size() == values.size()); }\n\n\tfor (uint i = 0 ; i < Requests.size (); i++)\n\t{\n\t\tif (Requests[i].Id == rid)\n\t\t{\n\t\t\tRequests[i].Answers.push_back (SAdminViewRow(varNames, values));\n\n\t\t\tRequests[i].NbReceived++;\n\t\t\tnldebug (\"ADMIN: ++ i %d rid %d NbWaiting %d NbReceived+ %d\", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);\n\n\t\t\treturn;\n\t\t}\n\t}\n\t// we received an unknown request, forget it\n\tnlwarning (\"ADMIN: Receive an answer for unknown request %d\", rid);\n}\n\n/*\nstatic bool emptyRequest (uint32 rid)\n{\n\tfor (uint i = 0 ; i < Requests.size (); i++)\n\t{\n\t\tif (Requests[i].Id == rid && Requests[i].NbWaiting != 0)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n*/\n\nstatic void cleanRequest ()\n{\n\tuint32 currentTime = CTime::getSecondsSince1970 ();\n\n\tfor (uint i = 0 ; i < Requests.size ();)\n\t{\n\t\t// timeout\n\t\tif (currentTime >= Requests[i].Time+RequestTimeout)\n\t\t{\n\t\t\tnlwarning (\"ADMIN: **** i %d rid %d -> Requests[i].NbWaiting (%d) != Requests[i].NbReceived (%d)\", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);\n\t\t\tRequests[i].NbWaiting = Requests[i].NbReceived;\n\t\t}\n\n\t\tif (Requests[i].NbWaiting <= Requests[i].NbReceived)\n\t\t{\n\t\t\t// the request is over, send to the php\n\n\t\t\tCMessage msgout(\"VIEW\");\n\t\t\tmsgout.serial (Requests[i].Id);\n\n\t\t\tfor (uint j = 0; j < Requests[i].Answers.size (); j++)\n\t\t\t{\n\t\t\t\tmsgout.serialCont (Requests[i].Answers[j].VarNames);\n\t\t\t\tmsgout.serialCont (Requests[i].Answers[j].Values);\n\t\t\t}\n\n\t\t\tif (Requests[i].SId.get() == 0)\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: Receive an answer for the fake request %d with %d answers\", Requests[i].Id, Requests[i].Answers.size ());\n\t\t\t\tfor (uint j = 0; j < Requests[i].Answers.size (); j++)\n\t\t\t\t{\n\t\t\t\t\tuint k;\n\t\t\t\t\tfor (k = 0; k < Requests[i].Answers[j].VarNames.size(); k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tInfoLog->displayRaw (\"%-10s\", Requests[i].Answers[j].VarNames[k].c_str());\n\t\t\t\t\t}\n\t\t\t\t\tInfoLog->displayRawNL(\"\");\n\t\t\t\t\tfor (k = 0; k < Requests[i].Answers[j].Values.size(); k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tInfoLog->displayRaw (\"%-10s\", Requests[i].Answers[j].Values[k].c_str());\n\t\t\t\t\t}\n\t\t\t\t\tInfoLog->displayRawNL(\"\");\n\t\t\t\t\tInfoLog->displayRawNL(\"-------------------------\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: The request is over, send the result to AES\");\n\t\t\t\tCUnifiedNetwork::getInstance ()->send (Requests[i].SId, msgout);\n\t\t\t}\n\n\t\t\t// set to 0 to erase it\n\t\t\tRequests[i].NbWaiting = 0;\n\t\t\tnldebug (\"ADMIN: ++ i %d rid %d NbWaiting0 %d NbReceived %d\", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);\n\t\t}\n\n\t\tif (Requests[i].NbWaiting == 0)\n\t\t{\n\t\t\tRequests.erase (Requests.begin ()+i);\n\t\t}\n\t\telse\n\t\t{\n\t\t\ti++;\n\t\t}\n\t}\n}\n\n// all remote command start with rc or RC\nbool isRemoteCommand(string &str)\n{\n\tif (str.size()<2) return false;\n\treturn tolower(str[0]) == 'r' && tolower(str[1]) == 'c';\n}\n\n\n// this callback is used to create a view for the admin system\nvoid serviceGetView (uint32 rid, const string &rawvarpath, TAdminViewResult &answer, bool async)\n{\n\tstring str;\n\tCLog logDisplayVars;\n\tCLightMemDisplayer mdDisplayVars;\n\tlogDisplayVars.addDisplayer (&mdDisplayVars);\n\tmdDisplayVars.setParam (4096);\n\n\tCVarPath varpath(rawvarpath);\n\n\tif (varpath.empty())\n\t\treturn;\n\n\t// special case for named command handler\n\tif (CCommandRegistry::getInstance().isNamedCommandHandler(varpath.Destination[0].first))\n\t{\n\t\tvarpath.Destination[0].first += \".\"+varpath.Destination[0].second;\n\t\tvarpath.Destination[0].second = \"\";\n\t}\n\n\tif (varpath.isFinal())\n\t{\n\t\tTAdminViewVarNames varNames;\n\t\tTAdminViewValues values;\n\n\t\t// add default row\n\t\tvarNames.push_back (\"service\");\n\t\tvalues.push_back (IService::getInstance ()->getServiceUnifiedName());\n\n\t\tfor (uint j = 0; j < varpath.Destination.size (); j++)\n\t\t{\n\t\t\tstring cmd = varpath.Destination[j].first;\n\n\t\t\t// replace = with space to execute the command\n\t\t\tstring::size_type eqpos = cmd.find(\"=\");\n\t\t\tif (eqpos != string::npos)\n\t\t\t{\n\t\t\t\tcmd[eqpos] = ' ';\n\t\t\t\tvarNames.push_back(cmd.substr(0, eqpos));\n\t\t\t}\n\t\t\telse\n\t\t\t\tvarNames.push_back(cmd);\n\n\t\t\tmdDisplayVars.clear ();\n\t\t\tICommand::execute(cmd, logDisplayVars, !ICommand::isCommand(cmd));\n\t\t\tconst std::deque<std::string>\t&strs = mdDisplayVars.lockStrings();\n\n\t\t\tif (ICommand::isCommand(cmd))\n\t\t\t{\n\t\t\t\t// we want the log of the command\n\t\t\t\tif (j == 0)\n\t\t\t\t{\n\t\t\t\t\tvarNames.clear ();\n\t\t\t\t\tvarNames.push_back (\"__log\");\n\t\t\t\t\tvalues.clear ();\n\t\t\t\t}\n\n\t\t\t\tvalues.push_back (\"----- Result from \"+IService::getInstance()->getServiceUnifiedName()+\" of command '\"+cmd+\"'\\n\");\n\t\t\t\tfor (uint k = 0; k < strs.size(); k++)\n\t\t\t\t{\n\t\t\t\t\tvalues.push_back (strs[k]);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\n\t\t\t\tif (strs.size()>0)\n\t\t\t\t{\n\t\t\t\t\tstr = strs[0].substr(0,strs[0].size()-1);\n\t\t\t\t\t// replace all spaces into udnerscore because space is a reserved char\n\t\t\t\t\tfor (uint i = 0; i < str.size(); i++) if (str[i] == ' ') str[i] = '_';\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstr = \"???\";\n\t\t\t\t}\n\t\t\t\tvalues.push_back (str);\n\t\t\t\tnlinfo (\"ADMIN: Add to result view '%s' = '%s'\", varpath.Destination[j].first.c_str(), str.c_str());\n\t\t\t}\n\t\t\tmdDisplayVars.unlockStrings();\n\t\t}\n\n\t\tif (!async)\n\t\t\tanswer.push_back (SAdminViewRow(varNames, values));\n\t\telse\n\t\t{\n\t\t\taddRequestWaitingNb (rid);\n\t\t\taddRequestAnswer (rid, varNames, values);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// there s an entity in the varpath, manage this case\n\n\t\tTAdminViewVarNames *varNames=0;\n\t\tTAdminViewValues *values=0;\n\n\t\t// varpath.Destination\t\tcontains the entity number\n\t\t// subvarpath.Destination\tcontains the command name\n\n\t\tfor (uint i = 0; i < varpath.Destination.size (); i++)\n\t\t{\n\t\t\tCVarPath subvarpath(varpath.Destination[i].second);\n\n\t\t\tfor (uint j = 0; j < subvarpath.Destination.size (); j++)\n\t\t\t{\n\t\t\t\t// set the variable name\n\t\t\t\tstring cmd = subvarpath.Destination[j].first;\n\n\t\t\t\tif (isRemoteCommand(cmd))\n\t\t\t\t{\n\t\t\t\t\tif (async && RemoteClientCallback != 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// ok we have to send the request to another side, just send and wait\n\t\t\t\t\t\taddRequestWaitingNb (rid);\n\t\t\t\t\t\tRemoteClientCallback (rid, cmd, varpath.Destination[i].first);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// replace = with space to execute the command\n\t\t\t\t\tstring::size_type eqpos = cmd.find(\"=\");\n\t\t\t\t\tif (eqpos != string::npos)\n\t\t\t\t\t{\n\t\t\t\t\t\tcmd[eqpos] = ' ';\n\t\t\t\t\t\t// add the entity\n\t\t\t\t\t\tcmd.insert(eqpos, \" \"+varpath.Destination[i].first);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// add the entity\n\t\t\t\t\t\tcmd += \" \"+varpath.Destination[i].first;\n\t\t\t\t\t}\n\n\t\t\t\t\tmdDisplayVars.clear ();\n\t\t\t\t\tICommand::execute(cmd, logDisplayVars, true);\n\t\t\t\t\tconst std::deque<std::string>\t&strs = mdDisplayVars.lockStrings();\n\t\t\t\t\tfor (uint k = 0; k < strs.size(); k++)\n\t\t\t\t\t{\n\t\t\t\t\t\tconst string &str = strs[k];\n\n\t\t\t\t\t\tstring::size_type pos = str.find(\" \");\n\t\t\t\t\t\tif(pos == string::npos)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tstring entity = str.substr(0, pos);\n\t\t\t\t\t\tstring value = str.substr(pos+1, str.size()-pos-2);\n\t\t\t\t\t\tfor (uint u = 0; u < value.size(); u++) if (value[u] == ' ') value[u] = '_';\n\n\t\t\t\t\t\t// look in the array if we already have something about this entity\n\n\t\t\t\t\t\tif (!async)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuint y;\n\t\t\t\t\t\t\tfor (y = 0; y < answer.size(); y++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (answer[y].Values[1] == entity)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// ok we found it, just push_back new stuff\n\t\t\t\t\t\t\t\t\tvarNames = &(answer[y].VarNames);\n\t\t\t\t\t\t\t\t\tvalues = &(answer[y].Values);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (y == answer.size ())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tanswer.push_back (SAdminViewRow());\n\n\t\t\t\t\t\t\t\tvarNames = &(answer[answer.size()-1].VarNames);\n\t\t\t\t\t\t\t\tvalues = &(answer[answer.size()-1].Values);\n\n\t\t\t\t\t\t\t\t// don't add service if we want an entity\n\t\t// todo when we work on entity, we don't need service name and server so we should remove them and collapse all var for the same entity\n\t\t\t\t\t\t\t\tvarNames->push_back (\"service\");\n\t\t\t\t\t\t\t\tstring name = IService::getInstance ()->getServiceUnifiedName();\n\t\t\t\t\t\t\t\tvalues->push_back (name);\n\n\t\t\t\t\t\t\t\t// add default row\n\t\t\t\t\t\t\t\tvarNames->push_back (\"entity\");\n\t\t\t\t\t\t\t\tvalues->push_back (entity);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tvarNames->push_back (cmd.substr(0, cmd.find(\" \")));\n\t\t\t\t\t\t\tvalues->push_back (value);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taddRequestWaitingNb (rid);\n\n\t\t\t\t\t\t\tTAdminViewVarNames varNames;\n\t\t\t\t\t\t\tTAdminViewValues values;\n\t\t\t\t\t\t\tvarNames.push_back (\"service\");\n\t\t\t\t\t\t\tstring name = IService::getInstance ()->getServiceUnifiedName();\n\t\t\t\t\t\t\tvalues.push_back (name);\n\n\t\t\t\t\t\t\t// add default row\n\t\t\t\t\t\t\tvarNames.push_back (\"entity\");\n\t\t\t\t\t\t\tvalues.push_back (entity);\n\n\t\t\t\t\t\t\tvarNames.push_back (cmd.substr(0, cmd.find(\" \")));\n\t\t\t\t\t\t\tvalues.push_back (value);\n\n\t\t\t\t\t\t\taddRequestAnswer (rid, varNames, values);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnlinfo (\"ADMIN: Add to result view for entity '%s', '%s' = '%s'\", varpath.Destination[i].first.c_str(), subvarpath.Destination[j].first.c_str(), str.c_str());\n\t\t\t\t\t}\n\t\t\t\t\tmdDisplayVars.unlockStrings();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n//\n// Alarms functions\n//\n\nvoid sendAdminEmail (const char *format, ...)\n{\n\tchar *text;\n\tNLMISC_CONVERT_VARGS (text, format, 4096);\n\n\ttime_t t = time (&t);\n\n\tstring str;\n\tstr  = asctime (localtime (&t));\n\tstr += \" Server \" + IService::getInstance()->getHostName();\n\tstr += \" service \" + IService::getInstance()->getServiceUnifiedName();\n\tstr += \" : \";\n\tstr += text;\n\n\tCMessage msgout(\"ADMIN_EMAIL\");\n\tmsgout.serial (str);\n\tif(IService::getInstance ()->getServiceShortName()==\"AES\")\n\t\tCUnifiedNetwork::getInstance ()->send (\"AS\", msgout);\n\telse\n\t\tCUnifiedNetwork::getInstance ()->send (\"AES\", msgout);\n\n\tnlinfo (\"ADMIN: Forwarded email to AS with '%s'\", str.c_str());\n}\n\nvoid initAdmin (bool dontUseAES)\n{\n\tif (!dontUseAES)\n\t{\n\t\tCUnifiedNetwork::getInstance()->setServiceUpCallback (\"AES\", cbAESConnection, NULL);\n\t\tCUnifiedNetwork::getInstance()->setServiceDownCallback (\"AES\", cbAESDisconnection, NULL);\n\t\tCUnifiedNetwork::getInstance()->addService (\"AES\", CInetAddress(\"localhost:49997\"));\n\t}\n\tCUnifiedNetwork::getInstance()->addCallbackArray (CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));\n}\n\n\nvoid updateAdmin()\n{\n\tuint32 CurrentTime = CTime::getSecondsSince1970();\n\n\n\t//\n\t// check admin requests\n\t//\n\n\tcleanRequest ();\n\n\n\t//\n\t// Check graph updates\n\t//\n\n\tstatic uint32 lastGraphUpdateCheck = 0;\n\n\tif (CurrentTime >= lastGraphUpdateCheck+1)\n\t{\n\t\tstring str;\n\t\tCLog logDisplayVars;\n\t\tCLightMemDisplayer mdDisplayVars;\n\t\tlogDisplayVars.addDisplayer (&mdDisplayVars);\n\n\t\tlastGraphUpdateCheck = CurrentTime;\n\n\t\tCMessage msgout (\"GRAPH_UPDATE\");\n\t\tbool empty = true;\n\t\tfor (uint j = 0; j < GraphUpdates.size(); j++)\n\t\t{\n\t\t\tif (CurrentTime >= GraphUpdates[j].LastUpdate + GraphUpdates[j].Update)\n\t\t\t{\n\t\t\t\t// have to send a new update for this var\n\t\t\t\tICommand::execute(GraphUpdates[j].Name, logDisplayVars, true, false);\n\t\t\t\tconst std::deque<std::string>\t&strs = mdDisplayVars.lockStrings();\n\t\t\t\tsint32 val;\n\t\t\t\tif (strs.size() != 1)\n\t\t\t\t{\n\t\t\t\t\tnlwarning (\"ADMIN: The graph update command execution not return exactly 1 line but %d\", strs.size());\n\t\t\t\t\tfor (uint i = 0; i < strs.size(); i++)\n\t\t\t\t\t  nlwarning (\"ADMIN: line %d: '%s'\", i, strs[i].c_str());\n\t\t\t\t\tval = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfromString(strs[0], val);\n\t\t\t\t}\n\t\t\t\tmdDisplayVars.unlockStrings ();\n\t\t\t\tmdDisplayVars.clear ();\n\n\t\t\t\tstring name = IService::getInstance()->getServiceAliasName();\n\t\t\t\tif (name.empty())\n\t\t\t\t\tname = IService::getInstance()->getServiceShortName();\n\n\t\t\t\tif(empty)\n\t\t\t\t\tmsgout.serial (CurrentTime);\n\n\t\t\t\tmsgout.serial (name);\n\t\t\t\tmsgout.serial (GraphUpdates[j].Name);\n\t\t\t\tmsgout.serial (val);\n\n\t\t\t\tempty = false;\n\n\t\t\t\tGraphUpdates[j].LastUpdate = CurrentTime;\n\t\t\t}\n\t\t}\n\n\t\tif(!empty)\n\t\t{\n\t\t\tif(IService::getInstance ()->getServiceShortName()==\"AES\")\n\t\t\t\tCUnifiedNetwork::getInstance ()->send (\"AS\", msgout);\n\t\t\telse\n\t\t\t\tCUnifiedNetwork::getInstance ()->send (\"AES\", msgout);\n\t\t}\n\t}\n\n\n\t//\n\t// Check alarms\n\t//\n\n\tstatic uint32 lastAlarmsCheck = 0;\n\n\tif (CurrentTime >= lastAlarmsCheck+AlarmCheckDelay)\n\t{\n\t\tstring str;\n\t\tCLog logDisplayVars;\n\t\tCLightMemDisplayer mdDisplayVars;\n\t\tlogDisplayVars.addDisplayer (&mdDisplayVars);\n\n\t\tlastAlarmsCheck = CTime::getSecondsSince1970();\n\n\t\tfor (uint i = 0; i < Alarms.size(); )\n\t\t{\n\t\t\tmdDisplayVars.clear ();\n\t\t\tICommand::execute(Alarms[i].Name, logDisplayVars, true, false);\n\t\t\tconst std::deque<std::string>\t&strs = mdDisplayVars.lockStrings();\n\n\t\t\tif (strs.size()>0)\n\t\t\t{\n\t\t\t\tstr = strs[0].substr(0,strs[0].size()-1);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tstr = \"???\";\n\t\t\t}\n\n\t\t\tmdDisplayVars.unlockStrings();\n\n\t\t\tif (str == \"???\")\n\t\t\t{\n\t\t\t\t// variable doesn't exist, remove it from alarms\n\t\t\t\tnlwarning (\"ADMIN: Alarm problem: variable '%s' returns ??? instead of a good value\", Alarms[i].Name.c_str());\n\t\t\t\tAlarms.erase (Alarms.begin()+i);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// compare the value\n\t\t\t\tuint32 err = Alarms[i].Limit;\n\t\t\t\tuint32 val = humanReadableToBytes(str);\n\t\t\t\tif (Alarms[i].GT && val >= err)\n\t\t\t\t{\n\t\t\t\t\tif (!Alarms[i].Activated)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo (\"ADMIN: VARIABLE TOO BIG '%s' %u >= %u\", Alarms[i].Name.c_str(), val, err);\n\t\t\t\t\t\tAlarms[i].Activated = true;\n\t\t\t\t\t\tsendAdminEmail (\"Alarm: Variable %s is %u that is greater or equal than the limit %u\", Alarms[i].Name.c_str(), val, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (!Alarms[i].GT && val <= err)\n\t\t\t\t{\n\t\t\t\t\tif (!Alarms[i].Activated)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo (\"ADMIN: VARIABLE TOO LOW '%s' %u <= %u\", Alarms[i].Name.c_str(), val, err);\n\t\t\t\t\t\tAlarms[i].Activated = true;\n\t\t\t\t\t\tsendAdminEmail (\"Alarm: Variable %s is %u that is lower or equal than the limit %u\", Alarms[i].Name.c_str(), val, err);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (Alarms[i].Activated)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo (\"ADMIN: variable is ok '%s' %u %s %u\", Alarms[i].Name.c_str(), val, (Alarms[i].GT?\"<\":\">\"), err);\n\t\t\t\t\t\tAlarms[i].Activated = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid setInformation (const vector<string> &alarms, const vector<string> &graphupdate)\n{\n\tuint i;\n\tsint tmp;\n\n\t// add only commands that I understand\n\tAlarms.clear ();\n\tfor (i = 0; i < alarms.size(); i+=3)\n\t{\n\t\tCVarPath shardvarpath (alarms[i]);\n\t\tif(shardvarpath.Destination.size() == 0 || shardvarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\t\tCVarPath servervarpath (shardvarpath.Destination[0].second);\n\t\tif(servervarpath.Destination.size() == 0 || servervarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\t\tCVarPath servicevarpath (servervarpath.Destination[0].second);\n\t\tif(servicevarpath.Destination.size() == 0 || servicevarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\n\t\tstring name = servicevarpath.Destination[0].second;\n\n\t\tif (IService::getInstance()->getServiceUnifiedName().find(servicevarpath.Destination[0].first) != string::npos && ICommand::exists(name))\n\t\t{\n\t\t\tfromString(alarms[i+1], tmp);\n\t\t\tnlinfo (\"ADMIN: Adding alarm '%s' limit %d order %s (varpath '%s')\", name.c_str(), tmp, alarms[i+2].c_str(), alarms[i].c_str());\n\t\t\tAlarms.push_back(CAlarm(name, tmp, alarms[i+2]==\"gt\"));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (IService::getInstance()->getServiceUnifiedName().find(servicevarpath.Destination[0].first) == string::npos)\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: Skipping alarm '%s' limit %d order %s (varpath '%s') (not for my service, i'm '%s')\", name.c_str(), fromString(alarms[i+1], tmp) ? tmp:tmp, alarms[i+2].c_str(), alarms[i].c_str(), IService::getInstance()->getServiceUnifiedName().c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: Skipping alarm '%s' limit %d order %s (varpath '%s') (var not exist)\", name.c_str(), fromString(alarms[i+1], tmp) ? tmp:tmp, alarms[i+2].c_str(), alarms[i].c_str());\n\t\t\t}\n\t\t}\n\t}\n\n\t// do the same with graph update\n\tGraphUpdates.clear ();\n\tfor (i = 0; i < graphupdate.size(); i+=2)\n\t{\n\t\tCVarPath shardvarpath (graphupdate[i]);\n\t\tif(shardvarpath.Destination.size() == 0 || shardvarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\t\tCVarPath servervarpath (shardvarpath.Destination[0].second);\n\t\tif(servervarpath.Destination.size() == 0 || servervarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\t\tCVarPath servicevarpath (servervarpath.Destination[0].second);\n\t\tif(servicevarpath.Destination.size() == 0 || servicevarpath.Destination[0].second.empty())\n\t\t\tcontinue;\n\n\t\tstring VarName = servicevarpath.Destination[0].second;\n\t\tstring ServiceName = servicevarpath.Destination[0].first;\n\n\t\tif (ICommand::exists(VarName) && (ServiceName == \"*\" || IService::getInstance()->getServiceShortName() == ServiceName))\n\t\t{\n\t\t\tfromString(graphupdate[i+1], tmp);\n\t\t\tnlinfo (\"ADMIN: Adding graphupdate '%s' update %d (varpath '%s')\", VarName.c_str(), tmp, graphupdate[i].c_str());\n\t\t\tGraphUpdates.push_back(CGraphUpdate(VarName, tmp));\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (IService::getInstance()->getServiceShortName() != ServiceName)\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: Skipping graphupdate '%s' limit %d (varpath '%s') (not for my service, i'm '%s')\", VarName.c_str(), fromString(graphupdate[i+1], tmp) ? tmp:tmp, graphupdate[i].c_str(), IService::getInstance()->getServiceUnifiedName().c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlinfo (\"ADMIN: Skipping graphupdate '%s' limit %d (varpath '%s') (var not exist)\", VarName.c_str(), fromString(graphupdate[i+1], tmp) ? tmp:tmp, graphupdate[i].c_str());\n\t\t\t}\n\t\t}\n\t}\n}\n\n//\n// Commands\n//\n\nNLMISC_CATEGORISED_COMMAND(nel, displayInformation, \"displays all admin information\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tuint i;\n\n\tlog.displayNL(\"There're %d alarms:\", Alarms.size());\n\tfor (i = 0; i < Alarms.size(); i++)\n\t{\n\t\tlog.displayNL(\" %d %s %d %s %s\", i, Alarms[i].Name.c_str(), Alarms[i].Limit, (Alarms[i].GT?\"gt\":\"lt\"), (Alarms[i].Activated?\"on\":\"off\"));\n\t}\n\tlog.displayNL(\"There're %d graphupdate:\", GraphUpdates.size());\n\tfor (i = 0; i < GraphUpdates.size(); i++)\n\t{\n\t\tlog.displayNL(\" %d %s %d %d\", i, GraphUpdates[i].Name.c_str(), GraphUpdates[i].Update, GraphUpdates[i].LastUpdate);\n\t}\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, getView, \"send a view and receive an array as result\", \"<varpath>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 1) return false;\n\n\tTAdminViewResult answer;\n\tserviceGetView (0, args[0], answer);\n\n\tlog.displayNL(\"have %d answer\", answer.size());\n\tfor (uint i = 0; i < answer.size(); i++)\n\t{\n\t\tlog.displayNL(\"  have %d value\", answer[i].VarNames.size());\n\n\t\tnlassert (answer[i].VarNames.size() == answer[i].Values.size());\n\n\t\tfor (uint j = 0; j < answer[i].VarNames.size(); j++)\n\t\t{\n\t\t\tlog.displayNL(\"    %s -> %s\", answer[i].VarNames[j].c_str(), answer[i].Values[j].c_str());\n\t\t}\n\t}\n\n\treturn true;\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"nel/net/buf_client.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/net/dummy_tcp_sock.h\"\n#include \"nel/net/net_log.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n#\tinclude <netinet/in.h>\n#endif\n\nusing namespace NLMISC;\nusing namespace std;\n\n\nnamespace NLNET {\n\n\nuint32 \tNbClientReceiveTask = 0;\n\n\n/***************************************************************************************************\n * User main thread (initialization)\n **************************************************************************************************/\n\n/*\n * Constructor\n */\n#ifdef NL_OS_UNIX\nCBufClient::CBufClient( bool nodelay, bool replaymode, bool initPipeForDataAvailable ) :\n\tCBufNetBase( initPipeForDataAvailable ),\n#else\nCBufClient::CBufClient( bool nodelay, bool replaymode, bool ) :\n\tCBufNetBase(),\n#endif\n\t_NoDelay( nodelay ),\n\t_PrevBytesDownloaded( 0 ),\n\t_PrevBytesUploaded( 0 ),\n\t_RecvTask( NULL ),\n\t_RecvThread( NULL )\n\t/*_PrevBytesReceived( 0 ),\n\t_PrevBytesSent( 0 )*/\n{\n\tnlnettrace( \"CBufClient::CBufClient\" ); // don't define a global object\n\n\tif ( replaymode )\n\t{\n\t\t_BufSock = new CNonBlockingBufSock( new CDummyTcpSock(), CBufNetBase::DefaultMaxExpectedBlockSize );\n\t}\n\telse\n\t{\n\n\t\t_BufSock = new CNonBlockingBufSock( NULL, CBufNetBase::DefaultMaxExpectedBlockSize );\n\t\t_RecvTask = new CClientReceiveTask( this, _BufSock );\n\t}\n}\n\n\n/*\n * Connects to the specified host\n * Precond: not connected\n */\nvoid CBufClient::connect( const CInetAddress& addr )\n{\n\tnlnettrace( \"CBufClient::connect\" );\n\tnlassert( ! _BufSock->Sock->connected() );\n\t_BufSock->setMaxExpectedBlockSize( maxExpectedBlockSize() );\n\t_BufSock->connect( addr, _NoDelay, true );\n\t_BufSock->setNonBlocking(); // ADDED: non-blocking client connection\n\t_PrevBytesDownloaded = 0;\n\t_PrevBytesUploaded = 0;\n\t/*_PrevBytesReceived = 0;\n\t_PrevBytesSent = 0;*/\n\n\t// Allow reconnection\n\tif ( _RecvThread != NULL )\n\t{\n\t\tdelete _RecvThread;\n\t}\n\n\t_RecvThread = IThread::create( _RecvTask, 1024*4*4 );\n\t_RecvThread->start();\n}\n\n\n/***************************************************************************************************\n * User main thread (running)\n **************************************************************************************************/\n\nvoid CBufClient::displayThreadStat (NLMISC::CLog *log)\n{\n\tlog->displayNL (\"client thread %p nbloop %d\", _RecvTask, _RecvTask->NbLoop);\n}\n\n\n/*\n * Sends a message to the remote host\n */\nvoid CBufClient::send( const NLMISC::CMemStream& buffer )\n{\n\tnlnettrace( \"CBufClient::send\" );\n\tnlassert( buffer.length() > 0 );\n\tnlassert( buffer.length() <= maxSentBlockSize() );\n\n\t// slow down the layer H_AUTO (CBufServer_send);\n\n\tif ( ! _BufSock->pushBuffer( buffer ) )\n\t{\n\t\t// Disconnection event if disconnected\n\t\t_BufSock->advertiseDisconnection( this, NULL );\n\t}\n}\n\n\n/*\n * Checks if there are some data to receive\n */\nbool CBufClient::dataAvailable()\n{\n\t// slow down the layer H_AUTO (CBufClient_dataAvailable);\n\t{\n\t\t/* If no data available, enter the 'while' loop and return false (1 volatile test)\n\t\t * If there are user data available, enter the 'while' and return true immediately (1 volatile test + 1 short locking)\n\t\t * If there is a disconnection event (rare), call the callback and loop\n\t\t */\n\t\twhile ( dataAvailableFlag() )\n\t\t{\n\t\t\t// Because _DataAvailable is true, the receive queue is not empty at this point\n\t\t\tuint8 val;\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\tval = recvfifo.value().frontLast ();\n\t\t\t}\n\n#ifdef NL_OS_UNIX\n\t\t\tuint8 b;\n\t\t\tif ( read( _DataAvailablePipeHandle[PipeRead], &b, 1 ) == -1 )\n\t\t\t\tnlwarning( \"LNETL1: Read pipe failed in dataAvailable\" );\n\t\t\t//nldebug( \"Pipe: 1 byte read (client %p)\", this );\n#endif\n\n\t\t\t// Test if it the next block is a system event\n\t\t\tswitch ( val )\n\t\t\t{\n\n\t\t\t// Normal message available\n\t\t\tcase CBufNetBase::User:\n\t\t\t\treturn true; // return immediatly, do not extract the message\n\n\t\t\t// Process disconnection event\n\t\t\tcase CBufNetBase::Disconnection:\n\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: Disconnection event\" );\n\t\t\t\t_BufSock->setConnectedState( false );\n\n\t\t\t\t// Call callback if needed\n\t\t\t\tif ( disconnectionCallback() != NULL )\n\t\t\t\t{\n\t\t\t\t\tdisconnectionCallback()( id(), argOfDisconnectionCallback() );\n\t\t\t\t}\n\n\t\t\t\t// Unlike the server version, we do not delete the CBufSock object here,\n\t\t\t\t// it will be done in the destructor of CBufClient\n\n\t\t\t\tbreak;\n\n\t\t\tdefault: // should not occur\n\t\t\t\t{\n\t\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\t\tvector<uint8> buffer;\n\t\t\t\t\trecvfifo.value().front (buffer);\n\t\t\t\t\tLNETL1_INFO( \"LNETL1: Invalid block type: %hu (should be = %hu)\", (uint16)(buffer[buffer.size()-1]), (uint16)val );\n\t\t\t\t\tLNETL1_INFO( \"LNETL1: Buffer (%d B): [%s]\", buffer.size(), stringFromVector(buffer).c_str() );\n\t\t\t\t\tLNETL1_INFO( \"LNETL1: Receive queue:\" );\n\t\t\t\t\trecvfifo.value().display();\n\t\t\t\t\tnlerror( \"LNETL1: Invalid system event type in client receive queue\" );\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Extract system event\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\trecvfifo.value().pop();\n\t\t\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t\t\t}\n\n\t\t}\n\t\t// _DataAvailable is false here\n\t\treturn false;\n\t}\n}\n\n\n#ifdef NL_OS_UNIX\n/* Wait until the receive queue contains something to read (implemented with a select()).\n * This is where the connection/disconnection callbacks can be called.\n * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n */\nvoid\tCBufClient::sleepUntilDataAvailable( uint usecMax )\n{\n\t// Prevent looping infinitely if the system time was changed\n\tif ( usecMax > 999999 ) // limit not told in Linux man but here: http://docs.hp.com/en/B9106-90009/select.2.html\n\t\tusecMax = 999999;\n\n\tfd_set readers;\n\ttimeval tv;\n\tdo\n\t{\n\t\tFD_ZERO( &readers );\n\t\tFD_SET( _DataAvailablePipeHandle[PipeRead], &readers );\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = usecMax;\n\t\tint res = ::select( _DataAvailablePipeHandle[PipeRead]+1, &readers, NULL, NULL, &tv );\n\t\tif ( res == -1 )\n\t\t\tnlerror( \"LNETL1: Select failed in sleepUntilDataAvailable (code %u)\", CSock::getLastError() );\n\t}\n\twhile ( ! dataAvailable() ); // will loop if only a connection/disconnection event was read\n}\n#endif\n\n\n/*\n * Receives next block of data in the specified buffer (resizes the vector)\n * Precond: dataAvailable() has returned true\n */\nvoid CBufClient::receive( NLMISC::CMemStream& buffer )\n{\n\tnlnettrace( \"CBufClient::receive\" );\n\t//nlassert( dataAvailable() );\n\n\t// Extract buffer from the receive queue\n\t{\n\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\tnlassert( ! recvfifo.value().empty() );\n\t\trecvfifo.value().front( buffer );\n\t\trecvfifo.value().pop();\n\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t}\n\n\t// Extract event type\n\tnlassert( buffer.buffer()[buffer.size()-1] == CBufNetBase::User );\n\t//commented for optimisation LNETL1_DEBUG( \"LNETL1: Client read buffer (%d+%d B)\", buffer.size(), sizeof(TSockId)+1 );\n\tbuffer.resize( buffer.size()-1 );\n}\n\n\n/*\n * Update the network (call this method evenly)\n */\nvoid CBufClient::update()\n{\n\t//nlnettrace( \"CBufClient::update\" );\n\n\t// Update sending\n\tbool sendingok = _BufSock->update();\n\n\t// Disconnection event if disconnected\n\tif ( ! ( _BufSock->Sock->connected() && sendingok ) )\n\t{\n\t\tif ( _BufSock->Sock->connected() )\n\t\t{\n\t\t\t_BufSock->Sock->disconnect();\n\t\t}\n\t\t_BufSock->advertiseDisconnection( this, NULL );\n\t}\n}\n\n\n/*\n * Disconnect the remote host\n */\nvoid CBufClient::disconnect( bool quick )\n{\n\tnlnettrace( \"CBufClient::disconnect\" );\n\n\t// Do not allow to disconnect a socket that is not connected\n\tnlassert( _BufSock->connectedState() );\n\n\t// When the NS tells us to remove this connection AND the connection has physically\n\t// disconnected but not yet logically (i.e. disconnection event not processed yet),\n\t// skip flushing and physical active disconnection\n\tif ( _BufSock->Sock->connected() )\n\t{\n\t\t// Flush sending is asked for\n\t\tif ( ! quick )\n\t\t{\n\t\t\t_BufSock->flush();\n\t\t}\n\n\t\t// Disconnect and prevent from advertising the disconnection\n\t\t_BufSock->disconnect( false );\n\t}\n\n\t// Empty the receive queue\n\t{\n\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\trecvfifo.value().clear();\n\t\tsetDataAvailableFlag( false );\n\t}\n}\n\n\n// Utility function for newBytes...()\ninline uint64 updateStatCounter( uint64& counter, uint64 newvalue )\n{\n\tuint64 result = newvalue - counter;\n\tcounter = newvalue;\n\treturn result;\n}\n\n\n/*\n * Returns the number of bytes downloaded since the previous call to this method\n */\nuint64 CBufClient::newBytesDownloaded()\n{\n\treturn updateStatCounter( _PrevBytesDownloaded, bytesDownloaded() );\n}\n\n\n/*\n * Returns the number of bytes uploaded since the previous call to this method\n */\nuint64 CBufClient::newBytesUploaded()\n{\n\treturn updateStatCounter( _PrevBytesUploaded, bytesUploaded() );\n}\n\n\n/*\n * Returns the number of bytes popped by receive() since the previous call to this method\n */\n/*uint64 CBufClient::newBytesReceived()\n{\n\treturn updateStatCounter( _PrevBytesReceived, bytesReceived() );\n}*/\n\n\n/*\n * Returns the number of bytes pushed by send() since the previous call to this method\n */\n/*uint64 CBufClient::newBytesSent()\n{\n\treturn updateStatCounter( _PrevBytesSent, bytesSent() );\n}*/\n\n\n/*\n * Destructor\n */\nCBufClient::~CBufClient()\n{\n\tnlnettrace( \"CBufClient::~CBufClient\" );\n\n\t// Disconnect if not done\n\tif ( _BufSock->Sock->connected() )\n\t{\n\t\tnlassert( _BufSock->connectedState() );\n\n\t\tdisconnect( true );\n\t}\n\n\t// Clean thread termination\n\tif ( _RecvThread != NULL )\n\t{\n\t\tLNETL1_DEBUG( \"LNETL1: Waiting for the end of the receive thread...\" );\n\t\t_RecvThread->wait();\n\t}\n\n\tif ( _RecvTask != NULL )\n\t\tdelete _RecvTask;\n\n\tif ( _RecvThread != NULL )\n\t\tdelete _RecvThread;\n\n\tif ( _BufSock != NULL )\n\t\tdelete _BufSock;\n\n\tnlnettrace( \"Exiting CBufClient::~CBufClient\" );\n}\n\n\n/***************************************************************************************************\n * Receive thread\n **************************************************************************************************/\n\n\n/*\n * Code of receiving thread for clients\n */\nvoid CClientReceiveTask::run()\n{\n\tNbClientReceiveTask++;\n\tNbNetworkTask++;\n\tnlnettrace( \"CClientReceiveTask::run\" );\n\n\t// 18/08/2005 : sonix : Changed time out from 60s to 1s, in some case, it\n\t//\t\t\t\t\t\tcan generate a 60 s wait on destruction of the CBufSock\n\t//\t\t\t\t\t\tBy the way, checking every 1s is not a time consuming\n\t_NBBufSock->Sock->setTimeOutValue( 1, 0 );\n\n\tbool connected = true;\n\twhile ( connected && _NBBufSock->Sock->connected())\n\t{\n\t\ttry\n\t\t{\n\t\t\t// ADDED: non-blocking client connection\n\n\t\t\t// Wait until some data are received (sleepin' select inside)\n\t\t\twhile ( ! _NBBufSock->Sock->dataAvailable() )\n\t\t\t{\n\t\t\t\tif ( ! _NBBufSock->Sock->connected() )\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Client connection %s closed\", sockId()->asString().c_str() );\n\t\t\t\t\t// The socket went to _Connected=false when throwing the exception\n\t\t\t\t\tconnected = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Process the data received\n\t\t\tif ( _NBBufSock->receivePart( 1 ) ) // 1 for the event type\n\t\t\t{\n\t\t\t\t//commented out for optimisation: LNETL1_DEBUG( \"LNETL1: Client %s received buffer (%u bytes)\", _SockId->asString().c_str(), buffer.size()/*, stringFromVector(buffer).c_str()*/ );\n\t\t\t\t// Add event type\n\t\t\t\t_NBBufSock->fillEventTypeOnly();\n\n\t\t\t\t// Push message into receive queue\n\t\t\t\t_Client->pushMessageIntoReceiveQueue( _NBBufSock->receivedBuffer() );\n\t\t\t}\n\n\t\t\tNbLoop++;\n\t\t}\n\t\tcatch (const ESocket&)\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Client connection %s broken\", sockId()->asString().c_str() );\n\t\t\tsockId()->Sock->disconnect();\n\t\t\tconnected = false;\n\t\t}\n\t}\n\n\tnlnettrace( \"Exiting CClientReceiveTask::run()\" );\n\tNbClientReceiveTask--;\n\tNbNetworkTask--;\n}\n\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, NbClientReceiveTask, \"Number of client receive thread\");\n\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_net_base.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/buf_net_base.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\n\nnamespace NLNET {\n\nuint32 \tNbNetworkTask = 0;\n\n// The value that will be used if setMaxExpectedBlockSize() is not called (or called with a negative argument)\nuint32 CBufNetBase::DefaultMaxExpectedBlockSize = 1048576; // 10 M unless changed by a NeL variable\n\n// The value that will be used if setMaxSentBlockSize() is not called (or called with a negative argument)\nuint32 CBufNetBase::DefaultMaxSentBlockSize = 1048576; // 10 M unless changed by a NeL variable\n\n\n/***************************************************************************************************\n * User main thread\n **************************************************************************************************/\n\n\n/*\n * Constructor\n */\n#ifdef NL_OS_UNIX\nCBufNetBase::CBufNetBase( bool isDataAvailablePipeSelfManaged ) :\n#else\nCBufNetBase::CBufNetBase() :\n#endif\n\t_RecvFifo(\"CBufNetBase::_RecvFifo\"),\n\t_DisconnectionCallback( NULL ),\n\t_DisconnectionCbArg( NULL ),\n\t_MaxExpectedBlockSize( DefaultMaxExpectedBlockSize ),\n\t_MaxSentBlockSize( DefaultMaxSentBlockSize ),\n\t_DataAvailable( false )\n{\n\t// Debug info for mutexes\n#ifdef MUTEX_DEBUG\n\tinitAcquireTimeMap();\n#endif\n#ifdef NL_OS_UNIX\n\t_IsDataAvailablePipeSelfManaged = isDataAvailablePipeSelfManaged;\n\tif ( _IsDataAvailablePipeSelfManaged )\n\t{\n\t\tif ( ::pipe( _DataAvailablePipeHandle ) != 0 )\n\t\t\tnlwarning( \"Unable to create D.A. pipe\" );\n\t}\n#endif\n}\n\n\n/*\n * Destructor\n */\nCBufNetBase::~CBufNetBase()\n{\n#ifdef NL_OS_UNIX\n\tif ( _IsDataAvailablePipeSelfManaged )\n\t{\n\t\t::close( _DataAvailablePipeHandle[PipeRead] );\n\t\t::close( _DataAvailablePipeHandle[PipeWrite] );\n\t}\n#endif\n}\n\n\n/*\n * Push message into receive queue (mutexed)\n * TODO OPTIM never use this function\n */\nvoid\tCBufNetBase::pushMessageIntoReceiveQueue( const std::vector<uint8>& buffer )\n{\n\t//sint32 mbsize;\n\t{\n\t\t//nldebug( \"BNB: Acquiring the receive queue... \");\n\t\tCFifoAccessor recvfifo( &_RecvFifo );\n\t\t//nldebug( \"BNB: Acquired, pushing the received buffer... \");\n\t\trecvfifo.value().push( buffer );\n\t\t//nldebug( \"BNB: Pushed, releasing the receive queue...\" );\n\t\t//mbsize = recvfifo.value().size() / 1048576;\n\t\tsetDataAvailableFlag( true );\n\t}\n#ifdef NL_OS_UNIX\n\t// Wake-up main thread (outside the critical section of CFifoAccessor, to allow main thread to be\n\t// read the fifo; if the main thread sees the Data Available flag is true but the pipe not written\n\t// yet, it will block on read()).\n\tuint8 b=0;\n\tif ( write( _DataAvailablePipeHandle[PipeWrite], &b, 1 ) == -1 )\n\t{\n\t\tnlwarning( \"LNETL1: Write pipe failed in pushMessageIntoReceiveQueue\" );\n\t}\n\t//nldebug( \"Pipe: 1 byte written (%p)\", this );\n#endif\n\t//nldebug( \"BNB: Released.\" );\n\t//if ( mbsize > 1 )\n\t//{\n\t//\tnlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t//}\n}\n\n/*\n * Push message into receive queue (mutexed)\n */\nvoid\tCBufNetBase::pushMessageIntoReceiveQueue( const uint8 *buffer, uint32 size )\n{\n\t//sint32 mbsize;\n\t{\n\t\t//nldebug( \"BNB: Acquiring the receive queue... \");\n\t\tCFifoAccessor recvfifo( &_RecvFifo );\n\t\t//nldebug( \"BNB: Acquired, pushing the received buffer... \");\n\t\trecvfifo.value().push( buffer, size );\n\t\t//nldebug( \"BNB: Pushed, releasing the receive queue...\" );\n\t\t//mbsize = recvfifo.value().size() / 1048576;\n\t\tsetDataAvailableFlag( true );\n#ifdef NL_OS_UNIX\n\t\t// Wake-up main thread\n\t\tuint8 b=0;\n\t\tif ( write( _DataAvailablePipeHandle[PipeWrite], &b, 1 ) == -1 )\n\t\t{\n\t\t\tnlwarning( \"LNETL1: Write pipe failed in pushMessageIntoReceiveQueue\" );\n\t\t}\n\t\t// nldebug( \"Pipe: 1 byte written\" );  2018-11-30\n#endif\n\t}\n\t//nldebug( \"BNB: Released.\" );\n\t/*if ( mbsize > 1 )\n\t{\n\t\tnlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t}*/\n}\n\n\n\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, NbNetworkTask, \"Number of server and client thread\");\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"nel/net/buf_server.h\"\n#include \"nel/net/net_log.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <cerrno>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#endif\n\n/*\n * On Linux, the default limit of descriptors is usually 1024, you can increase it with ulimit\n */\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLNET {\n\nuint32 \tNbServerListenTask = 0;\nuint32 \tNbServerReceiveTask = 0;\n\n/***************************************************************************************************\n * User main thread (initialization)\n **************************************************************************************************/\n\n/*\n * Constructor\n */\nCBufServer::CBufServer( TThreadStategy strategy,\n\tuint16 max_threads, uint16 max_sockets_per_thread, bool nodelay, bool replaymode, bool initPipeForDataAvailable ) :\n#ifdef NL_OS_UNIX\n\tCBufNetBase( initPipeForDataAvailable ),\n#else\n\tCBufNetBase(),\n#endif\n\t_ThreadStrategy( strategy ),\n\t_MaxThreads( max_threads ),\n\t_MaxSocketsPerThread( max_sockets_per_thread ),\n\t_ListenTask( NULL ),\n\t_ListenThread( NULL ),\n\t_ThreadPool(\"CBufServer::_ThreadPool\"),\n\t_ConnectionCallback( NULL ),\n\t_ConnectionCbArg( NULL ),\n\t_BytesPushedOut( 0 ),\n\t_BytesPoppedIn( 0 ),\n\t_PrevBytesPoppedIn( 0 ),\n\t_PrevBytesPushedOut( 0 ),\n\t_NbConnections (0),\n\t_NoDelay( nodelay ),\n\t_ReplayMode( replaymode )\n{\n\tnlnettrace( \"CBufServer::CBufServer\" );\n\tif ( ! _ReplayMode )\n\t{\n\t\t_ListenTask = new CListenTask( this );\n\t\t_ListenThread = IThread::create( _ListenTask, 1024*4*4 );\n\t}\n\t/*{\n\t\tCSynchronized<uint32>::CAccessor syncbpi ( &_BytesPushedIn );\n\t\tsyncbpi.value() = 0;\n\t}*/\n}\n\n\n/*\n * Listens on the specified port\n */\nvoid CBufServer::init( uint16 port )\n{\n\tnlnettrace( \"CBufServer::init\" );\n\tif ( ! _ReplayMode )\n\t{\n\t\t_ListenTask->init( port, maxExpectedBlockSize() );\n\t\t_ListenThread->start();\n\t}\n\telse\n\t{\n\t\tLNETL1_DEBUG( \"LNETL1: Binding listen socket to any address, port %hu\", port );\n\t}\n}\n\n\n/*\n * Begins to listen on the specified port (call before running thread)\n */\nvoid CListenTask::init( uint16 port, sint32 maxExpectedBlockSize )\n{\n\tnlnettrace( \"CListenTask::init\" );\n\t_ListenSock.init( port );\n\t_MaxExpectedBlockSize = maxExpectedBlockSize;\n}\n\n\n/***************************************************************************************************\n * User main thread (running)\n **************************************************************************************************/\n\n\n/*\n * Constructor\n */\nCServerTask::CServerTask() : NbLoop (0), _ExitRequired(false)\n{\n#ifdef NL_OS_UNIX\n\tif (pipe( _WakeUpPipeHandle ) == -1)\n\t{\n\t\tnlwarning(\"LNETL1: pipe() failed: code=%d '%s'\", errno, strerror(errno));\n\t}\n#endif\n}\n\n\n\n#ifdef NL_OS_UNIX\n/*\n * Wake the thread up, when blocked in select (Unix only)\n */\nvoid CServerTask::wakeUp()\n{\n\tuint8 b;\n\tif ( write( _WakeUpPipeHandle[PipeWrite], &b, 1 ) == -1 )\n\t{\n\t\tLNETL1_DEBUG( \"LNETL1: In CServerTask::wakeUp(): write() failed\" );\n\t}\n}\n#endif\n\n\n/*\n * Destructor\n */\nCServerTask::~CServerTask()\n{\n#ifdef NL_OS_UNIX\n\tclose( _WakeUpPipeHandle[PipeRead] );\n\tclose( _WakeUpPipeHandle[PipeWrite] );\n#endif\n}\n\n\n/*\n * Destructor\n */\nCBufServer::~CBufServer()\n{\n\tnlnettrace( \"CBufServer::~CBufServer\" );\n\n\t// Clean listen thread exit\n\tif ( ! _ReplayMode )\n\t{\n\t\t((CListenTask*)(_ListenThread->getRunnable()))->requireExit();\n\t\t((CListenTask*)(_ListenThread->getRunnable()))->close();\n#ifdef NL_OS_UNIX\n\t\t_ListenTask->wakeUp();\n#endif\n\t\t_ListenThread->wait();\n\t\tdelete _ListenThread;\n\t\tdelete _ListenTask;\n\n\t\t// Clean receive thread exits\n\t\tCThreadPool::iterator ipt;\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Waiting for end of threads...\" );\n\t\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\t// Tell the threads to exit and wake them up\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tnlnettrace( \"Requiring exit\" );\n\t\t\t\ttask->requireExit();\n\n\t\t\t\t// Wake the threads up\n\t#ifdef NL_OS_UNIX\n\t\t\t\ttask->wakeUp();\n\t#else\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\tnlnettrace( \"Disconnecting sockets (Win32)\" );\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\t(*ipb)->Sock->disconnect();\n\t\t\t\t\t}\n\t\t\t\t}\n\t#endif\n\n\t\t\t}\n\n\t\t\tnlnettrace( \"Waiting\" );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\t// Wait until the threads have exited\n\t\t\t\t(*ipt)->wait();\n\t\t\t}\n\n\t\t\tLNETL1_DEBUG( \"LNETL1: Deleting sockets, tasks and threads...\" );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\t// Delete the socket objects\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\tdelete (*ipb); // closes and deletes the socket\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Delete the task objects\n\t\t\t\tdelete task;\n\n\t\t\t\t// Delete the thread objects\n\t\t\t\tdelete (*ipt);\n\t\t\t}\n\t\t}\n\t}\n\n\tnlnettrace( \"Exiting CBufServer::~CBufServer\" );\n}\n\n\n/*\n * Disconnect the specified host\n * Set hostid to NULL to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * If quick is true, any pending data will not be sent before disconnecting.\n */\nvoid CBufServer::disconnect( TSockId hostid, bool quick )\n{\n\tnlnettrace( \"CBufServer::disconnect\" );\n\tif ( hostid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(hostid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn;\n\t\t}\n\n\t\t// Disconnect only if physically connected\n\t\tif ( hostid->Sock->connected() )\n\t\t{\n\t\t\tif ( ! quick )\n\t\t\t{\n\t\t\t\thostid->flush();\n\t\t\t}\n\t\t\thostid->Sock->disconnect(); // the connection will be removed by the next call of update()\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Disconnect all\n\t\tCThreadPool::iterator ipt;\n\t\t{\n\t\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( (*ipb)->Sock->connected() )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( ! quick )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t(*ipb)->flush();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t(*ipb)->Sock->disconnect();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n * Send a message to the specified host\n */\nvoid CBufServer::send( const CMemStream& buffer, TSockId hostid )\n{\n\tnlnettrace( \"CBufServer::send\" );\n\tnlassert( buffer.length() > 0 );\n\tnlassertex( buffer.length() <= maxSentBlockSize(), (\"length=%u max=%u\", buffer.length(), maxSentBlockSize()) );\n\n\t// slow down the layer H_AUTO (CBufServer_send);\n\n\tif ( hostid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(hostid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn;\n\t\t}\n\n\t\tpushBufferToHost( buffer, hostid );\n\t}\n\telse\n\t{\n\t\t// Push into all send queues\n\t\tCThreadPool::iterator ipt;\n\t\t{\n\t\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Send only if the socket is logically connected\n\t\t\t\t\t\tif ( (*ipb)->connectedState() )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpushBufferToHost( buffer, *ipb );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n * Checks if there are some data to receive\n */\nbool CBufServer::dataAvailable()\n{\n\t// slow down the layer H_AUTO (CBufServer_dataAvailable);\n\t{\n\t\t/* If no data available, enter the 'while' loop and return false (1 volatile test)\n\t\t * If there are user data available, enter the 'while' and return true immediately (1 volatile test + 1 short locking)\n\t\t * If there is a connection/disconnection event (rare), call the callback and loop\n\t\t */\n\t\twhile ( dataAvailableFlag() )\n\t\t{\n\t\t\t// Because _DataAvailable is true, the receive queue is not empty at this point\n\t\t\tvector<uint8> buffer;\n\t\t\tuint8 val;\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\tval = recvfifo.value().frontLast();\n\t\t\t\tif ( val != CBufNetBase::User )\n\t\t\t\t{\n\t\t\t\t\trecvfifo.value().front( buffer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*sint32 mbsize = recvfifo.value().size() / 1048576;\n\t\t\tif ( mbsize > 0 )\n\t\t\t{\n\t\t\t  nlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t\t\t}*/\n\n\t\t\t/*vector<uint8> buffer;\n\t\t\trecvfifo.value().front( buffer );*/\n\n#ifdef NL_OS_UNIX\n\t\t\tuint8 b;\n\t\t\tif ( read( _DataAvailablePipeHandle[PipeRead], &b, 1 ) == -1 )\n\t\t\t\tnlwarning( \"LNETL1: Read pipe failed in dataAvailable\" );\n\t\t\t//nldebug( \"Pipe: 1 byte read (server %p)\", this );\n#endif\n\n\t\t\t// Test if it the next block is a system event\n\t\t\t//switch ( buffer[buffer.size()-1] )\n\t\t\tswitch ( val )\n\t\t\t{\n\n\t\t\t// Normal message available\n\t\t\tcase CBufNetBase::User:\n\t\t\t\t{\n\t\t\t\t\treturn true; // return immediately, do not extract the message\n\t\t\t\t}\n\n\t\t\t// Process disconnection event\n\t\t\tcase CBufNetBase::Disconnection:\n\t\t\t\t{\n\t\t\t\t\tTSockId sockid = *((TSockId*)(&*buffer.begin()));\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Disconnection event for %p %s\", sockid, sockid->asString().c_str());\n\n\t\t\t\t\tsockid->setConnectedState( false );\n\n\t\t\t\t\t// Call callback if needed\n\t\t\t\t\tif ( disconnectionCallback() != NULL )\n\t\t\t\t\t{\n\t\t\t\t\t\tdisconnectionCallback()( sockid, argOfDisconnectionCallback() );\n\t\t\t\t\t}\n\n\t\t\t\t\t// remove from the list of valid client\n\t\t\t\t\tnlverify(_ConnectedClients.erase(sockid) == 1);\n\n\t\t\t\t\t// Add socket object into the synchronized remove list\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Adding the connection to the remove list\" );\n\t\t\t\t\tnlassert( ((CServerBufSock*)sockid)->ownerTask() != NULL );\n\t\t\t\t\t((CServerBufSock*)sockid)->ownerTask()->addToRemoveSet( sockid );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t// Process connection event\n\t\t\tcase CBufNetBase::Connection:\n\t\t\t\t{\n\t\t\t\t\tTSockId sockid = *((TSockId*)(&*buffer.begin()));\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Connection event for %p %s\", sockid, sockid->asString().c_str());\n\n\t\t\t\t\t// add this socket in the list of client\n\t\t\t\t\tnlverify(_ConnectedClients.insert(sockid).second);\n\n\t\t\t\t\tsockid->setConnectedState( true );\n\n\t\t\t\t\t// Call callback if needed\n\t\t\t\t\tif ( connectionCallback() != NULL )\n\t\t\t\t\t{\n\t\t\t\t\t\tconnectionCallback()( sockid, argOfConnectionCallback() );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdefault: // should not occur\n\t\t\t\tLNETL1_INFO( \"LNETL1: Invalid block type: %hu (should be = to %hu\", (uint16)(buffer[buffer.size()-1]), (uint16)(val) );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Buffer (%d B): [%s]\", buffer.size(), stringFromVector(buffer).c_str() );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Receive queue:\" );\n\t\t\t\t{\n\t\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\t\trecvfifo.value().display();\n\t\t\t\t}\n\t\t\t\tnlerror( \"LNETL1: Invalid system event type in server receive queue\" );\n\n\t\t\t}\n\n\t\t\t// Extract system event\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\trecvfifo.value().pop();\n\t\t\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t\t\t}\n\t\t}\n\t\t// _DataAvailable is false here\n\t\treturn false;\n\t}\n}\n\n\n#ifdef NL_OS_UNIX\n/* Wait until the receive queue contains something to read (implemented with a select()).\n * This is where the connection/disconnection callbacks can be called.\n * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n */\nvoid\tCBufServer::sleepUntilDataAvailable( uint usecMax )\n{\n\t// Prevent looping infinitely if the system time was changed\n\tif ( usecMax > 999999 ) // limit not told in Linux man but here: http://docs.hp.com/en/B9106-90009/select.2.html\n\t\tusecMax = 999999;\n\n\tfd_set readers;\n\ttimeval tv;\n\tdo\n\t{\n\t\tFD_ZERO( &readers );\n\t\tFD_SET( _DataAvailablePipeHandle[PipeRead], &readers );\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = usecMax;\n\t\tint res = ::select( _DataAvailablePipeHandle[PipeRead]+1, &readers, NULL, NULL, &tv );\n\t\tif ( res == -1 )\n\t\t\tnlerror( \"LNETL1: Select failed in sleepUntilDataAvailable (code %u)\", CSock::getLastError() );\n\t}\n\twhile ( ! dataAvailable() ); // will loop if only a connection/disconnection event was read\n}\n#endif\n\n\n/*\n * Receives next block of data in the specified. The length and hostid are output arguments.\n * Precond: dataAvailable() has returned true, phostid not null\n */\nvoid CBufServer::receive( CMemStream& buffer, TSockId* phostid )\n{\n\tnlnettrace( \"CBufServer::receive\" );\n\t//nlassert( dataAvailable() );\n\tnlassert( phostid != NULL );\n\n\t{\n\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\tnlassert( ! recvfifo.value().empty() );\n\t\trecvfifo.value().front( buffer );\n\t\trecvfifo.value().pop();\n\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t}\n\n\t// Extract hostid (and event type)\n\t*phostid = *((TSockId*)&(buffer.buffer()[buffer.size()-sizeof(TSockId)-1]));\n\tnlassert( buffer.buffer()[buffer.size()-1] == CBufNetBase::User );\n\n\tbuffer.resize( buffer.size()-sizeof(TSockId)-1 );\n\n\t// TODO OPTIM remove the nldebug for speed\n\t//commented for optimisation LNETL1_DEBUG( \"LNETL1: Read buffer (%d+%d B) from %s\", buffer.size(), sizeof(TSockId)+1, /*stringFromVector(buffer).c_str(), */(*phostid)->asString().c_str() );\n\n\t// Statistics\n\t_BytesPoppedIn += buffer.size() + sizeof(TBlockSize);\n}\n\n\n/*\n * Update the network (call this method evenly)\n */\nvoid CBufServer::update()\n{\n\t//nlnettrace( \"CBufServer::update-BEGIN\" );\n\n\t_NbConnections = 0;\n\n\t// For each thread\n\tCThreadPool::iterator ipt;\n\t{\n\t  //nldebug( \"UPD: Acquiring the Thread Pool\" );\n\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t//nldebug( \"UPD: Acquired.\" );\n\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t{\n\t\t\t// For each thread of the pool\n\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\tCConnections::iterator ipb;\n\t\t\t{\n\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t{\n\t\t\t\t    // For each socket of the thread, update sending\n\t\t\t\t    if ( ! ((*ipb)->Sock->connected() && (*ipb)->update()) )\n\t\t\t\t    {\n\t\t\t\t\t\t// Update did not work or the socket is not connected anymore\n\t\t\t\t        LNETL1_DEBUG( \"LNETL1: Socket %s is disconnected\", (*ipb)->asString().c_str() );\n\t\t\t\t\t\t// Disconnection event if disconnected (known either from flush (in update) or when receiving data)\n\t\t\t\t\t\t(*ipb)->advertiseDisconnection( this, *ipb );\n\n\t\t\t\t\t\t/*if ( (*ipb)->advertiseDisconnection( this, *ipb ) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Now the connection removal is in dataAvailable()\n\t\t\t\t\t\t\t// POLL6\n\t\t\t\t\t\t}*/\n\t\t\t\t    }\n\t\t\t\t    else\n\t\t\t\t    {\n\t\t\t\t\t\t_NbConnections++;\n\t\t\t\t    }\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t//nlnettrace( \"CBufServer::update-END\" );\n}\n\nuint32 CBufServer::getSendQueueSize( TSockId destid )\n{\n\tif ( destid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(destid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn destid->SendFifo.size();\n\t}\n\telse\n\t{\n\t\t// add all client buffers\n\n\t\tuint32 total = 0;\n\n\t\t// For each thread\n\t\tCThreadPool::iterator ipt;\n\t\t{\n\t\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\t// For each thread of the pool\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\t// For each socket of the thread, update sending\n\t\t\t\t\t\ttotal = (*ipb)->SendFifo.size ();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn total;\n\t}\n}\n\nvoid CBufServer::displayThreadStat (NLMISC::CLog *log)\n{\n\t// For each thread\n\tCThreadPool::iterator ipt;\n\t{\n\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t{\n\t\t\t// For each thread of the pool\n\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t// For each socket of the thread, update sending\n\t\t\tlog->displayNL (\"server receive thread %p nbloop %d\", task, task->NbLoop);\n\t\t}\n\t}\n\n\tlog->displayNL (\"server listen thread %p nbloop %d\", _ListenTask, _ListenTask->NbLoop);\n}\n\nvoid CBufServer::setTimeFlushTrigger( TSockId destid, sint32 ms )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setTimeFlushTrigger( ms );\n}\n\nvoid CBufServer::setSizeFlushTrigger( TSockId destid, sint32 size )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setSizeFlushTrigger( size );\n}\n\nbool CBufServer::flush( TSockId destid, uint *nbBytesRemaining)\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\treturn destid->flush( nbBytesRemaining );\n\telse\n\t\treturn true;\n}\nconst CInetAddress& CBufServer::hostAddress( TSockId hostid )\n{\n\tnlassert( hostid != InvalidSockId );\n\tif (_ConnectedClients.find(hostid) != _ConnectedClients.end())\n\t\treturn hostid->Sock->remoteAddr();\n\n\tstatic CInetAddress nullAddr;\n\treturn nullAddr;\n}\n\nvoid CBufServer::displaySendQueueStat (NLMISC::CLog *log, TSockId destid)\n{\n\tif ( destid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(destid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn;\n\t\t}\n\n\t\tdestid->SendFifo.displayStats(log);\n\t}\n\telse\n\t{\n\t\t// add all client buffers\n\n\t\t// For each thread\n\t\tCThreadPool::iterator ipt;\n\t\t{\n\t\t\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t\t{\n\t\t\t\t// For each thread of the pool\n\t\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\t\tCConnections::iterator ipb;\n\t\t\t\t{\n\t\t\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &task->_Connections );\n\t\t\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t\t\t{\n\t\t\t\t\t\t// For each socket of the thread, update sending\n\t\t\t\t\t\t(*ipb)->SendFifo.displayStats(log);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n * Returns the number of bytes received since the previous call to this method\n */\nuint64 CBufServer::newBytesReceived()\n{\n\tuint64 b = bytesReceived();\n\tuint64 nbrecvd = b - _PrevBytesPoppedIn;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbrecvd );\n\t_PrevBytesPoppedIn = b;\n\treturn nbrecvd;\n}\n\n/*\n * Returns the number of bytes sent since the previous call to this method\n */\nuint64 CBufServer::newBytesSent()\n{\n\tuint64 b = bytesSent();\n\tuint64 nbsent = b - _PrevBytesPushedOut;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbsent );\n\t_PrevBytesPushedOut = b;\n\treturn nbsent;\n}\n\n\n/***************************************************************************************************\n * Listen thread\n **************************************************************************************************/\n\n\n/*\n * Code of listening thread\n */\nvoid CListenTask::run()\n{\n\tNbNetworkTask++;\n\tNbServerListenTask++;\n\n\tnlnettrace( \"CListenTask::run\" );\n\n\tfd_set readers;\n#ifdef NL_OS_UNIX\n\tSOCKET descmax;\n\tdescmax = _ListenSock.descriptor()>_WakeUpPipeHandle[PipeRead]?_ListenSock.descriptor():_WakeUpPipeHandle[PipeRead];\n#endif\n\n\t// Accept connections\n\twhile ( ! exitRequired() )\n\t{\n\t\ttry\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Waiting incoming connection...\" );\n\t\t\t// Get and setup the new socket\n#ifdef NL_OS_UNIX\n\t\t\tFD_ZERO( &readers );\n\t\t\tFD_SET( _ListenSock.descriptor(), &readers );\n\t\t\tFD_SET( _WakeUpPipeHandle[PipeRead], &readers );\n\t\t\tint res = ::select( descmax+1, &readers, NULL, NULL, NULL ); /// Wait indefinitely\n\n\t\t\tswitch ( res )\n\t\t\t{\n\t\t\t//case  0 : continue; // time-out expired, no results\n\t\t\tcase -1 :\n\t\t\t\t// we'll ignore message (Interrupted system call) caused by a CTRL-C\n\t\t\t\tif (CSock::getLastError() == 4 || exitRequired() )\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG (\"LNETL1: Select failed (in listen thread): %s (code %u) but IGNORED\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError());\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tnlerror( \"LNETL1: Select failed (in listen thread): %s (code %u)\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError() );\n\t\t\t}\n\n\t\t\tif ( FD_ISSET( _WakeUpPipeHandle[PipeRead], &readers ) )\n\t\t\t{\n\t\t\t\tuint8 b;\n\t\t\t\tif ( read( _WakeUpPipeHandle[PipeRead], &b, 1 ) == -1 ) // we were woken-up by the wake-up pipe\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: In CListenTask::run(): read() failed\" );\n\t\t\t\t}\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: listen thread select woken-up\" );\n\t\t\t\tcontinue;\n\t\t\t}\n#elif defined (NL_OS_WINDOWS)\n\t\t\tFD_ZERO( &readers );\n\t\t\tFD_SET( _ListenSock.descriptor(), &readers );\n\t\t\tint res = ::select( 1, &readers, NULL, NULL, NULL ); /// Wait indefinitely\n\n\t\t\tif ( res == -1)\n\t\t\t{\n\t\t\t\tnlerror( \"LNETL1: Select failed (in listen thread): %s (code %u)\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError() );\n\t\t\t\tcontinue;\n\t\t\t}\n#endif\n\t\t\tLNETL1_DEBUG( \"LNETL1: Accepting an incoming connection...\" );\n\t\t\tCTcpSock *newSock = _ListenSock.accept();\n\t\t\tif (newSock != NULL)\n\t\t\t{\n\t\t\t\tCServerBufSock *bufsock = new CServerBufSock( newSock );\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: New connection : %s\", bufsock->asString().c_str() );\n\t\t\t\tbufsock->setNonBlocking();\n\t\t\t\tbufsock->setMaxExpectedBlockSize( _MaxExpectedBlockSize );\n\t\t\t\tif ( _Server->noDelay() )\n\t\t\t\t{\n\t\t\t\t\tbufsock->Sock->setNoDelay( true );\n\t\t\t\t}\n\n\t\t\t\t// Notify the new connection\n\t\t\t\tbufsock->advertiseConnection( _Server );\n\n\t\t\t\t// Dispatch the socket into the thread pool\n\t\t\t\t_Server->dispatchNewSocket( bufsock );\n\t\t\t}\n\n\t\t\tNbLoop++;\n\t\t}\n\t\tcatch (const ESocket &e)\n\t\t{\n\t\t\tLNETL1_INFO( \"LNETL1: Exception in listen thread: %s\", e.what() );\n\t\t\t// It can occur when too many sockets are open (e.g. 885 connections)\n\t\t}\n\t}\n\n\tnlnettrace( \"Exiting CListenTask::run\" );\n\tNbServerListenTask--;\n\tNbNetworkTask--;\n}\n\n/// Close listening socket\nvoid CListenTask::close()\n{\n\t_ListenSock.close();\n//\t_ListenSock.disconnect();\n}\n\n\n/*\n * Binds a new socket and send buffer to an existing or a new thread\n * Note: this method is called in the listening thread.\n */\nvoid CBufServer::dispatchNewSocket( CServerBufSock *bufsock )\n{\n\tnlnettrace( \"CBufServer::dispatchNewSocket\" );\n\n\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\tif ( _ThreadStrategy == SpreadSockets )\n\t{\n\t\t// Find the thread with the smallest number of connections and check if all\n\t\t// threads do not have the same number of connections\n\t\tuint min = 0xFFFFFFFF;\n\t\tuint max = 0;\n\t\tCThreadPool::iterator ipt, iptmin, iptmax;\n\t\tfor ( iptmin=iptmax=ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t{\n\t\t\tuint noc = receiveTask(ipt)->numberOfConnections();\n\t\t\tif ( noc < min )\n\t\t\t{\n\t\t\t\tmin = noc;\n\t\t\t\tiptmin = ipt;\n\t\t\t}\n\t\t\tif ( noc > max )\n\t\t\t{\n\t\t\t\tmax = noc;\n\t\t\t\tiptmax = ipt;\n\t\t\t}\n\t\t}\n\n\t\t// Check if we make the pool of threads grow (if we have not found vacant room\n\t\t// and if it is allowed to)\n\t\tif ( (poolsync.value().empty()) ||\n\t\t\t ((min == max) && (poolsync.value().size() < _MaxThreads)) )\n\t\t{\n\t\t\taddNewThread( poolsync.value(), bufsock );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Dispatch socket to an existing thread of the pool\n\t\t\tCServerReceiveTask *task = receiveTask(iptmin);\n\t\t\tbufsock->setOwnerTask( task );\n\t\t\ttask->addNewSocket( bufsock );\n#ifdef NL_OS_UNIX\n\t\t\ttask->wakeUp();\n#endif\n\n\t\t\tif ( min >= (uint)_MaxSocketsPerThread )\n\t\t\t{\n\t\t\t\tnlwarning( \"LNETL1: Exceeding the maximum number of sockets per thread\" );\n\t\t\t}\n\t\t\tLNETL1_DEBUG( \"LNETL1: New socket dispatched to thread %d\", iptmin-poolsync.value().begin() );\n\t\t}\n\n\t}\n\telse // _ThreadStrategy == FillThreads\n\t{\n\t\tCThreadPool::iterator ipt;\n\t\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t\t{\n\t\t\tuint noc = receiveTask(ipt)->numberOfConnections();\n\t\t\tif ( noc < _MaxSocketsPerThread )\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Check if we have to make the thread pool grow (if we have not found vacant room)\n\t\tif ( ipt == poolsync.value().end() )\n\t\t{\n\t\t\tif ( poolsync.value().size() == _MaxThreads )\n\t\t\t{\n\t\t\t\tnlwarning( \"LNETL1: Exceeding the maximum number of threads\" );\n\t\t\t}\n\t\t\taddNewThread( poolsync.value(), bufsock );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Dispatch socket to an existing thread of the pool\n\t\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t\t\tbufsock->setOwnerTask( task );\n\t\t\ttask->addNewSocket( bufsock );\n#ifdef NL_OS_UNIX\n\t\t\ttask->wakeUp();\n#endif\n\t\t\tLNETL1_DEBUG( \"LNETL1: New socket dispatched to thread %d\", ipt-poolsync.value().begin() );\n\t\t}\n\t}\n}\n\n\n/*\n * Creates a new task and run a new thread for it\n * Precond: bufsock not null\n */\nvoid CBufServer::addNewThread( CThreadPool& threadpool, CServerBufSock *bufsock )\n{\n\tnlnettrace( \"CBufServer::addNewThread\" );\n\tnlassert( bufsock != NULL );\n\n\t// Create new task and dispatch the socket to it\n\tCServerReceiveTask *task = new CServerReceiveTask( this );\n\tbufsock->setOwnerTask( task );\n\ttask->addNewSocket( bufsock );\n\n\t// Add a new thread to the pool, with this task\n\tIThread *thr = IThread::create( task, 1024*32 );\n\t{\n\t\tthreadpool.push_back( thr );\n\t\tthr->start();\n\t\tLNETL1_DEBUG( \"LNETL1: Added a new thread; pool size is %d\", threadpool.size() );\n\t\tLNETL1_DEBUG( \"LNETL1: New socket dispatched to thread %d\", threadpool.size()-1 );\n\t}\n}\n\n\n/***************************************************************************************************\n * Receive threads\n **************************************************************************************************/\n\n\n/*\n * Code of receiving threads for servers\n */\nvoid CServerReceiveTask::run()\n{\n\tNbNetworkTask++;\n\tNbServerReceiveTask++;\n\tnlnettrace( \"CServerReceiveTask::run\" );\n\n\tSOCKET descmax;\n\tfd_set readers;\n\n#if defined NL_OS_UNIX\n\t// POLL7\n\tif (nice( 2 ) == -1) // is this really useful as long as select() sleeps?\n\t{\n\t\tnlwarning(\"LNETL1: nice() failed: code=%d '%s'\", errno, strerror(errno));\n\t}\n#endif // NL_OS_UNIX\n\n\t// Copy of _Connections\n\tvector<TSockId>\tconnections_copy;\n\n\twhile ( ! exitRequired() )\n\t{\n\t\t// 1. Remove closed connections\n\t\tclearClosedConnections();\n\n\t\t// POLL8\n\n\t\t// 2-SELECT-VERSION : select() on the sockets handled in the present thread\n\n\t\tdescmax = 0;\n\t\tFD_ZERO( &readers );\n\t\tbool skip;\n\t\tbool alldisconnected = true;\n\t\tCConnections::iterator ipb;\n\t\t{\n\t\t\t// Lock _Connections\n\t\t\tCSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\n\t\t\t// Prepare to avoid select if there is no connection\n\t\t\tskip = connectionssync.value().empty();\n\n\t\t\t// Fill the select array and copy _Connections\n\t\t\tconnections_copy.clear();\n\t\t\tfor ( ipb=connectionssync.value().begin(); ipb!=connectionssync.value().end(); ++ipb )\n\t\t\t{\n\t\t\t\tif ( (*ipb)->Sock->connected() ) // exclude disconnected sockets that are not deleted\n\t\t\t\t{\n\t\t\t\t\talldisconnected = false;\n\t\t\t\t\t// Copy _Connections element\n\t\t\t\t\tconnections_copy.push_back( *ipb );\n\n\t\t\t\t\t// Add socket descriptor to the select array\n\t\t\t\t\tFD_SET( (*ipb)->Sock->descriptor(), &readers );\n\n\t\t\t\t\t// Calculate descmax for select\n\t\t\t\t\tif ( (*ipb)->Sock->descriptor() > descmax )\n\t\t\t\t\t{\n\t\t\t\t\t\tdescmax = (*ipb)->Sock->descriptor();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n#ifdef NL_OS_UNIX\n\t\t\t// Add the wake-up pipe into the select array\n\t\t\tFD_SET( _WakeUpPipeHandle[PipeRead], &readers );\n\t\t\tif ( _WakeUpPipeHandle[PipeRead]>descmax )\n\t\t\t{\n\t\t\t\tdescmax = _WakeUpPipeHandle[PipeRead];\n\t\t\t}\n#endif\n\n\t\t\t// Unlock _Connections, use connections_copy instead\n\t\t}\n\n#ifndef NL_OS_UNIX\n\t\t// Avoid select if there is no connection (Windows only)\n\t\tif ( skip || alldisconnected )\n\t\t{\n\t\t\tnlSleep( 1 ); // nice\n\t\t\tcontinue;\n\t\t}\n#endif\n\n#ifdef NL_OS_WINDOWS\n\t\tTIMEVAL tv;\n\t\ttv.tv_sec = 0; // short time because the newly added connections can't be added to the select fd_set\n\t\ttv.tv_usec = 10000;\n\n\t\t// Call select\n\t\tint res = ::select( descmax+1, &readers, NULL, NULL, &tv );\n\n#elif defined NL_OS_UNIX\n\n\t\t// Call select\n\t\tint res = ::select( descmax+1, &readers, NULL, NULL, NULL );\n\n#endif // NL_OS_WINDOWS\n\n\n\t\t// POLL9\n\n\t\t// 3. Test the result\n\t\tswitch ( res )\n\t\t{\n#ifdef NL_OS_WINDOWS\n\t\t\tcase  0 : continue; // time-out expired, no results\n#endif\n\t\t\tcase -1 :\n\t\t\t\t// we'll ignore message (Interrupted system call) caused by a CTRL-C\n\t\t\t\t/*if (CSock::getLastError() == 4)\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG (\"LNETL1: Select failed (in receive thread): %s (code %u) but IGNORED\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError());\n\t\t\t\t\tcontinue;\n\t\t\t\t}*/\n\t\t\t\t//nlerror( \"LNETL1: Select failed (in receive thread): %s (code %u)\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError() );\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: Select failed (in receive thread): %s (code %u)\", CSock::errorString( CSock::getLastError() ).c_str(), CSock::getLastError() );\n\t\t\t\tgoto end;\n\t\t}\n\n\t\t// 4. Get results\n\n\t\tvector<TSockId>::iterator ic;\n\t\tfor ( ic=connections_copy.begin(); ic!=connections_copy.end(); ++ic )\n\t\t{\n\t\t\tif ( FD_ISSET( (*ic)->Sock->descriptor(), &readers ) != 0 )\n\t\t\t{\n\t\t\t\tCServerBufSock *serverbufsock = static_cast<CServerBufSock*>(static_cast<CBufSock*>(*ic));\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t// 4. Receive data\n\t\t\t\t\tif ( serverbufsock->receivePart( sizeof(TSockId) + 1 ) ) // +1 for the event type\n\t\t\t\t\t{\n\t\t\t\t\t\tserverbufsock->fillSockIdAndEventType( *ic );\n\n\t\t\t\t\t\t// Push message into receive queue\n\t\t\t\t\t\t//uint32 bufsize;\n\t\t\t\t\t\t//sint32 mbsize;\n\n\t\t\t\t\t\t_Server->pushMessageIntoReceiveQueue( serverbufsock->receivedBuffer() );\n\n\t\t\t\t\t\t//recvfifo.value().display();\n\t\t\t\t\t\t//bufsize = serverbufsock->receivedBuffer().size();\n\t\t\t\t\t\t//mbsize = recvfifo.value().size() / 1048576;\n\t\t\t\t\t\t//nldebug( \"RCV: Released.\" );\n\t\t\t\t\t\t/*if ( mbsize > 1 )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t\t\t\t\t\t}*/\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t// Statistics\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCSynchronized<uint32>::CAccessor syncbpi ( &_Server->syncBytesPushedIn() );\n\t\t\t\t\t\t\tsyncbpi.value() += bufsize;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t*/\n\t\t\t\t\t}\n\t\t\t\t}\n//\t\t\t\tcatch (const ESocketConnectionClosed&)\n//\t\t\t\t{\n//\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Connection %s closed\", serverbufsock->asString().c_str() );\n//\t\t\t\t\t// The socket went to _Connected=false when throwing the exception\n//\t\t\t\t}\n\t\t\t\tcatch (const ESocket&)\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Connection %s broken\", serverbufsock->asString().c_str() );\n\t\t\t\t\t(*ic)->Sock->disconnect();\n\t\t\t\t}\n/*\n#ifdef NL_OS_UNIX\n\t\t\t\tskip = true; // don't check _WakeUpPipeHandle (yes, check it to read any written byte)\n#endif\n\n*/\n\t\t\t}\n\t\t}\n\n#ifdef NL_OS_UNIX\n\t\t// Test wake-up pipe\n\t\tif ( (!skip) && (FD_ISSET( _WakeUpPipeHandle[PipeRead], &readers )) )\n\t\t{\n\t\t\tuint8 b;\n\t\t\tif ( read( _WakeUpPipeHandle[PipeRead], &b, 1 ) == -1 ) // we were woken-up by the wake-up pipe\n\t\t\t{\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: In CServerReceiveTask::run(): read() failed\" );\n\t\t\t}\n\t\t\tLNETL1_DEBUG( \"LNETL1: Receive thread select woken-up\" );\n\t\t}\n#endif\n\n\t\tNbLoop++;\n\t}\nend:\n\tnlnettrace( \"Exiting CServerReceiveTask::run\" );\n\tNbServerReceiveTask--;\n\tNbNetworkTask--;\n}\n\n\n/*\n * Delete all connections referenced in the remove list (double-mutexed)\n */\n\nvoid CServerReceiveTask::clearClosedConnections()\n{\n\tCConnections::iterator ic;\n\t{\n\t\tNLMISC::CSynchronized<CConnections>::CAccessor removesetsync( &_RemoveSet );\n\t\t{\n\t\t\tif ( ! removesetsync.value().empty() )\n\t\t\t{\n\t\t\t\t// Delete closed connections\n\t\t\t\tNLMISC::CSynchronized<CConnections>::CAccessor connectionssync( &_Connections );\n\t\t\t\tfor ( ic=removesetsync.value().begin(); ic!=removesetsync.value().end(); ++ic )\n\t\t\t\t{\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Removing a connection\" );\n\n\t\t\t\t\tTSockId sid = (*ic);\n\n\t\t\t\t\t// Remove from the connection list\n\t\t\t\t\tconnectionssync.value().erase( *ic );\n\n\t\t\t\t\t// Delete the socket object\n\t\t\t\t\tdelete sid;\n\t\t\t\t}\n\t\t\t\t// Clear remove list\n\t\t\t\tremovesetsync.value().clear();\n\t\t\t}\n\t\t}\n\t}\n}\n\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, NbServerListenTask, \"Number of server listen thread\");\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, NbServerReceiveTask, \"Number of server receive thread\");\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_server_tcp.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"nel/net/buf_server_tcp.h\"\n#include \"nel/net/net_log.h\"\n#include \"nel/net/message.h\"\n\n#include \"event2/event.h\"\n#include \"event2/listener.h\"\n#include \"event2/bufferevent.h\"\n#include \"event2/thread.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <cerrno>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#endif\n\n#include \"nel/net/buf_server_tcp_func.h\"\n\n\n/*\n * On Linux, the default limit of descriptors is usually 1024, you can increase it with ulimit\n */\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLNET {\n\n/***************************************************************************************************\n * User main thread (initialization)\n **************************************************************************************************/\n\n/*\n * Constructor\n */\nCBufServerTcp::CBufServerTcp() :\n#ifdef NL_OS_UNIX\n    CBufNetBase(false),\n#else\n    CBufNetBase(),\n#endif\n    _ConnectionCallback(NULL)\n{\n\tnlnettrace( \"CBufServerTcp::CBufServerTcp\" );\n\n    _WebSocketReceiveTask = new CTcpReceiveTask();\n}\n\n/*\n * Listens on the specified port\n */\nvoid CBufServerTcp::init( uint16 port )\n{\n\tnlnettrace( \"CBufServerTcp::init\" );\n\n    _MaxExpectedBlockSize = maxExpectedBlockSize();\n\n    _WebSocketReceiveTask->init( this, port );\n    _WebSocketReceiveTask->start();\n}\n\n/*\n * Destructor\n */\nCBufServerTcp::~CBufServerTcp()\n{\n\tnlnettrace( \"CBufServerTcp::~CBufServerTcp\" );\n\n\t// Clean listen thread exit\n\n\n//\t\t((CListenTask*)(_ListenThread->getRunnable()))->requireExit();\n//\t\t((CListenTask*)(_ListenThread->getRunnable()))->close();\n//#ifdef NL_OS_UNIX\n//\t\t_ListenTask->wakeUp();\n//#endif\n//\t\t_ListenThread->wait();\n//\t\tdelete _ListenThread;\n//\t\tdelete _ListenTask;\n\n    _WebSocketReceiveTask->close();\n\n\tnlnettrace( \"Exiting CBufServerTcp::~CBufServer\" );\n}\n\n\n/*\n * Disconnect the specified host\n * Set hostid to NULL to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * If quick is true, any pending data will not be sent before disconnecting.\n */\nvoid CBufServerTcp::disconnect( TSockId hostid, bool quick )\n{\n\tnlnettrace( \"CBufServerTcp::disconnect\" );\n    if (hostid != InvalidSockId)\n    {\n        if (_ConnectedClients.find(hostid) == _ConnectedClients.end())\n        {\n            // this host is not connected\n            return;\n        }\n\n        if (hostid->connectedState())\n        {\n            hostid->advertiseDisconnection(this, hostid);\n            //bufferevent_trigger_event(hostid->m_BEVHandle, BEV_EVENT_READING | BEV_EVENT_ERROR, 0);\n        }\n\n        //// Disconnect only if physically connected\n        //if ( hostid->Sock->connected() )\n        //{\n        //\tif ( ! quick )\n        //\t{\n        //\t\thostid->flush();\n        //\t}\n        //\thostid->Sock->disconnect(); // the connection will be removed by the next call of update()\n        //}\n    }\n    else\n    {\n        // Disconnect all\n\n    }\n}\n\n\n/*\n * Send a message to the specified host\n */\nvoid CBufServerTcp::send( const CMemStream& buffer, TSockId hostid )\n{\n\tnlnettrace( \"CBufServerTcp::send\" );\n\tnlassert( buffer.length() > 0 );\n\tnlassertex( buffer.length() <= maxSentBlockSize(), (\"length=%u max=%u\", buffer.length(), maxSentBlockSize()) );\n\n\t// slow down the layer H_AUTO (CBufServer_send);\n\n\tif ( hostid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(hostid) != _ConnectedClients.end())\n\t\t{\n\t\t\thostid->SendToLibEvent(buffer);\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Push into all send queues\n        // ȫ㲥߼öʱʵ\n\t}\n}\n\n/*\n * Checks if there are some data to receive\n */\nbool CBufServerTcp::dataAvailable()\n{\n\t// slow down the layer H_AUTO (CBufServer_dataAvailable);\n\t{\n\t\t/* If no data available, enter the 'while' loop and return false (1 volatile test)\n\t\t * If there are user data available, enter the 'while' and return true immediately (1 volatile test + 1 short locking)\n\t\t * If there is a connection/disconnection event (rare), call the callback and loop\n\t\t */\n\t\twhile ( dataAvailableFlag() )\n\t\t{\n\t\t\t// Because _DataAvailable is true, the receive queue is not empty at this point\n\t\t\tvector<uint8> buffer;\n\t\t\tuint8 val;\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\tval = recvfifo.value().frontLast();\n\t\t\t\tif ( val != CBufNetBase::User )\n\t\t\t\t{\n\t\t\t\t\trecvfifo.value().front( buffer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*sint32 mbsize = recvfifo.value().size() / 1048576;\n\t\t\tif ( mbsize > 0 )\n\t\t\t{\n\t\t\t  nlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t\t\t}*/\n\n\t\t\t/*vector<uint8> buffer;\n\t\t\trecvfifo.value().front( buffer );*/\n\n\t\t\t// Test if it the next block is a system event\n\t\t\t//switch ( buffer[buffer.size()-1] )\n\t\t\tswitch ( val )\n\t\t\t{\n\n\t\t\t// Normal message available\n\t\t\tcase CBufNetBase::User:\n\t\t\t\t{\n\t\t\t\t\treturn true; // return immediately, do not extract the message\n\t\t\t\t}\n\n\t\t\t// Process disconnection event\n\t\t\tcase CBufNetBase::Disconnection:\n\t\t\t\t{\n                    TSockId sockid = *((TSockId*)(&*buffer.begin()));\n\n                    if (_ConnectedClients.count(sockid) > 0)\n                    {\n                        LNETL1_DEBUG(\"LNETL1: Disconnection event for %p %s\", sockid, sockid->asString().c_str());\n                        sockid->setConnectedState(false);\n\n                        // Call callback if needed\n                        if (disconnectionCallback() != NULL)\n                        {\n                            disconnectionCallback()(sockid, argOfDisconnectionCallback());\n                        }\n\n                        //  Զclose׽ֺfreeд \n                        bufferevent_free(sockid->m_BEVHandle);\n                        sockid->m_BEVHandle = NULL;\n\n                        if (sockid->m_Ssl != NULL)\n                        {\n                            nlwarning(\"tcp not setup ssl\");\n                            //SSL_free(sockid->m_Ssl);\n                            //sockid->m_Ssl = NULL;\n                        }\n\n                        // remove from the list of valid client\n                        nlverify(_ConnectedClients.erase(sockid) == 1);\n\n                        // Add socket object into the remove list\n                        LNETL1_DEBUG( \"LNETL1: Adding the connection to the remove list\" );\n                        _RmDisConnectSockids.push_back(sockid);\n                    }\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t// Process connection event\n\t\t\tcase CBufNetBase::Connection:\n\t\t\t\t{\n\t\t\t\t\tTSockId sockid = *((TSockId*)(&*buffer.begin()));\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Connection event for %p %s\", sockid, sockid->asString().c_str());\n\n\t\t\t\t\t// add this socket in the list of client\n\t\t\t\t\tnlverify(_ConnectedClients.insert(sockid).second);\n\n\t\t\t\t\tsockid->setConnectedState( true );\n\n\t\t\t\t\t// Call callback if needed\n\t\t\t\t\tif ( connectionCallback() != NULL )\n\t\t\t\t\t{\n\t\t\t\t\t\tconnectionCallback()( sockid, argOfConnectionCallback() );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdefault: // should not occur\n\t\t\t\tLNETL1_INFO( \"LNETL1: Invalid block type: %hu (should be = to %hu\", (uint16)(buffer[buffer.size()-1]), (uint16)(val) );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Buffer (%d B): [%s]\", buffer.size(), stringFromVector(buffer).c_str() );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Receive queue:\" );\n\t\t\t\t{\n\t\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\t\trecvfifo.value().display();\n\t\t\t\t}\n\t\t\t\tnlerror( \"LNETL1: Invalid system event type in server receive queue\" );\n\n\t\t\t}\n\n\t\t\t// Extract system event\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\trecvfifo.value().pop();\n\t\t\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t\t\t}\n\t\t}\n\n        // Remove closed connections\n        LNETL1_DEBUG(\"LNETL1: Removing disconnection\");\n        if (!_RmDisConnectSockids.empty())\n        {\n            for (uint i = 0; i < _RmDisConnectSockids.size(); ++i)\n            {\n                delete _RmDisConnectSockids[i];\n            }\n\n            _RmDisConnectSockids.clear();\n        }\n\n\t\t// _DataAvailable is false here\n\t\treturn false;\n\t}\n}\n\n\n#ifdef NL_OS_UNIX\n/* Wait until the receive queue contains something to read (implemented with a select()).\n * This is where the connection/disconnection callbacks can be called.\n * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n */\nvoid\tCBufServerTcp::sleepUntilDataAvailable( uint usecMax )\n{\n\t// Prevent looping infinitely if the system time was changed\n\tif ( usecMax > 999999 ) // limit not told in Linux man but here: http://docs.hp.com/en/B9106-90009/select.2.html\n\t\tusecMax = 999999;\n\n\tfd_set readers;\n\ttimeval tv;\n\tdo\n\t{\n\t\tFD_ZERO( &readers );\n\t\tFD_SET( _DataAvailablePipeHandle[PipeRead], &readers );\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = usecMax;\n\t\tint res = ::select( _DataAvailablePipeHandle[PipeRead]+1, &readers, NULL, NULL, &tv );\n\t\tif ( res == -1 )\n\t\t\tnlerror( \"LNETL1: Select failed in sleepUntilDataAvailable (code %u)\", CSock::getLastError() );\n\t}\n\twhile ( ! dataAvailable() ); // will loop if only a connection/disconnection event was read\n}\n#endif\n\n\n/*\n * Receives next block of data in the specified. The length and hostid are output arguments.\n * Precond: dataAvailable() has returned true, phostid not null\n */\nvoid CBufServerTcp::receive( CMemStream& buffer, TSockId* phostid )\n{\n\tnlnettrace( \"CBufServerTcp::receive\" );\n\t//nlassert( dataAvailable() );\n\tnlassert( phostid != NULL );\n\n\t{\n\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\tnlassert( ! recvfifo.value().empty() );\n\t\trecvfifo.value().front( buffer );\n\t\trecvfifo.value().pop();\n\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t}\n\n\t// Extract hostid (and event type)\n\t*phostid = *((TSockId*)&(buffer.buffer()[buffer.size()-sizeof(uint64)-1]));\n\tnlassert( buffer.buffer()[buffer.size()-1] == CBufNetBase::User );\n\n\tbuffer.resize( buffer.size()-sizeof(uint64)-1 );\n\n\t// TODO OPTIM remove the nldebug for speed\n\t//commented for optimisation LNETL1_DEBUG( \"LNETL1: Read buffer (%d+%d B) from %s\", buffer.size(), sizeof(TSockId)+1, /*stringFromVector(buffer).c_str(), */(*phostid)->asString().c_str() );\n\n\t// Statistics\n\t_BytesPoppedIn += buffer.size() + sizeof(TBlockSize);\n}\n\n\n/*\n * Update the network (call this method evenly)\n */\nvoid CBufServerTcp::update()\n{\n\t//nlnettrace( \"CBufServer::update-BEGIN\" );\n\n\t_NbConnections = 0;\n\n\t// For each thread\n\n\n\t//nlnettrace( \"CBufServer::update-END\" );\n}\n\nuint32 CBufServerTcp::getSendQueueSize( TSockId destid )\n{\n\tif ( destid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(destid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn destid->SendFifo.size();\n\t}\n\telse\n\t{\n\t\t// add all client buffers\n\n\t\tuint32 total = 0;\n\n\t\t// For each thread\n\n\t\treturn total;\n\t}\n}\n\nvoid CBufServerTcp::displayThreadStat (NLMISC::CLog *log)\n{\n\t//// For each thread\n\t//CThreadPool::iterator ipt;\n\t//{\n\t//\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t//\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t//\t{\n\t//\t\t// For each thread of the pool\n\t//\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t//\t\t// For each socket of the thread, update sending\n\t//\t\tlog->displayNL (\"server receive thread %p nbloop %d\", task, task->NbLoop);\n\t//\t}\n\t//}\n\n\t//log->displayNL (\"server listen thread %p nbloop %d\", _ListenTask, _ListenTask->NbLoop);\n}\n\nvoid CBufServerTcp::setTimeFlushTrigger( TSockId destid, sint32 ms )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setTimeFlushTrigger( ms );\n}\n\nvoid CBufServerTcp::setSizeFlushTrigger( TSockId destid, sint32 size )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setSizeFlushTrigger( size );\n}\n\nbool CBufServerTcp::flush( TSockId destid, uint *nbBytesRemaining)\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\treturn destid->flush( nbBytesRemaining );\n\telse\n\t\treturn true;\n}\nconst CInetAddress& CBufServerTcp::hostAddress( TSockId hostid )\n{\n\tnlassert( hostid != InvalidSockId );\n\tif (_ConnectedClients.find(hostid) != _ConnectedClients.end())\n\t\treturn hostid->Sock->remoteAddr();\n\n\tstatic CInetAddress nullAddr;\n\treturn nullAddr;\n}\n\nvoid CBufServerTcp::displaySendQueueStat (NLMISC::CLog *log, TSockId destid)\n{\n\n}\n\n/*\n * Returns the number of bytes received since the previous call to this method\n */\nuint64 CBufServerTcp::newBytesReceived()\n{\n\tuint64 b = bytesReceived();\n\tuint64 nbrecvd = b - _PrevBytesPoppedIn;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbrecvd );\n\t_PrevBytesPoppedIn = b;\n\treturn nbrecvd;\n}\n\n/*\n * Returns the number of bytes sent since the previous call to this method\n */\nuint64 CBufServerTcp::newBytesSent()\n{\n\tuint64 b = bytesSent();\n\tuint64 nbsent = b - _PrevBytesPushedOut;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbsent );\n\t_PrevBytesPushedOut = b;\n\treturn nbsent;\n}\n\nvoid CTcpReceiveTask::init( CBufServerTcp *server, uint16 port )\n{\n\t_Server = server;\n\n    struct sockaddr_in sin;  \n    memset(&sin, 0, sizeof(struct sockaddr_in));  \n    sin.sin_family = AF_INET;  \n    sin.sin_port = htons(port); \n\n#ifdef NL_OS_WINDOWS\n    evthread_use_windows_threads();\n#else\n    evthread_use_pthreads();\n#endif\n\n    pEventBase = event_base_new();\n    TcpListenArgs* pListenArgs = new struct TcpListenArgs(pEventBase,_Server);\n    \n\n    pEvListener = evconnlistener_new_bind(  pEventBase, tcp_listener_cb, (void*)pListenArgs, \n                                            LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, 10, \n                                            (struct sockaddr*)&sin, sizeof(struct sockaddr_in));  \n\n}\n\nvoid CTcpReceiveTask::run()\n{\n\tnlnettrace( \"CTcpReceiveTask::run\" );\n    event_base_dispatch(pEventBase);  \n}\n\nbool CTcpReceiveTask::start()\n{\n    _ProcTableThread = NLMISC::IThread::create( this );\n\n    if ( _ProcTableThread != NULL )\n    {\n        _ProcTableThread->start();\n        _ExitRequired = false;\n    }\n\n    return ( NULL != _ProcTableThread );\n}\n\nvoid CTcpReceiveTask::close()\n{\n    if ( NULL != _ProcTableThread )\n    {\n        _ExitRequired = true;\n        _ProcTableThread->wait();\n        evconnlistener_free(pEvListener);  \n        event_base_free(pEventBase); \n    }\n}\n\n\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_server_tcp_func.cpp",
    "content": "#include \"nel/net/buf_server_tcp_func.h\"\n#include \"nel/misc/sha1.h\"\n#include \"nel/misc/base64.h\"\n#include \"nel/net/buf_sock.h\"\n#include \"nel/net/callback_server_tcp.h\"\n#include \"nel/net/buf_server_tcp.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n#ifdef NL_OS_UNIX\n#\tdefine INVALID_SOCKET -1\n#endif\n\nvoid NLNET::tcp_socket_read_cb( bufferevent *bev, void *args )\n{  \n    char read_buffer[4096];  \n    size_t  len = bufferevent_read(bev, read_buffer, sizeof(read_buffer) );\n    CServerBufSock* pBufSock = (CServerBufSock*)args;\n    uint32 buff_len = pBufSock->appendToBuffer( (const uint8*)read_buffer, len );\n\n    while( buff_len >= sizeof(TBlockSize) )\n    {\n        uint8* buff         = pBufSock->getBuffer();\n        uint32 data_len     = ntohl(*(uint32*)(buff));\n\n        /// ѾչһϢ\n        if ( buff_len >= data_len+sizeof(TBlockSize) )\n        {\n            NLMISC::CMemStream& msg=pBufSock->CompleteMsg;\n\n            if (msg.isReading())\n            {\n                msg.invert();\n            }\n\n            msg.fill( buff+sizeof(TBlockSize), data_len );\n\n            uint8 event_type    = CBufNetBase::User;\n            uint64 sockid       = (uint64)pBufSock;\n            msg.serial( sockid );\n            msg.serial( event_type );\n            msg.invert();\n\n            pBufSock->m_BufNetHandle->pushMessageIntoReceiveQueue( msg.buffer(), msg.size() );\n            buff_len = pBufSock->leftShiftBuffer(data_len+sizeof(TBlockSize));\n        }\n        else\n        {\n            break;\n        }\n    }\n}  \n\nvoid NLNET::tcp_socket_event_cb( bufferevent *bev, short events, void *args )\n{  \n    if (events & BEV_EVENT_EOF)  \n        LNETL1_DEBUG(\"connection closed\\n\");  \n    else if (events & BEV_EVENT_ERROR)  \n        LNETL1_DEBUG(\"some other error\\n\");\n\n    LNETL1_DEBUG( \"tcp_socket_event_cb:%d\", events );\n\n    CServerBufSock* pBufSock = (CServerBufSock*)args;\n    pBufSock->advertiseDisconnection( pBufSock->m_BufNetHandle, pBufSock );\n}\n\nvoid NLNET::tcp_listener_cb( evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sock, int socklen, void *args )\n{  \n    TcpListenArgs*  pListenArgs = (TcpListenArgs*)args;\n    SOCKET          newSock = (SOCKET)fd;\n\n    if ( newSock == INVALID_SOCKET )\n    {\n        throw ESocket( \"Accept returned an invalid socket\");\n    }\n\n    // Construct and save a CTcpSock object\n    CInetAddress addr;\n    addr.setSockAddr( (struct sockaddr_in*)sock );\n    //LNETL0_DEBUG( \"LNETL0: Socket %d accepted an incoming connection from %s, opening socket %d\", _Sock, addr.asString().c_str(), newsock );\n    CTcpSock *pTcpSock = new CTcpSock( newSock, addr );\n    CServerBufSock *pBufSock = new CServerBufSock( pTcpSock );\n    LNETL1_DEBUG( \"LNETL1: New connection : %s\", pBufSock->asString().c_str() );\n\n    // Notify the new connection\n    pBufSock->advertiseConnection( pListenArgs->pServer );\n\n    //Ϊͻ˷һbufferevent  \n    bufferevent *bev =  bufferevent_socket_new(pListenArgs->pEventBase, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS);\n\n    pBufSock->m_BufNetHandle    = pListenArgs->pServer;\n    pBufSock->m_BEVHandle       = bev;\n\n    bufferevent_setcb(bev, tcp_socket_read_cb , NULL, tcp_socket_event_cb, (void*)pBufSock);\n    bufferevent_enable(bev, EV_READ | EV_PERSIST); \n}  \n\n\n"
  },
  {
    "path": "code/nel/src/net/buf_server_websocket.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"nel/net/buf_server_websocket.h\"\n#include \"nel/net/net_log.h\"\n#include \"nel/net/message.h\"\n\n#include \"event2/event.h\"\n#include \"event2/listener.h\"\n#include \"event2/bufferevent.h\"\n#include \"event2/thread.h\"\n\n#include \"openssl/ssl.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <cerrno>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#endif\n\n#include \"nel/net/buf_server_websocket_func.h\"\n\n/*\n * On Linux, the default limit of descriptors is usually 1024, you can increase it with ulimit\n */\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLNET {\n\n\n/***************************************************************************************************\n * User main thread (initialization)\n **************************************************************************************************/\n\n/*\n * Constructor\n */\nCBufServerWebsocket::CBufServerWebsocket() :\n#ifdef NL_OS_UNIX\n    CBufNetBase(false),\n#else\n    CBufNetBase(),\n#endif\n    _ConnectionCallback(NULL),\n    _SslCtx(NULL)\n{\n\tnlnettrace( \"CBufServerWebsocket::CBufServerWebsocket\" );\n\n    _WebSocketReceiveTask = new CWebSocketReceiveTask();\n}\n\n/*\n * Listens on the specified port\n */\nvoid CBufServerWebsocket::init( uint16 port )\n{\n\tnlnettrace( \"CBufServerWebsocket::init\" );\n\n    _MaxExpectedBlockSize = maxExpectedBlockSize();\n\n    _WebSocketReceiveTask->init( this, port );\n    _WebSocketReceiveTask->start();\n}\n\n/*\n * Destructor\n */\nCBufServerWebsocket::~CBufServerWebsocket()\n{\n\tnlnettrace( \"CBufServerWebsocket::~CBufServerWebsocket\" );\n\n\t// Clean listen thread exit\n\n\n//\t\t((CListenTask*)(_ListenThread->getRunnable()))->requireExit();\n//\t\t((CListenTask*)(_ListenThread->getRunnable()))->close();\n//#ifdef NL_OS_UNIX\n//\t\t_ListenTask->wakeUp();\n//#endif\n//\t\t_ListenThread->wait();\n//\t\tdelete _ListenThread;\n//\t\tdelete _ListenTask;\n\n\n\n    if ( _SslCtx!=NULL )\n    {\n        SSL_CTX_free((SSL_CTX*)_SslCtx);\n    }\n\n    _WebSocketReceiveTask->close();\n\n\tnlnettrace( \"Exiting CBufServerWebsocket::~CBufServer\" );\n}\n\n\n/*\n * Disconnect the specified host\n * Set hostid to NULL to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * If quick is true, any pending data will not be sent before disconnecting.\n */\nvoid CBufServerWebsocket::disconnect( TSockId hostid, bool quick )\n{\n\tnlnettrace( \"CBufServerWebsocket::disconnect\" );\n\tif ( hostid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(hostid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn;\n\t\t}\n\n        if ( hostid->connectedState() )\n        {\n            hostid->advertiseDisconnection(this, hostid);\n            //bufferevent_trigger_event(hostid->m_BEVHandle, BEV_EVENT_EOF, BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS);\n        }\n        \n\t\t//// Disconnect only if physically connected\n\t\t//if ( hostid->Sock->connected() )\n\t\t//{\n\t\t//\tif ( ! quick )\n\t\t//\t{\n\t\t//\t\thostid->flush();\n\t\t//\t}\n\t\t//\thostid->Sock->disconnect(); // the connection will be removed by the next call of update()\n\t\t//}\n\t}\n\telse\n\t{\n\t\t// Disconnect all\n\n\t}\n}\n\n\n/*\n * Send a message to the specified host\n */\nvoid CBufServerWebsocket::send( const CMemStream& buffer, TSockId hostid )\n{\n\tnlnettrace( \"CBufServerWebsocket::send\" );\n\tnlassert( buffer.length() > 0 );\n\tnlassertex( buffer.length() <= maxSentBlockSize(), (\"length=%u max=%u\", buffer.length(), maxSentBlockSize()) );\n\n\t// slow down the layer H_AUTO (CBufServer_send);\n\n    if ( hostid != InvalidSockId )\n    {\n        if (_ConnectedClients.find(hostid) != _ConnectedClients.end())\n        {\n            hostid->SendToLibEvent(buffer, true);\n        }\n    }\n    else\n    {\n        // Push into all send queues\n        // ȫ㲥߼öʱʵ\n    }\n}\n\n\n/*\n * Checks if there are some data to receive\n */\nbool CBufServerWebsocket::dataAvailable()\n{\n\t// slow down the layer H_AUTO (CBufServer_dataAvailable);\n\t{\n\t\t/* If no data available, enter the 'while' loop and return false (1 volatile test)\n\t\t * If there are user data available, enter the 'while' and return true immediately (1 volatile test + 1 short locking)\n\t\t * If there is a connection/disconnection event (rare), call the callback and loop\n\t\t */\n\t\twhile ( dataAvailableFlag() )\n\t\t{\n\t\t\t// Because _DataAvailable is true, the receive queue is not empty at this point\n\t\t\tvector<uint8> buffer;\n\t\t\tuint8 val;\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\tval = recvfifo.value().frontLast();\n\t\t\t\tif ( val != CBufNetBase::User )\n\t\t\t\t{\n\t\t\t\t\trecvfifo.value().front( buffer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/*sint32 mbsize = recvfifo.value().size() / 1048576;\n\t\t\tif ( mbsize > 0 )\n\t\t\t{\n\t\t\t  nlwarning( \"The receive queue size exceeds %d MB\", mbsize );\n\t\t\t}*/\n\n\t\t\t/*vector<uint8> buffer;\n\t\t\trecvfifo.value().front( buffer );*/\n\n\t\t\t// Test if it the next block is a system event\n\t\t\t//switch ( buffer[buffer.size()-1] )\n\t\t\tswitch ( val )\n\t\t\t{\n\n\t\t\t// Normal message available\n\t\t\tcase CBufNetBase::User:\n\t\t\t\t{\n\t\t\t\t\treturn true; // return immediately, do not extract the message\n\t\t\t\t}\n\n\t\t\t// Process disconnection event\n\t\t\tcase CBufNetBase::Disconnection:\n\t\t\t\t{\n                    TSockId sockid = *((TSockId*)(&*buffer.begin()));\n                    \n                    if (_ConnectedClients.count(sockid) > 0)\n                    {\n                        LNETL1_DEBUG(\"LNETL1: Disconnection event for %p %s\", sockid, sockid->asString().c_str());\n                        sockid->setConnectedState(false);\n\n                        // Call callback if needed\n                        if (disconnectionCallback() != NULL)\n                        {\n                            disconnectionCallback()(sockid, argOfDisconnectionCallback());\n                        }\n\n                        // Add socket object into the synchronized remove list\n                        //LNETL1_DEBUG( \"LNETL1: Adding the connection to the remove list\" );\n                        //nlassert( ((CServerBufSock*)sockid)->ownerTask() != NULL );\n                        //((CServerBufSock*)sockid)->ownerTask()->addToRemoveSet( sockid );\n\n\n                        //  Զclose׽ֺfreeд \n                        bufferevent_free(sockid->m_BEVHandle);\n\n                        if (sockid->m_Ssl != NULL)\n                        {\n                            //SSL_free((SSL*)sockid->m_Ssl);\n                            sockid->m_Ssl = NULL;\n                        }\n\n                        // remove from the list of valid client\n                        nlverify(_ConnectedClients.erase(sockid) == 1);\n\n\n                        // Add socket object into the remove list\n                        LNETL1_DEBUG(\"LNETL1: Adding the connection to the remove list\");\n                        _RmDisConnectSockids.push_back(sockid);\n                    }\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t// Process connection event\n\t\t\tcase CBufNetBase::Connection:\n\t\t\t\t{\n\t\t\t\t\tTSockId sockid = *((TSockId*)(&*buffer.begin()));\n\t\t\t\t\tLNETL1_DEBUG( \"LNETL1: Connection event for %p %s\", sockid, sockid->asString().c_str());\n\n\t\t\t\t\t// add this socket in the list of client\n\t\t\t\t\tnlverify(_ConnectedClients.insert(sockid).second);\n\n\t\t\t\t\tsockid->setConnectedState( true );\n\n\t\t\t\t\t// Call callback if needed\n\t\t\t\t\tif ( connectionCallback() != NULL )\n\t\t\t\t\t{\n\t\t\t\t\t\tconnectionCallback()( sockid, argOfConnectionCallback() );\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdefault: // should not occur\n\t\t\t\tLNETL1_INFO( \"LNETL1: Invalid block type: %hu (should be = to %hu\", (uint16)(buffer[buffer.size()-1]), (uint16)(val) );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Buffer (%d B): [%s]\", buffer.size(), stringFromVector(buffer).c_str() );\n\t\t\t\tLNETL1_INFO( \"LNETL1: Receive queue:\" );\n\t\t\t\t{\n\t\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\t\trecvfifo.value().display();\n\t\t\t\t}\n\t\t\t\tnlerror( \"LNETL1: Invalid system event type in server receive queue\" );\n\n\t\t\t}\n\n\t\t\t// Extract system event\n\t\t\t{\n\t\t\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\t\t\trecvfifo.value().pop();\n\t\t\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t\t\t}\n\t\t}\n\n        // Remove closed connections\n        LNETL1_DEBUG(\"LNETL1: Removing disconnection\");\n        if (!_RmDisConnectSockids.empty())\n        {\n            for (uint i = 0; i < _RmDisConnectSockids.size(); ++i)\n            {\n                delete _RmDisConnectSockids[i];\n            }\n\n            _RmDisConnectSockids.clear();\n        }\n\n\t\t// _DataAvailable is false here\n\t\treturn false;\n\t}\n}\n\n\n#ifdef NL_OS_UNIX\n/* Wait until the receive queue contains something to read (implemented with a select()).\n * This is where the connection/disconnection callbacks can be called.\n * \\param usecMax Max time to wait in microsecond (up to 1 sec)\n */\nvoid\tCBufServerWebsocket::sleepUntilDataAvailable( uint usecMax )\n{\n\t// Prevent looping infinitely if the system time was changed\n\tif ( usecMax > 999999 ) // limit not told in Linux man but here: http://docs.hp.com/en/B9106-90009/select.2.html\n\t\tusecMax = 999999;\n\n\tfd_set readers;\n\ttimeval tv;\n\tdo\n\t{\n\t\tFD_ZERO( &readers );\n\t\tFD_SET( _DataAvailablePipeHandle[PipeRead], &readers );\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = usecMax;\n\t\tint res = ::select( _DataAvailablePipeHandle[PipeRead]+1, &readers, NULL, NULL, &tv );\n\t\tif ( res == -1 )\n\t\t\tnlerror( \"LNETL1: Select failed in sleepUntilDataAvailable (code %u)\", CSock::getLastError() );\n\t}\n\twhile ( ! dataAvailable() ); // will loop if only a connection/disconnection event was read\n}\n#endif\n\n\n/*\n * Receives next block of data in the specified. The length and hostid are output arguments.\n * Precond: dataAvailable() has returned true, phostid not null\n */\nvoid CBufServerWebsocket::receive( CMemStream& buffer, TSockId* phostid )\n{\n\tnlnettrace( \"CBufServerWebsocket::receive\" );\n\t//nlassert( dataAvailable() );\n\tnlassert( phostid != NULL );\n\n\t{\n\t\tCFifoAccessor recvfifo( &receiveQueue() );\n\t\tnlassert( ! recvfifo.value().empty() );\n\t\trecvfifo.value().front( buffer );\n\t\trecvfifo.value().pop();\n\t\tsetDataAvailableFlag( ! recvfifo.value().empty() );\n\t}\n\n\t// Extract hostid (and event type)\n\t*phostid = *((TSockId*)&(buffer.buffer()[buffer.size()-sizeof(uint64)-1]));\n\tnlassert( buffer.buffer()[buffer.size()-1] == CBufNetBase::User );\n\n\tbuffer.resize( buffer.size()-sizeof(uint64)-1 );\n\n\t// TODO OPTIM remove the nldebug for speed\n\t//commented for optimisation LNETL1_DEBUG( \"LNETL1: Read buffer (%d+%d B) from %s\", buffer.size(), sizeof(TSockId)+1, /*stringFromVector(buffer).c_str(), */(*phostid)->asString().c_str() );\n\n\t// Statistics\n\t_BytesPoppedIn += buffer.size() + sizeof(TBlockSize);\n}\n\n\n/*\n * Update the network (call this method evenly)\n */\nvoid CBufServerWebsocket::update()\n{\n\t//nlnettrace( \"CBufServer::update-BEGIN\" );\n\n\t_NbConnections = 0;\n\n\t// For each thread\n\n\n\t//nlnettrace( \"CBufServer::update-END\" );\n}\n\nuint32 CBufServerWebsocket::getSendQueueSize( TSockId destid )\n{\n\tif ( destid != InvalidSockId )\n\t{\n\t\tif (_ConnectedClients.find(destid) == _ConnectedClients.end())\n\t\t{\n\t\t\t// this host is not connected\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn destid->SendFifo.size();\n\t}\n\telse\n\t{\n\t\t// add all client buffers\n\n\t\tuint32 total = 0;\n\n\t\t// For each thread\n\n\t\treturn total;\n\t}\n}\n\nvoid CBufServerWebsocket::displayThreadStat (NLMISC::CLog *log)\n{\n\t//// For each thread\n\t//CThreadPool::iterator ipt;\n\t//{\n\t//\tCSynchronized<CThreadPool>::CAccessor poolsync( &_ThreadPool );\n\t//\tfor ( ipt=poolsync.value().begin(); ipt!=poolsync.value().end(); ++ipt )\n\t//\t{\n\t//\t\t// For each thread of the pool\n\t//\t\tCServerReceiveTask *task = receiveTask(ipt);\n\t//\t\t// For each socket of the thread, update sending\n\t//\t\tlog->displayNL (\"server receive thread %p nbloop %d\", task, task->NbLoop);\n\t//\t}\n\t//}\n\n\t//log->displayNL (\"server listen thread %p nbloop %d\", _ListenTask, _ListenTask->NbLoop);\n}\n\nvoid CBufServerWebsocket::setTimeFlushTrigger( TSockId destid, sint32 ms )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setTimeFlushTrigger( ms );\n}\n\nvoid CBufServerWebsocket::setSizeFlushTrigger( TSockId destid, sint32 size )\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\tdestid->setSizeFlushTrigger( size );\n}\n\nbool CBufServerWebsocket::flush( TSockId destid, uint *nbBytesRemaining)\n{\n\tnlassert( destid != InvalidSockId );\n\tif (_ConnectedClients.find(destid) != _ConnectedClients.end())\n\t\treturn destid->flush( nbBytesRemaining );\n\telse\n\t\treturn true;\n}\nconst CInetAddress& CBufServerWebsocket::hostAddress( TSockId hostid )\n{\n\tnlassert( hostid != InvalidSockId );\n\tif (_ConnectedClients.find(hostid) != _ConnectedClients.end())\n\t\treturn hostid->Sock->remoteAddr();\n\n\tstatic CInetAddress nullAddr;\n\treturn nullAddr;\n}\n\nvoid CBufServerWebsocket::displaySendQueueStat (NLMISC::CLog *log, TSockId destid)\n{\n\n}\n\n\n/*\n * Returns the number of bytes received since the previous call to this method\n */\nuint64 CBufServerWebsocket::newBytesReceived()\n{\n\tuint64 b = bytesReceived();\n\tuint64 nbrecvd = b - _PrevBytesPoppedIn;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbrecvd );\n\t_PrevBytesPoppedIn = b;\n\treturn nbrecvd;\n}\n\n/*\n * Returns the number of bytes sent since the previous call to this method\n */\nuint64 CBufServerWebsocket::newBytesSent()\n{\n\tuint64 b = bytesSent();\n\tuint64 nbsent = b - _PrevBytesPushedOut;\n\t//nlinfo( \"b: %\" NL_I64 \"u   new: %\" NL_I64 \"u\", b, nbsent );\n\t_PrevBytesPushedOut = b;\n\treturn nbsent;\n}\n\nvoid CBufServerWebsocket::setupSsl( std::string& ssl_ca, std::string& ssl_crt, std::string& ssl_prvkey )\n{\n    SSL_library_init();\n    SSL_load_error_strings();\n\n    const SSL_METHOD* pMethod   = SSLv23_server_method();\n    _SslCtx                     = SSL_CTX_new(pMethod);\n\n    //  ǷҪУԷ֤ ˴֤ͻΪ SSL_VERIFY_NONE\n    SSL_CTX_set_verify((SSL_CTX *)_SslCtx, SSL_VERIFY_NONE, NULL);\n\n    //  CA֤  \n    if(!SSL_CTX_load_verify_locations((SSL_CTX *)_SslCtx, ssl_ca.c_str(), NULL))\n    {\n        nlwarning(\"SSL_CTX_load_verify_locations error!\");\n        return;\n    }\n\n    //  Լ֤  \n    if(SSL_CTX_use_certificate_file((SSL_CTX *)_SslCtx, ssl_crt.c_str(), SSL_FILETYPE_PEM) <= 0)\n    {\n        nlwarning(\"SSL_CTX_use_certificate_file error!\");\n        return;\n    }\n\n    //  Լ˽Կ  ˽ԿǣsslֹУԿͻ˷͹\n    //  ϢмܣȻͻʹ÷ĹԿнܣܺԭʼϢ\n    //  ͻ˷͵ϢһֱΪ˷ǿͻҪӵķ\n    if(SSL_CTX_use_PrivateKey_file((SSL_CTX *)_SslCtx, ssl_prvkey.c_str(), SSL_FILETYPE_PEM) <= 0)\n    {\n        nlwarning(\"SSL_CTX_use_PrivateKey_file error!\");\n        return;\n    }\n\n    // ж˽ԿǷȷ  \n    if(!SSL_CTX_check_private_key((SSL_CTX *)_SslCtx))\n    {\n        nlwarning(\"SSL_CTX_check_private_key error!\");\n        return;\n    }\n}\n\nvoid CWebSocketReceiveTask::init( CBufServerWebsocket *server, uint16 port )\n{\n\t_Server = server;\n\n    struct sockaddr_in sin;\n    memset(&sin, 0, sizeof(struct sockaddr_in));\n    sin.sin_family = AF_INET;\n    sin.sin_port = htons(port);\n\n#ifdef NL_OS_UNIX\n    evthread_use_pthreads();\n#else\n    evthread_use_windows_threads();\n#endif\n\n    pEventBase = event_base_new();\n    WSListenArgs* pListenArgs   = new struct WSListenArgs(pEventBase,_Server);\n    pListenArgs->pSslCtx        = server->getSslCtx();\n\n    pEvListener = evconnlistener_new_bind(  pEventBase, ws_listener_cb, (void*)pListenArgs, \n        LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE | LEV_OPT_THREADSAFE, 10,\n        (struct sockaddr*)&sin, sizeof(struct sockaddr_in));\n}\n\nvoid CWebSocketReceiveTask::run()\n{\n\tnlnettrace( \"CWebSocketReceiveTask::run\" );\n    event_base_dispatch(pEventBase);  \n}\n\nbool CWebSocketReceiveTask::start()\n{\n    _ProcTableThread = NLMISC::IThread::create( this );\n\n    if ( _ProcTableThread != NULL )\n    {\n        _ProcTableThread->start();\n        _ExitRequired = false;\n    }\n\n    return ( NULL != _ProcTableThread );\n}\n\nvoid CWebSocketReceiveTask::close()\n{\n    if ( NULL != _ProcTableThread )\n    {\n        _ExitRequired = true;\n        _ProcTableThread->wait();\n        evconnlistener_free(pEvListener);  \n        event_base_free(pEventBase); \n    }\n}\n\n\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/buf_server_websocket_func.cpp",
    "content": "#include \"nel/net/buf_server_websocket_func.h\"\n#include \"nel/misc/sha1.h\"\n#include \"nel/misc/base64.h\"\n#include \"nel/net/buf_sock.h\"\n#include \"nel/net/callback_server_websocket.h\"\n#include \"nel/net/buf_server_websocket.h\"\n\n#include \"event2/bufferevent_ssl.h\"\n#include \"openssl/ssl.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\n#ifdef NL_OS_UNIX\n#\tdefine INVALID_SOCKET -1\n#endif\n\nCSString NLNET::generate_key( const NLMISC::CSString &key )\n{\n    CSString tmp = key + \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n    CHashKey hash_key = getSHA1( (const uint8 *)tmp.c_str(), tmp.size() );\n    return base64_encode( hash_key.HashKeyString );\n}\n\nCSString NLNET::generate_websocket_response( CSString& sec_websocket_key )\n{\n    CSString resp;\n\n    resp += \"HTTP/1.1 101 WebSocket Protocol HandShake\\r\\n\";\n    resp += \"Connection: Upgrade\\r\\n\";\n    resp += \"Upgrade: WebSocket\\r\\n\";\n    //resp += \"Server: WebChat Demo Server\\r\\n\";\n    resp += \"Sec-WebSocket-Accept: \" + generate_key(sec_websocket_key) + \"\\r\\n\";\n    resp += \"\\r\\n\";\n\n    return resp;\n}\n\nsint32 NLNET::parse_frame_header( const uint8 *buf, WebSocketFrame& frame )\n{\n    if (!buf)\n    {\n        return -1;\n    }\n\n    unsigned char c1 = *buf;\n    unsigned char c2 = *(buf + 1);\n    frame.fin = (c1 >> 7) & 0xff;\n    frame.opcode = c1 & 0x0f;\n    frame.mask = (c2 >> 7) & 0xff;\n    frame.payload_len = c2 & 0x7f;\n\n    return 0;\n}\n\nvoid NLNET::ws_socket_read_cb( bufferevent *bev, void *args )\n{  \n    char read_buffer[4096];  \n    size_t  len = bufferevent_read(bev, read_buffer, sizeof(read_buffer) );\n    CServerBufSock* pBufSock = (CServerBufSock*)args;\n\n    if( !pBufSock->m_Handshake )\n    {\n        if( len < sizeof(read_buffer) )\n        {\n            read_buffer[len] = '\\0';\n            CSString  http_head(read_buffer);\n\n            CVectorSString  split_req;\n            http_head.splitLines( split_req );\n\n            for ( uint i=0; i<split_req.size(); ++i )\n            {\n                CVectorSString  split_key;\n                split_req[i].splitBySeparator(':', split_key);\n\n                if ( split_key.size() == 2 && split_key[0] == \"Sec-WebSocket-Key\"  )\n                {\n                    CSString res_val = split_key[1].strip();\n                    CSString res_key = generate_websocket_response(res_val);\n                    bufferevent_write(bev, res_key.c_str(), res_key.size() );\n                    pBufSock->m_Handshake = true;\n                }\n            }\n        }\n    }\n    else\n    {\n        uint32 buff_len = pBufSock->appendToBuffer( (const uint8*)read_buffer, len );\n\n        while( buff_len >= 2 )\n        {\n            WebSocketFrame frame;\n\n            uint8* buff = pBufSock->getBuffer();\n            parse_frame_header( buff, frame );\n\n            uint32 offset = 2;\n            if (frame.payload_len == 126)\n            {\n                frame.payload_len = ntohs(*(uint16*)(buff+offset));\n                offset = 4;\n            }\n            else if (frame.payload_len == 127)\n            {\n                frame.payload_len = myntohll(*(uint64*)(buff+offset));\n                offset = 10;\n            }\n            else if( frame.payload_len < 126 )\n            {\n                if( frame.fin == 1 && frame.opcode == WEBSOCK_FRAME_DIS_CONNECT )\n                {\n                    if( frame.mask == 1 )  {  offset += 4;  }\n\n                    //0x8 denotes a connection close\n                    buff_len = pBufSock->leftShiftBuffer( offset + frame.payload_len );\n\n                    LNETL1_DEBUG(\"WebSocket Connection Close 0x8.\");\n                    continue;\n                }\n                else if( frame.fin == 1 && frame.opcode == WEBSOCK_FRAME_PING )\n                {\n                    //0x9 denotes a ping\n                    if( frame.mask == 1 )  {  offset += 4;  }\n                    buff_len = pBufSock->leftShiftBuffer( offset + frame.payload_len );\n                    continue;\n                }\n                else if( frame.opcode == WEBSOCK_FRAME_HAVE_NEXT )\n                {\n                    LNETL1_DEBUG(\"frame.opcode == 0x0\");\n                    if( frame.mask == 1 )  {  offset += 4;  }\n                    buff_len = pBufSock->leftShiftBuffer( offset + frame.payload_len );\n                }\n                else if( frame.opcode == WEBSOCK_FRAME_TEXT || frame.opcode == WEBSOCK_FRAME_BIN )\n                {\n                    \n                }\n                else\n                {\n                    LNETL1_DEBUG( \"frame.opcode = %d\", frame.opcode );\n                    if( frame.mask == 1 )  {  offset += 4;  }\n                    buff_len = pBufSock->leftShiftBuffer( offset + frame.payload_len );\n                    continue;\n                }\n            }\n\n            uint32 data_len = frame.payload_len + offset + 4;\n\n            if( buff_len >= data_len )\n            {\n                ///  ѾչһϢ\n\n                if( frame.mask == 1 )\n                {\n                    // load mask\n                    memcpy( frame.masking_key, buff+offset, 4 );\n                    offset += 4;\n\n                    // unmask\n                    unmask_payload_data( frame, buff+offset );\n                }\n\n                if( frame.fin==0 || frame.fin==1 || frame.fin==2 )\n                {\n                    CSString msg_buff;\n                    msg_buff.assign( buff+offset, buff+offset+frame.payload_len );\n\n\n                    if( msg_buff.size() >= 4 )\n                    {\n                        uint32 msg_type_len = ntohl(*(uint32*)msg_buff.data());\n\n                        if( msg_type_len>9 && msg_type_len<65535 )\n                        {\n                            NLMISC::CMemStream& msg = pBufSock->CompleteMsg;\n\n                            if (msg.isReading())\n                            {\n                                msg.invert();\n                            }\n\n                            msg.fill( (const uint8*)msg_buff.data()+sizeof(uint32), msg_type_len );\n\n                            uint8 event_type    = CBufNetBase::User;\n                            uint64 sockid       = (uint64)pBufSock;\n                            msg.serial( sockid );\n                            msg.serial( event_type );\n                            msg.invert();\n\n                            pBufSock->m_BufNetHandle->pushMessageIntoReceiveQueue(msg.buffer(), msg.size() );\n                        }\n                    }\n                }\n\n                buff_len = pBufSock->leftShiftBuffer(data_len);\n            }\n            else\n            {\n                break;\n            }\n        }\n    }\n}  \n\nvoid NLNET::ws_socket_event_cb( bufferevent *bev, short events, void *args )\n{\n    if (events & BEV_EVENT_CONNECTED)  \n    {\n        return;\n    }\n\n    if (events & BEV_EVENT_EOF)  \n        LNETL1_DEBUG(\"connection closed\\n\");  \n    else if (events & BEV_EVENT_ERROR)  \n        LNETL1_DEBUG(\"some other error\\n\");\n\n    LNETL1_DEBUG( \"socket_event_cb:%d\", events );\n\n    CServerBufSock* pBufSock = (CServerBufSock*)args;\n    pBufSock->advertiseDisconnection( pBufSock->m_BufNetHandle, pBufSock );\n}\n\nvoid NLNET::ws_listener_cb( evconnlistener *listener, evutil_socket_t fd, struct sockaddr *sock, int socklen, void *args )\n{  \n    WSListenArgs*   pListenArgs = (WSListenArgs*)args;\n    NLNET::SOCKET   newSock = (NLNET::SOCKET)fd;\n\n    if ( newSock == INVALID_SOCKET )\n    {\n        throw ESocket( \"Accept returned an invalid socket\");\n    }\n\n    // Construct and save a CTcpSock object\n    CInetAddress addr;\n    addr.setSockAddr( (struct sockaddr_in*)sock );\n    //LNETL0_DEBUG( \"LNETL0: Socket %d accepted an incoming connection from %s, opening socket %d\", _Sock, addr.asString().c_str(), newsock );\n    CTcpSock *pTcpSock = new CTcpSock( newSock, addr );\n    CServerBufSock *pBufSock = new CServerBufSock( pTcpSock );\n    LNETL1_DEBUG( \"LNETL1: New connection : %s\", pBufSock->asString().c_str() );\n\n    // Notify the new connection\n    pBufSock->advertiseConnection( pListenArgs->pServer );\n\n    //Ϊͻ˷һbufferevent  \n    bufferevent *bev =  NULL;\n    \n    if ( pListenArgs->pSslCtx!=NULL )\n    {\n        SSL* pSsl   = SSL_new((SSL_CTX *)pListenArgs->pSslCtx);\n        bev         = bufferevent_openssl_socket_new(pListenArgs->pEventBase, fd, pSsl, BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE|BEV_OPT_DEFER_CALLBACKS);\n        pBufSock->m_Ssl = pSsl;\n    }\n    else\n    {\n        bev = bufferevent_socket_new(pListenArgs->pEventBase, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS);\n    }\n\n    pBufSock->m_BufNetHandle    = pListenArgs->pServer;\n    pBufSock->m_BEVHandle       = bev;\n\n    bufferevent_setcb(bev, ws_socket_read_cb , NULL, ws_socket_event_cb, (void*)pBufSock);\n    bufferevent_enable(bev, EV_READ | EV_PERSIST); \n}  \n\nvoid NLNET::fill_frame_buffer( const uint8* payload_data, uint32 payload_len, NLMISC::CObjectVector<uint8>& out_frame, uint8 opcode, uint8 fin/* =1 */ )\n{\n    out_frame.clear();\n\n    if (fin > 1 || opcode > 0xf) {\n        nlwarning(\"fill_frame_buffer  fin>1  opcode>0xf\");\n        return;\n    }\n\n    uint32  buff_len = payload_len + 4;\n    uint8   mask = 0;               //  must not mask at server endpoint\n    uint8   masking_key[4] = {0};   //  no need at server endpoint\n    uint8   c1 = 0x00;\n    uint8   c2 = 0x00;\n\n    c1 = c1 | (fin << 7);           //  set fin\n    c1 = c1 | opcode;               //  set opcode\n    c2 = c2 | (mask << 7);          //  set mask\n\n    if ( buff_len == 0 )\n    {\n        if (mask == 0)\n        {\n            out_frame.resize(2);\n            out_frame[0] = c1;\n            out_frame[1] = c2;\n        }\n        else\n        {\n            out_frame.resize(2+4);\n            out_frame[0] = c1;\n            out_frame[1] = c2;\n\n            memcpy( &out_frame[2], masking_key, sizeof(masking_key) );\n        }\n    }\n    else if ( buff_len <= 125 )\n    {\n        if (mask == 0)\n        {\n            out_frame.resize(2+buff_len);\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + buff_len;\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[2])=netlen;\n\n            memcpy( out_frame.getPtr()+2+sizeof(uint32), payload_data, payload_len );\n        }\n        else\n        {\n            out_frame.resize(2+4+buff_len);      // frame len + mask len + payload len + data\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + buff_len;\n\n            memcpy( out_frame.getPtr()+2, masking_key, sizeof(masking_key) );\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[6])=netlen;\n\n            memcpy( out_frame.getPtr()+10, payload_data, payload_len );\n        }\n    }\n    else if ( buff_len >= 126 && buff_len <= 65535 )\n    {\n        if (mask == 0)\n        {\n            out_frame.resize(4+buff_len);      //  frame len + payload len + data\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + 126;\n\n            uint16 tmplen = myhtons((uint16)buff_len);\n            memcpy( out_frame.getPtr()+2, &tmplen, 2 );\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[4])=netlen;\n\n            memcpy( out_frame.getPtr()+8, payload_data, payload_len );\n        }\n        else\n        {\n            out_frame.resize(4+4+buff_len);\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + 126;\n\n            uint16 tmplen = myhtons((uint16)buff_len);\n            memcpy( out_frame.getPtr()+2, &tmplen, 2 );\n            memcpy( out_frame.getPtr()+4, masking_key, sizeof(masking_key) );\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[8])=netlen;\n\n            memcpy( out_frame.getPtr()+12, payload_data, payload_len );\n        }\n    }\n    else if ( buff_len >= 65536 )\n    {\n        if (mask == 0)\n        {\n            out_frame.resize(2+8+buff_len);\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + 127;\n\n            uint64 tmplen = myhtonll(buff_len);\n            memcpy( out_frame.getPtr()+2, &tmplen, 8 );\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[10])=netlen;\n\n            memcpy( out_frame.getPtr()+14, payload_data, payload_len );\n        }\n        else\n        {\n            out_frame.resize(2+8+4+buff_len);\n\n            out_frame[0] = c1;\n            out_frame[1] = c2 + 127;\n\n            uint64 tmplen = myhtonll(buff_len);\n            memcpy( out_frame.getPtr()+2, &tmplen, 8 );\n            memcpy( out_frame.getPtr()+10, masking_key, sizeof(masking_key) );\n\n            uint32 netlen = myhtonl( (uint32)payload_len );\n            *(uint32*)&(out_frame[14])=netlen;\n\n            memcpy( out_frame.getPtr()+18, payload_data, payload_len );\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "code/nel/src/net/buf_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/net/buf_sock.h\"\n#include \"nel/net/buf_server.h\"\n#include \"nel/net/net_log.h\"\n#include \"nel/net/buf_server_websocket_func.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#elif defined NL_OS_UNIX\n#\tinclude <netinet/in.h>\n#endif\n\nusing namespace NLMISC;\nusing namespace std;\n\nNLMISC::CVariable<uint32> MaxTCPPacketSize(\"nel\", \"MaxTCPPacketSize\", \"Maximum size of TCP packets created by cumulating small packets\", 10240, 0, true);\n\n\nnamespace NLNET {\n\n\nNLMISC::CMutex nettrace_mutex(\"nettrace_mutex\");\n\n\n/*\n * Constructor\n */\nCBufSock::CBufSock( CTcpSock *sock ) :\n\tSock( sock ),\n\t_KnowConnected( false ),\n\t_LastFlushTime( 0 ),\n\t_TriggerTime( 20 ),\n\t_TriggerSize( -1 ),\n\t_RTSBIndex( 0 ),\n\t_AppId( 0 ),\n\t_ConnectedState( false ),\n    m_BEVHandle(NULL),\n    m_BufNetHandle(NULL),\n    m_Ssl(NULL),\n    m_Handshake(false)\n{\n\tnlnettrace( \"CBufSock::CBufSock\" ); // don't define a global object\n\n\tif ( Sock == NULL )\n\t  {\n\t\tSock = new CTcpSock();\n\t  }\n\n#ifdef NL_DEBUG\n\t_FlushTrigger = FTManual;\n#endif\n\t_LastFlushTime = CTime::getLocalTime();\n}\n\n\n/*\n * Destructor\n */\nCBufSock::~CBufSock()\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\n\tnlnettrace( \"CBufSock::~CBufSock\" );\n\n\tdelete Sock; // the socket disconnects automatically if needed\n\n\t// destroy the structur to be sure that other people will not access to this anymore\n\tAuthorizedCallback = \"\";\n\tSock = NULL;\n\t_KnowConnected = false;\n\t_LastFlushTime = 0;\n\t_TriggerTime = 0;\n\t_TriggerSize = 0;\n\t_ReadyToSendBuffer.clear ();\n\t_RTSBIndex = 0;\n\t_AppId = 0;\n\t_ConnectedState = false;\n}\n\n\n/*\n * Returns a readable string from a vector of bytes, beginning from pos, limited to 'len' characters. '\\0' are replaced by ' '\n */\nstring stringFromVectorPart( const vector<uint8>& v, uint32 pos, uint32 len )\n{\n\tnlassertex( pos+len <= v.size(), (\"pos=%u len=%u size=%u\", pos, len, v.size()) );\n\n\tstring s;\n\tif ( (! v.empty()) && (len!=0) )\n\t{\n\t\t// Copy contents\n\t\ts.resize( len );\n\t\tmemcpy( &*s.begin(), &*v.begin()+pos, len );\n\n\t\t// Replace '\\0' characters\n\t\tstring::iterator is;\n\t\tfor ( is=s.begin(); is!=s.end(); ++is )\n\t\t{\n\t\t\tif ( ! isprint((uint8)(*is)) || (*is) == '%' )\n\t\t\t{\n\t\t\t\t(*is) = '?';\n\t\t\t}\n\t\t}\n\t}\n\n\treturn s;\n}\n\n\n/*\n * Force to send data pending in the send queue now. In the case of a non-blocking socket\n * (see CNonBlockingBufSock), if all the data could not be sent immediately,\n * the returned nbBytesRemaining value is non-zero.\n * \\param nbBytesRemaining If the pointer is not NULL, the method sets the number of bytes still pending after the flush attempt.\n * \\returns False if an error has occured (e.g. the remote host is disconnected).\n * To retrieve the reason of the error, call CSock::getLastError() and/or CSock::errorString()\n *\n * Note: this method works with both blocking and non-blocking sockets\n * Precond: the send queue should not contain an empty block\n */\nbool CBufSock::flush( uint *nbBytesRemaining )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\t//nlnettrace( \"CBufSock::flush\" );\n\n\t// Copy data from the send queue to _ReadyToSendBuffer\n\tTBlockSize netlen;\n//\tvector<uint8> tmpbuffer;\n\n\tdo\n\t{\n\t\t// Process each element in the send queue\n\t\tuint8 *tmpbuffer = NULL;\n\t\tuint32 size = 0;\n\t\tif (! SendFifo.empty())\n\t\t{\n\t\t\tSendFifo.front( tmpbuffer, size );\n\t\t}\n\t\twhile ( ! SendFifo.empty() && ( (_ReadyToSendBuffer.size()==0) || (_ReadyToSendBuffer.size() +size < MaxTCPPacketSize) ) )\n\t\t{\n\t\t\t// Compute the size and add it into the beginning of the buffer\n\t\t\tnetlen = htonl( (TBlockSize)size );\n\t\t\tuint32 oldBufferSize = _ReadyToSendBuffer.size();\n\t\t\t_ReadyToSendBuffer.resize (oldBufferSize+sizeof(TBlockSize)+size);\n\t\t\t*(TBlockSize*)&(_ReadyToSendBuffer[oldBufferSize])=netlen;\n\t\t\t//nldebug( \"O-%u %u+L%u (0x%x)\", Sock->descriptor(), oldBufferSize, size, size );\n\n\n\t\t\t// Append the temporary buffer to the global buffer\n\t\t\tCFastMem::memcpy (&_ReadyToSendBuffer[oldBufferSize+sizeof(TBlockSize)], tmpbuffer, size);\n\t\t\tSendFifo.pop();\n\t\t\tif (! SendFifo.empty())\n\t\t\t{\n\t\t\t\tSendFifo.front( tmpbuffer, size );\n\t\t\t}\n\t\t}\n\n\t\t// Actual sending of _ReadyToSendBuffer\n\t\t//if ( ! _ReadyToSendBuffer.empty() )\n\t\tif ( _ReadyToSendBuffer.size() != 0 )\n\t\t{\n\t\t\t// Send\n\t\t\tCSock::TSockResult res;\n\t\t\tTBlockSize len = _ReadyToSendBuffer.size() - _RTSBIndex;\n\n\t\t\tres = Sock->send( _ReadyToSendBuffer.getPtr()+_RTSBIndex, len, false );\n\n\t\t\tif ( res == CSock::Ok )\n\t\t\t{\n/*\t\t\t\t// Debug display\n\t\t\t\tswitch ( _FlushTrigger )\n\t\t\t\t{\n\t\t\t\tcase FTTime : LNETL1_DEBUG( \"LNETL1: Time triggered flush for %s:\", asString().c_str() ); break;\n\t\t\t\tcase FTSize : LNETL1_DEBUG( \"LNETL1: Size triggered flush for %s:\", asString().c_str() ); break;\n\t\t\t\tdefault:\t  LNETL1_DEBUG( \"LNETL1: Manual flush for %s:\", asString().c_str() );\n\t\t\t\t}\n\t\t\t\t_FlushTrigger = FTManual;\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: %s sent effectively a buffer (%d on %d B)\", asString().c_str(), len, _ReadyToSendBuffer.size() );\n*/\n\n\t\t\t\t// TODO OPTIM remove the nldebug for speed\n\t\t\t\t//commented for optimisation LNETL1_DEBUG( \"LNETL1: %s sent effectively %u/%u bytes (pos %u wantedsend %u)\", asString().c_str(), len, _ReadyToSendBuffer.size(), _RTSBIndex, realLen/*, stringFromVectorPart(_ReadyToSendBuffer,_RTSBIndex,len).c_str()*/ );\n\n\t\t\t\tif ( _RTSBIndex+len == _ReadyToSendBuffer.size() ) // for non-blocking mode\n\t\t\t\t{\n\t\t\t\t\t// If sending is ok, clear the global buffer\n\t\t\t\t\t//nldebug( \"O-%u all %u bytes (%u to %u) sent\", Sock->descriptor(), len, _RTSBIndex, _ReadyToSendBuffer.size() );\n\t\t\t\t\t_ReadyToSendBuffer.clear();\n\t\t\t\t\t_RTSBIndex = 0;\n\t\t\t\t\tif ( nbBytesRemaining )\n\t\t\t\t\t\t*nbBytesRemaining = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Or clear only the data that was actually sent\n\t\t\t\t\tnlassertex( _RTSBIndex+len < _ReadyToSendBuffer.size(), (\"index=%u len=%u size=%u\", _RTSBIndex, len, _ReadyToSendBuffer.size()) );\n\t\t\t\t\t//nldebug( \"O-%u only %u B on %u (%u to %u) sent\", Sock->descriptor(), len, _ReadyToSendBuffer.size()-_RTSBIndex, _RTSBIndex, _ReadyToSendBuffer.size() );\n\t\t\t\t\t_RTSBIndex += len;\n\t\t\t\t\tif ( nbBytesRemaining )\n\t\t\t\t\t\t*nbBytesRemaining = _ReadyToSendBuffer.size() - _RTSBIndex;\n\t\t\t\t\tif ( _ReadyToSendBuffer.size() > 20480 ) // if big, clear data already sent\n\t\t\t\t\t{\n\t\t\t\t\t\tuint nbcpy = _ReadyToSendBuffer.size() - _RTSBIndex;\n\t\t\t\t\t\tfor (uint i = 0; i < nbcpy; i++)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_ReadyToSendBuffer[i] = _ReadyToSendBuffer[i+_RTSBIndex];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t_ReadyToSendBuffer.resize(nbcpy);\n\t\t\t\t\t\t//_ReadyToSendBuffer.erase( _ReadyToSendBuffer.begin(), _ReadyToSendBuffer.begin()+_RTSBIndex );\n\t\t\t\t\t\t_RTSBIndex = 0;\n\t\t\t\t\t\t//nldebug( \"O-%u Cleared data already sent, %u B remain\", Sock->descriptor(), nbcpy );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n#ifdef NL_DEBUG\n\t\t\t\t// Can happen in a normal behavior if, for example, the other side is not connected anymore\n\t\t\t\tLNETL1_DEBUG( \"LNETL1: %s failed to send effectively a buffer of %d bytes\", asString().c_str(), _ReadyToSendBuffer.size() );\n#endif\n\t\t\t\t// NEW: Clearing (loosing) the buffer if the sending can't be performed at all\n\t\t\t\t_ReadyToSendBuffer.clear();\n\t\t\t\t_RTSBIndex = 0;\n\t\t\t\tif ( nbBytesRemaining )\n\t\t\t\t\t*nbBytesRemaining = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ( nbBytesRemaining )\n\t\t\t\t*nbBytesRemaining = 0;\n\t\t}\n\n\t}\n\twhile ( !SendFifo.empty() && _ReadyToSendBuffer.size()==0 );\n\n\treturn true;\n}\n\n\n/* Sets the time flush trigger (in millisecond). When this time is elapsed,\n * all data in the send queue is automatically sent (-1 to disable this trigger)\n */\nvoid CBufSock::setTimeFlushTrigger( sint32 ms )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\t_TriggerTime = ms;\n\t_LastFlushTime = CTime::getLocalTime();\n}\n\n\n/*\n * Update the network sending (call this method evenly). Returns false if an error occured.\n */\nbool CBufSock::update()\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n//\tnlnettrace( \"CBufSock::update-BEGIN\" );\n\t// Time trigger\n\n\tif ( _TriggerTime != -1 )\n\t{\n\t\tTTime now = CTime::getLocalTime();\n\t\tif ( (sint32)(now-_LastFlushTime) >= _TriggerTime )\n\t\t{\n#ifdef NL_DEBUG\n\t\t\t_FlushTrigger = FTTime;\n#endif\n\t\t\tif ( flush() )\n\t\t\t{\n\t\t\t\t_LastFlushTime = now;\n//\t\t\t\tnlnettrace ( \"CBufSock::update-END time 1\" );\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n//\t\t\t\tnlnettrace ( \"CBufSock::update-END time 0\" );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\t// Size trigger\n\tif ( _TriggerSize != -1 )\n\t{\n\t\tif ( (sint32)SendFifo.size() > _TriggerSize )\n\t\t{\n#ifdef NL_DEBUG\n\t\t\t_FlushTrigger = FTSize;\n#endif\n//\t\t\tnlnettrace( \"CBufSock::update-END size\" );\n\t\t\treturn flush();\n\t\t}\n\t}\n//\tnlnettrace( \"CBufSock::update-END nosend\" );\n\treturn true;\n}\n\n\n/*\n * Connects to the specified addr; set connectedstate to true if no connection advertising is needed\n * Precond: not connected\n */\nvoid CBufSock::connect( const CInetAddress& addr, bool nodelay, bool connectedstate )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\tnlassert( ! Sock->connected() );\n\n\tSock->connect( addr );\n\t_ConnectedState = connectedstate;\n\t_KnowConnected = connectedstate;\n\tif ( nodelay )\n\t{\n\t\tSock->setNoDelay( true );\n\t}\n\t_ReadyToSendBuffer.clear();\n\t_RTSBIndex = 0;\n}\n\n\n/*\n * Disconnects; set connectedstate to false if no disconnection advertising is needed\n */\nvoid CBufSock::disconnect( bool connectedstate )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\tSock->disconnect();\n\t_ConnectedState = connectedstate;\n\t_KnowConnected = connectedstate;\n}\n\n\n/*\n * Returns a string with the characteristics of the object\n */\nstring CBufSock::asString() const\n{\n//\tstringstream ss;\n\tstring str;\n\tif (this == InvalidSockId) // tricky\n\t\tstr = \"<null>\";\n\telse\n\t{\n\t\t// if it crashs here, it means that the CBufSock was deleted and you try to access to the virtual table that is empty\n\t\t// because the object is destroyed.\n\t\tstr += typeStr();\n\t\tstr += NLMISC::toStringPtr(this) + \" (socket \";\n\n\t\tif (Sock == NULL)\n\t\t\tstr += \"<null>\";\n\t\telse\n\t\t\tstr += NLMISC::toString(Sock->descriptor());\n\n\t\tstr += \")\";\n\t}\n\treturn str;\n}\n\nbool CBufSock::SendToLibEvent( const CMemStream& buffer, bool add_ws_head/*=false*/ )\n{\n    nlassert (this != InvalidSockId);\t// invalid bufsock\n\n    if( connectedState() )\n    {\n        LNETL1_DEBUG( \"LNETL1: Pushing buffer to %s\", asString().c_str() );\n\n        if ( add_ws_head )\n        {\n            fill_frame_buffer( buffer.buffer(), buffer.length(), _ReadyToSendBuffer, WEBSOCK_FRAME_BIN );\n        }\n        else\n        {\n            uint32 netlen = htonl( (TBlockSize)buffer.length() );\n            _ReadyToSendBuffer.clear();\n            _ReadyToSendBuffer.resize (buffer.length()+sizeof(TBlockSize));\n            *(TBlockSize*)&(_ReadyToSendBuffer[0])=netlen;\n            CFastMem::memcpy (&_ReadyToSendBuffer[sizeof(TBlockSize)], buffer.buffer(), buffer.length());\n        }\n\n        bufferevent_write( m_BEVHandle, _ReadyToSendBuffer.getPtr(), _ReadyToSendBuffer.size() );\n        return true;\n    }\n\n    return false;\n}\n\n\n\n/*\n * Constructor\n */\nCNonBlockingBufSock::CNonBlockingBufSock( CTcpSock *sock, uint32 maxExpectedBlockSize ) :\n\tCBufSock( sock ),\n\t_MaxExpectedBlockSize( maxExpectedBlockSize ),\n\t_NowReadingBuffer( false ),\n\t_BytesRead( 0 ),\n\t_Length( 0 )\n{\n\tnlnettrace( \"CNonBlockingBufSock::CNonBlockingBufSock\" );\n}\n\n\n/*\n * Constructor with an existing socket (created by an accept())\n */\nCServerBufSock::CServerBufSock( CTcpSock *sock ) :\n\tCNonBlockingBufSock( sock ),\n\t_Advertised( false ),\n\t_OwnerTask( NULL )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\tnlnettrace( \"CServerBufSock::CServerBufSock\" );\n}\n\n\n// In Receive Threads:\n\n\n/*\n * Receives a part of a message (nonblocking socket only)\n */\nbool CNonBlockingBufSock::receivePart( uint32 nbExtraBytes )\n{\n\tnlassert (this != InvalidSockId);\t// invalid bufsock\n\tnlnettrace( \"CNonBlockingBufSock::receivePart\" );\n\n\tTBlockSize actuallen;\n\tif ( ! _NowReadingBuffer )\n\t{\n\t\t// Receiving length prefix\n\t\tactuallen = sizeof(_Length)-_BytesRead;\n\t\tCSock :: TSockResult ret = Sock->receive( (uint8*)(&_Length)+_BytesRead, actuallen, false );\n\t\tif (ret == CSock::ConnectionClosed)\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Connection %s closed\", asString().c_str() );\n\t\t\treturn false;\n\t\t}\n\t\telse if (ret == CSock::Error)\n\t\t{\n\t\t\tLNETL1_DEBUG( \"LNETL1: Socket error for %s\", asString().c_str() );\n\t\t\tSock->disconnect();\n\t\t\treturn false;\n\t\t}\n\n\t\t_BytesRead += actuallen;\n\t\tif ( _BytesRead == sizeof(_Length ) )\n\t\t{\n\t\t\tif ( _Length != 0 )\n\t\t\t{\n\t\t\t\t_Length = ntohl( _Length );\n\t\t\t\t//nldebug( \"I-%u L%u (0x%x) a%u\", Sock->descriptor(), _Length, _Length, actuallen );\n\n\t\t\t\t// Test size limit\n\t\t\t\tif ( _Length > _MaxExpectedBlockSize )\n\t\t\t\t{\n\t\t\t\t\tnlwarning( \"LNETL1: Socket %s received header length %u exceeding max expected %u... Disconnecting\", asString().c_str(), _Length, _MaxExpectedBlockSize );\n\t\t\t\t\tthrow ESocket( toString( \"Received length %u exceeding max expected %u from %s\", _Length, _MaxExpectedBlockSize, Sock->remoteAddr().asString().c_str() ).c_str(), false );\n\t\t\t\t}\n\n\t\t\t\t_NowReadingBuffer = true;\n\t\t\t\t_ReceiveBuffer.resize( _Length + nbExtraBytes );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlwarning( \"LNETL1: Socket %s received null length in block header\", asString().c_str() );\n\t\t\t}\n\t\t\t_BytesRead = 0;\n\t\t}\n\t}\n\n\tif ( _NowReadingBuffer )\n\t{\n\t\t// Receiving payload buffer\n\t\tactuallen = _Length-_BytesRead;\n\t\tSock->receive( &*_ReceiveBuffer.begin()+_BytesRead, actuallen );\n\t\t_BytesRead += actuallen;\n\n\t\tif ( _BytesRead == _Length )\n\t\t{\n#ifdef NL_DEBUG\n\t\t\tLNETL1_DEBUG( \"LNETL1: %s received buffer (%u bytes): [%s]\", asString().c_str(), _ReceiveBuffer.size(), stringFromVector(_ReceiveBuffer).c_str() );\n#endif\n\t\t\t_NowReadingBuffer = false;\n\t\t\t//nldebug( \"I-%u all %u B on %u\", Sock->descriptor(), actuallen );\n\t\t\t_BytesRead = 0;\n\t\t\treturn true;\n\t\t}\n\t\t//else\n\t\t//{\n\t\t//\tnldebug( \"I-%u only %u B on %u\", actuallen, Sock->descriptor(), _Length-(_BytesRead-actuallen) );\n\t\t//}\n\t}\n\n\treturn false;\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/callback_client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/net/callback_net_base.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/net_log.h\"\n\n\n#ifdef USE_MESSAGE_RECORDER\n#include \"nel/net/message_recorder.h\"\n#endif\n\n\nnamespace NLNET {\n\n\n/*\n * Constructor\n */\nCCallbackClient::CCallbackClient( TRecordingState rec, const std::string& recfilename, bool recordall, bool initPipeForDataAvailable ) :\n\tCCallbackNetBase( rec, recfilename, recordall ), CBufClient( true, rec==Replay, initPipeForDataAvailable )\n{\n\tLockDeletion = false;\n\tCBufClient::setDisconnectionCallback (_NewDisconnectionCallback, this);\n\n\t_IsAServer = false;\n\t_DefaultCallback = NULL;\n}\n\nCCallbackClient::~CCallbackClient()\n{\n\tnlassert(!LockDeletion);\n}\n\n/*\n * Send a message to the remote host (pushing to its send queue)\n * Recorded : YES\n * Replayed : MAYBE\n */\nvoid CCallbackClient::send (const CMessage &buffer, TSockId hostid, bool /* log */)\n{\n\tnlassert (hostid == InvalidSockId);\t// should always be InvalidSockId on client\n\tnlassert (connected ());\n\tnlassert (buffer.length() != 0);\n\tnlassert (buffer.typeIsSet());\n\n\t_BytesSent += buffer.length ();\n\n//\tif (log)\n\t{\n//\t\tnldebug (\"LNETL3C: Client: send(%s)\", buffer.toString().c_str());\n//\t\tnldebug (\"send message number %u\", SendNextValue);\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Send\n\t\tCBufClient::send (buffer);\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record sent message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n#endif\n}\n\n/*\n * Force to send all data pending in the send queue.\n * Recorded : NO\n * Replayed : NO\n */\nbool CCallbackClient::flush (TSockId hostid, uint *nbBytesRemaining)\n{\n\tnlassert (hostid == InvalidSockId);\t// should always be InvalidSockId on client\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Flush sending (nothing to do in replay mode)\n\t\treturn CBufClient::flush( nbBytesRemaining );\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\telse\n\t{\n\t\treturn true;\n\t}\n#endif\n}\n\n\n/*\n * Updates the network (call this method evenly)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackClient::update2 ( sint32 timeout, sint32 mintime )\n{\n\tLockDeletion = true;\n//\tnldebug (\"L3: Client: update()\");\n\n\tH_AUTO(L3UpdateClient2);\n\n\tbaseUpdate2 (timeout, mintime); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufClient::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n\n\tLockDeletion = false;\n}\n\n\n/*\n * Updates the network (call this method evenly) (legacy)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackClient::update ( sint32 timeout )\n{\n\tLockDeletion = true;\n//\tnldebug (\"L3: Client: update()\");\n\n\tH_AUTO(L3UpdateClient);\n\n\tbaseUpdate (timeout); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufClient::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n\n\tLockDeletion = false;\n}\n\n\n/*\n * Returns true if there are messages to read\n * Recorded : NO\n * Replayed : YES\n */\nbool CCallbackClient::dataAvailable ()\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Real dataAvailable()\n\t\treturn CBufClient::dataAvailable ();\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\telse\n\t{\n\t\t// Simulated dataAvailable()\n\t\treturn CCallbackNetBase::replayDataAvailable();\n\t}\n#endif\n}\n\n\n/*\n * Read the next message in the receive queue\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackClient::receive (CMessage &buffer, TSockId *hostid)\n{\n//\tnlassert (connected ());\n\t*hostid = InvalidSockId;\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Receive\n\t\tCBufClient::receive (buffer);\n\n\t\t// debug features, we number all packet to be sure that they are all sent and received\n\t\t// \\todo remove this debug feature when ok\n#ifdef NL_BIG_ENDIAN\n\t\tuint32 val = NLMISC_BSWAP32(*(uint32*)buffer.buffer ());\n#else\n\t\tuint32 val = *(uint32*)buffer.buffer ();\n#endif\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record received message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Receiving, *hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Retrieve received message loaded by dataAvailable()\n\t\tbuffer = _MR_Recorder.ReceivedMessages.front().Message;\n\t\t_MR_Recorder.ReceivedMessages.pop();\n\t}\n#endif\n\n\tbuffer.readType ();\n}\n\n/*\n *\n */\nTSockId\tCCallbackClient::getSockId (TSockId hostid)\n{\n\tnlassert (hostid == InvalidSockId);\n\n\treturn id ();\n}\n\n\n/*\n * Connect to the specified host\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackClient::connect( const CInetAddress& addr )\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n\t\ttry\n\t\t{\n#endif\n\n\t\t\t// Connect\n\t\t\tCBufClient::connect( addr );\n\n#ifdef USE_MESSAGE_RECORDER\n\t\t\tif ( _MR_RecordingState == Record )\n\t\t\t{\n\t\t\t\t// Record connection\n\t\t\t\tCMessage addrmsg;\n\t\t\t\taddrmsg.serial( const_cast<CInetAddress&>(addr) );\n\t\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Connecting, _BufSock, addrmsg );\n\t\t\t}\n\t\t}\n\t\tcatch (const ESocketConnectionFailed&)\n\t\t{\n\t\t\tif ( _MR_RecordingState == Record )\n\t\t\t{\n\t\t\t\t// Record connection\n\t\t\t\tCMessage addrmsg;\n\t\t\t\taddrmsg.serial( const_cast<CInetAddress&>(addr) );\n\t\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, ConnFailing, _BufSock, addrmsg );\n\t\t\t}\n\t\t\tthrow;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Check the connection : failure or not\n\t\tTNetworkEvent event = _MR_Recorder.replayConnectionAttempt( addr );\n\t\tswitch ( event )\n\t\t{\n\t\tcase Connecting :\n\t\t\t// Set the remote address\n\t\t\tnlassert( ! _BufSock->Sock->connected() );\n\t\t\t_BufSock->connect( addr, _NoDelay, true );\n\t\t\t_PrevBytesDownloaded = 0;\n\t\t\t_PrevBytesUploaded = 0;\n\t\t\t/*_PrevBytesReceived = 0;\n\t\t\t_PrevBytesSent = 0;*/\n\t\t\tbreak;\n\t\tcase ConnFailing :\n\t\t\tthrow ESocketConnectionFailed( addr );\n\t\t\t//break;\n\t\tdefault :\n\t\t\tnlwarning( \"LNETL3C: No connection event in replay data, at update #%\" NL_I64 \"u\", _MR_UpdateCounter );\n\t\t}\n\t}\n#endif\n}\n\n\n/*\n * Disconnect a connection\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackClient::disconnect( TSockId hostid )\n{\n\tnlassert (hostid == InvalidSockId);\t// should always be InvalidSockId on client\n\n\t// Disconnect only if connected (same as physically connected for the client)\n\tif ( _BufSock->connectedState() )\n\t{\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState != Replay )\n\t\t{\n#endif\n\n\t\t\t// Disconnect\n\t\t\tCBufClient::disconnect ();\n\n#ifdef USE_MESSAGE_RECORDER\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Read (skip) disconnection in the file\n\t\t\tif ( ! (_MR_Recorder.checkNextOne( _MR_UpdateCounter ) == Disconnecting) )\n\t\t\t{\n\t\t\t\tnlwarning( \"LNETL3C: No disconnection event in the replay data, at update #%\" NL_I64 \"u\", _MR_UpdateCounter );\n\t\t\t}\n\t\t}\n\t\t// Record or replay disconnection (because disconnect() in the client does not push a disc. event)\n\t\tnoticeDisconnection( _BufSock );\n#endif\n\t}\n}\n\n\n#ifdef USE_MESSAGE_RECORDER\n\n\n/*\n * replay connection and disconnection callbacks, client version\n */\nbool CCallbackClient::replaySystemCallbacks()\n{\n\tdo\n\t{\n\t\tif ( _MR_Recorder.ReceivedMessages.empty() )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tswitch( _MR_Recorder.ReceivedMessages.front().Event )\n\t\t\t{\n\t\t\tcase Receiving:\n\t\t\t\treturn true;\n\n\t\t\tcase Disconnecting:\n\t\t\t\tLNETL3_DEBUG( \"LNETL3C: Disconnection event\" );\n\t\t\t\t_BufSock->setConnectedState( false );\n\n\t\t\t\t// Call callback if needed\n\t\t\t\tif ( disconnectionCallback() != NULL )\n\t\t\t\t{\n\t\t\t\t\tdisconnectionCallback()( id(), argOfDisconnectionCallback() );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tnlerror( \"LNETL3C: Invalid system event type in client receive queue\" );\n\t\t\t}\n\t\t\t// Extract system event\n\t\t\t_MR_Recorder.ReceivedMessages.pop();\n\t\t}\n\t}\n\twhile ( true );\n}\n\n\n#endif // USE_MESSAGE_RECORDER\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/callback_net_base.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/hierarchical_timer.h\"\n\n#include \"nel/net/buf_sock.h\"\n#include \"nel/net/callback_net_base.h\"\n#include \"nel/net/net_log.h\"\n\n\n\n#ifdef USE_MESSAGE_RECORDER\n#ifdef NL_OS_WINDOWS\n#pragma message ( \"NeL Net layer 3: message recorder enabled\" )\n#endif // NL_OS_WINDOWS\n#include \"nel/net/message_recorder.h\"\n#else\n#ifdef NL_OS_WINDOWS\n#pragma message ( \"NeL Net layer 3: message recorder disabled\" )\n#endif // NL_OS_WINDOWS\n#endif\n\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Disconnection callback\n */\nvoid cbnbNewDisconnection (TSockId from, void *data)\n{\n\tnlassert (data != NULL);\n\tCCallbackNetBase *base = (CCallbackNetBase *)data;\n\n\tLNETL3_DEBUG(\"LNETL3NB: cbnbNewDisconnection()\");\n\n#ifdef USE_MESSAGE_RECORDER\n\t// Record or replay disconnection\n\tbase->noticeDisconnection( from );\n#endif\n\n\t// Call the client callback if necessary\n\tif (base->_DisconnectionCallback != NULL)\n\t\tbase->_DisconnectionCallback (from, base->_DisconnectionCbArg);\n}\n\n\n/*\n * Constructor\n */\nCCallbackNetBase::CCallbackNetBase(  TRecordingState /* rec */, const string& /* recfilename */, bool /* recordall */ )\n\t:\t_BytesSent(0),\n\t\t_BytesReceived(0),\n\t\t_NewDisconnectionCallback(cbnbNewDisconnection),\n\t\t_DefaultCallback(NULL),\n\t\t_PreDispatchCallback(NULL),\n\t\t_FirstUpdate (true),\n\t\t_UserData(NULL),\n\t\t_DisconnectionCallback(NULL),\n\t\t_DisconnectionCbArg(NULL)\n#ifdef USE_MESSAGE_RECORDER\n\t\t, _MR_RecordingState(rec), _MR_UpdateCounter(0)\n#endif\n{\n\tcreateDebug(); // for addNegativeFilter to work even in release and releasedebug modes\n\n#ifdef USE_MESSAGE_RECORDER\n\tswitch ( _MR_RecordingState )\n\t{\n\tcase Record :\n\t\t_MR_Recorder.startRecord( recfilename, recordall );\n\t\tbreak;\n\tcase Replay :\n\t\t_MR_Recorder.startReplay( recfilename );\n\t\tbreak;\n\tdefault:;\n\t\t// No recording\n\t}\n#endif\n}\n\n/** Set the user data */\nvoid CCallbackNetBase::setUserData(void *userData)\n{\n\t_UserData = userData;\n}\n\n/** Get the user data */\nvoid *CCallbackNetBase::getUserData()\n{\n\treturn _UserData;\n}\n\n/*\n *\tAppend callback array with the specified array\n */\nvoid CCallbackNetBase::addCallbackArray (const TCallbackItem *callbackarray, sint arraysize)\n{\n\tif (arraysize == 1 && callbackarray[0].Callback == NULL && string(\"\") == callbackarray[0].Key)\n\t{\n\t\t// it's an empty array, ignore it\n\t\treturn;\n\t}\n\n\t// resize the array\n\tsint oldsize = (sint)_CallbackArray.size();\n\n\t_CallbackArray.resize (oldsize + arraysize);\n\n//TOO MUCH MESSAGE\tnldebug (\"L3NB_CB: Adding %d callback to the array\", arraysize);\n\n\tfor (sint i = 0; i < arraysize; i++)\n\t{\n\t\tsint ni = oldsize + i;\n//TOO MUCH MESSAGE\t\tnldebug (\"L3NB_CB: Adding callback to message '%s', id '%d'\", callbackarray[i].Key, ni);\n\t\t// copy callback value\n\n\t\t_CallbackArray[ni] = callbackarray[i];\n\n\t}\n\n\n//\tLNETL3_DEBUG (\"LNETL3NB_CB: Added %d callback Now, there're %d callback associated with message type\", arraysize, _CallbackArray.size ());\n}\n\n\n/*\n * processOneMessage()\n */\nvoid CCallbackNetBase::processOneMessage ()\n{\n\t// slow down the layer H_AUTO (CCallbackNetBase_processOneMessage);\n\n\tCMessage msgin (\"\", true);\n\tTSockId tsid;\n\ttry\n\t{\n\t\treceive (msgin, &tsid);\n\t}\n\tcatch (const Exception &e)\n\t{\n\t\tnlwarning(e.what());\n\t\treturn;\n\t}\n\n\t_BytesReceived += msgin.length ();\n\n\t// now, we have to call the good callback\n\tsint pos = -1;\n\tstd::string name = msgin.getName ();\n\tsint i;\n\tfor (i = 0; i < (sint)_CallbackArray.size (); i++)\n\t{\n\t\tif (name == _CallbackArray[i].Key)\n\t\t{\n\t\t\tpos = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tTMsgCallback\tcb = NULL;\n\tif (pos < 0 || pos >= (sint16) _CallbackArray.size ())\n\t{\n\t\tif (_DefaultCallback == NULL)\n\t\t{\n\t\t\tnlwarning (\"LNETL3NB_CB: Callback %s not found in _CallbackArray\", msgin.toString().c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcb = _DefaultCallback;\n\t\t}\n\t}\n\telse\n\t{\n\t\tcb = _CallbackArray[pos].Callback;\n\t}\n\n\tTSockId realid = getSockId (tsid);\n\n\tif (!realid->AuthorizedCallback.empty() && msgin.getName() != realid->AuthorizedCallback)\n\t{\n\t\tnlwarning (\"LNETL3NB_CB: %s try to call the callback %s but only %s is authorized. Disconnect him!\", tsid->asString().c_str(), msgin.toString().c_str(), tsid->AuthorizedCallback.c_str());\n\t\tdisconnect (tsid);\n\t}\n\telse if (cb == NULL)\n\t{\n\t\tnlwarning (\"LNETL3NB_CB: Callback %s is NULL, can't call it\", msgin.toString().c_str());\n\t}\n\telse\n\t{\n\t\tLNETL3_DEBUG (\"LNETL3NB_CB: Calling callback (%s)%s\", msgin.getName().c_str(), (cb==_DefaultCallback)?\" DEFAULT_CB\":\"\");\n\n\t\tif (_PreDispatchCallback != NULL)\n\t\t{\n\t\t\t// call the pre dispatch callback\n\t\t\t_PreDispatchCallback(msgin, realid, *this);\n\t\t}\n\t\tcb(msgin, realid, *this);\n\t}\n\n/*\n\tif (pos < 0 || pos >= (sint16) _CallbackArray.size ())\n\t{\n\t\tif (_DefaultCallback == NULL)\n\t\t\tnlwarning (\"LNETL3NB_CB: Callback %s not found in _CallbackArray\", msgin.toString().c_str());\n\t\telse\n\t\t{\n\t\t\t// ...\n\t\t}\n\t}\n\telse\n\t{\n\t\tTSockId realid = getSockId (tsid);\n\n\t\tif (!realid->AuthorizedCallback.empty() && msgin.getName() != realid->AuthorizedCallback)\n\t\t{\n\t\t\tnlwarning (\"LNETL3NB_CB: %s try to call the callback %s but only %s is authorized. Disconnect him!\", tsid->asString().c_str(), msgin.toString().c_str(), tsid->AuthorizedCallback.c_str());\n\t\t\tdisconnect (tsid);\n\t\t}\n\t\telse if (_CallbackArray[pos].Callback == NULL)\n\t\t{\n\t\t\tnlwarning (\"LNETL3NB_CB: Callback %s is NULL, can't call it\", msgin.toString().c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLNETL3_DEBUG (\"LNETL3NB_CB: Calling callback (%s)\", _CallbackArray[pos].Key);\n\t\t\t_CallbackArray[pos].Callback (msgin, realid, *this);\n\t\t}\n\t}\n*/\n}\n\n\n/*\n * baseUpdate\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackNetBase::baseUpdate (sint32 timeout)\n{\n\tH_AUTO(L3UpdateCallbackNetBase);\n#ifdef NL_DEBUG\n\tnlassert( timeout >= -1 );\n#endif\n\n\tTTime t0 = CTime::getLocalTime();\n\n\t//\n\t// The first time, we init time counters\n\t//\n\tif (_FirstUpdate)\n\t{\n//\t\tLNETL3_DEBUG(\"LNETL3NB: First update()\");\n\t\t_FirstUpdate = false;\n\t\t_LastUpdateTime = t0;\n\t\t_LastMovedStringArray = t0;\n\t}\n\n\t/*\n\t * timeout -1    =>  read one message in the queue or nothing if no message in queue\n\t * timeout 0     =>  read all messages in the queue\n\t * timeout other =>  read all messages in the queue until timeout expired (at least all one time)\n\t */\n\n\tbool exit = false;\n\n\twhile (!exit)\n\t{\n\t\t// process all messages in the queue\n\t\twhile (dataAvailable ())\n\t\t{\n\t\t\tprocessOneMessage ();\n\t\t\tif (timeout == -1)\n\t\t\t{\n\t\t\t\texit = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// need to exit?\n\t\tif (timeout == 0 || (sint32)(CTime::getLocalTime() - t0) > timeout)\n\t\t{\n\t\t\texit = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// enable multithreading on windows :-/\n\t\t\t// slow down the layer H_AUTO (CCallbackNetBase_baseUpdate_nlSleep);\n\t\t\tnlSleep (10);\n\t\t}\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\t_MR_UpdateCounter++;\n#endif\n\n}\n\n\n/*\n * baseUpdate\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackNetBase::baseUpdate2 (sint32 timeout, sint32 mintime)\n{\n\tH_AUTO(L3UpdateCallbackNetBase2);\n#ifdef NL_DEBUG\n\tnlassert( timeout >= -1 );\n#endif\n\n\tTTime t0 = CTime::getLocalTime();\n\n\t//\n\t// The first time, we init time counters\n\t//\n\tif (_FirstUpdate)\n\t{\n//\t\tLNETL3_DEBUG(\"LNETL3NB: First update()\");\n\t\t_FirstUpdate = false;\n\t\t_LastUpdateTime = t0;\n\t\t_LastMovedStringArray = t0;\n\t}\n\n\t/*\n\t * Controlling the blocking time of this update loop:\n\t *\n\t * \"GREEDY\" MODE (legacy default mode)\n\t *   timeout -1   => While data are available, read all messages in the queue,\n\t *   mintime t>=0    return only when the queue is empty (and mintime is reached/exceeded).\n\t *\n\t * \"CONSTRAINED\" MODE (used by layer 5 with mintime=0)\n\t *   timeout t>0  => Read messages in the queue, exit when the timeout is reached/exceeded,\n\t *   mintime t>=0    or when there are no more data (and mintime is reached/exceeded).\n\t *\n\t * \"ONE-SHOT\"/\"HARE AND TORTOISE\" MODE\n\t *   timeout 0    => Read up to one message in the queue (nothing if empty), then return at\n\t *   mintime t>=0    once, or, if mintime not reached, sleep (yield cpu) and start again.\n\t *\n\t * Backward compatibility:\t\tbaseUpdate():\t\tTo have the same behaviour with baseUpdate2():\n\t *   Warning! The semantics\t\ttimeout t>0\t\t\ttimeout 0, mintime t>0\n\t *   of the timeout argument\ttimeout -1\t\t\ttimeout 0, mintime 0\n\t *   has changed\t\t\t\ttimeout 0\t\t\ttimeout -1, mintime 0\n\t *\n\t * About \"Reached/exceeded\"\n\t *   This loop does not control the time of the user-code in the callback. Thus if some data\n\t *   are available, the callback may take more time than specified in timeout. Then the loop\n\t *   will end when the timeout is \"exceeded\" instead of \"reached\". When yielding cpu, some\n\t *   more time than specified may be spent as well.\n\t *\n\t * Flooding Detection Option (TODO)\n\t *   _FloodingByteLimit => If setFloodingDetection() has been called, and the size of the\n\t *                    queue exceeds the flooding limit, the connection will be dropped and\n\t *                    the loop will return immediately.\n\t *\n\t * Message Frame Option (TODO)\n \t *   At the beginning of the loop, the number of pending messages would be read, and then\n\t *   only these messages would be processed in this loop, no more. As a result, any messages\n\t *   received in the meantime would be postponed until the next call.\n\t *   However, to do this we need to add a fast method getMsgNb() in NLMISC::CBufFifo\n\t *   (see more information in the class header of CBufFifo).\n\t *\n\t * Implementation notes:\n\t *   As CTime::getLocalTime() may be slow on certain platforms, we test it only\n\t *   if timeout > 0 or mintime > 0.\n\t *   As CTime::getLocalTime() is not an accurate time measure (ms unit, resolution on several\n\t *   ms on certain platforms), we compare with timeout & mintime using \"greater or equal\".\n\t *\n\t * Testing:\n\t *  See nel\\tools\\nel_unit_test\\net_ut\\layer3_test.cpp\n\t */\n\n//\t// TODO: Flooding Detection Option (would work best with the Message Frame Option, otherwise\n//\t// we won't detect here a flooding that would occur during the loop.\n//\tif ( _FloodingDetectionEnabled )\n//\t{\n//\t\tif ( getDataAvailableFlagV() )\n//\t\t{\n//\t\t\tuint64 nbBytesToHandle = getReceiveQueueSize(); // see above about a possible getMsgNb()\n//\t\t\tif ( nbBytesToHandle > _FloodingByteLimit )\n//\t\t\t{\n//\t\t\t\t// TODO: disconnect\n//\t\t\t}\n//\t\t}\n//\t}\n\n\t// Outer loop\n\twhile ( true )\n\t{\n\t\t// Inner loop\n\t\twhile ( dataAvailable () )\n\t\t{\n\t\t\tprocessOneMessage();\n\n\t\t\t// ONE-SHOT MODE/\"HARE AND TORTOISE\" (or CONSTRAINED with no more time): break\n\t\t\tif ( timeout == 0 )\n\t\t\t\tbreak;\n\t\t\t// CONTRAINED MODE: break if timeout reached even if more data are available\n\t\t\tif ( (timeout > 0) && ((sint32)(CTime::getLocalTime() - t0) >= timeout) )\n\t\t\t\tbreak;\n\t\t\t// GREEDY MODE (timeout -1): loop until no more data are available\n\t\t}\n\n\t\t// If mintime provided, loop until mintime reached, otherwise exit\n\t\tif ( mintime == 0 )\n\t\t\tbreak;\n\t\tif (((sint32)(CTime::getLocalTime() - t0) >= mintime))\n\t\t\tbreak;\n\t\tnlSleep( 0 ); // yield cpu\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\t_MR_UpdateCounter++;\n#endif\n\n}\n\n\nconst\tCInetAddress& CCallbackNetBase::hostAddress (TSockId /* hostid */)\n{\n\t// should never be called\n\tnlstop;\n\tstatic CInetAddress tmp;\n\treturn tmp;\n}\n\nvoid\tCCallbackNetBase::authorizeOnly (const char *callbackName, TSockId hostid)\n{\n\tLNETL3_DEBUG (\"LNETL3NB: authorizeOnly (%s, %s)\", callbackName, hostid->asString().c_str());\n\n\thostid = getSockId (hostid);\n\n\tnlassert (hostid != InvalidSockId);\n\n\thostid->AuthorizedCallback = (callbackName == NULL)?\"\":callbackName;\n}\n\n\n#ifdef USE_MESSAGE_RECORDER\n\n/*\n * Replay dataAvailable() in replay mode\n */\nbool CCallbackNetBase::replayDataAvailable()\n{\n\tnlassert( _MR_RecordingState == Replay );\n\n\tif ( _MR_Recorder.ReceivedMessages.empty() )\n\t{\n\t\t// Fill the queue of received messages related to the present update\n\t\t_MR_Recorder.replayNextDataAvailable( _MR_UpdateCounter );\n\t}\n\n\treturn replaySystemCallbacks();\n}\n\n\n/*\n * Record or replay disconnection\n */\nvoid CCallbackNetBase::noticeDisconnection( TSockId hostid )\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tif ( _MR_RecordingState != Replay )\n\t{\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record disconnection\n\t\t\tCMessage emptymsg;\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Disconnecting, hostid, emptymsg );\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Replay disconnection\n\t\thostid->disconnect( false );\n\t}\n}\n\n#endif // USE_MESSAGE_RECORDER\n\n} // NLNET\n\n"
  },
  {
    "path": "code/nel/src/net/callback_server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/net_log.h\"\n\n\n#ifdef USE_MESSAGE_RECORDER\n#include \"nel/net/dummy_tcp_sock.h\"\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Connection callback (the disconnection callback is in callback_net_base.cpp\n */\nvoid cbsNewConnection (TSockId from, void *data)\n{\n\tnlassert (data != NULL);\n\tCCallbackServer *server = (CCallbackServer *)data;\n\n\tLNETL3_DEBUG(\"LNETL3S: newConnection()\");\n\n#ifdef USE_MESSAGE_RECORDER\n\t// Record connection\n\tserver->noticeConnection( from );\n#endif\n\n\t// send all my association to the new client\n// association are disactivated so we don t need to send them\n//\tserver->sendAllMyAssociations (from);\n\n\t// call the client callback if necessary\n\tif (server->_ConnectionCallback != NULL)\n\t\tserver->_ConnectionCallback (from, server->_ConnectionCbArg);\n}\n\n\n/*\n * Constructor\n */\nCCallbackServer::CCallbackServer( TRecordingState rec, const string& recfilename, bool recordall, bool initPipeForDataAvailable ) :\n\tCCallbackNetBase( rec, recfilename, recordall ),\n\tCBufServer( DEFAULT_STRATEGY, DEFAULT_MAX_THREADS, DEFAULT_MAX_SOCKETS_PER_THREADS, true, rec==Replay, initPipeForDataAvailable ),\n\t_ConnectionCallback(NULL),\n\t_ConnectionCbArg(NULL)\n{\n#ifndef USE_MESSAGE_RECORDER\n\tnlassertex( rec==Off, (\"LNETL3S: The message recorder is disabled at compilation time ; switch the recording state Off\") );\n#endif\n\n\tCBufServer::setDisconnectionCallback (_NewDisconnectionCallback, this);\n\tCBufServer::setConnectionCallback (cbsNewConnection, this);\n\n\t_IsAServer = true;\n\t_DefaultCallback = NULL;\n}\n\n\n/*\n * Send a message to the specified host (pushing to its send queue)\n * Recorded : YES\n * Replayed : MAYBE\n */\nvoid CCallbackServer::send (const CMessage &buffer, TSockId hostid, bool /* log */)\n{\n\tnlassert (connected ());\n\tnlassert (buffer.length() != 0);\n\tnlassert (buffer.typeIsSet());\n\n\tif (hostid == InvalidSockId)\n\t{\n\t\t// broadcast\n\t\tsint nb = nbConnections ();\n\t\t_BytesSent += buffer.length () * nb;\n\t}\n\telse\n\t{\n\t\t_BytesSent += buffer.length ();\n\t}\n\n//\tif (log)\n\t{\n//\t\tLNETL3_DEBUG (\"LNETL3S: Server: send(%s, %s)\", buffer.toString().c_str(), hostid->asString().c_str());\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Send\n\t\tCBufServer::send (buffer, hostid);\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record sent message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n#endif\n}\n\n\n/*\n * Updates the network (call this method evenly)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServer::update2 ( sint32 timeout, sint32 mintime )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate2 ( timeout, mintime ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServer::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n\n}\n\n/*\n * Updates the network (call this method evenly) (legacy)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServer::update ( sint32 timeout )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate ( timeout ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServer::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n}\n\n\n/*\n * Read the next message in the receive queue\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackServer::receive (CMessage &buffer, TSockId *hostid)\n{\n\tnlassert (connected ());\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Receive\n\t\tCBufServer::receive (buffer, hostid);\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record received message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Receiving, *hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n\telse\n\t{\n\t\t// Retrieve received message loaded by dataAvailable()\n\t\tbuffer = _MR_Recorder.ReceivedMessages.front().Message;\n\t\t*hostid = _MR_Recorder.ReceivedMessages.front().SockId;\n\t\t_MR_Recorder.ReceivedMessages.pop();\n\t}\n#endif\n\n\tbuffer.readType ();\n}\n\n\n/*\n * Disconnect a connection\n * Set hostid to InvalidSockId to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * Before disconnecting, any pending data is actually sent.\n * Recorded : YES in noticeDisconnection called in the disconnection callback\n * Replayed : YES in noticeDisconnection called in the disconnection callback\n */\nvoid CCallbackServer::disconnect( TSockId hostid )\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// Disconnect\n\t\tCBufServer::disconnect( hostid );\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\t// else, no need to manually replay the disconnection, such as in CCallbackClient,\n\t// it will be replayed during the next update()\n#endif\n}\n\n\n/*\n *\n */\nTSockId CCallbackServer::getSockId (TSockId hostid)\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tnlassert (connected ());\n\tnlassert (hostid != NULL);\n\treturn hostid;\n}\n\n\n/*\n * Returns true if there are messages to read\n * Recorded : NO\n * Replayed : YES\n */\nbool CCallbackServer::dataAvailable ()\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Real dataAvailable()\n\t\treturn CBufServer::dataAvailable ();\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\telse\n\t{\n\t\t// Simulated dataAvailable()\n\t\treturn CCallbackNetBase::replayDataAvailable();\n\t}\n#endif\n}\n\n\n//-------------------------\n#ifdef USE_MESSAGE_RECORDER\n\n\n/*\n * Replay connection and disconnection callbacks, client version\n */\nbool CCallbackServer::replaySystemCallbacks()\n{\n\tdo\n\t{\n\t\tif ( _MR_Recorder.ReceivedMessages.empty() )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Translate the stored sockid to the replayed sockid\n\t\t\tTSockId sockid;\n\t\t\tstd::map<TSockId,TSockId>::iterator isi = _MR_SockIds.find( _MR_Recorder.ReceivedMessages.front().SockId );\n\t\t\tif ( isi != _MR_SockIds.end() )\n\t\t\t{\n\t\t\t\t// The sockid is found in the map if the connection already exists\n\t\t\t\tsockid = (*isi).second;\n\t\t\t\t_MR_Recorder.ReceivedMessages.front().SockId = sockid;\n\t\t\t}\n\n\t\t\t// Test event type\n\t\t\tswitch( _MR_Recorder.ReceivedMessages.front().Event )\n\t\t\t{\n\t\t\tcase Receiving:\n\t\t\t\treturn true;\n\n\t\t\tcase Disconnecting:\n\t\t\t\tLNETL3_DEBUG( \"LNETL3S: Disconnection event for %p\", sockid );\n\t\t\t\tsockid->Sock->disconnect();\n\t\t\t\tsockid->setConnectedState( false );\n\n\t\t\t\t// Call callback if needed\n\t\t\t\tif ( disconnectionCallback() != NULL )\n\t\t\t\t{\n\t\t\t\t\tdisconnectionCallback()( sockid, argOfDisconnectionCallback() );\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase Accepting:\n\t\t\t\t{\n\t\t\t\t// Replay connection:\n\n\t\t\t\t// Get remote address\n\t\t\t\tCInetAddress addr;\n\t\t\t\t_MR_Recorder.ReceivedMessages.front().Message.serial( addr );\n\n\t\t\t\t// Create a new connection\n\t\t\t\tsockid = new CBufSock( new CDummyTcpSock() );\n\t\t\t\tsockid->Sock->connect( addr );\n\t\t\t\t_MR_Connections.push_back( sockid );\n\n\t\t\t\t// Bind it to the \"old\" sockid\n\t\t\t\t_MR_SockIds.insert( make_pair( _MR_Recorder.ReceivedMessages.front().SockId, sockid ) );\n\n\t\t\t\tLNETL3_DEBUG( \"LNETL3S: Connection event for %p\", sockid );\n\t\t\t\tsockid->setConnectedState( true );\n\n\t\t\t\t// Call callback if needed\n\t\t\t\tif ( connectionCallback() != NULL )\n\t\t\t\t{\n\t\t\t\t\tconnectionCallback()( sockid, argOfConnectionCallback() );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tnlerror( \"LNETL3S: Invalid system event type in client receive queue\" );\n\t\t\t}\n\t\t\t// Extract system event\n\t\t\t_MR_Recorder.ReceivedMessages.pop();\n\t\t}\n\t}\n\twhile ( true );\n}\n\n\n/*\n * Record or replay connection\n */\nvoid CCallbackServer::noticeConnection( TSockId hostid )\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tif ( _MR_RecordingState != Replay )\n\t{\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record connection\n\t\t\tCMessage addrmsg;\n\t\t\taddrmsg.serial( const_cast<CInetAddress&>(hostAddress(hostid)) );\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Accepting, hostid, addrmsg );\n\t\t}\n\t}\n}\n\n#endif // USE_MESSAGE_RECORDER\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/callback_server_tcp.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/callback_server_tcp.h\"\n#include \"nel/net/net_log.h\"\n\n\n#ifdef USE_MESSAGE_RECORDER\n#include \"nel/net/dummy_tcp_sock.h\"\n#endif\n\n#include \"event.h\"\n#include <event2/util.h>\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Connection callback (the disconnection callback is in callback_net_base.cpp\n */\nvoid cbsTcpNewConnection (TSockId from, void *data)\n{\n\tnlassert (data != NULL);\n\tCCallbackServerTcp *server = (CCallbackServerTcp *)data;\n\n\tLNETL3_DEBUG(\"LNETL3S: WebSktNewConnection()\");\n\n#ifdef USE_MESSAGE_RECORDER\n\t// Record connection\n\tserver->noticeConnection( from );\n#endif\n\n\t// send all my association to the new client\n// association are disactivated so we don t need to send them\n//\tserver->sendAllMyAssociations (from);\n\n\t// call the client callback if necessary\n\tif (server->_ConnectionCallback != NULL)\n\t\tserver->_ConnectionCallback (from, server->_ConnectionCbArg);\n}\n\n\n/*\n * Constructor\n */\nCCallbackServerTcp::CCallbackServerTcp( TRecordingState rec, const string& recfilename, bool recordall, bool initPipeForDataAvailable ) :\n\tCCallbackNetBase( rec, recfilename, recordall ),\n\t_ConnectionCallback(NULL),\n\t_ConnectionCbArg(NULL)\n{\n#ifndef USE_MESSAGE_RECORDER\n\tnlassertex( rec==Off, (\"LNETL3S: The message recorder is disabled at compilation time ; switch the recording state Off\") );\n#endif\n\n\tCBufServerTcp::setDisconnectionCallback (_NewDisconnectionCallback, this);\n\tCBufServerTcp::setConnectionCallback (cbsTcpNewConnection, this);\n\n\t_IsAServer = true;\n\t_DefaultCallback = NULL;\n}\n\n\n/*\n * Send a message to the specified host (pushing to its send queue)\n * Recorded : YES\n * Replayed : MAYBE\n */\nvoid CCallbackServerTcp::send (const CMessage &buffer, TSockId hostid, bool /* log */)\n{\n\tnlassert (connected ());\n\tnlassert (buffer.length() != 0);\n    nlassert (buffer.typeIsSet());\n\n\tif (hostid == InvalidSockId)\n\t{\n\t\t// broadcast\n\t\tsint nb = nbConnections ();\n\t\t_BytesSent += buffer.length () * nb;\n\t}\n\telse\n\t{\n\t\t_BytesSent += buffer.length ();\n\t}\n\n//\tif (log)\n\t{\n//\t\tLNETL3_DEBUG (\"LNETL3S: Server: send(%s, %s)\", buffer.toString().c_str(), hostid->asString().c_str());\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Send\n\t\tCBufServerTcp::send (buffer, hostid);\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record sent message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n#endif\n}\n\n\n/*\n * Updates the network (call this method evenly)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServerTcp::update2 ( sint32 timeout, sint32 mintime )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate2 ( timeout, mintime ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServerTcp::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n\n}\n\n/*\n * Updates the network (call this method evenly) (legacy)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServerTcp::update ( sint32 timeout )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate ( timeout ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServerTcp::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n}\n\n\n/*\n * Read the next message in the receive queue\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackServerTcp::receive (CMessage &buffer, TSockId *hostid)\n{\n\tnlassert (connected ());\n\n    // Receive\n\tCBufServerTcp::receive (buffer, hostid);\n\tbuffer.readType ();\n}\n\n\n/*\n * Disconnect a connection\n * Set hostid to InvalidSockId to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * Before disconnecting, any pending data is actually sent.\n * Recorded : YES in noticeDisconnection called in the disconnection callback\n * Replayed : YES in noticeDisconnection called in the disconnection callback\n */\nvoid CCallbackServerTcp::disconnect( TSockId hostid )\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// Disconnect\n\t\tCBufServerTcp::disconnect( hostid );\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\t// else, no need to manually replay the disconnection, such as in CCallbackClient,\n\t// it will be replayed during the next update()\n#endif\n}\n\n\n/*\n *\n */\nTSockId CCallbackServerTcp::getSockId (TSockId hostid)\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tnlassert (connected ());\n\tnlassert (hostid != NULL);\n\treturn hostid;\n}\n\n\n/*\n * Returns true if there are messages to read\n * Recorded : NO\n * Replayed : YES\n */\nbool CCallbackServerTcp::dataAvailable ()\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Real dataAvailable()\n\t\treturn CBufServerTcp::dataAvailable ();\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\telse\n\t{\n\t\t// Simulated dataAvailable()\n\t\treturn CCallbackNetBase::replayDataAvailable();\n\t}\n#endif\n}\n\n\n//-------------------------\n#ifdef USE_MESSAGE_RECORDER\n\n\n/*\n * Replay connection and disconnection callbacks, client version\n */\nbool CCallbackServerTcp::replaySystemCallbacks()\n{\n    return false;\n}\n\n\n/*\n * Record or replay connection\n */\nvoid CCallbackServerTcp::noticeConnection( TSockId hostid )\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tif ( _MR_RecordingState != Replay )\n\t{\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record connection\n\t\t\tCMessage addrmsg;\n\t\t\taddrmsg.serial( const_cast<CInetAddress&>(hostAddress(hostid)) );\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Accepting, hostid, addrmsg );\n\t\t}\n\t}\n}\n\n#endif // USE_MESSAGE_RECORDER\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/callback_server_websocket.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/callback_server_websocket.h\"\n#include \"nel/net/net_log.h\"\n\n\n#ifdef USE_MESSAGE_RECORDER\n#include \"nel/net/dummy_tcp_sock.h\"\n#endif\n\n#include \"event.h\"\n#include <event2/util.h>\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Connection callback (the disconnection callback is in callback_net_base.cpp\n */\nvoid cbsWebSktNewConnection (TSockId from, void *data)\n{\n\tnlassert (data != NULL);\n\tCCallbackServerWebSocket *server = (CCallbackServerWebSocket *)data;\n\n\tLNETL3_DEBUG(\"LNETL3S: WebSktNewConnection()\");\n\n#ifdef USE_MESSAGE_RECORDER\n\t// Record connection\n\tserver->noticeConnection( from );\n#endif\n\n\t// send all my association to the new client\n// association are disactivated so we don t need to send them\n//\tserver->sendAllMyAssociations (from);\n\n\t// call the client callback if necessary\n\tif (server->_ConnectionCallback != NULL)\n\t\tserver->_ConnectionCallback (from, server->_ConnectionCbArg);\n}\n\n\n/*\n * Constructor\n */\nCCallbackServerWebSocket::CCallbackServerWebSocket( TRecordingState rec, const string& recfilename, bool recordall, bool initPipeForDataAvailable ) :\n\tCCallbackNetBase( rec, recfilename, recordall ),\n\t_ConnectionCallback(NULL),\n\t_ConnectionCbArg(NULL)\n{\n#ifndef USE_MESSAGE_RECORDER\n\tnlassertex( rec==Off, (\"LNETL3S: The message recorder is disabled at compilation time ; switch the recording state Off\") );\n#endif\n\n\tCBufServerWebsocket::setDisconnectionCallback (_NewDisconnectionCallback, this);\n\tCBufServerWebsocket::setConnectionCallback (cbsWebSktNewConnection, this);\n\n\t_IsAServer = true;\n\t_DefaultCallback = NULL;\n}\n\n\n/*\n * Send a message to the specified host (pushing to its send queue)\n * Recorded : YES\n * Replayed : MAYBE\n */\nvoid CCallbackServerWebSocket::send (const CMessage &buffer, TSockId hostid, bool /* log */)\n{\n\tnlassert (connected ());\n\tnlassert (buffer.length() != 0);\n\n\tif (hostid == InvalidSockId)\n\t{\n\t\t// broadcast\n\t\tsint nb = nbConnections ();\n\t\t_BytesSent += buffer.length () * nb;\n\t}\n\telse\n\t{\n\t\t_BytesSent += buffer.length ();\n\t}\n\n//\tif (log)\n\t{\n//\t\tLNETL3_DEBUG (\"LNETL3S: Server: send(%s, %s)\", buffer.toString().c_str(), hostid->asString().c_str());\n\t}\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Send\n\t\tCBufServerWebsocket::send (buffer, hostid);\n\n#ifdef USE_MESSAGE_RECORDER\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record sent message\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );\n\t\t}\n\t}\n#endif\n}\n\n\n/*\n * Updates the network (call this method evenly)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServerWebSocket::update2 ( sint32 timeout, sint32 mintime )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate2 ( timeout, mintime ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServerWebsocket::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n\n}\n\n/*\n * Updates the network (call this method evenly) (legacy)\n * Recorded : YES (in baseUpdate())\n * Replayed : YES (in baseUpdate())\n */\nvoid CCallbackServerWebSocket::update ( sint32 timeout )\n{\n\tH_AUTO(L3UpdateServer);\n\n\tnlassert (connected ());\n\n//\tLNETL3_DEBUG (\"LNETL3S: Client: update()\");\n\tbaseUpdate ( timeout ); // first receive\n\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// L1-2 Update (nothing to do in replay mode)\n\t\tCBufServerWebsocket::update (); // then send\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n#endif\n}\n\n\n/*\n * Read the next message in the receive queue\n * Recorded : YES\n * Replayed : YES\n */\nvoid CCallbackServerWebSocket::receive (CMessage &buffer, TSockId *hostid)\n{\n\tnlassert (connected ());\n\n    // Receive\n\tCBufServerWebsocket::receive (buffer, hostid);\n\tbuffer.readType ();\n}\n\n\n/*\n * Disconnect a connection\n * Set hostid to InvalidSockId to disconnect all connections.\n * If hostid is not null and the socket is not connected, the method does nothing.\n * Before disconnecting, any pending data is actually sent.\n * Recorded : YES in noticeDisconnection called in the disconnection callback\n * Replayed : YES in noticeDisconnection called in the disconnection callback\n */\nvoid CCallbackServerWebSocket::disconnect( TSockId hostid )\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\t\t// Disconnect\n\t\tCBufServerWebsocket::disconnect( hostid );\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\t// else, no need to manually replay the disconnection, such as in CCallbackClient,\n\t// it will be replayed during the next update()\n#endif\n}\n\n\n/*\n *\n */\nTSockId CCallbackServerWebSocket::getSockId (TSockId hostid)\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tnlassert (connected ());\n\tnlassert (hostid != NULL);\n\treturn hostid;\n}\n\n\n/*\n * Returns true if there are messages to read\n * Recorded : NO\n * Replayed : YES\n */\nbool CCallbackServerWebSocket::dataAvailable ()\n{\n#ifdef USE_MESSAGE_RECORDER\n\tif ( _MR_RecordingState != Replay )\n\t{\n#endif\n\n\t\t// Real dataAvailable()\n\t\treturn CBufServerWebsocket::dataAvailable ();\n\n#ifdef USE_MESSAGE_RECORDER\n\t}\n\telse\n\t{\n\t\t// Simulated dataAvailable()\n\t\treturn CCallbackNetBase::replayDataAvailable();\n\t}\n#endif\n}\n\n\n//-------------------------\n#ifdef USE_MESSAGE_RECORDER\n\n\n/*\n * Replay connection and disconnection callbacks, client version\n */\nbool CCallbackServerWebSocket::replaySystemCallbacks()\n{\n    return false;\n}\n\n\n/*\n * Record or replay connection\n */\nvoid CCallbackServerWebSocket::noticeConnection( TSockId hostid )\n{\n\tnlassert (hostid != InvalidSockId);\t// invalid hostid\n\tif ( _MR_RecordingState != Replay )\n\t{\n\t\tif ( _MR_RecordingState == Record )\n\t\t{\n\t\t\t// Record connection\n\t\t\tCMessage addrmsg;\n\t\t\taddrmsg.serial( const_cast<CInetAddress&>(hostAddress(hostid)) );\n\t\t\t_MR_Recorder.recordNext( _MR_UpdateCounter, Accepting, hostid, addrmsg );\n\t\t}\n\t}\n}\n\n#endif // USE_MESSAGE_RECORDER\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/define_sys.pb.cc",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: define_sys.proto\n\n#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n#include \"define_sys.pb.h\"\n\n#include <algorithm>\n\n#include <google/protobuf/stubs/common.h>\n#include <google/protobuf/stubs/once.h>\n#include <google/protobuf/io/coded_stream.h>\n#include <google/protobuf/wire_format_lite_inl.h>\n#include <google/protobuf/descriptor.h>\n#include <google/protobuf/generated_message_reflection.h>\n#include <google/protobuf/reflection_ops.h>\n#include <google/protobuf/wire_format.h>\n// @@protoc_insertion_point(includes)\n\nnamespace {\n\nconst ::google::protobuf::Descriptor* MsgDataHead_descriptor_ = NULL;\nconst ::google::protobuf::internal::GeneratedMessageReflection*\n  MsgDataHead_reflection_ = NULL;\nconst ::google::protobuf::Descriptor* MsgSession_descriptor_ = NULL;\nconst ::google::protobuf::internal::GeneratedMessageReflection*\n  MsgSession_reflection_ = NULL;\nconst ::google::protobuf::Descriptor* MsgPart_descriptor_ = NULL;\nconst ::google::protobuf::internal::GeneratedMessageReflection*\n  MsgPart_reflection_ = NULL;\nconst ::google::protobuf::EnumDescriptor* TUdpControlFlag_descriptor_ = NULL;\nconst ::google::protobuf::EnumDescriptor* TUdpControlCmd_descriptor_ = NULL;\n\n}  // namespace\n\n\nvoid protobuf_AssignDesc_define_5fsys_2eproto() {\n  protobuf_AddDesc_define_5fsys_2eproto();\n  const ::google::protobuf::FileDescriptor* file =\n    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n      \"define_sys.proto\");\n  GOOGLE_CHECK(file != NULL);\n  MsgDataHead_descriptor_ = file->message_type(0);\n  static const int MsgDataHead_offsets_[4] = {\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, control_flag_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, control_cmd_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, ack_idx_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, msg_idx_),\n  };\n  MsgDataHead_reflection_ =\n    new ::google::protobuf::internal::GeneratedMessageReflection(\n      MsgDataHead_descriptor_,\n      MsgDataHead::default_instance_,\n      MsgDataHead_offsets_,\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, _has_bits_[0]),\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgDataHead, _unknown_fields_),\n      -1,\n      ::google::protobuf::DescriptorPool::generated_pool(),\n      ::google::protobuf::MessageFactory::generated_factory(),\n      sizeof(MsgDataHead));\n  MsgSession_descriptor_ = file->message_type(1);\n  static const int MsgSession_offsets_[3] = {\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgSession, session_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgSession, check_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgSession, index_),\n  };\n  MsgSession_reflection_ =\n    new ::google::protobuf::internal::GeneratedMessageReflection(\n      MsgSession_descriptor_,\n      MsgSession::default_instance_,\n      MsgSession_offsets_,\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgSession, _has_bits_[0]),\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgSession, _unknown_fields_),\n      -1,\n      ::google::protobuf::DescriptorPool::generated_pool(),\n      ::google::protobuf::MessageFactory::generated_factory(),\n      sizeof(MsgSession));\n  MsgPart_descriptor_ = file->message_type(2);\n  static const int MsgPart_offsets_[5] = {\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, msg_idx_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, part_idx_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, part_max_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, msg_name_),\n    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, msg_body_),\n  };\n  MsgPart_reflection_ =\n    new ::google::protobuf::internal::GeneratedMessageReflection(\n      MsgPart_descriptor_,\n      MsgPart::default_instance_,\n      MsgPart_offsets_,\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, _has_bits_[0]),\n      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MsgPart, _unknown_fields_),\n      -1,\n      ::google::protobuf::DescriptorPool::generated_pool(),\n      ::google::protobuf::MessageFactory::generated_factory(),\n      sizeof(MsgPart));\n  TUdpControlFlag_descriptor_ = file->enum_type(0);\n  TUdpControlCmd_descriptor_ = file->enum_type(1);\n}\n\nnamespace {\n\nGOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\ninline void protobuf_AssignDescriptorsOnce() {\n  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n                 &protobuf_AssignDesc_define_5fsys_2eproto);\n}\n\nvoid protobuf_RegisterTypes(const ::std::string&) {\n  protobuf_AssignDescriptorsOnce();\n  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n    MsgDataHead_descriptor_, &MsgDataHead::default_instance());\n  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n    MsgSession_descriptor_, &MsgSession::default_instance());\n  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n    MsgPart_descriptor_, &MsgPart::default_instance());\n}\n\n}  // namespace\n\nvoid protobuf_ShutdownFile_define_5fsys_2eproto() {\n  delete MsgDataHead::default_instance_;\n  delete MsgDataHead_reflection_;\n  delete MsgSession::default_instance_;\n  delete MsgSession_reflection_;\n  delete MsgPart::default_instance_;\n  delete MsgPart_reflection_;\n}\n\nvoid protobuf_AddDesc_define_5fsys_2eproto() {\n  static bool already_here = false;\n  if (already_here) return;\n  already_here = true;\n  GOOGLE_PROTOBUF_VERIFY_VERSION;\n\n  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(\n    \"\\n\\020define_sys.proto\\\"Z\\n\\013MsgDataHead\\022\\024\\n\\014con\"\n    \"trol_flag\\030\\001 \\001(\\r\\022\\023\\n\\013control_cmd\\030\\002 \\001(\\r\\022\\017\\n\\007\"\n    \"ack_idx\\030\\003 \\001(\\r\\022\\017\\n\\007msg_idx\\030\\004 \\001(\\r\\\";\\n\\nMsgSes\"\n    \"sion\\022\\017\\n\\007session\\030\\001 \\001(\\t\\022\\r\\n\\005check\\030\\002 \\001(\\007\\022\\r\\n\\005\"\n    \"index\\030\\003 \\001(\\r\\\"b\\n\\007MsgPart\\022\\017\\n\\007msg_idx\\030\\001 \\001(\\r\\022\"\n    \"\\020\\n\\010part_idx\\030\\002 \\001(\\r\\022\\020\\n\\010part_max\\030\\003 \\001(\\r\\022\\020\\n\\010m\"\n    \"sg_name\\030\\004 \\001(\\t\\022\\020\\n\\010msg_body\\030\\005 \\001(\\014*5\\n\\017TUdpC\"\n    \"ontrolFlag\\022\\r\\n\\tPROTO_CMD\\020\\001\\022\\023\\n\\016PROTO_NEED_\"\n    \"ACK\\020\\200\\001*<\\n\\016TUdpControlCmd\\022\\021\\n\\rPROTO_CMD_AC\"\n    \"K\\020\\001\\022\\027\\n\\023PROTO_CMD_HEARTBEAT\\020\\002\", 388);\n  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n    \"define_sys.proto\", &protobuf_RegisterTypes);\n  MsgDataHead::default_instance_ = new MsgDataHead();\n  MsgSession::default_instance_ = new MsgSession();\n  MsgPart::default_instance_ = new MsgPart();\n  MsgDataHead::default_instance_->InitAsDefaultInstance();\n  MsgSession::default_instance_->InitAsDefaultInstance();\n  MsgPart::default_instance_->InitAsDefaultInstance();\n  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_define_5fsys_2eproto);\n}\n\n// Force AddDescriptors() to be called at static initialization time.\nstruct StaticDescriptorInitializer_define_5fsys_2eproto {\n  StaticDescriptorInitializer_define_5fsys_2eproto() {\n    protobuf_AddDesc_define_5fsys_2eproto();\n  }\n} static_descriptor_initializer_define_5fsys_2eproto_;\nconst ::google::protobuf::EnumDescriptor* TUdpControlFlag_descriptor() {\n  protobuf_AssignDescriptorsOnce();\n  return TUdpControlFlag_descriptor_;\n}\nbool TUdpControlFlag_IsValid(int value) {\n  switch(value) {\n    case 1:\n    case 128:\n      return true;\n    default:\n      return false;\n  }\n}\n\nconst ::google::protobuf::EnumDescriptor* TUdpControlCmd_descriptor() {\n  protobuf_AssignDescriptorsOnce();\n  return TUdpControlCmd_descriptor_;\n}\nbool TUdpControlCmd_IsValid(int value) {\n  switch(value) {\n    case 1:\n    case 2:\n      return true;\n    default:\n      return false;\n  }\n}\n\n\n// ===================================================================\n\n#ifndef _MSC_VER\nconst int MsgDataHead::kControlFlagFieldNumber;\nconst int MsgDataHead::kControlCmdFieldNumber;\nconst int MsgDataHead::kAckIdxFieldNumber;\nconst int MsgDataHead::kMsgIdxFieldNumber;\n#endif  // !_MSC_VER\n\nMsgDataHead::MsgDataHead()\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  // @@protoc_insertion_point(constructor:MsgDataHead)\n}\n\nvoid MsgDataHead::InitAsDefaultInstance() {\n}\n\nMsgDataHead::MsgDataHead(const MsgDataHead& from)\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  MergeFrom(from);\n  // @@protoc_insertion_point(copy_constructor:MsgDataHead)\n}\n\nvoid MsgDataHead::SharedCtor() {\n  _cached_size_ = 0;\n  control_flag_ = 0u;\n  control_cmd_ = 0u;\n  ack_idx_ = 0u;\n  msg_idx_ = 0u;\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n}\n\nMsgDataHead::~MsgDataHead() {\n  // @@protoc_insertion_point(destructor:MsgDataHead)\n  SharedDtor();\n}\n\nvoid MsgDataHead::SharedDtor() {\n  if (this != default_instance_) {\n  }\n}\n\nvoid MsgDataHead::SetCachedSize(int size) const {\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n}\nconst ::google::protobuf::Descriptor* MsgDataHead::descriptor() {\n  protobuf_AssignDescriptorsOnce();\n  return MsgDataHead_descriptor_;\n}\n\nconst MsgDataHead& MsgDataHead::default_instance() {\n  if (default_instance_ == NULL) protobuf_AddDesc_define_5fsys_2eproto();\n  return *default_instance_;\n}\n\nMsgDataHead* MsgDataHead::default_instance_ = NULL;\n\nMsgDataHead* MsgDataHead::New() const {\n  return new MsgDataHead;\n}\n\nvoid MsgDataHead::Clear() {\n#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \\\n  &reinterpret_cast<MsgDataHead*>(16)->f) - \\\n   reinterpret_cast<char*>(16))\n\n#define ZR_(first, last) do {                              \\\n    size_t f = OFFSET_OF_FIELD_(first);                    \\\n    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \\\n    ::memset(&first, 0, n);                                \\\n  } while (0)\n\n  ZR_(control_flag_, msg_idx_);\n\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n  mutable_unknown_fields()->Clear();\n}\n\nbool MsgDataHead::MergePartialFromCodedStream(\n    ::google::protobuf::io::CodedInputStream* input) {\n#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n  ::google::protobuf::uint32 tag;\n  // @@protoc_insertion_point(parse_start:MsgDataHead)\n  for (;;) {\n    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);\n    tag = p.first;\n    if (!p.second) goto handle_unusual;\n    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n      // optional uint32 control_flag = 1;\n      case 1: {\n        if (tag == 8) {\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &control_flag_)));\n          set_has_control_flag();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(16)) goto parse_control_cmd;\n        break;\n      }\n\n      // optional uint32 control_cmd = 2;\n      case 2: {\n        if (tag == 16) {\n         parse_control_cmd:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &control_cmd_)));\n          set_has_control_cmd();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(24)) goto parse_ack_idx;\n        break;\n      }\n\n      // optional uint32 ack_idx = 3;\n      case 3: {\n        if (tag == 24) {\n         parse_ack_idx:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &ack_idx_)));\n          set_has_ack_idx();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(32)) goto parse_msg_idx;\n        break;\n      }\n\n      // optional uint32 msg_idx = 4;\n      case 4: {\n        if (tag == 32) {\n         parse_msg_idx:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &msg_idx_)));\n          set_has_msg_idx();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectAtEnd()) goto success;\n        break;\n      }\n\n      default: {\n      handle_unusual:\n        if (tag == 0 ||\n            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n          goto success;\n        }\n        DO_(::google::protobuf::internal::WireFormat::SkipField(\n              input, tag, mutable_unknown_fields()));\n        break;\n      }\n    }\n  }\nsuccess:\n  // @@protoc_insertion_point(parse_success:MsgDataHead)\n  return true;\nfailure:\n  // @@protoc_insertion_point(parse_failure:MsgDataHead)\n  return false;\n#undef DO_\n}\n\nvoid MsgDataHead::SerializeWithCachedSizes(\n    ::google::protobuf::io::CodedOutputStream* output) const {\n  // @@protoc_insertion_point(serialize_start:MsgDataHead)\n  // optional uint32 control_flag = 1;\n  if (has_control_flag()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->control_flag(), output);\n  }\n\n  // optional uint32 control_cmd = 2;\n  if (has_control_cmd()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->control_cmd(), output);\n  }\n\n  // optional uint32 ack_idx = 3;\n  if (has_ack_idx()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->ack_idx(), output);\n  }\n\n  // optional uint32 msg_idx = 4;\n  if (has_msg_idx()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->msg_idx(), output);\n  }\n\n  if (!unknown_fields().empty()) {\n    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n        unknown_fields(), output);\n  }\n  // @@protoc_insertion_point(serialize_end:MsgDataHead)\n}\n\n::google::protobuf::uint8* MsgDataHead::SerializeWithCachedSizesToArray(\n    ::google::protobuf::uint8* target) const {\n  // @@protoc_insertion_point(serialize_to_array_start:MsgDataHead)\n  // optional uint32 control_flag = 1;\n  if (has_control_flag()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->control_flag(), target);\n  }\n\n  // optional uint32 control_cmd = 2;\n  if (has_control_cmd()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->control_cmd(), target);\n  }\n\n  // optional uint32 ack_idx = 3;\n  if (has_ack_idx()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->ack_idx(), target);\n  }\n\n  // optional uint32 msg_idx = 4;\n  if (has_msg_idx()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->msg_idx(), target);\n  }\n\n  if (!unknown_fields().empty()) {\n    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n        unknown_fields(), target);\n  }\n  // @@protoc_insertion_point(serialize_to_array_end:MsgDataHead)\n  return target;\n}\n\nint MsgDataHead::ByteSize() const {\n  int total_size = 0;\n\n  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    // optional uint32 control_flag = 1;\n    if (has_control_flag()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->control_flag());\n    }\n\n    // optional uint32 control_cmd = 2;\n    if (has_control_cmd()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->control_cmd());\n    }\n\n    // optional uint32 ack_idx = 3;\n    if (has_ack_idx()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->ack_idx());\n    }\n\n    // optional uint32 msg_idx = 4;\n    if (has_msg_idx()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->msg_idx());\n    }\n\n  }\n  if (!unknown_fields().empty()) {\n    total_size +=\n      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n        unknown_fields());\n  }\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = total_size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n  return total_size;\n}\n\nvoid MsgDataHead::MergeFrom(const ::google::protobuf::Message& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  const MsgDataHead* source =\n    ::google::protobuf::internal::dynamic_cast_if_available<const MsgDataHead*>(\n      &from);\n  if (source == NULL) {\n    ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n  } else {\n    MergeFrom(*source);\n  }\n}\n\nvoid MsgDataHead::MergeFrom(const MsgDataHead& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    if (from.has_control_flag()) {\n      set_control_flag(from.control_flag());\n    }\n    if (from.has_control_cmd()) {\n      set_control_cmd(from.control_cmd());\n    }\n    if (from.has_ack_idx()) {\n      set_ack_idx(from.ack_idx());\n    }\n    if (from.has_msg_idx()) {\n      set_msg_idx(from.msg_idx());\n    }\n  }\n  mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n}\n\nvoid MsgDataHead::CopyFrom(const ::google::protobuf::Message& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nvoid MsgDataHead::CopyFrom(const MsgDataHead& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nbool MsgDataHead::IsInitialized() const {\n\n  return true;\n}\n\nvoid MsgDataHead::Swap(MsgDataHead* other) {\n  if (other != this) {\n    std::swap(control_flag_, other->control_flag_);\n    std::swap(control_cmd_, other->control_cmd_);\n    std::swap(ack_idx_, other->ack_idx_);\n    std::swap(msg_idx_, other->msg_idx_);\n    std::swap(_has_bits_[0], other->_has_bits_[0]);\n    _unknown_fields_.Swap(&other->_unknown_fields_);\n    std::swap(_cached_size_, other->_cached_size_);\n  }\n}\n\n::google::protobuf::Metadata MsgDataHead::GetMetadata() const {\n  protobuf_AssignDescriptorsOnce();\n  ::google::protobuf::Metadata metadata;\n  metadata.descriptor = MsgDataHead_descriptor_;\n  metadata.reflection = MsgDataHead_reflection_;\n  return metadata;\n}\n\n\n// ===================================================================\n\n#ifndef _MSC_VER\nconst int MsgSession::kSessionFieldNumber;\nconst int MsgSession::kCheckFieldNumber;\nconst int MsgSession::kIndexFieldNumber;\n#endif  // !_MSC_VER\n\nMsgSession::MsgSession()\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  // @@protoc_insertion_point(constructor:MsgSession)\n}\n\nvoid MsgSession::InitAsDefaultInstance() {\n}\n\nMsgSession::MsgSession(const MsgSession& from)\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  MergeFrom(from);\n  // @@protoc_insertion_point(copy_constructor:MsgSession)\n}\n\nvoid MsgSession::SharedCtor() {\n  ::google::protobuf::internal::GetEmptyString();\n  _cached_size_ = 0;\n  session_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());\n  check_ = 0u;\n  index_ = 0u;\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n}\n\nMsgSession::~MsgSession() {\n  // @@protoc_insertion_point(destructor:MsgSession)\n  SharedDtor();\n}\n\nvoid MsgSession::SharedDtor() {\n  if (session_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n    delete session_;\n  }\n  if (this != default_instance_) {\n  }\n}\n\nvoid MsgSession::SetCachedSize(int size) const {\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n}\nconst ::google::protobuf::Descriptor* MsgSession::descriptor() {\n  protobuf_AssignDescriptorsOnce();\n  return MsgSession_descriptor_;\n}\n\nconst MsgSession& MsgSession::default_instance() {\n  if (default_instance_ == NULL) protobuf_AddDesc_define_5fsys_2eproto();\n  return *default_instance_;\n}\n\nMsgSession* MsgSession::default_instance_ = NULL;\n\nMsgSession* MsgSession::New() const {\n  return new MsgSession;\n}\n\nvoid MsgSession::Clear() {\n#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \\\n  &reinterpret_cast<MsgSession*>(16)->f) - \\\n   reinterpret_cast<char*>(16))\n\n#define ZR_(first, last) do {                              \\\n    size_t f = OFFSET_OF_FIELD_(first);                    \\\n    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \\\n    ::memset(&first, 0, n);                                \\\n  } while (0)\n\n  if (_has_bits_[0 / 32] & 7) {\n    ZR_(check_, index_);\n    if (has_session()) {\n      if (session_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n        session_->clear();\n      }\n    }\n  }\n\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n  mutable_unknown_fields()->Clear();\n}\n\nbool MsgSession::MergePartialFromCodedStream(\n    ::google::protobuf::io::CodedInputStream* input) {\n#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n  ::google::protobuf::uint32 tag;\n  // @@protoc_insertion_point(parse_start:MsgSession)\n  for (;;) {\n    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);\n    tag = p.first;\n    if (!p.second) goto handle_unusual;\n    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n      // optional string session = 1;\n      case 1: {\n        if (tag == 10) {\n          DO_(::google::protobuf::internal::WireFormatLite::ReadString(\n                input, this->mutable_session()));\n          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n            this->session().data(), this->session().length(),\n            ::google::protobuf::internal::WireFormat::PARSE,\n            \"session\");\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(21)) goto parse_check;\n        break;\n      }\n\n      // optional fixed32 check = 2;\n      case 2: {\n        if (tag == 21) {\n         parse_check:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_FIXED32>(\n                 input, &check_)));\n          set_has_check();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(24)) goto parse_index;\n        break;\n      }\n\n      // optional uint32 index = 3;\n      case 3: {\n        if (tag == 24) {\n         parse_index:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &index_)));\n          set_has_index();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectAtEnd()) goto success;\n        break;\n      }\n\n      default: {\n      handle_unusual:\n        if (tag == 0 ||\n            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n          goto success;\n        }\n        DO_(::google::protobuf::internal::WireFormat::SkipField(\n              input, tag, mutable_unknown_fields()));\n        break;\n      }\n    }\n  }\nsuccess:\n  // @@protoc_insertion_point(parse_success:MsgSession)\n  return true;\nfailure:\n  // @@protoc_insertion_point(parse_failure:MsgSession)\n  return false;\n#undef DO_\n}\n\nvoid MsgSession::SerializeWithCachedSizes(\n    ::google::protobuf::io::CodedOutputStream* output) const {\n  // @@protoc_insertion_point(serialize_start:MsgSession)\n  // optional string session = 1;\n  if (has_session()) {\n    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n      this->session().data(), this->session().length(),\n      ::google::protobuf::internal::WireFormat::SERIALIZE,\n      \"session\");\n    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(\n      1, this->session(), output);\n  }\n\n  // optional fixed32 check = 2;\n  if (has_check()) {\n    ::google::protobuf::internal::WireFormatLite::WriteFixed32(2, this->check(), output);\n  }\n\n  // optional uint32 index = 3;\n  if (has_index()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->index(), output);\n  }\n\n  if (!unknown_fields().empty()) {\n    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n        unknown_fields(), output);\n  }\n  // @@protoc_insertion_point(serialize_end:MsgSession)\n}\n\n::google::protobuf::uint8* MsgSession::SerializeWithCachedSizesToArray(\n    ::google::protobuf::uint8* target) const {\n  // @@protoc_insertion_point(serialize_to_array_start:MsgSession)\n  // optional string session = 1;\n  if (has_session()) {\n    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n      this->session().data(), this->session().length(),\n      ::google::protobuf::internal::WireFormat::SERIALIZE,\n      \"session\");\n    target =\n      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(\n        1, this->session(), target);\n  }\n\n  // optional fixed32 check = 2;\n  if (has_check()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteFixed32ToArray(2, this->check(), target);\n  }\n\n  // optional uint32 index = 3;\n  if (has_index()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->index(), target);\n  }\n\n  if (!unknown_fields().empty()) {\n    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n        unknown_fields(), target);\n  }\n  // @@protoc_insertion_point(serialize_to_array_end:MsgSession)\n  return target;\n}\n\nint MsgSession::ByteSize() const {\n  int total_size = 0;\n\n  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    // optional string session = 1;\n    if (has_session()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::StringSize(\n          this->session());\n    }\n\n    // optional fixed32 check = 2;\n    if (has_check()) {\n      total_size += 1 + 4;\n    }\n\n    // optional uint32 index = 3;\n    if (has_index()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->index());\n    }\n\n  }\n  if (!unknown_fields().empty()) {\n    total_size +=\n      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n        unknown_fields());\n  }\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = total_size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n  return total_size;\n}\n\nvoid MsgSession::MergeFrom(const ::google::protobuf::Message& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  const MsgSession* source =\n    ::google::protobuf::internal::dynamic_cast_if_available<const MsgSession*>(\n      &from);\n  if (source == NULL) {\n    ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n  } else {\n    MergeFrom(*source);\n  }\n}\n\nvoid MsgSession::MergeFrom(const MsgSession& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    if (from.has_session()) {\n      set_session(from.session());\n    }\n    if (from.has_check()) {\n      set_check(from.check());\n    }\n    if (from.has_index()) {\n      set_index(from.index());\n    }\n  }\n  mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n}\n\nvoid MsgSession::CopyFrom(const ::google::protobuf::Message& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nvoid MsgSession::CopyFrom(const MsgSession& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nbool MsgSession::IsInitialized() const {\n\n  return true;\n}\n\nvoid MsgSession::Swap(MsgSession* other) {\n  if (other != this) {\n    std::swap(session_, other->session_);\n    std::swap(check_, other->check_);\n    std::swap(index_, other->index_);\n    std::swap(_has_bits_[0], other->_has_bits_[0]);\n    _unknown_fields_.Swap(&other->_unknown_fields_);\n    std::swap(_cached_size_, other->_cached_size_);\n  }\n}\n\n::google::protobuf::Metadata MsgSession::GetMetadata() const {\n  protobuf_AssignDescriptorsOnce();\n  ::google::protobuf::Metadata metadata;\n  metadata.descriptor = MsgSession_descriptor_;\n  metadata.reflection = MsgSession_reflection_;\n  return metadata;\n}\n\n\n// ===================================================================\n\n#ifndef _MSC_VER\nconst int MsgPart::kMsgIdxFieldNumber;\nconst int MsgPart::kPartIdxFieldNumber;\nconst int MsgPart::kPartMaxFieldNumber;\nconst int MsgPart::kMsgNameFieldNumber;\nconst int MsgPart::kMsgBodyFieldNumber;\n#endif  // !_MSC_VER\n\nMsgPart::MsgPart()\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  // @@protoc_insertion_point(constructor:MsgPart)\n}\n\nvoid MsgPart::InitAsDefaultInstance() {\n}\n\nMsgPart::MsgPart(const MsgPart& from)\n  : ::google::protobuf::Message() {\n  SharedCtor();\n  MergeFrom(from);\n  // @@protoc_insertion_point(copy_constructor:MsgPart)\n}\n\nvoid MsgPart::SharedCtor() {\n  ::google::protobuf::internal::GetEmptyString();\n  _cached_size_ = 0;\n  msg_idx_ = 0u;\n  part_idx_ = 0u;\n  part_max_ = 0u;\n  msg_name_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());\n  msg_body_ = const_cast< ::std::string*>(&::google::protobuf::internal::GetEmptyStringAlreadyInited());\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n}\n\nMsgPart::~MsgPart() {\n  // @@protoc_insertion_point(destructor:MsgPart)\n  SharedDtor();\n}\n\nvoid MsgPart::SharedDtor() {\n  if (msg_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n    delete msg_name_;\n  }\n  if (msg_body_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n    delete msg_body_;\n  }\n  if (this != default_instance_) {\n  }\n}\n\nvoid MsgPart::SetCachedSize(int size) const {\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n}\nconst ::google::protobuf::Descriptor* MsgPart::descriptor() {\n  protobuf_AssignDescriptorsOnce();\n  return MsgPart_descriptor_;\n}\n\nconst MsgPart& MsgPart::default_instance() {\n  if (default_instance_ == NULL) protobuf_AddDesc_define_5fsys_2eproto();\n  return *default_instance_;\n}\n\nMsgPart* MsgPart::default_instance_ = NULL;\n\nMsgPart* MsgPart::New() const {\n  return new MsgPart;\n}\n\nvoid MsgPart::Clear() {\n#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>(      \\\n  &reinterpret_cast<MsgPart*>(16)->f) - \\\n   reinterpret_cast<char*>(16))\n\n#define ZR_(first, last) do {                              \\\n    size_t f = OFFSET_OF_FIELD_(first);                    \\\n    size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last);  \\\n    ::memset(&first, 0, n);                                \\\n  } while (0)\n\n  if (_has_bits_[0 / 32] & 31) {\n    ZR_(msg_idx_, part_idx_);\n    part_max_ = 0u;\n    if (has_msg_name()) {\n      if (msg_name_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n        msg_name_->clear();\n      }\n    }\n    if (has_msg_body()) {\n      if (msg_body_ != &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {\n        msg_body_->clear();\n      }\n    }\n  }\n\n#undef OFFSET_OF_FIELD_\n#undef ZR_\n\n  ::memset(_has_bits_, 0, sizeof(_has_bits_));\n  mutable_unknown_fields()->Clear();\n}\n\nbool MsgPart::MergePartialFromCodedStream(\n    ::google::protobuf::io::CodedInputStream* input) {\n#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n  ::google::protobuf::uint32 tag;\n  // @@protoc_insertion_point(parse_start:MsgPart)\n  for (;;) {\n    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);\n    tag = p.first;\n    if (!p.second) goto handle_unusual;\n    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {\n      // optional uint32 msg_idx = 1;\n      case 1: {\n        if (tag == 8) {\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &msg_idx_)));\n          set_has_msg_idx();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(16)) goto parse_part_idx;\n        break;\n      }\n\n      // optional uint32 part_idx = 2;\n      case 2: {\n        if (tag == 16) {\n         parse_part_idx:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &part_idx_)));\n          set_has_part_idx();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(24)) goto parse_part_max;\n        break;\n      }\n\n      // optional uint32 part_max = 3;\n      case 3: {\n        if (tag == 24) {\n         parse_part_max:\n          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(\n                 input, &part_max_)));\n          set_has_part_max();\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(34)) goto parse_msg_name;\n        break;\n      }\n\n      // optional string msg_name = 4;\n      case 4: {\n        if (tag == 34) {\n         parse_msg_name:\n          DO_(::google::protobuf::internal::WireFormatLite::ReadString(\n                input, this->mutable_msg_name()));\n          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n            this->msg_name().data(), this->msg_name().length(),\n            ::google::protobuf::internal::WireFormat::PARSE,\n            \"msg_name\");\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectTag(42)) goto parse_msg_body;\n        break;\n      }\n\n      // optional bytes msg_body = 5;\n      case 5: {\n        if (tag == 42) {\n         parse_msg_body:\n          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(\n                input, this->mutable_msg_body()));\n        } else {\n          goto handle_unusual;\n        }\n        if (input->ExpectAtEnd()) goto success;\n        break;\n      }\n\n      default: {\n      handle_unusual:\n        if (tag == 0 ||\n            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {\n          goto success;\n        }\n        DO_(::google::protobuf::internal::WireFormat::SkipField(\n              input, tag, mutable_unknown_fields()));\n        break;\n      }\n    }\n  }\nsuccess:\n  // @@protoc_insertion_point(parse_success:MsgPart)\n  return true;\nfailure:\n  // @@protoc_insertion_point(parse_failure:MsgPart)\n  return false;\n#undef DO_\n}\n\nvoid MsgPart::SerializeWithCachedSizes(\n    ::google::protobuf::io::CodedOutputStream* output) const {\n  // @@protoc_insertion_point(serialize_start:MsgPart)\n  // optional uint32 msg_idx = 1;\n  if (has_msg_idx()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->msg_idx(), output);\n  }\n\n  // optional uint32 part_idx = 2;\n  if (has_part_idx()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->part_idx(), output);\n  }\n\n  // optional uint32 part_max = 3;\n  if (has_part_max()) {\n    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->part_max(), output);\n  }\n\n  // optional string msg_name = 4;\n  if (has_msg_name()) {\n    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n      this->msg_name().data(), this->msg_name().length(),\n      ::google::protobuf::internal::WireFormat::SERIALIZE,\n      \"msg_name\");\n    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(\n      4, this->msg_name(), output);\n  }\n\n  // optional bytes msg_body = 5;\n  if (has_msg_body()) {\n    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(\n      5, this->msg_body(), output);\n  }\n\n  if (!unknown_fields().empty()) {\n    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n        unknown_fields(), output);\n  }\n  // @@protoc_insertion_point(serialize_end:MsgPart)\n}\n\n::google::protobuf::uint8* MsgPart::SerializeWithCachedSizesToArray(\n    ::google::protobuf::uint8* target) const {\n  // @@protoc_insertion_point(serialize_to_array_start:MsgPart)\n  // optional uint32 msg_idx = 1;\n  if (has_msg_idx()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->msg_idx(), target);\n  }\n\n  // optional uint32 part_idx = 2;\n  if (has_part_idx()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->part_idx(), target);\n  }\n\n  // optional uint32 part_max = 3;\n  if (has_part_max()) {\n    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->part_max(), target);\n  }\n\n  // optional string msg_name = 4;\n  if (has_msg_name()) {\n    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n      this->msg_name().data(), this->msg_name().length(),\n      ::google::protobuf::internal::WireFormat::SERIALIZE,\n      \"msg_name\");\n    target =\n      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(\n        4, this->msg_name(), target);\n  }\n\n  // optional bytes msg_body = 5;\n  if (has_msg_body()) {\n    target =\n      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(\n        5, this->msg_body(), target);\n  }\n\n  if (!unknown_fields().empty()) {\n    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n        unknown_fields(), target);\n  }\n  // @@protoc_insertion_point(serialize_to_array_end:MsgPart)\n  return target;\n}\n\nint MsgPart::ByteSize() const {\n  int total_size = 0;\n\n  if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    // optional uint32 msg_idx = 1;\n    if (has_msg_idx()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->msg_idx());\n    }\n\n    // optional uint32 part_idx = 2;\n    if (has_part_idx()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->part_idx());\n    }\n\n    // optional uint32 part_max = 3;\n    if (has_part_max()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::UInt32Size(\n          this->part_max());\n    }\n\n    // optional string msg_name = 4;\n    if (has_msg_name()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::StringSize(\n          this->msg_name());\n    }\n\n    // optional bytes msg_body = 5;\n    if (has_msg_body()) {\n      total_size += 1 +\n        ::google::protobuf::internal::WireFormatLite::BytesSize(\n          this->msg_body());\n    }\n\n  }\n  if (!unknown_fields().empty()) {\n    total_size +=\n      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n        unknown_fields());\n  }\n  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n  _cached_size_ = total_size;\n  GOOGLE_SAFE_CONCURRENT_WRITES_END();\n  return total_size;\n}\n\nvoid MsgPart::MergeFrom(const ::google::protobuf::Message& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  const MsgPart* source =\n    ::google::protobuf::internal::dynamic_cast_if_available<const MsgPart*>(\n      &from);\n  if (source == NULL) {\n    ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n  } else {\n    MergeFrom(*source);\n  }\n}\n\nvoid MsgPart::MergeFrom(const MsgPart& from) {\n  GOOGLE_CHECK_NE(&from, this);\n  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {\n    if (from.has_msg_idx()) {\n      set_msg_idx(from.msg_idx());\n    }\n    if (from.has_part_idx()) {\n      set_part_idx(from.part_idx());\n    }\n    if (from.has_part_max()) {\n      set_part_max(from.part_max());\n    }\n    if (from.has_msg_name()) {\n      set_msg_name(from.msg_name());\n    }\n    if (from.has_msg_body()) {\n      set_msg_body(from.msg_body());\n    }\n  }\n  mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n}\n\nvoid MsgPart::CopyFrom(const ::google::protobuf::Message& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nvoid MsgPart::CopyFrom(const MsgPart& from) {\n  if (&from == this) return;\n  Clear();\n  MergeFrom(from);\n}\n\nbool MsgPart::IsInitialized() const {\n\n  return true;\n}\n\nvoid MsgPart::Swap(MsgPart* other) {\n  if (other != this) {\n    std::swap(msg_idx_, other->msg_idx_);\n    std::swap(part_idx_, other->part_idx_);\n    std::swap(part_max_, other->part_max_);\n    std::swap(msg_name_, other->msg_name_);\n    std::swap(msg_body_, other->msg_body_);\n    std::swap(_has_bits_[0], other->_has_bits_[0]);\n    _unknown_fields_.Swap(&other->_unknown_fields_);\n    std::swap(_cached_size_, other->_cached_size_);\n  }\n}\n\n::google::protobuf::Metadata MsgPart::GetMetadata() const {\n  protobuf_AssignDescriptorsOnce();\n  ::google::protobuf::Metadata metadata;\n  metadata.descriptor = MsgPart_descriptor_;\n  metadata.reflection = MsgPart_reflection_;\n  return metadata;\n}\n\n\n// @@protoc_insertion_point(namespace_scope)\n\n// @@protoc_insertion_point(global_scope)\n"
  },
  {
    "path": "code/nel/src/net/dummy_tcp_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/dummy_tcp_sock.h\"\n#include \"nel/net/net_log.h\"\n\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\n\n/*\n * Set only the remote address\n */\nvoid CDummyTcpSock::connect( const CInetAddress& addr )\n{\n\t_RemoteAddr = addr;\n\t_Sock = 100;\n\n\t_BytesReceived = 0;\n\t_BytesSent = 0;\n\n\t//CSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t//sync.value() = true;\n\t_Connected = true;\n\n\tLNETL0_DEBUG( \"LNETL0: Socket connected to %s\", addr.asString().c_str() );\n}\n\n\n/*\n *Dummy disconnection\n */\nvoid CDummyTcpSock::disconnect()\n{\n\tLNETL0_DEBUG( \"LNETL0: Socket disconnecting from %s...\", _RemoteAddr.asString().c_str() );\n\n\t//CSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t//sync.value() = false;\n\t_Connected = false;\n}\n\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/email.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/report.h\"\n#include \"nel/misc/path.h\"\n\n#include \"nel/net/tcp_sock.h\"\n#include \"nel/net/email.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\nstatic string DefaultSMTPServer, DefaultFrom, DefaultTo;\n\n/* Conversion table.  for base 64 */\nstatic char tbl[65] = {\n\t'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',\n\t'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\n\t'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',\n\t'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',\n\t'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',\n\t'o', 'p', 'q', 'r', 's', 't', 'u', 'v',\n\t'w', 'x', 'y', 'z', '0', '1', '2', '3',\n\t'4', '5', '6', '7', '8', '9', '+', '/',\n\t'=' /* termination character */\n};\n\n/*\n * Encode the string S of length LENGTH to base64 format and place it\n * to STORE.  STORE will be 0-terminated, and must point to a writable\n * buffer of at least 1+BASE64_LENGTH(length) bytes.\n * where BASE64_LENGTH(len) = (4 * ((LENGTH + 2) / 3))\n */\nstatic void uuencode (const char *s, const char *store, const int length)\n{\n\tint i;\n\tunsigned char *p = (unsigned char *)store;\n\tunsigned char *us = (unsigned char *)s;\n\n\t/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */\n\tfor (i = 0; i < length; i += 3)\n\t{\n\t\t*p++ = tbl[us[0] >> 2];\n\t\t*p++ = tbl[((us[0] & 3) << 4) + (us[1] >> 4)];\n\t\t*p++ = tbl[((us[1] & 0xf) << 2) + (us[2] >> 6)];\n\t\t*p++ = tbl[us[2] & 0x3f];\n\t\tus += 3;\n\t}\n\t/* Pad the result if necessary...  */\n\tif (i == length + 1)\n\t{\n\t\t*(p - 1) = tbl[64];\n\t}\n\telse if (i == length + 2)\n\t{\n\t\t*(p - 1) = *(p - 2) = tbl[64];\n\t}\n\t/* ...and zero-terminate it.  */\n\t*p = '\\0';\n}\n\nbool sendEMailCommand (CTcpSock &sock, const std::string &command, uint32 code = 250)\n{\n\tstring buffer = command + \"\\r\\n\";\n\tuint32 size = (uint32)buffer.size();\n\tif(!command.empty())\n\t{\n\t\tif (sock.send ((uint8 *)buffer.c_str(), size) != CSock::Ok)\n\t\t{\n\t\t\tnlwarning (\"EMAIL: Can't send data to the server\");\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tstring res;\n\tchar c;\n\tfor(;;)\n\t{\n\t\tsize = 1;\n\n\t\tif (sock.receive((uint8*)&c, size, false) == CSock::Ok)\n\t\t{\n\t\t\tres += c;\n\t\t\tif (c == '\\n')\n\t\t\t{\n\t\t\t\tuint32 c;\n\t\t\t\tfromString(res, c);\n\t\t\t\tif (c != code)\n\t\t\t\t{\n\t\t\t\t\tnlwarning (\"EMAIL: EMail command '%s' returned '%s' instead of code %d on sock %s\", command.substr(0, 20).c_str(), res.substr(0, res.size()-2).c_str(), code, sock.remoteAddr().asString().c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"EMAIL: EMail connection closed before end of line, command '%s' returned '%s' on sock %s (code %d)\", command.substr(0, 20).c_str(), res.c_str(), sock.remoteAddr().asString().c_str(), code);\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\n\nbool sendEmail (const string &smtpServer, const string &from, const string &to, const string &subject, const string &body, const string &attachedFile, bool onlyCheck)\n{\n\tbool ok  = false;\n\tCTcpSock sock;\n\tuint i;\n\n\tstring formatedBody;\n\tstring formatedFrom;\n\tstring formatedTo;\n\tstring formatedSMTPServer;\n\n\ttry\n\t{\n\n\t\tif (smtpServer.empty())\n\t\t{\n\t\t\tif(DefaultSMTPServer.empty())\n\t\t\t{\n\t\t\t\tnlwarning (\"EMAIL: Can't send email because no SMTPServer was provided\");\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatedSMTPServer = DefaultSMTPServer;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tformatedSMTPServer = smtpServer;\n\t\t}\n\n\t\tsock.connect(CInetAddress(formatedSMTPServer, 25));\n\n\t\tif (!sock.connected())\n\t\t{\n\t\t\tnlwarning (\"EMAIL: Can't connect to email server %s\", formatedSMTPServer.c_str());\n\t\t\tgoto end;\n\t\t}\n\n\t\tif (to.empty())\n\t\t{\n\t\t\tif(DefaultTo.empty())\n\t\t\t{\n\t\t\t\tnlwarning (\"EMAIL: Can't send email because no To was provided\");\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatedTo = DefaultTo;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tformatedTo = to;\n\t\t}\n\n\t\tif(from.empty())\n\t\t{\n\t\t\tif (DefaultFrom.empty())\n\t\t\t{\n\t\t\t\tformatedFrom = CInetAddress::localHost().hostName();\n\t\t\t\tformatedFrom += \"@gnu.org\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatedFrom = DefaultFrom;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tformatedFrom = from;\n\t\t}\n\n\t\t// we must skip the first line\n\t\tformatedBody = \"\\r\\n\";\n\n\t\t// replace \\n with \\r\\n\n\t\tfor (i = 0; i < body.size(); i++)\n\t\t{\n\t\t\tif (body[i] == '\\n' && i > 0 && body[i-1] != '\\r')\n\t\t\t{\n\t\t\t\tformatedBody += '\\r';\n\t\t\t}\n\t\t\tformatedBody += body[i];\n\t\t}\n\n\t\t// add attachment if any\n\t\tif (!attachedFile.empty())\n\t\t{\n\t\t\tstring ext = CFile::getExtension(attachedFile);\n\n\t\t\tstring mimepart;\n\n\t\t\t// mime header and main mail text\n\n\t\t\tmimepart += \"Mime-Version: 1.0\\r\\n\";\n\t\t\tmimepart += \"Content-Type: multipart/mixed;\\r\\n\";\n\t\t\tmimepart += \" boundary=\\\"Multipart_nel\\\"\\r\\n\";\n\t\t\tmimepart += \"\\r\\n\";\n\t\t\tmimepart += \"This is a multi-part message in MIME format.\\r\\n\";\n\t\t\tmimepart += \"\\r\\n\";\n\t\t\tmimepart += \"--Multipart_nel\\r\\n\";\n\t\t\tmimepart += \"Content-Type: text/plain; charset=us-ascii\\r\\n\";\n\t\t\tmimepart += \"Content-Transfer-Encoding: 7bit\\r\\n\";\n\n\t\t\tformatedBody = mimepart + formatedBody;\n\n\t\t\t// mime attachment\n\n\t\t\tformatedBody += \"--Multipart_nel\\r\\n\";\n\t\t\tformatedBody += \"Content-Disposition: attachment;\\r\\n\";\n\n\t\t\tstring lext = toLower(ext);\n\t\t\tif(lext == \"tga\")\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: image/x-targa;\\r\\n\";\n\t\t\t}\n\t\t\telse if(lext == \"bmp\")\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: image/bmp;\\r\\n\";\n\t\t\t}\n\t\t\telse if(lext == \"png\")\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: image/png;\\r\\n\";\n\t\t\t}\n\t\t\telse if(lext == \"jpg\" || lext == \"jpeg\")\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: image/jpeg;\\r\\n\";\n\t\t\t}\n\t\t\telse if(lext == \"dmp\")\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: application/octet-stream;\\r\\n\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tformatedBody += \"Content-Type: text/plain; charset=us-ascii\\r\\n\";\n\t\t\t}\n\n\t\t\tformatedBody += \" name=\\\"\"+CFile::getFilename(attachedFile)+\"\\\"\\r\\n\";\n\t\t\tformatedBody += \"Content-Transfer-Encoding: base64\\r\\n\";\n\t\t\tformatedBody += \" filename=\\\"\"+CFile::getFilename(attachedFile)+\"\\\"\\r\\n\";\n\t\t\t// empty line to say that it s the end of the header\n\t\t\tformatedBody += \"\\r\\n\";\n\n\t\t\tstatic const size_t src_buf_size = 45;// This *MUST* be a multiple of 3\n\t\t\tstatic const size_t dst_buf_size = 4 * ((src_buf_size + 2) / 3);\n\t\t\tsize_t write_size = dst_buf_size;\n\t\t\tchar src_buf[src_buf_size + 1];\n\t\t\tchar dst_buf[dst_buf_size + 1];\n\t\t\tsize_t size;\n\n\t\t\tFILE *src_stream = fopen (attachedFile.c_str(), \"rb\");\n\t\t\tif (src_stream == NULL)\n\t\t\t{\n\t\t\t\tnlwarning (\"EMAIL: Can't attach file '%s' to the email because the file can't be open\", attachedFile.c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\twhile ((size = fread(src_buf, 1, src_buf_size, src_stream)) > 0)\n\t\t\t\t{\n\t\t\t\t\tif (size != src_buf_size)\n\t\t\t\t\t{\n\t\t\t\t\t\t/* write_size is always 60 until the last line */\n\t\t\t\t\t\twrite_size=(4 * ((size + 2) / 3));\n\t\t\t\t\t\t/* pad with 0s so we can just encode extra bits */\n\t\t\t\t\t\tmemset(&src_buf[size], 0, src_buf_size - size);\n\t\t\t\t\t}\n\t\t\t\t\t/* Encode the buffer we just read in */\n\t\t\t\t\tuuencode(src_buf, dst_buf, (int)size);\n\n\t\t\t\t\tformatedBody += dst_buf;\n\t\t\t\t\tformatedBody += \"\\r\\n\";\n\t\t\t\t}\n\t\t\t\tfclose (src_stream);\n\t\t\t}\n\t\t\tformatedBody += \"--Multipart_nel--\";\n\t\t}\n\n\t\t// debug, display what we send into a file\n\t\t//\t{\tFILE *fp = fopen (CFile::findNewFile(getLogDirectory() + \"mail.txt\").c_str(), \"wb\");\n\t\t//\tfwrite (formatedBody.c_str(), 1, formatedBody.size(), fp);\n\t\t//\tfclose (fp); }\n\n\t\tif(!sendEMailCommand (sock, \"\", 220)) goto end;\n\n\t\tif(onlyCheck)\n\t\t{\n\t\t\tif(!sendEMailCommand (sock, \"HELO localhost\")) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"MAIL FROM: \" + formatedFrom)) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"RCPT TO: \" + formatedTo)) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"QUIT\", 221)) goto end;\n\n\t\t\tok = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif(!sendEMailCommand (sock, \"HELO localhost\")) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"MAIL FROM: \" + formatedFrom)) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"RCPT TO: \" + formatedTo)) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"DATA\", 354)) goto end;\n\n\t\t\tstring buffer =\n\t\t\t\t\"From: \" + formatedFrom + \"\\r\\n\"\n\t\t\t\t\"To: \" + formatedTo + \"\\r\\n\"\n\t\t\t\t\"Subject: \" + subject + \"\\r\\n\"\n\t\t\t\t+ formatedBody + \"\\r\\n.\";\n\n\t\t\tif(!sendEMailCommand (sock, buffer)) goto end;\n\t\t\tif(!sendEMailCommand (sock, \"QUIT\", 221)) goto end;\n\n\t\t\tok = true;\n\t\t}\n\t}\n\tcatch (const Exception &e)\n\t{\n\t\tnlwarning (\"EMAIL: Can't send email: %s\", e.what());\n\t\tgoto end;\n\t}\n\nend:\n\tif (sock.connected())\n\t\tsock.close ();\n\n\treturn ok;\n}\n\nvoid setDefaultEmailParams (const std::string &smtpServer, const std::string &from, const std::string &to)\n{\n\tDefaultSMTPServer = smtpServer;\n\tDefaultFrom = from;\n\tDefaultTo = to;\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/inet_address.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/common.h\"\n\n#include \"nel/net/inet_address.h\"\n#include \"nel/net/sock.h\"\n#include \"nel/net/net_log.h\"\n\n\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <winsock2.h>\n#\tinclude <ws2tcpip.h>\n// for Windows 2000 compatibility\n#\tinclude <wspiapi.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <sys/socket.h>\n#\tinclude <arpa/inet.h>\n#\tinclude <netinet/in.h>\n#\tinclude <netdb.h>\n#\tdefine WSAGetLastError() 0\n#\tdefine SOCKET_ERROR -1\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\n\n#ifndef NI_MAXHOST\n#\tdefine NI_MAXHOST 1025\n#endif\n\nnamespace NLNET\n{\n\nbool CInetAddress::RetrieveNames = false;\n\n\n/*\n * Constructor\n */\nCInetAddress::CInetAddress()\n{\n\tinit();\n\t_SockAddr->sin_port = 0; // same as htons(0)\n\tmemset( &_SockAddr->sin_addr, 0, sizeof(in_addr) ); // same as htonl(INADDR_ANY)\n}\n\n\n/*\n * Constructor with ip address, port=0\n */\nCInetAddress::CInetAddress( const in_addr *ip, const char *hostname )\n{\n\tinit();\n\t_SockAddr->sin_port = 0;\n\tmemcpy( &_SockAddr->sin_addr, ip, sizeof(in_addr) );\n\n\t// get the host name to be displayed\n\tif(hostname)\n\t{\n\t\t_HostName = hostname;\n\t}\n\telse\n\t{\n\t\tupdateHostName();\n\t}\n\t_Valid = true;\n}\n\n\n/*\n * Update _HostName from _SockAddr current value \n */\nvoid CInetAddress::updateHostName()\n{\n\tchar host[NI_MAXHOST];\n\n\tsint status = getnameinfo((struct sockaddr *) _SockAddr, sizeof (struct sockaddr), host, NI_MAXHOST, NULL, 0, NI_NUMERICSERV);\n\n\tif ( status )\n\t{\n\t\t_HostName = ipAddress();\n\t}\n\telse\n\t{\n\t\t_HostName = string( host );\n\t}\n}\n\n\n/*\n * Alternate constructor (calls setByName())\n */\nCInetAddress::CInetAddress( const std::string& hostName, uint16 port )\n{\n\tinit();\n\tsetPort( port );\n\tsetByName( hostName );\n}\n\n\n/*\n * Alternate constructor (calls setNameAndPort())\n */\nCInetAddress::CInetAddress( const std::string& hostNameAndPort )\n{\n\tinit();\n\tsetNameAndPort( hostNameAndPort );\n}\n\n\n/*\n * Copy constructor\n */\nCInetAddress::CInetAddress( const CInetAddress& other )\n{\n\tinit();\n\t_HostName = other._HostName;\n\tmemcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );\n\t_Valid = other._Valid;\n}\n\n\n/*\n * Assignment operator\n */\nCInetAddress& CInetAddress::operator=( const CInetAddress& other )\n{\n\t_HostName = other._HostName;\n\tmemcpy( _SockAddr, other._SockAddr, sizeof( *_SockAddr ) );\n\t_Valid = other._Valid;\n\treturn *this;\n}\n\n\n/*\n * Comparison == operator\n */\nbool operator==( const CInetAddress& a1, const CInetAddress& a2 )\n{\n\t// Compares the sockaddr structure except the last 8 bytes equal to zero.\n\treturn ( memcmp( a1._SockAddr, a2._SockAddr, sizeof(sockaddr_in)-8 ) == 0 );\n}\n\n\n/*\n * Comparison < operator\n */\nbool operator<( const CInetAddress& a1, const CInetAddress& a2 )\n{\n\tif ( a1._SockAddr->sin_addr.s_addr == a2._SockAddr->sin_addr.s_addr )\n\t{\n\t\treturn ( a1.port() < a2.port() );\n\t}\n\telse\n\t{\n\t\treturn ( a1._SockAddr->sin_addr.s_addr < a2._SockAddr->sin_addr.s_addr );\n\t}\n}\n\n\n/*\n * Constructor contents\n */\nvoid CInetAddress::init()\n{\n\tCSock::initNetwork();\n\n\t_Valid = false;\n\n\t_SockAddr = new sockaddr_in;\n\n#ifdef NL_OS_FREEBSD\n    bzero(_SockAddr,sizeof(sockaddr_in));\n#endif\n\n\t_SockAddr->sin_family = AF_INET;\n\tmemset( _SockAddr->sin_zero, 0, 8 );\n}\n\n\n/*\n * Destructor\n */\nCInetAddress::~CInetAddress()\n{\n\tdelete _SockAddr;\n    _SockAddr = NULL;\n\t_Valid = false;\n}\n\n/*\n * Sets hostname and port (ex: www.nevrax.com:80)\n */\nvoid CInetAddress::setNameAndPort( const std::string& hostNameAndPort )\n{\n\tstring::size_type pos = hostNameAndPort.find_first_of (':');\n\tif (pos != string::npos)\n\t{\n\t\tuint16 port;\n\t\tfromString(hostNameAndPort.substr(pos + 1), port);\n\t\tsetPort( port );\n\t}\n\telse\n\t{\n\t\tsetPort( 0 );\n\t}\n\n\t// if pos == -1, it will copy all the string\n\tsetByName( hostNameAndPort.substr (0, pos) );\n}\n\n\n/*\n * Resolves a name\n */\nCInetAddress& CInetAddress::setByName( const std::string& hostName )\n{\n\t// Try to convert directly for addresses such as a.b.c.d\n\tin_addr iaddr;\n\tiaddr.s_addr = inet_addr( hostName.c_str() );\n\tif ( iaddr.s_addr == INADDR_NONE )\n\t{\n\t\t// Otherwise use the traditional DNS look-up\n\t\tstruct addrinfo hints;\n\t\tmemset(&hints, 0, sizeof(hints));\n\t\thints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version\n\t\thints.ai_socktype = SOCK_STREAM;\n\n\t\tstruct addrinfo *res = NULL;\n\t\tsint status = getaddrinfo(hostName.c_str(), NULL, &hints, &res);\n\n\t\tif (status)\n\t\t{\n\t\t\t_Valid = false;\n\t\t\tLNETL0_DEBUG( \"LNETL0: Network error: resolution of hostname '%s' failed: %s\", hostName.c_str(), gai_strerror(status) );\n\t\t\t// return *this;\n\t\t\tthrow ESocket( (string(\"Hostname resolution failed for \")+hostName).c_str() );\n\t\t}\n\n\t\tstruct addrinfo *p = res;\n\n\t\t// process all addresses\n\t\twhile (p != NULL)\n\t\t{\n\t\t\t// check address family\n\t\t\tif (p->ai_family == AF_INET)\n\t\t\t{\n\t\t\t\t// ipv4\n\t\t\t\tstruct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;\n\n\t\t\t\t// convert the IP to a string\n\t\t\t\t_HostName = string(inet_ntoa(ipv4->sin_addr));\n\t\t\t\tmemcpy( &_SockAddr->sin_addr, &ipv4->sin_addr, sizeof(in_addr) );\n\t\t\t}\n\t\t\telse if (p->ai_family == AF_INET6)\n\t\t\t{\n\t\t\t\t// ipv6\n\t\t\t\t// TODO: modify class to be able to handle IPv6\n\n\t\t\t\t// struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;\n\n\t\t\t\t// convert the IP to a string\n\t\t\t\t// inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));\n\t\t\t\t// memcpy( &_SockAddr->sin_addr, &ipv6->sin_addr, sizeof(in_addr) );\n\t\t\t}\n\n\t\t\t// process next address\n\t\t\tp = p->ai_next;\n\t\t}\n \n\t\t// free the linked list\n\t\tfreeaddrinfo(res);\n\t}\n\telse\n\t{\n\t\t_HostName = hostName;\n\t\tmemcpy( &_SockAddr->sin_addr, &iaddr, sizeof(iaddr) );\n\t}\n\t_Valid = true;\n\treturn *this;\n}\n\n\n/*\n * Sets port\n */\nvoid CInetAddress::setPort( uint16 port )\n{\n\t_SockAddr->sin_port = htons( port );\n\n}\n\n\n/* Sets internal socket address directly (contents is copied).\n * It also retrieves the host name if CInetAddress::RetrieveNames is true.\n */\nvoid CInetAddress::setSockAddr( const sockaddr_in* saddr )\n{\n\tmemcpy( _SockAddr, saddr, sizeof(*saddr) );\n\n\t// Get host name\n\t// Warning: when it can't find it, it take more than 4 seconds\n\tif ( CInetAddress::RetrieveNames )\n\t{\n\t\tupdateHostName();\n\t}\n\t_Valid = true;\n}\n\n\n/*\n * Returns if object (address and port) is valid\n */\nbool CInetAddress::isValid() const\n{\n\treturn ( _Valid && _SockAddr->sin_port!=0 ); // same as ntohs(0)\n}\n\n\n/*\n * Returns internal socket address (read only)\n */\nconst sockaddr_in *CInetAddress::sockAddr() const\n{\n\treturn _SockAddr;\n}\n\n\n/*\n * Returns internal IP address\n */\nuint32 CInetAddress::internalIPAddress() const\n{\n\treturn _SockAddr->sin_addr.s_addr;\n}\n\nuint32 CInetAddress::internalNetAddress() const\n{\n\tuint32 ip = internalIPAddress();\n\tif ((ip&0x00000080) == 0)\n\t{\n\t\t// A class\n\t\treturn ip & 0x000000FF;\n\t}\n\telse if ((ip&0x00000040) == 0)\n\t{\n\t\t// B class\n\t\treturn ip & 0x0000FFFF;\n\t}\n\telse if ((ip&0x00000020) == 0)\n\t{\n\t\t// C class\n\t\treturn ip & 0x00FFFFFF;\n\t}\n\telse if ((ip&0x00000010) == 0)\n\t{\n\t\t// D class\n\t\treturn ip & 0xFFFFFFFF;\n\t}\n\telse\n\t{\n\t\treturn ip;\n\t}\n}\n\n\n\n\n/*\n * Returns readable IP address. (ex: \"195.68.21.195\")\n */\nstring CInetAddress::ipAddress() const\n{\n\t/*stringstream ss; // or use inet_ntoa\n\tss << inet_ntoa ( _SockAddr->sin_addr );\n\treturn ss.str();*/\n\tconst char *name = inet_ntoa ( _SockAddr->sin_addr );\n\treturn name ? string (name) : \"\";\n}\n\n\n/*\n * Returns host name. (ex: \"www.nevrax.org\")\n */\nconst string& CInetAddress::hostName() const\n{\n\treturn _HostName;\n}\n\n\n/*\n * Returns port\n */\nuint16 CInetAddress::port() const\n{\n\treturn ntohs( _SockAddr->sin_port );\n}\n\n\n/*\n * Returns hostname and port as a string. (ex: \"www.nevrax.org:80 (195.68.21.195)\")\n */\nstd::string CInetAddress::asString() const\n{\n//\tstringstream ss;\n//\tss << hostName() << \":\" << port() << \" (\" << ipAddress() << \")\";\n//\treturn ss.str();\n\treturn hostName() + \":\" + NLMISC::toString(port()) + \" (\" + ipAddress() + \")\";\n}\n\n\n/*\n * Returns IP address and port as a string. (ex: \"195.68.21.195:80\")\n */\nstd::string CInetAddress::asIPString() const\n{\n//\tstringstream ss;\n//\tss << ipAddress() << \":\" << port();\n//\treturn ss.str();\n\treturn ipAddress() + \":\" + NLMISC::toString(port());\n}\n\n\n/*\n * Serialize\n */\nvoid CInetAddress::serial( NLMISC::IStream& s )\n{\n\tNLMISC::CMemStream *ms = dynamic_cast<NLMISC::CMemStream*>(&s);\n\tif ( ms && ms->stringMode() )\n\t{\n\t\t// String stream\n\t\tstring addrs;\n\t\tif ( ms->isReading() )\n\t\t{\n\t\t\tms->serial( addrs );\n\t\t\tsetNameAndPort( addrs );\n\t\t}\n\t\telse\n\t\t{\n\t\t\taddrs = asIPString();\n\t\t\tms->serial( addrs );\n\t\t}\n\t\ts.serial( _Valid );\n\t}\n\telse\n\t{\n\t\t// Binary stream\n\t\ts.serialBuffer( (uint8*)_SockAddr, sizeof(*_SockAddr) ); // this is possible only because the contents of _SockAddr is platform-independant !\n\t\ts.serial( _Valid );\n\n\t\tif(_Valid)\n\t\t{\n\t\t\t// retreive the fullname\n\t\t\tsetSockAddr (_SockAddr);\n\t\t}\n\n\t}\n}\n\n\n/*\n * Creates a CInetAddress object with local host address, port=0\n */\nCInetAddress CInetAddress::localHost()\n{\n\tconst uint maxlength = 80;\n\tchar localhost [maxlength];\n\tif ( gethostname( localhost, maxlength ) != 0 )\n\t\tthrow ESocket( \"Unable to get local hostname\" );\n\tCInetAddress localaddr = CInetAddress( string(localhost) );\n\n\tif ( localaddr.ipAddress() == \"127.0.0.1\" )\n\t{\n\t\tnlwarning (\"LNETL0: No network card detected! using localhost (127.0.0.1)\");\n\t}\n\n\treturn localaddr;\n}\n\n\n/* Returns the list of the local host addresses (with port=0)\n * (especially useful if the host is multihomed)\n */\nstd::vector<CInetAddress> CInetAddress::localAddresses()\n{\n\t// 1. Get local host name\n\tconst uint maxlength = 80;\n\tchar localhost [maxlength];\n\tif ( gethostname( localhost, maxlength ) == SOCKET_ERROR )\n\t{\n\t\tthrow ESocket( \"Unable to get local hostname\" );\n\t}\n\n\t// 2. Get address list\n\tvector<CInetAddress> vect;\n\n\tstruct addrinfo hints;\n\tmemset(&hints, 0, sizeof(hints));\n\thints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version\n\thints.ai_socktype = SOCK_STREAM;\n\n\tstruct addrinfo *res = NULL;\n\tsint status = getaddrinfo(localhost, NULL, &hints, &res);\n\n\tif (status)\n\t{\n\t\t// will come here if the local hostname (/etc/hostname in Linux) is not the real name\n\t\tthrow ESocket( (string(\"Hostname resolution failed for \")+string(localhost)).c_str() );\n\t}\n\n\tstruct addrinfo *p = res;\n\n\t// process all addresses\n\twhile (p != NULL)\n\t{\n\t\t// check address family\n\t\tif (p->ai_family == AF_INET)\n\t\t{\n\t\t\t// ipv4\n\t\t\tstruct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;\n\n\t\t\tvect.push_back( CInetAddress( &ipv4->sin_addr, localhost ) );\n\t\t}\n\t\telse if (p->ai_family == AF_INET6)\n\t\t{\n\t\t\t// ipv6\n\t\t\t// TODO: modify class to be able to handle IPv6\n\n\t\t\t// struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;\n\n\t\t\t// convert the IP to a string\n\t\t\t// inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));\n\t\t\t// memcpy( &_SockAddr->sin_addr, &ipv6->sin_addr, sizeof(in_addr) );\n\t\t}\n\n\t\t// process next address\n\t\tp = p->ai_next;\n\t}\n\n\t// free the linked list\n\tfreeaddrinfo(res);\n\n\tif(vect.empty())\n\t{\n\t\tthrow ESocket( (string(\"No network card detected for \")+string(localhost)).c_str() );\n\t}\n\n\treturn vect;\n}\n\nbool CInetAddress::is127001 () const\n{\n\treturn (internalIPAddress () == htonl(0x7F000001));\n}\n\n\nstd::string vectorCInetAddressToString(const std::vector<CInetAddress> &addrs)\n{\n\tstring str;\n\n\tfor (uint i = 0; i < addrs.size(); i++)\n\t{\n\t\tif (i != 0)\n\t\t\tstr += \" \";\n\t\tstr += addrs[i].asString().c_str ();\n\t}\n\treturn str;\n}\n\nuint32 stringToInternalIPAddress (const std::string &addr)\n{\n\treturn inet_addr( addr.c_str() );\n}\n\nstd::string internalIPAddressToString (uint32 addr)\n{\n\tstring res;\n\tres = toString((addr)&0xFF);\n\tres += \".\";\n\tres += toString((addr>>8)&0xFF);\n\tres += \".\";\n\tres += toString((addr>>16)&0xFF);\n\tres += \".\";\n\tres += toString((addr>>24)&0xFF);\n\treturn res;\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/listen_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/listen_sock.h\"\n#include \"nel/net/net_log.h\"\n\n\n#ifdef NL_OS_WINDOWS\n\n#ifndef NL_COMP_MINGW\n#\tdefine NOMINMAX\n#endif\n#include <windows.h>\ntypedef sint socklen_t;\n\n#elif defined NL_OS_UNIX\n\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/socket.h>\n#include <sys/ioctl.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n#include <netdb.h>\n#include <cerrno>\n#include <fcntl.h>\n#define SOCKET_ERROR -1\n#define INVALID_SOCKET -1\ntypedef int SOCKET;\n\n#endif\n\n\nusing namespace std;\n\n\nnamespace NLNET\n{\n\n\n/*\n * Constructor\n */\nCListenSock::CListenSock() : CTcpSock(), _Bound( false )\n{\n\t// Create socket\n\tcreateSocket( SOCK_STREAM, IPPROTO_TCP );\n\n\tsetBacklog( -1 );\n}\n\n\n/*\n * Prepares to receive connections on a specified port\n */\nvoid CListenSock::init( uint16 port )\n{\n    // Use any address\n\tCInetAddress localaddr; // By default, INETADDR_ANY (useful for gateways that have several ip addresses)\n\tlocaladdr.setPort( port );\n\tinit( localaddr );\n\n\t// Now set the address visible from outside\n\t_LocalAddr = CInetAddress::localHost();\n\t_LocalAddr.setPort( port );\n\tLNETL0_DEBUG( \"LNETL0: Socket %d listen socket is at %s\", _Sock, _LocalAddr.asString().c_str() );\n}\n\n\n/*\n * Prepares to receive connections on a specified address/port (useful when the host has several addresses)\n */\nvoid CListenSock::init( const CInetAddress& addr )\n{\n\tif ( ! addr.isValid() )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Binding listen socket to any address, port %hu\", addr.port() );\n\t}\n\n#ifndef NL_OS_WINDOWS\n\t// Set Reuse Address On (does not work on Win98 and is useless on Win2000)\n\tint value = true;\n\tif ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )\n\t{\n\t\tthrow ESocket( \"ReuseAddr failed\" );\n\t}\n#endif\n\n\t// Bind socket to port\n\tif ( ::bind( _Sock, (const sockaddr *)addr.sockAddr(), sizeof(sockaddr_in) ) != 0 )\n\t{\n\t\tthrow ESocket( \"Unable to bind listen socket to port\" );\n\t}\n\t_LocalAddr = addr;\n\t_Bound = true;\n\n\t// Listen\n\tif ( ::listen( _Sock, _BackLog ) != 0 ) // SOMAXCONN = maximum length of the queue of pending connections\n\t{\n\t\tthrow ESocket( \"Unable to listen on specified port\" );\n\t}\n//\tLNETL0_DEBUG( \"LNETL0: Socket %d listening at %s\", _Sock, _LocalAddr.asString().c_str() );\n}\n\n\n/*\n * Accepts an incoming connection, and creates a new socket\n */\nCTcpSock *CListenSock::accept()\n{\n\t// Accept connection\n\tsockaddr_in saddr;\n\tsocklen_t saddrlen = (socklen_t)sizeof(saddr);\n\tSOCKET newsock = (SOCKET)::accept( _Sock, (sockaddr*)&saddr, &saddrlen );\n\tif ( newsock == INVALID_SOCKET )\n\t{\n\t\tif (_Sock == INVALID_SOCKET)\n\t\t\t// normal case, the listen sock have been closed, just return NULL.\n\t\t\treturn NULL;\n\n\t  /*LNETL0_INFO( \"LNETL0: Error accepting a connection\");\n\t  // See accept() man on Linux\n\t  newsock = ::accept( _Sock, (sockaddr*)&saddr, &saddrlen );\n\t  if ( newsock == INVALID_SOCKET )*/\n\t    {\n\t\t\tthrow ESocket( \"Accept returned an invalid socket\");\n\t    }\n\t}\n\n\t// Construct and save a CTcpSock object\n\tCInetAddress addr;\n\taddr.setSockAddr( &saddr );\n\tLNETL0_DEBUG( \"LNETL0: Socket %d accepted an incoming connection from %s, opening socket %d\", _Sock, addr.asString().c_str(), newsock );\n\tCTcpSock *connection = new CTcpSock( newsock, addr );\n\treturn connection;\n}\n\n\n/*\n * Sets the number of the pending connections queue. -1 for the maximum possible value.\n */\nvoid CListenSock::setBacklog( sint backlog )\n{\n\tif ( backlog == -1 )\n\t{\n\t\t_BackLog = SOMAXCONN; // SOMAXCONN = maximum length of the queue of pending connections\n\t}\n\telse\n\t{\n\t\t_BackLog = backlog;\n\t}\n\tif ( _Bound )\n\t{\n\t\tif ( ::listen( _Sock, _BackLog ) != 0 )\n\t\t{\n\t\t\tthrow ESocket( \"Unable to listen on specified port, while changing backlog\" );\n\t\t}\n\t}\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/login_client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/system_info.h\"\n\n#include \"nel/net/callback_client.h\"\n\n#include \"nel/net/login_cookie.h\"\n#include \"nel/net/login_client.h\"\n\n#include \"nel/net/udp_sock.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\nCLoginClient::TShardList CLoginClient::ShardList;\nCCallbackClient *CLoginClient::_LSCallbackClient;\n\n\n//\n// CALLBACK FROM THE FS (Front-end Service)\n//\n\n// Callback for answer of the request shard\nstatic bool ShardValidate;\nstatic string ShardValidateReason;\nstatic void cbShardValidate (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t//\n\t// S14: receive \"SV\" message from FES\n\t//\n\n\tmsgin.serial (ShardValidateReason);\n\tShardValidate = true;\n}\n\nstatic TCallbackItem FESCallbackArray[] =\n{\n\t{ \"SV\", cbShardValidate },\n};\n\n//\n// CALLBACK FROM THE LS (Login Service)\n//\n\n// Callback for answer of the login password.\nstatic bool VerifyLoginPassword;\nstatic string VerifyLoginPasswordReason;\nstatic void cbVerifyLoginPassword (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t//\n\t// S04: receive the \"VLP\" message from LS\n\t//\n\n\tmsgin.serial (VerifyLoginPasswordReason);\n\tif(VerifyLoginPasswordReason.empty())\n\t{\n\t\tuint32 nbshard;\n\t\tmsgin.serial (nbshard);\n\n\t\tCLoginClient::ShardList.clear ();\n\t\tVerifyLoginPasswordReason.clear();\n\n\t\t// get the shard list\n\t\tfor (uint i = 0; i < nbshard; i++)\n\t\t{\n\t\t\tCLoginClient::CShardEntry se;\n\t\t\tmsgin.serial (se.Name, se.NbPlayers, se.Id);\n\t\t\tCLoginClient::ShardList.push_back (se);\n\t\t}\t\t\n\t}\n\tVerifyLoginPassword = true;\n}\n\n// Callback for answer of the request shard\nstatic bool ShardChooseShard;\nstatic string ShardChooseShardReason;\nstatic string ShardChooseShardAddr;\nstatic string ShardChooseShardCookie;\nstatic void cbShardChooseShard (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t//\n\t// S11: receive \"SCS\" message from LS\n\t//\n\n\tmsgin.serial (ShardChooseShardReason);\n\n\tif (ShardChooseShardReason.empty())\n\t{\n\t\tmsgin.serial (ShardChooseShardCookie);\n\t\tmsgin.serial (ShardChooseShardAddr);\n\t}\n\tShardChooseShard = true;\n}\n\nstatic TCallbackItem LSCallbackArray[] =\n{\n\t{ \"VLP\", cbVerifyLoginPassword },\n\t{ \"SCS\", cbShardChooseShard },\n};\n\nstring CLoginClient::authenticate(const string &loginServiceAddr, const ucstring &login, const string &cpassword, const string &application)\n{\n\tstring result = authenticateBegin(loginServiceAddr, login, cpassword, application);\n\tif (!result.empty()) return result;\n\twhile (CLoginClient::authenticateUpdate(result)) nlSleep(10);\n\treturn result;\t\n}\n\nstring CLoginClient::authenticateBegin(const string &loginServiceAddr, const ucstring &login, const string &cpassword, const string &application)\n{\n\tVerifyLoginPasswordReason = \"\";\n\tVerifyLoginPassword = false;\n\n\t// S01: connect to the LS\n\ttry\n\t{\n\t\tif(_LSCallbackClient == 0)\n\t\t{\n\t\t\t_LSCallbackClient = new CCallbackClient();\n\t\t\t_LSCallbackClient->addCallbackArray(LSCallbackArray, sizeof(LSCallbackArray) / sizeof(LSCallbackArray[0]));\n\t\t}\n\n\t\tstring addr = loginServiceAddr;\n\t\tif(addr.find(\":\") == string::npos)\n\t\t\taddr += \":49997\";\n\t\tif(_LSCallbackClient->connected())\n\t\t\t_LSCallbackClient->disconnect();\n\t\t_LSCallbackClient->connect (CInetAddress(addr));\n\t}\n\tcatch (const ESocket &e)\n\t{\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\tnlwarning(\"Connection refused to LS (addr:%s): %s\", loginServiceAddr.c_str(), e.what());\n\t\treturn toString(\"Connection refused to LS (addr:%s): %s\", loginServiceAddr.c_str(), e.what());\n\t}\n\t\n\t// S02: create and send the \"VLP\" message\n\tCMessage msgout(\"VLP\");\n\tmsgout.serial(const_cast<ucstring&>(login));\n\tmsgout.serial(const_cast<string&>(cpassword));\n\tmsgout.serial(const_cast<string&>(application));\n\t_LSCallbackClient->send(msgout);\n\n\treturn \"\";\n}\n\n// returns true if it needs to be called again\n// error not empty if something went wrong\nbool CLoginClient::authenticateUpdate(string &error)\n{\n\tif (!_LSCallbackClient)\n\t{\n\t\terror = \"CLoginClient::authenticateBegin() must be called first\";\n\t\tnlwarning(\"CLoginClient::authenticateUpdate(): %s\", error.c_str());\n\t\treturn false;\n\t}\n\tif (!_LSCallbackClient->connected())\n\t{\n\t\terror = \"Disconnected from LS\";\n\t\tnlwarning(\"CLoginClient::authenticateUpdate(): %s\", error.c_str());\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn false;\n\t}\n\t_LSCallbackClient->update();\n\tif (VerifyLoginPassword)\n\t{\n\t\terror = VerifyLoginPasswordReason;\n\t\tif (!error.empty())\n\t\t{\n\t\t\tnlwarning(\"CLoginClient::authenticateUpdate(): %s\", error.c_str());\n\t\t\t_LSCallbackClient->disconnect ();\n\t\t\tdelete _LSCallbackClient;\n\t\t\t_LSCallbackClient = 0;\n\t\t}\n\t\treturn false;\n\t}\n\treturn true; // no news, try again\n}\n\nstring CLoginClient::connectToShard(CLoginCookie &lc, const std::string &addr, CCallbackClient &cnx)\n{\n\tnlassert (!cnx.connected());\n\n\ttry\n\t{\n\t\t//\n\t\t// S12: connect to the FES and send \"SV\" message to the FES\n\t\t//\n\t\tcnx.connect (CInetAddress(addr));\n\t\tcnx.addCallbackArray (FESCallbackArray, sizeof(FESCallbackArray)/sizeof(FESCallbackArray[0]));\n\n\t\t// send the cookie\n\t\tCMessage msgout2 (\"SV\");\n\t\tmsgout2.serial (lc);\n\t\tcnx.send (msgout2);\n\n\t\t// wait the answer of the connection\n\t\tShardValidate = false;\n\t\twhile (cnx.connected() && !ShardValidate)\n\t\t{\n\t\t\tcnx.update ();\n\t\t\tnlSleep(10);\n\t\t}\n\n\t\t// have we received the answer?\n\t\tif (!ShardValidate) return \"FES disconnect me\";\n\t}\n\tcatch (const ESocket &e)\n\t{\n\t\treturn string(\"FES refused the connection (\") + e.what () + \")\";\n\t}\n\n\treturn ShardValidateReason;\n}\n\nstring CLoginClient::connectToShard (const std::string &addr, CUdpSock &cnx)\n{\n\tnlassert (!cnx.connected());\n\n\ttry\n\t{\n\t\t//\n\t\t// S12: connect to the FES. Note: In UDP mode, it's the user that have to send the cookie to the front end\n\t\t//\n\t\t// If a personal firewall such as ZoneAlarm is installed and permission not granted yet,\n\t\t// the connect blocks until the user makes a choice.\n\t\t// If the user denies the connection, the exception ESocket is thrown.\n\t\t// Other firewalls such as Kerio make the send() fail instead.\n\t\t//\n\t\tcnx.connect (CInetAddress(addr));\n\t}\n\tcatch (const ESocket &e)\n\t{\n\t\treturn string(\"FES refused the connection (\") + e.what () + \")\";\n\t}\n\n\treturn ShardValidateReason;\n}\n\nstring CLoginClient::connectToShard (const std::string &addr, CUdpSimSock &cnx)\n{\n\tnlassert (!cnx.connected());\n\n\t\n\ttry\n\t{\n\t\t//\n\t\t// S12: connect to the FES. Note: In UDP mode, it's the user that have to send the cookie to the front end\n\t\t//\n\t\t// See firewall comment in connectToShard(string,CUdpSock)\n\t\t//\n\t\tcnx.connect (CInetAddress(addr));\n\t}\n\tcatch (const ESocket &e)\n\t{\n\t\treturn string(\"FES refused the connection (\") + e.what () + \")\";\n\t}\n\n\treturn ShardValidateReason;\n}\n\nstring CLoginClient::confirmConnection(sint32 shardId)\n{\n\tnlassert(_LSCallbackClient != 0 && _LSCallbackClient->connected());\n\n\t//\n\t// S05: create and send the \"CS\" message with the shardid choice to the LS\n\t//\n\t\n\tif (!ShardList.size())\n\t{\n\t\t_LSCallbackClient->disconnect();\n\t\treturn \"No shard available\";\n\t}\n\t\n\tCLoginClient::CShardEntry *s = getShard(shardId);\n\tif (!s)\n\t{\n\t\t_LSCallbackClient->disconnect();\n\t\treturn \"Invalid shard selected\";\n\t}\n\n\t// send CS\n\tCMessage msgout (\"CS\");\n\tmsgout.serial (s->Id);\n\t_LSCallbackClient->send (msgout);\n\n\t// wait the answer\n\tShardChooseShard = false;\n\twhile (_LSCallbackClient->connected() && !ShardChooseShard)\n\t{\n\t\t_LSCallbackClient->update ();\n\t\tnlSleep(10);\n\t}\n\n\t// have we received the answer?\n\tif (!ShardChooseShard)\n\t{\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn \"CLoginClientMtp::confirmConnection(): LS disconnects me\";\n\t}\n\telse\n\t{\n\t\t_LSCallbackClient->disconnect ();\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t}\n\n\tif (!ShardChooseShardReason.empty())\n\t{\n\t\treturn ShardChooseShardReason;\n\t}\n\n\t// ok, we can try to connect to the good front end\n\n\tnlinfo(\"addr: '%s' cookie: %s\", ShardChooseShardAddr.c_str(), ShardChooseShardCookie.c_str());\n\n\treturn \"\";\n}\n\nstring CLoginClient::wantToConnectToShard(sint32 shardId, string &ip, string &cookie)\n{\n\tstring res = confirmConnection(shardId);\n\tif (!res.empty()) return res;\n\n\tip = ShardChooseShardAddr;\n\tcookie = ShardChooseShardCookie;\n\n\treturn \"\";\n}\n\nstring CLoginClient::selectShardBegin(sint32 shardId)\n{\n\tnlassert(_LSCallbackClient != 0 && _LSCallbackClient->connected());\n\t\n\tShardChooseShardReason = \"\";\n\tShardChooseShard = false;\n\n\tif (!ShardList.size())\n\t{\n\t\t_LSCallbackClient->disconnect();\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn \"No shard available\";\n\t}\t\n\tCLoginClient::CShardEntry *s = getShard(shardId);\n\tif (!s)\n\t{\n\t\t_LSCallbackClient->disconnect();\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn \"Invalid shard selected\";\n\t}\n\n\t// S05: create and send the \"CS\" message with the shardid choice to the LS\n\tCMessage msgout (\"CS\");\n\tmsgout.serial (s->Id);\n\t_LSCallbackClient->send (msgout);\n\n\treturn \"\";\n}\n\nbool CLoginClient::selectShardUpdate(string &error, string &ip, string &cookie)\n{\n\tif (!_LSCallbackClient)\n\t{\n\t\terror = \"CLoginClient::selectShardBegin() must be called first\";\n\t\tnlwarning(\"CLoginClient::selectShardUpdate(): %s\", error.c_str());\n\t\treturn false;\n\t}\n\tif (!_LSCallbackClient->connected())\n\t{\n\t\terror = \"Disconnected from LS\";\n\t\tnlwarning(\"CLoginClient::selectShardUpdate(): %s\", error.c_str());\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn false;\n\t}\n\t_LSCallbackClient->update();\n\tif (ShardChooseShard)\n\t{\n\t\terror = ShardChooseShardReason;\n\t\tip = ShardChooseShardAddr;\n\t\tcookie = ShardChooseShardCookie;\n\t\tif (!error.empty()) nlwarning(\"CLoginClient::selectShardUpdate(): %s\", error.c_str());\n\t\telse nlinfo(\"addr: '%s' cookie: %s\", ShardChooseShardAddr.c_str(), ShardChooseShardCookie.c_str());\n\t\t_LSCallbackClient->disconnect ();\n\t\tdelete _LSCallbackClient;\n\t\t_LSCallbackClient = 0;\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nCLoginClient::CShardEntry *CLoginClient::getShard (sint32 shardId)\n{\n\tfor(TShardList::iterator it=ShardList.begin();it!=ShardList.end();it++)\n\t{\n\t\tif((*it).Id == shardId)\n\t\t\treturn &(*it);\n\t}\n\treturn 0;\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/login_cookie.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/login_cookie.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\n\n/*\n * Comparison == operator\n */\nbool operator== (const CLoginCookie &c1, const CLoginCookie &c2)\n{\n\tnlassert (c1._Valid && c2._Valid);\n\n\treturn c1._UserAddr==c2._UserAddr && c1._UserKey==c2._UserKey && c1._UserId==c2._UserId;\n}\n\n/*\n * Comparison != operator\n */\nbool operator!= (const CLoginCookie &c1, const CLoginCookie &c2)\n{\n\treturn !(c1 == c2);\n}\n\nCLoginCookie::CLoginCookie (uint32 addr, uint32 id) : _Valid(true), _UserAddr(addr), _UserId(id)\n{\n\t// generates the key for this cookie\n\t_UserKey = generateKey();\n}\n\nuint32 CLoginCookie::generateKey()\n{\n\tuint32 t = (uint32)time (NULL);\n    srand (t);\n\n\tuint32 r = rand ();\n\tstatic uint32 n = 0;\n\tn++;\n\n\t// 12bits for the time (in second) => loop in 1 hour\n\t//  8bits for random => 256 case\n\t// 12bits for the inc number => can generate 4096 keys per second without any problem (if you generate more than this number, you could have 2 same keys)\n\treturn (t&0xFFF)<<20 | (r&0xFF)<<12 | (n&0xFFF);\n\n\t// 12bits for the time (in second) => loop in 1 hour\n\t// 20bits for the inc number => can generate more than 1 million keys per second without any problem (never exceed on my computer)\n//\treturn (t&0xFFF)<<20 | (n&0xFFFFF);\n}\n\n\n/* test key generation\nvoid main()\n{\n\tset<uint32> myset;\n\n\t// generates the key for this cookie\n\tfor(;;)\n\t{\n\t\tuint32 val = (t&0xFFF)<<20 | (r&0xFF)<<12 | (n&0xFFF);\n\t\tpair<set<uint32>::iterator,bool> p = myset.insert (val);\n\t\tif (!p.second) printf(\"%10u 0x%x already inserted\\n\", val, val);\n\t}\n}\n*/\n\n} // NL.\n"
  },
  {
    "path": "code/nel/src/net/login_server.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/service.h\"\n\n#include \"nel/net/login_cookie.h\"\n#include \"nel/net/login_server.h\"\n\n#include \"nel/net/udp_sock.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\nstruct CPendingUser\n{\n\tCPendingUser (const CLoginCookie &cookie, const string &un, const string &up, const string &ux, uint32 instanceId, uint32 charSlot)\n\t\t: Cookie (cookie), UserName(un), UserPriv(up), UserExtended(ux), InstanceId(instanceId), CharSlot(charSlot)\n\t{\n\t\tTime = CTime::getSecondsSince1970();\n\t}\n\n\tCLoginCookie Cookie;\n\tstring UserName;\n\tstring UserPriv;\t\t// privilege for executing commands from the clients\n\tstring UserExtended;\t// extended data (for free use)\n\tuint32 InstanceId;\t\t// the world instance in witch the user is awaited\n\tuint32 CharSlot;\t\t// the expected character slot, any other will be denied\n\tuint32 Time;\t\t\t// when the cookie is inserted in pending list\n};\n\nstatic list<CPendingUser> PendingUsers;\n\nstatic CCallbackServer *Server = NULL;\nstatic string ListenAddr;\n\nstatic bool AcceptInvalidCookie = false;\n\nstatic string DefaultUserPriv;\n\nstatic TDisconnectClientCallback DisconnectClientCallback = NULL;\n\n// true=tcp   false=udp\nstatic bool ModeTcp = 0;\n\n// default value is 15 minutes\nstatic uint TimeBeforeEraseCookie = 15*60;\n\n/// contains the correspondance between userid and the sockid\nmap<uint32, TSockId> UserIdSockAssociations;\n\nTNewClientCallback NewClientCallback = NULL;\n\nTNewCookieCallback NewCookieCallback = NULL;\n\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n///////////// CONNECTION TO THE WELCOME SERVICE //////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n\nvoid\tnotifyWSRemovedPendingCookie(CLoginCookie& cookie)\n{\n\tCMessage msgout (\"RPC\");\t// remove pending cookie\n\tmsgout.serial(cookie);\n\tCUnifiedNetwork::getInstance()->send (\"WS\", msgout);\n}\n\nvoid CLoginServer::refreshPendingList ()\n{\n\t// delete too old cookie\n\n\tlist<CPendingUser>::iterator it = PendingUsers.begin();\n\tuint32 Time = CTime::getSecondsSince1970();\n\twhile (it != PendingUsers.end ())\n\t{\n\t\tif ((*it).Time < Time - TimeBeforeEraseCookie)\n\t\t{\n\t\t\tnlinfo(\"LS: Removing cookie '%s' because too old\", (*it).Cookie.toString().c_str());\n\t\t\tnotifyWSRemovedPendingCookie((*it).Cookie);\n\t\t\tit = PendingUsers.erase (it);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tit++;\n\t\t}\n\t}\n}\n\n\nvoid cbWSChooseShard (CMessage &msgin, const std::string &/* serviceName */, TServiceId /* sid */)\n{\n\t// the WS call me that a new client want to come in my shard\n\tstring reason, userName, userPriv, userExtended;\n\tuint32 instanceId, charSlot;\n\tCLoginCookie cookie;\n\n//\trefreshPendingList ();\n\n\t//\n\t// S08: receive \"CS\" message from WS and send \"SCS\" message to WS\n\t//\n\n\tmsgin.serial (cookie);\n\tmsgin.serial (userName, userPriv, userExtended);\n\tmsgin.serial (instanceId);\n\tmsgin.serial (charSlot);\n\n\tvector<list<CPendingUser>::iterator> pendingToRemove;\n\tlist<CPendingUser>::iterator it;\n\tfor (it = PendingUsers.begin(); it != PendingUsers.end (); it++)\n\t{\n\t\tconst CPendingUser &pu = *it;\n\t\tif (pu.Cookie == cookie)\n\t\t{\n\t\t\t// the cookie already exists, erase it and return false\n\t\t\tnlwarning (\"LS: Cookie %s is already in the pending user list\", cookie.toString().c_str());\n//\t\t\tnotifyWSRemovedPendingCookie((*it).Cookie);\n\t\t\tPendingUsers.erase (it);\n\t\t\treason = \"cookie already exists\";\n\t\t\t// iterator is invalid, set it to end\n\t\t\tit = PendingUsers.end();\n\t\t\tbreak;\n\t\t}\n\t\telse if (pu.Cookie.getUserId() == cookie.getUserId())\n\t\t{\n\t\t\t// we already have a cookie for this user, remove the old one\n\t\t\tpendingToRemove.push_back(it);\n\t\t}\n\t}\n\t// remove any useless cookie\n\twhile (!pendingToRemove.empty())\n\t{\n\t\tPendingUsers.erase(pendingToRemove.back());\n\t\tpendingToRemove.pop_back();\n\t}\n\n\tif (it == PendingUsers.end ())\n\t{\n\t\t// add it to the awaiting client\n\t\tnlinfo (\"LS: New cookie %s (name '%s' priv '%s' extended '%s' instance %u slot %u) inserted in the pending user list (awaiting new client)\", cookie.toString().c_str(), userName.c_str(), userPriv.c_str(), userExtended.c_str(), instanceId, charSlot);\n\t\tPendingUsers.push_back (CPendingUser (cookie, userName, userPriv, userExtended, instanceId, charSlot));\n\t\treason = \"\";\n\n\t\t// callback if needed\n\t\tif (NewCookieCallback != NULL)\n\t\t{\n\t\t\tNewCookieCallback(cookie);\n\t\t}\n\t}\n\n\tCMessage msgout (\"SCS\");\n\tmsgout.serial (reason);\n\tmsgout.serial (cookie);\n\tmsgout.serial (ListenAddr);\n\tuint32 nbPending = (uint32)PendingUsers.size();\n\tmsgout.serial (nbPending);\n\tCUnifiedNetwork::getInstance()->send (\"WS\", msgout);\n}\n\nvoid cbWSDisconnectClient (CMessage &msgin, const std::string &serviceName, TServiceId /* sid */)\n{\n\t// the WS tells me that i have to disconnect a client\n\n\tuint32 userid;\n\tmsgin.serial (userid);\n\n\tif (ModeTcp)\n\t{\n\t\tmap<uint32, TSockId>::iterator it = UserIdSockAssociations.find (userid);\n\t\tif (it == UserIdSockAssociations.end ())\n\t\t{\n\t\t\tnlwarning (\"LS: Can't disconnect the user %d, he is not found\", userid);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo (\"LS: Disconnect the user %d\", userid);\n\t\t\tServer->disconnect ((*it).second);\n\t\t}\n\t}\n\n\tif (DisconnectClientCallback != NULL)\n\t{\n\t\tDisconnectClientCallback (userid, serviceName);\n\t}\n}\n\nstatic TUnifiedCallbackItem WSCallbackArray[] =\n{\n\t{ \"CS\", cbWSChooseShard },\n\t{ \"DC\", cbWSDisconnectClient },\n};\n\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n///////////// CONNECTION TO THE CLIENT ///////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n\nvoid cbShardValidation (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\t//\n\t// S13: receive \"SV\" message from the client\n\t//\n\n\t// the client send me a cookie\n\tCLoginCookie cookie;\n\tstring reason;\n\tmsgin.serial (cookie);\n\n\tstring userName, userPriv, userExtended;\n\tuint32 instanceId, charSlot;\n\t// verify that the user was pending\n\treason = CLoginServer::isValidCookie (cookie, userName, userPriv, userExtended, instanceId, charSlot);\n\n\t// if the cookie is not valid and we accept them, clear the error\n\tif(AcceptInvalidCookie && !reason.empty())\n\t{\n\t\treason = \"\";\n\t\tcookie.set (rand(), rand(), rand());\n\t}\n\n\tCMessage msgout2 (\"SV\");\n\tmsgout2.serial (reason);\n\tnetbase.send (msgout2, from);\n\n\tif (!reason.empty())\n\t{\n\t\tnlwarning (\"LS: User (%s) is not in the pending user list (cookie:%s)\", netbase.hostAddress(from).asString().c_str(), cookie.toString().c_str());\n\t\t// disconnect him\n\t\tnetbase.disconnect (from);\n\t}\n\telse\n\t{\n\t\t// add the user association\n\t\tuint32 userid = cookie.getUserId();\n\n\t\tif (ModeTcp)\n\t\t\tUserIdSockAssociations.insert (make_pair(userid, from));\n\n\t\t// identification OK, let's call the user callback\n\t\tif (NewClientCallback != NULL)\n\t\t\tNewClientCallback (from, cookie);\n\n\t\t// ok, now, he can call all callback\n\t\tServer->authorizeOnly (NULL, from);\n\t}\n}\n\nvoid ClientConnection (TSockId from, void * /* arg */)\n{\n\tnldebug(\"LS: new client connection: %s\", from->asString ().c_str ());\n\n\t// the client could only call \"SV\" message\n\tServer->authorizeOnly (\"SV\", from);\n}\n\n\nstatic const TCallbackItem ClientCallbackArray[] =\n{\n\t{ \"SV\", cbShardValidation },\n};\n\nvoid CLoginServer::setListenAddress(const string &la)\n{\n\t// if the var is empty or not found, take it from the listenAddress()\n\tif (la.empty() && ModeTcp && Server != NULL)\n\t{\n\t\tListenAddr = Server->listenAddress ().asIPString();\n\t}\n\telse\n\t{\n\t\tListenAddr = la;\n\t}\n\n\t// check that listen address is valid\n\tif (ListenAddr.empty())\n\t{\n\t\tnlerror(\"FATAL : listen address in invalid, it should be either set via ListenAddress variable or with -D argument\");\n\t\tnlstop;\n\t}\n\n\tnlinfo(\"LS: Listen Address that will be sent to the client is now '%s'\", ListenAddr.c_str());\n}\n\nuint32 CLoginServer::getNbPendingUsers()\n{\n\treturn (uint32)PendingUsers.size();\n}\n\nvoid cfcbListenAddress (CConfigFile::CVar &var)\n{\n\tCLoginServer::setListenAddress (var.asString());\n}\n\nvoid cfcbDefaultUserPriv(CConfigFile::CVar &var)\n{\n\t// set the new ListenAddr\n\tDefaultUserPriv = var.asString();\n\n\tnlinfo(\"LS: The default user priv is '%s'\", DefaultUserPriv.c_str());\n}\n\nvoid cfcbAcceptInvalidCookie(CConfigFile::CVar &var)\n{\n\t// set the new ListenAddr\n\tAcceptInvalidCookie = var.asInt() == 1;\n\n\tnlinfo(\"LS: This service %saccept invalid cookie\", AcceptInvalidCookie?\"\":\"doesn't \");\n}\n\nvoid cfcbTimeBeforeEraseCookie(CConfigFile::CVar &var)\n{\n\t// set the new ListenAddr\n\tTimeBeforeEraseCookie = var.asInt();\n\n\tnlinfo(\"LS: This service will remove cookie after %d seconds\", TimeBeforeEraseCookie);\n}\n\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n///////////// CONNECTION TO THE WELCOME SERVICE //////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////////////////////////\n\n// common init\nvoid CLoginServer::init (const string &listenAddress)\n{\n\t// connect to the welcome service\n\tconnectToWS ();\n\n\ttry {\n\t\tcfcbDefaultUserPriv(IService::getInstance()->ConfigFile.getVar(\"DefaultUserPriv\"));\n\t\tIService::getInstance()->ConfigFile.setCallback(\"DefaultUserPriv\", cfcbDefaultUserPriv);\n\t} catch(const Exception &) { }\n\n\ttry {\n\t\tcfcbAcceptInvalidCookie (IService::getInstance()->ConfigFile.getVar(\"AcceptInvalidCookie\"));\n\t\tIService::getInstance()->ConfigFile.setCallback(\"AcceptInvalidCookie\", cfcbAcceptInvalidCookie);\n\t} catch(const Exception &) { }\n\n\ttry {\n\t\tcfcbTimeBeforeEraseCookie (IService::getInstance()->ConfigFile.getVar(\"TimeBeforeEraseCookie\"));\n\t\tIService::getInstance()->ConfigFile.setCallback(\"TimeBeforeEraseCookie\", cfcbTimeBeforeEraseCookie);\n\t} catch(const Exception &) { }\n\n\t// setup the listen address\n\n\tstring la;\n\n\tif (IService::getInstance()->haveArg('D'))\n\t{\n\t\t// use the command line param if set\n\t\tla = IService::getInstance()->getArg('D');\n\t}\n\telse if (IService::getInstance()->ConfigFile.exists (\"ListenAddress\"))\n\t{\n\t\t// use the config file param if set\n\t\tla = IService::getInstance()->ConfigFile.getVar (\"ListenAddress\").asString();\n\t}\n\telse\n\t{\n\t\tla = listenAddress;\n\t}\n\tsetListenAddress (la);\n\tIService::getInstance()->ConfigFile.setCallback(\"ListenAddress\", cfcbListenAddress);\n}\n\n// listen socket is TCP\nvoid CLoginServer::init (CCallbackServer &server, TNewClientCallback ncl)\n{\n\tinit (server.listenAddress ().asIPString());\n\n\t// add callback to the server\n\tserver.addCallbackArray (ClientCallbackArray, sizeof (ClientCallbackArray) / sizeof (ClientCallbackArray[0]));\n\tserver.setConnectionCallback (ClientConnection, NULL);\n\n\tNewClientCallback = ncl;\n\tServer = &server;\n\n\tModeTcp = true;\n}\n\n// listen socket is UDP\nvoid CLoginServer::init (CUdpSock &server, TDisconnectClientCallback dc)\n{\n\tinit (server.localAddr ().asIPString());\n\n\tDisconnectClientCallback = dc;\n\n\tModeTcp = false;\n}\n\nvoid CLoginServer::init (const std::string &listenAddr, TDisconnectClientCallback dc)\n{\n\tinit (listenAddr);\n\n\tDisconnectClientCallback = dc;\n\n\tModeTcp = false;\n}\n\nvoid CLoginServer::addNewCookieCallback(TNewCookieCallback newCookieCb)\n{\n\tNewCookieCallback = newCookieCb;\n}\n\n\nstring CLoginServer::isValidCookie (const CLoginCookie &lc, string &userName, string &userPriv, string &userExtended, uint32 &instanceId, uint32 &charSlot)\n{\n\tuserName = userPriv = \"\";\n\n\tif (!AcceptInvalidCookie && !lc.isValid())\n\t\treturn \"The cookie is invalid\";\n\n\t// verify that the user was pending\n\tlist<CPendingUser>::iterator it;\n\tfor (it = PendingUsers.begin(); it != PendingUsers.end (); it++)\n\t{\n\t\tCPendingUser &pu = *it;\n\t\tif (pu.Cookie == lc)\n\t\t{\n\t\t\tnlinfo (\"LS: Cookie '%s' is valid and pending (user %s), send the client connection to the WS\", lc.toString ().c_str (), pu.UserName.c_str());\n\n\t\t\t// warn the WS that the client effectively connected\n\t\t\tuint8 con = 1;\n\t\t\tCMessage msgout (\"CC\");\n\t\t\tuint32 userid = lc.getUserId();\n\t\t\tmsgout.serial (userid);\n\t\t\tmsgout.serial (con);\n\n\t\t\tCUnifiedNetwork::getInstance()->send(\"WS\", msgout);\n\n\t\t\tuserName = pu.UserName;\n\t\t\tuserPriv = pu.UserPriv;\n\t\t\tuserExtended = pu.UserExtended;\n\t\t\tinstanceId = pu.InstanceId;\n\t\t\tcharSlot = pu.CharSlot;\n\n\t\t\t// ok, it was validate, remove it\n\t\t\tPendingUsers.erase (it);\n\n\t\t\treturn \"\";\n\t\t}\n\t}\n\n\t// we accept invalid cookie and it is one, fake\n\tif (AcceptInvalidCookie)\n\t{\n\t\tuserName = \"InvalidUserName\";\n\t\tuserPriv = DefaultUserPriv;\n\t\tinstanceId = 0xffffffff;\n\t\treturn \"\";\n\t}\n\n\t// problem\n\treturn \"I didn't receive the cookie from WS\";\n}\n\nvoid CLoginServer::connectToWS ()\n{\n\tCUnifiedNetwork::getInstance()->addCallbackArray(WSCallbackArray, sizeof(WSCallbackArray)/sizeof(WSCallbackArray[0]));\n}\n\nvoid CLoginServer::clientDisconnected (uint32 userId)\n{\n\tuint8 con = 0;\n\tCMessage msgout (\"CC\");\n\tmsgout.serial (userId);\n\tmsgout.serial (con);\n\n\tCUnifiedNetwork::getInstance()->send(\"WS\", msgout);\n\n\t// remove the user association\n\tif (ModeTcp)\n\t\tUserIdSockAssociations.erase (userId);\n}\n\n/// Call this method to retrieve the listen address\nconst std::string &CLoginServer::getListenAddress()\n{\n\treturn ListenAddr;\n}\n\nbool CLoginServer::acceptsInvalidCookie()\n{\n\treturn AcceptInvalidCookie;\n}\n\n\n//\n// Commands\n//\n\nNLMISC_CATEGORISED_COMMAND(nel, lsUsers, \"displays the list of all connected users\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tif (ModeTcp)\n\t{\n\t\tlog.displayNL (\"Display the %d connected users :\", UserIdSockAssociations.size());\n\t\tfor (map<uint32, TSockId>::iterator it = UserIdSockAssociations.begin(); it != UserIdSockAssociations.end (); it++)\n\t\t{\n\t\t\tlog.displayNL (\"> %u %s\", (*it).first, (*it).second->asString().c_str());\n\t\t}\n\t\tlog.displayNL (\"End of the list\");\n\t}\n\telse\n\t{\n\t\tlog.displayNL (\"No user list in udp mode\");\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, lsPending, \"displays the list of all pending users\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tlog.displayNL (\"Display the %d pending users :\", PendingUsers.size());\n\tfor (list<CPendingUser>::iterator it = PendingUsers.begin(); it != PendingUsers.end (); it++)\n\t{\n\t\tlog.displayNL (\"> %s %s\", (*it).Cookie.toString().c_str(), (*it).UserName.c_str());\n\t}\n\tlog.displayNL (\"End of the list\");\n\n\treturn true;\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, LSListenAddress, \"the listen address sended to the client to connect on this front_end\")\n{\n\tnlunreferenced(human);\n\n\tif (get)\n\t{\n\t\t*pointer = ListenAddr;\n\t}\n\telse\n\t{\n\t\tif ((*pointer).find (\":\") == string::npos)\n\t\t{\n\t\t\tnlwarning (\"LS: You must set the address + port (ie: \\\"itsalive.nevrax.org:38000\\\")\");\n\t\t\treturn;\n\t\t}\n\t\telse if ((*pointer).empty())\n\t\t{\n\t\t\tListenAddr = Server->listenAddress ().asIPString();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tListenAddr = *pointer;\n\t\t}\n\t\tnlinfo (\"LS: Listen Address that will be send to client is '%s'\", ListenAddr.c_str());\n\t}\n}\n\nNLMISC_CATEGORISED_VARIABLE(nel, string, DefaultUserPriv, \"Default User priv for people who don't use the login system\");\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/message.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/message.h\"\n\n/*#ifdef MESSAGES_PLAIN_TEXT\n#pragma message( \"CMessage: compiling messages as plain text\" )\n#else\n#pragma message( \"CMessage: compiling messages as binary\" )\n#endif*/\n\nnamespace NLNET\n{\n\nbool CMessage::_DefaultStringMode = false;\n\nconst char *LockedSubMessageError = \"a sub message is forbidden\";\n\n#define FormatLong 1\n#define FormatShort 0\n\n\n/*\n * Constructor by name\n */\nCMessage::CMessage (const std::string &name, bool inputStream, TStreamFormat streamformat, uint32 defaultCapacity) :\n\tNLMISC::CMemStream (inputStream, false, defaultCapacity),\n\t_Type(OneWay), _SubMessagePosR(0), _LengthR(0), _HeaderSize(0xFFFFFFFF), _TypeSet (false)\n{\n\tinit( name, streamformat );\n}\n\nCMessage::CMessage (const uint32 rpc_session, const std::string &name, bool inputStream, TStreamFormat streamformat, uint32 defaultCapacity) :\n\tNLMISC::CMemStream (inputStream, false, defaultCapacity),\n\t_Type(OneWay), _SubMessagePosR(0), _LengthR(0), _HeaderSize(0xFFFFFFFF), _TypeSet (false)\n{\n\tinit( name, streamformat );\n\tsession(rpc_session);\n}\n\n/*\n * Utility method\n */\nvoid CMessage::init( const std::string &name, TStreamFormat streamformat )\n{\n\tif ( streamformat == UseDefault )\n\t{\n\t\tsetStringMode( _DefaultStringMode );\n\t}\n\telse\n\t{\n\t\tsetStringMode( streamformat == String );\n\t}\n\n\tif (!name.empty())\n\t\tsetType (name);\n}\n\n\n/*\n * Constructor with copy from CMemStream\n */\nCMessage::CMessage (NLMISC::CMemStream &memstr) :\n\tNLMISC::CMemStream( memstr ),\n\t_Type(OneWay), _SubMessagePosR(0), _LengthR(0), _HeaderSize(0xFFFFFFFF), _TypeSet (false)\n{\n\tsint32 pos = getPos();\n\tbool reading = isReading();\n\tif ( reading ) // force input mode to read the type\n\t\treadType(); // sets _TypeSet, _HeaderSize and _LengthR\n\telse\n\t\tinvert(); // calls readType()\n\tif ( ! reading )\n\t\tinvert(); // set output mode back if necessary\n\tseek( pos, begin ); // sets the same position as the one in the memstream\n}\n\n\n/*\n * Copy constructor\n */\nCMessage::CMessage (const CMessage &other)\n\t:\tCMemStream(),\n\t\t_TypeSet(false)\n{\n\toperator= (other);\n}\n\n/*\n * Assignment operator\n */\nCMessage &CMessage::operator= (const CMessage &other)\n{\n//\tnlassertex( (!other.isReading()) || (!other.hasLockedSubMessage()), (\"Storing %s\", LockedSubMessageError) );\n\tnlassertex( (!isReading()) || (!hasLockedSubMessage()), (\"Assigning %s\", LockedSubMessageError) );\n\tif ( other.hasLockedSubMessage() )\n\t{\n\t\tassignFromSubMessage(other);\n\t}\n\telse\n\t{\n\n\t\tCMemStream::operator= (other);\n\t\t_Type = other._Type;\n\t\t_TypeSet = other._TypeSet;\n\t\t_Name = other._Name;\n\t\t_HeaderSize = other._HeaderSize;\n\t\t_SubMessagePosR = other._SubMessagePosR;\n\t\t_LengthR = other._LengthR;\n\t}\n\n\treturn *this;\n}\n\nvoid CMessage::swap(CMessage &other)\n{\n\tnlassert( !hasLockedSubMessage() );\n\tCMemStream::swap(other);\n\t_Name.swap(other._Name);\n\tstd::swap(_SubMessagePosR, other._SubMessagePosR);\n\tstd::swap(_LengthR, other._LengthR);\n\tstd::swap(_HeaderSize, other._HeaderSize);\n\tstd::swap(_TypeSet, other._TypeSet);\n\tstd::swap(_Type, other._Type);\n}\n\n\n/**\n * Similar to operator=, but makes the current message contain *only* the locked sub message in msgin\n * or the whole msgin if it is not locked\n *\n * Preconditions:\n * - msgin is an input message (isReading())\n * - The current message is blank (new or reset with clear())\n *\n * Postconditions:\n * - If msgin has been locked using lockSubMessage(), the current message contains only the locked\n *   sub message in msgin, otherwise the current message is exactly msgin\n * - The current message is an input message, it is not locked\n */\nvoid CMessage::assignFromSubMessage( const CMessage& msgin )\n{\n\tnlassert( msgin.isReading() );\n\tnlassert( ! _TypeSet );\n\tif ( ! isReading() )\n\t\tinvert();\n\n\tif ( msgin.hasLockedSubMessage() )\n\t{\n\t\tfill( msgin.buffer(), msgin._LengthR );\n\t\treadType();\n\t\tseek( msgin.getPos(), IStream::begin );\n\t}\n\telse\n\t{\n\t\toperator=( msgin );\n\t}\n}\n\nstruct EMsgNameIsNull : public NLMISC::EStream\n{\n    EMsgNameIsNull() : EStream( \"Msg name is null.\" ) {}\n};\n/*\n * Sets the message type as a string and put it in the buffer if we are in writing mode\n */\nvoid CMessage::setType (const std::string &name, TMessageType type)\n{\n\t// check if we already do a setType ()\n\tnlassert (!_TypeSet);\n\t// don't accept empty string\n\t//nlassert (!name.empty ());\n\n    if ( name.empty() )\n    {\n        throw EMsgNameIsNull();\n    }\n\n\t_Name = name;\n\t_Type = type;\n\n\tif (!isReading ())\n\t{\n\t\t// check if they don't already serial some stuffs\n\t\tnlassert (length () == 0);\n\n\t\t// if we can send the id instead of the string, \"just do it\" (c)nike!\n\t\t//NLMISC::CStringIdArray::TStringId id = _SIDA->getId (name);\n\n\t\t// Force binary mode for header\n\t\tbool msgmode = _StringMode;\n\t\t_StringMode = false;\n\n\t\t// debug features, we number all packet to be sure that they are all sent and received\n\t\t// \\todo remove this debug feature when ok\n\t\t// this value will be fill after in the callback function\n\t\tuint32 zeroValue = 0;\n\t\tserial (zeroValue);\n\n\n\t\tTFormat format;\n\t\tformat.LongFormat = FormatLong;\n\t\tformat.StringMode = msgmode;\n\t\tformat.MessageType = _Type;\n\t\t//nldebug( \"OUT format = %hu\", (uint16)format );\n\t\tserial (format);\n\n\t\t// End of binary header\n\t\t_StringMode = msgmode;\n\n\t\tserial ((std::string&)name);\n\n\t\t_HeaderSize = getPos ();\n\t}\n\n\t_TypeSet = true;\n}\n\n\n/*\n * Warning: MUST be of the same size than previous name!\n * Output message only.\n */\nvoid CMessage::changeType (const std::string &name)\n{\n\tsint32 prevPos = getPos();\n\tseek( sizeof(uint32)+sizeof(uint8), begin );\n\tserial ((std::string&)name);\n\tseek( prevPos, begin );\n}\n\nvoid CMessage::session( uint32 rpc_session )\n{\n\tpoke(rpc_session,0);\n}\n\nuint32 CMessage::session()\n{\n\tuint32 rpc_session = 0;\n\tsint32 prevPos = getPos();\n\tseek( 0, begin );\n\tserial (rpc_session);\n\tseek( prevPos, begin );\n\treturn rpc_session;\n}\n\n/*\n * Returns the size, in byte of the header that contains the type name of the message or the type number\n */\nuint32 CMessage::getHeaderSize () const\n{\n\tnlassert (_HeaderSize != 0xFFFFFFFF);\n\tnlassert(!hasLockedSubMessage());\n\treturn _HeaderSize;\n}\n\n\n/*\n * The message was filled with an CMemStream, Now, we'll get the message type on this buffer\n */\nvoid CMessage::readType ()\n{\n\tnlassert (isReading ());\n\n\t// debug features, we number all packet to be sure that they are all sent and received\n\t// \\todo remove this debug feature when ok\n\n\t// we remove the message from the message\n\tresetSubMessageInternals();\n\tconst uint HeaderSize = 4;\n\tseek (HeaderSize, begin);\n//\t\tuint32 zeroValue;\n//\t\tserial (zeroValue);\n\n\t// Force binary mode for header\n\t_StringMode = false;\n\n\tTFormat format;\n\tserial (format);\n\t//nldebug( \"IN format = %hu\", (uint16)format );\n\n\t// Set mode for the following of the buffer\n\t_StringMode = format.StringMode;\n\n\tstd::string name;\n\tserial (name);\n\tsetType (name, TMessageType(format.MessageType));\n\t_HeaderSize = getPos();\n}\n\n\n/*\n * Get the message name (input message only) and advance the current pos\n */\nstd::string CMessage::readTypeAtCurrentPos() const\n{\n\tnlassert( isReading() );\n\n\tconst uint HeaderSize = 4;\n\tseek( HeaderSize, current );\n\n\tbool sm = _StringMode;\n\t_StringMode = false;\n\n\tTFormat format;\n\tnlRead(*this, serial, format );\n\tbool LongFormat = format.LongFormat;\n\t_StringMode = format.StringMode;\n\t_Type = TMessageType(format.MessageType);\n\n\tif ( LongFormat )\n\t{\n\t\tstd::string name;\n\t\tnlRead(*this, serial, name );\n\t\t_StringMode = sm;\n\t\treturn name;\n\t}\n\telse\n\t\tnlerror( \"Id not supported\" );\n\n\n\t_StringMode = sm;\n\treturn \"\";\n}\n\n\n// Returns true if the message type was already set\nbool CMessage::typeIsSet () const\n{\n\treturn _TypeSet;\n}\n\n// Clear the message. With this function, you can reuse a message to create another message\nvoid CMessage::clear ()\n{\n\tnlassertex( (!isReading()) || (!hasLockedSubMessage()), (\"Clearing %s\", LockedSubMessageError) );\n\n\tCMemStream::clear ();\n\t_TypeSet = false;\n\t_SubMessagePosR = 0;\n\t_LengthR = 0;\n}\n\n/*\n * Returns the type name in string if available. Be sure that the message have the name of the message type\n */\nstd::string CMessage::getName () const\n{\n\tif ( hasLockedSubMessage() )\n\t{\n\t\tCMessage& notconstMsg = const_cast<CMessage&>(*this);\n\t\tsint32 savedPos = notconstMsg.getPos();\n\t\tuint32 subPosSaved = _SubMessagePosR;\n\t\tuint32 lenthRSaved = _LengthR;\n\t\tconst_cast<uint32&>(_SubMessagePosR) = 0;\n//\t\tconst_cast<uint32&>(_LengthR) = _Buffer.size();\n\t\tconst_cast<uint32&>(_LengthR) = _Buffer.getBuffer().size();\n\t\tnotconstMsg.seek( subPosSaved, begin ); // not really const... but removing the const from getName() would need too many const changes elsewhere\n\t\tstd::string name = notconstMsg.readTypeAtCurrentPos();\n\t\tnotconstMsg.seek( subPosSaved+savedPos, begin );\n\t\tconst_cast<uint32&>(_SubMessagePosR) = subPosSaved;\n\t\tconst_cast<uint32&>(_LengthR) = lenthRSaved;\n\t\treturn name;\n\t}\n\telse\n\t{\n        //throw EMsgNameIsNull();\n\t\t//nlassert (_TypeSet);\n\t\treturn _Name;\n\t}\n}\n\nstruct EMsgTypeIsNull : public NLMISC::EStream\n{\n    EMsgTypeIsNull() : EStream( \"Msg type is null.\" ) {}\n};\n\nCMessage::TMessageType CMessage::getType() const\n{\n\tif ( hasLockedSubMessage() )\n\t{\n\t\tCMessage& notconstMsg = const_cast<CMessage&>(*this);\n\t\tsint32 savedPos = notconstMsg.getPos();\n\t\tuint32 subPosSaved = _SubMessagePosR;\n\t\tuint32 lenthRSaved = _LengthR;\n\t\tconst_cast<uint32&>(_SubMessagePosR) = 0;\n//\t\tconst_cast<uint32&>(_LengthR) = _Buffer.size();\n\t\tconst_cast<uint32&>(_LengthR) = _Buffer.getBuffer().size();\n\t\tnotconstMsg.seek( subPosSaved, begin ); // not really const... but removing the const from getName() would need too many const changes elsewhere\n\t\tnotconstMsg.readTypeAtCurrentPos();\n\t\tnotconstMsg.seek( subPosSaved+savedPos, begin );\n\t\tconst_cast<uint32&>(_SubMessagePosR) = subPosSaved;\n\t\tconst_cast<uint32&>(_LengthR) = lenthRSaved;\n\t\treturn _Type;\n\t}\n\telse\n\t{\n        //throw EMsgTypeIsNull();\n\t\t//nlassert (_TypeSet);\n\t\treturn _Type;\n\t}\n}\n\n\n/* Returns a readable string to display it to the screen. It's only for debugging purpose!\n * Don't use it for anything else than to debugging, the string format could change in the future.\n * \\param hexFormat If true, display all bytes in hexadecimal\n * \\param textFormat If true, display all bytes as chars (above 31, otherwise '.')\n */\nstd::string CMessage::toString( bool hexFormat, bool textFormat ) const\n{\n\t//nlassert (_TypeSet);\n\tstd::string s = \"('\" + _Name + \"')\";\n\tif ( hexFormat )\n\t\ts += \" \" + CMemStream::toString( true );\n\tif ( textFormat )\n\t\ts += \" \" + CMemStream::toString( false );\n\treturn s;\n}\n\n\n/*\n * Return an input stream containing the stream beginning in the message at the specified pos\n */\nNLMISC::CMemStream\tCMessage::extractStreamFromPos( sint32 pos )\n{\n\tNLMISC::CMemStream msg( true );\n\tsint32 len = length() - pos;\n\n    if ( len>0 )\n    {\n        memcpy( msg.bufferToFill( len ), buffer() + pos, len );\n    }\n\n\treturn msg;\n}\n\n\n/*\n * Encapsulate/decapsulate another message inside the current message\n */\nvoid\tCMessage::serialMessage( CMessage& msg )\n{\n\tif ( isReading() )\n\t{\n\t\t// Init 'msg' with the contents serialised from 'this'\n\t\tuint32 len;\n\t\tserial( len );\n\t\tif ( ! msg.isReading() )\n\t\t\tmsg.invert();\n\t\tserialBuffer( msg.bufferToFill( len ), len );\n\t\tmsg.readType();\n\t\tmsg.invert();\n\t\tmsg.seek( 0, CMemStream::end );\n\t}\n\telse\n\t{\n\t\t// Store into 'this' the contents of 'msg'\n\t\tuint32 len = msg.length();\n\t\tserial( len );\n\t\tserialBuffer( const_cast<uint8*>(msg.buffer()), msg.length() );\n\t}\n}\n\n}\n"
  },
  {
    "path": "code/nel/src/net/message_recorder.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/message_recorder.h\"\n#include \"nel/net/inet_address.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\n\nnamespace NLNET {\n\n\n/// TNetworkEvent -> string\nstring EventToString( TNetworkEvent e )\n{\n\tswitch ( e )\n\t{\n\tcase Sending: return \"SEND\";\n\tcase Receiving: return \"RECV\";\n\tcase Connecting: return \"CONN\";\n\tcase ConnFailing: return \"CNFL\";\n\tcase Accepting: return \"ACCP\";\n\tcase Disconnecting: return \"DISC\";\n\tdefault: nlstop; return \"-ERR-\";\n\t}\n}\n\n/// string -> TNetworkEvent\nTNetworkEvent StringToEvent( string& s )\n{\n\tif ( s == \"RECV\" )\n\t\treturn Receiving;\n\telse if ( s == \"SEND\" )\n\t\treturn Sending;\n\telse if ( s == \"DISC\" )\n\t\treturn Disconnecting;\n\telse if ( s == \"ACCP\" )\n\t\treturn Accepting;\n\telse if ( s == \"CONN\" )\n\t\treturn Connecting;\n\telse if ( s == \"CNFL\" )\n\t\treturn ConnFailing;\n\telse\n\t{\n\t\tnlstop;\n\t\treturn Error;\n\t}\n}\n\n\n/*\n * Constructor\n */\nCMessageRecorder::CMessageRecorder() : _RecordAll(true)\n{\n#ifndef MESSAGES_PLAIN_TEXT\n\tnlerror( \"The message recorder works only with plain text messages. Please #define MESSAGES_PLAIN_TEXT\" );\n#endif\n}\n\n\n/*\n * Destructor\n */\nCMessageRecorder::~CMessageRecorder()\n{\n\tif ( !_Filename.empty() )\n\t{\n\t\tnldebug( \"MR:%s: End of recording\", _Filename.c_str() );\n\t}\n\tstopRecord();\n\tstopReplay();\n}\n\n\n/*\n * Start recording\n */\nbool CMessageRecorder::startRecord( const std::string& filename, bool recordall )\n{\n\t_Filename = filename;\n\t_File.open( _Filename.c_str(), ios_base::out );\n\t_File << endl;\n\t_RecordAll = recordall;\n\tif ( _File.fail() )\n\t{\n\t\tnlwarning( \"MR: Record: Cannot open file %s\", _Filename.c_str() );\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\tnldebug( \"MR: Start recording into %s\", _Filename.c_str() );\n\t\treturn true;\n\t}\n}\n\n\n/*\n * Same as stringFromVector() but assumes the vector contains only printable characters\n */\n/*string stringFromTextVector( const vector<uint8>& v )\n{\n\tstring s;\n\n\t// Copy contents\n\ts.resize( v.size() );\n\tmemcpy( &*s.begin(), &*v.begin(), v.size() );\n\n\treturn s;\n}*/\n\n\n/*\n * Add a record\n */\nvoid CMessageRecorder::recordNext( sint64 updatecounter, TNetworkEvent event, TSockId sockid, CMessage& message )\n{\n\tnlassert( _File.is_open() );\n\n\tif ( (_RecordAll) || (event != Sending) )\n\t{\n\t\t// Serial to stream\n\t\tTMessageRecord rec ( event, sockid, message, updatecounter /*CTime::getLocalTime()*/ );\n\t\tCMemStream stream ( false, true );\n\t\trec.serial( stream );\n\t\tchar c = '\\0';      // end of cstring\n\t\tstream.serial( c ); // added to the stream for _File << (char*)stream.buffer()\n\n\t\t// Dump to file\n\t\tnldebug( \"MR:%s: Recording [%s]\", _Filename.c_str(), stream.buffer() );\n\t\tint len = (int)(stream.length()-2); // not the null character (and its separator) at the end of the buffer\n\t\t_File << \"* \";\n\t\t_File <<  len; // if we put the expression directly, it makes an access violation ! Weird.\n\t\t_File << \" \";\n\t\t_File << (char*)stream.buffer() << endl;\n\t}\n}\n\n\n/*\n * Stop recording\n */\nvoid CMessageRecorder::stopRecord()\n{\n\t_File.close();\n\t_Filename = \"\";\n}\n\n\n/*\n * Start playback\n */\nbool CMessageRecorder::startReplay( const std::string& filename )\n{\n\t_Filename = filename;\n\t_File.open( _Filename.c_str(), ios_base::in );\n\tif ( _File.fail() )\n\t{\n\t\tnlerror( \"MR: Replay: Cannot open file %s\", _Filename.c_str() );\n\t\treturn false;\n\t}\n\telse\n\t{\n\t\tnldebug( \"MR: Start replaying from %s\", _Filename.c_str() );\n\t\treturn true;\n\t}\n}\n\n\n/*\n * Get next record (throw EStreamOverflow)\n */\nbool CMessageRecorder::loadNext( TMessageRecord& record )\n{\n\t// WARNING!!! This features doesn't work anymore becaues bufferAsVector() is not available with new CMemStream\n\tnlstop;\n\treturn false;\n\n\tnlassert( _File.is_open() );\n\n\t// Dump from file\n\tCMemStream stream ( true, true );\n\tuint32 len;\n\tchar c;\n\t_File >> c; // skip \"* \";\n\t_File >> (int&)len;\n\t_File.ignore(); // skip delimiter\n\tif ( ! _File.fail() )\n\t{\n\t\t_File.get( (char*)stream.bufferToFill( len+1 ), len+1, '\\0' );\n\t\t//stream.bufferAsVector().resize( len ); // cut end of cstring\n\t\tnldebug( \"MR:%s: Reading [%s]\", _Filename.c_str(), stream.buffer() );\n\n\t\t// Serial from stream\n\t\trecord.serial( stream ); // may throw EStreamOverflow if _File.fail()\n\t}\n\n\treturn ! _File.fail(); // retest\n}\n\n\n/*\n * Get the next record (from the preloaded records, or from the file)\n */\nbool CMessageRecorder::getNext( TMessageRecord& record, sint64 updatecounter )\n{\n\tif ( ! _PreloadedRecords.empty() )\n\t{\n\t\tif ( _PreloadedRecords.front().UpdateCounter == updatecounter )\n\t\t{\n\t\t\t// The requested record is in the preload\n\t\t\trecord = _PreloadedRecords.front();\n\t\t\t_PreloadedRecords.pop_front();\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// The requested record is not in the file\n\t\t\tnlassert( updatecounter < _PreloadedRecords.front().UpdateCounter ); // not >\n\t\t\treturn false;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif ( loadNext( record ) )\n\t\t{\n\t\t\tif ( record.UpdateCounter == updatecounter )\n\t\t\t{\n\t\t\t\t// The requested record has been loaded\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// The next loaded record is a new one\n\t\t\t\tnlassert( updatecounter < record.UpdateCounter ); // not >\n\t\t\t\t_PreloadedRecords.push_back( record ); // when we read one too far\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\n\n/*\n * Push the received blocks for this counter into the receive queue\n */\nvoid CMessageRecorder::replayNextDataAvailable( sint64 updatecounter )\n{\n\tTMessageRecord rec( true ); // input message\n\n\twhile ( getNext( rec, updatecounter ) )\n\t{\n\t\tswitch ( rec.Event )\n\t\t{\n\t\tcase Receiving :\n\t\tcase Accepting :\n\t\tcase Disconnecting :\n\t\t\tReceivedMessages.push( rec );\n\t\t\tbreak;\n\n\t\tcase Sending :\n\t\t\tbreak;\n\n\t\tcase Connecting :\n\t\tcase ConnFailing :\n\t\t\t_ConnectionAttempts.push_back( rec );\n\t\t\tbreak;\n\n\t\tdefault :\n\t\t\tnlstop;\n\t\t}\n\t}\n}\n\n\n/*\n * Returns true and the event type if the counter of the next data is updatecounter\n */\nTNetworkEvent CMessageRecorder::checkNextOne( sint64 updatecounter )\n{\n\tTMessageRecord record;\n\tif ( getNext( record, updatecounter ) )\n\t{\n\t\tnldebug( \"MR: Check next one: %s at update %\" NL_I64 \"u\", EventToString(record.Event).c_str(), updatecounter );\n\t\treturn record.Event;\n\t}\n\telse\n\t{\n\t\treturn Error;\n\t}\n}\n\n\n/*\n * Get the first stored connection attempt corresponding to addr\n */\nTNetworkEvent CMessageRecorder::replayConnectionAttempt( const CInetAddress& addr )\n{\n\tTNetworkEvent event;\n\tdeque<TMessageRecord>::iterator ipr;\n\n\tif ( ! _ConnectionAttempts.empty() )\n\t{\n\t\t// Search in the already processed connection attempts\n\t\tfor ( ipr=_ConnectionAttempts.begin(); ipr!=_ConnectionAttempts.end(); ++ipr )\n\t\t{\n\t\t\tCInetAddress stored_addr;\n\t\t\t(*ipr).Message.serial( stored_addr );\n\t\t\tif ( stored_addr == addr )\n\t\t\t{\n\t\t\t\t// Found\n\t\t\t\tevent = (*ipr).Event;\n\t\t\t\tnldebug( \"MR: Connection attempt found at update %\" NL_I64 \"u\", (*ipr).UpdateCounter );\n\t\t\t\t_ConnectionAttempts.erase( ipr );\n\t\t\t\treturn event;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Seek in the preloaded records\n\tfor ( ipr=_PreloadedRecords.begin(); ipr!=_PreloadedRecords.end(); ++ipr )\n\t{\n\t\tevent = (*ipr).Event;\n\t\tif ( (event == Connecting) || (event == ConnFailing) )\n\t\t{\n\t\t\tCInetAddress stored_addr;\n\t\t\t(*ipr).Message.serial( stored_addr );\n\t\t\tif ( stored_addr == addr )\n\t\t\t{\n\t\t\t\t// Found\n\t\t\t\tnldebug( \"MR: Connection attempt found at update %\" NL_I64 \"u\", (*ipr).UpdateCounter );\n\t\t\t\t_PreloadedRecords.erase( ipr );\n\t\t\t\treturn event;\n\t\t\t}\n\t\t}\n\t}\n\tif ( ipr==_PreloadedRecords.end() )\n\t{\n\t\t// If not found, load next records until found !\n\t\tTMessageRecord rec( true );\n\t\twhile ( loadNext( rec ) )\n\t\t{\n\t\t\tif ( ( rec.Event == Connecting ) || ( rec.Event == ConnFailing ) )\n\t\t\t{\n\t\t\t\tCInetAddress stored_addr;\n\t\t\t\trec.Message.serial( stored_addr );\n\t\t\t\tif ( stored_addr == addr )\n\t\t\t\t{\n\t\t\t\t\t// Found\n\t\t\t\t\tnldebug( \"MR: Connection attempt found at update %\" NL_I64 \"u\", rec.UpdateCounter );\n\t\t\t\t\treturn rec.Event;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t_PreloadedRecords.push_back( rec );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_PreloadedRecords.push_back( rec );\n\t\t\t}\n\t\t}\n\t\t// Not found\n\t\tnldebug( \"MR: Connection attempt not found\" );\n\t\treturn Error;\n\t}\n\tnlstop;\n\treturn Error;\n}\n\n\n/*\n * Stop playback\n */\nvoid CMessageRecorder::stopReplay()\n{\n\t_File.close();\n\t_Filename = \"\";\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/module.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/inet_address.h\"\n#include \"nel/net/module_message.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module_socket.h\"\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nnamespace NLNET\n{\n\n\t//////////////////////////////////////\n\t// Module interceptor implementation\n\t//////////////////////////////////////\n\tIModuleInterceptable::IModuleInterceptable()\n\t\t: _Registrar(NULL)\n\t{\n\t}\n\n\tIModuleInterceptable::~IModuleInterceptable()\n\t{\n\t\tif (_Registrar != NULL)\n\t\t\t_Registrar->unregisterInterceptor(this);\n\t}\n\n\tvoid IModuleInterceptable::registerInterceptor(IInterceptorRegistrar *registrar)\n\t{\n\t\tnlassert(registrar != NULL);\n\n\t\t_Registrar = registrar;\n\n\t\t_Registrar->registerInterceptor(this);\n\t}\n\n\tvoid IModuleInterceptable::interceptorUnregistered(IInterceptorRegistrar *registrar)\n\t{\n\t\tnlassert(registrar == _Registrar);\n\n\t\t_Registrar = NULL;\n\t}\n\n\tIInterceptorRegistrar *IModuleInterceptable::getRegistrar()\n\t{\n\t\treturn _Registrar;\n\t}\n\n\n\t//////////////////////////////////////\n\t// Module factory implementation\n\t//////////////////////////////////////\n\n\tIModuleFactory::IModuleFactory(const std::string &moduleClassName)\n\t\t: _ModuleClassName(moduleClassName)\n\t{\n\t}\n\n\tIModuleFactory::~IModuleFactory()\n\t{\n\t\t// Delete any module that still exist\n\t\twhile (!_ModuleInstances.empty())\n\t\t{\n\t\t\tCRefPtr<IModule> sanityCheck(*(_ModuleInstances.begin()));\n\n\t\t\tIModuleManager::getInstance().deleteModule(sanityCheck);\n\n\t\t\t// container is cleared by deleteModule (see below)\n\t\t\t// make sure the module is effectively destroyed\n\t\t\t// NB : is the code assert here, this mean that some user code\n\t\t\t// (or eventualy NeL code) have kept a smart pointer on the module\n\t\t\t// and this is bad. All smart pointer MUST be released when the\n\t\t\t// factory is about to be removed.\n\t\t\tnlassertex(sanityCheck == NULL, (\"Some code have kept pointer on module '%s'\", sanityCheck->getModuleName().c_str()));\n\t\t}\n\n\t\t// if the context is still active\n\t\tif (INelContext::isContextInitialised() && IModuleManager::isInitialized())\n\t\t\t// This factory is no longer available\n\t\t\tIModuleManager::getInstance().unregisterModuleFactory(this);\n\t}\n\n\tconst std::string &IModuleFactory::getModuleClassName() const\n\t{\n\t\treturn _ModuleClassName;\n\t}\n\n\n\tvoid IModuleFactory::deleteModule(IModule *module)\n\t{\n\t\tset<TModulePtr>::iterator it(_ModuleInstances.find(module));\n\t\tnlassert(it != _ModuleInstances.end());\n\n\t\tCRefPtr<IModule> sanityCheck(module);\n\n\t\t// removing this smart ptr must release the module\n\t\t_ModuleInstances.erase(it);\n\n\t\tnlassert(sanityCheck == NULL);\n\t}\n\n\tvoid IModuleFactory::registerModuleInFactory(TModulePtr module)\n\t{\n\t\tnlassert(module != NULL);\n\n\t\tnlassert(_ModuleInstances.find(module) == _ModuleInstances.end());\n\n\t\t// keep track of the module\n\t\t_ModuleInstances.insert(module);\n\n\t\tmodule->setFactory(this);\n\t}\n\n\t//////////////////////////////////////\n\t// CModuleTask implementation\n\t//////////////////////////////////////\n\tCModuleTask::CModuleTask (class CModuleBase * /*module */)\n\t\t: _FailInvoke(false)\n\t{\n//\t\tmodule->queueModuleTask(this);\n\t}\n\n\n\tvoid CModuleTask::initMessageQueue(CModuleBase * /* module */)\n\t{\n\t}\n\n\tvoid CModuleTask::flushMessageQueue(CModuleBase *module)\n\t{\n\t\t// process any queued message\n\t\twhile (!module->_SyncMessages.empty())\n\t\t{\n\t\t\tIModuleProxy *proxy = module->_SyncMessages.front().first;\n\t\t\tCMessage &msg = module->_SyncMessages.front().second;\n\n\t\t\tmodule->_onProcessModuleMessage(proxy, msg);\n\n\t\t\tmodule->_SyncMessages.pop_front();\n\t\t}\n\t}\n\n\tvoid CModuleTask::processPendingMessage(CModuleBase *module)\n\t{\n\t\tflushMessageQueue(module);\n\t}\n\n\n\t//////////////////////////////////////\n\t// Module base implementation\n\t//////////////////////////////////////\n\n\tCModuleBase::CModuleBase()\n\t\t: _CurrentSender(NULL),\n\t\t  _CurrentMessage(NULL),\n\t\t  _CurrentMessageFailed(false),\n\t\t  _MessageDispatchTask(NULL),\n\t\t  _ModuleFactory(NULL),\n\t\t  _ModuleId(INVALID_MODULE_ID)\n\t{\n\t\t// register module itself in the interceptor list\n\t\tIModuleInterceptable::registerInterceptor(this);\n\t}\n\n\tCModuleBase::~CModuleBase()\n\t{\n\t\t// deleting a module from it's own current task is forbiden\n\t\tnlassert(_ModuleTasks.empty()\n\t\t\t||  CCoTask::getCurrentTask() != _ModuleTasks.front());\n\n\t\t// terminate and release any pending module task\n\t\twhile (!_ModuleTasks.empty())\n\t\t{\n\t\t\tCModuleTask *task = _ModuleTasks.front();\n\n\t\t\t// deleting the task will waiting it to terminate\n\t\t\tdelete task;\n\n\t\t\t_ModuleTasks.erase(_ModuleTasks.begin());\n\t\t}\n\n\t\tif (_MessageDispatchTask)\n\t\t{\n\t\t\t// delete reception task\n\t\t\tdelete _MessageDispatchTask;\n\t\t}\n\n\t\t// unregister all interceptors\n\t\twhile (!_ModuleInterceptors.empty())\n\t\t{\n\t\t\tIModuleInterceptable *interceptor = *(_ModuleInterceptors.begin());\n\t\t\tunregisterInterceptor(interceptor);\n\t\t}\n\t}\n\n\tvoid CModuleBase::registerInterceptor(IModuleInterceptable *interceptor)\n\t{\n\t\t// check that this interceptor not already registered\n\t\tnlassert(find(_ModuleInterceptors.begin(), _ModuleInterceptors.end(), interceptor) == _ModuleInterceptors.end());\n\n\t\t// insert the interceptor in the list\n\t\t_ModuleInterceptors.push_back(interceptor);\n\t}\n\n\tvoid CModuleBase::unregisterInterceptor(IModuleInterceptable *interceptor)\n\t{\n\t\tTInterceptors::iterator it = find(_ModuleInterceptors.begin(), _ModuleInterceptors.end(), interceptor);\n\t\tnlassert(it != _ModuleInterceptors.end());\n\n\t\t_ModuleInterceptors.erase(it);\n\n\t\tinterceptor->interceptorUnregistered(this);\n\t}\n\n\tTModuleId\t\t\tCModuleBase::getModuleId() const\n\t{\n\t\treturn _ModuleId;\n\t}\n\n\tconst std::string\t&CModuleBase::getModuleName() const\n\t{\n\t\treturn _ModuleName;\n\t}\n\n\tconst std::string\t&CModuleBase::getModuleClassName() const\n\t{\n\t\treturn _ModuleFactory->getModuleClassName();\n\t}\n\n\tconst std::string\t&CModuleBase::getModuleFullyQualifiedName() const\n\t{\n\t\tif (_FullyQualifedModuleName.empty())\n\t\t{\n\t\t\tnlassertex(!_ModuleName.empty(), (\"Call to CModuleBase::getModuleFullyQualifiedName before module name have been set (did you call from module constructor ?)\"));\n\t\t\t// build the name\n\t\t\tstring hostName;\n\t\t\tif (IService::isServiceInitialized())\n\t\t\t\thostName = IService::getInstance()->getHostName();\n\t\t\telse\n\t\t\t\thostName = ::NLNET::CInetAddress::localHost().hostName();\n//\t\t\tint pid = ::getpid();\n\n\t\t\t_FullyQualifedModuleName = IModuleManager::getInstance().getUniqueNameRoot()+\":\"+_ModuleName;\n\t\t}\n\n\t\treturn _FullyQualifedModuleName;\n\t}\n\n\tstd::string\tCModuleBase::getModuleManifest() const\n\t{\n\t\tstring manifest;\n\n\t\t// call each interceptor in order to build the manifest\n\t\tTInterceptors::const_iterator first(_ModuleInterceptors.begin()), last(_ModuleInterceptors.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tIModuleInterceptable *interceptor = *first;\n\n\t\t\tmanifest += interceptor->buildModuleManifest() + \" \";\n\t\t}\n\n\t\tif (!manifest.empty() && manifest[manifest.size()-1] == ' ')\n\t\t\tmanifest.resize(manifest.size()-1);\n\n\t\treturn manifest;\n\t}\n\n\tvoid\tCModuleBase::onReceiveModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message)\n\t{\n\t\tH_AUTO(CModuleBase_onReceiveModuleMessage);\n\n\t\tif (!_ModuleTasks.empty())\n\t\t{\n\t\t\t// there is a task running, queue in the message\n\t\t\t_SyncMessages.push_back(make_pair(senderModuleProxy, message));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// go in user code for processing\n\t\t\tif (_MessageDispatchTask != NULL)\n\t\t\t{\n\t\t\t\t// process the message in the co task\n\t\t\t\t_CurrentSender = senderModuleProxy;\n\t\t\t\t_CurrentMessage = &message;\n\n\t\t\t\t_MessageDispatchTask->resume();\n\n\t\t\t\tif (_CurrentMessageFailed)\n\t\t\t\t\tthrow IModule::EInvokeFailed();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// normal processing by the main task\n\t\t\t\t_onProcessModuleMessage(senderModuleProxy, message);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid CModuleBase::_receiveModuleMessageTask()\n\t{\n\t\tH_AUTO(CModuleBase__receiveModuleMessageTask);\n\n\t\twhile (!_MessageDispatchTask->isTerminationRequested())\n\t\t{\n\t\t\t// we have a message to dispatch\n\t\t\ttry\n\t\t\t{\n\t\t\t\t// take a copy of the message to dispatch\n\t\t\t\tIModuleProxy *currentSender = _CurrentSender;\n\t\t\t\tCMessage currentMessage = *_CurrentMessage;\n\t\t\t\t_onProcessModuleMessage(currentSender, currentMessage);\n\t\t\t\t_CurrentMessageFailed = false;\n\t\t\t}\n\t\t\tcatch (const NLMISC::Exception &e)\n\t\t\t{\n\t\t\t\tnlwarning(\"In module task '%s' (cotask message receiver), exception '%e' thrown\", typeid(this).name(), e.what());\n\t\t\t\t// an exception have been thrown\n\t\t\t\t_CurrentMessageFailed = true;\n\t\t\t}\n\t\t\tcatch (...)\n\t\t\t{\n\t\t\t\tnlwarning(\"In module task '%s' (cotask message receiver), unknown exception thrown\", typeid(this).name());\n\t\t\t\t// an exception have been thrown\n\t\t\t\t_CurrentMessageFailed = true;\n\t\t\t}\n\t\t\t// switch to main task\n\t\t\t_MessageDispatchTask->yield();\n\t\t}\n\t}\n\n\n\tvoid CModuleBase::queueModuleTask(CModuleTask *task)\n\t{\n\t\t_ModuleTasks.push_back(task);\n\t}\n\n\tCModuleTask *CModuleBase::getActiveModuleTask()\n\t{\n\t\tif (_ModuleTasks.empty())\n\t\t\treturn NULL;\n\n\t\treturn _ModuleTasks.front();\n\t}\n\n\n\tconst std::string &CModuleBase::getInitStringHelp()\n\t{\n\t\tstatic string help;\n\t\treturn help;\n\t}\n\n\t// Init base module, init module name\n\tbool\tCModuleBase::initModule(const TParsedCommandLine &initInfo)\n\t{\n\t\t// read module init param for base module .\n\n\t\tif (initInfo.getParam(\"base.useCoTaskDispatch\"))\n\t\t{\n\t\t\t// init the message dispatch task\n//\t\t\tNLNET_START_MODULE_TASK(CModuleBase, _receiveModuleMessageTask);\n//\tTModuleTask<className> *task = new TModuleTask<className>(this, &className::methodName);\n\t\t\t _MessageDispatchTask = new TModuleTask<CModuleBase>(this,  TModuleTask<CModuleBase>::TMethodPtr(&CModuleBase::_receiveModuleMessageTask));\n\t\t}\n\n\t\t// register this module in the command executor\n\t\tregisterCommandsHandler();\n\n\t\treturn true;\n\t}\n\n\tconst std::string &CModuleBase::getCommandHandlerName() const\n\t{\n\t\treturn getModuleName();\n\t}\n\n\n\tvoid CModuleBase::plugModule(IModuleSocket *moduleSocket) throw (EModuleAlreadyPluggedHere)\n\t{\n\t\tCModuleSocket *sock = dynamic_cast<CModuleSocket*>(moduleSocket);\n\t\tnlassert(sock != NULL);\n\n\t\tTModuleSockets::iterator it(_ModuleSockets.find(moduleSocket));\n\t\tif (it != _ModuleSockets.end())\n\t\t\tthrow EModuleAlreadyPluggedHere();\n\n\n\t\t// ok, we can plug the module\n\n\t\tsock->_onModulePlugged(this);\n\n\t\t// all fine, store the socket pointer.\n\t\t_ModuleSockets.insert(moduleSocket);\n\t}\n\n\tvoid CModuleBase::unplugModule(IModuleSocket *moduleSocket)  throw (EModuleNotPluggedHere)\n\t{\n\t\tCModuleSocket *sock = dynamic_cast<CModuleSocket*>(moduleSocket);\n\t\tnlassert(sock != NULL);\n\n\t\tTModuleSockets::iterator it(_ModuleSockets.find(moduleSocket));\n\t\tif (it == _ModuleSockets.end())\n\t\t\tthrow EModuleNotPluggedHere();\n\n\t\tsock->_onModuleUnplugged(TModulePtr(this));\n\n\t\t_ModuleSockets.erase(it);\n\t}\n\n\tvoid CModuleBase::getPluggedSocketList(std::vector<IModuleSocket*> &resultList)\n\t{\n\t\tTModuleSockets::iterator first(_ModuleSockets.begin()), last(_ModuleSockets.end());\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\tresultList.push_back(*first);\n\t\t}\n\t}\n\n\t/** Do a module operation invocation.\n\t *\tCaller MUST be in a module task to call this method.\n\t *\tThe call is blocking until receptions of the operation\n\t *\tresult message (or a module down)\n\t */\n\tvoid CModuleBase::invokeModuleOperation(IModuleProxy *destModule, const NLNET::CMessage &opMsg, NLNET::CMessage &resultMsg) throw (EInvokeFailed)\n\t{\n\t\tH_AUTO(CModuleBase_invokeModuleOperation);\n\n\t\tnlassert(opMsg.getType() == CMessage::Request);\n\n\t\t// check that we are running in a coroutine task\n\t\tCModuleTask *task = dynamic_cast<CModuleTask *>(CCoTask::getCurrentTask());\n\t\tnlassert(task != NULL);\n\t\t// send the message to the module\n\t\tdestModule->sendModuleMessage(this, opMsg);\n\n\t\t// fill the invoke stack\n\t\t_InvokeStack.push_back(destModule);\n\n\t\tfor (;;)\n\t\t{\n\t\t\t// yield and wait for messages\n\t\t\ttask->yield();\n\n\t\t\tif (task->mustFailInvoke())\n\t\t\t{\n\t\t\t\tnlassert(!_InvokeStack.empty());\n\t\t\t\t// empty the invoke stack\n\t\t\t\t_InvokeStack.pop_back();\n\n\t\t\t\ttask->resetFailInvoke();\n\n\t\t\t\tthrow EInvokeFailed();\n\t\t\t}\n\n\t\t\twhile (!_SyncMessages.empty())\n\t\t\t{\n\t\t\t\tIModuleProxy *proxy = _SyncMessages.front().first;\n\t\t\t\tCMessage &msg = _SyncMessages.front().second;\n\t\t\t\tif (msg.getType() == CMessage::Response)\n\t\t\t\t{\n\t\t\t\t\t// we have the response message\n\t\t\t\t\tnlassert(proxy == destModule);\n\t\t\t\t\tresultMsg = msg;\n\t\t\t\t\t// remove this message form the queue\n\t\t\t\t\t_SyncMessages.pop_front();\n\t\t\t\t\t// empty the invoke stack\n\t\t\t\t\t_InvokeStack.pop_back();\n\t\t\t\t\t// stop reading received message now\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse if (msg.getType() == CMessage::Except)\n\t\t\t\t{\n\t\t\t\t\t// the other side returned an exception !\n\n\t\t\t\t\t// empty the invoke stack\n\t\t\t\t\t_InvokeStack.pop_back();\n\n\t\t\t\t\tthrow EInvokeFailed();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// another message, dispatch it normally\n//\t\t\t\t\tCMessage::TMessageType msgType = msg.getType();\n//\t\t\t\t\ttry\n//\t\t\t\t\t{\n\t\t\t\t\t\t_onProcessModuleMessage(proxy, msg);\n//\t\t\t\t\t}\n//\t\t\t\t\tcatch(...)\n//\t\t\t\t\t{\n//\t\t\t\t\t\tnlwarning(\"Some exception where throw will dispatching message '%s' from '%s' to '%s'\",\n//\t\t\t\t\t\t\tmsg.getName().c_str(),\n//\t\t\t\t\t\t\tproxy->getModuleName().c_str(),\n//\t\t\t\t\t\t\tthis->getModuleName().c_str());\n//\n//\t\t\t\t\t\tif (msgType == CMessage::Request)\n//\t\t\t\t\t\t{\n//\t\t\t\t\t\t\t// send back an exception message\n//\t\t\t\t\t\t\tCMessage except;\n//\t\t\t\t\t\t\texcept.setType(\"EXCEPT\", CMessage::Except);\n//\t\t\t\t\t\t\tproxy->sendModuleMessage(this, except);\n//\t\t\t\t\t\t}\n//\n//\t\t\t\t\t}\n\n\t\t\t\t\t// remove this message form the queue\n\t\t\t\t\t_SyncMessages.pop_front();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid CModuleBase::_onModuleUp(IModuleProxy *removedProxy)\n\t{\n\t\tH_AUTO(CModuleBase__onModuleUp);\n\n\t\t// call the normal callback in the interceptor list\n\t\tTInterceptors::iterator first(_ModuleInterceptors.begin()), last(_ModuleInterceptors.end());\n\t\tfor (;first != last; ++first)\n\t\t{\n\t\t\tIModuleInterceptable *interceptor = *first;\n\t\t\tinterceptor->onModuleUp(removedProxy);\n\t\t}\n\t}\n\n\tvoid CModuleBase::_onModuleDown(IModuleProxy *removedProxy)\n\t{\n\t\tH_AUTO(CModuleBase__onModuleDown);\n\n\t\t// remove any message from the message queue that come from this proxy\n\t\t{\n\t\t\tTMessageList::iterator first(_SyncMessages.begin()), last(_SyncMessages.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (first->first == removedProxy)\n\t\t\t\t{\n\t\t\t\t\t_SyncMessages.erase(first);\n\t\t\t\t\tfirst = _SyncMessages.begin();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// check the invocation stack also\n\t\t{\n\t\t\tTInvokeStack::iterator first(_InvokeStack.begin()), last(_InvokeStack.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (*first == removedProxy)\n\t\t\t\t{\n\t\t\t\t\t// at least, we need either a running task or the default dispatch task activated\n\t\t\t\t\tnlassert(!_ModuleTasks.empty() || _MessageDispatchTask != NULL);\n\n\t\t\t\t\t// gasp, we lost one of the module needed to managed the invocation stack!\n\t\t\t\t\t// make each call generate an exception\n\t\t\t\t\twhile (first != _InvokeStack.end())\n\t\t\t\t\t{\n\t\t\t\t\t\t// The module task can be either the first in the module task list or\n\t\t\t\t\t\t// the co routine dispatching task if it is activated\n\t\t\t\t\t\tCModuleTask *task = !_ModuleTasks.empty() ? _ModuleTasks.front() : _MessageDispatchTask;\n\t\t\t\t\t\ttask->failInvoke();\n\t\t\t\t\t\t// switch to task to unstack one level\n\t\t\t\t\t\ttask->resume();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// call the normal callback in the interceptor list\n\t\tTInterceptors::iterator first(_ModuleInterceptors.begin()), last(_ModuleInterceptors.end());\n\t\tfor (;first != last; ++first)\n\t\t{\n\t\t\t(*first)->onModuleDown(removedProxy);\n\t\t}\n\t}\n\n\tbool CModuleBase::_onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &message)\n\t{\n\t\tH_AUTO(CModuleBase__OnProcessModuleMessage);\n\n\t\t// try the call on each interceptor\n\t\tbool result;\n\t\tresult = false;\n\n\t\ttry\n\t\t{\n\t\t\tTInterceptors::iterator first(_ModuleInterceptors.begin()), last(_ModuleInterceptors.end());\n\t\t\tfor (;first != last; ++first)\n\t\t\t{\n\t\t\t\tif ((*first)->onProcessModuleMessage(senderModuleProxy, message))\n\t\t\t\t{\n\t\t\t\t\tresult = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch(...)\n\t\t{\n\t\t\tnlwarning(\"Some exception where throw will dispatching message '%s' from '%s' to '%s'\",\n\t\t\t\tmessage.getName().c_str(),\n\t\t\t\tsenderModuleProxy->getModuleName().c_str(),\n\t\t\t\tthis->getModuleName().c_str());\n\n\t\t\tif (message.getType() == CMessage::Request)\n\t\t\t{\n\t\t\t\t// send back an exception message\n\t\t\t\tCMessage except;\n\t\t\t\texcept.setType(\"EXCEPT\", CMessage::Except);\n\t\t\t\tsenderModuleProxy->sendModuleMessage(this, except);\n\t\t\t}\n\t\t\t// here we return true because the message have been processed\n\t\t\t// (even if the processing have raised some exception !)\n\t\t\tresult = true;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tvoid CModuleBase::setFactory(IModuleFactory *factory)\n\t{\n\t\tnlassert(_ModuleFactory == NULL);\n\n\t\t_ModuleFactory = factory;\n\t}\n\n\tIModuleFactory *CModuleBase::getFactory()\n\t{\n\t\treturn _ModuleFactory;\n\t}\n\n\tNLMISC_CLASS_COMMAND_IMPL(CModuleBase, plug)\n\t{\n\t\tnlunreferenced(human);\n\t\tnlunreferenced(quiet);\n\t\tnlunreferenced(rawCommandString);\n\n\t\tif (args.size() != 1)\n\t\t\treturn false;\n\n\t\tIModuleSocket *socket = IModuleManager::getInstance().getModuleSocket(args[0]);\n\n\t\tif (socket == NULL)\n\t\t{\n\t\t\tlog.displayNL(\"Unknown socket named '%s'\", args[0].c_str());\n\t\t\treturn true;\n\t\t}\n\n\t\tplugModule(socket);\n\n\t\tif (_ModuleSockets.find(socket) == _ModuleSockets.end())\n\t\t{\n\t\t\tlog.displayNL(\"Failed to plug the module '%s' into the socket '%s'\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tsocket->getSocketName().c_str());\n\t\t}\n\t\telse\n\t\t\tlog.displayNL(\"Module '%s' plugged into the socket '%s'\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tsocket->getSocketName().c_str());\n\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_IMPL(CModuleBase, unplug)\n\t{\n\t\tnlunreferenced(human);\n\t\tnlunreferenced(quiet);\n\t\tnlunreferenced(rawCommandString);\n\n\t\tif (args.size() != 1)\n\t\t\treturn false;\n\n\t\tIModuleSocket *socket = IModuleManager::getInstance().getModuleSocket(args[0]);\n\n\t\tif (socket == NULL)\n\t\t{\n\t\t\tlog.displayNL(\"Unknown socket named '%s'\", args[0].c_str());\n\t\t\treturn true;\n\t\t}\n\n\t\tif (_ModuleSockets.find(socket) == _ModuleSockets.end())\n\t\t{\n\t\t\tlog.displayNL(\"The module '%s' is not plugged in the socket '%s'\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tsocket->getSocketName().c_str());\n\t\t\treturn true;\n\t\t}\n\n\t\tunplugModule(socket);\n\n\t\tif (_ModuleSockets.find(socket) != _ModuleSockets.end())\n\t\t\tlog.displayNL(\"Failed to unplug the module '%s' from the socket '%s'\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tsocket->getSocketName().c_str());\n\t\telse\n\t\t\tlog.displayNL(\"Module '%s' unplugged out of the socket '%s'\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tsocket->getSocketName().c_str());\n\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_IMPL(CModuleBase, sendPing)\n\t{\n\t\tnlunreferenced(human);\n\t\tnlunreferenced(quiet);\n\t\tnlunreferenced(rawCommandString);\n\n\t\tif (args.size() != 1)\n\t\t\treturn false;\n\n\t\tstring modName = args[0];\n\n\t\t// look in each socket\n\t\tvector<IModuleSocket*> sockets;\n\t\tthis->getPluggedSocketList(sockets);\n\n\t\tfor (uint i=0; i<sockets.size(); ++i)\n\t\t{\n\t\t\tIModuleSocket *socket = sockets[i];\n\t\t\tvector<IModuleProxy*> proxList;\n\t\t\tsocket->getModuleList(proxList);\n\n\t\t\tfor (uint i=0; i<proxList.size(); ++i)\n\t\t\t{\n\t\t\t\tif (proxList[i]->getModuleName() == modName)\n\t\t\t\t{\n\t\t\t\t\t// we found it !\n\t\t\t\t\tCMessage ping(\"DEBUG_MOD_PING\");\n\t\t\t\t\tproxList[i]->sendModuleMessage(this, ping);\n\t\t\t\t\tlog.displayNL(\"Ping debug message send to '%s'\", modName.c_str());\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlog.displayNL(\"Can't find a route to send message to module '%s'\", modName.c_str());\n\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_IMPL(CModuleBase, dump)\n\t{\n\t\tnlunreferenced(human);\n\t\tnlunreferenced(quiet);\n\t\tnlunreferenced(rawCommandString);\n\n\t\tif (args.size() != 0)\n\t\t\treturn false;\n\n\t\tlog.displayNL(\"---------------------------\");\n\t\tlog.displayNL(\"Dumping base module state :\");\n\t\tlog.displayNL(\"---------------------------\");\n\t\tlog.displayNL(\"  Module name      : '%s'\", getModuleName().c_str());\n\t\tlog.displayNL(\"  Module full name : '%s'\", getModuleFullyQualifiedName().c_str());\n\t\tlog.displayNL(\"  Module class     : '%s'\", _ModuleFactory->getModuleClassName().c_str());\n\t\tlog.displayNL(\"  Module ID        : %u\", _ModuleId);\n\t\tlog.displayNL(\"  The module is plugged into %u sockets :\", _ModuleSockets.size());\n\t\t{\n\t\t\tTModuleSockets::iterator first(_ModuleSockets.begin()), last(_ModuleSockets.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModuleSocket *ps = *first;\n\t\t\t\tvector<IModuleProxy*>\tproxies;\n\t\t\t\tps->getModuleList(proxies);\n\n\t\t\t\tlog.displayNL(\"    Socket '%s', %u modules reachable :\", ps->getSocketName().c_str(), proxies.size()-1);\n\n\t\t\t\tfor (uint i=0; i<proxies.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tstring name = proxies[i]->getModuleName();\n\t\t\t\t\tif (name.find('/') != string::npos)\n\t\t\t\t\t\tname = name.substr(name.find('/')+1);\n\t\t\t\t\tif (name != getModuleFullyQualifiedName())\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"      Module '%s' (Module Proxy ID : %u, class : '%s')\",\n\t\t\t\t\t\t\tproxies[i]->getModuleName().c_str(),\n\t\t\t\t\t\t\tproxies[i]->getModuleProxyId(),\n\t\t\t\t\t\t\tproxies[i]->getModuleClassName().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\n\t/************************************************************************\n\t * CModuleProxy impl\n\t ************************************************************************/\n\n\tCModuleProxy::CModuleProxy(TModulePtr localModule, TModuleId localModuleId, const std::string &moduleClassName, const std::string &fullyQualifiedModuleName, const std::string &moduleManifest)\n\t\t: _ModuleProxyId(localModuleId),\n\t\t  _ForeignModuleId(INVALID_MODULE_ID),\n\t\t  _LocalModule(localModule),\n\t\t  _ModuleClassName(CStringMapper::map(moduleClassName)),\n\t\t  _FullyQualifiedModuleName(CStringMapper::map(fullyQualifiedModuleName)),\n\t\t  _Manifest(moduleManifest),\n\t\t  _SecurityData(NULL)\n\t{\n\t}\n\n\tTModuleId\tCModuleProxy::getModuleProxyId() const\n\t{\n\t\treturn _ModuleProxyId;\n\t}\n\n\tTModuleId\tCModuleProxy::getForeignModuleId() const\n\t{\n\t\treturn _ForeignModuleId;\n\t}\n\n\tuint32\t\tCModuleProxy::getModuleDistance() const\n\t{\n\t\treturn _Distance;\n\t}\n\n\tIModule\t\t\t\t*CModuleProxy::getLocalModule() const\n\t{\n\t\treturn _LocalModule;\n\t}\n\n\tCGatewayRoute\t\t*CModuleProxy::getGatewayRoute() const\n\t{\n\t\treturn _Route;\n\t}\n\n\tconst std::string &CModuleProxy::getModuleName() const\n\t{\n\t\treturn CStringMapper::unmap(_FullyQualifiedModuleName);\n\t}\n\tconst std::string &CModuleProxy::getModuleClassName() const\n\t{\n\t\treturn CStringMapper::unmap(_ModuleClassName);\n\t}\n\n\tconst std::string &CModuleProxy::getModuleManifest() const\n\t{\n\t\treturn _Manifest;\n\t}\n\n\n\tIModuleGateway *CModuleProxy::getModuleGateway() const\n\t{\n\t\treturn _Gateway;\n\t}\n\n\tvoid\t\tCModuleProxy::sendModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\tthrow (EModuleNotReachable)\n\t{\n\t\tH_AUTO(CModuleProxy_sendModuleMessage);\n\n\t\tif (_Gateway == NULL )\n\t\t{\n\t\t\tthrow EModuleNotReachable();\n\t\t}\n\n\t\t// We need to find the proxy for the sender using the addressee gateway\n\t\tIModuleProxy *senderProx = _Gateway->getPluggedModuleProxy(senderModule);\n\t\tif (senderProx == NULL )\n\t\t{\n\t\t\tthrow EModuleNotReachable();\n\t\t}\n\n\t\t_Gateway->sendModuleMessage(senderProx, this, message);\n\t}\n\n\tconst TSecurityData *CModuleProxy::findSecurityData(uint8 dataTag) const\n\t{\n\t\tconst TSecurityData *ms = _SecurityData;\n\n\t\twhile (ms != NULL)\n\t\t{\n\t\t\tif (ms->DataTag == dataTag)\n\t\t\t{\n\t\t\t\t// this block match !\n\t\t\t\treturn ms;\n\t\t\t}\n\n\t\t\t// try the next one\n\t\t\tms = ms->NextItem;\n\t\t}\n\n\t\t// not found\n\t\treturn NULL;\n\t}\n\n\n} // namespace NLNET\n"
  },
  {
    "path": "code/nel/src/net/module_common.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/net/module_common.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET\n{\n\n\tTParsedCommandLine::TParsedCommandLine(const TParsedCommandLine& copy)\n\t\t:ParamName(copy.ParamName), ParamValue(copy.ParamValue)\n\t{\n\n\n\n\t\tuint first = 0, last = (uint)copy.SubParams.size();\n\t\tSubParams.resize( last );\n\t\tfor (; first != last; ++first)\n\t\t{\n\t\t\t// calls recursively copy constructor\n\t\t\tSubParams[first] = new TParsedCommandLine(*copy.SubParams[first]);\n\t\t}\n\n\t}\n\n\tTParsedCommandLine::~TParsedCommandLine()\n\t{\n\t\tclear();\n\t};\n\n\tvoid TParsedCommandLine::clear()\n\t{\n\t\tfor (std::vector<TParsedCommandLine*>::iterator it=SubParams.begin(); it!=SubParams.end(); ++it)\n\t\t{\n\t\t\tdelete (*it);\n\t\t}\n\t\tSubParams.clear();\n\t\tParamName.clear();\n\t\tParamValue.clear();\n\t}\n\n\tbool TParsedCommandLine::parseParamList(const std::string &rawParamString)\n\t{\n\t\t// Cleanup the struct\n\t\tclear();\n\n\t\treturn _parseParamList(rawParamString);\n\t}\n\n\tstd::string TParsedCommandLine::toString() const\n\t{\n\t\tstring ret;\n\n\t\tret = ParamName;\n\t\tif (!ParamValue.empty())\n\t\t{\n\t\t\tret += \" = \"+ParamValue;\n\t\t}\n\n\t\tif (!SubParams.empty())\n\t\t{\n\t\t\tret += \" ( \";\n\n\t\t\tfor (uint i=0; i<SubParams.size(); ++i)\n\t\t\t{\n\t\t\t\tif (i >0)\n\t\t\t\t\tret += \" \";\n\t\t\t\tret += SubParams[i]->toString();\n\t\t\t}\n\n\t\t\tret += \" ) \";\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\n\n\tbool TParsedCommandLine::_parseParamList(const std::string &rawParamString)\n\t{\n\t\tCSString parsedString(rawParamString);\n\n\t\tfor (CSString part = parsedString.strtok(\" \\t\", true, false);\n\t\t\t!part.empty();\n\t\t\tpart = parsedString.strtok(\" \\t\", true, false))\n\t\t{\n\t\t\tif (part[0] == '(')\n\t\t\t{\n\t\t\t\t// this is a sub parameter list\n\t\t\t\tif (SubParams.empty() || SubParams.back()->ParamName.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"While parsing param string '%s', missing param header\", rawParamString.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (!SubParams.back()->ParamValue.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"While parsing param string '%s', Invalid sub param header '%s' for sub part '%s', must not define value\",\n\t\t\t\t\t\trawParamString.c_str(),\n\t\t\t\t\t\tSubParams.back()->ParamName.c_str(),\n\t\t\t\t\t\tpart.c_str());\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (part[part.size()-1] != ')')\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"While parsing param string '%s', Invalid sub param value '%s' missing closing ')'\",\n\t\t\t\t\t\trawParamString.c_str(),\n\t\t\t\t\t\tpart.c_str());\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tpart = part.stripBlockDelimiters();\n\n\t\t\t\tif (!SubParams.back()->_parseParamList(part))\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"Error parsing sub param list for header '%s' in '%s'\",\n\t\t\t\t\t\tSubParams.back()->ParamName.c_str(),\n\t\t\t\t\t\trawParamString.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (part[part.size()-1] == ')')\n\t\t\t{\n\t\t\t\tnlwarning(\"While parsing param string '%s', Invalid param value '%s' : missing openning '('\",\n\t\t\t\t\trawParamString.c_str(),\n\t\t\t\t\tpart.c_str());\n\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse if (part[0] == '\\\"')\n\t\t\t{\n\t\t\t\t// this is a quoted parameter value\n\t\t\t\tif (SubParams.empty() || !SubParams.back()->ParamValue.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"While parsing param string '%s', param '%s' already have the value '%s'\",\n\t\t\t\t\t\trawParamString.c_str(),\n\t\t\t\t\t\tSubParams.back()->ParamName.c_str(),\n\t\t\t\t\t\tSubParams.back()->ParamValue.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tSubParams.back()->ParamValue = part.unquote();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// this is a simple param\n\t\t\t\tCSString name = part.splitTo('=', true, true);\n\t\t\t\tif (name.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"Can't find param name for value '%s' in the param string '%s'\",\n\t\t\t\t\t\tpart.c_str(),\n\t\t\t\t\t\trawParamString.c_str());\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tCSString value = part.strtok(\"=\");\n\n\t\t\t\tSubParams.push_back( new TParsedCommandLine() );\n\t\t\t\tSubParams.back()->ParamName = name;\n\t\t\t\tSubParams.back()->ParamValue = value;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tconst TParsedCommandLine *TParsedCommandLine::getParam(const std::string &name) const\n\t{\n\t\tvector<string>\tparts;\n\t\tNLMISC::explode(name, string(\".\"), parts);\n\n\t\treturn _getParam(parts.begin(), parts.end());\n\t}\n\n\tvoid TParsedCommandLine::setParam(const std::string &name, const std::string &value)\n\t{\n\t\tvector<string>\tparts;\n\t\tNLMISC::explode(name, string(\".\"), parts);\n\n\t\tif (name.size() > 0)\n\t\t{\n\t\t\t// at least one part in the name\n\t\t\t// check if sub ojbcct exist\n\t\t\tTParsedCommandLine *sub = _getParam(parts.begin(), (parts.begin()+1));\n\t\t\tif (sub == NULL)\n\t\t\t{\n\t\t\t\tTParsedCommandLine * newElem = new TParsedCommandLine();\n\t\t\t\tnewElem->ParamName = parts[0];\n\t\t\t\tSubParams.push_back(newElem);\n\t\t\t\tsub = SubParams.back();\n\t\t\t}\n\n\t\t\tif (name.size() > 0)\n\t\t\t{\n\t\t\t\t// name is more deep, need to resurse\n\t\t\t\tparts.erase(parts.begin());\n\t\t\t\tCSString subName;\n\t\t\t\tsubName.join(reinterpret_cast<CVectorSString&>(parts), \".\");\n\t\t\t\tsub->setParam(subName, value);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// last level, set the value\n\t\t\t\tsub->ParamValue = value;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst TParsedCommandLine *TParsedCommandLine::_getParam(std::vector<std::string>::iterator it, std::vector<std::string>::iterator end) const\n\t{\n\t\treturn const_cast<TParsedCommandLine&>(*this)._getParam(it, end);\n\t}\n\n\tTParsedCommandLine *TParsedCommandLine::_getParam(std::vector<std::string>::iterator it, std::vector<std::string>::iterator end)\n\t{\n\t\tif (it == end)\n\t\t{\n\t\t\t// end of recursion, we found the searched param\n\t\t\treturn this;\n\t\t}\n\n\t\t// look for sub param\n\t\tfor (uint i=0; i<SubParams.size(); ++i)\n\t\t{\n\t\t\tif (SubParams[i]->ParamName == *it)\n\t\t\t\treturn SubParams[i]->_getParam(++it, end);\n\t\t}\n\n\t\t// parameter not found\n\t\treturn NULL;\n\t}\n\n\n} // namespace NLMISC\n"
  },
  {
    "path": "code/nel/src/net/module_gateway.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/module_message.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\n\nnamespace NLNET\n{\n\tstruct TSecurityDataDesc\n\t{\n\t\tTSecurityData\t*SecurityData;\n\n\t\tTSecurityDataDesc()\n\t\t\t: SecurityData(NULL)\n\t\t{\n\t\t}\n\n\t\tvoid serial(CMemStream &s)\n\t\t{\n\t\t\tif (!s.isReading())\n\t\t\t{\n\t\t\t\t// write mode\n\t\t\t\tTSecurityData *sd = SecurityData;\n\n\t\t\t\tuint32 nbSecBlock = 0;\n\t\t\t\tsint32 tagCountPos = s.reserve(4);\n\t\t\t\twhile (sd != NULL)\n\t\t\t\t{\n\t\t\t\t\tif (sd->DataTag == 0xff)\n\t\t\t\t\t{\n\t\t\t\t\t\tTUnknownSecurityData *usd = safe_cast<TUnknownSecurityData *>(sd);\n\t\t\t\t\t\ts.serial(usd->RealDataTag);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ts.serial(sd->DataTag);\n\t\t\t\t\t}\n\t\t\t\t\t// reserve a place to store the size of the next element\n\t\t\t\t\tsint32 pos = s.reserve(4);\n\t\t\t\t\ts.serial(*sd);\n\t\t\t\t\t// store the size\n\t\t\t\t\tuint32 size = s.getPos()-pos-4;\n\t\t\t\t\ts.poke(size, pos);\n\n\t\t\t\t\tnbSecBlock++;\n\t\t\t\t\tsd = sd->NextItem;\n\t\t\t\t}\n\n\t\t\t\t// store the number of item\n\t\t\t\ts.poke(nbSecBlock, tagCountPos);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlassert(SecurityData == NULL);\n\t\t\t\tTSecurityData **pLastSd = &SecurityData;\n\t\t\t\t// read mode\n\t\t\t\tuint32 nbSecBlock;\n\t\t\t\ts.serial(nbSecBlock);\n\n\t\t\t\tif (nbSecBlock == 0)\n\t\t\t\t\tSecurityData = NULL;\n\n\t\t\t\tfor (uint i=0; i<nbSecBlock; ++i)\n\t\t\t\t{\n\t\t\t\t\tuint8 dataTag;\n\t\t\t\t\ts.serial(dataTag);\n\t\t\t\t\tuint32 blockSize;\n\t\t\t\t\ts.serial(blockSize);\n\t\t\t\t\tsint32 pos = s.getPos();\n\t\t\t\t\tTSecurityData *sd;\n\n\t\t\t\t\ttry\n\t\t\t\t\t{\n\t\t\t\t\t\tTSecurityData::TCtorParam param(dataTag);\n\t\t\t\t\t\tsd = NLMISC_GET_FACTORY(TSecurityData, uint8).createObject(dataTag, param);\n\n\t\t\t\t\t\tif (sd == NULL)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we don't know this type, create an unknow security block\n\t\t\t\t\t\t\tsd = new TUnknownSecurityData(dataTag, blockSize);\n\t\t\t\t\t\t\tsd->serial(s);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsd->serial(s);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcatch(const EStreamOverflow &)\n\t\t\t\t\t{\n\t\t\t\t\t\t// FAILED to read the security block, rewind to old pos and serial as unknow\n\t\t\t\t\t\tnlwarning(\"Error while reading stream for security data type %u\", dataTag);\n\n\t\t\t\t\t\ts.seek(pos, NLMISC::IStream::begin);\n\t\t\t\t\t\tsd = new TUnknownSecurityData(dataTag, blockSize);\n\t\t\t\t\t\tsd->serial(s);\n\t\t\t\t\t}\n\n\t\t\t\t\t*pLastSd = sd;\n\t\t\t\t\tpLastSd = &(sd->NextItem);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t};\n\n\t/// Sub message for module description\n\tstruct TModuleDescCodec\n\t{\n\t\tTModuleId\tModuleProxyId;\n\t\tuint32\t\tModuleDistance;\n\t\tstring\t\tModuleFullName;\n\t\tstring\t\tModuleClass;\n\t\tstring\t\tModuleManifest;\n\t\tTSecurityDataDesc\tSecDesc;\n\n\n\t\tTModuleDescCodec()\n\t\t{\n\t\t}\n\n\t\tTModuleDescCodec(IModuleProxy *proxy)\n\t\t{\n\t\t\tModuleProxyId = proxy->getModuleProxyId();\n\t\t\tModuleDistance = proxy->getModuleDistance()+1;\n\t\t\tModuleFullName = proxy->getModuleName();\n\t\t\tModuleClass = proxy->getModuleClassName();\n\t\t\tModuleManifest = proxy->getModuleManifest();\n\t\t\tSecDesc.SecurityData = const_cast<TSecurityData*>(proxy->getFirstSecurityData());\n\t\t}\n\n\t\tvoid serial(NLMISC::CMemStream &s)\n\t\t{\n\t\t\ts.serial(ModuleProxyId);\n\t\t\ts.serial(ModuleDistance);\n\t\t\ts.serial(ModuleFullName);\n\t\t\ts.serial(ModuleManifest);\n\t\t\ts.serial(ModuleClass);\n\t\t\ts.serial(SecDesc);\n\t\t}\n\t};\n\n\t/// message for module distance update\n\tstruct TModuleDistanceChangeMsg\n\t{\n\t\tTModuleId\tModuleId;\n\t\tuint32\t\tNewDistance;\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(ModuleId);\n\t\t\ts.serial(NewDistance);\n\t\t}\n\t};\n\n\t/// message for module security update\n\tstruct TModuleSecurityChangeMsg\n\t{\n\t\tTModuleId\tModuleId;\n\n\t\tTSecurityDataDesc\tSecDesc;\n\n\t\tvoid serial(NLMISC::CMemStream &s)\n\t\t{\n\t\t\ts.serial(ModuleId);\n\t\t\ts.serial(SecDesc);\n\t\t}\n\t};\n\t/// Message for module removing\n\tstruct TModuleRemMsg\n\t{\n\t\tvector<TModuleId>\tRemovedModules;\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serialCont(RemovedModules);\n\t\t}\n\t};\n\n\t/// Message for module operation\n\tstruct TModuleOperationMsg\n\t{\n\t\tTModuleId\tModuleId;\n\t\tstring\t\tOperationName;\n\n\t\tCMessage\tMessageBody;\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(ModuleId);\n\t\t\ts.serial(OperationName);\n\t\t\ts.serial(MessageBody);\n\t\t}\n\t};\n\n\n\t/// message waiting next update for local dispatching\n\tstruct TLocalMessage\n\t{\n\t\tTModuleId\t\tSenderProxyId;\n\t\tTModuleId\t\tAddresseProxyId;\n\t\tCMessage\t\tMessage;\n\t};\n\n\n\t/** Register the gateway in the module manager gateway registry\n\t */\n\tvoid CModuleGateway::registerGateway()\n\t{\n\t\tIModuleManager::getInstance().registerModuleGateway(this);\n\t}\n\t/** Unregister the gateway in the module manager gateway registry\n\t */\n\tvoid CModuleGateway::unregisterGateway()\n\t{\n\t\tIModuleManager::getInstance().unregisterModuleGateway(this);\n\t}\n\n\n\t/** The standard gateway that interconnect module\n\t *\tacross process.\n\t */\n\tclass CStandardGateway :\n\t\tpublic CModuleBase,\n\t\tpublic CModuleGateway,\n\t\tpublic CModuleSocket\n\t{\n\t\ttypedef map<TModuleId, TModuleProxyPtr>\t\tTModuleProxies;\n\t\t/// Module proxies managed by this gateway. The map key is the module proxy id\n\t\tTModuleProxies\t\t_ModuleProxies;\n\n\t\ttypedef CTwinMap<TStringId, TModuleProxyPtr>\tTNamedProxyIdx;\n\t\t/// Index of name to proxy id\n\t\tTNamedProxyIdx\t\t_NameToProxyIdx;\n\n\t\t/// A structure to hold foreign proxy information\n\t\tstruct TKnownModuleInfo\n\t\t{\n\t\t\tTModuleId\t\tForeignProxyId;\n\t\t\tCGatewayRoute\t*Route;\n\t\t\tuint32\t\t\tModuleDistance;\n\t\t\tTStringId\t\tModuleClassId;\n\t\t};\n\n\t\ttypedef multimap<TStringId, TKnownModuleInfo>\tTKnownModuleInfos;\n\t\t/** List of known foreign module info.\n\t\t */\n\t\tTKnownModuleInfos\t_KnownModules;\n\n\t\ttypedef map<TModuleId, TModuleId>\t\t\t\tTLocalModuleIndex;\n\t\t/// Translation table to find module proxies for locally plugged module\n\t\t/// The map key is the local module id, the data is the associated proxy id\n\t\tTLocalModuleIndex\t\t_LocalModuleIndex;\n\n\t\ttypedef map<std::string, IGatewayTransport*>\t\tTTransportList;\n\t\t/// the list of active transport\n\t\tTTransportList\t\t_Transports;\n\n\t\ttypedef set<CGatewayRoute*>\t\tTRouteList;\n\t\t// the list of available routes\n\t\tTRouteList\t\t_Routes;\n\n\t\t/// The security plug-in (if any)\n\t\tCGatewaySecurity\t\t*_SecurityPlugin;\n\n\t\t/// Ping counter for debug purpose\n\t\tuint32\t\t\t\t\t_PingCounter;\n\n\t\ttypedef std::list<TLocalMessage>\tTLocalMessageList;\n\t\t/// List of local message waiting dispatching at next update\n\t\tTLocalMessageList\t\t_LocalMessages;\n\n\tpublic:\n\n\t\tCStandardGateway()\n\t\t\t:\t_SecurityPlugin(NULL),\n\t\t\t\t_PingCounter(0)\n\t\t{\n\t\t}\n\n\t\t~CStandardGateway()\n\t\t{\n\t\t\t// we need to unplug any plugged module\n\t\t\twhile (!_PluggedModules.getAToBMap().empty())\n\t\t\t{\n\t\t\t\t_PluggedModules.getAToBMap().begin()->second->unplugModule(this);\n\t\t\t}\n\n\t\t\t// delete all transport\n\t\t\twhile (!_Transports.empty())\n\t\t\t{\n\t\t\t\tdeleteTransport(_Transports.begin()->first);\n\t\t\t}\n\n\t\t\t// delete security plug-in\n\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t\tremoveSecurityPlugin();\n\n\t\t\t// must be done before the other destructors are called\n\t\t\tunregisterSocket();\n\t\t\tunregisterGateway();\n\t\t}\n\n\t\tCModuleProxy *getModuleProxy(TModuleId proxyId)\n\t\t{\n\t\t\tTModuleProxies::iterator it(_ModuleProxies.find(proxyId));\n\t\t\tif (it == _ModuleProxies.end())\n\t\t\t\treturn NULL;\n\t\t\treturn static_cast<CModuleProxy*>(it->second.getPtr());\n\t\t}\n\n\t\t/***********************************************************\n\t\t ** Gateway methods\n\t\t ***********************************************************/\n\t\tvirtual const std::string &getGatewayName() const\n\t\t{\n\t\t\treturn getModuleName();\n\t\t}\n\t\tvirtual const std::string &getFullyQualifiedGatewayName() const\n\t\t{\n\t\t\treturn getModuleFullyQualifiedName();\n\t\t}\n\n\t\t/// Create and bind to this gateway a new transport\n\t\tvirtual void createTransport(const std::string &transportClass, const std::string &instanceName)\n\t\t{\n\t\t\tif (_Transports.find(instanceName) != _Transports.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"A transport with the name '%s' already exist in this gateway\", instanceName.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIGatewayTransport::TCtorParam param;\n\t\t\tparam.Gateway = this;\n\t\t\tIGatewayTransport *transport = NLMISC_GET_FACTORY(IGatewayTransport, std::string).createObject(transportClass, param);\n\n\t\t\tif (transport == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"Failed to create a transport with the class '%s'\", transportClass.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Store the transport\n//\t\t\tTTransportInfo *ti = new TTransportInfo(transport);\n\t\t\t_Transports.insert(make_pair(instanceName, transport));\n//\t\t\t_TransportPtrIdx.insert(make_pair(transport, ti));\n\n\t\t\tnldebug(\"NETL6: Gateway transport %s (%s) created\", instanceName.c_str(), transportClass.c_str());\n\t\t}\n\n\t\t/// Delete a transport (this will close any open route)\n\t\tvirtual void deleteTransport(const std::string &instanceName)\n\t\t{\n\t\t\tTTransportList::iterator it(_Transports.find(instanceName));\n\t\t\tif (it == _Transports.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Unknown transport named '%s'\", instanceName.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnldebug(\"NETL6: Gateway transport '%s' deleted\", instanceName.c_str());\n\t\t\t// delete the transport\n\t\t\tIGatewayTransport *transport = it->second;\n//\t\t\tnlassert(_TransportPtrIdx.find(transport) != _TransportPtrIdx.end());\n//\t\t\t_TransportPtrIdx.erase(transport);\n\t\t\tdelete transport;\n//\t\t\tdelete it->second;\n\t\t\t_Transports.erase(it);\n\t\t}\n\n\t\t/// Activate/stop peer invisible mode on a transport\n\t\tvirtual void\tsetTransportPeerInvisible(const std::string &transportInstanceName, bool peerInvisible)\n\t\t{\n\t\t\tTTransportList::iterator it(_Transports.find(transportInstanceName));\n\t\t\tif (it == _Transports.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Unknown transport named '%s'\", transportInstanceName.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIGatewayTransport *transport= it->second;\n\n\t\t\tif (peerInvisible == transport->PeerInvisible)\n\t\t\t\t// nothing more to do\n\t\t\t\treturn;\n\n\t\t\t// set the mode\n\t\t\ttransport->PeerInvisible = peerInvisible;\n\n\t\t\tnldebug(\"NETL6: Gateway transport %s peer invisible mode %s\", transportInstanceName.c_str(), peerInvisible? \"ON\" : \"OFF\");\n\n\n\t\t\t// For each route of this transport, we need to disclose/undisclose peer modules\n\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayRoute *route = *first;\n\n\t\t\t\tif (route->getTransport() == transport)\n\t\t\t\t{\n\t\t\t\t\t// this route need to be filtered\n\t\t\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleProxy *proxy = first->second;\n\t\t\t\t\t\tif (proxy->getGatewayRoute() != NULL\n\t\t\t\t\t\t\t&& proxy->getGatewayRoute() != route\n\t\t\t\t\t\t\t&& proxy->getGatewayRoute()->getTransport() == transport)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// this module is on the same transport, but another route, remove/add it from the\n\t\t\t\t\t\t\t// route\n\t\t\t\t\t\t\tif (peerInvisible)\n\t\t\t\t\t\t\t\tundiscloseModuleToRoute(route, proxy);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// check firewall rules\n\t\t\t\t\t\t\t\tif (!route->getTransport()->Firewalled)\n\t\t\t\t\t\t\t\t\tdiscloseModuleToRoute(route, proxy);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// Activate/stop firewalling mode on a transport\n\t\tvirtual void\tsetTransportFirewallMode(const std::string &transportInstanceName, bool firewalled)\n\t\t\tthrow (EGatewayFirewallBreak)\n\t\t{\n\t\t\tTTransportList::iterator it(_Transports.find(transportInstanceName));\n\t\t\tif (it == _Transports.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Unknown transport named '%s'\", transportInstanceName.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIGatewayTransport *transport = it->second;\n\n\t\t\tif (firewalled == transport->Firewalled)\n\t\t\t\t// nothing to do\n\t\t\t\treturn;\n\n\t\t\tif (firewalled && transport->getRouteCount() != 0)\n\t\t\t\tthrow EGatewayFirewallBreak();\n\n\t\t\t/// set the firewall mode\n\t\t\ttransport->Firewalled = firewalled;\n\n\t\t\tnldebug(\"NETL6: Gateway transport %s firewall mode %s\", transportInstanceName.c_str(), firewalled? \"ON\" : \"OFF\");\n\n\t\t\tif (firewalled == false)\n\t\t\t{\n\t\t\t\t// we need to disclose all module not disclosed yet\n\t\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tCGatewayRoute *route = *first;\n\n\t\t\t\t\tif (route->getTransport() == transport)\n\t\t\t\t\t{\n\t\t\t\t\t\t// this route need to be unfiltered\n\t\t\t\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIModuleProxy *proxy = first->second;\n\t\t\t\t\t\t\tif (proxy->getGatewayRoute() == NULL || (proxy->getGatewayRoute() != route ))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// this module is on another route, disclose it if needed\n\t\t\t\t\t\t\t\tif (route->FirewallDisclosed.find(proxy->getModuleProxyId()) == route->FirewallDisclosed.end())\n\t\t\t\t\t\t\t\t\tdiscloseModuleToRoute(route, proxy);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// clear the firewall disclosed table\n\t\t\t\t\troute->FirewallDisclosed.clear();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// Send a command to a transport\n\t\tvirtual void transportCommand(const TParsedCommandLine &commandLine)\n\t\t{\n\t\t\tfor (uint i=1; i<commandLine.SubParams.size(); ++i)\n\t\t\t{\n\t\t\t\tconst TParsedCommandLine * subParam = commandLine.SubParams[i];\n\n\t\t\t\tstd::string transportName = subParam->ParamName;\n\t\t\t\tTTransportList::const_iterator it(_Transports.find(transportName));\n\t\t\t\tif (it == _Transports.end())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"Unknown transport named '%s', ignoring command.\", transportName.c_str());\n\t\t\t\t}\n\t\t\t\telse if (subParam->SubParams.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"Can't find sub param list for transport '%s' command\", transportName.c_str());\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"NETL6: Gateway transport %s, sending command '%s'\", transportName.c_str(), commandLine.toString().c_str());\n\t\t\t\t\t// ok, we have a valid transport, send the command\n\t\t\t\t\tIGatewayTransport *transport = it->second;\n\t\t\t\t\tif (!transport->onCommand(*subParam))\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual IGatewayTransport *getGatewayTransport(const std::string &transportName) const\n\t\t{\n\t\t\tTTransportList::const_iterator it(_Transports.find(transportName));\n\n\t\t\tif (it == _Transports.end())\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t\treturn it->second;\n\t\t}\n\n\t\tvirtual uint32\tgetTransportCount() const\n\t\t{\n\t\t\treturn (uint32)_Transports.size();\n\t\t}\n\n\t\tvirtual uint32\tgetRouteCount() const\n\t\t{\n\t\t\treturn (uint32)_Routes.size();\n\t\t}\n\n\t\tvirtual uint32 getReceivedPingCount() const\n\t\t{\n\t\t\treturn _PingCounter;\n\t\t}\n\n\t\tvirtual void onRouteAdded(CGatewayRoute *route)\n\t\t{\n\t\t\tnlassert(route != NULL);\n\t\t\t// Remember the new route\n\t\t\tnlassert(_Routes.find(route) == _Routes.end());\n\t\t\t_Routes.insert(route);\n\n\t\t\t// a new route is available, disclose known modules\n\t\t\t{\n\t\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModuleProxy *modProx = first->second;\n\n\t\t\t\t\t// only transmit module desc coming from other routes\n\t\t\t\t\t// and other transport if peer invisible\n\t\t\t\t\tif (isModuleProxyVisible(modProx, route))\n\t\t\t\t\t{\n\t\t\t\t\t\tdiscloseModuleToRoute(route, modProx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// A route is removed by a transport\n\t\tvirtual void onRouteRemoved(CGatewayRoute *route)\n\t\t{\n\t\t\tnlassert(route != NULL);\n\t\t\tnlassert(_Routes.find(route) != _Routes.end());\n\t\t\t// we need to remove all the proxy that come from this route\n//\t\t\tCGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());\n//\t\t\tfor (; first != last; ++first)\n\t\t\twhile (!route->ForeignToLocalIdx.getAToBMap().empty())\n\t\t\t{\n\t\t\t\tremoveForeignModule(route, route->ForeignToLocalIdx.getAToBMap().begin()->first);\n//\t\t\t\tTModuleId localProxyId = first->second;\n//\t\t\t\tTModuleProxies::iterator it(_ModuleProxies.find(localProxyId));\n//\t\t\t\tnlassert(it != _ModuleProxies.end());\n//\n//\t\t\t\tIModuleProxy *modProx = it->second;\n//\n//\t\t\t\t// trigger an event in the gateway\n//\t\t\t\tonRemoveModuleProxy(modProx);\n//\n//\t\t\t\t// remove proxy record from the proxy list\n//\t\t\t\t_ModuleProxies.erase(it);\n//\t\t\t\t_NameToProxyIdx.removeWithB(modProx);\n//\n//\t\t\t\t// Release the proxy object\n//\t\t\t\tIModuleManager::getInstance().releaseModuleProxy(modProx->getModuleProxyId());\n\t\t\t}\n\t\t\t// cleanup the translation table\n//\t\t\troute->ForeignToLocalIdx.clear();\n\n\t\t\t// clear the route tracker\n\t\t\t_Routes.erase(route);\n\n\t\t\t// cleanup route state\n\t\t\troute->ForeignToLocalIdx.clear();\n\t\t\troute->PendingEvents.clear();\n\t\t\troute->FirewallDisclosed.clear();\n\t\t\troute->NextMessageType = CModuleMessageHeaderCodec::mt_invalid;\n\t\t\troute->NextSenderProxyId = 0;\n\t\t\troute->NextAddresseeProxyId = 0;\n\t\t}\n\n\t\t/// A transport have received a message\n\t\tvirtual void onReceiveMessage(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveMessage);\n\t\t\t// dispatch the message\n\t\t\tif (from->NextMessageType != CModuleMessageHeaderCodec::mt_invalid)\n\t\t\t{\n\t\t\t\t// this message must be dispatched to a module\n\t\t\t\tonReceiveModuleMessage(from, msgin);\n\t\t\t}\n\t\t\t// Not a module message, dispatch the gateway message\n\t\t\telse if (msgin.getName() == \"MOD_OP\")\n\t\t\t{\n\t\t\t\tonReceiveModuleMessageHeader(from, msgin);\n\t\t\t}\n\t\t\telse if (msgin.getName() == \"MOD_UPD\")\n\t\t\t{\n\t\t\t\tonReceiveModuleUpdate(from, msgin);\n\t\t\t}\n//\t\t\telse if (msgin.getName() == \"MOD_ADD\")\n//\t\t\t{\n//\t\t\t\tonReceiveModuleAdd(from, msgin);\n//\t\t\t}\n//\t\t\telse if (msgin.getName() == \"MOD_REM\")\n//\t\t\t{\n//\t\t\t\tonReceiveModuleRemove(from, msgin);\n//\t\t\t}\n//\t\t\telse if (msgin.getName() == \"MOD_DST_UPD\")\n//\t\t\t{\n//\t\t\t\tonReceiveModuleDistanceUpdate(from, msgin);\n//\t\t\t}\n\t\t}\n\n\n\t\t/***********************************/\n\t\t/* security plug-in management*/\n\t\t/***********************************/\n\t\t/** create a security plug-in.\n\t\t *\tThere must be no security plug-in currently created.\n\t\t */\n\t\tvirtual void createSecurityPlugin(const std::string &className)\n\t\t{\n\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"NLNETL5 : CStandardGateway::createSecurityPlugin : plug-in already created \");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCGatewaySecurity::TCtorParam params;\n\t\t\tparams.Gateway = this;\n\t\t\tCGatewaySecurity *gs = NLMISC_GET_FACTORY(CGatewaySecurity, std::string).createObject(className, params);\n\t\t\tif (gs == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"NLNETL5 : CStandardGateway::createSecurityPlugin : can't create a security plug-in for class '%s'\", className.c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// store the security plug-in\n\t\t\t_SecurityPlugin = gs;\n\n\t\t\t// update security for all existing proxies\n\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModuleProxy *proxy = first->second;\n\t\t\t\t_SecurityPlugin->onNewProxy(proxy);\n\t\t\t}\n\t\t}\n\t\t/** Send a command to the security plug-in */\n\t\tvirtual void sendSecurityCommand(const TParsedCommandLine &command)\n\t\t{\n\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"NLNETL5 : CStandardGateway::sendSecurityCommand : plug-in NOT created \");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_SecurityPlugin->onCommand(command);\n\t\t}\n\n\t\t/** Remove the security plug-in.\n\t\t */\n\t\tvirtual void removeSecurityPlugin()\n\t\t{\n\t\t\tif (_SecurityPlugin == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"NLNETL5 : CStandardGateway::removeSecurityPlugin : plug-in not created\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// delete the plug-in (this can remove some security data)\n\t\t\t_SecurityPlugin->onDelete();\n\t\t\tdelete _SecurityPlugin;\n\t\t\t_SecurityPlugin = NULL;\n\t\t}\n\n\t\t/** Set a security data block. If a bloc of the same type\n\t\t *\talready exist in the list, the new one will replace the\n\t\t *\texisting one.\n\t\t */\n\t\tvoid setSecurityData(IModuleProxy *proxy, TSecurityData *securityData)\n\t\t{\n\t\t\tnlassert(proxy->getModuleGateway() == this);\n\t\t\tnlassert(securityData->NextItem == NULL);\n\n\t\t\tCModuleProxy *modProx = dynamic_cast<CModuleProxy*>(proxy);\n\t\t\tnlassert(modProx != NULL);\n\n\t\t\t// look in the existing security for a matching type and remove it\n\t\t\tremoveSecurityData(proxy, securityData->DataTag);\n\n\t\t\t// now, store the security data\n\t\t\tsecurityData->NextItem = modProx->_SecurityData;\n\t\t\tmodProx->_SecurityData = securityData;\n\n\n\t\t}\n\n\t\t/** Clear a block of security data\n\t\t *\tThe block is identified by the data tag\n\t\t */\n\t\tbool removeSecurityData(IModuleProxy *proxy, uint8 dataTag)\n\t\t{\n\t\t\tnlassert(proxy->getModuleGateway() == this);\n\n\t\t\tCModuleProxy *modProx = dynamic_cast<CModuleProxy*>(proxy);\n\t\t\tnlassert(modProx != NULL);\n\n\t\t\tbool ret = false;\n\t\t\tTSecurityData *prevSec = NULL;\n\t\t\tTSecurityData *currentSec = modProx->_SecurityData;\n\t\t\twhile (currentSec != NULL)\n\t\t\t{\n\t\t\t\tif (currentSec->DataTag == dataTag)\n\t\t\t\t{\n\t\t\t\t\tif (prevSec != NULL)\n\t\t\t\t\t\tprevSec->NextItem = currentSec->NextItem;\n\t\t\t\t\telse\n\t\t\t\t\t\tmodProx->_SecurityData = currentSec->NextItem;\n\n\t\t\t\t\tTSecurityData *toDelete = currentSec;\n\t\t\t\t\tcurrentSec = currentSec->NextItem;\n\t\t\t\t\ttoDelete->NextItem = NULL;\n\t\t\t\t\tdelete toDelete;\n\t\t\t\t\tret = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tprevSec = currentSec;\n\t\t\t\t\tcurrentSec = currentSec->NextItem;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tvoid replaceAllSecurityDatas(IModuleProxy *proxy, TSecurityData *securityData)\n\t\t{\n\t\t\tnlassert(proxy->getModuleGateway() == this);\n\n\t\t\tCModuleProxy *modProx = dynamic_cast<CModuleProxy*>(proxy);\n\t\t\tnlassert(modProx != NULL);\n\t\t\tnlassert(modProx->_SecurityData != securityData);\n\n\t\t\tif (modProx->_SecurityData != NULL)\n\t\t\t\tdelete modProx->_SecurityData;\n\n\t\t\tmodProx->_SecurityData = securityData;\n\t\t}\n\n\t\t/** Ask the gateway to resend the security data.\n\t\t *\tThe plug-in call this method after having changed\n\t\t *\tthe security info for a plug-in outside of the\n\t\t *\tonNewProxy call.\n\t\t */\n\t\tvoid forceSecurityUpdate(IModuleProxy *proxy)\n\t\t{\n\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayRoute *route = *first;\n\n\t\t\t\tif (isModuleProxyVisible(proxy, route))\n\t\t\t\t{\n\t\t\t\t\tupdateModuleSecurityDataToRoute(route, proxy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/***********************************/\n\t\t/* Inter gateway message reception */\n\t\t/***********************************/\n\n\t\t/** A gateway receive module operation */\n\t\tvoid onReceiveModuleMessage(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleMessage);\n\t\t\t// clean the message type now, any return path will be safe\n\t\t\tfrom->NextMessageType = CModuleMessageHeaderCodec::mt_invalid;\n\n\t\t\t// Retrieve sender and destination proxy and recall gateway send method\n\t\t\tIModuleProxy *senderProxy;\n\t\t\tIModuleProxy *addresseeProxy;\n\n\t\t\tTModuleProxies::iterator it;\n\n\t\t\t// sender proxy\n\t\t\tit = _ModuleProxies.find(from->NextSenderProxyId);\n\t\t\tif (it == _ModuleProxies.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Can't dispatch the module message, sender proxy %u is not in this gateway\", from->NextSenderProxyId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsenderProxy = it->second;\n\t\t\t// addressee proxy\n\t\t\tit = _ModuleProxies.find(from->NextAddresseeProxyId);\n\t\t\tif (it == _ModuleProxies.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Can't dispatch the module message '%s', sender proxy %u is not in this gateway\", msgin.getName().c_str(), from->NextAddresseeProxyId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\taddresseeProxy = it->second;\n\n\t\t\t// give the message to the gateway (either for local dispatch or for forwarding)\n\t\t\tsendModuleMessage(senderProxy, addresseeProxy, msgin);\n\t\t}\n\n\t\t// A gateway receive a module message header\n\t\tvoid onReceiveModuleMessageHeader(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleMessageHeader);\n\t\t\tif (from->NextMessageType != CModuleMessageHeaderCodec::mt_invalid)\n\t\t\t{\n\t\t\t\t// juste warn (but that is VERY BAD)\n\t\t\t\tnlwarning(\"Receiving a new module message header without having received the previous module message !\");\n\t\t\t}\n\n\t\t\t// store the message information in the route\n\t\t\tCModuleMessageHeaderCodec::decode(\n\t\t\t\tmsgin,\n\t\t\t\tfrom->NextMessageType,\n\t\t\t\tfrom->NextSenderProxyId,\n\t\t\t\tfrom->NextAddresseeProxyId);\n\n\t\t\t// translate sender id\n\t\t\tconst TModuleId *pmoduleId = from->ForeignToLocalIdx.getB(from->NextSenderProxyId);\n\t\t\tif (pmoduleId  == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"The sender proxy %u is unknown in the translation table, can't dispatch the message !\", from->NextSenderProxyId);\n\t\t\t\tfrom->NextMessageType = CModuleMessageHeaderCodec::mt_invalid;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfrom->NextSenderProxyId = *pmoduleId;\n\t\t\t// now, wait the message body\n\t\t}\n\n\t\t/** A gateway receive a general update message */\n\t\tvoid onReceiveModuleUpdate(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleUpdate);\n\t\t\twhile (uint32(msgin.getPos()) != msgin.length())\n\t\t\t{\n\t\t\t\tCGatewayRoute::TPendingEventType type = CGatewayRoute::pet_disclose_module;\n//\t\t\t\tmsgin.serialShortEnum(type);\n\t\t\t\tnlRead(msgin, serialShortEnum, type);\n\n\t\t\t\tswitch (type)\n\t\t\t\t{\n\t\t\t\tcase CGatewayRoute::pet_disclose_module:\n\n\t\t\t\t\tonReceiveModuleAdd(from, msgin);\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_undisclose_module:\n\n\t\t\t\t\tonReceiveModuleRemove(from, msgin);\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_update_distance:\n\n\t\t\t\t\tonReceiveModuleDistanceUpdate(from, msgin);\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_update_security:\n\n\t\t\t\t\tonReceiveModuleSecurityUpdate(from, msgin);\n\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// should not append\n\t\t\t\t\tnlstop;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/** A gateway send new modules information */\n\t\tvoid onReceiveModuleAdd(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleAdd);\n\t\t\tTModuleDescCodec modDesc;\n\t\t\tnlRead(msgin, serial, modDesc);\n\n\t\t\t// for each received module info\n\t\t\tTStringId modNameId = CStringMapper::map(modDesc.ModuleFullName);\n\t\t\t/// store the module information\n\t\t\tTKnownModuleInfo modInfo;\n\t\t\tmodInfo.ForeignProxyId = modDesc.ModuleProxyId;\n\t\t\tmodInfo.ModuleClassId = CStringMapper::map(modDesc.ModuleClass);\n\t\t\tmodInfo.ModuleDistance = modDesc.ModuleDistance;\n\t\t\tmodInfo.Route = from;\n\n\t\t\tnldebug(\"Gateway '%s' : store module info for '%s' (foreign ID %u) @ %u hop\",\n\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\tmodDesc.ModuleFullName.c_str(),\n\t\t\t\tmodDesc.ModuleProxyId,\n\t\t\t\tmodDesc.ModuleDistance);\n\n\t\t\t// Store module information\n\t\t\t_KnownModules.insert(make_pair(modNameId, modInfo));\n\n\t\t\tif (_NameToProxyIdx.getB(modNameId) != NULL)\n\t\t\t{\n\t\t\t\t// a proxy for this module already exist,\n\t\t\t\tIModuleProxy *modProx = *(_NameToProxyIdx.getB(modNameId));\n\n\t\t\t\t// fill the id translation table\n//\t\t\t\t\tfrom->ForeignToLocalIdx.insert(make_pair(modDesc.ModuleProxyId, modProx->getModuleProxyId()));\n\t\t\t\tfrom->ForeignToLocalIdx.add(modDesc.ModuleProxyId, modProx->getModuleProxyId());\n\n\t\t\t\t// check if this route is better\n\t\t\t\tif (modProx->getModuleDistance() > modInfo.ModuleDistance)\n\t\t\t\t{\n\t\t\t\t\t// update module distance and swap route\n\t\t\t\t\tCModuleProxy *proxy = static_cast<CModuleProxy*>(modProx);\n\n\t\t\t\t\tnldebug(\"Gateway '%s' : Use a shorter path for '%s' from %u to %u hops\",\n\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\tmodDesc.ModuleFullName.c_str(),\n\t\t\t\t\t\tproxy->_Distance,\n\t\t\t\t\t\tmodInfo.ModuleDistance);\n\n\t\t\t\t\tproxy->_Distance = modInfo.ModuleDistance;\n\t\t\t\t\tproxy->_Route = modInfo.Route;\n\n\t\t\t\t\tsendModuleDistanceUpdate(proxy);\n\t\t\t\t}\n\n\t\t\t\t// update the security if needed\n\t\t\t\tif (modDesc.SecDesc.SecurityData != NULL)\n\t\t\t\t{\n\t\t\t\t\tCModuleProxy *proxy = static_cast<CModuleProxy *>(modProx);\n\t\t\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\t_SecurityPlugin->onNewSecurityData(from, proxy, modDesc.SecDesc.SecurityData);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (proxy->_SecurityData != NULL)\n\t\t\t\t\t\t\tdelete proxy->_SecurityData;\n\t\t\t\t\t\tproxy->_SecurityData = modDesc.SecDesc.SecurityData;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// we need to create a new proxy\n\t\t\t\t// create a module proxy\n\t\t\t\tIModuleProxy *modProx = IModuleManager::getInstance().createModuleProxy(\n\t\t\t\t\tthis,\n\t\t\t\t\tfrom,\n\t\t\t\t\tmodDesc.ModuleDistance,\n\t\t\t\t\tNULL,\n\t\t\t\t\tmodDesc.ModuleClass,\n\t\t\t\t\tmodDesc.ModuleFullName,\n\t\t\t\t\tmodDesc.ModuleManifest,\n\t\t\t\t\tmodDesc.ModuleProxyId);\n\n\t\t\t\t// set the module security\n\t\t\t\tCModuleProxy *proxy = static_cast<CModuleProxy *>(modProx);\n\t\t\t\tproxy->_SecurityData = modDesc.SecDesc.SecurityData;\n\t\t\t\t// let the security plug-in add/remove security data\n\t\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t\t\t_SecurityPlugin->onNewProxy(proxy);\n\n\t\t\t\t// store the proxy in the proxy list\n\t\t\t\t_ModuleProxies.insert(make_pair(modProx->getModuleProxyId(), modProx));\n\t\t\t\t_NameToProxyIdx.add(modNameId, modProx);\n\n\t\t\t\t// Fill the proxy id translation table for this route\n//\t\t\t\t\tfrom->ForeignToLocalIdx.insert(make_pair(modDesc.ModuleProxyId, modProx->getModuleProxyId()));\n\t\t\t\tfrom->ForeignToLocalIdx.add(modDesc.ModuleProxyId, modProx->getModuleProxyId());\n\n\t\t\t\t// trigger an event in the gateway\n\t\t\t\tonAddModuleProxy(modProx);\n\t\t\t}\n\t\t}\n\n\t\tvoid onReceiveModuleRemove(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleRemove);\n\t\t\tTModuleId\tmoduleId;\n\t\t\tnlRead(msgin, serial, moduleId);\n\n\t\t\tremoveForeignModule(from, moduleId);\n\t\t}\n\n\t\tvoid onReceiveModuleDistanceUpdate(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleDistanceUpdate);\n\t\t\tTModuleId moduleId;\n\t\t\tuint32\tnewDistance;\n\n\t\t\tnlRead(msgin, serial, moduleId);\n\t\t\tnlRead(msgin, serial, newDistance);\n\n\t\t\t// translate the module id\n\t\t\tconst TModuleId *pModuleId = from->ForeignToLocalIdx.getB(moduleId);\n\t\t\tif (pModuleId == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"Receive a module distance update for foreign module %u, but no translation available\", moduleId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tTModuleId localId = *pModuleId;\n\n\t\t\t// now, retrieve the module info and update\n\t\t\tTModuleProxies::iterator it2(_ModuleProxies.find(localId));\n\t\t\tnlassert(it2 != _ModuleProxies.end());\n\t\t\tCModuleProxy *proxy = static_cast<CModuleProxy*>(it2->second.getPtr());\n\n\t\t\tpair<TKnownModuleInfos::iterator, TKnownModuleInfos::iterator> range;\n\t\t\trange = _KnownModules.equal_range(proxy->_FullyQualifiedModuleName);\n\n\t\t\tfor (; range.first != range.second; ++range.first)\n\t\t\t{\n\t\t\t\tTKnownModuleInfo &kmi = range.first->second;\n\t\t\t\tif (kmi.Route == from)\n\t\t\t\t{\n\t\t\t\t\t// we found the module info, update the data\n\t\t\t\t\tnldebug(\"Gateway '%s' : updating distance from %u to %u hop for module '%s'\",\n\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\tkmi.ModuleDistance,\n\t\t\t\t\t\tnewDistance,\n\t\t\t\t\t\tCStringMapper::unmap(range.first->first).c_str());\n\t\t\t\t\tkmi.ModuleDistance = newDistance;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnlassert(range.first != range.second);\n\n\t\t\t// check if the changed module is the one currently in use\n\t\t\tif (proxy->_Route == from)\n\t\t\t{\n\t\t\t\t// two task : first, if the new distance is greater, look\n\t\t\t\t// in available route for a shorter path,\n\t\t\t\t// second, send a module distance update for this module.\n\t\t\t\tif (proxy->_Distance < newDistance)\n\t\t\t\t{\n\t\t\t\t\t// look for a shorter path\n\t\t\t\t\trange = _KnownModules.equal_range(proxy->_FullyQualifiedModuleName);\n\n\t\t\t\t\tfor (; range.first != range.second; ++range.first)\n\t\t\t\t\t{\n\t\t\t\t\t\tTKnownModuleInfo &kmi = range.first->second;\n\t\t\t\t\t\tif (kmi.ModuleDistance < proxy->_Distance)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnldebug(\"Gateway '%s' : proxy '%s' use a new path from %u to %u hop\",\n\t\t\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\t\t\tproxy->getModuleName().c_str(),\n\t\t\t\t\t\t\t\tproxy->_Distance,\n\t\t\t\t\t\t\t\tkmi.ModuleDistance);\n\t\t\t\t\t\t\t// this path is shorter, use it now\n\t\t\t\t\t\t\tproxy->_Route = kmi.Route;\n\t\t\t\t\t\t\tproxy->_ForeignModuleId = kmi.ForeignProxyId;\n\t\t\t\t\t\t\tproxy->_Distance = kmi.ModuleDistance;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (range.first == range.second)\n\t\t\t\t\t{\n\t\t\t\t\t\t// no shorter path found, update the proxy\n\t\t\t\t\t\tnldebug(\"Gateway '%s' : proxy '%s' path distance changed from %u to %u hop\",\n\t\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\t\tproxy->getModuleName().c_str(),\n\t\t\t\t\t\t\tproxy->_Distance,\n\t\t\t\t\t\t\tnewDistance);\n\n\t\t\t\t\t\tproxy->_Distance = newDistance;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// the new distance is shorter, just update\n\t\t\t\t\tnldebug(\"Gateway '%s' : proxy '%s' path distance reduced from %u to %u hop\",\n\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\tproxy->getModuleName().c_str(),\n\t\t\t\t\t\tproxy->_Distance,\n\t\t\t\t\t\tnewDistance);\n\n\t\t\t\t\tproxy->_Distance = newDistance;\n\t\t\t\t}\n\n\t\t\t\t// send the distance update\n\t\t\t\tsendModuleDistanceUpdate(proxy);\n\t\t\t}\n\t\t}\n\n\t\tvoid onReceiveModuleSecurityUpdate(CGatewayRoute *from, const CMessage &msgin)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onReceiveModuleSecurityUpdate);\n//\t\t\tTModuleId foreignModuleId;\n//\t\t\tTSecurityData *modSec;\n\t\t\tTModuleSecurityChangeMsg secChg;\n\n\t\t\tnlRead(msgin, serial, secChg);\n//\t\t\tmsgin.serial(foreignModuleId);\n//\t\t\tmsgin.serialPolyPtr(modSec);\n\n\t\t\tconst TModuleId *pModuleId = from->ForeignToLocalIdx.getB(secChg.ModuleId);\n\t\t\tif (pModuleId == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"LNETL6 : receive module security update for unknown module foreign proxy %u\", secChg.ModuleId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tTModuleId moduleId = *pModuleId;\n\n\t\t\tCModuleProxy *modProx = getModuleProxy(moduleId);\n\t\t\tif (modProx == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"LNETL6 : receive module security update for unknown module proxy %u, foreign %u\", moduleId, secChg.ModuleId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// allow the security plug-in to affect the data\n\t\t\tif( _SecurityPlugin != NULL)\n\t\t\t{\n\t\t\t\t// let the plug-in update the security data\n\t\t\t\t_SecurityPlugin->onNewSecurityData(from, modProx, secChg.SecDesc.SecurityData);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// update the security data in the proxy\n\t\t\t\treplaceAllSecurityDatas(modProx, secChg.SecDesc.SecurityData);\n\t\t\t}\n\n\t\t\t// warn local module about new security data\n\t\t\t{\n\t\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModule *module = first->second;\n\n\t\t\t\t\tmodule->onModuleSecurityChange(modProx);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// update the security to peers\n\t\t\t{\n\t\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tCGatewayRoute *route = *first;\n\t\t\t\t\tif (isModuleProxyVisible(modProx, route))\n\t\t\t\t\t{\n\t\t\t\t\t\tupdateModuleSecurityDataToRoute(route, modProx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tvirtual void onAddModuleProxy(IModuleProxy *addedModule)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onAddmoduleProxy);\n\t\t\t// disclose module to local modules\n\t\t\tdiscloseModule(addedModule);\n\n\t\t\t// and send module info to any route\n\n\t\t\t// for each route\n\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayRoute *route = *first;\n\t\t\t\t// only send info to other routes\n\t\t\t\tif (isModuleProxyVisible(addedModule, route))\n\t\t\t\t{\n\t\t\t\t\tdiscloseModuleToRoute(route, addedModule);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual void onRemoveModuleProxy(IModuleProxy *removedModule)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onRemoveModuleProxy);\n\t\t\t// for each route\n\t\t\t{\n\t\t\t\t// for each route\n\t\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tCGatewayRoute *route = *first;\n\t\t\t\t\t// only send info to other routes\n\t\t\t\t\tif (isModuleProxyVisible(removedModule, route))\n\t\t\t\t\t{\n\t\t\t\t\t\tundiscloseModuleToRoute(route, removedModule);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// warn any locally plugged module\n\t\t\t{\n\t\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModule *module = first->second;\n\t\t\t\t\tif (removedModule->getGatewayRoute() != NULL\n\t\t\t\t\t\t|| module->getModuleId() != removedModule->getForeignModuleId())\n\t\t\t\t\t{\n\t\t\t\t\t\tmodule->_onModuleDown(removedModule);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual void discloseModule(IModuleProxy *moduleProxy)\n\t\t\tthrow (EGatewayNotConnected)\n\t\t{\n\t\t\tnlassert(moduleProxy->getModuleGateway() == this);\n\n\t\t\t// warn any plugged module\n\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModule *module = first->second;\n\t\t\t\tif (moduleProxy->getGatewayRoute() != NULL\n\t\t\t\t\t|| module->getModuleId() != moduleProxy->getForeignModuleId())\n\t\t\t\t{\n\t\t\t\t\tmodule->_onModuleUp(moduleProxy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual IModuleProxy *getPluggedModuleProxy(IModule *pluggedModule)\n\t\t{\n\t\t\tTLocalModuleIndex::iterator it(_LocalModuleIndex.find(pluggedModule->getModuleId()));\n\n\t\t\tif (it == _LocalModuleIndex.end())\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t{\n\t\t\t\tTModuleProxies::iterator it2(_ModuleProxies.find(it->second));\n\t\t\t\tnlassert(it2 != _ModuleProxies.end());\n\t\t\t\treturn it2->second;\n\t\t\t}\n\t\t}\n\n\t\tvirtual uint32\tgetProxyCount() const\n\t\t{\n\t\t\treturn (uint32)_ModuleProxies.size();\n\t\t}\n\n\t\t/// Fill a vector with the list of proxies managed here. The module are filled in ascending proxy id order.\n\t\tvirtual void\tgetModuleProxyList(std::vector<IModuleProxy*> &resultList) const\n\t\t{\n\t\t\tTModuleProxies::const_iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tresultList.push_back(first->second);\n\t\t\t}\n\t\t}\n\n\n\t\tvirtual void sendModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const NLNET::CMessage &message)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_sendModuleMessage);\n\t\t\t// manage firewall\n\t\t\tif (addresseeProxy->getGatewayRoute()\n\t\t\t\t&& addresseeProxy->getGatewayRoute()->getTransport()->Firewalled)\n\t\t\t{\n\t\t\t\tCGatewayRoute *route = addresseeProxy->getGatewayRoute();\n\t\t\t\t// the destination route is firewalled, we need to\n\t\t\t\t// disclose the sender module if it's not already done\n\t\t\t\tif (route->FirewallDisclosed.find(senderProxy->getModuleProxyId()) == route->FirewallDisclosed.end())\n\t\t\t\t{\n\t\t\t\t\tdiscloseModuleToRoute(route, senderProxy);\n\t\t\t\t\troute->FirewallDisclosed.insert(senderProxy->getModuleProxyId());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check for visibility rules\n\t\t\tif (!isModuleProxyVisible(addresseeProxy, senderProxy->getGatewayRoute()))\n\t\t\t{\n\t\t\t\tnlwarning(\"Module %u '%s' try to send message to %u '%s' but addressee is not visible, message discarded\",\n\t\t\t\t\tsenderProxy->getModuleProxyId(),\n\t\t\t\t\tsenderProxy->getModuleName().c_str(),\n\t\t\t\t\taddresseeProxy->getModuleProxyId(),\n\t\t\t\t\taddresseeProxy->getModuleName().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (addresseeProxy->getGatewayRoute() == NULL)\n\t\t\t{\n\t\t\t\t// the module is local, just forward the call to the dispatcher\n\t\t\t\tnlassert(senderProxy != NULL);\n\t\t\t\tnlassert(_ModuleProxies.find(senderProxy->getModuleProxyId()) != _ModuleProxies.end());\n\n\t\t\t\t// invert the message for immediate dispatching if needed\n\t\t\t\tif (!message.isReading())\n\t\t\t\t\tconst_cast<CMessage&>(message).invert();\n\n\t\t\t\t// check if the module support immediate dispatching\n\t\t\t\tTModuleId addresseeModId = addresseeProxy->getForeignModuleId();\n\n\t\t\t\tconst TModulePtr *adrcp = _PluggedModules.getB(addresseeModId);\n\t\t\t\tif (adrcp == NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"sendModuleMessage : can't find addressee module %u that is not plugged here !\", addresseeModId);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tIModule *addreseeMod = *adrcp;\n\t\t\t\tif (!addreseeMod->isImmediateDispatchingSupported())\n\t\t\t\t{\n\t\t\t\t\t// dispatch the message at next gateway update\n\t\t\t\t\t// this provide a coherent behavior between local and distant module message exchange\n\n\t\t\t\t\t_LocalMessages.push_back(TLocalMessage());\n\t\t\t\t\tTLocalMessage &lm = _LocalMessages.back();\n\t\t\t\t\tlm.SenderProxyId = senderProxy->getModuleProxyId();\n\t\t\t\t\tlm.AddresseProxyId = addresseeProxy->getModuleProxyId();\n\n\t\t\t\t\tnldebug(\"NETL6 : gateway '%s' : queuing local message '%s' from proxy %u to proxy %u\",\n\t\t\t\t\t\tgetModuleName().c_str(),\n\t\t\t\t\t\tmessage.getName().c_str(),\n\t\t\t\t\t\tlm.SenderProxyId,\n\t\t\t\t\t\tlm.AddresseProxyId);\n\n\t\t\t\t\tif (message.hasLockedSubMessage())\n\t\t\t\t\t{\n\t\t\t\t\t\tlm.Message.assignFromSubMessage(message);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tlm.Message = message;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// immediate dispatching\n\t\t\t\t\tdispatchModuleMessage(senderProxy, addresseeProxy, message);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// the module is distant, send the message via the route\n\t\t\t\t// create a message for sending\n\t\t\t\tCMessage msgHeader(\"MOD_OP\");\n\t\t\t\tCModuleMessageHeaderCodec::encode(\n\t\t\t\t\tmsgHeader,\n\t\t\t\t\tCModuleMessageHeaderCodec::mt_oneway,\n\t\t\t\t\tsenderProxy->getModuleProxyId(),\n\t\t\t\t\taddresseeProxy->getForeignModuleId());\n\n\t\t\t\t// send any pending module info\n\t\t\t\tsendPendingModuleUpdate(addresseeProxy->getGatewayRoute());\n\n\t\t\t\t// send the header\n\t\t\t\taddresseeProxy->getGatewayRoute()->sendMessage(msgHeader);\n\t\t\t\t// send the message\n\t\t\t\taddresseeProxy->getGatewayRoute()->sendMessage(message);\n\t\t\t}\n\t\t}\n\t\tvirtual void dispatchModuleMessage(IModuleProxy *senderProxy, IModuleProxy *addresseeProxy, const CMessage &message)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_dispatchModuleMessage);\n\t\t\tCMessage::TMessageType msgType = message.getType();\n\t\t\t// retrieve the address module from the proxy\n\t\t\tnlassert(addresseeProxy->getGatewayRoute() == NULL);\n\t\t\t// As the addressee is local, the foreign proxy id is the local module id (a bit triky...)\n\t\t\tTModuleId addresseeModId = addresseeProxy->getForeignModuleId();\n\n\t\t\tconst TModulePtr *adrcp = _PluggedModules.getB(addresseeModId);\n\t\t\tif (adrcp == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"dispatchModuleMessage : dispatching a message to module %u that is not plugged here !\", addresseeModId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIModule *addreseeMod = *adrcp;\n\n\t\t\t// finally, transmit the message to the module\n//\t\t\taddreseeMod->onProcessModuleMessage(senderProxy, message);\n\t\t\ttry\n\t\t\t{\n\t\t\t\taddreseeMod->onReceiveModuleMessage(senderProxy, message);\n\t\t\t}\n\t\t\tcatch(...)\n\t\t\t{\n\t\t\t\tnlwarning(\"An exception was thrown while dispatching message '%s' from '%s' to '%s'\",\n\t\t\t\t\tmessage.getName().c_str(),\n\t\t\t\t\tsenderProxy->getModuleName().c_str(),\n\t\t\t\t\taddresseeProxy->getModuleName().c_str());\n\n\t\t\t\tif (msgType == CMessage::Request)\n\t\t\t\t{\n\t\t\t\t\t// send back an exception message\n\t\t\t\t\tCMessage except;\n\t\t\t\t\texcept.setType(\"EXCEPT\", CMessage::Except);\n\t\t\t\t\tsenderProxy->sendModuleMessage(addreseeMod, except);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t/***********************************************************\n\t\t ** Module methods\n\t\t ***********************************************************/\n\t\tbool\tinitModule(const TParsedCommandLine &initInfo)\n\t\t{\n\t\t\tbool ret = CModuleBase::initModule(initInfo);\n\n\t\t\t// no options for now\n\n\t\t\tregisterSocket();\n\t\t\tregisterGateway();\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tstd::string\t\t\tbuildModuleManifest() const\n\t\t{\n\t\t\treturn string();\n\t\t}\n\n\n\t\tvoid\t\t\t\tonServiceUp(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonServiceDown(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleUpdate()\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway_onModuleUpdate);\n\t\t\t// send waiting local messages\n\t\t\twhile (!_LocalMessages.empty())\n\t\t\t{\n\t\t\t\tTLocalMessage &lm = _LocalMessages.front();\n\n\t\t\t\tIModuleProxy *senderProx = getModuleProxy(lm.SenderProxyId);\n\t\t\t\tIModuleProxy *addresseeProx = getModuleProxy(lm.AddresseProxyId);\n\n\t\t\t\tif (senderProx == NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"CStandardGateway : local message dispatching : Failed to retrieve proxy for sender module %u while dispatching message '%s' to %u\",\n\t\t\t\t\t\tlm.SenderProxyId,\n\t\t\t\t\t\tlm.Message.getName().c_str(),\n\t\t\t\t\t\tlm.AddresseProxyId);\n\t\t\t\t}\n\t\t\t\telse if (addresseeProx == NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"CStandardGateway : local message dispatching : Failed to retrieve proxy for addressee module %u while dispatching message '%s' from %u\",\n\t\t\t\t\t\tlm.AddresseProxyId,\n\t\t\t\t\t\tlm.Message.getName().c_str(),\n\t\t\t\t\t\tlm.SenderProxyId);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// we can dispatch the message\n\t\t\t\t\tdispatchModuleMessage(senderProx, addresseeProx, lm.Message);\n\t\t\t\t}\n\n\t\t\t\t_LocalMessages.pop_front();\n\t\t\t}\n\n\t\t\t// send pending module un/disclosure\n\t\t\t{\n\t\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tCGatewayRoute *route = *first;\n\t\t\t\t\tsendPendingModuleUpdate(route);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// update the transports\n\t\t\t{\n\t\t\t\tTTransportList::iterator first(_Transports.begin()), last(_Transports.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIGatewayTransport *transport = first->second;\n\n\t\t\t\t\ttransport->update();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid\t\t\t\tonApplicationExit()\n\t\t{\n\t\t\t// delete all transport\n\t\t\twhile (!_Transports.empty())\n\t\t\t{\n\t\t\t\tdeleteTransport(_Transports.begin()->first);\n\t\t\t}\n\t\t}\n\n\t\tvoid\t\t\t\tonModuleUp(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleDown(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\t\tbool\t\t\t\tonProcessModuleMessage(IModuleProxy * /* senderModuleProxy */, const CMessage &message)\n\t\t{\n\t\t\t// simple message for debug and unit testing\n\t\t\tif (message.getName() == \"DEBUG_MOD_PING\")\n\t\t\t{\n\t\t\t\t_PingCounter++;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tvoid\t\t\t\tonModuleSecurityChange(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\n\t\tvoid\tonModuleSocketEvent(IModuleSocket * /* moduleSocket */, TModuleSocketEvent /* eventType */)\n\t\t{\n\t\t}\n\n\t\t/***********************************************************\n\t\t ** Socket methods\n\t\t ***********************************************************/\n\n\t\tconst std::string &getSocketName()\n\t\t{\n\t\t\treturn getModuleName();\n\t\t}\n\n\t\tvoid _sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotReachable, EModuleNotPluggedHere)\n\t\t{\n\t\t\t// the socket implementation already checked that the module is plugged here\n\t\t\t// just check that the destination module effectively from here\n\t\t\tTLocalModuleIndex::iterator it(_LocalModuleIndex.find(senderModule->getModuleId()));\n\t\t\tnlassert(it != _LocalModuleIndex.end());\n\n\t\t\t// get the sender proxy\n\t\t\tTModuleProxies::iterator it2(_ModuleProxies.find(it->second));\n\t\t\tnlassert(it2 != _ModuleProxies.end());\n\n\t\t\tIModuleProxy *senderProx = it2->second;\n\n\t\t\t// get the addressee proxy\n\t\t\tit2 = _ModuleProxies.find(destModuleProxyId);\n\t\t\tnlassert(it2 != _ModuleProxies.end());\n\n\t\t\tIModuleProxy *destProx = it2->second;\n\n\n\t\t\tsendModuleMessage(senderProx, destProx, message);\n\t\t}\n\n\t\tvirtual void _broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t{\n\t\t\tH_AUTO(CModuleGetaway__broadcastModuleMessage);\n\t\t\t// send the message to all proxies (except the sender module)\n\t\t\tTLocalModuleIndex::iterator it(_LocalModuleIndex.find(senderModule->getModuleId()));\n\t\t\tnlassert(it != _LocalModuleIndex.end());\n\n\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModuleProxy *proxy = first->second;\n\n\t\t\t\tproxy->sendModuleMessage(senderModule, message);\n\t\t\t}\n\t\t}\n\n\t\tvoid onModulePlugged(IModule *pluggedModule)\n\t\t{\n\t\t\tnldebug(\"NETL6: Gateway %s : plugging module '%s' id=%u\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tpluggedModule->getModuleName().c_str(),\n\t\t\t\tpluggedModule->getModuleId());\n\n\t\t\t// A module has just been plugged here, we need to disclose it to the\n\t\t\t// other module, and disclose other module to it.\n\n\t\t\t// create a proxy for this module\n\t\t\tIModuleProxy *modProx = IModuleManager::getInstance().createModuleProxy(\n\t\t\t\t\tthis,\n\t\t\t\t\tNULL,\t// the module is local, so there is no route\n\t\t\t\t\t0,\t\t// the module is local, distance is 0\n\t\t\t\t\tpluggedModule,\t// the module is local, so store the module pointer\n\t\t\t\t\tpluggedModule->getModuleClassName(),\n\t\t\t\t\tpluggedModule->getModuleFullyQualifiedName(),\n\t\t\t\t\tpluggedModule->getModuleManifest(),\n\t\t\t\t\tpluggedModule->getModuleId()\t// the module is local, foreign id is the module id\n\t\t\t\t\t);\n\n\t\t\t// and store it in the proxies container\n\t\t\t_ModuleProxies.insert(make_pair(modProx->getModuleProxyId(), modProx));\n\t\t\t_NameToProxyIdx.add(CStringMapper::map(modProx->getModuleName()), modProx);\n\n\t\t\t// and also in the local module index\n\t\t\t_LocalModuleIndex.insert(make_pair(pluggedModule->getModuleId(), modProx->getModuleProxyId()));\n\n\n\t\t\t// trigger the new module proxy event\n\t\t\tonAddModuleProxy(modProx);\n//\t\t\t// disclose the new module to other modules\n//\t\t\tdiscloseModule(modProx);\n//\n\t\t\t// second, disclose already known proxies in the gateway to the plugged module\n\t\t\t{\n\t\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModuleProxy *modProx = first->second;\n\n\t\t\t\t\t// do not send a moduleUp on the module himself !\n\t\t\t\t\t// either the gateway is non null (distant module), or the\n\t\t\t\t\t// foreign module id is different of the local module (for local proxy,\n\t\t\t\t\t// the foreign module id store the local module id).\n\t\t\t\t\tif (modProx->getGatewayRoute() != NULL || modProx->getForeignModuleId() != pluggedModule->getModuleId())\n\t\t\t\t\t{\n\t\t\t\t\t\tpluggedModule->_onModuleUp(modProx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t}\n\t\t/// Called just after a module as been effectively unplugged from a socket\n\t\tvoid\t\t\t\tonModuleUnplugged(IModule *unpluggedModule)\n\t\t{\n\t\t\tnldebug(\"NETL6: Gateway %s : unplugging module '%s' id=%u\",\n\t\t\t\tgetModuleName().c_str(),\n\t\t\t\tunpluggedModule->getModuleName().c_str(),\n\t\t\t\tunpluggedModule->getModuleId());\n\n\t\t\t// remove the proxy info\n\t\t\tTLocalModuleIndex::iterator it(_LocalModuleIndex.find(unpluggedModule->getModuleId()));\n\t\t\tnlassert(it != _LocalModuleIndex.end());\n\t\t\tTModuleProxies::iterator it2(_ModuleProxies.find(it->second));\n\t\t\tnlassert(it2 != _ModuleProxies.end());\n\n\t\t\tIModuleProxy *modProx = it2->second;\n\n\t\t\t// warn the unplugged module that all proxies in this gateway become unavailable\n\t\t\t{\n\t\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModuleProxy *modProx = first->second;\n\n\t\t\t\t\tif (modProx->getGatewayRoute() != NULL\n\t\t\t\t\t\t|| modProx->getForeignModuleId() != unpluggedModule->getModuleId())\n\t\t\t\t\t{\n\t\t\t\t\t\tunpluggedModule->_onModuleDown(modProx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/// the gateway do the rest of the job\n\t\t\tonRemoveModuleProxy(modProx);\n\n\t\t\tTModuleId localProxyId = modProx->getModuleProxyId();\n\t\t\t// remove reference to the proxy\n\t\t\t_ModuleProxies.erase(it2);\n\t\t\t_NameToProxyIdx.removeWithB(modProx);\n\t\t\t_LocalModuleIndex.erase(it);\n\n\t\t\t// check in the local message queue if some message are to/from\n\t\t\t// this module\n\t\t\tTLocalMessageList::iterator first(_LocalMessages.begin()), last(_LocalMessages.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTLocalMessage &lm = *first;\n\t\t\t\tif (lm.AddresseProxyId == localProxyId\n\t\t\t\t\t|| lm.SenderProxyId == localProxyId)\n\t\t\t\t{\n\t\t\t\t\t// erase this message !\n\t\t\t\t\tnlwarning(\"CStandardGateway : while unplugging module %u from the gateway, locale message '%s' from proxy %u to proxy %u is lost\",\n\t\t\t\t\t\tunpluggedModule->getModuleId(),\n\t\t\t\t\t\tlm.Message.getName().c_str(),\n\t\t\t\t\t\tlm.SenderProxyId,\n\t\t\t\t\t\tlm.AddresseProxyId);\n\t\t\t\t\tTLocalMessageList::iterator next = first;\n\t\t\t\t\t++next;\n\t\t\t\t\tif (next == last)\n\t\t\t\t\t{\n\t\t\t\t\t\t_LocalMessages.erase(first);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_LocalMessages.erase(first);\n\t\t\t\t\t\tfirst = next;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\t// release the module proxy\n\t\t\tIModuleManager::getInstance().releaseModuleProxy(localProxyId);\n\n\t\t}\n\n\t\t////////////////////////////////////////////////////\n\t\t// Gateway internal methods\n\t\t////////////////////////////////////////////////////\n\n\t\tvoid removeForeignModule(CGatewayRoute *route, TModuleId foreignModuleId)\n\t\t{\n\t\t\t// translate the module id\n\t\t\tconst TModuleId *pModuleId = route->ForeignToLocalIdx.getB(foreignModuleId);\n\t\t\tif (pModuleId == NULL)\n\t\t\t{\n\t\t\t\t// oups !\n\t\t\t\tnlwarning(\"removeForeignModule : unknown foreign module id %u\", foreignModuleId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tTModuleId proxyId = *pModuleId;\n\n\t\t\t// retrieve the module proxy\n\t\t\tTModuleProxies::iterator it2(_ModuleProxies.find(proxyId));\n\t\t\tif (it2 == _ModuleProxies.end())\n\t\t\t{\n\t\t\t\t// oups !\n\t\t\t\tnlwarning(\"Gateway '%s' : removeForeignModule : can't find proxy for id %u coming from foreign id %u\",\n\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\tproxyId,\n\t\t\t\t\tforeignModuleId);\n\n\t\t\t\t// still remove the idx\n\t\t\t\troute->ForeignToLocalIdx.removeWithA(foreignModuleId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tCModuleProxy *modProx = static_cast<CModuleProxy *>(it2->second.getPtr());\n\n\t\t\t// remove module information\n\t\t\tpair<TKnownModuleInfos::iterator, TKnownModuleInfos::iterator> range;\n\t\t\trange = _KnownModules.equal_range(modProx->_FullyQualifiedModuleName);\n\t\t\tnlassert(range.first != range.second);\n\t\t\tbool found = false;\n\t\t\tfor (;range.first != range.second; ++range.first)\n\t\t\t{\n\t\t\t\tTKnownModuleInfo &kmi = range.first->second;\n\n\t\t\t\tif (kmi.Route == route)\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"Gateway '%s' : removing foreign module info for '%s'\",\n\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\tCStringMapper::unmap(range.first->first).c_str());\n\t\t\t\t\t// we have found the info relative to this module\n\t\t\t\t\t_KnownModules.erase(range.first);\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnlassert(found == true);\n\t\t\t// NB : stl debug mode don't allow to test with range.first when range;first is erased.\n//\t\t\t\tnlassert(range.first != range.second);\n\n\t\t\t// check if there is another view of this module\n\t\t\t// if so, we keep the proxy and, eventually, we update the distance\n\t\t\trange = _KnownModules.equal_range(modProx->_FullyQualifiedModuleName);\n\t\t\tif (range.first != range.second)\n\t\t\t{\n\t\t\t\t// clean the translation table\n\t\t\t\troute->ForeignToLocalIdx.removeWithA(foreignModuleId);\n\n\t\t\t\t// we keep the proxy, choose the best route\n\t\t\t\tTKnownModuleInfos::iterator best(_KnownModules.end());\n\n\t\t\t\tfor (; range.first != range.second; ++range.first)\n\t\t\t\t{\n\t\t\t\t\tif (best == _KnownModules.end()\n\t\t\t\t\t\t|| best->second.ModuleDistance > range.first->second.ModuleDistance)\n\t\t\t\t\t\tbest = range.first;\n\t\t\t\t}\n\t\t\t\tnlassert(best != _KnownModules.end());\n\t\t\t\tTKnownModuleInfo &kmi = best->second;\n\n\t\t\t\tif (modProx->_Route != kmi.Route)\n\t\t\t\t{\n\t\t\t\t\t// the best route has changed, update the proxy\n\n\t\t\t\t\tnldebug(\"Gateway '%s' : use a new route for module '%s' from %u to %u hop\",\n\t\t\t\t\t\tgetGatewayName().c_str(),\n\t\t\t\t\t\tmodProx->getModuleName().c_str(),\n\t\t\t\t\t\tmodProx->_Distance,\n\t\t\t\t\t\tkmi.ModuleDistance);\n\n\t\t\t\t\t// update the proxy data\n\t\t\t\t\tmodProx->_Route = kmi.Route;\n\t\t\t\t\tmodProx->_ForeignModuleId = kmi.ForeignProxyId;\n\t\t\t\t\tif (modProx->_Distance != kmi.ModuleDistance)\n\t\t\t\t\t{\n\t\t\t\t\t\t// the distance has changed, update and send the new distance to other gateway\n\t\t\t\t\t\tmodProx->_Distance = kmi.ModuleDistance;\n\t\t\t\t\t\tsendModuleDistanceUpdate(modProx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// do not remove proxy for local module from her !\n\t\t\t\tif (modProx->_Route != NULL)\n\t\t\t\t{\n\t\t\t\t\t// this module is no longer reachable, remove the proxy\n\n\t\t\t\t\t// trigger an event in the gateway\n\t\t\t\t\tonRemoveModuleProxy(modProx);\n\n\t\t\t\t\t// remove from the proxy list\n\t\t\t\t\t_NameToProxyIdx.removeWithB(modProx);\n\t\t\t\t\t_ModuleProxies.erase(it2);\n\t\t\t\t\t// release the proxy\n\t\t\t\t\tIModuleManager::getInstance().releaseModuleProxy(proxyId);\n\t\t\t\t}\n\t\t\t\t// clean the translation table\n\t\t\t\troute->ForeignToLocalIdx.removeWithA(foreignModuleId);\n\t\t\t}\n\t\t}\n\n\t\tvoid sendModuleDistanceUpdate(IModuleProxy *proxy)\n\t\t{\n\t\t\t// in fact, don't send immediately, store update in each\n\t\t\t// route and wait the next update or module message sending\n\t\t\t// to effectively send the update\n\n\t\t\t// for each route\n\t\t\tTRouteList::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayRoute *route = *first;\n\t\t\t\tif (isModuleProxyVisible(proxy, route))\n\t\t\t\t{\n\t\t\t\t\tupdateModuleDistanceToRoute(route, proxy);\n//\t\t\t\t\t// TODO : optimize by batch sending\n//\t\t\t\t\tTModuleDistanceChangeMsg mdu;\n//\n//\t\t\t\t\tmdu.ModuleId = proxy->getModuleProxyId();\n//\t\t\t\t\tmdu.NewDistance = proxy->getModuleDistance()+1;\n//\n//\t\t\t\t\tCMessage msg(\"MOD_DST_UPD\");\n//\t\t\t\t\tmsg.serial(mdu);\n//\n//\t\t\t\t\tsendPendingModuleUpdate(route);\n//\t\t\t\t\troute->sendMessage(msg);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/// Check if a module can be seen by a route\n\t\tbool isModuleProxyVisible(IModuleProxy *proxy, CGatewayRoute *route)\n\t\t{\n\t\t\tif (route == NULL)\n\t\t\t{\n\t\t\t\t// no route, we can see the proxy\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// check firewall rules\n\t\t\tif (route->getTransport()->Firewalled)\n\t\t\t{\n\t\t\t\tif (route->FirewallDisclosed.find(proxy->getModuleProxyId()) == route->FirewallDisclosed.end())\n\t\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// if the module is local, then, it can be seen\n\t\t\tif (proxy->getGatewayRoute() == NULL)\n\t\t\t\treturn true;\n\n\t\t\t// if the module is on the same route, it can't be seen (it is seen by the route outbound)\n\t\t\tif (proxy->getGatewayRoute() == route)\n\t\t\t\treturn false;\n\n\t\t\tIGatewayTransport *transport = route->getTransport();\n\t\t\t// if the module is on a different transport, it can be seen\n\t\t\tif (proxy->getGatewayRoute()->getTransport() != transport)\n\t\t\t{\n\t\t\t\t// we also need to check if this module is known in this route\n//\t\t\t\tCGatewayRoute::TForeignToLocalIdx::iterator it(route->ForeignToLocalIdx.find(proxy->getForeignModuleId()));\n\t\t\t\tif (route->ForeignToLocalIdx.getA(proxy->getModuleProxyId()) != NULL)\n\t\t\t\t\t// this module is known in this route, so not invisible\n\t\t\t\t\treturn false;\n\n\t\t\t\t// ok, we can see\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// if the transport in not in peer invisible, it can be seen\n\t\t\tif (!transport->PeerInvisible)\n\t\t\t\treturn true;\n\n\t\t\t// not visible\n\t\t\treturn false;\n\t\t}\n\n\t\t/// Disclose module information to a gateway route\n\t\tvoid discloseModuleToRoute(CGatewayRoute *route, IModuleProxy *proxy)\n\t\t{\n//\t\t\troute->PendingUndisclosure.erase(proxy->getModuleProxyId());\n\t\t\tCGatewayRoute::TPendingEvent pe;\n\t\t\tpe.EventType = CGatewayRoute::pet_disclose_module;\n\t\t\tpe.ModuleId = proxy->getModuleProxyId();\n\t\t\troute->PendingEvents.push_back(pe);\n//\t\t\troute->PendingDisclosure.insert(proxy);\n\t\t}\n\t\t/// Undisclose module information to a gateway route\n\t\tvoid undiscloseModuleToRoute(CGatewayRoute *route, IModuleProxy *proxy)\n\t\t{\n//\t\t\troute->PendingDisclosure.erase(proxy);\n//\t\t\troute->PendingUndisclosure.insert(proxy->getModuleProxyId());\n//\t\t\troute->FirewallDisclosed.erase(proxy->getModuleProxyId());\n\n\t\t\tCGatewayRoute::TPendingEvent pe;\n\t\t\tpe.EventType = CGatewayRoute::pet_undisclose_module;\n\t\t\tpe.ModuleId = proxy->getModuleProxyId();\n\t\t\troute->PendingEvents.push_back(pe);\n\n\t\t\troute->FirewallDisclosed.erase(proxy->getModuleProxyId());\n\t\t}\n\n\t\t/// the distance of a module need to be update to peers\n\t\tvoid updateModuleDistanceToRoute(CGatewayRoute *route, IModuleProxy *proxy)\n\t\t{\n\t\t\tCGatewayRoute::TPendingEvent pe;\n\t\t\tpe.EventType = CGatewayRoute::pet_update_distance;\n\t\t\tpe.ModuleId = proxy->getModuleProxyId();\n\t\t\troute->PendingEvents.push_back(pe);\n\t\t}\n\t\t/// The security data need to be updated to peers\n\t\tvoid updateModuleSecurityDataToRoute(CGatewayRoute *route, IModuleProxy *proxy)\n\t\t{\n\t\t\tCGatewayRoute::TPendingEvent pe;\n\t\t\tpe.EventType = CGatewayRoute::pet_update_security;\n\t\t\tpe.ModuleId = proxy->getModuleProxyId();\n\t\t\troute->PendingEvents.push_back(pe);\n\t\t}\n\n\t\tvoid sendPendingModuleUpdate(CGatewayRoute *route)\n\t\t{\n\t\t\tif (route->PendingEvents.empty())\n\t\t\t\treturn;\n\n\t\t\tCMessage updateMsg(\"MOD_UPD\");\n\n\t\t\t// compil all update in a single message\n\t\t\twhile (!route->PendingEvents.empty())\n\t\t\t{\n\t\t\t\tCGatewayRoute::TPendingEvent &pe = route->PendingEvents.front();\n\t\t\t\tswitch (pe.EventType)\n\t\t\t\t{\n\t\t\t\tcase CGatewayRoute::pet_disclose_module:\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleProxy *proxy = getModuleProxy(pe.ModuleId);\n\t\t\t\t\t\tif (proxy == NULL)\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t// store the update type\n\t\t\t\t\t\tupdateMsg.serialShortEnum(pe.EventType);\n\n\t\t\t\t\t\t// encode the message data\n\t\t\t\t\t\tTModuleDescCodec modDesc(proxy);\n\t\t\t\t\t\tupdateMsg.serial(modDesc);\n//\t\t\t\t\t\tmodDesc.encode(proxy, updateMsg);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_undisclose_module:\n\t\t\t\t\t{\n\t\t\t\t\t\t// store the update type\n\t\t\t\t\t\tupdateMsg.serialShortEnum(pe.EventType);\n\n\t\t\t\t\t\t// store the module id\n\t\t\t\t\t\tupdateMsg.serial(pe.ModuleId);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_update_distance:\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleProxy *proxy = getModuleProxy(pe.ModuleId);\n\t\t\t\t\t\tif (proxy == NULL)\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t// store the update type\n\t\t\t\t\t\tupdateMsg.serialShortEnum(pe.EventType);\n\n\t\t\t\t\t\t// store module ID and distance\n\t\t\t\t\t\tupdateMsg.serial(pe.ModuleId);\n\t\t\t\t\t\tuint32 distance = proxy->getModuleDistance()+1;\n\t\t\t\t\t\tupdateMsg.serial(distance);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase CGatewayRoute::pet_update_security:\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleProxy *proxy = getModuleProxy(pe.ModuleId);\n\t\t\t\t\t\tif (proxy == NULL)\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t// store the update type\n\t\t\t\t\t\tupdateMsg.serialShortEnum(pe.EventType);\n\n\t\t\t\t\t\t// store module ID and security data\n\t\t\t\t\t\tTModuleSecurityChangeMsg secChg;\n\t\t\t\t\t\tsecChg.ModuleId = pe.ModuleId;\n\t\t\t\t\t\tsecChg.SecDesc.SecurityData = const_cast<TSecurityData*>(proxy->getFirstSecurityData());\n\t\t\t\t\t\tupdateMsg.serial(secChg);\n//\t\t\t\t\t\tupdateMsg.serial(pe.ModuleId);\n//\t\t\t\t\t\tTSecurityData *modSec = const_cast<TSecurityData*>(proxy->getFirstSecurityData());\n//\t\t\t\t\t\tupdateMsg.serialPolyPtr(modSec);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\t// should not append\n\t\t\t\t\tnlstop;\n\t\t\t\t}\n\n\t\t\t\troute->PendingEvents.pop_front();\n\t\t\t}\n\n\t\t\t// now send the message\n\t\t\troute->sendMessage(updateMsg);\n\n//\t\t\t// send pending module proxy un/disclosure\n//\t\t\tif (!route->PendingDisclosure.empty())\n//\t\t\t{\n//\t\t\t\t// disclose new module\n//\t\t\t\tTModuleAddMsg message;\n//\t\t\t\tmessage.Modules.resize(route->PendingDisclosure.size());\n//\n//\t\t\t\tstd::set<IModuleProxy*>::iterator first(route->PendingDisclosure.begin()), last(route->PendingDisclosure.end());\n//\t\t\t\tfor (uint i=0; first != last; ++i, ++first)\n//\t\t\t\t{\n//\t\t\t\t\tTModuleDescMsg &modDesc = message.Modules[i];\n//\t\t\t\t\tIModuleProxy *addedModule = *first;\n//\n//\t\t\t\t\tmodDesc.ModuleProxyId = addedModule->getModuleProxyId();\n//\t\t\t\t\tmodDesc.ModuleClass\t = addedModule->getModuleClassName();\n//\t\t\t\t\tmodDesc.ModuleFullName = addedModule->getModuleName();\n//\t\t\t\t\tmodDesc.ModuleDistance = addedModule->getModuleDistance()+1;\n//\t\t\t\t}\n//\t\t\t\troute->PendingDisclosure.clear();\n//\n//\t\t\t\tCMessage buffer(\"MOD_ADD\");\n//\t\t\t\tbuffer.serial(message);\n//\n//\t\t\t\troute->sendMessage(buffer);\n//\t\t\t}\n//\t\t\tif (!route->PendingUndisclosure.empty())\n//\t\t\t{\n//\t\t\t\t// disclose new module\n//\t\t\t\tTModuleRemMsg message;\n//\t\t\t\tstd::copy(route->PendingUndisclosure.begin(), route->PendingUndisclosure.end(), back_insert_iterator<vector<TModuleId> >(message.RemovedModules));\n//\t\t\t\troute->PendingUndisclosure.clear();\n//\n//\t\t\t\tCMessage buffer(\"MOD_REM\");\n//\t\t\t\tbuffer.serial(message);\n//\n//\t\t\t\troute->sendMessage(buffer);\n//\t\t\t}\n\t\t}\n\n\t\tvoid getModuleList(std::vector<IModuleProxy*> &resultList)\n\t\t{\n\t\t\tTModuleProxies::iterator first(_ModuleProxies.begin()), last(_ModuleProxies.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tresultList.push_back(first->second);\n\t\t\t}\n\t\t}\n\n\n\t\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CStandardGateway, CModuleBase)\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, dump, \"dump various information about the gateway statue\", \"\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, transportListAvailableClass, \"list the available transport class\", \"no param\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, transportAdd, \"add a new transport to this gateway\", \"<transportClass> <instanceName>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, transportOptions, \"set a gateway level option on a transport\", \"<transportClass> ( [PeerInvisible] [Firewalled] )\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, transportCmd, \"send a command to a transport\", \"[<transportName> ( <cmd specific to transport> )]*\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, transportRemove, \"remove an existing transport instance\", \"<transportName>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, securityListAvailableClass, \"list the available security class\", \"no param\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, securityCreate, \"create a security plug-in\", \"<securityClassName>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, securityCommand, \"send a command to the security plug-in\", \"<cmd specific to plug-in>\")\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CStandardGateway, securityRemove, \"remove the security plug-in\", \"no parameter\")\n\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\t\tNLMISC_CLASS_COMMAND_DECL(securityRemove)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(args);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (_SecurityPlugin == NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"No security plug-in !\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tremoveSecurityPlugin();\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(securityCommand)\n\t\t{\n\t\t\tnlunreferenced(args);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tTParsedCommandLine command;\n\n\t\t\tif (!command.parseParamList(rawCommandString))\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Invalid command line\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (command.SubParams.size() < 2)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Invalid command line\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (_SecurityPlugin == NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"No security plug-in !\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tsendSecurityCommand(*command.SubParams[1]);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(securityCreate)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tif (_SecurityPlugin != NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"The gateway already have a security plug-in ! Remove it first\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tlog.displayNL(\"Creating a security plug-in '%s' in gateway '%s'\",\n\t\t\t\targs[0].c_str(),\n\t\t\t\tgetModuleName().c_str());\n\t\t\tcreateSecurityPlugin(args[0]);\n\n\t\t\treturn true;\n\n\t\t}\n\t\tNLMISC_CLASS_COMMAND_DECL(securityListAvailableClass)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 0)\n\t\t\t\treturn false;\n\n\t\t\tvector<string> list;\n\t\t\tNLMISC_GET_FACTORY(CGatewaySecurity, std::string).fillFactoryList(list);\n\n\t\t\tlog.displayNL(\"List of %u available security class :\", list.size());\n\n\t\t\tfor (uint i=0; i<list.size(); ++i)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"   '%s'\", list[i].c_str());\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(transportRemove)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(log);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tdeleteTransport(args[0]);\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(transportCmd)\n\t\t{\n\t\t\tnlunreferenced(args);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tTParsedCommandLine pcl;\n\t\t\tif (!pcl.parseParamList(rawCommandString))\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Invalid parameter string, parse error\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\ttransportCommand(pcl);\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(transportOptions)\n\t\t{\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() < 1)\n\t\t\t\treturn false;\n\n\t\t\t// parse the params\n\t\t\tTParsedCommandLine cl;\n\t\t\tif (!cl.parseParamList(rawCommandString))\n\t\t\t\treturn false;\n\n\t\t\tif (cl.SubParams.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tstring transName = cl.SubParams[1]->ParamName;\n\t\t\tif (_Transports.find(transName) == _Transports.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"unknown transport '%s'\", transName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n//\t\t\tIGatewayTransport *transport = _Transports.find(transName)->second;\n\n\t\t\t// check for peer invisible\n\t\t\tif (cl.SubParams[1]->getParam(\"PeerInvisible\"))\n\t\t\t\tsetTransportPeerInvisible(transName, true);\n\t\t\telse\n\t\t\t\tsetTransportPeerInvisible(transName, false);\n\n\t\t\t// check for firewall mode\n\t\t\tif (cl.SubParams[1]->getParam(\"Firewalled\"))\n\t\t\t\tsetTransportFirewallMode(transName, true);\n\t\t\telse\n\t\t\t\tsetTransportFirewallMode(transName, false);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(transportAdd)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 2)\n\t\t\t\treturn false;\n\n\t\t\tif (_Transports.find(args[1]) != _Transports.end())\n\t\t\t{\n\t\t\t\tlog.displayNL(\"A transport with that name already exist !\");\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tcreateTransport(args[0], args[1]);\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(transportListAvailableClass)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 0)\n\t\t\t\treturn false;\n\n\t\t\tvector<string> list;\n\t\t\tNLMISC_GET_FACTORY(IGatewayTransport, std::string).fillFactoryList(list);\n\n\t\t\tlog.displayNL(\"List of %u available transport class :\", list.size());\n\n\t\t\tfor (uint i=0; i<list.size(); ++i)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"   '%s'\", list[i].c_str());\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(dump)\n\t\t{\n\t\t\tif (!args.empty())\n\t\t\t\treturn false;\n\n\t\t\t// recall the dump for the module class\n\t\t\tNLMISC_CLASS_COMMAND_CALL_BASE(CModuleBase, dump);\n\n\t\t\tlog.displayNL(\"-----------------------------\");\n\t\t\tlog.displayNL(\"Dumping gateway information :\");\n\t\t\tlog.displayNL(\"-----------------------------\");\n\n\t\t\tlog.displayNL(\"The gateway has %u locally plugged module :\", _PluggedModules.getAToBMap().size());\n\t\t\t{\n\t\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModule *module = first->second;\n\t\t\t\t\tlog.displayNL(\"    ID:%5u : \\tName = '%s' \\tclass = '%s'\",\n\t\t\t\t\t\tmodule->getModuleId(),\n\t\t\t\t\t\tmodule->getModuleName().c_str(),\n\t\t\t\t\t\tmodule->getModuleClassName().c_str());\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tlog.displayNL(\"The gateway as %u transport activated :\", _Transports.size());\n\t\t\t{\n\t\t\t\tTTransportList::iterator first(_Transports.begin()), last(_Transports.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tconst string &name = first->first;\n\t\t\t\t\tIGatewayTransport *transport = first->second;\n\n\t\t\t\t\tlog.displayNL(\"Transport '%s' (transport class is '%s') :\",\n\t\t\t\t\t\tname.c_str(),\n\t\t\t\t\t\ttransport->getClassName().c_str());\n\t\t\t\t\tlog.displayNL(\"  * %s\", transport->PeerInvisible ? \"Peer module are NON visible\" : \"Peer modules are visible\");\n\t\t\t\t\tlog.displayNL(\"  * %s\", transport->Firewalled ? \"Firewall ON\" : \"Firewall OFF\");\n\t\t\t\t\ttransport->dump(log);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlog.displayNL(\"------------------------------\");\n\t\t\tlog.displayNL(\"------- End of dump ----------\");\n\t\t\tlog.displayNL(\"------------------------------\");\n\t\t\treturn true;\n\t\t}\n\n\t};\n\n\n\t// register the module factory\n\tNLNET_REGISTER_MODULE_FACTORY(CStandardGateway, \"StandardGateway\");\n\n\n\t/** Set a security data block. If a bloc of the same type\n\t *\talready exist in the list, the new one will replace the\n\t *\texisting one.\n\t */\n\tvoid CGatewaySecurity::setSecurityData(IModuleProxy *proxy, TSecurityData *securityData)\n\t{\n\t\t// forward the call to standard gateway\n\t\tCStandardGateway *sg = static_cast<CStandardGateway*>(_Gateway);\n\t\tsg->setSecurityData(proxy, securityData);\n\t}\n\n\t/** Clear a block of security data\n\t *\tThe block is identified by the data tag\n\t */\n\tbool CGatewaySecurity::removeSecurityData(IModuleProxy *proxy, uint8 dataTag)\n\t{\n\t\t// forward the call to standard gateway\n\t\tCStandardGateway *sg = static_cast<CStandardGateway*>(_Gateway);\n\t\treturn sg->removeSecurityData(proxy, dataTag);\n\t}\n\n\t/** Replace the complete set of security data with the new one.\n\t *\tSecurity data allocated on the proxy are freed,\n\t */\n\tvoid CGatewaySecurity::replaceAllSecurityDatas(IModuleProxy *proxy, TSecurityData *securityData)\n\t{\n\t\t// forward the call to standard gateway\n\t\tCStandardGateway *sg = static_cast<CStandardGateway*>(_Gateway);\n\t\tsg->replaceAllSecurityDatas(proxy, securityData);\n\t}\n\n\t/** Ask the gateway to resend the security data.\n\t *\tThe plug-in call this method after having changed\n\t *\tthe security info for a plug-in outside of the\n\t *\tonNewProxy call.\n\t */\n\tvoid CGatewaySecurity::forceSecurityUpdate(IModuleProxy *proxy)\n\t{\n\t\t// forward the call to standard gateway\n\t\tCStandardGateway *sg = static_cast<CStandardGateway*>(_Gateway);\n\t\tsg->forceSecurityUpdate(proxy);\n\t}\n\n\n\n\tvoid forceGatewayLink()\n\t{\n\t}\n\n} // namespace NLNET\n\n"
  },
  {
    "path": "code/nel/src/net/module_gateway_transport.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/module_message.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\n\nnamespace NLNET\n{\n\n\t// keep alive delay in seconds of inactivity\n\t// NB : it is useless to set it at a value less than 100\" because\n\t// according to RFC 1122 (Requirements for Internet Hosts),\n\t// the TCP transmission time out is a least of 100\" before\n\t// closing a connection without acknowledge.\n\t// That means modules seens from a dead connection will only be\n\t// removed after little more than 100\".\n\tconst uint32\tKEEP_ALIVE_DELAY = 120;\n\n\t/** the specialized route for server transport */\n\tclass CL3ServerRoute : public CGatewayRoute\n\t{\n\tpublic:\n\t\t/// The id of the socket in the server\n\t\tTSockId\t\t\tSockId;\n\n\t\t/// Time stamp of last message received/emitted\n\t\tmutable uint32\tLastCommTime;\n\n\n\t\tCL3ServerRoute(IGatewayTransport *transport)\n\t\t\t: CGatewayRoute(transport),\n\t\t\tLastCommTime(CTime::getSecondsSince1970())\n\t\t{\n\t\t}\n\n\t\tvoid sendMessage(const CMessage &message) const;\n\t};\n\n#define LAYER3_SERVER_CLASS_NAME \"L3Server\"\n\n\t/** Gateway transport using layer 3 server */\n\tclass CGatewayL3ServerTransport : public IGatewayTransport\n\t{\n\t\tfriend class CL3ServerRoute;\n\tpublic:\n\t\t/// The callback server that receive connection and dispatch message\n\t\tauto_ptr<CCallbackServer>\t\t\t_CallbackServer;\n\n\t\t/// A static mapper to retrieve transport from the CCallbackServer pointer\n\t\ttypedef map<CCallbackNetBase*, CGatewayL3ServerTransport*>\tTDispatcherIndex;\n\t\tstatic TDispatcherIndex\t\t\t\t_DispatcherIndex;\n\n\t\t/// The table that keep track of all routes\n\t\ttypedef std::map<TSockId, CL3ServerRoute*>\tTRouteMap;\n\t\tTRouteMap\t_Routes;\n\n\n\t\t/// Constructor\n\t\tCGatewayL3ServerTransport(const IGatewayTransport::TCtorParam &param)\n\t\t\t: IGatewayTransport(param)\n\t\t{\n\t\t}\n\n\t\t~CGatewayL3ServerTransport()\n\t\t{\n\t\t\tif (_CallbackServer.get() != NULL)\n\t\t\t{\n\t\t\t\t// the transport is still open, close it before destruction\n\t\t\t\tcloseServer();\n\t\t\t}\n\t\t}\n\n\t\tconst std::string &getClassName() const\n\t\t{\n\t\t\tstatic string className(LAYER3_SERVER_CLASS_NAME);\n\t\t\treturn className;\n\t\t}\n\n\t\tvirtual void update()\n\t\t{\n\t\t\tH_AUTO(L3S_update);\n\t\t\t// update the callback server\n\t\t\tif (_CallbackServer.get() != NULL)\n\t\t\t\t_CallbackServer->update2(100, 0);\n\n\t\t\tuint32 now = CTime::getSecondsSince1970();\n\t\t\t// check each connected client for keep alive\n\t\t\tTRouteMap::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCL3ServerRoute *route = first->second;\n\n\t\t\t\tif (now - route->LastCommTime > KEEP_ALIVE_DELAY)\n\t\t\t\t{\n\t\t\t\t\tnldebug(\"NETL6:L3Server: sending KeepAlive message\");\n\t\t\t\t\t// send a keep alive message\n\t\t\t\t\tCMessage keepAlive(\"KA\");\n\t\t\t\t\troute->sendMessage(keepAlive);\n\n\t\t\t\t\t// update the last event time\n\t\t\t\t\troute->LastCommTime = CTime::getSecondsSince1970();\n\t\t\t\t}\n\n\t\t\t\t// force a flush of the connection\n\t\t\t\t_CallbackServer->flush(route->SockId);\n\t\t\t}\n\n\n\t\t}\n\n\t\tvirtual uint32 getRouteCount() const\n\t\t{\n\t\t\treturn (uint32)_Routes.size();\n\t\t}\n\n\t\tvoid dump(NLMISC::CLog &log) const\n\t\t{\n\t\t\tIModuleManager &mm = IModuleManager::getInstance();\n\t\t\tlog.displayNL(\"  NeL Net layer 3 transport, SERVER mode\");\n\t\t\tif (_CallbackServer.get() == NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"  The server is currently closed.\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlog.displayNL(\"  The server is open on '%s' and support %u routes :\",\n\t\t\t\t\t_CallbackServer->listenAddress().asString().c_str(),\n\t\t\t\t\t_Routes.size());\n\t\t\t\tTRouteMap::const_iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTSockId\tsockId = first->first;\n\t\t\t\t\tCL3ServerRoute *route = first->second;\n\t\t\t\t\tlog.displayNL(\"    + route to '%s', %u entries in the proxy translation table :\",\n\t\t\t\t\t\tsockId->getTcpSock()->remoteAddr().asString().c_str(),\n\t\t\t\t\t\troute->ForeignToLocalIdx.getAToBMap().size());\n\n\t\t\t\t\t{\n\t\t\t\t\t\tCGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIModuleProxy *modProx = mm.getModuleProxy(first->second);\n\n\t\t\t\t\t\t\tlog.displayNL(\"      - Proxy '%s' : local proxy id %u => foreign module id %u\",\n\t\t\t\t\t\t\t\tmodProx != NULL ? modProx->getModuleName().c_str() : \"ERROR, invalid module\",\n\t\t\t\t\t\t\t\tfirst->second,\n\t\t\t\t\t\t\t\tfirst->first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlog.displayNL(\"  Dumping send buffers states\");\n\t\t\t\t_CallbackServer->displaySendQueueStat(&log);\n\t\t\t\tlog.displayNL(\"  Dumping receive buffers states\");\n\t\t\t\t_CallbackServer->displayReceiveQueueStat(&log);\n\t\t\t}\n\t\t}\n\n\t\tvoid onCommand(const CMessage &/* command */) throw (EInvalidCommand)\n\t\t{\n\t\t\t// nothing done for now\n\t\t\tthrow EInvalidCommand();\n\t\t}\n\t\t/// The gateway send a textual command to the transport\n\t\tbool onCommand(const TParsedCommandLine &command) throw (EInvalidCommand)\n\t\t{\n\t\t\tif (command.SubParams.size() < 1)\n\t\t\t\tthrow  EInvalidCommand();\n\n\t\t\tconst std::string &commandName = command.SubParams[0]->ParamName;\n\t\t\tif (commandName == \"open\")\n\t\t\t{\n\t\t\t\tconst TParsedCommandLine *portParam = command.getParam(\"port\");\n\t\t\t\tif (portParam == NULL)\n\t\t\t\t\tthrow EInvalidCommand();\n\n\t\t\t\tuint16 port;\n\t\t\t\tfromString(portParam->ParamValue, port);\n\n\t\t\t\topenServer(port);\n\t\t\t}\n\t\t\telse if (commandName == \"close\")\n\t\t\t{\n\t\t\t\tcloseServer();\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn false;\n\n\t\t\treturn true;\n\t\t}\n\n\t\t/// Open the server by starting listing for incoming connection on the specified port\n\t\tvoid openServer(uint16 port) throw (ETransportError)\n\t\t{\n\t\t\tif (_CallbackServer.get() != NULL)\n\t\t\t\tthrow ETransportError(\"openServer : The server is already open\");\n\n\t\t\t// create a new callback server\n\t\t\tauto_ptr<CCallbackServer> cbs = auto_ptr<CCallbackServer> (new CCallbackServer());\n\n\t\t\t// register the callbacks\n\t\t\tcbs->setConnectionCallback(cbConnection, static_cast<IGatewayTransport*>(this));\n\t\t\tcbs->setDisconnectionCallback(cbDisconnection, static_cast<IGatewayTransport*>(this));\n\t\t\tcbs->setDefaultCallback(cbDispatchMessage);\n\n\t\t\t// open the server\n\t\t\tcbs->init(port);\n\n\t\t\t_CallbackServer = cbs;\n\n\t\t\t// register it in the dispatcher\n\t\t\t_DispatcherIndex.insert(make_pair(_CallbackServer.get(), this));\n\t\t}\n\n\t\t/// Close the server, this will close the listing socket and any active connection\n\t\tvoid closeServer()\n\t\t{\n\t\t\tif (_CallbackServer.get() == NULL)\n\t\t\t\tthrow ETransportError(\"closeServer : The server is not open\");\n\n\t\t\t// close all client connections\n\t\t\twhile (!_Routes.empty())\n\t\t\t{\n\t\t\t\tCL3ServerRoute *route = _Routes.begin()->second;\n\n\t\t\t\t// close the connection\n\t\t\t\t_CallbackServer->disconnect(route->SockId);\n\t\t\t\t// callback the gateway\n\t\t\t\t_Gateway->onRouteRemoved(route);\n\n\t\t\t\t// delete route and cleanup\n\t\t\t\t_Routes.erase(_Routes.begin());\n\t\t\t\tdelete route;\n\t\t\t}\n\n\t\t\t// Remove the dispatcher info\n\t\t\t_DispatcherIndex.erase(_CallbackServer.get());\n\n\t\t\t// release the callback server\n\t\t\tdelete _CallbackServer.release();\n\t\t}\n\n\n\t\t/***************************************************/\n\t\t/** Event management                              **/\n\t\t/***************************************************/\n\n\t\t// handle the connection of a new client on the server\n\t\tvoid onConnection ( TSockId from)\n\t\t{\n\t\t\tH_AUTO(L3S_onConnection);\n\t\t\tnlassert(_Routes.find(from) == _Routes.end());\n\n\t\t\t// Create a new route for this connection\n\t\t\tCL3ServerRoute* route = new CL3ServerRoute(this);\n\t\t\troute->SockId = from;\n\n\t\t\t// update the last event time\n\t\t\troute->LastCommTime = CTime::getSecondsSince1970();\n\n\t\t\t// store the route information\n\t\t\t_Routes.insert(make_pair(from, route));\n\n\t\t\t// callback the gateway\n\t\t\t_Gateway->onRouteAdded(route);\n\t\t}\n\n\t\t// handle the deconnection of a new client on the server\n\t\tvoid onDisconnection ( TSockId from)\n\t\t{\n\t\t\tH_AUTO(L3S_onDisconnection);\n\t\t\tTRouteMap::iterator it(_Routes.find(from));\n\t\t\tnlassert(it != _Routes.end());\n\n\t\t\t// callback the gateway that this route is no more\n\t\t\t_Gateway->onRouteRemoved(it->second);\n\n\t\t\t// delete the route\n\t\t\tCL3ServerRoute *route = it->second;\n\t\t\t_Routes.erase(it);\n\t\t\tdelete route;\n\t\t}\n\n\t\t// Called to dispatch an incoming message to the gateway\n\t\tvoid onDispatchMessage(const CMessage &msgin, TSockId from, CCallbackNetBase &/* netbase */)\n\t\t{\n\t\t\tH_AUTO(L3S_onDispatchMessage);\n\t\t\tTRouteMap::iterator it(_Routes.find(from));\n\t\t\tnlassert(it != _Routes.end());\n\n\t\t\t// update the last event time\n\t\t\tit->second->LastCommTime = CTime::getSecondsSince1970();\n\n\t\t\tif (msgin.getName() == \"KA\")\n\t\t\t{\n\t\t\t\t// this is just a server prob, ignore it\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_Gateway->onReceiveMessage(it->second, msgin);\n\n\t\t}\n\n\n\t\t/***************************************************/\n\t\t/** static callback forwarder                     **/\n\t\t/***************************************************/\n\t\t// Forwarder to the real method\n\t\tstatic void cbConnection ( TSockId from, void *arg )\n\t\t{\n\t\t\tnlassert(arg != NULL);\n\t\t\tCGatewayL3ServerTransport *transport = dynamic_cast<CGatewayL3ServerTransport *>(static_cast<IGatewayTransport*>(arg));\n\t\t\tnlassert(transport != NULL);\n\n\t\t\ttransport->onConnection(from);\n\t\t}\n\n\t\t// Forwarder to the real method\n\t\tstatic void cbDisconnection ( TSockId from, void *arg )\n\t\t{\n\t\t\tnlassert(arg != NULL);\n\t\t\tCGatewayL3ServerTransport *transport = dynamic_cast<CGatewayL3ServerTransport *>(static_cast<IGatewayTransport*>(arg));\n\t\t\tnlassert(transport != NULL);\n\n\t\t\ttransport->onDisconnection(from);\n\t\t}\n\n\t\t// Forward to the real method, do the dispatching to the correct CGatewayL3ServerTransport instance\n\t\tstatic void cbDispatchMessage (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n\t\t{\n\t\t\t// retrieve the transport instance\n\t\t\tTDispatcherIndex::iterator it(_DispatcherIndex.find(&netbase));\n\t\t\tnlassert(it != _DispatcherIndex.end());\n\n\t\t\t// forward the call\n\t\t\tit->second->onDispatchMessage(msgin, from, netbase);\n\t\t}\n\n\t};\n\n\tCGatewayL3ServerTransport::TDispatcherIndex\tCGatewayL3ServerTransport::_DispatcherIndex;\n\n\t// register this class in the transport factory\n\tNLMISC_REGISTER_OBJECT(IGatewayTransport, CGatewayL3ServerTransport, std::string, string(LAYER3_SERVER_CLASS_NAME));\n\n\tvoid CL3ServerRoute::sendMessage(const CMessage &message) const\n\t{\n\t\tH_AUTO(L3SRoute_sendMessage);\n\t\tNLNET_AUTO_DELTE_ASSERT;\n\n\t\tCGatewayL3ServerTransport *trpt = static_cast<CGatewayL3ServerTransport*>(_Transport);\n\n\t\t// send the message\n\t\ttrpt->_CallbackServer->send(message, SockId);\n\n\t\t// update the last time\n\t\tLastCommTime = CTime::getSecondsSince1970();\n\t}\n\n\t/////////////////////////////////////////////////////////////////////////////////////////\n\t/////////////////////////////////////////////////////////////////////////////////////////\n\t/// Layer 3 client transport\n\t/////////////////////////////////////////////////////////////////////////////////////////\n\t/////////////////////////////////////////////////////////////////////////////////////////\n\tclass CL3ClientRoute : public CGatewayRoute\n\t{\n\tpublic:\n\t\t/// The server address for this route\n\t\tCInetAddress\t\t\t\tServerAddr;\n\t\t/// The Client callback\n\t\tmutable CCallbackClient\t\tCallbackClient;\n\t\t/// Time stamp of last message received/emitted\n\t\tmutable uint32\t\t\t\tLastCommTime;\n\n\t\t/// The last time we try to reconnect (in case of disconnection)\n\t\tuint32\t\t\t\t\t\tLastConnectionRetry;\n\n\t\t// conn id\n\t\tuint32\t\t\t\t\t\tConnId;\n\n\t\tCL3ClientRoute(IGatewayTransport *transport, CInetAddress serverAddr,uint32 connId)\n\t\t\t: CGatewayRoute(transport),\n\t\t\tServerAddr(serverAddr),\n\t\t\tLastCommTime(CTime::getSecondsSince1970()),\n\t\t\tLastConnectionRetry(0),\n\t\t\tConnId(connId)\n\t\t{\n\t\t}\n\n\t\tvoid sendMessage(const CMessage &message) const\n\t\t{\n\t\t\tNLNET_AUTO_DELTE_ASSERT;\n\t\t\tH_AUTO(L3CRoute_sendMessage);\n\t\t\tif (CallbackClient.connected())\n\t\t\t{\n\t\t\t\t// update the last comme time\n\t\t\t\tLastCommTime = CTime::getSecondsSince1970();\n\n\t\t\t\tCallbackClient.send(message);\n\t\t\t}\n\t\t}\n\t};\n\n#define LAYER3_CLIENT_CLASS_NAME \"L3Client\"\n\n\t/** Gateway transport using layer 3 client */\n\tclass CGatewayL3ClientTransport : public IGatewayTransport\n\t{\n\t\tfriend class CL3ClientRoute;\n\tpublic:\n\t\t/// A static mapper to retrieve transport from the CCallbackServer pointer\n\t\ttypedef map<CCallbackNetBase*, CGatewayL3ClientTransport*>\tTDispatcherIndex;\n\t\tstatic TDispatcherIndex\t\t\t\t_DispatcherIndex;\n\n\t\t/// Storage for active connection\n\t\ttypedef map<TSockId, CL3ClientRoute*>\tTClientRoutes;\n\t\tTClientRoutes\t\t\t_Routes;\n\n\t\t/// Indexed storage of active connection (used for stable connId)\n\t\t/// a NULL TSockeId mean a free connection slot.\n\t\ttypedef vector<TSockId>\t\tTClientRouteIds;\n\t\tTClientRouteIds\t\t\t_RouteIds;\n\t\t/// A list of free slot ready for use\n\t\ttypedef vector<TClientRouteIds::difference_type>\tTFreeRouteIds;\n\t\tTFreeRouteIds\t\t\t_FreeRoutesIds;\n\n\t\t/// the route to delete outside of the update loop\n\t\tlist<CL3ClientRoute*>\t_RouteToRemove;\n\n\t\t/// Retry interval for reconnection\n\t\tuint32\t\t\t\t\t_RetryInterval;\n\n\t\tenum\n\t\t{\n\t\t\t/// Default time interval (in seconds) between to reconnection attempts\n\t\t\tRETRY_INTERVAL =  5,\n\t\t\t/// A minimum value in case or configuration error\n\t\t\tMIN_RETRY_INTERVAL = 1,\n\t\t};\n\n\t\t/// Constructor\n\t\tCGatewayL3ClientTransport(const IGatewayTransport::TCtorParam &param)\n\t\t\t: IGatewayTransport(param),\n\t\t\t_RetryInterval(RETRY_INTERVAL)\n\t\t{\n\t\t}\n\n\t\t~CGatewayL3ClientTransport()\n\t\t{\n\t\t\tdeletePendingRoute();\n\n\t\t\t// close all open connection\n\t\t\tfor (uint i=0; i<_RouteIds.size(); ++i)\n\t\t\t{\n\t\t\t\tif (_RouteIds[i] != NULL)\n\t\t\t\t{\n\t\t\t\t\t// close this open connection\n\t\t\t\t\tclose(i);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid deletePendingRoute()\n\t\t{\n\t\t\tH_AUTO(L3C_deletePendingRoute);\n\t\t\t// delete any route pending\n\t\t\twhile (!_RouteToRemove.empty())\n\t\t\t{\n\t\t\t\tCL3ClientRoute *route = _RouteToRemove.front();\n\t\t\t\t_DispatcherIndex.erase(&(route->CallbackClient));\n\t\t\t\t_Routes.erase(route->CallbackClient.getSockId());\n\n\t\t\t\t_RouteIds[route->ConnId] = NULL;\n\t\t\t\t_FreeRoutesIds.push_back(route->ConnId);\n\t\t\t\tdelete route;\n\t\t\t\t_RouteToRemove.pop_front();\n\t\t\t}\n\t\t}\n\n\t\tconst std::string &getClassName() const\n\t\t{\n\t\t\tstatic string className(LAYER3_CLIENT_CLASS_NAME);\n\t\t\treturn className;\n\t\t}\n\n\t\tvirtual void update()\n\t\t{\n\t\t\tH_AUTO(L3C_update);\n\t\t\t// delete any route pending\n\t\t\tdeletePendingRoute();\n\n\t\t\tuint32 now = CTime::getSecondsSince1970();\n\t\t\t// update the client connection\n\t\t\tTClientRoutes::iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCL3ClientRoute *route = first->second;\n\n\t\t\t\tif (!route->CallbackClient.connected())\n\t\t\t\t{\n\t\t\t\t\t// this route is not connected, try a reconnect ?\n\t\t\t\t\tif (route->LastConnectionRetry + _RetryInterval < now)\n\t\t\t\t\t{\n\t\t\t\t\t\troute->LastConnectionRetry = now;\n\t\t\t\t\t\ttry\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnldebug(\"Connecting to %s...\", route->ServerAddr.asString().c_str());\n\t\t\t\t\t\t\troute->CallbackClient.connect(route->ServerAddr);\n\t\t\t\t\t\t\tnldebug(\"Connected to %s\", route->ServerAddr.asString().c_str());\n\t\t\t\t\t\t\t_Gateway->onRouteAdded(route);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcatch(...)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnlinfo(\"Server %s still not available for connection\", route->ServerAddr.asString().c_str());\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\troute->CallbackClient.update2(100, 0);\n\n\t\t\t\t\t// check dead connection. For client, we use a little longer timer to\n\t\t\t\t\t// avoid cross checking of client and server. If server is alive, then we receive\n\t\t\t\t\t// the server keep alive packet a little before we need to send the client one, thus\n\t\t\t\t\t// reseting the keep alive timer.\n\t\t\t\t\tif (now - route->LastCommTime > (KEEP_ALIVE_DELAY+5))\n\t\t\t\t\t{\n\t\t\t\t\t\tnldebug(\"NETL6:L3Client: sending KeepAlive message\");\n\n\t\t\t\t\t\t// send a keep alive message\n\t\t\t\t\t\tCMessage keepAlive(\"KA\");\n\n\t\t\t\t\t\troute->sendMessage(keepAlive);\n\t\t\t\t\t}\n\n\t\t\t\t\t// force a flush of the connection\n\t\t\t\t\troute->CallbackClient.flush();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual uint32 getRouteCount() const\n\t\t{\n\t\t\treturn (uint32)_Routes.size();\n\t\t}\n\n\t\tvoid dump(NLMISC::CLog &log) const\n\t\t{\n\t\t\tIModuleManager &mm = IModuleManager::getInstance();\n\t\t\tlog.displayNL(\"  NeL Net layer 3 transport, CLIENT mode\");\n\n\t\t\tlog.displayNL(\"  There are actually %u active route :\", _Routes.size());\n\n\t\t\tTClientRoutes::const_iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCL3ClientRoute *route = first->second;\n\t\t\t\tlog.displayNL(\"    + route to '%s', %s, %u entries in the proxy translation table :\",\n\t\t\t\t\troute->ServerAddr.asString().c_str(),\n\t\t\t\t\troute->CallbackClient.connected() ? \"connected\" : \"NOT CONNECTED\",\n\t\t\t\t\troute->ForeignToLocalIdx.getAToBMap().size());\n\t\t\t\t{\n\t\t\t\t\tCGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());\n\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleProxy *modProx = mm.getModuleProxy(first->second);\n\n\t\t\t\t\t\tlog.displayNL(\"      - Proxy '%s' : local proxy id %u => foreign module id %u\",\n\t\t\t\t\t\t\tmodProx != NULL ? modProx->getModuleName().c_str() : \"ERROR, invalid module\",\n\t\t\t\t\t\t\tfirst->second,\n\t\t\t\t\t\t\tfirst->first);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlog.displayNL(\"     Dumping send buffer state\");\n\t\t\t\troute->CallbackClient.displaySendQueueStat(&log);\n\t\t\t\tlog.displayNL(\"     Dumping receive buffer state\");\n\t\t\t\troute->CallbackClient.displayReceiveQueueStat(&log);\n\t\t\t}\n\t\t}\n\n\t\tvoid onCommand(const CMessage &/* command */) throw (EInvalidCommand)\n\t\t{\n\t\t\t// nothing done for now\n\t\t\tthrow EInvalidCommand();\n\t\t}\n\t\t/// The gateway send a textual command to the transport\n\t\tbool onCommand(const TParsedCommandLine &command) throw (EInvalidCommand)\n\t\t{\n\t\t\tif (command.SubParams.size() < 1)\n\t\t\t\tthrow  EInvalidCommand();\n\n\t\t\tconst std::string &commandName = command.SubParams[0]->ParamName;\n\t\t\tif (commandName == \"connect\")\n\t\t\t{\n\t\t\t\tconst TParsedCommandLine *addrParam = command.getParam(\"addr\");\n\t\t\t\tif (addrParam == NULL)\n\t\t\t\t\tthrow EInvalidCommand();\n\n\t\t\t\tCInetAddress addr(addrParam->ParamValue);\n\n\t\t\t\tconnect(addr);\n\t\t\t}\n\t\t\telse if (commandName == \"close\")\n\t\t\t{\n\t\t\t\tconst TParsedCommandLine *conIdParam= command.getParam(\"connId\");\n\t\t\t\tif (conIdParam == NULL)\n\t\t\t\t\tthrow EInvalidCommand();\n\n\t\t\t\tuint32\tconnId;\n\t\t\t\tfromString(conIdParam->ParamValue, connId);\n\n\t\t\t\tclose(connId);\n\t\t\t}\n\t\t\telse if (commandName == \"retryInterval\")\n\t\t\t{\n\t\t\t\tuint32 interval;\n\t\t\t\tfromString(command.SubParams[0]->ParamValue, interval);\n\t\t\t\t_RetryInterval = std::max(uint32(MIN_RETRY_INTERVAL), interval);\n\n\t\t\t\tnldebug(\"CGatewayL3ClientTransport : setting retry interval to %u\", _RetryInterval);\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn false;\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\t/// connect to a server\n\t\tvoid connect(CInetAddress &addr)\n\t\t{\n\t\t\tH_AUTO(L3C_connect);\n\t\t\tuint32 connId;\n\n\t\t\t// affect a connection id\n\t\t\tif (_FreeRoutesIds.empty())\n\t\t\t{\n\t\t\t\tconnId = (uint32)_RouteIds.size();\n\t\t\t\t_RouteIds.push_back(InvalidSockId);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tconnId = (uint32)_FreeRoutesIds.back();\n\t\t\t\t_FreeRoutesIds.pop_back();\n\t\t\t}\n\n\t\t\tauto_ptr<CL3ClientRoute> route = auto_ptr<CL3ClientRoute>(new CL3ClientRoute(this, addr, connId));\n\n\t\t\t// set the callbacks\n\t\t\troute->CallbackClient.setDisconnectionCallback(cbDisconnection, static_cast<IGatewayTransport*>(this));\n\t\t\troute->CallbackClient.setDefaultCallback(cbDispatchMessage);\n\n\t\t\ttry\n\t\t\t{\n\t\t\t\tnldebug(\"CGatewayL3ClientTransport : Connecting to %s...\", addr.asString().c_str());\n\t\t\t\troute->LastConnectionRetry = CTime::getSecondsSince1970();\n\t\t\t\t// connect to the server\n\t\t\t\troute->CallbackClient.connect(addr);\n\t\t\t\tnldebug(\"CGatewayL3ClientTransport : Connected to %s with connId %u\", addr.asString().c_str(), connId);\n\t\t\t}\n\t\t\tcatch (const ESocketConnectionFailed &)\n\t\t\t{\n\t\t\t\tnlinfo(\"CGatewayL3ClientTransport : Failed to connect to server %s, retrying in %u seconds\", addr.asString().c_str(), _RetryInterval);\n\t\t\t}\n\n\t\t\t// store the route\n\t\t\t_Routes.insert(make_pair(route->CallbackClient.getSockId(), route.get()));\n\t\t\t_RouteIds[connId] = route->CallbackClient.getSockId();\n\n\t\t\t// register it in the dispatcher\n\t\t\t_DispatcherIndex.insert(make_pair(&route->CallbackClient, this));\n\n\t\t\t// release the auto ptr\n\t\t\tCL3ClientRoute *rt = route.release();\n\n\t\t\t// callback the gateway about the new route\n\t\t\tif (rt->CallbackClient.connected())\n\t\t\t\t_Gateway->onRouteAdded(rt);\n\t\t}\n\n\t\t// handle the connection of a new client on the server\n\t\tvoid close ( uint32 connId)\n\t\t{\n\t\t\tH_AUTO(L3C_close);\n\t\t\t// some basic checks on connId\n\t\t\tif (connId >= _RouteIds.size())\n\t\t\t{\n\t\t\t\tnlwarning(\"CGatewayL3ClientTransport : Invalid connectionId %u, max is %u\", connId, _RouteIds.size()-1);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (_RouteIds[connId] == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"CGatewayL3ClientTransport : Invalid connectionId %u, the connection is unused now.\", connId);\n\t\t\t\treturn;\n\t\t\t}\n\n\n\t\t\tdeletePendingRoute();\n\n\t\t\t// retrieve the connection to close\n\t\t\tTClientRoutes::iterator it(_Routes.find(_RouteIds[connId]));\n\t\t\tnlassert(it != _Routes.end());\n\n\t\t\tCL3ClientRoute *route = it->second;\n\n\t\t\tnldebug(\"CGatewayL3ClientTransport : Closing connection %u to %s\", connId, route->ServerAddr.asString().c_str());\n\n\n\t\t\tif (route->CallbackClient.connected())\n\t\t\t{\n\t\t\t\t// callback gateway\n\t\t\t\t_Gateway->onRouteRemoved(route);\n\n\t\t\t\t// close the connection\n\t\t\t\troute->CallbackClient.disconnect();\n\t\t\t}\n\n\t\t\t// cleanup memory, index ...\n\t\t\t_DispatcherIndex.erase(&(route->CallbackClient));\n\t\t\t_Routes.erase(it);\n\t\t\tdelete route;\n\t\t\t_RouteIds[connId] = NULL;\n\t\t\t_FreeRoutesIds.push_back(connId);\n\t\t}\n\n\t\t/***************************************************/\n\t\t/** Event management                              **/\n\t\t/***************************************************/\n\n\t\t// handle the deconnection of a the client from the server\n\t\tvoid onDisconnection ( TSockId from)\n\t\t{\n\t\t\tH_AUTO(L3C_onDisconnection);\n\t\t\t// nothing to do, as route as kept persistent and try to reconnect\n\n\t\t\tTClientRoutes::iterator it(_Routes.find(from));\n\t\t\tnlassert(it != _Routes.end());\n\n\t\t\tnldebug(\"CGatewayL3ClientTransport : Disconnection from %s\", it->second->ServerAddr.asString().c_str());\n\n\n\t\t\t// callback the gateway that this route is no more\n\t\t\t_Gateway->onRouteRemoved(it->second);\n\n\t\t\t// update the last connection try to 'now'\n\t\t\tit->second->LastConnectionRetry = CTime::getSecondsSince1970();\n\n//\t\t\t// delete the route\n//\t\t\tCL3ClientRoute *route = it->second;\n//\n//\t\t\t_RouteToRemove.push_back(route);\n\t\t}\n\n\t\t// Called to dispatch an incoming message to the gateway\n\t\tvoid onDispatchMessage(const CMessage &msgin, TSockId from, CCallbackNetBase &/* netbase */)\n\t\t{\n\t\t\tH_AUTO(L3C_onDispatchMessage);\n\t\t\tTClientRoutes::iterator it(_Routes.find(from));\n\t\t\tnlassert(it != _Routes.end());\n\n\t\t\t// update last comm time\n\t\t\tit->second->LastCommTime = CTime::getSecondsSince1970();\n\n\t\t\tif (msgin.getName() == \"KA\")\n\t\t\t{\n\t\t\t\t// this is just a server prob, ignore it\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_Gateway->onReceiveMessage(it->second, msgin);\n\t\t}\n\n\n\t\t/***************************************************/\n\t\t/** static callback forwarder                     **/\n\t\t/***************************************************/\n\n\t\t// Forwarder to the real method\n\t\tstatic void cbDisconnection ( TSockId from, void *arg )\n\t\t{\n\t\t\tnlassert(arg != NULL);\n\t\t\tCGatewayL3ClientTransport *transport = dynamic_cast<CGatewayL3ClientTransport *>(static_cast<IGatewayTransport*>(arg));\n\t\t\tnlassert(transport != NULL);\n\n\t\t\ttransport->onDisconnection(from);\n\t\t}\n\n\t\t// Forward to the real method, do the dispatching to the correct CGatewayL3ServerTransport instance\n\t\tstatic void cbDispatchMessage (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n\t\t{\n\t\t\t// retrieve the transport instance\n\t\t\tTDispatcherIndex::iterator it(_DispatcherIndex.find(&netbase));\n\t\t\tnlassert(it != _DispatcherIndex.end());\n\n\t\t\t// forward the call\n\t\t\tit->second->onDispatchMessage(msgin, from, netbase);\n\t\t}\n\n\t};\n\n\tCGatewayL3ClientTransport::TDispatcherIndex\tCGatewayL3ClientTransport::_DispatcherIndex;\n\n\t// register this class in the transport factory\n\tNLMISC_REGISTER_OBJECT(IGatewayTransport, CGatewayL3ClientTransport, std::string, string(LAYER3_CLIENT_CLASS_NAME));\n\n\n\tvoid forceGatewayTransportLink()\n\t{\n\t}\n\n} // namespace NLNET\n"
  },
  {
    "path": "code/nel/src/net/module_l5_transport.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/module_message.h\"\n#include \"nel/net/unified_network.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/net_log.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n\n\nnamespace NLNET\n{\n\ttypedef uint8\tTL5TransportId;\n\n\tstruct TTransportDesc\n\t{\n\t\tTL5TransportId\t\tTransportId;\n\t\tstring\t\t\t\tSubNetName;\n\t\tbool\t\t\t\tInResponse;\n\n\t\tvoid serial(NLMISC::IStream &s)\n\t\t{\n\t\t\ts.serial(TransportId);\n\t\t\ts.serial(SubNetName);\n\t\t\ts.serial(InResponse);\n\t\t}\n\t};\n\n\t/** the specialized route for l5 transport */\n\tclass CL5Route : public CGatewayRoute\n\t{\n\tpublic:\n\t\t/// the service ID of the outbound service\n\t\tTServiceId\t\tServiceId;\n\n\t\t/// The transport ID at the outbound\n\t\tTL5TransportId\tForeignTransportId;\n\n\n\t\tCL5Route(IGatewayTransport *transport)\n\t\t\t: CGatewayRoute(transport)\n\t\t{\n\t\t}\n\n\t\tvoid sendMessage(const CMessage &message) const;\n\t};\n\n\t/** Utility class that generate 8bits unique transport id.\n\t *\tThe total L5 transport instance is limited to 256.\n\t *\tThis really should be enough or you have a problem in\n\t *\tyour design !\n\t *\tThe allocator keep released ID as long as possible\n\t *\tand reallocated them only when all other ids\n\t *\thave been used/allocated.\n\t */\n\tclass CTransportIdAllocator\n\t{\n\t\tNLMISC_SAFE_SINGLETON_DECL(CTransportIdAllocator);\n\tprivate:\n\t\tdeque<TL5TransportId>\t_FreeIds;\n\t\tset<TL5TransportId>\t\t_UsedIds;\n\n\t\tCTransportIdAllocator()\n\t\t{\n\t\t\t// fill the list of free ids;\n\t\t\tfor (TL5TransportId i=0; i<TL5TransportId(UINT64_CONSTANT(0xffffffffffffffff)); ++i)\n\t\t\t{\n\t\t\t\t_FreeIds.push_back(i);\n\t\t\t}\n\t\t}\n\n\tpublic:\n\t\tTL5TransportId allocateId()\n\t\t{\n\t\t\tnlassert(!_FreeIds.empty());\n\t\t\tTL5TransportId ret = _FreeIds.front();\n\t\t\t_FreeIds.pop_front();\n\t\t\tnlassert(_UsedIds.find(ret) == _UsedIds.end());\n\t\t\t_UsedIds.insert(ret);\n\t\t\treturn ret;\n\t\t}\n\n\t\tvoid releaseId(TL5TransportId id)\n\t\t{\n\t\t\tnlassert(_UsedIds.find(id) != _UsedIds.end());\n\t\t\t_UsedIds.erase(id);\n\t\t\t_FreeIds.push_back(id);\n\t\t}\n\t};\n\n\tNLMISC_SAFE_SINGLETON_IMPL(CTransportIdAllocator);\n\n#define LAYER5_CLASS_NAME \"L5Transport\"\n\n\t/** Gateway transport using layer 5 */\n\tclass CGatewayL5Transport : public IGatewayTransport\n\t{\n\t\tfriend class CL5Route;\n\tpublic:\n\t\t/// This transport ID\n\t\tTL5TransportId\t_TransportId;\n\n\t\t/// current open status\n\t\tbool\t\t\t_Open;\n\t\t/// Subnet name\n\t\tstring\t\t\t_SubNetName;\n\n\t\ttypedef std::map<TServiceId, CL5Route*>\tTRouteMap;\n\t\t/// The table that keep track of all routes\n\t\tTRouteMap\t_Routes;\n\n\t\ttypedef std::map<TL5TransportId, CGatewayL5Transport*>\tTTransportDispatcher;\n\t\t/// Global index of transport use to dispatch received message\n\t\tstatic TTransportDispatcher\t_TransportDispatcher;\n\n\t\t/// Constructor\n\t\tCGatewayL5Transport(const IGatewayTransport::TCtorParam &param)\n\t\t\t: IGatewayTransport(param),\n\t\t\t_Open(false)\n\t\t{\n\t\t\t// allocate a transport unique ID\n\t\t\t_TransportId = CTransportIdAllocator::getInstance().allocateId();\n\n\t\t\t// store the transport in the dispatcher\n\t\t\t_TransportDispatcher.insert(make_pair(_TransportId, this));\n\n\t\t\t// L5 transport is always peer invisible\n\t\t\tPeerInvisible = true;\n\t\t}\n\n\t\t~CGatewayL5Transport()\n\t\t{\n\t\t\tif (_Open)\n\t\t\t{\n\t\t\t\t// the transport is still open, close it before destruction\n\t\t\t\tclose();\n\t\t\t}\n\n\t\t\t// remove the transport from the dispatcher\n\t\t\tnlassert(_TransportDispatcher.find(_TransportId) != _TransportDispatcher.end());\n\t\t\t_TransportDispatcher.erase(_TransportId);\n\t\t\t// release the unique id\n\t\t\tCTransportIdAllocator::getInstance().releaseId(_TransportId);\n\t\t}\n\n\t\tconst std::string &getClassName() const\n\t\t{\n\t\t\tstatic string className(LAYER5_CLASS_NAME);\n\t\t\treturn className;\n\t\t}\n\n\t\tvirtual void update()\n\t\t{\n\t\t}\n\n\t\tvirtual uint32 getRouteCount() const\n\t\t{\n\t\t\treturn (uint32)_Routes.size();\n\t\t}\n\n\t\tvoid dump(NLMISC::CLog &log) const\n\t\t{\n\t\t\tIModuleManager &mm = IModuleManager::getInstance();\n\t\t\tlog.displayNL(\"  NeL Net layer 5 transport\");\n\t\t\tif (!_Open)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"  The transport is currently closed.\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tlog.displayNL(\"  The transport is open and support %u routes :\",\n\t\t\t\t\t_Routes.size());\n\t\t\t\tTRouteMap::const_iterator first(_Routes.begin()), last(_Routes.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTServiceId\tsid = first->first;\n\t\t\t\t\tCL5Route *route = first->second;\n\t\t\t\t\tlog.displayNL(\"    + route to service %hu('%s'), %u entries in the proxy translation table :\",\n\t\t\t\t\t\tsid.get(),\n\t\t\t\t\t\tCUnifiedNetwork::getInstance()->getServiceName(sid).c_str(),\n\t\t\t\t\t\troute->ForeignToLocalIdx.getAToBMap().size());\n\n\t\t\t\t\t{\n\t\t\t\t\t\tCGatewayRoute::TForeignToLocalIdx::TAToBMap::const_iterator first(route->ForeignToLocalIdx.getAToBMap().begin()), last(route->ForeignToLocalIdx.getAToBMap().end());\n\t\t\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tIModuleProxy *modProx = mm.getModuleProxy(first->second);\n\n\t\t\t\t\t\t\tlog.displayNL(\"      - Proxy '%s' : local proxy id %u => foreign module id %u\",\n\t\t\t\t\t\t\t\tmodProx != NULL ? modProx->getModuleName().c_str() : \"ERROR, invalid module\",\n\t\t\t\t\t\t\t\tfirst->second,\n\t\t\t\t\t\t\t\tfirst->first);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvoid onCommand(const CMessage &/* command */) throw (EInvalidCommand)\n\t\t{\n\t\t\t// nothing done for now\n\t\t\tthrow EInvalidCommand();\n\t\t}\n\t\t/// The gateway send a textual command to the transport\n\t\tbool onCommand(const TParsedCommandLine &command) throw (EInvalidCommand)\n\t\t{\n\t\t\tif (command.SubParams.size() < 1)\n\t\t\t\tthrow  EInvalidCommand();\n\n\t\t\tconst std::string &commandName = command.SubParams[0]->ParamName;\n\t\t\tif (commandName == \"open\")\n\t\t\t{\n\t\t\t\tstring subNetName;\n\n\t\t\t\t/// look for an optional sub network name\n\t\t\t\tconst TParsedCommandLine *netName = command.SubParams[0]->getParam(\"SubNet\");\n\t\t\t\tif (netName != NULL)\n\t\t\t\t{\n\t\t\t\t\tsubNetName = netName->ParamValue;\n\t\t\t\t}\n\n\t\t\t\topen(subNetName);\n\t\t\t}\n\t\t\telse if (commandName == \"close\")\n\t\t\t{\n\t\t\t\tclose();\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn false;\n\n\t\t\treturn true;\n\t\t}\n\n\n\t\t/// Open the server by establishing route with all known services\n\t\tvoid open(const std::string &subNetName) throw (ETransportError)\n\t\t{\n\t\t\tH_AUTO(L5_open);\n\n\t\t\tstatic TUnifiedCallbackItem L5TransportCallback[] =\n\t\t\t{\n\t\t\t\t{\"GW_L5_MSG\",\tCGatewayL5Transport::cbDispatchL5Message\t},\n\t\t\t\t{\"GW_L5_ADDTP\",\tCGatewayL5Transport::cbL5AddTransport\t\t},\n\t\t\t\t{\"GW_L5_REMTP\",\tCGatewayL5Transport::cbL5RemoveTransport\t},\n\t\t\t};\n\n\t\t\tif (_Open == true)\n\t\t\t\tthrow ETransportError(\"Transport already open\");\n\n\t\t\t_SubNetName = subNetName;\n\n\n\t\t\tCUnifiedNetwork *un = CUnifiedNetwork::getInstance();\n\n\t\t\tstatic bool callbackRegistered = false;\n\n\t\t\tif (!callbackRegistered)\n\t\t\t{\n\t\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport open : registering callbacks\");\n\t\t\t\t// set the service con/disconnect callback\n\t\t\t\tun->setServiceUpCallback(\"*\", CGatewayL5Transport::cbOnServiceUp);\n\t\t\t\tun->setServiceDownCallback(\"*\", CGatewayL5Transport::cbOnServiceDown);\n\t\t\t\t// set the message callback\n\t\t\t\tun->addCallbackArray(L5TransportCallback, sizeof(L5TransportCallback) / sizeof(TUnifiedCallbackItem));\n\n\t\t\t\tcallbackRegistered = true;\n\t\t\t}\n\n\n\t\t\t// create route and open route for each existing service\n\t\t\tconst vector<TServiceId>\t&connList = un->getConnectionList();\n\n\t\t\tset<TServiceId>\tuniqueService(connList.begin(), connList.end());\n\n\t\t\twhile (!uniqueService.empty())\n\t\t\t{\n\t\t\t\tTServiceId sid = *(uniqueService.begin());\n\t\t\t\tuniqueService.erase(uniqueService.begin());\n\n\t\t\t\tif ( un->isConnectionConnected(sid))\n\t\t\t\t{\n\t\t\t\t\t// send transport descriptor to other service\n\t\t\t\t\tonServiceUp(un->getServiceName(sid), sid);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// the Connection is not established right now. We wait for the ServiceUp callback\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_Open = true;\n\t\t}\n\n\t\t/// Close the server, this will close all route\n\t\tvoid close()\n\t\t{\n\t\t\tH_AUTO(L5_close);\n\n\t\t\tif (_Open == false)\n\t\t\t\tthrow ETransportError(\"closeServer : The server is not open\");\n\n\t\t\t// close all client connections\n\t\t\twhile (!_Routes.empty())\n\t\t\t{\n\t\t\t\tCL5Route *route = _Routes.begin()->second;\n\t\t\t\tTServiceId sid = route->ServiceId;\n\t\t\t\tonServiceDown(CUnifiedNetwork::getInstance()->getServiceName(sid), sid);\n\t\t\t}\n\n\t\t\t_Open = false;\n\t\t}\n\n\n\t\t/***************************************************/\n\t\t/** Event management                              **/\n\t\t/***************************************************/\n\n\t\tvoid onServiceUp(const std::string &serviceName, TServiceId sid)\n\t\t{\n\t\t\tH_AUTO(L5_onServiceUp);\n\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onServiceUp('%s')\", serviceName.c_str());\n\t\t\t// send the transport descriptor to the new service\n\t\t\tTTransportDesc\tdesc;\n\t\t\tdesc.SubNetName = _SubNetName;\n\t\t\tdesc.TransportId = _TransportId;\n\t\t\tdesc.InResponse = false;\n\n\t\t\tCMessage msg(\"GW_L5_ADDTP\");\n\t\t\tmsg.serial(desc);\n\n\t\t\tCUnifiedNetwork::getInstance()->send(sid, msg);\n\n\t\t\t// the route will be created by receiving this message\n\t\t}\n\n\t\tvoid onServiceDown(const std::string &/* serviceName */, TServiceId sid)\n\t\t{\n\t\t\tH_AUTO(L5_onServicedown);\n\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onServiceDown('%hu')\", sid.get());\n\t\t\t// retrieve the route\n\t\t\tTRouteMap::iterator it(_Routes.find(sid));\n\t\t\tif (it == _Routes.end())\n\t\t\t{\n\t\t\t\tnlinfo(\"Transport L5 : service down, can't find a route for the service\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tCL5Route *route = it->second;\n\n\t\t\t// warn the gateway\n\t\t\t_Gateway->onRouteRemoved(route);\n\n\t\t\t// release the route\n\t\t\t_Routes.erase(it);\n\t\t\tdelete route;\n\t\t}\n\n\t\t// Called to dispatch an incoming message to the gateway\n\t\tvoid onDispatchMessage(const CMessage &msgin, TServiceId sid)\n\t\t{\n\t\t\tH_AUTO(L5_onDispatchMessage);\n\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onDispatchMessage from service %hu\", sid.get());\n\t\t\t/// retrieve the route for dispatching\n\t\t\tTRouteMap::iterator it(_Routes.find(sid));\n\t\t\tif (it == _Routes.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"Gateway '%s' : Can't find route for service %hu for dispatching, message is discarded\",\n\t\t\t\t\t_Gateway->getGatewayName().c_str(),\n\t\t\t\t\tsid.get());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// read the message size\n\t\t\tuint32 msgLen;\n\t\t\tnlRead(msgin, serial, msgLen);\n\n\t\t\t// lock the sub message\n\t\t\tmsgin.lockSubMessage(msgLen);\n\n\t\t\t_Gateway->onReceiveMessage(it->second, msgin);\n\n\t\t\t// unlock the sub message\n\t\t\tmsgin.unlockSubMessage();\n\t\t}\n\n\t\tvoid onAddTransport(TServiceId sid, TTransportDesc &desc)\n\t\t{\n\t\t\tH_AUTO(L5_onAddTransport);\n\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onAddTransport from service %hu\", sid.get());\n\t\t\t// we need to create a route for this transport\n\t\t\t// create a new route and send the route open message\n\n\t\t\tif (_Routes.find(sid) != _Routes.end())\n\t\t\t{\n\t\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onAddTransport a route for this service alredy exist\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCL5Route *route = new CL5Route(this);\n\n\t\t\troute->ServiceId = sid;\n\t\t\troute->ForeignTransportId = desc.TransportId;\n\n\t\t\t// store the route infos\n\t\t\t_Routes.insert(make_pair(sid, route));\n\n\t\t\t// notify the gateway about the new route\n\t\t\t_Gateway->onRouteAdded(route);\n\n\t\t\tif (desc.InResponse == false)\n\t\t\t{\n\t\t\t\t// we need to send back this transport info to this service\n\t\t\t\tTTransportDesc desc;\n\t\t\t\tdesc.InResponse = true;\n\t\t\t\tdesc.SubNetName = _SubNetName;\n\t\t\t\tdesc.TransportId = _TransportId;\n\n\t\t\t\tCMessage msg(\"GW_L5_ADDTP\");\n\t\t\t\tmsg.serial(desc);\n\n\t\t\t\tCUnifiedNetwork::getInstance()->send(sid, msg);\n\t\t\t}\n\t\t}\n\n\t\tvoid onRemoveTransport(TServiceId sid, TTransportDesc &desc)\n\t\t{\n\t\t\tH_AUTO(L5_onRemoveTransport);\n\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport onRemoveTransport from service %hu\", sid.get());\n\t\t\t// Remove the route\n\t\t\tTRouteMap::iterator it(_Routes.find(sid));\n\t\t\tif (it == _Routes.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"onRemoveTransport : can't find a route to the transport %hu on service %u\",\n\t\t\t\t\tdesc.TransportId,\n\t\t\t\t\tsid.get());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCL5Route *route = it->second;\n\n\t\t\t// notify the gateway about the removed route\n\t\t\t_Gateway->onRouteRemoved(route);\n\n\t\t\t// erase the route info and delete the route\n\t\t\t_Routes.erase(it);\n\t\t\tdelete route;\n\t\t}\n\n\t\t/***************************************************/\n\t\t/** static callback forwarder                     **/\n\t\t/***************************************************/\n\t\t/// callback from layer 5\n\n\t\tstatic void cbL5AddTransport(CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)\n\t\t{\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport cbL5AddTransport from service %hu\", sid.get());\n\t\t\t// Receive a transport descriptor from another service, create\n\t\t\t// a route for it\n\n\t\t\tTTransportDesc\tdesc;\n\n\t\t\tmsgin.serial(desc);\n\n\t\t\t// for each existing transport here, check if they are in the\n\t\t\t// same sub net, if so, callback them for route creation\n\n\t\t\tTTransportDispatcher::iterator first(_TransportDispatcher.begin()), last(_TransportDispatcher.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayL5Transport *transport = first->second;\n\t\t\t\tif (transport->_Open\n\t\t\t\t\t&& transport->_SubNetName == desc.SubNetName\n\t\t\t\t\t&& (sid != IService::getInstance()->getServiceId()\n\t\t\t\t\t\t|| desc.TransportId != transport->_TransportId))\n\t\t\t\t{\n\t\t\t\t\t// this one is on the same subnet\n\t\t\t\t\ttransport->onAddTransport(sid, desc);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstatic void cbL5RemoveTransport(CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)\n\t\t{\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport cbL5RemoveTransport from service %hu\", sid.get());\n\t\t\t// Receive a transport descriptor from another service, delete\n\t\t\t// the route for it\n\n\t\t\tTTransportDesc\tdesc;\n\n\t\t\tmsgin.serial(desc);\n\n\t\t\t// for each existing transport here, check if they are in the\n\t\t\t// same sub net, if so, callback them for route creation\n\n\t\t\tTTransportDispatcher::iterator first(_TransportDispatcher.begin()), last(_TransportDispatcher.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayL5Transport *transport = first->second;\n\t\t\t\tif (transport->_Open\n\t\t\t\t\t&& transport->_SubNetName == desc.SubNetName\n\t\t\t\t\t&& desc.TransportId != transport->_TransportId)\n\t\t\t\t{\n\t\t\t\t\t// this one is on the same subnet\n\t\t\t\t\ttransport->onRemoveTransport(sid, desc);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstatic void cbDispatchL5Message (CMessage &msgin, const std::string &serviceName, TServiceId sid)\n\t\t{\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport cbDispatch called, receiving from %s\", serviceName.c_str());\n\t\t\t// dispatch the message to the route associated with the service\n\t\t\t// the first info in the message is the transport id\n\t\t\tTL5TransportId transportId;\n\t\t\tmsgin.serial(transportId);\n\n\t\t\t// look for a corresponding transport\n\t\t\tTTransportDispatcher::iterator it(_TransportDispatcher.find(transportId));\n\t\t\tif (it == _TransportDispatcher.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"ReceiveL5Message, can't find transport id %u for dispatching, message is discarded\",\n\t\t\t\t\ttransportId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tCGatewayL5Transport *transport = it->second;\n\t\t\ttransport->onDispatchMessage(msgin, sid);\n\t\t}\n\n\t\tstatic  void cbOnServiceUp (const std::string &serviceName, TServiceId sid, void * /* arg */)\n\t\t{\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport cbOnServiceUp called, service up for %s\", serviceName.c_str());\n\t\t\t// callback all open transport about the new service\n\t\t\tTTransportDispatcher::iterator first(_TransportDispatcher.begin()), last(_TransportDispatcher.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayL5Transport *transport = first->second;\n\n\t\t\t\tif (transport->_Open)\n\t\t\t\t\ttransport->onServiceUp(serviceName, sid);\n\t\t\t}\n\t\t}\n\n\t\tstatic  void cbOnServiceDown (const std::string &serviceName, TServiceId sid, void * /* arg */)\n\t\t{\n\t\t\tLNETL6_DEBUG(\"LNETL6: L5 transport cbOnServicedown called, service down for %s\", serviceName.c_str());\n\t\t\t// callback all open transport about the removed service\n\t\t\tTTransportDispatcher::iterator first(_TransportDispatcher.begin()), last(_TransportDispatcher.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tCGatewayL5Transport *transport = first->second;\n\n\t\t\t\tif (transport->_Open)\n\t\t\t\t\ttransport->onServiceDown(serviceName, sid);\n\t\t\t}\n\t\t}\n\n\t};\n\n\tCGatewayL5Transport::TTransportDispatcher\tCGatewayL5Transport::_TransportDispatcher;\n\n\t// register this class in the transport factory\n\tNLMISC_REGISTER_OBJECT(IGatewayTransport, CGatewayL5Transport, std::string, string(LAYER5_CLASS_NAME));\n\n\tvoid CL5Route::sendMessage(const CMessage &message) const\n\t{\n\t\tNLNET_AUTO_DELTE_ASSERT;\n\t\tH_AUTO(L5Route_sendMessage);\n\n\t\tCGatewayL5Transport *trpt = static_cast<CGatewayL5Transport*>(_Transport);\n\n\t\t// create a transport message\n\t\tCMessage wrapper(\"GW_L5_MSG\");\n\t\t// serial the transport identifier\n\t\twrapper.serial(trpt->_TransportId);;\n\n\t\t// insert the message in the wrapper\n\t\tnlWrite(wrapper, serialMessage, message);\n\t\t// send the message\n\t\tCUnifiedNetwork::getInstance()->send(ServiceId, wrapper);\n\t}\n\n\n\n\tvoid forceGatewayL5TransportLink()\n\t{\n\t}\n\n} // namespace NLNET\n"
  },
  {
    "path": "code/nel/src/net/module_local_gateway.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/module_message.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\n\n\nnamespace NLNET\n{\n\n\n\t/** A simple gateway that interconnect module locally\n\t *\tFor testing purpose and simple case.\n\t */\n\tclass CLocalGateway :\n\t\tpublic CModuleBase,\n\t\tpublic CModuleGateway,\n\t\tpublic CModuleSocket\n\t{\n\t\t// the proxy that represent this gateway\n//\t\tTModuleGatewayProxyPtr\t\t_ThisProxy;\n\n\t\ttypedef CTwinMap<TModuleProxyPtr, TStringId>\tTModuleProxies;\n\t\t// The modules proxies\n\t\tTModuleProxies\t\t_ModuleProxies;\n\n\n\tpublic:\n\n\t\tCLocalGateway()\n\t\t{\n\n\t\t}\n\n\t\t~CLocalGateway()\n\t\t{\n\t\t\t// we need to unplug any plugged module\n\t\t\twhile (!_PluggedModules.getAToBMap().empty())\n\t\t\t{\n\t\t\t\t_PluggedModules.getAToBMap().begin()->second->unplugModule(this);\n\t\t\t}\n\n\t\t\t// must be done before the other destructors are called\n\t\t\tunregisterSocket();\n\t\t\tunregisterGateway();\n\t\t}\n\n\t\t/***********************************************************\n\t\t ** Gateway methods\n\t\t ***********************************************************/\n\t\tvirtual const std::string &getGatewayName() const\n\t\t{\n\t\t\treturn getModuleName();\n\t\t}\n\t\tvirtual const std::string &getFullyQualifiedGatewayName() const\n\t\t{\n\t\t\treturn getModuleFullyQualifiedName();\n\t\t}\n\t\t/// Return the gateway proxy of this gateway\n//\t\tvirtual TModuleGatewayProxyPtr &getGatewayProxy()\n//\t\t{\n//\t\t\tnlassert(!_ThisProxy.isNull());\n//\t\t\treturn _ThisProxy;\n//\t\t}\n\n\t\t/// Create and bind to this gateway a new transport\n\t\tvirtual void createTransport(const std::string &/* transportClass */, const std::string &/* instanceName */)\n\t\t{\n\t\t}\n\t\t/// Delete a transport (this will close any open route)\n\t\tvirtual void deleteTransport(const std::string &/* instanceName */)\n\t\t{\n\t\t}\n\n\t\t/// Activate/stop peer invisible mode on a transport\n\t\tvirtual void\tsetTransportPeerInvisible(const std::string &/* transportInstanceName */, bool /* peerInvisible */)\n\t\t{\n\t\t\t// unsupported\n\t\t\tnlstop;\n\t\t}\n\n\t\t/// Activate/stop firewalling mode on a transport\n\t\tvirtual void\tsetTransportFirewallMode(const std::string &/* transportInstanceName */, bool /* firewalled */)\n\t\t\tthrow (EGatewayFirewallBreak)\n\t\t{\n\t\t\t// unsupported\n\t\t\tnlstop;\n\t\t}\n\n\t\t/// Send a command to a transport\n\t\tvirtual void transportCommand(const TParsedCommandLine &/* commandLine */)\n\t\t{\n\t\t}\n\t\tvirtual IGatewayTransport *getGatewayTransport(const std::string &/* transportName */) const\n\t\t{\n\t\t\t// there are no transport here\n\t\t\treturn NULL;\n\t\t}\n\n\t\tvirtual uint32\tgetTransportCount() const\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tvirtual uint32\tgetRouteCount() const\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tvirtual uint32 getReceivedPingCount() const\n\t\t{\n\t\t\treturn 0;\n\t\t}\n\n\t\tvirtual void onRouteAdded(CGatewayRoute * /* route */)\n\t\t{\n\t\t}\n\n\t\t/// A route is removed by a transport\n\t\tvirtual void onRouteRemoved(CGatewayRoute * /* route */)\n\t\t{\n\t\t}\n\n\t\t/// A transport have received a message\n\t\tvirtual void onReceiveMessage(CGatewayRoute * /* from */, const CMessage &/* msgin */)\n\t\t{\n\t\t}\n\n\t\tvirtual void createSecurityPlugin(const std::string &/* className */)\n\t\t{\n\t\t}\n\t\tvirtual void sendSecurityCommand(const TParsedCommandLine &/* command */)\n\t\t{\n\t\t}\n\t\tvirtual void removeSecurityPlugin()\n\t\t{\n\t\t}\n\n\n//\t\tvirtual  bool isGatewayServerOpen()\n//\t\t{\n//\t\t\treturn false;\n//\t\t}\n//\n//\t\tvirtual CInetAddress getGatewayServerAddress()\n//\t\t{\n//\t\t\tCInetAddress invalid;\n//\n//\t\t\treturn invalid;\n//\t\t}\n//\t\tvirtual void getGatewayClientList(std::vector<TModuleGatewayProxyPtr> gatewayList)\n//\t\t{\n//\t\t\treturn;\n//\t\t}\n//\t\tvirtual void openGatewayServer(uint16 listeningPort)\n//\t\t\tthrow (EGatewayAlreadyOpen, EGatewayPortInUse)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void closeGatewayServer()\n//\t\t\tthrow (EGatewayNotOpen)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void shutdownGatewayServer()\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void onGatewayServerOpen()\n//\t\t{\n//\t\t}\n//\t\tvirtual void onGatewayServerClose()\n//\t\t{\n//\t\t}\n//\t\tvirtual TModuleGatewayConstant onClientGatewayConnect(TModuleGatewayProxyPtr &clientGateway)\n//\t\t{\n//\t\t\treturn mgc_reject_connection;\n//\t\t}\n//\t\tvirtual void onClientGatewayDisconnect(TModuleGatewayProxyPtr &clientGateway)\n//\t\t{\n//\t\t}\n//\t\tvirtual void getGatewayServerList(std::vector<TModuleGatewayProxyPtr> serverList)\n//\t\t{\n//\t\t\treturn;\n//\t\t}\n//\t\tvirtual bool isGatewayConnected()\n//\t\t{\n//\t\t\treturn false;\n//\t\t}\n//\t\tvirtual void connectGateway(CInetAddress serverAddress)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void disconnectGateway(TModuleGatewayProxyPtr &serverGateway)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void onGatewayConnection(const TModuleGatewayProxyPtr &serverGateway, TModuleGatewayConstant connectionResult)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n//\t\tvirtual void onGatewayDisconnection(const TModuleGatewayProxyPtr &serverGateway)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n\t\tvirtual void onAddModuleProxy(IModuleProxy *addedModule)\n\t\t{\n\t\t\t// always disclose module to local modules\n\t\t\tdiscloseModule(addedModule);\n\t\t}\n\t\tvirtual void onRemoveModuleProxy(IModuleProxy * /* removedModule */)\n\t\t{\n\t\t}\n\t\tvirtual void discloseModule(IModuleProxy *moduleProxy)\n\t\t\tthrow (EGatewayNotConnected)\n\t\t{\n\t\t\t// check that the module is plugged here\n\t\t\tnlassert(_ModuleProxies.getB(moduleProxy) != NULL);\n\n//\t\t\tCModuleProxy *modProx = dynamic_cast<CModuleProxy *>(moduleProxy);\n//\t\t\tnlassert(modProx != NULL);\n\t\t\tnlassert(moduleProxy->getModuleGateway() == this);\n\n\t\t\t// warn any plugged module\n\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModule *module = first->second;\n\t\t\t\tif (module->getModuleId() != moduleProxy->getForeignModuleId())\n\t\t\t\t{\n\t\t\t\t\tmodule->_onModuleUp(moduleProxy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvirtual IModuleProxy *getPluggedModuleProxy(IModule * /* pluggedModule */)\n\t\t{\n\t\t\treturn NULL;\n\t\t}\n\n\t\tvirtual uint32\tgetProxyCount() const\n\t\t{\n\t\t\treturn (uint32)_ModuleProxies.getAToBMap().size();\n\t\t}\n\n\t\t/// Fill a vector with the list of proxies managed here. The module are filled in ascending proxy id order.\n\t\tvirtual void\tgetModuleProxyList(std::vector<IModuleProxy*> &resultList) const\n\t\t{\n\t\t\tmap<TModuleId, IModuleProxy*> index;\n\t\t\t{\n\t\t\t\tTModuleProxies::TAToBMap::const_iterator first(_ModuleProxies.getAToBMap().begin()), last(_ModuleProxies.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tindex.insert(make_pair(first->first->getModuleProxyId(), first->first));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// now build the vector\n\t\t\tmap<TModuleId, IModuleProxy*>::iterator first(index.begin()), last(index.end());\n\t\t\tfor( ; first != last; ++first)\n\t\t\t{\n\t\t\t\tresultList.push_back(first->second);\n\t\t\t}\n\t\t}\n\n\n//\t\tvirtual void onReceiveModuleMessage(TModuleGatewayProxyPtr &senderGateway, TModuleMessagePtr &message)\n//\t\t{\n//\t\t}\n\t\tvirtual void sendModuleMessage(IModuleProxy * /* senderProxy */, IModuleProxy * /* addresseeProxy */, const CMessage &/* message */)\n\t\t{\n\t\t}\n\t\tvirtual void dispatchModuleMessage(IModuleProxy * /* senderProxy */, IModuleProxy * /* addresseeProxy */, const CMessage &/* message */)\n\t\t{\n\t\t\tnlstop;\n//\t\t\tTModuleId sourceId = message->getSenderModuleProxyId();\n//\t\t\tTModuleProxies::TAToBMap::const_iterator firstSource(_ModuleProxies.getAToBMap().begin()), lastSource(_ModuleProxies.getAToBMap().end());\n//\t\t\tfor (; firstSource != lastSource && firstSource->first->getForeignModuleId() != sourceId; ++firstSource) {}\n//\t\t\tnlassert(  firstSource != lastSource );\n//\n//\t\t\tTPluggedModules::iterator first(_PluggedModules.begin()), last(_PluggedModules.end());\n//\t\t\tTModuleId destId = message->getAddresseeModuleProxyId();\n//\t\t\tfor (; first != last && (*first)->getModuleId() != destId; ++first) {}\n//\t\t\tif (first != last)\n//\t\t\t{\n//\t\t\t\t(*first)->onProcessModuleMessage(firstSource->first, message);\n//\t\t\t}\n\t\t}\n\t\t/***********************************************************\n\t\t ** Module methods\n\t\t ***********************************************************/\n\t\tbool\tinitModule(const TParsedCommandLine &initInfo)\n\t\t{\n\t\t\tbool ret = CModuleBase::initModule(initInfo);\n\n\t\t\t// in fact, this gateway is so simple, that it have no option !\n\n\t\t\tregisterSocket();\n\t\t\tregisterGateway();\n\n\t\t\treturn ret;\n\t\t}\n\n\t\tstd::string\t\t\tbuildModuleManifest() const\n\t\t{\n\t\t\treturn string();\n\t\t}\n\n\t\tvoid\t\t\t\tonServiceUp(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonServiceDown(const std::string &/* serviceName */, NLNET::TServiceId /* serviceId */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleUpdate()\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonApplicationExit()\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleUp(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleDown(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\t\tbool\t\t\t\tonProcessModuleMessage(IModuleProxy * /* senderModuleProxy */, const CMessage &/* message */)\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\tvoid\t\t\t\tonModuleSecurityChange(IModuleProxy * /* moduleProxy */)\n\t\t{\n\t\t}\n\t\tvoid\t\t\t\tonModuleSocketEvent(IModuleSocket * /* moduleSocket */, TModuleSocketEvent /* eventType */)\n\t\t{\n\t\t}\n\n\t\t/***********************************************************\n\t\t ** Socket methods\n\t\t ***********************************************************/\n\n\t\tconst std::string &getSocketName()\n\t\t{\n\t\t\treturn getModuleName();\n\t\t}\n\n\t\tvoid _sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotReachable, EModuleNotPluggedHere)\n\t\t{\n\t\t\tTModuleProxies::TAToBMap::const_iterator first(_ModuleProxies.getAToBMap().begin()), last(_ModuleProxies.getAToBMap().end());\n\t\t\tfor (; first != last && first->first->getModuleProxyId() != destModuleProxyId; ++first) {}\n\t\t\tif (first != last) {  first->first->sendModuleMessage(senderModule, message); return;}\n\t\t\tthrow EModuleNotReachable();\n\t\t}\n\t\tvirtual void _broadcastModuleMessage(IModule * /* senderModule */, const NLNET::CMessage &/* message */)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\n\t\tvoid onModulePlugged(IModule *pluggedModule)\n\t\t{\n\t\t\t// A module has just been plugged here, we need to disclose it to the\n\t\t\t// other module, and disclose other module to it.\n\n\t\t\t// create a proxy for this module\n\t\t\tIModuleProxy *modProx = IModuleManager::getInstance().createModuleProxy(\n\t\t\t\t\tthis,\n\t\t\t\t\tNULL,\t// the module is local, so there is no route\n\t\t\t\t\t0,\t\t// the module is local, distance is 0\n\t\t\t\t\tpluggedModule,\t// the module is local, so store the module pointer\n\t\t\t\t\tpluggedModule->getModuleClassName(),\n\t\t\t\t\tgetGatewayName()+\"/\"+pluggedModule->getModuleFullyQualifiedName(),\n\t\t\t\t\tpluggedModule->getModuleManifest(),\n//\t\t\t\t\t_ThisProxy,\n\t\t\t\t\tpluggedModule->getModuleId());\n\n\t\t\t// and store it\n\t\t\t_ModuleProxies.add(modProx, CStringMapper::map(modProx->getModuleName()));\n\n\t\t\t// disclose the new module to other modules\n\t\t\tdiscloseModule(modProx);\n\n\t\t\t// second, disclose already plugged proxy to the new one\n\t\t\t{\n\t\t\t\tTModuleProxies::TAToBMap::const_iterator first(_ModuleProxies.getAToBMap().begin()), last(_ModuleProxies.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tif (first->first->getModuleName() != pluggedModule->getModuleFullyQualifiedName())\n\t\t\t\t\t\tpluggedModule->_onModuleUp(first->first);\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t}\n\t\t/// Called just after a module as been effectively unplugged from a socket\n\t\tvoid\t\t\t\tonModuleUnplugged(IModule *unpluggedModule)\n\t\t{\n\t\t\t// remove the proxy info\n\t\t\tTModuleProxies::TBToAMap::const_iterator it(_ModuleProxies.getBToAMap().find(CStringMapper::map(getGatewayName()+\"/\"+unpluggedModule->getModuleFullyQualifiedName())));\n\t\t\tnlassert(it != _ModuleProxies.getBToAMap().end());\n\n\t\t\tIModuleProxy *modProx = it->second;\n\t\t\t// warn all connected module that a module become unavailable\n\t\t\t{\n\t\t\t\tTPluggedModules::TAToBMap::const_iterator first(_PluggedModules.getAToBMap().begin()), last(_PluggedModules.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModule *module = first->second;\n\t\t\t\t\tif (module->getModuleFullyQualifiedName() != modProx->getModuleName())\n\t\t\t\t\t\tmodule->_onModuleDown(it->second);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// warn the unplugged module that all plugged modules are become unavailable\n\t\t\t{\n\t\t\t\tTModuleProxies::TAToBMap::const_iterator first(_ModuleProxies.getAToBMap().begin()), last(_ModuleProxies.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tif (first->first->getModuleName() != unpluggedModule->getModuleFullyQualifiedName())\n\t\t\t\t\t\tunpluggedModule->_onModuleDown(first->first);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tTModuleId localProxyId = modProx->getModuleProxyId();\n\t\t\t// remove reference to the proxy\n\t\t\t_ModuleProxies.removeWithA(modProx);\n\n\t\t\t// release the module proxy\n\t\t\tIModuleManager::getInstance().releaseModuleProxy(localProxyId);\n\n\t\t}\n\n\t\tvoid getModuleList(std::vector<IModuleProxy*> &resultList)\n\t\t{\n\t\t\tTModuleProxies::TAToBMap::const_iterator first(_ModuleProxies.getAToBMap().begin()), last(_ModuleProxies.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tresultList.push_back(first->first);\n\t\t\t}\n\t\t}\n\n\t};\n\n\n\t// register the module factory\n\tNLNET_REGISTER_MODULE_FACTORY(CLocalGateway, \"LocalGateway\");\n\n\tvoid forceLocalGatewayLink()\n\t{\n\t}\n\n} // namespace NLNET\n\n"
  },
  {
    "path": "code/nel/src/net/module_manager.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n#include \"nel/misc/app_context.h\"\n#include \"nel/misc/dynloadlib.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/twin_map.h\"\n#include \"nel/misc/sstring.h\"\n#include \"nel/misc/smart_ptr_inline.h\"\n\n#include \"nel/net/module_common.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/net_log.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n// for init of the module manager (if not already done by the application)\nNLMISC_CATEGORISED_COMMAND(net, initModuleManager, \"force the initialisation of the module manager\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\t// not really hard in fact :)\n\tNLNET::IModuleManager::getInstance();\n\n\tlog.displayNL(\"Module manager is now initialised.\");\n\n\treturn true;\n}\n\n\nnamespace NLNET\n{\n\t/// Implementation class for module manager\n\tclass CModuleManager : public IModuleManager, public ICommandsHandler\n\t{\n\t\tNLMISC_SAFE_SINGLETON_DECL(CModuleManager);\n\n\tpublic:\n\n\t\tstatic void releaseInstance()\n\t\t{\n\t\t\tif (_Instance)\n\t\t\t{\n\t\t\t\tNLMISC::INelContext::getInstance().releaseSingletonPointer(\"CModuleManager\", _Instance);\n\t\t\t\tdelete _Instance;\n\t\t\t\t_Instance = NULL;\n\t\t\t}\n\t\t}\n\n\t\tstruct TModuleLibraryInfo : public CRefCount\n\t\t{\n\t\t\t/// The file name of the library with access path\n\t\t\tstd::string\t\t\t\t\tFullPathLibraryName;\n\t\t\t/// The short name of the library, i.e not path, no decoration (.dll or  .so and NeL compilation mode tag)\n\t\t\tstd::string\t\t\t\t\tShortLibraryName;\n\t\t\t/// The list of module factory name that are in use in the library.\n\t\t\tstd::vector<std::string>\tModuleFactoryList;\n\t\t\t/// The library handler\n\t\t\tCLibrary\t\t\t\t\tLibraryHandler;\n\t\t\t/// the NeL Module library interface pointer.\n\t\t\tCNelModuleLibrary\t\t\t*ModuleLibrary;\n\t\t};\n\n\t\t/** the user set unique name root, replace the normal unique name\n\t\t *\tgeneration system if not empty\n\t\t */\n\t\tstring _UniqueNameRoot;\n\n\t\ttypedef\tmap<std::string, CSmartPtr<TModuleLibraryInfo> >\tTModuleLibraryInfos;\n\t\t/// Module library registry\n\t\tTModuleLibraryInfos\t\t_ModuleLibraryRegistry;\n\n\t\ttypedef std::map<std::string, IModuleFactory*>\t\tTModuleFactoryRegistry;\n\t\t/// Module factory registry\n\t\tTModuleFactoryRegistry\t_ModuleFactoryRegistry;\n\n\t\ttypedef NLMISC::CTwinMap<std::string, TModulePtr>\tTModuleInstances;\n\t\t/// Modules instances tracker\n\t\tTModuleInstances\t\t_ModuleInstances;\n\n\t\ttypedef NLMISC::CTwinMap<TModuleId, TModulePtr>\t\tTModuleIds;\n\t\t/// Modules IDs tracker\n\t\tTModuleIds\t\t\t\t_ModuleIds;\n\n\t\t/// Local module ID generator\n\t\tTModuleId\t\t\t\t_LastGeneratedId;\n\n\t\ttypedef NLMISC::CTwinMap<TModuleId, TModuleProxyPtr>\tTModuleProxyIds;\n\t\t/// Modules proxy IDs tracker\n\t\tTModuleProxyIds\t\t\t_ModuleProxyIds;\n\n\t\ttypedef map<string, IModuleSocket *>\tTModuleSockets;\n\t\t/// Module socket registry\n\t\tTModuleSockets\t\t\t_ModuleSocketsRegistry;\n\n\t\ttypedef std::map<std::string, IModuleGateway*>\t\tTModuleGateways;\n\t\t/// Module factory registry\n\t\tTModuleGateways\t\t\t_ModuleGatewaysRegistry;\n\n\t\t///////////////////////////////////////////////////////////////////\n\t\t// Methods\n\t\t///////////////////////////////////////////////////////////////////\n\n\t\tstatic bool\t\tisInitialized()\n\t\t{\n\t\t\treturn _Instance != NULL;\n\t\t}\n\n\t\tconst std::string &getCommandHandlerName() const\n\t\t{\n\t\t\tstatic string moduleManagerName(\"moduleManager\");\n\t\t\treturn moduleManagerName;\n\t\t}\n\n\n\t\tCModuleManager() :\n\t\t\tIModuleManager(),\n\t\t\tICommandsHandler(),\n\t\t\t_LastGeneratedId(0)\n\t\t{\n\t\t\tregisterCommandsHandler();\n\n\t\t\t// register local module factory\n\t\t\tTLocalModuleFactoryRegistry &lmfr = TLocalModuleFactoryRegistry::instance();\n\t\t\taddModuleFactoryRegistry(lmfr);\n\t\t}\n\n\t\t~CModuleManager()\n\t\t{\n\t\t\t// unload any loaded module library\n\t\t\twhile (!_ModuleLibraryRegistry.empty())\n\t\t\t{\n\t\t\t\tTModuleLibraryInfo *mli = _ModuleLibraryRegistry.begin()->second;\n\t\t\t\tunloadModuleLibrary(mli->ShortLibraryName);\n\t\t\t}\n\n\t\t\t// delete any lasting modules\n\t\t\twhile (!_ModuleInstances.getAToBMap().empty())\n\t\t\t{\n\t\t\t\tdeleteModule(_ModuleInstances.getAToBMap().begin()->second);\n\t\t\t}\n\n\t\t\t// there should not be proxies or gateway lasting\n//\t\t\tnlassert(_ModuleProxyInstances.getAToBMap().empty());\n\n\t\t\t_Instance = NULL;\n\t\t}\n\n\t\tvirtual void applicationExit()\n\t\t{\n\t\t\tTModuleInstances::TAToBMap::const_iterator first(_ModuleInstances.getAToBMap().begin()), last(_ModuleInstances.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIModule *module = first->second;\n\n\t\t\t\tmodule->onApplicationExit();\n\t\t\t}\n\t\t}\n\n\t\tvirtual void setUniqueNameRoot(const std::string &uniqueNameRoot)\n\t\t{\n\t\t\t_UniqueNameRoot = uniqueNameRoot;\n\t\t}\n\n\t\tvirtual const std::string &getUniqueNameRoot()\n\t\t{\n\t\t\tif (_UniqueNameRoot.empty())\n\t\t\t{\n\t\t\t\tstring hostName;\n\t\t\t\tif (IService::isServiceInitialized())\n\t\t\t\t\thostName = IService::getInstance()->getHostName();\n\t\t\t\telse\n\t\t\t\t\thostName = ::NLNET::CInetAddress::localHost().hostName();\n\t\t\t\tint pid = ::getpid();\n\n\t\t\t\t_UniqueNameRoot = hostName+\":\"+toString(pid);\n\t\t\t}\n\n\t\t\treturn _UniqueNameRoot;\n\t\t}\n\n\n\t\tvoid addModuleFactoryRegistry(TLocalModuleFactoryRegistry &moduleFactoryRegistry)\n\t\t{\n\t\t\tvector<string> moduleList;\n\t\t\tmoduleFactoryRegistry.fillFactoryList(moduleList);\n\t\t\t// fill the module factory registry\n\t\t\tvector<string>::iterator first(moduleList.begin()), last(moduleList.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tconst std::string &className = *first;\n\t\t\t\tIModuleFactory *factory = moduleFactoryRegistry.getFactory(className);\n\t\t\t\tif (_ModuleFactoryRegistry.find(*first) != _ModuleFactoryRegistry.end())\n\t\t\t\t{\n\t\t\t\t\t// a module class of that name already exist\n\t\t\t\t\tnlinfo(\"CModuleManger : add module factory : module class '%s' is already registered; ignoring new factory @%p\",\n\t\t\t\t\t\tclassName.c_str(),\n\t\t\t\t\t\tfactory);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// store the factory\n\t\t\t\t\tnlinfo(\"Adding module '%s' factory\", className.c_str());\n\t\t\t\t\t_ModuleFactoryRegistry.insert(make_pair(className, factory));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvirtual bool loadModuleLibrary(const std::string &libraryName)\n\t\t{\n\t\t\t// build the short name\n\t\t\tstring path = CFile::getPath(libraryName);\n\t\t\tstring shortName = CLibrary::cleanLibName(libraryName);\n\n\t\t\tif (_ModuleLibraryRegistry.find(shortName) != _ModuleLibraryRegistry.end())\n\t\t\t{\n\t\t\t\t// this lib is already loaded !\n\t\t\t\tnlwarning(\"CModuleManager : trying to load library '%s' in '%s'\\n\"\n\t\t\t\t\t\"but it is already loaded as '%s', ignoring.\",\n\t\t\t\t\tshortName.c_str(),\n\t\t\t\t\tlibraryName.c_str(),\n\t\t\t\t\t_ModuleLibraryRegistry[shortName]->FullPathLibraryName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// now, load the library\n\t\t\tstring fullName = NLMISC::CPath::standardizePath(path)+CLibrary::makeLibName(shortName);\n\t\t\tstd::auto_ptr<TModuleLibraryInfo>\tmli = auto_ptr<TModuleLibraryInfo>(new TModuleLibraryInfo);\n\t\t\tif (!mli->LibraryHandler.loadLibrary(fullName, false, true, true))\n\t\t\t{\n\t\t\t\tnlwarning(\"CModuleManager : failed to load the library '%s' in '%s'\",\n\t\t\t\t\tshortName.c_str(),\n\t\t\t\t\tfullName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// the lib is loaded, check that it is a 'pure' nel library\n\t\t\tif (!mli->LibraryHandler.isLibraryPure())\n\t\t\t{\n\t\t\t\tnlwarning(\"CModuleManager : the library '%s' is not a pure Nel library\",\n\t\t\t\t\tshortName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// Check that the lib is a pure module library\n\t\t\tCNelModuleLibrary *modLib = dynamic_cast<CNelModuleLibrary *>(mli->LibraryHandler.getNelLibraryInterface());\n\t\t\tif (modLib == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"CModuleManager : the library '%s' is not a pure Nel Module library\",\n\t\t\t\t\tshortName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// ok, all is fine ! we can store the loaded library info\n\n\t\t\tmli->FullPathLibraryName = fullName;\n\t\t\tTLocalModuleFactoryRegistry &lmfr = modLib->getLocalModuleFactoryRegistry();\n\t\t\tlmfr.fillFactoryList(mli->ModuleFactoryList);\n\t\t\tmli->ModuleLibrary = modLib;\n\t\t\tmli->ShortLibraryName = shortName;\n\n\t\t\tpair<TModuleLibraryInfos::iterator, bool> ret = _ModuleLibraryRegistry.insert(make_pair(shortName, mli.release()));\n\t\t\tif (!ret.second)\n\t\t\t{\n\t\t\t\tnlwarning(\"CModuleManager : failed to store module library information !\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// fill the module factory registry\n\t\t\taddModuleFactoryRegistry(lmfr);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tvirtual bool unloadModuleLibrary(const std::string &libraryName)\n\t\t{\n\t\t\tstring shorName = CLibrary::cleanLibName(libraryName);\n\t\t\tTModuleLibraryInfos::iterator it(_ModuleLibraryRegistry.find(shorName));\n\t\t\tif (it == _ModuleLibraryRegistry.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"CModuleManager : failed to unload library '%s' : unknown or not loaded library\", shorName.c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// by erasing this entry, we delete the CLibrary object that hold the library\n\t\t\t// module, thus destroying any factory the belong into and deleting the\n\t\t\t// instantiated module !\n\t\t\t// Wow, that's pretty much for a single line ;)\n\t\t\t_ModuleLibraryRegistry.erase(it);\n\n\t\t\treturn true;\n\t\t}\n\n\t\t/** Register a module factory in the manager\n\t\t */\n//\t\tvirtual void registerModuleFactory(class IModuleFactory *moduleFactory)\n//\t\t{\n//\t\t\tnlstop;\n//\t\t}\n\t\t/** Unregister a module factory\n\t\t*/\n\t\tvirtual void unregisterModuleFactory(class IModuleFactory *moduleFactory)\n\t\t{\n\t\t\t// we need to remove the factory from the registry\n\t\t\tTModuleFactoryRegistry::iterator it(_ModuleFactoryRegistry.find(moduleFactory->getModuleClassName()));\n\n\t\t\tif (it == _ModuleFactoryRegistry.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"The module factory for class '%s' in not registered.\", moduleFactory->getModuleClassName().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (it->second != moduleFactory)\n\t\t\t{\n\t\t\t\tnlinfo(\"The module factory @%p for class '%s' is not the registered one, ignoring.\",\n\t\t\t\t\tmoduleFactory,\n\t\t\t\t\tmoduleFactory->getModuleClassName().c_str());\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tnlinfo(\"ModuleManager : unregistering factory for module class '%s'\", moduleFactory->getModuleClassName().c_str());\n\n\t\t\t// remove the factory\n\t\t\t_ModuleFactoryRegistry.erase(it);\n\t\t}\n\n\n\t\t/** Fill the vector with the list of available module.\n\t\t *\tNote that the vector is not cleared before being filled.\n\t\t */\n\t\tvirtual void getAvailableModuleClassList(std::vector<std::string> &moduleClassList)\n\t\t{\n\t\t\tTModuleFactoryRegistry::iterator first(_ModuleFactoryRegistry.begin()), last(_ModuleFactoryRegistry.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tmoduleClassList.push_back(first->first);\n\t\t\t}\n\t\t}\n\n\t\t/** Create a new module instance.\n\t\t *\tThe method create a module of the specified class with the\n\t\t *\tspecified local name.\n\t\t *\tThe class MUST be available in the factory and the\n\t\t *\tname MUST be unique OR empty.\n\t\t *\tIf the name is empty, the method generate a name using\n\t\t *\tthe module class and a number.\n\t\t */\n\t\tvirtual IModule *createModule(const std::string &className, const std::string &localName, const std::string &paramString)\n\t\t{\n\t\t\tTModuleFactoryRegistry::iterator it(_ModuleFactoryRegistry.find(className));\n\t\t\tif (it == _ModuleFactoryRegistry.end())\n\t\t\t{\n\t\t\t\tnlwarning(\"createModule : unknown module class '%s'\", className.c_str());\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tstring moduleName = localName;\n\t\t\tif (moduleName.empty())\n\t\t\t{\n\t\t\t\t// we need to generate a name\n\t\t\t\tuint i=0;\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tmoduleName = className+toString(i++);\n\t\t\t\t} while (_ModuleInstances.getB(moduleName) != NULL);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// check that the module name is unique\n\t\t\t\tif (_ModuleInstances.getB(moduleName) != NULL)\n\t\t\t\t{\n\t\t\t\t\tnlwarning(\"createModule : the name '%s' is already used by another module, can't instantiate the module\", moduleName.c_str());\n\t\t\t\t\treturn NULL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tIModuleFactory *mf = it->second;\n\t\t\t// sanity check\n\t\t\tnlassert(mf->getModuleClassName() == className);\n\t\t\tstd::auto_ptr<IModule> module = auto_ptr<IModule>(mf->createModule());\n\t\t\tif (module.get() == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"createModule : factory failed to create a module instance for class '%s'\", className.c_str());\n\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\tCModuleBase *modBase = dynamic_cast<CModuleBase*>(module.get());\n\t\t\tif (modBase == NULL)\n\t\t\t{\n\t\t\t\tnlwarning(\"Invalid module returned by factory for class '%s'\", className.c_str());\n\t\t\t\treturn NULL;\n\t\t\t}\n\n\t\t\t// init the module basic data\n\t\t\tmodBase->_ModuleName = moduleName;\n\t\t\tmodBase->_ModuleId = ++_LastGeneratedId;\n\n\t\t\t// init the module with parameter string\n\t\t\tTParsedCommandLine\tmii;\n\t\t\tmii.parseParamList(paramString);\n\t\t\tbool initResult = module->initModule(mii);\n\n\t\t\t// store the module in the manager\n\t\t\t_ModuleInstances.add(moduleName, module.get());\n\t\t\t_ModuleIds.add(modBase->_ModuleId, module.get());\n\n\t\t\tif (initResult)\n\t\t\t{\n\t\t\t\t// ok, all is fine, return the module\n\t\t\t\treturn module.release();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// error during initialization, delete the module\n\t\t\t\tnlwarning(\"Create module : the new module '%s' of class '%s' has failed to initilize properly.\",\\\n\t\t\t\t\tmoduleName.c_str(),\n\t\t\t\t\tclassName.c_str());\n\n\t\t\t\tdeleteModule(module.release());\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t}\n\n\t\tvoid deleteModule(IModule *module)\n\t\t{\n\t\t\tnlassert(module != NULL);\n\n\t\t\t// remove module from trackers\n\t\t\tnlassert(_ModuleInstances.getA(module) != NULL);\n\t\t\tnlassert(_ModuleIds.getA(module) != NULL);\n\n\t\t\t_ModuleInstances.removeWithB(module);\n\t\t\t_ModuleIds.removeWithB(module);\n\n\t\t\t// unplug the module if needed\n\t\t\tvector<IModuleSocket *> sockets;\n\t\t\tmodule->getPluggedSocketList(sockets);\n\t\t\tfor (uint i=0; i<sockets.size(); ++i)\n\t\t\t{\n\t\t\t\tmodule->unplugModule(sockets[i]);\n\t\t\t}\n\n\t\t\t// ask the factory to delete the module\n\t\t\tCModuleBase *modBase = dynamic_cast<CModuleBase *>(module);\n\t\t\tnlassert(modBase != NULL);\n\t\t\tmodBase->getFactory()->deleteModule(module);\n\t\t}\n\n\t\t/** Lookup in the created module for a module having the\n\t\t *\tspecified local name.\n\t\t */\n\t\tvirtual IModule *getLocalModule(const std::string &moduleName)\n\t\t{\n\t\t\tTModuleInstances::TAToBMap::const_iterator it(_ModuleInstances.getAToBMap().find(moduleName));\n\n\t\t\tif (it == _ModuleInstances.getAToBMap().end())\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t\treturn it->second;\n\t\t}\n\n\t\tvirtual void updateModules()\n\t\t{\n\t\t\tH_AUTO(CModuleManager_updateModules);\n\t\t\t// module are updated in creation order (i.e in module ID order)\n\t\t\tTModuleIds::TAToBMap::const_iterator first(_ModuleIds.getAToBMap().begin()), last(_ModuleIds.getAToBMap().end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tTModulePtr module = first->second;\n\n\t\t\t\tCModuleBase *modBase = dynamic_cast<CModuleBase *>(module.getPtr());\n\t\t\t\tif (modBase != NULL)\n\t\t\t\t{\n\t\t\t\t\t// look for module task to run\n\t\t\t\t\twhile (!modBase->_ModuleTasks.empty())\n\t\t\t\t\t{\n\t\t\t\t\t\tCModuleTask *task = modBase->_ModuleTasks.front();\n\t\t\t\t\t\ttask->resume();\n\t\t\t\t\t\t// check for finished task\n\t\t\t\t\t\tif (task->isFinished())\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tLNETL6_DEBUG(\"NLNETL6: updateModule : task %p is finished, delete and remove from task list\", task);\n\t\t\t\t\t\t\t// delete the task and resume the next one if any\n\t\t\t\t\t\t\tdelete task;\n\t\t\t\t\t\t\tmodBase->_ModuleTasks.erase(modBase->_ModuleTasks.begin());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// no more work for this update\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t{\n\t\t\t\t\tH_AUTO(CModuleManager_updateModules_2);\n\t\t\t\t\t// update the module internal\n\t\t\t\t\tfirst->second->onModuleUpdate();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/** Lookup in the created socket for a socket having the\n\t\t *\tspecified local name.\n\t\t */\n\t\tvirtual IModuleSocket *getModuleSocket(const std::string &socketName)\n\t\t{\n\t\t\tTModuleSockets::iterator it(_ModuleSocketsRegistry.find(socketName));\n\t\t\tif (it == _ModuleSocketsRegistry.end())\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t\treturn it->second;\n\t\t}\n\t\t/** Register a socket in the manager.\n\t\t */\n\t\tvirtual void registerModuleSocket(IModuleSocket *moduleSocket)\n\t\t{\n\t\t\tnlassert(moduleSocket != NULL);\n\t\t\tTModuleSockets::iterator it(_ModuleSocketsRegistry.find(moduleSocket->getSocketName()));\n\t\t\tnlassert(it == _ModuleSocketsRegistry.end());\n\n\t\t\tnldebug(\"Registering module socket '%s'\", moduleSocket->getSocketName().c_str());\n\t\t\t_ModuleSocketsRegistry.insert(make_pair(moduleSocket->getSocketName(), moduleSocket));\n\t\t}\n\t\t/** Unregister a socket in the manager.\n\t\t */\n\t\tvirtual void unregisterModuleSocket(IModuleSocket *moduleSocket)\n\t\t{\n\t\t\tnlassert(moduleSocket != NULL);\n\t\t\tTModuleSockets::iterator it(_ModuleSocketsRegistry.find(moduleSocket->getSocketName()));\n\t\t\tnlassert(it != _ModuleSocketsRegistry.end());\n\n\t\t\tnldebug(\"Unregistering module socket '%s'\", moduleSocket->getSocketName().c_str());\n\n\t\t\t_ModuleSocketsRegistry.erase(it);\n\t\t}\n\n\t\t/** Lookup in the created gateway for a gateway having the\n\t\t *\tspecified local name.\n\t\t */\n\t\tvirtual IModuleGateway *getModuleGateway(const std::string &gatewayName)\n\t\t{\n\t\t\tTModuleGateways::iterator it(_ModuleGatewaysRegistry.find(gatewayName));\n\t\t\tif (it == _ModuleGatewaysRegistry.end())\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t\treturn it->second;\n\t\t}\n\t\t/** Register a gateway in the manager.\n\t\t */\n\t\tvirtual void registerModuleGateway(IModuleGateway *moduleGateway)\n\t\t{\n\t\t\tnlassert(moduleGateway != NULL);\n\t\t\tTModuleGateways::iterator it(_ModuleGatewaysRegistry.find(moduleGateway->getGatewayName()));\n\t\t\tnlassert(it == _ModuleGatewaysRegistry.end());\n\n\t\t\tnldebug(\"Registering module gateway '%s'\", moduleGateway->getGatewayName().c_str());\n\t\t\t_ModuleGatewaysRegistry.insert(make_pair(moduleGateway->getGatewayName(), moduleGateway));\n\t\t}\n\t\t/** Unregister a socket in the manager.\n\t\t */\n\t\tvirtual void unregisterModuleGateway(IModuleGateway *moduleGateway)\n\t\t{\n\t\t\tnlassert(moduleGateway != NULL);\n\t\t\tTModuleGateways::iterator it(_ModuleGatewaysRegistry.find(moduleGateway->getGatewayName()));\n\t\t\tnlassert(it != _ModuleGatewaysRegistry.end());\n\n\t\t\tnldebug(\"Unregistering module gateway '%s'\", moduleGateway->getGatewayName().c_str());\n\n\t\t\t_ModuleGatewaysRegistry.erase(it);\n\t\t}\n\n\t\t/** Get a module proxy with the module ID */\n\t\tvirtual TModuleProxyPtr getModuleProxy(TModuleId moduleProxyId)\n\t\t{\n\t\t\tconst TModuleProxyPtr *pproxy = _ModuleProxyIds.getB(moduleProxyId);\n\n\t\t\tif (pproxy == NULL)\n\t\t\t\treturn NULL;\n\t\t\telse\n\t\t\t\treturn *pproxy;\n\t\t}\n\n\t\t/** Called by a module that is begin destroyed.\n\t\t *\tThis remove module information from the\n\t\t *\tthe manager\n\t\t */\n//\t\tvirtual void onModuleDeleted(IModule *module)\n//\t\t{\n//\t\t\t// not needed ? to remove\n//\t\t}\n\n\t\tvirtual IModuleProxy *createModuleProxy(\n\t\t\tIModuleGateway *gateway,\n\t\t\tCGatewayRoute *route,\n\t\t\tuint32 distance,\n\t\t\tIModule *localModule,\n\t\t\tconst std::string &moduleClassName,\n\t\t\tconst std::string &moduleFullyQualifiedName,\n\t\t\tconst std::string &moduleManifest,\n\t\t\tTModuleId foreignModuleId)\n\t\t{\n\t\t\tstd::auto_ptr<CModuleProxy> modProx = auto_ptr<CModuleProxy>(new CModuleProxy(localModule, ++_LastGeneratedId, moduleClassName, moduleFullyQualifiedName, moduleManifest));\n\t\t\tmodProx->_Gateway = gateway;\n\t\t\tmodProx->_Route = route;\n\t\t\tmodProx->_Distance = distance;\n\t\t\tmodProx->_ForeignModuleId = foreignModuleId;\n\n\t\t\tnldebug(\"Creating module proxy (ID : %u, foreign ID : %u, name : '%s', class : '%s' at %u hop\",\n\t\t\t\tmodProx->getModuleProxyId(),\n\t\t\t\tmodProx->getForeignModuleId(),\n\t\t\t\tmodProx->getModuleName().c_str(),\n\t\t\t\tmodProx->getModuleClassName().c_str(),\n\t\t\t\tmodProx->_Distance);\n\n//\t\t\t_ModuleProxyInstances.add(moduleFullyQualifiedName, TModuleProxyPtr(modProx.get()));\n\t\t\t_ModuleProxyIds.add(modProx->getModuleProxyId(), TModuleProxyPtr(modProx.get()));\n\n\t\t\treturn modProx.release();\n\t\t}\n\n\t\tvirtual void releaseModuleProxy(TModuleId moduleProxyId)\n\t\t{\n\t\t\tTModuleProxyIds::TAToBMap::const_iterator it(_ModuleProxyIds.getAToBMap().find(moduleProxyId));\n\t\t\tnlassert(it != _ModuleProxyIds.getAToBMap().end());\n\t\t\tCRefPtr<IModuleProxy> sanityCheck(it->second.getPtr());\n\n\t\t\tnldebug(\"Releasing module proxy ('%s', ID : %u)\",\n\t\t\t\tit->second->getModuleName().c_str(),\n\t\t\t\tmoduleProxyId);\n\n\t\t\t// remove the smart ptr, must delete the proxy\n//\t\t\t_ModuleProxyInstances.removeWithB(it->second);\n\t\t\t_ModuleProxyIds.removeWithB(it->second);\n\n\t\t\tnlassertex(sanityCheck == NULL, (\"Someone has kept a smart pointer on the proxy '%s' of class '%s'\", sanityCheck->getModuleName().c_str(), sanityCheck->getModuleClassName().c_str()));\n\t\t}\n\n\t\tvirtual uint32 getNbModule()\n\t\t{\n\t\t\treturn (uint32)_ModuleInstances.getAToBMap().size();\n\t\t}\n\n\t\tvirtual uint32 getNbModuleProxy()\n\t\t{\n\t\t\treturn (uint32)_ModuleProxyIds.getAToBMap().size();\n\t\t}\n\n\n\n\t\tNLMISC_COMMAND_HANDLER_TABLE_BEGIN(CModuleManager)\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleManager, dump, \"dump various information about module manager state\", \"\");\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleManager, loadLibrary, \"load a pure nel library module (give the path if needed and only the undecorated lib name)\", \"[path]<undecoratedLibName>\");\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleManager, unloadLibrary, \"unload a pure nel library module (give the undecorated name, any path will be removed\", \"<undecoratedLibName>\");\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleManager, createModule, \"create a new module instance\", \"<moduleClass> <instanceName> [*<moduleArg>]\");\n\t\t\tNLMISC_COMMAND_HANDLER_ADD(CModuleManager, deleteModule, \"delete a module instance\", \"<instanceName>\");\n\t\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\t\tNLMISC_CLASS_COMMAND_DECL(deleteModule)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tTModulePtr const *module = _ModuleInstances.getB(args[0]);\n\t\t\tif (module == NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Unknow module '%s'\", args[0].c_str());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tnlinfo(\"Deleting module '%s'\", args[0].c_str());\n\n\t\t\tCRefPtr<IModule>\tsanityCheck(*module);\n\t\t\tdeleteModule(*module);\n\t\t\tif (sanityCheck != NULL)\n\t\t\t{\n\t\t\t\tlog.displayNL(\"Failed to delete the module instance !\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(unloadLibrary)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(log);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() != 1)\n\t\t\t\treturn false;\n\n\t\t\tunloadModuleLibrary(args[0]);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(loadLibrary)\n\t\t{\n\t\t\tnlunreferenced(log);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() < 1)\n\t\t\t\treturn false;\n\n\t\t\tCSString libName = rawCommandString;\n\t\t\t// remove the command name\n\t\t\tlibName.strtok(\" \\t\");\n\n\t\t\t// load the library\n\t\t\treturn this->loadModuleLibrary(libName);\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(createModule)\n\t\t{\n\t\t\tnlunreferenced(log);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tif (args.size() < 2)\n\t\t\t\treturn false;\n\n\t\t\tCSString moduleArgs = rawCommandString;\n\t\t\t// remove the command name\n\t\t\tmoduleArgs.strtok(\" \\t\");\n\t\t\t// retrieve module class\n\t\t\tstring moduleClass = moduleArgs.strtok(\" \\t\");\n\t\t\t// retrieve module instance name\n\t\t\tstring moduleName = moduleArgs.strtok(\" \\t\");\n\n\t\t\tnlinfo(\"Creating module '%s' of class '%s' with params '%s'\",\n\t\t\t\tmoduleName.c_str(),\n\t\t\t\tmoduleClass.c_str(),\n\t\t\t\tmoduleArgs.c_str());\n\t\t\t// create the module instance\n\t\t\tIModule *module = createModule(moduleClass, moduleName, moduleArgs);\n\n\t\t\treturn module != NULL;\n\t\t}\n\n\t\tNLMISC_CLASS_COMMAND_DECL(dump)\n\t\t{\n\t\t\tnlunreferenced(rawCommandString);\n\t\t\tnlunreferenced(args);\n\t\t\tnlunreferenced(quiet);\n\t\t\tnlunreferenced(human);\n\n\t\t\tlog.displayNL(\"Dumping CModuleManager internal states :\");\n\t\t\t{\n\t\t\t\tstd::vector<std::string> moduleList;\n\t\t\t\tTLocalModuleFactoryRegistry::instance().fillFactoryList(moduleList);\n\t\t\t\tlog.displayNL(\" List of %u local modules classes :\", moduleList.size());\n\t\t\t\tfor (uint i=0; i<moduleList.size(); ++i)\n\t\t\t\t{\n\t\t\t\t\tif (_ModuleFactoryRegistry.find(moduleList[i]) == _ModuleFactoryRegistry.end())\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"    %s : UNAVAILABLE !\", moduleList[i].c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tIModuleFactory *modFact = TLocalModuleFactoryRegistry::instance().getFactory(moduleList[i]);\n\t\t\t\t\t\tlog.displayNL(\"    %s : OK\\tInit params : '%s'\", moduleList[i].c_str(), modFact->getInitStringHelp().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tlog.displayNL(\" List of %u loaded module libraries :\", _ModuleLibraryRegistry.size());\n\t\t\t\tTModuleLibraryInfos::iterator first(_ModuleLibraryRegistry.begin()), last(_ModuleLibraryRegistry.end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tTModuleLibraryInfo &mli = *(first->second);\n\t\t\t\t\tlog.displayNL(\"  Library '%s' loaded from '%s', contains %u modules classes:\",\n\t\t\t\t\t\tfirst->first.c_str(),\n\t\t\t\t\t\tmli.FullPathLibraryName.c_str(),\n\t\t\t\t\t\tmli.ModuleFactoryList.size());\n\t\t\t\t\t{\n\t\t\t\t\t\tvector<string>::iterator f2(mli.ModuleFactoryList.begin()), l2(mli.ModuleFactoryList.end());\n\t\t\t\t\t\tfor (uint i=0; i<mli.ModuleFactoryList.size(); ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (_ModuleFactoryRegistry.find(mli.ModuleFactoryList[i]) == _ModuleFactoryRegistry.end())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlog.displayNL(\"    %s : UNAVAILABLE, this class is already registered !\", mli.ModuleFactoryList[i].c_str());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlog.displayNL(\"    %s : OK\", mli.ModuleFactoryList[i].c_str());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tlog.displayNL(\" List of %u module instances :\", _ModuleInstances.getAToBMap().size());\n\t\t\t\tTModuleInstances::TAToBMap::const_iterator first(_ModuleInstances.getAToBMap().begin()), last(_ModuleInstances.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModule *module = first->second;\n\t\t\t\t\tlog.displayNL(\"    ID:%5u : \\tname = '%s' \\tclass = '%s'\",\n\t\t\t\t\t\tmodule->getModuleId(),\n\t\t\t\t\t\tmodule->getModuleName().c_str(),\n\t\t\t\t\t\tmodule->getModuleClassName().c_str());\n\t\t\t\t}\n\t\t\t}\n\t\t\t{\n\t\t\t\tlog.displayNL(\" List of %u module proxies :\", _ModuleProxyIds.getAToBMap().size());\n\t\t\t\tTModuleProxyIds::TAToBMap::const_iterator first(_ModuleProxyIds.getAToBMap().begin()), last(_ModuleProxyIds.getAToBMap().end());\n\t\t\t\tfor (; first != last; ++first)\n\t\t\t\t{\n\t\t\t\t\tIModuleProxy *modProx = first->second;\n\t\t\t\t\tif (modProx->getGatewayRoute() != NULL)\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"    ID:%5u (Foreign ID : %u) : \\tname = '%s' \\tclass = '%s'\",\n\t\t\t\t\t\t\tmodProx->getModuleProxyId(),\n\t\t\t\t\t\t\tmodProx->getForeignModuleId(),\n\t\t\t\t\t\t\tmodProx->getModuleName().c_str(),\n\t\t\t\t\t\t\tmodProx->getModuleClassName().c_str());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tlog.displayNL(\"    ID:%5u (Local proxy for module ID : %u) : \\tname = '%s' \\tclass = '%s'\",\n\t\t\t\t\t\t\tmodProx->getModuleProxyId(),\n\t\t\t\t\t\t\tmodProx->getForeignModuleId(),\n\t\t\t\t\t\t\tmodProx->getModuleName().c_str(),\n\t\t\t\t\t\t\tmodProx->getModuleClassName().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t};\n\n\tbool\t\tIModuleManager::isInitialized()\n\t{\n\t\treturn CModuleManager::isInitialized();\n\t}\n\n\tIModuleManager &IModuleManager::getInstance()\n\t{\n\t\treturn CModuleManager::getInstance();\n\t}\n\n\tvoid IModuleManager::releaseInstance()\n\t{\n\t\tCModuleManager::releaseInstance();\n\t}\n\n\tNLMISC_SAFE_SINGLETON_IMPL(CModuleManager);\n\n\n\textern void forceGatewayLink();\n\textern void forceLocalGatewayLink();\n\textern void forceGatewayTransportLink();\n\textern void forceGatewayL5TransportLink();\n\n\n\tvoid forceLink()\n\t{\n\t\tforceGatewayLink();\n\t\tforceLocalGatewayLink();\n\t\tforceGatewayTransportLink();\n\t\tforceGatewayL5TransportLink();\n\t}\n\n} // namespace NLNET\n\n"
  },
  {
    "path": "code/nel/src/net/module_message.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n#include \"nel/net/module_message.h\"\n\n// a stupid function to remove some more stupid visual warnings\nvoid foo_module_message() {}\n\nnamespace NLNET\n{\n//\tCModuleMessage::CModuleMessage(const CMessage &messageBody)\n//\t\t: MessageType(mt_invalid),\n//\t\tSenderModuleId(INVALID_MODULE_ID),\n//\t\tAddresseeModuleId(INVALID_MODULE_ID),\n//\t\tMessageBody(const_cast<CMessage&>(messageBody))\n//\t{\n//\n//\t}\n//\n//\n//\tvoid CModuleMessage::serial(NLMISC::IStream &s)\n//\t{\n//\t\tnlassert(mt_num_types < 0xFF);\n//\t\tnlassert(MessageType != mt_invalid);\n//\n//\t\ts.serialBitField8(reinterpret_cast<uint8&>(MessageType));\n//\t\ts.serial(SenderModuleId);\n//\t\ts.serial(AddresseeModuleId);\n//\t\tMessageBody.serialMessage()\n//\t}\n\n\n} // namespace NLNET\n"
  },
  {
    "path": "code/nel/src/net/module_socket.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n#include \"nel/net/module_socket.h\"\n#include \"nel/net/module.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/module_gateway.h\"\n#include \"nel/net/module_common.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET\n{\n\n\tCModuleSocket::CModuleSocket()\n\t\t: _SocketRegistered(false)\n\t{\n\t}\n\n\tCModuleSocket::~CModuleSocket()\n\t{\n\t\tunregisterSocket();\n\t}\n\n\n\tvoid CModuleSocket::registerSocket()\n\t{\n\t\tif (!_SocketRegistered)\n\t\t{\n\t\t\t_SocketRegistered = true;\n\t\t\tIModuleManager::getInstance().registerModuleSocket(this);\n\t\t}\n\t}\n\n\tvoid CModuleSocket::unregisterSocket()\n\t{\n\t\tif (_SocketRegistered)\n\t\t{\n\t\t\tIModuleManager::getInstance().unregisterModuleSocket(this);\n\t\t\t_SocketRegistered = false;\n\t\t}\n\t}\n\n\tvoid CModuleSocket::_onModulePlugged(const TModulePtr &pluggedModule)\n\t{\n\t\tTPluggedModules::TBToAMap::const_iterator it(_PluggedModules.getBToAMap().find(pluggedModule));\n\t\tif (it != _PluggedModules.getBToAMap().end())\n\t\t{\n\t\t\tthrow IModule::EModuleAlreadyPluggedHere();\n\t\t}\n\n\t\t_PluggedModules.add(pluggedModule->getModuleId(), pluggedModule);\n\n\t\t// callback socket implementation\n\t\tonModulePlugged(pluggedModule);\n\t}\n\n\tvoid CModuleSocket::_onModuleUnplugged(const TModulePtr &pluggedModule)\n\t{\n\t\tTPluggedModules::TBToAMap::const_iterator it(_PluggedModules.getBToAMap().find(pluggedModule));\n\t\tif (it == _PluggedModules.getBToAMap().end())\n\t\t{\n\t\t\tthrow EModuleNotPluggedHere();\n\t\t}\n\n\t\t// callback socket implementation\n\t\tonModuleUnplugged(pluggedModule);\n\n\t\t_PluggedModules.removeWithB(pluggedModule);\n\t}\n\n\tvoid CModuleSocket::sendModuleMessage(IModule *senderModule, TModuleId destModuleProxyId, const NLNET::CMessage &message )\n\t\t\tthrow (EModuleNotPluggedHere)\n\t{\n\t\tTPluggedModules::TBToAMap::const_iterator it(_PluggedModules.getBToAMap().find(senderModule));\n\t\tif (it == _PluggedModules.getBToAMap().end())\n\t\t{\n\t\t\tthrow EModuleNotPluggedHere();\n\t\t}\n\n\t\t// forward to socket implementation\n\t\t_sendModuleMessage(senderModule, destModuleProxyId, message);\n\n\t}\n\n\tvoid CModuleSocket::broadcastModuleMessage(IModule *senderModule, const NLNET::CMessage &message)\n\t\t\tthrow (EModuleNotPluggedHere)\n\t{\n\t\tTPluggedModules::TBToAMap::const_iterator it(_PluggedModules.getBToAMap().find(senderModule));\n\t\tif (it == _PluggedModules.getBToAMap().end())\n\t\t{\n\t\t\tthrow EModuleNotPluggedHere();\n\t\t}\n\n\t\t// forward to socket implementation\n\t\t_broadcastModuleMessage(senderModule, message);\n\t}\n\n} // namespace NLNET\n"
  },
  {
    "path": "code/nel/src/net/naming_client.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//\n// Includes\n//\n\n#include \"stdnet.h\"\n\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/service.h\"\n\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\n//\n// Variables\n//\n\nCCallbackClient *CNamingClient::_Connection = NULL;\nCNamingClient::TRegServices CNamingClient::_RegisteredServices;\n\nstatic TBroadcastCallback _RegistrationBroadcastCallback = NULL;\nstatic TBroadcastCallback _UnregistrationBroadcastCallback = NULL;\n\nTServiceId CNamingClient::_MySId(0);\n\nstd::list<CNamingClient::CServiceEntry>\tCNamingClient::RegisteredServices;\nNLMISC::CMutex CNamingClient::RegisteredServicesMutex(\"CNamingClient::RegisteredServicesMutex\");\n\n//\n//\n//\n\nvoid CNamingClient::setRegistrationBroadcastCallback (TBroadcastCallback cb)\n{\n\t_RegistrationBroadcastCallback = cb;\n}\n\nvoid CNamingClient::setUnregistrationBroadcastCallback (TBroadcastCallback cb)\n{\n\t_UnregistrationBroadcastCallback = cb;\n}\n\n//\n\n//\n\nstatic bool Registered;\nstatic bool RegisteredSuccess;\nstatic TServiceId *RegisteredSID = NULL;\nstatic string Reason;\nvoid cbRegisterBroadcast (CMessage &msgin, TSockId from, CCallbackNetBase &netbase);\n\nstatic void cbRegister (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tnlassert(RegisteredSID != NULL);\n\n\tmsgin.serial (RegisteredSuccess);\n\tif (RegisteredSuccess)\n\t{\n\t\tmsgin.serial (*RegisteredSID);\n\n\t\t// decode the registered services at the register process\n\t\tcbRegisterBroadcast (msgin, from, netbase);\n\t}\n\telse\n\t{\n\t\tmsgin.serial( Reason );\n\t}\n\tRegistered = true;\n}\n\n//\n\nstatic bool QueryPort;\nstatic uint16 QueryPortPort;\n\nstatic void cbQueryPort (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)\n{\n\tmsgin.serial (QueryPortPort);\n\tQueryPort = true;\n}\n\n//\n\n//static bool FirstRegisteredBroadcast;\n\nvoid cbRegisterBroadcast (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)\n{\n\tTServiceId::size_type size;\n\tstring name;\n\tTServiceId sid;\n\tvector<CInetAddress> addr;\n\n\tmsgin.serial (size);\n\n\tfor (TServiceId::size_type i = 0; i < size; i++)\n\t{\n\t\tmsgin.serial (name);\n\t\tmsgin.serial (sid);\n\t\tmsgin.serialCont (addr);\n\n\t\t// add it in the list\n\n\t\tstd::vector<CInetAddress> addrs;\n\t\tCNamingClient::find (sid, addrs);\n\n\t\tif (addrs.size() == 0)\n\t\t{\n\t\t\tCNamingClient::RegisteredServicesMutex.enter ();\n\t\t\tCNamingClient::RegisteredServices.push_back (CNamingClient::CServiceEntry (name, sid, addr));\n\t\t\tCNamingClient::RegisteredServicesMutex.leave ();\n\n\t\t\tnlinfo (\"NC: Registration Broadcast of the service %s-%hu '%s'\", name.c_str(), sid.get(), vectorCInetAddressToString(addr).c_str());\n\n\t\t\tif (_RegistrationBroadcastCallback != NULL)\n\t\t\t\t_RegistrationBroadcastCallback (name, sid, addr);\n\t\t}\n\t\telse if (addrs.size() == 1)\n\t\t{\n\t\t\tCNamingClient::RegisteredServicesMutex.enter ();\n\t\t\tfor (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)\n\t\t\t{\n\t\t\t\tif (sid == (*it).SId)\n\t\t\t\t{\n\t\t\t\t\t(*it).Name = name;\n\t\t\t\t\t(*it).Addr = addr;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tCNamingClient::RegisteredServicesMutex.leave ();\n\t\t\tnlinfo (\"NC: Registration Broadcast (update) of the service %s-%hu '%s'\", name.c_str(), sid.get(), addr[0].asString().c_str());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlstop;\n\t\t}\n\t}\n\n//\tFirstRegisteredBroadcast = true;\n\n\t//CNamingClient::displayRegisteredServices ();\n}\n\n//\n\nvoid cbUnregisterBroadcast (CMessage &msgin, TSockId /* from */, CCallbackNetBase &/* netbase */)\n{\n\tstring name;\n\tTServiceId sid;\n\tvector<CInetAddress> addrs;\n\n\tmsgin.serial (name);\n\tmsgin.serial (sid);\n\n\t// remove it in the list, if the service is not found, ignore it\n\n\tCNamingClient::RegisteredServicesMutex.enter ();\n\tfor (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)\n\t{\n\t\tCNamingClient::CServiceEntry &serviceEntry = *it;\n\t\tif (serviceEntry.SId == sid)\n\t\t{\n\t\t\t// check the structure\n\t\t\tnlassertex (serviceEntry.Name == name, (\"%s %s\",serviceEntry.Name.c_str(), name.c_str()));\n\n\t\t\taddrs = serviceEntry.Addr;\n\n\t\t\tCNamingClient::RegisteredServices.erase (it);\n\t\t\tbreak;\n\t\t}\n\t}\n\tCNamingClient::RegisteredServicesMutex.leave ();\n\n\tnlinfo (\"NC: Unregistration Broadcast of the service %s-%hu\", name.c_str(), sid.get());\n\n\t// send the ACK to the NS\n\n\tCMessage msgout (\"ACK_UNI\");\n\tmsgout.serial (sid);\n\tCNamingClient::_Connection->send (msgout);\n\n\t// oh my god, it s my sid! but i m alive, why this f*cking naming service want to kill me? ok, i leave it alone!\n\tif(CNamingClient::_MySId == sid)\n\t{\n\t\tnlwarning (\"NC: Naming Service asked me to leave, I leave!\");\n\t\tIService::getInstance()->exit();\n\t\treturn;\n\t}\n\n\tif (_UnregistrationBroadcastCallback != NULL)\n\t\t_UnregistrationBroadcastCallback (name, sid, addrs);\n\n\t//CNamingClient::displayRegisteredServices ();\n}\n\nvoid cbUpdateServiceState (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n    TServiceId  sid;\n    uint32      state;\n    msgin.serial( sid );\n    msgin.serial( state );\n\n    CNamingClient::RegisteredServicesMutex.enter ();\n    for (std::list<CNamingClient::CServiceEntry>::iterator it = CNamingClient::RegisteredServices.begin(); it != CNamingClient::RegisteredServices.end (); it++)\n    {\n        if (it->SId == sid)\n        {\n            it->RunningState = (TServiceRunningState)state;\n            break;\n        }\n    }\n    CNamingClient::RegisteredServicesMutex.leave ();\n\n    nlinfo (\"NC: cbUpdateServiceState  sid:%hu\", sid.get());\n}\n//\n\nstatic TCallbackItem NamingClientCallbackArray[] =\n{\n\t{ \"RG\", cbRegister },\n\t{ \"QP\", cbQueryPort },\n\n\t{ \"RGB\", cbRegisterBroadcast },\n\t{ \"UNB\", cbUnregisterBroadcast },\n\n    { \"USS\", cbUpdateServiceState }\n};\n\nvoid CNamingClient::connect( const CInetAddress &addr, CCallbackNetBase::TRecordingState rec, const vector<CInetAddress> &/* addresses */ )\n{\n\tnlassert (_Connection == NULL || (_Connection != NULL && !_Connection->connected ()));\n\n\tif (_Connection == NULL)\n\t{\n\t\t_Connection = new CCallbackClient( rec, \"naming_client.nmr\" );\n\t\t_Connection->addCallbackArray (NamingClientCallbackArray, sizeof (NamingClientCallbackArray) / sizeof (NamingClientCallbackArray[0]));\n\t}\n\n\t_Connection->connect (addr);\n\n/*\t// send the available addresses\n\tCMessage msgout (\"RS\");\n\tmsgout.serialCont (const_cast<vector<CInetAddress>&>(addresses));\n\t_Connection->send (msgout);\n\n\t// wait the message that contains all already connected services\n\tFirstRegisteredBroadcast = false;\n\twhile (!FirstRegisteredBroadcast && _Connection->connected ())\n\t{\n\t\t_Connection->update (-1);\n\t\tnlSleep (1);\n\t}\n*/}\n\n\nvoid CNamingClient::disconnect ()\n{\n\tif (_Connection != NULL)\n\t{\n\t\tif (_Connection->connected ())\n\t\t{\n\t\t\t_Connection->disconnect ();\n\t\t}\n\t\tdelete _Connection;\n\t\t_Connection = NULL;\n\t}\n\n\t// we don't call unregisterAllServices because when the naming service will see the disconnection,\n\t// it'll automatically unregister all services registered by this client.\n}\n\nstring CNamingClient::info ()\n{\n\tstring res;\n\n\tif (connected ())\n\t{\n\t\tres = \"connected to \";\n\t\tres += _Connection->remoteAddress().asString();\n\t}\n\telse\n\t{\n\t\tres = \"Not connected\";\n\t}\n\n\treturn res;\n}\n\nbool CNamingClient::registerService (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId &sid)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tCMessage msgout (\"RG\");\n\tmsgout.serial (const_cast<std::string&>(name));\n\tmsgout.serialCont (const_cast<vector<CInetAddress>&>(addr));\n\tsid.set(0);\n\tmsgout.serial (sid);\n\t_Connection->send (msgout);\n\n\t// wait the answer of the naming service \"RG\"\n\tRegistered = false;\n\tRegisteredSID = &sid;\n\twhile (!Registered)\n\t{\n\t\t_Connection->update (-1);\n\t\tnlSleep (1);\n\t}\n\tif (RegisteredSuccess)\n\t{\n\t\t_MySId = sid;\n\t\t_RegisteredServices.insert (make_pair (*RegisteredSID, name));\n\t\tnldebug (\"NC: Registered service %s-%hu at %s\", name.c_str(), sid.get(), addr[0].asString().c_str());\n\t}\n\telse\n\t{\n\t\tnldebug (\"NC: Naming service refused to register service %s at %s\", name.c_str(), addr[0].asString().c_str());\n\t\tnlwarning (\"NC: Startup denied: %s\", Reason.c_str());\n\t\tReason.clear();\n\t}\n\n\tRegisteredSID = NULL;\n\n\treturn RegisteredSuccess;\n}\n\nbool CNamingClient::registerServiceWithSId (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tCMessage msgout (\"RG\");\n\tmsgout.serial (const_cast<std::string&>(name));\n\tmsgout.serialCont (const_cast<vector<CInetAddress>&>(addr));\n\tmsgout.serial (sid);\n\t_Connection->send (msgout);\n\n\t// wait the answer of the naming service \"RGI\"\n\tRegistered = false;\n\tRegisteredSID = &sid;\n\twhile (!Registered)\n\t{\n\t\t_Connection->update (-1);\n\t\tnlSleep (1);\n\t}\n\tif (RegisteredSuccess)\n\t{\n\t\t_MySId = sid;\n\t\t_RegisteredServices.insert (make_pair (*RegisteredSID, name));\n\t\tnldebug (\"NC: Registered service with sid %s-%hu at %s\", name.c_str(), RegisteredSID->get(), addr[0].asString().c_str());\n\t}\n\telse\n\t{\n\t\tnlerror (\"NC: Naming service refused to register service with sid %s at %s\", name.c_str(), addr[0].asString().c_str());\n\t}\n\n\treturn RegisteredSuccess == 1;\n}\n\nvoid CNamingClient::resendRegisteration (const std::string &name, const std::vector<CInetAddress> &addr, TServiceId sid)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tCMessage msgout (\"RRG\");\n\tmsgout.serial (const_cast<std::string&>(name));\n\tmsgout.serialCont (const_cast<vector<CInetAddress>&>(addr));\n\tmsgout.serial (sid);\n\t_Connection->send (msgout);\n}\n\nvoid CNamingClient::unregisterService (TServiceId sid)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tCMessage msgout (\"UNI\");\n\tmsgout.serial (sid);\n\t_Connection->send (msgout);\n\n\tnldebug (\"NC: Unregistering service %s-%hu\", _RegisteredServices[sid].c_str(), sid.get());\n\t_RegisteredServices.erase (sid);\n}\n\nvoid CNamingClient::unregisterAllServices ()\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\twhile (!_RegisteredServices.empty())\n\t{\n\t\tTRegServices::iterator irs = _RegisteredServices.begin();\n\t\tTServiceId sid = (*irs).first;\n\t\tunregisterService (sid);\n\t}\n}\n\nuint16 CNamingClient::queryServicePort ()\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tCMessage msgout (\"QP\");\n\t_Connection->send (msgout);\n\n\t// wait the answer of the naming service \"QP\"\n\tQueryPort = false;\n\twhile (!QueryPort)\n\t{\n\t\t_Connection->update (-1);\n\t\tnlSleep (1);\n\t}\n\n\tnlinfo (\"NC: Received the answer of the query port (%hu)\", QueryPortPort);\n\n\treturn QueryPortPort;\n}\n\nbool CNamingClient::lookup (const std::string &name, CInetAddress &addr)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tvector<CInetAddress> addrs;\n\tfind (name, addrs);\n\n\tif (addrs.size()==0)\n\t\treturn false;\n\n\tnlassert (addrs.size()==1);\n\taddr = addrs[0];\n\n\treturn true;\n}\n\nbool CNamingClient::lookup (TServiceId sid, CInetAddress &addr)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tvector<CInetAddress> addrs;\n\tfind (sid, addrs);\n\n\tif (addrs.size()==0)\n\t\treturn false;\n\n\tnlassert (addrs.size()==1);\n\taddr = addrs[0];\n\n\treturn true;\n}\n\nbool CNamingClient::lookupAlternate (const std::string &name, CInetAddress &addr)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\t// remove it from his local list\n\n\tRegisteredServicesMutex.enter ();\n\tfor (std::list<CServiceEntry>::iterator it = RegisteredServices.begin(); it != RegisteredServices.end (); it++)\n\t{\n\t\tif ((*it).Addr[0] == addr)\n\t\t{\n\t\t\tRegisteredServices.erase (it);\n\t\t\tbreak;\n\t\t}\n\t}\n\tRegisteredServicesMutex.leave ();\n\n\tvector<CInetAddress> addrs;\n\tfind (name, addrs);\n\n\tif (addrs.size()==0)\n\t\treturn false;\n\n\tnlassert (addrs.size()==1);\n\taddr = addrs[0];\n\n\treturn true;\n}\n\nvoid CNamingClient::lookupAll (const std::string &name, std::vector<CInetAddress> &addrs)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\tfind (name, addrs);\n}\n\nbool CNamingClient::lookupAndConnect (const std::string &name, CCallbackClient &sock)\n{\n\tnlassert (_Connection != NULL && _Connection->connected ());\n\n\t// look up for service\n\tCInetAddress servaddr;\n\n\t// if service not found, return false\n\tif (!CNamingClient::lookup (name, servaddr))\n\t\treturn false;\n\n\tfor(;;)\n\t{\n\t\ttry\n\t\t{\n\t\t\t// try to connect to the server\n\t\t\tsock.connect (servaddr);\n\n\t\t\t// connection succeeded\n\t\t\treturn true;\n\t\t}\n\t\tcatch (const ESocketConnectionFailed &e)\n\t\t{\n\t\t\tnldebug( \"NC: Connection to %s failed: %s, tring another service if available\", servaddr.asString().c_str(), e.what() );\n\n\t\t\t// try another server and if service is not found, return false\n\t\t\tif (!CNamingClient::lookupAlternate (name, servaddr))\n\t\t\t\treturn false;\n\t\t}\n\t}\n}\n\n\n\nvoid CNamingClient::update ()\n{\n\t// get message for naming service (new registration for example)\n\tif (_Connection != NULL && _Connection->connected ())\n\t\t_Connection->update ();\n}\n\nvoid CNamingClient::SelfCanAccess()\n{\n    if ( _Connection!=NULL && _Connection->connected () )\n    {\n        TServiceId sid  = IService::getInstance()->getServiceId();\n        uint32 state    = ServiceCanAccess;\n        CMessage msgout (\"SSS\");\n        msgout.serial(sid);\n        msgout.serial(state);\n        _Connection->send (msgout);\n    }\n}\n\nbool CNamingClient::IsCanAccess( std::vector<std::string>& service_names )\n{\n    RegisteredServicesMutex.enter ();\n\n    for ( uint i=0; i<service_names.size(); ++i )\n    {\n        std::list<CServiceEntry>::iterator it = RegisteredServices.begin();\n\n        while( it!=RegisteredServices.end () )\n        {\n            if ( it->Name == service_names[i] )\n            {\n                if ( it->RunningState != ServiceCanAccess )\n                {\n                    RegisteredServicesMutex.leave ();\n                    return false;\n                }\n                break;\n            }\n\n            ++it;\n        }\n\n        if ( it==RegisteredServices.end () )\n        {\n            RegisteredServicesMutex.leave ();\n            return false;\n        }\n    }\n\n    RegisteredServicesMutex.leave ();\n    return true;\n}\n\n\n\n\n//\n// Commands\n//\n\nNLMISC_CATEGORISED_COMMAND(nel, services, \"displays registered services\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tCNamingClient::displayRegisteredServices (&log);\n\n\treturn true;\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/nel-net.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: nel-net\nVersion: @NL_VERSION@\nDescription: NeL @NL_VERSION@\nRequires:\nLibs: -L${libdir}\nLibs.private: @LIBS@ -lc -lpthread -lrt -ldl\nCflags: -I${includedir} -lc -lpthread -lrt -ldl\n"
  },
  {
    "path": "code/nel/src/net/net_displayer.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/net_displayer.h\"\n#include \"nel/net/message.h\"\n#include \"nel/net/naming_client.h\"\n\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/* This index must correspond to the index for \"LOG\" in CallbackArray in the Logging Service\n * (see CNetDisplayer::display())\n */\nconst sint16 LOG_CBINDEX = 0;\n\n\n/*\n * Constructor\n */\nCNetDisplayer::CNetDisplayer(bool autoConnect) :\n\t_Server(NULL), _ServerAllocated (false) // disable logging otherwise an infinite recursion may occur\n{\n\tif (autoConnect) findAndConnect();\n}\n\n\n/*\n * Find the server (using the NS) and connect\n */\nvoid CNetDisplayer::findAndConnect()\n{\n\tif (_Server == NULL)\n\t{\n\t\t_Server = new CCallbackClient();\n\t\t_ServerAllocated = true;\n\t}\n\n\tif ( CNamingClient::lookupAndConnect( \"LOGS\", *_Server ) )\n\t{\n\t\tnldebug( \"Connected to logging service\" );\n\t}\n}\n\n/*\n * Sets logging server address\n */\nvoid CNetDisplayer::setLogServer (const CInetAddress& logServerAddr)\n{\n\tif (_Server != NULL && _Server->connected()) return;\n\n\t_ServerAddr = logServerAddr;\n\n\tif (_Server == NULL)\n\t{\n\t\t_Server = new CCallbackClient();\n\t\t_ServerAllocated = true;\n\t}\n\n\ttry\n\t{\n\t\t_Server->connect (_ServerAddr);\n\t}\n\tcatch(const ESocket&)\n\t{\n\t\t// Silence\n\t}\n}\n\nvoid CNetDisplayer::setLogServer (CCallbackClient *server)\n{\n\tif (_Server != NULL && _Server->connected()) return;\n\n\t_Server = server;\n}\n\n\n/*\n * Destructor\n */\nCNetDisplayer::~CNetDisplayer ()\n{\n\tif (_ServerAllocated)\n\t{\n\t\t_Server->disconnect ();\n\t\tdelete _Server;\n\t}\n}\n\n\n/*\n * Sends the string to the logging server\n *\n * Log format: \"2000/01/15 12:05:30 <LogType> <ProcessName>: <Msg>\"\n */\nvoid CNetDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message)\n{\n\ttry\n\t{\n\t\tif (_Server == NULL || !_Server->connected())\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tbool needSpace = false;\n\t\t//stringstream ss;\n\t\tstring str;\n\n\t\tif (args.Date != 0)\n\t\t{\n\t\t\tstr += dateToHumanString(args.Date);\n\t\t\tneedSpace = true;\n\t\t}\n\n\t\tif (args.LogType != CLog::LOG_NO)\n\t\t{\n\t\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t\tstr += logTypeToString(args.LogType);\n\t\t\tneedSpace = true;\n\t\t}\n\n\t\tif (!args.ProcessName.empty())\n\t\t{\n\t\t\tif (needSpace) { str += \" \"; needSpace = false; }\n\t\t\tstr += args.ProcessName;\n\t\t\tneedSpace = true;\n\t\t}\n\n\t\tif (needSpace) { str += \": \"; needSpace = false; }\n\n\t\tstr += message;\n\n\t\tCMessage msg(\"LOG\" );\n\t\tstring s = str;\n\t\tmsg.serial( s );\n\t\t_Server->send (msg, 0, false);\n\t}\n\tcatch(const NLMISC::Exception& )\n\t{\n\t\t// Silence\n\t}\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/net_log.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#include \"stdnet.h\"\n\n#include \"nel/net/net_log.h\"\n#include \"nel/net/unitime.h\"\n\n\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\n\n//\n// Globals\n//\n\nNLMISC::CVariable<bool> VerboseLNETL0(\"nel\",\"VerboseLNETL0\",\"Enable verbose logging in Network Layer 0 operations\",false,0,true);\nNLMISC::CVariable<bool> VerboseLNETL1(\"nel\",\"VerboseLNETL1\",\"Enable verbose logging in Network Layer 1 operations\",false,0,true);\nNLMISC::CVariable<bool> VerboseLNETL2(\"nel\",\"VerboseLNETL2\",\"Enable verbose logging in Network Layer 2 operations\",false,0,true);\nNLMISC::CVariable<bool> VerboseLNETL3(\"nel\",\"VerboseLNETL3\",\"Enable verbose logging in Network Layer 3 operations\",false,0,true);\nNLMISC::CVariable<bool> VerboseLNETL4(\"nel\",\"VerboseLNETL4\",\"Enable verbose logging in Network Layer 4 operations\",false,0,true);\nNLMISC::CVariable<bool> VerboseLNETL5(\"nel\",\"VerboseLNETL5\",\"Enable verbose logging in Network Layer 5 operations\",true,0,true);\nNLMISC::CVariable<bool> VerboseLNETL6(\"nel\",\"VerboseLNETL6\",\"Enable verbose logging in Network Layer 6 operations\",true,0,true);\n\n\n\n\n/**************************************************************************\n********************* THIS CLASS IS DEPRECATED ****************************\n**************************************************************************/\n\n\n\n\n\n\nCNetLog NetLog;\n\n\n/*\n * Constructor\n */\nCNetLog::CNetLog() :\n\tCLog()\n{\n}\n\n\n/*\n * Log an output transfer (send)\n */\nvoid CNetLog::output( const char *srchost, uint8 msgnum,\n\t\t\t\t\t  const char *desthost, const char *msgname, uint32 msgsize )\n{\n/*OLD\tchar line [1024];\n\tsmprintf( line, 1024, \"@@%\" NL_I64 \"d@%s@%hu@%s@%s@%s@%u@\", (CUniTime::Sync?CUniTime::getUniTime():(TTime)0),\n\t\tsrchost, (uint16)msgnum, _ProcessName.c_str(), desthost, msgname, msgsize );\n\n\tdisplayRawNL( line );\n\t*/\n/*\tdisplayRawNL( \"@@%\" NL_I64 \"d@%s@%hu@%s@%s@%s@%u@\", (CUniTime::Sync?CUniTime::getUniTime():(TTime)0),\n\t\tsrchost, (uint16)msgnum, _ProcessName.c_str(), desthost, msgname, msgsize );\n*/\n\tdisplayRawNL( \"@@0@%s@%hu@%s@%s@%s@%u@\",\n\t\tsrchost, (uint16)msgnum, (*_ProcessName).c_str(), desthost, msgname, msgsize );\n}\n\n\n/*\n * Log an input transfer (receive)\n */\nvoid CNetLog::input( const char *srchost, uint8 msgnum, const char *desthost )\n{\n/*OLD\tchar line [1024];\n\tsmprintf( line, 1024, \"##%\" NL_I64 \"d#%s#%hu#%s#%s#\", (CUniTime::Sync?CUniTime::getUniTime():(TTime)0),\n\t\t\t  srchost, msgnum, _ProcessName.c_str(), desthost );\n\tdisplayRawNL( line );\n*/\n/*\tdisplayRawNL( \"##%\" NL_I64 \"d#%s#%hu#%s#%s#\", (CUniTime::Sync?CUniTime::getUniTime():(TTime)0),\n\t\t  srchost, msgnum, _ProcessName.c_str(), desthost );\n*/\n\tdisplayRawNL( \"##0#%s#%hu#%s#%s#\",\n\t\t  srchost, msgnum, (*_ProcessName).c_str(), desthost );\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/net_manager.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n/**************************************************************************\n********************* THIS CLASS IS DEPRECATED ****************************\n**************************************************************************/\n#ifdef NL_OS_WINDOWS\n#\tpragma message(NL_LOC_WRN \"You are using a deprecated feature of NeL, consider rewriting your code with replacement feature\")\n#else // NL_OS_UNIX\n#\twarning \"You are using a deprecated feature of NeL, consider rewriting your code with replacement feature\"\n#endif\n\n#include \"nel/misc/time_nl.h\"\n\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/net_manager.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\nCNetManager::TBaseMap\tCNetManager::_BaseMap;\n\nCCallbackNetBase::TRecordingState\tCNetManager::_RecordingState;\n\nTTime CNetManager::_NextUpdateTime = 0;\n\nstatic void nmNewConnection (TSockId from, void *arg)\n{\n\tnlassert (arg != NULL);\n\tCBaseStruct *basest = (CBaseStruct *)arg;\n\n\tnldebug(\"HNETL4: nmNewConnection() from service '%s'\", basest->Name.c_str ());\n\n\t// call the client callback if necessary\n\tif (basest->ConnectionCallback != NULL)\n\t\tbasest->ConnectionCallback (basest->Name, from, basest->ConnectionCbArg);\n}\n\nstatic void nmNewDisconnection (TSockId from, void *arg)\n{\n\tnlassert (arg != NULL);\n\tCBaseStruct *basest = (CBaseStruct *)arg;\n\n\tnldebug(\"HNETL4: nmNewDisconnection() from service '%s'\", basest->Name.c_str ());\n\n\t// call the client callback if necessary\n\tif (basest->DisconnectionCallback != NULL)\n\t\tbasest->DisconnectionCallback (basest->Name, from, basest->DisconnectionCbArg);\n}\n\n\n// find a not connected callbackclient or create a new one and connect to the Addr\nvoid CNetManager::createConnection(CBaseStruct &Base, const CInetAddress &Addr, const string& name)\n{\n\tuint i;\n\tfor (i = 0; i < Base.NetBase.size (); i++)\n\t{\n\t\tif (!Base.NetBase[i]->connected ())\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (i == Base.NetBase.size ())\n\t{\n\t\tCCallbackClient *cc = new CCallbackClient( _RecordingState, name+string(\".nmr\") );\n\t\tBase.NetBase.push_back (cc);\n\t}\n\n\tCCallbackClient *cc = dynamic_cast<CCallbackClient *>(Base.NetBase[i]);\n\n\tcc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &Base);\n\n\ttry\n\t{\n\t\tcc->connect (Addr);\n\n\t\tif (Base.ConnectionCallback != NULL)\n\t\t\tBase.ConnectionCallback (Base.Name, cc->getSockId(), Base.ConnectionCbArg);\n\t}\n\tcatch (ESocketConnectionFailed &e)\n\t{\n\t\tnlinfo (\"HNETL4: can't connect now (%s)\", e.what ());\n\t}\n}\n\n\nvoid RegistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)\n{\n\tnldebug(\"HNETL4: RegistrationBroadcast() of service %s-%hu\", name.c_str (), (uint16)sid.get());\n\n\t// find if this new service is interesting\n\tfor (CNetManager::ItBaseMap itbm = CNetManager::_BaseMap.begin (); itbm != CNetManager::_BaseMap.end (); itbm++)\n\t{\n\t\tif ((*itbm).second.Type == CBaseStruct::Client && !(*itbm).second.NetBase[0]->connected())\n\t\t{\n\t\t\tif (name == (*itbm).first)\n\t\t\t{\n\t\t\t\t// ok! it's cool, the service is here, go and connect to him!\n// ace warning don't work if more than one connection\n\t\t\t\tCNetManager::createConnection ((*itbm).second, addr[0], name);\n\t\t\t}\n\t\t}\n\t\telse if ((*itbm).second.Type == CBaseStruct::Group)\n\t\t{\n\t\t\t// ok, it's a group, try to see if it wants this!\n\t\t\tfor (uint i = 0; i < (*itbm).second.ServiceNames.size (); i++)\n\t\t\t{\n\t\t\t\tif ((*itbm).second.ServiceNames[i] == name)\n\t\t\t\t{\n// ace warning don't work if more than one connection\n\t\t\t\t\tCNetManager::createConnection ((*itbm).second, addr[0], name);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n}\n\nstatic void UnregistrationBroadcast (const std::string &name, TServiceId sid, const vector<CInetAddress> &addr)\n{\n\tnldebug(\"HNETL4: UnregistrationBroadcast() of service %s-%hu\", name.c_str (), (uint16)sid.get());\n}\n\nvoid CNetManager::init (const CInetAddress *addr, CCallbackNetBase::TRecordingState rec )\n{\n\tif (addr == NULL) return;\n\n\t_RecordingState = rec;\n\n\t// connect to the naming service (may generate a ESocketConnectionFailed exception)\n\n\tvector<CInetAddress> laddr = CInetAddress::localAddresses();\n\tCNamingClient::connect( *addr, _RecordingState, laddr );\n\n\t// connect the callback to know when a new service comes in or goes down\n\tCNamingClient::setRegistrationBroadcastCallback (RegistrationBroadcast);\n\tCNamingClient::setUnregistrationBroadcastCallback (UnregistrationBroadcast);\n}\n\nvoid CNetManager::release ()\n{\n\tif (CNamingClient::connected ())\n\t\tCNamingClient::disconnect ();\n\n\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t{\n\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t{\n\t\t\t(*itbm).second.NetBase[i]->disconnect ();\n\t\t\tdelete (*itbm).second.NetBase[i];\n\t\t}\n\t}\n\t_BaseMap.clear ();\n}\n\nvoid CNetManager::addServer (const std::string &serviceName, uint16 servicePort, bool external)\n{\n\tTServiceId sid;\n\taddServer (serviceName, servicePort, sid, external);\n}\n\nvoid CNetManager::addServer (const std::string &serviceName, uint16 servicePort, TServiceId &sid, bool external)\n{\n\tnldebug (\"HNETL4: Adding server '%s' in CNetManager\", serviceName.c_str ());\n\tItBaseMap itbm = find (serviceName);\n\n\t// check if it's a new server\n\tnlassert ((*itbm).second.NetBase.empty());\n\n\tCCallbackServer *cs = new CCallbackServer( _RecordingState, serviceName+string(\".nmr\") );\n\t(*itbm).second.NetBase.push_back (cs);\n\n\t(*itbm).second.Type = CBaseStruct::Server;\n\n\t// install the server\n\n\tcs->setConnectionCallback (nmNewConnection, (void*) &((*itbm).second));\n\tcs->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));\n\n\tif (servicePort == 0)\n\t{\n\t\tnlassert (CNamingClient::connected ());\n\t\tservicePort = CNamingClient::queryServicePort ();\n\t}\n\n\tcs->init (servicePort);\n\n\t// register the server to the naming service if we are connected to Naming Service\n\n\tif (CNamingClient::connected () && !external)\n\t{\n\t\t//CInetAddress addr = CInetAddress::localHost ();\n\t\t//addr.setPort (servicePort);\n\t\tvector<CInetAddress> addr = CInetAddress::localAddresses();\n\t\tfor (uint i = 0; i < addr.size(); i++)\n\t\t\taddr[i].setPort(servicePort);\n\n\t\tif (sid.get() == 0)\n\t\t{\n\t\t\tCNamingClient::registerService (serviceName, addr, sid);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCNamingClient::registerServiceWithSId (serviceName, addr, sid);\n\t\t}\n\t}\n\tnlinfo (\"HNETL4: Server '%s' added, registered and listen to port %hu\", serviceName.c_str (), servicePort);\n}\n\n\nvoid CNetManager::addClient (const std::string &serviceName, const std::string &addr, bool autoRetry)\n{\n\tnldebug (\"HNETL4: Adding client '%s' with addr '%s' in CNetManager\", serviceName.c_str (), addr.c_str());\n\tItBaseMap itbm = find (serviceName);\n\n\t// it's a new client, add the connection\n\t(*itbm).second.Type = CBaseStruct::ClientWithAddr;\n\t(*itbm).second.AutoRetry = autoRetry;\n\n\tif ((*itbm).second.ServiceNames.empty())\n\t{\n\t\t(*itbm).second.ServiceNames.push_back(addr);\n\t}\n\telse\n\t{\n\t\t(*itbm).second.ServiceNames[0] = addr;\n\t}\n\n\tnlassert ((*itbm).second.NetBase.size() < 2);\n\n\tcreateConnection ((*itbm).second, addr, serviceName);\n}\n\n\nvoid CNetManager::addClient (const std::string &serviceName)\n{\n\tnlassert (CNamingClient::connected ());\n\tnldebug (\"HNETL4: Adding client '%s' in CNetManager\", serviceName.c_str ());\n\tItBaseMap itbm = find (serviceName);\n\n\t// check if it's a new client\n\tnlassert ((*itbm).second.NetBase.empty());\n\n\tCCallbackClient *cc = new CCallbackClient( _RecordingState, serviceName+string(\".nmr\") ); // ? - would not work if several clients with the same name\n\t(*itbm).second.NetBase.push_back (cc);\n\n\t(*itbm).second.Type = CBaseStruct::Client;\n\n\tcc->CCallbackNetBase::setDisconnectionCallback (nmNewDisconnection, (void*) &((*itbm).second));\n\n\t// find the service in the naming_service and connect if exists\n\tif (CNamingClient::lookupAndConnect (serviceName, *cc))\n\t{\n\t\t// call the user that we are connected\n\t\tif ((*itbm).second.ConnectionCallback != NULL)\n\t\t\t(*itbm).second.ConnectionCallback (serviceName, cc->getSockId(), (*itbm).second.ConnectionCbArg);\n\t}\n}\n\n\n\nvoid CNetManager::addGroup (const std::string &groupName, const std::string &serviceName)\n{\n\tnlassert (CNamingClient::connected ());\n\tnldebug (\"HNETL4: Adding '%s' to group '%s' in CNetManager\", serviceName.c_str (), groupName.c_str());\n\tItBaseMap itbm = find (groupName);\n\n\t(*itbm).second.Type = CBaseStruct::Group;\n\n\t// check if you don't already add this service in this group\n\tvector<string>::iterator it = std::find ((*itbm).second.ServiceNames.begin(), (*itbm).second.ServiceNames.end(), serviceName);\n\tnlassert (it == (*itbm).second.ServiceNames.end());\n\n\t(*itbm).second.ServiceNames.push_back(serviceName);\n\n\n\t// find the service in the naming_service and connect if exists\n\tvector<CInetAddress> addrs;\n\tCNamingClient::lookupAll (serviceName, addrs);\n\n\t// connect to all these services\n\tfor (uint i = 0; i < addrs.size (); i++)\n\t{\n\t\tcreateConnection ((*itbm).second, addrs[i], serviceName);\n\t}\n}\n\n\nvoid CNetManager::addCallbackArray (const std::string &serviceName, const TCallbackItem *callbackarray, CStringIdArray::TStringId arraysize)\n{\n\tnldebug (\"HNETL4: addingCallabckArray() for service '%s'\", serviceName.c_str ());\n\tItBaseMap itbm = find (serviceName);\n\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t{\n//\t\tif ((*itbm).second.NetBase[i]->connected())\n\t\t(*itbm).second.NetBase[i]->addCallbackArray (callbackarray, arraysize);\n\t}\n}\n\nvoid CNetManager::update (TTime timeout)\n{\n//\tnldebug (\"HNETL4: update()\");\n\n//\tsint64 p1 = CTime::getPerformanceTime ();\n\n\tTTime t0 = CTime::getLocalTime ();\n\n\tif (timeout > 0)\n\t{\n\t\tif (_NextUpdateTime == 0)\n\t\t{\n\t\t\t_NextUpdateTime = t0 + timeout;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTTime err = t0 - _NextUpdateTime;\n\t\t\t_NextUpdateTime += timeout;\n\n\t\t\t// if we are too late, resync to the next value\n\t\t\twhile (err > timeout)\n\t\t\t{\n\t\t\t\terr -= timeout;\n\t\t\t\t_NextUpdateTime += timeout;\n\t\t\t}\n\n\t\t\ttimeout -= err;\n\t\t\tif (timeout < 0) timeout = 0;\n\t\t}\n\t}\n\n//\tsint64 p2 = CTime::getPerformanceTime ();\n\n\twhile (true)\n\t{\n\t\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t\t{\n\t\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t\t{\n\t\t\t\t// we get and treat all messages in this connection\n\t\t\t\t(*itbm).second.NetBase[i]->update (0);\n\t\t\t\tif ((*itbm).second.NetBase[i]->connected())\n\t\t\t\t{\n\t\t\t\t\t// if connected, update\n//\t\t\t\t\t(*itbm).second.NetBase[i]->update ();\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstatic TTime lastTime = CTime::getLocalTime();\n\t\t\t\t\tif (CTime::getLocalTime() - lastTime > 5000)\n\t\t\t\t\t{\n\t\t\t\t\t\tlastTime = CTime::getLocalTime();\n\n\t\t\t\t\t\t// if not connected, try to connect ClientWithAddr\n\t\t\t\t\t\tif ((*itbm).second.Type == CBaseStruct::ClientWithAddr && (*itbm).second.AutoRetry)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tCCallbackClient *cc = dynamic_cast<CCallbackClient *>((*itbm).second.NetBase[i]);\n\t\t\t\t\t\t\ttry\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnlassert ((*itbm).second.ServiceNames.size()==1);\n\t\t\t\t\t\t\t\tcc->connect (CInetAddress((*itbm).second.ServiceNames[0]));\n\n\t\t\t\t\t\t\t\tif ((*itbm).second.ConnectionCallback != NULL)\n\t\t\t\t\t\t\t\t\t(*itbm).second.ConnectionCallback ((*itbm).second.Name, cc->getSockId(), (*itbm).second.ConnectionCbArg);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcatch (ESocketConnectionFailed &e)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// can't connect now, try later\n\t\t\t\t\t\t\t\tnlinfo(\"HNETL4: can't connect now to %s (reason: %s)\", (*itbm).second.ServiceNames[0].c_str(), e.what());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If it's the end, don't nlSleep()\n\t\tif (CTime::getLocalTime() - t0 > timeout)\n\t\t\tbreak;\n\n\t\t// Enable windows multithreading before rescanning all connections\n\t\t// slow down the layer H_BEFORE (CNetManager_update_nlSleep);\n\t\tnlSleep (1);\n\t\t// slow down the layer H_AFTER (CNetManager_update_nlSleep);\n\t}\n\n//\tsint64 p3 = CTime::getPerformanceTime ();\n\n\tif (CNamingClient::connected ())\n\t\tCNamingClient::update ();\n\n//\tsint64 p4 = CTime::getPerformanceTime ();\n\n//\tnlinfo(\"time : %f %f %f %d\", CTime::ticksToSecond(p2-p1), CTime::ticksToSecond(p3-p2), CTime::ticksToSecond(p4-p3), timeout);\n}\n\n\nvoid CNetManager::send (const std::string &serviceName, const CMessage &buffer, TSockId hostid)\n{\n\tnldebug (\"HNETL4: send for service '%s' message %s to %s\", serviceName.c_str(), buffer.toString().c_str(), hostid->asString().c_str());\n\tItBaseMap itbm = find (serviceName);\n\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t{\n\t\tif ((*itbm).second.NetBase[i]->connected())\n\t\t\t(*itbm).second.NetBase[i]->send (buffer, hostid);\n\t}\n}\n\nCCallbackNetBase *CNetManager::getNetBase (const std::string &serviceName)\n{\n\tItBaseMap itbm = find (serviceName);\n\treturn (*itbm).second.NetBase[0];\n}\n\nvoid CNetManager::setConnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)\n{\n\tnldebug (\"HNETL4: setConnectionCallback() for service '%s'\", serviceName.c_str ());\n\tItBaseMap itbm = find (serviceName);\n\t(*itbm).second.ConnectionCallback = cb;\n\t(*itbm).second.ConnectionCbArg = arg;\n}\n\nvoid CNetManager::setDisconnectionCallback (const std::string &serviceName, TNetManagerCallback cb, void *arg)\n{\n\tnldebug (\"HNETL4: setDisconnectionCallback() for service '%s'\", serviceName.c_str ());\n\tItBaseMap itbm = find (serviceName);\n\t(*itbm).second.DisconnectionCallback = cb;\n\t(*itbm).second.DisconnectionCbArg = arg;\n}\n\n\nCNetManager::ItBaseMap CNetManager::find (const std::string &serviceName)\n{\n\t// find the service or add it if not found\n\tpair<ItBaseMap, bool> p;\n\tp = _BaseMap.insert (make_pair (serviceName, CBaseStruct (serviceName)));\n\treturn p.first;\n}\n\nuint64 CNetManager::getBytesSent ()\n{\n\tuint64 sent = 0;\n\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t{\n\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t{\n\t\t\tsent += (*itbm).second.NetBase[i]->getBytesSent ();\n\t\t}\n\t}\n\treturn sent;\n}\n\nuint64 CNetManager::getBytesReceived ()\n{\n\tuint64 received = 0;\n\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t{\n\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t{\n\t\t\treceived += (*itbm).second.NetBase[i]->getBytesReceived ();\n\t\t}\n\t}\n\treturn received;\n}\n\nuint64 CNetManager::getSendQueueSize ()\n{\n\tuint64 val = 0;\n\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t{\n\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t{\n\t\t\tval += (*itbm).second.NetBase[i]->getSendQueueSize ();\n\t\t}\n\t}\n\treturn val;\n}\n\nuint64 CNetManager::getReceiveQueueSize ()\n{\n\tuint64 val = 0;\n\tfor (ItBaseMap itbm = _BaseMap.begin (); itbm != _BaseMap.end (); itbm++)\n\t{\n\t\tfor (uint32 i = 0; i < (*itbm).second.NetBase.size(); i++)\n\t\t{\n\t\t\tval += (*itbm).second.NetBase[i]->getReceiveQueueSize ();\n\t\t}\n\t}\n\treturn val;\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/service.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n//\n// Includes\n//\n\n#ifdef NL_OS_WINDOWS\n// these defines is for IsDebuggerPresent(). it'll not compile on windows 95\n// just comment this and the IsDebuggerPresent to compile on windows 95\n#\tinclude <direct.h>\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#endif\n\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/mutex.h\"\n#include \"nel/misc/window_displayer.h\"\n#include \"nel/misc/gtk_displayer.h\"\n#include \"nel/misc/win_displayer.h\"\n#include \"nel/misc/path.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n#include \"nel/misc/report.h\"\n#include \"nel/misc/system_info.h\"\n#include \"nel/misc/timeout_assertion_thread.h\"\n\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/service.h\"\n#include \"nel/net/unified_network.h\"\n#include \"nel/net/net_displayer.h\"\n#include \"nel/net/email.h\"\n#include \"nel/net/varpath.h\"\n#include \"nel/net/admin.h\"\n#include \"nel/net/module_manager.h\"\n#include \"nel/net/transport_class.h\"\n\n#include \"stdin_monitor_thread.h\"\n\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET\n{\n\n\n//\n// Constants\n//\n\nstatic const sint Signal[] = {\n  SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM\n};\n\nstatic const char *SignalName[]=\n{\n  \"SIGABRT\", \"SIGFPE\", \"SIGILL\", \"SIGINT\", \"SIGSEGV\", \"SIGTERM\"\n};\n\nstatic const char* NegFiltersNames[] =\n{\n   \"NegFiltersDebug\",\n   \"NegFiltersInfo\",\n   \"NegFiltersWarning\",\n   \"NegFiltersAssert\",\n   \"NegFiltersError\",\n   0\n};\n\n\n//\n// Variables\n//\n\nTUnifiedCallbackItem EmptyCallbackArray[1] = { { \"\", NULL } };\n\n// class static member\nIService\t*IService::_Instance = NULL;\n\nstatic sint ExitSignalAsked = 0;\n\n// services stat\nCVariable<sint32> UserSpeedLoop (\"nel\", \"UserSpeedLoop\", \"duration of the last user loop (in ms)\", 10, false);\nCVariable<sint32> NetSpeedLoop (\"nel\", \"NetSpeedLoop\", \"duration of the last network loop (in ms)\", 10, false);\n/// The time passed in callback during the loop\nCVariable<uint32> L5CallbackTime(\"nel\", \"L5CallbackTime\", \"Time passed in the L5 callback function in the last loop (in ms)\", 0, 100 );\n/// The number of L5 callback treated\nCVariable<uint32> L5CallbackCount(\"nel\", \"L5CallbackCount\", \"The number of layer 5 callback received in the last loop\", 0, 100 );\n\nextern uint32 TotalCallbackCalled;\nextern uint32 TimeInCallback;\nuint32 LastTotalCallbackCalled = 0;\nuint32 LastTimeInCallback = 0;\n\n\n\n// this is the thread that initialized the signal redirection\n// we'll ignore other thread signals\nstatic size_t SignalisedThread;\n\nstatic CFileDisplayer fd;\nstatic CNetDisplayer commandDisplayer(false);\n//static CLog commandLog;\n\nstatic string CompilationDate;\nstatic uint32 LaunchingDate;\n\nstatic uint32 NbUserUpdate = 0;\n\nstring CompilationMode = nlMode;\n\n//static bool Bench = false;\n\nCVariable<bool> Bench (\"nel\", \"Bench\", \"1 if benching 0 if not\", 0, true);\n\n// This produce an assertion in the thread if the update loop is too slow\nstatic CTimeoutAssertionThread\tMyTAT;\nstatic void\t\t\t\t\t\tUpdateAssertionThreadTimeoutCB(IVariable &var) { uint32 timeOut; fromString(var.toString(), timeOut); MyTAT.timeout(timeOut); }\nstatic CVariable<uint32>\t\tUpdateAssertionThreadTimeout(\"nel\", \"UpdateAssertionThreadTimeout\", \"in millisecond, timeout before thread assertion\", 0, 0, true, UpdateAssertionThreadTimeoutCB);\n\n// Flag to enable/disable the flushing of the sending queues when the service is shut down\n// Default: false (matches the former behavior)\n// Set it to true in services that need to send data on exit (for instance in their release() method)\nCVariable<bool>\t\t\t\t\tFlushSendingQueuesOnExit(\"nel\", \"FlushSendingQueuesOnExit\",\n\t\"Flag to enable/disable the flushing of the sending queues when the service is shut down\", false, 0, true );\n\n// If FlushSendingQueuesOnExit is on, only the sending queues to these specified services will be flushed\n// Format: service short names separated by ':'\n// Default: \"\" (all will be flushed if FlushSendingQueuesOnExit is on, none if it is off)\nCVariable<string>\t\t\t\tNamesOfOnlyServiceToFlushSending(\"nel\", \"NamesOfOnlyServiceToFlushSending\",\n\t\"If FlushSendingQueuesOnExit is on, only the sending queues to these specified services will be flushed (ex: \\\"WS:LS\\\"; all will be flushed if empty string)\", \"\", 0, true );\n\n\n//\n// Signals managing\n//\n\n// This function is called when a signal comes\nstatic void sigHandler(int Sig)\n{\n\t// redirect the signal for the next time\n\tsignal(Sig, sigHandler);\n\n\t// find the signal\n\tfor (int i = 0; i < (int)(sizeof(Signal)/sizeof(Signal[0])); i++)\n\t{\n\t\tif (Sig == Signal[i])\n\t\t{\n\t\t\tif (getThreadId () != SignalisedThread)\n\t\t\t{\n\t\t\t\tnldebug (\"SERVICE: Not the main thread (%u, %u) received the signal (%s, %d), ignore it\", getThreadId (), SignalisedThread, SignalName[i],Sig);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnlinfo (\"SERVICE: Signal %s (%d) received\", SignalName[i], Sig);\n\t\t\t\tswitch (Sig)\n\t\t\t\t{\n\t\t\t\t// Note: SIGKILL (9) and SIGSTOP (19) can't be trapped\n\t\t\t\tcase SIGINT  :\n\t\t\t\t  if (IService::getInstance()->haveLongArg(\"nobreak\"))\n\t\t\t\t    {\n\t\t\t\t      // ignore ctrl-c\n\t\t\t\t      nlinfo(\"SERVICE: Ignoring ctrl-c\");\n\t\t\t\t      return;\n\t\t\t\t    }\n\t\t\t\tcase SIGABRT :\n\t\t\t\tcase SIGILL  :\n\t\t\t\tcase SIGSEGV :\n\t\t\t\tcase SIGTERM :\n\t\t\t\t// you should not call a function and system function like printf in a SigHandle because\n\t\t\t\t// signal-handler routines are usually called asynchronously when an interrupt occurs.\n\t\t\t\tif (ExitSignalAsked == 0)\n\t\t\t\t{\n\t\t\t\t\tnlinfo (\"SERVICE: Receive a signal that said that i must exit\");\n\t\t\t\t\tExitSignalAsked = Sig;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnlinfo (\"SERVICE: Signal already received, launch the brutal exit\");\n\t\t\t\t\texit (EXIT_FAILURE);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tnlwarning (\"SERVICE: Unknown signal received (%d)\", Sig);\n}\n\n// Initialise the signal redirection\nstatic void initSignal()\n{\n\tSignalisedThread = getThreadId ();\n#ifdef NL_DEBUG\n\t// in debug mode, we only trap the SIGINT signal (for ctrl-c handling)\n\t//signal(Signal[3], sigHandler);\n\t//nldebug(\"Signal : %s (%d) trapped\", SignalName[3], Signal[3]);\n#else\n\t// in release, redirect all signals\n// don't redirect now because too hard to debug...\n//\tfor (int i = 0; i < (int)(sizeof(Signal)/sizeof(Signal[0])); i++)\n//\t{\n//\t\tsignal(Signal[i], sigHandler);\n//\t\tnldebug(\"Signal %s (%d) trapped\", SignalName[i], Signal[i]);\n//\t}\n//\n\tif (IService::getInstance()->haveLongArg(\"nobreak\"))\n\t{\n\t\tsignal(Signal[3], sigHandler);\n\t}\n#endif\n}\n\nvoid cbDirectoryChanged (IVariable &var)\n{\n\tIService *instance = IService::getInstance();\n\n\t// Convert to full path if required\n\t// (warning: ConvertSavesFilesDirectoryToFullPath, read from the config file, won't be ready for the initial variable assigments done before the config file has been loaded)\n\tstring vp = var.toString();\n\tif ((var.getName() != \"SaveFilesDirectory\") || instance->ConvertSavesFilesDirectoryToFullPath.get())\n\t{\n\t\tvp = CPath::getFullPath(vp);\n\t\tvar.fromString(vp);\n\t}\n\tnlinfo (\"SERVICE: '%s' changed to '%s'\", var.getName().c_str(), vp.c_str());\n\n\t// Update the running directory if needed\n\tif (var.getName() == \"RunningDirectory\")\n\t{\n\t\tCPath::setCurrentPath(vp);\n\t}\n\n\t// Call the callback if provided\n\tif (instance->_DirectoryChangedCBI)\n\t\tinstance->_DirectoryChangedCBI->onVariableChanged(var);\n}\n\n\n//\n// Service built-in callbacks\n//\n\nvoid cbReceiveShardId (CMessage& msgin, const string &serviceName, TServiceId serviceId)\n{\n\tuint32 shardId;\n\tmsgin.serial(shardId);\n\n\tif (IService::getInstance()->getDontUseNS())\n\t{\n\t\t// we don't use NS, so shard ID message don't concern us\n\t\treturn;\n\t}\n\n\tif (serviceName != \"WS\")\n\t{\n\t\tnlwarning(\"SERVICE: received unauthorized R_SH_ID callback from service %s-%uh asking to set ShardId to %d\", serviceName.c_str(), serviceId.get(), shardId);\n\t\treturn;\n\t}\n\n\tnlinfo(\"SERVICE: ShardId is %u\", shardId);\n\tIService::getInstance()->setShardId( shardId );\n}\n\nstd::string IService::getServiceStatusString() const\n{\n\tstatic string emptyString;\n\n\treturn emptyString;\n}\n\n\n//\nvoid IService::anticipateShardId( uint32 shardId )\n{\n\tif ( ! ((_ShardId == DEFAULT_SHARD_ID) || (shardId == _ShardId)) )\n\t\tnlerror( \"IService::anticipateShardId() overwrites %u with %u\", _ShardId, shardId );\n\t_ShardId = shardId;\n}\n\n//\nvoid IService::setShardId( uint32 shardId )\n{\n\tif ( ! ((_ShardId == DEFAULT_SHARD_ID) || (shardId == _ShardId)) )\n\t\tnlwarning( \"SERVICE: The shardId from the WS (%u) is different from the anticipated shardId (%u)\", shardId, _ShardId );\n\t_ShardId = shardId;\n}\n\nTUnifiedCallbackItem builtinServiceCallbacks [] =\n{\n\t{ \"R_SH_ID\", cbReceiveShardId },\n};\n\n\n\n//\n// Class implementation\n//\n\n// Ctor\nIService::IService() :\n\tWindowDisplayer(0),\n\tWriteFilesDirectory(\"nel\", \"WriteFilesDirectory\", \"directory where to save generic shard information (packed_sheets for example)\", \".\", 0, true, cbDirectoryChanged),\n\tSaveFilesDirectory(\"nel\", \"SaveFilesDirectory\", \"directory where to save specific shard information (shard time for example)\", \".\", 0, true, cbDirectoryChanged),\n\tConvertSavesFilesDirectoryToFullPath(\"nel\", \"ConvertSaveFilesDirectoryToFullPath\", \"If true (default), the provided SaveFilesDirectory will be converted to a full path (ex: saves -> /home/dir/saves)\", true, 0, true ),\n\tListeningPort(\"nel\", \"ListeningPort\", \"listening port for this service\", 0, 0, true),\n\t_RecordingState(CCallbackNetBase::Off),\n\t_UpdateTimeout(100),\n\t_SId(0),\n\t_ExitStatus(0),\n\t_Initialized(false),\n\tConfigDirectory(\"nel\", \"ConfigDirectory\", \"directory where config files are\", \".\", 0, true, cbDirectoryChanged),\n\tLogDirectory(\"nel\", \"LogDirectory\", \"directory where the service is logging\", \".\", 0, true, cbDirectoryChanged),\n\tRunningDirectory(\"nel\", \"RunningDirectory\", \"directory where the service is running on\", \".\", 0, true, cbDirectoryChanged),\n\tVersion(\"nel\", \"Version\", \"Version of the shard\", \"\"),\n\t_CallbackArray (0),\n\t_CallbackArraySize (0),\n\t_DontUseNS(false),\n\t_DontUseAES(false),\n\t_ResetMeasures(false),\n\t_ShardId(0),\n\t_ClosureClearanceStatus(CCMustRequestClearance),\n\t_RequestClosureClearanceCallback(NULL),\n\t_DirectoryChangedCBI(NULL)\n{\n\t// Singleton\n\t_Instance = this;\n\n\t// register in the safe singleton registry\n\tINelContext::getInstance().setSingletonPointer(\"IService\", this);\n}\n\nIService::~IService()\n{\n\t// unregister the singleton\n\tINelContext::getInstance().releaseSingletonPointer(\"IService\", this);\n}\n\n\nbool IService::haveArg (char argName) const\n{\n\tfor (uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif (_Args[i].size() >= 2 && _Args[i][0] == '-')\n\t\t{\n\t\t\tif (_Args[i][1] == argName)\n\t\t\t{\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\n\nstring IService::getArg (char argName) const\n{\n\tfor (uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif (_Args[i].size() >= 2 && _Args[i][0] == '-')\n\t\t{\n\t\t\tif (_Args[i][1] == argName)\n\t\t\t{\n\t\t\t\t/* Remove the first and last '\"' :\n\t\t\t\t-c\"C:\\Documents and Settings\\toto.tmp\"\n\t\t\t\twill return :\n\t\t\t\tC:\\Documents and Settings\\toto.tmp\n\t\t\t\t*/\n\t\t\t\tuint begin = 2;\n\t\t\t\tif (_Args[i].size() < 3)\n\t\t\t\t\treturn \"\";\n\t\t\t\t\t//throw Exception (\"Parameter '-%c' is malformed, missing content\", argName);\n\n\t\t\t\tif (_Args[i][begin] == '\"')\n\t\t\t\t\tbegin++;\n\n\t\t\t\t// End\n\t\t\t\tuint size = (uint)_Args[i].size();\n\t\t\t\tif (size && _Args[i][size-1] == '\"')\n\t\t\t\t\tsize--;\n\t\t\t\tsize = (uint)(std::max((int)0, (int)size-(int)begin));\n\t\t\t\treturn _Args[i].substr(begin, size);\n\t\t\t}\n\t\t}\n\t}\n\tthrow Exception (\"Parameter '-%c' is not found in command line\", argName);\n}\n\n\nbool IService::haveLongArg (const char* argName) const\n{\n\tfor (uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif (_Args[i].left(2)==\"--\" && _Args[i].leftCrop(2).splitTo('=')==argName)\n\t\t{\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\nstring IService::getLongArg (const char* argName) const\n{\n\tfor (uint32 i = 0; i < _Args.size(); i++)\n\t{\n\t\tif (_Args[i].left(2)==\"--\" && _Args[i].leftCrop(2).splitTo('=')==argName)\n\t\t{\n\t\t\tNLMISC::CSString val= _Args[i].splitFrom('=');\n\t\t\tif (!val.empty())\n\t\t\t{\n\t\t\t\treturn val.unquoteIfQuoted();\n\t\t\t}\n\t\t\tif (i+1<_Args.size() && _Args[i+1].c_str()[0]!='-')\n\t\t\t{\n\t\t\t\treturn _Args[i+1].unquoteIfQuoted();\n\t\t\t}\n\n\t\t\treturn std::string();\n\t\t}\n\t}\n\treturn std::string();\n}\n\n\nvoid IService::setArgs (const char *args)\n{\n\t_Args.push_back (\"<ProgramName>\");\n\n\tstring sargs (args);\n\tstring::size_type pos1 = 0, pos2 = 0;\n\n\tdo\n\t{\n\t\t// Look for the first non space character\n\t\tpos1 = sargs.find_first_not_of (\" \", pos2);\n\t\tif (pos1 == string::npos) break;\n\n\t\t// Look for the first space or \"\n\t\tpos2 = sargs.find_first_of (\" \\\"\", pos1);\n\t\tif (pos2 != string::npos)\n\t\t{\n\t\t\t// \" ?\n\t\t\tif (sargs[pos2] == '\"')\n\t\t\t{\n\t\t\t\t// Look for the final \\\"\n\t\t\t\tpos2 = sargs.find_first_of (\"\\\"\", pos2+1);\n\t\t\t\tif (pos2 != string::npos)\n\t\t\t\t{\n\t\t\t\t\t// Look for the first space\n\t\t\t\t\tpos2 = sargs.find_first_of (\" \", pos2+1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Compute the size of the string to extract\n\t\tstring::difference_type length = (pos2 != string::npos) ? pos2-pos1 : string::npos;\n\n\t\tstring tmp = sargs.substr (pos1, length);\n\t\t_Args.push_back (tmp);\n\t}\n\twhile (pos2 != string::npos);\n}\n\nvoid IService::setArgs (int argc, const char **argv)\n{\n\tfor (sint i = 0; i < argc; i++)\n\t{\n\t\t_Args.push_back (argv[i]);\n\t}\n}\n\n\nvoid cbLogFilter (CConfigFile::CVar &var)\n{\n\tCLog *log = NULL;\n\tif (var.Name == \"NegFiltersDebug\")\n\t{\n\t\tlog = DebugLog;\n\t}\n\telse if (var.Name == \"NegFiltersInfo\")\n\t{\n\t\tlog = InfoLog;\n\t}\n\telse if (var.Name == \"NegFiltersWarning\")\n\t{\n\t\tlog = WarningLog;\n\t}\n\telse if (var.Name == \"NegFiltersAssert\")\n\t{\n\t\tlog = AssertLog;\n\t}\n\telse if (var.Name == \"NegFiltersError\")\n\t{\n\t\tlog = ErrorLog;\n\t}\n\telse\n\t{\n\t\tnlstop;\n\t}\n\n\tnlinfo (\"SERVICE: Updating %s from config file\", var.Name.c_str());\n\n\t// remove all old filters from config file\n\tCConfigFile::CVar &oldvar = IService::getInstance()->ConfigFile.getVar (var.Name);\n\tfor (uint j = 0; j < oldvar.size(); j++)\n\t{\n\t\tlog->removeFilter (oldvar.asString(j).c_str());\n\t}\n\n\t// add all new filters from config file\n\tfor (uint i = 0; i < var.size(); i++)\n\t{\n\t\tlog->addNegativeFilter (var.asString(i).c_str());\n\t}\n}\n\nvoid cbExecuteCommands (CConfigFile::CVar &var)\n{\n\tfor (uint i = 0; i < var.size(); i++)\n\t{\n\t\tICommand::execute (var.asString(i), IService::getInstance()->CommandLog);\n\t}\n}\n\n\n\n//\n// The main function of the service\n//\n\nsint IService::main (const char *serviceShortName, const char *serviceLongName, uint16 servicePort, const char *configDir, const char *logDir, const char *compilationDate)\n{\n\tbool userInitCalled = false;\n\tCConfigFile::CVar *var = NULL;\n\n\tIThread *timeoutThread = NULL;\n\n\t// a short name service can't be a number\n\tuint tmp;\n\tnlassert (!fromString(serviceShortName, tmp));\n\n\ttry\n\t{\n\t\tcreateDebug();\n\t\t// init the module manager\n\t\tIModuleManager::getInstance();\n\t\t//\n\t\t// Init parameters\n\t\t//\n\n\t\t// at the very beginning, eventually wrote a file with the pid\n\t\tif (haveLongArg(\"writepid\"))\n\t\t{\n\t\t\t// use legacy C primitives\n\t\t\tFILE *fp = fopen(\"pid.state\", \"wt\");\n\t\t\tif (fp)\n\t\t\t{\n\t\t\t\tfprintf(fp, \"%u\", getpid());\n\t\t\t\tfclose(fp);\n\t\t\t}\n\t\t}\n\n\t\t_ShortName = serviceShortName;\n\t\tCLog::setProcessName (_ShortName);\n\n\t\t// get the path where to run the service if any in the command line\n\t\tif (haveArg('A'))\n\t\t\tRunningDirectory = CPath::standardizePath(getArg('A'));\n\n\t\tConfigDirectory = CPath::standardizePath(configDir);\n\t\tLogDirectory = CPath::standardizePath(logDir);\n\t\t_LongName = serviceLongName;\n\n\t\tCompilationDate = compilationDate;\n\n\t\tLaunchingDate = CTime::getSecondsSince1970();\n\n\t\tListeningPort = servicePort;\n\n\t\tsetReportEmailFunction ((void*)sendEmail);\n\t\t// setDefaultEmailParams (\"gw.nevrax.com\", \"\", \"cado@nevrax.com\");\n\n\n\t\t//\n\t\t// Load the config file\n\t\t//\n\n\t\t// get the config file dir if any in the command line\n\t\tif (haveArg('C'))\n\t\t\tConfigDirectory = CPath::standardizePath(getArg('C'));\n\n\t\tstring cfn = ConfigDirectory.c_str() + _LongName + \".cfg\";\n\t\tif (!CFile::fileExists(ConfigDirectory.c_str() + _LongName + \".cfg\"))\n\t\t{\n\t\t\t// check if the default exists\n\t\t\tif (!CFile::fileExists(ConfigDirectory.c_str() + _LongName + \"_default.cfg\"))\n\t\t\t{\n\t\t\t\tnlerror (\"SERVICE: Neither the config file '%s' nor the default one can be found, can't launch the service\", cfn.c_str());\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// create the basic .cfg that link the default one\n\t\t\t\tFILE *fp = fopen (cfn.c_str(), \"w\");\n\t\t\t\tif (fp == NULL)\n\t\t\t\t{\n\t\t\t\t\tnlerror (\"SERVICE: Can't create config file '%s'\", cfn.c_str());\n\t\t\t\t}\n\t\t\t\tfprintf(fp, \"// link the default config file for %s\\n\", _LongName.c_str());\n\t\t\t\tfprintf(fp, \"RootConfigFilename = \\\"%s_default.cfg\\\";\\n\", _LongName.c_str());\n\t\t\t\tfclose (fp);\n\t\t\t}\n\t\t}\n\n\t\tConfigFile.load (cfn);\n\n\t\t// setup variable with config file variable\n\t\tIVariable::init (ConfigFile);\n\n\t\tif (ConfigFile.exists(\"DefaultEmailSMTP\") && ConfigFile.exists(\"DefaultEmailTo\"))\n\t\t\tNLNET::setDefaultEmailParams(\n\t\t\t\tConfigFile.getVar(\"DefaultEmailSMTP\").asString(),\n\t\t\t\tConfigFile.exists(\"DefaultEmailFrom\")\n\t\t\t\t? ConfigFile.getVar(\"DefaultEmailFrom\").asString()\n\t\t\t\t: \"service@opennel.org\",\n\t\t\t\tConfigFile.getVar(\"DefaultEmailTo\").asString());\n\n\t\t//\n\t\t// Set the shard Id\n\t\t//\n\n\t\tif ((var = ConfigFile.getVarPtr(\"NoWSShardId\")) != NULL)\n\t\t{\n\t\t\t_ShardId = var->asInt();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// something high enough as default\n\t\t\t_ShardId = DEFAULT_SHARD_ID;\n\t\t}\n\n\t\tif (haveArg('Z'))\n\t\t{\n\t\t\tstring s = IService::getInstance()->getArg('Z');\n\t\t\tif (s == \"u\")\n\t\t\t{\n\t\t\t\t// do not release the module manager\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// release the module manager\n\t\t\t\tIModuleManager::getInstance().releaseInstance();\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\t// we have to call this again because the config file can changed this variable but the cmd line is more prioritary\n\t\tif (haveArg('A'))\n\t\t\tRunningDirectory = CPath::standardizePath(getArg('A'));\n\n\n        // set the aes aliasname if present in cfg file\n        CConfigFile::CVar *varAliasName= ConfigFile.getVarPtr(\"AESAliasName\");\n        if (varAliasName != NULL)\n        {\n            _AliasName = varAliasName->asString();\n            nlinfo(\"SERVICE: Setting alias name to: '%s'\",_AliasName.c_str());\n        }\n\n        // set the aes aliasname if is present in the command line\n        if (haveArg('N'))\n        {\n            _AliasName = getArg('N');\n            nlinfo(\"SERVICE: Setting alias name to: '%s'\",_AliasName.c_str());\n        }\n\n\n\t\t//\n\t\t// Init debug/log stuffs (must be first things otherwise we can't log if errors)\n\t\t//\n\n\t\t// get the log dir if any in the command line\n\t\tif (haveArg('L'))\n\t\t\tLogDirectory = CPath::standardizePath(getArg('L'));\n\n\t\tchangeLogDirectory (LogDirectory);\n\n\t\tbool noLog= (ConfigFile.exists (\"DontLog\")) && (ConfigFile.getVar(\"DontLog\").asInt() == 1);\n\t\t//noLog|=haveLongArg(\"nolog\");\n\t\tif (!noLog)\n\t\t{\n\t\t\t// we create the log with service name filename (\"test_service_ALIAS.log\" for example)\n\t\t\tstring logname = LogDirectory.toString() + _LongName;\n            if (!_AliasName.empty())\n            {\n                logname += \"_\" + _AliasName;\n            }\n\t\t\t//if (haveArg('N'))\n\t\t\t//\tlogname += \"_\" + toLower(getArg('N'));\n\n\t\t\tlogname += \".log\";\n\t\t\tfd.setParam (logname, false);\n\n\t\t\tDebugLog->addDisplayer (&fd);\n\t\t\tInfoLog->addDisplayer (&fd);\n\t\t\tWarningLog->addDisplayer (&fd);\n\t\t\tAssertLog->addDisplayer (&fd);\n\t\t\tErrorLog->addDisplayer (&fd);\n\t\t\tCommandLog.addDisplayer (&fd, true);\n\t\t}\n\n\t\tbool dontUseStdIn= (ConfigFile.exists (\"DontUseStdIn\")) && (ConfigFile.getVar(\"DontUseStdIn\").asInt() == 1);\n\t\tif (!dontUseStdIn)\n\t\t{\n\t\t\tIStdinMonitorSingleton::getInstance()->init();\n\t\t}\n\n\t\t//\n\t\t// Init the hierarchical timer\n\t\t//\n\n\t\tCHTimer::startBench(false, true);\n\t\tCHTimer::endBench();\n\n\t\t//\n\t\t// Set the assert mode\n\t\t//\n\n\t\tif (ConfigFile.exists (\"Assert\"))\n\t\t\tsetAssert (ConfigFile.getVar(\"Assert\").asInt() == 1);\n\n\t\t//\n\t\t// Set the update timeout if found in the cfg\n\t\t//\n\t\tif ((var = ConfigFile.getVarPtr(\"UpdateTimeout\")) != NULL)\n\t\t{\n\t\t\t_UpdateTimeout = var->asInt();\n\t\t}\n\n\t\t//\n\t\t// Set the negative filter from the config file\n\t\t//\n\n\t\tfor(const char **name = NegFiltersNames; *name; name++)\n\t\t{\n\t\t\tif ((var = ConfigFile.getVarPtr (*name)) != NULL)\n\t\t\t{\n\t\t\t\tConfigFile.setCallback (*name, cbLogFilter);\n\t\t\t\tcbLogFilter(*var);\n\t\t\t}\n\t\t}\n\n\t\tConfigFile.setCallback (\"Commands\", cbExecuteCommands);\n\t\tif ((var = ConfigFile.getVarPtr (\"Commands\")) != NULL)\n\t\t{\n\t\t\tcbExecuteCommands(*var);\n\t\t}\n\n\t\t//\n\t\t// Command line start\n\t\t//\n\t\tcommandStart ();\n\n\t\t//\n\t\t// Create the window if needed\n\t\t//\n\n\t\tif ((var = ConfigFile.getVarPtr (\"WindowStyle\")) != NULL)\n\t\t{\n\t\t\tstring disp = var->asString ();\n#ifdef NL_USE_GTK\n\t\t\tif (disp == \"GTK\")\n\t\t\t{\n\t\t\t\tWindowDisplayer = new CGtkDisplayer (\"DEFAULT_WD\");\n\t\t\t}\n#endif // NL_USE_GTK\n\n#ifdef NL_OS_WINDOWS\n\t\t\tif (disp == \"WIN\")\n\t\t\t{\n\t\t\t\tWindowDisplayer = new CWinDisplayer (\"DEFAULT_WD\");\n\t\t\t}\n#endif // NL_OS_WINDOWS\n\n\t\t\tif (WindowDisplayer == NULL && disp != \"NONE\")\n\t\t\t{\n\t\t\t\tnlinfo (\"SERVICE: Unknown value for the WindowStyle (should be GTK, WIN or NONE), use no window displayer\");\n\t\t\t}\n\t\t}\n\n\t\tvector <pair<string,uint> > displayedVariables;\n\t\t//uint speedNetLabel, speedUsrLabel, rcvLabel, sndLabel, rcvQLabel, sndQLabel, scrollLabel;\n\t\tif (WindowDisplayer != NULL)\n\t\t{\n\t\t\t//\n\t\t\t// Init window param if necessary\n\t\t\t//\n\n\t\t\tsint x=-1, y=-1, w=-1, h=-1, fs=10, history=-1;\n\t\t\tbool iconified = false, ww = false;\n\t\t\tstring fn;\n\n\t\t\tif ((var = ConfigFile.getVarPtr(\"XWinParam\")) != NULL) x = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"YWinParam\")) != NULL) y = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"WWinParam\")) != NULL) w = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"HWinParam\")) != NULL) h = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"HistoryWinParam\")) != NULL) history = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"IWinParam\")) != NULL) iconified = var->asInt() == 1;\n\t\t\tif ((var = ConfigFile.getVarPtr(\"FontSize\")) != NULL) fs = var->asInt();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"FontName\")) != NULL) fn = var->asString();\n\t\t\tif ((var = ConfigFile.getVarPtr(\"WordWrap\")) != NULL) ww = var->asInt() == 1;\n\n\t\t\tif (haveArg('I')) iconified = true;\n\n\t\t\tWindowDisplayer->create (string(\"*INIT* \") + _ShortName + \" \" + _LongName, iconified, x, y, w, h, history, fs, fn, ww, &CommandLog);\n\n\t\t\tDebugLog->addDisplayer (WindowDisplayer);\n\t\t\tInfoLog->addDisplayer (WindowDisplayer);\n\t\t\tWarningLog->addDisplayer (WindowDisplayer);\n\t\t\tErrorLog->addDisplayer (WindowDisplayer);\n\t\t\tAssertLog->addDisplayer (WindowDisplayer);\n\t\t\tCommandLog.addDisplayer(WindowDisplayer, true);\n\n\t\t\t// adding default displayed variables\n\t\t\tdisplayedVariables.push_back(make_pair(string(\"NetLop|NetSpeedLoop\"), WindowDisplayer->createLabel (\"NetLop\")));\n\t\t\tdisplayedVariables.push_back(make_pair(string(\"UsrLop|UserSpeedLoop\"), WindowDisplayer->createLabel (\"UsrLop\")));\n\t\t\tdisplayedVariables.push_back(make_pair(string(\"|Scroller\"), WindowDisplayer->createLabel (\"NeL Rulez\")));\n\n\t\t\tCConfigFile::CVar *v = ConfigFile.getVarPtr(\"DisplayedVariables\");\n\t\t\tif (v != NULL)\n\t\t\t{\n\t\t\t\tfor (uint i = 0; i < v->size(); i++)\n\t\t\t\t{\n\t\t\t\t\tdisplayedVariables.push_back(make_pair(v->asString(i), WindowDisplayer->createLabel (v->asString(i).c_str())));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnlinfo (\"SERVICE: Starting Service '%s' using NeL (\" __DATE__ \" \" __TIME__ \") compiled %s\", _ShortName.c_str(), CompilationDate.c_str());\n\t\tnlinfo (\"SERVICE: On OS: %s\", CSystemInfo::getOS().c_str());\n\n\t\tsetExitStatus (EXIT_SUCCESS);\n\n\t\t//\n\t\t// Redirect signal if needed (in release mode only)\n\t\t//\n\n#ifdef NL_OS_WINDOWS\n#\tifdef NL_NO_DEBUG\n\t\tinitSignal();\n#\telse\n\t\t// don't install signal is the application is started in debug mode\n\t\tif (IsDebuggerPresent ())\n\t\t{\n\t\t\t//nlinfo(\"Running with the debugger, don't redirect signals\");\n\t\t\tinitSignal();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//nlinfo(\"Running without the debugger, redirect SIGINT signal\");\n\t\t\tinitSignal();\n\t\t}\n#\tendif\n#else // NL_OS_UNIX\n\t\tinitSignal();\n#endif\n\n\n\t\t//\n\t\t// Ignore SIGPIPE (broken pipe) on unix system\n\t\t//\n\n#ifdef NL_OS_UNIX\n\t\t// Ignore the SIGPIPE signal\n\t\tsigset_t SigList;\n\t\tbool IgnoredPipe = true;\n\t\tif (sigemptyset (&SigList) == -1)\n\t\t{\n\t\t\tperror(\"sigemptyset()\");\n\t\t\tIgnoredPipe = false;\n\t\t}\n\n\t\tif (sigaddset (&SigList, SIGPIPE) == -1)\n\t\t{\n\t\t\tperror(\"sigaddset()\");\n\t\t\tIgnoredPipe = false;\n\t\t}\n\n\t\tif (sigprocmask (SIG_BLOCK, &SigList, NULL) == -1)\n\t\t{\n\t\t\tperror(\"sigprocmask()\");\n\t\t\tIgnoredPipe = false;\n\t\t}\n\t\tnldebug (\"SERVICE: SIGPIPE %s\", IgnoredPipe?\"Ignored\":\"Not Ignored\");\n#endif // NL_OS_UNIX\n\n\n\t\t//\n\t\t// Initialize the network system\n\t\t//\n\n\t\tstring localhost;\n\t\ttry\n\t\t{\n\t\t\t// Initialize WSAStartup and network stuffs\n\t\t\tCSock::initNetwork();\n\n\t\t\t// Get the localhost name\n\t\t\tlocalhost = CInetAddress::localHost().hostName();\n\t\t}\n\t\tcatch (const NLNET::ESocket &)\n\t\t{\n\t\t\tlocalhost = \"<UnknownHost>\";\n\t\t}\n\n\t\t// Set the localhost name and service name to the logger\n\t\tCLog::setProcessName (localhost+\"/\"+_ShortName);\n\t\tnlinfo (\"SERVICE: Host: %s\", localhost.c_str());\n\n\t\t//\n\t\t// Initialize server parameters\n\t\t//\n\n\t\t// set the listen port if there are a port arg in the command line\n\t\tif (haveArg('P'))\n\t\t{\n\t\t\tNLMISC::fromString(getArg('P'), ListeningPort);\n\t\t}\n\n\t\t// Load the recording state from the config file\n\t\tif ((var = ConfigFile.getVarPtr (\"Rec\")) != NULL)\n\t\t{\n\t\t\tstring srecstate = toUpper(var->asString());\n\t\t\tif ( srecstate == \"RECORD\" )\n\t\t\t{\n\t\t\t\t_RecordingState = CCallbackNetBase::Record;\n\t\t\t\tnlinfo( \"SERVICE: Service recording messages\" );\n\t\t\t}\n\t\t\telse if ( srecstate == \"REPLAY\" )\n\t\t\t{\n\t\t\t\t_RecordingState = CCallbackNetBase::Replay;\n\t\t\t\tnlinfo( \"SERVICE: Service replaying messages\" );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_RecordingState = CCallbackNetBase::Off;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Not found\n\t\t\t_RecordingState = CCallbackNetBase::Off;\n\t\t}\n\n\t\t// Load the default stream format\n\t\tif ((var = ConfigFile.getVarPtr (\"StringMsgFormat\")) != NULL)\n\t\t{\n\t\t\tCMessage::setDefaultStringMode( var->asInt() == 1 );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Not found => binary\n\t\t\tCMessage::setDefaultStringMode( false );\n\t\t}\n\n\n\t\t///\n\t\t/// Layer5 Startup\n\t\t///\n\n\t\t// get the sid\n\t\tif ((var = ConfigFile.getVarPtr (\"SId\")) != NULL)\n\t\t{\n\t\t\tsint32 sid = var->asInt();\n\t\t\tif (sid<=0 || sid>255)\n\t\t\t{\n\t\t\t\tnlwarning(\"SERVICE: Bad SId value in the config file, %d is not in [0;255] range\", sid);\n\t\t\t\t_SId.set(0);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_SId.set(static_cast<uint16>(sid));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// ok, SId not found, use dynamic sid\n\t\t\t_SId.set(0);\n\t\t}\n\n\n\t\t// look if we don't want to use NS\n\t\tif ((var = ConfigFile.getVarPtr (\"DontUseNS\")) != NULL)\n\t\t{\n\t\t\t// if we set the value in the config file, get it\n\t\t\t_DontUseNS = (var->asInt() == 1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// if not, we use ns only if service is not ns, ls, aes, as\n\t\t\t_DontUseNS = false;\n\t\t}\n\t\tif (haveLongArg(\"nons\"))\n\t\t{\n\t\t\t// command line override\n\t\t\t_DontUseNS = true;\n\t\t}\n\n\t\t//\n\t\t// Register all network associations (must be before the CUnifiedNetwork::getInstance()->init)\n\t\t//\n\n\t\tif ((var = ConfigFile.getVarPtr (\"Networks\")) != NULL)\n\t\t{\n\t\t\tfor (uint8 i = 0; i < var->size (); i++)\n\t\t\t\tCUnifiedNetwork::getInstance()->addNetworkAssociation (var->asString(i), i);\n\t\t}\n\n\t\tif ((var = ConfigFile.getVarPtr (\"DefaultNetworks\")) != NULL)\n\t\t{\n\t\t\tfor (uint8 i = 0; i < var->size (); i++)\n\t\t\t\tCUnifiedNetwork::getInstance()->addDefaultNetwork(var->asString(i));\n\t\t}\n\n\t\t// normal setup for the common services\n\t\tif (!_DontUseNS)\n\t\t{\n\t\t\tbool ok = false;\n\t\t\twhile (!ok)\n\t\t\t{\n\t\t\t\tstring LSAddr;\n\n\t\t\t\tif (haveArg('B'))\n\t\t\t\t{\n\t\t\t\t\t// if the naming service address is set on the command line, get it (overwrite the cfg)\n\t\t\t\t\tLSAddr = getArg('B');\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// else read the naming service address from the config file\n\t\t\t\t\tLSAddr = ConfigFile.getVar (\"NSHost\").asString();\n\t\t\t\t}\n\n\t\t\t\t// if there's no port to the NS, use the default one 50000\n\t\t\t\tif (LSAddr.find(\":\") == string::npos)\n\t\t\t\t\tLSAddr += \":50000\";\n\n\t\t\t\tCInetAddress loc(LSAddr);\n\t\t\t\ttry\n\t\t\t\t{\n\t\t\t\t\t// todo: check if app not closed by user, or you get stuck here\n\n\t\t\t\t\tif ( CUnifiedNetwork::getInstance()->init (&loc, _RecordingState, _ShortName, ListeningPort, _SId) )\n\t\t\t\t\t{\n\t\t\t\t\t\tok = true;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnlinfo( \"SERVICE: Exiting...\" );\n\t\t\t\t\t\tbeep( 880, 400 );\n\t\t\t\t\t\tbeep( 440, 400 );\n\t\t\t\t\t\tbeep( 220, 400 );\n\n\t\t\t\t\t\t// remove the stdin monitor thread\n\t\t\t\t\t\tIStdinMonitorSingleton::getInstance()->release(); // does nothing if not initialized\n\n\t\t\t\t\t\t// release the module manager\n\t\t\t\t\t\tIModuleManager::getInstance().releaseInstance();\n\n\t\t\t\t\t\treturn 10;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch (const ESocketConnectionFailed &)\n\t\t\t\t{\n\t\t\t\t\tnlinfo (\"SERVICE: Could not connect to the Naming Service (%s). Retrying in a few seconds...\", loc.asString().c_str());\n\t\t\t\t\tnlSleep (5000);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCUnifiedNetwork::getInstance()->init(NULL, _RecordingState, _ShortName, ListeningPort, _SId);\n\t\t}\n\n\t\t// get the hostname for later use\n\t\t_HostName = CInetAddress::localHost().hostName();\n\n\t\t// At this point, the _SId must be ok if we use the naming service.\n\t\t// If it's 0, it means that we don't use NS and we left the other side server to find a sid for your connection\n\n\t\tif(!_DontUseNS)\n\t\t{\n\t\t\tnlassert (_SId.get() != 0);\n\t\t}\n\n\t\t//\n\t\t// Connect to the local AES and send identification\n\t\t//\n\n\t\t// look if we don't want to use NS\n\t\tif ((var = ConfigFile.getVarPtr (\"DontUseAES\")) != NULL)\n\t\t{\n\t\t\t// if we set the value in the config file, get it\n\t\t\t_DontUseAES = var->asInt() == 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// if not, we use aes only if service is not aes or as\n\t\t\t_DontUseAES = false;\n\t\t}\n\n\t\tinitAdmin (_DontUseAES);\n\n\t\twhile (NLNET::CUnifiedNetwork::getInstance()->tryFlushAllQueues() != 0)\n\t\t{\n\t\t\tnlSleep(10);\n\t\t}\n\n\t\t//\n\t\t// Add callback array\n\t\t//\n\n\t\t// add inner service callback array\n\t\tNLNET::CUnifiedNetwork::getInstance()->addCallbackArray(builtinServiceCallbacks, sizeof(builtinServiceCallbacks)/sizeof(builtinServiceCallbacks[0]));\n\n\t\t// add callback set in the NLNET_SERVICE_MAIN macro\n\t\tNLNET::CUnifiedNetwork::getInstance()->addCallbackArray(_CallbackArray, _CallbackArraySize);\n\n\t\t//\n\t\t// Now we have the service id, we can set the entites id generator\n\t\t//\n\n\t\tNLMISC::CEntityId::setServiceId(TServiceId8(_SId).get());\n\n\t\t// Set the localhost name and service name and the sid\n\t\tCLog::setProcessName (localhost+\"/\"+_ShortName+\"-\"+toString(_SId.get()));\n\n\n\t\t//\n\t\t// Add default pathes\n\t\t//\n\n\t\tif ((var = ConfigFile.getVarPtr (\"IgnoredFiles\")) != NULL)\n\t\t{\n\t\t\tfor (uint i = 0; i < var->size(); i++)\n\t\t\t{\n\t\t\t\tCPath::addIgnoredDoubleFile (var->asString(i));\n\t\t\t}\n\t\t}\n\n\t\tif ((var = ConfigFile.getVarPtr (\"Paths\")) != NULL)\n\t\t{\n\t\t\tfor (uint i = 0; i < var->size(); i++)\n\t\t\t{\n\t\t\t\tCPath::addSearchPath (var->asString(i), true, false);\n\t\t\t}\n\t\t}\n\n\t\tif ((var = ConfigFile.getVarPtr (\"PathsNoRecurse\")) != NULL)\n\t\t{\n\t\t\tfor (uint i = 0; i < var->size(); i++)\n\t\t\t{\n\t\t\t\tCPath::addSearchPath (var->asString(i), false, false);\n\t\t\t}\n\t\t}\n\n\t\t// if we can, try to setup where to save files\n\t\tif (IService::getInstance()->haveArg('W'))\n\t\t{\n\t\t\t// use the command line param if set (must be done after the config file has been loaded)\n\t\t\tSaveFilesDirectory = IService::getInstance()->getArg('W');\n\t\t}\n\n\t\tCTransportClass::init();\n\n\t\t//\n\t\t// Call the user service init\n\t\t//\n\n\t\tuserInitCalled = true; // the bool must be put *before* the call to init()\n\n\t\tsetCurrentStatus(\"Initializing\");\n\t\tinit ();\n\t\tclearCurrentStatus(\"Initializing\");\n\n\n\t\t//\n\t\t// Connects to the present services\n\t\t// WARNING: only after the user init() was called because the\n\t\t// addService may call up service callbacks.\n\t\t//\n\n\t\tCUnifiedNetwork::getInstance()->connect();\n\n\t\t//\n\t\t// Say to the AES that the service is ready\n\t\t//\n\n\t\tif (!_DontUseAES)\n\t\t{\n\t\t\t// send the ready message (service init finished)\n\t\t\tCMessage msgout (\"SR\");\n\t\t\tCUnifiedNetwork::getInstance()->send(\"AES\", msgout);\n\t\t}\n\n\n\t\t_Initialized = true;\n\n\t\tnlinfo (\"SERVICE: Service initialized, executing StartCommands\");\n\n\t\t//\n\t\t// Call the user command from the config file if any\n\t\t//\n\t\tstring cmdRoot(\"StartCommands\");\n\t\tvector<string>\tposts;\n\n\t\t// add an empty string (for the common part of start commands)\n\t\tposts.push_back(string());\n\n\t\tif (IService::getInstance()->haveArg('S'))\n\t\t{\n\t\t\tstring s = IService::getInstance()->getArg('S');\n\t\t\tposts.push_back(s);\n\t\t}\n\n\t\tCConfigFile::CVar *var;\n\t\tfor (uint i=0; i<posts.size(); ++i)\n\t\t{\n\t\t\tstring varName = cmdRoot + posts[i];\n\t\t\tif ((var = IService::getInstance()->ConfigFile.getVarPtr (varName)) != NULL)\n\t\t\t{\n\t\t\t\tfor (uint i = 0; i < var->size(); i++)\n\t\t\t\t{\n\t\t\t\t\tICommand::execute (var->asString(i), CommandLog);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstring str;\n\t\tCLog logDisplayVars;\n\t\tCLightMemDisplayer mdDisplayVars;\n\t\tlogDisplayVars.addDisplayer (&mdDisplayVars);\n\n\t\t//\n\t\t// Activate the timeout assertion thread\n\t\t//\n\n\t\ttimeoutThread = IThread::create(&MyTAT, 1024*4*4);\n\t\ttimeoutThread->start();\n\n\t\t//\n\t\t// Set service ready\n\t\t//\n\n\t\tnlinfo (\"SERVICE: Service ready\");\n\n\t\tif (WindowDisplayer != NULL)\n\t\t\tWindowDisplayer->setTitleBar (_ShortName + \" \" + _LongName + \" \" + Version.c_str());\n\n\t\t//\n\t\t// Call the user service update each loop and check files and network activity\n\t\t//\n\n\t\tTTime\tcheckCpuProcTime = 0;\n\n\t\tfor(;;)\n\t\t{\n\t\t\tMyTAT.activate();\n\n\t\t\tif(Bench) CHTimer::startBench(false, true, false);\n\n\t\t\t// count the amount of time to manage internal system\n\t\t\tTTime bbefore = CTime::getLocalTime ();\n\n\t\t\t// every second, check for CPU usage\n\t\t\tif (bbefore - checkCpuProcTime > 1000)\n\t\t\t{\n\t\t\t\tcheckCpuProcTime = bbefore;\n\t\t\t\t_CPUUsageStats.peekMeasures();\n\t\t\t}\n\n\t\t\t// call the user update and exit if the user update asks it\n\t\t\t{\n\t\t\t\tH_AUTO(NLNETServiceUpdate);\n\t\t\t\tif (!update ())\n\t\t\t\t{\n\t\t\t\t\tCHTimer::endBench();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// deal with any input waiting from stdin\n\t\t\t{\n\t\t\t\tH_AUTO(NLNETStdinMonitorUpdate);\n\t\t\t\tIStdinMonitorSingleton::getInstance()->update();\n\t\t\t}\n\n\t\t\t// if the launching mode is 'quit after the first update' we set the exit signal\n\t\t\tif (haveArg('Q'))\n\t\t\t{\n\t\t\t\t// we use -100 so that the final return code ends as 0 (100+ExitSignalAsked) because\n\t\t\t\t// otherwise we can't launch services with -Q in a makefile\n\t\t\t\tExitSignalAsked = -100;\n\t\t\t}\n\t\t\tNbUserUpdate++;\n\n\t\t\t// count the amount of time to manage internal system\n\t\t\tTTime before = CTime::getLocalTime ();\n\n\t\t\tif (WindowDisplayer != NULL)\n\t\t\t{\n\t\t\t\t// update the window displayer and quit if asked\n\t\t\t\tif (!WindowDisplayer->update ())\n\t\t\t\t{\n\t\t\t\t\tnlinfo (\"SERVICE: The window displayer was closed by user, need to quit\");\n\t\t\t\t\tExitSignalAsked = 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// stop the loop if the exit signal asked\n\t\t\tif (ExitSignalAsked != 0)\n\t\t\t{\n\t\t\t\tif ( _RequestClosureClearanceCallback )\n\t\t\t\t{\n\t\t\t\t\tif ( _ClosureClearanceStatus == CCClearedForClosure )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Clearance has been granted\n\t\t\t\t\t\tCHTimer::endBench();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( _ClosureClearanceStatus == CCMustRequestClearance )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( _RequestClosureClearanceCallback() )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Direct clearance\n\t\t\t\t\t\t\t_ClosureClearanceStatus = CCClearedForClosure;\n\t\t\t\t\t\t\tCHTimer::endBench();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Delayed clearance\n\t\t\t\t\t\t\t_ClosureClearanceStatus = CCWaitingForClearance;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if ( _ClosureClearanceStatus >= CCCallbackThenClose )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Always direct closure, because we don't have a connection to the naming service anymore\n\t\t\t\t\t\t// But still call the callback\n\t\t\t\t\t\t_RequestClosureClearanceCallback();\n\t\t\t\t\t\tCHTimer::endBench();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Immediate closure, no clearance needed\n\t\t\t\t\tCHTimer::endBench();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCConfigFile::checkConfigFiles ();\n\n\t\t\tupdateAdmin ();\n\n\t\t\tCFile::checkFileChange();\n\n\t\t\t// update updatable interface\n\t\t\tset<IServiceUpdatable*>::iterator first(_Updatables.begin()), last(_Updatables.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tIServiceUpdatable *updatable = *first;\n\t\t\t\tupdatable->serviceLoopUpdate();\n\t\t\t}\n\n\t\t\t// get and manage layer 5 messages\n\t\t\tCUnifiedNetwork::getInstance()->update (_UpdateTimeout);\n\n\n\t\t\t// update modules\n\t\t\tIModuleManager::getInstance().updateModules();\n\n\n\t\t\t// Allow direct closure if the naming service was lost\n\t\t\tif ( _RequestClosureClearanceCallback )\n\t\t\t{\n\t\t\t\tif ( ! CNamingClient::connected() )\n\t\t\t\t{\n\t\t\t\t\tif ( _ClosureClearanceStatus < CCCallbackThenClose )\n\t\t\t\t\t\t_ClosureClearanceStatus += CCCallbackThenClose; // change status but backup old value\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif ( _ClosureClearanceStatus >= CCCallbackThenClose )\n\t\t\t\t\t\t_ClosureClearanceStatus -= CCCallbackThenClose; // set the closure state back if the NS comes back\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tNetSpeedLoop = (sint32) (CTime::getLocalTime () - before);\n\t\t\tUserSpeedLoop = (sint32) (before - bbefore);\n\t\t\tL5CallbackTime = TimeInCallback - LastTimeInCallback;\n\t\t\tLastTimeInCallback = TimeInCallback;\n\t\t\tL5CallbackCount = TotalCallbackCalled - LastTotalCallbackCalled;\n\t\t\tLastTotalCallbackCalled = TotalCallbackCalled;\n\n\t\t\tif (WindowDisplayer != NULL)\n\t\t\t{\n\t\t\t\tstatic TTime lt = 0;\n\t\t\t\tTTime ct = CTime::getLocalTime();\n\t\t\t\tif(ct > lt+100)\n\t\t\t\t{\n\t\t\t\t\tlt = ct;\n\t\t\t\t\tuint64 rcv, snd, rcvq, sndq;\n\t\t\t\t\trcv = CUnifiedNetwork::getInstance()->getBytesReceived ();\n\t\t\t\t\tsnd = CUnifiedNetwork::getInstance()->getBytesSent ();\n\t\t\t\t\trcvq = CUnifiedNetwork::getInstance()->getReceiveQueueSize ();\n\t\t\t\t\tsndq = CUnifiedNetwork::getInstance()->getSendQueueSize ();\n\n\t\t\t\t\tfor (uint i = 0; i < displayedVariables.size(); i++)\n\t\t\t\t\t{\n\t\t\t\t\t\t// it s a separator, do nothing\n\t\t\t\t\t\tif (displayedVariables[i].first.empty())\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t// it s a command, do nothing\n\t\t\t\t\t\tif (displayedVariables[i].first[0] == '@')\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tstring dispName = displayedVariables[i].first;\n\t\t\t\t\t\tstring varName = dispName;\n\t\t\t\t\t\tstring::size_type pos = dispName.find(\"|\");\n\t\t\t\t\t\tif (pos != string::npos)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tvarName = displayedVariables[i].first.substr(pos+1);\n\t\t\t\t\t\t\tdispName = displayedVariables[i].first.substr(0, pos);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (dispName.empty())\n\t\t\t\t\t\t\tstr = \"\";\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tstr = dispName + \": \";\n\n\t\t\t\t\t\tmdDisplayVars.clear ();\n\t\t\t\t\t\tICommand::execute(varName, logDisplayVars, true);\n\t\t\t\t\t\tconst std::deque<std::string>\t&strs = mdDisplayVars.lockStrings();\n\t\t\t\t\t\tif (strs.size()>0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstr += strs[0].substr(0,strs[0].size()-1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tstr += \"???\";\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmdDisplayVars.unlockStrings();\n\t\t\t\t\t\tWindowDisplayer->setLabel (displayedVariables[i].second, str);\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// nldebug (\"SYNC: updatetimeout must be %d and is %d, sleep the rest of the time\", _UpdateTimeout, delta);\n\n\t\t\tCHTimer::endBench();\n\n\t\t\t// Resetting the hierarchical timer must be done outside the top-level timer\n\t\t\tif ( _ResetMeasures )\n\t\t\t{\n\t\t\t\tCHTimer::clear();\n\t\t\t\t_ResetMeasures = false;\n\t\t\t}\n\n\t\t\tMyTAT.deactivate();\n\t\t}\n\t}\n\tcatch (const EFatalError &)\n\t{\n\t\t// Somebody call nlerror, so we have to quit now, the message already display\n\t\t// so we don't have to to anything\n\t\tsetExitStatus (EXIT_FAILURE);\n\t}\n\tcatch (const ESocket &e)\n\t{\n\t\t// Catch NeL network exception to release the system cleanly\t\tsetExitStatus (EXIT_FAILURE);\n\t\tErrorLog->displayNL( \"NeL Exception in \\\"%s\\\": %s\", _ShortName.c_str(), e.what() );\n\t}\n\tcatch ( uint ) // SEH exceptions\n\t{\n\t\tErrorLog->displayNL( \"SERVICE: System exception\" );\n\t}\n\n\ttry\n\t{\n\t\tnlinfo (\"SERVICE: Service starts releasing\");\n\n\t\t//\n\t\t// Call the user service release() if the init() was called\n\t\t//\n\n\t\tif (userInitCalled)\n\t\t{\n\t\t\tsetCurrentStatus(\"Releasing\");\n\t\t\trelease ();\n\t\t}\n\n\t\tCTransportClass::release();\n\n\t\t//\n\t\t// Delete all network connection (naming client also)\n\t\t//\n\n\t\tstd::vector<std::string> namesOfOnlyServiceToFlushSendingV;\n\t\texplode( NamesOfOnlyServiceToFlushSending.get(), string(\":\"), namesOfOnlyServiceToFlushSendingV, true );\n\t\tCUnifiedNetwork::getInstance()->release (FlushSendingQueuesOnExit.get(), namesOfOnlyServiceToFlushSendingV);\n\n\t\t// warn the module layer that the application is about to close\n\t\tIModuleManager::getInstance().applicationExit();\n\n//\t\t// release the network\n//\t\tCSock::releaseNetwork ();\n//\n\t\t//\n\t\t// Remove the window displayer\n\t\t//\n\n\t\tif (WindowDisplayer != NULL)\n\t\t{\n\t\t\tDebugLog->removeDisplayer (WindowDisplayer);\n\t\t\tInfoLog->removeDisplayer (WindowDisplayer);\n\t\t\tWarningLog->removeDisplayer (WindowDisplayer);\n\t\t\tErrorLog->removeDisplayer (WindowDisplayer);\n\t\t\tAssertLog->removeDisplayer (WindowDisplayer);\n\t\t\tCommandLog.removeDisplayer (WindowDisplayer);\n\n\t\t\tdelete WindowDisplayer;\n\t\t\tWindowDisplayer = NULL;\n\t\t}\n\n\t\tnlinfo (\"SERVICE: Service released successfully\");\n\t}\n\tcatch (const EFatalError &)\n\t{\n\t\t// Somebody call nlerror, so we have to quit now, the message already display\n\t\t// so we don't have to to anything\n\t\tsetExitStatus (EXIT_FAILURE);\n\t}\n\n\t// remove the stdin monitor thread\n\tIStdinMonitorSingleton::getInstance()->release(); // does nothing if not initialized\n\n\t// release the module manager\n\tIModuleManager::getInstance().releaseInstance();\n\n\t// release the network\n\tCSock::releaseNetwork ();\n\n\t// stop the timeout thread\n\tMyTAT.quit();\n\tif (timeoutThread != NULL)\n\t{\n\t\ttimeoutThread->wait();\n\t\tdelete timeoutThread;\n\t}\n\n\tCHTimer::display();\n\tCHTimer::displayByExecutionPath ();\n\tCHTimer::displayHierarchical(&CommandLog, true, 64);\n\tCHTimer::displayHierarchicalByExecutionPathSorted (&CommandLog, CHTimer::TotalTime, true, 64);\n\n\tnlinfo (\"SERVICE: Service ends\");\n\n\treturn ExitSignalAsked?100+ExitSignalAsked:getExitStatus ();\n}\n\nvoid IService::exit (sint code)\n{\n\tnlinfo (\"SERVICE: Somebody called IService::exit(), I have to quit\");\n\tExitSignalAsked = code;\n}\n\n/// Push a new status on the status stack.\nvoid IService::setCurrentStatus(const std::string &status)\n{\n\t// remove the status if it is already in the stack\n\t_ServiceStatusStack.erase(std::remove(_ServiceStatusStack.begin(), _ServiceStatusStack.end(), status), _ServiceStatusStack.end());\n\n\t// insert the status on top of the stack\n\t_ServiceStatusStack.push_back(status);\n\n}\n\n/// Remove a status from the status stack. If this status is at top of stack, the next status become the current status\nvoid IService::clearCurrentStatus(const std::string &status)\n{\n\t// remove the status of the stack\n\t_ServiceStatusStack.erase(std::remove(_ServiceStatusStack.begin(), _ServiceStatusStack.end(), status), _ServiceStatusStack.end());\n}\n\n/// Add a tag in the status string\nvoid IService::addStatusTag(const std::string &statusTag)\n{\n\t_ServiveStatusTags.insert(statusTag);\n}\n\n/// Remove a tag from the status string\nvoid IService::removeStatusTag(const std::string &statusTag)\n{\n\t_ServiveStatusTags.erase(statusTag);\n}\n\n/// Get the current status with attached tags\nstd::string IService::getFullStatus() const\n{\n\tstring result;\n\n\t// get hold of the status at the top of the status stack\n\tif (!_ServiceStatusStack.empty())\n\t{\n\t\tresult = _ServiceStatusStack.back();\n\t}\n\n\t// add status tags to the result so far\n\tset<string>::const_iterator first(_ServiveStatusTags.begin()), last(_ServiveStatusTags.end());\n\tfor (; first != last; ++first)\n\t{\n\t\tif (first != _ServiveStatusTags.begin() || !result.empty())\n\t\t\tresult += \" \";\n\t\tresult += *first;\n\t}\n\n\t// return the result\n\treturn result.empty()? \"Online\": result;\n}\n\n\n/*\n * Require to reset the hierarchical timer\n */\nvoid IService::requireResetMeasures()\n{\n\t_ResetMeasures = true;\n}\n\n\n/*\n *\n */\nstd::string IService::getServiceUnifiedName () const\n{\n\tnlassert (!_ShortName.empty());\n\tstring res;\n\tif (!_AliasName.empty())\n\t{\n\t\tres = _AliasName+\"/\";\n\t}\n\tres += _ShortName;\n\tif (_SId.get() != 0)\n\t{\n\t\tres += \"-\";\n\t\tres += toString (_SId.get());\n\t}\n\treturn res;\n}\n\n\n/*\n * Returns the date of launch of the service. Unit: see CTime::getSecondsSince1970()\n */\nuint32\t\tIService::getLaunchingDate () const\n{\n\treturn LaunchingDate;\n}\n\n\nvoid IService::registerUpdatable(IServiceUpdatable *updatable)\n{\n\t_Updatables.insert(updatable);\n}\n\nvoid IService::unregisterUpdatable(IServiceUpdatable *updatable)\n{\n\t_Updatables.erase(updatable);\n}\n\n//\n// Commands and Variables for controling all services\n//\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, LaunchingDate, \"date of the launching of the program\")\n{\n\tnlunreferenced(human);\n\tif (get) *pointer = asctime (localtime ((time_t*)&LaunchingDate));\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, Uptime, \"time from the launching of the program\")\n{\n\tif (get)\n\t{\n\t\tif (human)\n\t\t\t*pointer = secondsToHumanReadable (CTime::getSecondsSince1970() - LaunchingDate);\n\t\telse\n\t\t\t*pointer = NLMISC::toString(CTime::getSecondsSince1970() - LaunchingDate);\n\t}\n\telse\n\t{\n\t\tNLMISC::fromString(*pointer, LaunchingDate);\n\t\tLaunchingDate = CTime::getSecondsSince1970() - LaunchingDate;\n\t}\n}\n\nNLMISC_CATEGORISED_VARIABLE(nel, string, CompilationDate, \"date of the compilation\");\nNLMISC_CATEGORISED_VARIABLE(nel, string, CompilationMode, \"mode of the compilation\");\n\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, NbUserUpdate, \"number of time the user IService::update() called\");\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, Scroller, \"current size in bytes of the sent queue size\")\n{\n\tnlunreferenced(human);\n\n\tif (get)\n\t{\n\t\t// display the scroll text\n\t\tstatic string foo =\t\"Welcome to NeL Service! This scroll is used to see the update frequency of the main function and to see if the service is frozen or not. Have a nice day and hope you'll like NeL!!! \"\n\t\t\t\t\t\t\t\"Welcome to NeL Service! This scroll is used to see the update frequency of the main function and to see if the service is frozen or not. Have a nice day and hope you'll like NeL!!! \";\n\t\tstatic int pos = 0;\n\t\t*pointer = foo.substr ((pos++)%(foo.size()/2), 10);\n\t}\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, quit, \"exit the service\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tlog.displayNL(\"User ask me with a command to quit\");\n\tExitSignalAsked = 0xFFFF;\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, brutalQuit, \"exit the service brutally\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(log);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\t::exit (0xFFFFFFFF);\n\n\treturn true;\n}\n\n\n#ifdef MUTEX_DEBUG\nNLMISC_CATEGORISED_COMMAND(nel, mutex, \"display mutex values\", \"\")\n{\n\tif(args.size() != 0) return false;\n\n\tmap<CFairMutex*,TMutexLocks>\tacquiretimes = getNewAcquireTimes();\n\n\tmap<CFairMutex*,TMutexLocks>::iterator im;\n\tfor ( im=acquiretimes.begin(); im!=acquiretimes.end(); ++im )\n\t{\n\t\tlog.displayNL( \"%d %p %s: %.0f %.0f, called %u times th(%d, %d wait)%s\", (*im).second.MutexNum, (*im).first, (*im).second.MutexName.c_str(),\n\t\t\tCTime::cpuCycleToSecond((*im).second.TimeToEnter)*1000.0, CTime::cpuCycleToSecond((*im).second.TimeInMutex)*1000.0,\n\t\t\t(*im).second.Nb, (*im).second.ThreadHavingTheMutex, (*im).second.WaitingMutex,\n\t\t\t(*im).second.Dead?\" DEAD\":\"\");\n\t}\n\n\treturn true;\n}\n#endif // MUTEX_DEBUG\n\nNLMISC_CATEGORISED_COMMAND(nel, serviceInfo, \"display information about this service\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tlog.displayNL (\"Service %s '%s' using NeL (\" __DATE__ \" \" __TIME__ \")\", IService::getInstance()->getServiceLongName().c_str(), IService::getInstance()->getServiceUnifiedName().c_str());\n\tlog.displayNL (\"Service listening port: %d\", IService::getInstance()->ListeningPort.get());\n\tlog.displayNL (\"Service running directory: '%s'\", IService::getInstance()->RunningDirectory.c_str());\n\tlog.displayNL (\"Service log directory: '%s'\", IService::getInstance()->LogDirectory.c_str());\n\tlog.displayNL (\"Service save files directory: '%s'\", IService::getInstance()->SaveFilesDirectory.c_str());\n\tlog.displayNL (\"Service write files directory: '%s'\", IService::getInstance()->WriteFilesDirectory.c_str());\n\tlog.displayNL (\"Service config directory: '%s' config filename: '%s.cfg'\", IService::getInstance()->ConfigDirectory.c_str(), IService::getInstance()->_LongName.c_str());\n\tlog.displayNL (\"Service id: %hu\", IService::getInstance()->_SId.get());\n\tlog.displayNL (\"Service update timeout: %dms\", IService::getInstance()->_UpdateTimeout);\n\tlog.displayNL (\"Service %suse naming service\", IService::getInstance()->_DontUseNS?\"don't \":\"\");\n\tlog.displayNL (\"Service %suse admin executor service\", IService::getInstance()->_DontUseAES?\"don't \":\"\");\n\tlog.displayNL (\"NeL is compiled in %s mode\", CompilationMode.c_str());\n\n\tlog.displayNL (\"Services arguments: %d args\", IService::getInstance()->_Args.size ());\n\tfor (uint i = 0; i < IService::getInstance()->_Args.size (); i++)\n\t{\n\t\tlog.displayNL (\"  argv[%d] = '%s'\", i, IService::getInstance()->_Args[i].c_str ());\n\t}\n\n\tlog.displayNL (\"Naming service info: %s\", CNamingClient::info().c_str());\n\n\tICommand::execute (\"services\", log);\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, resetMeasures, \"reset hierarchical timer\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(log);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tIService::getInstance()->requireResetMeasures();\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, getWinDisplayerInfo, \"display the info about the pos and size of the window displayer\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tuint32 x,y,w,h;\n\tIService::getInstance()->WindowDisplayer->getWindowPos (x,y,w,h);\n\tlog.displayNL (\"Window Displayer : XWinParam = %d; YWinParam = %d; WWinParam = %d; HWinParam = %d;\", x, y, w, h);\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, displayConfigFile, \"display the variables of the default configfile\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tIService::getInstance()->ConfigFile.display (&log);\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, getUnknownConfigFileVariables, \"display the variables from config file that are called but not present\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(args);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tlog.displayNL (\"%d Variables not found in the configfile '%s'\", IService::getInstance()->ConfigFile.UnknownVariables.size(), IService::getInstance()->ConfigFile.getFilename().c_str() );\n\tfor (uint i = 0; i < IService::getInstance()->ConfigFile.UnknownVariables.size(); i++)\n\t{\n\t\tlog.displayNL (\"  %s\", IService::getInstance()->ConfigFile.UnknownVariables[i].c_str());\n\t}\n\treturn true;\n}\n\n// -1 = service is quitting\n// 0 = service is not connected\n// 1 = service is running\n// 2 = service is launching\n// 3 = service failed launching\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, string, State, \"Set this value to 0 to shutdown the service and 1 to start the service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\n\t{\n\t}\n\telse\n\t{\n\t\tif (IService::getInstance()->getServiceShortName() == \"AES\" || IService::getInstance()->getServiceShortName() == \"AS\")\n\t\t{\n\t\t\tnlinfo (\"SERVICE: I can't set State=0 because I'm the admin and I should never quit\");\n\t\t}\n\t\telse if (*pointer == \"0\" || *pointer == \"2\")\n\t\t{\n\t\t\t// ok, we want to set the value to false, just quit\n\t\t\tnlinfo (\"SERVICE: User ask me with a command to quit using the State variable\");\n\t\t\tExitSignalAsked = 0xFFFE;\n\t\t\tIService *srv = IService::getInstance();\n\t\t\tif( srv == NULL )\n\t\t\t{\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsrv->setCurrentStatus(\"Quitting\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"SERVICE: Unknown value for State '%s'\", (*pointer).c_str());\n\t\t}\n\t}\n\n\t// whether reading or writing, the internal value of the state variable should end up as the result of getFullStatus()\n\tIService *srv = IService::getInstance();\n\tif( srv == NULL )\n\t{\n\t\treturn;\n\t}\n\t*pointer= srv->getFullStatus();\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, uint32, ShardId, \"Get value of shardId set for this particular service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\n\t{\n\t\t*pointer = IService::getInstance()->getShardId();\n\t}\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, CPULoad, \"Get instant CPU load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPULoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, ProcessLoad, \"Get instant CPU load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, CPUUserLoad, \"Get instant CPU user load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUUserLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, CPUSytemLoad, \"Get instant CPU system load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, CPUNiceLoad, \"Get instant CPU nice processes load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, CPUIOWaitLoad, \"Get instant CPU IO wait load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, ProcessUserLoad, \"Get instant CPU user load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessUserLoad(); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, ProcessSystemLoad, \"Get instant CPU system load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(); }\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanCPULoad, \"Get instant CPU load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPULoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanProcessLoad, \"Get instant CPU load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanCPUUserLoad, \"Get instant CPU user load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUUserLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanCPUSytemLoad, \"Get instant CPU system load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanCPUNiceLoad, \"Get instant CPU nice processes load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanCPUIOWaitLoad, \"Get instant CPU IO wait load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanProcessUserLoad, \"Get instant CPU user load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessUserLoad(CCPUTimeStat::Mean); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, MeanProcessSystemLoad, \"Get instant CPU system load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(CCPUTimeStat::Mean); }\n}\n\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakCPULoad, \"Get instant CPU load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPULoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakProcessLoad, \"Get instant CPU load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakCPUUserLoad, \"Get instant CPU user load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUUserLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakCPUSytemLoad, \"Get instant CPU system load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakCPUNiceLoad, \"Get instant CPU nice processes load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakCPUIOWaitLoad, \"Get instant CPU IO wait load of the server\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakProcessUserLoad, \"Get instant CPU user load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessUserLoad(CCPUTimeStat::Peak); }\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(cpu, float, PeakProcessSystemLoad, \"Get instant CPU system load of the process/service\")\n{\n\tnlunreferenced(human);\n\t// read or write the variable\n\tif (get)\t{ *pointer = IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(CCPUTimeStat::Peak); }\n}\n\n\n} //NLNET\n"
  },
  {
    "path": "code/nel/src/net/sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/sock.h\"\n#include \"nel/net/net_log.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <winsock2.h>\n#\tinclude <windows.h>\n#\tdefine socklen_t int\n#\tdefine ERROR_NUM WSAGetLastError()\n#\tdefine ERROR_WOULDBLOCK WSAEWOULDBLOCK\n\n#elif defined NL_OS_UNIX\n\n#\tinclude <unistd.h>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#\tinclude <sys/socket.h>\n#\tinclude <sys/ioctl.h>\n#\tinclude <netinet/in.h>\n#\tinclude <netinet/tcp.h>\n#\tinclude <arpa/inet.h>\n#\tinclude <netdb.h>\n#\tinclude <fcntl.h>\n#\tinclude <cerrno>\n\n#\tdefine SOCKET_ERROR -1\n#\tdefine INVALID_SOCKET -1\n#\tdefine ERROR_NUM errno\n#\tdefine ERROR_WOULDBLOCK EWOULDBLOCK\n#\tdefine ERROR_MSG strerror(errno)\n\n// BSD compatible constant\n#\tifndef FNDELAY\n#\t\tdefine FNDELAY O_NDELAY\n#\tendif\n\ntypedef int SOCKET;\n\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\nbool CSock::_Initialized = false;\n\n\n/*\n * ESocket constructor\n */\nESocket::ESocket( const char *reason, bool systemerror, CInetAddress *addr )\n{\n/*it doesnt work on linux, should do something more cool\n  \tstd::stringstream ss;\n\tss << \"Socket error: \" << reason;\n\tif ( systemerror )\n\t{\n\t\tss << \" (\" << ERROR_NUM;\n#ifdef NL_OS_UNIX\n\t\tss << \": \" << ERROR_MSG;\n#endif\n\t\tss << \") \" << std::endl;\n\t}\n\t_Reason = ss.str();\n  */\n  \t_Reason = \"Socket error: \";\n\tuint errornum = CSock::getLastError();\n\tchar str[256];\n\tif ( addr != NULL )\n\t{\n\t\t// Version with address\n\t\tsmprintf( str, 256, reason, addr->asString().c_str() ); // reason *must* contain \"%s\"\n\t\t_Reason += str;\n\t}\n\telse\n\t{\n\t\t// Version without address\n\t\t_Reason += reason;\n\t}\n\tif ( systemerror )\n\t{\n\t\t_Reason += \" (\";\n\t\tsmprintf( str, 256, \"%d\", errornum );\n\t\t_Reason += str;\n\t\tif ( errornum != 0 )\n\t\t{\n\t\t\t_Reason += \": \";\n\t\t\t_Reason += CSock::errorString( errornum );\n\t\t}\n\t\t_Reason += \")\";\n\t}\n\tLNETL0_INFO( \"LNETL0: Exception will be launched: %s\", _Reason.c_str() );\n\n}\n\n\n/*\n * Initializes the network engine if it is not already done (under Windows, calls WSAStartup()).\n */\nvoid CSock::initNetwork()\n{\n\tif ( ! CSock::_Initialized )\n\t{\n#ifdef NL_OS_WINDOWS\n\t\tWORD winsock_version = MAKEWORD( 2, 0 );\n\t\tWSADATA wsaData;\n\t\tif ( WSAStartup( winsock_version, &wsaData ) != 0 )\n\t\t{\n\t\t\tthrow ESocket( \"Winsock initialization failed\" );\n\t\t}\n#endif\n\t\tCSock::_Initialized = true;\n\t}\n}\n\n/*\n * Releases the network engine\n */\nvoid CSock::releaseNetwork()\n{\n#ifdef NL_OS_WINDOWS\n\tWSACleanup();\n#endif\n\tCSock::_Initialized = false;\n}\n\n\n/* Returns the code of the last error that has occured.\n * Note: This code is platform-dependant. On Unix, it is errno; on Windows it is the Winsock error code.\n * See also errorString()\n */\nuint CSock::getLastError()\n{\n\treturn (uint)ERROR_NUM;\n}\n\n\n/*\n * Returns a string explaining the network error (see getLastError())\n */\nstd::string CSock::errorString( uint errorcode )\n{\n#ifdef NL_OS_WINDOWS\n\tswitch( errorcode )\n\t{\n\tcase WSAEINTR\t\t /*10004*/: return \"Blocking operation interrupted\";\n\tcase WSAEINVAL\t\t /*10022*/: return \"Invalid socket (maybe not bound) or argument\";\n\tcase WSAEMFILE\t\t /*10024*/: return \"Too many open sockets\";\n\tcase WSAENOTSOCK\t /*10038*/: return \"Socket operation on nonsocket (maybe invalid select descriptor)\";\n\tcase WSAEMSGSIZE\t /*10040*/: return \"Message too long\";\n\tcase WSAEADDRINUSE   /*10048*/: return \"Address already in use (is this service already running in this computer?)\";\n\tcase WSAEADDRNOTAVAIL/*10049*/: return \"Address not available\";\n\tcase WSAENETDOWN\t /*10050*/: return \"Network is down\";\n\tcase WSAENETUNREACH  /*10051*/: return \"Network is unreachable\";\n\tcase WSAECONNRESET   /*10054*/: return \"Connection reset by peer\";\n\tcase WSAENOBUFS\t\t /*10055*/: return \"No buffer space available; please close applications or reboot\";\n\tcase WSAESHUTDOWN\t /*10058*/: return \"Cannot send/receive after socket shutdown\";\n\tcase WSAETIMEDOUT\t /*10060*/: return \"Connection timed-out\";\n\tcase WSAECONNREFUSED /*10061*/:\treturn \"Connection refused, the server may be offline\";\n\tcase WSAEHOSTUNREACH /*10065*/: return \"Remote host is unreachable\";\n\tcase WSANOTINITIALISED /*093*/: return \"'Windows Sockets' not initialized\";\n\tdefault:\t\t\t\t\t\treturn \"\";\n\t}\n#elif defined NL_OS_UNIX\n\treturn std::string( strerror( errorcode ) );\n#endif\n\n}\n\n\n\n/*\n * Constructor\n */\nCSock::CSock( bool logging ) :\n\t_Sock( INVALID_SOCKET ),\n\t_Logging( logging ),\n\t_NonBlocking( false ),\n\t_BytesReceived( 0 ),\n\t_BytesSent( 0 ),\n\t_TimeoutS( 0 ),\n\t_TimeoutUs( 0 ),\n\t_MaxReceiveTime( 0 ),\n\t_MaxSendTime( 0 ),\n\t_Blocking( false )\n\t{\n\tnlassert( CSock::_Initialized );\n\t/*{\n\t\tCSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t\tsync.value() = false;\n\t}*/\n\t_Connected = false;\n}\n\n\n/*\n * Construct a CSock object using an existing connected socket descriptor and its associated remote address\n */\nCSock::CSock( SOCKET sock, const CInetAddress& remoteaddr ) :\n\t_Sock( sock ),\n\t_RemoteAddr( remoteaddr ),\n\t_Logging( true ),\n\t_NonBlocking( false ),\n\t_BytesReceived( 0 ),\n\t_BytesSent( 0 ),\n\t_MaxReceiveTime( 0 ),\n\t_MaxSendTime( 0 )\n{\n\tnlassert( CSock::_Initialized );\n\t/*{\n\t\tCSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t\tsync.value() = true;\n\t}*/\n\t_Connected = true;\n\n\t// Check remote address\n\tif ( ! _RemoteAddr.isValid() )\n\t{\n\t\tthrow ESocket( \"Could not init a socket object with an invalid address\", false );\n\t}\n\n\t// Get local socket name\n\tsetLocalAddress();\n\n#ifdef NL_OS_UNIX\n\t// We set the close-on-exec flag on the socket to be sure that when\n\t// we call the exec() to spawn an application in the AES for example,\n\t// that the AES listen socket will be close and not given to the child.\n\t// From google:\n\t// Manipulate the close-on-exec flag to determine if a file descriptor\n\t// should be closed as part of the normal processing of the exec subroutine.\n\t// If the flag is set, the file descriptor is closed.\n\t// If the flag is clear, the file descriptor is left open\n\tioctl(_Sock, FIOCLEX, NULL);\n\t// fcntl should be more portable but not tested fcntl(_Sock, F_SETFD, FD_CLOEXEC);\n#endif\n\t}\n\n\n/*\n * Creates the socket and get a valid descriptor\n */\nvoid CSock::createSocket( int type, int protocol )\n{\n\tnlassert( _Sock == INVALID_SOCKET );\n\n\t_Sock = (SOCKET)socket( AF_INET, type, protocol ); // or IPPROTO_IP (=0) ?\n\tif ( _Sock == INVALID_SOCKET )\n\t{\n\t\tthrow ESocket( \"Socket creation failed\" );\n\t}\n\n\tif ( _Logging )\n\t{\n//\t\tLNETL0_DEBUG( \"LNETL0: Socket %d open (TCP)\", _Sock );\n\t}\n\n#ifdef NL_OS_UNIX\n\t// We set the close-on-exec flag on the socket to be sure that when\n\t// we call the exec() to spawn an application in the AES for example,\n\t// that the AES listen socket will be close and not given the to child.\n\t// From google:\n\t// Manipulate the close-on-exec flag to determine if a file descriptor\n\t// should be closed as part of the normal processing of the exec subroutine.\n\t// If the flag is set, the file descriptor is closed.\n\t// If the flag is clear, the file descriptor is left open\n\tioctl(_Sock, FIOCLEX, NULL);\n\t// fcntl should be more portable but not tested fcntl(_Sock, F_SETFD, FD_CLOEXEC);\n#endif\n\n}\n\n\n/*\n * Closes the listening socket\n */\nvoid CSock::close()\n{\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d closing for %s at %s\", _Sock, _RemoteAddr.asString().c_str(), _LocalAddr.asString().c_str() );\n\t}\n\tSOCKET sockToClose = _Sock;\n\t// preset to invalid to bypass exception in listen thread\n\t_Sock = INVALID_SOCKET;\n#ifdef NL_OS_WINDOWS\n\tclosesocket( sockToClose );\n#elif defined NL_OS_UNIX\n\t::close( sockToClose );\n#endif\n\t_Connected = false;\n}\n\n\n/*\n * Destructor\n */\nCSock::~CSock()\n{\n\t//nlinfo( \"Report for %s socket %s: Max send time: %u Max recv time: %u\", _NonBlocking?\"non-blocking\":\"blocking\", remoteAddr().asString().c_str(), _MaxSendTime, _MaxReceiveTime );\n\t//nlinfo( \"Max send time: %u\", _MaxSendTime);\n\tif ( _Sock != INVALID_SOCKET )\n\t{\n\t\tif ( _Logging )\n\t\t{\n\t\t\tLNETL0_DEBUG( \"LNETL0: Socket %d closing for %s at %s\", _Sock, _RemoteAddr.asString().c_str(), _LocalAddr.asString().c_str() );\n\t\t}\n\n\t\tif ( connected() )\n\t\t{\n#ifdef NL_OS_WINDOWS\n\t\t\tshutdown( _Sock, SD_BOTH );\n\t\t}\n\t\tclosesocket( _Sock );\n#elif defined NL_OS_UNIX\n\t\t\tshutdown( _Sock, SHUT_RDWR );\n\t\t}\n\t\t::close( _Sock );\n#endif\n\t\t_Sock = INVALID_SOCKET;\n\t}\n}\n\n\n/*\n * Connection\n */\nvoid CSock::connect( const CInetAddress& addr )\n{\n\tLNETL0_DEBUG( \"LNETL0: Socket %d connecting to %s...\", _Sock, addr.asString().c_str() );\n\n\t// Check address\n\tif ( ! addr.isValid() )\n\t{\n\t\tthrow ESocket( \"Unable to connect to invalid address\", false );\n\t}\n\n#ifndef NL_OS_WINDOWS\n    // Set Reuse Address On (does not work on Win98 and is useless on Win2000)\n    int value = true;\n    if ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )\n    {\n        throw ESocket( \"ReuseAddr failed\" );\n    }\n#endif\n\n\t// Connection (when _Sock is a datagram socket, connect establishes a default destination address)\n\tif ( ::connect( _Sock, (const sockaddr *)(addr.sockAddr()), sizeof(sockaddr_in) ) != 0 )\n\t{\n/*\t\tif ( _Logging )\n\t\t{\n#ifdef NL_OS_WINDOWS\n\t\t\tnldebug( \"Impossible to connect socket %d to %s %s (%d)\", _Sock, addr.hostName().c_str(), addr.asIPString().c_str(), ERROR_NUM );\n#elif defined NL_OS_UNIX\n\t\t\tnldebug( \"Impossible to connect socket %d to %s %s (%d:%s)\", _Sock, addr.hostName().c_str(), addr.asIPString().c_str(), ERROR_NUM, strerror(ERROR_NUM) );\n#endif\n\t\t}\n*/\n\n\t\tthrow ESocketConnectionFailed( addr );\n\t}\n\tsetLocalAddress();\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d connected to %s (local %s)\", _Sock, addr.asString().c_str(), _LocalAddr.asString().c_str() );\n\t}\n\t_RemoteAddr = addr;\n\n\t_BytesReceived = 0;\n\t_BytesSent = 0;\n\n\t/*CSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\tsync.value() = true;*/\n\t_Connected = true;\n}\n\n\n/*\n * Checks if there is some data to receive\n */\nbool CSock::dataAvailable()\n{\n    fd_set fdset;\n    FD_ZERO( &fdset );\n    FD_SET( _Sock, &fdset );\n    timeval tv;\n    tv.tv_sec = _TimeoutS;\n    tv.tv_usec = _TimeoutUs;\n\n    // Test for message received.\n    int res = select( _Sock+1, &fdset, NULL, NULL, &tv );\n    switch ( res  )\n    {\n    case  0 : return false;\n    case -1 : throw ESocket( \"CSock::dataAvailable(): select failed\" );\n    default : return true;\n    }\n}\n\n\n/*\n * Sets the local address\n */\nvoid CSock::setLocalAddress()\n{\n\tsockaddr saddr;\n\tsocklen_t saddrlen = sizeof(saddr);\n\tif ( getsockname( _Sock, &saddr, &saddrlen ) != 0 )\n\t{\n\t\tthrow ESocket( \"Unable to find local address\" );\n\t}\n\t_LocalAddr.setSockAddr( (const sockaddr_in *)&saddr );\n}\n\n\n/*\n * Sends data, or returns false if it would block\n */\nCSock::TSockResult CSock::send( const uint8 *buffer, uint32& len, bool throw_exception )\n{\n\tTTicks before = CTime::getPerformanceTime();\n\tlen = ::send( _Sock, (const char*)buffer, len, 0 );\n\t_MaxSendTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxSendTime );\n\n//\tnldebug (\"CSock::send(): Sent %d bytes to %d (%d)\", len, _Sock, ERROR_NUM);\n\n\tif ( _Logging )\n\t{\n//\t\tLNETL0_DEBUG (\"LNETL0: CSock::send(): Sent %d bytes to %d res: %d (%d)\", realLen, _Sock, len, ERROR_NUM);\n\t}\n\n\tif ( ((int)len) == SOCKET_ERROR )\n\t{\n\t\tif ( ERROR_NUM == ERROR_WOULDBLOCK )\n\t\t{\n\t\t\tH_AUTO(L0SendWouldBlock);\n\t\t\tlen = 0;\n\t\t\t//nlSleep(10);\n\t\t\tif (!_Blocking)\n\t\t\t{\n\t\t\t\t//nldebug(\"SendWouldBlock - %s / %s Entering snooze mode\",_LocalAddr.asString().c_str(),_RemoteAddr.asString().c_str());\n\t\t\t\t_Blocking= true;\n\t\t\t}\n\t\t\treturn Ok;\n\t\t}\n\t\tif ( throw_exception )\n\t\t{\n#ifdef NL_OS_WINDOWS\n\t\t\tthrow ESocket( NLMISC::toString( \"Unable to send data: error %u\", GetLastError() ).c_str() );\n#else\n\t\t\tthrow ESocket( \"Unable to send data\" );\n#endif\n\t\t}\n\t\treturn Error;\n\t}\n\t_BytesSent += len;\n\n\tif (_Blocking)\n\t{\n\t\t//nldebug(\"SendWouldBlock - %s / %s Leaving snooze mode\",_LocalAddr.asString().c_str(),_RemoteAddr.asString().c_str());\n\t\t_Blocking= false;\n\t}\n\treturn Ok;\n}\n\n\n\n/*\n * Receives data\n */\nCSock::TSockResult CSock::receive( uint8 *buffer, uint32& len, bool throw_exception )\n{\n\tif ( _NonBlocking )\n\t{\n\t\t// Receive incoming message (only the received part)\n\n\t\tTTicks before = CTime::getPerformanceTime();\n\t\tlen = ::recv( _Sock, (char*)buffer, len, 0 );\n\n\t\t//nlinfo (\"CSock::receive(): NBM Received %d bytes to %d res: %d (%d)\", realLen, _Sock, len, ERROR_NUM);\n\n\t\tif ( _Logging )\n\t\t{\n//\t\t\tLNETL0_DEBUG (\"LNETL0: CSock::receive(): NBM Received %d bytes to %d res: %d (%d)\", realLen, _Sock, len, ERROR_NUM);\n\t\t}\n\n\t\t_MaxReceiveTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxReceiveTime );\n\t\tswitch ( (sint)len )\n\t\t{\n\t\t\t// Graceful disconnection\n\t\t\tcase 0 :\n\t\t\t{\n\t\t\t\t/*{\n\t\t\t\t\tCSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t\t\t\t\tsync.value() = false;\n\t\t\t\t}*/\n\t\t\t\t_Connected = false;\n\t\t\t\tif ( throw_exception )\n\t\t\t\t{\n\t\t\t\t\tthrow ESocketConnectionClosed();\n\t\t\t\t}\n\t\t\t\treturn CSock::ConnectionClosed;\n\t\t\t}\n\n\t\t\t// Socket error or call would block\n\t\t\tcase SOCKET_ERROR :\n\t\t\t{\n\t\t\t\tlen = 0;\n\t\t\t\tif ( ERROR_NUM == ERROR_WOULDBLOCK )\n\t\t\t\t{\n\t\t\t\t\t// Call would block\n\t\t\t\t\treturn CSock::WouldBlock;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Socket error\n\t\t\t\t\tif ( throw_exception )\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow ESocket( \"Unable to receive data\" );\n\t\t\t\t\t}\n\t\t\t\t\treturn CSock::Error;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse // Blocking Mode\n\t{\n\t\t// Receive incoming message, waiting until a complete message has arrived\n\t\tuint total = 0;\n\t\tsint brecvd;\n\n\t\twhile ( total < len )\n\t\t{\n\t\t\tTTicks before = CTime::getPerformanceTime();\n\t\t\tbrecvd = ::recv( _Sock, (char*)(buffer+total), len-total, 0 );\n\n//\t\t\tnlinfo (\"CSock::receive(): BM Received %d bytes to %d res: %d (%d) total %d\", len, _Sock, brecvd, ERROR_NUM, total);\n\n\t\t\t_MaxReceiveTime = max( (uint32)(CTime::ticksToSecond(CTime::getPerformanceTime()-before)*1000.0f), _MaxReceiveTime );\n\n\t\t\tswitch ( brecvd )\n\t\t\t{\n\t\t\t\t// Graceful disconnection\n\t\t\t\tcase 0 :\n\t\t\t\t{\n\t\t\t\t\t/*{\n\t\t\t\t\t\tCSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\t\t\t\t\t\tsync.value() = false;\n\t\t\t\t\t}*/\n\t\t\t\t\t_Connected = false;\n\t\t\t\t\tlen = total;\n\t\t\t\t\t_BytesReceived += len;\n\n\t\t\t\t\tif ( throw_exception )\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow ESocketConnectionClosed();\n\t\t\t\t\t}\n\t\t\t\t\treturn CSock::ConnectionClosed;\n\t\t\t\t}\n\n\t\t\t\t// Socket error\n\t\t\t\tcase SOCKET_ERROR :\n\t\t\t\t{\n\t\t\t\t\tlen = total;\n\t\t\t\t\t_BytesReceived += len;\n\n\t\t\t\t\tif ( throw_exception )\n\t\t\t\t\t{\n\t\t\t\t\t\tthrow ESocket( \"Unable to receive data\" );\n\t\t\t\t\t}\n\t\t\t\t\treturn CSock::Error;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttotal += brecvd;\n\t\t}\n\t}\n\n\t/*if ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d received %d bytes\", _Sock, len );\n\t}*/\n\t_BytesReceived += len;\n\treturn CSock::Ok;\n}\n\n\n/*\n * Sets the socket in nonblocking mode\n */\nvoid CSock::setNonBlockingMode ( bool bm )\n{\n\tif ( _NonBlocking != bm )\n\t{\n#ifdef NL_OS_WINDOWS\n\t\tu_long b = bm;\n\t\tif ( ioctlsocket( _Sock, FIONBIO, &b ) != 0 )\n#else\n\t\tif ( fcntl( _Sock, F_SETFL, FNDELAY | fcntl( _Sock, F_GETFL, 0 ) ) == -1 )\n#endif\n\t\t{\n\t\t\tthrow ESocket( \"Cannot set nonblocking mode\" );\n\t\t}\n\t\t_NonBlocking = bm;\n\t}\n}\n\n\n/*\n * Sets the send buffer size\n */\nvoid CSock::setSendBufferSize( sint32 size )\n{\n  setsockopt( _Sock, SOL_SOCKET, SO_SNDBUF, (char*)(&size), (socklen_t)sizeof(size) );\n}\n\n/*\n * Gets the send buffer size\n */\nsint32 CSock::getSendBufferSize()\n{\n  int size = -1;\n  socklen_t bufsize;\n  getsockopt( _Sock, SOL_SOCKET, SO_SNDBUF, (char*)(&size), &bufsize );\n  return size;\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/stdin_monitor_thread.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n//-----------------------------------------------------------------------------\n// includes\n//-----------------------------------------------------------------------------\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/command.h\"\n\n#include \"stdin_monitor_thread.h\"\n\n\n//-----------------------------------------------------------------------------\n// namespace: NLNET\n//-----------------------------------------------------------------------------\n\nnamespace NLNET\n{\n\n\t//-----------------------------------------------------------------------------\n\t// class CStdinMonitorThread\n\t//-----------------------------------------------------------------------------\n\n\tclass CStdinMonitorThread : public NLMISC::IRunnable\n\t{\n\tpublic:\n\t\t// ctor\n\t\tCStdinMonitorThread();\n\n\t\t// main routine executed when the thread is started\n\t\tvoid run();\n\n\t\t// interface for adding commands, retrieving commands and verifying whether there are commands waiting\n\t\tvoid pushCommand(std::string nextCommand);\n\t\tstd::string popCommand();\n\t\tbool commandWaiting() const;\n\n\tprivate:\n\t\tstd::string _NextCommand;\n\t\tvolatile bool _CommandWaiting;\n\n\t};\n\n\t//-----------------------------------------------------------------------------\n\t// methods CStdinMonitorThread\n\t//-----------------------------------------------------------------------------\n\n\tCStdinMonitorThread::CStdinMonitorThread()\n\t{\n\t\t_CommandWaiting= false;\n\t}\n\n\tvoid CStdinMonitorThread::run ()\n\t{\n\t\twhile(!feof(stdin))\n\t\t{\n\t\t\t// wait for the main thread to deal with the previous command\n\t\t\twhile (commandWaiting())\n\t\t\t{\n\t\t\t\tNLMISC::nlSleep(1);\n\t\t\t}\n\n\t\t\t// get the next command from the command line\n\t\t\tchar theCommand[1024] = \"\";\n\t\t\tif (!fgets(theCommand, sizeofarray(theCommand), stdin))\n\t\t\t{\n\t\t\t\tnlwarning(\"fgets failed\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// push the command to allow reader thread to deal with it\n\t\t\tpushCommand(theCommand);\n\t\t}\n\t}\n\n\tvoid CStdinMonitorThread::pushCommand(std::string nextCommand)\n\t{\n\t\t// wait for the previous command to be treated\n\t\twhile (_CommandWaiting)\n\t\t{\n\t\t\tNLMISC::nlSleep(1);\n\t\t}\n\n\t\t// copy the next command into the appropriate buffer\n\t\t_NextCommand= nextCommand;\n\n\t\twhile (!_NextCommand.empty()\n\t\t\t\t&& (_NextCommand[_NextCommand.size()-1] == '\\n'\n\t\t\t\t\t|| _NextCommand[_NextCommand.size()-1] == '\\r'))\n\t\t{\n\t\t\t_NextCommand = _NextCommand.substr(0, _NextCommand.size()-1);\n\t\t}\n\n\t\t// set the _CommandWaiting flag, to allow reader thread to treat the new command\n\t\t_CommandWaiting= true;\n\t}\n\n\tstd::string CStdinMonitorThread::popCommand()\n\t{\n\t\t// wait for a command to be ligned up (waiting)\n\t\twhile (!_CommandWaiting)\n\t\t{\n\t\t}\n\n\t\t// copy out the next command\n\t\tstd::string result= _NextCommand;\n\n\t\t// clear out the next command variable ready for its next use\n\t\t_NextCommand.clear();\n\n\t\t// clear the _CommandWaiting flag, to allow writer thread to add a new command\n\t\t_CommandWaiting= false;\n\n\t\t// all done so return the command\n\t\treturn result;\n\t}\n\n\tbool CStdinMonitorThread::commandWaiting() const\n\t{\n\t\treturn _CommandWaiting;\n\t}\n\n\n\t//-----------------------------------------------------------------------------\n\t// class CStdinMonitorSingleton\n\t//-----------------------------------------------------------------------------\n\n\tclass CStdinMonitorSingleton: public IStdinMonitorSingleton\n\t{\n\tpublic:\n\t\t// static for getting hold of the singleton instance\n\t\tstatic CStdinMonitorSingleton* getInstance();\n\n\t\t// methods required by IStdinMonitorSingleton\n\t\tvoid init();\n\t\tvoid update();\n\t\tvoid release();\n\n\tprivate:\n\t\t// this is a singleton so dissallow construction from outside...\n\t\tCStdinMonitorSingleton();\n\t\tCStdinMonitorSingleton(const CStdinMonitorSingleton&);\n\t\tCStdinMonitorSingleton& operator =(const CStdinMonitorSingleton&);\n\n\tprivate:\n\t\t// data for the singleton instance\n\t\tCStdinMonitorThread* _StdinMonitorThreadInstance;\n\t\tNLMISC::IThread* _StdinMonitorThreadHandle;\n\t};\n\n\n\t//-----------------------------------------------------------------------------\n\t// methods IStdinMonitorSingleton\n\t//-----------------------------------------------------------------------------\n\n\tIStdinMonitorSingleton* IStdinMonitorSingleton::getInstance()\n\t{\n\t\treturn CStdinMonitorSingleton::getInstance();\n\t}\n\n\n\t//-----------------------------------------------------------------------------\n\t// methods CStdinMonitorSingleton\n\t//-----------------------------------------------------------------------------\n\n\tCStdinMonitorSingleton* CStdinMonitorSingleton::getInstance()\n\t{\n\t\tstatic CStdinMonitorSingleton* instance= NULL;\n\t\tif (instance==NULL)\n\t\t\tinstance= new CStdinMonitorSingleton;\n\t\treturn instance;\n\t}\n\n\tvoid CStdinMonitorSingleton::init()\n\t{\n\t\t_StdinMonitorThreadInstance= new CStdinMonitorThread;\n\t\t_StdinMonitorThreadHandle = NLMISC::IThread::create (_StdinMonitorThreadInstance, 1024*4*4);\n\t\t_StdinMonitorThreadHandle->start();\n\t}\n\n\tvoid CStdinMonitorSingleton::update()\n\t{\n\t\t// if we're not initialised yet then return\n\t\tif (_StdinMonitorThreadInstance== NULL)\n\t\t\treturn;\n\n\t\t// if there's a command waiting then treat it (not more than one command per visit)\n\t\tif (_StdinMonitorThreadInstance->commandWaiting())\n\t\t{\n\t\t\tstd::string nextCommand= _StdinMonitorThreadInstance->popCommand();\n\t\t\tif (!nextCommand.empty())\n\t\t\t{\n\t\t\t\tNLMISC::ICommand::execute(nextCommand,*NLMISC::InfoLog);\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid CStdinMonitorSingleton::release()\n\t{\n\t\t// if we've never been initialised or we've already been released thent there's nothing more to do...\n\t\tif (_StdinMonitorThreadInstance== NULL)\n\t\t\treturn;\n\n\t\t// terminate the thread and wait for it to finish\n\t\t_StdinMonitorThreadHandle->terminate();\n\t\t_StdinMonitorThreadHandle->wait();\n\n\t\t// destroy the thread object instance and reset the pointer to NULL to mark as 'uninitialised'\n\t\tdelete _StdinMonitorThreadInstance;\n\t\t_StdinMonitorThreadInstance= NULL;\n\t}\n\n\tCStdinMonitorSingleton::CStdinMonitorSingleton()\n\t{\n\t\t_StdinMonitorThreadHandle= NULL;\n\t\t_StdinMonitorThreadInstance= NULL;\n\t}\n\n\tCStdinMonitorSingleton::CStdinMonitorSingleton(const CStdinMonitorSingleton&)\n\t{\n\t\t_StdinMonitorThreadHandle= NULL;\n\t\t_StdinMonitorThreadInstance= NULL;\n\t}\n\n\tCStdinMonitorSingleton& CStdinMonitorSingleton::operator =(const CStdinMonitorSingleton&)\n\t{\n\t\treturn *this;\n\t}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/stdin_monitor_thread.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n\n#ifndef NL_STDIN_MONITOR_THREAD_H\n#define NL_STDIN_MONITOR_THREAD_H\n\nnamespace NLNET\n{\n\t//-----------------------------------------------------------------------------\n\t// class IStdinMonitorSingleton\n\t//-----------------------------------------------------------------------------\n\n\tclass IStdinMonitorSingleton\n\t{\n\tpublic:\n\t\t// static for getting hold of the singleton instance\n\t\tstatic IStdinMonitorSingleton* getInstance();\n\n\t\t// methods required by IStdinMonitorSingleton\n\t\tvirtual void init()=0;\n\t\tvirtual void update()=0;\n\t\tvirtual void release()=0;\n\n\t\t// virtual destructor\n\t\tvirtual ~IStdinMonitorSingleton() { }\n\t};\n\n} // NLMISC\n\n#endif\n"
  },
  {
    "path": "code/nel/src/net/stdnet.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n"
  },
  {
    "path": "code/nel/src/net/stdnet.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"nel/misc/types_nl.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tdefine _WIN32_WINDOWS\t0x0410\n#\tifndef NL_COMP_MINGW\n#\t\tdefine WINVER\t\t\t0x0400\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <winsock2.h>\n#\tinclude <windows.h>\n#endif // NL_OS_WINDOWS\n\n#include <map>\n#include <set>\n#include <list>\n#include <cmath>\n#include <ctime>\n#include <csignal>\n#include <queue>\n\n#include <deque>\n#include <memory>\n#include <string>\n#include <vector>\n#include <cstdio>\n#include <utility>\n#include <cstdlib>\n#include <algorithm>\n#include <exception>\n#include <cctype>\n#include <limits>\n\n#include <errno.h>\n\n#include \"nel/misc/debug.h\"\n\n#include \"nel/misc/common.h\"\n#include \"nel/misc/stream.h\"\n#include \"nel/misc/time_nl.h\"\n#include \"nel/misc/command.h\"\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/mem_stream.h\"\n#include \"nel/misc/hierarchical_timer.h\"\n"
  },
  {
    "path": "code/nel/src/net/tcp_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/tcp_sock.h\"\n#include \"nel/net/net_log.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <winsock2.h>\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#\tdefine socklen_t int\n#\tdefine ERROR_NUM WSAGetLastError()\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#\tinclude <sys/socket.h>\n#\tinclude <netinet/in.h>\n#\tinclude <netinet/tcp.h>\n#\tinclude <arpa/inet.h>\n#\tinclude <netdb.h>\n#\tinclude <cerrno>\n#\tdefine SOCKET_ERROR -1\n#\tdefine INVALID_SOCKET -1\n#\tdefine ERROR_NUM errno\n#\tdefine ERROR_MSG strerror(errno)\ntypedef int SOCKET;\n#endif\n\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Constructor\n */\nCTcpSock::CTcpSock( bool logging ) :\n\tCSock( logging )\n{}\n\n\n/*\n * Construct a CTcpSocket object using an already connected socket\n */\nCTcpSock::CTcpSock( SOCKET sock, const CInetAddress& remoteaddr ) :\n\tCSock( sock, remoteaddr )\n{}\n\n\n/* Connection. You can reconnect a socket after being disconnected.\n * This method does not return a boolean, otherwise a programmer could ignore the result and no\n * exception would be thrown if connection fails :\n * - If addr is not valid, an exception ESocket is thrown\n * - If connect() fails for another reason, an exception ESocketConnectionFailed is thrown\n */\nvoid CTcpSock::connect( const CInetAddress& addr )\n{\n\t// Create a new socket\n\tif ( _Sock != INVALID_SOCKET )\n\t{\n\t  if ( _Logging )\n\t    {\n//\t\tLNETL0_DEBUG( \"LNETL0: Closing socket %d before reconnecting\", _Sock );\n\t    }\n\t  close();\n\t}\n\tcreateSocket( SOCK_STREAM, IPPROTO_TCP );\n\n\t// activate keep alive\n\tsetKeepAlive(true);\n\n\t// Connection\n\tCSock::connect( addr );\n}\n\n\n/*\n * Active disconnection. After disconnecting, you can't connect back with the same socket.\n */\nvoid CTcpSock::disconnect()\n{\n\tLNETL0_DEBUG( \"LNETL0: Socket %d disconnecting from %s...\", _Sock, _RemoteAddr.asString().c_str() );\n\n\t// This shutdown resets the connection immediately (not a graceful closure)\n#ifdef NL_OS_WINDOWS\n\t::shutdown( _Sock, SD_BOTH );\n#elif defined NL_OS_UNIX\n\t::shutdown( _Sock, SHUT_RDWR );\n#endif\n\t/*CSynchronized<bool>::CAccessor sync( &_SyncConnected );\n\tsync.value() = false;*/\n\t_Connected = false;\n}\n\n\n/*\n * Active disconnection for download way only\n */\nvoid CTcpSock::shutdownReceiving()\n{\n#ifdef NL_OS_WINDOWS\n\t::shutdown( _Sock, SD_RECEIVE );\n#elif defined NL_OS_UNIX\n\t::shutdown( _Sock, SHUT_RD );\n#endif\n}\n\n\n/*\n * Active disconnection for upload way only\n */\nvoid CTcpSock::shutdownSending()\n{\n#ifdef NL_OS_WINDOWS\n\t::shutdown( _Sock, SD_SEND );\n#elif defined NL_OS_UNIX\n\t::shutdown( _Sock, SHUT_WR );\n#endif\n}\n\n\n\nvoid CTcpSock::setKeepAlive( bool keepAlive)\n{\n\tnlassert(_Sock != INVALID_SOCKET);\n\tint b = keepAlive?1:0;\n\tif ( setsockopt( _Sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&b, sizeof(b) ) != 0 )\n\t{\n\t\tthrow ESocket( \"setKeepAlive failed\" );\n\t}\n}\n\n/*\n * Sets/unsets TCP_NODELAY\n */\nvoid CTcpSock::setNoDelay( bool value )\n{\n\tint b = value?1:0;\n\tif ( setsockopt( _Sock, IPPROTO_TCP, TCP_NODELAY, (char*)&b, sizeof(b) ) != 0 )\n\t{\n\t\tthrow ESocket( \"setNoDelay failed\" );\n\t}\n}\n\n\n/* Sets a custom TCP Window size (SO_RCVBUF and SO_SNDBUF).\n * You must close the socket is necessary, before calling this method.\n *\n * See http://www.ncsa.uiuc.edu/People/vwelch/net_perf/tcp_windows.html\n */\nvoid CTcpSock::connectWithCustomWindowSize( const CInetAddress& addr, int windowsize )\n{\n\t// Create socket\n\tif ( _Sock != INVALID_SOCKET )\n\t{\n\t\tnlerror( \"Cannot connect with custom window size when already connected\" );\n\t}\n\tcreateSocket( SOCK_STREAM, IPPROTO_TCP );\n\n\t// Change window size\n\tif ( setsockopt( _Sock, SOL_SOCKET, SO_SNDBUF, (char*)&windowsize, sizeof(windowsize) ) != 0\n\t  || setsockopt( _Sock, SOL_SOCKET, SO_RCVBUF, (char*)&windowsize, sizeof(windowsize) ) != 0 )\n\t{\n\t\tthrow ESocket( \"setWindowSize failed\" );\n\t}\n\n\t// Connection\n\tCSock::connect( addr );\n}\n\n\n/*\n * Returns the TCP Window Size for the current socket\n */\nuint32 CTcpSock::getWindowSize()\n{\n\tint windowsize = 0;\n\tsocklen_t len = sizeof( windowsize );\n\n\t/* send buffer -- query for buffer size */\n\tif ( getsockopt( _Sock, SOL_SOCKET, SO_SNDBUF, (char*) &windowsize, &len ) == 0 )\n\t{\n\t\treturn windowsize;\n\t}\n\telse\n\t{\n\t\treturn 0;\n\t}\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/transport_class.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n/*\n * Limitations: Not threadsafe, not reentrant.\n */\n\n//\n// Includes\n//\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/types_nl.h\"\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/entity_id.h\"\n#include \"nel/misc/sheet_id.h\"\n\n#include \"nel/net/unified_network.h\"\n\n#include \"nel/net/transport_class.h\"\n\n\n//\n// Namespace\n//\n\nusing namespace std;\nusing namespace NLMISC;\nusing namespace NLNET;\n\nnamespace NLNET {\n\n//\n// Globals\n//\n\nNLMISC::CVariable<bool> VerboseNETTC(\"nel\",\"VerboseNETTC\",\"Enable verbose logging in CTransportClass operations\",true,0,true);\n\n\n//\n// Variables\n//\n\nuint CTransportClass::Mode = 0;\t// 0=nothing 1=read 2=write 3=register\n\nmap<string, CTransportClass::CRegisteredClass>\tCTransportClass::LocalRegisteredClass;\t// registered class that are in my program\n\nCTransportClass::CRegisteredClass\tCTransportClass::TempRegisteredClass;\n\nNLNET::CMessage\tCTransportClass::TempMessage;\n\nvector<CTransportClass::CRegisteredBaseProp *> CTransportClass::DummyProp;\n\nbool CTransportClass::Init = false;\n\n\n//\n// Functions\n//\n\nstring typeToString (CTransportClass::TProp type)\n{\n\tstring conv[] = {\n\t\t\"PropUInt8\", \"PropUInt16\", \"PropUInt32\", \"PropUInt64\",\n\t\t\"PropSInt8\", \"PropSInt16\", \"PropSInt32\", \"PropSInt64\",\n\t\t\"PropBool\", \"PropFloat\", \"PropDouble\", \"PropString\", \"PropDataSetRow\", \"PropSheetId\", \"PropUCString\", \"PropUKN\" };\n//\t\t\"PropBool\", \"PropFloat\", \"PropDouble\", \"PropString\", \"PropDataSetRow\", \"PropEntityId\", \"PropSheetId\", \"PropUKN\" };\n\n\tif (type > CTransportClass::PropUKN)\n\t\treturn \"<InvalidType>\";\n\treturn conv[type];\n}\n\nvoid CTransportClass::displayDifferentClass (TServiceId sid, const string &className, const vector<CRegisteredBaseProp> &otherClass, const vector<CRegisteredBaseProp *> &myClass)\n{\n\tNETTC_INFO (\"NETTC: Service with sid %hu send me the TransportClass '%s' with differents properties:\", sid.get(), className.c_str());\n\tNETTC_INFO (\"NETTC:  My local TransportClass is:\");\n\tfor (uint i = 0; i < myClass.size(); i++)\n\t{\n\t\tNETTC_INFO (\"NETTC:    Property: %d Name: '%s' type: '%s'\", i, myClass[i]->Name.c_str(), typeToString(myClass[i]->Type).c_str());\n\t}\n\n\tNETTC_INFO (\"NETTC:  The other side TransportClass is:\");\n\tfor (uint i = 0; i < otherClass.size(); i++)\n\t{\n\t\tNETTC_INFO (\"NETTC:    Property: %d Name: '%s' type: '%s'\", i, otherClass[i].Name.c_str(), typeToString(otherClass[i].Type).c_str());\n\t}\n}\n\nvoid CTransportClass::registerOtherSideClass (TServiceId sid, TOtherSideRegisteredClass &osrc)\n{\n\tfor (TOtherSideRegisteredClass::iterator it = osrc.begin(); it != osrc.end (); it++)\n\t{\n\t\t// find the class name in the map\n\n\t\tTRegisteredClass::iterator res = LocalRegisteredClass.find ((*it).first);\n\t\tif (res == LocalRegisteredClass.end ())\n\t\t{\n\t\t\t// The other service knows a class that we don't\n\t\t\t// there was previously an nlwarning here but that was wrong because it is quite normal for this to happen when one service\n\t\t\t// ueses different transport classes to communicate with several different services, so the message has been changed to an nldebug\n\t\t\tNETTC_DEBUG (\"NETTC: the other side class '%s' declared from service %d is not registered in my system, skip it\", (*it).first.c_str(),(uint32)sid.get());\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (sid.get() >= (*res).second.Instance->States.size ())\n\t\t\t(*res).second.Instance->States.resize (sid.get()+1);\n\n\t\t(*res).second.Instance->States[sid.get()].clear ();\n\n\t\tfor (sint j = 0; j < (sint)(*it).second.size (); j++)\n\t\t{\n\t\t\t// check each prop to see the correspondance\n\n\t\t\t// try to find the prop name in the array\n\t\t\tuint k;\n\t\t\tfor (k = 0; k < (*res).second.Instance->Prop.size(); k++)\n\t\t\t{\n\t\t\t\tif ((*it).second[j].Name == (*res).second.Instance->Prop[k]->Name)\n\t\t\t\t{\n\t\t\t\t\tif ((*it).second[j].Type != (*res).second.Instance->Prop[k]->Type)\n\t\t\t\t\t{\n\t\t\t\t\t\tnlwarning (\"NETTC: Property '%s' of the class '%s' have not the same type in the 2 sides (%s %s)\", (*it).second[j].Name.c_str(), (*it).first.c_str(), typeToString((*it).second[j].Type).c_str(), typeToString((*res).second.Instance->Prop[k]->Type).c_str());\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (k == (*res).second.Instance->Prop.size())\n\t\t\t{\n\t\t\t\t// not found, put -1\n\t\t\t\t(*res).second.Instance->States[sid.get()].push_back (make_pair (-1, (*it).second[j].Type));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// same, store the index\n\t\t\t\t(*res).second.Instance->States[sid.get()].push_back (make_pair (k, PropUKN));\n\t\t\t}\n\t\t}\n\n\t\t// check if the version are the same\n\t\tif ((*it).second.size () != (*res).second.Instance->Prop.size ())\n\t\t{\n\t\t\t// 2 class don't have the same number of prop => different class => display class\n\t\t\tdisplayDifferentClass (sid, (*it).first.c_str(), (*it).second, (*res).second.Instance->Prop);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// check if the prop are same\n\t\t\tfor (uint i = 0; i < (*res).second.Instance->Prop.size (); i++)\n\t\t\t{\n\t\t\t\tif ((*res).second.Instance->Prop[i]->Name != (*it).second[i].Name)\n\t\t\t\t{\n\t\t\t\t\t// different name => different class => display class\n\t\t\t\t\tdisplayDifferentClass (sid, (*it).first.c_str(), (*it).second, (*res).second.Instance->Prop);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telse if ((*res).second.Instance->Prop[i]->Type != (*it).second[i].Type)\n\t\t\t\t{\n\t\t\t\t\t// different type => different class => display class\n\t\t\t\t\tdisplayDifferentClass (sid, (*it).first.c_str(), (*it).second, (*res).second.Instance->Prop);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdisplayLocalRegisteredClass ();\n}\n\n\nvoid CTransportClass::registerClass (CTransportClass &instance)\n{\n\tnlassert (Init);\n\tnlassert (Mode == 0);\n\n\t// set the mode to register\n\tMode = 3;\n\n\t// clear the current class\n\tTempRegisteredClass.clear ();\n\n\t// set the instance pointer\n\tTempRegisteredClass.Instance = &instance;\n\n\t// fill name and props\n\tTempRegisteredClass.Instance->description ();\n\n\t// add the new registered class in the array\n\tLocalRegisteredClass[TempRegisteredClass.Instance->Name] = TempRegisteredClass;\n\n\t// set to mode none\n\tMode = 0;\n}\n\nvoid CTransportClass::unregisterClass ()\n{\n\tfor (TRegisteredClass::iterator it = LocalRegisteredClass.begin(); it != LocalRegisteredClass.end (); it++)\n\t{\n\t\tfor (uint j = 0; j < (*it).second.Instance->Prop.size (); j++)\n\t\t{\n\t\t\tdelete (*it).second.Instance->Prop[j];\n\t\t}\n\t\t(*it).second.Instance->Prop.clear ();\n\t\t(*it).second.Instance = NULL;\n\t}\n\tLocalRegisteredClass.clear ();\n}\n\nvoid CTransportClass::displayLocalRegisteredClass (CRegisteredClass &c)\n{\n\tNETTC_DEBUG (\"NETTC:  > %s\", c.Instance->Name.c_str());\n\tfor (uint j = 0; j < c.Instance->Prop.size (); j++)\n\t{\n\t\tNETTC_DEBUG (\"NETTC:    > %s %s\", c.Instance->Prop[j]->Name.c_str(), typeToString(c.Instance->Prop[j]->Type).c_str());\n\t}\n\n\tfor (uint l = 0; l < c.Instance->States.size (); l++)\n\t{\n\t\tif (c.Instance->States[l].size () != 0)\n\t\t{\n\t\t\tNETTC_DEBUG (\"NETTC:      > sid: %u\", l);\n\t\t\tfor (uint k = 0; k < c.Instance->States[l].size (); k++)\n\t\t\t{\n\t\t\t\tNETTC_DEBUG (\"NETTC:      - %d type : %s\", c.Instance->States[l][k].first, typeToString(c.Instance->States[l][k].second).c_str());\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid CTransportClass::displayLocalRegisteredClass ()\n{\n\tNETTC_DEBUG (\"NETTC:> LocalRegisteredClass:\");\n\tfor (TRegisteredClass::iterator it = LocalRegisteredClass.begin(); it != LocalRegisteredClass.end (); it++)\n\t{\n\t\tdisplayLocalRegisteredClass ((*it).second);\n\t}\n}\n\nvoid cbTCReceiveMessage (CMessage &msgin, const string &name, TServiceId sid)\n{\n\tNETTC_DEBUG (\"NETTC: cbReceiveMessage\");\n\n\tCTransportClass::TempMessage.clear();\n\tCTransportClass::TempMessage.assignFromSubMessage( msgin );\n\n\tstring className;\n\tCTransportClass::readHeader(CTransportClass::TempMessage, className);\n\n\tCTransportClass::TRegisteredClass::iterator it = CTransportClass::LocalRegisteredClass.find (className);\n\tif (it == CTransportClass::LocalRegisteredClass.end ())\n\t{\n\t\tnlwarning (\"NETTC: Receive unknown transport class '%s' received from %s-%hu\", className.c_str(), name.c_str(), sid.get());\n\t\treturn;\n\t}\n\n\tnlassert ((*it).second.Instance != NULL);\n\n\tif (!(*it).second.Instance->read (name, sid))\n\t{\n\t\tnlwarning (\"NETTC: Can't read the transportclass '%s' received from %s-%hu (probably not registered on sender service)\", className.c_str(), name.c_str(), sid.get());\n\t}\n}\n\nvoid cbTCReceiveOtherSideClass (CMessage &msgin, const string &/* name */, TServiceId sid)\n{\n\tNETTC_DEBUG (\"NETTC: cbReceiveOtherSideClass\");\n\n\tCTransportClass::TOtherSideRegisteredClass osrc;\n\n\tuint32 nbClass;\n\tmsgin.serial (nbClass);\n\n\tNETTC_DEBUG (\"NETTC: %d class\", nbClass);\n\n\tfor (uint i = 0; i < nbClass; i++)\n\t{\n\t\tstring className;\n\t\tmsgin.serial (className);\n\n\t\tosrc.push_back(make_pair (className, vector<CTransportClass::CRegisteredBaseProp>()));\n\n\t\tuint32 nbProp;\n\t\tmsgin.serial (nbProp);\n\n\t\tNETTC_DEBUG (\"NETTC:   %s (%d prop)\", className.c_str(), nbProp);\n\n\t\tfor (uint j = 0; j < nbProp; j++)\n\t\t{\n\t\t\tCTransportClass::CRegisteredBaseProp prop;\n\t\t\tmsgin.serial (prop.Name);\n\t\t\tmsgin.serialEnum (prop.Type);\n\t\t\tNETTC_DEBUG (\"NETTC:     %s %s\", prop.Name.c_str(), typeToString(prop.Type).c_str());\n\t\t\tosrc[osrc.size()-1].second.push_back (prop);\n\t\t}\n\t}\n\n\t// we have the good structure\n\tCTransportClass::registerOtherSideClass (sid, osrc);\n}\n\nstatic TUnifiedCallbackItem CallbackArray[] =\n{\n\t{ \"CT_LRC\", cbTCReceiveOtherSideClass },\n\t{ \"CT_MSG\", cbTCReceiveMessage },\n};\n\nvoid cbTCUpService (const std::string &serviceName, TServiceId sid, void * /* arg */)\n{\n\tNETTC_DEBUG (\"NETTC: CTransportClass Service %s %hu is up\", serviceName.c_str(), sid.get());\n\tif (sid.get() >= 256)\n\t\treturn;\n\tCTransportClass::sendLocalRegisteredClass (sid);\n}\n\nvoid CTransportClass::init ()\n{\n\t// this isn't an error!\n\tif (Init) return;\n\n\tCUnifiedNetwork::getInstance()->addCallbackArray (CallbackArray, sizeof (CallbackArray) / sizeof (CallbackArray[0]));\n\n\t// create an instance of all d'ifferent prop types\n\n\tDummyProp.resize (PropUKN);\n\n\tnlassert (PropUInt8 < PropUKN); DummyProp[PropUInt8] = new CTransportClass::CRegisteredProp<uint8>;\n\tnlassert (PropUInt16 < PropUKN); DummyProp[PropUInt16] = new CTransportClass::CRegisteredProp<uint16>;\n\tnlassert (PropUInt32 < PropUKN); DummyProp[PropUInt32] = new CTransportClass::CRegisteredProp<uint32>;\n\tnlassert (PropUInt64 < PropUKN); DummyProp[PropUInt64] = new CTransportClass::CRegisteredProp<uint64>;\n\tnlassert (PropSInt8 < PropUKN); DummyProp[PropSInt8] = new CTransportClass::CRegisteredProp<sint8>;\n\tnlassert (PropSInt16 < PropUKN); DummyProp[PropSInt16] = new CTransportClass::CRegisteredProp<sint16>;\n\tnlassert (PropSInt32 < PropUKN); DummyProp[PropSInt32] = new CTransportClass::CRegisteredProp<sint32>;\n\tnlassert (PropSInt64 < PropUKN); DummyProp[PropSInt64] = new CTransportClass::CRegisteredProp<sint64>;\n\tnlassert (PropBool < PropUKN); DummyProp[PropBool] = new CTransportClass::CRegisteredProp<bool>;\n\tnlassert (PropFloat < PropUKN); DummyProp[PropFloat] = new CTransportClass::CRegisteredProp<float>;\n\tnlassert (PropDouble < PropUKN); DummyProp[PropDouble] = new CTransportClass::CRegisteredProp<double>;\n\tnlassert (PropString < PropUKN); DummyProp[PropString] = new CTransportClass::CRegisteredProp<string>;\n//\tnlassert (PropDataSetRow < PropUKN); DummyProp[PropDataSetRow] = new CTransportClass::CRegisteredProp<TDataSetRow>;\n//\tnlassert (PropEntityId < PropUKN); DummyProp[PropEntityId] = new CTransportClass::CRegisteredProp<CEntityId>;\n\tnlassert (PropSheetId < PropUKN); DummyProp[PropSheetId] = new CTransportClass::CRegisteredProp<CSheetId>;\n\tnlassert (PropUCString < PropUKN); DummyProp[PropUCString] = new CTransportClass::CRegisteredProp<ucstring>;\n\n\t// we have to know when a service comes, so add callback (put the callback before all other one because we have to send this message first)\n\tCUnifiedNetwork::getInstance()->setServiceUpCallback(\"*\", cbTCUpService, NULL, false);\n\n\tInit = true;\n}\n\nvoid CTransportClass::release ()\n{\n\tunregisterClass ();\n\n\tfor (uint i = 0; i < DummyProp.size (); i++)\n\t{\n\t\tdelete DummyProp[i];\n\t}\n\tDummyProp.clear ();\n}\n\nvoid CTransportClass::createLocalRegisteredClassMessage ()\n{\n\tTempMessage.clear ();\n\tif (TempMessage.isReading())\n\t\tTempMessage.invert();\n\tTempMessage.setType (\"CT_LRC\");\n\n\tuint32 nbClass = (uint32)LocalRegisteredClass.size ();\n\tTempMessage.serial (nbClass);\n\n\tfor (TRegisteredClass::iterator it = LocalRegisteredClass.begin(); it != LocalRegisteredClass.end (); it++)\n\t{\n\t\tnlassert ((*it).first == (*it).second.Instance->Name);\n\n\t\tTempMessage.serial ((*it).second.Instance->Name);\n\n\t\tuint32 nbProp = (uint32)(*it).second.Instance->Prop.size ();\n\t\tTempMessage.serial (nbProp);\n\n\t\tfor (uint j = 0; j < (*it).second.Instance->Prop.size (); j++)\n\t\t{\n\t\t\t// send the name and the type of the prop\n\t\t\tTempMessage.serial ((*it).second.Instance->Prop[j]->Name);\n\t\t\tTempMessage.serialEnum ((*it).second.Instance->Prop[j]->Type);\n\t\t}\n\t}\n}\n\n\n/*\n * Get the name of message (for displaying), or extract the class name if it is a transport class.\n *\n * Preconditions:\n * - msgin is an input message that contains a valid message\n *\n * Postconditions:\n * - the pos in msgin was modified\n * - msgName contains \"msg %s\" or \"transport class %s\" where %s is the name of message, or the name\n * transport class is the message is a CT_MSG.\n */\nvoid getNameOfMessageOrTransportClass( NLNET::CMessage& msgin, std::string& msgName )\n{\n\tif ( msgin.getName() == \"CT_MSG\" )\n\t{\n\t\ttry\n\t\t{\n\t\t\tmsgin.seek( msgin.getHeaderSize(), NLMISC::IStream::begin );\n\t\t\tmsgin.serial( msgName );\n\t\t}\n\t\tcatch (const EStreamOverflow&)\n\t\t{\n\t\t\tmsgName = \"<Name not found>\";\n\t\t}\n\t\tmsgName = \"transport class \" + msgName;\n\t}\n\telse\n\t{\n\t\tmsgName = \"msg \" + msgin.getName();\n\t}\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/udp_sim_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/config_file.h\"\n\n#include \"nel/net/udp_sock.h\"\n#include \"nel/net/udp_sim_sock.h\"\n\nusing namespace std;\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n//\n// Class\n//\n\nstruct CBufferizedOutPacket\n{\n\tCBufferizedOutPacket (CUdpSock *client, const uint8 *packet, uint32 packetSize, uint32 delay, const CInetAddress *addr):\n\t\tClient(client), PacketSize(packetSize), Time(CTime::getLocalTime()+delay)\n\t{\n\t\tnlassert (packetSize > 0);\n\t\tnlassert (packet != NULL);\n\t\tnlassert (client != NULL);\n\n\t\tPacket = new uint8[packetSize];\n\t\tmemcpy (Packet, packet, packetSize);\n\n\t\tif (addr != NULL)\n\t\t{\n\t\t\tAddr = new CInetAddress;\n\t\t\t*Addr = *addr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tAddr = NULL;\n\t\t}\n\t}\n\n\t~CBufferizedOutPacket ()\n\t{\n\t\tnlassert (Packet != NULL);\n\t\tdelete [] Packet;\n\t\tPacket = NULL;\n\t\tClient = NULL;\n\t\tPacketSize = 0;\n\t\tTime = 0;\n\t\tif (Addr != NULL)\n\t\t\tdelete Addr;\n\t}\n\n\tCUdpSock\t\t*Client;\n\tuint8\t\t\t*Packet;\n\tuint32\t\t\t PacketSize;\n\tTTime\t\t\t Time;\n\tCInetAddress\t*Addr;\n};\n\n\n//\n// Variables\n//\n\n//queue<CBufferizedOutPacket*> CUdpSimSock::BufferizedOutPackets;\n//queue<CBufferizedOutPacket*> CUdpSimSock::BufferizedInPackets;\n\nuint32\tCUdpSimSock::_InLag = 0;\nuint8\tCUdpSimSock::_InPacketLoss = 0;\n\nuint32\tCUdpSimSock::_OutLag = 0;\nuint8\tCUdpSimSock::_OutPacketLoss = 0;\nuint8\tCUdpSimSock::_OutPacketDuplication = 0;\nuint8\tCUdpSimSock::_OutPacketDisordering = 0;\n\n//\n// Functions\n//\n\nvoid CUdpSimSock::sendUDPNow (const uint8 *buffer, uint32 len, const CInetAddress *addr)\n{\n\tif (addr == NULL)\n\t\tUdpSock.send (buffer, len);\n\telse\n\t\tUdpSock.sendTo (buffer, len, *addr);\n}\n\nvoid CUdpSimSock::sendUDP (const uint8 *buffer, uint32& len, const CInetAddress *addr)\n{\n\tnlassert (buffer != NULL);\n\tnlassert (len > 0);\n\n\tif ((float)rand()/(float)(RAND_MAX)*100.0f >= _OutPacketLoss)\n\t{\n\t\tsint32 lag = _OutLag /*+ (rand()%40) - 20*/;// void disordering\n\n\t\tif (lag > 100)\n\t\t{\n\t\t\t// send the packet later\n\n\t\t\tCBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDisordering && _BufferizedOutPackets.size() > 0)\n\t\t\t{\n\t\t\t\tCBufferizedOutPacket *bp2 = _BufferizedOutPackets.back();\n\n\t\t\t\t// exange the time\n\t\t\t\tTTime t = bp->Time;\n\t\t\t\tbp->Time = bp2->Time;\n\t\t\t\tbp2->Time = t;\n\n\t\t\t\t// exange packet in the buffer\n\t\t\t\t_BufferizedOutPackets.back() = bp;\n\t\t\t\tbp = bp2;\n\t\t\t}\n\n\t\t\t_BufferizedOutPackets.push (bp);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)\n\t\t\t{\n\t\t\t\tCBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, lag, addr);\n\t\t\t\t_BufferizedOutPackets.push (bp);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// send the packet NOW\n\n\t\t\tsendUDPNow (buffer, len, addr);\n\n\t\t\t// duplicate the packet\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f < _OutPacketDuplication)\n\t\t\t{\n\t\t\t\tsendUDPNow (buffer, len, addr);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n\nvoid CUdpSimSock::updateBufferizedPackets ()\n{\n\tTTime ct = CTime::getLocalTime ();\n\twhile (!_BufferizedOutPackets.empty())\n\t{\n\t\tCBufferizedOutPacket *bp = _BufferizedOutPackets.front ();\n\t\tif (bp->Time <= ct)\n\t\t{\n\t\t\t// time to send the message\n\t\t\tsendUDPNow (bp->Packet, bp->PacketSize, bp->Addr);\n\t\t\tdelete bp;\n\t\t\t_BufferizedOutPackets.pop ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid\t\t\t\tcbSimVar (CConfigFile::CVar &var)\n{\n\t     if (var.Name == \"SimInLag\") CUdpSimSock::_InLag = var.asInt ();\n\telse if (var.Name == \"SimInPacketLost\") CUdpSimSock::_InPacketLoss = uint8(var.asInt ());\n\telse if (var.Name == \"SimOutLag\") CUdpSimSock::_OutLag = var.asInt ();\n\telse if (var.Name == \"SimOutPacketLost\") CUdpSimSock::_OutPacketLoss = uint8(var.asInt ());\n\telse if (var.Name == \"SimOutPacketDuplication\") CUdpSimSock::_OutPacketDuplication = uint8(var.asInt ());\n\telse if (var.Name == \"SimOutPacketDisordering\") CUdpSimSock::_OutPacketDisordering = uint8(var.asInt ());\n\telse nlstop;\n}\n\nvoid\t\t\t\tCUdpSimSock::setSimValues (NLMISC::CConfigFile &cf)\n{\n\tcf.setCallback (\"SimInLag\", cbSimVar);\n\tcf.setCallback (\"SimInPacketLost\", cbSimVar);\n\tcf.setCallback (\"SimOutLag\", cbSimVar);\n\tcf.setCallback (\"SimOutPacketLost\", cbSimVar);\n\tcf.setCallback (\"SimOutPacketDuplication\", cbSimVar);\n\tcf.setCallback (\"SimOutPacketDisordering\", cbSimVar);\n\n\tCConfigFile::CVar *pv;\n\tpv = cf.getVarPtr(\"SimInLag\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n\tpv = cf.getVarPtr(\"SimInPacketLost\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n\tpv = cf.getVarPtr(\"SimOutLag\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n\tpv = cf.getVarPtr(\"SimOutPacketLost\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n\tpv = cf.getVarPtr(\"SimOutPacketDuplication\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n\tpv = cf.getVarPtr(\"SimOutPacketDisordering\");\n\tif( pv )\n\t\tcbSimVar( *pv );\n}\n\nvoid\t\t\t\tCUdpSimSock::connect( const CInetAddress& addr )\n{\n\tUdpSock.connect (addr);\n}\n\nvoid\t\t\t\tCUdpSimSock::close()\n{\n\tUdpSock.close ();\n}\n\nuint8 buffer [10000];\n\nbool\t\t\t\tCUdpSimSock::dataAvailable ()\n{\n\tupdateBufferizedPackets ();\n\n\tif (_InLag > 0)\n\t{\n\t\twhile (UdpSock.dataAvailable ())\n\t\t{\n\t\t\tCInetAddress addr;\n\t\t\tuint len = 10000;\n\t\t\tUdpSock.receivedFrom (buffer, len, addr);\n\n\t\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f >= _InPacketLoss)\n\t\t\t{\n\t\t\t\tCBufferizedOutPacket *bp = new CBufferizedOutPacket (&UdpSock, buffer, len, _InLag, &addr);\n\t\t\t\t_BufferizedInPackets.push (bp);\n\t\t\t}\n\t\t}\n\n\t\tTTime ct = CTime::getLocalTime ();\n\t\tif (!_BufferizedInPackets.empty() && _BufferizedInPackets.front ()->Time <= ct)\n\t\t\treturn true;\n\t\telse\n\t\t\treturn false;\n\t}\n\telse\n\t{\n\t\tif ((float)rand()/(float)(RAND_MAX)*100.0f >= _InPacketLoss)\n\t\t{\n\t\t\treturn UdpSock.dataAvailable ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// consume data\n\t\t\tif (UdpSock.dataAvailable ())\n\t\t\t{\n\t\t\t\tCInetAddress addr;\n\t\t\t\tuint len = 10000;\n\t\t\t\tUdpSock.receivedFrom (buffer, len, addr);\n\t\t\t}\n\n\t\t\t// packet lost\n\t\t\treturn false;\n\t\t}\n\t}\n}\n\nbool\t\t\t\tCUdpSimSock::receive (uint8 *buffer, uint32& len, bool throw_exception)\n{\n\tif (_InLag> 0)\n\t{\n\t\tif (_BufferizedInPackets.empty())\n\t\t{\n\t\t\tif (throw_exception)\n\t\t\t\tthrow Exception (\"no data available\");\n\t\t\treturn false;\n\t\t}\n\n\t\tCBufferizedOutPacket *bp = _BufferizedInPackets.front ();\n\t\tuint32 s = min (len, bp->PacketSize);\n\t\tmemcpy (buffer, bp->Packet, s);\n\t\tlen = s;\n\n\t\tdelete bp;\n\t\t_BufferizedInPackets.pop ();\n\t\treturn true;\n\t}\n\telse\n\t{\n\t\treturn UdpSock.receive(buffer, len, throw_exception);\n\t}\n}\n\nCSock::TSockResult\tCUdpSimSock::send (const uint8 *buffer, uint32& len, bool /* throw_exception */)\n{\n\tsendUDP (buffer, len);\n\treturn CSock::Ok;\n}\n\nvoid CUdpSimSock::sendTo (const uint8 *buffer, uint32& len, const CInetAddress& addr)\n{\n\tsendUDP (buffer, len, &addr);\n}\n\nbool\t\t\t\tCUdpSimSock::connected()\n{\n\treturn UdpSock.connected ();\n}\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/udp_sock.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/udp_sock.h\"\n#include \"nel/net/net_log.h\"\n\n#ifdef NL_OS_WINDOWS\n#\tinclude <winsock2.h>\n#\tifndef NL_COMP_MINGW\n#\t\tdefine NOMINMAX\n#\tendif\n#\tinclude <windows.h>\n#\tdefine socklen_t int\n#\tdefine ERROR_NUM WSAGetLastError()\n#elif defined NL_OS_UNIX\n#\tinclude <unistd.h>\n#\tinclude <sys/types.h>\n#\tinclude <sys/time.h>\n#\tinclude <sys/socket.h>\n#\tinclude <netinet/in.h>\n#\tinclude <netinet/tcp.h>\n#\tinclude <arpa/inet.h>\n#\tinclude <netdb.h>\n#\tinclude <cerrno>\n//#include <fcntl.h>\n#\tdefine SOCKET_ERROR -1\n#\tdefine INVALID_SOCKET -1\n#\tdefine ERROR_NUM errno\n#\tdefine ERROR_MSG strerror(errno)\ntypedef int SOCKET;\n#endif\n\nusing namespace NLMISC;\n\nnamespace NLNET {\n\n\n/*\n * Constructor\n */\nCUdpSock::CUdpSock( bool logging ) :\n\tCSock( logging ),\n\t_Bound( false )\n{\n\t// Socket creation\n\tcreateSocket( SOCK_DGRAM, IPPROTO_UDP );\n}\n\n\n/** Binds the socket to the specified port. Call bind() for an unreliable socket if the host acts as a server and waits for\n * messages. If the host acts as a client, call sendTo(), there is no need to bind the socket.\n */\nvoid CUdpSock::bind( uint16 port )\n{\n\tCInetAddress addr; // any IP address\n\taddr.setPort( port );\n\tbind( addr );\n\tsetLocalAddress(); // will not set the address if the host is multihomed, use bind(CInetAddress) instead\n}\n\n\n/*\n * Same as bind(uint16) but binds on a specified address/port (useful when the host has several addresses)\n */\nvoid CUdpSock::bind( const CInetAddress& addr )\n{\n#ifndef NL_OS_WINDOWS\n\t// Set Reuse Address On (does not work on Win98 and is useless on Win2000)\n\tint value = true;\n\tif ( setsockopt( _Sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) ) == SOCKET_ERROR )\n\t{\n\t\tthrow ESocket( \"ReuseAddr failed\" );\n\t}\n\n    struct timeval timeout={0,10000};\n    setsockopt(_Sock,SOL_SOCKET,SO_SNDTIMEO,&timeout,sizeof(timeout));\n#else\n    int timeout = 10;\n    setsockopt(_Sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));\n#endif\n\n\t_LocalAddr = addr;\n\n\t// Bind the socket\n\tif ( ::bind( _Sock, (sockaddr*)(_LocalAddr.sockAddr()), sizeof(sockaddr) ) == SOCKET_ERROR )\n\t{\n\t\tthrow ESocket( \"Bind failed\" );\n\t}\n\t_Bound = true;\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d bound at %s\", _Sock, _LocalAddr.asString().c_str() );\n\t}\n}\n\n\n/*\n * Sends a message\n */\nvoid CUdpSock::sendTo( const uint8 *buffer, uint len, const CInetAddress& addr )\n{\n\n\t//  Send\n\tif ( ::sendto( _Sock, (const char*)buffer, len, 0, (sockaddr*)(addr.sockAddr()), sizeof(sockaddr) ) != (sint32)len )\n\t{\n\t\tthrow ESocket( \"Unable to send datagram\" );\n\t}\n\t_BytesSent += len;\n\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d sent %d bytes to %s\", _Sock, len, addr.asString().c_str() );\n\t}\n\n\t// If socket is unbound, retrieve local address\n\tif ( ! _Bound )\n\t{\n\t\tsetLocalAddress();\n\t\t_Bound = true;\n\t}\n\n#ifdef NL_OS_WINDOWS\n\t// temporary by ace to know size of SO_MAX_MSG_SIZE\n\tstatic bool first = true;\n\tif (first)\n\t{\n\t\tuint MMS, SB;\n\t\tint  size = sizeof (MMS);\n\t\tgetsockopt (_Sock, SOL_SOCKET, SO_SNDBUF, (char *)&SB, &size);\n\t\tgetsockopt (_Sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&MMS, &size);\n\t\tLNETL0_INFO (\"LNETL0: The udp SO_MAX_MSG_SIZE=%u, SO_SNDBUF=%u\", MMS, SB);\n\t\tfirst = false;\n\t}\n#endif\n}\n\n\n/*\n * Receives data from the peer. (blocking function)\n */\nbool CUdpSock::receive( uint8 *buffer, uint32& len, bool throw_exception )\n{\n\tnlassert( _Connected && (buffer!=NULL) );\n\n\t// Receive incoming message\n\tlen = ::recv( _Sock, (char*)buffer, len , 0 );\n\n\t// Check for errors (after setting the address)\n\tif ( ((int)len) == SOCKET_ERROR )\n\t{\n\t\tif ( throw_exception )\n\t\t\tthrow ESocket( \"Cannot receive data\" );\n\t\treturn false;\n\t}\n\n\t_BytesReceived += len;\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d received %d bytes from peer %s\", _Sock, len, _RemoteAddr.asString().c_str() );\n\t}\n\treturn true;\n}\n\n\n/*\n * Receives data and say who the sender is. (blocking function)\n */\nbool CUdpSock::receivedFrom( uint8 *buffer, uint& len, CInetAddress& addr, bool throw_exception )\n{\n\t// Receive incoming message\n\tsockaddr_in saddr;\n\tsocklen_t saddrlen = sizeof(saddr);\n\n\tlen = ::recvfrom( _Sock, (char*)buffer, len , 0, (sockaddr*)&saddr, &saddrlen );\n\n\t// If an error occurs, the saddr is not valid\n\t// When the remote socket is closed, get sender's address to know who is quitting\n\taddr.setSockAddr( &saddr );\n\n\t// Check for errors (after setting the address)\n\tif ( ((int)len) == SOCKET_ERROR )\n\t{\n\t\tif ( throw_exception )\n\t\t\tthrow ESocket( \"Cannot receive data\" );\n\t\treturn false;\n\t}\n\n\t_BytesReceived += len;\n\tif ( _Logging )\n\t{\n\t\tLNETL0_DEBUG( \"LNETL0: Socket %d received %d bytes from %s\", _Sock, len, addr.asString().c_str() );\n\t}\n\treturn true;\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/unified_network.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n#include \"nel/misc/entity_id.h\" // for createMessage()\n#include \"nel/misc/variable.h\"\n#include \"nel/misc/thread.h\"\n#include \"nel/misc/mutex.h\"\n\n#include \"nel/net/unified_network.h\"\n#include \"nel/net/module_common.h\"\n#include \"nel/net/naming_client.h\"\n\n#ifdef NL_OS_UNIX\n#include <sched.h>\n#endif\n\nusing namespace std;\nusing namespace NLMISC;\n\n\nnamespace NLNET {\n\nstatic size_t ThreadCreator = 0;\n\nstatic const uintptr_t AppIdDeadConnection = 0xDEAD;\n\nuint32 TotalCallbackCalled = 0;\n\nuint32 TimeInCallback =0;\n\n#ifdef NL_OS_UNIX\n/// Yield method (Unix only)\nCVariable<uint32> UseYieldMethod(\"nel\", \"UseYieldMethod\", \"0=select 1=usleep 2=nanosleep 3=sched_yield 4=none\", 0, 0, true );\n#endif\n\n/// Reduce sending lag\nCVariable<bool> FlushSendsBeforeSleep(\"nel\", \"FlushSendsBeforeSleep\", \"If true, send buffers will be flushed before sleep, not in next update\", true, 0, true );\n\n/// Network congestion monitoring\nCVariable<uint> L5TotalBytesInLowLevelSendQueues(\"nel\", \"L5TotalBytesInLowLevelSendQueues\", \"Number of bytes pending in send queues (postponed by non-blocking send()) for network congestion monitoring. N/A if FlushSendsBeforeSleep disabled)\", 0, 0, true );\n\n/// Receiving size limit\nCVariablePtr<uint32> DefaultMaxExpectedBlockSize(\"nel\", \"DefaultMaxExpectedBlockSize\", \"If receiving more than this value in bytes, the connection will be dropped\", &CBufNetBase::DefaultMaxExpectedBlockSize, true );\n\n/// Sending size limit\nCVariablePtr<uint32> DefaultMaxSentBlockSize(\"nel\", \"DefaultMaxSentBlockSize\", \"If sending more than this value in bytes, the program may be stopped\", &CBufNetBase::DefaultMaxSentBlockSize, true );\n\n#define AUTOCHECK_DISPLAY nlwarning\n//#define AUTOCHECK_DISPLAY CUnifiedNetwork::getInstance()->displayInternalTables (), nlerror\n\nconst TServiceId\tTServiceId::InvalidId = TServiceId(std::numeric_limits<uint16>::max());\n\n//\n// Callbacks from NAMING SERVICE\n//\n\n// when a service registers\nvoid\tuNetRegistrationBroadcast(const string &name, TServiceId sid, const vector<CInetAddress> &addr)\n{\n\tnldebug (\"HNETL5: + naming %s-%u '%s'\", name.c_str(), sid.get(), vectorCInetAddressToString(addr).c_str ());\n\n\tCUnifiedNetwork *uni= CUnifiedNetwork::getInstance();\n\n\tif (uni->_SId == sid)\n\t{\n\t\t// it's me! don't add me!!!\n\t\treturn;\n\t}\n\n\t// add the unified connection\n\n\tif(sid.get() >= uni->_IdCnx.size ())\n\t\tuni->_IdCnx.resize (sid.get()+1);\n\n\tif (uni->_IdCnx[sid.get()].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t{\n\t\tuni->_IdCnx[sid.get()] = CUnifiedNetwork::CUnifiedConnection(name, sid, false);\n\t\tuni->_UsedConnection.push_back (sid);\n\t}\n\n\tif (!uni->_IdCnx[sid.get()].ExtAddress.empty ())\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: %s-%u already inserted in the table with '%s'\", name.c_str(), sid.get(), vectorCInetAddressToString (uni->_IdCnx[sid.get()].ExtAddress).c_str ());\n\n\t// set the list of external addresses\n\n\tnlassert (!addr.empty());\n\n\tuni->_IdCnx[sid.get()].ExtAddress = addr;\n\n\t// associate nid with ext address\n\tuni->_IdCnx[sid.get()].setupNetworkAssociation (uni->_NetworkAssociations, uni->_DefaultNetwork);\n}\n\n// when a service unregisters\nvoid\tuNetUnregistrationBroadcast(const string &name, TServiceId sid, const vector<CInetAddress> &addr)\n{\n\tnldebug (\"HNETL5: - naming %s-%u '%s'\", name.c_str(), sid.get(), vectorCInetAddressToString (addr).c_str ());\n\n\t// get the service connection\n\tCUnifiedNetwork *uni = CUnifiedNetwork::getInstance();\n\n\tCUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);\n\tif (uc == 0) return;\t// should never happen, the getUnifiedConnection() will generate a AUTOCHECK_DISPLAY\n\n\t// call the user callback\n\n\tuni->callServiceDownCallback(uc->ServiceName, uc->ServiceId);\n\n\tif(!uc->Connections.empty ())\n\t{\n\t\t// set all connection to dead, now, all messages received on this socket will be ignored and closed\n\t\tfor (uint i = 0; i < uc->Connections.size (); ++i)\n\t\t{\n\t\t\tif (uc->Connections[i].valid())\n\t\t\t\tuc->Connections[i].setAppId (AppIdDeadConnection);\n\t\t}\n\n\t\t//\n\t\t// It's the first connection that added the _NamedCnx so if there's no connection, no need to\n\t\t// remove entry in _NamedCnx\n\t\t//\n\n\t\tuni->removeNamedCnx (uc->ServiceName, uc->ServiceId);\n\t}\n\n\t// remove the _UsedConnection\n\tbool found = false;\n\tfor (vector<TServiceId>::iterator it = uni->_UsedConnection.begin (); it != uni->_UsedConnection.end(); it++)\n\t{\n\t\tif (*it == uc->ServiceId)\n\t\t{\n\t\t\tfound = true;\n\t\t\tuni->_UsedConnection.erase (it);\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!found)\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: can't find the sid %hu in the _UsedConnection\", uc->ServiceId.get());\n\n\t// reset the unified connection\n\tuc->reset ();\n}\n\n\n//\n// Callbacks from connection/disconnection services\n//\n\nvoid\tuncbConnection(TSockId from, void * /* arg */)\n{\n\tnlinfo (\"HNETL5: + connec '%s'\", from->asString().c_str());\n\n\tfrom->setAppId (AppIdDeadConnection);\n}\n\nvoid\tuncbDisconnection(TSockId from, void * /* arg */)\n{\n\tif(from->appId () == AppIdDeadConnection)\n\t{\n\t\tnlinfo (\"HNETL5: - connec '%s'\", from->asString().c_str());\n\t}\n\telse\n\t{\n\t\tCUnifiedNetwork\t*uni = CUnifiedNetwork::getInstance();\n\t\tTServiceId\t\tsid(uint16(from->appId()));\n\t\tCUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);\n\t\tif (uc == 0)\n\t\t{\n\t\t\tnlinfo (\"HNETL5: - connec '%s' sid %hu\", from->asString().c_str(), sid.get());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlinfo (\"HNETL5: - connec '%s' %s-%hu\", from->asString().c_str(), uc->ServiceName.c_str (), sid.get());\n\n\t\t\tif (uc->IsExternal)\n\t\t\t{\n\t\t\t\tif (!uc->AutoRetry)\n\t\t\t\t{\n\t\t\t\t\t// If it s a external service with no auto retry, remove the connection\n\n\t\t\t\t\t// call the user callback\n\t\t\t\t\tuni->callServiceDownCallback(uc->ServiceName, uc->ServiceId);\n\n\t\t\t\t\tuni->removeNamedCnx (uc->ServiceName, uc->ServiceId);\n\n\t\t\t\t\tuni->_ConnectionToReset.push_back(uc->ServiceId);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// call the user callback\n\t\t\t\t\tuni->callServiceDownCallback(uc->ServiceName, uc->ServiceId);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// reset the connection\n\t\t\t\tuint i;\n\t\t\t\tfor (i = 0; i < uc->Connections.size (); i++)\n\t\t\t\t{\n\t\t\t\t\tif (uc->Connections[i].valid() && uc->Connections[i].CbNetBase->getSockId(uc->Connections[i].HostId) == from)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (uc->Connections[i].IsServerConnection)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// we have to remove the stuffs now because HostId will not be accessible later\n\t\t\t\t\t\t\tuc->Connections[i].reset();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// if it s a client, we can't delete now because the callback client is currently in use\n\t\t\t\t\t\t\t// only disconnect\n\t\t\t\t\t\t\tif(uc->Connections[i].CbNetBase->connected ())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuc->Connections[i].CbNetBase->disconnect (uc->Connections[i].HostId);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (i == uc->Connections.size ())\n\t\t\t\t{\n\t\t\t\t\tAUTOCHECK_DISPLAY (\"HNETL5: received a disconnection from a service but the connection is not in my list!\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfrom->setAppId (AppIdDeadConnection);\n\t}\n}\n\n//\n// Callback from identification services\n//\n\nvoid\tuncbServiceIdentification(CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tstring\t\tinSName;\n\tTServiceId\tinSid;\n\n\tif (from->appId () != AppIdDeadConnection)\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: received a connect ident from an unknown connection 0x%\" NL_I64 \"X\", from->appId ());\n\n\t// recover the service name and id\n\tmsgin.serial(inSName);\n\tmsgin.serial(inSid);\n\tuint8 pos;\n\tmsgin.serial (pos);\n\tbool isExternal;\n\tmsgin.serial (isExternal);\n\n\tnlinfo (\"HNETL5: + connect ident '%s' %s-%hu pos %hu ext %d\", from->asString().c_str(), inSName.c_str(), inSid.get(), (uint16)pos, (uint8)isExternal);\n\n\tif(isExternal)\n\t{\n\t\tnlassert (pos == 0);\n\t}\n\n\tif (inSid.get() == 0)\n\t{\n\t\tif (isExternal)\n\t\t{\n\t\t\tinSid = CUnifiedNetwork::getInstance ()->_ExtSId;\n\t\t\tCUnifiedNetwork::getInstance ()->_ExtSId.set(CUnifiedNetwork::getInstance ()->_ExtSId.get()+1);\n\t\t\t// the following was an nlwarning but this is in fact desired behavior and not an error so we have changed to nlinfo\n\t\t\tnlinfo (\"HNETL5: Received a connection from a service with a SId 0, we give him the SId %d\", inSid.get());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Received a connection from a service with a SId 0 and wasn't external, disconnecting it\");\n\t\t\tnetbase.disconnect();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tfrom->setAppId(inSid.get());\n\n\t// add a new connection to the list\n\tCUnifiedNetwork\t\t*uni= CUnifiedNetwork::getInstance();\n\n\tif(inSid.get() >= uni->_IdCnx.size ())\n\t{\n\t\tuni->_IdCnx.resize (inSid.get()+1);\n\t}\n\n\tswitch(uni->_IdCnx[inSid.get()].State)\n\t{\n\tcase CUnifiedNetwork::CUnifiedConnection::NotUsed:\t\t// add the new unified connection\n\t\tuni->_IdCnx[inSid.get()] = CUnifiedNetwork::CUnifiedConnection(inSName, inSid, isExternal);\n\t\tuni->_UsedConnection.push_back (inSid);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (uni->_IdCnx[inSid.get()].IsExternal != isExternal)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: Receive a connection that is not totally external %d %d\", uni->_IdCnx[inSid.get()].IsExternal, isExternal);\n\t\treturn;\n\t}\n\n\tbool FirstConnection = (uni->_IdCnx[inSid.get()].Connections.size () == 0);\n\n\t// add the connection to the already inserted unified connection\n\tif (pos >= uni->_IdCnx[inSid.get()].Connections.size ())\n\t{\n\t\tuni->_IdCnx[inSid.get()].Connections.resize(pos+1);\n\t}\n\tuni->_IdCnx[inSid.get()].Connections[pos] = CUnifiedNetwork::CUnifiedConnection::TConnection(&netbase, from);\n\n\t// If the connection is external, we'll never receive the ExtAddress by the naming service, so add it manually\n\tif (isExternal)\n\t{\n\t\tuni->_IdCnx[inSid.get()].ExtAddress.push_back (netbase.hostAddress (from));\n\t\tuni->_IdCnx[inSid.get()].setupNetworkAssociation (uni->_NetworkAssociations, uni->_DefaultNetwork);\n\t}\n\n\t// send the callback to the user with the first connection\n\tif (FirstConnection)\n\t{\n\t\t// insert the name in the map to be able to send message with the name\n\t\tuni->addNamedCnx (inSName, inSid);\n\n\t\tuni->callServiceUpCallback (inSName, inSid);\n\t}\n}\n\n// the callbacks wrapper\nvoid\tuncbMsgProcessing(CMessage &msgin, TSockId from, CCallbackNetBase &/* netbase */)\n{\n\tif (from->appId() == AppIdDeadConnection)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: Receive a message from a dead connection\");\n\t\treturn;\n\t}\n\n\tCUnifiedNetwork\t\t\t\t\t\t\t\t\t*uni = CUnifiedNetwork::getInstance();\n\tTServiceId\t\t\t\t\t\t\t\t\t\tsid(uint16(from->appId()));\n\tCUnifiedNetwork::TMsgMappedCallback::iterator\titcb;\n\n\titcb = uni->_Callbacks.find(msgin.getName());\n\tif (itcb == uni->_Callbacks.end())\n\t{\n\t\t// the callback doesn't exist\n\t\tnlwarning (\"HNETL5: Can't find callback '%s' called by service %hu\", msgin.getName().c_str(), sid.get());\n\t}\n\telse\n\t{\n\t\tCUnifiedNetwork::CUnifiedConnection *uc = uni->getUnifiedConnection (sid);\n\n\t\tif (uc == 0)\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Received a message from a service %hu that is not ready (bad appid? 0x%\" NL_I64 \"X)\", sid.get(), from->appId ());\n\t\t\treturn;\n\t\t}\n\t\tif((*itcb).second == 0)\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Received message %s from a service %hu but the associated callback is NULL\", msgin.getName ().c_str(), sid.get());\n\t\t\treturn;\n\t\t}\n\n\t\t{\n\t\t\tstatic map<string, CHTimer> timers;\n\t\t\tmap<string, CHTimer>::iterator it;\n\n\t\t\t{\n\t\t\t\tH_AUTO(L5UCHTimerOverhead);\n\t\t\t\tstring callbackName = \"USRCB_\" + msgin.getName();\n\t\t\t\tit = timers.find(callbackName);\n\t\t\t\tif(it == timers.end())\n\t\t\t\t{\n\t\t\t\t\tit = timers.insert(make_pair(callbackName, CHTimer(NULL))).first;\n\t\t\t\t\t(*it).second.setName((*it).first.c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t{\n\t\t\t\tH_AUTO(L5UserCallback);\n\n\t\t\t\tTTime before = CTime::getLocalTime();\n\n\t\t\t\t(*it).second.before();\n//\t\t\t\tconst std::string &cbName = itcb->first;\n\t\t\t\t(*itcb).second (msgin, uc->ServiceName, sid);\n\t\t\t\t(*it).second.after();\n\n\t\t\t\tTTime after = CTime::getLocalTime();\n\n\t\t\t\t// sum the time used to do callback\n\t\t\t\tTimeInCallback += uint32((after-before));\n\t\t\t}\n\t\t}\n\n\t\tuc->TotalCallbackCalled++;\n\t\tTotalCallbackCalled++;\n\t}\n}\n\n\nTCallbackItem\tunServerCbArray[] =\n{\n\t{ \"UN_SIDENT\", uncbServiceIdentification }\n};\n\n\n//\n// Alive check thread\n//\n\nclass CAliveCheck : public NLMISC::IRunnable\n{\npublic:\n\tCAliveCheck() : ExitRequired(false)\t{ }\n\n\tvirtual void\trun();\n\tvirtual\t\t\t~CAliveCheck()\t{ }\n\n\tvolatile bool\tExitRequired;\n\n\tstatic CAliveCheck*\tThread;\n\n\tstruct CCheckAddress\n\t{\n\t\tCCheckAddress() : ConnectionId(0xDEAD), NeedCheck(false), AddressValid(false) { }\n\t\tCInetAddress\tAddress;\n\t\tstd::string\t\tServiceName;\n\t\tTServiceId\t\tServiceId;\n\t\tuint\t\t\tConnectionId;\n\t\tuint\t\t\tConnectionIndex;\n\t\tvolatile bool\tNeedCheck;\n\t\tvolatile bool\tAddressValid;\n\t};\n\n\tCCheckAddress\t\tCheckList[128];\n\n\tvoid\t\t\tcheckService(CInetAddress address, uint connectionId, uint connectionIndex, const std::string &service, TServiceId id);\n\n};\n\nCAliveCheck*\tCAliveCheck::Thread = NULL;\nIThread*\t\tAliveThread = NULL;\n\n\nvoid\tCAliveCheck::run()\n{\n\t// setup thread\n\tThread = this;\n\n\tTTime\tt = CTime::getLocalTime();\n\n\twhile (!ExitRequired)\n\t{\n\t\tif (CTime::getLocalTime() - t < 10000)\n\t\t{\n\t\t\tnlSleep(100);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor ( uint32 i=0; i<sizeof(CheckList)/sizeof(CheckList[0]); ++i)\n\t\t{\n\t\t\tif (CheckList[i].NeedCheck && !CheckList[i].AddressValid)\n\t\t\t{\n\t\t\t\ttry\n\t\t\t\t{\n                    CTcpSock\t_ts;\n                    _ts.connect(CheckList[i].Address);\n                    // success (no exception)\n                    CheckList[i].AddressValid = true;\n                    _ts.disconnect();\n\n\t\t\t\t\t//CCallbackClient\tcbc;\n\t\t\t\t\t//cbc.connect(CheckList[i].Address);\n\t\t\t\t\t//// success (no exception)\n\t\t\t\t\t//CheckList[i].AddressValid = true;\n\t\t\t\t\t//cbc.disconnect();\n\t\t\t\t}\n\t\t\t\tcatch (const ESocketConnectionFailed &e)\n\t\t\t\t{\n#if FINAL_VERSION\n\t\t\t\t\tnlinfo (\"HNETL5: can't connect to %s-%hu now (%s)\", CheckList[i].ServiceName.c_str(), CheckList[i].ServiceId.get(), e.what ());\n#else\n\t\t\t\t\tnlwarning (\"HNETL5: can't connect to %s-%hu now (%s)\", CheckList[i].ServiceName.c_str(), CheckList[i].ServiceId.get(), e.what ());\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tt = CTime::getLocalTime();\n\t}\n\n\tExitRequired = false;\n}\n\nvoid\tCAliveCheck::checkService(CInetAddress address, uint connectionId, uint connectionIndex, const std::string &service, TServiceId id)\n{\n\tfor (uint i=0; i<sizeof(CheckList)/sizeof(CheckList[0]); ++i)\n\t{\n\t\tif (CheckList[i].NeedCheck)\n\t\t\tcontinue;\n\n\t\tCheckList[i].Address = address;\n\t\tCheckList[i].ConnectionId = connectionId;\n\t\tCheckList[i].ConnectionIndex = connectionIndex;\n\t\tCheckList[i].ServiceName = service;\n\t\tCheckList[i].ServiceId = id;\n\n\t\tCheckList[i].AddressValid = false;\n\t\tCheckList[i].NeedCheck = true;\n\n\t\treturn;\n\t}\n}\n\n\n//\n//\n//\n\nbool\tCUnifiedNetwork::init(const CInetAddress *addr, CCallbackNetBase::TRecordingState rec,\n\t\t\t\t\t\t\t  const string &shortName, uint16 port, TServiceId &sid)\n{\n\t// the commands can now be invoked\n\tregisterCommandsHandler();\n\n\tif (_Initialised)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: Unified network layer already initialized\");\n\t\treturn true;\n\t}\n\n\tThreadCreator = NLMISC::getThreadId();\n\n\tvector<CInetAddress> laddr = CInetAddress::localAddresses();\n\n\t_RecordingState = rec;\n\t_Name = shortName;\n\t_SId = sid;\n\n\tif (addr != 0)\n\t\t_NamingServiceAddr = *addr;\n\n\t// if the address isn't 0, uses the naming service\n\tif (_NamingServiceAddr.isValid ())\n\t{\n\t\t// connect the callback to know when a new service comes in or goes down\n\t\tCNamingClient::setRegistrationBroadcastCallback(uNetRegistrationBroadcast);\n\t\tCNamingClient::setUnregistrationBroadcastCallback(uNetUnregistrationBroadcast);\n\n\t\t// connect to the naming service (may generate a ESocketConnectionFailed exception)\n\t\tCNamingClient::connect(_NamingServiceAddr, _RecordingState, laddr);\n\n\t\tif (port == 0)\n\t\t\tport = CNamingClient::queryServicePort ();\n\t}\n\n#ifdef NL_OS_UNIX\n\t/// Init the main pipe to select() on data available\n\tif ( ::pipe( _MainDataAvailablePipe ) != 0 )\n\t\tnlwarning( \"Unable to create main D.A. pipe\" );\n\t//nldebug( \"Pipe: created\" );\n#endif\n\n\t// setup the server callback only if server port != 0, otherwise there's no server callback\n\t_ServerPort = port;\n\n\tif(_ServerPort != 0)\n\t{\n\t\tnlassert (_CbServer == 0);\n\t\t_CbServer = new CCallbackServer( CCallbackNetBase::Off, \"\", true, false ); // don't init one pipe per connection\n#ifdef NL_OS_UNIX\n\t\t_CbServer->setExternalPipeForDataAvailable( _MainDataAvailablePipe ); // the main pipe is shared for all connections\n\t\t//nldebug( \"Pipe: set (server %p)\", _CbServer );\n#endif\n\t\tbool retry = false;\n\t\tdo\n\t\t{\n\t\t\tretry = false;\n\t\t\ttry\n\t\t\t{\n\t\t\t\t_CbServer->init(port);\n\t\t\t}\n\t\t\tcatch (const ESocket &)\n\t\t\t{\n\t\t\t\tnlwarning(\"Failed to init the listen socket on port %u, is the service already running ?\", port);\n\t\t\t\t// wait a little before retrying\n\t\t\t\tnlSleep(5000);\n\n\t\t\t\tretry = true;\n\t\t\t}\n\t\t} while(retry);\n\n\t\t_CbServer->addCallbackArray(unServerCbArray, 1);\t\t\t\t// the service ident callback\n\t\t_CbServer->setDefaultCallback(uncbMsgProcessing);\t\t\t\t// the default callback wrapper\n\t\t_CbServer->setConnectionCallback(uncbConnection, NULL);\n\t\t_CbServer->setDisconnectionCallback(uncbDisconnection, NULL);\n\t}\n\telse\n\t{\n\t\tnlinfo (\"HNETL5: ServerPort is 0 so I don't create a CCallbackServer\");\n\t}\n\n\tif (CNamingClient::connected())\n\t{\n\t\t// register the service\n\t\tfor (uint i = 0; i < laddr.size(); i++)\n\t\t\tladdr[i].setPort(_ServerPort);\n\n\t\tif (_SId.get() == 0)\n\t\t{\n\t\t\tif ( ! CNamingClient::registerService(_Name, laddr, _SId) )\n\t\t\t{\n\t\t\t\tnlinfo (\"HNETL5: Registration denied\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCNamingClient::registerServiceWithSId(_Name, laddr, _SId);\n\t\t}\n\n\t\tsid = _SId;\n\n\t\tnlinfo (\"HNETL5: Server '%s' added, registered and listen to port %hu\", _Name.c_str (), _ServerPort);\n\t}\n\n\tAliveThread = IThread::create(new CAliveCheck(), 1024*32);\n\tAliveThread->start();\n\n\t_Initialised = true;\n\treturn true;\n}\n\nvoid\tCUnifiedNetwork::connect()\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::connect() whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tif (CNamingClient::connected())\n\t{\n\t\t// get the services list\n\t\tconst list<CNamingClient::CServiceEntry>\t&services = CNamingClient::getRegisteredServices();\n\n\t\t// connects to the registered services\n\t\tlist<CNamingClient::CServiceEntry>::const_iterator\tits;\n\n\t\t// don't connect to itself\n\t\tfor (its = services.begin(); its != services.end(); ++its)\n\t\t{\n\t\t\tif (_SId != (*its).SId)\n\t\t\t{\n\t\t\t\t// add service with name, address, ident, not external, service id, and not autoretry (obsolete)\n\t\t\t\t// we put the last true because the name callback should already inserted it by uNetRegistrationBroadcast()\n\t\t\t\taddService((*its).Name, (*its).Addr, true, false, (*its).SId, false, true);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// don't process services received after mine because they'll connect to me\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid\tCUnifiedNetwork::release(bool mustFlushSendQueues, const std::vector<std::string>& namesOfOnlyServiceToFlushSending)\n{\n\tif (!_Initialised)\n\t\treturn;\n\n\t// the commands can't be invoked\n\tunregisterCommandsHandler();\n\n\t// terminate the auto reconnection thread\n\tif (CAliveCheck::Thread)\n\t{\n\t\tCAliveCheck::Thread->ExitRequired = true;\n\t\tAliveThread->wait();\n\t\tdelete CAliveCheck::Thread;\n\t\tdelete AliveThread;\n\t}\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\t// Ensure all outgoing data are sent before disconnecting, if requested\n\tif ( mustFlushSendQueues )\n\t{\n\t\tnlinfo( \"HNETL5: Flushing sending queues...\" );\n\t\tfloat totalBytes = 0;\n\t\tuint bytesRemaining, i=0;\n\t\twhile ( (bytesRemaining = tryFlushAllQueues( namesOfOnlyServiceToFlushSending )) != 0 )\n\t\t{\n\t\t\tif ( i == 0 )\n\t\t\t\ttotalBytes = (float)bytesRemaining;\n\t\t\tif ( i % 20 == 0 )\n\t\t\t{\n\t\t\t\tnldebug( \"%.1f%% of %.3f KB flushed so far\", // display without HNETL5 to bypass filters!\n\t\t\t\t\t((float)(bytesRemaining-totalBytes))/totalBytes, totalBytes / 1024.0f );\n\t\t\t}\n\n\t\t\t++i;\n\n\t\t\tnlSleep( 100 );\n\t\t}\n\t\tnldebug( \"HNETL5: Flush done in %u steps\", i+1 );\n\t}\n\n\t// disconnect all clients\n\tif(_CbServer)\n\t{\n\t\t_CbServer->disconnect(InvalidSockId);\n\t\tdelete _CbServer;\n\t\t_CbServer = 0;\n\t}\n\n\t// disconnect all connections to servers\n\tfor (uint i = 0; i<_IdCnx.size(); ++i)\n\t{\n\t\tif (_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t\t{\n\t\t\tfor(uint j = 0 ; j < _IdCnx[i].Connections.size (); j++)\n\t\t\t{\n\t\t\t\tif (_IdCnx[i].Connections[j].valid() && !_IdCnx[i].Connections[j].IsServerConnection)\n\t\t\t\t{\n\t\t\t\t\tif (_IdCnx[i].Connections[j].CbNetBase->connected ())\n\t\t\t\t\t\t_IdCnx[i].Connections[j].CbNetBase->disconnect();\n\n\t\t\t\t\tdelete _IdCnx[i].Connections[j].CbNetBase;\n\t\t\t\t}\n\t\t\t}\n\t\t\t_IdCnx[i].Connections.clear ();\n\t\t}\n\t}\n\n\t// clear all other data\n\t_IdCnx.clear();\n\t_UsedConnection.clear ();\n\t_NamedCnx.clear();\n\t_UpCallbacks.clear();\n\t_DownCallbacks.clear();\n\t_Callbacks.clear();\n\n\t// disconnect the connection with the naming service\n\tif (CNamingClient::connected ())\n\t\tCNamingClient::disconnect ();\n\n#ifdef NL_OS_UNIX\n\t::close( _MainDataAvailablePipe[PipeRead] );\n\t::close( _MainDataAvailablePipe[PipeWrite] );\n#endif\n}\n\nvoid\tCUnifiedNetwork::addService(const string &name, const CInetAddress &addr, bool sendId, bool external, TServiceId sid, bool autoRetry, bool shouldBeAlreayInserted)\n{\n\tvector <CInetAddress> addrs;\n\taddrs.push_back (addr);\n\taddService (name, addrs, sendId, external, sid, autoRetry, shouldBeAlreayInserted);\n}\n\nvoid\tCUnifiedNetwork::addService(const string &name, const vector<CInetAddress> &addr, bool sendId, bool external, TServiceId sid, bool autoRetry, bool shouldBeAlreayInserted)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::addService() whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tif (external)\n\t{\n\t\tsid = _ExtSId;\n\t\t_ExtSId.set(_ExtSId.get()+1);\n\t}\n\n\tnlinfo(\"HNETL5: addService %s-%hu '%s'\", name.c_str(), sid.get(), vectorCInetAddressToString(addr).c_str());\n\n\tif (external && addr.size () != 1)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: Can't add external service with more than one connection\");\n\t}\n\n\t// add the entry in the unified connection table\n\n\tif (sid.get() >= _IdCnx.size())\n\t\t_IdCnx.resize(sid.get()+1);\n\n\tCUnifiedConnection\t*uc = &_IdCnx[sid.get()];\n\n\t// at this point it s possible that the service already added in the _IdCnx by the uNetRegistrationBroadcast()\n\n\tif (shouldBeAlreayInserted && _IdCnx[sid.get()].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)  AUTOCHECK_DISPLAY (\"HNETL5: the unified connection should already set by the naming reg broadcast and is not (%hu)\", sid.get());\n\tif (!shouldBeAlreayInserted && _IdCnx[sid.get()].State == CUnifiedNetwork::CUnifiedConnection::Ready)  AUTOCHECK_DISPLAY (\"HNETL5: the unified connection should not already set but is (%hu)\", sid.get());\n\n\tif (_IdCnx[sid.get()].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t{\n\t\t*uc = CUnifiedConnection(name, sid, external);\n\t\t_UsedConnection.push_back (sid);\n\t}\n\telse\n\t{\n\t\t// If the entry already set, check that all is correct\n\t\tif (name != uc->ServiceName) AUTOCHECK_DISPLAY (\"HNETL5: name are different in addService %s %s\", name.c_str (), uc->ServiceName.c_str ());\n\t\tif (sid != uc->ServiceId) AUTOCHECK_DISPLAY (\"HNETL5: sid are different in addService %hu %hu\", sid.get(), uc->ServiceId.get());\n\t\tif (addr != uc->ExtAddress) AUTOCHECK_DISPLAY (\"HNETL5: external addr are different in addService '%s' '%s'\", vectorCInetAddressToString(addr).c_str(), vectorCInetAddressToString(uc->ExtAddress).c_str ());\n\t}\n\tuc->AutoRetry = autoRetry;\n\tuc->SendId = sendId;\n\tuc->ExtAddress = addr;\n\tnlassert (!addr.empty());\n\n\t// associate nid with ext address\n\tuc->setupNetworkAssociation (_NetworkAssociations, _DefaultNetwork);\n\n\t// connect to all connection\n\tbool\tconnectSuccess;\n\n\tif (uc->Connections.size () < addr.size ())\n\t{\n\t\tuc->Connections.resize (addr.size ());\n\t}\n\n\tvector<CInetAddress> laddr = CInetAddress::localAddresses();\n\n\tfor (uint i = 0; i < addr.size(); i++)\n\t{\n\t\t// first we have to look if we have a network that can established the connection\n\n\t\tuint j = 0;\n\t\t// it s 127.0.0.1, it s ok\n\t\tif (!addr[i].is127001 ())\n\t\t{\n\t\t\tfor (j = 0; j < laddr.size (); j++)\n\t\t\t{\n\t\t\t\tif (laddr[j].internalNetAddress () == addr[i].internalNetAddress ())\n\t\t\t\t{\n\t\t\t\t\t// it's ok, we can try\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't found a valid network, we'll try with the first one.\n\t\t\t// It's happen, for example, when you try to connect to a service that is not in the network but use IP translation\n\t\t\tif (j == laddr.size ())\n\t\t\t{\n\t\t\t\tnlwarning (\"HNETL5: I can't access '%s' because I haven't a net card on this network, we'll use the first network\", addr[i].asString ().c_str ());\n\t\t\t\tj = 0;\n\t\t\t}\n\t\t}\n\n\t\t// Create a new connection with the service, setup callback and connect\n\t\tCCallbackClient\t*cbc = new CCallbackClient( CCallbackNetBase::Off, \"\", true, false ); // don't init one pipe per connection\n#ifdef NL_OS_UNIX\n\t\tcbc->setExternalPipeForDataAvailable( _MainDataAvailablePipe ); // the main pipe is shared for all connections\n\t\t//nldebug( \"Pipe: set (client %p)\", cbc );\n#endif\n\t\tcbc->setDisconnectionCallback(uncbDisconnection, NULL);\n\t\tcbc->setDefaultCallback(uncbMsgProcessing);\n\t\tcbc->getSockId()->setAppId(sid.get());\n\n\t\ttry\n\t\t{\n\t\t\tcbc->connect(addr[i]);\n\t\t\tconnectSuccess = true;\n\t\t}\n\t\tcatch (const ESocketConnectionFailed &e)\n\t\t{\n\t\t\tnlwarning (\"HNETL5: can't connect to %s (sid %u) now (%s) '%s'\", name.c_str(), sid.get(), e.what (), addr[i].asString ().c_str());\n\t\t\tconnectSuccess = false;\n\t\t}\n\n\t\tif (!connectSuccess && !autoRetry)\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Can't add service because no retry and can't connect\");\n\t\t\tdelete cbc;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tuc->Connections[i] = CUnifiedNetwork::CUnifiedConnection::TConnection(cbc);\n\t\t}\n\n\t\tif (connectSuccess && sendId)\n\t\t{\n\t\t\t// send identification to the service\n\t\t\tCMessage\tmsg(\"UN_SIDENT\");\n\t\t\tmsg.serial(_Name);\n\t\t\tTServiceId\t\tssid = _SId;\n\t\t\tif (uc->IsExternal)\n\t\t\t{\n\t\t\t\t// in the case that the service is external, we can't send our sid because the external service can\n\t\t\t\t// have other connection with the same sid (for example, LS can have 2 WS with same sid => sid = 0 and leave\n\t\t\t\t// the other side to find a good number\n\t\t\t\tssid.set(0);\n                j = 0;\n\t\t\t}\n\t\t\tmsg.serial(ssid);\t// serializes a 16 bits service id\n\t\t\tuint8 pos = uint8(j);\n\t\t\tmsg.serial(pos);\t// send the position in the connection table\n\t\t\tmsg.serial (uc->IsExternal);\n\t\t\tcbc->send (msg);\n\t\t}\n\t}\n\n\tif (addr.size () != uc->Connections.size())\n\t{\n\t\tnlwarning (\"HNETL5: Can't connect to all connections to the service %d/%d\", addr.size (), uc->Connections.size());\n\t}\n\n\tbool cntok = false;\n\tfor (uint j = 0; j < uc->Connections.size(); j++)\n\t{\n\t\tif (uc->Connections[j].CbNetBase != NULL)\n\t\t{\n\t\t\tif (uc->Connections[j].CbNetBase->connected ())\n\t\t\t{\n\t\t\t\tcntok = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (cntok)\n\t{\n\t\t// add the name only if at least one connection is ok\n\t\taddNamedCnx (name, sid);\n\n\t\tcallServiceUpCallback (name, sid); // global callback (\"*\") will be called even for external service\n\t}\n\n\tnldebug (\"HNETL5: addService was successful\");\n}\n//\n//\n//\n\n#define\tTIME_BLOCK(tick, instr) \\\n{ \\\n\tTTicks\t_time_block_before = CTime::getPerformanceTime(); \\\n\tinstr ; \\\n\tTTicks\t_time_block_after = CTime::getPerformanceTime(); \\\n\ttick += (_time_block_after - _before); \\\n}\n\n/*\n *\n */\nvoid\tCUnifiedNetwork::update(TTime timeout)\n{\n\tH_AUTO(CUnifiedNetworkUpdate);\n\n\tH_BEFORE(UNMisc1);\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::update() whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tbool\tenableRetry;\t// true every 5 seconds to reconnect if necessary\n\n\t// Compute the real timeout based on the next update timeout\n\tTTime t0 = CTime::getLocalTime ();\n\tif (timeout > 0)\n\t{\n\t\tif (_NextUpdateTime == 0)\n\t\t{\n\t\t\t_NextUpdateTime = t0 + timeout;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tTTime err = t0 - _NextUpdateTime;\n\t\t\t_NextUpdateTime += timeout;\n\n\t\t\t// if we are too late, resync to the next value\n\t\t\twhile (err > timeout)\n\t\t\t{\n\t\t\t\terr -= timeout;\n\t\t\t\t_NextUpdateTime += timeout;\n\t\t\t}\n\n\t\t\ttimeout -= err;\n\t\t\tif (timeout < 0) timeout = 0;\n\t\t}\n\t}\n\tTTime remainingTime = timeout;\n\n\t// check if we need to retry to connect to the client\n\tenableRetry = (t0-_LastRetry > 5000);\n\tif (enableRetry)\n\t\t_LastRetry = t0;\n\n\tH_AFTER(UNMisc1);\n\n\tH_BEFORE(UNNamingCheck);\n\t// Try to reconnect to the naming service if connection lost\n\tif (_NamingServiceAddr.isValid ())\n\t{\n\t\tif (CNamingClient::connected ())\n\t\t{\n\t\t\tCNamingClient::update ();\n\t\t}\n\t\telse if (enableRetry)\n\t\t{\n\t\t\tH_AUTO(L5NSReconnect);\n\t\t\ttry\n\t\t\t{\n\t\t\t\tvector<CInetAddress> laddr = CInetAddress::localAddresses();\n\t\t\t\tCNamingClient::connect (_NamingServiceAddr, _RecordingState, laddr);\n\t\t\t\t// re-register the service\n\t\t\t\tfor (uint i = 0; i < laddr.size(); i++)\n\t\t\t\t\tladdr[i].setPort(_ServerPort);\n\t\t\t\tCNamingClient::resendRegisteration (_Name, laddr, _SId);\n\t\t\t}\n\t\t\tcatch (const ESocketConnectionFailed &)\n\t\t\t{\n\t\t\t\tnlwarning (\"HNETL5: Could not connect to the Naming Service (%s). Retrying in a few seconds...\", _NamingServiceAddr.asString().c_str());\n\t\t\t}\n\t\t}\n\t}\n\tH_AFTER(UNNamingCheck);\n\n\tH_BEFORE(UNUpdateCnx);\n\tfor(;;)\n\t{\n\t\tH_AUTO(L5OneLoopUpdate);\n\n\t\tif (CAliveCheck::Thread)\n\t\t{\n\t\t\tuint\ti;\n\t\t\tfor (i=0; i<sizeof(CAliveCheck::Thread->CheckList)/sizeof(CAliveCheck::Thread->CheckList[0]); ++i)\n\t\t\t{\n\t\t\t\tCAliveCheck::CCheckAddress\t&address = CAliveCheck::Thread->CheckList[i];\n\t\t\t\tif (address.NeedCheck && address.AddressValid)\n\t\t\t\t{\n\t\t\t\t\tCUnifiedConnection &uc = _IdCnx[address.ConnectionId];\n\t\t\t\t\tif (uc.ServiceName == address.ServiceName &&\n\t\t\t\t\t\tuc.ServiceId == address.ServiceId &&\n\t\t\t\t\t\tuc.ValidRequested)\n\t\t\t\t\t{\n\t\t\t\t\t\tuc.ValidRequested = false;\n\t\t\t\t\t\tuc.ValidExternal = true;\n\t\t\t\t\t}\n\n\t\t\t\t\taddress.NeedCheck = false;\n\t\t\t\t\taddress.AddressValid = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// update all server connections\n\t\tif (_CbServer)\n\t\t{\n\t\t\t_CbServer->update2((sint32)remainingTime, 0);\n\t\t}\n\n\t\t// update all client connections\n\t\tfor (uint k = 0; k<_UsedConnection.size(); ++k)\n\t\t{\n\t\t\tH_AUTO(UNBrowseConnections);\n\t\t\tnlassert (_IdCnx[_UsedConnection[k].get()].State == CUnifiedNetwork::CUnifiedConnection::Ready);\n\t\t\tfor (uint j = 0; j < _IdCnx[_UsedConnection[k].get()].Connections.size (); j++)\n\t\t\t{\n\t\t\t\t// WARNING : don't take a reference in the outside loop because\n\t\t\t\t//\t\t\t_IdCnx can be resized by execution of a callback\n\t\t\t\tCUnifiedConnection &uc = _IdCnx[_UsedConnection[k].get()];\n\t\t\t\tnlassert(_IdCnx[_UsedConnection[k].get()].Connections.size() > j);\n\t\t\t\tCUnifiedConnection::TConnection &conn = _IdCnx[_UsedConnection[k].get()].Connections[j];\n\t\t\t\tH_AUTO(UNBrowseSubConnections);\n\t\t\t\tif (!conn.valid())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (conn.IsServerConnection)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tnlassert(uc.Connections.size() > j);\n\t\t\t\tif (conn.CbNetBase->connected ())\n\t\t\t\t{\n\t\t\t\tnlassert(uc.Connections.size() > j);\n\t\t\t\t\tconn.CbNetBase->update2((sint32)remainingTime, 0);\n\t\t\t\t}\n\t\t\t\telse if (enableRetry && uc.AutoRetry)\n\t\t\t\t{\n\t\t\t\t\tif (uc.ValidExternal)\n\t\t\t\t\t{\n\t\t\t\t\t\tuc.ValidExternal = false;\n\t\t\t\t\t\tuc.ValidRequested = false;\n\t\t\t\t\t\tautoReconnect( uc, j );\n\t\t\t\t\t}\n\t\t\t\t\telse if (!uc.ValidRequested && CAliveCheck::Thread)\n\t\t\t\t\t{\n\t\t\t\t\t\tuc.ValidRequested = true;\n\t\t\t\t\t\tCAliveCheck::Thread->checkService(uc.ExtAddress[j], _UsedConnection[k].get(), j, uc.ServiceName, uc.ServiceId);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// reset closed client connection\n\t\tfor (uint i=0; i<_ConnectionToReset.size(); ++i)\n\t\t{\n\t\t\t// remove the _UsedConnection\n\t\t\tbool found = false;\n\t\t\tfor (vector<TServiceId>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)\n\t\t\t{\n\t\t\t\tif (*it == _IdCnx[_ConnectionToReset[i].get()].ServiceId)\n\t\t\t\t{\n\t\t\t\t\tfound = true;\n\t\t\t\t\t_UsedConnection.erase (it);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!found)\n\t\t\t\tAUTOCHECK_DISPLAY (\"HNETL5: can't find the sid %hu in the _UsedConnection\", _IdCnx[_ConnectionToReset[i].get()].ServiceId.get());\n\t\t\t_IdCnx[_ConnectionToReset[i].get()].reset();\n\t\t}\n\t\t_ConnectionToReset.clear();\n\n\t\tenableRetry = false;\n\n\t\tif ( FlushSendsBeforeSleep.get() )\n\t\t{\n\t\t\t// Flush all connections\n\t\t\tL5TotalBytesInLowLevelSendQueues = tryFlushAllQueues();\n\t\t}\n\n\t\t//      t0 --------- previousTime -------------------------- t0 + timeout\n\t\t//                                    prevRemainingTime\n\t\t//\n\t\t//      t0 -------------- currentTime ---------------------- t0 + timeout\n\t\t//                                        remainingTime\n\t\tTTime prevRemainingTime = remainingTime;\n\t\tTTime currentTime = CTime::getLocalTime();\n\t\tremainingTime = t0 + timeout - currentTime;\n\n\t\t// If it's the end (or if the Unix system time was changed forwards), don't sleep (currentTime > t0 + timeout)\n\t\tif ( remainingTime <= 0 )\n\t\t\tbreak;\n\n\t\t// If the Unix system time was changed backwards, don't wait more than requested and don't provide an erroneous time to the sleep function that would fail (currentTime < previousTime)\n\t\tif ( remainingTime > prevRemainingTime )\n\t\t{\n\t\t\t// Restart at previousTime\n\t\t\tnldebug( \"Backward time sync detected (at least -%\" NL_I64 \"d ms)\", remainingTime - prevRemainingTime );\n\t\t\tremainingTime = prevRemainingTime;\n\t\t\tt0 = currentTime - (timeout - remainingTime);\n\t\t}\n\n#ifdef NL_OS_UNIX\n\t\t// Sleep until the time expires or we receive a message\n\t\tH_BEFORE(L5UpdateSleep);\n\t\tswitch ( UseYieldMethod.get() )\n\t\t{\n\t\tcase 0: sleepUntilDataAvailable( remainingTime ); break; // accurate sleep with select()\n\t\tcase 1: ::usleep(1000); break; // 20 ms\n\t\tcase 2: nlSleep(1); break; // 10 ms (by nanosleep, but 20 ms measured on kernel 2.4.20)\n\t\tcase 3:\t::sched_yield(); break; // makes all slow (at least on kernel 2.4.20) !\n\t\tdefault: break; // don't sleep at all, makes all slow!\n\t\t}\n\t\tH_AFTER(L5UpdateSleep);\n#else\n\t\t// Enable windows multithreading before rescanning all connections\n\t\tH_TIME(L5UpdateSleep, nlSleep(1);); // 0 (yield) would be too harmful to other applications\n#endif\n\t}\n\tH_AFTER(UNUpdateCnx);\n\n\tH_TIME(UNAutoCheck, autoCheck(););\n}\n\n\n/*\n * Auto-reconnect\n */\nvoid CUnifiedNetwork::autoReconnect( CUnifiedConnection &uc, uint connectionIndex )\n{\n\tH_AUTO(L5AutoReconnect);\n\ttry\n\t{\n\t\tCCallbackClient *cbc = (CCallbackClient *)uc.Connections[connectionIndex].CbNetBase;\n\t\tcbc->connect(uc.ExtAddress[connectionIndex]);\n\t\tuc.Connections[connectionIndex].CbNetBase->getSockId()->setAppId(uc.ServiceId.get());\n\t\tnlinfo (\"HNETL5: reconnection to %s-%hu success\", uc.ServiceName.c_str(), uc.ServiceId.get());\n\n\t\t// add the name only if at least one connection is ok\n\t\tif (!haveNamedCnx (uc.ServiceName, uc.ServiceId))\n\t\t\taddNamedCnx (uc.ServiceName, uc.ServiceId);\n\n\t\t// resend the identification is necessary\n\t\tif (uc.SendId)\n\t\t{\n\t\t\t// send identification to the service\n\t\t\tCMessage\tmsg(\"UN_SIDENT\");\n\t\t\tmsg.serial(_Name);\n\n\t\t\tTServiceId\t\tssid = _SId;\n\t\t\tif (uc.IsExternal)\n\t\t\t{\n\t\t\t\t// in the case that the service is external, we can't send our sid because the external service can\n\t\t\t\t// have other connection with the same sid (for example, LS can have 2 WS with same sid => sid = 0 and leave\n\t\t\t\t// the other side to find a good number\n\t\t\t\tssid.set(0);\n\t\t\t}\n\t\t\tmsg.serial(ssid);\t// serializes a 16 bits service id\n\t\t\tuint8 pos = uint8(connectionIndex);\n\t\t\tmsg.serial(pos);\t// send the position in the connection table\n\t\t\tmsg.serial (uc.IsExternal);\n\t\t\tuc.Connections[connectionIndex].CbNetBase->send (msg, uc.Connections[connectionIndex].HostId);\n\t\t}\n\n\t\t// call the user callback\n\t\tcallServiceUpCallback (uc.ServiceName, uc.ServiceId);\n\t}\n\tcatch (const ESocketConnectionFailed &e)\n\t{\n#if FINAL_VERSION\n\t\tnlinfo (\"HNETL5: can't connect to %s-%hu now (%s)\", uc.ServiceName.c_str(), uc.ServiceId.get(), e.what ());\n#else\n\t\tnlwarning (\"HNETL5: can't connect to %s-%hu now (%s)\", uc.ServiceName.c_str(), uc.ServiceId.get(), e.what ());\n#endif\n\t}\n}\n\n#ifdef NL_OS_UNIX\n/*\n *\n */\nvoid CUnifiedNetwork::sleepUntilDataAvailable( TTime msecMax )\n{\n\t// Prevent looping infinitely if an erroneous time was provided\n\tif ( msecMax > 999 ) // limit not told in Linux man but here: http://docs.hp.com/en/B9106-90009/select.2.html\n\t\tmsecMax = 999;\n\n\t// Prepare for select()\n\tfd_set readers;\n\tFD_ZERO( &readers );\n\tFD_SET( _MainDataAvailablePipe[PipeRead], &readers );\n\tSOCKET descmax = _MainDataAvailablePipe[PipeRead] + 1;\n\n\t// Select\n\ttimeval tv;\n\ttv.tv_sec = 0;\n\ttv.tv_usec = msecMax * 1000;\n\t//nldebug( \"Select %u ms\", (uint)msecMax );\n\t//TTime before = CTime::getLocalTime();\n\tint res = ::select( descmax+1, &readers, NULL, NULL, &tv );\n\tif ( res == -1 )\n\t\tnlwarning( \"HNETL5: Select failed in sleepUntilDataAvailable\");\n\t//nldebug( \"Slept %u ms\", (uint)(CTime::getLocalTime()-before) );\n}\n#endif\n\n\n\nbool CUnifiedNetwork::isConnectionConnected(TServiceId sid) const\n{\n\t// a Connected connection is a connection that is Ready but that is not yet connected (serverUp will be called latter via L5).\n\treturn sid.get() < _IdCnx.size()\n\t\t&& _IdCnx[sid.get()].State == CUnifiedConnection::Ready\n\t\t&& !_IdCnx[sid.get()].Connections.empty();\n}\n//\n//\n//\nuint8 CUnifiedNetwork::findConnectionId (TServiceId sid, uint8 nid)\n{\n\tif (_IdCnx[sid.get()].Connections.size () == 0)\n\t{\n\t\tnlwarning (\"HNETL5: Can't send message to %s because no connection are available\", _IdCnx[sid.get()].ServiceName.c_str ());\n\t\treturn 0xFF;\n\t}\n\n\t// by default, connection id will be the default one\n\tuint8 connectionId = _IdCnx[sid.get()].DefaultNetwork;\n\n\tif (nid == 0xFF)\n\t{\n\t\t// it s often happen because they didn't set a good network configuration, so it s in debug to disable it easily\n\t\t//nldebug (\"HNETL5: nid %hu, will use the default connection %hu\", (uint16)nid, (uint16)connectionId);\n\t}\n\telse if (nid >= _IdCnx[sid.get()].NetworkConnectionAssociations.size())\n\t{\n\t\tnlwarning (\"HNETL5: No net association for nid %hu, use the default connection %hu\", (uint16)nid, (uint16)connectionId);\n\t}\n\telse\n\t{\n\t\tif (_IdCnx[sid.get()].NetworkConnectionAssociations[nid] >= _IdCnx[sid.get()].Connections.size ())\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Can't send message to %s because nid %d point on a bad connection (%d and only have %d cnx), use default connection\", _IdCnx[sid.get()].ServiceName.c_str (), nid, connectionId, _IdCnx[sid.get()].Connections.size ());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconnectionId = _IdCnx[sid.get()].NetworkConnectionAssociations[nid];\n\t\t}\n\t}\n\n\tif (connectionId >= _IdCnx[sid.get()].Connections.size() || !_IdCnx[sid.get()].Connections[connectionId].valid() || !_IdCnx[sid.get()].Connections[connectionId].CbNetBase->connected())\n\t{\n\t\t// there's a problem with the selected connectionID, so try to find a valid one\n\t\tnlwarning (\"HNETL5: Can't find selected connection id %hu to send message to %s because connection is not valid or connected, find a valid connection id\", (uint16)connectionId, _IdCnx[sid.get()].ServiceName.c_str ());\n\n\t\tfor (connectionId = 0; connectionId < _IdCnx[sid.get()].Connections.size(); connectionId++)\n\t\t{\n\t\t\tif (_IdCnx[sid.get()].Connections[connectionId].valid() && _IdCnx[sid.get()].Connections[connectionId].CbNetBase->connected())\n\t\t\t{\n\t\t\t\t// we found one at last, use this one\n\t\t\t\t//nldebug (\"HNETL5: Ok, we found a valid connectionid, use %hu\",  (uint16)connectionId);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (connectionId == _IdCnx[sid.get()].Connections.size())\n\t\t{\n\t\t\tnlwarning (\"HNETL5: Can't send message to %s because default connection is not exist, valid or connected\", _IdCnx[sid.get()].ServiceName.c_str ());\n\t\t\treturn 0xFF;\n\t\t}\n\t}\n\treturn connectionId;\n}\n\n\n//\n//\n//\n\nuint\tCUnifiedNetwork::send(const string &serviceName, const CMessage &msgout, bool warnIfNotFound, uint8 nid)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::send(const string&, const CMessage&) whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tTNameMappedConnection::const_iterator\t\t\t\t\t\t\t\tit;\n\tpair<TNameMappedConnection::const_iterator,TNameMappedConnection::const_iterator>\trange;\n\trange = _NamedCnx.equal_range(serviceName);\n\n\tuint found = 0;\n\tif (range.first != _NamedCnx.end())\n\t{\n\t\tfor (it=range.first; it!=range.second; ++it)\n\t\t{\n\t\t\tTServiceId\tsid = it->second;\n\t\t\tif (sid.get() >= _IdCnx.size () || _IdCnx[sid.get()].State != CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\t{\n\t\t\t\t// It often happen when the service is down (connection broke and the naming not already say that it s down)\n\t\t\t\t// In this case, just warn\n\t\t\t\tnlwarning (\"HNETL5: Can't send %s to the service '%s' because it was in the _NamedCnx but not in _IdCnx (means that the service is down)\", msgout.getName().c_str(), serviceName.c_str ());\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t++found;\n\n\t\t\tuint8 connectionId = findConnectionId (sid, nid);\n\t\t\tif (connectionId == 0xff)\t// failed\n\t\t\t{\n\t\t\t\tnlwarning (\"HNETL5: Can't send %s message to %hu because no connection available\", msgout.getName().c_str(), sid.get());\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t_IdCnx[sid.get()].Connections[connectionId].CbNetBase->send (msgout, _IdCnx[sid.get()].Connections[connectionId].HostId);\n\t\t}\n\t}\n\n\tif (!found && warnIfNotFound)\n\t\tnlwarning (\"HNETL5: can't find service %s to send message %s\", serviceName.c_str(), msgout.getName().c_str());\n\n\treturn found;\n}\n\nbool\tCUnifiedNetwork::send(TServiceId sid, const CMessage &msgout, uint8 nid)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::send(TServiceId, const CMessage&) whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tif (sid.get() >= _IdCnx.size () || _IdCnx[sid.get()].State != CUnifiedNetwork::CUnifiedConnection::Ready)\n\t{\n\t\t// Happens when trying to send a message to an unknown service id\n\t\tnlwarning (\"HNETL5: Can't send %s to the service '%hu' because not in _IdCnx\", msgout.getName().c_str(), sid.get());\n\t\treturn false;\n\t}\n\n\tuint8 connectionId = findConnectionId (sid, nid);\n\tif (connectionId == 0xff)\t// failed\n\t{\n\t\tnlwarning (\"HNETL5: Can't send %s to the service '%hu' because no connection available\", msgout.getName().c_str(), sid.get());\n\t\treturn false;\n\t}\n\n\t_IdCnx[sid.get()].Connections[connectionId].CbNetBase->send (msgout, _IdCnx[sid.get()].Connections[connectionId].HostId);\n\treturn true;\n}\n\nvoid\tCUnifiedNetwork::sendAll(const CMessage &msgout, uint8 nid)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::send(const CMessage&) whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tfor (TServiceId::size_type i=0; i<_IdCnx.size(); ++i)\n\t{\n\t\tif (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t{\n\t\t\tuint8 connectionId = findConnectionId (TServiceId(i), nid);\n\t\t\tif (connectionId == 0xff)\t// failed\n\t\t\t{\n\t\t\t\tnlwarning (\"HNETL5: Can't send message to %u because no connection available\", i);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t_IdCnx[i].Connections[connectionId].CbNetBase->send (msgout, _IdCnx[i].Connections[connectionId].HostId);\n\t\t}\n\t}\n}\n\n\n/* Flush all the sending queues, and report the number of bytes still pending.\n * To ensure all data are sent before stopping a service, you may want to repeat\n * calling this method evenly until it returns 0.\n * \\param namesOfOnlyServiceToFlushSending If not empty, only the send queues to the\n * services specified (by short name) will be flushed.\n */\nuint\tCUnifiedNetwork::tryFlushAllQueues(const std::vector<std::string>& namesOfOnlyServiceToFlushSending)\n{\n\tH_AUTO(L5FlushAll);\n\tuint bytesRemaining = 0;\n\tfor (uint k = 0; k<_UsedConnection.size(); ++k)\n\t{\n\t\tH_AUTO(UNFABrowseConnections);\n\t\tCUnifiedConnection &uc = _IdCnx[_UsedConnection[k].get()];\n\n\t\t// Skip the connection if it is not found in the 'only' list (except if the list is empty)\n\t\tif ( (! namesOfOnlyServiceToFlushSending.empty()) &&\n\t\t\t (std::find( namesOfOnlyServiceToFlushSending.begin(), namesOfOnlyServiceToFlushSending.end(), uc.ServiceName ) == namesOfOnlyServiceToFlushSending.end()) )\n\t\t\t continue;\n\n\t\tnlassert (uc.State == CUnifiedNetwork::CUnifiedConnection::Ready);\n\t\tfor (uint j = 0; j < uc.Connections.size (); j++)\n\t\t{\n\t\t\tH_AUTO(UNFABrowseSubConnections);\n\t\t\tif (!uc.Connections[j].valid())\n\t\t\t\tcontinue;\n\n\t\t\tif (uc.Connections[j].CbNetBase->connected ())\n\t\t\t{\n\t\t\t\tuint bytesRemainingLocal;\n\t\t\t\tuc.Connections[j].CbNetBase->flush(uc.Connections[j].HostId, &bytesRemainingLocal);\n\t\t\t\tbytesRemaining += bytesRemainingLocal;\n\t\t\t}\n\t\t}\n\t}\n\treturn bytesRemaining;\n}\n\n\n//\n//\n//\n\nvoid\tCUnifiedNetwork::addCallbackArray (const TUnifiedCallbackItem *callbackarray, sint arraysize)\n{\n\tuint\ti;\n\n\tfor (i=0; i<(uint)arraysize; ++i)\n\t{\n\t\tif ( NULL != callbackarray[i].Key )\n\t\t{\n\t\t\t_Callbacks.insert(make_pair(string(callbackarray[i].Key),callbackarray[i].Callback));\n\t\t\tnlinfo(\"addCallbackArray =================== %s\",callbackarray[i].Key);\n\t\t}\n\t}\n}\n\n\nvoid\tCUnifiedNetwork::setServiceUpCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg, bool back)\n{\n\tnlassert (cb != NULL);\n\tif (serviceName == \"*\")\n\t{\n\t\tif (back)\n\t\t\t_UpUniCallback.push_back (make_pair(cb, arg));\n\t\telse\n\t\t\t_UpUniCallback.insert (_UpUniCallback.begin(), make_pair(cb, arg));\n\t}\n\telse\n\t{\n\t\tif (back)\n\t\t\t_UpCallbacks[serviceName].push_back (make_pair(cb, arg));\n\t\telse\n\t\t\t_UpCallbacks[serviceName].insert (_UpCallbacks[serviceName].begin(), make_pair(cb, arg));\n\t}\n}\n\nvoid\tCUnifiedNetwork::removeServiceUpCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg)\n{\n\tif (serviceName == \"*\")\n\t{\n\t\tuint i;\n\t\tfor (i=0; i<_UpUniCallback.size(); ++i)\n\t\t{\n\t\t\tif (_UpUniCallback[i].first == cb && _UpUniCallback[i].second == arg)\n\t\t\t{\n\t\t\t\t// we found it\n\t\t\t\t_UpUniCallback.erase(_UpUniCallback.begin()+i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i == _UpUniCallback.size())\n\t\t{\n\t\t\tnlwarning(\"HNETL5 : can't remove service up callback, not found\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (_UpCallbacks.find(serviceName) != _UpCallbacks.end())\n\t\t{\n\t\t\tstd::list<TCallbackArgItem> &list = _UpCallbacks[serviceName];\n\t\t\tstd::list<TCallbackArgItem>::iterator first(list.begin()), last(list.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (first->first == cb && first->second == arg)\n\t\t\t\t{\n\t\t\t\t\tlist.erase(first);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (first == last)\n\t\t\t{\n\t\t\t\tnlwarning(\"HNETL5 : can't remove service up callback, not found\");\n\t\t\t}\n\n\t\t\tif (list.empty())\n\t\t\t{\n\t\t\t\t// no more callback for this service\n\t\t\t\t_UpCallbacks.erase(serviceName);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"HNETL5 : can't remove service up callback, not found\");\n\t\t}\n\t}\n}\n\nvoid\tCUnifiedNetwork::setServiceDownCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg, bool back)\n{\n\tnlassert (cb != NULL);\n\tif (serviceName == \"*\")\n\t{\n\t\tif (back)\n\t\t\t_DownUniCallback.push_back (make_pair(cb, arg));\n\t\telse\n\t\t\t_DownUniCallback.insert (_DownUniCallback.begin(), make_pair(cb, arg));\n\t}\n\telse\n\t{\n\t\tif (back)\n\t\t\t_DownCallbacks[serviceName].push_back (make_pair(cb, arg));\n\t\telse\n\t\t\t_DownCallbacks[serviceName].insert (_DownCallbacks[serviceName].begin(), make_pair(cb, arg));\n\t}\n}\n\nvoid\tCUnifiedNetwork::removeServiceDownCallback (const string &serviceName, TUnifiedNetCallback cb, void *arg)\n{\n\tif (serviceName == \"*\")\n\t{\n\t\tuint i;\n\t\tfor (i=0; i<_DownUniCallback.size(); ++i)\n\t\t{\n\t\t\tif (_DownUniCallback[i].first == cb && _DownUniCallback[i].second == arg)\n\t\t\t{\n\t\t\t\t// we found it\n\t\t\t\t_DownUniCallback.erase(_DownUniCallback.begin()+i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i == _DownUniCallback.size())\n\t\t{\n\t\t\tnlwarning(\"HNETL5 : can't remove service down callback, not found\");\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (_DownCallbacks.find(serviceName) != _DownCallbacks.end())\n\t\t{\n\t\t\tstd::list<TCallbackArgItem> &list = _DownCallbacks[serviceName];\n\t\t\tstd::list<TCallbackArgItem>::iterator first(list.begin()), last(list.end());\n\t\t\tfor (; first != last; ++first)\n\t\t\t{\n\t\t\t\tif (first->first == cb && first->second == arg)\n\t\t\t\t{\n\t\t\t\t\tlist.erase(first);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (first == last)\n\t\t\t{\n\t\t\t\tnlwarning(\"HNETL5 : can't remove service down callback, not found\");\n\t\t\t}\n\n\t\t\tif (list.empty())\n\t\t\t{\n\t\t\t\t// no more callback for this service\n\t\t\t\t_DownCallbacks.erase(serviceName);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnlwarning(\"HNETL5 : can't remove service down callback, not found\");\n\t\t}\n\t}\n}\n//\n//\n//\n\nuint64 CUnifiedNetwork::getBytesSent ()\n{\n\tuint64\tsent = 0;\n\tuint\tj;\n\n\tfor (vector<TServiceId>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)\n\t{\n\t\tif (_IdCnx[it->get()].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\tfor (j=0; j<_IdCnx[it->get()].Connections.size (); ++j)\n\t\t\t\tif(_IdCnx[it->get()].Connections[j].valid () && !_IdCnx[it->get()].Connections[j].IsServerConnection)\n\t\t\t\t\tsent += _IdCnx[it->get()].Connections[j].CbNetBase->getBytesSent();\n\t}\n\n\tif(_CbServer)\n\t\tsent += _CbServer->getBytesSent();\n\treturn sent;\n}\n\nuint64 CUnifiedNetwork::getBytesReceived ()\n{\n\tuint64\treceived = 0;\n\tuint\tj;\n\n\tfor (vector<TServiceId>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)\n\t{\n\t\tif (_IdCnx[it->get()].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\tfor (j=0; j<_IdCnx[it->get()].Connections.size (); ++j)\n\t\t\t\tif(_IdCnx[it->get()].Connections[j].valid () && !_IdCnx[it->get()].Connections[j].IsServerConnection)\n\t\t\t\t\treceived += _IdCnx[it->get()].Connections[j].CbNetBase->getBytesReceived();\n\t}\n\n\tif (_CbServer)\n\t\treceived += _CbServer->getBytesReceived();\n\treturn received;\n}\n\nuint64 CUnifiedNetwork::getSendQueueSize ()\n{\n\tuint64\tsent = 0;\n\tuint\tj;\n\n\tfor (vector<TServiceId>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)\n\t{\n\t\tif (_IdCnx[it->get()].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\tfor (j=0; j<_IdCnx[it->get()].Connections.size (); ++j)\n\t\t\t\tif(_IdCnx[it->get()].Connections[j].valid () && !_IdCnx[it->get()].Connections[j].IsServerConnection)\n\t\t\t\t\tsent += _IdCnx[it->get()].Connections[j].CbNetBase->getSendQueueSize();\n\t}\n\n\tif (_CbServer)\n\t\tsent += _CbServer->getSendQueueSize();\n\treturn sent;\n}\n\nuint64 CUnifiedNetwork::getReceiveQueueSize ()\n{\n\tuint64\treceived = 0;\n\tuint\tj;\n\n\tfor (vector<TServiceId>::iterator it = _UsedConnection.begin (); it != _UsedConnection.end(); it++)\n\t{\n\t\tif (_IdCnx[it->get()].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\tfor (j=0; j<_IdCnx[it->get()].Connections.size (); ++j)\n\t\t\t\tif(_IdCnx[it->get()].Connections[j].valid () && !_IdCnx[it->get()].Connections[j].IsServerConnection)\n\t\t\t\t\treceived += _IdCnx[it->get()].Connections[j].CbNetBase->getReceiveQueueSize();\n\t}\n\n\tif (_CbServer)\n\t\treceived += _CbServer->getReceiveQueueSize();\n\treturn received;\n}\n\nCCallbackNetBase\t*CUnifiedNetwork::getNetBase(const std::string &name, TSockId &host, uint8 nid)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::getNetBase() whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tsint\tcount = (sint)_NamedCnx.count(name);\n\n\tif (count <= 0)\n\t{\n\t\tnlwarning (\"HNETL5: couldn't access the service %s\", name.c_str());\n\t\thost = InvalidSockId;\n\t\treturn NULL;\n\t}\n\telse if (count > 1)\n\t{\n\t\tnlwarning (\"HNETL5: %d services %s to getNetBase, returns the first valid\", count, name.c_str());\n\t}\n\n\tTNameMappedConnection::const_iterator\titnmc = _NamedCnx.find(name);\n\n\tuint8 connectionId = findConnectionId ((*itnmc).second, nid);\n\tif (connectionId == 0xff)\t// failed\n\t{\n\t\tnlwarning (\"HNETL5: Can't getNetBase %s because no connection available\", name.c_str());\n\t\thost = InvalidSockId;\n\t\treturn NULL;\n\t}\n\n\thost = _IdCnx[itnmc->second.get()].Connections[connectionId].HostId;\n\treturn _IdCnx[itnmc->second.get()].Connections[connectionId].CbNetBase;\n}\n\nCCallbackNetBase\t*CUnifiedNetwork::getNetBase(TServiceId sid, TSockId &host, uint8 nid)\n{\n\tnlassertex(_Initialised == true, (\"Try to CUnifiedNetwork::getNetBase() whereas it is not initialised yet\"));\n\n\tif (ThreadCreator != NLMISC::getThreadId()) nlwarning (\"HNETL5: Multithread access but this class is not thread safe thread creator = %u thread used = %u\", ThreadCreator, NLMISC::getThreadId());\n\n\tif (sid.get() >= _IdCnx.size () || _IdCnx[sid.get()].State != CUnifiedNetwork::CUnifiedConnection::Ready)\n\t{\n\t\tnlwarning (\"HNETL5: Can't get net base to the service '%hu' because not in _IdCnx\", sid.get());\n\t\thost = InvalidSockId;\n\t\treturn NULL;\n\t}\n\n\tuint8 connectionId = findConnectionId (sid, nid);\n\tif (connectionId == 0xff)\t// failed\n\t{\n\t\tnlwarning (\"HNETL5: Can't getNetBase %hu because no connection available\", sid.get());\n\t\thost = InvalidSockId;\n\t\treturn NULL;\n\t}\n\n\thost = _IdCnx[sid.get()].Connections[connectionId].HostId;\n\treturn _IdCnx[sid.get()].Connections[connectionId].CbNetBase;\n}\n\nTUnifiedMsgCallback CUnifiedNetwork::findCallback (const std::string &callbackName)\n{\n\tTMsgMappedCallback::iterator\titcb = _Callbacks.find(callbackName);\n\tif (itcb == _Callbacks.end())\n\t\treturn NULL;\n\telse\n\t\treturn (*itcb).second;\n}\n\nbool CUnifiedNetwork::isServiceLocal (const std::string &serviceName)\n{\n\t// it s me, of course we are local\n\tif (serviceName == _Name)\n\t\treturn true;\n\n\tpair<TNameMappedConnection::const_iterator,TNameMappedConnection::const_iterator>\trange;\n\trange = _NamedCnx.equal_range(serviceName);\n\n\tif (range.first != _NamedCnx.end())\n\t{\n\t\tTServiceId\tsid = (*(range.first)).second;\n\t\treturn isServiceLocal (sid);\n\t}\n\n\treturn false;\n}\n\nbool CUnifiedNetwork::isServiceLocal (TServiceId sid)\n{\n\t// it s me, of course we are local\n\tif (sid == _SId)\n\t\treturn true;\n\n\tif (sid.get() >= _IdCnx.size () || _IdCnx[sid.get()].State != CUnifiedNetwork::CUnifiedConnection::Ready)\n\t{\n\t\treturn false;\n\t}\n\n\tvector<CInetAddress> laddr = CInetAddress::localAddresses();\n\n\tfor (uint i = 0; i < laddr.size(); i++)\n\t{\n\t\tfor (uint j = 0; j < _IdCnx[sid.get()].ExtAddress.size(); j++)\n\t\t{\n\t\t\tif (_IdCnx[sid.get()].ExtAddress[j].is127001 ())\n\t\t\t\treturn true;\n\n\t\t\tif (_IdCnx[sid.get()].ExtAddress[j].internalIPAddress () == laddr[i].internalIPAddress ())\n\t\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n\n/*\n * Return the name of the specified service, or \"\" if not found\n */\nstd::string\t\t\tCUnifiedNetwork::getServiceName(TServiceId sid)\n{\n\tstring s;\n\tCUnifiedConnection *c = getUnifiedConnection(sid, false);\n\tif (c)\n\t\ts = c->ServiceName;\n\treturn s;\n}\n\n\n/*\n * Return a string identifying the service, using the format \"NAME-sid\" (or \"sid\" only if not found)\n */\nstd::string\t\t\tCUnifiedNetwork::getServiceUnifiedName(TServiceId sid)\n{\n\tstring s;\n\tCUnifiedConnection *c = getUnifiedConnection(sid, false);\n\tif (c)\n\t\ts = c->ServiceName + \"-\";\n\ts += toString(sid.get());\n\treturn s;\n}\n\n\n//\n//\n//\n\n//CUnifiedNetwork\t*CUnifiedNetwork::_Instance = NULL;\nNLMISC_SAFE_SINGLETON_IMPL(CUnifiedNetwork);\n\nbool CUnifiedNetwork::isUsed ()\n{\n\treturn (_Instance != NULL);\n}\n\n//\n//\n//\n\nCUnifiedNetwork::CUnifiedConnection\t*CUnifiedNetwork::getUnifiedConnection (TServiceId sid, bool warn)\n{\n\tif (sid.get() < _IdCnx.size () && _IdCnx[sid.get()].State == CUnifiedConnection::Ready)\n\t{\n\t\tif (sid != _IdCnx[sid.get()].ServiceId)\n\t\t{\n\t\t\tAUTOCHECK_DISPLAY (\"HNETL5: Sid index %hu is not the same that in the entry %hu\", sid.get(), _IdCnx[sid.get()].ServiceId.get());\n\t\t\treturn NULL;\n\t\t}\n\t\treturn &_IdCnx[sid.get()];\n\t}\n\telse\n\t{\n\t\tif ( warn )\n\t\t\tnlwarning (\"HNETL5: Try to get a bad unified connection (sid %hu is not in the table)\", sid.get());\n\t\treturn NULL;\n\t}\n}\n\nvoid\tCUnifiedNetwork::autoCheck()\n{\n\tH_AUTO(L5UpdateAutoCheck);\n\tuint i, j;\n\n\tfor (i = 0; i < _IdCnx.size (); i++)\n\t{\n\t\tif (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t{\n\t\t\t_IdCnx[i].AutoCheck = 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_IdCnx[i].AutoCheck = 0;\n\t\t}\n\t}\n\n\tTNameMappedConnection::iterator\titn;\n\tfor (itn = _NamedCnx.begin(); itn != _NamedCnx.end(); ++itn)\n\t{\n\t\tif ((*itn).first != _IdCnx[itn->second.get()].ServiceName)\n\t\t\tAUTOCHECK_DISPLAY (\"HLNET5: problem with name synchro between _NameCnx '%s' and _IdCnx '%s' '%hd'\",\n\t\t\t\t\t\t\t\t\t(*itn).first.c_str(),\n\t\t\t\t\t\t\t\t\t_IdCnx[itn->second.get()].ServiceName.c_str (),\n\t\t\t\t\t\t\t\t\titn->second.get());\n\t\tif (_IdCnx[itn->second.get()].AutoCheck == 0)\n\t\t\tAUTOCHECK_DISPLAY (\"HLNET5: problem with name synchro between _NameCnx '%s' and _IdCnx '%s' '%hd'\",\n\t\t\t\t\t\t\t\t\t(*itn).first.c_str(),\n\t\t\t\t\t\t\t\t\t_IdCnx[itn->second.get()].ServiceName.c_str (),\n\t\t\t\t\t\t\t\t\titn->second.get());\n\t\tif (_IdCnx[itn->second.get()].AutoCheck > 1)\n\t\t\tAUTOCHECK_DISPLAY (\"HLNET5: problem with name synchro between _NameCnx '%s' and _IdCnx '%s' '%hd' more than one entry is named with the same name\",\n\t\t\t\t\t\t\t\t\t(*itn).first.c_str(),\n\t\t\t\t\t\t\t\t\t_IdCnx[itn->second.get()].ServiceName.c_str (),\n\t\t\t\t\t\t\t\t\titn->second.get());\n\t\t_IdCnx[itn->second.get()].AutoCheck++;\n\t}\n\n\tfor (i = 0; i < _UsedConnection.size (); i++)\n\t{\n\t\tif (_IdCnx[_UsedConnection[i].get()].State != CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t\tAUTOCHECK_DISPLAY (\"HLNET5: problem with the _UsedConnection syncro sid %d is not used in _IdCnx\", _UsedConnection[i].get());\n\t}\n\n\tfor (i = 0; i < _IdCnx.size (); i++)\n\t{\n\t\tif (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t{\n\t\t\tfor (j = 0; j < _UsedConnection.size (); j++)\n\t\t\t{\n\t\t\t\tif (_UsedConnection[j].get() == i) break;\n\t\t\t}\n\t\t\tif (j == _UsedConnection.size ()) AUTOCHECK_DISPLAY (\"HLNET5: problem with the _UsedConnection syncro sid %d is not in _UsedConnection\", i);\n\t\t}\n\t}\n\n\tfor (i = 0; i < _IdCnx.size (); i++)\n\t{\n\t\tif (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t\t{\n\t\t\tif (_IdCnx[i].ServiceName != \"DEAD\") AUTOCHECK_DISPLAY (\"HLNET5: sid %d name should be DEAD and is '%s'\", i, _IdCnx[i].ServiceName.c_str ());\n\t\t\tif (_IdCnx[i].ServiceId.get() != 0xDEAD) AUTOCHECK_DISPLAY (\"HLNET5: sid %d sid should be 0xDEAD and is 0x%X\", i, _IdCnx[i].ServiceId.get());\n\t\t\tif (!_IdCnx[i].Connections.empty ()) AUTOCHECK_DISPLAY (\"HLNET5: sid %d connection size should be 0 and is %d\", i, _IdCnx[i].Connections.size ());\n\t\t\tif (!_IdCnx[i].ExtAddress.empty ()) AUTOCHECK_DISPLAY (\"HLNET5: sid %d ext addr size should be 0 and is %d\", i, _IdCnx[i].ExtAddress.size ());\n\t\t\tif (_IdCnx[i].AutoCheck != 0) AUTOCHECK_DISPLAY (\"HLNET5: sid %d prob with syncro with _NamedCnx\", i);\n\t\t}\n\t\telse if (_IdCnx[i].State == CUnifiedNetwork::CUnifiedConnection::Ready)\n\t\t{\n\t\t\tif (_IdCnx[i].ServiceId.get() != i) AUTOCHECK_DISPLAY (\"HNETL5: Bad syncro sid index sid entry for %d %d\", i, _IdCnx[i].ServiceId.get());\n\n\t\t\tif (_IdCnx[i].ServiceName == \"DEAD\") AUTOCHECK_DISPLAY (\"HLNET5: sid %d name should not be DEAD and is '%s'\", i, _IdCnx[i].ServiceName.c_str ());\n\t\t\tif (_IdCnx[i].ServiceId.get() == 0xDEAD) AUTOCHECK_DISPLAY (\"HLNET5: sid %d sid should not be 0xDEAD and is 0x%X\", i, _IdCnx[i].ServiceId.get());\n\t\t\tif (!_IdCnx[i].ExtAddress.empty () && _IdCnx[i].Connections.size () > _IdCnx[i].ExtAddress.size()) AUTOCHECK_DISPLAY (\"HLNET5: sid %d ext addr size should not be 0 and is %d\", i, _IdCnx[i].ExtAddress.size ());\n\n\t\t\tif (_IdCnx[i].AutoRetry == true && _IdCnx[i].Connections.size () > 1) AUTOCHECK_DISPLAY (\"HLNET5: sid %d auto retry with more than one connection %d\", i, _IdCnx[i].Connections.size ());\n\t\t\tif (_IdCnx[i].AutoRetry == true && _IdCnx[i].IsExternal == false) AUTOCHECK_DISPLAY (\"HLNET5: sid %d auto retry with internal connection\", i);\n\t\t\tif (_IdCnx[i].AutoRetry == true && _IdCnx[i].Connections[0].valid() == false) AUTOCHECK_DISPLAY (\"HLNET5: sid %d auto retry with invalid connection\", i);\n\n\t\t\tfor (j = 0; j < _IdCnx[i].Connections.size (); j++)\n\t\t\t{\n\t\t\t\tif (_IdCnx[i].Connections[j].valid() && !_IdCnx[i].Connections[j].IsServerConnection && _IdCnx[i].Connections[j].CbNetBase->connected () && _IdCnx[i].Connections[j].getAppId() != i) AUTOCHECK_DISPLAY (\"HLNET5: sid %d bad appid %\" NL_I64 \"X\", i, _IdCnx[i].Connections[j].getAppId());\n\t\t\t}\n\n\t\t\tfor (j = 0; j < _IdCnx[i].NetworkConnectionAssociations.size (); j++)\n\t\t\t{\n\t\t\t\tif (_IdCnx[i].NetworkConnectionAssociations[j] != 0)\n\t\t\t\t{\n\t\t\t\t\tif (_NetworkAssociations[j] != _IdCnx[i].ExtAddress[_IdCnx[i].NetworkConnectionAssociations[j]].internalNetAddress ()) AUTOCHECK_DISPLAY (\"HLNET5: sid %d nid %d have address 0x%08x and is not the good connection net 0x%08x\", i, j, _NetworkAssociations[j], _IdCnx[i].ExtAddress[_IdCnx[i].NetworkConnectionAssociations[j]].internalNetAddress ());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nvoid CUnifiedNetwork::displayInternalTables (NLMISC::CLog *log)\n{\n\tuint i, j;\n\tlog->displayNL (\"%d Named Connections:\", _NamedCnx.size ());\n\tfor (TNameMappedConnection::iterator it = _NamedCnx.begin(); it != _NamedCnx.end (); it++)\n\t{\n\t\tlog->displayNL (\"> '%s' -> %hu\", (*it).first.c_str(), it->second.get());\n\t}\n\n\tuint nbused = 0;\n\tfor (i = 0; i < _IdCnx.size (); i++)\n\t{\n\t\tif(_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t\t\tnbused++;\n\t}\n\n\tlog->displayNL (\"%u/%u Unified Connections:\", nbused, _IdCnx.size ());\n\tfor (i = 0; i < _IdCnx.size (); i++)\n\t{\n\t\tif(_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t\t{\n\t\t\t_IdCnx[i].display (false, log);\n\t\t\tfor (j = 0; j < _IdCnx[i].NetworkConnectionAssociations.size (); j++)\n\t\t\t{\n\t\t\t\tlog->displayNL (\"     * nid %d -> cnxn %hu\", j, (uint16)_IdCnx[i].NetworkConnectionAssociations[j]);\n\t\t\t}\n\t\t}\n\t}\n\n\tlog->displayNL (\"%u Used Unified Connections:\", _UsedConnection.size());\n\tfor (i = 0; i < _UsedConnection.size (); i++)\n\t{\n\t\tlog->displayNL (\"> %hu\", _UsedConnection[i].get());\n\t}\n\n\tlog->displayNL (\"%u Network Associations:\", _NetworkAssociations.size());\n\tfor (i = 0; i < _NetworkAssociations.size (); i++)\n\t{\n\t\tlog->displayNL (\"> 0x%08x -> '%s'\", _NetworkAssociations[i], internalIPAddressToString (_NetworkAssociations[i]).c_str ());\n\t}\n}\n\nbool CUnifiedNetwork::haveNamedCnx (const std::string &name, TServiceId sid)\n{\n\tCUnifiedNetwork::TNameMappedConnection::iterator\t\t\t\t\t\t\t\t\t\t\tit;\n\tpair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator>\trange;\n\trange = _NamedCnx.equal_range(name);\n\n\tif (range.first != range.second)\n\t{\n\t\tfor (it=range.first; it!=range.second && (*it).second!=sid; ++it)\n\t\t\t;\n\n\t\treturn (it != range.second);\n\t}\n\treturn false;\n}\n\nvoid CUnifiedNetwork::addNamedCnx (const std::string &name, TServiceId sid)\n{\n\t// check if not already inserted\n\tCUnifiedNetwork::TNameMappedConnection::iterator\t\t\t\t\t\t\t\t\t\t\tit;\n\tpair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator>\trange;\n\trange = _NamedCnx.equal_range(name);\n\n\tif (range.first != range.second)\n\t{\n\t\tfor (it=range.first; it!=range.second && (*it).second!=sid; ++it)\n\t\t\t;\n\n\t\tif (it != range.second)\n\t\t{\n\t\t\tAUTOCHECK_DISPLAY (\"HNETL5: Try to add 2 times the same connection %s-%hu\", name.c_str(), sid.get());\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// insert the name in the map to be able to send message with the name\n\t_NamedCnx.insert(make_pair(name, sid));\n}\n\nvoid CUnifiedNetwork::removeNamedCnx (const std::string &name, TServiceId sid)\n{\n\t// get all map nodes of that service name\n\tCUnifiedNetwork::TNameMappedConnection::iterator\t\t\t\t\t\t\t\t\t\t\tit;\n\tpair<CUnifiedNetwork::TNameMappedConnection::iterator,CUnifiedNetwork::TNameMappedConnection::iterator>\trange;\n\trange = _NamedCnx.equal_range(name);\n\n\t// assume not empty\n\tif (range.first == range.second)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: The unified connection %s-%hu wasn't on the _NamedCnx\", name.c_str(), sid.get());\n\t\treturn;\n\t}\n\n\t// select good service id\n\tfor (it=range.first; it!=range.second && (*it).second!=sid; ++it)\n\t\t;\n\n\t// assume id exists\n\tif (it == range.second)\n\t{\n\t\tAUTOCHECK_DISPLAY (\"HNETL5: The unified connection %s-%hu wasn't on the _NamedCnx\", name.c_str(), sid.get());\n\t\treturn;\n\t}\n\n\t// remove service for map\n\t_NamedCnx.erase(it);\n}\n\nvoid CUnifiedNetwork::addNetworkAssociation (const string &networkName, uint8 nid)\n{\n\tif (nid >= _NetworkAssociations.size ())\n\t\t_NetworkAssociations.resize (nid+1, 0xFF);\n\n\t_NetworkAssociations[nid] = stringToInternalIPAddress (networkName);\n\tnlinfo (\"HNETL5: Associate network '%s' 0x%08x '%s' to nid %hu\", networkName.c_str(), _NetworkAssociations[nid], internalIPAddressToString (_NetworkAssociations[nid]).c_str(), (uint16)nid);\n}\n\nvoid CUnifiedNetwork::callServiceUpCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback)\n{\n\t// now we warn the user\n\tCUnifiedNetwork::TNameMappedCallback::iterator\tit = _UpCallbacks.find(serviceName);\n\tif (it != _UpCallbacks.end())\n\t{\n\t\t// call it\n\t\tfor (list<TCallbackArgItem>::iterator it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)\n\t\t{\n\t\t\tTUnifiedNetCallback\tcb = (*it2).first;\n\t\t\tif (cb)\n\t\t\t\tcb(serviceName, sid, (*it2).second);\n\t\t\telse\n\t\t\t\tnlwarning (\"HNETL5: User set an empty callback for '%s' service up\", serviceName.c_str());\n\t\t}\n\t}\n\n\tif(callGlobalCallback)\n\t{\n\t\tfor (uint c = 0; c < _UpUniCallback.size (); c++)\n\t\t{\n\t\t\tif (_UpUniCallback[c].first != NULL)\n\t\t\t\t_UpUniCallback[c].first (serviceName, sid, _UpUniCallback[c].second);\n\t\t\telse\n\t\t\t\tnlwarning (\"HNETL5: User set an empty callback for '*' service up\");\n\t\t}\n\t}\n}\n\nvoid CUnifiedNetwork::callServiceDownCallback (const std::string &serviceName, TServiceId sid, bool callGlobalCallback)\n{\n\t// now we warn the user\n\tCUnifiedNetwork::TNameMappedCallback::iterator\tit = _DownCallbacks.find(serviceName);\n\tif (it != _DownCallbacks.end())\n\t{\n\t\t// call it\n\t\tfor (list<TCallbackArgItem>::iterator it2 = (*it).second.begin(); it2 != (*it).second.end(); it2++)\n\t\t{\n\t\t\tTUnifiedNetCallback\tcb = (*it2).first;\n\t\t\tif (cb)\n\t\t\t\tcb(serviceName, sid, (*it2).second);\n\t\t\telse\n\t\t\t\tnlwarning (\"HNETL5: User set an empty callback for '%s' service down\", serviceName.c_str());\n\t\t}\n\t}\n\n\tif(callGlobalCallback)\n\t{\n\t\tfor (uint c = 0; c < _DownUniCallback.size (); c++)\n\t\t{\n\t\t\tif (_DownUniCallback[c].first != NULL)\n\t\t\t\t_DownUniCallback[c].first (serviceName, sid, _DownUniCallback[c].second);\n\t\t\telse\n\t\t\t\tnlwarning (\"HNETL5: User set an empty callback for '*' service down\");\n\t\t}\n\t}\n}\n\nvoid CUnifiedNetwork::CUnifiedConnection::display (bool full, CLog *log)\n{\n\tlog->displayNL (\"> %s-%hu %s %s %s (%d ExtAddr %d Cnx) TotalCb %d\", ServiceName.c_str (), ServiceId.get(), IsExternal?\"External\":\"NotExternal\",\n\t\tAutoRetry?\"AutoRetry\":\"NoAutoRetry\", SendId?\"SendId\":\"NoSendId\", ExtAddress.size (), Connections.size (), TotalCallbackCalled);\n\n\tuint maxc = (uint)std::max (ExtAddress.size (), Connections.size ());\n\n\tfor (uint j = 0; j < maxc; j++)\n\t{\n\t\tstring base;\n\t\tif(j < ExtAddress.size ())\n\t\t{\n\t\t\tbase += ExtAddress[j].asString ();\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbase += \"NotValid\";\n\t\t}\n\n\t\tstring ext;\n\t\tif(j < Connections.size () && Connections[j].valid())\n\t\t{\n\t\t\tif(Connections[j].IsServerConnection)\n\t\t\t{\n\t\t\t\text += \"Server \";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\text += \"Client \";\n\t\t\t}\n\t\t\text += Connections[j].CbNetBase->getSockId (Connections[j].HostId)->asString ();\n\t\t\text += \" AppId:\" + toString(Connections[j].getAppId());\n\t\t\tif (Connections[j].CbNetBase->connected ())\n\t\t\t\text += \" Connected\";\n\t\t\telse\n\t\t\t\text += \" NotConnected\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\text += \"NotValid\";\n\t\t}\n\n\t\tlog->displayNL (\"  - %s %s\", base.c_str (), ext.c_str ());\n\t\tif(full)\n\t\t{\n\t\t\tlog->displayNL (\"     * ReceiveQueueStat\");\n\t\t\tConnections[j].CbNetBase->displayReceiveQueueStat(log);\n\t\t\tlog->displayNL (\"     * SendQueueStat\");\n\t\t\tConnections[j].CbNetBase->displaySendQueueStat(log, Connections[j].HostId);\n\t\t\tlog->displayNL (\"     * ThreadStat\");\n\t\t\tConnections[j].CbNetBase->displayThreadStat(log);\n\t\t}\n\t}\n}\n\n\n//\n// Commands\n//\n\nbool createMessage (CMessage &msgout, const vector<string> &args, CLog &log)\n{\n\tfor (uint i = 2; i < args.size (); i+=2)\n\t{\n\t\tstring type = args[i+0];\n\t\tstring value = args[i+1];\n\n\t\t\t if (type == \"s8\")\t\t\t{ sint8  v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"s16\")\t\t\t{ sint16 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"s32\")\t\t\t{ sint32 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"s64\")\t\t\t{ sint64 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"u8\")\t\t\t{ uint8  v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"u16\")\t\t\t{ uint16 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"u32\")\t\t\t{ uint32 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"u64\")\t\t\t{ uint64 v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"f\")\t\t\t{ float  v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"d\")\t\t\t{ double v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"b\")\t\t\t{ bool   v; fromString(value, v); msgout.serial (v); }\n\t\telse if (type == \"s\")\t\t\t{ msgout.serial (value); }\n\t\telse if (type == \"e\")\t\t\t{ CEntityId e; e.fromString(value.c_str()); msgout.serial(e); }\n\t\telse { log.displayNL (\"type '%s' is not a valid type\", type.c_str()); return false; }\n\t}\n\treturn true;\n}\n\n\n//\n// Commands and Variables\n//\n\nNLMISC_CATEGORISED_VARIABLE(nel, uint32, TotalCallbackCalled, \"Total callback called number on layer 5\");\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, uint64, SendQueueSize, \"current size in bytes of all send queues\")\n{\n\tnlunreferenced(human);\n\t\n\tif (get)\n\t{\n\t\tif (!CUnifiedNetwork::isUsed ())\n\t\t\t*pointer = 0;\n\t\telse\n\t\t\t*pointer = CUnifiedNetwork::getInstance()->getSendQueueSize();\n\t}\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, uint64, ReceiveQueueSize, \"current size in bytes of all receive queues\")\n{\n\tnlunreferenced(human);\n\n\tif (get)\n\t{\n\t\tif (!CUnifiedNetwork::isUsed ())\n\t\t\t*pointer = 0;\n\t\telse\n\t\t\t*pointer = CUnifiedNetwork::getInstance()->getReceiveQueueSize();\n\t}\n}\n\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, uint64, ReceivedBytes, \"total of bytes received by this service\")\n{\n\tnlunreferenced(human);\n\n\tif (get)\n\t{\n\t\tif (!CUnifiedNetwork::isUsed ())\n\t\t\t*pointer = 0;\n\t\telse\n\t\t\t*pointer = CUnifiedNetwork::getInstance()->getBytesReceived ();\n\t}\n}\n\nNLMISC_CATEGORISED_DYNVARIABLE(nel, uint64, SentBytes, \"total of bytes sent by this service\")\n{\n\tnlunreferenced(human);\n\n\tif (get)\n\t{\n\t\tif (!CUnifiedNetwork::isUsed ())\n\t\t\t*pointer = 0;\n\t\telse\n\t\t\t*pointer = CUnifiedNetwork::getInstance()->getBytesSent ();\n\t}\n}\n\n\n/*\n * Simulate a message that comes from the network.\n *\n * for the bool (b type), you must set the value to 1 or 0\n * for the string (s type), we don't manage space inside a string\n * for stl containers, you have first to put a u32 type that is the size of the container and after all elements\n * (ex: if you want to put a vector<uint16> that have 3 elements: u32 3 u16 10 u16 11 u16 12)\n *\n * ex: msgin 128 REGISTER u32 10 u32 541 u32 45\n * You'll receive a fake message REGISTER that seems to come from the service number 128 with 3 uint32.\n *\n */\n\nNLMISC_CATEGORISED_COMMAND(nel, msgin, \"Simulate an input message from another service (ex: msgin 128 REGISTER u32 10 b 1 f 1.5)\", \"<ServiceName>|<ServiceId> <MessageName> [<ParamType> <Param>]*\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() < 2) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't do that because the service doesn't use CUnifiedNetwork\");\n\t\treturn false;\n\t}\n\n\tuint16 sId;\n\tfromString(args[0], sId);\n\n\tTServiceId serviceId(sId);\n\tstring serviceName = args[0].c_str();\n\tstring messageName = args[1].c_str();\n\n\tif (serviceId.get() > 255)\n\t{\n\t\tlog.displayNL (\"Service Id %d must be between [1;255]\", serviceId.get());\n\t\treturn false;\n\t}\n\n\tif ((args.size()-2) % 2 != 0)\n\t{\n\t\tlog.displayNL (\"The number of parameter must be a multiple of 2\");\n\t\treturn false;\n\t}\n\n\tCMessage msg (messageName);\n\n\tif (!createMessage (msg, args, log))\n\t\treturn false;\n\n\tmsg.invert ();\n\n\tTUnifiedMsgCallback cb = CUnifiedNetwork::getInstance()->findCallback (messageName);\n\n\tif (cb == NULL)\n\t{\n\t\tlog.displayNL (\"Callback for message '%s' is not found\", messageName.c_str());\n\t}\n\telse\n\t{\n\t\tcb (msg, serviceName, serviceId);\n\t}\n\n\treturn true;\n}\n\n/*\n * Create a message and send it to the specified service\n *\n * for the bool (b type), you must set the value to 1 or 0\n * for the string (s type), we don't manage space inside a string\n * for stl containers, you have first to put a u32 type that is the size of the container and after all elements\n * (ex: if you want to put a vector<uint16> that have 3 elements: u32 3 u16 10 u16 11 u16 12)\n *\n * ex: msgout 128 REGISTER u32 10 u32 541 u32 45\n * You'll send a real message REGISTER to the service number 128 with 3 uint32.\n *\n */\n\nNLMISC_CATEGORISED_COMMAND(nel, msgout, \"Send a message to a specified service (ex: msgout 128 REGISTER u32 10 b 1 f 1.5)\", \"<ServiceName>|<ServiceId> <MessageName> [<ParamType> <Param>]*\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() < 2) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't do that because the service doesn't use CUnifiedNetwork\");\n\t\treturn false;\n\t}\n\n\tuint16 nId;\n\tfromString(args[0], nId);\n\n\tTServiceId serviceId(nId);\n\tstring serviceName = args[0].c_str();\n\tstring messageName = args[1].c_str();\n\n\tif (serviceId.get() > 255)\n\t{\n\t\tlog.displayNL (\"Service Id %d must be between [1;255]\", serviceId.get());\n\t\treturn false;\n\t}\n\n\tif ((args.size()-2) % 2 != 0)\n\t{\n\t\tlog.displayNL (\"The number of parameter must be a multiple of 2\");\n\t\treturn false;\n\t}\n\n\tCMessage msg (messageName);\n\n\tif (!createMessage (msg, args, log))\n\t\treturn false;\n\n\tTSockId host = InvalidSockId;\n\tCCallbackNetBase *cnb = NULL;\n\n\tif (serviceId.get() != 0)\n\t\tcnb = CUnifiedNetwork::getInstance()->getNetBase (serviceId, host);\n\telse\n\t\tcnb = CUnifiedNetwork::getInstance()->getNetBase (serviceName, host);\n\n\tif (cnb == NULL)\n\t{\n\t\tlog.displayNL (\"'%s' is a bad <ServiceId> or <ServiceName>\", args[0].c_str());\n\t\treturn false;\n\t}\n\n\tcnb->send (msg, host);\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, l5QueuesStats, \"Displays queues stats of network layer5\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't display internal table because layer5 is not used\");\n\t\treturn false;\n\t}\n\n\tlog.displayNL (\"%u Unified Connections:\", CUnifiedNetwork::getInstance()->_IdCnx.size ());\n\tfor (uint i = 0; i < CUnifiedNetwork::getInstance()->_IdCnx.size (); i++)\n\t{\n\t\tif(CUnifiedNetwork::getInstance()->_IdCnx[i].State != CUnifiedNetwork::CUnifiedConnection::NotUsed)\n\t\t{\n\t\t\tCUnifiedNetwork::getInstance()->_IdCnx[i].display (true, &log);\n\t\t}\n\t}\n\n\treturn true;\n}\n\n\nNLMISC_CATEGORISED_COMMAND(nel, l5InternalTables, \"Displays internal table of network layer5\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't display internal table because layer5 is not used\");\n\t\treturn false;\n\t}\n\n\tCUnifiedNetwork::getInstance ()->displayInternalTables(&log);\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, l5Callback, \"Displays all callback registered in layer5\", \"\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 0) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't display internal table because layer5 is not used\");\n\t\treturn false;\n\t}\n\n\tlog.displayNL (\"There're %d registered callbacks:\", CUnifiedNetwork::getInstance()->_Callbacks.size());\n\tuint i = 0;\n\tfor (CUnifiedNetwork::TMsgMappedCallback::iterator it = CUnifiedNetwork::getInstance()->_Callbacks.begin(); it != CUnifiedNetwork::getInstance()->_Callbacks.end(); it++)\n\t{\n\t\tlog.displayNL (\" %d '%s' %s\", i++, (*it).first.c_str(), ((*it).second == NULL?\"have a NULL address\":\"\"));\n\t}\n\n\treturn true;\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, isServiceLocal, \"Says if a service is local or not compare with this service\", \"<sid>|<service name>\")\n{\n\tnlunreferenced(human);\n\tnlunreferenced(quiet);\n\tnlunreferenced(rawCommandString);\n\n\tif(args.size() != 1) return false;\n\n\tif (!CUnifiedNetwork::isUsed ())\n\t{\n\t\tlog.displayNL(\"Can't do that because the service doesn't use CUnifiedNetwork\");\n\t\treturn false;\n\t}\n\n\tuint16 nId;\n\tfromString(args[0], nId);\n\n\tTServiceId sid(nId);\n\tif (sid.get() > 0)\n\t{\n\t\tlog.displayNL (\"Service %s-%hu and sid %s are %son the same computer\", CUnifiedNetwork::getInstance ()->_Name.c_str(), CUnifiedNetwork::getInstance ()->_SId.get(), args[0].c_str(), CUnifiedNetwork::getInstance ()->isServiceLocal (sid)?\"\":\"not \");\n\t}\n\telse\n\t{\n\t\tlog.displayNL (\"Service %s-%hu and %s are %son the same computer\", CUnifiedNetwork::getInstance ()->_Name.c_str(), CUnifiedNetwork::getInstance ()->_SId.get(), args[0].c_str(), CUnifiedNetwork::getInstance ()->isServiceLocal (args[0])?\"\":\"not \");\n\t}\n\n\treturn true;\n}\n\nNLMISC_CLASS_COMMAND_IMPL(CUnifiedNetwork, addService)\n{\n\tnlunreferenced(human);\n\tnlunreferenced(quiet);\n\tnlunreferenced(args);\n\n\tTParsedCommandLine pcl;\n\tpcl.parseParamList(rawCommandString);\n\n\tif (pcl.SubParams.size() != 2)\n\t\treturn false;\n\n\t// syntax is as follow :\n\t// <serviceName> ( address=<address:port> [sid=<serviceId>] [sendId] [external] [autoRetry] )\n\n\tTParsedCommandLine * serviceInfo = pcl.SubParams[1];\n\tconst TParsedCommandLine *address = serviceInfo->getParam(\"address\");\n\tif (address == NULL)\n\t{\n\t\tlog.displayNL(\"Can't find param 'address'\");\n\t\treturn false;\n\t}\n\n\tCInetAddress ia(address->ParamValue);;\n\tif (!ia.isValid())\n\t{\n\t\tlog.displayNL(\"Can't parse internet address in '%s'\", address->ParamValue.c_str());\n\t\treturn false;\n\t}\n\n\tTServiceId serviceId(0);\n\tconst TParsedCommandLine *sid = serviceInfo->getParam(\"sid\");\n\tif (sid != NULL)\n\t{\n\t\tuint16 nId;\n\t\tfromString(sid->ParamValue, nId);\n\t\tserviceId.set(nId);\n\t}\n\n\tbool sendId = serviceInfo->getParam(\"sendId\") != NULL;\n\tbool external = serviceInfo->getParam(\"external\") != NULL;\n\tbool autoRetry = serviceInfo->getParam(\"autoRetry\") != NULL;\n\n\tlog.displayNL(\"Adding service '%s' as sid %u with [sendId = %s], [external = %s], [autoRetry = %s]\",\n\t\tserviceInfo->ParamName.c_str(),\n\t\tsid,\n\t\tsendId ? \"YES\" : \"NO\",\n\t\texternal ? \"YES\" : \"NO\",\n\t\tautoRetry ? \"YES\" : \"NO\"\n\t\t);\n\n\taddService(serviceInfo->ParamName,\n\t\t\t\tia,\n\t\t\t\tsendId,\n\t\t\t\texternal,\n\t\t\t\tserviceId,\n\t\t\t\tautoRetry,\n\t\t\t\tfalse);\n\n\treturn true;\n\n}\n\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/unitime.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/net/callback_client.h\"\n#include \"nel/net/callback_server.h\"\n#include \"nel/net/naming_client.h\"\n#include \"nel/net/message.h\"\n\n#include \"nel/net/unitime.h\"\n\nusing namespace NLMISC;\nusing namespace std;\n\nnamespace NLNET\n{\n\nTTime _CUniTime::_SyncUniTime = 0;\nTTime _CUniTime::_SyncLocalTime = 0;\nbool _CUniTime::_Simulate = false;\n\nbool _CUniTime::Sync = false;\n\n\nvoid _CUniTime::setUniTime (NLMISC::TTime /* uTime */, NLMISC::TTime /* lTime */)\n{\n\tnlstop;\n/*\tif (Sync)\n\t{\n\t\tTTime lt = getLocalTime ();\n\t\tTTime delta = uTime - lTime + _SyncLocalTime - _SyncUniTime;\n\n\t\tnlinfo (\"_CUniTime::setUniTime(%\" NL_I64 \"d, %\" NL_I64 \"d): Resyncing delta %\" NL_I64 \"dms\",uTime,lTime,delta);\n\t}\n\telse\n\t{\n\t\tnlinfo (\"_CUniTime::setUniTime(%\" NL_I64 \"d, %\" NL_I64 \"d)\",uTime,lTime);\n\t\tSync = true;\n\t}\n\t_SyncUniTime = uTime;\n\t_SyncLocalTime = lTime;\n*/}\n\nvoid _CUniTime::setUniTime (NLMISC::TTime /* uTime */)\n{\n\tnlstop;\n//\tsetUniTime (uTime, getLocalTime ());\n}\n\n\n\nTTime _CUniTime::getUniTime ()\n{\n\tnlstop;\n\treturn 0;\n/*\tif (!Sync)\n\t{\n\t\tnlerror (\"called getUniTime before calling syncUniTimeFromServer\");\n\t}\n\treturn getLocalTime () - (_SyncLocalTime - _SyncUniTime);\n*/\n}\n\n\nconst char *_CUniTime::getStringUniTime ()\n{\n\tnlstop;\n\treturn getStringUniTime(_CUniTime::getUniTime());\n}\n\n\nconst char *_CUniTime::getStringUniTime (TTime ut)\n{\n\tnlstop;\n\tstatic char str[512];\n\n\tuint32 ms = (uint32) (ut % 1000); // time in ms 1000ms dans 1s\n\tut /= 1000;\n\n\tuint32 s = (uint32) (ut % 60); // time in seconds 60s dans 1mn\n\tut /= 60;\n\n\tuint32 m = (uint32) (ut % 60); // time in minutes 60m dans 1h\n\tut /= 60;\n\n\tuint32 h = (uint32) (ut % 9); // time in hours 9h dans 1j\n\tut /= 9;\n\n\tuint32 day = (uint32) (ut % (8*4)); // time in days 8day dans 1month\n\tut /= 8;\n\n\tuint32 week = (uint32) (ut % 4); // time in weeks 4week dans 1month\n\tut /= 4;\n\n\tuint32 month = (uint32) (ut % 12); // time in months 12month dans 1year\n\tut /= 12;\n\n\tuint  year =  (uint32) ut;\t// time in years\n\n\tsmprintf (str, 512, \"%02d/%02d/%04d (week %d) %02d:%02d:%02d.%03d\", day+1, month+1, year+1, week+1, h, m, s, ms);\n\treturn str;\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n/////////////// SYNCHRONISATION BETWEEN TIME SERVICE AND OTHER SERVICES ////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n\nstatic bool GetUniversalTime;\nstatic uint32 GetUniversalTimeSecondsSince1970;\nstatic TTime GetUniversalTimeUniTime;\n\n/*\nstatic void cbGetUniversalTime (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tnlstop;\n\t// get the association between a date and unitime\n\tmsgin.serial (GetUniversalTimeSecondsSince1970);\n\tmsgin.serial (GetUniversalTimeUniTime);\n\tGetUniversalTime = true;\n}\n*/\n\n/***************************************************************/\n/******************* THE FOLLOWING CODE IS COMMENTED OUT *******/\n/***************************************************************\nstatic TCallbackItem UniTimeCallbackArray[] =\n{\n\t{ \"GUT\", cbGetUniversalTime }\n};\n***************************************************************/\n\nvoid _CUniTime::syncUniTimeFromService (CCallbackNetBase::TRecordingState /* rec */, const CInetAddress * /* addr */)\n{\n\tnlstop;\n/***************************************************************/\n/******************* THE FOLLOWING CODE IS COMMENTED OUT *******/\n/***************************************************************\n\tTTime deltaAdjust, lt;\n\tuint32 firstsecond, nextsecond;\n\tTTime before, after, delta;\n\n\t// create a message with type in the full text format\n\tCMessage msgout (\"AUT\");\n\tCCallbackClient server( rec, \"TS.nmr\" );\n\tserver.addCallbackArray (UniTimeCallbackArray, sizeof (UniTimeCallbackArray) / sizeof (UniTimeCallbackArray[0]));\n\n\tif (addr == NULL)\n\t{\n\t\tCNamingClient::lookupAndConnect (\"TS\", server);\n\t}\n\telse\n\t{\n\t\tserver.connect (*addr);\n\t}\n\n\tif (!server.connected()) goto error;\n\n\tserver.send (msgout);\n\n\t// before time\n\tbefore = CTime::getLocalTime ();\n\n\t// receive the answer\n\tGetUniversalTime = false;\n\twhile (!GetUniversalTime)\n\t{\n\t\tif (!server.connected()) goto error;\n\n\t\tserver.update ();\n\n\t\tnlSleep( 0 );\n\t}\n\n\t// after, before and delta is not used. It's only for information purpose.\n\tafter = CTime::getLocalTime ();\n\tdelta = after - before;\n\n\tnlinfo (\"_CUniTime::syncUniTimeFromService(): ping:%\" NL_I64 \"dms, time:%ds, unitime:%\" NL_I64 \"dms\", delta, GetUniversalTimeSecondsSince1970, GetUniversalTimeUniTime);\n\n// <-- from here to the \"-->\" comment, the block must be executed in less than one second or an infinite loop occurs\n\n\t// get the second\n\tfirstsecond = CTime::getSecondsSince1970 ();\n\tnextsecond = firstsecond+1;\n\n\t// wait the next start of the second (take 100% of CPU to be more accurate)\n\twhile (nextsecond != CTime::getSecondsSince1970 ())\n\t\tnlassert (CTime::getSecondsSince1970 () <= nextsecond);\n\n// -->\n\n\t// get the local time of the beginning of the next second\n\tlt = CTime::getLocalTime ();\n\n\tif ( ! _Simulate )\n\t{\n\t\tif (abs((sint32)((TTime)nextsecond - (TTime)GetUniversalTimeSecondsSince1970)) > 10)\n\t\t{\n\t\t\tnlerror (\"the time delta (between me and the Time Service) is too big (more than 10s), servers aren't NTP synchronized\");\n\t\t\tgoto error;\n\t\t}\n\n\t\t// compute the delta between the other side and our side number of second since 1970\n\t\tdeltaAdjust = ((TTime) nextsecond - (TTime) GetUniversalTimeSecondsSince1970) * 1000;\n\n\t\t// adjust the unitime to the current localtime\n\t\tGetUniversalTimeUniTime += deltaAdjust;\n\n\t\tnlinfo (\"_CUniTime::syncUniTimeFromService(): rtime:%ds, runitime:%\" NL_I64 \"ds, rlocaltime:%\" NL_I64 \"d, deltaAjust:%\" NL_I64 \"dms\", nextsecond, GetUniversalTimeUniTime, lt, deltaAdjust);\n\t}\n\telse\n\t{\n\t\tnlinfo (\"_CUniTime::syncUniTimeFromService(): runitime:%\" NL_I64 \"ds, rlocaltime:%\" NL_I64 \"d\", GetUniversalTimeUniTime, lt);\n\t}\n\n\t_CUniTime::setUniTime (GetUniversalTimeUniTime, lt);\n\n\tserver.disconnect ();\n\treturn;\n\nerror:\n\tnlerror (\"Time Service is not found, lost or can't synchronize universal time\");\n***************************************************************/\n\n}\n\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n/////////////// SYNCHRONISATION BETWEEN CLIENT AND SHARD ///////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////////////////////////\n\n// Server part\n\nstatic void cbServerAskUniversalTime (CMessage& /* msgin */, TSockId from, CCallbackNetBase &netbase)\n{\n\tnlstop;\n\tTTime ut = _CUniTime::getUniTime ();\n\n\t// afficher l adresse de celui qui demande\n\tnlinfo(\"UT: Send the universal time %\" NL_I64 \"d to '%s'\", ut, netbase.hostAddress(from).asString().c_str());\n\n\tCMessage msgout (\"GUT\");\n\tmsgout.serial (ut);\n\tnetbase.send (msgout, from);\n}\n\nTCallbackItem ServerTimeServiceCallbackArray[] =\n{\n\t{ \"AUT\", cbServerAskUniversalTime },\n};\n\nvoid _CUniTime::installServer (CCallbackServer *server)\n{\n\tnlstop;\n\tstatic bool alreadyAddedCallback = false;\n\tnlassert (server != NULL);\n\tnlassert (!alreadyAddedCallback);\n\n\tserver->addCallbackArray (ServerTimeServiceCallbackArray, sizeof (ServerTimeServiceCallbackArray) / sizeof (ServerTimeServiceCallbackArray[0]));\n\talreadyAddedCallback = true;\n}\n\n// Client part\n\nstatic bool GetClientUniversalTime;\nstatic TTime GetClientUniversalTimeUniTime;\n\n/*\nstatic void cbClientGetUniversalTime (CMessage &msgin, TSockId from, CCallbackNetBase &netbase)\n{\n\tnlstop;\n\t// get the association between a date and unitime\n\tmsgin.serial (GetClientUniversalTimeUniTime);\n\tGetClientUniversalTime = true;\n}\n*/\n\n/***************************************************************/\n/******************* THE FOLLOWING CODE IS COMMENTED OUT *******/\n/***************************************************************\nstatic TCallbackItem ClientUniTimeCallbackArray[] =\n{\n\t{ \"GUT\", cbClientGetUniversalTime }\n};\n***************************************************************/\n\n\nvoid _CUniTime::syncUniTimeFromServer (CCallbackClient * /* client */)\n{\n\tnlstop;\n/***************************************************************/\n/******************* THE FOLLOWING CODE IS COMMENTED OUT *******/\n/***************************************************************\n\n\tstatic bool alreadyAddedCallback = false;\n\tnlassert (client != NULL);\n\n\tif (!alreadyAddedCallback)\n\t{\n\t\tclient->addCallbackArray (ClientUniTimeCallbackArray, sizeof (ClientUniTimeCallbackArray) / sizeof (ClientUniTimeCallbackArray[0]));\n\t\talreadyAddedCallback = true;\n\t}\n\n\tsint attempt = 0;\n\tTTime bestdelta = 60000;\t// 1 minute\n\n\tif (!client->connected ()) goto error;\n\n\twhile (attempt < 10)\n\t{\n\t\tCMessage msgout (\"AUT\");\n\n\t\tif (!client->connected()) goto error;\n\n\t\t// send the message\n\t\tclient->send (msgout);\n\n\t\t// before time\n\t\tTTime before = CTime::getLocalTime ();\n\n\t\t// receive the answer\n\t\tGetClientUniversalTime = false;\n\t\twhile (!GetClientUniversalTime)\n\t\t{\n\t\t\tif (!client->connected()) goto error;\n\n\t\t\tclient->update ();\n\t\t}\n\n\t\tTTime after = CTime::getLocalTime (), delta = after - before;\n\n\t\tif (delta < 10 || delta < bestdelta)\n\t\t{\n\t\t\tbestdelta = delta;\n\n\t\t\t_CUniTime::setUniTime (GetClientUniversalTimeUniTime, (before+after)/2);\n\n\t\t\tif (delta < 10) break;\n\t\t}\n\t\tattempt++;\n\t}\n\tclient->disconnect ();\n\tnlinfo (\"Universal time is %\" NL_I64 \"dms with a mean error of %\" NL_I64 \"dms\", _CUniTime::getUniTime(), bestdelta/2);\n\treturn;\nerror:\n\tnlwarning (\"there's no connection or lost or can't synchronize universal time\");\n***************************************************************/\n}\n\n\n//\n// Commands\n//\n/*\nNLMISC_CATEGORISED_COMMAND(nel, time, \"displays the universal time\", \"\")\n{\n\tif(args.size() != 0) return false;\n\n\tif ( _CUniTime::Sync )\n\t{\n\t\tlog.displayNL (\"CTime::getLocalTime(): %\" NL_I64 \"dms, _CUniTime::getUniTime(): %\" NL_I64 \"dms\", CTime::getLocalTime (), _CUniTime::getUniTime ());\n\t\tlog.displayNL (\"_CUniTime::getStringUniTime(): '%s'\", _CUniTime::getStringUniTime());\n\t}\n\telse\n\t{\n\t\tlog.displayNL (\"CTime::getLocalTime(): %\" NL_I64 \"dms <Universal time not sync>\", CTime::getLocalTime ());\n\t}\n\n\treturn true;\n}\n*/\n\n} // NLNET\n"
  },
  {
    "path": "code/nel/src/net/varpath.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include \"stdnet.h\"\n\n#include \"nel/misc/types_nl.h\"\n\n#include \"nel/misc/debug.h\"\n#include \"nel/misc/config_file.h\"\n#include \"nel/misc/displayer.h\"\n#include \"nel/misc/log.h\"\n\n#include \"nel/net/varpath.h\"\n\n\n//\n// Namespaces\n//\n\nusing namespace std;\nusing namespace NLMISC;\n\n\n//\n// Variables\n//\n\n\n\n//\n// Functions\n//\n\n/**\n *\n * VarPath ::= [bloc '.']* bloc\n * bloc    ::= '[' [VarPath ',']* VarPath ']'  |  name\n * name    ::= [ascii]* ['*']\n *\n *\n */\n/*bool CVarPath::getDest (uint level, vector<string> &dest)\n{\n\treturn true;\n}*/\n\nstring CVarPath::getToken ()\n{\n\tstring res;\n\n\tif (TokenPos >= RawVarPath.size())\n\t\treturn res;\n\n\tres += RawVarPath[TokenPos];\n\n\tswitch (RawVarPath[TokenPos++])\n\t{\n\tcase '.': case '*': case '[': case ']': case ',': case '=': case ' ':\n\t\tbreak;\n\tdefault :\n\t\twhile (TokenPos < RawVarPath.size() && RawVarPath[TokenPos] != '.' && RawVarPath[TokenPos] != '[' && RawVarPath[TokenPos] != ']' && RawVarPath[TokenPos] != ',' && RawVarPath[TokenPos] != '=' && RawVarPath[TokenPos] != ' ')\n\t\t{\n\t\t\tres += RawVarPath[TokenPos++];\n\t\t}\n\t\tbreak;\n\t}\n\treturn res;\n}\n\n\nvoid CVarPath::decode ()\n{\n\tvector<string> dest;\n\tTokenPos = 0;\n\tDestination.clear ();\n\n\tstring val = getToken ();\n\n\tif (val.empty())\n\t\treturn;\n\n\tif (val == \"[\" )\n\t{\n\t\tfor(;;)\n\t\t{\n\t\t\tuint osbnb = 0;\n\t\t\tstring d;\n\t\t\tfor(;;)\n\t\t\t{\n\t\t\t\tval = getToken ();\n\t\t\t\tif (val == \"[\")\n\t\t\t\t\tosbnb++;\n\n\t\t\t\t// end of token\n\t\t\t\tif (val.empty())\n\t\t\t\t{\n\t\t\t\t\tnlwarning (\"VP: Bad VarPath '%s', suppose it s an empty varpath\", RawVarPath.c_str());\n\t\t\t\t\tDestination.clear ();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (osbnb == 0 && (val == \",\" || val == \"]\"))\n\t\t\t\t\tbreak;\n\n\t\t\t\tif (val == \"]\")\n\t\t\t\t\tosbnb--;\n\n\t\t\t\td += val;\n\t\t\t}\n\t\t\tdest.push_back (d);\n\t\t\tif (val == \"]\")\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse if (val != \".\" && val != \",\" && val != \"]\")\n\t{\n\t\tdest.push_back (val);\n\t}\n\telse\n\t{\n\t\tnlwarning (\"VP: Malformated VarPath '%s' before position %d\", RawVarPath.c_str (), TokenPos);\n\t\treturn;\n\t}\n\n\t// must be a . or end of string\n\tval = getToken ();\n\tif (val == \" \")\n\t{\n\t\t// special case, there s a space that means that everything after is not really part of the varpath.\n\t\tDestination.push_back (make_pair(RawVarPath, string(\"\")));\n\t\treturn;\n\t}\n\telse if (val != \".\" && !val.empty() && val != \"=\")\n\t{\n\t\tnlwarning (\"VP: Malformated VarPath '%s' before position %d\", RawVarPath.c_str (), TokenPos);\n\t\treturn;\n\t}\n\n\tfor (uint i = 0; i < dest.size(); ++i)\n\t{\n\t\tstring srv, var;\n\t\tstring::size_type pos;\n\n\t\tif ((pos = dest[i].find ('.')) != string::npos)\n\t\t{\n\t\t\tsrv = dest[i].substr(0, pos);\n\t\t\tvar = dest[i].substr(pos+1);\n\t\t\tif (TokenPos < RawVarPath.size())\n\t\t\t\tvar += val + RawVarPath.substr (TokenPos);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsrv = dest[i];\n\t\t\tif (val == \"=\")\n\t\t\t{\n\t\t\t\tsrv += val + RawVarPath.substr (TokenPos);\n\t\t\t\tvar = \"\";\n\t\t\t}\n\t\t\telse\n\t\t\t\tvar = RawVarPath.substr (TokenPos);\n\t\t}\n\n\t\tDestination.push_back (make_pair(srv, var));\n\t}\n\n\t//display ();\n}\n\nbool CVarPath::isFinal ()\n{\n\tif(Destination.size() == 0) return true;\n\tif(Destination[0].second.size() == 0) return true;\n\treturn false;\n}\n\nvoid CVarPath::display ()\n{\n\tnlinfo (\"VP: VarPath dest = %d\", Destination.size ());\n\tfor (uint i = 0; i < Destination.size (); i++)\n\t{\n\t\tnlinfo (\"VP:  > '%s' '%s'\", Destination[i].first.c_str(), Destination[i].second.c_str());\n\t}\n}\n\nNLMISC_CATEGORISED_COMMAND(nel, varPath, \"Test a varpath (for debug purpose)\", \"<rawvarpath>\")\n{\n\tnlunreferenced(rawCommandString);\n\tnlunreferenced(quiet);\n\tnlunreferenced(human);\n\n\tif(args.size() != 1) return false;\n\n\tCVarPath vp (args[0]);\n\n\tlog.displayNL (\"VarPath contains %d destination\", vp.Destination.size ());\n\tfor (uint i = 0; i < vp.Destination.size (); i++)\n\t{\n\t\tlog.displayNL (\"Dest '%s' value '%s'\", vp.Destination[i].first.c_str(), vp.Destination[i].second.c_str());\n\t}\n\tlog.displayNL (\"End of varpath\");\n\n\treturn true;\n}\n"
  },
  {
    "path": "code/nel/tools/CMakeLists.txt",
    "content": "#ADD_SUBDIRECTORY(misc)\n#ADD_SUBDIRECTORY(memory)\n\nIF(WITH_3D)\n  ADD_SUBDIRECTORY(3d)\nENDIF(WITH_3D)\n\nIF(WITH_PACS)\n  ADD_SUBDIRECTORY(pacs)\nENDIF(WITH_PACS)\n\nIF(WITH_LOGIC)\n  ADD_SUBDIRECTORY(logic)\nENDIF(WITH_LOGIC)\n\nIF(WITH_GEORGES)\n#  ADD_SUBDIRECTORY(georges)\nENDIF(WITH_GEORGES)\n\nIF(WITH_SOUND)\n  ADD_SUBDIRECTORY(sound)\nENDIF(WITH_SOUND)\n\nIF(WITH_NEL_TESTS)\n  ADD_SUBDIRECTORY(nel_unit_test)\nENDIF(WITH_NEL_TESTS)\n\n#build_gamedata\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/CMakeLists.txt",
    "content": "FILE(GLOB SRC *.cpp *.h)\n\nADD_EXECUTABLE(nel_unit_test ${SRC})\n\nINCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR} ${CPPTEST_INCLUDE_DIR})\n\nTARGET_LINK_LIBRARIES(nel_unit_test ${CPPTEST_LIBRARIES} nelmisc nelnet)\nNL_DEFAULT_PROPS(nel_unit_test \"Unit Tests\")\nNL_ADD_RUNTIME_FLAGS(nel_unit_test)\n\nADD_DEFINITIONS(${LIBXML2_DEFINITIONS} -DNEL_UNIT_BASE=\"${PROJECT_SOURCE_DIR}/tools/nel_unit_test/\")\n\nINSTALL(TARGETS nel_unit_test RUNTIME DESTINATION ${NL_BIN_PREFIX})\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/__ligo_class.xml",
    "content": "<?xml version=\"1.0\"?>\n<NEL_LIGO_PRIMITIVE_CLASS>\n\t<ALIAS_DYNAMIC_BITS BIT_COUNT=\"20\"/>\n\t<ALIAS_STATIC_FILE_ID FILE_NAME=\"file_index.cfg\"/>\n\n\t<PRIMITIVE CLASS_NAME=\"root\" TYPE=\"node\" AUTO_INIT=\"true\" DELETABLE=\"true\">\n\t\t<PARAMETER NAME=\"name\" TYPE=\"string\" VISIBLE=\"true\"/>\n\t\t<PARAMETER NAME=\"path\" TYPE=\"string\" VISIBLE=\"true\"/>\n\t\t<DYNAMIC_CHILD CLASS_NAME=\"test\"/>\n\t</PRIMITIVE>\n\n\t<!-- the alias class, used by all other class that need persistent aliases-->\n\t<PRIMITIVE CLASS_NAME=\"alias\" TYPE=\"alias\" AUTO_INIT=\"true\" DELETABLE=\"false\">\n\t</PRIMITIVE>\n\n\t<PRIMITIVE CLASS_NAME=\"test\" TYPE=\"node\" AUTO_INIT=\"false\" DELETABLE=\"true\" NUMBERIZE=\"false\">\n\t\t<PARAMETER NAME=\"name\" TYPE=\"string\" VISIBLE=\"true\"/>\n\t\t<STATIC_CHILD CLASS_NAME=\"alias\" NAME=\"alias\"/>\n\t\t<DYNAMIC_CHILD CLASS_NAME=\"test\"/>\n\t</PRIMITIVE>\n</NEL_LIGO_PRIMITIVE_CLASS>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/__test_prim.primitive",
    "content": "<?xml version=\"1.0\"?>\n<PRIMITIVES VERSION=\"1\">\n  <ROOT_PRIMITIVE TYPE=\"CPrimNode\">\n    <ALIAS LAST_GENERATED=\"1\"/>\n    <CHILD TYPE=\"CPrimNode\">\n      <PROPERTY TYPE=\"string\">\n        <NAME>class</NAME>\n        <STRING>test</STRING>\n      </PROPERTY>\n      <PROPERTY TYPE=\"string\">\n        <NAME>name</NAME>\n        <STRING>test_root</STRING>\n      </PROPERTY>\n      <CHILD TYPE=\"CPrimAlias\">\n        <ALIAS VALUE=\"1\"/>\n        <PROPERTY TYPE=\"string\">\n          <NAME>class</NAME>\n          <STRING>alias</STRING>\n        </PROPERTY>\n        <PROPERTY TYPE=\"string\">\n          <NAME>name</NAME>\n          <STRING>alias</STRING>\n        </PROPERTY>\n      </CHILD>\n    </CHILD>\n  </ROOT_PRIMITIVE>\n</PRIMITIVES>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/debug_cfg_with_error_main.cfg",
    "content": "﻿#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 1\n// This config file include the config file with error then generate an error\n// WARNING : is you add lines, update the code in the test\n\n\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 1\n// In this cfg, we introduce an error in a line after define and if clause\n\n\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 5\n\t\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 7\n\t\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 9\n\t// nothing\n\t\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 13\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg\" 15\n\t\n\n// Here is the offending line, at line 18\nABadVar iable = \"foo\";\n\n// Some additionnal garbase lines\n\nAGoodVar = \"bar\";\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 6\n\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 8\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 9\n\t\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 11\n\t// nothing\n\t\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 15\n#fileline \"r:/code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg\" 17\n\t\n\n// Some additionnal garbase lines\n\nAGoodVar = \"bar\";\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/nel_unit_test.cpp",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#include <nel/misc/types_nl.h>\n\n#include <fstream>\n#include <cpptest.h>\n\n#include <nel/misc/debug.h>\n\nusing namespace std;\n\n#ifdef NL_OS_WINDOWS\n#\tdefine NEL_UNIT_DATA \"\"\n#endif\n\n#include \"ut_misc.h\"\n#include \"ut_net.h\"\n#include \"ut_ligo.h\"\n// Add a line here when adding a new test MODULE\n\n#ifdef _MSC_VER\n\n#include <Windows.h>\n\n/** A special stream buffer that output in the 'output debug string' feature of windows.\n */\nclass CDebugOutput : public streambuf\n{\n\tint_type overflow(int_type c)\n\t{\n\t\tstring str(pbase(), pptr());\n\n\t\tif (c != traits_type::eof())\n\t\t\tstr += c;\n\t\tOutputDebugString(str.c_str() );\n\n\t\treturn c;\n\t}\n};\n// The instance of the streambug\nostream msvDebug(new CDebugOutput);\n\n#endif\n\nstatic void usage()\n{\n\tcout << \"usage: mytest [MODE]\\n\"\n\t\t << \"where MODE may be one of:\\n\"\n\t\t << \"  --compiler\\n\"\n\t\t << \"  --html\\n\"\n\t\t << \"  --text-terse (default)\\n\"\n\t\t << \"  --text-verbose\\n\";\n\texit(0);\n}\n\nstatic auto_ptr<Test::Output> cmdline(int argc, char* argv[])\n{\n\tif (argc > 2)\n\t\tusage(); // will not return\n\t\n\tTest::Output* output = 0;\n\t\n\tif (argc == 1)\n\t\toutput = new Test::TextOutput(Test::TextOutput::Verbose);\n\telse\n\t{\n\t\tconst char* arg = argv[1];\n\t\tif (strcmp(arg, \"--compiler\") == 0)\n\t\t{\n#ifdef _MSC_VER\n\t\t\toutput = new Test::CompilerOutput(Test::CompilerOutput::MSVC, msvDebug);\n#elif defined(__GNUC__)\n\t\t\toutput = new Test::CompilerOutput(Test::CompilerOutput::GCC);\n#else\n\t\t\toutput = new Test::CompilerOutput;\n#endif\n\t\t}\n\t\telse if (strcmp(arg, \"--html\") == 0)\n\t\t\toutput =  new Test::HtmlOutput;\n\t\telse if (strcmp(arg, \"--text-terse\") == 0)\n\t\t\toutput = new Test::TextOutput(Test::TextOutput::Terse);\n\t\telse if (strcmp(arg, \"--text-verbose\") == 0)\n\t\t\toutput = new Test::TextOutput(Test::TextOutput::Verbose);\n\t\telse\n\t\t{\n\t\t\tcout << \"invalid commandline argument: \" << arg << endl;\n\t\t\tusage(); // will not return\n\t\t}\n\t}\n\n\treturn auto_ptr<Test::Output>(output);\n}\n\n// Main test program\n//\nint main(int argc, char *argv[])\n{\n\tstatic const char *outputFileName = \"result.html\";\n\n\t// init Nel context\n\tnew NLMISC::CApplicationContext;\n\n\tbool noerrors = false;\n\n\ttry\n\t{\n\t\tTest::Suite ts;\n\n\t\tts.add(auto_ptr<Test::Suite>(new CUTMisc));\n\t\tts.add(auto_ptr<Test::Suite>(new CUTNet));\n\t\t//ts.add(auto_ptr<Test::Suite>(new CUTLigo));\n\t\t// Add a line here when adding a new test MODULE\n\n\t\tauto_ptr<Test::Output> output(cmdline(argc, argv));\n\t\tnoerrors = ts.run(*output);\n\n\t\tTest::HtmlOutput* const html = dynamic_cast<Test::HtmlOutput*>(output.get());\n\t\tif (html)\n\t\t{\n\t\t\tstd::ofstream fout(outputFileName);\n\t\t\thtml->generate(fout, true, \"NeLTest\");\n\t\t}\n\t}\n\tcatch (...)\n\t{\n\t\tcout << \"unexpected exception encountered\";\n\t\treturn EXIT_FAILURE;\n\t}\n\tif(noerrors)\n\t\tnlinfo(\"No errors during unit testing\");\n\telse\n\t\tnlwarning(\"Errors during unit testing\");\n\treturn noerrors?EXIT_SUCCESS:EXIT_FAILURE;\n}\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/result.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n  <meta name=\"generator\" content=\"CppTest - http://cpptest.sourceforge.net\" />\n  \n  <title>NeLTest Unit Tests Results</title>\n  \n  <style type=\"text/css\" media=\"screen\">\n    <!--\n    hr  {\n      width: 100%;\n      border-width: 0px;\n      height: 1px;\n      color: #cccccc;\n      background-color: #cccccc;\n      padding: 0px;\n    }\n    \n    table {\n      width:100%;\n      border-collapse:separate;\n      border-spacing: 2px;\n      border:0px;\n    }\n    tr {\n      margin:0px;\n      padding:0px;\n    }\n    td {\n      margin:0px;\n      padding:1px;\n    }\n    .table_summary {\n    }\n    .table_suites {\n    }\n    .table_suite {\n    }\n    .table_result {\n      margin: 0px 0px 1em 0px;\n    }\n    .tablecell_title {\n      background-color: #a5cef7;\n      font-weight: bold;\n    }\n    \n    .tablecell_success {\n      background-color: #efefe7;\n    }\n    \n    .tablecell_error {\n      color: #ff0808;\n      background-color: #efefe7;\n      font-weight: bold;\n    }\n    p.spaced {\n      margin: 0px;\n      padding: 1em 0px 2em 0px;\n    }\n    p.unspaced {\n      margin: 0px;\n      padding: 0px 0px 2em 0px;\n    }\n    -->\n  </style>\n</head>\n\n<body>\n\n<h1><a name=\"top\"></a>NeLTest Unit Tests Results</h1>\n\n<div style=\"text-align:right\">\nDesigned by <a href=\"http://cpptest.sourceforge.net\">CppTest</a>\n</div>\n<hr />\n\n<h2>Summary</h2>\n<table summary=\"Summary of test results\" class=\"table_summary\">\n  <tr>\n    <td style=\"width:30%\" class=\"tablecell_title\">Tests</td>\n    <td style=\"width:30%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:30%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td style=\"width:30%\" class=\"tablecell_error\">66</td>\n    <td style=\"width:30%\" class=\"tablecell_error\">1</td>\n    <td style=\"width:30%\" class=\"tablecell_error\">98%</td>\n    <td style=\"width:10%\" class=\"tablecell_error\">35.265000</td>\n  </tr>\n</table>\n<hr />\n\n<h2>Test suites</h2>\n<table summary=\"Test Suites\" class=\"table_suites\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Tests</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscCoTask\">CUTMiscCoTask</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">2</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscCommand\">CUTMiscCommand</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">5</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.015000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscConfigFile\">CUTMiscConfigFile</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">6</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.032000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscDebug\">CUTMiscDebug</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">2</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscDynLibLoad \">CUTMiscDynLibLoad </a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscFile\">CUTMiscFile</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">4</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.859000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscPackFile\">CUTMiscPackFile</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">11</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.016000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscSingleton\">CUTMiscSingleton</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">2</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscSString\">CUTMiscSString</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscStream\">CUTMiscStream</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">4</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTMiscVariable \">CUTMiscVariable </a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_error\"><a href=\"#CUTMiscTypes\">CUTMiscTypes</a></td>\n    <td style=\"width:10%\" class=\"tablecell_error\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_error\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_error\">0%</td>\n    <td style=\"width:10%\" class=\"tablecell_error\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTNetLayer3\">CUTNetLayer3</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">2.312000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTNetMessage\">CUTNetMessage</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">3</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTNetModule\">CUTNetModule</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">21</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">32.031000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\"><a href=\"#CUTLigoPrimitive\">CUTLigoPrimitive</a></td>\n    <td style=\"width:10%\" class=\"tablecell_success\">1</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">100%</td>\n    <td style=\"width:10%\" class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<hr />\n\n<h3><a name=\"CUTMiscCoTask\"></a>Suite: CUTMiscCoTask</h3>\n<table summary=\"Details for suite CUTMiscCoTask\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">runTasks</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">tasksAndThreads</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscCommand\"></a>Suite: CUTMiscCommand</h3>\n<table summary=\"Details for suite CUTMiscCommand\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">createOneInstance</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.015000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">createAnotherInstance</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">deleteOneInstance</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">derivedClass</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">derivedClassAndBaseCall</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscConfigFile\"></a>Suite: CUTMiscConfigFile</h3>\n<table summary=\"Details for suite CUTMiscConfigFile\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">configWithInclude</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.016000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">configWithOptional</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">configWithDefine</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">configWithBadTest</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">configIncludeAndOptional</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">reportErrorInSubFiles</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.016000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscDebug\"></a>Suite: CUTMiscDebug</h3>\n<table summary=\"Details for suite CUTMiscDebug\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testInstanceCounter</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testInstanceCounterOutput</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscDynLibLoad \"></a>Suite: CUTMiscDynLibLoad </h3>\n<table summary=\"Details for suite CUTMiscDynLibLoad \" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">libraryNameDecoration</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscFile\"></a>Suite: CUTMiscFile</h3>\n<table summary=\"Details for suite CUTMiscFile\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">copyOneBigFile</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.187000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">copyDifferentFileSize</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.203000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">moveOneBigFile</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.203000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">moveDifferentFileSize</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.266000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscPackFile\"></a>Suite: CUTMiscPackFile</h3>\n<table summary=\"Details for suite CUTMiscPackFile\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">addBnp</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromBnp</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">addXmlpack</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.016000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromXmlpack</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">compressMemory</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromBnpCompressed</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromXmlpackCompressed</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">decompressMemory</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromBnpUncompressed</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadFromXmlpackUncompressed</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">loadXmlpackWithSameName</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscSingleton\"></a>Suite: CUTMiscSingleton</h3>\n<table summary=\"Details for suite CUTMiscSingleton\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">createSingleton</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">accessSingleton</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscSString\"></a>Suite: CUTMiscSString</h3>\n<table summary=\"Details for suite CUTMiscSString\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testStrtok</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscStream\"></a>Suite: CUTMiscStream</h3>\n<table summary=\"Details for suite CUTMiscStream\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">constAndStream</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">memStreamSwap</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">copyOnWrite</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">preallocatedBitStream</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscVariable \"></a>Suite: CUTMiscVariable </h3>\n<table summary=\"Details for suite CUTMiscVariable \" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">declareVar</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTMiscTypes\"></a>Suite: CUTMiscTypes</h3>\n<table summary=\"Details for suite CUTMiscTypes\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_error\"><a href=\"#CUTMiscTypes_basicTypes\">basicTypes</a></td>\n    <td class=\"tablecell_error\">1</td>\n    <td class=\"tablecell_error\">false</td>\n    <td class=\"tablecell_error\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTNetLayer3\"></a>Suite: CUTNetLayer3</h3>\n<table summary=\"Details for suite CUTNetLayer3\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">sendReceiveUpdate</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">2.312000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTNetMessage\"></a>Suite: CUTNetMessage</h3>\n<table summary=\"Details for suite CUTNetMessage\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">messageSwap</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">lockSubMEssage</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">lockSubMEssageWithLongName</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTNetModule\"></a>Suite: CUTNetModule</h3>\n<table summary=\"Details for suite CUTNetModule\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testModuleInitInfoParsing</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testModuleInitInfoQuering</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testModuleInitInfoBadParsing</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">localModuleFactory</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.016000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">failedInit</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">createLocalGateway</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">plugLocalGateway</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">gatewayTransportManagement</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">1.219000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">connectGateways</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.828000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">moduleDisclosure</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">1.328000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">moduleMessaging</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">1.625000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">localMessageQueing</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.609000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">uniqueNameGenerator</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">gwPlugUnplug</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">peerInvisible</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">3.453000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">firewalling</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">3.438000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">distanceAndConnectionLoop</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">6.109000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">securityPlugin</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">5.094000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">synchronousMessaging</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">1.031000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">layer3Autoconnect</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">6.672000</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">interceptorTest</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.609000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<h3><a name=\"CUTLigoPrimitive\"></a>Suite: CUTLigoPrimitive</h3>\n<table summary=\"Details for suite CUTLigoPrimitive\" class=\"table_suite\">\n  <tr>\n    <td class=\"tablecell_title\">Name</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Errors</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Success</td>\n    <td style=\"width:10%\" class=\"tablecell_title\">Time (s)</td>\n  </tr>\n  <tr>\n    <td class=\"tablecell_success\">testAliasGenerator</td>\n    <td class=\"tablecell_success\">0</td>\n    <td class=\"tablecell_success\">true</td>\n    <td class=\"tablecell_success\">0.000000</td>\n  </tr>\n</table>\n<p class=\"spaced\"><a href=\"#top\">Back to top</a>\n</p>\n<hr />\n\n<h2>Test results</h2>\n<h3><a name=\"CUTMiscTypes_basicTypes\"></a>CUTMiscTypes::basicTypes</h3>\n<table summary=\"Test Failure\" class=\"table_result\">\n  <tr>\n    <td style=\"width:15%\" class=\"tablecell_title\">Test</td>\n    <td class=\"tablecell_success\">CUTMiscTypes::basicTypes</td>\n  </tr>\n  <tr>\n    <td style=\"width:15%\" class=\"tablecell_title\">File</td>\n    <td class=\"tablecell_success\">d:\\ryzom\\nel\\tools\\nel_unit_test\\ut_misc_types.h:31</td>\n  </tr>\n  <tr>\n    <td style=\"width:15%\" class=\"tablecell_title\">Message</td>\n    <td class=\"tablecell_success\">sizeof(time_t) == sizeof(uint32)</td>\n  </tr>\n</table>\n<p class=\"unspaced\"><a href=\"#CUTMiscTypes\">Back to CUTMiscTypes</a>\n</p>\n<hr />\n\n\n<p>\n  <a href=\"http://validator.w3.org/#validate-by-upload\">\n    Valid XHTML 1.0 Strict\n  </a>\n</p>\n</body>\n</html>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/run_test.bat",
    "content": "nel_unit_test.exe --html\nstart result.html\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_ligo.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_LIGO\n#define UT_LIGO\n\n#include <nel/ligo/primitive.h>\n\n#include \"ut_ligo_primitive.h\"\n// Add a line here when adding a new test CLASS\n\nstruct CUTLigo : public Test::Suite\n{\n\tCUTLigo()\n\t{\n\t\tadd(auto_ptr<Test::Suite>(new CUTLigoPrimitive));\n\t\t// Add a line here when adding a new test CLASS\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_ligo_primitive.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_LIGO_PRIMITIVE\n#define UT_LIGO_PRIMITIVE\n\n#include <nel/ligo/ligo_config.h>\n#include <nel/ligo/primitive_utils.h>\n\nclass CUTLigoPrimitive : public Test::Suite\n{\npublic:\n\tCUTLigoPrimitive()\n\t{\n\t\tTEST_ADD(CUTLigoPrimitive::testAliasGenerator)\n\t}\n\nprivate:\n\n\tstring\t_RestorePath;\n\tstring\t_WorkingPath;\n\tstring\t_RefPrimFileName;\n\tvoid setup()\n\t{\n\t\t_RestorePath = NLMISC::CPath::getCurrentPath();\n\t\tNLMISC::CPath::setCurrentPath(_WorkingPath.c_str());\n\n\t\t_RefPrimFileName = \"__test_prim.primitive\";\n\n\t\t// register ligo class factory\n\t\tNLLIGO::Register();\n\n\t\t// create a primitive config file\n\t\tnlinfo(\"Building a default ligo class file\");\n\n\t\tconst char\t*CLASS_FILE_NAME = \"__ligo_class.xml\";\n\n\t\tstring classfile;\n\t\tclassfile = string()\n\t\t+\t\"<?xml version=\\\"1.0\\\"?>\\n\"\n\t\t+\t\"<NEL_LIGO_PRIMITIVE_CLASS>\\n\"\n\t\t+\t\"\t<ALIAS_DYNAMIC_BITS BIT_COUNT=\\\"20\\\"/>\\n\"\n\t\t+\t\"\t<ALIAS_STATIC_FILE_ID FILE_NAME=\\\"file_index.cfg\\\"/>\\n\"\n\t\t+\t\"\\n\"\n\t\t+\t\"\t<PRIMITIVE CLASS_NAME=\\\"root\\\" TYPE=\\\"node\\\" AUTO_INIT=\\\"true\\\" DELETABLE=\\\"true\\\">\\n\"\n\t\t+\t\"\t\t<PARAMETER NAME=\\\"name\\\" TYPE=\\\"string\\\" VISIBLE=\\\"true\\\"/>\\n\"\n\t\t+\t\"\t\t<PARAMETER NAME=\\\"path\\\" TYPE=\\\"string\\\" VISIBLE=\\\"true\\\"/>\\n\"\n\t\t+\t\"\t\t<DYNAMIC_CHILD CLASS_NAME=\\\"test\\\"/>\\n\"\n\t\t+\t\"\t</PRIMITIVE>\\n\"\n\t\t+\t\"\\n\"\n\t\t+\t\"\t<!-- the alias class, used by all other class that need persistent aliases-->\\n\"\n\t\t+\t\"\t<PRIMITIVE CLASS_NAME=\\\"alias\\\" TYPE=\\\"alias\\\" AUTO_INIT=\\\"true\\\" DELETABLE=\\\"false\\\">\\n\"\n\t\t+\t\"\t</PRIMITIVE>\\n\"\n\t\t+\t\"\\n\"\n\t\t+\t\"\t<PRIMITIVE CLASS_NAME=\\\"test\\\" TYPE=\\\"node\\\" AUTO_INIT=\\\"false\\\" DELETABLE=\\\"true\\\" NUMBERIZE=\\\"false\\\">\\n\"\n\t\t+\t\"\t\t<PARAMETER NAME=\\\"name\\\" TYPE=\\\"string\\\" VISIBLE=\\\"true\\\"/>\\n\"\n\t\t+\t\"\t\t<STATIC_CHILD CLASS_NAME=\\\"alias\\\" NAME=\\\"alias\\\"/>\\n\"\n\t\t+\t\"\t\t<DYNAMIC_CHILD CLASS_NAME=\\\"test\\\"/>\\n\"\n\t\t+\t\"\t</PRIMITIVE>\\n\"\n\t\t+\t\"</NEL_LIGO_PRIMITIVE_CLASS>\";\n\n\t\tFILE *fp = fopen(CLASS_FILE_NAME, \"wt\");\n\t\tnlassert(fp != NULL);\n\t\tsize_t s = fwrite(classfile.data(), 1, classfile.size(), fp);\n\t\tnlassert(s == classfile.size());\n\t\tfclose(fp);\n\n\t\t// init ligo\n\t\tNLLIGO::CPrimitiveContext::instance().CurrentLigoConfig = &_LigoConfig;\n\t\t_LigoConfig.readPrimitiveClass(CLASS_FILE_NAME, false);\n\n\t\t// create a reference primitive\n\t\tif (NLMISC::CFile::isExists(_RefPrimFileName))\n\t\t{\n\t\t\tNLMISC::CFile::deleteFile(_RefPrimFileName);\n\t\t}\n\t\tNLLIGO::CPrimitives primDoc;\n\t\tnlassert(primDoc.RootNode != NULL);\n\n\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc;\n\n\t\tNLLIGO::IPrimitive *p = dynamic_cast<NLLIGO::IPrimitive *> (NLMISC::CClassRegistry::create (\"CPrimNode\"));\n\t\tp->addPropertyByName(\"class\", new NLLIGO::CPropertyString(\"test\"));\n\t\tp->addPropertyByName(\"name\", new NLLIGO::CPropertyString(\"test_root\"));\n\t\tprimDoc.RootNode->insertChild(p);\n\n\t\tNLLIGO::CPrimAlias *pa = dynamic_cast<NLLIGO::CPrimAlias *> (NLMISC::CClassRegistry::create (\"CPrimAlias\"));\n\t\tpa->addPropertyByName(\"class\", new NLLIGO::CPropertyString(\"alias\"));\n\t\tpa->addPropertyByName(\"name\", new NLLIGO::CPropertyString(\"alias\"));\n\t\tp->insertChild(pa);\n\t\t\n\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL;\n\n\t\t// save the file\n\t\tsaveXmlPrimitiveFile(primDoc, _RefPrimFileName);\n\t}\n\t\n\tvoid tear_down()\n\t{\n\t\tNLMISC::CPath::setCurrentPath(_RestorePath.c_str());\n\t}\n\n\tvoid testAliasGenerator()\n\t{\n\t\t//Known bug : is we load/save a primitive and replacing a primitive node with itself (conserving the alias), the \n\t\t// 'last generated alias' counter is incremented.\n\t\tuint32 lastGeneratedAlias;\n\n\t\t// First, load then save the doc\n\t\t{\n\t\t\tNLLIGO::CPrimitives primDoc;\n\n\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc;\n\t\t\tloadXmlPrimitiveFile(primDoc, _RefPrimFileName, _LigoConfig);\n\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL;\n\n\t\t\tlastGeneratedAlias = primDoc.getLastGeneratedAlias();\n\n\t\t\t// get a copy of the primitive\n\t\t\tNLLIGO::IPrimitive *prim = NULL;\n\t\t\tNLLIGO::IPrimitive *primCopy = NULL;\n\t\t\tTEST_ASSERT(primDoc.RootNode->getChild(prim, 0));\n\t\t\tif (prim)\n\t\t\t{\n\t\t\t\tprimCopy = prim->copy();\n\t\t\t\tTEST_ASSERT(primCopy != NULL);\n\t\t\t\tif (primCopy)\n\t\t\t\t{\n\t\t\t\t\t// remove the primitive\n\t\t\t\t\tprimDoc.RootNode->removeChild(prim);\n\n\t\t\t\t\t// insert the copy\n\t\t\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc;\n\t\t\t\t\tprimDoc.RootNode->insertChild(primCopy);\n\t\t\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// save the file\n\t\t\tsaveXmlPrimitiveFile(primDoc, _RefPrimFileName);\n\t\t}\n\n\t\t// second, reload the file and check the last generated alias\n\t\t{\n\t\t\tNLLIGO::CPrimitives primDoc;\n\n\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &primDoc;\n\t\t\tloadXmlPrimitiveFile(primDoc, _RefPrimFileName, _LigoConfig);\n\t\t\tNLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL;\n\n\t\t\tTEST_ASSERT(lastGeneratedAlias == primDoc.getLastGeneratedAlias());\n\t\t}\n\t}\n\n\tNLLIGO::CLigoConfig\t\t_LigoConfig;\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC\n#define UT_MISC\n\n#include \"ut_misc_co_task.h\"\n#include \"ut_misc_command.h\"\n#include \"ut_misc_config_file.h\"\n#include \"ut_misc_debug.h\"\n#include \"ut_misc_dynlibload.h\"\n#include \"ut_misc_file.h\"\n#include \"ut_misc_pack_file.h\"\n#include \"ut_misc_singleton.h\"\n#include \"ut_misc_sstring.h\"\n#include \"ut_misc_stream.h\"\n#include \"ut_misc_variable.h\"\n#include \"ut_misc_types.h\"\n#include \"ut_misc_string_common.h\"\n// Add a line here when adding a new test CLASS\n\nstruct CUTMisc : public Test::Suite\n{\n\tCUTMisc()\n\t{\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscCoTask));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscCommand));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscConfigFile));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscDebug));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscDynLibLoad));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscFile));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscPackFile));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscSingleton));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscSString));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscStream));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscVariable));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscTypes));\n\t\tadd(auto_ptr<Test::Suite>(new CUTMiscStringCommon));\n\t\t// Add a line here when adding a new test CLASS\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_co_task.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_CO_TASK\n#define UT_MISC_CO_TASK\n\n#include <nel/misc/co_task.h>\n#include <nel/misc/thread.h>\n\nconst char *referenceResult[] =\n{\n\t\"Task1 : 0\",\n\t\"Task2 : 0\",\n\t\"Main : 0\",\n\n\t\"Task1 : 1\",\n\t\"Task2 : 1\",\n\t\"Main : 1\",\n\n\t\"Task1 : 2\",\n\t\"Task2 : 2\",\n\n\t\"Task1 : 3\",\n\t\"Task2 : 3\",\n\n\t\"Task1 : 4\",\n\t\"Task2 : 4\",\n\n\t\"Task2 : 5\",\n\n\t\"Task2 : 6\",\n};\n\nconst char *referenceResultThread1[] =\n{\n\t\"Task1 : 0\",\n\t\"Thread : 0\",\n\n\t\"Task1 : 1\",\n\t\"Thread : 1\",\n\n\t\"Task1 : 2\",\n\t\"Thread : 2\",\n\n\t\"Task1 : 3\",\n\t\"Thread : 3\",\n\n\t\"Task1 : 4\",\n\t\"Thread : 4\",\n};\n\nconst char *referenceResultThread2[] =\n{\n\t\"Task2 : 0\",\n\t\"Main : 0\",\n\n\t\"Task2 : 1\",\n\t\"Main : 1\",\n\n\t\"Task2 : 2\",\n\n\t\"Task2 : 3\",\n\n\t\"Task2 : 4\",\n};\n\nvector<string>\tresult;\nvector<string>\tresult2;\n\n// a simple task\nclass CTask1 : public NLMISC::CCoTask\n{\n\tvector<string>\t&Output;\npublic:\n\tCTask1(vector<string> &output = result)\n\t\t: Output(output)\n\t{}\n\n\tvoid run()\n\t{\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tstring s = NLMISC::toString(\"Task1 : %u\", i);\n\t\t\tOutput.push_back(s);\n\t\t\tyield();\n\t\t}\n\t}\n};\n\n// another simple task\nclass CTask2 : public NLMISC::CCoTask\n{\n\tvector<string>\t&Output;\n\npublic:\n\t\tCTask2(vector<string> &output = result)\n\t\t: Output(output)\n\t{}\n\n\tvoid run()\n\t{\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tstring s = NLMISC::toString(\"Task2 : %u\", i);\n\t\t\tOutput.push_back(s);\n\t\t\tyield();\n\t\t}\n\t}\n};\n\n// a thread runnable class\nclass CTaskThread : public NLMISC::IRunnable\n{\n\tvoid run()\n\t{\n\t\tCTask1\tt1(result2);\n\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tt1.resume();\n\t\t\tstring s = NLMISC::toString(\"Thread : %u\", i);\n\t\t\tresult2.push_back(s);\n\t\t\tNLMISC::nlSleep(0);\n\t\t}\n\t}\n};\n\n// Test suite for coroutine task\nclass CUTMiscCoTask: public Test::Suite\n{\npublic:\n\tCUTMiscCoTask()\n\t{\n\t\tTEST_ADD(CUTMiscCoTask::runTasks);\n\t\tTEST_ADD(CUTMiscCoTask::tasksAndThreads);\n\n\t}\n\n\tvoid tasksAndThreads()\n\t{\n\t\t// test running task in two separate thread (this stress the \n\t\t// multithreading support of task). CoTask API ;ake use of\n\t\t// thread local storage API to store by thread current task info.\n\n\t\tresult.clear();\n\t\tresult2.clear();\n\n\t\tCTaskThread\ttt;\n\t\tNLMISC::IThread *th = NLMISC::IThread::create(&tt);\n\n\t\tCTask2\tt2;\n\n\t\t// start the thread\n\t\tth->start();\n\n\t\tfor (uint i=0; i<2; ++i)\n\t\t{\n\t\t\tt2.resume();\n\t\t\tstring s = NLMISC::toString(\"Main : %u\", i);\n\t\t\tresult.push_back(s);\n\t\t\tNLMISC::nlSleep(0);\n\t\t}\n\n\t\t// wait task completion\n\t\tt2.wait();\n\n\t\t// wait thread completion\n\t\tth->wait();\n\n\t\tdelete th;\n\n\t\t// test result\n\t\tfor (uint i=0; i<sizeofarray(referenceResultThread1); ++i)\n\t\t{\n\t\t\tstring &s1 = result2[i];\n\t\t\tconst char *s2 = referenceResultThread1[i];\n\t\t\tTEST_ASSERT(referenceResultThread1[i] == result2[i]);\n\t\t}\n\t\tfor (uint i=0; i<sizeofarray(referenceResultThread2); ++i)\n\t\t{\n\t\t\tstring &s1 = result[i];\n\t\t\tconst char *s2 = referenceResultThread2[i];\n\t\t\tTEST_ASSERT(referenceResultThread2[i] == result[i]);\n\t\t}\n\t}\n\t\n\tvoid runTasks()\n\t{\n\t\t/// Run two main task and two working task at once and check that the result\n\t\tresult.clear();\n\n\t\t// create the two task object\n\t\tCTask1 t1;\n\t\tCTask2 t2;\n\n\t\t// start the two task (can be done in the loop, but we want the task output first)\n\t\tt1.resume();\n\t\tt2.resume();\n\n\t\t// loop and run the main task and the two sub task\n\t\tfor (uint i=0; i<2; ++i)\n\t\t{\n\t\t\tstring s = NLMISC::toString(\"Main : %u\", i);\n\t\t\tresult.push_back(s);\n\t\t\tt1.resume();\n\t\t\tt2.resume();\n\t\t}\n\n\t\t// continue to run the task until the first is terminated\n\t\twhile (!t1.isFinished())\n\t\t{\n\t\t\tt1.resume();\n\t\t\tt2.resume();\n\t\t}\n\n\t\t// wait task termination\n\t\tt1.wait();\n\t\tt2.wait();\n\n\t\t// check the generated result\n\t\tTEST_ASSERT(sizeofarray(referenceResult) == result.size());\n\t\tfor (uint i=0; i<sizeofarray(referenceResult); ++i)\n\t\t{\n\t\t\tstring &s1 = result[i];\n\t\t\tconst char *s2 = referenceResult[i];\n\t\t\tTEST_ASSERT(referenceResult[i] == result[i]);\n\t\t}\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_command.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_COMMAND\n#define UT_MISC_COMMAND\n\n#include <nel/misc/command.h>\n\nvector<string>\tcallList;\n\nclass TTest : public NLMISC::ICommandsHandler\n{\nprotected:\n\tstd::string _Name;\npublic:\n\tconst std::string &getCommandHandlerName() const\n\t{\n\t\treturn _Name;\n\t}\n\n\tvoid setName(const std::string &name)\n\t{\n\t\tnlassert(_Name.empty());\n\t\t_Name = name;\n\n\t\tregisterCommandsHandler();\n\t}\n\n\tNLMISC_COMMAND_HANDLER_TABLE_BEGIN(TTest)\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTest, theCommand1, \"help\", \"args\")\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTest, theCommand2, \"other help\", \"other args\")\n\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\n\tNLMISC_CLASS_COMMAND_DECL(theCommand1)\n\t{\n\t\tcallList.push_back(_Name+\".theCommand1\");\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_DECL(theCommand2)\n\t{\n\t\tcallList.push_back(_Name+\".theCommand2\");\n\t\treturn true;\n\t}\n\n};\n\nclass TTestDerived : public TTest\n{\npublic:\n\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived, TTest)\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived, derivedCommand, \"help\", \"args\")\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived, commandToOverride, \"help\", \"args\")\n\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\tNLMISC_CLASS_COMMAND_DECL(derivedCommand)\n\t{\n\t\tcallList.push_back(_Name+\".derivedCommand\");\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_DECL(commandToOverride)\n\t{\n\t\tcallList.push_back(_Name+\".commandToOverride\");\n\t\treturn true;\n\t}\n\n};\n\nclass TTestDerived2 : public TTestDerived\n{\npublic:\n\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived2, TTestDerived)\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived2, derivedCommand2, \"help\", \"args\")\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived2, commandToOverride, \"help\", \"args\")\n\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\tNLMISC_CLASS_COMMAND_DECL(derivedCommand2)\n\t{\n\t\tcallList.push_back(_Name+\".derivedCommand2\");\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_DECL(commandToOverride)\n\t{\n\t\tcallList.push_back(_Name+\".command Overidden\");\n\t\treturn true;\n\t}\n\n};\n\nclass TTestDerived3 : public TTestDerived2\n{\n\t// empty class\n};\n\nclass TTestDerived4 : public TTestDerived3\n{\npublic:\n\tNLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(TTestDerived4, TTestDerived3)\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived4, derivedCommand4, \"help\", \"args\")\n\t\tNLMISC_COMMAND_HANDLER_ADD(TTestDerived4, theCommand1, \"help\", \"args\")\n\tNLMISC_COMMAND_HANDLER_TABLE_END\n\n\tNLMISC_CLASS_COMMAND_DECL(derivedCommand4)\n\t{\n\t\tcallList.push_back(_Name+\".derivedCommand4\");\n\t\treturn true;\n\t}\n\n\tNLMISC_CLASS_COMMAND_DECL(theCommand1)\n\t{\n\t\tcallList.push_back(_Name+\".recallBase\");\n\t\tNLMISC_CLASS_COMMAND_CALL_BASE(TTestDerived3, theCommand1);\n\t\treturn true;\n\t}\n};\n\nclass CUTMiscCommand : public Test::Suite\n{\n\tTTest\t*t1;\n\tTTest\t*t2;\npublic:\n\tCUTMiscCommand()\n\t{\n\t\tTEST_ADD(CUTMiscCommand::createOneInstance);\n\t\tTEST_ADD(CUTMiscCommand::createAnotherInstance);\n\t\tTEST_ADD(CUTMiscCommand::deleteOneInstance);\n\t\tTEST_ADD(CUTMiscCommand::derivedClass);\n\t\tTEST_ADD(CUTMiscCommand::derivedClassAndBaseCall);\n\t}\n\n\tvoid derivedClassAndBaseCall()\n\t{\n\t\tTTestDerived4\tt4;\n\t\tt4.setName(\"T4\");\n\n\t\tcallList.clear();\n\n\t\tNLMISC::ICommand::execute(\"T4.derivedCommand4\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 1);\n\t\tTEST_ASSERT(callList[0] == \"T4.derivedCommand4\");\n\n\t\tNLMISC::ICommand::execute(\"T4.theCommand1\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 3);\n\t\tTEST_ASSERT(callList[1] == \"T4.recallBase\");\n\t\tTEST_ASSERT(callList[2] == \"T4.theCommand1\");\n\t}\n\n\tvoid derivedClass()\n\t{\n\t\tTTestDerived t1;\n\t\tt1.setName(\"T1\");\n\t\tTTestDerived2 t2;\n\t\tt2.setName(\"T2\");\n\n\t\tcallList.clear();\n\n\t\tNLMISC::ICommand::execute(\"T1.theCommand1\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 1);\n\t\tTEST_ASSERT(callList[0] == \"T1.theCommand1\");\n\n\t\tNLMISC::ICommand::execute(\"T1.derivedCommand\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 2);\n\t\tTEST_ASSERT(callList[1] == \"T1.derivedCommand\");\n\n\t\tNLMISC::ICommand::execute(\"T1.commandToOverride\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 3);\n\t\tTEST_ASSERT(callList[2] == \"T1.commandToOverride\");\n\t\t\n\n\t\tNLMISC::ICommand::execute(\"T2.theCommand1\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 4);\n\t\tTEST_ASSERT(callList[3] == \"T2.theCommand1\");\n\n\t\tNLMISC::ICommand::execute(\"T2.derivedCommand\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 5);\n\t\tTEST_ASSERT(callList[4] == \"T2.derivedCommand\");\n\n\t\tNLMISC::ICommand::execute(\"T2.commandToOverride\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 6);\n\t\tTEST_ASSERT(callList[5] == \"T2.command Overidden\");\n\t}\n\n\t\n\tvoid createOneInstance()\n\t{\n\t\tt1 = new TTest;\n\t\tt1->setName(\"inst1\");\n\n\t\tTEST_ASSERT(callList.empty());\n\n\t\tNLMISC::ICommand::execute(\"inst1.theCommand1\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 1);\n\t\tTEST_ASSERT(callList[0] == \"inst1.theCommand1\");\n\n\t\tNLMISC::ICommand::execute(\"inst1.theCommand2\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 2);\n\t\tTEST_ASSERT(callList[0] == \"inst1.theCommand1\");\n\t\tTEST_ASSERT(callList[1] == \"inst1.theCommand2\");\n\t}\n\n\tvoid createAnotherInstance()\n\t{\n\t\tt2 = new TTest;\n\t\tt2->setName(\"inst2\");\n\n\t\tTEST_ASSERT(callList.size() == 2);\n\n\t\tNLMISC::ICommand::execute(\"inst2.theCommand1\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 3);\n\t\tTEST_ASSERT(callList[0] == \"inst1.theCommand1\");\n\t\tTEST_ASSERT(callList[1] == \"inst1.theCommand2\");\n\t\tTEST_ASSERT(callList[2] == \"inst2.theCommand1\");\n\n\t\tNLMISC::ICommand::execute(\"inst2.theCommand2\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 4);\n\t\tTEST_ASSERT(callList[0] == \"inst1.theCommand1\");\n\t\tTEST_ASSERT(callList[1] == \"inst1.theCommand2\");\n\t\tTEST_ASSERT(callList[2] == \"inst2.theCommand1\");\n\t\tTEST_ASSERT(callList[3] == \"inst2.theCommand2\");\n\t}\n\n\tvoid deleteOneInstance()\n\t{\n\t\tdelete t1;\n\n\t\tNLMISC::ICommand::execute(\"inst1.theCommand2\", *NLMISC::InfoLog);\n\t\tTEST_ASSERT(callList.size() == 4);\n\t\tTEST_ASSERT(callList[0] == \"inst1.theCommand1\");\n\t\tTEST_ASSERT(callList[1] == \"inst1.theCommand2\");\n\t\tTEST_ASSERT(callList[2] == \"inst2.theCommand1\");\n\t\tTEST_ASSERT(callList[3] == \"inst2.theCommand2\");\n\n\t}\n\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_config_file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_CONFIG_FILE\n#define UT_MISC_CONFIG_FILE\n\n#include <nel/misc/path.h>\n\n#ifndef NEL_UNIT_BASE\n#define NEL_UNIT_BASE \"\"\n#endif // NEL_UNIT_BASE\n\n// Test suite for CConfigFile class\nclass CUTMiscConfigFile : public Test::Suite\n{\n\tstring\t\t_WorkingPath;\n\tstring\t\t_OldPath;\npublic:\n\tCUTMiscConfigFile ()\n\t{\n\t\tTEST_ADD(CUTMiscConfigFile::configWithInclude);\n\t\tTEST_ADD(CUTMiscConfigFile::configWithOptional);\n\t\tTEST_ADD(CUTMiscConfigFile::configWithDefine);\n\t\tTEST_ADD(CUTMiscConfigFile::configWithBadTest);\n\t\tTEST_ADD(CUTMiscConfigFile::configIncludeAndOptional);\n\t\tTEST_ADD(CUTMiscConfigFile::reportErrorInSubFiles);\n\t}\n\n\tvoid setup()\n\t{\n\t\t_OldPath = NLMISC::CPath::getCurrentPath();\n\t\tNLMISC::CPath::setCurrentPath(_WorkingPath.c_str());\n\t}\n\n\tvoid tear_down()\n\t{\n\t\tNLMISC::CPath::setCurrentPath(_OldPath.c_str());\n\t}\n\t\n\tvoid configWithInclude()\n\t{\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tTEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_include.cfg\"));\n\n\t\tTEST_ASSERT(configFile.loaded());\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgWithInclude\") != NULL);\n\t\tTEST_ASSERT(configFile.getVar(\"CfgWithInclude\").asString(0) == \"ok\");\n\t\tTEST_ASSERT(configFile.getVarPtr(\"IncludedCfg\") != NULL);\n\t\tTEST_ASSERT(configFile.getVar(\"IncludedCfg\").asString(0) == \"ok\");\n\t}\n\n\tvoid configWithOptional()\n\t{\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tTEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_optional.cfg\"));\n\n\t\tTEST_ASSERT(configFile.loaded());\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgWithInclude\") != NULL);\n\t\tTEST_ASSERT(configFile.getVar(\"CfgWithInclude\").asString(0) == \"ok\");\n\t\tTEST_ASSERT(configFile.getVarPtr(\"IncludedCfg\") != NULL);\n\t\tTEST_ASSERT(configFile.getVar(\"IncludedCfg\").asString(0) == \"ok\");\n\t}\n\n\n\tvoid configWithDefine()\n\t{\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tTEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_define.cfg\"));\n\n\t\tTEST_ASSERT(configFile.loaded());\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgReadableVar\") != NULL);\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgNotToBeFound\") == NULL);\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgInvisible\") == NULL);\n\t\tTEST_ASSERT(configFile.getVarPtr(\"CfgMustExist\") != NULL);\n\t}\n\n\tclass  CMyDisplayer : public NLMISC::IDisplayer\n\t{\n\tpublic:\n\t\tvector<string>\tLines;\n\t\n\t\tvirtual void doDisplay( const NLMISC::CLog::TDisplayInfo& args, const char *message)\n\t\t{\n\t\t\tLines.push_back(message);\n\t\t}\n\t};\n\n\tvoid configWithBadTest()\n\t{\n\t\t// override the warning channel to get the error on unclosed if\n\t\tCMyDisplayer warnings;\n\t\tNLMISC::CLog logger;\n\t\tlogger.addDisplayer(&warnings);\n\t\tNLMISC::CNLWarningOverride\toverride(&logger);\n\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tstring fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE \"ut_misc_files/cfg_with_bad_test.cfg\", false);\n\n\t\tTEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_bad_test.cfg\"));\n\n\t\tTEST_ASSERT(configFile.getVarPtr(\"ASimpleVar\") != NULL);\n\n\t\t// check that we have the warnings\n\t\tTEST_ASSERT(warnings.Lines.size() == 13);\n\t\tTEST_ASSERT(warnings.Lines[0].find(string(\"Preprocess: In file \")+fullName+\"(6) : Error unrecognized preprocessor command\") != string::npos);\n\t\tTEST_ASSERT(warnings.Lines[1].find(string(\"Preprocess: In file \")+fullName+\"(9) : Error found '#endif' without matching #if\") != string::npos);\n\n\t\t// skip the I18N warning from parseMarkedString\n\t\tTEST_ASSERT(warnings.Lines[3].find(string(\"Preprocess: In file \")+fullName+\"(12) : Error parsing include file command\") != string::npos);\n\t\t// skip the I18N warning from parseMarkedString\n\t\tTEST_ASSERT(warnings.Lines[5].find(string(\"Preprocess: In file \")+fullName+\"(13) : Error parsing include file command\") != string::npos);\n\t\t// skip the I18N warning from parseMarkedString\n\t\tTEST_ASSERT(warnings.Lines[7].find(string(\"Preprocess: In file \")+fullName+\"(14) : Error parsing optional file command\") != string::npos);\n\t\t// skip the I18N warning from parseMarkedString\n\t\tTEST_ASSERT(warnings.Lines[9].find(string(\"Preprocess: In file \")+fullName+\"(15) : Error parsing optional file command\") != string::npos);\n\t\tTEST_ASSERT(warnings.Lines[10].find(string(\"Preprocess: In file \")+fullName+\"(16) : Error parsing #define command\") != string::npos);\n\t\tTEST_ASSERT(warnings.Lines[11].find(string(\"Preprocess: In file \")+fullName+\"(17) : Error parsing #ifdef command\") != string::npos);\n\t\t\n\t\tTEST_ASSERT(warnings.Lines[12].find(\"Preprocess: Missing 1 closing #endif after parsing\") != string::npos);\n\t}\n\n\tvoid configIncludeAndOptional()\n\t{\n\t\tCMyDisplayer warnings;\n\t\tNLMISC::CLog logger;\n\t\tlogger.addDisplayer(&warnings);\n\t\tNLMISC::CNLWarningOverride\toverride(&logger);\n\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tstring fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE \"ut_misc_files/cfg_with_include_and_optional.cfg\", false);\n\n\n\t\tTEST_THROWS_NOTHING(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_include_and_optional.cfg\"));\n\n\t\t// check that we have the warnings only for the 'include' command\n\t\tTEST_ASSERT(warnings.Lines.size() == 1);\n\t\tTEST_ASSERT(warnings.Lines[0].find(string(\"Preprocess: In file \")+fullName+\"(2) : Cannot include file 'a_missing_file.cfg'\") != string::npos);\n\t}\n\n\tvoid reportErrorInSubFiles()\n\t{\n\t\tCMyDisplayer warnings;\n\t\tNLMISC::CLog logger;\n\t\tlogger.addDisplayer(&warnings);\n\t\tNLMISC::CNLWarningOverride\toverride(&logger);\n\n\t\tNLMISC::CConfigFile configFile;\n\n\t\tstring fullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE \"ut_misc_files/cfg_with_error_main.cfg\", false);\n\t\tstring subfullName = NLMISC::CPath::getFullPath(NEL_UNIT_BASE \"ut_misc_files/cfg_with_error.cfg\", false);\n\n\n\t\tTEST_THROWS(configFile.load(NEL_UNIT_BASE \"ut_misc_files/cfg_with_error_main.cfg\"), NLMISC::EParseError);\n\n\t\t// check that we have error report with correct filename and line number\n\t\tTEST_ASSERT(warnings.Lines.size() == 1);\n\t\t// the first error is in the subfile\n\t\tTEST_ASSERT(warnings.Lines[0].find(string(\"CF: Parsing error in file \")+subfullName+\" line 18\") != string::npos);\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_debug.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_DEBUG\n#define UT_MISC_DEBUG\n\n#include <nel/misc/debug.h>\n#include <nel/misc/dynloadlib.h>\n\nclass CMiscUnitTestNelLibrary : public NLMISC::INelLibrary { \n\tvoid onLibraryLoaded(bool firstTime) { } \n\tvoid onLibraryUnloaded(bool lastTime) { }  \n};\nNLMISC_DECL_PURE_LIB(CMiscUnitTestNelLibrary);\n\n// Test suite for CInstanceCounter\nclass CFoo1\n{\npublic:\n\tNL_INSTANCE_COUNTER_DECL(CFoo1);\n};\nNL_INSTANCE_COUNTER_IMPL(CFoo1);\n\nclass CFoo2\n{\npublic:\n\tNL_INSTANCE_COUNTER_DECL(CFoo2);\n};\n\nNL_INSTANCE_COUNTER_IMPL(CFoo2);\n\nclass CFoo3 : public CFoo2\n{\npublic:\n\tNL_INSTANCE_COUNTER_DECL(CFoo3);\n};\n\nNL_INSTANCE_COUNTER_IMPL(CFoo3);\n\n\nclass CUTMiscDebug : public Test::Suite\n{\npublic:\n\tCUTMiscDebug()\n\t{\n\t\tTEST_ADD(CUTMiscDebug::testInstanceCounter)\n\t\tTEST_ADD(CUTMiscDebug::testInstanceCounterOutput)\n\t}\n\t\nprivate:\n\tvoid testInstanceCounter()\n\t{\n\t\tsint32 n;\n\t\t{\n\t\t\tCFoo1\tfoo1;\n\n\t\t\tsint32 n = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 1);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 1);\n\n\t\t\tNLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter();\n\n\t\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 1);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 0);\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == -1);\n\n\t\t{\n\t\t\tCFoo1\tfoo1;\n\t\t\tCFoo1\tother(foo1);\n\n\t\t\tsint32 n = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 2);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 1);\n\n\t\t\tNLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter();\n\n\t\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 2);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 0);\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == -2);\n\n\t\t{\n\t\t\tCFoo1\tfoo1;\n\t\t\tCFoo1\tother;\n\n\t\t\tfoo1 = other;\n\n\t\t\tsint32 n = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 2);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 0);\n\n\t\t\tNLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter();\n\n\t\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\t\tTEST_ASSERT(n == 2);\n\t\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\t\tTEST_ASSERT(n == 0);\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == -2);\n\n\t\tCFoo1\t*foo1s[10];\n\t\tCFoo2\t*foo2s[10];\n\t\tCFoo3\t*foo3s[10];\n\t\tfor (uint i=0; i<10; ++i)\n\t\t{\n\t\t\tfoo1s[i] = new CFoo1;\n\t\t\tfoo2s[i] = new CFoo2;\n\t\t\tfoo3s[i] = new CFoo3;\n\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 10);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == 8);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo2);\n\t\tTEST_ASSERT(n == 20);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2);\n\t\tTEST_ASSERT(n == 20);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo3);\n\t\tTEST_ASSERT(n == 10);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3);\n\t\tTEST_ASSERT(n == 10);\n\n\t\tNLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter();\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 10);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo2);\n\t\tTEST_ASSERT(n == 20);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo3);\n\t\tTEST_ASSERT(n == 10);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3);\n\t\tTEST_ASSERT(n == 0);\n\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tdelete foo1s[i];\n\t\t\tdelete foo2s[i];\n\t\t\tdelete foo3s[i];\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 5);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == -5);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo2);\n\t\tTEST_ASSERT(n == 10);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2);\n\t\tTEST_ASSERT(n == -10);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo3);\n\t\tTEST_ASSERT(n == 5);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3);\n\t\tTEST_ASSERT(n == -5);\n\t\tfor (uint i=5; i<10; ++i)\n\t\t{\n\t\t\tdelete foo1s[i];\n\t\t\tdelete foo2s[i];\n\t\t\tdelete foo3s[i];\n\t\t}\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo1);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo1);\n\t\tTEST_ASSERT(n == -10);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo2);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo2);\n\t\tTEST_ASSERT(n == -20);\n\t\tn = NL_GET_INSTANCE_COUNTER(CFoo3);\n\t\tTEST_ASSERT(n == 0);\n\t\tn = NL_GET_INSTANCE_COUNTER_DELTA(CFoo3);\n\t\tTEST_ASSERT(n == -10);\n\t}\n\n\tvoid testInstanceCounterOutput()\n\t{\n\t\tNLMISC::CInstanceCounterManager::getInstance().resetDeltaCounter();\n\n\t\tCFoo1\t*foo1s[10];\n\t\tCFoo2\t*foo2s[10];\n\t\tCFoo3\t*foo3s[10];\n\t\tfor (uint i=0; i<10; ++i)\n\t\t{\n\t\t\tfoo1s[i] = new CFoo1;\n\t\t\tfoo2s[i] = new CFoo2;\n\t\t\tfoo3s[i] = new CFoo3;\n\n\t\t}\n\n\t\tstring ref = \"Listing 3 Instance counters :\\n\"\n\t\t\t\t\t \"  Class 'CFoo1               ', \\t        10 instances, \\t        10 delta\\n\"\n\t\t\t\t\t \"  Class 'CFoo2               ', \\t        20 instances, \\t        20 delta\\n\"\n\t\t\t\t\t \"  Class 'CFoo3               ', \\t        10 instances, \\t        10 delta\\n\";\n\n\t\tstring ret = NLMISC::CInstanceCounterManager::getInstance().displayCounters();\n\n\t\tnlinfo(\"%s\", ref.c_str());\n\t\tnlinfo(\"%s\", ret.c_str());\n\t\tTEST_ASSERT(ref == ret);\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_dynlibload.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_DYNLIBLOAD\n#define UT_MISC_DYNLIBLOAD\n\n#include <nel/misc/dynloadlib.h>\n\nclass CUTMiscDynLibLoad : public Test::Suite\n{\npublic:\n\tCUTMiscDynLibLoad ()\n\t{\n\t\tTEST_ADD(CUTMiscDynLibLoad ::libraryNameDecoration)\n\t}\n\n\tvoid libraryNameDecoration()\n\t{\n\t\tstring libName = \"libmylib_with_dll_so_some_very_bad_rd_df_tag_inside_df\";\n\t\tstring fileName = \"some/path/to/add/difficulties/\"+NLMISC::CLibrary::makeLibName(libName);\n\t\tstring cleanedName = NLMISC::CLibrary::cleanLibName(fileName);\n\n\t\tTEST_ASSERT(cleanedName == libName);\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_FILE\n#define UT_MISC_FILE\n\n#include <nel/misc/file.h>\n#include <nel/misc/path.h>\n\n// Test suite for NLMISC::CFile behavior\nstruct CUTMiscFile : public Test::Suite\n{\n\tCUTMiscFile()\n\t{\n\t\tTEST_ADD(CUTMiscFile::copyOneBigFile);\n\t\tTEST_ADD(CUTMiscFile::copyDifferentFileSize);\n\t\tTEST_ADD(CUTMiscFile::moveOneBigFile);\n\t\tTEST_ADD(CUTMiscFile::moveDifferentFileSize);\n\t\t// Add a line here when adding a new test METHOD\n\t}\n\nprivate:\n\tstring\t_SrcFile;\n\tstring\t_DstFile;\n\n\tvoid setup()\n\t{\n\t\t_SrcFile = \"__copy_file_src.foo\";\n\t\t_DstFile = \"__copy_file_dst.foo\";\n\t}\n\n\tvoid tear_down()\n\t{\n\t}\n\n\tvoid copyFileSize(uint fileSize)\n\t{\n\t\t// create a source file (using standard c code)\n\t\tFILE *fp = fopen(_SrcFile.c_str(), \"wb\");\n\t\tnlverify(fp != NULL);\n\n\t\tfor (uint i=0; i<fileSize; ++i)\n\t\t{\n\t\t\tuint8 c = uint8(i & 0xff);\n\t\t\tnlverify(fwrite(&c, 1, 1, fp) == 1);\n\t\t}\n\t\tfclose(fp);\n\t\tfp = NULL;\n\n\t\tNLMISC::CFile::copyFile(_DstFile, _SrcFile, false);\n\n\t\t// verify the resulting file\n\t\tfp = fopen(_DstFile.c_str(), \"rb\");\n\t\tTEST_ASSERT(fp != NULL);\n\t\tif (fp)\n\t\t{\n\t\t\tfor (uint i=0; i<fileSize; ++i)\n\t\t\t{\n\t\t\t\tuint8 c;\n\t\t\t\tsize_t nbRead = fread(&c, 1,1, fp);\n\t\t\t\tTEST_ASSERT(nbRead == 1);\n\t\t\t\tif (nbRead != 1)\n\t\t\t\t\tbreak;\n\t\t\t\tTEST_ASSERT_MSG(c == uint8(i & 0xff), \"File content changed during copy\");\n\t\t\t\tif (c != uint8(i & 0xff))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tfclose(fp);\n\t\t}\n\t}\n\n\n\tvoid copyOneBigFile()\n\t{\n\t\t// check for a big file\n\t\tcopyFileSize(1024*1024);\n\t}\n\n\tvoid copyDifferentFileSize()\n\t{\n\t\t// check for a series of size\n\t\tfor (uint i=0; i<10; ++i)\n\t\t{\n\t\t\tcopyFileSize(i);\n\t\t}\n\n\t\tsrand(1234);\n\t\tfor (uint i=0; i<1024; ++i)\n\t\t{\n\t\t\ti += rand()%10;\n\t\t\tcopyFileSize(i);\n\t\t}\n\t}\n\n\tvoid moveFileSize(size_t fileSize)\n\t{\n\t\t// remove the destination if any\n\t\tFILE *fp = fopen(_DstFile.c_str(), \"rb\");\n\t\tif (fp != NULL)\n\t\t{\n\t\t\tfclose(fp);\n\t\t\tNLMISC::CFile::deleteFile(_DstFile);\n\t\t}\n\n\t\t// create a source file (using standard c code)\n\t\tfp = fopen(_SrcFile.c_str(), \"wb\");\n\t\tnlverify(fp != NULL);\n\n\t\tfor (uint i=0; i<fileSize; ++i)\n\t\t{\n\t\t\tuint8 c = uint8(i & 0xff);\n\t\t\tnlverify(fwrite(&c, 1, 1, fp) == 1);\n\t\t}\n\t\tfclose(fp);\n\t\tfp = NULL;\n\n\t\tNLMISC::CFile::moveFile(_DstFile.c_str(), _SrcFile.c_str());\n\n\t\t// verify the resulting file\n\t\tfp = fopen(_SrcFile.c_str(), \"rb\");\n\t\tTEST_ASSERT_MSG(fp == NULL, \"The source file is not removed\");\n\t\tif (fp)\n\t\t\tfclose(fp);\n\n\t\tfp = fopen(_DstFile.c_str(), \"rb\");\n\t\tTEST_ASSERT(fp != NULL);\n\t\tif (fp)\n\t\t{\n\t\t\tfor (uint i=0; i<fileSize; ++i)\n\t\t\t{\n\t\t\t\tuint8 c;\n\t\t\t\tsize_t nbRead = fread(&c, 1,1, fp);\n\t\t\t\tTEST_ASSERT(nbRead == 1);\n\t\t\t\tif (nbRead != 1)\n\t\t\t\t\tbreak;\n\t\t\t\tTEST_ASSERT_MSG(c == uint8(i & 0xff), \"File content changed during move\");\n\t\t\t\tif (c != uint8(i & 0xff))\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tfclose(fp);\n\t\t}\n\t}\n\n\tvoid moveOneBigFile()\n\t{\n\t\t// check for a big file\n\t\tmoveFileSize(1024*1024);\n\t}\n\n\tvoid moveDifferentFileSize()\n\t{\n\t\t// check for a series of size\n\t\tfor (uint i=0; i<10; ++i)\n\t\t{\n\t\t\tmoveFileSize(i);\n\t\t}\n\n\t\tsrand(1234);\n\t\tfor (uint i=0; i<1024; ++i)\n\t\t{\n\t\t\ti += rand()%10;\n\t\t\tmoveFileSize(i);\n\t\t}\n\t}\n\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_bad_test.cfg",
    "content": "\n// insert a var just to prove we can't read it\nASimpleVar = \"hello\";\n\n// A bad preprocessor command\n# UnknowCommand\n\n// a closing endif without matching ifdef\n#endif\n\t\n// a series of invalid command\n#include blop\t// missing quote\n#include \"blop\t// missing closing quote\n#optional blop\n#optional \"blop\n#define *1234\t// invalid label\n#ifdef *1234\t\t// still invalid label\n\t\n\n// a opening ifdef not closed\n#ifdef FOO\n\n// NB : do not close the #ifdef"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_define.cfg",
    "content": "\n#define FOO\n# define BAR\n\t\n#ifdef FOOBAR\n\tthis is an invalid content that should be ignored by parser\n#endif\n\n #   ifdef     FOOBAR\n\tthis is another invalid content that should be \n\tignored by parser with some free alignement\n\t \nCfgNotToBeFound=\"iCan'tBeThere\";\n      # endif\n\n#ifdef FOO\n\t// A simple var in a valid bloc\nCfgReadableVar=\"You can see me\";\n#endif\n\n// Multi test imbrication\n#ifdef FOO\t// ok\n# ifdef FOOBAR  // not ok\n#  ifdef BAR\t// ok, but in a not ok scope\nCfgInvisible = \"You can't see me !\";\n#  endif\n# endif\n#endif\n\t\n#ifndef FOOBAR\n\t// this one must exist\n\tCfgMustExist=\"hello world\";\n#endif\n\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error.cfg",
    "content": "// In this cfg, we introduce an error in a line after define and if clause\n\n\n#define FOO\n\t\n#define BAR\n\t\n#ifdef FOO\n\t// nothing\n#endif\n\t\n#ifndef BAR\n\t// nothing\n#endif\n\t\n\n// Here is the offending line, at line 18\nABadVar iable = \"foo\";\n\n// Some additionnal garbase lines\n\nAGoodVar = \"bar\";\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_error_main.cfg",
    "content": "// This config file include the config file with error then generate an error\n// WARNING : is you add lines, update the code in the test\n\n\n#include \"cfg_with_error.cfg\"\n\n#define FOO\n#define BAR\n\t\n#ifdef FOO\n\t// nothing\n#endif\n\t\n#ifndef BAR\n\t// nothing\n#endif\n\t\n\n// Some additionnal garbase lines\n\nAGoodVar = \"bar\";\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_include.cfg",
    "content": "\n\n#include \"included_cfg.cfg\"\n\n// #include \"not_found_file.cfg\" this include should not work\n//#include \"not_found_file.cfg\" this include should not work\n// not a valid include #include \"not_found_file.cfg\n\n\nCfgWithInclude = \"ok\";\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_include_and_optional.cfg",
    "content": "// include of a missing file, should generate a warning\n#include \"a_missing_file.cfg\"\n\n// optional include a a missing file, just issue an info log\t\n#optional \"a_missing_file.cfg\"\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/cfg_with_optional.cfg",
    "content": "\n\n#optional \"included_cfg.cfg\"\n\n// #include \"not_found_file.cfg\" this include should not work\n//#include \"not_found_file.cfg\" this include should not work\n// not a valid include #include \"not_found_file.cfg\n\n\nCfgWithInclude = \"ok\";\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/file1_in_bnp.txt",
    "content": "The content of the first file"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/file2_in_bnp.txt",
    "content": "Another content but for the second file"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_bnp.txt\">\nThe content of the first file\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_bnp.txt\">\nAnother content but for the second file\n\t</nel:xml_file>\n\t<nel:xml_file name=\"files.bnp\">\nThe content of the first fileAnother content but for the second file\u0002\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/.xml_pack_index",
    "content": "file1_in_sub_1.xml\nfile2_in_sub_1.xml\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/file1_in_sub_1.xml",
    "content": "<myxml><withSomethink name=\"foo\"/></myxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/file2_in_sub_1.xml",
    "content": "<anotherxml><withSomethink name=\"bar\"/></anotherxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_1/samename/samename.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_sub_1.xml\">\n<myxml><withSomethink name=\"foo\"/></myxml>\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_sub_1.xml\">\n<anotherxml><withSomethink name=\"bar\"/></anotherxml>\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/.xml_pack_index",
    "content": "file1_in_sub_2.xml\nfile2_in_sub_2.xml\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/file1_in_sub_2.xml",
    "content": "<myxml><withSomethink name=\"foo\"/></myxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/file2_in_sub_2.xml",
    "content": "<anotherxml><withSomethink name=\"bar\"/></anotherxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/files_for_xml_subpack/same_subfolder_2/samename/samename.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_sub_2.xml\">\n<myxml><withSomethink name=\"foo\"/></myxml>\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_sub_2.xml\">\n<anotherxml><withSomethink name=\"bar\"/></anotherxml>\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/included_cfg.cfg",
    "content": "\nIncludedCfg = \"ok\";\n\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/xml_files/file1_in_xml_pack.xml",
    "content": "<myxml><withSomethink name=\"foo\"/></myxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/xml_files/file2_in_xml_pack.xml",
    "content": "<anotherxml><withSomethink name=\"bar\"/></anotherxml>"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_sub_1.xml\">\n<myxml><withSomethink name=\"foo\"/></myxml>\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_sub_1.xml\">\n<anotherxml><withSomethink name=\"bar\"/></anotherxml>\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_sub_2.xml\">\n<myxml><withSomethink name=\"foo\"/></myxml>\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_sub_2.xml\">\n<anotherxml><withSomethink name=\"bar\"/></anotherxml>\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_files/xml_files/xml_files.xml_pack",
    "content": "<nel:packed_xml>\n\t<nel:xml_file name=\"file1_in_xml_pack.xml\">\n<myxml><withSomethink name=\"foo\"/></myxml>\n\t</nel:xml_file>\n\t<nel:xml_file name=\"file2_in_xml_pack.xml\">\n<anotherxml><withSomethink name=\"bar\"/></anotherxml>\n\t</nel:xml_file>\n</nel:packed_xml>\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_pack_file.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_PACK_FILE\n#define UT_MISC_PACK_FILE\n\n\n// Commenting out the ifdef since the files are authored on Windows\n// and therefore always have a Windows-style newline.\n//#ifdef NL_OS_WINDOWS\nconst string NewLine(\"\\r\\n\");\n//#elif defined(NL_OS_UNIX)\n//const string NewLine(\"\\n\");\n//#else\n//#error \"Specify the new line format for text file\";\n//#endif\n\n#ifndef NEL_UNIT_BASE\n#define NEL_UNIT_BASE \"\"\n#endif // NEL_UNIT_BASE\n\n// Test suite for bnp and xml pack files\nclass CUTMiscPackFile : public Test::Suite\n{\n\tstring\t\t_WorkingPath;\n\tstring\t\t_OldPath;\npublic:\n\tCUTMiscPackFile ()\n\t{\n\t\tTEST_ADD(CUTMiscPackFile::addBnp);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromBnp);\n\t\tTEST_ADD(CUTMiscPackFile::addXmlpack);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromXmlpack);\n\t\tTEST_ADD(CUTMiscPackFile::compressMemory);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromBnpCompressed);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromXmlpackCompressed);\n\t\tTEST_ADD(CUTMiscPackFile::decompressMemory);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromBnpUncompressed);\n\t\tTEST_ADD(CUTMiscPackFile::loadFromXmlpackUncompressed);\n\t\tTEST_ADD(CUTMiscPackFile::loadXmlpackWithSameName);\n\t}\n\n\tvoid setup()\n\t{\n\t\t_OldPath = NLMISC::CPath::getCurrentPath();\n\t\tNLMISC::CPath::setCurrentPath(_WorkingPath.c_str());\n\t\tstring pathAfter = NLMISC::CPath::getCurrentPath();\n\t}\n\n\tvoid tear_down()\n\t{\n\t\tNLMISC::CPath::setCurrentPath(_OldPath.c_str());\n\t}\n\n\tvoid addBnp()\n\t{\n\t\t// add bnp file in the path and access to file inside\n\t\tNLMISC::CPath::addSearchBigFile(NEL_UNIT_BASE \"ut_misc_files/files.bnp\", false, false);\n\t}\n\n\tvoid loadFromBnp()\n\t{\n\t\t// lookup for the file\n\t\tstring filename = NLMISC::CPath::lookup(\"file1_in_bnp.txt\", true, true, false);\n\t\tTEST_ASSERT(filename == \"files.bnp@file1_in_bnp.txt\");\n\n\t\t// read the first file content\n\t\t{\n\t\t\tNLMISC::CIFile file1(filename);\n\t\t\tstring content1;\n\t\t\tcontent1.resize(file1.getFileSize());\n\t\t\tfile1.serialBuffer((uint8*)content1.data(), file1.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tTEST_ASSERT(content1 == \"The content of the first file\");\n\t\t}\n\n\t\t// lookup for the 2nd file\n\t\tfilename = NLMISC::CPath::lookup(\"file2_in_bnp.txt\", true, true, false);\n\t\tTEST_ASSERT(filename == \"files.bnp@file2_in_bnp.txt\");\n\n\t\t{\n\t\t\t// read the second file content\n\t\t\tNLMISC::CIFile file2(filename);\n\t\t\tstring content2;\n\t\t\tcontent2.resize(file2.getFileSize());\n\t\t\tfile2.serialBuffer((uint8*)content2.data(), file2.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tTEST_ASSERT(content2 == \"Another content but for the second file\");\n\t\t}\n\t}\n\n\tvoid addXmlpack()\n\t{\n\t\t// add xml_pack file in the path and access to file inside\n\t\tNLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE \"ut_misc_files/xml_files/xml_files.xml_pack\", false, false);\n\t}\n\n\tvoid loadFromXmlpack()\n\t{\n\t\t// lookup for the file\n\t\tstring filename = NLMISC::CPath::lookup(\"file1_in_xml_pack.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/xml_files.xml_pack@@file1_in_xml_pack.xml\");\n\n\t\t// read the first file content\n\t\t{\n\t\t\tNLMISC::CIFile file1(filename);\n\t\t\tstring content1;\n\t\t\tcontent1.resize(file1.getFileSize());\n\t\t\tfile1.serialBuffer((uint8*)content1.data(), file1.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tstring refText = \"<myxml><withSomethink name=\\\"foo\\\"/></myxml>\"+NewLine;\n\t\t\tTEST_ASSERT(content1 == refText);\n\t\t}\n\n\t\t// lookup for the 2nd file\n\t\tfilename = NLMISC::CPath::lookup(\"file2_in_xml_pack.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/xml_files.xml_pack@@file2_in_xml_pack.xml\");\n\n\t\t{\n\t\t\t// read the second file content\n\t\t\tNLMISC::CIFile file2(filename);\n\t\t\tstring content2;\n\t\t\tcontent2.resize(file2.getFileSize());\n\t\t\tfile2.serialBuffer((uint8*)content2.data(), file2.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tstring refText=\"<anotherxml><withSomethink name=\\\"bar\\\"/></anotherxml>\"+NewLine;\n\t\t\tTEST_ASSERT(content2 == refText);\n\t\t}\n\t}\n\n\tvoid compressMemory()\n\t{\n//#ifdef WIN32\n//_CrtCheckMemory();\n//#endif\n\t\tNLMISC::CPath::memoryCompress();\n//#ifdef WIN32\n//_CrtCheckMemory();\n//#endif\n\t}\n\n\tvoid loadFromBnpCompressed()\n\t{\n\t\t// simply recall loadFromBnp\n\t\tloadFromBnp();\n\t}\n\n\tvoid loadFromXmlpackCompressed()\n\t{\n\t\t// simply recall loadFromXmlpack\n\t\tloadFromXmlpack();\n\t}\n\n\tvoid decompressMemory()\n\t{\n\t\tNLMISC::CPath::memoryUncompress();\n\t}\n\n\tvoid loadFromBnpUncompressed()\n\t{\n\t\t// simply recall loadFromBnp\n\t\tloadFromBnp();\n\t}\n\n\tvoid loadFromXmlpackUncompressed()\n\t{\n\t\t// simply recall loadFromXmlpack\n\t\tloadFromXmlpack();\n\t}\n\n\tvoid loadXmlpackWithSameName()\n\t{\n\t\t// we support xml_pack file in subfolder that have the same name\n\t\t// but the 'addSearchPath' or add xml pack must be done\n\t\t// at a higher discriminant directory\n\n//\t\tNLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack\", true, false, NULL);\n//\t\tNLMISC::CPath::addSearchXmlpackFile(NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack\", true, false, NULL);\n\t\tNLMISC::CPath::addSearchPath(NEL_UNIT_BASE \"ut_misc_files/xml_files\", true, false);\n\n\t\t// lookup for the files in first subdirectory\n\t\tstring filename = NLMISC::CPath::lookup(\"file1_in_sub_1.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack@@file1_in_sub_1.xml\");\n\t\tfilename = NLMISC::CPath::lookup(\"file2_in_sub_1.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_1/samename/samename.xml_pack@@file2_in_sub_1.xml\");\n\n\t\t// lookup for the files in the second subdirectory\n\t\tfilename = NLMISC::CPath::lookup(\"file1_in_sub_2.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack@@file1_in_sub_2.xml\");\n\t\tfilename = NLMISC::CPath::lookup(\"file2_in_sub_2.xml\", true, true, false);\n\t\tTEST_ASSERT(filename == NEL_UNIT_BASE \"ut_misc_files/xml_files/same_subfolder_2/samename/samename.xml_pack@@file2_in_sub_2.xml\");\n\n\t\t// read the file content of the first file in first pack\n\t\tfilename = NLMISC::CPath::lookup(\"file1_in_sub_1.xml\", true, true, false);\n\n\t\t// check that we can read the file modif date\n\t\tuint32 d = NLMISC::CFile::getFileModificationDate(filename);\n\t\tTEST_ASSERT(d != 0);\n\t\t{\n\t\t\tNLMISC::CIFile file1(filename);\n\t\t\tstring content1;\n\t\t\tcontent1.resize(file1.getFileSize());\n\t\t\tfile1.serialBuffer((uint8*)content1.data(), file1.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tstring refText = \"<myxml><withSomethink name=\\\"foo\\\"/></myxml>\"+NewLine;\n\t\t\tTEST_ASSERT(content1 == refText);\n\t\t}\n\n\t\t// read the file content of the second file in the second pack\n\t\tfilename = NLMISC::CPath::lookup(\"file2_in_sub_2.xml\", true, true, false);\n\t\t{\n\t\t\t// read the second file content\n\t\t\tNLMISC::CIFile file2(filename);\n\t\t\tstring content2;\n\t\t\tcontent2.resize(file2.getFileSize());\n\t\t\tfile2.serialBuffer((uint8*)content2.data(), file2.getFileSize());\n\t\t\t\n\t\t\t// check the file content\n\t\t\tstring refText=\"<anotherxml><withSomethink name=\\\"bar\\\"/></anotherxml>\"+NewLine;\n\t\t\tTEST_ASSERT(content2 == refText);\n\t\t}\n\n\t}\n\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_singleton.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_SINGLETON\n#define UT_MISC_SINGLETON\n\n#include <nel/misc/command.h>\n\nclass CSafeSingleton\n{\n\tNL_INSTANCE_COUNTER_DECL(CSafeSingleton);\n\tNLMISC_SAFE_SINGLETON_DECL(CSafeSingleton);\n\tCSafeSingleton() {}\n};\n\nNL_INSTANCE_COUNTER_IMPL(CSafeSingleton);\nNLMISC_SAFE_SINGLETON_IMPL(CSafeSingleton);\n\n\nclass CUnsafeSingleton\n{\n\tNL_INSTANCE_COUNTER_DECL(CUnsafeSingleton);\n\n\tstatic CUnsafeSingleton\t*_Instance;\n\n\tCUnsafeSingleton() {}\n\tCUnsafeSingleton(const CUnsafeSingleton &other) {}\n\npublic:\n\n\tstatic CUnsafeSingleton &getInstance()\n\t{\n\t\tif (_Instance == NULL)\n\t\t\t_Instance = new CUnsafeSingleton;\n\t\treturn *_Instance;\n\t}\n};\n\nNL_INSTANCE_COUNTER_IMPL(CUnsafeSingleton);\nCUnsafeSingleton\t*CUnsafeSingleton::_Instance = NULL;\n\n\n// Test suite for Singleton behavior\nclass CUTMiscSingleton : public Test::Suite\n{\n\tstd::string WorkingPath;\n\tstd::string OldPath;\npublic:\n\tCUTMiscSingleton()\n\t{\n\t\tTEST_ADD(CUTMiscSingleton::createSingleton);\n\t\tTEST_ADD(CUTMiscSingleton::accessSingleton);\n\t\t//TEST_ADD(CUTMiscSingleton::multiDllSingleton);\n\t}\n\n\tvoid setup()\n\t{\n\t\tOldPath = NLMISC::CPath::getCurrentPath();\n\n\t\tNLMISC::CPath::setCurrentPath(WorkingPath.c_str());\n\t}\n\n\tvoid tear_down()\n\t{\n\t\tNLMISC::CPath::setCurrentPath(OldPath.c_str());\n\t}\n\t\n\tvoid createSingleton()\n\t{\n\t\tTEST_ASSERT(NLMISC::CInstanceCounterManager::getInstance().getInstanceCounter(\"CSafeSingleton\") == 0);\n\t\tCSafeSingleton &ss = CSafeSingleton::getInstance();\n\t\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1);\n\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 0);\n\t\tCUnsafeSingleton &us = CUnsafeSingleton::getInstance();\n\t\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1);\n\t}\n\n\tvoid accessSingleton()\n\t{\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1);\n\t\tCSafeSingleton &ss = CSafeSingleton::getInstance();\n\t\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CSafeSingleton) == 1);\n\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1);\n\t\tCUnsafeSingleton &us = CUnsafeSingleton::getInstance();\n\t\n\t\tTEST_ASSERT(NL_GET_INSTANCE_COUNTER(CUnsafeSingleton) == 1);\n\t}\n\n\t/*void multiDllSingleton()\n\t{\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().exists(\"aDynLibCommand\") == false);\n\n\t\tCLibrary lib;\n\t\tif (lib.loadLibrary(\"dyn_lib_test\", true, true, true) != true)\n\t\t{\n\t\t\tTEST_ASSERT_MSG(false, \"failed to reload the dll for testing singletons across dlls\");\n\t\t\treturn;\n\t\t}\n\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().isCommand(\"aDynLibCommand\") == true);\n\n\t\tIDynLibTest *libTest = dynamic_cast<IDynLibTest*>(lib.getNelLibraryInterface());\n\t\tTEST_ASSERT(libTest != NULL);\n\n\t\tlibTest->testSingleton(this);\n\t}*/\n\n\tvoid assertmentWrapper(Test::Source src)\n\t{\n\t\tassertment(src);\n\t}\n\n\tbool continue_after_failureWrapper()\n\t{\n\t\treturn continue_after_failure();\n\t}\n\n\tfriend class CDynLibTest;\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_sstring.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_SSTRING\n#define UT_MISC_SSTRING\n\n#include <nel/misc/sstring.h>\n\nstruct CUTMiscSString : public Test::Suite\n{\n\tCUTMiscSString()\n\t{\n\t\tTEST_ADD(CUTMiscSString::testStrtok);\n\t\t// Add a line here when adding a new test METHOD\n\t}\n\n\tvoid testStrtok()\n\t{\n\t\tNLMISC::CSString testLine(\"  a=b  c   (a=e b=c) \\t\\t  c(a=e b=c) toto(bimbo(foo(bar(a=b))))\");\n\n\t\tNLMISC::CSString part;\n\t\tpart = testLine.strtok(\" \\t\", true, false);\n\t\tTEST_ASSERT(part == \"a=b\");\n\t\tpart = testLine.strtok(\" \\t\", true, false);\n\t\tTEST_ASSERT(part == \"c\");\n\t\tpart = testLine.strtok(\" \\t\", true, false);\n\t\tTEST_ASSERT(part == \"(a=e b=c)\");\n\t\tpart = testLine.strtok(\" \\t\", true, false);\n\t\tTEST_ASSERT(part == \"c\");\n\t\tpart = testLine.strtok(\" \\t=\", true, false);\n\t\tTEST_ASSERT(part == \"(a=e b=c)\");\n\t\tpart = testLine.strtok(\" \\t=\", true, false);\n\t\tTEST_ASSERT(part == \"toto\");\n\t\tpart = testLine.strtok(\" \\t=\", true, false);\n\t\tTEST_ASSERT(part == \"(bimbo(foo(bar(a=b))))\");\n\t\tpart = part.stripBlockDelimiters();\n\t\tNLMISC::CSString part2 = part.strtok(\" \\t=\", true, false);\n\t\tTEST_ASSERT(part2 == \"bimbo\");\n\t\tpart2 = part.strtok(\" \\t=\", true, false);\n\t\tTEST_ASSERT(part2 == \"(foo(bar(a=b)))\");\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_stream.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_STREAM\n#define UT_MISC_STREAM\n\n#include <nel/misc/stream.h>\n#include <nel/misc/bit_mem_stream.h>\n\n// The following line is known to crash in a Ryzom service\nNLMISC::CBitMemStream globalBms( false, 2048 ); // global to avoid reallocation\n\n// Test suite for stream based classes\n// ! not complete at all at time of writing !\nclass CUTMiscStream: public Test::Suite\n{\npublic:\n\tCUTMiscStream ()\n\t{\n\t\tTEST_ADD(CUTMiscStream::constAndStream);\n\t\tTEST_ADD(CUTMiscStream::memStreamSwap);\n\t\tTEST_ADD(CUTMiscStream::copyOnWrite);\n\t\tTEST_ADD(CUTMiscStream::preallocatedBitStream);\n\t}\n\n\tvoid preallocatedBitStream()\n\t{\n\t\tNLMISC::CBitMemStream localBms( false, 2048 ); // global to avoid reallocation\n\t}\n\n\n\tvoid copyOnWrite()\n\t{\n\t\t// test the copy on write strategy in the mem stream (and derived) class.\n\t\t// The point is to be able to copy a mem stream (e.g a NLNET::CMessage) \n\t\t// but to do not copy the stream buffer.\n\t\t// If more than one stream use the same buffer, any attempt to \n\t\t// modifye the buffer content while lead to a buffer duplication\n\n\t\tNLMISC::CMemStream s1;\n\t\tNLMISC::CMemStream s2;\n\t\tNLMISC::CMemStream s3;\n\n\n\t\tuint32 i = 1;\n\t\ts1.serial(i);\n\n\t\ts2 = s1;\n\t\ts3 = s2;\n\n\t\tTEST_ASSERT(s1.buffer() == s2.buffer());\n\t\tTEST_ASSERT(s1.buffer() == s3.buffer());\n\n\t\t// change s1\n\t\ts1.serial(i);\n\t\tTEST_ASSERT(s1.buffer() != s2.buffer());\n\t\tTEST_ASSERT(s2.buffer() == s3.buffer());\n\n\t\ts2.invert();\n\t\ts3 = s2;\n\n\t\tTEST_ASSERT(s2.buffer() == s3.buffer());\n\n\t\ts2.serial(i);\n\n\t\tTEST_ASSERT(s2.buffer() == s3.buffer());\n\n\n\t}\n\n\tenum TEnum\n\t{\n\t\te_a,\n\t\te_b,\n\t\te_c,\n\t\te_d\n\t};\n\n\tvoid constAndStream()\n\t{\n\t\t// check that we can serialize with const stream or const object\n\n\n\t\tNLMISC::CMemStream s1;\n\t\tNLMISC::IStream &is1 = s1;\n\n\t\tconst string str(\"toto\");\n\t\tconst uint32 i(1234546);\n\t\tconst TEnum\te(e_a);\n\t\tstring str2(\"titi\");\n\t\tuint32 i2(123456);\n\t\tTEnum\te2(e_b);\n\n\t\t// no need for const cast any more\n\t\tnlWriteSerial(s1, str);\n\t\tnlWriteSerial(s1, i);\n\t\tnlWrite(s1, serialEnum, e);\n\t\tnlWriteSerial(is1, str);\n\t\tnlWriteSerial(is1, i);\n\t\tnlWrite(is1, serialEnum, i);\n\t\t// this work as well\n\t\ts1.serial(str2);\n\t\ts1.serial(i2);\n\t\ts1.serialEnum(e2);\n\n\t\tis1.serial(str2);\n\t\tis1.serial(i2);\n\t\tis1.serialEnum(e2);\n\n\t\tconst NLMISC::CMemStream &s2 = s1;\n\t\tconst NLMISC::IStream &is2 = s2;\n\n\t\tstring str3;\n\t\tuint32 i3;\n\t\tTEnum e3(e_c);\n\t\t// cant write in a const stream\n\t\tTEST_THROWS(nlReadSerial(s2, str3), NLMISC::ENotInputStream);\n\t\tTEST_THROWS(nlReadSerial(s2, i3), NLMISC::ENotInputStream);\n\t\tTEST_THROWS(nlRead(s2, serialEnum, e3), NLMISC::ENotInputStream);\n\t\tTEST_THROWS(nlReadSerial(is2, str3), NLMISC::ENotInputStream);\n\t\tTEST_THROWS(nlReadSerial(is2, i3), NLMISC::ENotInputStream);\n\t\tTEST_THROWS(nlRead(is2, serialEnum, e3), NLMISC::ENotInputStream);\n\n\n\t\ts1.invert();\n\n\t\tnlReadSerial(s2, str3);\n\t\tnlReadSerial(s2, i3);\n\t\tnlRead(s2, serialEnum, e3);\n\t\tnlReadSerial(is2, str3);\n\t\tnlReadSerial(is2, i3);\n\t\tnlRead(is2, serialEnum, e3);\n\n\n\t\t// cant read a const value\n\t\tTEST_THROWS(nlWriteSerial(s1, str), NLMISC::ENotOutputStream);\n\t\tTEST_THROWS(nlWriteSerial(s1, i), NLMISC::ENotOutputStream);\n\t\tTEST_THROWS(nlWrite(s1, serialEnum, e), NLMISC::ENotOutputStream);\n\t\tTEST_THROWS(nlWriteSerial(is1, str), NLMISC::ENotOutputStream);\n\t\tTEST_THROWS(nlWriteSerial(is1, i), NLMISC::ENotOutputStream);\n\t\tTEST_THROWS(nlWrite(is1, serialEnum, e), NLMISC::ENotOutputStream);\n\n\t}\n\t\n\tvoid memStreamSwap()\n\t{\n\t\tNLMISC::CMemStream ms2;\n\t\t\t\n\t\tstring s;\n\t\t{\n\t\t\tNLMISC::CMemStream ms1;\n\n\t\t\ts = \"foo1\";\n\t\t\tms1.serial(s);\n\t\t\ts = \"foo2\";\n\t\t\tms1.serial(s);\n\t\t\ts = \"\";\n\n\t\t\tms2.swap(ms1);\n\n\t\t\t// check that ms1 is empty now\n\t\t\tTEST_ASSERT(ms1.length() == 0);\n\t\t}\n\n\t\tTEST_ASSERT(!ms2.isReading());\n\t\tms2.invert();\n\t\tms2.serial(s);\n\t\tTEST_ASSERT(s == \"foo1\");\n\t\tms2.serial(s);\n\t\tTEST_ASSERT(s == \"foo2\");\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_string_common.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_STRING_COMMON\n#define UT_MISC_STRING_COMMON\n\n#include <nel/misc/string_common.h>\n\nstruct CUTMiscStringCommon : public Test::Suite\n{\n\tCUTMiscStringCommon()\n\t{\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringSint8);\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringUint8);\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringSint16);\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringUint16);\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringSint32);\n\t\tTEST_ADD(CUTMiscStringCommon::fromStringUint32);\n\t\t// Add a line here when adding a new test METHOD\n\t}\n\n\tvoid fromStringSint8()\n\t{\n\t\tbool ret;\n\n\t\t// tests for sint8\n\t\tsint8 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// negative value\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(ret && val == -1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"-128\", val);\n\t\tTEST_ASSERT(ret && val == -128);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"127\", val);\n\t\tTEST_ASSERT(ret && val == 127);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-129\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"128\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n\n\tvoid fromStringUint8()\n\t{\n\t\tbool ret;\n\n\t\t// tests for uint8\n\t\tuint8 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"0\", val);\n\t\tTEST_ASSERT(ret && val == 0);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"255\", val);\n\t\tTEST_ASSERT(ret && val == 255);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"256\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n\n\tvoid fromStringSint16()\n\t{\n\t\tbool ret;\n\n\t\t// tests for sint16\n\t\tsint16 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// negative value\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(ret && val == -1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"-32768\", val);\n\t\tTEST_ASSERT(ret && val == -32768);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"32767\", val);\n\t\tTEST_ASSERT(ret && val == 32767);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-32769\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"32768\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n\n\tvoid fromStringUint16()\n\t{\n\t\tbool ret;\n\n\t\t// tests for uint16\n\t\tuint16 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"0\", val);\n\t\tTEST_ASSERT(ret && val == 0);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"65535\", val);\n\t\tTEST_ASSERT(ret && val == 65535);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"65536\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n\n\tvoid fromStringSint32()\n\t{\n\t\tbool ret;\n\n\t\t// tests for sint32\n\t\tsint32 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// negative value\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(ret && val == -1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"-2147483648\", val);\n\t\tTEST_ASSERT(ret && val == INT_MIN);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"2147483647\", val);\n\t\tTEST_ASSERT(ret && val == INT_MAX);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-2147483649\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"2147483648\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n\n\tvoid fromStringUint32()\n\t{\n\t\tbool ret;\n\n\t\t// tests for uint32\n\t\tuint32 val;\n\n\t\t// positive value\n\t\tret = NLMISC::fromString(\"1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// bad character\n\t\tret = NLMISC::fromString(\"a\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// right character and bad character\n\t\tret = NLMISC::fromString(\"1a\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// min limit\n\t\tret = NLMISC::fromString(\"0\", val);\n\t\tTEST_ASSERT(ret && val == 0);\n\n\t\t// max limit\n\t\tret = NLMISC::fromString(\"4294967295\", val);\n\t\tTEST_ASSERT(ret && val == 4294967295);\n\n\t\t// min limit -1\n\t\tret = NLMISC::fromString(\"-1\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// max limit +1\n\t\tret = NLMISC::fromString(\"4294967296\", val);\n\t\tTEST_ASSERT(!ret && val == 0);\n\n\t\t// with period\n\t\tret = NLMISC::fromString(\"1.2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with coma\n\t\tret = NLMISC::fromString(\"1,2\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with spaces before\n\t\tret = NLMISC::fromString(\"  10\", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with spaces after\n\t\tret = NLMISC::fromString(\"10  \", val);\n\t\tTEST_ASSERT(ret && val == 10);\n\n\t\t// with 0s before\n\t\tret = NLMISC::fromString(\"001\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\n\t\t// with + before\n\t\tret = NLMISC::fromString(\"+1\", val);\n\t\tTEST_ASSERT(ret && val == 1);\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_types.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_TYPES\n#define UT_MISC_TYPES\n\n#include <nel/misc/variable.h>\n\nclass CUTMiscTypes: public Test::Suite\n{\npublic:\n\tCUTMiscTypes ()\n\t{\n\t\tTEST_ADD(CUTMiscTypes::basicTypes)\n\t}\n\n\tvoid basicTypes()\n\t{\n\t\t// this doesn't work on 64bit architectures\n\t\t//Test_ASSERT(sizeof(uint) == sizeof(void*));\n\n\t\tTEST_ASSERT(sizeof(sint8) == 1);\n\t\tTEST_ASSERT(sizeof(uint8) == 1);\n\t\tTEST_ASSERT(sizeof(sint16) == 2);\n\t\tTEST_ASSERT(sizeof(uint16) == 2);\n\t\tTEST_ASSERT(sizeof(sint32) == 4);\n\t\tTEST_ASSERT(sizeof(uint32) == 4);\n\t\tTEST_ASSERT(sizeof(sint64) == 8);\n\t\tTEST_ASSERT(sizeof(uint64) == 8);\n\n\t\tTEST_ASSERT(sizeof(sint) >= 4);\n\t\tTEST_ASSERT(sizeof(uint) >= 4);\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_misc_variable.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_MISC_VARIABLE\n#define UT_MISC_VARIABLE\n\n#include <nel/misc/variable.h>\n\nclass CUTMiscVariable : public Test::Suite\n{\npublic:\n\tCUTMiscVariable ()\n\t{\n\t\tTEST_ADD(CUTMiscVariable ::declareVar)\n\t}\n\n\tvoid declareVar()\n\t{\n\t\t{\n\t\t\tNLMISC::CVariable<std::string> myLocalVar(\"test\", \"myLocalVar\", \"no help\", \"\");\n\n\t\t\tTEST_ASSERT(myLocalVar.get() == string(\"\"));\n\t\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(\"myLocalVar foo\", (*NLMISC::InfoLog)));\n\t\t\tTEST_ASSERT(myLocalVar.get() == string(\"foo\"));\n\t\t}\n\n\t\tTEST_ASSERT(!NLMISC::CCommandRegistry::getInstance().execute(\"myLocalVar foo\", (*NLMISC::InfoLog)));\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_net.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_NET\n#define UT_NET\n\n#include <nel/net/message.h>\n\n#include \"ut_net_layer3.h\"\n#include \"ut_net_message.h\"\n#include \"ut_net_module.h\"\n// Add a line here when adding a new test CLASS\n\nstruct CUTNet : public Test::Suite\n{\n\tCUTNet()\n\t{\n\t\tadd(auto_ptr<Test::Suite>(new CUTNetLayer3));\n\t\tadd(auto_ptr<Test::Suite>(new CUTNetMessage));\n\t\tadd(auto_ptr<Test::Suite>(new CUTNetModule));\n\t\t// Add a line here when adding a new test CLASS\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_net_layer3.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_NET_LAYER3\n#define UT_NET_LAYER3\n\n#include <nel/net/callback_client.h>\n#include <nel/net/callback_server.h>\n\nuint16 TestPort1 = 56000;\n\nuint NbTestReceived = 0;\n\nNLNET::CMessage msgoutExpectingAnswer0, msgoutSimple0, msgoutSimple50;\n\n// Data structure for messages\nstruct TData\n{\n\tstring PayloadString;\n\tbool ExpectingAnswer;\n\n\t// Constructor\n\tTData() : ExpectingAnswer(false) {}\n\n\t// Serial\n\tvoid serial( NLMISC::IStream& s )\n\t{\n\t\ts.serial( PayloadString );\n\t\ts.serial( ExpectingAnswer );\n\t}\n};\n\n// This callback must not take more than 10 ms\nvoid cbTest( NLNET::CMessage &msgin, NLNET::TSockId from, NLNET::CCallbackNetBase &netbase )\n{\n\tNLMISC::TTime before = NLMISC::CTime::getLocalTime();\n\n\t// Read data from the message\n\tTData data;\n\tmsgin.serial( data );\n\tif ( data.PayloadString == \"Payload\" )\n\t\t++NbTestReceived;\n\n\t// Send the answer if required\n\tif ( data.ExpectingAnswer )\n\t\tnetbase.send( msgoutSimple0, from );\n\n\t// Check that the duration is compatible with our timeout tests\n\tNLMISC::TTime maxDuration;\n\tif ( msgin.getName() == \"TEST_50\" )\n\t{\n\t\twhile ( NLMISC::CTime::getLocalTime() - before < 49 ); // wait\n\t\tmaxDuration = 70;\n\t}\n\telse\n\t\tmaxDuration = 10;\n\tNLMISC::TTime actualDuration = NLMISC::CTime::getLocalTime() - before;\n\tif ( actualDuration > maxDuration )\n\t\tnlerror( \"The callback cbTest takes too long (%u) for %s, please fix the test\", (uint)actualDuration, msgin.getName().c_str() );\n}\n\n\nstatic NLNET::TCallbackItem CallbackArray[] =\n{\n\t{ \"TEST_0\", cbTest },\n\t{ \"TEST_50\", cbTest }\n};\n\n\n// Test suite for layer 3\nclass CUTNetLayer3: public Test::Suite\n{\npublic:\n\n\t//\n\tCUTNetLayer3 ()\n\t{\n\t\t_Server = NULL;\n\t\t_Client = NULL;\n\t\tTEST_ADD(CUTNetLayer3::sendReceiveUpdate);\n\n\t}\n\n\t//\n\t~CUTNetLayer3 ()\n\t{\n\t\tif ( _Server )\n\t\t\tdelete _Server;\n\t\t_Server = NULL;\n\t\tif ( _Client )\n\t\t\tdelete _Client;\n\t\t_Client = NULL;\n\t}\n\n\t//\n\tvoid sendReceiveUpdate()\n\t{\n\t\t// Prepare messages for tests\n\t\tTData data;\n\t\tdata.PayloadString = \"Payload\";\n\t\tdata.ExpectingAnswer = true;\n\t\tmsgoutExpectingAnswer0.clear(); // optional\n\t\tmsgoutExpectingAnswer0.setType( \"TEST_0\" ); // could be passed to the constructor\n\t\tmsgoutExpectingAnswer0.serial( data );\n\t\tdata.ExpectingAnswer = false;\n\t\tmsgoutSimple0.clear(); // optional\n\t\tmsgoutSimple0.setType( \"TEST_0\" ); // could be passed to the constructor\n\t\tmsgoutSimple0.serial( data );\n\t\tmsgoutSimple50.clear(); // optional\n\t\tmsgoutSimple50.setType( \"TEST_50\" ); // could be passed to the constructor\n\t\tmsgoutSimple50.serial( data );\n\n\t\t// Init connections\n\t\t_Server = new NLNET::CCallbackServer();\n\t\t_Server->init( TestPort1 );\n\t\t_Server->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(NLNET::TCallbackItem) );\n\t\t_Client = new NLNET::CCallbackClient();\n\t\t_Client->connect( NLNET::CInetAddress( \"localhost\", TestPort1 ) );\n\t\t_Client->addCallbackArray( CallbackArray, sizeof(CallbackArray)/sizeof(NLNET::TCallbackItem) );\n\n\t\t// TEST: Simple message transmission\n\t\tNbTestReceived = 0;\n\t\t_Client->send( msgoutExpectingAnswer0 );\n\t\tfor ( uint i=0; i!=10; ++i ) // give some time to receive\n\t\t{\n\t\t\t_Client->update();\n\t\t\t_Server->update(); // legacy version\n\t\t\tNLMISC::nlSleep( 50 );\n\t\t}\n\t\tTEST_ASSERT( NbTestReceived == 2 ); // answer and reply\n\n\t\t// TEST: ONE-SHOT update mode on the receiver\n\t\tNbTestReceived = 0;\n\t\tfor ( uint i=0; i!=20; ++i ) // send 20 messages\n\t\t\t_Client->send( msgoutSimple0 );\n\t\twhile ( NbTestReceived < 20 )\n\t\t{\n\t\t\t_Client->update2();\n\t\t\tuint prevNbTestReceived = NbTestReceived;\n\t\t\t_Server->update2( 0 ); // shortest time-out = ONE-SHOT mode\n\t\t\tTEST_ASSERT( (NbTestReceived == prevNbTestReceived) ||\n\t\t\t\t\t\t (NbTestReceived == prevNbTestReceived + 1) );\n\t\t\tNLMISC::nlSleep( 10 );\n\t\t}\n\t\t\n\t\t// TEST: GREEDY update mode on the receiver\n\t\tNbTestReceived = 0;\n\t\tfor ( uint i=0; i!=20; ++i ) // send 20 messages\n\t\t\t_Client->send( msgoutSimple0 );\n\t\tfor ( uint i=0; i!=10; ++i ) // make sure all messages are flushed\n\t\t{\n\t\t\t_Client->update2();\n\t\t\tNLMISC::nlSleep( 10 );\n\t\t}\n\t\t_Server->update2( -1 ); // receive all\n\t\tTEST_ASSERT( NbTestReceived == 20 );\n\n\t\t// TEST: CONSTRAINED update mode on the receiver\n\t\tNbTestReceived = 0;\n\t\tfor ( uint i=0; i!=20; ++i ) // send 20 messages that will trigger a time-consuming callback\n\t\t\t_Client->send( msgoutSimple50 );\n\t\tfor ( uint i=0; i!=10; ++i ) // make sure all messages are flushed\n\t\t{\n\t\t\t_Client->update2();\n\t\t\tNLMISC::nlSleep( 10 );\n\t\t}\n\t\twhile ( NbTestReceived < 20 )\n\t\t{\n\t\t\tuint prevNbTestReceived = NbTestReceived;\n\t\t\t_Server->update2( 80 ); // no more time than two callback executions\n\t\t\tTEST_ASSERT( NbTestReceived <= prevNbTestReceived + 2 );\n\t\t}\n\n\t\t// TEST: CONSTRAINED with minTime update mode on the receiver\n\t\tNbTestReceived = 0;\n\t\twhile ( NbTestReceived < 20 )\n\t\t{\n\t\t\t_Client->send( msgoutSimple0 );\n\t\t\t_Client->send( msgoutSimple0 ); // send 2 messages at a time\n\t\t\t_Client->update2();\n\t\t\tNLMISC::TTime before = NLMISC::CTime::getLocalTime();\n\t\t\t_Server->update2( -1, 30 );\n\t\t\tNLMISC::TTime duration = NLMISC::CTime::getLocalTime() - before;\n\t\t\tTEST_ASSERT( duration >= 30 );\n\t\t}\n\t}\n\nprivate:\n\tNLNET::CCallbackServer *_Server;\n\tNLNET::CCallbackClient *_Client;\n\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_net_message.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_NET_MESSAGE\n#define UT_NET_MESSAGE\n\nclass CUTNetMessage: public Test::Suite\n{\npublic:\n\tCUTNetMessage ()\n\t{\n\t\tTEST_ADD(CUTNetMessage::messageSwap);\n\t\tTEST_ADD(CUTNetMessage::lockSubMEssage);\n\t\tTEST_ADD(CUTNetMessage::lockSubMEssageWithLongName);\n\n\t}\n\n\tvoid lockSubMEssageWithLongName()\n\t{\n\t\tNLNET::CMessage master(\"BIG\");\n\n\t\t// serial some stuff\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tmaster.serial(i);\n\t\t}\n\n\t\tuint32 sizes[4];\n\n\t\t// serial 4 sub messages\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tNLNET::CMessage sub(NLMISC::toString(\"A_VERY_LONG_SUB_MESSAGE_NAME_%u\", i));\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tsub.serial(j);\n\t\t\t}\n\n\t\t\tstring s(\"A VERY LONG MESSAGE THAT COULD BE A PROBLEM TO HANDLE\");\n\t\t\tsub.serial(s);\n\n\t\t\tsizes[i] = sub.length();\n\n\t\t\tmaster.serialMessage(sub);\n\t\t}\n\n\t\t// invert the message\n\t\tmaster.invert();\n\n\t\t// now, unpack and check\n\n\t\t// read the first master data\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tuint8 b;\n\t\t\tmaster.serial(b);\n\n\t\t\tTEST_ASSERT(b == i);\n\t\t}\n\n\t\t// unpack each sub message\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tuint32 subSize;\n\t\t\tmaster.serial(subSize);\n\n\t\t\tmaster.lockSubMessage(subSize);\n\t\t\tTEST_ASSERT(subSize == sizes[i]);\n\n\t\t\tTEST_ASSERT(master.getName() == NLMISC::toString(\"A_VERY_LONG_SUB_MESSAGE_NAME_%u\", i));\n\t\t\tTEST_ASSERT(master.length() == sizes[i]);\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tuint8 b;\n\t\t\t\tmaster.serial(b);\n\t\t\t\tTEST_ASSERT(b == j);\n\t\t\t}\n\n\t\t\tstring s;\n\t\t\tmaster.serial(s);\n\t\t\tTEST_ASSERT(s == \"A VERY LONG MESSAGE THAT COULD BE A PROBLEM TO HANDLE\");\n\n\t\t\tTEST_ASSERT(master.getPos() == master.length());\n\n\t\t\tmaster.unlockSubMessage();\n\t\t}\n\n\t\t// rewind the message\n\t\tmaster.seek(master.getHeaderSize(), NLMISC::IStream::begin);\n\n\t\t// read the first master data\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tuint8 b;\n\t\t\tmaster.serial(b);\n\n\t\t\tTEST_ASSERT(b == i);\n\t\t}\n\n\t\t// assign from each sub message\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tuint32 subSize;\n\t\t\tmaster.serial(subSize);\n\n\t\t\tmaster.lockSubMessage(subSize);\n\n\t\t\tTEST_ASSERT(subSize == sizes[i]);\n\n\t\t\tTEST_ASSERT(master.getName() == NLMISC::toString(\"A_VERY_LONG_SUB_MESSAGE_NAME_%u\", i));\n\t\t\tTEST_ASSERT(master.length() == sizes[i]);\n\n\t\t\tNLNET::CMessage sub;\n\t\t\tsub.assignFromSubMessage(master);\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tuint8 b;\n\t\t\t\tsub.serial(b);\n\t\t\t\tTEST_ASSERT(b == j);\n\t\t\t}\n\n\t\t\tstring s;\n\t\t\tsub.serial(s);\n\t\t\tTEST_ASSERT(s == \"A VERY LONG MESSAGE THAT COULD BE A PROBLEM TO HANDLE\");\n\n\t\t\tTEST_ASSERT(sub.getPos() == sub.length());\n\n\t\t\tmaster.unlockSubMessage();\n\t\t}\n\n\t}\n\n\tvoid lockSubMEssage()\n\t{\n\t\tNLNET::CMessage master(\"BIG\");\n\n\t\t// serial some stuff\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tmaster.serial(i);\n\t\t}\n\n\t\tsint32 sizes[4];\n\n\t\t// serial 4 sub messages\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tNLNET::CMessage sub(NLMISC::toString(\"SUB_%u\", i));\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tsub.serial(j);\n\t\t\t}\n\n\t\t\tstring s(\"A MESSAGE\");\n\t\t\tsub.serial(s);\n\n\t\t\tsizes[i] = sub.length();\n\n\t\t\tmaster.serialMessage(sub);\n\t\t}\n\n\t\t// invert the message\n\t\tmaster.invert();\n\n\t\t// now, unpack and check\n\n\t\t// read the first master data\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tuint8 b;\n\t\t\tmaster.serial(b);\n\n\t\t\tTEST_ASSERT(b == i);\n\t\t}\n\n\t\t// unpack each sub message\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tuint32 subSize;\n\t\t\tmaster.serial(subSize);\n\n\t\t\tmaster.lockSubMessage(subSize);\n\t\t\tTEST_ASSERT(subSize == sizes[i]);\n\n\t\t\tTEST_ASSERT(master.getName() == NLMISC::toString(\"SUB_%u\", i));\n\t\t\tTEST_ASSERT(master.length() == sizes[i]);\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tuint8 b;\n\t\t\t\tmaster.serial(b);\n\t\t\t\tTEST_ASSERT(b == j);\n\t\t\t}\n\n\t\t\tstring s;\n\t\t\tmaster.serial(s);\n\t\t\tTEST_ASSERT(s == \"A MESSAGE\");\n\n\t\t\tTEST_ASSERT(master.getPos() == master.length());\n\n\t\t\tmaster.unlockSubMessage();\n\t\t}\n\n\t\t// rewind the message\n\t\tmaster.seek(master.getHeaderSize(), NLMISC::IStream::begin);\n\n\t\t// read the first master data\n\t\tfor (uint8 i=0; i<10; ++i)\n\t\t{\n\t\t\tuint8 b;\n\t\t\tmaster.serial(b);\n\n\t\t\tTEST_ASSERT(b == i);\n\t\t}\n\n\t\t// assign from each sub message\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tuint32 subSize;\n\t\t\tmaster.serial(subSize);\n\n\t\t\tmaster.lockSubMessage(subSize);\n\n\t\t\tTEST_ASSERT(subSize == sizes[i]);\n\n\t\t\tTEST_ASSERT(master.getName() == NLMISC::toString(\"SUB_%u\", i));\n\t\t\tTEST_ASSERT(master.length() == sizes[i]);\n\n\t\t\tNLNET::CMessage sub;\n\t\t\tsub.assignFromSubMessage(master);\n\n\t\t\tfor (uint8 j=0; j<i*4; ++j)\n\t\t\t{\n\t\t\t\tuint8 b;\n\t\t\t\tsub.serial(b);\n\t\t\t\tTEST_ASSERT(b == j);\n\t\t\t}\n\n\t\t\tstring s;\n\t\t\tsub.serial(s);\n\t\t\tTEST_ASSERT(s == \"A MESSAGE\");\n\n\t\t\tTEST_ASSERT(sub.getPos() == sub.length());\n\n\t\t\tmaster.unlockSubMessage();\n\t\t}\n\n\t}\n\t\n\tvoid messageSwap()\n\t{\n\t\tNLNET::CMessage msg2;\n\t\t\t\n\t\tstring s;\n\t\t{\n\t\t\tNLNET::CMessage msg1;\n\t\t\tmsg1.setType(\"NAME\", NLNET::CMessage::Request);\n\n\t\t\ts = \"foo1\";\n\t\t\tmsg1.serial(s);\n\t\t\ts = \"foo2\";\n\t\t\tmsg1.serial(s);\n\t\t\ts = \"\";\n\n\t\t\tmsg2.swap(msg1);\n\n\t\t\t// check that ms1 is empty now\n\t\t\tTEST_ASSERT(msg1.length() == 0);\n\t\t\tTEST_ASSERT(!msg1.typeIsSet());\n\t\t}\n\n\t\tTEST_ASSERT(!msg2.isReading());\n\t\tmsg2.invert();\n\t\tTEST_ASSERT(msg2.typeIsSet());\n\t\tTEST_ASSERT(msg2.getName() == \"NAME\");\n\t\tTEST_ASSERT(msg2.getType() == NLNET::CMessage::Request);\n\t\tmsg2.serial(s);\n\t\tTEST_ASSERT(s == \"foo1\");\n\t\tmsg2.serial(s);\n\t\tTEST_ASSERT(s == \"foo2\");\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nel/tools/nel_unit_test/ut_net_module.h",
    "content": "// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>\n// Copyright (C) 2010  Winch Gate Property Limited\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU Affero General Public License as\n// published by the Free Software Foundation, either version 3 of the\n// License, or (at your option) any later version.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU Affero General Public License for more details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\n#ifndef UT_NET_MODULE\n#define UT_NET_MODULE\n\n#include <nel/misc/dynloadlib.h>\n#include <nel/misc/command.h>\n#include <nel/misc/path.h>\n#include <nel/net/module_common.h>\n#include <nel/net/module_manager.h>\n#include <nel/net/module.h>\n#include <nel/net/inet_address.h>\n#include <nel/net/module_socket.h>\n#include <nel/net/module_gateway.h>\n#include <nel/net/service.h>\n\nclass CModuleType0 : public NLNET::CModuleBase\n{\npublic:\n\n\tuint\tPingCount;\n\tuint\tResponseReceived;\n\n\tset<NLNET::TModuleProxyPtr>\tModuleType0;\n\n\tuint32\tModuleUpCalled;\n\tuint32\tModuleDownCalled;\n\tuint32\tProcessMessageCalled;\n\tuint32\tSecurityUpdateCalled;\n\n\n\tCModuleType0()\n\t\t: PingCount(0),\n\t\tResponseReceived(0)\n\t{\n\t\tModuleUpCalled = 0;\n\t\tModuleDownCalled = 0;\n\t\tProcessMessageCalled = 0;\n\t\tSecurityUpdateCalled = 0;\n\t}\n\n\tstd::string\t\t\t\t\tbuildModuleManifest() const\n\t{\n\t\treturn \"CModuleType0\";\n\t}\n\n\tbool initModule(const NLNET::TParsedCommandLine &param)\n\t{\n\t\tbool ret = CModuleBase::initModule(param);\n\t\tif (param.getParam(\"FAIL\") != NULL)\n\t\t\treturn false;\n\n\t\treturn ret;\n\t}\n\n\tvoid\t\t\t\tonServiceUp(const std::string &serviceName, NLNET::TServiceId serviceId)\n\t{\n\t}\n\t/// A nel layer 5 service has stopped.\n\tvoid\t\t\t\tonServiceDown(const std::string &serviceName, NLNET::TServiceId serviceId) \n\t{\n\t}\n\tvoid\t\t\t\tonModuleUpdate()\n\t{\n\t}\n\t/** The service main loop is terminating it job', all module will be\n\t *\tdisconnected and removed after this callback.\n\t */\n\tvoid\t\t\t\tonApplicationExit() \n\t{\n\t}\n\n\tvoid\t\t\t\tonModuleUp(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tModuleUpCalled++;\n\n\t\tif (moduleProxy->getModuleClassName() == getModuleClassName())\n\t\t\tModuleType0.insert(moduleProxy);\n\t}\n\t/** Called by a socket to inform this module that another\n\t *\tmodule has been deleted OR has been no more accessible (due to\n\t *\tsome gateway disconnection).\n\t */\n\tvoid\t\t\t\tonModuleDown(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tModuleDownCalled++;\n\n\t\tif (moduleProxy->getModuleClassName() == getModuleClassName())\n\t\t\tModuleType0.erase(moduleProxy);\n\t}\n\n\tbool\t\t\t\tonProcessModuleMessage(NLNET::IModuleProxy *senderModuleProxy, const NLNET::CMessage &message)\n\t{\n\t\tProcessMessageCalled++;\n\n\t\tif (message.getName() == \"DEBUG_MOD_PING\")\n\t\t{\n\t\t\tPingCount++;\n\t\t\treturn true;\n\t\t}\n\t\telse if (message.getName() == \"HELLO\")\n\t\t{\n\t\t\tNLNET::CMessage ping(\"DEBUG_MOD_PING\");\n\t\t\tsenderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping));\n\t\t\tsenderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping));\n\t\t\t{\n\t\t\t\tNLNET::CMessage resp;\n\t\t\t\tresp.setType(\"HELLO_RESP\", NLNET::CMessage::Response);\n\n\t\t\t\tsenderModuleProxy->sendModuleMessage(this, resp);\n\t\t\t}\n\t\t\tsenderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping));\n\t\t\tsenderModuleProxy->sendModuleMessage(this, NLNET::CMessage(ping));\n\t\t\treturn true;\n\t\t}\n\t\telse if (message.getName() == \"HELLO2\")\n\t\t{\n\t\t\t// the response for the life, the universe and all other things...\n\t\t\tthrow 42;\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tvoid\t\t\t\tonModuleSecurityChange(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tSecurityUpdateCalled++;\n\t}\n\n\tvoid\t\t\t\tonModuleSocketEvent(NLNET::IModuleSocket *moduleSocket, IModule::TModuleSocketEvent eventType)\n\t{\n\t}\n\n\tvoid startTaskA()\n\t{\n\t\t// start a task on module \n\t\tNLNET_START_MODULE_TASK(CModuleType0, taskA);\n\t}\n\n\t// test task A \n\tvoid\t\ttaskA()\n\t{\n\t\t// use the first like me in the list\n\t\tnlassert(!ModuleType0.empty());\n\n\t\tNLNET::TModuleProxyPtr proxy = *ModuleType0.begin();\n\n\t\tNLNET::CMessage msg;\n\t\tmsg.setType(\"HELLO\", NLNET::CMessage::Request);\n\t\tNLNET::CMessage resp;\n\t\tinvokeModuleOperation(proxy, msg, resp);\n\n\t\tnlassert(resp.getName() == \"HELLO_RESP\");\n\n\t\tResponseReceived++;\n\t}\n\n\tvoid startTaskB()\n\t{\n\t\t// start a task on module\n\t\tNLNET_START_MODULE_TASK(CModuleType0, taskB);\n\t}\n\n\t// test task B \n\tvoid\t\ttaskB()\n\t{\n\t\t// use the first like me in the list\n\t\tnlassert(!ModuleType0.empty());\n\n\t\tNLNET::TModuleProxyPtr proxy = *ModuleType0.begin();\n\n\t\tNLNET::CMessage msg;\n\t\tmsg.setType(\"HELLO2\", NLNET::CMessage::Request);\n\t\tNLNET::CMessage resp;\n\n\t\ttry\n\t\t{\n\t\t\tinvokeModuleOperation(proxy, msg, resp);\n\t\t}\n\t\tcatch(const IModule::EInvokeFailed &)\n\t\t{\n\t\t\tResponseReceived++;\n\t\t}\n\t}\n\n};\n\nNLNET_REGISTER_MODULE_FACTORY(CModuleType0, \"ModuleType0\");\n\n// A module that doesn't support immediate dispatching\nclass CModuleAsync : public CModuleType0\n{\npublic:\n\n\tbool isImmediateDispatchingSupported() const \n\t{ \n\t\treturn false; \n\t}\n};\n\nNLNET_REGISTER_MODULE_FACTORY(CModuleAsync, \"ModuleAsync\");\n\nenum TTestSecurityTypes\n{\n\ttst_type1,\n\ttst_type2,\n\ttst_type3,\n\ttst_type4,\n};\n\n// security type 1 data : contains host gateway name\nstruct TSecurityType1 : public NLNET::TSecurityData\n{\n\tstring\tSecurityGatewayName;\n\n\tTSecurityType1(const TCtorParam &param)\n\t\t: NLNET::TSecurityData(param)\n\t{\n\t}\n\n\tvoid serial(NLMISC::CMemStream &s)\n\t{\n\t\ts.serial(SecurityGatewayName);\n\t}\n\n};\n\nNLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType1, uint8, tst_type1);\n\n\n// security type 2 data : contains host gateway name and a predefined integer value\nstruct TSecurityType2 : public NLNET::TSecurityData\n{\n\tstring\tSecurityGatewayName;\n\tuint32\tIntegerValue;\n\n\tTSecurityType2(const TCtorParam &param)\n\t\t: NLNET::TSecurityData(param)\n\t{\n\t\tIntegerValue = 0x12345678;\n\t}\n\n\tvoid serial(NLMISC::CMemStream &s)\n\t{\n\t\ts.serial(SecurityGatewayName);\n\t\ts.serial(IntegerValue);\n\t}\n};\n\nNLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType2, uint8, tst_type2);\n\n\n// security type 3 data, same as type 1\nstruct TSecurityType3 : public NLNET::TSecurityData\n{\n\tstring\tSecurityGatewayName;\n\n\tTSecurityType3(const TCtorParam &param)\n\t\t: NLNET::TSecurityData(param)\n\t{\n\t}\n\n\tvoid serial(NLMISC::CMemStream &s)\n\t{\n\t\ts.serial(SecurityGatewayName);\n\t}\n\n};\nNLMISC_REGISTER_OBJECT(NLNET::TSecurityData, TSecurityType3, uint8, tst_type3);\n\n// security type 4 data, same as type 1 but not registered\nstruct TSecurityType4 : public NLNET::TSecurityData\n{\n\tstring\tSecurityGatewayName;\n\n\tTSecurityType4(const TCtorParam &param)\n\t\t: NLNET::TSecurityData(param)\n\t{\n\t}\n\n\tvoid serial(NLMISC::CMemStream &s)\n\t{\n\t\ts.serial(SecurityGatewayName);\n\t}\n};\n\n/** a sample security plug-in that add type 1 security data to local modules,\n *\ttype 2 security to foreign module,\n *\tand that remove received type 1 security from foreign module\n */\nclass CTestSecurity1 : public NLNET::CGatewaySecurity\n{\npublic:\n\tCTestSecurity1(const TCtorParam &params)\n\t\t: NLNET::CGatewaySecurity(params)\n\t{}\n\n\tvirtual void onNewProxy(NLNET::IModuleProxy *proxy)\n\t{\n\t\tif (proxy->getGatewayRoute() == NULL)\n\t\t{\n\t\t\t// add a type 1 security\n\t\t\tTSecurityType1 *st1 = new TSecurityType1(NLNET::TSecurityData::TCtorParam(tst_type1));\n\t\t\tst1->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName();\n\n\t\t\tsetSecurityData(proxy, st1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// remove any type 1 data and set a type 2 data\n\t\t\tremoveSecurityData(proxy, tst_type1);\n\t\t\tTSecurityType2 *st2 = new TSecurityType2(NLNET::TSecurityData::TCtorParam(tst_type2));\n\t\t\tst2->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName();\n\n\t\t\tsetSecurityData(proxy, st2);\n\t\t}\n\n\t\tforceSecurityUpdate(proxy);\n\t}\n\n\tvoid onNewSecurityData(NLNET::CGatewayRoute *from, NLNET::IModuleProxy *proxy, NLNET::TSecurityData *firstSecurityData)\n\t{\n\t\t// replace the complete security set\n\t\treplaceAllSecurityDatas(proxy, firstSecurityData);\n\t\t// remove any type 1 data and set a type 2 data\n\t\tremoveSecurityData(proxy, tst_type1);\n\t\tTSecurityType2 *st2 = new TSecurityType2(NLNET::TSecurityData::TCtorParam(tst_type2));\n\t\tst2->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName();\n\n\t\tsetSecurityData(proxy, st2);\n\n\t\t// we don't need to update in this case  (update is always done by gateway)\n\t}\n\n\tvirtual void onDelete()\n\t{\n\t\tvector<NLNET::IModuleProxy*>\tproxies;\n\t\t_Gateway->getModuleProxyList(proxies);\n\n\t\t// remove any security data managed by this plug-in\n\t\tfor (uint i=0; i<proxies.size(); ++i)\n\t\t{\n\t\t\tNLNET::IModuleProxy *proxy = proxies[i];\n\t\t\tif (proxy->getFirstSecurityData() != NULL)\n\t\t\t{\n\t\t\t\tbool update = false;\n\t\t\t\tupdate |= removeSecurityData(proxy, tst_type1);\n\t\t\t\tupdate |= removeSecurityData(proxy, tst_type2);\n\t\t\t\tif (update)\n\t\t\t\t\tforceSecurityUpdate(proxy);\n\t\t\t}\n\t\t}\n\t}\n\n};\nNLMISC_REGISTER_OBJECT(NLNET::CGatewaySecurity, CTestSecurity1, std::string, \"TestSecurity1\");\n\n/** a sample security plug-in that add type 3 and type 4 security data to local modules,\n */\nclass CTestSecurity2 : public NLNET::CGatewaySecurity\n{\npublic:\n\tCTestSecurity2(const TCtorParam &params)\n\t\t: NLNET::CGatewaySecurity(params)\n\t{}\n\n\tvirtual void onNewProxy(NLNET::IModuleProxy *proxy)\n\t{\n\t\tif (proxy->getGatewayRoute() == NULL)\n\t\t{\n\t\t\t// add a type 3 security\n\t\t\tTSecurityType3 *st3 = new TSecurityType3(NLNET::TSecurityData::TCtorParam(tst_type3));\n\t\t\tst3->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName();\n\t\t\tsetSecurityData(proxy, st3);\n\t\t\t// add a type 4 security\n\t\t\tTSecurityType4 *st4 = new TSecurityType4(NLNET::TSecurityData::TCtorParam(tst_type4));\n\t\t\tst4->SecurityGatewayName = _Gateway->getFullyQualifiedGatewayName();\n\t\t\tsetSecurityData(proxy, st4);\n\t\t\tforceSecurityUpdate(proxy);\n\t\t}\n\t}\n\n\tvoid onNewSecurityData(NLNET::CGatewayRoute *from, NLNET::IModuleProxy *proxy, NLNET::TSecurityData *firstSecurityData)\n\t{\n\t\t// replace the complete security set\n\t\treplaceAllSecurityDatas(proxy, firstSecurityData);\n\t}\n\n\tvirtual void onDelete()\n\t{\n\t\tvector<NLNET::IModuleProxy*>\tproxies;\n\t\t_Gateway->getModuleProxyList(proxies);\n\n\t\t// remove any security data managed by this plug-in\n\t\tfor (uint i=0; i<proxies.size(); ++i)\n\t\t{\n\t\t\tNLNET::IModuleProxy *proxy = proxies[i];\n\t\t\tif (proxy->getGatewayRoute() == NULL)\n\t\t\t{\n\t\t\t\tremoveSecurityData(proxy, tst_type3);\n\t\t\t\tremoveSecurityData(proxy, tst_type4);\n\t\t\t\tforceSecurityUpdate(proxy);\n\t\t\t}\n\t\t}\n\t}\n};\nNLMISC_REGISTER_OBJECT(NLNET::CGatewaySecurity, CTestSecurity2, std::string, \"TestSecurity2\");\n\n\n// A module interceptor\nclass CInterceptor : public NLNET::IModuleInterceptable\n{\npublic:\n\tstring\tName;\n\tuint32\tModuleUpCalled;\n\tuint32\tModuleDownCalled;\n\tuint32\tProcessMessageCalled;\n\tuint32\tSecurityUpdateCalled;\n\n\tCInterceptor(NLNET::IInterceptorRegistrar *registrar, const string &name)\n\t\t:\tName(name)\n\t{\n\t\tNLNET::IModuleInterceptable::registerInterceptor(registrar),\n\t\tModuleUpCalled = 0;\n\t\tModuleDownCalled = 0;\n\t\tProcessMessageCalled = 0;\n\t\tSecurityUpdateCalled = 0;\n\t}\n\n\tvirtual std::string\t\t\tbuildModuleManifest() const\n\t{\n\t\treturn Name;\n\t}\n\n\tvirtual void\t\t\t\tonModuleUp(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tModuleUpCalled++;\n\t}\n\n\tvirtual void\t\t\t\tonModuleDown(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tModuleDownCalled++;\n\t}\n\n\tvirtual bool\t\t\t\tonProcessModuleMessage(NLNET::IModuleProxy *senderModuleProxy, const NLNET::CMessage &message)\n\t{\n\t\tProcessMessageCalled++;\n\t\treturn false;\n\t}\n\n\tvirtual void\t\t\t\tonModuleSecurityChange(NLNET::IModuleProxy *moduleProxy)\n\t{\n\t\tSecurityUpdateCalled++;\n\t}\n};\n\n// Test suite for Modules class\nclass CUTNetModule : public Test::Suite\n{\n\tstring\t_WorkingPath;\n\tstring\t_RestorePath;\n\npublic:\n\t// utility to look for a specified proxy in a vector of proxy\n\t// return true if the proxy if found\n\tbool lookForModuleProxy(const vector<NLNET::IModuleProxy*> proxList, const std::string &modName)\n\t{\n\t\tfor (uint i=0; i<proxList.size(); ++i)\n\t\t{\n\t\t\tif (proxList[i]->getModuleName().find(modName) == (proxList[i]->getModuleName().size() - modName.size()))\n\t\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tNLNET::IModuleProxy *retrieveModuleProxy(NLNET::IModuleGateway *gw, const std::string &modName)\n\t{\n\t\tvector<NLNET::IModuleProxy*> proxList;\n\t\tgw->getModuleProxyList(proxList);\n\n\t\tfor (uint i=0; i<proxList.size(); ++i)\n\t\t{\n\t\t\tif (proxList[i]->getModuleName().find(modName) == (proxList[i]->getModuleName().size() - modName.size()))\n\t\t\t\treturn proxList[i];\n\t\t}\n\n\t\treturn NULL;\n\t}\n\n\tvoid setup()\n\t{\n\t\t_RestorePath = NLMISC::CPath::getCurrentPath();\n\n\t\tNLMISC::CPath::setCurrentPath(_WorkingPath.c_str());\n\t}\n\n\tvoid tear_down()\n\t{\n\t\tNLMISC::CPath::setCurrentPath(_RestorePath.c_str());\n\t}\n\n\tCUTNetModule ()\n\t{\n\t\tTEST_ADD(CUTNetModule::testModuleInitInfoParsing);\n\t\tTEST_ADD(CUTNetModule::testModuleInitInfoQuering);\n\t\tTEST_ADD(CUTNetModule::testModuleInitInfoBadParsing);\n\t\tTEST_ADD(CUTNetModule::localModuleFactory);\n\t\t//TEST_ADD(CUTNetModule::loadModuleLib);\n\t\t//TEST_ADD(CUTNetModule::createModule);\n\t\t//TEST_ADD(CUTNetModule::deleteModule);\n\t\tTEST_ADD(CUTNetModule::failedInit);\n\t\t//TEST_ADD(CUTNetModule::unloadModuleLib);\n\t\tTEST_ADD(CUTNetModule::createLocalGateway);\n\t\tTEST_ADD(CUTNetModule::plugLocalGateway);\n\t\t//TEST_ADD(CUTNetModule::moduleManagerCommands);\n\t\tTEST_ADD(CUTNetModule::gatewayTransportManagement);\n\t\tTEST_ADD(CUTNetModule::connectGateways);\n\t\tTEST_ADD(CUTNetModule::moduleDisclosure);\n\t\tTEST_ADD(CUTNetModule::moduleMessaging);\n\t\tTEST_ADD(CUTNetModule::localMessageQueing);\n\t\tTEST_ADD(CUTNetModule::uniqueNameGenerator);\n\t\tTEST_ADD(CUTNetModule::gwPlugUnplug);\n\t\tTEST_ADD(CUTNetModule::peerInvisible);\n\t\tTEST_ADD(CUTNetModule::firewalling);\n\t\tTEST_ADD(CUTNetModule::distanceAndConnectionLoop);\n\t\tTEST_ADD(CUTNetModule::securityPlugin);\n\t\tTEST_ADD(CUTNetModule::synchronousMessaging);\n\t\tTEST_ADD(CUTNetModule::layer3Autoconnect);\n\t\tTEST_ADD(CUTNetModule::interceptorTest);\n\t}\n\n\tvoid interceptorTest()\n\t{\n\t\t// Check that the interceptor system.\n\n\t\t// TODO : right now, there is no test of the security update call\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\t// create the modules\n\t\tNLNET::IModule *gw = mm.createModule(\"StandardGateway\", \"gw\", \"\");\n\t\tNLNET::IModule *mod = mm.createModule(\"ModuleType0\", \"mod\", \"\");\n\t\tNLNET::IModuleGateway *gGw = dynamic_cast<NLNET::IModuleGateway *>(gw);\n\t\tCModuleType0 *mod0 = dynamic_cast<CModuleType0*>(mod);\n\n\t\tTEST_ASSERT(gGw != NULL);\n\t\tTEST_ASSERT(mod0 != NULL);\n\n\t\t// create the interceptors and attach it to the mod0\n\t\tCInterceptor *inter0 = new CInterceptor(mod, \"Inter0\");\n\t\tCInterceptor *inter1 = new CInterceptor(mod, \"Inter1\");\n\n\t\t// plug the modules\n\t\tcr.execute(\"gw.plug gw\", NLMISC::InfoLog());\n\t\tcr.execute(\"mod.plug gw\", NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// send a message to the module fro; the gateway\n\t\tNLNET::CMessage msg(\"foo\");\n\t\tNLNET::IModuleProxy *modProx = retrieveModuleProxy(gGw, \"mod\");\n\t\tTEST_ASSERT(modProx != NULL);\n\t\tmodProx->sendModuleMessage(gw, msg);\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// check the module manifest\n\t\tTEST_ASSERT(modProx->getModuleManifest() == \"CModuleType0 Inter0 Inter1\");\n\n\t\t// unplug the modules\n\t\tcr.execute(\"gw.unplug gw\", NLMISC::InfoLog());\n\t\tcr.execute(\"mod.unplug gw\", NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// now check that all methods have been called in that\n\t\t// module and in the two interceptors,\n\t\t// also check the manifest string content.\n\t\tTEST_ASSERT(mod0->ModuleUpCalled == 1);\n\t\tTEST_ASSERT(mod0->ModuleDownCalled == 1);\n\t\tTEST_ASSERT(mod0->ProcessMessageCalled == 1);\n//\t\tTEST_ASSERT(mod0->SecurityUpdateCalled);\n\t\t\n\t\tTEST_ASSERT(inter0->ModuleUpCalled == 1);\n\t\tTEST_ASSERT(inter0->ModuleDownCalled == 1);\n\t\tTEST_ASSERT(inter0->ProcessMessageCalled == 1);\n//\t\tTEST_ASSERT(inter0->SecurityUpdateCalled);\n\t\t\n\t\tTEST_ASSERT(inter1->ModuleUpCalled == 1);\n\t\tTEST_ASSERT(inter1->ModuleDownCalled == 1);\n\t\tTEST_ASSERT(inter1->ProcessMessageCalled == 1);\n//\t\tTEST_ASSERT(inter1->SecurityUpdateCalled);\n\n\n\t\t// delete the modules\n\t\tmm.deleteModule(gw);\n\t\tmm.deleteModule(mod);\n\n\t\t// delete the interceptors\n\t\tdelete inter0;\n\t\tdelete inter1;\n\t}\n\t\n\tvoid layer3Autoconnect()\n\t{\n\t\t// Check that layer 3 client can automatically reconnect in case of server \n\t\t// down/up\n\t\t//\n\t\t//\tWe create two gateway, gw1 and gw2, plugged in themselves, then we create\n\t\t//\ta layer 3 client on gw1, update the network, then we create the layer 3 server\n\t\t//\ton gw2, update the network then check that module are connected.\n\t\t//\n\t\t//\tThen we close the L3 server on gw2, update the network, check that module\n\t\t//\tare diconnected and reopen the L3 server and recheck that module are connected.\n\t\t//\n\t\t//\n\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\t// create the modules\n\t\tNLNET::IModule *gw1 = mm.createModule(\"StandardGateway\", \"gw1\", \"\");\n\t\tNLNET::IModule *gw2 = mm.createModule(\"StandardGateway\", \"gw2\", \"\");\n\t\tNLNET::IModuleGateway *gGw1 = dynamic_cast<NLNET::IModuleGateway *>(gw1);\n\t\tNLNET::IModuleGateway *gGw2 = dynamic_cast<NLNET::IModuleGateway *>(gw2);\n\n\t\t// plug gateway in themselves\n\t\tcr.execute(\"gw1.plug gw1\", NLMISC::InfoLog());\n\t\tcr.execute(\"gw2.plug gw2\", NLMISC::InfoLog());\n\n\t\t// create the client transport\n\t\tcr.execute(\"gw1.transportAdd L3Client l3c\", NLMISC::InfoLog());\n\t\tcr.execute(\"gw1.transportCmd l3c(retryInterval=1)\", NLMISC::InfoLog());\n\t\tcr.execute(\"gw1.transportCmd l3c(connect addr=localhost:8062)\", NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") == NULL);\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") == NULL);\n\n\t\t// open the server\n\t\tcr.execute(\"gw2.transportAdd L3Server l3s\", NLMISC::InfoLog());\n\t\tcr.execute(\"gw2.transportCmd l3s(open port=8062)\", NLMISC::InfoLog());\n\t\t\n\t\t// update the network (give more time because we must cover the Layer3 client reconnection timer)\n\t\tfor (uint i=0; i<40; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(50);\n\t\t}\n\n\t\t// check module connectivity\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") != NULL);\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") != NULL);\n\n\t\t// exchange some message\n\t\tcr.execute(\"gw1.sendPing \"+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog());\n\t\tcr.execute(\"gw2.sendPing \"+gw1->getModuleFullyQualifiedName(), NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// check the ping counter\n\t\tTEST_ASSERT(gGw1->getReceivedPingCount() == 1);\n\t\tTEST_ASSERT(gGw2->getReceivedPingCount() == 1);\n\n\t\t// flood a little with ping\n\t\tfor (uint i=0; i<100; ++i)\n\t\t\tcr.execute(\"gw1.sendPing \"+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog());\n\n\t\t// close the server\n\t\tcr.execute(\"gw2.transportCmd l3s(close)\", NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// test no connectivity\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") == NULL);\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw2, \"gw1\") == NULL);\n\n\t\t// re-open the server\n\t\tcr.execute(\"gw2.transportCmd l3s(open port=8062)\", NLMISC::InfoLog());\n\n\t\t// update the network (give more time because we must cover the Layer3 client reconnection timer)\n\t\tfor (uint i=0; i<40; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(50);\n\t\t}\n\n\t\t// check module connectivity\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw1, \"gw2\") != NULL);\n\t\tTEST_ASSERT(retrieveModuleProxy(gGw2, \"gw1\") != NULL);\n\n\t\t// exchange some message\n\t\tcr.execute(\"gw1.sendPing \"+gw2->getModuleFullyQualifiedName(), NLMISC::InfoLog());\n\t\tcr.execute(\"gw2.sendPing \"+gw1->getModuleFullyQualifiedName(), NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// check the ping counter\n\t\tTEST_ASSERT(gGw1->getReceivedPingCount() == 2);\n\t\tTEST_ASSERT(gGw2->getReceivedPingCount() == 2);\n\n\t\t// cleanup modules\n\t\tmm.deleteModule(gw1);\n\t\tmm.deleteModule(gw2);\n\t}\n\n\tvoid synchronousMessaging()\n\t{\n\t\t// check that the synchronous messaging is working\n\t\t// by using module task\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\n\t\t// create the modules\n\t\tNLNET::IModule *gw = mm.createModule(\"StandardGateway\", \"gw\", \"\");\n\t\tNLNET::IModule *m1 = mm.createModule(\"ModuleType0\", \"m1\", \"\");\n\t\tNLNET::IModule *m2 = mm.createModule(\"ModuleType0\", \"m2\", \"\");\n\n\t\t// plug the two modules in the gateway\n\t\tcr.execute(\"m1.plug gw\", NLMISC::InfoLog());\n\t\tcr.execute(\"m2.plug gw\", NLMISC::InfoLog());\n\n\t\t// update the network\n\t\tfor (uint i=0; i<15; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\tCModuleType0 *mod1 = dynamic_cast<CModuleType0 *>(m1);\n\n\t\t// start a task on module 1\n\t\tmod1->startTaskA();\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\n\t\tTEST_ASSERT(mod1->PingCount == 4);\n\t\tTEST_ASSERT(mod1->ResponseReceived == 1);\n\n\t\t// start a task on module 1\n\t\tmod1->startTaskB();\n\n\t\t// update the network\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\n\t\tTEST_ASSERT(mod1->PingCount == 4);\n\t\tTEST_ASSERT(mod1->ResponseReceived == 2);\n\t\tmm.deleteModule(m1);\n\t\tmm.deleteModule(m2);\n\t\tmm.deleteModule(gw);\n\t}\n\n\tvoid securityPlugin()\n\t{\n\t\t// Check that security plug-in work well.\n\t\t//\n\t\t//\tWe connect three gateway in series with the central gateway\n\t\t//\tusing a security module that adds security data to\n\t\t//\tproxies :\n\t\t//\t\tFor local proxies, it adds type 1 security data\n\t\t//\t\tFor foreign proxies, it adds type 2 security data\n\t\t//\t\tfor foreign proxies, it removes any type 1 security data found\n\t\t//\n\t\t//         gw1 (l3c) -------- (l3s) gw2 (l3c) ------ (l3s) gw3\n\t\t//          ^                        ^\n\t\t//          |                        |\n\t\t//    SecurityPlugin2          SecurityPlugin1\n\t\t//\n\t\t//\tAfter connecting and plugging-in each gateway into themselves, \n\t\t//\twe check the presence and content of the security datas.\n\t\t//  then we remove the securityPlugin1 and check that all \n\t\t//\tsecurity data have been removed,\n\t\t//\tThen, we re create the securityPlugin1 and recheck\n\t\t//\tthen one again, we remove it and recheck.\n\t\t//\n\t\t//\tFor the second part of the check, we create a security\n\t\t//\tplug-in 2 on gw1 that add 'type3' security data on\n\t\t//\tlocal plug-in.\n\t\t//\tWe also plug the security plug-in 1 and then we check that \n\t\t//\twe have the correct security data\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *gw1, *gw2, *gw3;\n\n\t\t// create the modules\n\t\tgw1 = mm.createModule(\"StandardGateway\", \"gw1\", \"\");\n\t\tgw2 = mm.createModule(\"StandardGateway\", \"gw2\", \"\");\n\t\tgw3 = mm.createModule(\"StandardGateway\", \"gw3\", \"\");\n\n\t\tTEST_ASSERT(gw1 != NULL);\n\t\tTEST_ASSERT(gw2 != NULL);\n\t\tTEST_ASSERT(gw3 != NULL);\n\n\t\t// plug gateway in themselves\n\t\tNLNET::IModuleSocket *sGw1, *sGw2, *sGw3;\n\t\tsGw1 = mm.getModuleSocket(\"gw1\");\n\t\tsGw2 = mm.getModuleSocket(\"gw2\");\n\t\tsGw3 = mm.getModuleSocket(\"gw3\");\n\n\t\tTEST_ASSERT(sGw1 != NULL);\n\t\tTEST_ASSERT(sGw2 != NULL);\n\t\tTEST_ASSERT(sGw3 != NULL);\n\n\t\tgw1->plugModule(sGw1);\n\t\tgw2->plugModule(sGw2);\n\t\tgw3->plugModule(sGw3);\n\n\t\tstring cmd;\n\t\t// create security plug-in\n\t\tcmd = \"gw2.securityCreate TestSecurity1\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// create the transports\n\t\tcmd = \"gw1.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// connect transport\n\t\tcmd = \"gw2.transportCmd l3s(open port=8062)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportCmd l3s(open port=8063)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw1.transportCmd l3c(connect addr=localhost:8062)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportCmd l3c(connect addr=localhost:8063)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t\n\t\tfor (uint retry = 0; retry < 2; ++retry)\n\t\t{\n\t\t\tif (retry > 0)\n\t\t\t{\n\t\t\t\t// recreate the security plug-in\n\t\t\t\tcmd = \"gw2.securityCreate TestSecurity1\";\n\t\t\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\t\t}\n\t\t\t// update the network\n\t\t\tfor (uint i=0; i<15; ++i)\n\t\t\t{\n\t\t\t\tmm.updateModules();\n\t\t\t\tNLMISC::nlSleep(40);\n\t\t\t}\n\t\t\tNLNET::IModuleGateway *gGw1, *gGw2, *gGw3; \n\t\t\tgGw1 = dynamic_cast<NLNET::IModuleGateway *>(gw1);\n\t\t\tTEST_ASSERT(gGw1 != NULL);\n\t\t\tgGw2 = dynamic_cast<NLNET::IModuleGateway *>(gw2);\n\t\t\tTEST_ASSERT(gGw2 != NULL);\n\t\t\tgGw3 = dynamic_cast<NLNET::IModuleGateway *>(gw3);\n\t\t\tTEST_ASSERT(gGw3 != NULL);\n\t\t\t\n\n\t\t\t// check security data\n\t\t\tNLNET::IModuleProxy *proxGw1_1, *proxGw2_1, *proxGw3_1;\n\t\t\tNLNET::IModuleProxy *proxGw1_2, *proxGw2_2, *proxGw3_2;\n\t\t\tNLNET::IModuleProxy *proxGw1_3, *proxGw2_3, *proxGw3_3;\n\n\t\t\tproxGw1_1 = retrieveModuleProxy(gGw1, \"gw1\");\n\t\t\tproxGw2_1 = retrieveModuleProxy(gGw1, \"gw2\");\n\t\t\tproxGw3_1 = retrieveModuleProxy(gGw1, \"gw3\");\n\t\t\tproxGw1_2 = retrieveModuleProxy(gGw2, \"gw1\");\n\t\t\tproxGw2_2 = retrieveModuleProxy(gGw2, \"gw2\");\n\t\t\tproxGw3_2 = retrieveModuleProxy(gGw2, \"gw3\");\n\t\t\tproxGw1_3 = retrieveModuleProxy(gGw3, \"gw1\");\n\t\t\tproxGw2_3 = retrieveModuleProxy(gGw3, \"gw2\");\n\t\t\tproxGw3_3 = retrieveModuleProxy(gGw3, \"gw3\");\n\n\t\t\tTEST_ASSERT(proxGw1_1 != NULL);\n\t\t\tTEST_ASSERT(proxGw2_1 != NULL);\n\t\t\tTEST_ASSERT(proxGw3_1 != NULL);\n\t\t\tTEST_ASSERT(proxGw1_2 != NULL);\n\t\t\tTEST_ASSERT(proxGw2_2 != NULL);\n\t\t\tTEST_ASSERT(proxGw3_2 != NULL);\n\t\t\tTEST_ASSERT(proxGw1_3 != NULL);\n\t\t\tTEST_ASSERT(proxGw2_3 != NULL);\n\t\t\tTEST_ASSERT(proxGw3_3 != NULL);\n\n\t\t\tconst NLNET::TSecurityData *ms;\n\t\t\tconst TSecurityType1 *st1;\n\t\t\tconst TSecurityType2 *st2;\n\n\t\t\tms = proxGw1_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\n\t\t\tms = proxGw1_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type2);\n\t\t\tst2 = dynamic_cast<const TSecurityType2 *>(ms);\n\t\t\tTEST_ASSERT(st2 != NULL);\n\t\t\tTEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st2->IntegerValue == 0x12345678);\n\t\t\tTEST_ASSERT(st2->NextItem == NULL);\n\n\t\t\tms = proxGw1_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type2);\n\t\t\tst2 = dynamic_cast<const TSecurityType2 *>(ms);\n\t\t\tTEST_ASSERT(st2 != NULL);\n\t\t\tTEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st2->IntegerValue == 0x12345678);\n\t\t\tTEST_ASSERT(st2->NextItem == NULL);\n\n\t\t\tms = proxGw2_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type1);\n\t\t\tst1 = dynamic_cast<const TSecurityType1 *>(ms);\n\t\t\tTEST_ASSERT(st1 != NULL);\n\t\t\tTEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st1->NextItem == NULL);\n\n\t\t\tms = proxGw2_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type1);\n\t\t\tst1 = dynamic_cast<const TSecurityType1 *>(ms);\n\t\t\tTEST_ASSERT(st1 != NULL);\n\t\t\tTEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st1->NextItem == NULL);\n\n\t\t\tms = proxGw2_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type1);\n\t\t\tst1 = dynamic_cast<const TSecurityType1 *>(ms);\n\t\t\tTEST_ASSERT(st1 != NULL);\n\t\t\tTEST_ASSERT(st1->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st1->NextItem == NULL);\n\n\t\t\tms = proxGw3_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type2);\n\t\t\tst2 = dynamic_cast<const TSecurityType2 *>(ms);\n\t\t\tTEST_ASSERT(st2 != NULL);\n\t\t\tTEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st2->IntegerValue == 0x12345678);\n\t\t\tTEST_ASSERT(st2->NextItem == NULL);\n\n\t\t\tms = proxGw3_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms != NULL);\n\t\t\tTEST_ASSERT(ms->DataTag == tst_type2);\n\t\t\tst2 = dynamic_cast<const TSecurityType2 *>(ms);\n\t\t\tTEST_ASSERT(st2 != NULL);\n\t\t\tTEST_ASSERT(st2->SecurityGatewayName == gw2->getModuleFullyQualifiedName());\n\t\t\tTEST_ASSERT(st2->IntegerValue == 0x12345678);\n\t\t\tTEST_ASSERT(st2->NextItem == NULL);\n\n\t\t\tms = proxGw3_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\n\t\t\t// remove the security plug-in\n\t\t\t// create security plug-in\n\t\t\tcmd = \"gw2.securityRemove\";\n\t\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t\t// update the network\n\t\t\tfor (uint i=0; i<15; ++i)\n\t\t\t{\n\t\t\t\tmm.updateModules();\n\t\t\t\tNLMISC::nlSleep(40);\n\t\t\t}\n\n\t\t\tms = proxGw1_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw1_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw1_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw2_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw2_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw2_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw3_1->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw3_2->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t\tms = proxGw3_3->getFirstSecurityData();\n\t\t\tTEST_ASSERT(ms == NULL);\n\t\t}\n\n\t\t// part 2\n\t\t// create the security plug-in\n\t\tcmd = \"gw2.securityCreate TestSecurity1\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw1.securityCreate TestSecurity2\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<15; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\tNLNET::IModuleGateway *gGw1, *gGw2, *gGw3; \n\t\tgGw1 = dynamic_cast<NLNET::IModuleGateway *>(gw1);\n\t\tTEST_ASSERT(gGw1 != NULL);\n\t\tgGw2 = dynamic_cast<NLNET::IModuleGateway *>(gw2);\n\t\tTEST_ASSERT(gGw2 != NULL);\n\t\tgGw3 = dynamic_cast<NLNET::IModuleGateway *>(gw3);\n\t\tTEST_ASSERT(gGw3 != NULL);\n\t\t\n\n\t\t// check security data\n\t\tNLNET::IModuleProxy *proxGw1_1, *proxGw2_1, *proxGw3_1;\n\t\tNLNET::IModuleProxy *proxGw1_2, *proxGw2_2, *proxGw3_2;\n\t\tNLNET::IModuleProxy *proxGw1_3, *proxGw2_3, *proxGw3_3;\n\n\t\tproxGw1_1 = retrieveModuleProxy(gGw1, \"gw1\");\n\t\tproxGw2_1 = retrieveModuleProxy(gGw1, \"gw2\");\n\t\tproxGw3_1 = retrieveModuleProxy(gGw1, \"gw3\");\n\t\tproxGw1_2 = retrieveModuleProxy(gGw2, \"gw1\");\n\t\tproxGw2_2 = retrieveModuleProxy(gGw2, \"gw2\");\n\t\tproxGw3_2 = retrieveModuleProxy(gGw2, \"gw3\");\n\t\tproxGw1_3 = retrieveModuleProxy(gGw3, \"gw1\");\n\t\tproxGw2_3 = retrieveModuleProxy(gGw3, \"gw2\");\n\t\tproxGw3_3 = retrieveModuleProxy(gGw3, \"gw3\");\n\n\t\tTEST_ASSERT(proxGw1_1 != NULL);\n\t\tTEST_ASSERT(proxGw2_1 != NULL);\n\t\tTEST_ASSERT(proxGw3_1 != NULL);\n\t\tTEST_ASSERT(proxGw1_2 != NULL);\n\t\tTEST_ASSERT(proxGw2_2 != NULL);\n\t\tTEST_ASSERT(proxGw3_2 != NULL);\n\t\tTEST_ASSERT(proxGw1_3 != NULL);\n\t\tTEST_ASSERT(proxGw2_3 != NULL);\n\t\tTEST_ASSERT(proxGw3_3 != NULL);\n\n\t\tconst NLNET::TSecurityData *ms;\n//\t\tconst TSecurityType1 *st1;\n//\t\tconst TSecurityType2 *st2;\n\n\t\tms = proxGw1_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tTEST_ASSERT(dynamic_cast<const TSecurityType4*>(ms) != NULL);\n\n\t\tms = proxGw1_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_2->findSecurityData(0xff);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tTEST_ASSERT(dynamic_cast<const NLNET::TUnknownSecurityData*>(ms) != NULL);\n\n\t\tms = proxGw1_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_3->findSecurityData(0xff);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tTEST_ASSERT(dynamic_cast<const NLNET::TUnknownSecurityData*>(ms) != NULL);\n\n\n\t\tms = proxGw2_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw2_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw2_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\n\t\tms = proxGw3_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw3_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw3_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\t// remove the security plug-in\n\t\t// create security plug-in\n\t\tcmd = \"gw1.securityRemove\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<15; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\tms = proxGw1_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw1_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_2->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw1_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw1_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw1_3->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\n\t\tms = proxGw2_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw2_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_2->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw2_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw2_3->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\n\t\tms = proxGw3_1->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_1->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw3_2->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms != NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_2->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\tms = proxGw3_3->findSecurityData(tst_type1);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type2);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type3);\n\t\tTEST_ASSERT(ms == NULL);\n\t\tms = proxGw3_3->findSecurityData(tst_type4);\n\t\tTEST_ASSERT(ms == NULL);\n\n\t\t// cleanup\n\t\tmm.deleteModule(gw1);\n\t\tmm.deleteModule(gw2);\n\t\tmm.deleteModule(gw3);\n\t}\n\n\tvoid distanceAndConnectionLoop()\n\t{\n\t\t// Check that we support a closed loop or multi connection\n\t\t// of gateway and that the gateway chooses the best \n\t\t// route to reach a module when more than one is possible\n\t\t// and that the distance is updated\n\t\t//\n\t\t// For this test, we use the following context:\n\t\t//\tthree gateway (gw1, gw2, gw3), each having a layer 3\n\t\t//\tserver and client transport.\n\t\t//\tone gateway (gw4) having just a layer3 server\n\t\t//\tgw1 connects on gw2, gw2 connects on gw3, gw3 connects on gw4.\n\t\t//\twe check the module list and distance, then gw3 connects to gw1, closing\n\t\t//\tthe loop.\n\t\t//\twe recheck module list and distance.\n\t\t//\tWe then disconnect gw3 from gw1 and recheck module list and distance.\n\t\t//\n\t\t//\tFinally, we create a second connection from gw1 to gw2 and\n\t\t//\trecheck module list and distances\n\t\t//\t\n\t\t//                     /---<optional>---\\\n\t\t//      (l3s) gw1 (l3c)                  (l3s) gw2 (l3c) ------ (l3s) gw3 (l3c) ------ (l3s) gw4\n\t\t//\t      |            \\----------------/                                   |\n\t\t//\t      |                                                                 |\n\t\t//\t      |                                                                 |\n\t\t//         \\------------------<optional>-----------------------------------/\n\t\t//\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *gw1, *gw2, *gw3, *gw4;\n\n\t\t// create the modules\n\t\tgw1 = mm.createModule(\"StandardGateway\", \"gw1\", \"\");\n\t\tgw2 = mm.createModule(\"StandardGateway\", \"gw2\", \"\");\n\t\tgw3 = mm.createModule(\"StandardGateway\", \"gw3\", \"\");\n\t\tgw4 = mm.createModule(\"StandardGateway\", \"gw4\", \"\");\n\n\t\tTEST_ASSERT(gw1 != NULL);\n\t\tTEST_ASSERT(gw2 != NULL);\n\t\tTEST_ASSERT(gw3 != NULL);\n\t\tTEST_ASSERT(gw4 != NULL);\n\n\t\t// plug gateway into themselves\n\t\tNLNET::IModuleSocket *sGw1, *sGw2, *sGw3, *sGw4;\n\t\tsGw1 = mm.getModuleSocket(\"gw1\");\n\t\tsGw2 = mm.getModuleSocket(\"gw2\");\n\t\tsGw3 = mm.getModuleSocket(\"gw3\");\n\t\tsGw4 = mm.getModuleSocket(\"gw4\");\n\n\t\tTEST_ASSERT(sGw1 != NULL);\n\t\tTEST_ASSERT(sGw2 != NULL);\n\t\tTEST_ASSERT(sGw3 != NULL);\n\t\tTEST_ASSERT(sGw4 != NULL);\n\n\t\tgw1->plugModule(sGw1);\n\t\tgw2->plugModule(sGw2);\n\t\tgw3->plugModule(sGw3);\n\t\tgw4->plugModule(sGw4);\n\n\t\tstring cmd;\n\t\t// create the transports\n\t\tcmd = \"gw1.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw1.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw4.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// connect transport\n\t\tcmd = \"gw1.transportCmd l3s(open port=8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportCmd l3s(open port=8062)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportCmd l3s(open port=8063)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw4.transportCmd l3s(open port=8064)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw1.transportCmd l3c(connect addr=localhost:8062)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw2.transportCmd l3c(connect addr=localhost:8063)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw3.transportCmd l3c(connect addr=localhost:8064)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<15; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(40);\n\t\t}\n\n\t\t// check the modules list\n\t\t// ok, now, check that each gateways know the gateway it must know\n\t\tNLNET::IModuleGateway *gGw1, *gGw2, *gGw3, *gGw4;\n\t\tgGw1 = dynamic_cast<NLNET::IModuleGateway *>(gw1);\n\t\tTEST_ASSERT(gGw1 != NULL);\n\t\tgGw2 = dynamic_cast<NLNET::IModuleGateway *>(gw2);\n\t\tTEST_ASSERT(gGw2 != NULL);\n\t\tgGw3 = dynamic_cast<NLNET::IModuleGateway *>(gw3);\n\t\tTEST_ASSERT(gGw3 != NULL);\n\t\tgGw4 = dynamic_cast<NLNET::IModuleGateway *>(gw4);\n\t\tTEST_ASSERT(gGw4 != NULL);\n\n\t\tvector<NLNET::IModuleProxy*> proxList;\n\t\tgGw1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw3->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw4->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\n\t\t// check the distance\n\t\tNLNET::IModuleProxy *gw1_1Prox, *gw1_2Prox, *gw1_3Prox, *gw1_4Prox; \n\t\tNLNET::IModuleProxy *gw2_1Prox, *gw2_2Prox, *gw2_3Prox, *gw2_4Prox; \n\t\tNLNET::IModuleProxy *gw3_1Prox, *gw3_2Prox, *gw3_3Prox, *gw3_4Prox; \n\t\tNLNET::IModuleProxy *gw4_1Prox, *gw4_2Prox, *gw4_3Prox, *gw4_4Prox; \n\n\t\tgw1_1Prox = retrieveModuleProxy(gGw1, \"gw1\");\n\t\tTEST_ASSERT(gw1_1Prox != NULL);\n\t\tTEST_ASSERT(gw1_1Prox->getModuleDistance() == 0);\n\t\tgw1_2Prox = retrieveModuleProxy(gGw2, \"gw1\");\n\t\tTEST_ASSERT(gw1_2Prox != NULL);\n\t\tTEST_ASSERT(gw1_2Prox->getModuleDistance() == 1);\n\t\tgw1_3Prox = retrieveModuleProxy(gGw3, \"gw1\");\n\t\tTEST_ASSERT(gw1_3Prox != NULL);\n\t\tTEST_ASSERT(gw1_3Prox->getModuleDistance() == 2);\n\t\tgw1_4Prox = retrieveModuleProxy(gGw4, \"gw1\");\n\t\tTEST_ASSERT(gw1_4Prox != NULL);\n\t\tTEST_ASSERT(gw1_4Prox->getModuleDistance() == 3);\n\n\t\tgw2_1Prox = retrieveModuleProxy(gGw1, \"gw2\");\n\t\tTEST_ASSERT(gw2_1Prox != NULL);\n\t\tTEST_ASSERT(gw2_1Prox->getModuleDistance() == 1);\n\t\tgw2_2Prox = retrieveModuleProxy(gGw2, \"gw2\");\n\t\tTEST_ASSERT(gw2_2Prox != NULL);\n\t\tTEST_ASSERT(gw2_2Prox->getModuleDistance() == 0);\n\t\tgw2_3Prox = retrieveModuleProxy(gGw3, \"gw2\");\n\t\tTEST_ASSERT(gw2_3Prox != NULL);\n\t\tTEST_ASSERT(gw2_3Prox->getModuleDistance() == 1);\n\t\tgw2_4Prox = retrieveModuleProxy(gGw4, \"gw2\");\n\t\tTEST_ASSERT(gw2_4Prox != NULL);\n\t\tTEST_ASSERT(gw2_4Prox->getModuleDistance() == 2);\n\n\t\tgw3_1Prox = retrieveModuleProxy(gGw1, \"gw3\");\n\t\tTEST_ASSERT(gw3_1Prox != NULL);\n\t\tTEST_ASSERT(gw3_1Prox->getModuleDistance() == 2);\n\t\tgw3_2Prox = retrieveModuleProxy(gGw2, \"gw3\");\n\t\tTEST_ASSERT(gw3_2Prox != NULL);\n\t\tTEST_ASSERT(gw3_2Prox->getModuleDistance() == 1);\n\t\tgw3_3Prox = retrieveModuleProxy(gGw3, \"gw3\");\n\t\tTEST_ASSERT(gw3_3Prox != NULL);\n\t\tTEST_ASSERT(gw3_3Prox->getModuleDistance() == 0);\n\t\tgw3_4Prox = retrieveModuleProxy(gGw4, \"gw3\");\n\t\tTEST_ASSERT(gw3_4Prox != NULL);\n\t\tTEST_ASSERT(gw3_4Prox->getModuleDistance() == 1);\n\n\t\tgw4_1Prox = retrieveModuleProxy(gGw1, \"gw4\");\n\t\tTEST_ASSERT(gw4_1Prox != NULL);\n\t\tTEST_ASSERT(gw4_1Prox->getModuleDistance() == 3);\n\t\tgw4_2Prox = retrieveModuleProxy(gGw2, \"gw4\");\n\t\tTEST_ASSERT(gw4_2Prox != NULL);\n\t\tTEST_ASSERT(gw4_2Prox->getModuleDistance() == 2);\n\t\tgw4_3Prox = retrieveModuleProxy(gGw3, \"gw4\");\n\t\tTEST_ASSERT(gw4_3Prox != NULL);\n\t\tTEST_ASSERT(gw4_3Prox->getModuleDistance() == 1);\n\t\tgw4_4Prox = retrieveModuleProxy(gGw4, \"gw4\");\n\t\tTEST_ASSERT(gw4_4Prox != NULL);\n\t\tTEST_ASSERT(gw4_4Prox->getModuleDistance() == 0);\n\n\t\t// now, connect gw3 to gw1\n\t\tcmd = \"gw3.transportCmd l3c(connect addr=localhost:8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check module list\n\t\tproxList.clear();\n\t\tgGw1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw3->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw4->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\n\t\t// check the distances\n\t\tgw1_1Prox = retrieveModuleProxy(gGw1, \"gw1\");\n\t\tTEST_ASSERT(gw1_1Prox != NULL);\n\t\tTEST_ASSERT(gw1_1Prox->getModuleDistance() == 0);\n\t\tgw1_2Prox = retrieveModuleProxy(gGw2, \"gw1\");\n\t\tTEST_ASSERT(gw1_2Prox != NULL);\n\t\tTEST_ASSERT(gw1_2Prox->getModuleDistance() == 1);\n\t\tgw1_3Prox = retrieveModuleProxy(gGw3, \"gw1\");\n\t\tTEST_ASSERT(gw1_3Prox != NULL);\n\t\tTEST_ASSERT(gw1_3Prox->getModuleDistance() == 1);\n\t\tgw1_4Prox = retrieveModuleProxy(gGw4, \"gw1\");\n\t\tTEST_ASSERT(gw1_4Prox != NULL);\n\t\tTEST_ASSERT(gw1_4Prox->getModuleDistance() == 2);\n\n\t\tgw2_1Prox = retrieveModuleProxy(gGw1, \"gw2\");\n\t\tTEST_ASSERT(gw2_1Prox != NULL);\n\t\tTEST_ASSERT(gw2_1Prox->getModuleDistance() == 1);\n\t\tgw2_2Prox = retrieveModuleProxy(gGw2, \"gw2\");\n\t\tTEST_ASSERT(gw2_2Prox != NULL);\n\t\tTEST_ASSERT(gw2_2Prox->getModuleDistance() == 0);\n\t\tgw2_3Prox = retrieveModuleProxy(gGw3, \"gw2\");\n\t\tTEST_ASSERT(gw2_3Prox != NULL);\n\t\tTEST_ASSERT(gw2_3Prox->getModuleDistance() == 1);\n\t\tgw2_4Prox = retrieveModuleProxy(gGw4, \"gw2\");\n\t\tTEST_ASSERT(gw2_4Prox != NULL);\n\t\tTEST_ASSERT(gw2_4Prox->getModuleDistance() == 2);\n\n\t\tgw3_1Prox = retrieveModuleProxy(gGw1, \"gw3\");\n\t\tTEST_ASSERT(gw3_1Prox != NULL);\n\t\tTEST_ASSERT(gw3_1Prox->getModuleDistance() == 1);\n\t\tgw3_2Prox = retrieveModuleProxy(gGw2, \"gw3\");\n\t\tTEST_ASSERT(gw3_2Prox != NULL);\n\t\tTEST_ASSERT(gw3_2Prox->getModuleDistance() == 1);\n\t\tgw3_3Prox = retrieveModuleProxy(gGw3, \"gw3\");\n\t\tTEST_ASSERT(gw3_3Prox != NULL);\n\t\tTEST_ASSERT(gw3_3Prox->getModuleDistance() == 0);\n\t\tgw3_4Prox = retrieveModuleProxy(gGw4, \"gw3\");\n\t\tTEST_ASSERT(gw3_4Prox != NULL);\n\t\tTEST_ASSERT(gw3_4Prox->getModuleDistance() == 1);\n\n\t\tgw4_1Prox = retrieveModuleProxy(gGw1, \"gw4\");\n\t\tTEST_ASSERT(gw4_1Prox != NULL);\n\t\tTEST_ASSERT(gw4_1Prox->getModuleDistance() == 2);\n\t\tgw4_2Prox = retrieveModuleProxy(gGw2, \"gw4\");\n\t\tTEST_ASSERT(gw4_2Prox != NULL);\n\t\tTEST_ASSERT(gw4_2Prox->getModuleDistance() == 2);\n\t\tgw4_3Prox = retrieveModuleProxy(gGw3, \"gw4\");\n\t\tTEST_ASSERT(gw4_3Prox != NULL);\n\t\tTEST_ASSERT(gw4_3Prox->getModuleDistance() == 1);\n\t\tgw4_4Prox = retrieveModuleProxy(gGw4, \"gw4\");\n\t\tTEST_ASSERT(gw4_4Prox != NULL);\n\t\tTEST_ASSERT(gw4_4Prox->getModuleDistance() == 0);\n\n\t\t// close gw3 to gw1\n\t\tcmd = \"gw3.transportCmd l3c(close connId=1)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check module list\n\t\tproxList.clear();\n\t\tgGw1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw3->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw4->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\n\t\t// check the distances\n\t\tgw1_1Prox = retrieveModuleProxy(gGw1, \"gw1\");\n\t\tTEST_ASSERT(gw1_1Prox != NULL);\n\t\tTEST_ASSERT(gw1_1Prox->getModuleDistance() == 0);\n\t\tgw1_2Prox = retrieveModuleProxy(gGw2, \"gw1\");\n\t\tTEST_ASSERT(gw1_2Prox != NULL);\n\t\tTEST_ASSERT(gw1_2Prox->getModuleDistance() == 1);\n\t\tgw1_3Prox = retrieveModuleProxy(gGw3, \"gw1\");\n\t\tTEST_ASSERT(gw1_3Prox != NULL);\n\t\tTEST_ASSERT(gw1_3Prox->getModuleDistance() == 2);\n\t\tgw1_4Prox = retrieveModuleProxy(gGw4, \"gw1\");\n\t\tTEST_ASSERT(gw1_4Prox != NULL);\n\t\tTEST_ASSERT(gw1_4Prox->getModuleDistance() == 3);\n\n\t\tgw2_1Prox = retrieveModuleProxy(gGw1, \"gw2\");\n\t\tTEST_ASSERT(gw2_1Prox != NULL);\n\t\tTEST_ASSERT(gw2_1Prox->getModuleDistance() == 1);\n\t\tgw2_2Prox = retrieveModuleProxy(gGw2, \"gw2\");\n\t\tTEST_ASSERT(gw2_2Prox != NULL);\n\t\tTEST_ASSERT(gw2_2Prox->getModuleDistance() == 0);\n\t\tgw2_3Prox = retrieveModuleProxy(gGw3, \"gw2\");\n\t\tTEST_ASSERT(gw2_3Prox != NULL);\n\t\tTEST_ASSERT(gw2_3Prox->getModuleDistance() == 1);\n\t\tgw2_4Prox = retrieveModuleProxy(gGw4, \"gw2\");\n\t\tTEST_ASSERT(gw2_4Prox != NULL);\n\t\tTEST_ASSERT(gw2_4Prox->getModuleDistance() == 2);\n\n\t\tgw3_1Prox = retrieveModuleProxy(gGw1, \"gw3\");\n\t\tTEST_ASSERT(gw3_1Prox != NULL);\n\t\tTEST_ASSERT(gw3_1Prox->getModuleDistance() == 2);\n\t\tgw3_2Prox = retrieveModuleProxy(gGw2, \"gw3\");\n\t\tTEST_ASSERT(gw3_2Prox != NULL);\n\t\tTEST_ASSERT(gw3_2Prox->getModuleDistance() == 1);\n\t\tgw3_3Prox = retrieveModuleProxy(gGw3, \"gw3\");\n\t\tTEST_ASSERT(gw3_3Prox != NULL);\n\t\tTEST_ASSERT(gw3_3Prox->getModuleDistance() == 0);\n\t\tgw3_4Prox = retrieveModuleProxy(gGw4, \"gw3\");\n\t\tTEST_ASSERT(gw3_4Prox != NULL);\n\t\tTEST_ASSERT(gw3_4Prox->getModuleDistance() == 1);\n\n\t\tgw4_1Prox = retrieveModuleProxy(gGw1, \"gw4\");\n\t\tTEST_ASSERT(gw4_1Prox != NULL);\n\t\tTEST_ASSERT(gw4_1Prox->getModuleDistance() == 3);\n\t\tgw4_2Prox = retrieveModuleProxy(gGw2, \"gw4\");\n\t\tTEST_ASSERT(gw4_2Prox != NULL);\n\t\tTEST_ASSERT(gw4_2Prox->getModuleDistance() == 2);\n\t\tgw4_3Prox = retrieveModuleProxy(gGw3, \"gw4\");\n\t\tTEST_ASSERT(gw4_3Prox != NULL);\n\t\tTEST_ASSERT(gw4_3Prox->getModuleDistance() == 1);\n\t\tgw4_4Prox = retrieveModuleProxy(gGw4, \"gw4\");\n\t\tTEST_ASSERT(gw4_4Prox != NULL);\n\t\tTEST_ASSERT(gw4_4Prox->getModuleDistance() == 0);\n\n\t\t// make a double connection from gw1 to gw2\n\t\tcmd = \"gw1.transportCmd l3c(connect addr=localhost:8062)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check module list\n\t\tproxList.clear();\n\t\tgGw1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw3->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tproxList.clear();\n\t\tgGw4->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\n\t\t// check the distances\n\t\tgw1_1Prox = retrieveModuleProxy(gGw1, \"gw1\");\n\t\tTEST_ASSERT(gw1_1Prox != NULL);\n\t\tTEST_ASSERT(gw1_1Prox->getModuleDistance() == 0);\n\t\tgw1_2Prox = retrieveModuleProxy(gGw2, \"gw1\");\n\t\tTEST_ASSERT(gw1_2Prox != NULL);\n\t\tTEST_ASSERT(gw1_2Prox->getModuleDistance() == 1);\n\t\tgw1_3Prox = retrieveModuleProxy(gGw3, \"gw1\");\n\t\tTEST_ASSERT(gw1_3Prox != NULL);\n\t\tTEST_ASSERT(gw1_3Prox->getModuleDistance() == 2);\n\t\tgw1_4Prox = retrieveModuleProxy(gGw4, \"gw1\");\n\t\tTEST_ASSERT(gw1_4Prox != NULL);\n\t\tTEST_ASSERT(gw1_4Prox->getModuleDistance() == 3);\n\n\t\tgw2_1Prox = retrieveModuleProxy(gGw1, \"gw2\");\n\t\tTEST_ASSERT(gw2_1Prox != NULL);\n\t\tTEST_ASSERT(gw2_1Prox->getModuleDistance() == 1);\n\t\tgw2_2Prox = retrieveModuleProxy(gGw2, \"gw2\");\n\t\tTEST_ASSERT(gw2_2Prox != NULL);\n\t\tTEST_ASSERT(gw2_2Prox->getModuleDistance() == 0);\n\t\tgw2_3Prox = retrieveModuleProxy(gGw3, \"gw2\");\n\t\tTEST_ASSERT(gw2_3Prox != NULL);\n\t\tTEST_ASSERT(gw2_3Prox->getModuleDistance() == 1);\n\t\tgw2_4Prox = retrieveModuleProxy(gGw4, \"gw2\");\n\t\tTEST_ASSERT(gw2_4Prox != NULL);\n\t\tTEST_ASSERT(gw2_4Prox->getModuleDistance() == 2);\n\n\t\tgw3_1Prox = retrieveModuleProxy(gGw1, \"gw3\");\n\t\tTEST_ASSERT(gw3_1Prox != NULL);\n\t\tTEST_ASSERT(gw3_1Prox->getModuleDistance() == 2);\n\t\tgw3_2Prox = retrieveModuleProxy(gGw2, \"gw3\");\n\t\tTEST_ASSERT(gw3_2Prox != NULL);\n\t\tTEST_ASSERT(gw3_2Prox->getModuleDistance() == 1);\n\t\tgw3_3Prox = retrieveModuleProxy(gGw3, \"gw3\");\n\t\tTEST_ASSERT(gw3_3Prox != NULL);\n\t\tTEST_ASSERT(gw3_3Prox->getModuleDistance() == 0);\n\t\tgw3_4Prox = retrieveModuleProxy(gGw4, \"gw3\");\n\t\tTEST_ASSERT(gw3_4Prox != NULL);\n\t\tTEST_ASSERT(gw3_4Prox->getModuleDistance() == 1);\n\n\t\tgw4_1Prox = retrieveModuleProxy(gGw1, \"gw4\");\n\t\tTEST_ASSERT(gw4_1Prox != NULL);\n\t\tTEST_ASSERT(gw4_1Prox->getModuleDistance() == 3);\n\t\tgw4_2Prox = retrieveModuleProxy(gGw2, \"gw4\");\n\t\tTEST_ASSERT(gw4_2Prox != NULL);\n\t\tTEST_ASSERT(gw4_2Prox->getModuleDistance() == 2);\n\t\tgw4_3Prox = retrieveModuleProxy(gGw3, \"gw4\");\n\t\tTEST_ASSERT(gw4_3Prox != NULL);\n\t\tTEST_ASSERT(gw4_3Prox->getModuleDistance() == 1);\n\t\tgw4_4Prox = retrieveModuleProxy(gGw4, \"gw4\");\n\t\tTEST_ASSERT(gw4_4Prox != NULL);\n\t\tTEST_ASSERT(gw4_4Prox->getModuleDistance() == 0);\n\n\t\t// release modules\n\t\tmm.deleteModule(gw1);\n\t\tmm.deleteModule(gw2);\n\t\tmm.deleteModule(gw3);\n\t\tmm.deleteModule(gw4);\n\t}\n\n\tvoid firewalling()\n\t{\n\t\t// check that, with firewall mode enabled, unsafe root can only see protected\n\t\t// modules if they initiate the dialog first (i.e only a protected module can send\n\t\t// a message to an unsafe module).\n\t\t//\n\t\t// for this test, we have the following context :\n\t\t// 'master' : a gateway that accesses connection on two transports, one 'firewalled', the other one normal\n\t\t// 'peer1' : gateway connected to gateway 'master' on a firewalled transport\n\t\t// 'peer2' : gateway connected to gateway 'master' on a firewalled transport\n\t\t// 'other' : gateway connected to gateway 'master' on a classic transport\n\t\t//\n\t\t//\tpeer1 (l3c)-----\\\n\t\t//\t\t\t         >-|<- (l3s1/Firewalled) master (l3s2) ----- (l3c) other\n\t\t//\tpeer2 (l3c)-----/\n\t\t//\n\t\t//  'peer1' and 'peer2' must not see any module except modules that try to communicate with them\n\t\t//\t'master' and 'other' must see 'peer1', 'peer2', 'master' and 'other'\n\t\t//\n\t\t//\tSwitching OFF the firewall should disclose all modules,\n\t\t//\tswitching ON then must throw an exception\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *peer1, *peer2, *master, *other;\n\n\t\t// create the modules\n\t\tpeer1 = mm.createModule(\"StandardGateway\", \"peer1\", \"\");\n\t\tpeer2 = mm.createModule(\"StandardGateway\", \"peer2\", \"\");\n\t\tmaster = mm.createModule(\"StandardGateway\", \"master\", \"\");\n\t\tother = mm.createModule(\"StandardGateway\", \"other\", \"\");\n\n\t\tTEST_ASSERT(peer1 != NULL);\n\t\tTEST_ASSERT(peer2 != NULL);\n\t\tTEST_ASSERT(master != NULL);\n\t\tTEST_ASSERT(other != NULL);\n\n\t\t// plug gateway in themselves\n\t\tNLNET::IModuleSocket *sPeer1, *sPeer2, *sMaster, *sOther;\n\t\tsPeer1 = mm.getModuleSocket(\"peer1\");\n\t\tsPeer2 = mm.getModuleSocket(\"peer2\");\n\t\tsMaster = mm.getModuleSocket(\"master\");\n\t\tsOther = mm.getModuleSocket(\"other\");\n\n\t\tTEST_ASSERT(sPeer1 != NULL);\n\t\tTEST_ASSERT(sPeer2 != NULL);\n\t\tTEST_ASSERT(sMaster != NULL);\n\t\tTEST_ASSERT(sOther != NULL);\n\n\t\tpeer1->plugModule(sPeer1);\n\t\tpeer2->plugModule(sPeer2);\n\t\tmaster->plugModule(sMaster);\n\t\tother->plugModule(sOther);\n\n\t\tstring cmd;\n\t\t// create the transports\n\t\tcmd = \"peer1.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer2.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportAdd L3Server l3s1\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportAdd L3Server l3s2\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"other.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// Set option and connect transport\n\t\tcmd = \"master.transportOptions l3s1(Firewalled)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportCmd l3s1(open port=8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportCmd l3s2(open port=8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer1.transportCmd l3c(connect addr=localhost:8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer2.transportCmd l3c(connect addr=localhost:8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"other.transportCmd l3c(connect addr=localhost:8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// d'ho ! all done, now let's run some loop of update\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// ok, now, check that each gateway only knows the gateway it must know\n\t\tNLNET::IModuleGateway *gPeer1, *gPeer2, *gMaster, *gOther;\n\t\tgPeer1 = dynamic_cast<NLNET::IModuleGateway *>(peer1);\n\t\tTEST_ASSERT(gPeer1 != NULL);\n\t\tgPeer2 = dynamic_cast<NLNET::IModuleGateway *>(peer2);\n\t\tTEST_ASSERT(gPeer2 != NULL);\n\t\tgMaster = dynamic_cast<NLNET::IModuleGateway *>(master);\n\t\tTEST_ASSERT(gMaster != NULL);\n\t\tgOther = dynamic_cast<NLNET::IModuleGateway *>(other);\n\t\tTEST_ASSERT(gOther != NULL);\n\n\t\tvector<NLNET::IModuleProxy*> proxList;\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 1);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 1);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\t\n\t\t// now send the debug 'PING' message from 'other' to 'peer1', and a message from 'master' to 'peer2'\n\t\t{\n\t\t\tNLNET::CMessage ping(\"DEBUG_MOD_PING\");\n\n\t\t\t// retrieve peer1 proxy from other\n\t\t\tNLNET::IModuleProxy *peer1Prox = retrieveModuleProxy(gMaster, \"peer1\");\n\t\t\tTEST_ASSERT(peer1Prox != NULL);\n\t\t\tpeer1Prox->sendModuleMessage(master, ping);\n\t\t}\n\t\t{\n\t\t\tNLNET::CMessage ping(\"DEBUG_MOD_PING\");\n\n\t\t\t// retrieve peer1 proxy from other\n\t\t\tNLNET::IModuleProxy *peer2Prox = retrieveModuleProxy(gOther, \"peer2\");\n\t\t\tTEST_ASSERT(peer2Prox != NULL);\n\t\t\tpeer2Prox->sendModuleMessage(other, ping);\n\t\t}\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check new proxy table and ping counter\n\t\tTEST_ASSERT(gPeer1->getReceivedPingCount() == 1);\n\t\tproxList.clear();\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\n\t\tTEST_ASSERT(gPeer2->getReceivedPingCount() == 1);\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\t// now, remove firewall mode\n\t\tcmd = \"master.transportOptions l3s1()\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check new proxy table and ping counter\n\t\tproxList.clear();\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tTEST_ASSERT(gPeer2->getReceivedPingCount() == 1);\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\t// no try reactivate firewall mode with active route\n\t\tcmd = \"master.transportOptions l3s1(Firewalled)\";\n\t\tTEST_THROWS(cr.execute(cmd, NLMISC::InfoLog()), NLNET::IModuleGateway::EGatewayFirewallBreak);\n\n\n\t\t// cleanup\n\t\tmm.deleteModule(peer1);\n\t\tmm.deleteModule(peer2);\n\t\tmm.deleteModule(master);\n\t\tmm.deleteModule(other);\n\n\t}\n\n\tvoid peerInvisible()\n\t{\n\t\t// check that, with peer invisible enable, the peer modules are effectively invisible,\n\t\t// and, also, check that other modules, on other route are visible.\n\t\t// for this test, we have the following context :\n\t\t// 'master' : a gateway that acces connection on to transport, on 'peer invisible', the other normal\n\t\t// 'peer1' : gateway connected to gateway 'master' on a peer invisible transport\n\t\t// 'peer2' : gateway connected to gateway 'master' on a peer invisible transport\n\t\t// 'other' : gateway connected to gateway 'master' on a classic transport\n\t\t//\n\t\t//\tpeer1 (l3c)-----\\\n\t\t//\t\t\t         >-- (l3s1/PeerInvisible) master (l3s2) ----- (l3c) other\n\t\t//\tpeer2 (l3c)-----/\n\t\t//\n\t\t//  'peer1' must see 'master' and 'other'\n\t\t//\t'peer2' must see 'master' and 'other'\n\t\t//\t'master' must see 'peer1', 'peer2' and 'other'\n\t\t//\t'other' must see 'peer1', 'peer2' and 'master'\n\t\t//\n\t\t//\tWhen switching the PeerInvisible option to OFF, peer1 and peer2 must see each other\n\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *peer1, *peer2, *master, *other;\n\n\t\t// create the modules\n\t\tpeer1 = mm.createModule(\"StandardGateway\", \"peer1\", \"\");\n\t\tpeer2 = mm.createModule(\"StandardGateway\", \"peer2\", \"\");\n\t\tmaster = mm.createModule(\"StandardGateway\", \"master\", \"\");\n\t\tother = mm.createModule(\"StandardGateway\", \"other\", \"\");\n\n\t\tTEST_ASSERT(peer1 != NULL);\n\t\tTEST_ASSERT(peer2 != NULL);\n\t\tTEST_ASSERT(master != NULL);\n\t\tTEST_ASSERT(other != NULL);\n\n\t\t// plug gateway in themselves\n\t\tNLNET::IModuleSocket *sPeer1, *sPeer2, *sMaster, *sOther;\n\t\tsPeer1 = mm.getModuleSocket(\"peer1\");\n\t\tsPeer2 = mm.getModuleSocket(\"peer2\");\n\t\tsMaster = mm.getModuleSocket(\"master\");\n\t\tsOther = mm.getModuleSocket(\"other\");\n\n\t\tTEST_ASSERT(sPeer1 != NULL);\n\t\tTEST_ASSERT(sPeer2 != NULL);\n\t\tTEST_ASSERT(sMaster != NULL);\n\t\tTEST_ASSERT(sOther != NULL);\n\n\t\tpeer1->plugModule(sPeer1);\n\t\tpeer2->plugModule(sPeer2);\n\t\tmaster->plugModule(sMaster);\n\t\tother->plugModule(sOther);\n\n\t\tstring cmd;\n\t\t// create the transports\n\t\tcmd = \"peer1.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer2.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportAdd L3Server l3s1\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportAdd L3Server l3s2\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"other.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// Set option and connect transport\n\t\tcmd = \"master.transportOptions l3s1(PeerInvisible)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportCmd l3s1(open port=8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"master.transportCmd l3s2(open port=8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer1.transportCmd l3c(connect addr=localhost:8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"peer2.transportCmd l3c(connect addr=localhost:8060)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"other.transportCmd l3c(connect addr=localhost:8061)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// d'ho ! all done, now let's run some loop of update\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// ok, now, check that each gateway only knows the gateway it must know\n\t\tNLNET::IModuleGateway *gPeer1, *gPeer2, *gMaster, *gOther;\n\t\tgPeer1 = dynamic_cast<NLNET::IModuleGateway *>(peer1);\n\t\tTEST_ASSERT(gPeer1 != NULL);\n\t\tgPeer2 = dynamic_cast<NLNET::IModuleGateway *>(peer2);\n\t\tTEST_ASSERT(gPeer2 != NULL);\n\t\tgMaster = dynamic_cast<NLNET::IModuleGateway *>(master);\n\t\tTEST_ASSERT(gMaster != NULL);\n\t\tgOther = dynamic_cast<NLNET::IModuleGateway *>(other);\n\t\tTEST_ASSERT(gOther != NULL);\n\n\t\tvector<NLNET::IModuleProxy*> proxList;\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 3);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 3);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\t// now, remove the 'PeerInvisible' options\n\t\tcmd = \"master.transportOptions l3s1()\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check new proxy table\n\t\tproxList.clear();\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\n\t\t// now, re set the 'PeerInvisible' options\n\t\tcmd = \"master.transportOptions l3s1(PeerInvisible)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the network\n\t\tfor (uint i=0; i<7; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check new proxy table\n\t\tproxList.clear();\n\t\tgPeer1->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 3);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgPeer2->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 3);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgMaster->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\n\t\tproxList.clear();\n\t\tgOther->getModuleProxyList(proxList);\n\t\tTEST_ASSERT(proxList.size() == 4);\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"other\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"master\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer1\"));\n\t\tTEST_ASSERT(lookForModuleProxy(proxList, \"peer2\"));\n\t\t// cleanup\n\t\tmm.deleteModule(peer1);\n\t\tmm.deleteModule(peer2);\n\t\tmm.deleteModule(master);\n\t\tmm.deleteModule(other);\n\n\t}\n\n\tvoid gwPlugUnplug()\n\t{\n\t\t// check that multiple plug/unplug operations work well\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *mod = mm.createModule(\"StandardGateway\", \"gw\", \"\");\n\t\tTEST_ASSERT(mod != NULL);\n\n\t\tNLNET::IModuleSocket *socket = mm.getModuleSocket(\"gw\");\n\t\tTEST_ASSERT(socket != NULL);\n\t\tmod->plugModule(socket);\n\t\tmod->unplugModule(socket);\n\t\tmod->plugModule(socket);\n\t\tmod->unplugModule(socket);\n\t\tmod->plugModule(socket);\n\n\t\tstd::vector<NLNET::IModuleProxy*> result;\n\t\tsocket->getModuleList(result);\n\t\tTEST_ASSERT(result.size() == 1);\n\n\t\tmod->unplugModule(socket);\n\n\t\tmm.deleteModule(mod);\n\t}\n\n\tvoid uniqueNameGenerator()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tmm.setUniqueNameRoot(\"foo\");\n\n\t\t// create a simple module\n\t\tNLNET::IModule *mod = mm.createModule(\"ModuleType0\", \"mod\", \"\");\n\t\tTEST_ASSERT(mod != NULL);\n\t\tTEST_ASSERT(mod->getModuleFullyQualifiedName() == \"foo:mod\");\n\t\tmm.deleteModule(mod);\n\n\t\t// reset the unique name to normal value\n\t\tmm.setUniqueNameRoot(string());\n\n\t\tmod = mm.createModule(\"ModuleType0\", \"mod\", \"\");\n\t\tTEST_ASSERT(mod != NULL);\n\t\tTEST_ASSERT(mod->getModuleFullyQualifiedName() != \"foo:mod\");\n\n\t\tmm.deleteModule(mod);\n\t}\n\n\tvoid localMessageQueing()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *mods = mm.createModule(\"StandardGateway\", \"gws\", \"\");\n\t\tTEST_ASSERT(mods != NULL);\n\t\tNLNET::IModuleGateway *gws = dynamic_cast<NLNET::IModuleGateway*>(mods);\n\t\tTEST_ASSERT(gws != NULL);\n\n\t\t// get the socket interface of the gateway\n\t\tNLNET::IModuleSocket *socketGws = mm.getModuleSocket(\"gws\");\n\t\tTEST_ASSERT(socketGws != NULL);\n\n\t\t// create two modules that will communicate localy\n\t\tNLNET::IModule *m1= mm.createModule(\"ModuleType0\", \"m1\", \"\");\n\t\tTEST_ASSERT(m1!= NULL);\n\t\tNLNET::IModule *m2= mm.createModule(\"ModuleAsync\", \"m2\", \"\");\n\t\tTEST_ASSERT(m2!= NULL);\n\n\t\tm1->plugModule(socketGws);\n\t\tm2->plugModule(socketGws);\n\n\t\t// update the networks\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(50);\n\t\t}\n\n\t\t// retrieve module proxy and send one ping to each other\n\t\tvector<NLNET::IModuleProxy*>\tproxiesC;\n\t\tgws->getModuleProxyList(proxiesC);\n\t\tTEST_ASSERT(proxiesC.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxiesC, \"m2\"));\n\t\tNLNET::IModuleProxy *pm2 = retrieveModuleProxy(gws, \"m2\");\n\t\tTEST_ASSERT(pm2 != NULL);\n\t\tNLNET::CMessage aMessage(\"DEBUG_MOD_PING\");\n\t\tpm2->sendModuleMessage(m1, aMessage);\n\n\t\tproxiesC.clear();\n\t\tgws->getModuleProxyList(proxiesC);\n\t\tTEST_ASSERT(proxiesC.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxiesC, \"m1\"));\n\t\tNLNET::IModuleProxy *pm1 = retrieveModuleProxy(gws, \"m1\");\n\t\tTEST_ASSERT(pm1 != NULL);\n\t\taMessage = NLNET::CMessage(\"DEBUG_MOD_PING\");\n\t\tpm1->sendModuleMessage(m2, aMessage);\n\n\t\t// check received ping count\n\t\tCModuleType0 *mod1 = dynamic_cast<CModuleType0*>(m1);\n\t\tTEST_ASSERT(mod1 != NULL);\n\t\tTEST_ASSERT(mod1->PingCount == 1);\n\t\tCModuleType0 *mod2 = dynamic_cast<CModuleType0*>(m2);\n\t\tTEST_ASSERT(mod2 != NULL);\n\t\tTEST_ASSERT(mod2->PingCount == 0);\n\t\n\t\t// update the networks\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(50);\n\t\t}\n\n\t\t// check received ping count\n\t\tTEST_ASSERT(mod1->PingCount == 1);\n\t\tTEST_ASSERT(mod2->PingCount == 1);\n\n\t\t// update the networks\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(50);\n\t\t}\n\n\t\t// check received ping count\n\t\tTEST_ASSERT(mod1->PingCount == 1);\n\t\tTEST_ASSERT(mod2->PingCount == 1);\n\n\n\t\t// cleanup\n\t\tmm.deleteModule(m1);\n\t\tmm.deleteModule(m2);\n\t\tmm.deleteModule(mods);\n\t}\n\n\tvoid moduleMessaging()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\t// create two gateway an connect them, plug the gateway on themselves and send a message\n\t\tNLNET::IModule *mods = mm.createModule(\"StandardGateway\", \"gws\", \"\");\n\t\tTEST_ASSERT(mods != NULL);\n\t\tNLNET::IModuleGateway *gws = dynamic_cast<NLNET::IModuleGateway*>(mods);\n\t\tTEST_ASSERT(gws != NULL);\n\n\t\t// plug the module in itself before opening connection\n\t\tNLNET::IModuleSocket *socketGws = mm.getModuleSocket(\"gws\");\n\t\tTEST_ASSERT(socketGws != NULL);\n\t\tmods->plugModule(socketGws);\n\n\t\t// add transport for server mode\n\t\tstring cmd = \"gws.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gws.transportCmd l3s(open port=6185)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\tNLNET::IModule *modc = mm.createModule(\"StandardGateway\", \"gwc\", \"\");\n\t\tTEST_ASSERT(modc != NULL);\n\t\tNLNET::IModuleGateway *gwc = dynamic_cast<NLNET::IModuleGateway*>(modc);\n\t\tTEST_ASSERT(gwc != NULL);\n\t\t// add transport for client mode\n\t\tcmd = \"gwc.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// plug the module in itself before opening connection\n\t\tNLNET::IModuleSocket *socketGwc = mm.getModuleSocket(\"gwc\");\n\t\tTEST_ASSERT(socketGwc != NULL);\n\t\tmodc->plugModule(socketGwc);\n\n\t\t// update the gateways...\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// send a message from gws to gwc using the proxy\n\t\t// First, get the proxy for the client (must be the second one)\n\t\tvector<NLNET::IModuleProxy*>\tproxiesS;\n\t\tgws->getModuleProxyList(proxiesS);\n\t\tTEST_ASSERT(proxiesS.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxiesS, \"gwc\"));\n\t\tNLNET::CMessage aMessage(\"DEBUG_MOD_PING\");\n\t\tproxiesS[1]->sendModuleMessage(mods, aMessage);\n\n\t\t// update the gateways...\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// check that the ping has been received\n\t\tTEST_ASSERT(gwc->getReceivedPingCount() == 1);\n\n\t\t// send two crossing messages simultaneously\n\t\tvector<NLNET::IModuleProxy*>\tproxiesC;\n\t\tgwc->getModuleProxyList(proxiesC);\n\t\tTEST_ASSERT(proxiesC.size() == 2);\n\t\tTEST_ASSERT(lookForModuleProxy(proxiesC, \"gws\"));\n\t\tproxiesS[1]->sendModuleMessage(mods, aMessage);\n\t\tproxiesC[1]->sendModuleMessage(modc, aMessage);\n\n\t\t// update the gateways...\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\t\t// check that the ping has been received\n\t\tTEST_ASSERT(gwc->getReceivedPingCount() == 2);\n\t\tTEST_ASSERT(gws->getReceivedPingCount() == 1);\n\t\t\n\n\t\t// send with ISocket\n\t\tsocketGws->sendModuleMessage(mods, proxiesS[1]->getModuleProxyId(), aMessage);\n\t\t// update the gateways...\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\t\t// check that the ping has been received\n\t\tTEST_ASSERT(gwc->getReceivedPingCount() == 3);\n\t\tTEST_ASSERT(gws->getReceivedPingCount() == 1);\n\n\t\t// cleanup modules\n\t\tmm.deleteModule(mods);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gws\") == NULL);\n\t\tmm.deleteModule(modc);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gwc\") == NULL);\n\t}\n\n\tvoid moduleDisclosure()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\t\tNLMISC::CCommandRegistry &cr = NLMISC::CCommandRegistry::getInstance();\n\n\t\tNLNET::IModule *mods = mm.createModule(\"StandardGateway\", \"gws\", \"\");\n\t\tTEST_ASSERT(mods != NULL);\n\t\tNLNET::IModuleGateway *gws = dynamic_cast<NLNET::IModuleGateway*>(mods);\n\t\tTEST_ASSERT(gws != NULL);\n\n\t\tTEST_ASSERT(gws->getProxyCount() == 0);\n\n\t\t// plug the module in itself before opening connection\n\t\tNLNET::IModuleSocket *socketGws = mm.getModuleSocket(\"gws\");\n\t\tTEST_ASSERT(socketGws != NULL);\n\t\tmods->plugModule(socketGws);\n\n\t\t// now, there must be one proxy in the gateway\n\t\tTEST_ASSERT(gws->getProxyCount() == 1);\n\t\tvector<NLNET::IModuleProxy*>\tproxies;\n\t\tgws->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 1);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() == NULL);\n\t\tTEST_ASSERT(proxies[0]->getForeignModuleId() == mods->getModuleId());\n\n\t\t// add transport for server mode\n\t\tstring cmd = \"gws.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gws.transportCmd l3s(open port=6185)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\tNLNET::IModule *modc = mm.createModule(\"StandardGateway\", \"gwc\", \"\");\n\t\tTEST_ASSERT(modc != NULL);\n\t\tNLNET::IModuleGateway *gwc = dynamic_cast<NLNET::IModuleGateway*>(modc);\n\t\tTEST_ASSERT(gwc != NULL);\n\t\t// add transport for client mode\n\t\tcmd = \"gwc.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\tfor (uint i=0; i<5; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// The server must have not changed\n\t\tTEST_ASSERT(gws->getProxyCount() == 1);\n\n\t\t// The client must have one proxy\n\t\tTEST_ASSERT(gwc->getProxyCount() == 1);\n\t\tproxies.clear();\n\t\tgwc->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 1);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() != NULL);\n\t\tTEST_ASSERT(proxies[0]->getModuleName().find(\"gws\") == proxies[0]->getModuleName().size() - 3);\n\n\t\t// plug the client module in itself after opening connection\n\t\tNLNET::IModuleSocket *socketGwc = mm.getModuleSocket(\"gwc\");\n\t\tTEST_ASSERT(socketGwc != NULL);\n\t\tmodc->plugModule(socketGwc);\n\n\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// The server must have now the two modules\n\t\tTEST_ASSERT(gws->getProxyCount() == 2);\n\t\tproxies.clear();\n\t\tgws->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 2);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() == NULL);\n\t\tTEST_ASSERT(proxies[0]->getForeignModuleId() == mods->getModuleId());\n\t\tTEST_ASSERT(proxies[1]->getGatewayRoute() != NULL);\n\t\tTEST_ASSERT(proxies[1]->getModuleName().find(\"gwc\") == proxies[1]->getModuleName().size() - 3);\n\n\t\t// The client must have two module also\n\t\tTEST_ASSERT(gwc->getProxyCount() == 2);\n\t\tproxies.clear();\n\t\tgwc->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 2);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() != NULL);\n\t\tTEST_ASSERT(proxies[0]->getModuleName().find(\"gws\") == proxies[1]->getModuleName().size() - 3);\n\t\tTEST_ASSERT(proxies[1]->getGatewayRoute() == NULL);\n\t\tTEST_ASSERT(proxies[1]->getForeignModuleId() == modc->getModuleId());\n\n\n\t\t// unplug the client module in itself after opening connection\n\t\tmods->unplugModule(socketGws);\n\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tNLMISC::nlSleep(100);\n\t\t\tmm.updateModules();\n\t\t}\n\n\t\t// The server must have one module left\n\t\tTEST_ASSERT(gws->getProxyCount() == 1);\n\t\tproxies.clear();\n\t\tgws->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 1);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() != NULL);\n\t\tTEST_ASSERT(proxies[0]->getModuleName().find(\"gwc\") == proxies[0]->getModuleName().size() - 3);\n\n\t\t// The client must have one module left\n\t\tTEST_ASSERT(gwc->getProxyCount() == 1);\n\t\tproxies.clear();\n\t\tgwc->getModuleProxyList(proxies);\n\t\tTEST_ASSERT(proxies.size() == 1);\n\t\tTEST_ASSERT(proxies[0]->getGatewayRoute() == NULL);\n\t\tTEST_ASSERT(proxies[0]->getForeignModuleId() == modc->getModuleId());\n\t\t\n\t\t// Dump the module state\n\t\tcmd = \"gws.dump\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc.dump\";\n\t\tTEST_ASSERT(cr.execute(cmd, NLMISC::InfoLog()));\n\n\t\t// cleanup modules\n\t\tmm.deleteModule(mods);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gws\") == NULL);\n\t\tmm.deleteModule(modc);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gwc\") == NULL);\n\t}\n\n\tvoid connectGateways()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\tNLNET::IModule *mods = mm.createModule(\"StandardGateway\", \"gws\", \"\");\n\t\tTEST_ASSERT(mods != NULL);\n\t\tNLNET::IModuleGateway *gws = dynamic_cast<NLNET::IModuleGateway*>(mods);\n\t\tTEST_ASSERT(gws != NULL);\n\t\t// add transport for server mode\n\t\tstring cmd = \"gws.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gws.transportCmd l3s(open port=6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\t\t\n\t\tNLNET::IModule *modc1 = mm.createModule(\"StandardGateway\", \"gwc1\", \"\");\n\t\tTEST_ASSERT(modc1 != NULL);\n\t\tNLNET::IModuleGateway *gwc1 = dynamic_cast<NLNET::IModuleGateway*>(modc1);\n\t\tTEST_ASSERT(gwc1 != NULL);\n\t\t// add transport for client mode\n\t\tcmd = \"gwc1.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc1.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\tTEST_ASSERT(gws->getRouteCount() == 1);\n\t\tTEST_ASSERT(gwc1->getRouteCount() == 1);\n\t\t\t\n\t\t// do a second connect to the server for stress\n\t\t// add transport for client mode\n\t\tcmd = \"gwc1.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// create third gateway\n\t\tNLNET::IModule *modc2 = mm.createModule(\"StandardGateway\", \"gwc2\", \"\");\n\t\tTEST_ASSERT(modc2 != NULL);\n\t\tNLNET::IModuleGateway *gwc2 = dynamic_cast<NLNET::IModuleGateway*>(modc2);\n\t\tTEST_ASSERT(gwc2 != NULL);\n\t\t// add transport for client mode\n\t\tcmd = \"gwc2.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc2.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the module to update the network callback client and server\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\t// give some time to the listen and receiver thread to do there jobs\n\t\t\tNLMISC::nlSleep(100);\n\t\t\tmm.updateModules();\n\t\t}\n\n\t\tTEST_ASSERT(gws->getRouteCount() == 3);\n\t\tTEST_ASSERT(gwc1->getRouteCount() == 2);\n\t\tTEST_ASSERT(gwc2->getRouteCount() == 1);\n\n\t\t// dump the gateways state\n\t\tcmd = \"gws.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc1.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gwc2.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// cleanup the modules\n\t\tmm.deleteModule(mods);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gws\") == NULL);\n\t\tmm.deleteModule(modc1);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gwc1\") == NULL);\n\t\tmm.deleteModule(modc2);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gwc2\") == NULL);\n\t}\n\n\tvoid gatewayTransportManagement()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\t// create a gateway module\n\t\tNLNET::IModule *mod = mm.createModule(\"StandardGateway\", \"gw\", \"\");\n\t\tTEST_ASSERT(mod != NULL);\n\t\tNLNET::IModuleGateway *gw = dynamic_cast<NLNET::IModuleGateway*>(mod);\n\t\tTEST_ASSERT(gw != NULL);\n\n\t\t// Create a layer 3 server transport\n\t\t// send a transport creation command\n\t\tstring cmd = \"gw.transportAdd L3Server l3s\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tNLNET::IGatewayTransport *transportL3s = gw->getGatewayTransport(\"l3s\");\n\t\tTEST_ASSERT(transportL3s != NULL);\n\n\t\t// send a transport command\n\t\tcmd = \"gw.transportCmd l3s(open port=6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// Create a layer 3 client transport\n\t\t// send a transport creation command\n\t\tcmd = \"gw.transportAdd L3Client l3c\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tNLNET::IGatewayTransport *transportL3c = gw->getGatewayTransport(\"l3c\");\n\t\tTEST_ASSERT(transportL3c != NULL);\n\n\t\t// send a transport command\n\t\tcmd = \"gw.transportCmd l3c(connect addr=localhost:6185)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the module to update the network callback client and server\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\t// give some time to the listen and receiver thread to do there jobs\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\tTEST_ASSERT(transportL3s->getRouteCount() == 1);\t\n\t\tTEST_ASSERT(transportL3c->getRouteCount() == 1);\n\t\tTEST_ASSERT(gw->getRouteCount() == 2);\n\t\t\n\t\t// dump the gateways state\n\t\tcmd = \"gw.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t\n\t\t// close all connections\n\t\tcmd = \"gw.transportCmd l3s(close)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\t\n\t\tcmd = \"gw.transportCmd l3c(close connId=0)\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// update the module to update the network callback client and server\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\t// give some time to the listen and receiver thread to do there jobs\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\tTEST_ASSERT(transportL3s->getRouteCount() == 0);\n\t\tTEST_ASSERT(transportL3c->getRouteCount() == 0);\n\t\tTEST_ASSERT(gw->getRouteCount() == 0);\n\n\t\t// Remove transports\n\t\tcmd = \"gw.transportRemove l3s\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t\tcmd = \"gw.transportRemove l3c\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\tTEST_ASSERT(gw->getGatewayTransport(\"l3c\") == NULL);\n\t\tTEST_ASSERT(gw->getGatewayTransport(\"l3s\") == NULL);\n\t\tTEST_ASSERT(gw->getTransportCount() == 0);\n\n\t\t// update the module to update the network callback client and server\n\t\tfor (uint i=0; i<4; ++i)\n\t\t{\n\t\t\t// give some time to the listen and receiver thread to do there jobs\n\t\t\tmm.updateModules();\n\t\t\tNLMISC::nlSleep(100);\n\t\t}\n\n\t\t// cleanup the modules\n\t\tmm.deleteModule(mod);\n\t\tTEST_ASSERT(mm.getLocalModule(\"gw\") == NULL);\n\t}\n\n/*\tvoid moduleManagerCommands()\n\t{\n\t\tstring cmd;\n\t\t// load a library\n\t\tcmd = \"moduleManager.loadLibrary net_module_lib_test/net_module_lib_test\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// dump the module state\n\t\tcmd = \"moduleManager.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// create a module\n\t\tcmd = \"moduleManager.createModule ModuleType1 AModuleName\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// dump the module state\n\t\tcmd = \"moduleManager.dump\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\n\t\t// delete the module\n\t\tcmd = \"moduleManager.deleteModule AModuleName\";\n\t\tTEST_ASSERT(NLMISC::CCommandRegistry::getInstance().execute(cmd, NLMISC::InfoLog()));\n\t}*/\n\n\tvoid plugLocalGateway()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\tNLNET::IModule *gateway1 = mm.createModule(\"LocalGateway\", \"g1\", \"\");\n\t\tTEST_ASSERT(gateway1 != NULL);\n\t\tNLNET::IModule *gateway2 = mm.createModule(\"LocalGateway\", \"g2\", \"\");\n\t\tTEST_ASSERT(gateway2 != NULL);\n\n\t\tNLNET::IModuleSocket *socket1 = mm.getModuleSocket(\"g1\");\n\t\tTEST_ASSERT(socket1 != NULL);\n\t\tNLNET::IModuleSocket *socket2 = mm.getModuleSocket(\"g2\");\n\t\tTEST_ASSERT(socket2 != NULL);\n\t\tgateway1->plugModule(socket1);\n\t\tgateway1->plugModule(socket2);\n\t\tgateway2->plugModule(socket1);\n\t\tgateway2->plugModule(socket2);\n\n\t\tmm.deleteModule(gateway1);\n\t\tTEST_ASSERT(mm.getLocalModule(\"g1\") == NULL);\n\t\tmm.deleteModule(gateway2);\n\t\tTEST_ASSERT(mm.getLocalModule(\"g2\") == NULL);\n\t}\n\n\tvoid createLocalGateway()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\tNLNET::IModule *gateway = mm.createModule(\"LocalGateway\", \"localGateway\", \"\");\n\t\tTEST_ASSERT(gateway != NULL);\n\n\t\tNLNET::IModule *mod1 = mm.createModule(\"ModuleType0\", \"plugged1\", \"\");\n\t\tTEST_ASSERT(mod1 != NULL);\n\t\tNLNET::IModule *mod2 = mm.createModule(\"ModuleType0\", \"plugged2\", \"\");\n\t\tTEST_ASSERT(mod2 != NULL);\n\n\t\tNLNET::IModuleSocket *socket = mm.getModuleSocket(\"localGateway\");\n\t\tTEST_ASSERT(socket != NULL);\n\t\tmod1->plugModule(socket);\n\t\tmod2->plugModule(socket);\n\n\t\tmm.deleteModule(mod1);\n\t\tTEST_ASSERT(mm.getLocalModule(\"plugged1\") == NULL);\n\t\tmm.deleteModule(mod2);\n\t\tTEST_ASSERT(mm.getLocalModule(\"plugged2\") == NULL);\n\n\t\tmm.deleteModule(gateway);\n\t\tTEST_ASSERT(mm.getLocalModule(\"localGateway\") == NULL);\n\t}\n\n/*\tvoid unloadModuleLib()\n\t{\n\t\tIModuleManager &mm = IModuleManager::getInstance();\n\n\t\tCRefPtr<IModule> module1 = mm.createModule(\"ModuleType1\", \"TheModule2\", \"the args\");\n\t\tTEST_ASSERT(module1 != NULL);\n\n\t\tTEST_ASSERT(mm.unloadModuleLibrary(\"net_module_lib_test\"));\n\n\t\t// the module must have been deleted\n\t\tTEST_ASSERT(module1 == NULL);\n\n\t\tTModulePtr module2 = mm.createModule(\"ModuleType1\", \"TheModuleThatCantBeCreated\", \"the args\");\n\t\tTEST_ASSERT(module2 == NULL);\n\t}*/\n\n\tvoid failedInit()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\tNLNET::IModule *module = mm.createModule(\"ModuleType0\", \"FailingInit\", \"FAIL\");\n\t\tTEST_ASSERT(module == NULL);\n\t}\n\n/*\tvoid deleteModule()\n\t{\n\t\tIModuleManager &mm = IModuleManager::getInstance();\n\n\t\tIModule *module = mm.createModule(\"ModuleType1\", \"TheModuleToDelete\", \"the args\");\n\t\tTEST_ASSERT(module != NULL);\n\n\t\tCRefPtr<IModule> checkPtr(module);\n\n\t\tmm.deleteModule(module);\n\t\tTEST_ASSERT(checkPtr == NULL);\n\t}*/\n\n/*\tvoid createModule()\n\t{\n\t\tIModuleManager &mm = IModuleManager::getInstance();\n\n\t\tTModulePtr module = mm.createModule(\"ModuleType1\", \"TheModule\", \"the args\");\n\t\tTEST_ASSERT(module != NULL);\n\n\t\tTEST_ASSERT(module->getModuleClassName() == \"ModuleType1\");\n\t\tTEST_ASSERT(module->getModuleName() == \"TheModule\");\n\n\t\tstring lh;\n\t\tif (IService::isServiceInitialized())\n\t\t\tlh = IService::getInstance()->getHostName();\n\t\telse\n\t\t\tlh = ::NLNET::CInetAddress::localHost().hostName();\n\t\tstring fqmn = lh+\":\"+toString(getpid())+\":TheModule\";\n\n\t\tTEST_ASSERT(module->getModuleFullyQualifiedName() == fqmn);\n\t}*/\n\n/*\tvoid loadModuleLib()\n\t{\n\t\tstring moduleLibName = \"net_module_lib_test/net_module_lib_test\";\n\n\t\tIModuleManager &mm = IModuleManager::getInstance();\n\t\tTEST_ASSERT(mm.loadModuleLibrary(moduleLibName));\n\n\t\tvector<string>\tmoduleList;\n\t\tmm.getAvailableModuleClassList(moduleList);\n\n\t\tTEST_ASSERT(moduleList.size() == 6);\n\t\tTEST_ASSERT(moduleList[0] == \"LocalGateway\");\n\t\tTEST_ASSERT(moduleList[1] == \"ModuleAsync\");\n\t\tTEST_ASSERT(moduleList[2] == \"ModuleType0\");\n\t\tTEST_ASSERT(moduleList[3] == \"ModuleType1\");\n\t\tTEST_ASSERT(moduleList[4] == \"ModuleType2\");\n\t\tTEST_ASSERT(moduleList[5] == \"StandardGateway\");\n\t}*/\n\n\tvoid localModuleFactory()\n\t{\n\t\tNLNET::IModuleManager &mm = NLNET::IModuleManager::getInstance();\n\n\t\tvector<string>\tmoduleList;\n\t\tmm.getAvailableModuleClassList(moduleList);\n\n\t\tTEST_ASSERT(moduleList.size() == 4);\n\t\tTEST_ASSERT(moduleList[0] == \"LocalGateway\");\n\t\tTEST_ASSERT(moduleList[1] == \"ModuleAsync\");\n\t\tTEST_ASSERT(moduleList[2] == \"ModuleType0\");\n\t\tTEST_ASSERT(moduleList[3] == \"StandardGateway\");\n\t}\n\n\tvoid testModuleInitInfoBadParsing()\n\t{\n\t\tNLNET::TParsedCommandLine\tmif;\n\n\t\tstring\tparamString = \" a=1   b=2   ( b=1) \";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \" lswkd ,fpqoj(( cruq fzemfwijf ujr wmozejifp_zujf woijpc_u ' \";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \"a ( b=2\";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \"a  b=2)\";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \"a  b=2\\\"toto\\\"\";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \"=a\";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\n\t\tparamString = \"a(=b)\";\n\t\tTEST_ASSERT(!mif.parseParamList(paramString));\n\t}\n\n\tvoid testModuleInitInfoQuering()\n\t{\n\t\tNLNET::TParsedCommandLine\tmif;\n\n\t\tstring\tparamString = \" a=1   b=2   sub   ( y=22 zzzz=12 subsub (g=\\\"bean in box\\\" z=2) ) \"; \n\n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\n\t\tTEST_ASSERT(mif.getParam(\"a\") != NULL);\n\t\tTEST_ASSERT(mif.getParam(\"a\") == mif.SubParams[0]);\n\n\t\tTEST_ASSERT(mif.getParam(\"sub\") != NULL);\n\t\tTEST_ASSERT(mif.getParam(\"sub\") == mif.SubParams[2]);\n\n\t\tTEST_ASSERT(mif.getParam(\"foo\") == NULL);\n\n\t\tTEST_ASSERT(mif.getParam(\"sub.subsub.g\") != NULL);\n\t\tTEST_ASSERT(mif.getParam(\"sub.subsub.g\") == mif.SubParams[2]->SubParams[2]->SubParams[0]);\n\t}\n\n\tvoid testModuleInitInfoParsing()\n\t{\n\t\tNLNET::TParsedCommandLine\tmif;\n\n\t\tstring\tparamString = \"a\"; \n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\t\tparamString = \"a=1\"; \n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\t\tparamString = \"a(b=1)\"; \n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\t\tparamString = \"a a a a\"; \n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\t\tTEST_ASSERT(mif.SubParams.size() == 4);\n\t\tparamString = \" a ( b=1 )\"; \n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\n\t\tparamString = \" a=1   b=2   sub   ( y=22 zzzz=12 subsub (g=\\\"bean in box\\\" z=2) ) \"; \n\n\t\tTEST_ASSERT(mif.parseParamList(paramString));\n\n\t\tTEST_ASSERT(mif.SubParams.size() == 3);\n\n\t\tTEST_ASSERT(mif.SubParams[0]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[0]->ParamName == \"a\");\n\t\tTEST_ASSERT(mif.SubParams[0]->ParamValue == \"1\");\n\n\t\tTEST_ASSERT(mif.SubParams[1]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[1]->ParamName == \"b\");\n\t\tTEST_ASSERT(mif.SubParams[1]->ParamValue == \"2\");\n\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams.size() == 3);\n\t\tTEST_ASSERT(mif.SubParams[2]->ParamName == \"sub\");\n\t\tTEST_ASSERT(mif.SubParams[2]->ParamValue.empty());\n\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[0]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[0]->ParamName == \"y\");\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[0]->ParamValue == \"22\");\n\t\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[1]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[1]->ParamName == \"zzzz\");\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[1]->ParamValue == \"12\");\n\t\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams.size() == 2);\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->ParamName == \"subsub\");\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->ParamValue.empty());\n\t\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->ParamName == \"g\");\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[0]->ParamValue == \"bean in box\");\n\t\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->SubParams.size() == 0);\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->ParamName == \"z\");\n\t\tTEST_ASSERT(mif.SubParams[2]->SubParams[2]->SubParams[1]->ParamValue == \"2\");\n\t}\n};\n\n#endif\n"
  },
  {
    "path": "code/nelDashBuild.cmd",
    "content": "@echo off\n# Default the source directory to the current directory.\nset NEL_DIR=%CD%\nset BUILDTYPE=Experimental\n# Load the development environment. If you run MSVC2008 you may need to change this to VS90COMNTOOLS.\ncall \"%VS80COMNTOOLS%vsvars32.bat\"\n\nif \"%1\" == \"\" (\n  rem No arguments were specified. Print out usage information.\n  echo Usage: %0 <Continuous|Experimental|Nightly> [c:\\path\\to\\source]\n  exit /b\n)\nset BUILDTYPE=%1\n\nif not \"%2\" == \"\" (\nset NEL_DIR=%2\n)\n\n\n# Execute the build. If you run an Express version of MSVC you may need to change devenv to vcexpress.\ndevenv \"%NEL_DIR%\\build\\NeL.sln\" /build Debug /project %1%\n"
  },
  {
    "path": "code/nelDashBuild.sh",
    "content": "#!/bin/sh\n#\n# Usage: ./nelDashBuild.sh <Continuous|Experimental|Nightly> [/path/to/source]\n#\n# \n\n# Default the source directory to where this is run from.\nNEL_DIR=`pwd`\nBUILDTYPE=\"Continuous\"\n\n# Check to make sure we have at least one argument. Output usage.\nif [ $# -lt 1 ];\nthen\n  echo \"Usage: $0 <Continuous|Experimental|Nightly> [/path/to/source]\"\n  exit;\nelse\n  # Save the build type.\n  BUILDTYPE=$1\nfi\n\n# If we have more than one argument assume the 2nd argument is the source dir.\nif [ $# -gt 1 ];\nthen\n  NEL_DIR=$2\nfi\n\n# Change to the NeL source dir for this build.\nif [ -e $NEL_DIR/build ];\nthen\n  cd $NEL_DIR/build\nelse\n  echo \"$0: Failed to change to build dir: $NEL_DIR/build\"\n  exit;\nfi\n\n#this is due to a bug, the process extracts information from the svn output which needs to be in english\n#export LC_MESSAGES=en_GB\n\n# Start the build\nmake -j -l 2.0 $1\n\n"
  },
  {
    "path": "code/revision.h.in",
    "content": "#ifndef REVISION_H\n#define REVISION_H\n\n#cmakedefine REVISION \"${REVISION}\"\n#cmakedefine BUILD_DATE \"${BUILD_DATE}\"\n\n#endif\n"
  },
  {
    "path": "tools/protobuf/JS/README.md",
    "content": "\n1,安装 nodejs  命令行下\n\n2,安装淘宝cnpm 国外有很多库被墙，淘宝自己弄个了国内同步的\nnpm install -g cnpm --registry=https://registry.npm.taobao.org\n\n3,cnpm install protobufjs@6.8.4 -g\n\n4,cnpm install @egret/protobuf -g\n\n5,使用 protobuf_gen_js.bat 生成\n\n"
  },
  {
    "path": "tools/protobuf/JS/protobuf/protofile/hold",
    "content": ""
  },
  {
    "path": "tools/protobuf/JS/protobuf_gen_js.bat",
    "content": "del .\\protobuf\\protofile\\*.proto /f /a /q\ncopy ..\\*.proto .\\protobuf\\protofile\\\n\ncall pb-egret generate\n\ndel .\\protobuf\\protofile\\*.proto /f /a /q\npause\n\n"
  },
  {
    "path": "tools/protobuf/define_attrib.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nenum TAttribType\n{\n\tINVALID_ATTRIB                           =\t0;\n\n\tID\t=\t2001001\t;\n\tLEVEL_UP_EXP_INT\t=\t2001002\t;\n\tNAME_STRING\t=\t2001003\t;\n\tLIFE_INT\t=\t2001004\t;\n\tLIFE_CURR_INT\t=\t2001005\t;\n\n};\n\n\n\n\n\n"
  },
  {
    "path": "tools/protobuf/define_pro.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nenum TEvent\n{\n\tEventInvalid\t\t\t                = 0;  \t\t//  无效事件\n    EventPlayerUp\t                        = 2;  \t\t//  玩家升级\t \n\tEventCostMoney                          = 40; \t\t//  消费金钱\n\tEventLogin                              = 46;\t\t//  玩家登录\n};\n\n\n///  标识占据第几位   0-63\nenum TPlayerFlagBit\n{\n\tPLAYER_FLAG_TEST_0                      = 0;\t\t//\t玩家第一次做xx事的标识位\n\tPLAYER_FLAG_FIRST_CARD_ONE              = 1;\t\t//\t\n\tPLAYER_FLAG_FIRST_CARD_TEN              = 2;\t\t//\t\n\t\n};\n\nenum TErrorType\n{\n\tINVALID_TYPE                            = 0;\n\t\n\tACCOUNT_LOGGED                          = 1;\n\tSERVER_FULL                             = 2;\n\tSERVER_NOT_OPEN                         = 3;\n\tTEXT_SUCESS                             = 4;\n\tTEXT_FAIL                               = 5;\n\tPWD_ERROR                               = 6;\n\tPLAYER_ONLINE_TO_FES                    = 7;\n\tPLAYER_EXISTS                           = 8;\n\tPLAYER_RELOAD                           = 9;\n\tSUCESS                                  = 23;\n\tNO_AUTH_TYPE                            = 24;\n\tCONFIG_NOT_FOUND                        = 33;\t\t// 配置未找到\n\tNOT_ENOUGH_MONEY                        = 37;\t\t//\t金币不足\n\t\n\tPLAYER_BASE_ERROR                       = 128;\t\t//\t玩家基本数据不正确\n\t\n};\n\nenum TGender\n{\n\tMALE          = 0;\t//\t男性\n\tFEMALE        = 1;\t//\t女性\n};\n\n\n// 房间付费方式\nenum TGameConsumePay\n{\n\tTGC_GOLD \t= 0;\n\tTGC_SILVER\t= 1;\n}\n\n//房间付费机制\nenum TPaymentMechanism\n{\n    ROOM_OWNER_OPTION   = 0; // 房主;\n    AA_SYSTEM_OPTION    = 1; // AA制;\n    BIG_OWNER_OPTION    = 2; // 大赢家;\n\tVIP_TISSUE_OPTION   = 3; // 消耗高级牌友圈房卡;\n}\n\nenum TRoomCmdRecord\n{\n\tRC_ACTION_NULL \t\t\t\t\t= 0;        // 用户过牌;\n\tRC_ACTION_START_GAME\t\t\t= 1;\t\t// 游戏开始;      ( MsgRecordNodeList 中的 card_value[0] 为 会儿皮 )\n\tRC_ACTION_OPERATE_RESULT \t\t= 2;\t\t// 用户选择权限结果;\n\tRC_ACTION_SEND_CARD\t\t\t\t= 3;\t\t// 用户发牌;\n\tRC_ACTION_OUT_CARD\t\t\t\t= 4;\t\t// 用户出牌;\n\tRC_ACTION_SHOWDOWN_DIANPAO\t\t= 5;\t\t// 用户点炮胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card ) \n\tRC_ACTION_SHOWDOWN_ZIMO\t\t\t= 6;\t\t// 用户自摸胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN_QIANGGANGHU\t= 7;\t\t// 用户抢杠胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN_LIUJU\t\t= 8; \t\t// 用户流局胡牌;   有梦的情况( MsgRecordNodeList 中的 card_index 为 other_count、 card_value 为 other_card )\n\tRC_ACTION_SHOWDOWN\t\t\t\t= 9; \t\t// 进入结算\n\tRC_ACTION_CONTRACT\t\t\t\t= 10; \t\t// 户承包关系;  ( MsgRecordNodeList 中的 TarGetID 为承包id 、 ActionID为被承包id )\n\tRC_ACTION_SEND_FLOWER_CARD\t\t= 11; \t\t// 用户抓牌花牌;  ( MsgRecordNodeList 中的 card_index 为 flower_num )\n\tRC_ACTION_START_FLOWER_CARD\t\t= 12; \t\t// 用户手牌补花;  ( MsgRecordNodeList 中的 card_index 为 flower_num )\n\tRC_ACTION_OPERATE_CHOICE\t\t= 13; \t\t// 用户选择权限;\n\tRC_ACTION_MINGLOU\t\t\t\t= 14; \t\t// 用户明楼;\n\tRC_ACTION_SEND_HAND_CARD\t\t= 15; \t\t// 用户发送手牌;\n\tRC_ACTION_CATHECTIC\t\t\t\t= 16; \t\t// 用户下注;\n\tRC_ACTION_HUNYOU\t\t\t    = 17; \t\t// 用户混悠;\n\tRC_ACTION_TRUST_STATE\t\t\t= 18; \t\t// 用户托管状态;\n}\n\n\nenum TShowDownEvent\n{\n\tEVENT_XIAOHU \t\t\t\t= 1;\t// 小胡;\n\tEVENT_MEIHUI \t\t\t\t= 2;\t// 没会;\n\tEVENT_HUIGUIWEI\t\t\t\t= 3;\t// 会归位;\n\tEVENT_GANGKAIHUA\t\t\t= 4;\t// 杠开花;\n\tEVENT_TIANHU \t\t\t\t= 5;\t// 天胡;\n\tEVENT_DIHU \t\t\t\t\t= 6;\t// 地胡;\n\tEVENT_SIGEHUI\t\t\t\t= 7;\t// 四个会;\n\tEVENT_QIDUI \t\t\t\t= 8;\t// 七对;\n\tEVENT_QINGQIDUI\t\t\t\t= 9;\t// 清七对;\n\tEVENT_HAOHUAQIDUI\t\t\t= 10;\t// 豪华七对;\n\tEVENT_CHAOHUAQIDUI  \t\t= 11;\t// 超豪华七对;\n\tEVENT_CHAOCHAOHAOHUAQIDUI\t= 12;\t// 超超豪华七对;\n\tEVENT_ZHUANGJIA \t\t\t= 13;\t// 庄家;\n\tEVENT_MINGGANG \t\t\t\t= 14;\t// 明杠;\n\tEVENT_ANGANG\t\t\t\t= 15;\t// 暗杠;\n\tEVENT_SIXIFENG\t\t\t\t= 16;\t// 四喜风;\n\tEVENT_SANZHIJIAN \t\t\t= 17;\t// 三支箭;\n\tEVENT_HUIMINGGANG\t\t\t= 18;\t// 会明杠;\n\tEVENT_HUIANGANG\t\t\t\t= 19;\t// 会暗杠;\n\tEVENT_MENG\t\t\t\t\t= 20;\t// 梦;\n\tEVENT_GENZHUANG\t\t\t\t= 21;\t// 跟庄(罚款);\n\tEVENT_SHISANYAO\t\t\t\t= 22;\t// 十三幺;\n\tEVENT_LONG\t\t\t\t\t= 23;\t// 一条龙;\n\tEVENT_QINGYISE\t\t\t\t= 24;\t// 清一色;\n\tEVENT_HUNYISE\t\t\t\t= 25;\t// 混一色;\n\tEVENT_PENGPENGHU\t\t\t= 26;\t// 碰碰胡;\n\tEVENT_JIANGYISE\t\t\t\t= 27;\t// 将一色;\n\tEVENT_HAIDILAOYUE\t\t\t= 28;\t// 海底捞月;\n\tEVENT_HUGANGFANG\t\t\t= 29;\t// 胡杠放;\n\tEVENT_WUHUAGUO   \t\t\t= 30;\t// 无花果;\n\tEVENT_TING\t\t\t\t\t= 31;\t// 听牌;\n\tEVENT_PFFLOWER              = 32;   // 碰风花;\n\tEVENT_KOU_PAI\t\t\t\t= 33;\t// 扣牌;\n\tEVENT_THREE_ZUAN            = 34;   // 三钻;\n    EVENT_FOUR_ZUAN             = 35;   // 四钻;\n\tEVENT_DIAOWUWAN             = 36;   // 吊五万;\n\tEVENT_ZHUOWUKUI             = 37;   // 捉五魁;\n\tEVENT_ZHI_GANG              = 38;   // 直杠;\n\tEVENT_DIANPAO               = 39;   // 点炮;\n\tEVENT_ZIMO                  = 40;   // 自摸;\n\tEVENT_QIANGGANGHU           = 41;   // 抢杠胡;\n\tEVENT_BASESCORE             = 42;   // 底分;\n\tEVENT_JIAPINGHU             = 43;   // 夹平胡;\n\tEVENT_SHISANBUKAO           = 44;   // 十三不靠;\n\tEVENT_PAOPEIPINGHU          = 45;   // 跑配平胡;\n\tEVENT_PAOPEIQIDUI           = 46;   // 跑配七对;\n\tEVENT_KANHUI\t            = 47;   // 砍会\n\tEVENT_MINGLOU\t            = 48;   // 明楼\n\tEVENT_XIAOGANGKAIHUA\t\t= 49;\t// 小杠开花;\n\tEVENT_HUANGZHUANG\t\t\t= 50;\t// 荒庄;\n\tEVENT_HAOHUAQQIDUI\t\t\t= 51;\t// 豪华清七对;\n\tEVENT_CHAOHUAQQIDUI  \t\t= 52;\t// 超豪华清七对;\n\tEVENT_CHAOCHAOHAOHUAQQIDUI\t= 53;\t// 超超豪华清七对;\n\tEVENT_PIAOCAI               = 54;   // 飘财;\n\tEVENT_BAOTOU                = 55;   // 爆头;\n\tEVENT_LAOZHUANG             = 56;   // 老庄;\n\tEVENT_DASANYUAN             = 57;   // 大三元\n\tEVENT_DIAOYU                = 58;   // 钓鱼\n\tEVENT_SUIJIYISE             = 59;   // 随机清一色\n\tEVENT_LANPAI                = 60;   // 烂牌\n\tEVENT_QIXINGLANPAI          = 61;   // 七星烂牌\n\tEVENT_SANCAISHEN\t        = 62;   // 三财神\n\tEVENT_QIFENGDAO\t\t        = 63;   // 七风倒\n\tEVENT_QIFENGBAIDA           = 64;   // 七风百搭\n\tEVENT_SHISANBAIDA           = 65;   // 十三白搭\n\tEVENT_QUANFENGZI            = 66;   // 全风子\n\tEVENT_DANDIAO\t            = 67;   // 单吊\n\tEVENT_WUCAI\t\t            = 68;   // 无财\n\tEVENT_QUANFENGZIPENGPENGHU  = 69;   // 全风子大碰胡\n\tEVENT_QUANFENGZIQIDUI       = 70;   // 全风子七对子\n\tEVENT_DIANPAOFEN       \t\t= 71;   // 点炮分\n\tEVENT_QIANGGANGHUFEN        = 72;   // 抢杠胡分\n\tEVENT_ZIMOFEN\t\t        = 73;   // 自摸分\n\tEVENT_DUIDUIHU\t\t\t\t= 74;\t// 对对胡\n\tEVENT_MEIBAIDA\t\t\t\t= 75;\t// 没百搭\n\tEVENT_SANBAIDA\t\t\t\t= 76;\t// 三百搭\n\tEVENT_DADIAOCHE\t\t\t\t= 77;\t// 大吊车\n\tEVENT_SHUANGPIAO            = 78;   // 双飘财\n\tEVENT_SANPIAO               = 79;   // 三飘财\n\tEVENT_LANBAIDA              = 80;   // 烂百搭\n\tEVENT_FENGZIBAIDA\t\t\t= 81;\t// 风字百搭\n\tEVENT_SIHUA\t\t\t\t\t= 82;\t// 四花牌\n\tEVENT_CHUNHUA\t\t\t\t= 83;\t// 纯花\n\tEVENT_PENGFENGHUA\t\t\t= 84;\t// 碰风花\n\tEVENT_GANGHUA\t\t\t\t= 85;\t// 杠花\n\tEVENT_HUNPENG\t\t\t\t= 86;\t// 混碰\n\tEVENT_QINGPENG\t\t\t\t= 87;\t// 清碰\n\tEVENT_HUNQIDUI\t\t\t\t= 88;\t// 混七对\n\tEVENT_HUAPAI                = 89;   // 花牌\n\tEVENT_GUODAN                = 90;   // 过蛋儿\n\tEVENT_MENQING               = 91;   // 闭门（门前清）\n\tEVENT_SANJIABIMEN           = 92;   // 三家闭门\n\tEVENT_SHOWBAYI              = 93;   // 手把一\n\tEVENT_SIGUIYI               = 94;   // 四归一\n\tEVENT_XUANFENGGANG          = 95;   // 旋风杠\n\tEVENT_JIEGANG               = 96;   // 借杠\n\tEVENT_ZIYISE                = 97;   // 随机字一色\n\tEVENT_TESHUYISE             = 98;   // 特殊清一色\n\tEVENT_19LAOTOUBAIDA\t\t\t= 99;\t// 19老头百搭\n\tEVENT_QIANGANGXIAOHU        = 100;  // 强杠小胡\n\tEVENT_BUQIUREN              = 101;  // 不求人清一色\n\tEVENT_CONTRACT\t\t\t\t= 102;\t// 承包\n\tEVENT_ZHAMA\t\t\t\t\t= 103;\t// 扎码\n\tEVENT_HUNBAZHANG            = 104;  // 胡八张\n\tEVENT_QUEYIMEN              = 105;  // 缺一门\n\tEVENT_HUIDIAO               = 106;  // 会吊\n\tEVENT_QINGHU                = 107;  // 清胡\n\tEVENT_HUIDIAOHUI            = 108;  // 会吊会\n\tEVENT_PIAOHU\t            = 109;  // 飘胡\n\tEVENT_THREEBIAN\t            = 110;  // 三边\n\tEVENT_FOURBIAN\t            = 111;  // 四边\n\tEVENT_SUHU                  = 112;  // 素胡\n\tEVENT_HUNDIAOHUN            = 113;  // 会吊会\n\tEVENT_DAIZHUANG             = 114;  // 带庄\n\tEVENT_JIA1FEN             \t= 115;  // 加1分\n\tEVENT_JIA2FEN             \t= 116;  // 加2分\n\tEVENT_WUZI             \t\t= 117;  // 无字;\n\tEVENT_KANZHANG             \t= 118;  // 坎张;\n\tEVENT_BIANZHANG             = 119;  // 边张;\n\tEVENT_SBALUOHAN             = 120;  // 十八罗汉\n\tEVENT_HONGZGBAO             = 121;  // 红中宝          \n\tEVENT_QUEYI\t                = 122;  // 缺一\n\tEVENT_LUANYAO               = 123;  // 乱幺;\n\tEVENT_BAO3QIANGGANGHU\t\t= 124;\t// 包三抢杠胡\n\tEVENT_ERWUBAJIANG           = 125;  // 258将\n\tEVENT_GUJIANG               = 126;  // 孤将\n\tEVENT_DUANYAOJIU            = 127;  // 断幺九\n\tEVENT_YIBIANGAO             = 128;  // 一边高\n\tEVENT_GULIANLIU             = 129;  // 孤连六\n\tEVENT_DAXIAOWU              = 130;  // 大小五\n\tEVENT_GOUSHAN               = 131;  // 够扇\n\tEVENT_ZHONGFABAI            = 132;  // 中发白\n\tEVENT_THREEZA               = 133;  // 三砸\n\tEVENT_FOURZA                = 134;  // 四砸\n\tEVENT_KAWUKUI               = 135;  // 卡五魁\n\tEVENT_ANXIAO                = 136;  // 暗潇\n\tEVENT_SANGEYI               = 137;  // 三个一\n\tEVENT_SANGEJIU              = 138;  // 三个九\n\tEVENT_SUQIDUI               = 139;  // 素七对\n\tEVENT_HUIDIAOQIXIAODUI      = 140;  // 会吊七小对\n\tEVENT_MANGUAN               = 141;  // 满贯\n\tEVENT_HUIBENLONG            = 142;  // 本会儿龙\n\tEVENT_DIAOWUKUI             = 143;  // 吊五魁\n\tEVENT_LAZHUANG              = 144;  // 拉庄\n\tEVENT_LIUGANG               = 145;  // 流杠\n\tEVENT_SULONG                = 146;  // 素龙\n\tEVENT_HUNLONG\t\t\t\t= 147;  // 混龙\n\tEVENT_HEIFENG\t\t\t\t= 148;  // 黑风\n\tEVENT_HONGFENG\t\t\t\t= 149;  // 红风\n\tEVENT_YIJIU     \t\t\t= 150;  // 一九\n\tEVENT_ZMH_PH\t\t\t\t= 151;\t// 桥东自摸屁胡\n\tEVENT_ZMH_MQ\t\t\t\t= 152;\t// 桥东自摸门清\n\tEVENT_QGH_PH\t\t\t\t= 153;\t// 桥东抢杠胡屁胡\n\tEVENT_QGH_MQ\t\t\t\t= 154;\t// 桥东抢杠胡门清\n\tEVENT_DPH_PH\t\t\t\t= 155;\t// 桥东点炮胡屁胡\n\tEVENT_DPH_MQ\t\t\t\t= 156;\t// 桥东点炮胡门清\n\tEVENT_QYS_LONG\t\t\t\t= 157;\t// 清一色+一条龙\n\tEVENT_LIANGXI\t\t\t\t= 158;\t// 亮喜\n\tEVENT_BUXI\t\t\t\t\t= 159;\t// 补喜\n\tEVENT_PENG\t\t\t\t\t= 160;\t// 碰\n\tEVENT_DAJIANG    \t\t\t= 161;\t// 大将\n\tEVENT_FENGYISE    \t\t\t= 162;\t// 风一色\n\tEVENT_QIDUIHUIDIAO          = 163;  // 七对会调\n\tEVENT_QIDUIHUIDIAOHUI       = 164;  // 七对会调会\n\tEVENT_DASIXI       \t\t\t= 165;  // 大四喜\n\tEVENT_XIAOSIXI       \t\t= 166;  // 小四喜\n\tEVENT_XIAOSANYUAN       \t= 167;  // 小三元\n\tEVENT_GANGGANGHU \t\t\t= 168;  // 杠杠胡\n\tEVENT_BUHUAHU \t\t\t\t= 169;  // 花上\n\tEVENT_LIANGTAIHUA \t\t\t= 170;  // 两台花\n\tEVENT_LIANGTAIHUAQUEYI \t\t= 171;  // 两台花缺一\n\tEVENT_HUAGANG\t\t \t\t= 172;  // 花杠\n\tEVENT_HUISCORE              = 173;  // 混儿加分\n\tEVENT_HUWEI                 = 174;  // 胡尾\n\tEVENT_ANKAN                 = 175;  // 暗坎\n\tEVENT_HUNERDIAO             = 176;  // 混儿吊\n\tEVENT_PINGHU                = 177;  // 平胡\n\tEVENT_HUNERYOU              = 178;  // 混儿悠\n\tEVENT_YITIAOZHENLONG        = 179;  // 一条真龙\n\tEVENT_YITIAOJIALONG         = 180;  // 一条假龙\n\tEVENT_HUANGJINGANG          = 181;  // 黄金杠\n\tEVENT_ZMH_PH_PINGHU\t\t\t= 182;\t// 桥东自摸屁胡，平胡（上面是大胡）\n\tEVENT_ZMH_MQ_PINGHU\t\t\t= 183;\t// 桥东自摸门清，平胡\n\tEVENT_QGH_PH_PINGHU\t\t\t= 184;\t// 桥东抢杠胡屁胡，平胡\n\tEVENT_QGH_MQ_PINGHU\t\t\t= 185;\t// 桥东抢杠胡门清，平胡\n\tEVENT_DPH_PH_PINGHU\t\t\t= 186;\t// 桥东点炮胡屁胡，平胡\n\tEVENT_DPH_MQ_PINGHU\t\t\t= 187;\t// 桥东点炮胡门清，平胡\n\tEVENT_PINGHU_MINGGANG\t\t= 188;\t// 平胡明杠（桥东用，相对于大胡）\n\tEVENT_PINGHU_ANGANG\t\t\t= 189;\t// 平胡暗杠（桥东）\n\tEVENT_DIANPAO_QIDUI\t\t\t= 190;\t// 点炮七对（桥东）\n\tEVENT_ZIMO_QIDUI\t\t\t= 191;\t// 自摸七对（桥东）\n\tEVENT_PINGHU_GENZHUANG\t\t= 192;\t// 平胡跟庄(罚款)（桥东用）;\n\tEVENT_FAGANG \t\t\t\t= 193;  // 满城罚杠;\n\tEVENT_ZIMOFENGKE            = 194;  // 自摸风刻(天台);\n\tEVENT_ZIMOFENGDIAO          = 195;  // 自摸风调(天台);\n\tEVENT_ZIMOKE                = 196;  // 自摸刻子(天台);\n\tEVENT_ZIMOJIA               = 197;  // 自摸夹子(天台);\n\tEVENT_ZIMODIAO              = 198;  // 自摸单调(天台);\n\tEVENT_DIANPAOKE             = 199;  // 点炮刻字(天台);\n\tEVENT_DIANPAODIAO           = 200;  // 点炮单调(天台);\n    EVENT_DIANPAOJIA            = 201;  // 点炮夹子(天台);\n\tEVENT_FENGKEZI              = 202;  // 风刻子(天台);\n\tEVENT_NORMALKEZI            = 203;  // 正常刻子(天台);\n\tEVENT_ZIJIAHUA              = 204;  // 自家花(天台);\n\tEVENT_SIGEHUA               = 205;  // 四个花(天台);\n\tEVENT_BAGEHUA               = 206;  // 八个花(天台);\n    EVENT_BIANKADIAOSANQI       = 207;  // 边卡吊三七;\n\tEVENT_ZIJIAPENG             = 208;  // 自家碰(天台);\n\tEVENT_ZIJIAKEZI             = 209;  // 自家刻(天台);\n\tEVENT_HONGZHONGPENG         = 210;  // 红中碰(天台);\n\tEVENT_HONGZHONGKEZI         = 211;  // 红中刻(天台);\n\tEVENT_FACAIPENG             = 212;  // 发财碰(天台);\n\tEVENT_FACAIKEZI             = 213;  // 发财刻(天台);\n\tEVENT_HUJUEZHANG            = 214;  // 胡绝张\n\tEVENT_YIBANGAO              = 215;  // 一般高\n\tEVENT_LIANLIU               = 216;  // 连六\n\tEVENT_QUANLAOTOU\t\t\t= 217;\t// 全老头\n\tEVENT_LUANLAOTOU\t\t\t= 218;\t// 乱老头\n\tEVENT_SANBAIDAZUOKE\t\t\t= 219;\t// 三百搭作刻\n\tEVENT_CHUBAIDA\t\t\t\t= 220;\t// 出百搭\n\tEVENT_CHAOQIANGGANGHU \t\t= 221;\t// 超抢杠胡(东台);\n\tEVENT_DUISHANGGANG \t\t\t= 222;\t// 对上杠(东台);\n\tEVENT_DUITIANTING \t\t\t= 223;\t// 对天听(东台);\n\tEVENT_DUIDANDIAO \t\t\t= 224;\t// 对单钓(东台);\n\tEVENT_SHANGGANG \t\t\t= 225;\t// 上杠(东台);\n\tEVENT_TIANTING \t\t\t\t= 226;\t// 天听(东台);\n\tEVENT_GANGSHANGDIANPAO \t\t= 227;\t// 杠上点炮(东台);\n\tEVENT_BAIDADUIZUOTOU\t\t= 228;\t// 百搭对作头（嘉善硬自摸）\n\tEVENT_SHUANGGANKAN\t\t\t= 229;\t// 双干坎（嘉善硬自摸）\n\tEVENT_GANGKAIHUIDIAOHUI\t\t= 230;\t// 杠开会吊会儿\n\tEVENT_HUIDIAOLONG\t\t\t= 231;\t// 会吊龙\n\tEVENT_HUIDIAOBENHUILONG\t\t= 232;\t// 会吊本会龙\n\tEVENT_ZHANGMAO\t\t\t\t= 233;\t// 长毛\n\tEVENT_ZIJIAGANG             = 234;  // 自家杠(天台);\n\tEVENT_HONGZHONGGANG         = 235;  // 红中杠(天台);\n\tEVENT_FACAIGANG             = 236;  // 发财杠(天台);\n\tEVENT_ZIJIADUI              = 237;  // 自家对子(天台);\n\tEVENT_FACAIDUI              = 238;  // 发财对子(天台);\n\tEVENT_HONGZHONGDUI          = 239;  // 红中对子(天台);\n\tEVENT_YIJIUCARD             = 240;  // 1，9 组合(清河);\n\tEVENT_HUADUIZIJIA           = 241;  // 花墩子+\n\tEVENT_HUADUIZIJIAN          = 242;  // 花墩子-\n\tEVENT_QYS_QIDUI\t\t\t\t= 243;\t// 清一色+七对\t\n\tEVENT_ZHONGMA\t\t\t\t= 244;  // 中马  (自由麻将)\n\tEVENT_PENGHOUGANG\t\t\t= 245;  // 碰后杠(自由麻将)\n\tEVENT_QYS_HUIDIAO\t\t\t= 246;  // 清一色混吊(易县麻将)\n\tEVENT_ZIMOWUHUN \t\t\t= 247;  // 自摸无混(易县麻将)\n\tEVENT_HENGYIHENGJIU\t\t\t= 248;\t// 清河横一横九\n\tENENT_CAIFENG\t\t\t\t= 249;\t// 清河彩风组合\n\tEVENT_DDZDIFEN              = 250;  // 斗地主底分\n\tEVENT_ZHADAN                = 251;  // 斗地主炸弹翻倍\n\tEVENT_CHUNTIAN              = 252;  // 斗地主春天翻倍\n\tEVENT_MINGPAI               = 253;  // 斗地主明牌翻倍\n\tEVENT_DIPAI                 = 254;  // 斗地主底牌翻倍\n\tEVENT_QIANGDIZHU            = 255;  // 斗地主抢地主翻倍\n\tEVENT_JIABEI                = 256;  // 斗地主加倍翻倍\n\tEVENT_JIAOFEN               = 257;  // 斗地主叫分翻倍\n\tEVENT_XIAOWANG              = 258;  // 斗地主底牌小王翻倍\n\tEVENT_DAWANG                = 259;  // 斗地主底牌大王翻倍\t\n\tEVENT_DUIZI                 = 260;  // 斗地主底牌对子翻倍\n\tEVENT_TONGHUA               = 261;  // 斗地主底牌同花翻倍\n\tEVENT_SHUNZI                = 262;  // 斗地主底牌顺子翻倍\n\tEVENT_SANZHANG              = 263;  // 斗地主底牌三张翻倍\n\tEVENT_TONGHUASHUN           = 264;  // 斗地主底牌同花顺翻倍\t\n\tEVENT_DAIYIJIU              = 265;  // 带一九\n\tEVENT_LONGQIDUI             = 266;  // 龙七对\n\tEVENT_GEN                   = 267;  // 根\n\tEVENT_JINGOUHU              = 268;  // 金钩胡\n\tEVENT_ZHONGZHANG            = 269;  // 中张\n\tEVENT_GANGSHANGPAO          = 270;  // 杠上炮\n\tEVENT_DIANPAOHU             = 271;  // 点炮胡\n\tEVENT_BEIZIMO               = 272;  // 被自摸\n\tEVENT_ZIMOHU                = 273;  // 自摸胡\n\tEVENT_GUAFENG               = 274;  // 刮风\n\tEVENT_BEIGUAFENG            = 275;  // 被刮风\n\tEVENT_XIAYU                 = 276;  // 下雨\n\tEVENT_BEIXIAYU              = 277;  // 被下雨\n\tEVENT_MIANXIAGANG           = 278;  // 面下杠(二次杠)\n\tEVENT_BEIMIANXIAGANG        = 279;  // 被面下杠(二次杠)\n\tEVENT_HUJIAOZHUANYI         = 280;  // 呼叫转移\n\tEVENT_BEIHUJIAOZHUANYI      = 281;  // 被呼叫转移\n\tEVENT_CHAHUAZHU             = 282;  // 查花猪\n\tEVENT_CHAJIAO               = 283;  // 查叫\n\tEVENT_BEICHAHUAZHU          = 284;  // 被查花猪\n\tEVENT_BEICHAJIAO            = 285;  // 被查叫\n\t\n}\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "tools/protobuf/lua/protobuf_gen_lua.bat",
    "content": "del *.proto /f /a /q\ndel *.pb /f /a /q\ncopy ..\\*.proto .\n\ndel ..\\..\\..\\code\\EVA\\server\\script\\DataTable\\*.proto /f /a /q\ncopy ..\\*.proto ..\\..\\..\\code\\EVA\\server\\script\\DataTable\\proto\\ /y\n\nprotoc-3.2.0rc2 --descriptor_set_out=./ProtoMsg.pb define_pro.proto define_attrib.proto msg_client.proto msg_service.proto msg_doudizhu.proto\n\ncopy ProtoMsg.pb ..\\..\\..\\code\\EVA\\server\\script\\DataTable\\  /y\ndel *.proto /f /a /q\ndel *.pb /f /a /q\npause\n\n"
  },
  {
    "path": "tools/protobuf/msg_client.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nimport \"define_pro.proto\";\n\nmessage MsgLogin\n{\n  optional string       Version         = 1;\n  optional string       Channel         = 2;\n  optional string       AppName         = 3;\n  optional string       User            = 4;\n  optional string       NonceStr        = 5;\n  optional string       Token           = 6;\n  optional uint64       Timestamp       = 7;\n  optional uint64       UID             = 8;\n  optional string       RoomType        = 9;\n  \n  \n}\n\nmessage MsgPlayerInfo\n{\n  optional uint64       UID             = 1;\n  optional string       Nickname        = 2;\n  optional uint32       Portrait        = 3;\n  optional uint64       Money           = 4;\n  optional uint64       RMB             = 5;\n  optional uint32       Main            = 6;\n  optional uint64       FlagBit         = 7;\n}\n\nmessage MsgCreatePrivateRoom\n{\n\toptional uint32 \t\t\t\tconsume_id          = 1;\n\toptional TGameConsumePay \t\tconsume_kind\t \t= 2;\n\toptional string \t\t\t\troom_type\t        = 3;\n\toptional uint32 \t\t    \tspecial_kind        = 4;\n\toptional uint32 \t\t\t \tscore   \t        = 5;\n\toptional uint32 \t\t\t\tgame_versione\t\t= 6;\n\toptional TPaymentMechanism\t\tpay_ment\t\t    = 7;\n\toptional uint32\t\t\t\t\tplayer_number\t\t= 8;\n\toptional uint64\t\t\t\t\ttissue_id\t\t\t= 9;\n}\n\nmessage MsgEnterPrivateRoom\n{\n\toptional uint64\t\t\t\t\troom_id\t\t\t\t= 1;\n    optional string                 room_type           = 2;\n\toptional string \t\t\t\tapp_name\t\t\t= 3;\n\toptional uint32\t\t\t\t\tgame_version\t\t= 4;\n}\n\nmessage MsgCard\n{\n\toptional uint32                 card                = 1;\n}\n\nmessage MsgCards\n{\n    optional uint32                 type                = 1;\n\trepeated uint32                 cards               = 2;\n}\n\nmessage MsgInt\n{\n\toptional int64      value        = 1;\n}\n\nmessage MsgBool\n{\n\toptional bool       value        = 1;\n}\n\nmessage MsgString\n{\n\toptional string     str        = 1;\n}\n\nmessage MsgError\n{\n\toptional uint32     errno       = 1;\n    optional uint64     value       = 2;\n}\n\n////////////////////////////////   Record Start    //////////////////////\n\nmessage MsgRecordRoleInfo\n{\n\toptional uint64\t\t\tid        \t\t = 1;\n\toptional uint32\t\t\tseat        \t = 2;\n\toptional string\t\t\tusename   \t\t = 3;\n\toptional int64\t \t\tscore     \t\t = 4;\n\trepeated uint32 \t\thand_card \t\t = 5;\n\toptional string         nick_name\t\t = 6;\n\toptional uint32\t\t\tgame_state\t\t = 7;\n\toptional uint32\t\t\tseries\t\t\t = 8;\n\toptional int64\t\t\tcurrent_score    = 9;\n}\n\nmessage MsgRecordRoomInfo\n{\n\toptional uint32 \t    special_kind      = 1;\n\toptional uint64 \t\tbanker\t\t\t  = 2;\n\toptional uint32         score\t\t\t  = 3;\n\toptional uint32\t\t\tgame_count\t\t  = 4;\n\trepeated uint32         bottom_cards \t  = 5;\n}\n\nmessage MsgRecordEvent\n{\n\toptional uint32 \t\tevent_id \t\t = 1;\n\toptional uint32 \t\tcount\t \t\t = 2;\n\trepeated int32 \t\t\tscore\t     \t = 3;\n\trepeated uint32 \t\tscore_count    \t = 4;\n}\n\nmessage MsgRecordWeaveCard\n{\n \toptional uint32 \t\tcard       \t\t= 1;\n\toptional uint32\t\t\twik\t\t   \t\t= 2;\n\toptional uint32\t\t\tbarkind\t\t\t= 3;\n\trepeated uint32\t\t    mix_card\t\t= 4;    // 组合牌;\n}\n\nmessage MsgRecordShowDown\t\t\t\t\t\t\t\n{\n\toptional uint64\t\t\t\t\tid       \t\t = 1;\n\toptional int64\t\t\t\t\tscore    \t\t = 2;\n\toptional int64\t\t\t\t\tfixedscore\t\t = 3;\n\toptional int64\t\t\t\t\tparam1   \t  \t = 4;\n\toptional int64\t\t\t\t\tparam2\t \t\t = 5;\n\toptional uint32 \t\t\t\thucard\t\t\t = 6;\n\trepeated MsgRecordEvent \t\tevent    \t\t = 7;\n\toptional int64\t\t\t\t\tmoney\t\t\t = 8;\n\toptional int64          \t\tparam3\t\t\t = 9;\n\toptional int64          \t\tparam4\t\t\t = 10;\n\toptional int64          \t\tparam5\t\t\t = 11;\n\toptional int64          \t\tplay_id\t\t\t = 12;\n\trepeated uint32  \t\t\t\thand_card\t\t = 13;\n\trepeated MsgRecordWeaveCard \tweave_card       = 14;\n\trepeated uint32\t\t\t\t\thucard_list      = 15;\n}\n\nmessage MsgGDShowDownRole\n{\n\toptional uint64\t\trole_id \t \t= 1;\n\toptional uint32\t\tgame_count  \t= 2;\n\toptional uint32\t\tseries\t\t \t= 3;\n\toptional int32\t\tscore  \t     \t= 4;\n\toptional int32\t\tcurrent_score \t= 5;\n}\n\nmessage MsgGDRankInfo\n{\n\trepeated uint64\t\trank_list\t\t= 1;\n}\n\nmessage MsgRecordNodeList\n{\n\toptional uint32\t\t\t\t\tcmd_id  \t \t= 1;\t\t\n\trepeated uint32\t\t\t\t\tcard_value\t \t= 2;\n\toptional uint32\t\t\t\t\tcard_index   \t= 3;\n\toptional uint64\t\t\t\t\taction_id    \t= 4;\n\toptional uint32\t\t\t\t\taction_wik\t \t= 5;\n\toptional uint64\t\t\t\t\ttarget_id \t \t= 6;\n\toptional uint32\t\t\t\t\tnode_size\t \t= 7;\n\trepeated MsgRecordRoleInfo \t\trole_data \t  \t= 8;\n\toptional MsgRecordRoomInfo\t\troom_data\t  \t= 9;\n\trepeated MsgRecordShowDown\t\tshowdown_list \t= 10;\n\trepeated MsgRecordNodeList\t\tnext_node     \t= 11;\n\trepeated MsgGDShowDownRole\t\twin_role\t\t= 12;\n\trepeated MsgGDShowDownRole \t\tlost_role\t\t= 13;\n\toptional MsgGDRankInfo\t\t\troom_ranking\t= 14;\n}\n\n\n\n////////////////////////////////   Record End    ////////////////////////////\n\n\n\n\n\n"
  },
  {
    "path": "tools/protobuf/msg_doudizhu.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nimport \"msg_client.proto\";\n\nenum TDDZPlayerWik                                                     // 玩家权限\n{\n\tASK_DDZ_NULL                         = 1;                        // 空\n\tASK_DDZ_TISHI                        = 2;                        // 提示 \n\tASK_DDZ_BUCHU                        = 3;                        // 不出\n\tASK_DDZ_CHUPAI                       = 4;                        // 出牌\n\tASK_DDZ_DIZHU_MINGPAI                = 5;                        // 地主明牌\n};\n\nenum TDDZPlayerState                                                    // 玩家状态\n{\n\tSTATE_DDZ_READY                        = 1;                      // 准备\n\tSTATE_DDZ_GUOPAI                       = 2;                      // 过牌\n\tSTATE_DDZ_CHUNTIAN                     = 3;                      // 春天\n\tSTATE_DDZ_NEWROLE                      = 4;                      // 新玩家\n\tSTATE_DDZ_ROOM_OWNER                   = 5;                      // 房主\n\tSTATE_DDZ_RELIEVE\t\t\t           = 6;\t\t\t            // 解除房间状态;\n\tSTATE_DDZ_LEAVE                        = 7;                      // 离开状态                    \n    STATE_DDZ_LIMIT                        = 8;                      // 限制状态\n\tSTATE_DDZ_OFFLINE                      = 9;                     // 脱机状态;\n\tSTATE_DDZ_MINGPAI                      = 10;                     // 明牌 状态;\n\tSTATE_DDZ_DIZHU                        = 11;                     // 地主状态;\n\tSTATE_DDZ_NONGMING                     = 12;                     // 农民状态;\n\tSTATE_DDZ_JIABEI                       = 13;                    // 加倍状态\n\tSTATE_DDZ_QIANGDIZHU                   = 14;                    // 抢地主状态\n\tSTATE_DDZ_SELECT_JIABEI                = 15;                    // 选择加倍状态\n\tSTATE_DDZ_SELECT_MINGPAISTART          = 16;                    // 选择明牌开始状态\n\tSTATE_DDZ_FENGDING                     = 17;                   // 封顶状态\n\tSTATE_DDZ_CONTINUE_GAME                = 18;                   // 继续游戏状态\n};\n\nenum TDDZState                          \t\t\t\t\t\t\t// 游戏房间状态\n{\n\tTDDZStateWait        \t        \t= 0;\t\t\t\t\t\t// 等待开始\n\tTDDZStateCheckStartGame             = 1;                        // 检查是否可以开始游戏\n\tTDDZStateSelectMingCardStart        = 2;                        // 选择明牌开始阶段\n    TDDZStateStartGame   \t   \t        = 3;\t\t\t\t\t\t// 开始游戏\t\n\tTDDZStateSendCard\t \t            = 4; \t\t\t\t\t\t// 发送手牌\n\tTDDZStateQiangDiZhu\t \t            = 5; \t\t\t\t\t\t// 抢地主阶段\n\tTDDZStateSelectAddTimes\t        \t= 6; \t\t\t\t\t\t// 选择加倍阶段\n\tTDDZStateAction \t        \t\t= 7;\t\t\t\t\t\t// 玩家自由活动\n\tTDDZStateOutCard                    = 8;                        // 出牌状态\n\tTDDZStateShowDown\t\t         \t= 9;     \t\t\t\t\t// 游戏结算\n\tTDDZStateRelieveRoom                = 10;                       // 解散房间\n};\n\nenum TDDZCT                             \t\t\t\t\t    \t// 牌型\n{\n\tCT_DDZ_ERROR\t\t\t\t\t\t= 0;\t\t\t\t\t\t// 错误类型\n\tCT_DDZ_SINGLE\t\t\t\t\t\t= 1;\t\t\t\t\t\t// 单牌类型\n\tCT_DDZ_DOUBLE\t\t\t\t\t\t= 2;\t\t\t\t        // 对子类型\n\tCT_DDZ_THREE_TIAO\t\t\t\t\t= 3;\t\t\t\t\t    // 三条类型\n\tCT_DDZ_THREE_TIAO_WITH_ONE          = 4;    \t\t\t\t\t// 三带一单类型\n\tCT_DDZ_THREE_TIAO_WITH_YIDUI        = 5;    \t\t\t\t\t// 三带一对类型\n\tCT_DDZ_SHUN_ZI\t\t\t\t\t\t= 6;\t\t\t\t\t\t// 顺子类型\n\tCT_DDZ_LIAN_DUI\t\t\t\t        = 7;\t\t\t\t\t\t// 连对类型\n\tCT_DDZ_FEIJI_WITH_NULL              = 8;    \t\t\t\t\t// 飞机不带类型\n\tCT_DDZ_FEIJI_WITH_ONE               = 9;    \t\t\t\t\t// 飞机带单类型\n\tCT_DDZ_FEIJI_WITH_YIDUI             = 10;    \t\t\t\t\t// 飞机带对类型\n\tCT_DDZ_FOUR_WITHDOUBLE              = 11;    \t\t\t\t\t// 四带二类型\n\tCT_DDZ_FOUR_LIANGDUI                = 12;    \t\t\t\t\t// 四带二对类型\n\tCT_DDZ_ZHADAN_SIZHANG               = 13;   \t\t\t\t\t// 炸弹\n\tCT_DDZ_HUOJIAN\t\t\t\t \t    = 14;\t\t\t\t\t\t// 火箭\n};\n\nenum TDDZBottomType                             \t\t\t    // 底牌牌型\n{\n\tDDZ_BT_NULL\t\t\t\t\t\t= 0;\t\t\t\t\t\t// 无类型\n\tDDZ_BT_XIAO_KING\t\t\t    = 1;\t\t\t\t\t\t// 小王类型\n\tDDZ_BT_DA_KING\t\t\t\t    = 2;\t\t\t\t        // 大王类型\n\tDDZ_BT_DUIZI\t\t\t\t\t= 3;\t\t\t\t\t    // 对子类型\n\tDDZ_BT_TONGHUA                  = 4;    \t\t\t\t\t// 同花类型\n\tDDZ_BT_SHUNZI\t\t\t\t    = 5;\t\t\t\t\t\t// 顺子类型\n\tDDZ_BT_SANZHANG\t\t\t\t    = 6;\t\t\t\t\t\t// 三张类型\n\tDDZ_BT_TONGHUASHUN              = 7;    \t\t\t\t\t// 同花顺类型\n};\n\nenum TDDZQiangDiZhu                             \t\t\t   // 抢地主权限\n{\n\tDDZ_QDZ_JIAODIZHU\t\t\t\t   = 1;\t\t\t\t   // 叫地主\n\tDDZ_QDZ_BUJIAO\t\t\t\t\t   = 2;\t\t\t\t   // 不叫\n\tDDZ_QDZ_QIANGDIZHU\t\t\t\t   = 3;\t\t\t\t   // 抢地主\n\tDDZ_QDZ_BUQIANG\t\t\t\t\t   = 4;\t\t\t\t   // 不抢\n};\n\nenum TDDZJiaoFen                            \t\t\t       // 叫分权限\n{\n\tDDZ_JF_BUJIAO\t\t\t\t\t   = 1;\t\t\t\t   // 不叫\n\tDDZ_JF_JIAO_ONE\t\t\t\t       = 2;\t\t\t\t   // 叫一分\n\tDDZ_JF_JIAO_TWO\t\t\t\t       = 3;\t\t\t\t   // 叫二分\n\tDDZ_JF_JIAO_THREE\t\t\t\t   = 4;\t\t\t\t   // 叫三分\n};\n\nenum TDDZAddTimes                           \t\t\t       // 加倍选择\n{\n\tDDZ_AT_NULL\t\t\t\t\t       = 0;\t\t\t\t  \n\tDDZ_AT_BUJIABIE\t\t\t\t       = 1;\t\t\t\t       // 不加倍\n\tDDZ_AT_JIABIE\t\t\t           = 2;\t\t\t\t       // 加倍\n};\n\nenum TDDZMingPaiType                           \t\t\t       // 明牌选择\n{\n\tDDZ_MP_NULL\t\t\t\t\t       = 0;\t\t\t\t   \n\tDDZ_MP_NORMALSTART\t\t\t\t   = 1;\t\t\t\t       // 普通开始\n\tDDZ_MP_MINGPAISTART\t\t\t       = 2;\t\t\t\t       // 明牌开始\n};\n\nenum TGameSpecialKindDouDiZhu               // 斗地主房间玩法\n{\n\tTSK_DDZ_NULL\t   \t= 0;\n\tTSK_DDZ_QDZ\t   \t\t= 1;\t    // 抢地主\n\tTSK_DDZ_JF\t   \t\t= 2;\t    // 叫分\n\tTSK_DDZ_BFD\t   \t\t= 3;        // 不封顶\n\tTSK_DDZ_16\t   \t\t= 4;        // 16封顶\n\tTSK_DDZ_32        \t= 5;        // 32封顶\n\tTSK_DDZ_64   \t\t= 6;        // 64封顶\n\tTSK_DDZ_DIPAI     \t= 7;        // 底牌翻倍\n\tTSK_DDZ_JIABEI  \t= 8;        // 加倍\n\tTSK_DDZ_MINGPAI  \t= 9;        // 明牌\n}\n\nmessage MsgQiangDiZhu                                               // 抢地主信息(服务器发给客户端的)\n{\n\toptional uint64 playid                = 1;                      // 玩家id\n\toptional uint64 qingdizhu_wiki        = 2;                      // 玩家可操作的权限\n}\n\nmessage MsgQiangDiZhuResult                                          // 抢地主结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                  = 1;                       // 玩家id\n\toptional uint64 result                  = 2;                       // 玩家选择的结果\n\toptional uint64 state                   = 3;                       // 状态\n\trepeated uint32 dizhu_cards             = 4;             \t         // 刷新地主的手牌\n\toptional uint64 cardcount               = 5;                       // 手牌数量\n\toptional uint64 multiple                = 6;                       // 房间倍数\n}\n\nmessage MsgBRQiangDiZhuResult                                       // 抢地主最终结果(服务器广播的)\n{\n\trepeated MsgQiangDiZhuResult player_list  = 1;\n\toptional uint64 multiple                  = 2;                  // 房间倍数\n\trepeated MsgDiPaiMutiple dipai_multi_list = 3;                  // 底牌翻倍列表\n}\n\nmessage MsgDiPaiMutiple                                             // 底牌翻倍的类型事件\n{\n\toptional uint32 \t\t\tevent_id\t\t= 1;\n\toptional uint32 \t\t\tcount\t\t\t= 2;\n}\n\nmessage MsgMingPaiResult                                             // 选择明牌结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                      = 1;                        // 玩家id\n\toptional uint64 result                      = 2;                        // 玩家选择的结果\n\toptional uint64 state                       = 3;                        // 状态\n\trepeated uint32 dizhu_cards                 = 4;             \t        // 地主明牌时刷新手牌\n\toptional uint64 multiple                    = 5;                        // 房间倍数\n}\n\nmessage MsgJiaBeiResult                                              // 选择加倍结果(客户端发给服务器的，服务器广播的)\n{\n\toptional uint64 playid                = 1;                       // 玩家id\n\toptional uint64 result                = 2;                       // 玩家选择的结果\n\toptional uint64 state                 = 3;                       // 状态\n}\n\nmessage MsgDDZPlayer                                                // 玩家信息\n{\n\toptional MsgPlayerInfo      player_base          = 1;\t\t\t// 玩家信息(房间信息填充)\n\toptional uint32 \t\t\tstate\t\t\t\t = 2;\t        // 玩家状态\n\toptional uint32 \t\t\thand_count\t\t\t = 3;           // 手牌数量\n\trepeated uint32             card_list            = 4;          \t// 手牌列表(房间信息、showdown填充)\n\toptional uint32 \t\t\tseats\t\t\t\t = 5;\t        // 座位(房间信息填充)\n\toptional int64              score                = 6;           // 玩家当前的积分\n\toptional int64      \t\tshow_down_score      = 7;           // 玩家该局游戏的加减分\n\toptional uint32             qingdizhu_wiki       = 8;           // 玩家抢地主的权限\n\toptional uint32             qingdizhu_value      = 9;           // 玩家抢地主的结果\n\toptional uint32             multiple             = 10;          // 玩家倍数,(结算时使用)\n\toptional uint32      \t\tintegral_num         = 11;          // 加券数\n\trepeated uint32             out_cards     \t\t = 12;          // 上把玩家出的牌信息\n\toptional uint32  \t        out_type\t\t\t = 13;          // 上把玩家的出牌种类\n}\n\nmessage MsgDDZActon\n{\n\toptional uint64  \t        new_actionid        = 1; \t\t\t    // 当前活动玩家\n\toptional uint64  \t        old_actionid\t\t= 2; \t\t\t    // 上把的活动玩家\n\trepeated uint32             last_out_cards      = 3;             \t// 上把玩家出的牌信息\n\toptional uint32  \t        last_out_type\t\t= 4;                // 上把玩家的出牌种类\n\toptional uint32             wik                 = 5;                // 当前活动玩家的权限  TDDZPlayerWik\n\trepeated MsgDDZPlayer       player_list         = 6;                // 玩家信息\n}\n\n\nmessage MsgDDZUserOutCard\n{\n\toptional uint64 \t            old_actionid\t    = 1;              // 旧玩家ID\n\toptional uint32  \t            out_type\t\t    = 2;              // 出牌种类\n\toptional uint32  \t            hand_count          = 3;              // 玩家手牌数量\n\trepeated uint32                 out_cards           = 4;              // 出牌列表\n\toptional uint64                 multiple            = 5;              // 房间倍数\n\trepeated uint32                 hand_cards          = 6;              // 明牌玩家剩余的手牌，客户端刷新使用\n}\n\nmessage MsgDDZRoom                                                      // 房间信息\n{       \n\toptional uint32                      \troom_state              = 1;     // 房间当前状态   TDDZState\n\toptional uint32 \t\t\t\t\t    state_time \t\t        = 2;     // 状态运行时间\n\trepeated MsgDDZPlayer\t\t\t        player_list\t\t        = 3;     // 玩家信息\n\toptional uint64 \t\t\t\t\t    action_id \t\t        = 4;     // 当前活动玩家\n\toptional uint64\t\t\t\t\t\t    room_id\t\t\t        = 5;     // 房间ID\n\toptional uint32                         game_count              = 6;     // 当前是该房间的第几局\n\toptional MsgCreatePrivateRoom\t\t    private_room \t        = 7;\t    // 私房信息;\n\toptional MsgDDZUserOutCard              last_outcard            = 8;     // 房间上家牌的信息\n\toptional uint32                         wik                     = 9;     // 当前活动玩家的权限  TDDZPlayerWik\n\toptional uint32                         bottom_cards            = 10;    // 底牌列表\n\toptional uint64                         multiple                = 11;    // 房间倍数\n\trepeated MsgDiPaiMutiple \t\t\t    dipai_multi_list        = 12;    // 底牌翻倍列表\n\toptional uint32\t\t\t\t\t\t    room_pay_type           = 13;    // 付费类型\n}\n\nmessage MsgDDZRoomShowDown                                              // 结算房间信息\n{       \n\toptional uint32                       room_state           = 1;     // 房间当前状态    TDDZState\n\toptional uint32 \t\t\t\t\t  state_time \t\t   = 2;     // 状态运行时间\n\trepeated MsgDDZPlayer\t\t\t      player_list\t\t   = 3;     // 玩家信息\n\toptional uint64\t\t\t\t\t\t  room_id\t\t\t   = 4;     // 房间ID\n\toptional uint32                       game_count           = 5;     // 当前是该房间的第几局\n\toptional uint32 \t\t\t          time \t\t           = 6;     // 时间 \n\toptional bool                         game_over            = 8;     // 是否结束\n\trepeated MsgDDZShowDownEvent\t      event_count\t  \t   = 9;\t\t// 结算事件;\n\trepeated MsgDDZIntegralCount\t\t  integral_list \t   = 10;\t// 积分卷;\n}\n\n// 积分卷\nmessage MsgDDZIntegralCount\n{\n\toptional uint64\t\t\t\troleid\t\t\t= 1;\n\toptional uint32 \t\t\tcount \t\t\t= 2;\n}\n\nmessage MsgDDZShowDownEvent                                            // 结算事件;\n{\n\toptional uint32 \t\t\tevent_id\t\t= 1;\n\toptional uint32 \t\t\tcount\t\t\t= 2;\n}"
  },
  {
    "path": "tools/protobuf/msg_service.proto",
    "content": "syntax = \"proto2\";\npackage PB;\n\nmessage MsgGameType\n{\n    optional string         Type                    = 1;\n    optional uint32         Max                     = 2;\n    optional uint32         Curr                    = 3;    \n    \n}\n\nmessage MsgServiceInfo\n{\n    repeated MsgGameType    RoomList                = 1;\n    optional uint32         MaxPlayer               = 2;\n    optional uint32         CurrPlayer              = 3;\n    optional uint32         ServiceID               = 4;\n    optional string         ServiceName             = 5;\n\n}\n"
  },
  {
    "path": "tools/server/admin/common.php",
    "content": "<?php\n\n\t//error_reporting(E_ALL); // extreme debug info ;)\n\tset_time_limit(180); // 3 min time out\n\n\t// add the path for the nel class files\n\tini_set('include_path',ini_get('include_path') .':./nel/');\n\n\trequire_once('config.php');\n\n\trequire_once(NELTOOL_SYSTEMBASE .'functions_common.php');\n\trequire_once(NELTOOL_SYSTEMBASE .'functions_auth.php');\n\n\t//assert_options(ASSERT_ACTIVE, 1);\n\t//assert_options(ASSERT_WARNING, 0);\n\t//assert_options(ASSERT_QUIET_EVAL, 1);\n\t//assert_options(ASSERT_CALLBACK, 'nt_common_assert');\n\n\trequire_once(NELTOOL_SYSTEMBASE .'functions_mysqli.php');\n\trequire_once(NELTOOL_SYSTEMBASE .'smarty/Smarty.class.php');\n\trequire_once(NELTOOL_SYSTEMBASE. 'functions_tool_administration.php');\n\trequire_once(NELTOOL_SYSTEMBASE. 'nel/admin_modules_itf.php');\n\n\t// lets set up the database\n\t$db = new sql_db(NELTOOL_DBHOST, NELTOOL_DBUSER, NELTOOL_DBPASS, NELTOOL_DBNAME);\n\tif (!is_object($db)) die(\"error on db init\");\n\n\t// lets set up the smarty template engine\n\t$tpl = new Smarty;\n\tif (!is_object($tpl)) die(\"error on smarty init\");\n\n    $iPhone = (strstr($_SERVER['HTTP_USER_AGENT'], \"iPhone\") !== FALSE);\n\t$tpl->assign('iPhone', $iPhone);\n\n\t$tpl->template_dir\t= NELTOOL_SYSTEMBASE .'/templates/default/';\n\t$tpl->compile_dir\t= NELTOOL_SYSTEMBASE .'/templates/default_c/';\n\t$tpl->config_dir\t= NELTOOL_SYSTEMBASE .'/templates/config/';\n\t$tpl->cache_dir\t\t= NELTOOL_SYSTEMBASE .'/templates/cache/';\n\n\t$tpl->caching = false;\n\t$tpl->clear_all_cache();\n\tif (NELTOOL_DEBUG) $tpl->debugging = false;\n\n\tif (defined('NELTOOL_NO_USER_NEEDED'))\n\t{\n\t\t// this is used for cron jobs that don't need authentifications when running\n\t}\n\telse\n\t{\n\t\tnt_auth_start_session();\n\n\t\t$NELTOOL = array(\n\t\t\t\t\t\t'POST_VARS'\t\t=> &$_POST,\n\t\t\t\t\t\t'GET_VARS'\t\t=> &$_GET,\n\t\t\t\t\t\t'COOKIE_VARS'\t=> &$_COOKIE,\n\t\t\t\t\t\t'SESSION_VARS'\t=> &$_SESSION,\n\t\t\t\t\t\t'SERVER_VARS'\t=> &$_SERVER,\n\t\t\t\t\t\t);\n\n\t\t$nel_user = null;\n\t\t$nel_debug = array();\n\n\t\tnt_common_add_debug(date(\"Y-m-d H:i:s\",time()));\n\t\tnt_common_add_debug('-- Basic init complete, time to get some work done.');\n\n\n\t\t// login and session process\n\t\tif (isset($NELTOOL['GET_VARS']['mode']) && ($NELTOOL['GET_VARS']['mode'] == 'logout'))\n\t\t{\n\t\t\t$nel_user = null;\n\t\t\tnt_auth_stop_session();\n\t\t\tnt_common_redirect('');\n\t\t\texit();\n\t\t}\n\t\telseif (isset($NELTOOL['SESSION_VARS']['nelid']) && !empty($NELTOOL['SESSION_VARS']['nelid']))\n\t\t{\n\t\t\t$nel_user = nt_auth_load_user($NELTOOL['SESSION_VARS']['nelid']);\n\t\t}\n\t\telseif (isset($NELTOOL['POST_VARS']['nel_login']) && isset($NELTOOL['POST_VARS']['nel_passwd']) && ($NELTOOL['POST_VARS']['action'] == 'login'))\n\t\t{\n\t\t\t$nel_user = nt_auth_check_login($NELTOOL['POST_VARS']['nel_login'], $NELTOOL['POST_VARS']['nel_passwd']);\n\t\t\tif ($nel_user)\n\t\t\t{\n\t\t\t\tnt_auth_set_session_var('nelid',$nel_user['user_id']);\n\t\t\t\tnt_auth_set_logging_count($nel_user['user_id']);\n\t\t\t\t$nel_user['new_login'] = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!$nel_user)\n\t\t{\n\t\t\tnt_auth_load_login();\n\t\t\texit();\n\t\t}\n\n\t\tnt_common_add_debug('-- User authentification complete.');\n\n\t\t// some site settings\n\n\t\tif (NELTOOL_DEBUG && ($nel_user['group_level'] == 10)) // need to use the array instead of the value being hardcoded\n\t\t{\n\t\t\t$tpl->assign('NELTOOL_DEBUG', true); //$nel_debug);\n\t\t}\n\n\t\t$tpl->assign('nel_script',\t\t\t$NELTOOL['SERVER_VARS']['SCRIPT_NAME']);\n\t\t$tpl->assign('nel_request_uri', \tbasename($NELTOOL['SERVER_VARS']['REQUEST_URI']));\n\t\t$tpl->assign('nel_tool_title',\t\tNELTOOL_SITETITLE);\n\t\t$tpl->assign('nel_web_base_uri',\tNELTOOL_SITEBASE);\n\n\t\t$tpl->assign('tool_title',\t\t\t\"&lt;unknown&gt;\");\n\t\t$tpl->assign('user_info',\t\t\t$nel_user['user_name'] .' ('. $nel_user['group_name'] .')');\n\n\t\t// load user & group applications/domains/shards\n\n\t\t$nel_user['access'] = array(\n\t\t\t\t\t\t\t\t\t'applications'\t\t\t=> tool_admin_applications_get_list(),\n\t\t\t\t\t\t\t\t\t'user_applications'\t\t=> tool_admin_users_applications_get_list($nel_user['user_id']),\n\t\t\t\t\t\t\t\t\t'user_domains'\t\t\t=> tool_admin_users_domains_get_list($nel_user['user_id']),\n\t\t\t\t\t\t\t\t\t'user_shards'\t\t\t=> tool_admin_users_shards_get_list($nel_user['user_id']),\n\t\t\t\t\t\t\t\t\t'group_applications'\t=> tool_admin_groups_applications_get_list($nel_user['user_group_id']),\n\t\t\t\t\t\t\t\t\t'group_domains'\t\t\t=> tool_admin_groups_domains_get_list($nel_user['user_group_id']),\n\t\t\t\t\t\t\t\t\t'group_shards'\t\t\t=> tool_admin_groups_shards_get_list($nel_user['user_group_id']),\n\t\t\t\t\t\t\t\t\t);\n\n\t\t$nel_user['access']['domains'] = tool_admin_users_groups_domains_merge();\n\t\t$nel_user['access']['shards'] = tool_admin_users_groups_shards_merge();\n\t\t$nel_user['has_lock'] = false;\n\n\t\t//nt_common_add_debug($nel_user);\n\n\t\t// load the user application menu\n\n\t\t$tool_application_list = tool_admin_applications_build_menu_list($nel_user['access']);\n\t\t$tpl->assign('nel_menu',\t\t\t$tool_application_list);\n\t\t$tpl->assign('menu_style',\t\t\t$nel_user['user_menu_style']);\n\t\t$tpl->assign('unknown_menu',\t\t'imgs/icon_unknown.png');\n\n\t\tif (isset($nel_user['new_login']))\n\t\t{\n\t\t\t$default_user_application_id\t= 0;\n\t\t\tif (isset( $nel_user['user_default_application_id']) &&($nel_user['user_default_application_id'] > 0)) {\n                $default_user_application_id\t= $nel_user['user_default_application_id']; \n\t\t\t}elseif (isset( $nel_user['group_default_application_id']) &&($nel_user['group_default_application_id'] > 0)) {\n                $default_user_application_id\t= $nel_user['group_default_application_id'];\n            }\n            \n\t\t\tif ($default_user_application_id > 0)\n\t\t\t{\n\t\t\t\tnt_common_add_debug(\"default application : user:\". $nel_user['user_default_application_id'] .\" group:\". $nel_user['group_default_application_id']);\n\t\t\t\t$default_user_application_data\t= tool_admin_applications_get_default($tool_application_list, $default_user_application_id);\n\t\t\t\tnt_common_redirect($default_user_application_data['application_uri']);\n\t\t\t\texit();\n\t\t\t}\n\t\t}\n\n\t\t$nel_tool_extra_css = '';\n\t\tif (BG_IMG !== null)\n\t\t{\n\t\t\t$nel_tool_extra_css .= \"<style><!--\\n\";\n\t\t\t$nel_tool_extra_css .= \"body { background: url(\". BG_IMG .\"); }\\n\";\n\t\t\t$nel_tool_extra_css .= \"--></style>\\n\";\n\t\t}\n\t\t$tpl->assign('nel_tool_extra_css', $nel_tool_extra_css);\n\t\t$tpl->assign('system_time',\ttime());\n\n\t\tnt_common_add_debug('-- Common init. complete.');\n\t}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/config.php",
    "content": "<?php\n\n\tdefine('NELTOOL_LOADED', true);\n\n\t// database information for nel tool\n\tdefine('NELTOOL_DBHOST','127.0.0.1');\n\tdefine('NELTOOL_DBUSER','shard');\n\tdefine('NELTOOL_DBPASS','');\n\tdefine('NELTOOL_DBNAME','nel_tool');\n\n\t// site paths definitions\n\t//define('NELTOOL_SITEBASE',$_SERVER['PHP_SELF']);\n\t//define('NELTOOL_SYSTEMBASE',dirname( dirname(__FILE__) ) . '/admin/');\n\t\n\t//define('NELTOOL_SITEBASE', '.');\n\tdefine('NELTOOL_SITEBASE', '');\n\tdefine('NELTOOL_SYSTEMBASE', '/usr/local/www/nginx/admin/');\n\t#define('NELTOOL_SYSTEMBASE', 'D:/xampp/htdocs/admin/');\n\t\n\tdefine('NELTOOL_LOGBASE', NELTOOL_SYSTEMBASE .'/logs/');\n\tdefine('NELTOOL_IMGBASE', NELTOOL_SYSTEMBASE .'/imgs/');\n\n\t//define('NELTOOL_RRDTOOL',       '/usr/local/bin/sudo /usr/local/bin/rrdtool');\n    define('NELTOOL_RRDTOOL',       '/usr/local/bin/sudo /usr/local/bin/rrdtool');\n    define('NELTOOL_RRDSYSBASE',    NELTOOL_SYSTEMBASE . 'graphs_output/');\n    define('NELTOOL_RRDWEBBASE',    NELTOOL_SITEBASE . 'graphs_output/');\n\n\tdefine('NELTOOL_SITETITLE', 'MT Admin');\n\tdefine('NELTOOL_SESSIONID', 'sid');\n\n\tdefine('NELTOOL_DEBUG', true);\n\n\t// SQL table names\n\tdefine('NELDB_PREFIX',\t\t\t\t\t\t'neltool_');\n\n\t// for later use\n\t// the config table will gather some of the settings\n\t// that are currently written in this config.php file\n\t//define('NELDB_CONFIG_TABLE', \t\t\t\tNELDB_PREFIX .'config');\n\n\tdefine('NELDB_USER_TABLE', \t\t\t\t\tNELDB_PREFIX .'users');\n\tdefine('NELDB_GROUP_TABLE', \t\t\t\tNELDB_PREFIX .'groups');\n\n\tdefine('NELDB_LOG_TABLE',\t\t\t\t\tNELDB_PREFIX .'logs');\n\tdefine('NELDB_NOTE_TABLE',\t\t\t\t\tNELDB_PREFIX .'notes');\n\n\tdefine('NELDB_STAT_HD_TIME_TABLE',\t\t\tNELDB_PREFIX .'stats_hd_times');\n\tdefine('NELDB_STAT_HD_TABLE',\t\t\t\tNELDB_PREFIX .'stats_hd_datas');\n\n\tdefine('NELDB_ANNOTATION_TABLE',\t\t\tNELDB_PREFIX .'annotations');\n\tdefine('NELDB_LOCK_TABLE',\t\t\t\t\tNELDB_PREFIX .'locks');\n\n\tdefine('NELDB_APPLICATION_TABLE',\t\t\tNELDB_PREFIX .'applications');\n\tdefine('NELDB_GROUP_APPLICATION_TABLE',\t\tNELDB_PREFIX .'group_applications');\n\tdefine('NELDB_USER_APPLICATION_TABLE',\t\tNELDB_PREFIX .'user_applications');\n\n\tdefine('NELDB_DOMAIN_TABLE',\t\t\t\tNELDB_PREFIX .'domains');\n\tdefine('NELDB_USER_DOMAIN_TABLE',\t\t\tNELDB_PREFIX .'user_domains');\n\tdefine('NELDB_GROUP_DOMAIN_TABLE',\t\t\tNELDB_PREFIX .'group_domains');\n\n\tdefine('NELDB_SHARD_TABLE',\t\t\t\t\tNELDB_PREFIX .'shards');\n\tdefine('NELDB_USER_SHARD_TABLE',\t\t\tNELDB_PREFIX .'user_shards');\n\tdefine('NELDB_GROUP_SHARD_TABLE',\t\t\tNELDB_PREFIX .'group_shards');\n\n\tdefine('NELDB_RESTART_GROUP_TABLE',\t\t\tNELDB_PREFIX .'restart_groups');\n\tdefine('NELDB_RESTART_MESSAGE_TABLE',\t\tNELDB_PREFIX .'restart_messages');\n\tdefine('NELDB_RESTART_SEQUENCE_TABLE',\t\tNELDB_PREFIX .'restart_sequences');\n\n\tdefine('VIEW_DELAY', 0);\n\tdefine('HARDWARE_REFRESH',\t600);\n    define('LOCK_TIMEOUT',      1800);\n    define('BG_IMG',            'imgs/bg_live.png');\n\n\t$nel_user_group_levels\t= array(array(\t'level_id'\t\t=>\t0,\n\t\t\t\t\t\t\t\t\t\t\t'level_name'\t=>\t'Normal'),\n\t\t\t\t\t\t\t\t\tarray(\t'level_id'\t\t=>\t10,\n\t\t\t\t\t\t\t\t\t\t\t'level_name'\t=>\t'Administrator'),\n\t\t\t\t\t\t\t\t\t);\n\n\t$restart_notification_emails = array('li9chuan@qq.com');\n\n?>\n"
  },
  {
    "path": "tools/server/admin/crons/cron_harddisk.php",
    "content": "<?php\n\n    ob_start();\n    set_time_limit(180); // 3 min time out\n\n    define('NELTOOL_NO_USER_NEEDED',    true);\n    define('NELTOOL_CRON_DEBUG',        false);\n\n\tif ($_GET['dbg']) define('NELTOOL_CRON_DEBUG', true);\n\n\tif (defined('NELTOOL_CRON_DEBUG')) echo \"Checking HDs ... \\n\";\n\n\trequire_once('../common.php');\n\trequire_once('../functions_tool_main.php');\n\n\t$domainList = tool_admin_domains_get_list();\n\t$service_command = \"aes.execScript df\";\n\tif (defined('NELTOOL_CRON_DEBUG')) echo \"domainList\\n\". print_r($domainList,true) .\"\\n\";\n\n\t$aesList = array();\n\n\tif (is_array($domainList))\n\t{\n\t\treset($domainList);\n\t\tforeach($domainList as $domain_data)\n\t\t{\n\t\t\tif ($domain_data['domain_hd_check'] == 1)\n\t\t\t{\n\t\t\t\t//echo '<pre>'. print_r($domain_data, true) .'</pre>';\n\n\t\t\t\t$adminService = new MyAdminService;\n\t\t\t\tif (@$adminService->connect($domain_data['domain_as_host'], $domain_data['domain_as_port'], $res) !== false)\n\t\t\t\t{\n\t\t\t\t\t$status\t\t\t= $adminService->getStates();\n\t\t\t\t\t$domainServices\t= tool_main_parse_status($status);\n\t\t\t\t\t$aesList\t\t= tool_main_get_aes_from_status($domainServices);\n\n\t\t\t\t\t//echo '<pre>'. print_r($aesList, true) .'</pre>';\n\n\t\t\t\t\tif (sizeof($aesList))\n\t\t\t\t\t{\n\t\t\t\t\t\treset($aesList);\n\t\t\t\t\t\tforeach($aesList as $service)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// error\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$aes_df_result = $tpl->get_template_vars('tool_execute_result');\n\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\n\t\t\t\t\t\tif (defined('NELTOOL_NO_USER_NEEDED') && defined('NELTOOL_CRON_DEBUG')) echo '<pre>'. print_r($aes_df_result, true) .'</pre>';\n\n\t\t\t\t\t\ttool_main_update_hd_data_for_domain($domain_data['domain_id'], $aes_df_result);\n\t\t\t\t\t}\n\n\t\t\t\t\tunset($adminService);\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n\n\tif (defined('NELTOOL_CRON_DEBUG')) echo \"checked \". sizeof($aesList) .\" servers!\\n\";\n\n    if (defined('NELTOOL_CRON_DEBUG'))\n    {\n        if ($fp = fopen(\"./logs/checkdisk_\". date(\"YmdHis\", time()) .\".log\", \"w\"))\n        {\n            fputs($fp, ob_get_contents());\n            fclose($fp);\n        }\n    }\n    \n    ob_end_clean();\n\n?>\n"
  },
  {
    "path": "tools/server/admin/crons/cron_harddisk.sh",
    "content": "#!/bin/sh\n\ncd /home/atrium-admin/public_html/crons\n/usr/bin/php4 cron_harddisk.php\ncd -\n"
  },
  {
    "path": "tools/server/admin/crons/index.html",
    "content": ""
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Filelist.xml",
    "content": "<xml xmlns:o=\"urn:schemas-microsoft-com:office:office\">\n <o:MainFile HRef=\"HOWTO_Restarting_Ryzom_Game_Shards.htm\"/>\n <o:File HRef=\"Hd36.xml\"/>\n <o:File HRef=\"Hu37.js\"/>\n <o:File HRef=\"H38.css\"/>\n <o:File HRef=\"Hz63.htm\"/>\n <o:File HRef=\"lt_off.gif\"/>\n <o:File HRef=\"lt_over.gif\"/>\n <o:File HRef=\"rt_off.gif\"/>\n <o:File HRef=\"rt_over.gif\"/>\n <o:File HRef=\"Hn68.htm\"/>\n <o:File HRef=\"Hf69.htm\"/>\n <o:File HRef=\"HOWTO_Restarting_Ryzom_Game_Shards.htm\"/>\n <o:File HRef=\"Hg39_1.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg39_1.gif\"/>\n <o:File HRef=\"Hg41_2.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg41_2.gif\"/>\n <o:File HRef=\"Hg43_3.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg43_3.gif\"/>\n <o:File HRef=\"Hg45_4.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg45_4.gif\"/>\n <o:File HRef=\"Hg47_5.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg47_5.gif\"/>\n <o:File HRef=\"Hg49_6.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg49_6.gif\"/>\n <o:File HRef=\"Hg51_7.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg51_7.gif\"/>\n <o:File HRef=\"Hg53_8.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg53_8.gif\"/>\n <o:File HRef=\"Hg55_9.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg55_9.gif\"/>\n <o:File HRef=\"Hg57_10.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg57_10.gif\"/>\n <o:File HRef=\"Hg59_11.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg59_11.gif\"/>\n <o:File HRef=\"Hg61_12.htm\"/>\n <o:File HRef=\"\"/>\n <o:File HRef=\"Hg61_12.gif\"/>\n <o:File HRef=\"Filelist.xml\"/>\n</xml>"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/H38.css",
    "content": "BODY {background:#FFFFFF}\n\n.menuItem {\n\tfont-family:sans-serif; font-size:small;\n\twidth:220;padding-left:20;\n\tbackground-color:menu;\n\tcolor:black   \n}\n\n.highlightItem {\n\tfont-family:sans-serif; font-size:small;\n\twidth:220; padding-left:20;\n\tbackground-Color:highlight; color:white;\n}\n\n.navBar {\n\tbackground-Color:buttonface;\n}\n\n.oldNavBar {\n\tbackground-Color:black;\n}\n\n.pageView {\n\tbackground-Color:white;\n}\n\n.propViewer {\n\tbackground-Color:white;\n\tcolor: black;\n\tfont-family: Verdana;\n\tfont-style: italic;\n\tfont-weight: bold;\n\tfont-size: medium;\n\ttext-align: center;\n}\n\n.propViewerTABLE {\n\tbackground-Color: black;\n\tfont-weight: medium;\n\tborder-width: 1pt;\n\tborder-color: black;\n}\n\n.propViewerTHEAD {\n\tbackground-Color: rgb(230,230,230); \n\tcolor: black;\n\tfont-family: Verdana;\n\tfont-style: italic;\n\tfont-weight: medium;\n\tfont-size: small;\n}\n\n.propViewerHeaderSep {\n\tbackground-Color: black;\n\theight: 0pt;\n}\n\n.propViewerLines {\n\tbackground-Color: black;\n\theight: 2pt;\n}\n\n.propViewerTD {\n\tfont-family: Verdana;\n\tcolor: black;\n\tfont-size: x-small;\n\tfont-style: normal;\n\talign: center;\n}\n\n.propViewerEvenRow {\n\tbackground-Color: rgb(253,254,238);\n}\n\n.propViewerOddRow {\n\tbackground-Color: rgb(254,254,247); \n}\n\n.clTab {\n\tcursor:hand;\n\tbackground:buttonface;\n\tfont: 0.7em Arial;\n\tpadding-left:3px;\n\tpadding-right:3px;\n\ttext-align:center;\n}\n\n.clBorder {\n\tbackground:windowframe;\n\tfont:1pt;\n}\n\n.clScroll {\n\tfont:8pt Courier New;\n\tcolor:threeddarkshadow;\n\tcursor:default;\n\tline-height:10pt;\n}\n\n.clScroll2 {\n\tfont:10pt Arial;\n\tcolor:threeddarkshadow;\n\tcursor:default;\n\tline-height:11pt;\n}\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/H70_2.htm",
    "content": "<html>\n<head>\n<link rel=\"File-List\" href=\"Filelist.xml\">\n<title>Restarting Ryzom Game Shards</title>\n  <META NAME=\"Title\" CONTENT=\"Drawing1\">\n  <META NAME=\"Subject\" CONTENT=\"\">\n  <META NAME=\"Author\" CONTENT=\"Miller\">\n  <META NAME=\"Manager\" CONTENT=\"\">\n  <META NAME=\"Company\" CONTENT=\"nevrax\">\n  <META NAME=\"Category\" CONTENT=\"\">\n  <META NAME=\"Keywords\" CONTENT=\"\">\n  <META NAME=\"Description\" CONTENT=\"\">\n\n<script>\n<!--\nvar appVer = navigator.appVersion;\nvar msie = appVer.indexOf( \"MSIE \" );\nvar msieWin31 = (appVer.indexOf( \"Windows 3.1\" ) >= 0)\nvar isMac = (appVer.indexOf(\"Macintosh\") >= 0);\nvar ver = 0;\n\nif( msie >= 0 )\n\tver = parseFloat(appVer.substring(msie + 5, appVer.indexOf(\";\", msie)));\nelse\n\tver = parseInt(appVer);\n\nvar loadPage = true;\n\nif ( !(!msieWin31 && ((msie >= 0 && ver >= 4.0) || (msie < 0 && ver >= 4))) )\n{\n\tif (window.confirm(\"Your browser does not support features requred by this web page. Do you still want to load this page?\"))\n\t\twindow.location.href = \"Hg39_1.htm\";\n\n\tloadPage = false;\n}\n\nif ( loadPage )\n{\n\tif( msie >= 0 && ( (isMac && ver>=5) || (!isMac && ver>=4) ) )\n\t\twindow.location.replace(\"Hf69.htm\");\n\telse\n\t{\n\t\tif ( !msieWin31 && ((msie >= 0 && ver >= 3.02) || (msie < 0 && ver >= 3)) )\n\t\t\twindow.location.replace(\"Hf69.htm\");\n\t\telse\n\t\t\twindow.location.href = \"Hf69.htm\";\n\t}\n}\n//-->\n</script>\n</head>\n\n<frameset>\n <noframes>\n  <body>\n  <p>This page requires a browser that supports frames, your's doesn't.</p>\n  </body>\n </noframes>\n</frameset>\n</html>\n\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/HOWTO_Restarting_Ryzom_Game_Shards.htm",
    "content": "<html>\n<head>\n<title></title>\n<script>\n<!--\nvar appVer = navigator.appVersion;\nvar msie = appVer.indexOf( \"MSIE \" );\nvar msieWin31 = (appVer.indexOf( \"Windows 3.1\" ) >= 0)\nvar isMac = (appVer.indexOf(\"Macintosh\") >= 0);\nvar ver = 0;\n\nif( msie >= 0 )\n\tver = parseFloat(appVer.substring(msie + 5, appVer.indexOf(\";\", msie)));\nelse\n\tver = parseInt(appVer);\n\nif( msie < 0 && ver < 5 )\n\twindow.location.replace(\"H70_2.htm\");\n//-->\n</script>\n</head>\n\n<IFRAME src=\"H70_2.htm\" width=\"100%\" height=\"100%\" frameborder=\"1\" scrolling=\"auto\">\n\t<!-- No IFRAMEsupport --> \n</IFRAME>\n\n</html>\n\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hd36.xml",
    "content": "<VisioDocument xmlns=\"urn:schemas-microsoft-com:office:visio\">\n\t<DocumentProperties>\n\t\t<Title>Drawing1</Title>\n\t\t<HyperlinkBase href=\"\"></HyperlinkBase>\n\t</DocumentProperties>\n\t<Pages>\n\t\t<Page ID=\"0\" Name=\"Login\" NameU=\"Login\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{91046659-FA77-48AA-838A-13606C3334E1}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>1. Login to the Ryzom Admin tool.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.318897637795276</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{9694EB16-4F3E-45C6-AC40-A3F7C0563AD0}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<Text>Click the 'Main' button at the top right of the screen to get a view something like this:</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.925196850393698</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{E278AF4A-0A5C-4BCC-AC75-A8E6FE8361C4}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.444881889763779</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.471653543307085</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"4\" Name=\"Select Shard\" NameU=\"Select Shard\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{53468736-A9AF-404C-B1A9-A223BFC10EAC}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>2. Select the shard that you want to restart</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.318897637795274</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{93800CE6-47A4-46E4-B900-E5039B76B569}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.865354330708659</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{94487BB2-17A4-422E-927B-D2A6374093C2}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">0.590551181102362</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.566929133858269</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{5F962DD6-F08A-4685-A6CE-A59A6BA485CB}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.809004357293814</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.571398391822701</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"5\" Name=\"Lock The Shard\" NameU=\"Open Restart Interface\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{56F4C05F-E3AD-4A95-8828-B2469697E908}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>3. Click the 'lock shard' button to take control of the shard that you've selected \n\n</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.227356009930337</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.111767279090113</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{704902DF-2483-46CA-AA4B-CFABE2A95C3C}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.865354330708659</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{FEFABA33-0ACE-46A3-BD3A-53ECF294A55F}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>The pink 'restart sequence' button will appear</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.354717958339129</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.200787401574803</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{5052404E-0A6A-4304-BEDB-F52DB69B727B}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606298</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.747244094488188</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{D98A873E-5773-4FAF-A1FC-F149BB8B6FB1}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.722440944881890</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.999999999999998</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{0F99CEFB-BDAE-4F11-B4BE-B1CF3D1BB89B}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.330657900600900</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.004469257964431</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{222F2967-F340-4C22-A612-7C9907901A2C}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.283464566929134</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.881889763779529</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{5653314C-D54A-4E36-8771-5A38412A59DF}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.645618530522161</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.886359021743961</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"6\" Name=\"Open Restart Interface\" NameU=\"Page-5\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{BDE767EC-13C0-4B5B-8C25-BFE8C758C9E0}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>4. Click on the 'restart sequence' button</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913385</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.515748031496063</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{B328EC33-C001-400E-9D6A-16A5D8BC44FC}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.055118110236219</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{44C39972-0D7F-49E8-BD60-D350E169D9A1}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>You will be prompted to continue:</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.387357830271215</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{06DF5344-0785-4B93-BEFD-F16C5E1EAAF2}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.449803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">5.487795275590552</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{3FF55A02-8ABE-444F-8A0B-FBBA7BBB7DEC}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<Text>The restart sequence interface will appear below the shard services. It should have the following appearance:</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.216535433070866</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.429133858267717</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{ACEAE92A-DDAE-4B1F-959B-3282BA71E40C}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606297</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">1.961417322834646</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{EB575663-AC91-4B5A-B31A-331DE34E463B}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.283464566929134</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.196850393700787</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{67BF0A86-B828-477F-B836-334E7513C9F9}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.645618530522159</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.201319651665219</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"9\" UniqueID=\"{1F3DAC6E-25BA-4538-9976-2ACCADA7AE0D}\" Name=\"Sheet.9\" NameU=\"Sheet.9\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.661417322834646</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">0.866141732283465</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"10\" UniqueID=\"{74395526-F3F7-4925-811A-D7D049F7DF35}\" Name=\"Sheet.10\" NameU=\"Sheet.10\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.545224829734759</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">0.791870832767583</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"7\" Name=\"Stop The Shard\" NameU=\"Stop The Shard\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{31E77A8F-693D-4B1F-BE50-117E8FE519D8}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>5. Click on the 'Stop the Shard' button\n</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913385</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.391951006124234</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{DA027A63-AE68-4DDC-9B3E-61AB026CCA38}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.055118110236219</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{E7E9498A-7BC7-4857-8981-722B704A3B55}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>You will be prompted to continue</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.344887613645888</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.397637795275591</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{92D07E73-83DC-492B-B007-4DD0DB5F08ED}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.950590551181103</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">5.487795275590552</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{CB7D0DE0-1727-4ECF-8117-0F65CAAF1623}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<Text>WARNING: Pressing this button has a direct effect on the game. Don't press this button unless you are sure of what you're doing.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913385</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.330708661417323</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{12203F01-74D5-4FB9-9748-2E500C409BBD}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.011811023622047</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.759842519685039</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{A962D7F8-DF38-4EDC-9DF1-EF4B55CE7319}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.492075223435546</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.764311777649471</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"9\" UniqueID=\"{9894559C-FA13-48E4-ADDE-7527A933B3A3}\" Name=\"Sheet.9\" NameU=\"Sheet.9\">\n\t\t\t\t\t<Text>Pressing OK here will broadcast a message to all players who are logged in telling them that shard will be shut down and will prevent new players from logging in.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.838582677165354</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.740157480314961</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"12\" UniqueID=\"{44AFCC79-A261-4B30-AFAE-C8CE2F0C4007}\" Name=\"Sheet.12\" NameU=\"Sheet.12\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.215551181102361</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.671259842519685</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"13\" UniqueID=\"{0BAA1F29-B8A5-471D-9E4B-C883C52D6361}\" Name=\"Sheet.13\" NameU=\"Sheet.13\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.539640283161631</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.517154135620743</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"14\" UniqueID=\"{E4E0E8D6-0149-494F-9AD4-9D0A60B32CDD}\" Name=\"Sheet.14\" NameU=\"Sheet.14\">\n\t\t\t\t\t<Text>Clicking the ‘Cancel’ Button will close the ‘Restart Interface’ without any effect on the shard</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">8.169291338582674</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.169291338582676</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"8\" Name=\"Wait For Shard To Stop\" NameU=\"Wait While Shard Stops\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{C7B5CE63-9315-41B7-93F9-29F1E51232D2}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>During this time messages are broadcast to the players warning them that the game shard is going to be stopped and that they should log out</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.200787401574803</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.122047244094491</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{B3693731-3147-4AFE-AE09-462FF2A7E4E3}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>This sequence starts automatically when the 'Step 1' timer reaches zero.\nDuring this time persistent data is saved and the game services shut down cleanly</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.413385826771653</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.677165354330715</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{F7564B18-B62A-4608-B3EF-39F0A0701BF6}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<Text>When the 'Step 2' timer reaches zero, the 'Running State' column should read 'stopped' for all services.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.291338582677165</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.232283464566931</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{9ACC6263-A071-41F5-9849-FEB5EDDC5931}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913385</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.654330708661423</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{558E6563-9759-445F-B371-B20920CFEFDD}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.021653543307086</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.874803149606306</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"14\" UniqueID=\"{79DD6E3E-E59C-495C-B49A-07C9FEA2C9CB}\" Name=\"Sheet.14\" NameU=\"Sheet.14\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.444881889763779</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">5.121456692913391</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"15\" UniqueID=\"{3DD6FC05-D7B8-4288-B28F-16BE9C4375C0}\" Name=\"Sheet.15\" NameU=\"Sheet.15\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.441535433070867</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">1.835236220472441</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"16\" UniqueID=\"{3C313C95-E3AD-4898-9C7B-074F25E9ADA4}\" Name=\"Sheet.16\" NameU=\"Sheet.16\">\n\t\t\t\t\t<Text>6. Wait for the shutdown sequence to begin</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.133858267716535</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.515748031496065</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"17\" UniqueID=\"{F2FCE633-315B-404D-A488-59B6CA352B5D}\" Name=\"Sheet.17\" NameU=\"Sheet.17\">\n\t\t\t\t\t<Text>7. Wait for the shutdown sequence to go through.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.003937007874015</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.169291338582683</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"22\" UniqueID=\"{F79C068C-AE31-4E35-9A2B-70A1FB8D03CE}\" Name=\"Sheet.22\" NameU=\"Sheet.22\">\n\t\t\t\t\t<Text>If this is not the case then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.452755905511811</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-0.688976377952756</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"23\" UniqueID=\"{AD8AA1FB-658F-41BE-82AF-94AFB6547B71}\" Name=\"Sheet.23\" NameU=\"Sheet.23\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606298</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-2.319291338582677</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"20\" UniqueID=\"{A72A4857-0D9D-47B1-8950-7817FF995CEF}\" Name=\"Sheet.20\" NameU=\"Sheet.20\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.841535433070866</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-2.834645669291338</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"21\" UniqueID=\"{716965B1-2BE1-4F9C-BC30-A97A0FE77C28}\" Name=\"Sheet.21\" NameU=\"Sheet.21\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.559988609262317</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-2.830176411326904</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"13\" UniqueID=\"{F15AB4DE-5320-4E74-B095-3B163AC8B72A}\" Name=\"Sheet.13\" NameU=\"Sheet.13\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.235236220472441</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.881889763779526</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"18\" UniqueID=\"{CB1A76CA-3E0C-4CC2-880D-CA80A0578FEA}\" Name=\"Sheet.18\" NameU=\"Sheet.18\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.539640283161631</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.716890432038076</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{B206D675-FF7D-40A9-BEE2-B0C6C000256A}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.511760262805623</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.879272407570738</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"19\" UniqueID=\"{5B2C41F6-96A7-4FFB-8E63-CEB046B7E636}\" Name=\"Sheet.19\" NameU=\"Sheet.19\">\n\t\t\t\t\t<Text>Clicking the ‘Cancel’ Button will abort the shutdown sequence and allow players to login to the shard</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">8.169291338582676</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.350393700787400</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"9\" Name=\"Restart 1/4\" NameU=\"Restart 1/4\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{257D7146-9FCF-4EFB-8425-900F469A375A}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>8. Start the start sequence by pressing the '1/4 - Start Low Level' button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.232283464566929</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.278433945756781</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{94A82F74-C565-4116-9301-590BB88C33B6}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<Text>The services will start launching</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.232283464566929</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.972440944881889</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{F2FE4233-25DF-4BE8-98F5-4EAA471D3075}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.688582677165352</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{ED749B20-77FE-49E1-A210-5B63FC35F4A5}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<Text>9. Click on the shard name every few seconds or so to update the view until the 'ts', 'ms' and 'rns' services are all running.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">7.244094488188976</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">2.854330708661416</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{F8A20637-DBD7-4590-9F73-DCBA7230246A}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">5.518897637795275</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{35599E83-EC04-4D59-94AE-3A0F15DD9D0A}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.175196850393701</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.389763779527558</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{4A6902B5-E486-4C19-85C3-C755CCF74F85}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.684988609262318</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.394233037491990</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{5B926AFF-7FA9-429F-BC35-528E4DA2B296}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.279527559055118</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.694881889763780</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"9\" UniqueID=\"{687A6544-E301-4E0E-97FC-178DC4387FE4}\" Name=\"Sheet.9\" NameU=\"Sheet.9\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.104279947844995</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.886359021743958</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"10\" UniqueID=\"{D39AA23A-1D8B-444F-A7CD-EC7C32F4F557}\" Name=\"Sheet.10\" NameU=\"Sheet.10\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.269685039370079</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.799212598425196</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"11\" UniqueID=\"{0E162B7C-00AB-435B-8073-8D60578C0E07}\" Name=\"Sheet.11\" NameU=\"Sheet.11\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.104279947844995</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.803681856389628</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"12\" UniqueID=\"{FEA9BAB7-28A1-469A-A8CE-D982D57F1DAD}\" Name=\"Sheet.12\" NameU=\"Sheet.12\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.269685039370079</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.330708661417321</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"13\" UniqueID=\"{E4DFF36B-07DB-4355-B9EA-CF012A76D02B}\" Name=\"Sheet.13\" NameU=\"Sheet.13\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.104279947844995</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.335177919381754</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"14\" UniqueID=\"{D55F9F74-DEB2-492D-AD85-648575ED5702}\" Name=\"Sheet.14\" NameU=\"Sheet.14\">\n\t\t\t\t\t<Text>The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s'\nThis step should only take a few seconds</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314960</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">2.362204724409448</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"15\" UniqueID=\"{51711FC0-116D-4ACF-8A4A-84FBCCBAD2D1}\" Name=\"Sheet.15\" NameU=\"Sheet.15\">\n\t\t\t\t\t<Text>If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314960</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">1.870078740157480</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"17\" UniqueID=\"{3EF00317-FD9D-44CE-BC58-6DFB7C441A46}\" Name=\"Sheet.17\" NameU=\"Sheet.17\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">0.239763779527558</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"18\" UniqueID=\"{FFD0135C-E7F2-40DA-92E6-3CA4ABADA802}\" Name=\"Sheet.18\" NameU=\"Sheet.18\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.841535433070867</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-0.275590551181102</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"19\" UniqueID=\"{8C263C36-B033-4921-BB78-247E64CFFF31}\" Name=\"Sheet.19\" NameU=\"Sheet.19\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.559988609262317</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-0.271121293216669</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"10\" Name=\"Restart 2/4\" NameU=\"Restart 2/4\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{85ED2C5D-1C7F-46F5-870D-F2D3DDF0AB21}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>10. Click on the '2/4 - Start Mid Level' button to continue the start sequence</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.133858267716535</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.278433945756781</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{0218F1DB-9A95-4880-A45F-18B28D0A2D9B}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.688582677165353</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{1A376A9E-242A-4750-BE5B-F7B3487D433D}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>The main game services will be started... they will take a minute or two to initialise so patience is required.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.708661417322834</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.169291338582678</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{C9D5EFB4-71DB-4694-BA18-E7F7246C8B11}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<Text>11. Click on the shard name every few seconds or so to update the view until the 'egs', 'ios' and 'gpms' services are all running.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">7.677165354330708</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.578740157480314</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{11E32F08-8437-419C-B657-A83A6394B6C5}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.155511811023622</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.251968503937007</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{6FE2B0F7-62D3-4139-AF16-008A3F59B8E8}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.675146089577279</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.256437761901440</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"28\" UniqueID=\"{ABB078BF-224D-4767-9A45-B0A5D67126A3}\" Name=\"Sheet.28\" NameU=\"Sheet.28\">\n\t\t\t\t\t<Text>The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s'\nThis step will generally take one or two minutes but may be a little longer. It should not exceed 5 minutes.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">7.775590551181102</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.086614173228346</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"29\" UniqueID=\"{4C8CAEF9-005B-4F3A-AC9F-D9C10B86A720}\" Name=\"Sheet.29\" NameU=\"Sheet.29\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.444881889763779</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.520472440944881</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"30\" UniqueID=\"{F712D519-205B-44B5-BE5C-A4F468E04235}\" Name=\"Sheet.30\" NameU=\"Sheet.30\">\n\t\t\t\t\t<Text>If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314961</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">2.066929133858268</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"34\" UniqueID=\"{15580980-71BB-471E-B8BD-9464640A6CE6}\" Name=\"Sheet.34\" NameU=\"Sheet.34\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.448228346456693</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">0.436614173228346</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"11\" Name=\"Restart 3/4\" NameU=\"Restart 3/4\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{C0392C49-02D5-484D-976B-0CD87E1C4D89}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>12. Click on the '3/4 - Start High Level' button to continue the start sequence</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.822834645669291</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.318897637795274</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{E5B99E4F-FC7E-4CD9-8EDF-CFE91F4B0F2A}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.688582677165353</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{90403A77-D05E-4759-B78C-70B23EB378FD}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>The AI services will be started... they will take a minute or so to initialise</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.960629921259843</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.972440944881889</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{0F371B65-D209-4F1A-BD97-91D1F0C7484B}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<Text>13. Click on the shard name every few seconds or so to update the view until the 'ais' services are all running.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.062992125984252</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">2.854330708661417</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{775ACF8D-1674-453D-A9E6-19B3BC449543}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220472</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">5.518897637795275</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{F44A8A30-F5AF-49DB-B507-6FDCD226FD77}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.155511811023622</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.114173228346456</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{49352680-CBFA-40FD-9FB3-143D20AC1838}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.675146089577279</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.118642486310888</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{C944A512-488B-4C7A-A015-7833E2D1775A}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.427165354330709</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.131889763779526</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"9\" UniqueID=\"{5517BBA3-2F01-4061-BD00-18C0A1015DA7}\" Name=\"Sheet.9\" NameU=\"Sheet.9\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.281158906272716</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.110971265772092</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"10\" UniqueID=\"{A3A03F60-E8E8-47EB-9678-42AD7434467C}\" Name=\"Sheet.10\" NameU=\"Sheet.10\">\n\t\t\t\t\t<Text>The 'running state' and 'state' columns for these services should both read 'online' and the 'Report' column should read '01s'\nThis step should take roughly one minute.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.496062992125983</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">2.362204724409448</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"11\" UniqueID=\"{7D7ECFF5-FB60-4F47-B80E-86B59E004422}\" Name=\"Sheet.11\" NameU=\"Sheet.11\">\n\t\t\t\t\t<Text>If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314960</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">1.870078740157481</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"12\" UniqueID=\"{DDCEC7BB-40E9-487F-A556-5E8AFA3378B7}\" Name=\"Sheet.12\" NameU=\"Sheet.12\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.448228346456692</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">0.239763779527558</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"12\" Name=\"Restart 4/4\" NameU=\"Restart 4/4\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{E9E9F9AE-15E5-4D41-A9D4-0ACC4A949AF0}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>14. Click on the '4/4 - Start Top Level' button to continue the start sequence</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.669291338582677</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.318897637795276</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{6396E82F-CC31-469C-9B8A-DE0F6276536F}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.688582677165353</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{65C4EB35-7385-4CBC-B0A6-EE84B1E08F15}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>The Front end communication services will be started</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.232283464566929</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.972440944881889</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{0D7D1297-D358-4699-84DA-FB7D80FD1F7B}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<Text>15. Click on the shard name every few seconds or so to update the view until ALL services are running.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.099628492123085</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.381889763779527</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{264B34C5-2D81-40FD-94FB-BCBF210D60B7}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.145669291338582</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.956692913385828</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{1A698E0F-72A8-4E80-9357-6F9F94447243}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.675146089577279</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.961162171350260</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"12\" UniqueID=\"{B8D5671C-1E1F-4932-8E95-8500346C233D}\" Name=\"Sheet.12\" NameU=\"Sheet.12\">\n\t\t\t\t\t<Text>The 'running state' and 'state' columns for ALL services should both read 'online' and the 'Report' column should read '01s'\nNOTE: The RWS service state will read ‘open’ when the other services read ‘online’.\nThis step should only take a few seconds.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.416119539372975</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.786526684164478</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"14\" UniqueID=\"{FB1DF6B6-0C39-4D54-9B49-415935ABA98C}\" Name=\"Sheet.14\" NameU=\"Sheet.14\">\n\t\t\t\t\t<Text>If the states don't update correctly then the developers should be contacted and you should click the ‘Give Up, Shard cannot be started’ button.</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314961</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">1.476377952755906</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"15\" UniqueID=\"{93CDC813-41D3-4D73-B2FB-DA534449AE2B}\" Name=\"Sheet.15\" NameU=\"Sheet.15\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.448228346456693</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">-0.153937007874017</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"21\" UniqueID=\"{2BAFD75E-F18C-4298-9D8D-1DD5BCBE7E90}\" Name=\"Sheet.21\" NameU=\"Sheet.21\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.444881889763779</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.047047244094488</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"13\" Name=\"Hand Over To Customer Support\" NameU=\"Hand Over To Customer Support\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{42C447C9-9AD0-4C18-AD6D-A29B7C10556F}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>16. Click on the 'Hand Over to Customer Support' button to finish the start sequence</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.566929133858268</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.318897637795276</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{D5C588D5-6461-461E-8A83-5E2E5449DAB6}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.343110236220473</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">9.688582677165353</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{3B45D0ED-78FF-4450-BB23-788CBEDDF4CC}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>The shard is now open in restricted mode - the customer support team can log in and check that everything is ok before the shard opens\nThe customer support volunteers can now open the shard to the players when they are ready</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.035433070866141</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">7.785870516185478</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{EA816466-9F16-48B6-9775-FAE624D2205C}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<Text>17. Click on the 'Done' button to exit the 'restart sequence' interface</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.232283464566930</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.988188976377953</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{F14AE284-B99B-4797-A050-EEEDFE9D8190}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.591141732283464</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{CB130AE9-8699-4502-A3F4-8ACC6A2B0FB0}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">2.942913385826772</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.818897637795274</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"7\" UniqueID=\"{EBCAFF62-237E-438D-8721-3015E0ABF8DC}\" Name=\"Sheet.7\" NameU=\"Sheet.7\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">5.472390184065468</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.823366895759707</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"8\" UniqueID=\"{00336F69-60AA-409F-A8BB-BD12F93E6155}\" Name=\"Sheet.8\" NameU=\"Sheet.8\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.240157480314961</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.011811023622048</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"9\" UniqueID=\"{C31975B7-2A4A-439A-875D-D6CC02B9969C}\" Name=\"Sheet.9\" NameU=\"Sheet.9\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">6.564909869104838</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">3.016280281586480</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t\t<Page ID=\"14\" Name=\"Unlock Shard\" NameU=\"Unlock Shard\">\n\t\t\t<Shapes>\n\t\t\t\t<Shape ID=\"1\" UniqueID=\"{F782C94F-C0B9-46FF-BE0D-EA77C795405B}\" Name=\"Sheet.1\" NameU=\"Sheet.1\">\n\t\t\t\t\t<Text>18. Click on the 'Unlock Shard' button to finish</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">11.278433945756781</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"2\" UniqueID=\"{0608B00D-9D95-49E4-A9FA-406420B65696}\" Name=\"Sheet.2\" NameU=\"Sheet.2\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">8.921850393700787</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"3\" UniqueID=\"{6F7A8B9A-2058-4DD5-8007-3FF3B03B6423}\" Name=\"Sheet.3\" NameU=\"Sheet.3\">\n\t\t\t\t\t<Text>You should be back to a view that looks something like this:</Text>\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.346456692913386</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">6.397637795275590</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"4\" UniqueID=\"{15BA5C88-518E-44AB-B7CE-CB3BC34524D1}\" Name=\"Sheet.4\" NameU=\"Sheet.4\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">3.349803149606299</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">4.000590551181102</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"5\" UniqueID=\"{EFFD49D9-5552-44FE-9DD4-B82C89B1615C}\" Name=\"Sheet.5\" NameU=\"Sheet.5\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">1.771653543307087</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.019685039370080</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t\t<Shape ID=\"6\" UniqueID=\"{AC6B9CC9-5D5E-4A40-9358-021097808101}\" Name=\"Sheet.6\" NameU=\"Sheet.6\">\n\t\t\t\t\t<XForm>\n\t\t\t\t\t\t<PinX Unit=\"MM\">4.379870499026097</PinX>\n\t\t\t\t\t\t<PinY Unit=\"MM\">10.004469257964434</PinY>\n\t\t\t\t\t</XForm>\n\t\t\t\t</Shape>\n\t\t\t</Shapes>\n\t\t</Page>\n\t</Pages>\n</VisioDocument>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hf69.htm",
    "content": "<html>\n<head>\n<title>\nRestarting Ryzom Game Shards\n</title>\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar g_NavBarLoaded = g_TitleBarLoaded = false; \n\nfunction FileEntry (pageID, pageName, priImage, secImage) \n{\n\tthis.PageID\t  = pageID;\n\tthis.PageName = pageName;\n\tthis.PriImage = priImage;\n\tthis.SecImage = secImage;\n}\n\ng_FileList = new  Array(\n new FileEntry (0, \"Login\", \"Hg39_1.htm\", \"\"),\n new FileEntry (4, \"Select Shard\", \"Hg41_2.htm\", \"\"),\n new FileEntry (5, \"Lock The Shard\", \"Hg43_3.htm\", \"\"),\n new FileEntry (6, \"Open Restart Interface\", \"Hg45_4.htm\", \"\"),\n new FileEntry (7, \"Stop The Shard\", \"Hg47_5.htm\", \"\"),\n new FileEntry (8, \"Wait For Shard To Stop\", \"Hg49_6.htm\", \"\"),\n new FileEntry (9, \"Restart 1/4\", \"Hg51_7.htm\", \"\"),\n new FileEntry (10, \"Restart 2/4\", \"Hg53_8.htm\", \"\"),\n new FileEntry (11, \"Restart 3/4\", \"Hg55_9.htm\", \"\"),\n new FileEntry (12, \"Restart 4/4\", \"Hg57_10.htm\", \"\"),\n new FileEntry (13, \"Hand Over To Customer Support\", \"Hg59_11.htm\", \"\"),\n new FileEntry (14, \"Unlock Shard\", \"Hg61_12.htm\", \"\")\n\n);\n\nvar g_SupportingFileList = new Array (\n\t\"Hd36.xml\",\n\t\"\",\n\t\"\",\n\t\"Hn68.htm\",\n\t\"Hz63.htm\"\n);\n\nvar FileIndex_XML\t= 0;\nvar FileIndex_CP\t= 1;\nvar FileIndex_Nav\t= 2;\nvar FileIndex_Nav2\t= 3;\nvar FileIndex_Zoom\t= 4;\n\nvar FrameCP\t\t\t= '<frame name=\"frmCustProp\" src=\"' + g_SupportingFileList[FileIndex_CP] + '\" frameborder=\"yes\" scrolling=\"auto\">';\nvar FramePageView\t= '<frame name=\"frmPageView\" src=\"javascript:parent.BlankPage(' + \"'white'\" + ')\" frameborder=\"no\" scrolling=\"auto\">';\nvar FrameNavBar\t\t= '<frame name=\"frmNavBar\" src=\"javascript:parent.BlankPage(' + \"'white'\" + ')\" frameborder=\"no\" scrolling=\"no\">';\nvar FrameZoom\t\t= '<frame name=\"frmZoomBox\" src=\"' + g_SupportingFileList[FileIndex_Zoom] + '\" frameborder=\"yes\" scrolling=\"no\">';\nvar FramePlaceHolder= '<frame name=\"frmPlaceHolder\" src=\"javascript:parent.BlankPage(' + \"'white'\" + ')\" frameborder=\"no\" scrolling=\"no\" noresize>';\n\nfunction HTMLExport() { } \ng_theApp = new HTMLExport();\n\ng_theApp.ActiveViewMgr = null;\ng_theApp.PageUpdateFunc = null;\ng_theApp.ZoomResetFunc = null;\ng_theApp.CPResetFunc = null;\ng_theApp.custPropEntryPoint = null;\ng_theApp.VisDocName = \"Restarting Ryzom Game Shards.vsd\";\ng_theApp.VisDocPath = \"C:\\\\Documents and Settings\\\\Miller\\\\Bureau\\\\\";\ng_theApp.FileList = g_FileList;\ng_theApp.CurrentPageIX = -1;\ng_theApp.DocHasBaseHL = false;\ng_theApp.objParser = null;\ng_theApp.appVer = navigator.appVersion;\ng_theApp.isNav = (navigator.appName == \"Netscape\")\ng_theApp.verNav = 0;\n\ng_theApp.PriFormatMinIE\t\t\t= 3.00;\ng_theApp.PriFormatMinNav\t\t= 3.00;\ng_theApp.PriFormatSupportsZoom\t= 0;\ng_theApp.SecFormatMinIE\t\t\t= 0.00;\ng_theApp.SecFormatMinNav\t\t= 0.00;\ng_theApp.SecFormatSupportsZoom\t= 0;\n\nvar msie = g_theApp.appVer.indexOf( \"MSIE \" );\n\ng_theApp.isIE = (msie >= 0);\ng_theApp.verIE = 0;\n\nif (g_theApp.isIE)\n{\n\tg_theApp.verIE = parseFloat(g_theApp.appVer.substring(msie + 5, g_theApp.appVer.indexOf(\";\", msie)));\n\n\tif (g_theApp.verIE >= 5.0)\n\t{\n\t\tg_theApp.objParser = new ActiveXObject(\"Microsoft.XMLDOM\");\n\t\n\t\t// Instruct the parser to use synchronous data transfer\n\t\tg_theApp.objParser.async = false;\n\t\n\t\t// Call the load method of the XML parser object, passing in the path to\n\t\t// the file containing the XML data\n\t\tg_theApp.objParser.load(g_SupportingFileList[FileIndex_XML]);\n\t\tif (g_theApp.objParser.parseError.errorCode != 0)\n\t\t{\n\t\t\tg_theApp.objParser = null;\n\t\t}\n\n\t\tif (g_theApp.objParser != null)\n\t\t{\n\t\t\tvar baseHyperlink = g_theApp.objParser.selectSingleNode(\"VisioDocument/DocumentProperties/HyperlinkBase\");\n\t\t\tif (baseHyperlink != null && baseHyperlink.attributes != null)\n\t\t\t{\n\t\t\t\tvar basehref = baseHyperlink.attributes.getNamedItem (\"href\");\n\t\t\t\tg_theApp.DocHasBaseHL = (basehref != null && basehref.text.length > 0)\n\t\t\t}\n\t\t}\n\t}\n}\nelse\n{\n\tg_theApp.verNav = parseInt(g_theApp.appVer);\n}\n\n// Create the HTML frameset. \nCreateDocument ();\n\nfunction BlankPage(color) \n{\n\tif ( (null != color) && (\"\" == color) )\n\t\tcolor = \"black\"; \n\n\treturn \"<html><body bgcolor='\" + color + \"'></body></html>\";\n}\n\nfunction LoadFrames()\n{\n\tif (g_theApp.isIE && g_theApp.verIE >= 5.0)\n\t{ \n\t\tif (this.frmNavBar != null)\n\t\t{\n\t\t\t// Load the newer version of the nav bar if it was created, otherwise, \n\t\t\t// load the older one. \n\t\t\tvar strNavBarFile = g_SupportingFileList[FileIndex_Nav];\n\t\t\tif (strNavBarFile.length <= 0)\n\t\t\t{\n\t\t\t\tstrNavBarFile = g_SupportingFileList[FileIndex_Nav2];\n\t\t\t}\n\n\t\t\tthis.frmNavBar.location.replace (strNavBarFile);\n\t\t}\n\t}\n\telse \n\t{\n\t\tif (this.frmNavBar != null)\n\t\t{\n\t\t\tthis.frmNavBar.location.replace (g_SupportingFileList[FileIndex_Nav2]);\n\t\t}\n\t}\n\n\t// Load the first page. \n\tGoToPage (0);\n}\n\nfunction CreateFrameset (frame1, frame2, framesetAttrs, defaultFramesetAttrs)\n{\n\tif (frame1 != null && frame1.length > 0 && \n\t\tframe2 != null && frame2.length > 0)\n\t{\n\t\tvar strFrameset;\n\n\t\tstrFrameset = \"<frameset \" + framesetAttrs + \">\";\n\t\tstrFrameset += frame1;\n\t\tstrFrameset += frame2;\n\t\tstrFrameset += \"</frameset>\";\n\n\t\treturn strFrameset;\n\t}\n\telse if (frame1 != null && frame1.length > 0)\n\t{\n\t\tif (defaultFramesetAttrs != null && defaultFramesetAttrs.length > 0)\n\t\t{\n\t\t\treturn CreateFrameset (frame1, \" \", defaultFramesetAttrs, \"\");\n\t\t}\n\t\treturn frame1;\n\t}\n\telse if (frame2 != null && frame2.length > 0)\n\t{\n\t\tif (defaultFramesetAttrs != null && defaultFramesetAttrs.length > 0)\n\t\t{\n\t\t\treturn CreateFrameset (\" \", frame2, defaultFramesetAttrs, \"\");\n\t\t}\n\t\treturn frame2;\n\t}\n\n\treturn \"\";\n}\n\nfunction CreateDocument ()\n{\n\tvar frameCPText = \"\";\n\tvar frameNavBarText = \"\";\n\tvar frameZoomText = \"\";\n\n\t// Does the current output format support zooming? \n\tif (ZoomAvailable ())\n\t{\n\t\tframeZoomText = FrameZoom;\n\t}\n\n\t// Do we want a nav bar?\n\tif (g_FileList.length > 1 &&\n\t\t(g_SupportingFileList[FileIndex_Nav].length > 0 || \n\t\t g_SupportingFileList[FileIndex_Nav2].length > 0))\n\t{\n\t\tframeNavBarText = FrameNavBar;\n\t}\n\n\t// Do we have a prop viewer file, and does this browser support XML? \n\tif (g_SupportingFileList[FileIndex_CP].length > 0 &&\n\t\tg_SupportingFileList[FileIndex_XML].length > 0 &&\n\t\tSupportsXML () &&\n\t\tg_theApp.objParser != null)\n\t{\n\t\tframeCPText = FrameCP;\n\t}\n\n\t// Create a frameset with the nav bar/zoom\n\tvar frmsetNavZoom = CreateFrameset (frameNavBarText, frameZoomText, 'name=\"frmsetNavBar\" cols=\"*,120\"', \"\");\n\n\t// Now put that frameset inside another frameset. This one will contain the actual\n\t// output pages. \n\tvar frmsetOutput = CreateFrameset (FramePageView, \n\t\t\t\t\t\t\t\t\t   frmsetNavZoom, \n\t\t\t\t\t\t\t\t\t   'rows=\"*,30\" framespacing=0 onload=\"LoadFrames()\"',\n\t\t\t\t\t\t\t\t\t   '');//'rows=\"*\" framespacing=0 onload=\"LoadFrames()\"');\n\n\t// Now put this frameset inside another one. This one will contain the \n\t// custom property viewer as well. \n\tvar frmsetTotal = CreateFrameset (frameCPText, frmsetOutput, 'cols=\"25%,75%\" onload=\"LoadFrames()\"', \"\");\n\n\t// One last check to make sure that we actually have a frameset to load. \n\tif (frmsetTotal == FramePageView)\n\t{\n\t\tfrmsetTotal = CreateFrameset (FramePageView, FramePlaceHolder, 'rows=\"100%,0\" onload=\"LoadFrames()\"', \"\");\n\t}\n\n\tdocument.write (frmsetTotal);\n}\n\n//-->\n</script>\n</head>\n\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg39_1.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 0;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg39_1.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg41_2.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 4;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg41_2.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg43_3.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 5;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg43_3.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg45_4.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 6;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg45_4.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg47_5.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 7;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg47_5.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg49_6.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 8;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg49_6.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg51_7.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 9;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg51_7.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg53_8.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 10;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg53_8.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg55_9.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 11;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg55_9.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg57_10.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 12;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg57_10.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg59_11.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 13;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg59_11.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hg61_12.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<title>\nRestarting Ryzom Game Shards\n</title>\n\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nvar pageID = 14;\n\nfunction BodyOnLoad ()\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tPageUpdated(pageIndex);\n\t}\n}\n\n//-->\n</script>\n</head>\n\n<body class=\"pageView\" bgcolor=\"#FFFFFF\" onload=\"BodyOnLoad()\" onclick=\"clickMenu()\">\n<base target=\"_top\">\n\n<div id=menu1 \n  onclick=\"clickMenu()\" \n  onmouseover=\"toggleMenu()\" \n  onmouseout=\"toggleMenu()\" \n  style=\"position:absolute; \n         display:none; \n         border: 2px outset black; \n         width:220; \n         background-color:menu; \n\t\t z-index:10\"> \n</div> \n\n<DIV id=RasterDiv>\n\n<center>\n  <IMG SRC=\"Hg61_12.gif\" ALT=\"\" BORDER=\"0\" USEMAP=\"#visImageMap\">\n</center>\n\n<MAP NAME=\"visImageMap\">\n</MAP>\n\n\n\n</DIV>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hn68.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\nif (g_theApp.isNav)\n\t{\n\twindow.captureEvents(Event.RESIZE);\n\twindow.onresize=handleResize;\n\t}\n\nfunction NavBarOnLoad()\n\t{\n\tif( IsFrame(\"frmNavBar\" ) )\n\t\t{\n\t\tLoadDiv('NavBar', UpdateNavBar, InitNavBar);\n\t\tparent.g_NavBarLoaded = true;\n\n\t\tg_theApp.PageUpdateFunc = UpdateNavBar;\n/*\n\t\tif ( ZoomAvailable() )\n\t\t\t{\n\t\t\tif ( null != (div = new CDiv('divZoom', document)) )\n\t\t\t\tdiv.Show();\n\n\t\t\tdocument.zoomForm.zoomFactor.onchange();\n\t\t\t}\n*/\n\t\tGoToPage(0);\n\t\t}\n\t\t\n\treturn;\n\t}\n\nfunction NavBarOnUnload ()\n\t{\n\tg_theApp.PageUpdateFunc = null;\n\t}\n\nfunction LoadDiv(divId, initProc, loadProc)\n\t{\n\tif ( g_theApp.isIE )\n\t\t{\n\t\tdocument.ondragstart=CancelDrag;\n\t\tdocument.onselectstart=CancelDrag;\n\t\t}\n\t\n\tif ( !g_theApp.isNav )\n\t\t{\n\t\tdocument.body.style.margin = 2\n\t\tdocument.body.style.top = 0;\n\t\t}\n\t\n\tif ( initProc != null )\n\t\tinitProc();\n\t\t\n\tif ( loadProc != null)\n\t\tloadProc();\n\t\n\tif ( null != (div = new CDiv(divId, document)) )\n\t\tdiv.Show();\n\t}\n\nfunction InitNavBar()\n\t{\n/*\n\tif ( g_theApp.isIE )\n\t\t{\n\t\tdiv = new CImage('btnPrev');\n\t\tdiv.put_Title(jsLoadString(IDS_TITLE_PREVPAGE));\n\t\t\t\n\t\tdiv = new CImage('btnNext');\n\t\tdiv.put_Title(jsLoadString(IDS_TITLE_NEXTPAGE));\n\t\t}\n*/\n\t}\n\nfunction UpdateNavBar()\n\t{\n\tvar entry;\n\t\n\tix = 0;\n\tentry = g_theApp.FileList[g_theApp.CurrentPageIX];\n\n\tif ( null != entry )\n\t\tix = g_theApp.CurrentPageIX;\n\n\tif ( null != (theForm = GetPageForm()) )\n\t\t{\n\t\tif (theForm.pageSelect != null)\n\t\t\t{\n\t\t\ttheForm.pageSelect.selectedIndex = ix;\n\t\t\t}\n\t\t}\n\t}\n\nfunction SelectPage()\n\t{\n\ttheForm = GetPageForm();\n\n\tvar selectedIndex = theForm.pageSelect.selectedIndex;\n\tGoToPage(parseInt(theForm.pageSelect[selectedIndex].value));\n\t}\n\nfunction GetPageForm()\n\t{\n\treturn FindForm('pageForm', document);\n\t}\n\n//-->\n</script>\n\n\n</head>\n<body class=\"oldNavBar\" onload=\"NavBarOnLoad()\" onunload=\"NavBarOnUnload()\" bgcolor=\"#000000\" link=\"#000000\" vlink=\"#000000\" alink=\"#000000\" topmargin=0>\n\n<div id=\"NavBar\" name=\"NavBar\" align=\"center\" style=\"position:absolute;top:0;width:100%;\">\n\n<table width=\"100&#37;\" cellpadding=\"0\" cellspacing=\"0\">\n<tr>\n\n<td valign=\"top\" nowrap align=\"center\">\n<form id=\"pageForm\" name=\"pageForm\">\n<script>\n<!--\nif ( document.images )\n\t{\n\tm_ltOut  = new Image(); m_ltOut.src = \"lt_off.gif\";\n\tm_ltOver = new Image(); m_ltOver.src = \"lt_over.gif\";\n\tm_ltDown = new Image(); m_ltDown.src = \"lt_click.gif\";\n\tm_rtOut  = new Image(); m_rtOut.src = \"rt_off.gif\";\n\tm_rtOver = new Image(); m_rtOver.src = \"rt_over.gif\";\n\tm_rtDown = new Image(); m_rtDown.src = \"rt_click.gif\";\n\t}\n\nfunction imgOver(id) { if ( document.images ) document.images[id].src = eval(\"m_\" + id + \"Over.src\"); }\nfunction imgOut(id)  { if ( document.images ) document.images[id].src = eval(\"m_\" + id + \"Out.src\"); }\n//-->\n</script>\n<a href=\"javascript:GoToPrevPage()\" onMouseOver=\"javascript:imgOver('lt');\" onMouseOut=\"javascript:imgOut('lt');\">\n<img src=\"lt_off.gif\" name=\"lt\" id=\"lt\" border=\"0\" WIDTH=\"26\" HEIGHT=\"18\">\n</a>\n<select id=\"pageSelect\" name=\"pageSelect\" onchange=\"javascript:SelectPage();\">\n<script>\n<!--\nfor ( var i in g_theApp.FileList )\n\t{\n\tdocument.write('<option value=\"' + i + '\"');\n\n\tif ( i == 0 )\n\t\tdocument.write(' selected');\n\n\tdocument.write('>' + html_escape(g_theApp.FileList[i].PageName) + '</option>');\n\t}\n//-->\n</script>\n</select>\n<a href=\"javascript:GoToNextPage()\" onMouseOver=\"javascript:imgOver('rt');\" onMouseOut=\"javascript:imgOut('rt');\">\n<img src=\"rt_off.gif\" id=\"rt\" name=\"rt\" border=\"0\" WIDTH=\"26\" HEIGHT=\"18\">\n</a>\n</form>\n</td>\n\n</tr></table>\n\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hu37.js",
    "content": "\nvar g_theApp = parent.g_theApp;\n\nvar layerRef=\"\";\nvar layerStyleRef = \"\";\nvar styleSwitch = \"\";\nvar FILEProtocol = \"file://\";\nvar HTTPProtocol = \"http://\";\n\nif (navigator.appName == \"Netscape\")\n\t{\n\tlayerStyleRef=\"layer.\";\n\tlayerRef=\"document.layers\";\n\tstyleSwitch=\"\";\n\t}\nelse\n\t{\n\tlayerStyleRef=\"layer.style.\";\n\tlayerRef=\"document.all\";\n\tstyleSwitch=\".style\";\n\t}\n\nfunction CImage(id)\n\t{\n\tthis.id = id;\n\n\tif ( g_theApp.isIE )\n\t\tthis.image = eval('document.images.' + this.id);\n\telse\n\t\tthis.image = eval('document.images[\"' + this.id + '\"]');\n\n\tthis.put_Source = SetSource;\n\tthis.get_Source = GetSource;\n\tthis.put_Title = put_Title;\n\tthis.get_Title = get_Title;\n\t}\n\nfunction SetSource(newsrc)\n\t{\n\tif ( this.image )\n\t\tthis.image.src = newsrc;\n\t}\n\nfunction GetSource()\n\t{\n\tif ( this.image )\n\t\treturn this.image.src;\n\t}\n\nfunction put_Title(txt)\n\t{\n\tif ( this.image && g_theApp.isIE )\n\t\tthis.image.title = txt;\n\t}\n\nfunction get_Title(txt)\n\t{\n\tif ( this.image && g_theApp.isIE )\n\t\treturn this.image.title;\n\t}\n\nfunction CDiv(id, doc)\n\t{\n\tthis.id = id;\n\tthis.layer = FindLayer(id, doc);\n\n\tthis.Show = Show;\n\tthis.Hide = Hide;\n\tthis.IsHidden = IsHidden;\n\tthis.put_innerHTML = put_innerHTML;\n\t}\n\nfunction Show()\n\t{\n\tif ( this.layer )\n\t\teval('this.' + layerStyleRef + 'visibility' + '= \"visible\"');\n\t}\n\nfunction Hide()\n\t{\n\tif ( this.layer )\n\t\teval('this.' + layerStyleRef + 'visibility' + '= \"hidden\"');\n\t}\n\nfunction IsHidden()\n\t{\n\tif ( this.layer && \n\t\t (-1 != eval('this.' + layerStyleRef + 'visibility').indexOf(\"hid\")) )\n\t\treturn true;\n\t\n\treturn false;\n\t}\n\nfunction put_innerHTML(txt)\n\t{\n\tif ( this.layer )\n\t\t{\n\t\tif ( g_theApp.isIE )\n\t\t\tthis.layer.innerHTML = txt;\n\t\telse\n\t\t\t{\n\t\t\tthis.layer.document.writeln(txt);\n\t\t\tthis.layer.document.close();\n\t\t\t}\n\t\t}\n\t}\n\nfunction SetZoomControl(f)\n\t{\n\tif ( !parent.g_NavBarLoaded )\n\t\treturn;\n\n\tvar formZoom = FindForm(\"zoomForm\", parent.frmZoomBox.document);\n\tif (formZoom != null)\n\t\t{\n\t\ts = formZoom.zoomFactor;\n\n\t\tif ( -1 != f )\n\t\t\tf *= 100;\n\n\t\tfor ( i = 0 ; i < s.options.length ; i++ )\n\t\t\t{\n\t\t\tif ( s.options[i].value == f )\n\t\t\t\t{\n\t\t\t\ts.selectedIndex = i;\n\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\nfunction zoom_onchange(val)\n{\n\tif ( g_theApp.ActiveViewMgr )\n\t{\n\t\tif ( g_theApp.ActiveViewMgr.ZoomIsPresent == true)\n\t\t{\n\t\t\tg_theApp.ActiveViewMgr.put_Zoom(parseInt(val));\n\t\t}\n\t}\n}\n\nfunction CViewMgr()\n\t{\n//Set all zoom functions to null assuming the addons related\n//to the data will provide their own functions.\n\tthis.onResize = null;\n\tthis.put_Zoom = null;\n\tthis.get_Zoom = null;\n\tthis.ApplyZoom = null;\n\t\n\t//General functions.\n\tthis.onLoad = ViewMgrOnLoad;\n\tthis.put_Location = ViewMgrDefaultFind; //MUST BE SET FOR FIND FEATURE \n\tthis.ZoomIsPresent = false;\n\t}\n\nfunction ViewMgrOnLoad()\n\t{\n\tthis.id = \"ConvertedImage\";\n\tthis.zoomFactor = -1;\n\tthis.zoomLast = -1;\n\tthis.origWH = 1;\n\tthis.origWidth = 100;\n\n\tif ( g_theApp.isIE )\n\t{\n\t\tp = document.all;\n\t\tthis.s = document.all(this.id).style;\n\t\t\n\n\t\tif ( this.s )\n\t\t{\n\t\t\tthis.s.position = \"absolute\";\n\t\t\tthis.origWidth = this.s.pixelWidth;\n\t\t\tthis.origWH = this.s.pixelWidth / this.s.pixelHeight;\n\t\t}\n\t}\n\telse\n\t{\n\t\tthis.s = null;\n\t}\n\tSetZoomControl(this.zoomFactor);\n}\n\nfunction ViewMgrDefaultFind()\n{\n\treturn;\n}\n\nfunction handleResize()\n\t{\n\tlocation.reload();\n\treturn false;\n\t}\n\nfunction IsFrame(frameName)\n\t{\n\treturn window.name == frameName;\n\t}\n\nfunction UpdNavBar()\n\t{\n\tif (g_theApp.PageUpdateFunc != null)\n\t\tg_theApp.PageUpdateFunc ();\n\n\tif ( parent.g_NavBarLoaded )\n\t\t//parent.frmZoomBox.UpdateNavBar();\n\t\tparent.frmNavBar.UpdateNavBar();\n\t}\n\nfunction UpdZoom()\n\t{\n\tif (g_theApp.ZoomResetFunc != null)\n\t\tg_theApp.ZoomResetFunc ();\n\t}\n\nfunction UpdCPViewer()\n\t{\n\tif (g_theApp.CPResetFunc != null)\n\t\tg_theApp.CPResetFunc ();\n\t}\n\nfunction UpdTitleBar()\n\t{\n\tif ( parent.g_TitleBarLoaded )\n\t\tparent.frmTitleBar.UpdateTitleBar();\n\t}\n\nfunction GetCurPageNum()\t{ return g_theApp.CurrentPageIX; }\nfunction GetNumPages()\t\t{ return g_theApp.FileList.length; }\n\nfunction GoToNextPage()\t\t{ GoToPage(g_theApp.CurrentPageIX + 1); }\nfunction GoToPrevPage()\t\t{ GoToPage(g_theApp.CurrentPageIX - 1); }\nfunction GoToFirstPage()\t{ GoToPage(0); }\nfunction GoToLastPage()\t\t{ GoToPage(gDocTable.length - 1) };\n\nfunction GoToPage(ix)\n\t{\n\tvar entry;\n\n\tif ( (g_theApp != null) &&\n\t\t (ix != g_theApp.CurrentPageIX) && \n\t\t (null != (entry = g_theApp.FileList[ix])) )\n\t\t{\n\t\tvar newPage;\n\n\t\tif (SupportsPriOutputType ())\n\t\t\t{\n\t\t\tnewPage = entry.PriImage;\n\n\t\t\tif ( \"\" == newPage )\n\t\t\t\tnewPage = newPage = entry.SecImage;\n\t\t\t}\n\t\telse\n\t\t\tnewPage = entry.SecImage;\n\n\t\tif (frames[\"frmPageView\"] != null)\n\t\t\t{\n\t\t\tframes[\"frmPageView\"].window.location = newPage;\n\t\t\t}\n\t\telse\n\t\t\t{\n\t\t\tparent.frmPageView.location = newPage;\n\t\t\t}\n\n\t\tPageUpdated (ix);\n\t\t}\n\t}\n\nfunction PageUpdated (ix)\n{\n\tg_theApp.CurrentPageIX = ix;\n\tNotifyPageSyncs(ix);\n}\n\nfunction GoToPageByName(pageName)\n{\n\tvar pageIndex = PageIndexFromName (pageName);\n\tif (pageIndex >= 0)\n\t{\n\t\tGoToPage (pageIndex);\n\t}\n}\n\nfunction GoToPageByID(pageID)\n{\n\tvar pageIndex = PageIndexFromID (pageID);\n\tif (pageIndex >= 0)\n\t{\n\t\tGoToPage (pageIndex);\n\t}\n}\n\nfunction PageIndexFromName (pageName)\n{\n\tif (g_theApp != null)\n\t{\n\t\tvar entry;\n\n\t\tvar count;\n\t\tvar fileEntry;\n\t\tvar bFoundEntry = false;\n\t\tfor (count = 0; \n\t\t\t count < g_theApp.FileList.length && !bFoundEntry; \n\t\t\t count++)\n\t\t{\n\t\t\tfileEntry = g_theApp.FileList[count];\n\t\t\tif (pageName == fileEntry.PageName)\n\t\t\t{\n\t\t\t\treturn count;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn -1;\n}\n\nfunction PageIndexFromID (pageID)\n{\n\tif (g_theApp != null)\n\t{\n\t\tvar entry;\n\n\t\tvar count;\n\t\tvar fileEntry;\n\t\tvar bFoundEntry = false;\n\t\tfor (count = 0; \n\t\t\t count < g_theApp.FileList.length && !bFoundEntry; \n\t\t\t count++)\n\t\t{\n\t\t\tfileEntry = g_theApp.FileList[count];\n\t\t\tif (pageID == fileEntry.PageID)\n\t\t\t{\n\t\t\t\treturn count;\n\t\t\t}\n\t\t}\n\t}\n\treturn -1;\n}\n\nfunction ZoomAvailable()\n{\n\tif (SupportsPriOutputType () && g_theApp.FileList[0].PriImage != \"\")\n\t{\n\t\treturn g_theApp.PriFormatSupportsZoom;\n\t}\n\telse\n\t{\n\t\treturn (g_theApp.SecFormatSupportsZoom && g_theApp.FileList[0].SecImage != \"\");\n\t}\n}\n\nfunction NotifyPageSyncs(ix)\n\t{\n\tUpdNavBar();\n\tUpdTitleBar();\n\tUpdZoom();\n\tUpdCPViewer();\n\t}\n\nfunction HasPrevSld()\t{ return (GetCurPageNum() > 0); }\nfunction HasNextSld()\t{ return ((GetCurPageNum() + 1) < GetNumPages()); }\n\nfunction CancelDrag()\n\t{\n\twindow.event.cancelBubble=true;\n\twindow.event.returnValue=false\n\t}\n\nfunction html_escape(txt)\n\t{\n\tvar result = \"\";\n\n\tfor ( var i = 0 ; i < txt.length ; i++ )\n\t\t{\n\t\tif ( txt.charAt(i) == '&' )\n\t\t\tresult += \"&amp;\";\n\t\telse if ( txt.charAt(i) == '<' )\n\t\t\tresult += \"&lt;\";\n\t\telse if ( txt.charAt(i) == '>' )\n\t\t\tresult += \"&gt;\";\n\t\telse\n\t\t\tresult += txt.charAt(i);\n\t\t}\n\n\treturn result;\n\t}\n\nfunction FindForm(form, doc)\n\t{\n\tif ( g_theApp.isIE )\n\t\treturn doc.forms[form];\n\telse if ( null != doc )\n\t\t{\n\t\tif ( null != doc.forms )\n\t\t\t{\n\t\t\tfor ( i = 0 ; i < doc.forms.length ; i++ )\n\t\t\t\t{\n\t\t\t\tif ( form == doc.forms[i].name )\n\t\t\t\t\treturn doc.forms[i];\n\t\t\t\t}\n\t\t\t}\n\n\t\tif ( null != doc.layers )\n\t\t\t{\n\t\t\tfor ( i = 0 ; i < doc.layers.length ; i++ )\n\t\t\t\t{\n\t\t\t\tresult = FindForm(form, doc.layers[i].document);\n\n\t\t\t\tif ( null != result )\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\treturn null;\n\t}\n\nfunction FindLayer(layer, doc)\n\t{\n\tvar result = null;\n\n\tif ( g_theApp.isIE )\n\t\treturn doc.all(layer);\n\telse if ( (null != doc) && (null != doc.layers) )\n\t\t{\n\t\tfor ( i = 0 ; i < doc.layers.length ; i++ )\n\t\t\t{\n\t\t\tresult = doc.layers[i];\n\n\t\t\tif ( layer == result.name )\n\t\t\t\treturn result;\n\n\t\t\tresult = FindLayer(layer, result.document);\n\n\t\t\tif ( null != result )\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\treturn null;\n\t}\n\nfunction Unquote (str)\n{\n\tvar nStartIndex = 0;\n\tvar nEndIndex = str.length;\n\n\tif (str.charAt (0) == '\"')\n\t{\n\t\tnStartIndex = 1;\n\t}\n\n\tif (str.charAt (nEndIndex - 1) == '\"')\n\t{\n\t\tnEndIndex -= 1;\n\t}\n\n\treturn str.substring (nStartIndex, nEndIndex);\n}\n\nfunction ConvertXorYCoordinate(PosValue, OldMin, OldMax, NewMin, NewMax, MapBackwards)\n{\n//This is a simple conversion routine that changes from one system to another.\n\tvar OldMid = (OldMax - OldMin) / 2;\n\tvar NewMid = (NewMax - NewMin) / 2;\n\tvar ConvertResult = 1 * PosValue;\n\tConvertResult = ConvertResult - (OldMin + OldMid);\n\tConvertResult = ConvertResult / OldMid;\n\tif(MapBackwards != 0)\n\t{\n\t\tConvertResult = 0 - ConvertResult;\n\t}\n\tConvertResult = ConvertResult * NewMid;\n\tConvertResult = ConvertResult + (NewMin + NewMid);\n\treturn ConvertResult;\n}\n\nfunction GoToURL (defURL)\n{\n\tif ((g_theApp == null) || !SupportsXML () || (g_theApp.objParser == null))\n\t{\n\t\tif (defURL.indexOf (\"javascript:\") == 0)\n\t\t{\n\t\t\t// This is actually a function call, not a URL. \n\t\t\teval (defURL);\n\t\t\treturn;\n\t\t}\n\n\t\tparent.location = defURL;\n\t}\n}\n\nvar el;\nfunction showMenu(pageID, shapeID) {\n\n\tif (SupportsXML ())\n\t{\n\t\tvar shapeXML = FindShapeXML (pageID, shapeID);\n\t\tif (shapeXML != null)\n\t\t{\n\t\t\tCreateHLMenu (shapeXML);\n\n\t\t\t//ContextElement=window.event.srcElement;\n\t\t\tparent.frmPageView.menu1.style.leftPos += 10;\n\t\t\tparent.frmPageView.menu1.style.posLeft = event.clientX;\n\t\t\tparent.frmPageView.menu1.style.posTop = event.clientY;\n\t\t\tparent.frmPageView.menu1.style.display = \"\";\n\n\t\t\tvar clientWidth = event.srcElement.document.body.clientWidth;\n\t\t\tvar clientHeight = event.srcElement.document.body.clientHeight;\n\n\t\t\tvar menuWidth = parseInt (parent.frmPageView.menu1.style.width);\n\t\t\tvar margin = 10;\n\n\t\t\t// Figure out where to place the menu (X). \n\t\t\tvar menuX = event.clientX;\n\t\t\tif (event.clientX + parent.frmPageView.menu1.clientWidth > clientWidth)\n\t\t\t{\n\t\t\t\tmenuX = clientWidth - parent.frmPageView.menu1.clientWidth - margin;\n\t\t\t\tif (menuX < margin)\n\t\t\t\t{\n\t\t\t\t\tmenuX = margin;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Figure out where to place the menu (Y). \n\t\t\tvar menuY = event.clientY;\n\t\t\tif (event.clientY + parent.frmPageView.menu1.clientHeight > clientHeight)\n\t\t\t{\n\t\t\t\tmenuY = clientHeight - parent.frmPageView.menu1.clientHeight - margin;\n\t\t\t\tif (menuY < margin)\n\t\t\t\t{\n\t\t\t\t\tmenuY = margin;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tparent.frmPageView.menu1.style.posLeft = menuX;\n\t\t\tparent.frmPageView.menu1.style.posTop = menuY;\n\n\t\t\tparent.frmPageView.menu1.setCapture();\n\n\t\t\tevent.cancelBubble = true;\n\t\t}\n\t}\n}\n\nfunction toggleMenu() {\n\tel=event.srcElement;\n\tif (el.className==\"menuItem\") {\n\t  el.className=\"highlightItem\";\n\t} else if (el.className==\"highlightItem\") {\n\t  el.className=\"menuItem\";\n\t}\n}\n\nfunction clickMenu()\n{\n\tif (parent.frmPageView.menu1.style.display != \"none\")\n\t{\n\t\tparent.frmPageView.menu1.releaseCapture();\n\t\tparent.frmPageView.menu1.style.display=\"none\";\n\t\tel=event.srcElement;\n\t\tif (el.doFunction != null) {\n\t\t eval(el.doFunction);\n\t\t}\n\t}\n}\n\nfunction CreateHLMenu (shapeNode)\n{\n\t// Create the HTML string. \n\tvar strHLMenuHTML = \"\";\n\n\tif (shapeNode != null)\n\t{\n\t\t// Look up all the Hyperlink nodes. \n\t\tvar hlColl = shapeNode.selectNodes (\"Scratch/B/SolutionXML/HLURL:Hyperlinks/HLURL:Hyperlink\");\n\n\t\t// Walk the list of Hyperlink nodes to generate the menu.\n\t\tvar hlCount = hlColl.length;\n\t\tfor (var count = 0; count < hlCount; count++)\n\t\t{\n\t\t\tvar strDoFunction = \"\";\n\t\t\tvar strDesc = \"\";\n\t\t\tvar strAddress = \"\";\n\n\t\t\tvar hlAddress = hlColl.item(count).selectSingleNode(\"HLURL:Address/textnode()\");\n\t\t\tif (hlAddress != null && hlAddress.text.length > 0 && IsValidAddress (hlAddress.text))\n\t\t\t{\n\t\t\t\tstrDoFunction = \"'parent.location.href=\";\n\n\t\t\t\t// Get the absolute URL. \n\t\t\t\tvar absoluteURL = hlColl.item(count).selectSingleNode(\"HLURL:AbsoluteURL/textnode()\");\n\t\t\t\tif (g_theApp.DocHasBaseHL && absoluteURL != null && absoluteURL.text.length > 0)\n\t\t\t\t{\n\t\t\t\t\t// Use the absolute URL for our hyperlink. \n\t\t\t\t\tstrAddress = absoluteURL.text;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Just use the address field. \n\t\t\t\t\tstrAddress = hlAddress.text;\n\t\t\t\t}\n\n\t\t\t\tstrDoFunction += '\"' + EscapePath (strAddress) + '\"' + \";'\";\n\n\t\t\t\t// Now try to get the description field. If empty, use the address as the description. \n\t\t\t\thlDesc = hlColl.item(count).selectSingleNode(\"HLURL:Description/textnode()\");\n\t\t\t\tif (hlDesc != null && hlDesc.text.length > 0)\n\t\t\t\t{\n\t\t\t\t\tstrDesc = hlDesc.text;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tstrDesc = strAddress;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse // Address is not present, assume it's a link into a different page in this document. \n\t\t\t{\n\t\t\t\thlAddress = hlColl.item(count).selectSingleNode(\"HLURL:SubAddress/textnode()\");\n\t\t\t\tif (hlAddress != null && hlAddress.text.length > 0)\n\t\t\t\t{\n\t\t\t\t\tstrAddress = hlAddress.text;\n\n\t\t\t\t\t// Strip off the shape id (if present). \n\t\t\t\t\tvar pageShapeSep = strAddress.lastIndexOf ('/');\n\t\t\t\t\tif (pageShapeSep > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tstrAddress = strAddress.substring (0, pageShapeSep);\n\t\t\t\t\t}\n\n\t\t\t\t\tstrAddress = unescape(strAddress);\n\n\t\t\t\t\tvar pageIndex = PageIndexFromName (strAddress);\n\n\t\t\t\t\tstrDoFunction = \"'GoToPage (\" + pageIndex + \");'\";\n\n\t\t\t\t\t// Just set the description to the page name as well. \n\t\t\t\t\tstrDesc = strAddress;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (strDoFunction.length > 0 && strDesc.length > 0)\n\t\t\t{\n\t\t\t\tstrHLMenuHTML += \"<div class='menuItem' doFunction=\" + strDoFunction + \">\";\n\t\t\t\tstrHLMenuHTML += strDesc + \"</div>\";\n\t\t\t}\n\t\t}\n\t}\n\n\tparent.frmPageView.menu1.innerHTML = strHLMenuHTML;\n}\n\nfunction IsValidAddress (strAddress)\n{\n\tvar ret = false;\n\n\tif (strAddress != null && strAddress.length > 0)\n\t{\n\t\tvar strFullPath = g_theApp.VisDocPath + g_theApp.VisDocName;\n\n\t\tif (strAddress != strFullPath &&\n\t\t\tstrAddress != g_theApp.VisDocName)\n\t\t{\n\t\t\t// Points to something other than this file, go ahead \n\t\t\t// and consider it valid. \n\t\t\tret = true;\n\t\t}\n\t}\n\n\treturn ret;\n}\n\nfunction FindShapeXML (pageID, shapeID)\n{\n\tvar shapeObj = null;\n\n\tif (g_theApp != null && g_theApp.objParser != null)\n\t{\n\t\t// Get the Pages collection. \n\t\tvar pagesObj = g_theApp.objParser.selectSingleNode(\"VisioDocument/Pages\");\n\t\tif(!pagesObj)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\t// Get the correct page. \n\t\tvar pageQuerryString = './/Page[@ID = \"' + pageID + '\"]';\n\t\tvar pageObj = pagesObj.selectSingleNode(pageQuerryString);\n\t\tif(!pageObj)\n\t\t{\n\t\t\treturn null;\n\t\t}\n\n\t\t// Get the correct shape.\n\t\tvar shapeQuerryString = './/Shape[@ID = \"' + shapeID + '\"]';\n\t\tshapeObj = pageObj.selectSingleNode(shapeQuerryString);\n\t}\n\n\treturn shapeObj;\n}\n\nfunction UpdateProps(pageID, shapeID)\n{\n\t// Check to see if we should ignore this event. \n\tif (window.event != null &&\n\t\twindow.event.ctrlKey)\n\t{\n\t\t// If the control key is down, do nothing!\n\t\treturn;\n\t}\n\n\tif (SupportsXML ())\n\t{\n\t\tvar shape = FindShapeXML (pageID, shapeID);\n\n\t\tif (g_theApp.custPropEntryPoint != null)\n\t\t\tg_theApp.custPropEntryPoint (shape);\n\t}\n}\n\nfunction SupportsXML ()\n{\n\treturn (g_theApp != null && g_theApp.isIE && g_theApp.verIE >= 5.0);\n}\n\nfunction SupportsPriOutputType ()\n{\n\tif (g_theApp.isIE)\t// IE\n\t{\n\t\treturn ((g_theApp.verIE >= g_theApp.PriFormatMinIE) && (g_theApp.PriFormatMinIE > 0.0));\n\t}\n\telse if (g_theApp.isNav)\t// Nav\n\t{\n\t\treturn ((g_theApp.verNav >= g_theApp.PriFormatMinNav) && (g_theApp.PriFormatMinNav > 0.0));\n\t}\n\n\t// Unsupported browser. \n\treturn false;\n}\n\nfunction EscapePath (strPath)\n{\n\tvar strResult = \"\";\n\n\tfor ( var i = 0 ; i < strPath.length ; i++ )\n\t{\n\t\tif ( strPath.charAt(i) == '\\\\' )\n\t\t{\n\t\t\tstrResult += \"\\\\\\\\\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrResult += strPath.charAt(i);\n\t\t}\n\t}\n\n\treturn strResult;\n}\n"
  },
  {
    "path": "tools/server/admin/docs/shard_restart/Hz63.htm",
    "content": "<html>\n<head>\n<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"H38.css\">\n<script src=\"Hu37.js\"></script>\n<script>\n<!--\ng_theApp.ZoomResetFunc = ResetZoom;\n\nfunction ResetZoom()\n{\n\tvar formZoom = FindForm('zoomForm', document);\n\tformZoom.zoomFactor.selectedIndex = 0;\n}\n//-->\n</script>\n<style>\nbody { position:absolute;top:-5px; }\n#NavBar { position:absolute;top:0px;left:0px }\n</style>\n</head>\n<body class=\"navBar\">\n\n<div id=\"NavBar\" name=\"NavBar\">\n\n<table width=\"100&#37;\" cellpadding=\"0\" cellspacing=\"0\">\n<tr>\n\n<td valign=\"top\" nowrap align=\"center\">\n\n<td nowrap align=\"right\">\n<span id=\"divZoom\" name=\"divZoom\" style=\"position:relative;top:0px;\">\n<form id=\"zoomForm\" name=\"zoomForm\">\n<select id=\"zoomFactor\" name=\"zoomFactor\"\nonchange=\"javascript:zoom_onchange(zoomFactor[zoomFactor.selectedIndex].value)\">\n<option value=\"-1\" selected>Fit In Window\n<option value=\"1200\">1200&#37;\n<option value=\"800\">800&#37;\n<option value=\"600\">600&#37;\n<option value=\"400\">400&#37;\n<option value=\"200\">200&#37;\n<option value=\"150\">150&#37;\n<option value=\"100\">100&#37;\n<option value=\"75\">75&#37;\n<option value=\"50\">50&#37;\n<option value=\"25\">25&#37;\n</select>\n</form>\n</span>\n</td>\n\n</tr></table>\n\n</div>\n</body>\n</html>\n\n"
  },
  {
    "path": "tools/server/admin/functions_auth.php",
    "content": "<?php\n\n\t/*\n\t * THIS FILE SHOULD ONLY INCLUDE AUTHENTIFICATION RELATED FUNCTIONS\n\t */\n\n\tfunction nt_auth_set_logging_count($user_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"UPDATE \". NELDB_USER_TABLE .\" SET user_logged_count=user_logged_count+1,user_logged_last=\". time() .\" WHERE user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction nt_auth_load_user($nelid)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" LEFT JOIN \". NELDB_GROUP_TABLE .\" ON (user_group_id=group_id) WHERE user_id=\". $nelid;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction nt_auth_get_group_name($group_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"SELECT user_name FROM \". NELDB_USER_TABLE .\" WHERE user_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$row = $db->sql_fetchrow($result);\n\t\t\t\treturn $row['user_name'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction nt_auth_check_login($user,$passwd)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$user = trim($user);\n\t\t$passwd = md5(trim($passwd));\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" LEFT JOIN \". NELDB_GROUP_TABLE .\" ON (user_group_id=group_id) WHERE user_name='\". $user .\"' AND user_password='\". $passwd .\"' AND user_active=1 AND group_active=1\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\t\treturn $data;\n\t}\n\n\tfunction nt_auth_load_login()\n\t{\n\t\tglobal $tpl;\n\n\t\t$tpl->assign('tool_login_title','Login');\n\t\t$tpl->display('index_login.tpl');\n\t}\n\n   function nt_auth_start_session()\n\t{\n\t\tsession_name(NELTOOL_SESSIONID);\n\t\tsession_cache_limiter('nocache');\n\t\tsession_start();\n\n        header(\"Expires: Mon, 01 May 2000 06:00:00 GMT\");\n        header(\"Last-Modified: \" . gmdate(\"D, d M Y H:i:s\") . \" GMT\");\n        header(\"Cache-Control: no-store, no-cache, must-revalidate\");\n        header(\"Cache-Control: post-check=0, pre-check=0\", false);\n        header(\"Pragma: no-cache\");\n\t}\n\n    function nt_auth_stop_session()\n\t{\n\t\tglobal $NELTOOL;\n\n\t    foreach($NELTOOL['SESSION_VARS'] as $key => $val)\n\t    {\n\t      unset($NELTOOL['SESSION_VARS'][$key]);\n\t    }\n\t}\n\n    function nt_auth_set_session_var($name,$value)\n\t{\n        global $NELTOOL;\n\n        $NELTOOL['SESSION_VARS'][$name] = $value;\n\t}\n\n\tfunction nt_auth_get_session_var($name)\n\t{\n        global $NELTOOL;\n\n        if (isset($NELTOOL['SESSION_VARS'][$name])) return $NELTOOL['SESSION_VARS'][$name];\n        return null;\n\t}\n\n    function nt_auth_unset_session_var($name)\n\t{\n        global $NELTOOL;\n\n        unset($NELTOOL['SESSION_VARS'][$name]);\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_common.php",
    "content": "<?php\n\n\t/*\n\t * THIS FILE SHOULD ONLY INCLUDE SMALL USEFUL FUNCTIONS\n\t */\n\n\t/*\n\t * pushes some data in the debug variable\n\t */\n\tfunction nt_common_add_debug($data)\n\t{\n\t\tglobal $nel_debug;\n\n\t\tif (is_array($data))\t$nel_debug[] = print_r($data,true);\n\t\telse\t\t\t\t\t$nel_debug[] = $data;\n\t}\n\n\t/*\n\t * redirects to a defined url\n\t */\n    function nt_common_redirect($url)\n    {\n        $url = trim($url);\n        if (substr($url,0,1) == '/')    $url = substr($url,1);\n\n        $redirect = NELTOOL_SITEBASE . $url;\n\n        header(\"Location: \". $redirect);\n        exit();\n    }\n\n\t/*\n\t * adds a user action log\n\t */\n\tfunction nt_common_add_log($userinfo, $log_action, $log_desc)\n\t{\n\t\tglobal $db, $NELTOOL;\n\n\t\t$log_action = trim($log_action);\n\t\t$log_desc\t= trim($log_desc);\n\n\t\tif (!is_array($userinfo) && (!isset($userinfo['user_id'])))\treturn false;\n\t\tif ($log_action == '') \t\t\t\t\t\t\t\t\t\treturn false;\n\t\tif ($log_desc == '') \t\t\t\t\t\t\t\t\t\treturn false;\n\n\t\t$sql = \"INSERT INTO \". NELDB_LOG_TABLE .\" ('log_user_id','log_action','log_description','log_date','log_ip') VALUES ('\". $userinfo['user_id'] .\"','\". addslashes($log_action) .\"','\". addslashes($log_desc) .\"','\". time() .\"','\". $NELTOOL['SERVER_VARS']['REMOTE_ADDR'] .\"')\";\n\t\t$db->sql_query($sql);\n\n\t\treturn true;\n\t}\n\n\n\tif (!function_exists('array_combine'))\n\t{\n\t\tfunction array_combine( $keys, $vals )\n\t\t{\n\t\t\t$keys = array_values( (array) $keys );\n\t\t\t$vals = array_values( (array) $vals );\n\t\t\t$n = max( count( $keys ), count( $vals ) );\n\t\t\t$r = array();\n\t\t\tfor( $i=0; $i<$n; $i++ )\n\t\t\t{\n\t\t\t\t$r[ $keys[ $i ] ] = $vals[ $i ];\n\t\t\t}\n\t\t\treturn $r;\n\t\t}\n\t}\n\n\tif (!function_exists('array_chunk')) {\n\n\t\tfunction array_chunk($input,$size,$preserve_keys=false)\n\t\t{\n\t       @reset($input);\n\n\t       $i = $j = 0;\n\n\t       while (@list($key,$value) = @each($input))\n\t       {\n\t           if( !( isset( $chunks[$i] ) ) )\n\t           {\n\t               $chunks[$i] = array();\n\t           }\n\n\t           if( count( $chunks[$i] ) < $size )\n\t           {\n\t               if( $preserve_keys )\n\t               {\n\t                   $chunks[$i][$key] = $value;\n\t                   $j++;\n\t               }\n\t               else\n\t               {\n\t                   $chunks[$i][] = $value;\n\t               }\n\t           }\n\t           else\n\t           {\n\t               $i++;\n\n\t               if( $preserve_keys )\n\t               {\n\t                   $chunks[$i][$key] = $value;\n\t                   $j++;\n\t               }\n\t               else\n\t               {\n\t                   $j = 0;\n\t                   $chunks[$i][$j] = $value;\n\t               }\n\t           }\n\t       }\n\n\t       return $chunks;\n\t   }\n\t}\n\n\tfunction array_natsort_list($array)\n\t{\n\t\t// for all arguments without the first starting at end of list\n\t\tfor ($i=func_num_args();$i>1;$i--)\n\t\t{\n\t\t\t// get column to sort by\n\t\t\t$sort_by = func_get_arg($i-1);\n\n\t\t\t// clear arrays\n\t\t\t$new_array = array();\n\t\t\t$temporary_array = array();\n\n\t\t\t// walk through original array\n\t\t\tforeach($array as $original_key => $original_value)\n\t\t\t{\n\t\t\t\t// and save only values\n\t\t\t\t$temporary_array[] = $original_value[$sort_by];\n\t\t\t}\n\n\t\t\t// sort array on values\n\t\t\tnatsort($temporary_array);\n\n\t\t\t// delete double values\n\t\t\t$temporary_array = array_unique($temporary_array);\n\n\t\t\t// walk through temporary array\n\t\t\tforeach($temporary_array as $temporary_value)\n\t\t\t{\n\t\t\t\t// walk through original array\n\t\t\t\tforeach($array as $original_key => $original_value)\n\t\t\t\t{\n\t\t\t\t\t// and search for entries having the right value\n\t\t\t\t\tif($temporary_value == $original_value[$sort_by])\n\t\t\t\t\t{\n\t\t\t\t\t\t// save in new array\n\t\t\t\t\t\t$new_array[$original_key] = $original_value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// update original array\n\t\t\t$array = $new_array;\n\t\t}\n\n\t\treturn $array;\n\t}\n\n  \tfunction nt_common_assert( $script, $line, $message )\n  \t{\n  \t\tnt_common_add_debug('ASSERT ('. $script .':'. $line .') : '. ereg_replace( '^.*//\\*', '', $message ));\n\t\t//exit;\n\t}\n\n\tfunction nt_log($data)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\n\t\t$log_user_name\t= $nel_user['user_name'];\n\t\t$log_date\t\t= time();\n\t\t$log_data\t\t= addslashes(trim($data));\n\n\t\t$sql = \"INSERT INTO \". NELDB_LOG_TABLE .\" (`logs_user_name`,`logs_date`,`logs_data`) VALUES ('\". $log_user_name .\"','\". $log_date .\"','\". $log_data .\"')\";\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction nt_sleep($delay)\n\t{\n\t\tif ($delay > 0)\n\t\t{\n\t\t\tsleep($delay);\n\t\t}\n\t}\n\n\tfunction nt_email($subject,$message,$emails=null)\n\t{\n\t\tif ($message !== '' && $subject !== '')\n\t\t{\n\t\t\tif ($emails === null)\n\t\t\t{\n\t\t\t\t$emails = 'vl@ryzom.com';\n\t\t\t}\n\t\t\telseif (is_array($emails))\n\t\t\t{\n\t\t\t\t$emails = implode(', ', $emails);\n\t\t\t}\n\n\t\t\t$headers = \"From: vl@ryzom.com\\r\\nReply-To: vl@ryzom.com\\r\\nX-Mailer: Shard Admin Tool\\r\\n\";\n\t\t\tmail($emails, $subject, $message, $headers);\n\t\t}\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_mysql.php",
    "content": "<?php\n/***************************************************************************\n *                                 mysql.php\n *                            -------------------\n *   begin                : Saturday, Feb 13, 2001\n *   copyright            : (C) 2001 The phpBB Group\n *   email                : support@phpbb.com\n *\n *   $Id: functions_mysql.php,v 1.2 2006/07/06 15:17:22 powles Exp $\n *\n ***************************************************************************/\n\n/***************************************************************************\n *\n *   This program is free software; you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation; either version 2 of the License, or\n *   (at your option) any later version.\n *\n ***************************************************************************/\n\nif(!defined(\"SQL_LAYER\"))\n{\n\ndefine(\"SQL_LAYER\",\"mysql\");\n\nclass sql_db\n{\n\n\tvar $db_connect_id;\n\tvar $query_result;\n\tvar $row = array();\n\tvar $rowset = array();\n\tvar $num_queries = 0;\n\n\t//\n\t// Constructor\n\t//\n\tfunction sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true)\n\t{\n\n\t\t$this->persistency = $persistency;\n\t\t$this->user = $sqluser;\n\t\t$this->password = $sqlpassword;\n\t\t$this->server = $sqlserver;\n\t\t$this->dbname = $database;\n\n\t\tif($this->persistency)\n\t\t{\n\t\t\t$this->db_connect_id = mysql_pconnect($this->server, $this->user, $this->password);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$this->db_connect_id = mysql_connect($this->server, $this->user, $this->password);\n\t\t}\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\tif($database != \"\")\n\t\t\t{\n\t\t\t\t$this->dbname = $database;\n\t\t\t\t$dbselect = mysql_select_db($this->dbname);\n\t\t\t\tif(!$dbselect)\n\t\t\t\t{\n\t\t\t\t\tmysql_close($this->db_connect_id);\n\t\t\t\t\t$this->db_connect_id = $dbselect;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $this->db_connect_id;\n\t\t}\n\t\telse\n\t\t{\n\t\t\techo \"Connection to mySQL failed!\";\n\t\t\texit;\n\t\t}\n\t}\n\n\t//\n\t// Other base methods\n\t//\n\tfunction sql_close()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\tif($this->query_result)\n\t\t\t{\n\t\t\t\t@mysql_free_result($this->query_result);\n\t\t\t}\n\t\t\t$result = mysql_close($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t//\n\t// Base query method\n\t//\n\tfunction sql_query($query = \"\", $transaction = FALSE)\n\t{\n\t\t// Remove any pre-existing queries\n\t\tunset($this->query_result);\n\t\tif($query != \"\")\n\t\t{\n\t\t\tnt_common_add_debug($query);\n\t\t\t$this->num_queries++;\n\t\t\t$this->query_result = mysql_query($query, $this->db_connect_id);\n\t\t}\n\t\tif($this->query_result)\n\t\t{\n\t\t\tunset($this->row[$this->query_result]);\n\t\t\tunset($this->rowset[$this->query_result]);\n\t\t\treturn $this->query_result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn ( $transaction == 'END_TRANSACTION' ) ? true : false;\n\t\t}\n\t}\n\n\tfunction sql_select_db($dbname)\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysql_select_db($dbname, $this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\treturn false;\n\t}\n\tfunction sql_reselect_db()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysql_select_db($this->dbname, $this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\treturn false;\n\t}\n\t//\n\t// Other query methods\n\t//\n\tfunction sql_numrows($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysql_num_rows($query_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_affectedrows()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysql_affected_rows($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_numfields($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysql_num_fields($query_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fieldname($offset, $query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysql_field_name($query_id, $offset);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fieldtype($offset, $query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysql_field_type($query_id, $offset);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fetchrow($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$this->row[$query_id] = mysql_fetch_array($query_id);\n\t\t\treturn $this->row[$query_id];\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fetchrowset($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\tunset($this->rowset[$query_id]);\n\t\t\tunset($this->row[$query_id]);\n\t\t\twhile($this->rowset[$query_id] = mysql_fetch_array($query_id))\n\t\t\t{\n\t\t\t\t$result[] = $this->rowset[$query_id];\n\t\t\t}\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fetchfield($field, $rownum = -1, $query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\tif($rownum > -1)\n\t\t\t{\n\t\t\t\t$result = mysql_result($query_id, $rownum, $field);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif(empty($this->row[$query_id]) && empty($this->rowset[$query_id]))\n\t\t\t\t{\n\t\t\t\t\tif($this->sql_fetchrow())\n\t\t\t\t\t{\n\t\t\t\t\t\t$result = $this->row[$query_id][$field];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif($this->rowset[$query_id])\n\t\t\t\t\t{\n\t\t\t\t\t\t$result = $this->rowset[$query_id][$field];\n\t\t\t\t\t}\n\t\t\t\t\telse if($this->row[$query_id])\n\t\t\t\t\t{\n\t\t\t\t\t\t$result = $this->row[$query_id][$field];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_rowseek($rownum, $query_id = 0){\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysql_data_seek($query_id, $rownum);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_nextid(){\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysql_insert_id($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_freeresult($query_id = 0){\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\n\t\tif ( $query_id )\n\t\t{\n\t\t\tunset($this->row[$query_id]);\n\t\t\tunset($this->rowset[$query_id]);\n\n\t\t\t@mysql_free_result($query_id);\n\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_error($query_id = 0)\n\t{\n\t\t$result[\"message\"] = mysql_error($this->db_connect_id);\n\t\t$result[\"code\"] = mysql_errno($this->db_connect_id);\n\n\t\treturn $result;\n\t}\n\n} // class sql_db\n\nclass sql_db_string extends sql_db\n{\n\t//\n\t// Constructor ($connstring format : mysql://user:password@host/dbname)\n\t//\n\tfunction sql_db_string($connstring, $persistency = true)\n\t{\n\t\t$ret = false;\n\n\t\tif ($connstring != '')\n\t\t{\n\t\t\tif (ereg(\"^mysql\\:\\/\\/([^\\:]+)\\:([^\\@]+)\\@([^\\\\]+)\\/([^\\/]+)[\\/]?$\", $connstring, $params))\n\t\t\t{\n\t\t\t\t$sqlserver \t\t= $params[3];\n\t\t\t\t$sqluser\t\t= $params[1];\n\t\t\t\t$sqlpassword\t= $params[2];\n\t\t\t\t$database\t\t= $params[4];\n\n\t\t\t\t$ret = $this->sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency);\n\t\t\t}\n\t\t}\n\n\t\treturn $ret;\n\t}\n} // class sql_db_string\n\n\n} // if ... define\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_mysqli.php",
    "content": "<?php\n/***************************************************************************\n *                                 mysql.php\n *                            -------------------\n *   begin                : Saturday, Feb 13, 2001\n *   copyright            : (C) 2001 The phpBB Group\n *   email                : support@phpbb.com\n *\n *   $Id: functions_mysql.php,v 1.2 2006/07/06 15:17:22 powles Exp $\n *\n ***************************************************************************/\n\n/***************************************************************************\n *\n *   This program is free software; you can redistribute it and/or modify\n *   it under the terms of the GNU General Public License as published by\n *   the Free Software Foundation; either version 2 of the License, or\n *   (at your option) any later version.\n *\n ***************************************************************************/\n\n/***************************************************************************\n *\n * NOTE: this is striped down version from phpBB mysql.php file\n *       modified to work with mysqli\n *\n ***************************************************************************/\n\nif(!defined(\"SQL_LAYER\"))\n{\n\ndefine(\"SQL_LAYER\",\"mysqli\");\n\nclass sql_db\n{\n\n\tvar $db_connect_id;\n\tvar $query_result;\n\tvar $num_queries = 0;\n\n\t//\n\t// Constructor\n\t//\n\tfunction sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true)\n\t{\n\n\t\t$this->persistency = $persistency;\n\t\t$this->user = $sqluser;\n\t\t$this->password = $sqlpassword;\n\t\t$this->server = $sqlserver;\n\t\t$this->dbname = $database;\n\n\t\tif($this->persistency)\n\t\t{\n\t\t\t$this->server = 'p:'.$this->server;\n\t\t}\n\n\t\t$this->db_connect_id = mysqli_connect($this->server, $this->user, $this->password);\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\tif($database != \"\")\n\t\t\t{\n\t\t\t\t$this->dbname = $database;\n\t\t\t\t$dbselect = mysqli_select_db($this->db_connect_id, $this->dbname);\n\t\t\t\tif(!$dbselect)\n\t\t\t\t{\n\t\t\t\t\tmysqli_close($this->db_connect_id);\n\t\t\t\t\t$this->db_connect_id = $dbselect;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $this->db_connect_id;\n\t\t}\n\t\telse\n\t\t{\n\t\t\techo \"Connection to mySQL failed!\";\n\t\t\texit;\n\t\t}\n\t}\n\n\t//\n\t// Other base methods\n\t//\n\tfunction sql_close()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\tif($this->query_result)\n\t\t\t{\n\t\t\t\t@mysqli_free_result($this->query_result);\n\t\t\t}\n\t\t\t$result = mysqli_close($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t//\n\t// Base query method\n\t//\n\tfunction sql_query($query = \"\", $transaction = FALSE)\n\t{\n\t\t// Remove any pre-existing queries\n\t\tunset($this->query_result);\n\t\tif($query != \"\")\n\t\t{\n\t\t\tnt_common_add_debug($query);\n\t\t\t$this->num_queries++;\n\t\t\t$this->query_result = mysqli_query($this->db_connect_id, $query);\n\t\t}\n\t\tif($this->query_result)\n\t\t{\n\t\t\treturn $this->query_result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn ( $transaction == 'END_TRANSACTION' ) ? true : false;\n\t\t}\n\t}\n\n\tfunction sql_select_db($dbname)\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysqli_select_db($this->db_connect_id, $dbname);\n\t\t\treturn $result;\n\t\t}\n\t\treturn false;\n\t}\n\tfunction sql_reselect_db()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysqli_select_db($this->db_connect_id, $this->dbname);\n\t\t\treturn $result;\n\t\t}\n\t\treturn false;\n\t}\n\t//\n\t// Other query methods\n\t//\n\tfunction sql_numrows($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysqli_num_rows($query_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_affectedrows()\n\t{\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysqli_affected_rows($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_numfields($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\t$result = mysqli_num_fields($query_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\t// function sql_fieldname($query_id = 0){}\n\t// function sql_fieldtype($offset, $query_id = 0){}\n\tfunction sql_fetchrow($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\treturn mysqli_fetch_array($query_id);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_fetchrowset($query_id = 0)\n\t{\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\t\tif($query_id)\n\t\t{\n\t\t\twhile($row = mysqli_fetch_array($query_id))\n\t\t\t{\n\t\t\t\t$result[] = $row;\n\t\t\t}\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\t// function sql_fetchfield($field, $rownum = -1, $query_id = 0){}\n\t// function sql_rowseek($rownum, $query_id = 0){}\n\tfunction sql_nextid(){\n\t\tif($this->db_connect_id)\n\t\t{\n\t\t\t$result = mysqli_insert_id($this->db_connect_id);\n\t\t\treturn $result;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_freeresult($query_id = 0){\n\t\tif(!$query_id)\n\t\t{\n\t\t\t$query_id = $this->query_result;\n\t\t}\n\n\t\tif ( $query_id )\n\t\t{\n\t\t\t@mysqli_free_result($query_id);\n\n\t\t\treturn true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t}\n\tfunction sql_error($query_id = 0)\n\t{\n\t\t$result[\"message\"] = mysqli_error($this->db_connect_id);\n\t\t$result[\"code\"] = mysqli_errno($this->db_connect_id);\n\n\t\treturn $result;\n\t}\n\n} // class sql_db\n\nclass sql_db_string extends sql_db\n{\n\t//\n\t// Constructor ($connstring format : mysql://user:password@host/dbname)\n\t//\n\tfunction sql_db_string($connstring, $persistency = true)\n\t{\n\t\t$ret = false;\n\t\tif ($connstring != '')\n\t\t{\n\t\t\tif (preg_match(\"#^mysqli?://([^:]+)(?::([^@]*))?@([^\\\\/]+)/([^/]+)[/]?$#\", $connstring, $params))\n\t\t\t{\n\t\t\t\t$sqlserver\t\t= $params[3];\n\t\t\t\t$sqluser\t\t= $params[1];\n\t\t\t\t$sqlpassword\t= $params[2];\n\t\t\t\t$database\t\t= $params[4];\n\n\t\t\t\t$ret = $this->sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency);\n\t\t\t}\n\t\t}\n\n\t\treturn $ret;\n\t}\n} // class sql_db_string\n\n\n} // if ... define\n\n"
  },
  {
    "path": "tools/server/admin/functions_tool_administration.php",
    "content": "<?php\n\n\t$tool_admin_menu\t= array(array('title'\t=>\t'Main',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'help',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=help',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'', // ALWAYS LEAVE EMPTY !\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Users',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'users',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=users',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_users.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_user',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Groups',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'groups',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=groups',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_groups.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_group',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Restarts',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'restarts',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=restarts',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_restarts.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_restart',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Applications',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'applications',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=applications',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_applications.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_application',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Domains',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'domains',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=domains',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_domains.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_domain',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Shards',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'shards',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=shards',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_shards.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_shard',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Logs',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'logs',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_administration.php?toolmode=logs',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_administration_logs.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'tool_admin_logs',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\t);\n\n\t$tool_language_list\t= array(array('lang_id'\t\t=>\t'en',\n\t\t\t\t\t\t\t\t\t  'lang_name'\t=>\t'English',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('lang_id'\t\t=>\t'fr',\n\t\t\t\t\t\t\t\t\t  'lang_name'\t=>\t'French',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('lang_id'\t\t=>\t'de',\n\t\t\t\t\t\t\t\t\t  'lang_name'\t=>\t'German',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\t);\n\n\tfunction tool_admin_menu_get_item_from_key($key)\n\t{\n\t\tglobal $tool_admin_menu;\n\n\t\treset($tool_admin_menu);\n\t\tforeach($tool_admin_menu as $tool_menu)\n\t\t{\n\t\t\tif ($tool_menu['key'] == $key)\treturn $tool_menu;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_admin_users_get_list($group_list)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" ORDER BY user_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = array();\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\t$row['user_group_name'] = tool_admin_groups_get_name_from_id($group_list, $row['user_group_id']);\n\t\t\t\t\t$data[] = $row;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_get_user_list($group_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_group_id=\". $group_id .\" ORDER BY user_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" ORDER BY group_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\t$row['group_level_name'] = tool_admin_groups_get_level_name_from_id($row['group_level']);\n\t\t\t\t\t$data[] = $row;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_get_level_name_from_id($group_level)\n\t{\n\t\tglobal $nel_user_group_levels;\n\n\t\treset($nel_user_group_levels);\n\t\tforeach($nel_user_group_levels as $level_data)\n\t\t{\n\t\t\tif ($group_level == $level_data['level_id'])\n\t\t\t{\n\t\t\t\treturn $level_data['level_name'];\n\t\t\t}\n\t\t}\n\n\t\treturn tool_admin_groups_get_level_name_from_id(0);\n\t}\n\n\tfunction tool_admin_groups_get_name_from_id($group_list, $group_id)\n\t{\n\t\t$data = 'unknown';\n\n\t\treset($group_list);\n\t\tforeach($group_list as $group_data)\n\t\t{\n\t\t\tif ($group_data['group_id'] == $group_id)\n\t\t\t{\n\t\t\t\t$data = $group_data['group_name'];\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_get_id($user_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_id=\". $user_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_add($user_name, $user_password, $user_group, $user_active)\n\t{\n\t\tglobal $db;\n\n\t\t$user_name \t\t= trim($user_name);\n\t\t$user_password\t= trim($user_password);\n\n\t\tif ($user_name == '')\t\treturn \"/!\\ Error: user name is empty!\";\n\t\tif ($user_password == '')\treturn \"/!\\ Error: password is empty!\";\n\n\t\t$user_exists = tool_admin_users_name_exist($user_name);\n\t\tif (!$user_exists)\n\t\t{\n\t\t\t$sql  = \"INSERT INTO \". NELDB_USER_TABLE;\n\t\t\t$sql .= \" (`user_name`,`user_password`,`user_group_id`,`user_created`,`user_active`)\";\n\t\t\t$sql .= \" VALUES \";\n\t\t\t$sql .= \" ('\". $user_name .\"','\". md5($user_password) .\"','\". $user_group .\"','\". time() .\"','\". $user_active .\"')\";\n\t\t\t$db->sql_query($sql);\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn \"/!\\ Error: user name already exists in the database!\";\n\t}\n\n\tfunction tool_admin_users_name_exist($user_name)\n\t{\n\t\tglobal $db;\n\n\t\t$exists = false;\n\n\t\t$sql = \"SELECT user_id, user_name FROM \". NELDB_USER_TABLE .\" WHERE user_name='\". $user_name .\"'\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$exists = true;\n\t\t\t}\n\t\t}\n\n\t\treturn $exists;\n\t}\n\n\tfunction tool_admin_users_del($user_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_TABLE .\" WHERE user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_users_update($user_id, $user_name, $user_password, $user_group, $user_active)\n\t{\n\t\tglobal $db;\n\n\t\t$user_name\t\t= trim($user_name);\n\t\t$user_password\t= trim($user_password);\n\n\t\tif ($user_name == \"\") \t\t\t\t\t\treturn \"/!\\ Error: user name is empty!\";\n\t\tif (!ereg(\"^([[:alnum:]]+)$\",$user_name))\treturn \"/!\\ Error: invalid user name, only alpha numerical characters allowed!\";\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_name='\". $user_name .\"' AND user_id<>\". $user_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: user name already exists in database!\";\n\t\t\t}\n\t\t}\n\n\t\t$sql_ext = \"\";\n\t\tif ($user_password != '')\t$sql_ext = \",user_password='\". md5($user_password) .\"'\";\n\n\t\t$sql = \"UPDATE \". NELDB_USER_TABLE .\" SET user_name='\". $user_name .\"',user_group_id='\". $user_group .\"',user_active='\". $user_active .\"'\". $sql_ext .\" WHERE user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_groups_get_id($group_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" WHERE group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_add($group_name, $group_level, $group_default, $group_active)\n\t{\n\t\tglobal $db;\n\n\t\t$group_name = trim($group_name);\n\t\tif ($group_name == '')\t\treturn \"/!\\ Error: group name is empty!\";\n\n\t\t$group_exists = tool_admin_groups_name_exist($group_name);\n\t\tif (!$group_exists)\n\t\t{\n\t\t\tif ($group_default == 1)\n\t\t\t{\n\t\t\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_default=0\";\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\n\t\t\t$sql  = \"INSERT INTO \". NELDB_GROUP_TABLE;\n\t\t\t$sql .= \" (`group_name`,`group_level`,`group_default`,`group_active`) \";\n\t\t\t$sql .= \" VALUES \";\n\t\t\t$sql .= \" ('\". $group_name .\"',\". $group_level .\",\". $group_default .\",\". $group_active .\")\";\n\t\t\t$db->sql_query($sql);\n\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn \"/!\\ Error: group name already exists in the database!\";\n\t}\n\n\tfunction tool_admin_groups_name_exist($group_name)\n\t{\n\t\tglobal $db;\n\n\t\t$exists = false;\n\n\t\t$sql = \"SELECT group_id, group_name FROM \". NELDB_GROUP_TABLE .\" WHERE group_name='\". $group_name .\"'\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$exists = true;\n\t\t\t}\n\t\t}\n\n\t\treturn $exists;\n\t}\n\n\n\tfunction tool_admin_groups_del($group_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_TABLE .\" WHERE group_id=\". $group_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_groups_update($group_id, $group_name, $group_level, $group_default, $group_active)\n\t{\n\t\tglobal $db;\n\n\t\t$group_name = trim($group_name);\n\n\t\tif ($group_name == \"\")\t\t\t\t\t\treturn \"/!\\ Error: group name is empty!\";\n\t\tif (!ereg(\"^([[:alnum:]]+)$\",$group_name))\treturn \"/!\\ Error: invalid group name, only alpha numerical characters allowed!\";\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" WHERE group_name='\". $group_name .\"' AND group_id<>\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: group name already exists in database!\";\n\t\t\t}\n\t\t}\n\n\t\tif ($group_default == 1)\n\t\t{\n\t\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_default=0\";\n\t\t\t$db->sql_query($sql);\n\t\t}\n\n\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_name='\". $group_name .\"',group_level='\". $group_level .\"',group_default='\". $group_default .\"',group_active='\". $group_active .\"' WHERE group_id=\". $group_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_groups_update_default_domain($group_id, $domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" WHERE group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$row = $db->sql_fetchrow($result);\n\n\t\t\t\tif ($row['group_default_domain_id'] != $domain_id)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_default_domain_id=\". $domain_id .\",group_default_shard_id=0 WHERE group_id=\". $group_id;\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: invalid group id!\";\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_groups_update_default_shard($group_id, $shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" WHERE group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_default_shard_id=\". $shard_id .\" WHERE group_id=\". $group_id;\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: invalid group id!\";\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_groups_update_default_application($group_id, $application_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_TABLE .\" WHERE group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$sql = \"UPDATE \". NELDB_GROUP_TABLE .\" SET group_default_application_id=\". $application_id .\" WHERE group_id=\". $group_id;\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: invalid group id!\";\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\n\tfunction tool_admin_applications_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_APPLICATION_TABLE .\" ORDER BY application_order ASC, application_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_applications_get_id($application_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_APPLICATION_TABLE .\" WHERE application_id=\". $application_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_applications_add($application_name, $application_uri, $application_restriction, $application_icon, $application_order, $application_visible)\n\t{\n\t\tglobal $db;\n\n\t\t$application_name = trim($application_name);\n\t\tif ($application_name == '')\treturn \"/!\\ Error: application name is empty!\";\n\n\t\t$application_exists = tool_admin_applications_name_exist($application_name);\n\t\tif (!$application_exists)\n\t\t{\n\t\t\t$sql  = \"INSERT INTO \". NELDB_APPLICATION_TABLE;\n\t\t\t$sql .= \" (`application_name`,`application_uri`,`application_restriction`,`application_order`,`application_visible`,`application_icon`) \";\n\t\t\t$sql .= \" VALUES \";\n\t\t\t$sql .= \" ('\". $application_name .\"','\". $application_uri .\"','\". $application_restriction .\"','\". $application_order .\"','\". $application_visible .\"','\". $application_icon .\"')\";\n\t\t\t$db->sql_query($sql);\n\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn \"/!\\ Error: application name already exists in the database!\";\n\t}\n\n\tfunction tool_admin_applications_name_exist($application_name)\n\t{\n\t\tglobal $db;\n\n\t\t$exists = false;\n\n\t\t$sql = \"SELECT application_id, application_name FROM \". NELDB_APPLICATION_TABLE .\" WHERE application_name='\". $application_name .\"'\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$exists = true;\n\t\t\t}\n\t\t}\n\n\t\treturn $exists;\n\t}\n\n\tfunction tool_admin_applications_del($application_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_APPLICATION_TABLE .\" WHERE user_application_application_id=\". $application_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_APPLICATION_TABLE .\" WHERE group_application_application_id=\". $application_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_APPLICATION_TABLE .\" WHERE application_id=\". $application_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_applications_update($application_id, $application_name, $application_uri, $application_restriction, $application_icon, $application_order, $application_visible)\n\t{\n\t\tglobal $db;\n\n\t\t$application_name = trim($application_name);\n\t\tif ($application_name == \"\")\treturn \"/!\\ Error: application name is empty!\";\n\n\t\t$sql = \"SELECT * FROM \". NELDB_APPLICATION_TABLE .\" WHERE application_name='\". $application_name .\"' AND application_id<>\". $application_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: application name already exists in database!\";\n\t\t\t}\n\t\t}\n\n\t\t$sql = \"UPDATE \". NELDB_APPLICATION_TABLE .\" SET application_name='\". $application_name .\"',application_uri='\". $application_uri .\"',application_restriction='\". $application_restriction .\"',application_icon='\". $application_icon .\"',application_order='\". $application_order .\"',application_visible='\". $application_visible .\"' WHERE application_id=\". $application_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_domains_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_DOMAIN_TABLE .\" ORDER BY domain_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_domains_add($domain_name, $domain_application, $domain_as_host, $domain_as_port, $domain_rrd_path, $domain_las_admin_path, $domain_las_local_path, $domain_sql_string, $domain_cs_sql_string, $domain_hd_check, $domain_mfs_web)\n\t{\n\t\tglobal $db;\n\n\t\t$domain_name = trim($domain_name);\n\t\tif ($domain_name == '')\treturn \"/!\\ Error: domain name is empty!\";\n\n\t\t$domain_exists = tool_admin_domains_name_exist($domain_name);\n\t\tif (!$domain_exists)\n\t\t{\n\t\t\t$sql  = \"INSERT INTO \". NELDB_DOMAIN_TABLE;\n\t\t\t$sql .= \" (`domain_name`,`domain_application`,`domain_as_host`,`domain_as_port`,`domain_rrd_path`,`domain_las_admin_path`,`domain_las_local_path`,`domain_sql_string`,`domain_hd_check`,`domain_mfs_web`,`domain_cs_sql_string`) \";\n\t\t\t$sql .= \" VALUES \";\n\t\t\t$sql .= \" ('\". $domain_name .\"','\". $domain_application .\"','\". $domain_as_host .\"','\". $domain_as_port .\"','\". $domain_rrd_path .\"','\". $domain_las_admin_path .\"','\". $domain_las_local_path .\"','\". $domain_sql_string .\"',\". $domain_hd_check .\",'\". $domain_mfs_web .\"','\". $domain_cs_sql_string .\"') \";\n\t\t\t$db->sql_query($sql);\n\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn \"/!\\ Error: domain name already exists in the database!\";\n\t}\n\n\tfunction tool_admin_domains_name_exist($domain_name)\n\t{\n\t\tglobal $db;\n\n\t\t$exists = false;\n\n\t\t$sql = \"SELECT domain_id, domain_name FROM \". NELDB_DOMAIN_TABLE .\" WHERE domain_name='\". $domain_name .\"'\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$exists = true;\n\t\t\t}\n\t\t}\n\n\t\treturn $exists;\n\t}\n\n\tfunction tool_admin_domains_get_id($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_DOMAIN_TABLE .\" WHERE domain_id=\". $domain_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_domains_del($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_SHARD_TABLE  .\" WHERE user_shard_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_DOMAIN_TABLE .\" WHERE user_domain_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_SHARD_TABLE  .\" WHERE group_shard_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_DOMAIN_TABLE .\" WHERE group_domain_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_SHARD_TABLE .\" WHERE shard_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_DOMAIN_TABLE .\" WHERE domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t}\n\n\tfunction tool_admin_domains_update($domain_id, $domain_name, $domain_application, $domain_as_host, $domain_as_port, $domain_rrd_path, $domain_las_admin_path, $domain_las_local_path, $domain_sql_string, $domain_cs_sql_string, $domain_hd_check, $domain_mfs_web)\n\t{\n\t\tglobal $db;\n\n\t\t$domain_name = trim($domain_name);\n\n\t\tif ($domain_name == \"\")\treturn \"/!\\ Error: domain name is empty!\";\n\n\t\t$sql = \"SELECT * FROM \". NELDB_DOMAIN_TABLE .\" WHERE domain_name='\". $domain_name .\"' AND domain_id<>\". $domain_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: domain name already exists in database!\";\n\t\t\t}\n\t\t}\n\n\t\t$sql = \"UPDATE \". NELDB_DOMAIN_TABLE .\" SET domain_name='\". $domain_name.\"',domain_application='\". $domain_application .\"',domain_as_host='\". $domain_as_host .\"',domain_as_port='\". $domain_as_port .\"',domain_rrd_path='\". $domain_rrd_path .\"',domain_las_admin_path='\". $domain_las_admin_path .\"',domain_las_local_path='\". $domain_las_local_path .\"',domain_sql_string='\". $domain_sql_string .\"',domain_hd_check=\". $domain_hd_check .\",domain_mfs_web='\". $domain_mfs_web .\"',domain_cs_sql_string='\". $domain_cs_sql_string .\"' WHERE domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_shards_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" LEFT JOIN \". NELDB_DOMAIN_TABLE .\" ON (shard_domain_id=domain_id) ORDER BY domain_name ASC, shard_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_shards_add($shard_name, $shard_as_id, $shard_domain_id, $shard_language)\n\t{\n\t\tglobal $db;\n\n\t\t$shard_name = trim($shard_name);\n\t\tif ($shard_name == '')\treturn \"/!\\ Error: shard name is empty!\";\n\n\t\t$shard_as_id = trim($shard_as_id);\n\t\t//if (!is_numeric($shard_as_id))\treturn \"/!\\ Error: shard AS Id is invalid!\";\n\n\t\t//$shard_exists = tool_admin_shards_name_exist($shard_as_id);\n\t\t//if (!$shard_exists)\n\t\t//{\n\t\t\t$sql  = \"INSERT INTO \". NELDB_SHARD_TABLE;\n\t\t\t$sql .= \" (`shard_name`,`shard_as_id`,`shard_domain_id`,`shard_lang`) \";\n\t\t\t$sql .= \" VALUES \";\n\t\t\t$sql .= \" ('\". $shard_name .\"','\". $shard_as_id .\"','\". $shard_domain_id .\"','\". $shard_language .\"') \";\n\t\t\t$db->sql_query($sql);\n\t\t\treturn \"\";\n\t\t//}\n        //\n\t\t//return \"/!\\ Error: shard AS Id already exists in the database!\";\n\t}\n\n\tfunction tool_admin_shards_name_exist($shard_as_id, $except_id=false)\n\t{\n\t\tglobal $db;\n\n\t\tif ($shard_as_id == '*' || $shard_as_id == '?') return false;\n\n\t\t$exists = false;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" WHERE shard_as_id='\". $shard_as_id .\"'\";\n\t\tif ($except_id !== false)\t$sql .= \" AND shard_id<>\". $except_id;\n\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$exists = true;\n\t\t\t}\n\t\t}\n\n\t\treturn $exists;\n\t}\n\n\tfunction tool_admin_shards_get_id($shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" WHERE shard_id=\". $shard_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_shards_del($shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_SHARD_TABLE .\" WHERE user_shard_shard_id=\". $shard_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_SHARD_TABLE .\" WHERE group_shard_shard_id=\". $shard_id;\n\t\t$db->sql_query($sql);\n\n\t\t$sql = \"DELETE FROM \". NELDB_SHARD_TABLE .\" WHERE shard_id=\". $shard_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_shards_update($shard_id, $shard_name, $shard_as_id, $shard_domain_id, $shard_language)\n\t{\n\t\tglobal $db;\n\n\t\t$shard_name = trim($shard_name);\n\t\tif ($shard_name == '')\treturn \"/!\\ Error: shard name is empty!\";\n\n\t\t$shard_as_id = trim($shard_as_id);\n\t\t//if (!is_numeric($shard_as_id))\treturn \"/!\\ Error: shard AS Id is invalid!\";\n\n\t\t//$shard_exists = tool_admin_shards_name_exist($shard_as_id, $shard_id);\n\t\t//if (!$shard_exists)\n\t\t//{\n\t\t\t$sql = \"UPDATE \". NELDB_SHARD_TABLE .\" SET shard_name='\". $shard_name .\"',shard_as_id='\". $shard_as_id .\"',shard_domain_id='\". $shard_domain_id .\"',shard_lang='\". $shard_language .\"' WHERE shard_id=\". $shard_id;\n\t\t\t$db->sql_query($sql);\n\n\t\t\treturn \"\";\n\t\t//}\n        //\n\t\t//return \"/!\\ Error: shard AS Id already exists in the database!\";\n\n\t}\n\n\n\tfunction tool_admin_users_domains_update($user_id, $group_id, $domain_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$user_domains\t= tool_admin_users_domains_get_list($user_id, true);\n\t\t$group_domains\t= tool_admin_groups_domains_get_list($group_id, true);\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_DOMAIN_TABLE .\" WHERE user_domain_user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($domain_ids) and sizeof($domain_ids))\n\t\t{\n\t\t\treset($domain_ids);\n\t\t\tforeach($domain_ids as $domain_id)\n\t\t\t{\n\t\t\t\tif (is_numeric($domain_id) && $domain_id > 0)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"INSERT INTO \". NELDB_USER_DOMAIN_TABLE .\" (`user_domain_user_id`,`user_domain_domain_id`) VALUES ('\". $user_id .\"','\". $domain_id .\"')\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// now we remove all shards except those that belong to the user AND group\n\n\t\t$sql  = \"DELETE FROM \". NELDB_USER_SHARD_TABLE .\" WHERE user_shard_user_id=\". $user_id;\n\t\tif (is_array($domain_ids)    && sizeof($domain_ids)) \t$sql .= \" AND user_shard_domain_id NOT IN (\". implode(',',array_values($domain_ids)) .\")\";\n\t\tif (is_array($group_domains) && sizeof($group_domains))\t$sql .= \" AND user_shard_domain_id NOT IN (\". implode(',',array_values($group_domains)) .\")\";\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_users_domains_get_list($user_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_DOMAIN_TABLE .\" LEFT JOIN \". NELDB_DOMAIN_TABLE .\" ON (user_domain_domain_id=domain_id) WHERE user_domain_user_id=\". $user_id .\" ORDER BY domain_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['user_domain_domain_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_domains_get_list($group_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_DOMAIN_TABLE .\" LEFT JOIN \". NELDB_DOMAIN_TABLE .\" ON (group_domain_domain_id=domain_id) WHERE group_domain_group_id=\". $group_id .\" ORDER BY domain_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['group_domain_domain_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\t\t//nt_common_add_debug($data);\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_domains_merge($domain_list, $user_list, $group_list)\n\t{\n\t\t$data = array();\n\n\t\tif (is_array($domain_list) && sizeof($domain_list))\n\t\t{\n\t\t\treset($domain_list);\n\t\t\tforeach($domain_list as $domain)\n\t\t\t{\n\t\t\t\tif (in_array($domain['domain_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$domain['domain_disabled']\t= true;\n\t\t\t\t\t$domain['domain_visible']\t= true;\n\t\t\t\t}\n\t\t\t\telseif (in_array($domain['domain_id'], $user_list))\n\t\t\t\t{\n\t\t\t\t\t$domain['domain_selected'] \t= true;\n\t\t\t\t\t$domain['domain_visible']\t= true;\n\t\t\t\t}\n\n\t\t\t\t$data[] = $domain;\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_shards_get_list($user_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_SHARD_TABLE .\" LEFT JOIN \". NELDB_SHARD_TABLE .\" ON (user_shard_shard_id=shard_id) WHERE user_shard_user_id=\". $user_id .\" ORDER BY shard_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['user_shard_shard_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_shards_get_list($group_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_SHARD_TABLE .\" LEFT JOIN \". NELDB_SHARD_TABLE .\" ON (group_shard_shard_id=shard_id) WHERE group_shard_group_id=\". $group_id .\" ORDER BY shard_name ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['group_shard_shard_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_shards_merge($domain_list, $shard_list, $user_list, $group_list)\n\t{\n\t\t$data1 = array();\n\n\t\tif (is_array($shard_list) && sizeof($shard_list))\n\t\t{\n\t\t\treset($shard_list);\n\t\t\tforeach($shard_list as $shard)\n\t\t\t{\n\t\t\t\tif (in_array($shard['shard_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$shard['shard_disabled'] \t= true;\n\t\t\t\t}\n\t\t\t\telseif (in_array($shard['shard_id'], $user_list))\n\t\t\t\t{\n\t\t\t\t\t$shard['shard_selected']\t= true;\n\t\t\t\t}\n\n\t\t\t\t$data1[] = $shard;\n\t\t\t}\n\n\t\t\t$shard_list = $data1;\n\t\t}\n\n\t\t$data2 = array();\n\n\t\t// now we sort the shards by their domain\n\t\tif (is_array($domain_list) && sizeof($domain_list))\n\t\t{\n\t\t\treset($domain_list);\n\t\t\tforeach($domain_list as $domain)\n\t\t\t{\n\t\t\t\t// looks for the shards that belong to this domain\n\t\t\t\treset($shard_list);\n\t\t\t\tforeach($shard_list as $shard)\n\t\t\t\t{\n\t\t\t\t\tif ($domain['domain_id'] == $shard['shard_domain_id'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$domain['shard_list'][] = $shard;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$data2[] = $domain;\n\t\t\t}\n\n\t\t\t$domain_list = $data2;\n\t\t}\n\n\t\treturn $domain_list;\n\t}\n\n\tfunction tool_admin_users_shards_update($user_id, $group_id, $shard_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_SHARD_TABLE .\" WHERE user_shard_user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($shard_ids) && sizeof($shard_ids))\n\t\t{\n\t\t\treset($shard_ids);\n\t\t\tforeach($shard_ids as $shard_tmp)\n\t\t\t{\n\t\t\t\t$tmp = explode('_', $shard_tmp);\n\t\t\t\t$domain_id\t= $tmp[0];\n\t\t\t\t$shard_id\t= $tmp[1];\n\n\t\t\t\tif (is_numeric($domain_id) && is_numeric($shard_id) && $domain_id > 0 && $shard_id > 0)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"INSERT INTO \". NELDB_USER_SHARD_TABLE .\" (`user_shard_user_id`,`user_shard_shard_id`,`user_shard_domain_id`) VALUES ('\". $user_id .\"','\". $shard_id .\"','\". $domain_id .\"')\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tool_admin_groups_domains_update($group_id, $domain_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_DOMAIN_TABLE .\" WHERE group_domain_group_id=\". $group_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($domain_ids) and sizeof($domain_ids))\n\t\t{\n\t\t\treset($domain_ids);\n\t\t\tforeach($domain_ids as $domain_id)\n\t\t\t{\n\t\t\t\tif (is_numeric($domain_id) && $domain_id > 0)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"INSERT INTO \". NELDB_GROUP_DOMAIN_TABLE .\" (`group_domain_group_id`,`group_domain_domain_id`) VALUES ('\". $group_id .\"','\". $domain_id .\"')\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t$sql  = \"DELETE FROM \". NELDB_GROUP_SHARD_TABLE .\" WHERE group_shard_group_id=\". $group_id;\n\t\tif (is_array($domain_ids)    && sizeof($domain_ids)) \t$sql .= \" AND group_shard_domain_id NOT IN (\". implode(',',array_values($domain_ids)) .\")\";\n\t\t$db->sql_query($sql);\n\n\t\t// we need to check some stuff for each user in this group\n\n\t\t// first we get the list of users that belong to his group\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\t// get a user\n\t\t\t\t\t$user_id = $row['user_id'];\n\n\t\t\t\t\t// get the domains specific to the user\n\t\t\t\t\t$user_domain_list = tool_admin_users_domains_get_list($user_id, true);\n\n\t\t\t\t\t// then we delete the shard that don't belong to the group nor user\n\t\t\t\t\t$sql  = \"DELETE FROM \". NELDB_USER_SHARD_TABLE .\" WHERE user_shard_user_id=\". $user_id;\n\t\t\t\t\tif (is_array($domain_ids) && sizeof($domain_ids)) \t\t\t\t$sql .= \" AND user_shard_domain_id NOT IN (\". implode(',', array_values($domain_ids)) .\")\";\n\t\t\t\t\tif (is_array($user_domain_list) && sizeof($user_domain_list))\t$sql .= \" AND user_shard_domain_id NOT IN (\". implode(',', array_values($user_domain_list)) .\")\";\n\t\t\t\t\t$db->sql_query($sql);\n\n\t\t\t\t\t// make sure users don't have a domain that already belongs to a group\n\t\t\t\t\t$sql  = \"DELETE FROM \". NELDB_USER_DOMAIN_TABLE .\" WHERE user_domain_user_id=\". $user_id;\n\t\t\t\t\tif (is_array($domain_ids) && sizeof($domain_ids))\t\t\t\t$sql .= \" AND user_domain_domain_id IN (\". implode(',', array_values($domain_ids)) .\")\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t}\n\n\tfunction tool_admin_groups_domains_merge($domain_list, $group_list)\n\t{\n\t\t$data = array();\n\n\t\tif (is_array($domain_list) && sizeof($domain_list))\n\t\t{\n\t\t\treset($domain_list);\n\t\t\tforeach($domain_list as $domain)\n\t\t\t{\n\t\t\t\tif (in_array($domain['domain_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$domain['domain_visible']\t= true;\n\t\t\t\t\t$domain['domain_selected']\t= true;\n\t\t\t\t}\n\n\t\t\t\t$data[] = $domain;\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_shards_merge($domain_list, $shard_list, $group_list)\n\t{\n\t\t$data1 = array();\n\n\t\tif (is_array($shard_list) && sizeof($shard_list))\n\t\t{\n\t\t\treset($shard_list);\n\t\t\tforeach($shard_list as $shard)\n\t\t\t{\n\t\t\t\tif (in_array($shard['shard_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$shard['shard_selected'] \t= true;\n\t\t\t\t}\n\n\t\t\t\t$data1[] = $shard;\n\t\t\t}\n\n\t\t\t$shard_list = $data1;\n\t\t}\n\n\t\t$data2 = array();\n\n\t\t// now we sort the shards by their domain\n\t\tif (is_array($domain_list) && sizeof($domain_list) && is_array($shard_list) && sizeof($shard_list))\n\t\t{\n\t\t\treset($domain_list);\n\t\t\tforeach($domain_list as $domain)\n\t\t\t{\n\t\t\t\t// looks for the shards that belong to this domain\n\t\t\t\treset($shard_list);\n\t\t\t\tforeach($shard_list as $shard)\n\t\t\t\t{\n\t\t\t\t\tif ($domain['domain_id'] == $shard['shard_domain_id'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$domain['shard_list'][] = $shard;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$data2[] = $domain;\n\t\t\t}\n\n\t\t\t$domain_list = $data2;\n\t\t}\n\n\t\treturn $domain_list;\n\t}\n\n\tfunction tool_admin_groups_shards_update($group_id, $shard_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_SHARD_TABLE .\" WHERE group_shard_group_id=\". $group_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($shard_ids) && sizeof($shard_ids))\n\t\t{\n\t\t\t$user_shard_ids = array();\n\n\t\t\treset($shard_ids);\n\t\t\tforeach($shard_ids as $shard_tmp)\n\t\t\t{\n\t\t\t\t$tmp = explode('_', $shard_tmp);\n\t\t\t\t$domain_id\t= $tmp[0];\n\t\t\t\t$shard_id\t= $tmp[1];\n\n\t\t\t\t$group_shard_ids[] = $shard_id;\n\n\t\t\t\tif (is_numeric($domain_id) && is_numeric($shard_id) && $domain_id > 0 && $shard_id > 0)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"INSERT INTO \". NELDB_GROUP_SHARD_TABLE .\" (`group_shard_group_id`,`group_shard_shard_id`,`group_shard_domain_id`) VALUES ('\". $group_id .\"','\". $shard_id .\"','\". $domain_id .\"')\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// we need to check some stuff for each user in this group\n\n\t\t\t// first we get the list of users that belong to his group\n\t\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_group_id=\". $group_id;\n\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t{\n\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t{\n\t\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t\t{\n\t\t\t\t\t\t// get a user\n\t\t\t\t\t\t$user_ids[] = $row['user_id'];\n\t\t\t\t\t}\n\n\t\t\t\t\t$sql = \"DELETE FROM \". NELDB_USER_SHARD_TABLE .\" WHERE user_shard_user_id IN (\". implode(',',array_values($user_ids)) .\") AND user_shard_shard_id IN (\". implode(',', array_values($group_shard_ids)) .\")\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\tfunction tool_admin_groups_applications_update($group_id, $application_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_GROUP_APPLICATION_TABLE .\" WHERE group_application_group_id=\". $group_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($application_ids) && sizeof($application_ids))\n\t\t{\n\t\t\treset($application_ids);\n\t\t\tforeach($application_ids as $application_id)\n\t\t\t{\n\t\t\t\t$sql = \"INSERT INTO \". NELDB_GROUP_APPLICATION_TABLE .\" (`group_application_group_id`,`group_application_application_id`) VALUES ('\". $group_id .\"','\". $application_id .\"')\";\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\n\t\t\t// we need to make sure no user in this group has this application\n\t\t\t$sql = \"SELECT * FROM \". NELDB_USER_TABLE .\" WHERE user_group_id=\". $group_id;\n\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t{\n\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t{\n\t\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t\t{\n\t\t\t\t\t\t// get a user\n\t\t\t\t\t\t$user_ids[] = $row['user_id'];\n\t\t\t\t\t}\n\n\t\t\t\t\t$sql = \"DELETE FROM \". NELDB_USER_APPLICATION_TABLE .\" WHERE user_application_user_id IN (\". implode(',',array_values($user_ids)) .\") AND user_application_application_id IN (\". implode(',', array_values($application_ids)) .\")\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\n\tfunction tool_admin_groups_applications_get_list($group_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_GROUP_APPLICATION_TABLE .\" LEFT JOIN \". NELDB_APPLICATION_TABLE .\" ON (group_application_application_id=application_id) WHERE group_application_group_id=\". $group_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['group_application_application_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_groups_applications_merge($appl_list, $group_list)\n\t{\n\t\t$data1 = array();\n\n\t\tif (is_array($appl_list) && sizeof($appl_list))\n\t\t{\n\t\t\treset($appl_list);\n\t\t\tforeach($appl_list as $appl)\n\t\t\t{\n\t\t\t\tif (in_array($appl['application_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$appl['application_selected'] = true;\n\t\t\t\t}\n\n\t\t\t\t$data1[] = $appl;\n\t\t\t}\n\n\t\t\t$appl_list = $data1;\n\t\t}\n\n\t\treturn $appl_list;\n\t}\n\n\tfunction tool_admin_users_applications_get_list($user_id, $compact = false)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\t\t$data1 = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_USER_APPLICATION_TABLE .\" LEFT JOIN \". NELDB_APPLICATION_TABLE .\" ON (user_application_application_id=application_id) WHERE user_application_user_id=\". $user_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data1 = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\tif ($compact)\n\t\t{\n\t\t\treset($data1);\n\t\t\tforeach($data1 as $data_tmp)\n\t\t\t{\n\t\t\t\t$data[] = $data_tmp['user_application_application_id'];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = $data1;\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_users_applications_merge($appl_list, $user_list, $group_list)\n\t{\n\t\t$data1 = array();\n\n\t\tif (is_array($appl_list) && sizeof($appl_list))\n\t\t{\n\t\t\treset($appl_list);\n\t\t\tforeach($appl_list as $appl)\n\t\t\t{\n\t\t\t\tif (in_array($appl['application_id'], $group_list))\n\t\t\t\t{\n\t\t\t\t\t$appl['application_disabled'] = true;\n\t\t\t\t}\n\t\t\t\telseif (in_array($appl['application_id'], $user_list))\n\t\t\t\t{\n\t\t\t\t\t$appl['application_selected'] = true;\n\t\t\t\t}\n\n\t\t\t\t$data1[] = $appl;\n\t\t\t}\n\n\t\t\t$appl_list = $data1;\n\t\t}\n\n\t\treturn $appl_list;\n\t}\n\n\tfunction tool_admin_users_applications_update($user_id, $application_ids)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_USER_APPLICATION_TABLE .\" WHERE user_application_user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\n\t\tif (is_array($application_ids) && sizeof($application_ids))\n\t\t{\n\t\t\treset($application_ids);\n\t\t\tforeach($application_ids as $application_id)\n\t\t\t{\n\t\t\t\tif (is_numeric($application_id) && $application_id > 0)\n\t\t\t\t{\n\t\t\t\t\t$sql = \"INSERT INTO \". NELDB_USER_APPLICATION_TABLE .\" (`user_application_user_id`,`user_application_application_id`) VALUES ('\". $user_id .\"','\". $application_id .\"')\";\n\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tool_admin_applications_build_menu_list($user_access)\n\t{\n\t\t$menu = array();\n\n//\t\treturn $user_access['applications'];\n\n\t\tif (is_array($user_access['applications']) && sizeof($user_access['applications']))\n\t\t{\n\t\t\treset($user_access['applications']);\n\t\t\tforeach($user_access['applications'] as $appl_data)\n\t\t\t{\n\t\t\t\tif ($appl_data['application_visible'] == 1)\n\t\t\t\t{\n\t\t\t\t\t$user_check \t= tool_admin_applications_build_menu_check($appl_data['application_id'], $user_access['user_applications'], 'user_application_application_id');\n\t\t\t\t\t$group_check\t= tool_admin_applications_build_menu_check($appl_data['application_id'], $user_access['group_applications'], 'group_application_application_id');\n\n\t\t\t\t\tif ($appl_data['application_restriction'] == '')\n\t\t\t\t\t{\n\t\t\t\t\t\t$menu[] = $appl_data;\n\t\t\t\t\t}\n\t\t\t\t\telseif ($user_check || $group_check)\n\t\t\t\t\t{\n\t\t\t\t\t\t$menu[] = $appl_data;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $menu;\n\t}\n\n\tfunction tool_admin_applications_get_default($data, $application_id)\n\t{\n\t\tif (is_array($data) && sizeof($data))\n\t\t{\n\t\t\treset($data);\n\t\t\tforeach($data as $dt)\n\t\t\t{\n\t\t\t\tif ($dt['application_id'] == $application_id)\n\t\t\t\t{\n\t\t\t\t\treturn $dt;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction tool_admin_applications_build_menu_check($appl_id, $data, $data_name)\n\t{\n\t\tif (is_array($data) && sizeof($data))\n\t\t{\n\t\t\treset($data);\n\t\t\tforeach($data as $dt)\n\t\t\t{\n\t\t\t\tif ($dt[$data_name] == $appl_id)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction tool_admin_applications_check($appl)\n\t{\n\t\tglobal $nel_user;\n\n\t\t$ua = $nel_user['access']['user_applications'];\n\t\t$ga = $nel_user['access']['group_applications'];\n\n\t\tif (is_array($ua) && sizeof($ua))\n\t\t{\n\t\t\treset($ua);\n\t\t\tforeach($ua as $a)\n\t\t\t{\n\t\t\t\tif ($a['application_restriction'] == $appl)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (is_array($ga) && sizeof($ga))\n\t\t{\n\t\t\treset($ga);\n\t\t\tforeach($ga as $a)\n\t\t\t{\n\t\t\t\tif ($a['application_restriction'] == $appl)\n\t\t\t\t{\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction tool_admin_menu_get_list($ie)\n\t{\n\t\tglobal $tool_admin_menu;\n\t\tglobal $nel_user;\n\n\t\t$new_menu = array();\n\n\t\treset($tool_admin_menu);\n\t\tforeach($tool_admin_menu as $menu_item)\n\t\t{\n\t\t\tif (($menu_item['access'] == '') || tool_admin_applications_check($menu_item['access']))\n\t\t\t{\n\t\t\t\tif ($ie === false)\n\t\t\t\t{\n\t\t\t\t\t$new_menu[] = $menu_item;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $new_menu;\n\t}\n\n\tfunction tool_admin_users_groups_domains_merge()\n\t{\n\t\tglobal $nel_user;\n\n\t\t$user_domains = array();\n\n\t\t$ud = $nel_user['access']['user_domains'];\n\t\t$gd = $nel_user['access']['group_domains'];\n\n\t\t$dd = tool_admin_domains_get_list();\n\n\t\tif (is_array($dd) && sizeof($dd))\n\t\t{\n\t\t\treset($dd);\n\t\t\tforeach($dd as $domain_item)\n\t\t\t{\n\t\t\t\tif (is_array($ud))\n\t\t\t\t{\n\t\t\t\t\treset($ud);\n\t\t\t\t\tforeach($ud as $udomain)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($domain_item['domain_id'] == $udomain['domain_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$user_domains[] = $domain_item;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (is_array($gd))\n\t\t\t\t{\n\t\t\t\t\treset($gd);\n\t\t\t\t\tforeach($gd as $gdomain)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($domain_item['domain_id'] == $gdomain['domain_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$user_domains[] = $domain_item;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $user_domains;\n\t}\n\n\tfunction tool_admin_users_groups_shards_merge()\n\t{\n\t\tglobal $nel_user;\n\n\t\t$user_shards = array();\n\n\t\t$us = $nel_user['access']['user_shards'];\n\t\t$gs = $nel_user['access']['group_shards'];\n\n\t\t$ss = tool_admin_shards_get_list();\n\n\t\tif (is_array($ss) && sizeof($ss))\n\t\t{\n\t\t\treset($ss);\n\t\t\tforeach($ss as $shard_item)\n\t\t\t{\n\t\t\t\tif (is_array($us))\n\t\t\t\t{\n\t\t\t\t\treset($us);\n\t\t\t\t\tforeach($us as $ushard)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($shard_item['shard_id'] == $ushard['shard_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$user_shards[] = $shard_item;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (is_array($gs))\n\t\t\t\t{\n\t\t\t\t\treset($gs);\n\t\t\t\t\tforeach($gs as $gshard)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($shard_item['shard_id'] == $gshard['shard_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$user_shards[] = $shard_item;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $user_shards;\n\t}\n\n\tfunction tool_admin_logs_get_count()\n\t{\n\t\tglobal $db;\n\n\t\t$total = 0;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_LOG_TABLE;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\t$total = $db->sql_numrows($result);\n\t\t}\n\n\t\treturn $total;\n\t}\n\n\tfunction tool_admin_logs_get_list($start=0,$limit=25)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_LOG_TABLE .\" ORDER BY logs_id DESC LIMIT \". $start .\",\". $limit;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_domains_get_nel($application)\n\t{\n\t\tglobal $db;\n\n\t\t$domain_data = null;\n\n\t\tif ($db->sql_select_db('nel'))\n\t\t{\n\t\t\t$sql = \"SELECT * FROM domain WHERE domain_name='\". $application .\"'\";\n\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t{\n\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t{\n\t\t\t\t\t$domain_data = $db->sql_fetchrow($result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$db->sql_reselect_db();\n\t\t}\n\n\t\treturn $domain_data;\n\t}\n\n\t//function tool_admin_domains_update_nel($domain_id, $domain_name, $domain_version, $domain_status)\n\tfunction tool_admin_domains_update_nel($domain_id, $domain_name, $domain_status)\n\t{\n\t\tglobal $db;\n\n\t\tif ($db->sql_select_db('nel'))\n\t\t{\n\t\t\t//$sql = \"UPDATE domain SET status='\". $domain_status .\"',patch_version=\". $domain_version .\" WHERE domain_id=\". $domain_id .\" AND domain_name='\". $domain_name .\"'\";\n\t\t\t$sql = \"UPDATE domain SET status='\". $domain_status .\"' WHERE domain_id=\". $domain_id .\" AND domain_name='\". $domain_name .\"'\";\n\t\t\t$db->sql_query($sql);\n\n\t\t\t$db->sql_reselect_db();\n\t\t}\n\t}\n\n\tfunction tool_admin_restarts_get_list($order='ASC')\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_GROUP_TABLE .\" ORDER BY restart_group_order \". $order .\", restart_group_name \". $order;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_restarts_add($restart_name, $restart_list, $restart_order)\n\t{\n\t\tglobal $db;\n\n\t\t$restart_name = trim($restart_name);\n\t\tif ($restart_name == '')\treturn \"/!\\ Error: restart group name is empty!\";\n\n\t\t$restart_list = trim($restart_list);\n\t\tif ($restart_list == '')\treturn \"/!\\ Error: restart group list is empty!\";\n\n\t\t$restart_order = trim($restart_order);\n\t\tif (!is_numeric($restart_order)) return \"/!\\ Error: restart group order is not numeric!\";\n\n\t\t$sql  = \"INSERT INTO \". NELDB_RESTART_GROUP_TABLE;\n\t\t$sql .= \" (`restart_group_id`,`restart_group_name`,`restart_group_list`,`restart_group_order`) \";\n\t\t$sql .= \" VALUES \";\n\t\t$sql .= \" (0,'\". $restart_name .\"','\". $restart_list .\"','\". $restart_order .\"') \";\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_restarts_get_id($restart_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_GROUP_TABLE .\" WHERE restart_group_id=\". $restart_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_restarts_del($restart_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_RESTART_GROUP_TABLE .\" WHERE restart_group_id=\". $restart_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_restarts_update($restart_id, $restart_name, $restart_list, $restart_order)\n\t{\n\t\tglobal $db;\n\n\t\t$restart_name = trim($restart_name);\n\t\tif ($restart_name == '')\treturn \"/!\\ Error: restart group name is empty!\";\n\n\t\t$restart_list = trim($restart_list);\n\t\tif ($restart_list == '')\treturn \"/!\\ Error: restart group list is empty!\";\n\n\t\t$restart_order = trim($restart_order);\n\t\tif (!is_numeric($restart_order)) return \"/!\\ Error: restart group order is not numeric!\";\n\n\t\t$sql = \"UPDATE \". NELDB_RESTART_GROUP_TABLE .\" SET restart_group_name='\". $restart_name .\"',restart_group_list='\". $restart_list .\"',restart_group_order='\". $restart_order .\"' WHERE restart_group_id=\". $restart_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_restart_messages_add($message_name, $message_value, $message_lang)\n\t{\n\t\tglobal $db;\n\n\t\t$message_name = trim($message_name);\n\t\tif ($message_name == '')\treturn \"/!\\ Error: restart message name is empty!\";\n\n\t\t$message_value = trim($message_value);\n\t\tif ($message_value == '')\treturn \"/!\\ Error: restart message value is empty!\";\n\n\t\t$sql  = \"INSERT INTO \". NELDB_RESTART_MESSAGE_TABLE;\n\t\t$sql .= \" (`restart_message_id`,`restart_message_name`,`restart_message_value`,`restart_message_lang`) \";\n\t\t$sql .= \" VALUES \";\n\t\t$sql .= \" (0,'\". $message_name .\"','\". $message_value .\"','\". $message_lang .\"') \";\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_admin_restart_messages_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_MESSAGE_TABLE .\" ORDER BY restart_message_name ASC, restart_message_lang ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_restart_messages_get_id($message_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_MESSAGE_TABLE .\" WHERE restart_message_id=\". $message_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_restart_messages_get_list_from_name($message_name,$lang=null)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql_ext = '';\n\t\tif ($lang !== null)\n\t\t{\n\t\t\t$sql_ext = \" AND restart_message_lang='\". $lang .\"'\";\n\t\t}\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_MESSAGE_TABLE .\" WHERE restart_message_name='\". $message_name .\"' \". $sql_ext .\" ORDER BY restart_message_lang ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_admin_restart_messages_del($message_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_RESTART_MESSAGE_TABLE .\" WHERE restart_message_id=\". $message_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_admin_restart_messages_update($message_id, $message_name, $message_value, $message_lang)\n\t{\n\t\tglobal $db;\n\n\t\t$message_name = trim($message_name);\n\t\tif ($message_name == '')\treturn \"/!\\ Error: restart message name is empty!\";\n\n\t\t$message_value = trim($message_value);\n\t\tif ($message_value == '')\treturn \"/!\\ Error: restart message value is empty!\";\n\n\t\t$sql = \"UPDATE \". NELDB_RESTART_MESSAGE_TABLE .\" SET restart_message_name='\". $message_name .\"',restart_message_value='\". $message_value .\"',restart_message_lang='\". $message_lang .\"' WHERE restart_message_id=\". $message_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_applications.php",
    "content": "<?php\n\n\tfunction tool_applications_menu_get_list()\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_APPLICATION_TABLE .\" WHERE application_visible=1 AND application_uri<>'' ORDER BY application_order ASC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrowset($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_event_entities.php",
    "content": "<?php\n\n\tfunction tool_ee_parse_getview($data)\n\t{\n\t\t$entity_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $ais_data)\n\t\t{\n\t\t\t$service_name \t= 'n/a';\n\t\t\t$answers\t\t= 0;\n\t\t\t$values\t\t\t= 0;\n\t\t\t$values_read\t= 0;\n\n\t\t\t$entity = array();\n\n\t\t\treset($ais_data);\n\t\t\tforeach($ais_data as $ais_line)\n\t\t\t{\n\t\t\t\t$ais_line = trim($ais_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^have ([[:digit:]]+) answer$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$answers = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^have ([[:digit:]]+) value$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^service ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['service_id'] = trim($eregs[1]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^entity ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['entity'] = trim($eregs[1]);\n\t\t\t\t\t$entity_string = str_replace(array('(',')','0x'), '', $entity['entity']);\n\t\t\t\t\t$entity_string = str_replace(':','_', $entity_string);\n\t\t\t\t\t$entity['entity_string'] = $entity_string;\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^NamedEntityName ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['entity_name'] = trim($eregs[1]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^NamedEntityState ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['entity_state'] = trim($eregs[1]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^NamedEntityParam1 ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['entity_param1'] = trim($eregs[1]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^NamedEntityParam2 ->(.*)$\", $ais_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$values_read++;\n\t\t\t\t\t$entity['entity_param2'] = trim($eregs[1]);\n\t\t\t\t}\n\n\t\t\t\tif (sizeof($entity) && ($values_read == $values) && ($values > 0))\n\t\t\t\t{\n\t\t\t\t\t$entity['service'] = $service_name;\n\t\t\t\t\t$entity['service_code'] = md5($service_name);\n\t\t\t\t\t$entity_data[] = $entity;\n\t\t\t\t\t$entity = array();\n\t\t\t\t\t$values = 0;\n\t\t\t\t\t$values_read = 0;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn $entity_data;\n\t}\n\n\tfunction tool_ee_get_entities($data)\n\t{\n\t\t$entities = array();\n\n\t\treset($data);\n\t\tforeach($data as $dkey => $dval)\n\t\t{\n\t\t\t$dkey_bits = explode('_', $dkey);\n\t\t\t$dkey_nums = sizeof($dkey_bits);\n\n\t\t\tif ($dkey_nums > 4)\n\t\t\t{\n\t\t\t\t$_entity_bit_4 \t\t= array_pop($dkey_bits);\n\t\t\t\t$_entity_bit_3 \t\t= array_pop($dkey_bits);\n\t\t\t\t$_entity_bit_2 \t\t= array_pop($dkey_bits);\n\t\t\t\t$_entity_bit_1 \t\t= array_pop($dkey_bits);\n\n\t\t\t\t$dkey_bits\t\t\t= array_reverse($dkey_bits);\n\t\t\t\t$_entity_service\t= array_pop($dkey_bits);\n\t\t\t\t$dkey_bits\t\t\t= array_reverse($dkey_bits);\n\n\t\t\t\t$dkey_entity \t\t= $_entity_bit_1 .'_'. $_entity_bit_2 .'_'. $_entity_bit_3 .'_'. $_entity_bit_4;\n\t\t\t\t$dkey_name\t\t\t= implode('_', $dkey_bits);\n\n\t\t\t\tif (!isset($entities[$_entity_service .'_'. $dkey_entity]))\n\t\t\t\t{\n\t\t\t\t\t$entities[$_entity_service .'_'. $dkey_entity] = array();\n\t\t\t\t}\n\n\t\t\t\t$entities[$_entity_service .'_'. $dkey_entity][$dkey_name] = trim($dval);\n\t\t\t}\n\t\t}\n\n\t\treturn $entities;\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_graphs.php",
    "content": "<?php\n\n\t$tool_graph_menu\t= array(array('title'\t=>\t'CCU',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'ccu',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_graphs.php?toolmode=ccu',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_graphs_ccu.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Tech Shard',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'tech',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_graphs.php?toolmode=tech',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_graphs_tech.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Hi-Res Shard',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'hires',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_graphs.php?toolmode=hires',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_graphs_hires.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'Old',\n\t\t\t\t\t\t\t\t\t  'key'\t\t=>\t'old',\n\t\t\t\t\t\t\t\t\t  'uri'\t\t=>\t'tool_graphs.php?toolmode=old',\n\t\t\t\t\t\t\t\t\t  'tpl'\t\t=>\t'tool_graphs.tpl',\n\t\t\t\t\t\t\t\t\t  'access'\t=>\t'',\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\t);\n\n\t$tool_hires_frames\t= array(array('title'\t=> \t'10 seconds',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t10000,\n\t\t\t\t\t\t\t\t\t  'step'\t=>\t0,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'30 seconds',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t30000,\n\t\t\t\t\t\t\t\t\t  'step'\t=>\t0,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\ttrue,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=>\t'90 seconds',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t90000,\n\t\t\t\t\t\t\t\t\t  'step'\t=>\t0,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\t);\n\n\t$tool_lowres_frames\t= array(array('title'\t=> \t'20 minutes',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t1200,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=> \t'3 hours',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t10800,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=> \t'24 hours',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t86400,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\ttrue,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=> \t'7 days',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t604800,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=> \t'30 days',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t2592000,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\tarray('title'\t=> \t'90 days',\n\t\t\t\t\t\t\t\t\t  'value'\t=>\t7776000,\n\t\t\t\t\t\t\t\t\t  'default'\t=>\tfalse,\n\t\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t\t);\n\n\tfunction tool_graphs_time_frame_get_default($list)\n\t{\n\t\treset($list);\n\t\tforeach($list as $frame)\n\t\t{\n\t\t\tif ($frame['default'] == true) return $frame['value'];\n\t\t}\n\t}\n\n\tfunction tool_graphs_menu_get_list()\n\t{\n\t\tglobal $tool_graph_menu;\n\t\tglobal $nel_user;\n\n\t\t$new_menu = array();\n\n\t\treset($tool_graph_menu);\n\t\tforeach($tool_graph_menu as $menu_item)\n\t\t{\n\t\t\tif (($menu_item['access'] == '') || tool_admin_applications_check($menu_item['access']))\n\t\t\t{\n\t\t\t\t$new_menu[] = $menu_item;\n\t\t\t}\n\t\t}\n\n\t\treturn $new_menu;\n\t}\n\n\tfunction tool_graphs_menu_get_item_from_key($key)\n\t{\n\t\tglobal $tool_graph_menu;\n\n\t\treset($tool_graph_menu);\n\t\tforeach($tool_graph_menu as $tool_menu)\n\t\t{\n\t\t\tif ($tool_menu['key'] == $key)\treturn $tool_menu;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_graphs_find($needles, $list)\n\t{\n\t\t$result = array();\n\n\t\treset($needles);\n\t\tforeach($needles as $needle)\n\t\t{\n\t\t\tif (isset($list[$needle['variable']]))\n\t\t\t{\n\t\t\t\tnt_common_add_debug(\"variable found \". $needle['variable']);\n\t\t\t\treset($list[$needle['variable']]);\n\t\t\t\tforeach($list[$needle['variable']] as $var)\n\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug(\"checking '\". $needle['service'] .\"' in '\". $var['service'] .\"'\");\n\t\t\t\t\tif (ereg(\"^\". $needle['service'] .\".*$\",$var['service']))\n\t\t\t\t\t{\n\t\t\t\t\t\tnt_common_add_debug(\"adding \". $var['service']);\n\t\t\t\t\t\t$result[] = $var;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $result;\n\t}\n\n\tfunction tool_graphs_get_list_v2($dir, $shard_match, $high=false, $domain=false)\n\t{\n\t\t$data = array();\n\n\t\t//if (!ereg(\"^[a-zA-Z0-9_]+$\",$shard_match) && !$domain) return $data;\n\n\t\tif (substr($dir, -1) != '/') $dir .= '/';\n\n\t\tif (is_dir($dir))\n\t\t{\n\t\t\tif ($handle = opendir($dir))\n\t\t\t{\n\t\t\t\twhile (($file = readdir($handle)) !== false)\n\t\t\t\t{\n\t\t\t\t\tif (($file != '.') && ($file != '..'))\n\t\t\t\t\t{\n\t\t\t\t\t\t$filelist[] = $file;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tclosedir($handle);\n\n\t\t\t\tsort($filelist);\n\t\t\t\tnt_common_add_debug($filelist);\n\n\t\t\t\t//fes_arispotle_01.NetSpeedLoop.hrd\n\t\t\t\t//egs_arispotle.TickSpeedLoop.hrd\n\t\t\t\t//$my_ereg = \"^([^_]+_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^\\ ]+)\\.([hr])rd$\";\n\t\t\t\t//$my_ereg = \"^([^_]+_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^\\ ]+)\\.rrd$\";\n\t\t\t\t$my_ereg\t= \"^([^_]+(_[^_]+)?_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^.]+)\\.\". ($high === true ? 'h':'r') .\"rd$\";\n\t\t\t\tnt_common_add_debug(\"using regexp: \".$my_ereg);\n\n\t\t\t\t// 0: complete file name\n\t\t\t\t// 1: service alias (eg. fes_arispotle_01)\n\t\t\t\t// 2: n/a\n\t\t\t\t// 3: shard (eg. arispotle)\n\t\t\t\t// 4: n/a\n\t\t\t\t// 5: variable (eg. NetSpeedLoop)\n\n\t\t\t\t// this is special, mainly to catch domain wide variables, such as su.* which don't have a shard\n\t\t\t\t$my_ereg2\t= \"^([^_]+(_[^_]+)?(_[^\\ \\.])?)\\.([^.]+)\\.\". ($high === true ? 'h':'r') .\"rd$\";\n\t\t\t\tnt_common_add_debug(\"using regexp2: \".$my_ereg2);\n\n\t\t\t\t// 0: complete file name\n\t\t\t\t// 1: service alias (eg. fes_arispotle_01)\n\t\t\t\t// 2: n/a\n\t\t\t\t// 3: n/a\n\t\t\t\t// 4: variable (eg. NetSpeedLoop)\n\n\n\t\t\t\treset($filelist);\n\t\t\t\tforeach($filelist as $file)\n\t\t\t\t//while (($file = readdir($handle)) !== false)\n\t\t\t\t{\n\t\t\t\t\t//nt_common_add_debug(\"checking : \". $file);\n\t\t\t\t\tif (ereg($my_ereg, $file, $params))\n\t\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug(\"ok\".$file);\n\t\t\t\t\t\t//nt_common_add_debug($params);\n\t\t\t\t\t\t$tmp = array(\t'rd_file'\t=> $params[0],\n\t\t\t\t\t\t\t\t\t\t'service'\t=> $params[1],\n\t\t\t\t\t\t\t\t\t\t'shard'\t\t=> $params[3],\n\t\t\t\t\t\t\t\t\t\t'variable'\t=> $params[5]);\n\n\t\t\t\t\t\t$data[$params[5]][] = $tmp;\n\t\t\t\t\t}\n\t\t\t\t\telseif (ereg($my_ereg2, $file, $params))\n\t\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug(\"ok2\".$file);\n\t\t\t\t\t\t$tmp = array(\t'rd_file'\t=> $params[0],\n\t\t\t\t\t\t\t\t\t\t'service'\t=> $params[1],\n\t\t\t\t\t\t\t\t\t\t'shard'\t\t=> 'open',\n\t\t\t\t\t\t\t\t\t\t'variable'\t=> $params[4]);\n\n\t\t\t\t\t\t$data[$params[4]][] = $tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\tnt_common_add_debug(array(array_keys($data), $data));\n\n\t\treturn array('variables' => array_keys($data), 'datas' => $data);\n\n\t}\n\n\n\tfunction tool_graphs_get_list($dir, $shard_match)\n\t{\n\t\t$data = array();\n\n\t\tif (substr($dir, -1) != '/') $dir .= '/';\n\n\t\tif (is_dir($dir))\n\t\t{\n\t\t\tif ($handle = opendir($dir))\n\t\t\t{\n\t\t\t\t//fes_arispotle_01.NetSpeedLoop.hrd\n\t\t\t\t//egs_arispotle.TickSpeedLoop.hrd\n\t\t\t\t$my_ereg = \"^([^_]+_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^\\ ]+)\\.([hr])rd$\";\n\t\t\t\t$my_ereg = \"^([^_]+_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^\\ ]+)\\.rrd$\";\n\t\t\t\t$my_ereg = \"^([^_]+(_[^_]+)?_(\". $shard_match .\")(_[^\\ \\.])?)\\.([^.]+)\\.rrd$\";\n\t\t\t\t//nt_common_add_debug($my_ereg);\n\n\t\t\t\t// 0: complete file name\n\t\t\t\t// 1: service alias (eg. fes_arispotle_01)\n\t\t\t\t// 2: n/a\n\t\t\t\t// 3: shard (eg. arispotle)\n\t\t\t\t// 4: n/a\n\t\t\t\t// 5: variable (eg. NetSpeedLoop)\n\t\t\t\t// 6: graph type, h/r : high/low (removed)\n\n\t\t\t\twhile (($file = readdir($handle)) !== false)\n\t\t\t\t{\n\t\t\t\t\tif (($file != '.') && ($file != '..'))\n\t\t\t\t\t{\n\t\t\t\t\t\t//nt_common_add_debug(\"checking : \". $file);\n\t\t\t\t\t\tif (ereg($my_ereg, $file, $params))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$high_file = str_replace('.rrd','.hrd',$file);\n\t\t\t\t\t\t\tif (!file_exists($dir . $high_file)) $high_file = '';\n\n\t\t\t\t\t\t\t//nt_common_add_debug($params);\n\t\t\t\t\t\t\t$tmp = array(\t'low_file'\t=> $params[0],\n\t\t\t\t\t\t\t\t\t\t\t'high_file'\t=> $high_file,\n\t\t\t\t\t\t\t\t\t\t\t'service'\t=> $params[1],\n\t\t\t\t\t\t\t\t\t\t\t'shard'\t\t=> $params[3],\n\t\t\t\t\t\t\t\t\t\t\t'variable'\t=> $params[5]);\n\n\t\t\t\t\t\t\t$data[$params[5]][] = $tmp;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tclosedir($handle);\n\t\t\t}\n\t\t}\n\n\t\tnt_common_add_debug(array(array_keys($data), $data));\n\n\t\treturn array('variables' => array_keys($data), 'datas' => $data);\n\t}\n\n\tfunction tool_graphs_get_data($data, $variable, $service)\n\t{\n\t\treset($data);\n\t\tforeach($data as $svar => $sdata)\n\t\t{\n\t\t\tif ($svar == $variable)\n\t\t\t{\n\t\t\t\treset($sdata);\n\t\t\t\tforeach($sdata as $sidata)\n\t\t\t\t{\n\t\t\t\t\tif ($sidata['service'] == $service)\n\t\t\t\t\t{\n\t\t\t\t\t\treturn $sidata;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_graphs_extract_mean_values($data)\n\t{\n\t\t$result = array('ref' => array(), 'val' => array());\n\n\t\t$base = null;\n\n\t\treset($data);\n\t\tforeach($data as $sdata)\n\t\t{\n\t\t\t$tmp_data = explode(':', $sdata);\n\n\t\t\t// get reference as t0\n\t\t\tif (!$base) $base = trim($tmp_data[1]);\n\n\t\t\t$val_data = explode(' ', $tmp_data[2]);\n\n\t\t\t$result['ref'][] = $tmp_data[1] - $base;\n\t\t\t$result['val'][] = trim($val_data[1]);\n\t\t}\n\n\t\treturn $result;\n\t}\n\n\tfunction tool_graphs_xaxis_callback($aVal)\n\t{\n\t\treturn ($aVal / 1000) .'k';\n\t}\n\n// ######################################################################################################################\n// ######################################################################################################################\n\n\tfunction tool_graphs_rrd_get_list($dir)\n\t{\n\t\t$dir_list = array();\n\n\t\tif ($handle = opendir($dir))\n\t\t{\n   \t\t\twhile (false !== ($file = readdir($handle)))\n   \t\t\t{\n       \t\t\tif (($file != \".\") && ($file != \"..\") && (substr($file, -4) == '.rrd'))\n       \t\t\t{\n\t\t\t\t\t$dir_list[] = array('name' => $file, 'code' => base64_encode($file));\n       \t\t\t}\n   \t\t\t}\n\n   \t\t\tclosedir($handle);\n\t\t}\n\n\t\treturn $dir_list;\n\t}\n\n\tfunction tool_graphs_build_rrd($fname,$period=0)\n\t{\n\t\t$rrdperiod\t= '-'. $period;\n\t\t$rrdfile\t= RRD_PATH . $fname;\n\t\t$webimage \t= GFX_PATH . $fname .'_'. $period .'.gif';\n\n\t\t$opts = array(\t\"--start\", $rrdperiod, \"DEF:val=\". $rrdfile .\":var:AVERAGE\", \"LINE2:val#0000FF\");\n\t\t$ret = rrd_graph($webimage, $opts, count($opts));\n\n\t\tif ( is_array($ret) )\n\t\t{\n\t\t\treturn array('status' => true, 'img' => $webimage);\n\t\t}\n\n\t\t$err = rrd_error();\n\t\treturn array('status' => false, 'error' => \"Error: rrd_graph() -- $err\");\n\t}\n\n\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_guild_locator.php",
    "content": "<?php\n\n\tfunction tool_gl_parse_dump_guild_list($data)\n\t{\n\t\t$guild_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $egs_data)\n\t\t{\n\t\t\t$service_name = 'n/a';\n\n\t\t\treset($egs_data);\n\t\t\tforeach($egs_data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^id = ([^\\ ]+)\\:([^\\ ]+) \\(Local\\) ([^\\ ]+), name = '([^\\']+)', ([^\\ ]+) members$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'shardid'\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'guildid'\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'name'\t\t\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'guildeid'\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'members'\t\t=>\t$eregs[5],\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $guild_data;\n\t}\n\n\tfunction tool_gl_parse_dump_guild($data)\n\t{\n\t\t$guild_data = array();\n\n\t\t// this command can only handle 1 guild\n\t\tif (is_array($data) && (sizeof($data) == 1))\n\t\t{\n\t\t\t$data = $data[0];\n\n\t\t\treset($data);\n\t\t\tforeach($data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['service_name'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^<GUILD_DUMP> Guild id: ([^\\ ]+)\\:([^\\ ]+) \\(Local\\), name: '([^\\']+)', eid: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['shard_id']\t\t= $eregs[1];\n\t\t\t\t\t$guild_data['guild_id']\t\t= $eregs[2];\n\t\t\t\t\t$guild_data['guild_name']\t= $eregs[3];\n\t\t\t\t\t$guild_data['guild_eid']\t= $eregs[4];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Description: '([^\\']+)'$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['guild_description'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Money: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['guild_money']\t= $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Creation date: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['guild_creation'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Race: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['guild_race'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Nb of members: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['members_count'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Nb of members with grade 'Leader': ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['members_leader_count']\t= $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Nb of members with grade 'HighOfficer': ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['members_highofficier_count'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Nb of members with grade 'Officer': ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['members_officer_count'] = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Nb of members with grade 'Member': ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data['members_member_count']\t= $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Member '([^\\ ]+)\\(([^\\ ]+)\\)' ([^\\ ]+), index: ([^\\ ]+), grade: ([^\\ ]+), enter time: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$member = array('name'\t\t=> $eregs[1],\n\t\t\t\t\t\t\t\t\t'shard'\t\t=> $eregs[2],\n\t\t\t\t\t\t\t\t\t'eid'\t\t=> $eregs[3],\n\t\t\t\t\t\t\t\t\t'index'\t\t=> $eregs[4],\n\t\t\t\t\t\t\t\t\t'grade'\t\t=> $eregs[5],\n\t\t\t\t\t\t\t\t\t'entertime'\t=> $eregs[6]);\n\n\t\t\t\t\t$guild_data[$eregs[5]][] = $member;\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Owned Outpost: alias (\\([^\\ ]+\\)), name '([^\\ ]+)', sheet '([^\\ ]+)'$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$outpost = array(\t'alias'\t=> $eregs[1],\n\t\t\t\t\t\t\t\t\t\t'name'\t=> $eregs[2],\n\t\t\t\t\t\t\t\t\t\t'sheet'\t=> $eregs[3]);\n\n\t\t\t\t\t$guild_data['outposts'][] = $outpost;\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Challenged Outpost: alias (\\([^\\ ]+\\)), name '([^\\ ]+)', sheet '([^\\ ]+)'$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$outpost = array(\t'alias'\t=> $eregs[1],\n\t\t\t\t\t\t\t\t\t\t'name'\t=> $eregs[2],\n\t\t\t\t\t\t\t\t\t\t'sheet'\t=> $eregs[3]);\n\n\t\t\t\t\t$guild_data['challenged_outposts'][] = $outpost;\n\t\t\t\t}\n\n\n\t\t\t}\n\t\t}\n\n\t\treturn $guild_data;\n\t}\n\n\tfunction tool_gl_parse_grade_change($data)\n\t{\n\t\tnt_common_add_debug($data);\n\n\t\t//Member 'Duff(too)' now has grade 'HighOfficer'\n\t\t//Cannot set 'Duff(too)' as 'HighOfficer' because max count for this grade (1) has been reached\n\n\t\t$guild_data = null;\n\n\t\tif (is_array($data) && (sizeof($data) == 1))\n\t\t{\n\t\t\t$data = $data[0];\n\n\t\t\treset($data);\n\t\t\tforeach($data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\n\t\t\t\tif (ereg(\"^Member '([^\\ ]+)\\(([^\\ ]+)\\)' now has grade '([^\\ ]+)'$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data[] = \"Member \". $eregs[1] .\"  has now the grade of \". $eregs[3] .\"!\";\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Cannot set '([^\\ ]+)\\(([^\\ ]+)\\)' as '([^\\ ]+)' because max count for this grade \\(([^\\ ]+)\\) has been reached$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$guild_data[] = \"Could not change grade of member \". $eregs[1] .\" to \". $eregs[3] .\" (grade is full)\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $guild_data;\n\t}\n\n\tfunction tool_gl_view_forum($host,$shard,$guild,$thread=null,$recover=null)\n\t{\n\t\t$ch = curl_init();\n\n\t\tif (trim($host) == \"\") return \"No MFS Web Host Configured for this domain!\";\n\n\t\t$url = \"http://\". $host .\"/admin.php\";\n\n\t\t$uri_params  = 'user_login=support';\n\t\t$uri_params .= '&shard='. $shard;\n\t\t$uri_params .= '&forum='. $guild;\n\n\t\tif ($thread !== null && $recover === null)\n\t\t{\n\t\t\t$uri_params .= '&thread='. $thread;\n\t\t}\n\t\telseif ($recover !== null && $thread !== null)\n\t\t{\n\t\t\t$uri_params .= '&recover_thread='. $guild;\n\t\t\t$uri_params .= '&recover_threadthread='. $thread;\n\t\t}\n\n\t\tnt_common_add_debug(\"curling '$url' with '$uri_params'\");\n\n\t\tcurl_setopt($ch, CURLOPT_URL, $url);\n\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t\tcurl_setopt($ch, CURLOPT_POSTFIELDS, $uri_params);\n\t\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 0 = debug , 1 = normal\n\t\tcurl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 0 = debug , 1 = normal\n\t\tcurl_setopt($ch, CURLOPT_NOPROGRESS, 0);\n\t\tcurl_setopt($ch, CURLOPT_USERAGENT, \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\");\n\t\tcurl_setopt($ch, CURLOPT_HEADER, 1); // has to be 1 due to using redirections\n\t\tcurl_setopt($ch, CURLOPT_TIMEOUT, 120);\n\n\t\tob_start();\n\t\t$curlOutput\t= curl_exec ($ch);\n\t\tob_end_clean();\n\n\t\t$curlError\t= curl_errno($ch);\n\t\tif ($curlError != 0)\n\t\t{\n\t\t\t$outp\t\t= \"CURL Error [ $curlError ] : \". curl_error($ch);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$curlData \t= tool_gl_CurlParseResponse($curlOutput);\n\t\t\t$outp\t\t= $curlData[2];\n\t\t}\n\n\t\tcurl_close ($ch);\n\n\t\treturn $outp;\n\t}\n\n\n\tfunction tool_gl_CurlParseResponse($response)\n\t{\n\t\t/*\n\t\treturns an array in the following format which varies depending on headers returned\n\n\t\t[0] => the HTTP error or response code such as 404\n\t\t[1] => Array\n\t\t(\n\t\t[Date] => Wed, 28 Apr 2004 23:29:20 GMT\n\t\t[Set-Cookie] => COOKIESTUFF\n\t\t[Expires] => Thu, 01 Dec 1994 16:00:00 GMT\n\t\t[Content-Type] => text/html\n\t\t)\n\t\t[2] => Response body (string)\n\t\t*/\n\n\t\tdo\n\t\t{\n\t\t\tlist($response_headers,$response) = explode(\"\\r\\n\\r\\n\",$response,2);\n\t\t\t$response_header_lines = explode(\"\\r\\n\",$response_headers);\n\n\t\t\t// first line of headers is the HTTP response code\n\t\t\t$http_response_line = array_shift($response_header_lines);\n\t\t\tif (preg_match('@^HTTP/[0-9]\\.[0-9] ([0-9]{3})@',$http_response_line, $matches))\n\t\t\t{\n\t\t\t\t$response_code = $matches[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$response_code = \"Error\";\n\t\t\t}\n\t\t}\n\t\twhile ((substr($response_code, 0,1) == \"1\") || (substr($response_code, 0,1) == \"3\"));\n\n\t\t$response_body = $response;\n\n\t\t// put the rest of the headers in an array\n\t\t$response_header_array = array();\n\t\tforeach ($response_header_lines as $header_line)\n\t\t{\n\t\t\tlist($header,$value) = explode(': ',$header_line,2);\n\t\t\t$response_header_array[$header] = $value;\n\t\t}\n\n\t\treturn array($response_code,$response_header_array,$response_body);\n\t}\n\n\tfunction tool_gl_parse_forum_view($data)\n\t{\n\t\tif (strpos($data,'Warning') !== false)\n\t\t{\n\t\t\t$result = 'Failed to open forums!';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = explode(\"\\n\",$data);\n\t\t\t$result = array();\n\n\t\t\treset($data);\n\t\t\tforeach($data as $line)\n\t\t\t{\n\t\t\t\t$line = trim($line);\n\t\t\t\tif (ereg(\"^FILE:thread\\_([[:digit:]]+)\\.index$\",$line,$regs))\n\t\t\t\t{\n\t\t\t\t\t$result[] = array(\t\"raw\" \t\t=> $line,\n\t\t\t\t\t\t\t\t\t\t\"file\"\t\t=> 'thread_'. $regs[1] .'.index',\n\t\t\t\t\t\t\t\t\t\t\"thread\"\t=> $regs[1],\n\t\t\t\t\t\t\t\t\t\t\"recover\"\t=> 0);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^FILE:\\_thread\\_([[:digit:]]+)\\.index$\",$line,$regs))\n\t\t\t\t{\n\t\t\t\t\t$result[] = array(\t\"raw\" \t\t=> $line,\n\t\t\t\t\t\t\t\t\t\t\"file\"\t\t=> '_thread_'. $regs[1] .'.index',\n\t\t\t\t\t\t\t\t\t\t\"thread\"\t=> $regs[1],\n\t\t\t\t\t\t\t\t\t\t\"recover\"\t=> 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\treturn $result;\n\t}\n\n\tfunction tool_gl_parse_thread_view($data)\n\t{\n/*\nSUPPORT MODE!-- THREAD Elementals of Atys thread_0.index\nTOPIC: Guild Website  SUBMIT: Scar\nAUTHOR: Scar DATE: &lt;i&gt;date#06/10/06&lt;/i&gt; 01:34 POST: is at http://www.elementals-of-atys.com\nAUTHOR: Scorp DATE: &lt;i&gt;date#06/10/06&lt;/i&gt; 03:56 POST: can we please make sure that we all register there asap please, communication is going to be vital to this guild, I will get vent or TS setup in a few days,\n-- END THREAD Elementals of Atys thread_0.index\n*/\n\t\tif (strpos($data,'Warning') !== false)\n\t\t{\n\t\t\t$result = 'Failed to open thread!';\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$data = explode(\"\\n\",$data);\n\t\t\t$result = array();\n\n\t\t\treset($data);\n\t\t\tforeach($data as $line)\n\t\t\t{\n\t\t\t\t$line = trim($line);\n\t\t\t\tif (ereg(\"^SUPPORT.*THREAD (.*) ([\\_]?thread\\_[[:digit:]]+\\.index)$\",$line,$regs))\n\t\t\t\t{\n\t\t\t\t\t$result['header'] = array(\t'raw'\t=> $line,\n\t\t\t\t\t\t\t\t\t\t\t\t'guild'\t=> $regs[1],\n\t\t\t\t\t\t\t\t\t\t\t\t'file'\t=> $regs[2]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^TOPIC: (.*) SUBMIT: (.*)$\",$line,$regs))\n\t\t\t\t{\n\t\t\t\t\t$result['topic'] = array(\t'raw'\t=> $line,\n\t\t\t\t\t\t\t\t\t\t\t\t'topic'\t=> nl2br($regs[1]),\n\t\t\t\t\t\t\t\t\t\t\t\t'who'\t=> $regs[2]);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^AUTHOR: ([^\\ ]+) DATE: ([^\\ ]+ [[:digit:]]{2}\\:[[:digit:]]{2}) POST: (.*)$\",$line,$regs))\n\t\t\t\t{\n\t\t\t\t\t$result['data'][] = array(\t'raw'\t=> $line,\n\t\t\t\t\t\t\t\t\t\t\t\t'who'\t=> $regs[1],\n\t\t\t\t\t\t\t\t\t\t\t\t'date'\t=> $regs[2],\n\t\t\t\t\t\t\t\t\t\t\t\t'post'\t=> nl2br($regs[3]));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\treturn $result;\n\t}\n\n\tfunction tool_gl_recover_thread($shard, $forum, $thread)\n\t{\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_log_analyser.php",
    "content": "<?php\n\n\tfunction tool_las_get_file_list($path)\n\t{\n\t\tif (substr($path,-1) != '/') $path .= '/';\n\n\t\t$file_list\t= null;\n\n\t\tif ($handle = opendir($path))\n\t\t{\n\t\t\twhile (false !== ($file = readdir($handle)))\n\t\t\t{\n\t\t\t\tif ($file != '.' && $file != '..')\n\t\t\t\t{\n\t\t\t\t\tif (!is_array($file_list)) $file_list = array();\n\n\t\t\t\t\t$tmp = array(\t'name'\t=> $file,\n\t\t\t\t\t\t\t\t\t'path'\t=> $path,\n\t\t\t\t\t\t\t\t\t'size'\t=> filesize($path . $file),\n\t\t\t\t\t\t\t\t\t'date'\t=> filemtime($path . $file),\n\t\t\t\t\t\t\t\t\t'code'\t=> base64_encode($file),\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t$file_list[] = $tmp;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (is_array($file_list))\n\t\t\t{\n\t\t\t\treset($file_list);\n\t\t\t\tforeach($file_list as $tmp_key => $tmp_val)\n\t\t\t\t{\n\t\t\t\t\t$date_ary[$tmp_key] = $file_list['date'];\n\t\t\t\t}\n\n\t\t\t\tarray_multisort($date_ary, SORT_DESC, $file_list);\n\t\t\t}\n\n\t\t\tclosedir($handle);\n\t\t}\n\n\n\t\treturn $file_list;\n\t}\n\n\tfunction tool_las_check_for_file($data, $name)\n\t{\n\t\treset($data);\n\t\tforeach($data as $filedata)\n\t\t{\n\t\t\tif ($filedata['name'] == $name)\treturn $filedata;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_las_parse_eids_to_array($eids)\n\t{\n\t\t$eids = trim($eids);\n\t\t$eids = ereg_replace(\"[[:space:]]+\",\" \",$eids);\n\t\t$eids = str_replace(\")(\",\") (\",$eids);\n\n\t\t$tmp = explode(\" \",$eids);\n\n\t\treset($tmp);\n\t\tforeach($tmp as $ktmp => $vtmp)\n\t\t{\n\t\t\t$vtmp = trim($vtmp);\n\t\t\tif (!eregi(\"^\\(0x[^\\)]+\\)$\",$vtmp))\t\tunset($tmp[$ktmp]);\n\t\t\telse\t\t\t\t\t\t\t\t\t$tmp[$ktmp] = $vtmp;\n\t\t}\n\n\t\treturn $tmp;\n\t}\n\n\tfunction tool_las_read_file($filename, $max_lines, $line_start, &$line_previous, &$line_next)\n\t{\n\t\t$data = null;\n\n\t\t$line_previous\t= $line_start - $max_lines;\n\t\t$line_next\t\t= $line_start + $max_lines;\n\n\t\tif ($line_previous < 0)\t$line_previous\t= -1;\n\n\t\t$lines_read = 0;\n\n\t\tif ($fp = fopen($filename,'r'))\n\t\t{\n\t\t\t// skip lines up to $line_start\n\t\t\tfor ($i = 0; $i < $line_start; ++$i)\tfgets($fp);\n\n\t\t\tfor ($i = 0; $i < $max_lines; ++$i)\n\t\t\t{\n\t\t\t\t$tmp = fgets($fp);\n\t\t\t\tif ($tmp)\n\t\t\t\t{\n\t\t\t\t\t$tmp = trim($tmp);\n\t\t\t\t\tif ($tmp != '')\t$data[] = $tmp;\n\n\t\t\t\t\t$lines_read++;\n\t\t\t\t}\n\t\t\t\telse break;\n\t\t\t}\n\n\t\t\tfclose($fp);\n\t\t}\n\n\t\tif ($lines_read < $max_lines)\n\t\t{\n\t\t\t$line_next = -1;\n\t\t}\n\n\t\tnt_common_add_debug(\"tool_las_read_file() : \". $max_lines .\" - \". $line_start .\" - \". $line_previous .\" - \". $line_next);\n\n\t\treturn $data;\n\t}\n\n\n\n\n\n\tfunction tool_las_trim_leading_zero($data)\n\t{\n\t\twhile ($data[0] === '0')\n\t\t{\n\t\t\t$data = substr($data, 1);\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_las_parse_eid($eid, &$uid, &$slotid, &$charid)\n\t{\n\t\t$uid\t= 0;\n\t\t$slotid\t= 0;\n\t\t$charid = 0;\n\n\t\t$ret\t= false;\n\n\t\t$eid = trim($eid);\n\t\tif (ereg(\"^\\(0x([[:alnum:]]{9})([[:digit:]])(\\:[[:alnum:]]+)*[\\)]?$\", $eid, $eid_params))\n\t\t{\n\t\t\t$uid\t= intval('0x'. tool_las_trim_leading_zero($eid_params[1]),16);\n\t\t\t$slotid\t= $eid_params[2];\n\t\t\t$charid\t= ($uid * 16) + $slotid;\n\n\t\t\t$ret\t= true;\n\t\t}\n\n\t\treturn $ret;\n\t}\n\n\tfunction tool_las_parse_file($fname)\n\t{\n\t\t$data = array();\n\n\t\tif ($fp = fopen($fname, \"r\"))\n\t\t{\n\t\t\twhile (!feof($fp))\n\t\t\t{\n\t\t\t\t$input = fgets($fp);\n\t\t\t\t$input = trim($input);\n\n\t\t\t\tif (substr($input, 0, 2) == '#$')\n\t\t\t\t{\n\t\t\t\t\t$input = trim(substr($input, 2));\n\t\t\t\t\t//echo $input .\"<br />\";\n\n\t\t\t\t\tif (ereg(\"^[^\\ ]+\\: LogChat[[:space:]]+\\: ([^\\ ]+) says '(.*)' to (.*)$\", $input, $params))\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_las_parse_eid($params[1], $_uid, $_slotid, $_charid);\n\n\t\t\t\t\t\t$data[$_charid] = $params[1];\n\n\t\t\t\t\t\tforeach(explode(' ', $params[3]) as $eid_listener)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttool_las_parse_eid($eid_listener, $listener_uid, $listener_slotid, $listener_charid);\n\n\t\t\t\t\t\t\tif ($listener_uid != 0)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$data[$listener_charid] = $eid_listener;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfclose($fp);\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_las_get_character_names($dbname, $data)\n\t{\n\t\tglobal $db;\n\n\t\t$char_data = array();\n\n\t\tif ($db->sql_select_db($dbname))\n\t\t{\n\t\t\t$sql = \"SELECT char_id,char_name FROM characters WHERE char_id IN (\". implode(',', array_keys($data)) .\")\";\n\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t{\n\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t{\n\t\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t\t{\n\t\t\t\t\t\t$char_data[$row['char_id']] = $row['char_name'];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$db->sql_reselect_db();\n\t\t}\n\n\t\treturn $char_data;\n\t}\n\n\tfunction tool_las_fpassthru_replace($path, $fname, $search_eid_ary, $search_char_ary)\n\t{\n\t\tif ($fp = fopen($path . $fname, \"r\"))\n\t\t{\n\t\t\tstream_set_timeout($fp, 180);\n\n\t\t\theader(\"Content-type: text/plain\");\n\t\t\theader(\"Content-Disposition: attachment; filename=las_parsed_\". $fname);\n\t\t\theader(\"Pragma: no-cache\");\n\t\t\theader(\"Expires: 0\");\n\n\t\t\t$data = \"\";\n\n\t\t\twhile (!feof($fp))\n\t\t\t{\n\t\t\t\t$tmp = fgets($fp);\n\t\t\t\t$tmp = str_replace($search_eid_ary, $search_char_ary, $tmp);\n\t\t\t\techo $tmp;\n\t\t\t}\n\n\t\t\tfclose($fp);\n\t\t}\n\t}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_main.php",
    "content": "<?php\n\n\t$refresh_rates = array( \n\t\t\t\t\t\t\tarray('desc' => 'Every 5 secs',\n\t\t\t\t\t\t\t\t  'secs' => 5,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Every 30 secs',\n\t\t\t\t\t\t\t\t  'secs' => 30,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Every 1 min.',\n\t\t\t\t\t\t\t\t  'secs' => 60,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Every 5 min.',\n\t\t\t\t\t\t\t\t  'secs' => 300,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Every 10 min.',\n\t\t\t\t\t\t\t\t  'secs' => 600,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Every 30 min.',\n\t\t\t\t\t\t\t\t  'secs' => 1800,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\tarray('desc' => 'Never',\n\t\t\t\t\t\t\t\t  'secs' => 0,\n\t\t\t\t\t\t\t\t  ),\n\t\t\t\t\t\t\t);\n\n\tclass MyAdminService extends CAdminServiceWeb\n\t{\n\t\tfunction commandResult($serviceModuleName, $result)\n\t\t{\n\t\t\tglobal $tpl;\n\t\t\tglobal $command_return_data;\n\n\t\t\tnt_common_add_debug(\"Service $serviceModuleName returned '$result'\");\n\n\t\t\t$data = \"===[ Service \". strtoupper($serviceModuleName) .\" returned ]===\\n\". trim($result) .\"\\n\\n\";\n\n\t\t\tif (isset($command_return_data))\t$command_return_data[] = explode(\"\\n\", $data);\n\t\t\t$tpl->append('tool_execute_result', $data);\n\t\t}\n\n\t\tfunction invokeError($methodName, $errorString)\n\t\t{\n\t\t\tglobal $tpl;\n\n\t\t\tnt_common_add_debug(\"AS Error in '$methodName' : $errorString\");\n\t\t\t$tpl->assign('tool_as_error', \"AS Error in '$methodName' : $errorString\");\n\t\t}\n\t}\n\n\n\tfunction tool_main_check_user_domain($domain_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\tif (!$domain_id) return false;\n\n\t\t$ud = $nel_user['access']['domains'];\n\n\t\tif (is_array($ud))\n\t\t{\n\t\t\treset($ud);\n\t\t\tforeach($ud as $udomain)\n\t\t\t{\n\t\t\t\tif ($domain_id == $udomain['domain_id'])\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction tool_main_check_user_shard($shard_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\tif (!$shard_id) return false;\n\n\t\t$us = $nel_user['access']['shards'];\n\n\t\tif (is_array($us))\n\t\t{\n\t\t\treset($us);\n\t\t\tforeach($us as $ushard)\n\t\t\t{\n\t\t\t\tif ($shard_id == $ushard['shard_id'])\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction tool_main_get_domain_name($domain_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['domains']);\n\t\tforeach($nel_user['access']['domains'] as $domain)\n\t\t{\n\t\t\tif ($domain['domain_id'] == $domain_id)\n\t\t\t{\n\t\t\t\treturn $domain['domain_name'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_domain_data($domain_id, $field)\n\t{\n\t\tglobal $nel_user;\n\t\treset($nel_user['access']['domains']);\n\t\tforeach($nel_user['access']['domains'] as $domain)\n\t\t{\n\t\t\tif ($domain['domain_id'] == $domain_id)\n\t\t\t{\n//\t\techo \"ok $domain_id : $field : \".$domain[$field];\n\t\t\t\treturn $domain[$field];\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\n\tfunction tool_main_get_domain_rrd_path($domain_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['domains']);\n\t\tforeach($nel_user['access']['domains'] as $domain)\n\t\t{\n\t\t\tif ($domain['domain_id'] == $domain_id)\n\t\t\t{\n\t\t\t\treturn $domain['domain_rrd_path'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_shard_name($shard_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['shards']);\n\t\tforeach($nel_user['access']['shards'] as $shard)\n\t\t{\n\t\t\tif ($shard['shard_id'] == $shard_id)\n\t\t\t{\n\t\t\t\treturn $shard['shard_name'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_shard_as_id($shard_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['shards']);\n\t\tforeach($nel_user['access']['shards'] as $shard)\n\t\t{\n\t\t\tif ($shard['shard_id'] == $shard_id)\n\t\t\t{\n\t\t\t\treturn $shard['shard_as_id'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_shard_data($shard_id, $field)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['shards']);\n\t\tforeach($nel_user['access']['shards'] as $shard)\n\t\t{\n\t\t\tif ($shard['shard_id'] == $shard_id)\n\t\t\t{\n\t\t\t\treturn $shard[$field];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\n\tfunction tool_main_get_domain_host($domain_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['domains']);\n\t\tforeach($nel_user['access']['domains'] as $domain)\n\t\t{\n\t\t\tif ($domain['domain_id'] == $domain_id)\n\t\t\t{\n\t\t\t\treturn $domain['domain_as_host'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_domain_port($domain_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\treset($nel_user['access']['domains']);\n\t\tforeach($nel_user['access']['domains'] as $domain)\n\t\t{\n\t\t\tif ($domain['domain_id'] == $domain_id)\n\t\t\t{\n\t\t\t\treturn $domain['domain_as_port'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_elapsed_time_string($seconds, &$string)\n\t{\n\t\t//returns an array of numeric values representing days, hours, minutes & seconds respectively\n\t\t$ret=array('days'=>0,'hours'=>0,'minutes'=>0,'seconds'=>0,'totalseconds'=>0);\n\n\t\t$totalsec = $seconds;\n\t\t$ret['totalseconds'] = $totalsec;\n\t\t//print $earlierDate. \":\". $laterDate. \":\". $totalsec .\"<br>\";\n\n\t\tif ($totalsec >= 86400)\n\t\t{\n\t\t\t$ret['days'] = floor($totalsec/86400);\n\t\t\t$totalsec = $totalsec % 86400;\n\t\t}\n\t\tif ($totalsec >= 3600)\n\t\t{\n\t\t\t$ret['hours'] = floor($totalsec/3600);\n\t\t\t$totalsec = $totalsec % 3600;\n\t\t}\n\t\tif ($totalsec >= 60)\n\t\t{\n\t\t\t$ret['minutes'] = floor($totalsec/60);\n\t\t}\n\t\t$ret['seconds'] = $totalsec % 60;\n\n\t\t$string = '';\n\t\t$string .= ($ret['days'] > 0) ? tool_main_leftpad($ret['days']).'d ' : '';\n\t\t$string .= (($ret['hours'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['hours']).'h ' : '';\n\t\t$string .= (($ret['minutes'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['minutes']).'m ' : '';\n\t\t$string .= (($ret['seconds'] > 0) || (strlen($string) > 0)) ? tool_main_leftpad($ret['seconds']).'s ' : '';\n\n\t\t$ret['string'] = trim($string);\n\n\t\treturn $ret;\n\t}\n\n\tfunction tool_main_leftpad($n,$cc=2,$ch='0')\n\t{\n\t\treturn str_pad($n, $cc, $ch, STR_PAD_LEFT);\n\t}\n\n\tfunction tool_main_get_shards_from_status($status, $filters)\n\t{\n\t\t$result = array();\n\n\t\tif (is_array($status) && sizeof($status))\n\t\t{\n\t\t\treset($status);\n\t\t\tforeach($status as $sline)\n\t\t\t{\n\t\t\t\t$shard_name = trim($sline['ShardName']);\n\n\t\t\t\tif (($shard_name != '') && (isset($filters[$shard_name]) || isset($filters['_all_'])))\n\t\t\t\t{\n\t\t\t\t\t$result[] = $shard_name;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$result = array_values(array_unique($result));\n\t\t}\n\n\t\treturn $result;\n\t}\n\n\tfunction tool_main_get_aes_from_status($status)\n\t{\n\t\t$result = array();\n\t\tif (is_array($status) && sizeof($status))\n\t\t{\n\t\t\treset($status);\n\t\t\tforeach($status as $skey => $sline)\n\t\t\t{\n\t\t\t\t$short_name\t\t= trim($sline['ShortName']);\n\t\t\t\t$running_state\t= trim($sline['RunningState']);\n\t\t\t\tif (($short_name == 'AES') && ($running_state == 'online'))\n\t\t\t\t{\n\t\t\t\t\t$result[] = $sline['AliasName'];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn $result;\n\t}\n\n\tfunction tool_main_parse_status($status)\n\t{\n\t\t$check_graphs = tool_admin_applications_check('tool_main_graphs');\n\n\t\t$_sort_list = array();\n\t\t$domainServices = array();\n\t\t$sortedServices = array();\n\t\tif (is_array($status) && sizeof($status))\n\t\t{\n\t\t\treset($status);\n\t\t\tforeach($status as $sline)\n\t\t\t{\n\t\t\t\t$vars = array();\n\t\t\t\t$vars['_flags_'] = array();\n\n\t\t\t\t$sline_vars = explode(\"\\t\", $sline);\n\t\t\t\treset($sline_vars);\n\t\t\t\tforeach($sline_vars as $sline_var)\n\t\t\t\t{\n\t\t\t\t\t$sline_parts = explode(\"=\", $sline_var);\n\n\t\t\t\t\tif ($sline_parts[0] == 'RunningState')\n\t\t\t\t\t{\n\t\t\t\t\t\t// this is a small fix to an unknown server bug :)\n\t\t\t\t\t\tif \t\t(trim($sline_parts[1]) == 'topped') $sline_parts[1] = 'rs_stopped';\n\t\t\t\t\t\telseif\t(trim($sline_parts[1]) == 'nline') $sline_parts[1] = 'rs_online';\n\n\t\t\t\t\t\t$vars['_flags_'][$sline_parts[1]] = true;\n\t\t\t\t\t\t$sline_parts[1] = substr($sline_parts[1], 3);\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'RunningOrders')\n\t\t\t\t\t{\n\t\t\t\t\t\t$vars['_flags_'][$sline_parts[1]] = true;\n\t\t\t\t\t\t$sline_parts[1] = substr($sline_parts[1], 3);\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'RunningTags')\n\t\t\t\t\t{\n\t\t\t\t\t\t$_tmp = explode(\" \", trim($sline_parts[1]));\n\t\t\t\t\t\treset($_tmp);\n\t\t\t\t\t\tforeach($_tmp as $_tmp_key => $_tmp_part)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$vars['_flags_'][$_tmp_part] = true;\n\t\t\t\t\t\t\t$_tmp_part\t\t\t= str_replace('_',' ',substr($_tmp_part, 3));\n\t\t\t\t\t\t\t$_tmp[$_tmp_key]\t= $_tmp_part;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$sline_parts[1] = implode(' / ', $_tmp);\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'NoReportSince')\n\t\t\t\t\t{\n\t\t\t\t\t\t$_today\t\t= time();\n\t\t\t\t\t\t$_day\t\t= date(\"d\", $_today);\n\t\t\t\t\t\t$_month\t\t= date(\"m\", $_today);\n\t\t\t\t\t\t$_year\t\t= date(\"Y\", $_today);\n\t\t\t\t\t\t$_base_day\t= mktime(0, 0, 0, $_month, $_day, $_year);\n\n\t\t\t\t\t\tif ($sline_parts[1] >= $_base_day)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$sline_parts[1] = 'n/a';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$time0 = 0 + $sline_parts[1]; // convert to a number ;)\n\t\t\t\t\t\t\tif \t\t($time0 > 60)\t$vars['_flags_']['alert_red'] = true;\n\t\t\t\t\t\t\telseif  ($time0 > 40)\t$vars['_flags_']['alert_orange_dark'] = true;\n\t\t\t\t\t\t\telseif  ($time0 > 25)\t$vars['_flags_']['alert_orange_light'] = true;\n\n\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($sline_parts[1],$sline_parts[1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'UpTime')\n\t\t\t\t\t{\n\t\t\t\t\t\t$_today\t\t= time();\n\t\t\t\t\t\t$_day\t\t= date(\"d\", $_today);\n\t\t\t\t\t\t$_month\t\t= date(\"m\", $_today);\n\t\t\t\t\t\t$_year\t\t= date(\"Y\", $_today);\n\t\t\t\t\t\t$_base_day\t= mktime(0, 0, 0, $_month, $_day, $_year);\n\n\t\t\t\t\t\tif ($sline_parts[1] >= $_base_day)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$sline_parts[1] = 'n/a';\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($sline_parts[1],$sline_parts[1]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'State')\n\t\t\t\t\t{\n\t\t\t\t\t\tif (strtolower($sline_parts[1]) == 'stalled')\t\t$vars['_flags_']['alert_red'] = true;\n\t\t\t\t\t\telseif (strtolower($sline_parts[1]) == 'halted')\t$vars['_flags_']['alert_red'] = true;\n\t\t\t\t\t\t$vars['_flags_'][$sline_parts[1]] = true;\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'Hostname')\n\t\t\t\t\t{\n\t\t\t\t\t\t$sline_parts[1] = substr($sline_parts[1], 0, strpos($sline_parts[1], '.'));\n\t\t\t\t\t}\n\t\t\t\t\telseif ($sline_parts[0] == 'AliasName')\n\t\t\t\t\t{\n\t\t\t\t\t\t$vars['_flags_']['alias_code'] = '';\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t//print_r($sline_parts);print_r('</br>');\n\t\t\t\t\tif( count($sline_parts)==2 )\n\t\t\t\t\t{\n\t\t\t\t\t\t$vars[$sline_parts[0]] = $sline_parts[1];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// check is service is chain crashing\n\t\t\t\tif (in_array('rt_chain_crashing', array_keys($vars['_flags_'])))\n\t\t\t\t{\n\t\t\t\t\t// check is service is online (anything that is not stopped)\n\t\t\t\t\tif (!in_array('rs_stopped', array_keys($vars['_flags_'])))\n\t\t\t\t\t{\n\t\t\t\t\t\t// check the start counts for crashing age\n\t\t\t\t\t\t$crash_counts = explode(' ', $vars['StartCounter']);\n\t\t\t\t\t\tif     ($crash_counts[0] >= 5)\t$vars['_flags_']['alert_red'] = true;\n\t\t\t\t\t\telseif ($crash_counts[1] >= 5)\t$vars['_flags_']['alert_orange_dark'] = true;\n\t\t\t\t\t\telseif ($crash_counts[2] >= 5)\t$vars['_flags_']['alert_orange_light'] = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//$vars['_flags_']['has_graphs'] = tool_main_check_rrd_files($vars['AliasName']);\n\t\t\t\t$_sort_list[] = $vars['AliasName'];\n\n\t\t\t\t$domainServices[] = $vars;\n\t\t\t}\n\n\t\t\t/*                       һܼŹ󣬾ô   li9chuan 2014-9-11\n\t\t\tsort($_sort_list);\n\n\t\t\treset($_sort_list);\n\t\t\tforeach($_sort_list as $_sort_name)\n\t\t\t{\n\t\t\t\treset($domainServices);\n\t\t\t\tforeach($domainServices as $serviceRow)\n\t\t\t\t{\n\t\t\t\t\tif ($_sort_name == $serviceRow['AliasName'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$sortedServices[] = $serviceRow;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t//*/\n\t\t}\n\n        //return $sortedServices;\n\t\treturn $domainServices;\n\t}\n\n\tfunction tool_main_check_rrd_files($service)\n\t{\n\t\tif ($handle = opendir(NELTOOL_RRDBASE))\n\t\t{\n   \t\t\twhile (false !== ($file = readdir($handle)))\n   \t\t\t{\n       \t\t\tif ($file != \".\" && $file != \"..\")\n       \t\t\t{\n       \t\t\t\t$file_parts = explode(\".\", $file);\n       \t\t\t\tif (sizeof($file_parts) == 3)\n       \t\t\t\t{\n       \t\t\t\t\tif (($service == $file_parts[0]) && (($file_parts[2] == 'rrd') || ($file_parts[2] == 'hrd')))\n       \t\t\t\t\t{\n       \t\t\t\t\t\tclosedir($handle);\n       \t\t\t\t\t\treturn true;\n       \t\t\t\t\t}\n       \t\t\t\t}\n       \t\t\t}\n   \t\t\t}\n   \t\t\tclosedir($handle);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tfunction tool_main_get_checked_services()\n\t{\n\t\tglobal $NELTOOL;\n\n\t\t$services = array();\n\n\t\treset($NELTOOL['POST_VARS']);\n\t\tforeach($NELTOOL['POST_VARS'] as $post_key => $post_val)\n\t\t{\n\t\t\t$val = 'service_'. $post_val;\n\t\t\tif ($post_key == $val)\n\t\t\t{\n\t\t\t\t$services[] = $post_val;\n\t\t\t}\n\t\t}\n\n\t\treturn $services;\n\t}\n\n\tfunction tool_main_get_shard_ids($shard_id)\n\t{\n\t\tglobal $nel_user;\n\n\t\t$data = array();\n\t\treset($nel_user['access']['shards']);\n\t\tforeach($nel_user['access']['shards'] as $shards)\n\t\t{\n\t\t\tif ($shards['shard_id'] == $shard_id)\n\t\t\t{\n\t\t\t\t$shards_tmp = trim($shards['shard_as_id']);\n\t\t\t\tif ($shards_tmp == '*')\n\t\t\t\t{\n\t\t\t\t\t$data['_all_'] = true;\n\t\t\t\t}\n\t\t\t\telseif ($shards_tmp == '?')\n\t\t\t\t{\n\t\t\t\t\t$data['_unknown_'] = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t$shard_parts = explode(':', $shards_tmp);\n\t\t\t\t\treset($shard_parts);\n\t\t\t\t\tforeach($shard_parts as $shard_as_id)\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($shard_as_id == '?')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$data['_unknown_'] = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$data[$shard_as_id] = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_get_shards_orders($orders)\n\t{\n\t\t$data = array();\n\n\t\tif (is_array($orders) && sizeof($orders))\n\t\t{\n\t\t\treset($orders);\n\t\t\tforeach($orders as $order_line)\n\t\t\t{\n\t\t\t\t$order_items = explode(\"\\t\", $order_line);\n\n\t\t\t\t$shard_name\t\t= \"\";\n\t\t\t\t$shard_order\t= \"\";\n\n\t\t\t\treset($order_items);\n\t\t\t\tforeach($order_items as $order_parts)\n\t\t\t\t{\n\t\t\t\t\t$order_bits = explode(\"=\", $order_parts);\n\n\t\t\t\t\t$order_bits[0] = trim($order_bits[0]);\n\t\t\t\t\t$order_bits[1] = trim($order_bits[1]);\n\n\t\t\t\t\tif ($order_bits[0] == 'ShardName')\n\t\t\t\t\t{\n\t\t\t\t\t\t$shard_name = $order_bits[1];\n\t\t\t\t\t}\n\t\t\t\t\telseif ($order_bits[0] == 'Orders')\n\t\t\t\t\t{\n\t\t\t\t\t\t$shard_order = substr($order_bits[1],3);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ($shard_name != \"\" && $shard_order != \"\")\n\t\t\t\t{\n\t\t\t\t\t$data[$shard_name] = $shard_order;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_get_last_hd_time_for_domain($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$timer = 0;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_STAT_HD_TIME_TABLE .\" WHERE hd_domain_id=\". $domain_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t\t$timer = $data['hd_last_time'];\n\t\t\t}\n\t\t}\n\n\t\treturn $timer;\n\t}\n\n\tfunction tool_main_update_hd_time_for_domain($domain_id, $now)\n\t{\n\t\tglobal $db;\n\n\t\t//if ($stat_time == 0)\t$sql = \"INSERT INTO \". NELDB_STAT_HD_TIME_TABLE .\" (`hd_domain_id`,`hd_last_time`) VALUES (\". $domain_id .\",\". $now .\")\";\n\t\t//else\t\t\t\t\t$sql = \"UPDATE \". NELDB_STAT_HD_TIME_TABLE .\" SET hd_last_time=\". $now .\" WHERE hd_domain_id=\". $domain_id;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_STAT_HD_TIME_TABLE .\" WHERE hd_domain_id=\". $domain_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$sql = \"UPDATE \". NELDB_STAT_HD_TIME_TABLE .\" SET hd_last_time=\". $now .\" WHERE hd_domain_id=\". $domain_id;\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$sql = \"INSERT INTO \". NELDB_STAT_HD_TIME_TABLE .\" (`hd_domain_id`,`hd_last_time`) VALUES (\". $domain_id .\",\". $now .\")\";\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tool_main_update_hd_data_for_domain($domain_id, $data)\n\t{\n\t\tglobal $db;\n\n\t\t$aes_status = array();\n\n\t\tif (is_array($data) && sizeof($data))\n\t\t{\n\t\t\treset($data);\n\t\t\tforeach($data as $aes)\n\t\t\t{\n\t\t\t\t$aes_server = null;\n\n\t\t\t\t//$hd_found_slash_mount\t\t= null;\n\t\t\t\t//$hd_found_slash_home \t\t= null;\n\t\t\t\t//$hd_found_slash_home_nevrax = null;\n\t\t\t\t//$hd_found_slash \t\t\t= null;\n\n\t\t\t\t$aes_hd_ready\t= false;\n\n\t\t\t\t$aes_data = explode(\"\\n\", $aes);\n\t\t\t\treset($aes_data);\n\t\t\t\tforeach($aes_data as $aes_line)\n\t\t\t\t{\n\t\t\t\t\t$aes_line = trim($aes_line);\n\n\t\t\t\t\t// clean up the multiple blank characters\n\t\t\t\t\t$aes_line = ereg_replace(\"[[:space:]]+\",\" \",$aes_line);\n\n\t\t\t\t\tif (ereg(\"^===\\[ Service AES_([^[:space:]]+) returned \\]===$\", $aes_line, $regs))\n\t\t\t\t\t{\n\t\t\t\t\t\t$aes_server = strtolower($regs[1]);\n\t\t\t\t\t\t$aes_status[$aes_server] = array();\n\t\t\t\t\t}\n\t\t\t\t\telseif (ereg(\"^-* Command output begin -*$\", $aes_line, $regs))\n\t\t\t\t\t{\n\t\t\t\t\t\t$aes_hd_ready = true;\n\t\t\t\t\t}\n\t\t\t\t\telseif (ereg(\"^-* Command output end -*$\", $aes_line, $regs))\n\t\t\t\t\t{\n\t\t\t\t\t\t$aes_hd_ready = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($aes_hd_ready)\n\t\t\t\t\t{\n\t\t\t\t\t\t$aes_line_data = explode(\" \", $aes_line);\n\n\t\t\t\t\t\tif (($aes_line_data[0] != 'Filesystem') && ($aes_line_data[1] != 'Command'))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t//if\t((strpos($aes_line_data[5],\"/mnt/rsbk\") == 0)\n\t\t\t\t\t\t\t// ||\t($aes_line_data[5] == \"/home\")\n\t\t\t\t\t\t\t// ||\t($aes_line_data[5] == \"/home/nevrax\")\n\t\t\t\t\t\t\t// ||\t($aes_line_data[5] == \"/\"))\n\t\t\t\t\t\t\t//{\n\t\t\t\t\t\t\t\t$aes_status[$aes_server][] = array(\t'device'\t\t=>\t$aes_line_data[0],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'size'\t\t\t=>\t$aes_line_data[1],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'used'\t\t\t=>\t$aes_line_data[2],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'free'\t\t\t=>\t$aes_line_data[3],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'usedpercent'\t=>\tstr_replace('%','',$aes_line_data[4]),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'mount'\t\t\t=>\t$aes_line_data[5],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t//}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\t//if ((substr($aes_line, 0, 5) == \"/dev/\") && $aes_server)\n\t\t\t\t\t//{\n                    //\n\t\t\t\t\t//\t$aes_line_data = explode(\" \", $aes_line);\n                    //\n\t\t\t\t\t//\t// 0 : device name\n\t\t\t\t\t//\t// 1 : device size\n\t\t\t\t\t//\t// 2 : used\n\t\t\t\t\t//\t// 3 : available\n\t\t\t\t\t//\t// 4 : used percentage\n\t\t\t\t\t//\t// 5 : mount point\n                    //\n\t\t\t\t\t//\tif \t($aes_line_data[5] == \"/home\")\n\t\t\t\t\t//\t{\n\t\t\t\t\t//\t\t$hd_found_slash_home = $aes_line_data;\n\t\t\t\t\t//\t}\n                    //\n\t\t\t\t\t//\tif\t($aes_line_data[5] == \"/home/nevrax\")\n\t\t\t\t\t//\t{\n\t\t\t\t\t//\t\t$hd_found_slash_home_nevrax = $aes_line_data;\n\t\t\t\t\t//\t}\n                    //\n\t\t\t\t\t//\tif\t($aes_line_data[5] == \"/\")\n\t\t\t\t\t//\t{\n\t\t\t\t\t//\t\t$hd_found_slash = $aes_line_data;\n\t\t\t\t\t//\t}\n                    //\n\t\t\t\t\t//\t//if (($aes_line_data[5] == \"/\") || ($aes_line_data[5] == \"/home/nevrax\"))\n\t\t\t\t\t//\t//{\n\t\t\t\t\t//\t//\t$aes_status[$aes_server][] = array(\t'device'\t\t=>\t$aes_line_data[0],\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t'size'\t\t\t=>\t$aes_line_data[1],\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t'used'\t\t\t=>\t$aes_line_data[2],\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t'free'\t\t\t=>\t$aes_line_data[3],\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t'usedpercent'\t=>\tstr_replace('%','',$aes_line_data[4]),\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t'mount'\t\t\t=>\t$aes_line_data[5],\n\t\t\t\t\t//\t//\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t//\t//}\n                    //\n\t\t\t\t\t//}\n\t\t\t\t}\n\n\t\t\t\t//$tmp = null;\n                //\n\t\t\t\t//if\t\t(is_array($hd_found_slash_mount))\t\t$tmp = $hd_found_slash_mount;\n\t\t\t\t//elseif\t(is_array($hd_found_slash_home))\t\t$tmp = $hd_found_slash_home;\n\t\t\t\t//elseif\t(is_array($hd_found_slash_home_nevrax))\t$tmp = $hd_found_slash_home_nevrax;\n\t\t\t\t//elseif\t(is_array($hd_found_slash))\t\t\t\t$tmp = $hd_found_slash;\n                //\n\t\t\t\t//if (is_array($tmp))\n\t\t\t\t//{\n\t\t\t\t//\t$aes_status[$aes_server][] = array(\t'device'\t\t=>\t$tmp[0],\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t'size'\t\t\t=>\t$tmp[1],\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t'used'\t\t\t=>\t$tmp[2],\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t'free'\t\t\t=>\t$tmp[3],\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t'usedpercent'\t=>\tstr_replace('%','',$tmp[4]),\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t'mount'\t\t\t=>\t$tmp[5],\n\t\t\t\t//\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t//}\n\t\t\t}\n\n\t\t\tif (sizeof($aes_status))\n\t\t\t{\n\t\t\t\tnt_common_add_debug($aes_status);\n\t\t\t\t//echo '<pre>'. print_r($aes_status, true) .'</pre>';\n\n\n\t\t\t\t$sql = \"DELETE FROM \". NELDB_STAT_HD_TABLE .\" WHERE hd_domain_id=\". $domain_id;\n\t\t\t\t$db->sql_query($sql);\n\n\t\t\t\treset($aes_status);\n\t\t\t\tforeach($aes_status as $server_name => $server_datas)\n\t\t\t\t{\n\t\t\t\t\treset($server_datas);\n\t\t\t\t\tforeach($server_datas as $server_hd)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (trim($server_name) != '')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$sql  = \"INSERT INTO \". NELDB_STAT_HD_TABLE .\" (`hd_domain_id`,`hd_server`,`hd_device`,`hd_size`,`hd_used`,`hd_free`,`hd_percent`,`hd_mount`)\";\n\t\t\t\t\t\t\t$sql .= \" VALUES (\". $domain_id .\",'\". $server_name .\"','\". $server_hd['device'] .\"','\". $server_hd['size'] .\"',\";\n\t\t\t\t\t\t\t$sql .= \"'\". $server_hd['used'] .\"','\". $server_hd['free'] .\"','\". $server_hd['usedpercent'] .\"','\". $server_hd['mount'] .\"')\";\n\t\t\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (defined('NELTOOL_CRON_DEBUG')) echo \"<br />SQL:$sql\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttool_main_update_hd_time_for_domain($domain_id, time());\n\t\t\t}\n\t\t}\n\n\t}\n\n\tfunction tool_main_get_hd_data_for_domain($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\t//$sql = \"SELECT * FROM \". NELDB_STAT_HD_TABLE .\" WHERE hd_domain_id=\". $domain_id .\" AND hd_mount='/' ORDER BY hd_percent DESC\";\n\t\t$sql = \"SELECT * FROM \". NELDB_STAT_HD_TABLE .\" WHERE hd_domain_id=\". $domain_id .\" ORDER BY hd_percent DESC\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\t$outp  = '<b>'. $row['hd_server'] .'</b> : '. $row['hd_device'] .'<br>';\n\t\t\t\t\t$outp .= ' Mount : '. $row['hd_mount'] .'<br>';\n\t\t\t\t\t$outp .= ' Size : '. $row['hd_size'] .'<br>';\n\t\t\t\t\t$outp .= ' Used : '. $row['hd_used'] .'<br>';\n\t\t\t\t\t$outp .= ' Free : '. $row['hd_free'] .'<br>';\n\n\t\t\t\t\t$row['summary'] = $outp;\n\t\t\t\t\t$data[] = $row;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_get_annotation($domain_id, $shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_ANNOTATION_TABLE .\" WHERE 1=0\";\n\t\tif ($domain_id > 0)\t$sql .= \" OR annotation_domain_id=\". $domain_id;\n\t\tif ($shard_id  > 0)\t$sql .= \" OR annotation_shard_id=\". $shard_id;\n\t\t$sql .= \" ORDER BY annotation_date DESC\";\n\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_get_lock($domain_id, $shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_LOCK_TABLE .\" WHERE 1=0 \";\n\t\tif ($domain_id > 0)\t$sql .= \" OR lock_domain_id=\". $domain_id;\n\t\tif ($shard_id  > 0) $sql .= \" OR lock_shard_id=\". $shard_id;\n\t\t$sql .= \" ORDER BY lock_date DESC\";\n\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_delete_lock_shard($shard_id)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\n\t\tnt_log(\"Shard Unlock (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"') by '\". $nel_user['user_name'] .\"'\");\n\t\t$sql = \"DELETE FROM \". NELDB_LOCK_TABLE .\" WHERE lock_shard_id=\". $shard_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_main_delete_lock_domain($domain_id)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\n\t\tnt_log(\"Domain Unlock (Domain: '\". $AS_Name .\"') by '\". $nel_user['user_name'] .\"'\");\n\t\t$sql = \"DELETE FROM \". NELDB_LOCK_TABLE .\" WHERE lock_domain_id=\". $domain_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\n\tfunction tool_main_set_lock_shard($domain_id, $shard_id, $log=true)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\n\t\t// we need to check if the shard is *all*\n\t\t// if its the case, we go for a lock domain instead\n\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" WHERE shard_id=\". $shard_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$shard_row = $db->sql_fetchrow($result);\n\n\t\t\t\tif ($shard_row['shard_as_id'] == \"*\")\n\t\t\t\t{\n\t\t\t\t\treturn tool_main_set_lock_domain($domain_id, $log);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t$data = tool_main_get_lock($domain_id, $shard_id);\n\t\t$now = time();\n\n\t\tif (is_array($data) && ($data['lock_shard_id'] > 0))\n\t\t{\n\t\t\tif ($log) nt_log(\"Shard Lock (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"') by '\". $nel_user['user_name'] .\"'\");\n\t\t\t$sql = \"UPDATE \". NELDB_LOCK_TABLE .\" SET lock_user_name='\". $nel_user['user_name'] .\"',lock_update=\". $now .\" WHERE lock_id=\". $data['lock_id'];\n\t\t\t$db->sql_query($sql);\n\t\t}\n\t\telseif (!$data)\n\t\t{\n\t\t\tif ($log) nt_log(\"Shard Lock (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"') by '\". $nel_user['user_name'] .\"'\");\n\t\t\t$sql = \"INSERT INTO \". NELDB_LOCK_TABLE .\" (`lock_shard_id`,`lock_user_name`,`lock_date`,`lock_update`) VALUES (\". $shard_id .\",'\". $nel_user['user_name'] .\"',\". $now .\",\". $now .\")\";\n\t\t\t$db->sql_query($sql);\n\t\t}\n\n\t}\n\n\tfunction tool_main_get_domain_shard_list($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" WHERE shard_domain_id=\". $domain_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\t$data[] = $row['shard_id'];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_set_lock_domain($domain_id, $log=true)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\n\t\t// to lock a domain you need to remove all locks from any shard in it\n\n\t\t$lock_data = tool_main_get_lock($domain_id, 0);\n\n\t\t$now = time();\n\n\t\tif (is_array($lock_data))\n\t\t{\n\t\t\t$sql = \"UPDATE \". NELDB_LOCK_TABLE .\" SET lock_user_name='\". $nel_user['user_name'] .\"',lock_update=\". $now .\" WHERE lock_id=\". $lock_data['lock_id'];\n\t\t\t$db->sql_query($sql);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$shard_list = tool_main_get_domain_shard_list($domain_id);\n\t\t\t$shard_list = array_values($shard_list);\n\n\t\t\t$sql = \"DELETE FROM \". NELDB_LOCK_TABLE .\" WHERE lock_shard_id IN (\". implode(',', $shard_list) .\")\";\n\t\t\t$db->sql_query($sql);\n\n\t\t\t$sql = \"INSERT INTO \". NELDB_LOCK_TABLE .\" (`lock_domain_id`,`lock_user_name`,`lock_date`,`lock_update`) VALUES (\". $domain_id .\",'\". $nel_user['user_name'] .\"',\". $now .\",\". $now .\")\";\n\t\t\t$db->sql_query($sql);\n\t\t}\n\n\t\tif ($log) nt_log(\"Domain Lock (Domain: '\". $AS_Name .\"') by '\". $nel_user['user_name'] .\"'\");\n\t}\n\n\tfunction tool_main_set_annotation($domain_id, $shard_id, $annotation)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\n\t\t$annotation = htmlentities(trim($annotation), ENT_QUOTES);\n\n\t\t$data = tool_main_get_lock($domain_id, $shard_id);\n\n\t\tif ($data['lock_domain_id'])\n\t\t{\n\t\t\t// its a domain lock\n\t\t\t$shard_list = tool_main_get_domain_shard_list($domain_id);\n\t\t\t$shard_list = array_values($shard_list);\n\n\t\t\t$sql = \"DELETE FROM \". NELDB_ANNOTATION_TABLE .\" WHERE annotation_shard_id IN (\". implode(',', $shard_list) .\")\";\n\t\t\t$db->sql_query($sql);\n\n\t\t\t$annotation_data = tool_main_get_annotation($domain_id, 0);\n\t\t\tif ($annotation_data)\n\t\t\t{\n\t\t\t\tnt_log(\"Domain Annotation (Domain: '\". $AS_Name .\"') by '\". $nel_user['user_name'] .\"' : \". $annotation);\n\t\t\t\t$sql = \"UPDATE \". NELDB_ANNOTATION_TABLE .\" SET annotation_data='\". $annotation .\"',annotation_user_name='\". $nel_user['user_name'] .\"',annotation_date=\". time() .\" WHERE annotation_id=\". $annotation_data['annotation_id'];\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnt_log(\"Domain Annotation (Domain: '\". $AS_Name .\"') by '\". $nel_user['user_name'] .\"' : \". $annotation);\n\t\t\t\t$sql  = \"INSERT INTO \". NELDB_ANNOTATION_TABLE .\" (`annotation_domain_id`,`annotation_data`,`annotation_user_name`,`annotation_date`) VALUES \";\n\t\t\t\t$sql .= \"(\". $domain_id .\",'\". $annotation .\"','\". $nel_user['user_name'] .\"',\". time() .\")\";\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// its a shard lock\n\t\t\t$annotation_data = tool_main_get_annotation(0, $shard_id);\n\t\t\tif ($annotation_data)\n\t\t\t{\n\t\t\t\tnt_log(\"Shard Annotation (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"') by '\". $nel_user['user_name'] .\"' : \". $annotation);\n\t\t\t\t$sql = \"UPDATE \". NELDB_ANNOTATION_TABLE .\" SET annotation_data='\". $annotation .\"',annotation_user_name='\". $nel_user['user_name'] .\"',annotation_date=\". time() .\" WHERE annotation_id=\". $annotation_data['annotation_id'];\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnt_log(\"Shard Annotation (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"') by '\". $nel_user['user_name'] .\"' : \". $annotation);\n\t\t\t\t$sql  = \"INSERT INTO \". NELDB_ANNOTATION_TABLE .\" (`annotation_shard_id`,`annotation_data`,`annotation_user_name`,`annotation_date`) VALUES \";\n\t\t\t\t$sql .= \"(\". $shard_id .\",'\". $annotation .\"','\". $nel_user['user_name'] .\"',\". time() .\")\";\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t}\n\t}\n\n\n\tfunction tool_main_get_shards_info_from_db($application, $status, $filters, $ringsqlstring='')\n\t{\n\t\t$shard_list\t\t\t= array();\n\t\t$shard_list_result\t= array();\n\n\t\t//nt_common_add_debug('in tool_main_get_shards_info_from_db()');\n\t\t//nt_common_add_debug($status);\n\n\t\tif (is_array($status) && sizeof($status))\n\t\t{\n\t\t\treset($status);\n\t\t\tforeach($status as $sline)\n\t\t\t{\n\t\t\t\t$shard_name = trim($sline['ShardName']);\n\t\t\t\t$shard_id\t= trim($sline['ShardId']);\n\n\t\t\t\tif (($shard_name != '' && $shard_id != '') && (isset($filters[$shard_name]) || isset($filters['_all_'])))\n\t\t\t\t{\n\t\t\t\t\tif (!in_array($shard_name, array_values($shard_list)))\n\t\t\t\t\t{\n\t\t\t\t\t\t$shard_list[$shard_id] = $shard_name;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnt_common_add_debug('shard_list :');\n\t\tnt_common_add_debug($shard_list);\n\n\t\treset($shard_list);\n\t\tforeach($shard_list as $shard_key => $shard_application)\n\t\t{\n\t\t\tif (is_numeric($shard_key))\n\t\t\t{\n\t\t\t\t$shard_list2[$shard_key] = $shard_application;\n\t\t\t}\n\t\t}\n\n\t\t//nt_common_add_debug('shard_list2 :');\n\t\t//nt_common_add_debug($shard_list2);\n\n\t\tif ($ringsqlstring == '')\n\t\t{\n\t\t\tglobal $db;\n\t\t\t$db->sql_select_db('nel');\n\n\t\t\t//$sql = \"SELECT * FROM shard WHERE ShardId IN (\". implode(',', array_keys($shard_list)) .\")\";\n\t\t\tif (is_array($shard_list2) && sizeof($shard_list2))\n\t\t\t{\n\t\t\t\t$sql = \"SELECT * FROM shard, domain WHERE shard.domain_id=domain.domain_id AND shard.ShardId IN (\". implode(',', array_keys($shard_list2)) .\") AND domain.domain_name='\". $application .\"'\";\n\n\t\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t\t{\n\t\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t\t{\n\t\t\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// patch to support live and ats mysql changes\n\t\t\t\t\t\t\t$state = '';\n\t\t\t\t\t\t\tif (isset($row['State']))\t\t\t\t$state = $row['State'];\n\t\t\t\t\t\t\telseif (isset($row['RequiredState']))\t$state = $row['RequiredState'];\n\n\t\t\t\t\t\t\t$shard_name = $shard_list[$row['ShardId']];\n\t\t\t\t\t\t\t$shard_list_result[$shard_name] = array('shard_id'\t=> $row['ShardId'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'version'\t=> $row['Version'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'state'\t\t=> substr($state,3),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'motd'\t\t=> $row['MOTD'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$db->sql_reselect_db();\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$db = new sql_db_string($ringsqlstring);\n\t\t\tif (is_object($db))\n\t\t\t{\n\t\t\t\tif (is_array($shard_list2) && sizeof($shard_list2))\n\t\t\t\t{\n\t\t\t\t\t//nt_common_add_debug(\"tool_main_get_shards_info_from_db()\");\n\t\t\t\t\t//nt_common_add_debug($shard_list2);\n\n\t\t\t\t\t$sql = \"SELECT * FROM shard WHERE shard_id IN (\". implode(',', array_keys($shard_list2)) .\")\";\n\n\t\t\t\t\tif ($result = $db->sql_query($sql))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// patch to support live and ats mysql changes\n\t\t\t\t\t\t\t\t$state = '';\n\t\t\t\t\t\t\t\tif (isset($row['State']))\t\t\t\t$state = $row['State'];\n\t\t\t\t\t\t\t\telseif (isset($row['RequiredState']))\t$state = $row['RequiredState'];\n\n\t\t\t\t\t\t\t\t$shard_name = $shard_list[$row['shard_id']];\n\t\t\t\t\t\t\t\t$shard_list_result[$shard_name] = array('shard_id'\t=> $row['shard_id'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//'version'\t=> $row['Version'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'state'\t\t=> substr($state,3),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'motd'\t\t=> $row['MOTD'],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug('in tool_main_get_shards_info_from_db() : shard_list2 is empty !');\n\t\t\t\t\t//nt_common_add_debug('dumping : filters');\n\t\t\t\t\t//nt_common_add_debug($filters);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// db error\n\t\t\t}\n\n\t\t}\n\n\n\t\treturn $shard_list_result;\n\t}\n\n\tfunction tool_main_get_su_from_status($status)\n\t{\n\t\tif (is_array($status) && sizeof($status))\n\t\t{\n\t\t\treset($status);\n\t\t\tforeach($status as $sline)\n\t\t\t{\n\t\t\t\tif ($sline['ShortName'] == 'SU')\n\t\t\t\t{\n\t\t\t\t\treturn $sline['AliasName'];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_set_restart_mode($domain_id, $shard_id, $restart_mode=0)\n\t{\n\t\tglobal $db, $nel_user, $tpl;\n\t\tglobal $AS_ShardRestart, $AS_ShardDomainRestart;\n\n\t\t$sequence_info = tool_main_get_restart_sequence($nel_user['user_name'], $domain_id, $shard_id);\n\n\t\tif (!$sequence_info)\n\t\t{\n\t\t\t$sequence_info = tool_main_add_restart_sequence($nel_user['user_name'], $domain_id, $shard_id, $restart_mode);\n\t\t}\n\n\t\tif ($sequence_info)\n\t\t{\n\t\t\t$sql = \"UPDATE \". NELDB_SHARD_TABLE .\" SET shard_restart=\". $sequence_info['restart_sequence_id'] .\" WHERE shard_id=\". $shard_id .\" AND shard_domain_id=\". $domain_id;\n\t\t\t$db->sql_query($sql);\n\n\t\t\t// update shards information\n\t\t\t$nel_user['access']['user_shards']\t= tool_admin_users_shards_get_list($nel_user['user_id']);\n\t\t\t$nel_user['access']['group_shards']\t= tool_admin_groups_shards_get_list($nel_user['user_group_id']);\n\t\t\t$nel_user['access']['shards'] \t\t= tool_admin_users_groups_shards_merge();\n\t\t\t$tpl->assign('tool_shard_list',\t$nel_user['access']['shards']);\n\n\t\t\t// update shard restart information\n\t\t\t$AS_ShardRestart\t\t= tool_main_get_shard_data($shard_id, 'shard_restart');\n\t\t\t$AS_ShardDomainRestart\t= tool_main_get_domain_shard_restart($view_domain_id);\n\t\t\t$tpl->assign('tool_shard_restart_status', \t\t$AS_ShardRestart);\n\t\t\t$tpl->assign('tool_domain_has_shard_restart',\t$AS_ShardDomainRestart);\n\t\t}\n\n\t\treturn $sequence_info;\n\t}\n\n\tfunction tool_main_add_restart_sequence($user_name, $domain_id, $shard_id, $step=0)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\t\tglobal $restart_notification_emails;\n\n\t\t$now = time();\n\n\t\t$sql  = \"INSERT INTO \". NELDB_RESTART_SEQUENCE_TABLE;\n\t\t$sql .= \" (`restart_sequence_domain_id`,`restart_sequence_shard_id`,`restart_sequence_user_name`,\";\n\t\t$sql .= \"  `restart_sequence_step`,`restart_sequence_date_start`,`restart_sequence_date_end`) VALUES \";\n\t\t$sql .= \" (\". $domain_id .\",\". $shard_id .\",'\". $user_name .\"',\";\n\t\t$sql .=       $step .\",\". $now .\",\". $now .\")\";\n\t\t$db->sql_query($sql);\n\n\t\t$sequence_info = tool_main_get_restart_sequence_by_id($db->sql_nextid());\n\n\t\tnt_log(\"Shard Restart (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"' - Sequence: '\". $sequence_info['restart_sequence_id'] .\"') started by '\". $nel_user['user_name'] .\"'\");\n\n\t\t$email_subject\t= \"[Shard Admin Tool] Restart Sequence Begins (id: \".$sequence_info['restart_sequence_id'].\", step: \". $step .\") for shard \".$AS_Name.\"/\".$AS_ShardName.\" by \".$nel_user['user_name'];\n\t\t$email_message\t= $email_subject;\n\t\tnt_email($email_subject,$email_message,$restart_notification_emails);\n\n\t\treturn $sequence_info;\n\t}\n\n\tfunction tool_main_get_restart_sequence($user_name, $domain_id, $shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_SEQUENCE_TABLE .\" WHERE restart_sequence_domain_id=\". $domain_id .\" AND restart_sequence_shard_id=\". $shard_id .\" AND restart_sequence_user_name='\". $user_name .\"' AND restart_sequence_step=0 AND restart_sequence_date_start=restart_sequence_date_end\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_get_restart_sequence_by_id($sequence_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_RESTART_SEQUENCE_TABLE .\" WHERE restart_sequence_id=\". $sequence_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_set_next_restart_sequence_step($sequence_id, $step=null)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\t\tglobal $restart_notification_emails;\n\n\t\t$now = time();\n\n\t\tif ($step === null)\n\t\t{\n\t\t\t$sequence_info = tool_main_get_restart_sequence_by_id($sequence_id);\n\t\t\t$step = $sequence_info['restart_sequence_step'] + 1;\n\t\t}\n\n\t\t$sql = \"UPDATE \". NELDB_RESTART_SEQUENCE_TABLE .\" SET restart_sequence_step=\". $step .\",restart_sequence_date_end=\". $now .\" WHERE restart_sequence_id=\". $sequence_id;\n\t\t$db->sql_query($sql);\n\n\t\tnt_log(\"Shard Restart (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"' - Sequence: '\". $sequence_id .\"') - \". $nel_user['user_name'] .\" moved to step \". $step);\n\n\t\tif ($step !== null)\n\t\t{\n\t\t\t$email_subject\t= \"[Shard Admin Tool] Restart Sequence Updated (id: \".$sequence_id.\", step: \". $step .\") for shard \".$AS_Name.\"/\".$AS_ShardName.\" by \".$nel_user['user_name'];\n\t\t\t$email_message\t= $email_subject;\n\t\t\tnt_email($email_subject,$email_message,$restart_notification_emails);\n\t\t}\n\n\t\treturn tool_main_get_restart_sequence_by_id($sequence_id);\n\t}\n\n\tfunction tool_main_set_end_restart_sequence($sequence_id)\n\t{\n\t\tglobal $db;\n\t\tglobal $nel_user;\n\t\tglobal $AS_Name, $AS_ShardName;\n\t\tglobal $restart_notification_emails;\n\n\t\t//$sequence_info = tool_main_set_next_restart_sequence_step($sequence_id);\n\t\t$sequence_info = tool_main_get_restart_sequence_by_id($sequence_id);\n\n\t\t$sql = \"UPDATE \". NELDB_SHARD_TABLE .\" SET shard_restart=0 WHERE shard_domain_id=\". $sequence_info['restart_sequence_domain_id'] .\" AND shard_id=\". $sequence_info['restart_sequence_shard_id'];\n\t\t$db->sql_query($sql);\n\n\t\tnt_log(\"Shard Restart (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"' - Sequence: '\". $sequence_id .\"') - \". $nel_user['user_name'] .\" ended the sequence !\". $step);\n\n\t\t$email_subject\t= \"[Shard Admin Tool] Restart Sequence Ends (id: \".$sequence_info['restart_sequence_id'].\", step: \". $sequence_info['restart_sequence_step'] .\") for shard \".$AS_Name.\"/\".$AS_ShardName.\" by \".$nel_user['user_name'];\n\t\t$email_message\t= $email_subject;\n\t\tnt_email($email_subject,$email_message,$restart_notification_emails);\n\t}\n\n\tfunction tool_main_get_domain_shard_restart($domain_id)\n\t{\n\t\tglobal $db;\n\n\t\t$num = 0;\n\t\t$sql = \"SELECT * FROM \". NELDB_SHARD_TABLE .\" WHERE shard_domain_id=\". $domain_id .\" AND shard_restart>0\";\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\t$num = $db->sql_numrows($result);\n\t\t}\n\n\t\treturn $num;\n\t}\n\n\tfunction tool_main_get_restart_services($InternalName, $domainServices, $restart_list)\n\t{\n\t\t// lets sort each services by 'type'\n\t\tnt_common_add_debug(\"RESTART DEBUG\");\n\t\tnt_common_add_debug($domainServices);\n\n\t\t$sortedServices = array();\n\n\t\treset($domainServices);\n\t\tforeach($domainServices as $domainService)\n\t\t{\n\t\t\tif ($domainService['ShardName'] == $InternalName)\n\t\t\t{\n\t\t\t\t// this should be the real 'type'\n\t\t\t\t// $type = $domainService['ShortName'];\n\t\t\t\t// but instead we'll take the first part of the AliasName (as in \"rws\" or \"rws_aniro\")\n\t\t\t\t$type = explode('_',$domainService['AliasName']);\n\t\t\t\t$type = trim(strtolower($type[0]));\n\n\t\t\t\tif (!isset($sortedServices[$type]))\n\t\t\t\t{\n\t\t\t\t\t$sortedServices[$type] = array();\n\t\t\t\t}\n\n\t\t\t\t$sortedServices[$type][] = $domainService['AliasName'];\n\t\t\t\tnt_common_add_debug(\"Adding '\". $domainService['AliasName'] .\"' to '$type'\");\n\t\t\t}\n\t\t}\n\n\t\treset($restart_list);\n\t\tforeach($restart_list as $restart_key => $restart_group)\n\t\t{\n\t\t\t$group_list = explode(',', $restart_group['restart_group_list']);\n\t\t\t$tmp_list = array();\n\n\t\t\treset($group_list);\n\t\t\tforeach($group_list as $group_service_type)\n\t\t\t{\n\t\t\t\t$group_service_type = trim($group_service_type);\n\t\t\t\tnt_common_add_debug(\"looking for '$group_service_type'\");\n\n\t\t\t\tif (isset($sortedServices[$group_service_type]))\n\t\t\t\t{\n\t\t\t\t\t$tmp_list[] = implode(',',$sortedServices[$group_service_type]);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug(\"not found!\");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$restart_list[$restart_key]['service_list'] = implode(',',$tmp_list);\n\n\t\t}\n\n        nt_common_add_debug(\"RESTART SERVICES DEBUG\");\n\t\tnt_common_add_debug($restart_list);\n\n\t\treturn $restart_list;\n\t}\n\n\tfunction tool_main_get_all_restart_services($restart_list)\n\t{\n\t\t$stop_data = array();\n\t\t$stop_list = '';\n\n\t\treset($restart_list);\n\t\tforeach($restart_list as $restart_key => $restart_group)\n\t\t{\n\t\t\t$stop_data[] = $restart_group['service_list'];\n\t\t}\n\n\t\t$stop_list = implode(',', $stop_data);\n\t\treturn $stop_list;\n\t}\n\n\tfunction tool_main_get_shardid_from_status($domainServices, $InternalName)\n\t{\n\t\treset($domainServices);\n\t\tforeach($domainServices as $service)\n\t\t{\n\t\t\tif (($service['ShardName'] == $InternalName) && (is_numeric($service['ShardId'])))\n\t\t\t{\n\t\t\t\treturn $service['ShardId'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_get_egs_from_status($domainServices, $InternalName)\n\t{\n\t\treset($domainServices);\n\t\tforeach ($domainServices as $service)\n\t\t{\n\t\t\tif (($service['ShardName'] == $InternalName) && ($service['ShortName'] == 'EGS'))\n\t\t\t{\n\t\t\t\treturn $service['AliasName'];\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tfunction tool_main_set_restart_sequence_timer($sequence_id, $timer)\n\t{\n\t\tglobal $db;\n\n\t\t$now \t\t= time();\n\t\t$timer \t\t= $timer;\n\t\t$new_timer\t= $now + $timer;\n\n\t\t$sql = \"UPDATE \". NELDB_RESTART_SEQUENCE_TABLE .\" SET restart_sequence_date_end=\". $now .\",restart_sequence_timer=\". $new_timer .\" WHERE restart_sequence_id=\". $sequence_id;\n\t\t$db->sql_query($sql);\n\n\t\treturn array('start' => $now, 'end' => $new_timer);\n\t}\n\n\tfunction tool_main_change_restart_notification($event_list, $mode, $sql_connection)\n\t{\n\t\tif ($sql_connection != '' && sizeof($event_list))\n\t\t{\n\t\t\t$csdb = new sql_db_string($sql_connection);\n\t\t\tif (is_object($csdb))\n\t\t\t{\n\t\t\t\t$sql = \"UPDATE Sorbot_events SET event_action=\". $mode .\",event_time=\". time() .\",event_lap=0 WHERE event_id IN (\". implode(',', array_values($event_list)) .\")\";\n\t\t\t\t$csdb->sql_query($sql);\n\n\t\t\t\t$csdb->sql_close();\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction tool_main_add_restart_notification($sequence_id, $service_su, $service_egs, $shard_id, $sorbot_message_type, $sql_connection, $shard_lang='en')\n\t{\n\t\tnt_common_add_debug('tool_main_add_restart_notification()');\n\n\t\tif ($sql_connection != '')\n\t\t{\n\t\t\t$csdb = new sql_db_string($sql_connection);\n\t\t\tif (is_object($csdb))\n\t\t\t{\n\t\t\t\t$sequence_info\t= tool_main_get_restart_sequence_by_id($sequence_id);\n\t\t\t\t$shard_info\t\t= tool_main_get_domain_shard_data($sequence_info['restart_sequence_domain_id'], $sequence_info['restart_sequence_shard_id']);\n\n\t\t\t\tif ($sorbot_message_type == 4102)\n\t\t\t\t{\n\t\t\t\t\t//$open_timer\t= 60*25; // 25 minutes before a shard opens itself\n\t\t\t\t\t// new timer\n\t\t\t\t\t$open_timer\t= 60*10; // 10 minutes before a shard opens itself\n\t\t\t\t}\n\t\t\t\telse // 4101\n\t\t\t\t{\n\t\t\t\t\t$open_timer = 0;\n\t\t\t\t}\n\n\t\t\t\tif ($sequence_info && $shard_info)\n\t\t\t\t{\n\t\t\t\t\t// lets find the shard id used by the ticket system\n\t\t\t\t\t$sql = \"SELECT * FROM ForumCS_tickets_shards WHERE shard_ca='\". $shard_info['domain_application'] .\"' AND shard_id='\". $shard_id .\"'\";\n\t\t\t\t\tif ($result = $csdb->sql_query($sql))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($csdb->sql_numrows($result))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$ticketsystem_shard_info = $csdb->sql_fetchrow($result);\n\t\t\t\t\t\t\tnt_common_add_debug($ticketsystem_shard_info);\n\n\t\t\t\t\t\t\t$ticketsystem_shard_id = $ticketsystem_shard_info['id'];\n\n\t\t\t\t\t\t\t// now we have the shard id, lets see which klients servers wants events for it\n\t\t\t\t\t\t\t$sql = \"SELECT * FROM Sorbot_botconfig WHERE config_name='shardRestart' AND config_value LIKE '%:\". $ticketsystem_shard_id .\":%'\";\n\t\t\t\t\t\t\tif ($result2 = $csdb->sql_query($sql))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ($csdb->sql_numrows($result2))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t//$klients_servers = array();\n\t\t\t\t\t\t\t\t\t//while ($row = $csdb->sql_fetchrow($result2))\n\t\t\t\t\t\t\t\t\t//{\n\t\t\t\t\t\t\t\t\t//\t$klients_servers[] = $row['server_name'];\n\t\t\t\t\t\t\t\t\t//}\n\n\t\t\t\t\t\t\t\t\t// NOTE: live but not in CVS yet !\n\t\t\t\t\t\t\t\t\t$local_timer = $open_timer;\n\n\t\t\t\t\t\t\t\t\t$klients_servers = array();\n\t\t\t\t\t\t\t\t\twhile ($row = $csdb->sql_fetchrow($result2))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$klients_servers[] = $row['server_name'];\n\n\t\t\t\t\t\t\t\t\t\t// lets find if there is any specific opening timer, and keep the lowest one\n\t\t\t\t\t\t\t\t\t\t$sql = \"SELECT * FROM Sorbot_botconfig WHERE server_name='\". $row['server_name'] .\"' AND config_name='shardRestartOpenTimer'\";\n\t\t\t\t\t\t\t\t\t\tif ($result3 = $csdb->sql_query($sql))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tif ($csdb->sql_numrows($result3))\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$timer_row = $csdb->sql_fetchrow($result3);\n\t\t\t\t\t\t\t\t\t\t\t\tif ($timer_row['config_value'] < $local_timer)\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t$local_timer = $timer_row['config_value'];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$open_timer = $local_timer;\n\t\t\t\t\t\t\t\t\t// END NOTE: live but not in CVS yet !\n\n\t\t\t\t\t\t\t\t\t// ok now we the list of servers that want this event, lets give it to them\n\n\t\t\t\t\t\t\t\t\t// lets build some messages\n\t\t\t\t\t\t\t\t\t$klients_countdown = '';\n\t\t\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($sequence_info['restart_sequence_timer'] - $sequence_info['restart_sequence_date_end'], $klients_countdown);\n\t\t\t\t\t\t\t\t\t$klients_countdown = trim($klients_countdown);\n\n\t\t\t\t\t\t\t\t\t$klients_open_countdown = '';\n\t\t\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($open_timer, $klients_open_countdown);\n\t\t\t\t\t\t\t\t\t$klients_open_countdown = trim($klients_open_countdown);\n\n\t\t\t\t\t\t\t\t\t$opening_message = tool_admin_restart_messages_get_list_from_name('opening',$shard_lang);\n\t\t\t\t\t\t\t\t\t$opening_message = $opening_message[0]['restart_message_value'];\n\n\t\t\t\t\t\t\t\t\t$opened_message = tool_admin_restart_messages_get_list_from_name('opened',$shard_lang);\n\t\t\t\t\t\t\t\t\t$opened_message = $opening_message[0]['restart_message_value'];\n\n\t\t\t\t\t\t\t\t\t$klients_messages = array(\t'before' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance in progress for '\". $ticketsystem_shard_info['shard_name'] .\"' - Shard LOCKED - (\". date(\"r\",$sequence_info['restart_sequence_date_start']) .\" - Countdown set to \". $klients_countdown .\")\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] A Shard Restart has been triggered for shard '\". $ticketsystem_shard_info['shard_name'] .\"' on \". date(\"r\",$sequence_info['restart_sequence_date_start']),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] Shard is LOCKED and should go down in \". $klients_countdown,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'at' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance in progress for '\". $ticketsystem_shard_info['shard_name'] .\"' - Shard DOWN - (\". date(\"r\",$sequence_info['restart_sequence_date_start']) .\")\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] A Shard Restart has been triggered for shard '\". $ticketsystem_shard_info['shard_name'] .\"' on \". date(\"r\",$sequence_info['restart_sequence_date_start']),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] Shard is DOWN after a countdown of \". $klients_countdown,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'over' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance in finished for '\". $ticketsystem_shard_info['shard_name'] .\"' - Shard LOCKED - Ready for CSRs ! ETA : |EventETA| - To Open : .sorOpenShard |EventID| 0\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] The Shard Restart that has been triggered for shard '\". $ticketsystem_shard_info['shard_name'] .\"' on \". date(\"r\",$sequence_info['restart_sequence_date_start']) .\" is now finished !\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] Shard is LOCKED and Ready for CSRs, it will OPEN automatically in |EventTIME| !\",/*. $klients_open_countdown .\" !\",*/\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] To change the OPEN countdown,  you need to send me the command : .sorOpenShard |EventID| <seconds>\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] Example to OPEN the Shard now, you need to send me the command : .sorOpenShard |EventID| 0\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'open' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance over for '\". $ticketsystem_shard_info['shard_name'] .\"' - Shard OPEN \",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] The shard '\". $ticketsystem_shard_info['shard_name'] .\"' should now be OPEN to all !\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'cancel' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance has been cancelled for '\". $ticketsystem_shard_info['shard_name'] .\"' - Shard OPEN\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] The shard restart has been CANCELLED for '\". $ticketsystem_shard_info['shard_name'] .\"', the shard is OPEN again !\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'giveup' => array(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\".topic Shard Maintenance for '\". $ticketsystem_shard_info['shard_name'] .\"' is on hold for technical issues - Shard DOWN\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\"[Shard Maintenance] The shard restart has been set ON HOLD for technical issues !\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'opening' => $opening_message,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'opened' => $opened_message,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t$notification_info = array(\t'sequence'\t=> $sequence_info,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'ts'\t\t=> $ticketsystem_shard_info,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'messages'\t=> $klients_messages,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'shard'\t\t=> $shard_info,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'opentimer'\t=> $open_timer,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'shardid'\t=> $shard_id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'shardsu'\t=> $service_su,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'shardegs'\t=> $service_egs,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t$notification_data = base64_encode(serialize($notification_info));\n\n\t\t\t\t\t\t\t\t\t$event_insert_ids = array();\n\n\t\t\t\t\t\t\t\t\t$sql = \"LOCK TABLES Sorbot_events WRITE\";\n\t\t\t\t\t\t\t\t\t$csdb->sql_query($sql);\n\n\t\t\t\t\t\t\t\t\treset($klients_servers);\n\t\t\t\t\t\t\t\t\tforeach($klients_servers as $klient_server)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$sql  = \"INSERT INTO Sorbot_events (`server_name`,`event_action`,`event_time`,`event_lap`,`event_params`) \";\n\t\t\t\t\t\t\t\t\t\t$sql .= \" VALUES ('\". $klient_server .\"',\". $sorbot_message_type .\",\". time() .\",\". $open_timer .\",'\". $notification_data .\"')\";\n\t\t\t\t\t\t\t\t\t\t$csdb->sql_query($sql);\n\t\t\t\t\t\t\t\t\t\t$event_insert_ids[] = $csdb->sql_nextid();\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// we have a list of all the events, lets save them somewhere\n\t\t\t\t\t\t\t\t\t// lets inform each events of all other events for the same sequence\n\t\t\t\t\t\t\t\t\tif (sizeof($event_insert_ids))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$notification_info['eventlist'] = array_values($event_insert_ids);\n\t\t\t\t\t\t\t\t\t\t$notification_data = base64_encode(serialize($notification_info));\n\n\t\t\t\t\t\t\t\t\t\t$sql = \"UPDATE Sorbot_events SET event_params='\". $notification_data .\"' WHERE event_id IN (\". implode(',', array_values($event_insert_ids)) .\")\";\n\t\t\t\t\t\t\t\t\t\t$csdb->sql_query($sql);\n\n\t\t\t\t\t\t\t\t\t\t// save the events locally too\n\t\t\t\t\t\t\t\t\t\ttool_main_set_restart_sequence_events($sequence_id, implode(',',array_values($event_insert_ids)));\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$sql = \"UNLOCK TABLES\";\n\t\t\t\t\t\t\t\t\t$csdb->sql_query($sql);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('no klients server found wanting to hear about this event');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnt_common_add_debug('no shard found in TS matching the application and shard id');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnt_common_add_debug('query failed ?!');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug('missing some information about the sequence ?!');\n\t\t\t\t}\n\n\t\t\t\t$csdb->sql_close();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tnt_common_add_debug('failed to init db!');\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tnt_common_add_debug('no db string to work with');\n\t\t}\n\t}\n\n\tfunction tool_main_set_restart_sequence_events($sequence_id, $events)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"UPDATE \". NELDB_RESTART_SEQUENCE_TABLE .\" SET restart_sequence_events='\". $events .\"' WHERE restart_sequence_id=\". $sequence_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_main_get_domain_shard_data($domain_id, $shard_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\t$sql  = \"SELECT \". NELDB_DOMAIN_TABLE .\".domain_id,\";\n\t\t$sql .=            NELDB_DOMAIN_TABLE .\".domain_name,\";\n\t\t$sql .=            NELDB_DOMAIN_TABLE .\".domain_as_host,\";\n\t\t$sql .=            NELDB_DOMAIN_TABLE .\".domain_as_port,\";\n\t\t$sql .=            NELDB_DOMAIN_TABLE .\".domain_application,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_id,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_name,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_as_id,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_domain_id,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_lang,\";\n\t\t$sql .=            NELDB_SHARD_TABLE .\".shard_restart\";\n\t\t$sql .= \" FROM \". NELDB_DOMAIN_TABLE .\",\". NELDB_SHARD_TABLE;\n\t\t$sql .= \" WHERE domain_id=shard_domain_id AND domain_id=\". $domain_id .\" AND shard_id=\". $shard_id;\n\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_main_set_restart_sequence_user($AS_ShardRestart)\n\t{\n\t\tglobal $db;\n\t\tglobal $AS_Name, $AS_ShardName;\n\t\tglobal $nel_user;\n\t\tglobal $restart_notification_emails;\n\n\t\t$sequence_info\t= tool_main_get_restart_sequence_by_id($AS_ShardRestart);\n\n\t\tif ($sequence_info)\n\t\t{\n\t\t\t$sql = \"UPDATE \". NELDB_RESTART_SEQUENCE_TABLE .\" SET restart_sequence_user_name='\". $nel_user['user_name'] .\"' WHERE restart_sequence_id=\". $AS_ShardRestart;\n\t\t\t$db->sql_query($sql);\n\n\t\t\tnt_log(\"Shard Restart (Domain: '\". $AS_Name .\"' - Shard: '\". $AS_ShardName .\"' - Sequence: '\". $AS_ShardRestart .\"') owner set to '\". $nel_user['user_name'] .\"'\");\n\n\t\t\t$email_subject\t= \"[Shard Admin Tool] Restart Sequence Takeover (id: \".$sequence_info['restart_sequence_id'].\", step: \". $sequence_info['restart_sequence_step'] .\") for shard \".$AS_Name.\"/\".$AS_ShardName.\" by \".$nel_user['user_name'];\n\t\t\t$email_message\t= $email_subject;\n\t\t\tnt_email($email_subject,$email_message,$restart_notification_emails);\n\t\t}\n\t}\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/functions_tool_mfs.php",
    "content": "<?php\n\n\tfunction tool_mfs_HTTPOpen($url)\n\t{\n\t\t$ch = curl_init();\n\n\t\t$url = \"http://su1:50000/admin.php\";\n\n\t\t$uri_params  = 'user_login=support';\n\t\t$uri_params .= '&shard=103';\n\t\t$uri_params .= '&forum=Atrium Keepers';\n\n\t\tcurl_setopt($ch, CURLOPT_URL, $url);\n\t\tcurl_setopt($ch, CURLOPT_POST, 1);\n\t\tcurl_setopt($ch, CURLOPT_POSTFIELDS, $uri_params);\n\t\tcurl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 0 = debug , 1 = normal\n\t\tcurl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // 0 = debug , 1 = normal\n\t\tcurl_setopt($ch, CURLOPT_NOPROGRESS, 0);\n\t\tcurl_setopt($ch, CURLOPT_USERAGENT, \"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\");\n\t\tcurl_setopt($ch, CURLOPT_HEADER, 1); // has to be 1 due to using redirections\n\t\tcurl_setopt($ch, CURLOPT_TIMEOUT, 120);\n\n\t\tob_start();\n\t\t$curlOutput\t= curl_exec ($ch);\n\t\tob_end_clean();\n\n\t\t$curlError\t= curl_errno($ch);\n\t\tif ($curlError != 0)\n\t\t{\n\t\t\t$outp\t\t= \"CURL Error [ $curlError ] : \". curl_error($ch);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$curlData \t= tool_mfs_HTTPParseResponse($curlOutput);\n\t\t\t$outp\t\t= $curlData[2];\n\t\t}\n\n\t\tcurl_close ($ch);\n\n\t\treturn $outp;\n\t}\n\n\n\tfunction tool_mfs_HTTPParseResponse($response)\n\t{\n\t\t/*\n\t\treturns an array in the following format which varies depending on headers returned\n\n\t\t[0] => the HTTP error or response code such as 404\n\t\t[1] => Array\n\t\t(\n\t\t[Date] => Wed, 28 Apr 2004 23:29:20 GMT\n\t\t[Set-Cookie] => COOKIESTUFF\n\t\t[Expires] => Thu, 01 Dec 1994 16:00:00 GMT\n\t\t[Content-Type] => text/html\n\t\t)\n\t\t[2] => Response body (string)\n\t\t*/\n\n\t\tdo\n\t\t{\n\t\t\tlist($response_headers,$response) = explode(\"\\r\\n\\r\\n\",$response,2);\n\t\t\t$response_header_lines = explode(\"\\r\\n\",$response_headers);\n\n\t\t\t// first line of headers is the HTTP response code\n\t\t\t$http_response_line = array_shift($response_header_lines);\n\t\t\tif (preg_match('@^HTTP/[0-9]\\.[0-9] ([0-9]{3})@',$http_response_line, $matches))\n\t\t\t{\n\t\t\t\t$response_code = $matches[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$response_code = \"Error\";\n\t\t\t}\n\t\t}\n\t\twhile ((substr($response_code, 0,1) == \"1\") || (substr($response_code, 0,1) == \"3\"));\n\n\t\t$response_body = $response;\n\n\t\t// put the rest of the headers in an array\n\t\t$response_header_array = array();\n\t\tforeach ($response_header_lines as $header_line)\n\t\t{\n\t\t\tlist($header,$value) = explode(': ',$header_line,2);\n\t\t\t$response_header_array[$header] = $value;\n\t\t}\n\n\t\treturn array($response_code,$response_header_array,$response_body);\n\t}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_notes.php",
    "content": "<?php\n\n\tfunction js_html_entity_decode($string)\n\t{\n\t   // replace numeric entities\n\t   $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec(\"\\\\1\"))', $string);\n\t   $string = preg_replace('~&#([0-9]+);~e', 'chr(\\\\1)', $string);\n\t   // replace literal entities\n\t   $trans_tbl = get_html_translation_table(HTML_ENTITIES);\n\t   $trans_tbl = array_flip($trans_tbl);\n\t   return strtr($string, $trans_tbl);\n\t}\n\n\tfunction tool_notes_get_list($user_id, $active=null)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\tif ($active === null)\t// edit note list\n\t\t\t$sql = \"SELECT * FROM \". NELDB_NOTE_TABLE .\" WHERE note_user_id=\". $user_id .\" ORDER BY note_active DESC, note_date DESC\";\n\t\telse\t\t\t\t\t// view note list\n\t\t\t$sql = \"SELECT * FROM \". NELDB_NOTE_TABLE .\" WHERE (note_user_id=\". $user_id .\" OR note_global=1) AND note_active='\". $active .\"' ORDER BY note_global DESC, note_title ASC\";\n\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\twhile ($row = $db->sql_fetchrow($result))\n\t\t\t\t{\n\t\t\t\t\tif ($active)\n\t\t\t\t\t{\n\t\t\t\t\t\t$row['note_data'] = addslashes(htmlentities(html_entity_decode(str_replace(\"\\r\\n\",\"<br>\",$row['note_data']), ENT_QUOTES), ENT_COMPAT));\n\t\t\t\t\t\t$row['note_title2'] = addslashes(htmlentities(html_entity_decode($row['note_title'], ENT_QUOTES), ENT_COMPAT));\n\t\t\t\t\t}\n\t\t\t\t\t$data[] = $row;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_notes_add($user_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction)\n\t{\n\t\tglobal $db;\n\n\t\t$note_title\t= trim(stripslashes($note_title));\n\t\t$note_data\t= trim(stripslashes($note_data));\n\n\t\tif ($note_title == '')\treturn \"/!\\ Error: note title is empty!\";\n\t\t//if ($note_data == '')\treturn \"/!\\ Error: note data is empty!\";\n\n\t\tif ($note_mode == 'text')\t$note_mode = 0;\n\t\telse\t\t\t\t\t\t$note_mode = 1;\n\n\t\t$sql  = \"INSERT INTO \". NELDB_NOTE_TABLE .\" (`note_user_id`,`note_title`,`note_data`,`note_date`,`note_active`,`note_global`,`note_mode`,`note_popup_uri`,`note_popup_restriction`) VALUES \";\n\t\t$sql .= \" ('\". $user_id .\"','\". htmlentities($note_title, ENT_QUOTES) .\"','\". htmlentities($note_data, ENT_QUOTES) .\"','\". time() .\"',\". $note_active .\",\". $note_global .\",\". $note_mode .\",'\". $note_uri .\"','\". $note_restriction .\"')\";\n\n\t\t$db->sql_query($sql);\n\n\t\treturn \"\";\n\t}\n\n\tfunction tool_notes_get_id($user_id, $note_id)\n\t{\n\t\tglobal $db;\n\n\t\t$data = array();\n\n\t\t$sql = \"SELECT * FROM \". NELDB_NOTE_TABLE .\" WHERE note_id=\". $note_id .\" AND note_user_id=\". $user_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n\t\t\t\t$data = $db->sql_fetchrow($result);\n\t\t\t\t$data['note_title'] = $data['note_title'];\n\t\t\t\t$data['note_data'] = $data['note_data'];\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_notes_del($user_id, $note_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"DELETE FROM \". NELDB_NOTE_TABLE .\" WHERE note_id=\". $note_id .\" AND note_user_id=\". $user_id;\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_notes_update($user_id, $note_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction)\n\t{\n\t\tglobal $db;\n\n\t\tif ($note_mode == 'text')\t$note_mode = 0;\n\t\telse\t\t\t\t\t\t$note_mode = 1;\n\n\t\t$sql = \"SELECT * FROM \". NELDB_NOTE_TABLE .\" WHERE note_id=\". $note_id .\" AND note_user_id=\". $user_id;\n\t\tif ($result = $db->sql_query($sql))\n\t\t{\n\t\t\tif ($db->sql_numrows($result))\n\t\t\t{\n//\t\t\t\t$sql = \"UPDATE \". NELDB_NOTE_TABLE .\" SET note_title='\". htmlentities($note_title, ENT_QUOTES) .\"',note_data='\". htmlentities($note_data, ENT_QUOTES) .\"',note_date='\". time() .\"',note_active='\". $note_active .\"',note_global='\". $note_global .\"',note_mode=\". $note_mode .\",note_popup_uri='\". $note_uri .\"',note_popup_restriction='\". $note_restriction .\"'  WHERE note_id=\". $note_id;\n\t\t\t\t$sql = \"UPDATE \". NELDB_NOTE_TABLE .\" SET note_title='\". htmlentities($note_title, ENT_QUOTES) .\"',note_data='\". htmlentities($note_data, ENT_QUOTES) .\"',note_date='\". time() .\"',note_active='\". $note_active .\"',note_global='\". $note_global .\"'  WHERE note_id=\". $note_id;\n\t\t\t\t$db->sql_query($sql);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\treturn \"/!\\ Error: no such note for this user!\";\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_player_locator.php",
    "content": "<?php\n\n\tfunction tool_pl_parse_relocate($data)\n\t{\n\t\t$entity_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $su_data)\n\t\t{\n\t\t\t$service_name = 'n/a';\n\n\t\t\treset($su_data);\n\t\t\tforeach($su_data as $su_line)\n\t\t\t{\n\t\t\t\t$su_line = trim($su_line);\n\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $su_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^The character ([^\\ ]+) of user ([^\\ ]+) has been relocated on shard ([^\\ ]+)$\", $su_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'uid'\t\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'charid'\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'shardid'\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'success'\t\t=>\t1,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Can't reloc character because user ([^\\ ]+) owner of char ([^\\ ]+) is online$\", $su_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'uid'\t\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'charid'\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'shardid'\t\t=>\t'na',\n\t\t\t\t\t\t\t\t\t\t\t'success'\t\t=>\t0,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\treturn $entity_data;\n\t}\n\n\tfunction tool_pl_parse_locate($data)\n\t{\n\t\t$entity_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $egs_data)\n\t\t{\n\t\t\t$service_name = 'n/a';\n\n\t\t\treset($egs_data);\n\t\t\tforeach($egs_data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^UId ([^\\ ]+) UserName '([^\\ ]*)' EId ([^\\ ]+) EntityName '([^\\ ]*)' EntitySlot ([^\\ ]+) SaveFile ([^\\ ]+) ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'uid'\t\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'user_name'\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'eid'\t\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'entity_name'\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'entity_slot'\t=>\t$eregs[5],\n\t\t\t\t\t\t\t\t\t\t\t'save_file'\t\t=>\t$eregs[6],\n\t\t\t\t\t\t\t\t\t\t\t'status'\t\t=>\t$eregs[7],\n\t\t\t\t\t\t\t\t\t\t\t'posx'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'posy'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'posz'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'session'\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^UId ([^\\ ]+) UserName '([^\\ ]*)' EId ([^\\ ]+) EntityName '([^\\ ]*)' EntitySlot ([^\\ ]+) SaveFile ([^\\ ]+) Pos: ([^,\\ ]+),([^,\\ ]+),([^,\\ ]+) Session: ([^\\ ]+) ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'uid'\t\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'user_name'\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'eid'\t\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'entity_name'\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'entity_slot'\t=>\t$eregs[5],\n\t\t\t\t\t\t\t\t\t\t\t'save_file'\t\t=>\t$eregs[6],\n\t\t\t\t\t\t\t\t\t\t\t'status'\t\t=>\t$eregs[11],\n\t\t\t\t\t\t\t\t\t\t\t'posx'\t\t\t=>\t$eregs[7],\n\t\t\t\t\t\t\t\t\t\t\t'posy'\t\t\t=>\t$eregs[8],\n\t\t\t\t\t\t\t\t\t\t\t'posz'\t\t\t=>\t$eregs[9],\n\t\t\t\t\t\t\t\t\t\t\t'session'\t\t=>\t$eregs[10],\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $entity_data;\n\t}\n\n\tfunction tool_pl_parse_display_players($data)\n\t{\n\t\t$entity_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $egs_data)\n\t\t{\n\t\t\t$service_name = 'n/a';\n\n\t\t\treset($egs_data);\n\t\t\tforeach($egs_data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Player: ([^\\ ]+) Name: ([^\\ ]+) ID: ([^\\ ]+) FE: ([^\\ ]+) Sheet: ([^\\ ]+) - ([^\\ ]+) Priv: '([^\\ ]*)'$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'player'\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'name'\t\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'id'\t\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'fe'\t\t\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'sheet'\t\t\t=>\t$eregs[5] .' - '. $eregs[6],\n\t\t\t\t\t\t\t\t\t\t\t'priv'\t\t\t=>\t$eregs[7],\n\t\t\t\t\t\t\t\t\t\t\t'posx'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'posy'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'posz'\t\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t'session'\t\t=>\t'n/a',\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^Player: ([^\\ ]+) Name: ([^\\ ]+) ID: ([^\\ ]+) FE: ([^\\ ]+) Sheet: ([^\\ ]+) - ([^\\ ]+) Priv: '([^\\ ]*)' Pos: ([^,\\ ]+),([^,\\ ]+),([^,\\ ]+) Session: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'player'\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'name'\t\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'id'\t\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'fe'\t\t\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'sheet'\t\t\t=>\t$eregs[5] .' - '. $eregs[6],\n\t\t\t\t\t\t\t\t\t\t\t'priv'\t\t\t=>\t$eregs[7],\n\t\t\t\t\t\t\t\t\t\t\t'posx'\t\t\t=>\t$eregs[8],\n\t\t\t\t\t\t\t\t\t\t\t'posy'\t\t\t=>\t$eregs[9],\n\t\t\t\t\t\t\t\t\t\t\t'posz'\t\t\t=>\t$eregs[10],\n\t\t\t\t\t\t\t\t\t\t\t'session'\t\t=>\t$eregs[11],\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $entity_data;\n\t}\n\n\tfunction tool_pl_get_character_check_list($AS_Application, $AS_RingSQL)\n\t{\n\t\tglobal $db;\n\n\t\t$data = null;\n\n\t\tif ($AS_RingSQL == '')\n\t\t{\n\t\t\tif ($db->sql_select_db('nel'))\n\t\t\t{\n\t\t\t\t$sql = \"SELECT ring_db_name FROM domain WHERE domain_name='\". $AS_Application .\"'\";\n\t\t\t\tif ($resutl = $db->sql_query($sql))\n\t\t\t\t{\n\t\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t\t{\n\t\t\t\t\t\t$domain_row = $db->sql_fetchrow($result);\n\n\t\t\t\t\t\tif ($db->sql_select_db($domain_row['ring_db_name']))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$sql = \"SELECT * FROM characters WHERE user_id=0\";\n\t\t\t\t\t\t\tif ($result2 = $db->sql_query($sql))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ($db->sql_numrows($result2))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$data = $db->sql_fetchrowset($result2);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$db->sql_reselect_db();\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$db2 = new sql_db_string($AS_RingSQL);\n\t\t\tif (is_object($db2))\n\t\t\t{\n\t\t\t\t$sql = \"SELECT * FROM characters WHERE user_id=0\";\n\t\t\t\tif ($result2 = $db2->sql_query($sql))\n\t\t\t\t{\n\t\t\t\t\tif ($db2->sql_numrows($result2))\n\t\t\t\t\t{\n\t\t\t\t\t\t$data = $db2->sql_fetchrowset($result2);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $data;\n\t}\n\n\tfunction tool_pl_fix_character_check_list($AS_Application)\n\t{\n\t\tglobal $db;\n\n\t\tif ($db->sql_select_db('nel'))\n\t\t{\n\t\t\t$sql = \"SELECT ring_db_name FROM domain WHERE domain_name='\". $AS_Application .\"'\";\n\t\t\tif ($resutl = $db->sql_query($sql))\n\t\t\t{\n\t\t\t\tif ($db->sql_numrows($result))\n\t\t\t\t{\n\t\t\t\t\t$domain_row = $db->sql_fetchrow($result);\n\n\t\t\t\t\tif ($db->sql_select_db($domain_row['ring_db_name']))\n\t\t\t\t\t{\n\t\t\t\t\t\t$sql = \"UPDATE characters SET user_id=FLOOR(char_id/16) WHERE user_id=0\";\n\t\t\t\t\t\t$db->sql_query($sql);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$db->sql_reselect_db();\n\t\t}\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_preferences.php",
    "content": "<?php\n\n\t/*\n\t * checks whether a password matches a users password\n\t */\n\tfunction tool_pref_check_old_password($userinfo, $password)\n\t{\n\t\tif (!is_array($userinfo) && !isset($userinfo['user_id'])) return false;\n\n\t\t$encoded_password = md5($password);\n\t\tif ($encoded_password == $userinfo['user_password']) return true;\n\n\t\treturn false;\n\t}\n\n\t/*\n\t * update a user's password\n\t */\n\tfunction tool_pref_update_user_password($userinfo, $password)\n\t{\n\t\tglobal $db;\n\n\t\tif (!is_array($userinfo) && !isset($userinfo['user_id'])) \treturn false;\n\t\tif ($password == '')\t\t\t\t\t\t\t\t\t\treturn false;\n\n\t\t$encoded_password = md5(trim($password));\n\n\t\t$sql = \"UPDATE \". NELDB_USER_TABLE .\" SET user_password='\". $encoded_password .\"' WHERE user_id=\". $userinfo['user_id'];\n\t\t$db->sql_query($sql);\n\n\t\treturn true;\n\t}\n\n\tfunction tool_pref_update_menu_style($userinfo, $menu)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"UPDATE \". NELDB_USER_TABLE .\" SET user_menu_style=\". $menu .\" WHERE user_id=\". $userinfo['user_id'];\n\t\t$db->sql_query($sql);\n\t}\n\n\tfunction tool_pref_update_default_application($userinfo, $application_id)\n\t{\n\t\tglobal $db;\n\n\t\t$sql = \"UPDATE \". NELDB_USER_TABLE .\" SET user_default_application_id=\". $application_id .\" WHERE user_id=\". $userinfo['user_id'];\n\t\t$db->sql_query($sql);\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/functions_tool_shop.php",
    "content": "<?php\n\n\tfunction tool_shop_get_check_items()\n\t{\n\t\tglobal $NELTOOL;\n\t\t$check_items = \"\";\n\n\t\treset($NELTOOL['POST_VARS']);\n\t\tforeach($NELTOOL['POST_VARS'] as $post_key => $post_val)\n\t\t{\n\t\t\t$val = 'checkshoplist_'. $post_val;\n\t\t\tif ($post_key == $val)\n\t\t\t{\n\t\t\t\t$check_items = $check_items .\"`\". $post_val;\n\t\t\t}\n\t\t}\n\n\t\treturn $check_items;\n\t}\n\t\n\tfunction tool_sp_parse_shop_list($data)\n\t{\n\t\t$entity_data = array();\n\n\t\treset($data);\n\t\tforeach($data as $egs_data)\n\t\t{\n\t\t\t$service_name = 'n/a';\n\n\t\t\treset($egs_data);\n\t\t\tforeach($egs_data as $egs_line)\n\t\t\t{\n\t\t\t\t$egs_line = trim($egs_line);\n\t\t\t\tif (ereg(\"^===\\[ Service ([^\\ ]+) returned \\]===$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$service_name = $eregs[1];\n\t\t\t\t}\n\t\t\t\telseif (ereg(\"^SID: ([^\\ ]+) IDX: ([^\\ ]+) TID: ([^\\ ]+) Name: ([^\\ ]+) NUM: ([^\\ ]+) PRICE: ([^\\ ]+)$\", $egs_line, $eregs))\n\t\t\t\t{\n\t\t\t\t\t$entity_data[] = array(\t'service'\t\t=>\t$service_name,\n\t\t\t\t\t\t\t\t\t\t\t'shardid'\t\t=>\t$eregs[1],\n\t\t\t\t\t\t\t\t\t\t\t'idx'\t\t\t=>\t$eregs[2],\n\t\t\t\t\t\t\t\t\t\t\t'tid'\t\t\t=>\t$eregs[3],\n\t\t\t\t\t\t\t\t\t\t\t'name'\t\t\t=>\t$eregs[4],\n\t\t\t\t\t\t\t\t\t\t\t'num'\t\t\t=>\t$eregs[5],\n\t\t\t\t\t\t\t\t\t\t\t'price'\t\t\t=>\t$eregs[6],\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $entity_data;\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/graphs_output/placeholder",
    "content": ""
  },
  {
    "path": "tools/server/admin/index.php",
    "content": "<?php\n\n// Enw4k.XHXuULw\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_notes.php');\n\n\tnt_common_add_debug('-- Starting on \\'index.php\\'');\n\n\t$tpl->assign('tool_title', \"Main\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($_GET['domain']))\n\t{\n\t\tif ($view_domain_id != $_GET['domain'])\n\t\t{\n\t\t\t$view_domain_id = $_GET['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($_GET['shard']))\n\t{\n\t\t$view_shard_id = $_GET['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (!tool_main_check_user_domain($view_domain_id))\t$view_domain_id = null;\n\tif (!tool_main_check_user_shard($view_shard_id))\t$view_shard_id\t= null;\n\n\t$current_refresh_rate = nt_auth_get_session_var('current_refresh_rate');\n\n\tif (isset($_POST['services_refresh']))\n\t{\n\t\tif ($current_refresh_rate != $_POST['services_refresh'])\n\t\t{\n\t\t\t$current_refresh_rate = $_POST['services_refresh'];\n\t\t\tnt_auth_set_session_var('current_refresh_rate',$current_refresh_rate);\n\t\t}\n\t}\n\n\tif ($current_refresh_rate == null)\n\t{\n\t\t$current_refresh_rate = 0;\n\t}\n\telseif ($current_refresh_rate > 0)\n\t{\n\t\t$tpl->assign('nel_tool_refresh',\t'<meta http-equiv=refresh content=\"'. $current_refresh_rate .'\">');\n\t}\n\n\t$tpl->assign('tool_refresh_list',\t\t$refresh_rates);\n\t$tpl->assign('tool_refresh_rate',\t\t$current_refresh_rate);\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\t$AS_Host \t\t\t\t= tool_main_get_domain_host($view_domain_id);\n\t$AS_Port \t\t\t\t= tool_main_get_domain_port($view_domain_id);\n\t$AS_Name \t\t\t\t= tool_main_get_domain_name($view_domain_id);\n\t$AS_Application\t\t\t= tool_main_get_domain_data($view_domain_id, 'domain_application');\n\t$AS_RingSQL\t\t\t\t= tool_main_get_domain_data($view_domain_id, 'domain_sql_string');\n\t$AS_CsSQL\t\t\t\t= tool_main_get_domain_data($view_domain_id, 'domain_cs_sql_string');\n\t$AS_ShardName\t\t\t= tool_main_get_shard_name($view_shard_id);\n\t$AS_InternalName\t\t= tool_main_get_shard_as_id($view_shard_id);\n\t$AS_ShardRestart\t\t= tool_main_get_shard_data($view_shard_id, 'shard_restart');\n\t$AS_ShardDomainRestart\t= tool_main_get_domain_shard_restart($view_domain_id);\n\t$AS_ShardLang\t\t\t= tool_main_get_shard_data($view_shard_id, 'shard_lang');\n\n\t$tpl->assign('tool_shard_restart_status',\t\t$AS_ShardRestart);\n\t$tpl->assign('tool_domain_has_shard_restart',\t$AS_ShardDomainRestart);\n\n\t$tool_no_domain_lock = false;\n\tif (($AS_InternalName == '*') && ($AS_ShardDomainRestart > 0))\n\t{\n\t\t$tool_no_domain_lock = true;\n\t\t$tpl->assign('tool_no_domain_lock', $tool_no_domain_lock);\n\t}\n\n\t$tpl->assign('tool_page_title', $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t$tool_annotation_info\t= tool_main_get_annotation($view_domain_id, $view_shard_id);\n\t$tool_lock_info\t\t\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\n\t// we check if the last activity on the lock is too old, in which case we unlock\n\t// and only if there are no restart sequence going on (prevent loosing lock when inactive for too long during restart sequence - patch ...)\n\tif ((LOCK_TIMEOUT > 0) && is_array($tool_lock_info) && ($AS_ShardRestart == 0) && !$tool_no_domain_lock)\n\t{\n\t\t$now = time();\n\t\tif ($tool_lock_info['lock_update'] + LOCK_TIMEOUT < $now)\n\t\t{\n\t\t\tif ($tool_lock_info['lock_domain_id'])\ttool_main_delete_lock_domain($view_domain_id);\n\t\t\tif ($tool_lock_info['lock_shard_id'])\ttool_main_delete_lock_shard($view_shard_id);\n\n\t\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\t\t}\n\t}\n\n\t// we update the lock data for the last activity time\n\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'])\n\t{\n\t\tif ($tool_lock_info['lock_domain_id'])\ttool_main_set_lock_domain($view_domain_id, false);\n\t\tif ($tool_lock_info['lock_shard_id'])\ttool_main_set_lock_shard($view_domain_id, $view_shard_id, false);\n\n\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\t}\n\n\tif (tool_admin_applications_check('tool_main_lock_shard') || tool_admin_applications_check('tool_main_lock_domain'))\n\t{\n\t\tif (isset($NELTOOL['POST_VARS']['lock']))\n\t\t{\n\t\t\t$tool_lock_mode = $NELTOOL['POST_VARS']['lock'];\n\t\t\tswitch ($tool_lock_mode)\n\t\t\t{\n\t\t\t\tcase 'lock shard':\n\n\t\t\t\t\tif (tool_admin_applications_check('tool_main_lock_shard'))\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_main_set_lock_shard($view_domain_id, $view_shard_id);\n\t\t\t\t\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\n\t\t\t\t\t\tif ($AS_ShardRestart > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttool_main_set_restart_sequence_user($AS_ShardRestart);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'lock domain':\n\n\t\t\t\t\tif (tool_admin_applications_check('tool_main_lock_domain'))\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_main_set_lock_domain($view_domain_id);\n\t\t\t\t\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'unlock shard':\n\n\t\t\t\t\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'])\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_main_delete_lock_shard($view_shard_id);\n\t\t\t\t\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'unlock domain':\n\n\t\t\t\t\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'])\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_main_delete_lock_domain($view_domain_id);\n\t\t\t\t\t\t$tool_lock_info\t= tool_main_get_lock($view_domain_id, $view_shard_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'update annotation':\n\n\t\t\t\t\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_annotation\t= $NELTOOL['POST_VARS']['annotation'];\n\t\t\t\t\t\ttool_main_set_annotation($view_domain_id, $view_shard_id, $tool_annotation);\n\t\t\t\t\t\t$tool_annotation_info = tool_main_get_annotation($view_domain_id, $view_shard_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'restart sequence':\n\n\t\t\t\t\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'] && tool_admin_applications_check('tool_main_easy_restart'))\n\t\t\t\t\t{\n\t\t\t\t\t\t$restart_ws_state  = $NELTOOL['POST_VARS']['restart_ws_state'];\n\n\t\t\t\t\t\t$restart_first_step = 0;\n\n\t\t\t\t\t\t// if restart_ws_state == '' means that i didn't find a shard_id\n\t\t\t\t\t\t// which means the shard has been shutdown completely including AES and RAS\n\t\t\t\t\t\tif ($restart_ws_state == 'close' || $restart_ws_state == '') $restart_first_step = 3;\n\n\t\t\t\t\t\t$tool_restart_info = tool_main_set_restart_mode($view_domain_id, $view_shard_id, $restart_first_step);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (is_array($tool_lock_info) && $tool_lock_info['lock_user_name'] == $nel_user['user_name'])\n\t\t{\n\t\t\tif (tool_admin_applications_check('tool_main_start'))\t\t\t\t$tpl->assign('restriction_tool_main_start',\t\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_stop'))        \t\t$tpl->assign('restriction_tool_main_stop',\t\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_restart'))     \t\t$tpl->assign('restriction_tool_main_restart',\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_kill'))        \t\t$tpl->assign('restriction_tool_main_kill',\t\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_abort'))       \t\t$tpl->assign('restriction_tool_main_abort',\t\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_execute'))     \t\t$tpl->assign('restriction_tool_main_execute',\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_ws'))     \t\t\t\t$tpl->assign('restriction_tool_main_ws',\t\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_ws_old'))     \t\t\t$tpl->assign('restriction_tool_main_ws_old',\t\t\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_reset_counters'))  \t$tpl->assign('restriction_tool_main_reset_counters',\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_service_autostart'))\t$tpl->assign('restriction_tool_main_service_autostart',\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_shard_autostart'))\t\t$tpl->assign('restriction_tool_main_shard_autostart',\ttrue);\n\t\t\tif (tool_admin_applications_check('tool_main_easy_restart'))\t\t$tpl->assign('restriction_tool_main_easy_restart',\t\ttrue);\n\n\t\t\t$nel_user['has_lock'] = true;\n\t\t\tif ($tool_lock_info['lock_shard_id'] > 0)\t\t$tpl->assign('tool_has_shard_lock',\t\ttrue);\n\t\t\telseif ($tool_lock_info['lock_domain_id'] > 0)\t$tpl->assign('tool_has_domain_lock',\ttrue);\n\n\t\t\tif ($AS_ShardRestart > 0)\n\t\t\t{\n\t\t\t\t// define the shards language\n\t\t\t\t$tpl->assign('tool_shard_language',\t\t\t$AS_ShardLang);\n\t\t\t\t$tpl->assign('tool_language_list',\t\t\t$tool_language_list);\n\n\t\t\t\t$tool_restart_message_reboot_list = tool_admin_restart_messages_get_list_from_name('reboot');\n\t\t\t\t$tpl->assign('tool_restart_message_reboot_list', \t$tool_restart_message_reboot_list);\n\n\t\t\t\t$tool_restart_stop_list = tool_admin_restarts_get_list('DESC');\n\t\t\t\t$tool_restart_start_list = tool_admin_restarts_get_list('ASC');\n\n\t\t\t\t// they are assigned at the end of the script\n\t\t\t\t//$tpl->assign('tool_restart_stop_actions',\t$tool_restart_stop_list);\n\t\t\t\t//$tpl->assign('tool_restart_start_actions',\t$tool_restart_start_list);\n\n\t\t\t\t//$tool_restart_message_ready_list = tool_admin_restart_messages_get_list_from_name('ready');\n\t\t\t\t//$tpl->assign('tool_restart_message_ready_list', \t$tool_restart_message_ready_list);\n\n\t\t\t\t//$tool_restart_message_list = tool_admin_restart_messages_get_list_from_name('open');\n\n\t\t\t\t// restart information\n\t\t\t\t$tool_restart_info = tool_main_get_restart_sequence_by_id($AS_ShardRestart);\n\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\n\t\t\t}\n\n\n\t\t\t$tpl->assign('tool_has_lock',\t\t\ttrue);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$tpl->assign('tool_no_lock',\t\t\ttrue);\n\t\t\t$tpl->assign('tool_no_annotation',\t\ttrue);\n\t\t}\n\t}\n\n\tif (tool_admin_applications_check('tool_main_lock_shard'))  $tpl->assign('restriction_tool_main_lock_shard',true);\n\tif (tool_admin_applications_check('tool_main_lock_domain')) $tpl->assign('restriction_tool_main_lock_domain',true);\n\telseif (!tool_admin_applications_check('tool_main_lock_domain')\n\t      && tool_admin_applications_check('tool_main_lock_shard')\n\t      && (tool_main_get_shard_as_id($view_shard_id) == \"*\"))\n\t{\n\t\t// you have shard lock access\n\t\t// but you don't have domain access\n\t\t// and you are viewing the * shard\n\t\t// locking the shard * will lock the domain\n\t\t// so you must not be able to lock this shard\n\t\t$tpl->assign('tool_cant_lock', true);\n\t}\n\n\t$tpl->assign('tool_lock_info',\t\t\t$tool_lock_info);\n\t$tpl->assign('tool_annotation_info',\t$tool_annotation_info);\n\n\tif (tool_admin_applications_check('tool_notes'))\n\t{\n\t\t$tool_note_list = tool_notes_get_list($nel_user['user_id'], 1);\n\n\t\tif (sizeof($tool_note_list))\n\t\t{\n\t\t\t$tpl->assign('restriction_tool_notes',\ttrue);\n\t\t\t$tpl->assign('tool_note_list',\t\t\t$tool_note_list);\n\t\t}\n\t}\n\n\n\t$tool_as_error = null;\n\n\tif ($AS_Host && $AS_Port)\n\t{\n\t\t$adminService = new MyAdminService;\n\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t{\n\t\t\tnt_common_add_debug($res);\n\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ($nel_user['has_lock'])\n\t\t\t{\n\t\t\t\t//nt_common_add_debug(\"HTTP_POST_VARS\");\n\t\t\t\t//nt_common_add_debug($HTTP_POST_VARS);\n\t\t\t\t//echo '<pre>'. print_r($HTTP_POST_VARS,true) .'</pre>';\n\t\t\t\t//die();\n\n\t\t\t\t// make sure you are the one who has its name in the restart info\n\t\t\t\t// as you can take over the lock and the restart sequence\n\t\t\t\t// we don't want more than 1 client executing the restart commands if they think they still have the lock\n\t\t\t\tif (isset($tool_restart_info) && ($tool_restart_info['restart_sequence_user_name'] == $nel_user['user_name']) && tool_admin_applications_check('tool_main_easy_restart'))\n\t\t\t\t{\n\t\t\t\t\t$tool_seq_id\t\t\t= $NELTOOL['POST_VARS']['restart_sequence_id'];\n\t\t\t\t\t$tool_seq_step\t\t\t= $NELTOOL['POST_VARS']['restart_sequence_step'];\n\n\t\t\t\t\t$restart_shard_id \t\t= $NELTOOL['POST_VARS']['restart_shard_id'];\n\t\t\t\t\t$service_su\t\t\t\t= $NELTOOL['POST_VARS']['restart_su'];\n\t\t\t\t\t$service_egs\t\t\t= $NELTOOL['POST_VARS']['restart_egs'];\n\n\t\t\t\t\t$restart_stop_services\t= $NELTOOL['POST_VARS']['restart_stop_services'];\n\n\t\t\t\t\tif (isset($NELTOOL['POST_VARS']['restart_check_ws']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// we are starting the restart sequence\n\t\t\t\t\t\t$restart_ws_state\t\t= $NELTOOL['POST_VARS']['restart_ws_state'];\n\n\t\t\t\t\t\tif ($restart_ws_state == 'open')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// shard needs a regular restart\n\n\t\t\t\t\t\t\t// - broadcast a message on the shard\n\n\t\t\t\t\t\t\t$restart_reboot_message_id \t\t= $NELTOOL['POST_VARS']['restart_message_reboot_id'];\n\t\t\t\t\t\t\t$restart_reboot_message_data\t= tool_admin_restart_messages_get_id($restart_reboot_message_id);\n\t\t\t\t\t\t\t$restart_reboot_message\t\t\t= $restart_reboot_message_data['restart_message_value'];\n\n\t\t\t\t\t\t\tif ($restart_reboot_message != '')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = \"broadcast repeat=10 every=60 \". $restart_reboot_message;\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service_egs);\n\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service_egs' ...\");\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service_egs, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service_egs .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// - prepare next step (timer countdown to 10 minutes)\n\n\t\t\t\t\t\t\tif($restart_shard_id == 301)\n\t\t\t\t\t\t\t{\n                                // Fast restart for yubo shard (1mn)\n\t\t\t\t\t\t\t\ttool_main_set_restart_sequence_timer($tool_seq_id, 60);\n\t\t\t\t\t\t\t\tnt_common_add_debug(\"fast restart for yubo shard 301\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttool_main_set_restart_sequence_timer($tool_seq_id, 600);\n\t\t\t\t\t\t\t\tnt_common_add_debug(\"normal restart for live shard\");\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// - lets start by locking the WS\n\n\t\t\t\t\t\t\t$service_command = 'rsm.setWSState '. $restart_shard_id .' RESTRICTED \"\"';\n\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service_su' ...\");\n\n\t\t\t\t\t\t\t$adminService->serviceCmd($service_su, $service_command);\n\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service_su .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// shard needs an immediate restart\n\n\t\t\t\t\t\t\t// - prepare next step (timer countdown to a few seconds)\n\n\t\t\t\t\t\t\ttool_main_set_restart_sequence_timer($tool_seq_id, 30);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// - inform CS about the restart\n\t\t\t\t\t\ttool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4101, $AS_CsSQL, $AS_ShardLang);\n\n\t\t\t\t\t\t// - resend the services to stop for the next step\n\n\t\t\t\t\t\t$tpl->assign('tool_restart_stop_actions', $restart_stop_services);\n\n\t\t\t\t\t\t// - move on to the next step\n\n\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1);\n\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_back']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// this makes you go to the next step\n\t\t\t\t\t\tif ($tool_seq_id == $tool_restart_info['restart_sequence_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step - 1);\n\t\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_end']))\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_main_set_end_restart_sequence($tool_seq_id);\n\t\t\t\t\t\tnt_common_redirect('index.php');\n\t\t\t\t\t\texit();\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_continue']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// this makes you go to the next step\n\t\t\t\t\t\tif ($tool_seq_id == $tool_restart_info['restart_sequence_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1);\n\t\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_giveup']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// update klients events to giveup mode\n\n\t\t\t\t\t\t//$klients_events = explode(',',$tool_restart_info['restart_sequence_events']);\n\t\t\t\t\t\t//tool_main_change_restart_notification($klients_events, 4105, $AS_CsSQL);\n\t\t\t\t\t\ttool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4105, $AS_CsSQL, $AS_ShardLang);\n\n\t\t\t\t\t\ttool_main_set_end_restart_sequence($tool_seq_id);\n\t\t\t\t\t\tnt_common_redirect('index.php');\n\t\t\t\t\t\texit();\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_cancel']))\n\t\t\t\t\t{\n\t\t\t\t\t\tif ($restart_ws_state != 'open')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// - broadcast a message on the shard\n\n\t\t\t\t\t\t\t$restart_reboot_message_data\t= tool_admin_restart_messages_get_list_from_name('cancel', $AS_ShardLang);\n\n\t\t\t\t\t\t\tif (sizeof($restart_reboot_message_data))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$restart_reboot_message = $restart_reboot_message_data[0]['restart_message_value'];\n\n\t\t\t\t\t\t\t\tif ($restart_reboot_message != '')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = \"broadcast \". $restart_reboot_message;\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service_egs);\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service_egs' ...\");\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service_egs, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service_egs .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// update the klients events to cancelled mode\n\n\t\t\t\t\t\t\t$klients_events = explode(',',$tool_restart_info['restart_sequence_events']);\n\t\t\t\t\t\t\ttool_main_change_restart_notification($klients_events, 4104, $AS_CsSQL);\n\n\t\t\t\t\t\t\t// - open the WS again\n\n\t\t\t\t\t\t\t$service_command = 'rsm.setWSState '. $restart_shard_id .' OPEN \"\"';\n\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service_su' ...\");\n\n\t\t\t\t\t\t\t$adminService->serviceCmd($service_su, $service_command);\n\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service_su .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\n\t\t\t\t\t\t\t// end the sequence and refresh\n\n\t\t\t\t\t\t\ttool_main_set_end_restart_sequence($tool_seq_id);\n\t\t\t\t\t\t\tnt_common_redirect('index.php');\n\t\t\t\t\t\t\texit();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_wait_timer']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// step 1, waited for the timer, lets shutdown the shard\n\n\t\t\t\t\t\t$service_list = explode(',', $restart_stop_services);\n\n\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// comment out to prevent stopping services for testing purposes\n\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'stopService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'stopService' on '$service' ...\");\n\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'stopService');\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for stopService');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// - prepare next step (timer countdown to a few seconds)\n\n\t\t\t\t\t\ttool_main_set_restart_sequence_timer($tool_seq_id, 30);\n\n\t\t\t\t\t\t// - move on to the next step\n\n\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1);\n\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_shutdown_timer']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// step 2, waited for the shutdown timer, lets move on\n\n\t\t\t\t\t\t// - move on to the next step\n\n\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1);\n\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_start_group']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// step 4, start a group of services\n\t\t\t\t\t\t$tool_seq_start_id \t\t= $NELTOOL['POST_VARS']['restart_start_group_id'];\n\t\t\t\t\t\t$tool_seq_start_list\t= $NELTOOL['POST_VARS']['restart_start_group_list'];\n\n\t\t\t\t\t\tif (isset($tool_restart_start_list))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tforeach($tool_restart_start_list as $restart_start_group)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif ($restart_start_group['restart_group_id'] == $tool_seq_start_id)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_list = explode(',', $tool_seq_start_list);\n\n\t\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'startService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'startService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'startService');\n\t\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for startService');\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_stop_group']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// step 3, stop a group of services\n\t\t\t\t\t\t$tool_seq_stop_id \t= $NELTOOL['POST_VARS']['restart_stop_group_id'];\n\t\t\t\t\t\t$tool_seq_stop_list\t= $NELTOOL['POST_VARS']['restart_stop_group_list'];\n\n\t\t\t\t\t\tif (isset($tool_restart_stop_list))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$service_list = explode(',', $tool_seq_stop_list);\n\n\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'stopService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'stopService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'stopService');\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for stopService');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telseif (isset($NELTOOL['POST_VARS']['restart_over']))\n\t\t\t\t\t{\n\t\t\t\t\t\t// this makes you go to the next step\n\t\t\t\t\t\tif ($tool_seq_id == $tool_restart_info['restart_sequence_id'])\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// - inform CS that the shard is ready and locked\n\t\t\t\t\t\t\ttool_main_add_restart_notification($tool_seq_id, $service_su, $service_egs, $restart_shard_id, 4102, $AS_CsSQL, $AS_ShardLang);\n\n\t\t\t\t\t\t\t$tool_restart_info = tool_main_set_next_restart_sequence_step($tool_seq_id, $tool_seq_step + 1);\n\t\t\t\t\t\t\t$tpl->assign('tool_restart_info', $tool_restart_info);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t//elseif (isset($NELTOOL['POST_VARS']['restart_broadcast_open']))\n\t\t\t\t\t//{\n\t\t\t\t\t//\t// step 6, open ws, end restart sequence\n                    //\n\t\t\t\t\t//\t// - open WS\n\t\t\t\t\t//\t$service \t\t\t= $NELTOOL['POST_VARS']['restart_su'];\n\t\t\t\t\t//\t$restart_shard_id \t= $NELTOOL['POST_VARS']['restart_shard_id'];\n                    //\n\t\t\t\t\t//\t$service_command = 'rsm.setWSState '. $restart_shard_id .' OPEN \"\"';\n\t\t\t\t\t//\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n                    //\n\t\t\t\t\t//\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t//\tif (!$adminService->waitCallback())\n\t\t\t\t\t//\t{\n\t\t\t\t\t//\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t//\t}\n                    //\n\t\t\t\t\t//\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t//\tnt_sleep(VIEW_DELAY);\n                    //\n\t\t\t\t\t//\t// - end restart sequence\n\t\t\t\t\t//\ttool_main_set_end_restart_sequence($tool_seq_id);\n\t\t\t\t\t//\tnt_common_redirect('index.php');\n\t\t\t\t\t//\texit();\n\t\t\t\t\t//}\n\t\t\t\t}\n\t\t\t\telseif (isset($_POST['shards_update']) && tool_admin_applications_check('tool_main_shard_autostart'))\n\t\t\t\t{\n\t\t\t\t\t$shard_update_mode\t= $_POST['shards_update'];\n\t\t\t\t\t$shard_update_name\t= $_POST['shards_update_name'];\n\n\t\t\t\t\tswitch ($shard_update_mode)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'auto restart on':\n\n\t\t\t\t\t\t\t$as_command = \"setShardStartMode \". $shard_update_name .\" on\";\n\n\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : $as_command\");\n\t\t\t\t\t\t\tnt_common_add_debug(\"about to run '$as_command' ...\");\n\t\t\t\t\t\t\t$adminService->globalCmd($as_command);\n\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback for \\''. $as_command .'\\'');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'auto restart off':\n\n\t\t\t\t\t\t\t$as_command = \"setShardStartMode \". $shard_update_name .\" off\";\n\n\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : $as_command\");\n\t\t\t\t\t\t\tnt_common_add_debug(\"about to run '$as_command' ...\");\n\t\t\t\t\t\t\t$adminService->globalCmd($as_command);\n\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback for \\''. $as_command .'\\'');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t\telseif (isset($_POST['ws_update']) && tool_admin_applications_check('tool_main_ws'))\n\t\t\t\t{\n\t\t\t\t\t$shard_ws_su\t\t\t= $_POST['ws_su'];\n\t\t\t\t\t$shard_ws_shard_name\t= $_POST['ws_shard_name'];\n\t\t\t\t\t$shard_ws_shard_id\t\t= $_POST['ws_shard_id'];\n\n\t\t\t\t\t$shard_ws_state\t\t\t= $_POST['ws_state_'. $shard_ws_shard_name];\n\t\t\t\t\t$shard_ws_motd\t\t\t= $_POST['ws_motd_'. $shard_ws_shard_name];\n\n\t\t\t\t\t// coders don't know how to write it seems\n\t\t\t\t\t// ace: now they know if ($shard_ws_state == 'close') $shard_ws_state = 'closed';\n\n\t\t\t\t\t//nt_common_add_debug(\"request for \". $shard_ws_su .\"/\". $shard_ws_shard_name .\" to set STATE:\". $shard_ws_state .\" (\". $shard_ws_motd .\")\");\n\n\t\t\t\t\t$service = $shard_ws_su;\n\t\t\t\t\t$service_command = 'rsm.setWSState '. $shard_ws_shard_id .' '. strtoupper($shard_ws_state) .' \"'. $shard_ws_motd .'\"';\n\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\n\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t{\n\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t}\n\n\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t}\n\t\t\t\telseif (isset($_POST['services_update']))\n\t\t\t\t{\n\t\t\t\t\t$service_update_mode\t= $_POST['services_update'];\n\n\t\t\t\t\tswitch ($service_update_mode)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'open ws': // 2\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_ws_old'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = \"ShardOpen 2\";\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'lock ws': // 1\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_ws_old'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = \"ShardOpen 1\";\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'close ws':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_ws_old'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = \"ShardOpen 0\";\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$tpl->clear_assign('tool_execute_result');\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'activate':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_service_autostart'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'activateService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'activateService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'activateService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback for \\''. $service .'\\'');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'deactivate':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_service_autostart'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'deactivateService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'deactivateService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'deactivateService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback for \\''. $service .'\\'');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'reset counters':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_reset_counters'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'resetStartCounter' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'resetStartCounter' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, 'aes.resetStartCounter');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback for \\''. $service .'\\'');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'start':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_start'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'startService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'startService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'startService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for startService');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_stop'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'stopService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'stopService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'stopService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for stopService');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'restart':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_restart'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'restartService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'restartService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'restartService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for restartService');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'kill':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_kill'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'killService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'killService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'killService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for killService');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'abort':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_abort'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : 'abortService' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'abortService' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t$adminService->controlCmd($service, 'abortService');\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for abortService');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tnt_sleep(VIEW_DELAY);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'execute':\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_main_execute'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tif (isset($_POST['service_command']))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = trim(stripslashes(html_entity_decode($_POST['service_command'], ENT_QUOTES)));\n\t\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_command', \thtmlentities($service_command, ENT_QUOTES));\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} // if ($nel_user['has_lock'])\n\n\t\t\t$status_orders\t= $adminService->getShardOrders();\n\t\t\t$status \t\t= $adminService->getStates();\n\t\t\tnt_common_add_debug($status_orders);\n\t\t\tnt_common_add_debug($status);\n\n\t\t\t$domainServices = tool_main_parse_status($status);\n\t\t\t$shardRunList\t= tool_main_get_shards_from_status($domainServices, $tool_shard_filters);\n\t\t\t$shardRunOrders\t= tool_main_get_shards_orders($status_orders);\n\t\t\tnt_common_add_debug($shardRunList);\n\t\t\tnt_common_add_debug($shardRunOrders);\n\n\t\t\t$shardInfos\t\t= tool_main_get_shards_info_from_db($AS_Application, $domainServices, $tool_shard_filters, $AS_RingSQL);\n\t\t\tnt_common_add_debug(\"shard infos :\");\n\t\t\tnt_common_add_debug($shardInfos);\n\n\t\t\t$tpl->assign('tool_services_list',\t$domainServices);\n\t\t\t$tpl->assign('tool_shard_run_list',\t$shardRunList);\n\t\t\t$tpl->assign('tool_shard_orders',\t$shardRunOrders);\n\n\t\t\t$tpl->assign('tool_shard_su_name',\ttool_main_get_su_from_status($domainServices));\n\t\t\t$tpl->assign('tool_shard_infos',\t$shardInfos);\n\t\t\t$tpl->assign('tool_shard_ws_states',array('close','dev','restricted','open'));\n\n\t\t\tif (isset($shardInfos[$AS_InternalName]))\n\t\t\t{\n\t\t\t\t$tpl->assign('tool_restart_ws_state', $shardInfos[$AS_InternalName]['state']);\n\t\t\t}\n\n\t\t\tif (isset($tool_restart_stop_list) && isset($tool_restart_info) && tool_admin_applications_check('tool_main_easy_restart'))\n\t\t\t{\n\t\t\t\t// lets get a list of services for each group\n\t\t\t\t$tool_restart_start_group_list\t= tool_main_get_restart_services($AS_InternalName, $domainServices, $tool_restart_start_list);\n\t\t\t\t$tpl->assign('tool_restart_start_actions',\t$tool_restart_start_group_list);\n\n\t\t\t\t$tool_restart_stop_group_list\t= tool_main_get_all_restart_services($tool_restart_start_group_list);\n\t\t\t\t$tpl->assign('tool_restart_stop_actions',\t$tool_restart_stop_group_list);\n\n\t\t\t\t// get the shard id\n\t\t\t\t$tool_restart_shard_id\t= tool_main_get_shardid_from_status($domainServices, $AS_InternalName);\n\t\t\t\t$tpl->assign('tool_restart_shard_id',\t\t$tool_restart_shard_id);\n\n\t\t\t\t// find the shard egs for broadcasts\n\t\t\t\t$tool_restart_egs_name\t= tool_main_get_egs_from_status($domainServices, $AS_InternalName);\n\t\t\t\t$tpl->assign('tool_restart_egs_name',\t\t$tool_restart_egs_name);\n\t\t\t}\n\n\t\t}\n\n\t\t$tool_hd_list = tool_main_get_hd_data_for_domain($view_domain_id);\n\t\tnt_common_add_debug($tool_hd_list);\n\t\t$tpl->assign('tool_hd_list',\t\t$tool_hd_list);\n\t\t$tpl->assign('tool_hd_time',\t\ttool_main_get_last_hd_time_for_domain($view_domain_id));\n\t}\n\t//else\n\t//{\n\t//\tnt_common_add_debug('invalid host/port!');\n\t//}\n\n\t$tpl->display('index.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_balls.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_ROUNDBALLS.INC\n// Description:\tBase64 encoded images for small round markers\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_balls.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass ImgData_Balls extends ImgData {\n    var $name = 'Round Balls';\n    var $an = array(MARK_IMG_LBALL => 'imgdata_large',\n\t\t    MARK_IMG_MBALL => 'imgdata_small',\n\t\t    MARK_IMG_SBALL => 'imgdata_xsmall',\n\t\t    MARK_IMG_BALL => 'imgdata_xsmall');\n    var $colors_1 = array('blue','lightblue','brown','darkgreen',\n\t\t\t      'green','purple','red','gray','yellow','silver','gray');\n    var $index_1  = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7,\n\t\t\t      'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2);\n    var $maxidx_1 = 9 ;\n\n    var $colors_2 = array('blue','bluegreen','brown','cyan',\n\t\t\t  'darkgray','greengray','gray','green',\n\t\t\t  'greenblue','lightblue','lightred',\n\t\t\t  'purple','red','white','yellow');\n\t\t\t  \n\t\n    var $index_2 =  array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12,\n\t\t\t  'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10,\n\t\t\t  'greenblue'=>3,'lightblue'=>1,'lightred'=>14,\n\t\t\t  'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4);\n\t\t\t\n    var $maxidx_2 = 14 ;\n\n\n    var $colors_3 = array('bluegreen','cyan','darkgray','greengray',\n\t\t\t  'gray','graypurple','green','greenblue','lightblue',\n\t\t\t  'lightred','navy','orange','purple','red','yellow');\n\t\n    var $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10,\n\t\t\t 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7,\n\t\t\t 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12,\n\t\t\t 'purple'=>8,'red'=>5,'yellow'=>6);\n    var $maxidx_3 = 14 ;\n\n    var $colors,$index,$maxidx;\n    var $imgdata_large ;\n    var $imgdata_small ;\n    var $imgdata_xsmall ;\n\n\n    function GetImg($aMark,$aIdx) {\n\tswitch( $aMark ) {\n\t    case MARK_IMG_SBALL:\n\t    case MARK_IMG_BALL:\n\t\t$this->colors = $this->colors_3;\n\t\t$this->index = $this->index_3 ;\n\t\t$this->maxidx = $this->maxidx_3 ;\n\t\tbreak;\n\t    case MARK_IMG_MBALL:\n\t\t$this->colors = $this->colors_2;\n\t\t$this->index = $this->index_2 ;\n\t\t$this->maxidx = $this->maxidx_2 ;\n\t\tbreak;\n\t    default:\n\t\t$this->colors = $this->colors_1;\n\t\t$this->index = $this->index_1 ;\n\t\t$this->maxidx = $this->maxidx_1 ;\n\t\tbreak;\n\t}\n\treturn parent::GetImg($aMark,$aIdx);\n    }\n\n    function ImgData_Balls() {\n\n//==========================================================\n// File: bl_red.png\n//==========================================================\n\t$this->imgdata_large[0][0]= 1072 ;\n\t$this->imgdata_large[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'.\n\t    'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'.\n\t    'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'.\n\t    'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'.\n\t    'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'.\n\t    'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'.\n\t    'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'.\n\t    'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'.\n\t    'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'.\n\t    'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'.\n\t    'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'.\n\t    'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'.\n\t    'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'.\n\t    'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'.\n\t    'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'.\n\t    'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'.\n\t    'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'.\n\t    'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'.\n\t    'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'.\n\t    'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'.\n\t    'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'.\n\t    'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'.\n\t    'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'.\n\t    'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'.\n\t    'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'.\n\t    'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'.\n\t    'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'.\n\t    'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'.\n\t    'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bl_bluegreen.png\n//==========================================================\n\t$this->imgdata_large[1][0]= 1368 ;\n\t$this->imgdata_large[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'.\n\t    'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'.\n\t    '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'.\n\t    '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'.\n\t    'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'.\n\t    'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'.\n\t    'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'.\n\t    'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'.\n\t    'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'.\n\t    'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'.\n\t    'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'.\n\t    'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'.\n\t    'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'.\n\t    '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'.\n\t    'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'.\n\t    'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'.\n\t    'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'.\n\t    'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'.\n\t    'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'.\n\t    'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'.\n\t    'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'.\n\t    'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'.\n\t    'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'.\n\t    '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'.\n\t    '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'.\n\t    'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'.\n\t    'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'.\n\t    'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'.\n\t    'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'.\n\t    'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'.\n\t    'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'.\n\t    'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'.\n\t    'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'.\n\t    'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'.\n\t    '0zz7G56hAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bl_yellow.png\n//==========================================================\n\t$this->imgdata_large[2][0]= 1101 ;\n\t$this->imgdata_large[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'.\n\t    'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'.\n\t    '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'.\n\t    'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'.\n\t    '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'.\n\t    'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'.\n\t    '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'.\n\t    'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'.\n\t    'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'.\n\t    'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'.\n\t    'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'.\n\t    'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'.\n\t    'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'.\n\t    'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'.\n\t    'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'.\n\t    'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'.\n\t    'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'.\n\t    'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'.\n\t    'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'.\n\t    'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'.\n\t    'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'.\n\t    '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'.\n\t    'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'.\n\t    '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'.\n\t    'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'.\n\t    'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'.\n\t    'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'.\n\t    'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'.\n\t    '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'.\n\t    'SXAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bl_silver.png\n//==========================================================\n\t$this->imgdata_large[3][0]= 1481 ;\n\t$this->imgdata_large[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'.\n\t    'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'.\n\t    'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'.\n\t    'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'.\n\t    'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'.\n\t    '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'.\n\t    'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'.\n\t    'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'.\n\t    'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'.\n\t    'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'.\n\t    'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'.\n\t    'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'.\n\t    'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'.\n\t    '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'.\n\t    'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.\n\t    'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'.\n\t    'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'.\n\t    'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'.\n\t    'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'.\n\t    'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'.\n\t    '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'.\n\t    'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'.\n\t    'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'.\n\t    'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'.\n\t    'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'.\n\t    'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'.\n\t    'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'.\n\t    'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'.\n\t    'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'.\n\t    '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'.\n\t    'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'.\n\t    'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'.\n\t    'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'.\n\t    'NlNT9CliMAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bl_purple.png\n//==========================================================\n\t$this->imgdata_large[4][0]= 1149 ;\n\t$this->imgdata_large[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'.\n\t    'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'.\n\t    'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'.\n\t    'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'.\n\t    'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'.\n\t    'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'.\n\t    'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'.\n\t    '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'.\n\t    'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'.\n\t    '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'.\n\t    'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'.\n\t    'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'.\n\t    'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'.\n\t    'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'.\n\t    'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'.\n\t    'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'.\n\t    'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'.\n\t    'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'.\n\t    'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'.\n\t    'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'.\n\t    'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'.\n\t    'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'.\n\t    'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'.\n\t    'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'.\n\t    'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'.\n\t    'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'.\n\t    'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'.\n\t    'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'.\n\t    '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'.\n\t    'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'.\n\t    'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bl_gray.png\n//==========================================================\n\t$this->imgdata_large[5][0]= 905 ;\n\t$this->imgdata_large[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'.\n\t    'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'.\n\t    'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'.\n\t    'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'.\n\t    'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'.\n\t    'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'.\n\t    'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'.\n\t    'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'.\n\t    'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'.\n\t    'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'.\n\t    'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'.\n\t    'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'.\n\t    'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'.\n\t    'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'.\n\t    'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'.\n\t    'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'.\n\t    'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'.\n\t    'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'.\n\t    'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'.\n\t    'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'.\n\t    'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'.\n\t    'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'.\n\t    'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'.\n\t    'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'.\n\t    'RK5CYII=' ; \n\n//==========================================================\n// File: bl_brown.png\n//==========================================================\n\t$this->imgdata_large[6][0]= 1053 ;\n\t$this->imgdata_large[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'.\n\t    'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'.\n\t    'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'.\n\t    'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'.\n\t    'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'.\n\t    'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'.\n\t    'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'.\n\t    'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'.\n\t    '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'.\n\t    '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'.\n\t    'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'.\n\t    'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'.\n\t    'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'.\n\t    'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'.\n\t    'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'.\n\t    'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'.\n\t    'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'.\n\t    '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'.\n\t    'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'.\n\t    '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'.\n\t    'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'.\n\t    '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'.\n\t    'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'.\n\t    'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'.\n\t    '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'.\n\t    'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'.\n\t    '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'.\n\t    'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'.\n\t    'QmCC' ; \n\n//==========================================================\n// File: bl_darkgreen.png\n//==========================================================\n\t$this->imgdata_large[7][0]= 1113 ;\n\t$this->imgdata_large[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'.\n\t    'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'.\n\t    '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'.\n\t    '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'.\n\t    'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'.\n\t    'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'.\n\t    'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'.\n\t    'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'.\n\t    'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'.\n\t    'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'.\n\t    'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'.\n\t    'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'.\n\t    'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'.\n\t    'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'.\n\t    'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'.\n\t    'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'.\n\t    'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'.\n\t    'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'.\n\t    'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'.\n\t    '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'.\n\t    'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'.\n\t    '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'.\n\t    'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'.\n\t    'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'.\n\t    'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'.\n\t    'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'.\n\t    'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'.\n\t    'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'.\n\t    'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'.\n\t    'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bl_green.png\n//==========================================================\n\t$this->imgdata_large[8][0]= 1484 ;\n\t$this->imgdata_large[8][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'.\n\t    'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'.\n\t    'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'.\n\t    'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'.\n\t    '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'.\n\t    'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'.\n\t    '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'.\n\t    'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'.\n\t    'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'.\n\t    'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'.\n\t    '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'.\n\t    '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'.\n\t    'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'.\n\t    'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'.\n\t    'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'.\n\t    'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'.\n\t    'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'.\n\t    'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'.\n\t    'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'.\n\t    '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'.\n\t    'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'.\n\t    'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'.\n\t    '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'.\n\t    'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'.\n\t    'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'.\n\t    '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'.\n\t    'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'.\n\t    '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'.\n\t    'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'.\n\t    'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'.\n\t    'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'.\n\t    'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'.\n\t    'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'.\n\t    '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'.\n\t    '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'.\n\t    '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'.\n\t    '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'.\n\t    '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bl_blue.png\n//==========================================================\n\t$this->imgdata_large[9][0]= 1169 ;\n\t$this->imgdata_large[9][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'.\n\t    'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'.\n\t    'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'.\n\t    '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'.\n\t    'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'.\n\t    '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'.\n\t    'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'.\n\t    'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'.\n\t    'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'.\n\t    'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'.\n\t    'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'.\n\t    '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'.\n\t    'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'.\n\t    'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'.\n\t    'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'.\n\t    'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'.\n\t    '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'.\n\t    'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'.\n\t    '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'.\n\t    'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'.\n\t    'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'.\n\t    'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'.\n\t    'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'.\n\t    'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'.\n\t    'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'.\n\t    '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'.\n\t    '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'.\n\t    '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'.\n\t    'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'.\n\t    'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'.\n\t    'VORK5CYII=' ; \n\n//==========================================================\n// File: bs_red.png\n//==========================================================\n\t$this->imgdata_small[0][0]= 437 ;\n\t$this->imgdata_small[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'.\n\t    'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'.\n\t    'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'.\n\t    'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'.\n\t    'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'.\n\t    'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'.\n\t    'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'.\n\t    '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'.\n\t    'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'.\n\t    'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'.\n\t    'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; \n\n\n//==========================================================\n// File: bs_lightblue.png\n//==========================================================\n\t$this->imgdata_small[1][0]= 657 ;\n\t$this->imgdata_small[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'.\n\t    'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'.\n\t    'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'.\n\t    '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'.\n\t    'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'.\n\t    'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'.\n\t    'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'.\n\t    'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'.\n\t    'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'.\n\t    'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'.\n\t    'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'.\n\t    'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'.\n\t    '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'.\n\t    'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'.\n\t    'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'.\n\t    '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'.\n\t    'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'.\n\t    'qvIlIAMH7YAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bs_gray.png\n//==========================================================\n\t$this->imgdata_small[2][0]= 550 ;\n\t$this->imgdata_small[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'.\n\t    'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'.\n\t    'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'.\n\t    'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'.\n\t    'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'.\n\t    'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'.\n\t    'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'.\n\t    '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'.\n\t    'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'.\n\t    'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'.\n\t    'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'.\n\t    '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'.\n\t    'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'.\n\t    'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'.\n\t    'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bs_greenblue.png\n//==========================================================\n\t$this->imgdata_small[3][0]= 503 ;\n\t$this->imgdata_small[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'.\n\t    'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'.\n\t    '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'.\n\t    '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'.\n\t    'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'.\n\t    'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'.\n\t    'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'.\n\t    'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'.\n\t    'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'.\n\t    'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'.\n\t    'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'.\n\t    'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'.\n\t    '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'.\n\t    '4/IOkAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bs_yellow.png\n//==========================================================\n\t$this->imgdata_small[4][0]= 507 ;\n\t$this->imgdata_small[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'.\n\t    'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'.\n\t    'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'.\n\t    'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'.\n\t    'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'.\n\t    'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'.\n\t    '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'.\n\t    'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'.\n\t    'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'.\n\t    'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'.\n\t    'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'.\n\t    'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'.\n\t    'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'.\n\t    'KgEq+FpPbfAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bs_darkgray.png\n//==========================================================\n\t$this->imgdata_small[5][0]= 611 ;\n\t$this->imgdata_small[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'.\n\t    'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'.\n\t    'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'.\n\t    'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'.\n\t    'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'.\n\t    'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'.\n\t    'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'.\n\t    'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'.\n\t    'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'.\n\t    'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'.\n\t    'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'.\n\t    'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'.\n\t    'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'.\n\t    'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'.\n\t    'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'.\n\t    'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'.\n\t    'AAAASUVORK5CYII=' ; \n\n\n//==========================================================\n// File: bs_darkgreen.png\n//==========================================================\n\t$this->imgdata_small[6][0]= 666 ;\n\t$this->imgdata_small[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'.\n\t    'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'.\n\t    'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'.\n\t    'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'.\n\t    'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'.\n\t    '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'.\n\t    'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'.\n\t    'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'.\n\t    'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'.\n\t    'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'.\n\t    'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'.\n\t    'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'.\n\t    'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'.\n\t    'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'.\n\t    'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'.\n\t    'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bs_purple.png\n//==========================================================\n\t$this->imgdata_small[7][0]= 447 ;\n\t$this->imgdata_small[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'.\n\t    'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'.\n\t    'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'.\n\t    'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'.\n\t    'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'.\n\t    'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'.\n\t    'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'.\n\t    'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'.\n\t    'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'.\n\t    'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'.\n\t    'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'.\n\t    'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; \n\n\n//==========================================================\n// File: bs_brown.png\n//==========================================================\n\t$this->imgdata_small[8][0]= 677 ;\n\t$this->imgdata_small[8][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'.\n\t    'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'.\n\t    'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'.\n\t    'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'.\n\t    'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'.\n\t    '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'.\n\t    'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'.\n\t    'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'.\n\t    'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'.\n\t    'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'.\n\t    'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'.\n\t    'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'.\n\t    'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'.\n\t    'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'.\n\t    'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'.\n\t    'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'.\n\t    'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'.\n\t    'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'.\n\t    'YII=' ; \n\n//==========================================================\n// File: bs_blue.png\n//==========================================================\n\t$this->imgdata_small[9][0]= 436 ;\n\t$this->imgdata_small[9][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'.\n\t    'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'.\n\t    'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'.\n\t    'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'.\n\t    'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'.\n\t    'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'.\n\t    'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'.\n\t    'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'.\n\t    'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'.\n\t    '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'.\n\t    't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bs_green.png\n//==========================================================\n\t$this->imgdata_small[10][0]= 452 ;\n\t$this->imgdata_small[10][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'.\n\t    'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'.\n\t    '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'.\n\t    'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'.\n\t    '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'.\n\t    'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'.\n\t    'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'.\n\t    'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'.\n\t    'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'.\n\t    'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'.\n\t    'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'.\n\t    'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'.\n\t    'YII=' ; \n\n\n//==========================================================\n// File: bs_white.png\n//==========================================================\n\t$this->imgdata_small[11][0]= 480 ;\n\t$this->imgdata_small[11][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'.\n\t    'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'.\n\t    'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'.\n\t    'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'.\n\t    'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'.\n\t    'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'.\n\t    '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'.\n\t    'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'.\n\t    'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'.\n\t    'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'.\n\t    '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; \n\n\n//==========================================================\n// File: bs_cyan.png\n//==========================================================\n\t$this->imgdata_small[12][0]= 633 ;\n\t$this->imgdata_small[12][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'.\n\t    'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'.\n\t    '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'.\n\t    'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'.\n\t    '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'.\n\t    'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'.\n\t    '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'.\n\t    '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'.\n\t    'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'.\n\t    'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'.\n\t    'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'.\n\t    'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'.\n\t    'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'.\n\t    'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'.\n\t    'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'.\n\t    'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bs_bluegreen.png\n//==========================================================\n\t$this->imgdata_small[13][0]= 493 ;\n\t$this->imgdata_small[13][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'.\n\t    'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'.\n\t    'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'.\n\t    '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'.\n\t    'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'.\n\t    '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'.\n\t    'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'.\n\t    'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'.\n\t    'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'.\n\t    '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'.\n\t    'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'.\n\t    'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'.\n\t    'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'.\n\t    '5ErkJggg==' ; \n\n//==========================================================\n// File: bs_lightred.png\n//==========================================================\n\t$this->imgdata_small[14][0]= 532 ;\n\t$this->imgdata_small[14][1]=\n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'.\n\t    'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'.\n\t    'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'.\n\t    'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'.\n\t    'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'.\n\t    'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'.\n\t    'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'.\n\t    'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'.\n\t    'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'.\n\t    'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'.\n\t    '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'.\n\t    'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'.\n\t    'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'.\n\t    'RU5ErkJggg==' ;\n\n//==========================================================\n// File: bxs_lightred.png\n//==========================================================\n\t$this->imgdata_xsmall[0][0]= 432 ;\n\t$this->imgdata_xsmall[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'.\n\t    'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'.\n\t    'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'.\n\t    'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'.\n\t    'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'.\n\t    'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'.\n\t    'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'.\n\t    'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'.\n\t    'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'.\n\t    'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'.\n\t    'DaB7Du8MiEAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bxs_bluegreen.png\n//==========================================================\n\t$this->imgdata_xsmall[1][0]= 397 ;\n\t$this->imgdata_xsmall[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'.\n\t    'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'.\n\t    'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'.\n\t    '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'.\n\t    'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'.\n\t    '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'.\n\t    'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'.\n\t    'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'.\n\t    'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'.\n\t    'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'.\n\t    '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bxs_navy.png\n//==========================================================\n\t$this->imgdata_xsmall[2][0]= 353 ;\n\t$this->imgdata_xsmall[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'.\n\t    'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'.\n\t    'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'.\n\t    'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'.\n\t    'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'.\n\t    'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'.\n\t    'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'.\n\t    'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'.\n\t    's5S60AAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bxs_gray.png\n//==========================================================\n\t$this->imgdata_xsmall[3][0]= 492 ;\n\t$this->imgdata_xsmall[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'.\n\t    'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'.\n\t    'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'.\n\t    'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'.\n\t    'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'.\n\t    'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'.\n\t    'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'.\n\t    '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'.\n\t    'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'.\n\t    'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'.\n\t    'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'.\n\t    'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'.\n\t    'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'.\n\t    'SuQmCC' ; \n\n//==========================================================\n// File: bxs_graypurple.png\n//==========================================================\n\t$this->imgdata_xsmall[4][0]= 542 ;\n\t$this->imgdata_xsmall[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'.\n\t    'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'.\n\t    'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'.\n\t    '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'.\n\t    'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'.\n\t    'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'.\n\t    'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'.\n\t    '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'.\n\t    'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'.\n\t    'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'.\n\t    'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.\n\t    'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'.\n\t    'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'.\n\t    'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'.\n\t    'hkeRpo8AAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bxs_red.png\n//==========================================================\n\t$this->imgdata_xsmall[5][0]= 357 ;\n\t$this->imgdata_xsmall[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'.\n\t    'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'.\n\t    'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'.\n\t    'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'.\n\t    'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'.\n\t    'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'.\n\t    'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'.\n\t    'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'.\n\t    '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'.\n\t    'yXBg73lwGUAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: bxs_yellow.png\n//==========================================================\n\t$this->imgdata_xsmall[6][0]= 414 ;\n\t$this->imgdata_xsmall[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'.\n\t    'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'.\n\t    'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'.\n\t    'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'.\n\t    'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'.\n\t    'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'.\n\t    '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'.\n\t    'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'.\n\t    'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'.\n\t    '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'.\n\t    'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'.\n\t    'CC' ; \n\n//==========================================================\n// File: bxs_greenblue.png\n//==========================================================\n\t$this->imgdata_xsmall[7][0]= 410 ;\n\t$this->imgdata_xsmall[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'.\n\t    'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'.\n\t    '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'.\n\t    '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'.\n\t    'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'.\n\t    'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'.\n\t    'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'.\n\t    'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'.\n\t    'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'.\n\t    'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'.\n\t    'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bxs_purple.png\n//==========================================================\n\t$this->imgdata_xsmall[8][0]= 364 ;\n\t$this->imgdata_xsmall[8][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'.\n\t    'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'.\n\t    'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'.\n\t    'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'.\n\t    'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'.\n\t    'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'.\n\t    'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'.\n\t    'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'.\n\t    'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'.\n\t    'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bxs_green.png\n//==========================================================\n\t$this->imgdata_xsmall[9][0]= 370 ;\n\t$this->imgdata_xsmall[9][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'.\n\t    'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'.\n\t    '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'.\n\t    'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'.\n\t    '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'.\n\t    'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'.\n\t    'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'.\n\t    'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'.\n\t    'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'.\n\t    '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bxs_darkgreen.png\n//==========================================================\n\t$this->imgdata_xsmall[10][0]= 563 ;\n\t$this->imgdata_xsmall[10][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'.\n\t    'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'.\n\t    'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'.\n\t    'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'.\n\t    'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'.\n\t    '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'.\n\t    'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'.\n\t    'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'.\n\t    'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'.\n\t    'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'.\n\t    'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'.\n\t    'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'.\n\t    'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'.\n\t    'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'.\n\t    'I=' ; \n\n//==========================================================\n// File: bxs_cyan.png\n//==========================================================\n\t$this->imgdata_xsmall[11][0]= 530 ;\n\t$this->imgdata_xsmall[11][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'.\n\t    'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'.\n\t    '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'.\n\t    'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'.\n\t    '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'.\n\t    'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'.\n\t    '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'.\n\t    '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'.\n\t    'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'.\n\t    'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'.\n\t    'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'.\n\t    'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'.\n\t    'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'.\n\t    'RK5CYII=' ; \n\n//==========================================================\n// File: bxs_orange.png\n//==========================================================\n\t$this->imgdata_xsmall[12][0]= 572 ;\n\t$this->imgdata_xsmall[12][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'.\n\t    'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'.\n\t    'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'.\n\t    'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'.\n\t    'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'.\n\t    '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'.\n\t    'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'.\n\t    'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'.\n\t    'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'.\n\t    'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'.\n\t    'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'.\n\t    'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'.\n\t    'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'.\n\t    'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'.\n\t    'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'.\n\t    'AASUVORK5CYII=' ; \n\n//==========================================================\n// File: bxs_lightblue.png\n//==========================================================\n\t$this->imgdata_xsmall[13][0]= 554 ;\n\t$this->imgdata_xsmall[13][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'.\n\t    'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'.\n\t    'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'.\n\t    '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'.\n\t    'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'.\n\t    'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'.\n\t    'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'.\n\t    'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'.\n\t    'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'.\n\t    'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'.\n\t    'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'.\n\t    'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'.\n\t    'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'.\n\t    'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'.\n\t    'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: bxs_darkgray.png\n//==========================================================\n\t$this->imgdata_xsmall[14][0]= 574 ;\n\t$this->imgdata_xsmall[14][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'.\n\t    'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'.\n\t    'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'.\n\t    'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'.\n\t    'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'.\n\t    'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'.\n\t    'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'.\n\t    'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'.\n\t    'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'.\n\t    'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'.\n\t    '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'.\n\t    'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'.\n\t    'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'.\n\t    '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'.\n\t    'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'.\n\t    'AAAABJRU5ErkJggg==' ; \n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_bevels.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_BEVELS.INC\n// Description:\tBase64 encoded images for round bevels\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_bevels.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass ImgData_Bevels extends ImgData {\n    var $name = 'Round Bevels';\n    var $an = array(MARK_IMG_BEVEL => 'imgdata');\n    \n    var $colors = array('green','purple','orange','red','yellow');\n    var $index  = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3);\n    var $maxidx = 4 ;\n\n    var $imgdata ;\n\n    function ImgData_Bevels() {\n//==========================================================\n// File: bullets_balls_red_013.png\n//==========================================================\n\t$this->imgdata[0][0]= 337 ;\n\t$this->imgdata[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'.\n\t    'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'.\n\t    'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'.\n\t    'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'.\n\t    'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'.\n\t    'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'.\n\t    'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'.\n\t    '==' ; \n\n//==========================================================\n// File: bullets_balls_green_013.png\n//==========================================================\n\t$this->imgdata[1][0]= 344 ;\n\t$this->imgdata[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'.\n\t    'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'.\n\t    'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'.\n\t    'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'.\n\t    'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'.\n\t    'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'.\n\t    'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'.\n\t    'VORK5CYII=' ; \n\n//==========================================================\n// File: bullets_balls_oy_035.png\n//==========================================================\n\t$this->imgdata[2][0]= 341 ;\n\t$this->imgdata[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'.\n\t    'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'.\n\t    'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'.\n\t    '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'.\n\t    'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'.\n\t    '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'.\n\t    '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'.\n\t    '5CYII=' ; \n\n//==========================================================\n// File: bullets_balls_oy_036.png\n//==========================================================\n\t$this->imgdata[3][0]= 340 ;\n\t$this->imgdata[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'.\n\t    'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'.\n\t    'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'.\n\t    'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'.\n\t    'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'.\n\t    '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'.\n\t    '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'.\n\t    'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ;\n\n//==========================================================\n// File: bullets_balls_pp_019.png\n//==========================================================\n\t$this->imgdata[4][0]= 334 ;\n\t$this->imgdata[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'.\n\t    'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'.\n\t    'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'.\n\t    'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'.\n\t    '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'.\n\t    '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'.\n\t    'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; \n\n    }\n}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_diamonds.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_DIAMONDS.INC\n// Description:\tBase64 encoded images for diamonds\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_diamonds.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass ImgData_Diamonds extends ImgData {\n    var $name = 'Diamonds';\n    var $an = array(MARK_IMG_DIAMOND =>'imgdata');\n    var $colors = array('lightblue','darkblue','gray', \n\t\t\t'blue','pink','purple','red','yellow');\n    var $index  = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, \n\t\t\t'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3);\n\n    var $maxidx = 7 ;\n    var $imgdata ;\n\n    function ImgData_Diamonds() {\n//==========================================================\n// File: diam_red.png\n//==========================================================\n\t$this->imgdata[0][0]= 668 ;\n\t$this->imgdata[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'.\n\t    'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'.\n\t    'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'.\n\t    'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'.\n\t    'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'.\n\t    'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'.\n\t    'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'.\n\t    'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'.\n\t    'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'.\n\t    'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'.\n\t    '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'.\n\t    'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'.\n\t    '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'.\n\t    'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'.\n\t    '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'.\n\t    'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'.\n\t    'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'.\n\t    'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: diam_pink.png\n//==========================================================\n\t$this->imgdata[1][0]= 262 ;\n\t$this->imgdata[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'.\n\t    'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'.\n\t    'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'.\n\t    'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'.\n\t    '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'.\n\t    'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'.\n\t    '==' ; \n\n//==========================================================\n// File: diam_blue.png\n//==========================================================\n\t$this->imgdata[2][0]= 662 ;\n\t$this->imgdata[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'.\n\t    'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'.\n\t    'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'.\n\t    'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'.\n\t    'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'.\n\t    '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'.\n\t    'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'.\n\t    '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'.\n\t    'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'.\n\t    'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'.\n\t    'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'.\n\t    'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'.\n\t    'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'.\n\t    'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'.\n\t    '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'.\n\t    'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'.\n\t    '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'.\n\t    'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: diam_yellow.png\n//==========================================================\n\t$this->imgdata[3][0]= 262 ;\n\t$this->imgdata[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'.\n\t    'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'.\n\t    'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'.\n\t    'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'.\n\t    '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'.\n\t    'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'.\n\t    '==' ; \n\n//==========================================================\n// File: diam_lightblue.png\n//==========================================================\n\t$this->imgdata[4][0]= 671 ;\n\t$this->imgdata[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'.\n\t    'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'.\n\t    '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'.\n\t    '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'.\n\t    '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'.\n\t    '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'.\n\t    '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'.\n\t    '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'.\n\t    'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.\n\t    'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'.\n\t    'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'.\n\t    'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'.\n\t    'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'.\n\t    'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'.\n\t    'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'.\n\t    'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'.\n\t    'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'.\n\t    '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: diam_purple.png\n//==========================================================\n\t$this->imgdata[5][0]= 657 ;\n\t$this->imgdata[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'.\n\t    'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'.\n\t    'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'.\n\t    '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'.\n\t    'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'.\n\t    'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'.\n\t    'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'.\n\t    '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'.\n\t    'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'.\n\t    'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'.\n\t    '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'.\n\t    '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'.\n\t    'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'.\n\t    'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'.\n\t    'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'.\n\t    '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'.\n\t    'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'.\n\t    'EdF1ECWW1SAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: diam_gray.png\n//==========================================================\n\t$this->imgdata[6][0]= 262 ;\n\t$this->imgdata[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'.\n\t    'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'.\n\t    'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'.\n\t    'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'.\n\t    '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'.\n\t    'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'.\n\t    '==' ; \n\n//==========================================================\n// File: diam_blgr.png\n//==========================================================\n\t$this->imgdata[7][0]= 262 ;\n\t$this->imgdata[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'.\n\t    'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'.\n\t    'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'.\n\t    'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'.\n\t    'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'.\n\t    '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'.\n\t    'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'.\n\t    '==' ; \n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_pushpins.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_PUSHPINS.INC\n// Description:\tBase64 encoded images for pushpins\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_pushpins.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass ImgData_PushPins extends ImgData {\n    var $name = 'Push pins';\n    var $an = array(MARK_IMG_PUSHPIN => 'imgdata_small',\n\t\t    MARK_IMG_SPUSHPIN => 'imgdata_small',\n\t\t    MARK_IMG_LPUSHPIN => 'imgdata_large');\n\n    var $colors = array('blue','green','orange','pink','red');\n    var $index  = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ;\n    var $maxidx = 4 ;\n    var $imgdata_large, $imgdata_small ;\n\n    function ImgData_PushPins() {\n\n\t// The anchor should be where the needle \"hits\" the paper\n\t// (bottom left corner)\n\t$this->anchor_x = 0;\n\t$this->anchor_y = 1;\n\n//==========================================================\n// File: ppl_red.png\n//==========================================================\n\t$this->imgdata_large[0][0]= 2490 ;\n\t$this->imgdata_large[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'.\n\t    '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'.\n\t    'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'.\n\t    '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'.\n\t    'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'.\n\t    'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'.\n\t    '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'.\n\t    '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'.\n\t    'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'.\n\t    'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'.\n\t    'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'.\n\t    'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'.\n\t    'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'.\n\t    'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'.\n\t    'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'.\n\t    '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'.\n\t    'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'.\n\t    'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'.\n\t    'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'.\n\t    'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'.\n\t    'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'.\n\t    'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'.\n\t    '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'.\n\t    'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'.\n\t    'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'.\n\t    'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'.\n\t    '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'.\n\t    'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'.\n\t    'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'.\n\t    'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'.\n\t    'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'.\n\t    'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'.\n\t    'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'.\n\t    'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'.\n\t    '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'.\n\t    'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'.\n\t    'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'.\n\t    'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'.\n\t    'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'.\n\t    'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'.\n\t    'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'.\n\t    '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'.\n\t    'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'.\n\t    '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'.\n\t    'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'.\n\t    'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'.\n\t    'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'.\n\t    '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'.\n\t    'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'.\n\t    'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'.\n\t    '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'.\n\t    'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'.\n\t    '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'.\n\t    'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'.\n\t    'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'.\n\t    'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'.\n\t    'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'.\n\t    'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'.\n\t    'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'.\n\t    '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'.\n\t    'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'.\n\t    'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'.\n\t    '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'.\n\t    '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'.\n\t    'Nqn4AAAAAElFTkSuQmCC' ; \n\n//==========================================================\n// File: ppl_orange.png\n//==========================================================\n\t$this->imgdata_large[1][0]= 2753 ;\n\t$this->imgdata_large[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'.\n\t    'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'.\n\t    'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'.\n\t    'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'.\n\t    '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'.\n\t    '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'.\n\t    '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'.\n\t    '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'.\n\t    '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'.\n\t    'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'.\n\t    'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'.\n\t    'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'.\n\t    'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'.\n\t    'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'.\n\t    'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'.\n\t    'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'.\n\t    'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'.\n\t    'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'.\n\t    'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'.\n\t    'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'.\n\t    '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'.\n\t    'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'.\n\t    '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'.\n\t    'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'.\n\t    'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'.\n\t    'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'.\n\t    'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'.\n\t    'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'.\n\t    'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'.\n\t    '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'.\n\t    'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'.\n\t    'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'.\n\t    'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'.\n\t    'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'.\n\t    'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'.\n\t    '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'.\n\t    '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'.\n\t    'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'.\n\t    'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'.\n\t    'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'.\n\t    'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'.\n\t    'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'.\n\t    'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'.\n\t    'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'.\n\t    'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'.\n\t    'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'.\n\t    'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'.\n\t    'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'.\n\t    'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'.\n\t    'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'.\n\t    'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'.\n\t    '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'.\n\t    'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'.\n\t    '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'.\n\t    'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'.\n\t    'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'.\n\t    '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'.\n\t    'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'.\n\t    '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'.\n\t    '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'.\n\t    'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'.\n\t    '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'.\n\t    'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'.\n\t    'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'.\n\t    'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'.\n\t    'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'.\n\t    'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'.\n\t    'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'.\n\t    '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'.\n\t    'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'.\n\t    'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'.\n\t    'n5N4cAAAAASUVORK5CYII=' ; \n\n//==========================================================\n// File: ppl_pink.png\n//==========================================================\n\t$this->imgdata_large[2][0]= 2779 ;\n\t$this->imgdata_large[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'.\n\t    'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'.\n\t    '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'.\n\t    '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'.\n\t    'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'.\n\t    'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'.\n\t    'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'.\n\t    'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'.\n\t    'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'.\n\t    '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'.\n\t    'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'.\n\t    'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'.\n\t    'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'.\n\t    'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'.\n\t    'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'.\n\t    'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'.\n\t    'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'.\n\t    'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'.\n\t    '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'.\n\t    'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'.\n\t    'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'.\n\t    'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'.\n\t    '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'.\n\t    'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'.\n\t    'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'.\n\t    'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'.\n\t    'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'.\n\t    'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'.\n\t    'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'.\n\t    'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'.\n\t    'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'.\n\t    'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'.\n\t    'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'.\n\t    'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'.\n\t    'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'.\n\t    'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'.\n\t    'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'.\n\t    'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'.\n\t    'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'.\n\t    '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'.\n\t    'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'.\n\t    'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'.\n\t    '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'.\n\t    'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'.\n\t    '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'.\n\t    'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'.\n\t    'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'.\n\t    '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'.\n\t    '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'.\n\t    'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'.\n\t    'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'.\n\t    'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'.\n\t    'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'.\n\t    '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'.\n\t    'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'.\n\t    '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'.\n\t    'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'.\n\t    'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'.\n\t    'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'.\n\t    'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'.\n\t    'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'.\n\t    'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'.\n\t    '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'.\n\t    'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'.\n\t    'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'.\n\t    'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'.\n\t    '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'.\n\t    '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'.\n\t    'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'.\n\t    'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'.\n\t    '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'.\n\t    'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'.\n\t    'rkJggg==' ; \n\n//==========================================================\n// File: ppl_blue.png\n//==========================================================\n\t$this->imgdata_large[3][0]= 2284 ;\n\t$this->imgdata_large[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'.\n\t    'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'.\n\t    'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'.\n\t    'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'.\n\t    'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'.\n\t    'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'.\n\t    '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'.\n\t    'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'.\n\t    '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'.\n\t    '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'.\n\t    'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'.\n\t    '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'.\n\t    'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'.\n\t    'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'.\n\t    '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'.\n\t    'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'.\n\t    'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'.\n\t    'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'.\n\t    'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'.\n\t    'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'.\n\t    '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'.\n\t    'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'.\n\t    'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'.\n\t    'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'.\n\t    'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'.\n\t    'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'.\n\t    'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'.\n\t    'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'.\n\t    'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'.\n\t    'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'.\n\t    'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'.\n\t    'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'.\n\t    'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'.\n\t    'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'.\n\t    'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'.\n\t    'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'.\n\t    'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'.\n\t    'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'.\n\t    'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'.\n\t    't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'.\n\t    'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'.\n\t    'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'.\n\t    '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'.\n\t    'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'.\n\t    'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'.\n\t    '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'.\n\t    'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'.\n\t    'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'.\n\t    'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'.\n\t    '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'.\n\t    'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'.\n\t    'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'.\n\t    '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'.\n\t    'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'.\n\t    'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'.\n\t    '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'.\n\t    'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'.\n\t    'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'.\n\t    'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: ppl_green.png\n//==========================================================\n\t$this->imgdata_large[4][0]= 2854 ;\n\t$this->imgdata_large[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'.\n\t    'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'.\n\t    'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'.\n\t    'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'.\n\t    'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'.\n\t    'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'.\n\t    'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'.\n\t    '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'.\n\t    'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'.\n\t    'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'.\n\t    'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'.\n\t    'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'.\n\t    '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'.\n\t    'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'.\n\t    'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'.\n\t    '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'.\n\t    'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'.\n\t    'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'.\n\t    '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'.\n\t    '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'.\n\t    'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'.\n\t    'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'.\n\t    'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'.\n\t    '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'.\n\t    'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'.\n\t    'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'.\n\t    'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'.\n\t    'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'.\n\t    'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'.\n\t    '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'.\n\t    'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'.\n\t    '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'.\n\t    'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'.\n\t    'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'.\n\t    'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'.\n\t    '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'.\n\t    'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'.\n\t    'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'.\n\t    'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'.\n\t    'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'.\n\t    'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'.\n\t    'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'.\n\t    'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'.\n\t    'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'.\n\t    'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'.\n\t    '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'.\n\t    'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'.\n\t    'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'.\n\t    'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'.\n\t    'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'.\n\t    'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'.\n\t    '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'.\n\t    'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'.\n\t    'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'.\n\t    'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'.\n\t    'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'.\n\t    'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'.\n\t    'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'.\n\t    'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'.\n\t    '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'.\n\t    'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'.\n\t    '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'.\n\t    'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'.\n\t    'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'.\n\t    'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'.\n\t    'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'.\n\t    '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'.\n\t    'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'.\n\t    'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'.\n\t    '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'.\n\t    'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'.\n\t    'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'.\n\t    'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'.\n\t    'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'.\n\t    'rkJggg==' ; \n\n\n//==========================================================\n// File: pp_red.png\n//==========================================================\n\t$this->imgdata_small[0][0]= 384 ;\n\t$this->imgdata_small[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.\n\t    'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'.\n\t    'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'.\n\t    'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'.\n\t    'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'.\n\t    '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'.\n\t    'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'.\n\t    'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'.\n\t    's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'.\n\t    'AElFTkSuQmCC' ; \n\n//==========================================================\n// File: pp_orange.png\n//==========================================================\n\t$this->imgdata_small[1][0]= 403 ;\n\t$this->imgdata_small[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.\n\t    'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'.\n\t    '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'.\n\t    'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'.\n\t    'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'.\n\t    'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'.\n\t    'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'.\n\t    'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'.\n\t    'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'.\n\t    'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: pp_pink.png\n//==========================================================\n\t$this->imgdata_small[2][0]= 419 ;\n\t$this->imgdata_small[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.\n\t    'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'.\n\t    'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'.\n\t    'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'.\n\t    'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'.\n\t    'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'.\n\t    'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'.\n\t    'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'.\n\t    'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'.\n\t    'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'.\n\t    'VORK5CYII=' ; \n\n\n//==========================================================\n// File: pp_blue.png\n//==========================================================\n\t$this->imgdata_small[3][0]= 883 ;\n\t$this->imgdata_small[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'.\n\t    'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'.\n\t    'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'.\n\t    'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'.\n\t    'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'.\n\t    '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'.\n\t    'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'.\n\t    'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'.\n\t    'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'.\n\t    'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'.\n\t    'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'.\n\t    'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'.\n\t    'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'.\n\t    'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'.\n\t    'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'.\n\t    'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'.\n\t    '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'.\n\t    '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'.\n\t    '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'.\n\t    'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'.\n\t    'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'.\n\t    'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'.\n\t    'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'.\n\t    'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: pp_green.png\n//==========================================================\n\t$this->imgdata_small[4][0]= 447 ;\n\t$this->imgdata_small[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.\n\t    'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'.\n\t    'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'.\n\t    'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'.\n\t    'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'.\n\t    'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'.\n\t    'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'.\n\t    'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'.\n\t    'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'.\n\t    'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'.\n\t    'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; \n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_squares.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_SQUARES.INC\n// Description:\tBase64 encoded images for squares\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_squares.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass ImgData_Squares extends ImgData {\n    var $name = 'Squares';\n    var $an = array(MARK_IMG_SQUARE =>'imgdata');\n    \n    var $colors = array('bluegreen','blue','green', \n\t\t\t'lightblue','orange','purple','red','yellow');\n    var $index  = array('bluegreen' =>2,'blue'=>5,'green'=>6, \n\t\t\t'lightblue'=>0,'orange'=>7,'purple'=>4,'red'=>3,'yellow'=>1);\n    var $maxidx = 7 ;\n    var $imgdata ;\n\n    function ImgData_Squares () {\n//==========================================================\n//sq_lblue.png\n//==========================================================\n\t$this->imgdata[0][0]= 362 ;\n\t$this->imgdata[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAIAAADZrBkAAAAABm'.\n\t    'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'.\n\t    'B3RJTUUH0wMLFgojiPx/ygAAAPdJREFUeNpj/P377+kzHx89/c'.\n\t    'VAHNBQ5VBX52HavPWWjg6nnDQbkXoUFTnnL7zD9PPXrz17HxCj'.\n\t    'E6Jn6fL7H7/+ZWJgYCBGJ7IeBgYGJogofp1oehDa8OjE1IOiDa'.\n\t    'tOrHoYGBhY0NwD0enirMDAwMDFxYRVD7ptyDrNTAU0NXix6sGu'.\n\t    'jYGBgZOT9e/f/0xMjFyczFgVsGAKCfBza2kKzpl3hIuT1c9Xb/'.\n\t    'PW58/foKchJqx6tmy98vbjj8cvPm/afMnXW1JShA2fNmQ9EBFc'.\n\t    'Opnw6MGjkwm/Hlw6mQjqwaqTiRg9mDoZv//4M2/+UYJ64EBWgj'.\n\t    'cm2hwA8l24oNDl+DMAAAAASUVORK5CYII=' ; \n\n//==========================================================\n//sq_yellow.png\n//==========================================================\n\t$this->imgdata[1][0]= 338 ;\n\t$this->imgdata[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAWl'.\n\t    'BMVEX////+/+H+/9/9/9v8/8P8/8H8/7v8/7n6/4P5/335/3n5'.\n\t    '/3X4/1f4/1P3/031/w30/wn0/wPt+ADp9ADm8ADk7gDc5gDa5A'.\n\t    'DL1ADFzgCwuACqsgClrABzeAC9M0MzAAAAAWJLR0QAiAUdSAAA'.\n\t    'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEDlOgDj'.\n\t    'EAAAB+SURBVHjaVcpbCsQgDEDRGERGKopjDa2a/W9zfLWj9/Nw'.\n\t    'Ac21ZRBOtZlRN9ApzSYFaDUj79KIorRDbJNO9bN/GUSh2ZRJFJ'.\n\t    'S18iorURBiyksO8buT0zkfYaUqzI91ckfhWhoGXTLzsDjI68Sz'.\n\t    'pGMjrzPzauA/iXk1AtykmvgBC8UcWUdc9HkAAAAASUVORK5CYI'.\n\t    'I=' ; \n\n//==========================================================\n//sq_blgr.png\n//==========================================================\n\t$this->imgdata[2][0]= 347 ;\n\t$this->imgdata[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAZl'.\n\t    'BMVEX////0+vv0+vrz+fry+frv+Png7e/d7e/a6+zY6+250tSz'.\n\t    '0tSyztCtztGM0NWIz9SDzdNfsLVcrrRZrbJOp61MpqtIr7dHn6'.\n\t    'RErrZArLQ6q7M2g4kygYcsp68npa4ctr8QZ20JnqepKsl4AAAA'.\n\t    'AWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU'.\n\t    '1FB9MDCxYEByp8tpUAAAB7SURBVHjaVcjRFoIgDADQWZpWJpjY'.\n\t    'MsnG//9kzIFn3McLzfArDA3MndFjrhvgfDHFBEB9pt0CVzwrY3'.\n\t    'n2yicjhY4vTSp0nbXtN+hCV53SHDWe61dZY+/9463r2XuifHAM'.\n\t    '0SoH+6xEcovUlCfefeFSIwfTTQ3fB+pi4lV/bTIgvmaA7a0AAA'.\n\t    'AASUVORK5CYII=' ; \n\n//==========================================================\n//sq_red.png\n//==========================================================\n\t$this->imgdata[3][0]= 324 ;\n\t$this->imgdata[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'.\n\t    'BMVEX////++Pn99/j99ff99fb98/X98/T98PL55uj43+P24+bw'.\n\t    'kKPvjaHviJ3teJHpxMnoL2Pjs73WW3rWNljVWXnUVnbUK1DTJk'.\n\t    '3SUHPOBz/KQmmxPVmuOFasNFOeIkWVka/fAAAAAWJLR0QAiAUd'.\n\t    'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEHd'.\n\t    'ceT+8AAABtSURBVHjaVchbAkMwEAXQq6i3VrQiQfa/zDYTw8z5'.\n\t    'PCjGt9JVWFt1XWPh1fWNdfDy+tq6WPfRUPENNKnSnXNWPB4uv2'.\n\t    'b54nSZ8jHrMtOxvWZZZtpD4KP6xLkO9/AhzhaCOMhJh68cOjzV'.\n\t    '/K/4Ac2cG+nBcaRuAAAAAElFTkSuQmCC' ; \n\n//==========================================================\n//sq_pink.png\n//==========================================================\n\t$this->imgdata[4][0]= 445 ;\n\t$this->imgdata[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAApV'.\n\t    'BMVEX////6+Pz69/v49Pr38/r17/jr4+/l3Onj2efh1ua/L+i+'.\n\t    'q8m+Lue9Lua8qsS8LuW8LeS7pca5LOG4LN+2Y9O2YNW1ZdO1Kt'.\n\t    'y0atC0aNGzb82zbc6zKtuzKdqycsuwa8qtJtOISZ2GRpuFN6GE'.\n\t    'NqCDQpmCMZ+BPpd/LJ1/K519S5B9Jpx9Jpt9JZt6RY11BJZ1BJ'.\n\t    'V0BJV0BJRzBJNvNoRtIoJUEmdZ/XbrAAAAAWJLR0QAiAUdSAAA'.\n\t    'AAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYDF3iKMD'.\n\t    'YAAACeSURBVHjaVczbEoIgGARgCiMtrexoWpaa2FHUgvd/tH4Y'.\n\t    'BnEvv9ldhNPradPnnGBUTtPDzMRPSIF46SaBoR25dYjz3I20Lb'.\n\t    'ek6BgQz73Il7KKpSgCO0pTHU0886J1sCe0ZYbALjGhjFnEM2es'.\n\t    'VhZVI4d+B1QtfnV47ywCEaKeP/p7JdLejSYt0j6NIiOq1wJZIs'.\n\t    'QTDA0ELHwhPBCwyR/Cni9cOmzJtwAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n//sq_blue.png\n//==========================================================\n\t$this->imgdata[5][0]= 283 ;\n\t$this->imgdata[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAQl'.\n\t    'BMVEX////4+fz39/z19vvy8vru7/ni4+7g4fHW1ue8vteXmt6B'.\n\t    'hdhiZ7FQVaZETcxCSJo1Oq4zNoMjKakhJHcKFaMEC2jRVYdWAA'.\n\t    'AAAWJLR0QAiAUdSAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0'.\n\t    'SU1FB9MDCxYDN0PkEP4AAABfSURBVHjaVchHAoAgDATAVcCCIF'.\n\t    'j4/1elJEjmOFDHKVgDv4iz640gLs+LMF6ZUv/VqcXXplU7Gqpy'.\n\t    'PFzBT5qml9NzlOX259riWHlS4kOffviHD8PQYZx2EFMPRkw+9Q'.\n\t    'FSnRPeWEDzKAAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n//sq_green.png\n//==========================================================\n\t$this->imgdata[6][0]= 325 ;\n\t$this->imgdata[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAXV'.\n\t    'BMVEX////2+vX1+vX1+fT0+fPz+PPx9/Dv9u7u9e3h7uHe697a'.\n\t    '6dnO2s3I1sa10LOvza2ay5aEwYBWlE9TqE5Tkk1RkEpMrUJMg0'.\n\t    'hKiUNGpEFBojw8oTcsbScaYBMWlwmMT0NtAAAAAWJLR0QAiAUd'.\n\t    'SAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEFd'.\n\t    'nFx90AAABuSURBVHjaVc9HAoAgDADB2HuJWLDx/2cKBITscW4L'.\n\t    '5byzMIWtZobNDZIZtrcCGZsRQ8GwvRSRNxIiMuysODKG3alikl'.\n\t    'ueOPlpKTLBaRmOZxQxaXlfb5ZWI9om4WntrXiDSJzp7SBkwMQa'.\n\t    'FEy0VR/NAB2kNuj7rgAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n//sq_orange.png\n//==========================================================\n\t$this->imgdata[7][0]= 321 ;\n\t$this->imgdata[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAAUV'.\n\t    'BMVEX/////8+n/8uf/8OP/59H/5Mv/zqH/zJ3/ypv/yJf/vYH/'.\n\t    'u33/uXn/n0n/nUX/m0H/lzn/ljf/lDP/kS3/kCv/iR//hxv/fg'.\n\t    'n/fAX/eQDYZgDW6ia5AAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAL'.\n\t    'EgAACxIB0t1+/AAAAAd0SU1FB9MDCxYEJIgbx+cAAAB2SURBVH'.\n\t    'jaVczRCoQwDETRbLAWLZSGUA35/w/dVI0283i4DODew3YESmWW'.\n\t    'kg5gWkoQAe6TleUQI/66Sy7i56+kLk7cht2N0+hcnJgQu0SqiC'.\n\t    '1SzSIbzWSi6gavqJ63wSduRi2f+kwyD5rEukwCdZ1kGAMGMfv9'.\n\t    'AbWuGMOr5COSAAAAAElFTkSuQmCC' ; \n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/imgdata_stars.inc",
    "content": "<?php\n//=======================================================================\n// File:\tIMGDATA_STARS.INC\n// Description:\tBase64 encoded images for stars\n// Created: \t2003-03-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: imgdata_stars.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n\nclass ImgData_Stars extends ImgData {\n    var $name = 'Stars';\n    var $an = array(MARK_IMG_STAR => 'imgdata');\n\n    var $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow');\n    var $index  = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, \n\t\t\t'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6);\n    var $maxidx = 7 ;\n    var $imgdata ;\n\n    function ImgData_Stars() {\n//==========================================================\n// File: bstar_green_001.png\n//==========================================================\n\t$this->imgdata[0][0]= 329 ;\n\t$this->imgdata[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'.\n\t    'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'.\n\t    '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'.\n\t    'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'.\n\t    'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'.\n\t    'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'.\n\t    'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'.\n\t    'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'.\n\t    'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; \n//==========================================================\n// File: bstar_blred.png\n//==========================================================\n\t$this->imgdata[1][0]= 325 ;\n\t$this->imgdata[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'.\n\t    'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'.\n\t    'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'.\n\t    'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_red_001.png\n//==========================================================\n\t$this->imgdata[2][0]= 325 ;\n\t$this->imgdata[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'.\n\t    'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'.\n\t    'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'.\n\t    'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_blgr_001.png\n//==========================================================\n\t$this->imgdata[3][0]= 325 ;\n\t$this->imgdata[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'.\n\t    'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'.\n\t    'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'.\n\t    'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_blgr_002.png\n//==========================================================\n\t$this->imgdata[4][0]= 325 ;\n\t$this->imgdata[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'.\n\t    'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'.\n\t    'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'.\n\t    'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_blue_001.png\n//==========================================================\n\t$this->imgdata[5][0]= 325 ;\n\t$this->imgdata[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'.\n\t    'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'.\n\t    'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'.\n\t    'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_oy_007.png\n//==========================================================\n\t$this->imgdata[6][0]= 325 ;\n\t$this->imgdata[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'.\n\t    'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'.\n\t    'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'.\n\t    'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n\n//==========================================================\n// File: bstar_lred.png\n//==========================================================\n\t$this->imgdata[7][0]= 325 ;\n\t$this->imgdata[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'.\n\t    'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'.\n\t    'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'.\n\t    'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'.\n\t    'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'.\n\t    'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'.\n\t    'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'.\n\t    'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'.\n\t    'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; \n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpg-config.inc",
    "content": "<?php\n//=======================================================================\n// File:\tJPG-CONFIG.INC\n// Description:\tConfiguration file for JpGraph library\n// Created: \t2004-03-27\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpg-config.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n\n\n//------------------------------------------------------------------------\n// Directories for cache and font directory. \n//\n// CACHE_DIR:\n// The full absolute name of the directory to be used to store the\n// cached image files. This directory will not be used if the USE_CACHE\n// define (further down) is false. If you enable the cache please note that\n// this directory MUST be readable and writable for the process running PHP.\n// Must end with '/'\n//\n// TTF_DIR:\n// Directory where TTF fonts can be found. Must end with '/'\n//\n// The default values used if these defines are left commented out are:\n//\n// UNIX:\n//   CACHE_DIR /tmp/jpgraph_cache/\n//   TTF_DIR   /usr/X11R6/lib/X11/fonts/truetype/\n//   MBTTF_DIR /usr/share/fonts/ja/TrueType/\n//\n// WINDOWS:\n//   CACHE_DIR $SERVER_TEMP/jpgraph_cache/\n//   TTF_DIR   $SERVER_SYSTEMROOT/fonts/\n//   MBTTF_DIR $SERVER_SYSTEMROOT/fonts/\n//\n//------------------------------------------------------------------------\n// DEFINE(\"CACHE_DIR\",\"/tmp/jpgraph_cache/\");\n// DEFINE(\"TTF_DIR\",\"/usr/X11R6/lib/X11/fonts/truetype/\");\n// DEFINE(\"MBTTF_DIR\",\"/usr/share/fonts/ja/TrueType/\");\n\n//-------------------------------------------------------------------------\n// Cache directory specification for use with CSIM graphs that are\n// using the cache.\n// The directory must be the filesysystem name as seen by PHP\n// and the 'http' version must be the same directory but as \n// seen by the HTTP server relative to the 'htdocs' ddirectory. \n// If a relative path is specified it is taken to be relative from where\n// the image script is executed.\n// Note: The default setting is to create a subdirectory in the \n// directory from where the image script is executed and store all files\n// there. As ususal this directory must be writeable by the PHP process.\nDEFINE(\"CSIMCACHE_DIR\",\"csimcache/\"); \nDEFINE(\"CSIMCACHE_HTTP_DIR\",\"csimcache/\");\n\n//------------------------------------------------------------------------\n// Defines for font setup\n//------------------------------------------------------------------------\n\n// Actual name of the TTF file used together with FF_CHINESE aka FF_BIG5\n// This is the TTF file being used when the font family is specified as\n// either FF_CHINESE or FF_BIG5\nDEFINE('CHINESE_TTF_FONT','bkai00mp.ttf');\n\n// Special unicode cyrillic language support\nDEFINE(\"LANGUAGE_CYRILLIC\",false);\n\n// If you are setting this config to true the conversion\n// will assume that the input text is windows 1251, if\n// false it will assume koi8-r\nDEFINE(\"CYRILLIC_FROM_WINDOWS\",false);\n\n// Japanese TrueType font used with FF_MINCHO, FF_PMINCHO, FF_GOTHIC, FF_PGOTHIC\nDEFINE('MINCHO_TTF_FONT','ipam.ttf');\nDEFINE('PMINCHO_TTF_FONT','ipamp.ttf');\nDEFINE('GOTHIC_TTF_FONT','ipag.ttf');\nDEFINE('PGOTHIC_TTF_FONT','ipagp.ttf');\n\n//------------------------------------------------------------------------\n// Various JpGraph Settings. Adjust accordingly to your\n// preferences. Note that cache functionality is turned off by\n// default (Enable by setting USE_CACHE to true)\n//------------------------------------------------------------------------\n\n// Deafult graphic format set to \"auto\" which will automatically\n// choose the best available format in the order png,gif,jpeg\n// (The supported format depends on what your PHP installation supports)\nDEFINE(\"DEFAULT_GFORMAT\",\"auto\");\n\n// Should the image be a truecolor image? \n// Note 1: Has only effect with GD 2.0.1 and above.\n// Note 2: GD 2.0.1 + PHP 4.0.6 on Win32 crashes when trying to use \n// trucolor.\n// Note 3: MUST be enabled to get background images working with GD2\nDEFINE('USE_TRUECOLOR',true);\n\n// Specify what version of the GD library is installed.\n// If this is set to 'auto' the version will be automatically \n// determined.\n// However since determining the library takes ~1ms you can also \n// manually specify the version if you know what version you have. \n// This means that you should \n// set this define to true if you have GD 2.x installed to save 1ms. \nDEFINE(\"USE_LIBRARY_GD2\",'auto');\n\n// Should the cache be used at all? By setting this to false no\n// files will be generated in the cache directory.  \n// The difference from READ_CACHE being that setting READ_CACHE to\n// false will still create the image in the cache directory\n// just not use it. By setting USE_CACHE=false no files will even\n// be generated in the cache directory.\nDEFINE(\"USE_CACHE\",false);\n\n// Should we try to find an image in the cache before generating it? \n// Set this define to false to bypass the reading of the cache and always\n// regenerate the image. Note that even if reading the cache is \n// disabled the cached will still be updated with the newly generated\n// image. Set also \"USE_CACHE\" below.\nDEFINE(\"READ_CACHE\",true);\n\n// Determine if the error handler should be image based or purely\n// text based. Image based makes it easier since the script will\n// always return an image even in case of errors.\nDEFINE(\"USE_IMAGE_ERROR_HANDLER\",true);\n\n// Determine if the library should also setup the default PHP\n// error handler to generate a graphic error mesage. This is useful\n// during development to be able to see the error message as an image\n// instead as a \"red-cross\" in a page where an image is expected.\nDEFINE(\"INSTALL_PHP_ERR_HANDLER\",false);\n\n// Should the library examin the global php_errmsg string and convert\n// any error in it to a graphical representation. This is handy for the\n// occasions when, for example, header files cannot be found and this results\n// in the graph not being created and just a \"red-cross\" image would be seen.\n// This should be turned off for a production site.\nDEFINE(\"CATCH_PHPERRMSG\",true);\n\n// If the color palette is full should JpGraph try to allocate\n// the closest match? If you plan on using background images or\n// gradient fills it might be a good idea to enable this.\n// If not you will otherwise get an error saying that the color palette is \n// exhausted. The drawback of using approximations is that the colors \n// might not be exactly what you specified. \n// Note1: This does only apply to paletted images, not truecolor \n// images since they don't have the limitations of maximum number\n// of colors.\nDEFINE(\"USE_APPROX_COLORS\",true);\n\n// Should usage of deprecated functions and parameters give a fatal error?\n// (Useful to check if code is future proof.)\nDEFINE(\"ERR_DEPRECATED\",true);\n\n// Should the time taken to generate each picture be branded to the lower\n// left in corner in each generated image? Useful for performace measurements\n// generating graphs\nDEFINE(\"BRAND_TIMING\",false);\n\n// What format should be used for the timing string?\nDEFINE(\"BRAND_TIME_FORMAT\",\"(%01.3fs)\");\n\n//------------------------------------------------------------------------\n// The following constants should rarely have to be changed !\n//------------------------------------------------------------------------\n\n// What group should the cached file belong to\n// (Set to \"\" will give the default group for the \"PHP-user\")\n// Please note that the Apache user must be a member of the\n// specified group since otherwise it is impossible for Apache\n// to set the specified group.\nDEFINE(\"CACHE_FILE_GROUP\",\"wwwadmin\");\n\n// What permissions should the cached file have\n// (Set to \"\" will give the default persmissions for the \"PHP-user\")\nDEFINE(\"CACHE_FILE_MOD\",0664);\n\n// Decide if we should use the bresenham circle algorithm or the\n// built in Arc(). Bresenham gives better visual apperance of circles \n// but is more CPU intensive and slower then the built in Arc() function\n// in GD. Turned off by default for speed\nDEFINE(\"USE_BRESENHAM\",false);\n\n// Special file name to indicate that we only want to calc\n// the image map in the call to Graph::Stroke() used\n// internally from the GetHTMLCSIM() method.\nDEFINE(\"_CSIM_SPECIALFILE\",\"_csim_special_\");\n\n// HTTP GET argument that is used with image map\n// to indicate to the script to just generate the image\n// and not the full CSIM HTML page.\nDEFINE(\"_CSIM_DISPLAY\",\"_jpg_csimd\");\n\n// Special filename for Graph::Stroke(). If this filename is given\n// then the image will NOT be streamed to browser of file. Instead the\n// Stroke call will return the handler for the created GD image.\nDEFINE(\"_IMG_HANDLER\",\"__handle\");\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH.PHP\n// Description:\tPHP Graph Plotting library. Base module.\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nrequire_once('jpg-config.inc');\n\n// Version info\nDEFINE('JPG_VERSION','1.20.3');\n\n// For internal use only\nDEFINE(\"_JPG_DEBUG\",false);\nDEFINE(\"_FORCE_IMGTOFILE\",false);\nDEFINE(\"_FORCE_IMGDIR\",'/tmp/jpgimg/');\n\n\n//------------------------------------------------------------------------\n// Automatic settings of path for cache and font directory\n// if they have not been previously specified\n//------------------------------------------------------------------------\nif(USE_CACHE) {\n    if (!defined('CACHE_DIR')) {\n\tif ( strstr( PHP_OS, 'WIN') ) {\n\t    if( empty($_SERVER['TEMP']) ) {\n\t\t$t = new ErrMsgText();\n\t\t$msg = $t->Get(11,$file,$lineno);\n\t\tdie($msg);\n\t    }\n\t    else {\n\t\tDEFINE('CACHE_DIR', $_SERVER['TEMP'] . '/');\n\t    }\n\t} else {\n\t    DEFINE('CACHE_DIR','/tmp/jpgraph_cache/');\n\t}\n    }\n}\nelseif( !defined('CACHE_DIR') ) {\n    DEFINE('CACHE_DIR', '');\n}\n\nif (!defined('TTF_DIR')) {\n    if (strstr( PHP_OS, 'WIN') ) {\n\t$sroot = getenv('SystemRoot');\n        if( empty($sroot) ) {\n\t    $t = new ErrMsgText();\n\t    $msg = $t->Get(12,$file,$lineno);\n\t    die($msg);\n        }\n\telse {\n\t  DEFINE('TTF_DIR', $sroot.'/fonts/');\n        }\n    } else {\n\tDEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/');\n    }\n}\n\n//------------------------------------------------------------------\n// Constants which are used as parameters for the method calls\n//------------------------------------------------------------------\n\n// TTF Font families\nDEFINE(\"FF_COURIER\",10);\nDEFINE(\"FF_VERDANA\",11);\nDEFINE(\"FF_TIMES\",12);\nDEFINE(\"FF_COMIC\",14);\nDEFINE(\"FF_ARIAL\",15);\nDEFINE(\"FF_GEORGIA\",16);\nDEFINE(\"FF_TREBUCHE\",17);\n\n// Gnome Vera font\n// Available from http://www.gnome.org/fonts/\nDEFINE(\"FF_VERA\",19);\nDEFINE(\"FF_VERAMONO\",20);\nDEFINE(\"FF_VERASERIF\",21);\n\n// Chinese font\nDEFINE(\"FF_SIMSUN\",30);\nDEFINE(\"FF_CHINESE\",31);\nDEFINE(\"FF_BIG5\",31);\n\n// Japanese font\nDEFINE(\"FF_MINCHO\",40);\nDEFINE(\"FF_PMINCHO\",41);\nDEFINE(\"FF_GOTHIC\",42);\nDEFINE(\"FF_PGOTHIC\",43);\n\n// Limits for TTF fonts\nDEFINE('_FF_FIRST',10);\nDEFINE('_FF_LAST',43);\n\n// Older deprecated fonts \nDEFINE(\"FF_BOOK\",91);    // Deprecated fonts from 1.9\nDEFINE(\"FF_HANDWRT\",92); // Deprecated fonts from 1.9\n\n// TTF Font styles\nDEFINE(\"FS_NORMAL\",9001);\nDEFINE(\"FS_BOLD\",9002);\nDEFINE(\"FS_ITALIC\",9003);\nDEFINE(\"FS_BOLDIT\",9004);\nDEFINE(\"FS_BOLDITALIC\",9004);\n\n//Definitions for internal font, new style\nDEFINE(\"FF_FONT0\",1);\nDEFINE(\"FF_FONT1\",2);\nDEFINE(\"FF_FONT2\",4);\n\n// Tick density\nDEFINE(\"TICKD_DENSE\",1);\nDEFINE(\"TICKD_NORMAL\",2);\nDEFINE(\"TICKD_SPARSE\",3);\nDEFINE(\"TICKD_VERYSPARSE\",4);\n\n// Side for ticks and labels. \nDEFINE(\"SIDE_LEFT\",-1);\nDEFINE(\"SIDE_RIGHT\",1);\nDEFINE(\"SIDE_DOWN\",-1);\nDEFINE(\"SIDE_BOTTOM\",-1);\nDEFINE(\"SIDE_UP\",1);\nDEFINE(\"SIDE_TOP\",1);\n\n// Legend type stacked vertical or horizontal\nDEFINE(\"LEGEND_VERT\",0);\nDEFINE(\"LEGEND_HOR\",1);\n\n// Mark types for plot marks\nDEFINE(\"MARK_SQUARE\",1);\nDEFINE(\"MARK_UTRIANGLE\",2);\nDEFINE(\"MARK_DTRIANGLE\",3);\nDEFINE(\"MARK_DIAMOND\",4);\nDEFINE(\"MARK_CIRCLE\",5);\nDEFINE(\"MARK_FILLEDCIRCLE\",6);\nDEFINE(\"MARK_CROSS\",7);\nDEFINE(\"MARK_STAR\",8);\nDEFINE(\"MARK_X\",9);\nDEFINE(\"MARK_LEFTTRIANGLE\",10);\nDEFINE(\"MARK_RIGHTTRIANGLE\",11);\nDEFINE(\"MARK_FLASH\",12);\nDEFINE(\"MARK_IMG\",13);\nDEFINE(\"MARK_FLAG1\",14);\nDEFINE(\"MARK_FLAG2\",15);\nDEFINE(\"MARK_FLAG3\",16);\nDEFINE(\"MARK_FLAG4\",17);\n\n// Builtin images\nDEFINE(\"MARK_IMG_PUSHPIN\",50);\nDEFINE(\"MARK_IMG_SPUSHPIN\",50);\nDEFINE(\"MARK_IMG_LPUSHPIN\",51);\nDEFINE(\"MARK_IMG_DIAMOND\",52);\nDEFINE(\"MARK_IMG_SQUARE\",53);\nDEFINE(\"MARK_IMG_STAR\",54);\nDEFINE(\"MARK_IMG_BALL\",55);\nDEFINE(\"MARK_IMG_SBALL\",55);\nDEFINE(\"MARK_IMG_MBALL\",56);\nDEFINE(\"MARK_IMG_LBALL\",57);\nDEFINE(\"MARK_IMG_BEVEL\",58);\n\n// Inline defines\nDEFINE(\"INLINE_YES\",1);\nDEFINE(\"INLINE_NO\",0);\n\n// Format for background images\nDEFINE(\"BGIMG_FILLPLOT\",1);\nDEFINE(\"BGIMG_FILLFRAME\",2);\nDEFINE(\"BGIMG_COPY\",3);\nDEFINE(\"BGIMG_CENTER\",4);\n\n// Depth of objects\nDEFINE(\"DEPTH_BACK\",0);\nDEFINE(\"DEPTH_FRONT\",1);\n\n// Direction\nDEFINE(\"VERTICAL\",1);\nDEFINE(\"HORIZONTAL\",0);\n\n\n// Axis styles for scientific style axis\nDEFINE('AXSTYLE_SIMPLE',1);\nDEFINE('AXSTYLE_BOXIN',2);\nDEFINE('AXSTYLE_BOXOUT',3);\nDEFINE('AXSTYLE_YBOXIN',4);\nDEFINE('AXSTYLE_YBOXOUT',5);\n\n// Style for title backgrounds\nDEFINE('TITLEBKG_STYLE1',1);\nDEFINE('TITLEBKG_STYLE2',2);\nDEFINE('TITLEBKG_STYLE3',3);\nDEFINE('TITLEBKG_FRAME_NONE',0);\nDEFINE('TITLEBKG_FRAME_FULL',1);\nDEFINE('TITLEBKG_FRAME_BOTTOM',2);\nDEFINE('TITLEBKG_FRAME_BEVEL',3);\nDEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1);\nDEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2);\nDEFINE('TITLEBKG_FILLSTYLE_SOLID',3);\n\n// Style for background gradient fills\nDEFINE('BGRAD_FRAME',1);\nDEFINE('BGRAD_MARGIN',2);\nDEFINE('BGRAD_PLOT',3);\n\n// Width of tab titles\nDEFINE('TABTITLE_WIDTHFIT',0);\nDEFINE('TABTITLE_WIDTHFULL',-1);\n\n// Defines for 3D skew directions\nDEFINE('SKEW3D_UP',0);\nDEFINE('SKEW3D_DOWN',1);\nDEFINE('SKEW3D_LEFT',2);\nDEFINE('SKEW3D_RIGHT',3);\n\n\n\n//\n// Get hold of gradient class (In Version 2.x)\n// A client of the library has to manually include this\n//\nrequire_once 'jpgraph_gradient.php';\n\n\nclass ErrMsgText {\n    var $lt=NULL;\n    var $supportedLocales = array('en');\n    function ErrMsgText() {\n\tGLOBAL $__jpg_err_locale;\n\tif( !in_array($__jpg_err_locale,$this->supportedLocales) )\n\t    $aLoc = 'en';\n\trequire_once('lang/'.$__jpg_err_locale.'.inc.php');\n\t$this->lt = $_jpg_messages;\n    }\n\n    function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {\n\tif( !isset($this->lt[$errnbr]) ) {\n\t    return 'Internal error: The specified error message does not exist in the chosen locale. (Please blame the translator...))';\n\t}\n\t$ea = $this->lt[$errnbr];\n\t$j=0;\n\tif( $a1 !== null ) {\n\t    $argv[$j++] = $a1;\n\t    if( $a2 !== null ) {\n\t\t$argv[$j++] = $a2;\n\t\tif( $a3 !== null ) {\n\t\t    $argv[$j++] = $a3;\n\t\t    if( $a4 !== null ) {\n\t\t\t$argv[$j++] = $a4;\n\t\t\tif( $a5 !== null ) {\n\t\t\t    $argv[$j++] = $a5;\n\t\t\t}\n\t\t    }\n\t\t}\n\t    }\n\t}\n\t$numargs = $j; \n\tif( $ea[1] != $numargs ) {\n\t    // Error message argument count do not match.\n\t    // Just return the error message without arguments.\n\t    return $ea[0];\n\t}\n\tswitch( $numargs ) {\n\t    case 1:\n\t\t$msg = sprintf($ea[0],$argv[0]);\n\t\tbreak;\n\t    case 2:\n\t\t$msg = sprintf($ea[0],$argv[0],$argv[1]);\n\t\tbreak;\n\t    case 3:\n\t\t$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]);\n\t\tbreak;\n\t    case 4:\n\t\t$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]);\n\t\tbreak;\n\t    case 5:\n\t\t$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]);\n\t\tbreak;\n\t    case 0:\n\t    default:\n\t\t$msg = sprintf($ea[0]);\n\t\tbreak;\n\t}\n\treturn $msg;\n    }\n}\n\n//\n// A wrapper class that is used to access the specified error object\n// (to hide the global error parameter and avoid having a GLOBAL directive\n// in all methods.\n//\nGLOBAL $__jpg_err;\nGLOBAL $__jpg_err_locale ;\n$__jpg_err_locale = 'en';\nclass JpGraphError {\n    function Install($aErrObject) {\n\tGLOBAL $__jpg_err;\n\t$__jpg_err = $aErrObject;\n    }\n    function Raise($aMsg,$aHalt=true){\n\tGLOBAL $__jpg_err;\n\t$tmp = new $__jpg_err;\n\t$tmp->Raise($aMsg,$aHalt);\n    }\n    function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {\n\tGLOBAL $__jpg_err;\n\t$t = new ErrMsgText();\n\t$msg = $t->Get($errnbr,$a1,$a2,$a3,$a4,$a5);\n\t$tmp = new $__jpg_err;\n\t$tmp->Raise($msg);\n    }\n}\n \n//\n// ... and install the default error handler\n//\nif( USE_IMAGE_ERROR_HANDLER ) {\n    $__jpg_err = \"JpGraphErrObjectImg\";\n}\nelse {\n    $__jpg_err = \"JpGraphErrObject\"; \n}\n\n//\n// Make GD sanity check\n//\nif( !function_exists(\"imagetypes\") || !function_exists('imagecreatefromstring') ) {\n    JpGraphError::RaiseL(25001);\n//(\"This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)\");\n}\n\n//\n// Routine to determine if GD1 or GD2 is installed\n//\nfunction CheckGDVersion() {\n    $GDfuncList = get_extension_funcs('gd');\n    if( !$GDfuncList ) return 0 ;\n    else {\n\tif( in_array('imagegd2',$GDfuncList) && \n\t    in_array('imagecreatetruecolor',$GDfuncList))\n\t    return 2;\n\telse\n\t    return 1;\n    } \n}\n\n//\n// Check what version of the GD library is installed.\n//\n$GLOBALS['gd2'] = false;\nif( USE_LIBRARY_GD2 === 'auto' ) {\n    $gdversion = CheckGDVersion();\n    if( $gdversion == 2 ) {\n\t$GLOBALS['gd2'] = true;\n\t$GLOBALS['copyfunc'] = 'imagecopyresampled';\n    }\n    elseif( $gdversion == 1 ) {\n\t$GLOBALS['gd2'] = false;\n\t$GLOBALS['copyfunc'] = 'imagecopyresized';\n    }\n    else {\n\tJpGraphError::RaiseL(25002);\n//(\" Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.\");\n    }\n}\nelse {\n    $GLOBALS['gd2'] = USE_LIBRARY_GD2;\n    $GLOBALS['copyfunc'] = USE_LIBRARY_GD2 ? 'imagecopyresampled' : 'imagecopyresized';\n}\n\n\n//\n// First of all set up a default error handler\n//\n\n\n//=============================================================\n// The default trivial text error handler.\n//=============================================================\nclass JpGraphErrObject {\n\n    var $iTitle = \"JpGraph Error\";\n    var $iDest = false;\n\n    function JpGraphErrObject() {\n\t// Empty. Reserved for future use\n    }\n\n    function SetTitle($aTitle) {\n\t$this->iTitle = $aTitle;\n    }\n\n    function SetStrokeDest($aDest) { \n\t$this->iDest = $aDest; \n    }\n\n    // If aHalt is true then execution can't continue. Typical used for fatal errors.\n    function Raise($aMsg,$aHalt=true) {\n\t$aMsg = $this->iTitle.' '.$aMsg;\n\tif ($this->iDest) {\n\t    $f = @fopen($this->iDest,'a');\n\t    if( $f ) {\n\t\t@fwrite($f,$aMsg);\n\t\t@fclose($f);\n\t    }\n\t}\n\telse {\n\t    echo $aMsg;\n\t}\n\tif( $aHalt )\n\t    die();\n    }\n}\n\n//==============================================================\n// An image based error handler\n//==============================================================\nclass JpGraphErrObjectImg extends JpGraphErrObject {\n\n    function Raise($aMsg,$aHalt=true) {\n\t$img_iconerror = \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'.\n\t    'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.\n\t    'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'.\n\t    'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.\n\t    'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.\n\t    'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'.\n\t    '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'.\n\t    'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'.\n\t    'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'.\n\t    'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'.\n\t    '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'.\n\t    'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'.\n\t    'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'.\n\t    'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'.\n\t    'qL72fwAAAABJRU5ErkJggg==' ;\n\n\tif( function_exists(\"imagetypes\") )\n\t    $supported = imagetypes();\n\telse\n\t    $supported = 0;\n\n\tif( !function_exists('imagecreatefromstring') )\n\t    $supported = 0;\n\n\tif( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) {\n\t    // Special case for headers already sent or that the installation doesn't support\n\t    // the PNG format (which the error icon is encoded in). \n\t    // Dont return an image since it can't be displayed\n\t    die($this->iTitle.' '.$aMsg);\t\t\n\t}\n\n\t$aMsg = wordwrap($aMsg,55);\n\t$lines = substr_count($aMsg,\"\\n\");\n\n\t// Create the error icon GD\n\t$erricon = Image::CreateFromString(base64_decode($img_iconerror));   \n\n\t// Create an image that contains the error text.\n\t$w=400; \t\n\t$h=100 + 15*max(0,$lines-3);\n\n\t$img = new Image($w,$h);\n\n\t// Drop shadow\n\t$img->SetColor(\"gray\");\n\t$img->FilledRectangle(5,5,$w-1,$h-1,10);\n\t$img->SetColor(\"gray:0.7\");\n\t$img->FilledRectangle(5,5,$w-3,$h-3,10);\n\t\n\t// Window background\n\t$img->SetColor(\"lightblue\");\n\t$img->FilledRectangle(1,1,$w-5,$h-5);\n\t$img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40);\n\n\t// Window border\n\t$img->SetColor(\"black\");\n\t$img->Rectangle(1,1,$w-5,$h-5);\n\t$img->Rectangle(0,0,$w-4,$h-4);\n\t\n\t// Window top row\n\t$img->SetColor(\"darkred\");\n\tfor($y=3; $y < 18; $y += 2 ) \n\t    $img->Line(1,$y,$w-6,$y);\n\n\t// \"White shadow\"\n\t$img->SetColor(\"white\");\n\n\t// Left window edge\n\t$img->Line(2,2,2,$h-5);\n\t$img->Line(2,2,$w-6,2);\n\n\t// \"Gray button shadow\"\n\t$img->SetColor(\"darkgray\");\n\n\t// Gray window shadow\n\t$img->Line(2,$h-6,$w-5,$h-6);\n\t$img->Line(3,$h-7,$w-5,$h-7);\n\n\t// Window title\n\t$m = floor($w/2-5);\n\t$l = 100;\n\t$img->SetColor(\"lightgray:1.3\");\n\t$img->FilledRectangle($m-$l,2,$m+$l,16);\n\n\t// Stroke text\n\t$img->SetColor(\"darkred\");\n\t$img->SetFont(FF_FONT2,FS_BOLD);\n\t$img->StrokeText($m-50,15,$this->iTitle);\n\t$img->SetColor(\"black\");\n\t$img->SetFont(FF_FONT1,FS_NORMAL);\n\t$txt = new Text($aMsg,52,25);\n\t$txt->Align(\"left\",\"top\");\n\t$txt->Stroke($img);\n\tif ($this->iDest) {\n           $img->Stream($this->iDest);\n\t} else {\n\t    $img->Headers();\n\t    $img->Stream();\n\t}\n\tif( $aHalt )\n\t    die();\n    }\n}\n\n//\n// Setup PHP error handler\n//\nfunction _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) {\n    // Respect current error level\n    if( $errno & error_reporting() ) {\n\tJpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); \n    }\n}\n\nif( INSTALL_PHP_ERR_HANDLER ) {\n    set_error_handler(\"_phpErrorHandler\");\n}\n\n//\n//Check if there were any warnings, perhaps some wrong includes by the user\n//\nif( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && \n    !preg_match('|Deprecated|', $GLOBALS['php_errormsg'])) {\n    JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']);\n}\n\n\n// Useful mathematical function\nfunction sign($a) {return $a >= 0 ? 1 : -1;}\n\n// Utility function to generate an image name based on the filename we\n// are running from and assuming we use auto detection of graphic format\n// (top level), i.e it is safe to call this function\n// from a script that uses JpGraph\nfunction GenImgName() {\n    global $_SERVER;\n\n    // Determine what format we should use when we save the images\n    $supported = imagetypes();\n    if( $supported & IMG_PNG )\t   $img_format=\"png\";\n    elseif( $supported & IMG_GIF ) $img_format=\"gif\";\n    elseif( $supported & IMG_JPG ) $img_format=\"jpeg\";\n\n    if( !isset($_SERVER['PHP_SELF']) )\n\tJpGraphError::RaiseL(25005);\n//(\" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files.\");\n    $fname = basename($_SERVER['PHP_SELF']);\n    if( !empty($_SERVER['QUERY_STRING']) ) {\n\t$q = @$_SERVER['QUERY_STRING'];\n\t$fname .= '?'.preg_replace(\"/\\W/\", \"_\", $q).'.'.$img_format;\n    }\n    else {\n\t$fname = substr($fname,0,strlen($fname)-4).'.'.$img_format;\n    }\n    return $fname;\n}\n\nclass LanguageConv {\n    var $g2312 = null ;\n\n    function Convert($aTxt,$aFF) {\n\tif( LANGUAGE_CYRILLIC ) {\n\t    if( CYRILLIC_FROM_WINDOWS ) {\n\t\t$aTxt = convert_cyr_string($aTxt, \"w\", \"k\"); \n\t    }\n\t    $isostring = convert_cyr_string($aTxt, \"k\", \"i\");\n\t    $unistring = LanguageConv::iso2uni($isostring);\n\t    return $unistring;\n\t}\n\telseif( $aFF === FF_SIMSUN ) {\n\t    // Do Chinese conversion\n\t    if( $this->g2312 == null ) {\n\t\tinclude_once 'jpgraph_gb2312.php' ;\n\t\t$this->g2312 = new GB2312toUTF8();\n\t    }\n\t    return $this->g2312->gb2utf8($aTxt);\n\t}\n\telseif( $aFF === FF_CHINESE ) {\n\t    if( !function_exists('iconv') ) {\n\t\tJpGraphError::RaiseL(25006);\n//('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the \"--width-iconv\" when configured).');\n\t    }\n\t    return iconv('BIG5','UTF-8',$aTxt);\n\t}\n\telse \n\t    return $aTxt;\n    }\n\n    // Translate iso encoding to unicode\n    function iso2uni ($isoline){\n\t$uniline='';\n\tfor ($i=0; $i < strlen($isoline); $i++){\n\t    $thischar=substr($isoline,$i,1);\n\t    $charcode=ord($thischar);\n\t    $uniline.=($charcode>175) ? \"&#\" . (1040+($charcode-176)). \";\" : $thischar;\n\t}\n\treturn $uniline;\n    }\n}\n\n//===================================================\n// CLASS JpgTimer\n// Description: General timing utility class to handle\n// time measurement of generating graphs. Multiple\n// timers can be started.\n//===================================================\nclass JpgTimer {\n    var $start;\n    var $idx;\t\n//---------------\n// CONSTRUCTOR\n    function JpgTimer() {\n\t$this->idx=0;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    // Push a new timer start on stack\n    function Push() {\n\tlist($ms,$s)=explode(\" \",microtime());\t\n\t$this->start[$this->idx++]=floor($ms*1000) + 1000*$s;\t\n    }\n\n    // Pop the latest timer start and return the diff with the\n    // current time\n    function Pop() {\n\tassert($this->idx>0);\n\tlist($ms,$s)=explode(\" \",microtime());\t\n\t$etime=floor($ms*1000) + (1000*$s);\n\t$this->idx--;\n\treturn $etime-$this->start[$this->idx];\n    }\n} // Class\n\n$gJpgBrandTiming = BRAND_TIMING;\n//===================================================\n// CLASS DateLocale\n// Description: Hold localized text used in dates\n//===================================================\nclass DateLocale {\n \n    var $iLocale = 'C'; // environmental locale be used by default\n\n    var $iDayAbb = null;\n    var $iShortDay = null;\n    var $iShortMonth = null;\n    var $iMonthName = null;\n\n//---------------\n// CONSTRUCTOR\t\n    function DateLocale() {\n\tsettype($this->iDayAbb, 'array');\n\tsettype($this->iShortDay, 'array');\n\tsettype($this->iShortMonth, 'array');\n\tsettype($this->iMonthName, 'array');\n\n\n\t$this->Set('C');\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Set($aLocale) {\n\tif ( in_array($aLocale, array_keys($this->iDayAbb)) ){ \n\t    $this->iLocale = $aLocale;\n\t    return TRUE;  // already cached nothing else to do!\n\t}\n\n\t$pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME\n\t$res = @setlocale(LC_TIME, $aLocale);\n\tif ( ! $res ){\n\t    JpGraphError::RaiseL(25007,$aLocale);\n//(\"You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.\");\n\t    return FALSE;\n\t}\n \n\t$this->iLocale = $aLocale;\n\n\tfor ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){\n\t    $day = strftime('%a', strtotime(\"$ofs day\"));\n\t    $day{0} = strtoupper($day{0});\n\t    $this->iDayAbb[$aLocale][]= $day{0};\n\t    $this->iShortDay[$aLocale][]= $day;\n\t}\n\n\tfor($i=1; $i<=12; ++$i) {\n\t    list($short ,$full) = explode('|', strftime(\"%b|%B\",strtotime(\"2001-$i-01\")));\n\t    $this->iShortMonth[$aLocale][] = ucfirst($short);\n\t    $this->iMonthName [$aLocale][] = ucfirst($full);\n\t}\n\n\t// Return to original locale\n\tsetlocale(LC_TIME, $pLocale);\n\n\treturn TRUE;\n    }\n\n\n    function GetDayAbb() {\n\treturn $this->iDayAbb[$this->iLocale];\n    }\n\t\n    function GetShortDay() {\n\treturn $this->iShortDay[$this->iLocale];\n    }\n\n    function GetShortMonth() {\n\treturn $this->iShortMonth[$this->iLocale];\n    }\n\t\n    function GetShortMonthName($aNbr) {\n\treturn $this->iShortMonth[$this->iLocale][$aNbr];\n    }\n\n    function GetLongMonthName($aNbr) {\n\treturn $this->iMonthName[$this->iLocale][$aNbr];\n    }\n\n    function GetMonth() {\n\treturn $this->iMonthName[$this->iLocale];\n    }\n}\n\n$gDateLocale = new DateLocale();\n$gJpgDateLocale = new DateLocale();\n\n\n//=======================================================\n// CLASS Footer\n// Description: Encapsulates the footer line in the Graph\n//=======================================================\nclass Footer {\n    var $left,$center,$right;\n    var $iLeftMargin = 3;\n    var $iRightMargin = 3;\n    var $iBottomMargin = 3;\n\n    function Footer() {\n\t$this->left = new Text();\n\t$this->left->ParagraphAlign('left');\n\t$this->center = new Text();\n\t$this->center->ParagraphAlign('center');\n\t$this->right = new Text();\n\t$this->right->ParagraphAlign('right');\n    }\n\n    function Stroke(&$aImg) {\n\t$y = $aImg->height - $this->iBottomMargin;\n\t$x = $this->iLeftMargin;\n\t$this->left->Align('left','bottom');\n\t$this->left->Stroke($aImg,$x,$y);\n\n\t$x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;\n\t$this->center->Align('center','bottom');\n\t$this->center->Stroke($aImg,$x,$y);\n\n\t$x = $aImg->width - $this->iRightMargin;\n\t$this->right->Align('right','bottom');\n\t$this->right->Stroke($aImg,$x,$y);\n    }\n}\n\n\n//===================================================\n// CLASS Graph\n// Description: Main class to handle graphs\n//===================================================\nclass Graph {\n    var $cache=null;\t\t// Cache object (singleton)\n    var $img=null;\t\t\t// Img object (singleton)\n    var $plots=array();\t// Array of all plot object in the graph (for Y 1 axis)\n    var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis)\n    var $ynplots=array();\n    var $xscale=null;\t\t// X Scale object (could be instance of LinearScale or LogScale\n    var $yscale=null,$y2scale=null, $ynscale=array();\n    var $iIcons = array();      // Array of Icons to add to \n    var $cache_name;\t\t// File name to be used for the current graph in the cache directory\n    var $xgrid=null;\t\t// X Grid object (linear or logarithmic)\n    var $ygrid=null,$y2grid=null; \n    var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1;\t// Frame around graph\n    var $boxed=false, $box_color=array(0,0,0), $box_weight=1;\t\t// Box around plot area\n    var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102);\t// Shadow for graph\n    var $xaxis=null;\t\t// X-axis (instane of Axis class)\n    var $yaxis=null, $y2axis=null, $ynaxis=array();\t// Y axis (instance of Axis class)\n    var $margin_color=array(200,200,200);\t// Margin color of graph\n    var $plotarea_color=array(255,255,255);\t// Plot area color\n    var $title,$subtitle,$subsubtitle; \t// Title and subtitle(s) text object\n    var $axtype=\"linlin\";\t\t// Type of axis\n    var $xtick_factor;\t\t\t// Factot to determine the maximum number of ticks depending on the plot with\n    var $texts=null, $y2texts=null; \t// Text object to ge shown in the graph\n    var $lines=null, $y2lines=null;\n    var $bands=null, $y2bands=null;\n    var $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale offset in fractions and for centering bars in absolute pixels\n    var $background_image=\"\",$background_image_type=-1,$background_image_format=\"png\";\n    var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;\n    var $image_bright=0, $image_contr=0, $image_sat=0;\n    var $inline;\n    var $showcsim=0,$csimcolor=\"red\"; //debug stuff, draw the csim boundaris on the image if <>0\n    var $grid_depth=DEPTH_BACK;\t// Draw grid under all plots as default\n    var $iAxisStyle = AXSTYLE_SIMPLE;\n    var $iCSIMdisplay=false,$iHasStroked = false;\n    var $footer;\n    var $csimcachename = '', $csimcachetimeout = 0;\n    var $iDoClipping = false;\n    var $y2orderback=true;\n    var $tabtitle;\n    var $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;\n    var $bkg_gradfrom='navy', $bkg_gradto='silver';\n    var $titlebackground = false;\n    var\t$titlebackground_color = 'lightblue',\n\t$titlebackground_style = 1,\n\t$titlebackground_framecolor = 'blue',\n\t$titlebackground_framestyle = 2,\n\t$titlebackground_frameweight = 1,\n\t$titlebackground_bevelheight = 3 ;\n    var $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;\n    var $titlebkg_scolor1='black',$titlebkg_scolor2='white';\n    var $framebevel = false, $framebeveldepth = 2 ;\n    var $framebevelborder = false, $framebevelbordercolor='black';\n    var $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4';\n    var $background_image_mix=100;\n    var $background_cflag = '';\n    var $background_cflag_type = BGIMG_FILLPLOT;\n    var $background_cflag_mix = 100;\n    var $iImgTrans=false,\n\t$iImgTransHorizon = 100,$iImgTransSkewDist=150,\n\t$iImgTransDirection = 1, $iImgTransMinSize = true,\n\t$iImgTransFillColor='white',$iImgTransHighQ=false,\n\t$iImgTransBorder=false,$iImgTransHorizonPos=0.5;\n    var $iYAxisDeltaPos=50;\n    var $iIconDepth=DEPTH_BACK;\n    var $iAxisLblBgType = 0,\n\t$iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',\n\t$iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';\n    var $iTables=NULL;\n\n//---------------\n// CONSTRUCTOR\n\n    // aWIdth \t\tWidth in pixels of image\n    // aHeight  \tHeight in pixels of image\n    // aCachedName\tName for image file in cache directory \n    // aTimeOut\t\tTimeout in minutes for image in cache\n    // aInline\t\tIf true the image is streamed back in the call to Stroke()\n    //\t\t\tIf false the image is just created in the cache\n    function Graph($aWidth=300,$aHeight=200,$aCachedName=\"\",$aTimeOut=0,$aInline=true) {\n\tGLOBAL $gJpgBrandTiming;\n\t// If timing is used create a new timing object\n\tif( $gJpgBrandTiming ) {\n\t    global $tim;\n\t    $tim = new JpgTimer();\n\t    $tim->Push();\n\t}\n\n\tif( !is_numeric($aWidth) || !is_numeric($aHeight) ) {\n\t    JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');\n\t}\n\t\t\n\t// Automatically generate the image file name based on the name of the script that\n\t// generates the graph\n\tif( $aCachedName==\"auto\" )\n\t    $aCachedName=GenImgName();\n\t\t\t\n\t// Should the image be streamed back to the browser or only to the cache?\n\t$this->inline=$aInline;\n\t\t\n\t$this->img\t= new RotImage($aWidth,$aHeight);\n\n\t$this->cache \t= new ImgStreamCache($this->img);\n\t$this->cache->SetTimeOut($aTimeOut);\n\n\t$this->title = new Text();\n\t$this->title->ParagraphAlign('center');\n\t$this->title->SetFont(FF_FONT2,FS_BOLD);\n\t$this->title->SetMargin(3);\n\t$this->title->SetAlign('center');\n\n\t$this->subtitle = new Text();\n\t$this->subtitle->ParagraphAlign('center');\n\t$this->subtitle->SetMargin(2);\n\t$this->subtitle->SetAlign('center');\n\n\t$this->subsubtitle = new Text();\n\t$this->subsubtitle->ParagraphAlign('center');\n\t$this->subsubtitle->SetMargin(2);\n\t$this->subsubtitle->SetAlign('center');\n\n\t$this->legend = new Legend();\n\t$this->footer = new Footer();\n\n\t// Window doesn't like '?' in the file name so replace it with an '_'\n\t$aCachedName = str_replace(\"?\",\"_\",$aCachedName);\n\n\t// If the cached version exist just read it directly from the\n\t// cache, stream it back to browser and exit\n\tif( $aCachedName!=\"\" && READ_CACHE && $aInline )\n\t    if( $this->cache->GetAndStream($aCachedName) ) {\n\t\texit();\n\t    }\n\t\t\t\t\n\t$this->cache_name = $aCachedName;\n\t$this->SetTickDensity(); // Normal density\n\n\t$this->tabtitle = new GraphTabTitle();\n    }\n//---------------\n// PUBLIC METHODS\t\n    // Enable final image perspective transformation\n    function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) {\n\t$this->iImgTrans = true;\n\t$this->iImgTransHorizon = $aHorizon;\n\t$this->iImgTransSkewDist= $aSkewDist;\n\t$this->iImgTransDirection = $aDir;\n\t$this->iImgTransMinSize = $aMinSize;\n\t$this->iImgTransFillColor=$aFillColor;\n\t$this->iImgTransHighQ=$aQuality;\n\t$this->iImgTransBorder=$aBorder;\n\t$this->iImgTransHorizonPos=$aHorizonPos;\n    }\n\n    // Set Image format and optional quality\n    function SetImgFormat($aFormat,$aQuality=75) {\n\t$this->img->SetImgFormat($aFormat,$aQuality);\n    }\n\n    // Should the grid be in front or back of the plot?\n    function SetGridDepth($aDepth) {\n\t$this->grid_depth=$aDepth;\n    }\n\n    function SetIconDepth($aDepth) {\n\t$this->iIconDepth=$aDepth;\n    }\n\t\n    // Specify graph angle 0-360 degrees.\n    function SetAngle($aAngle) {\n\t$this->img->SetAngle($aAngle);\n    }\n\n    function SetAlphaBlending($aFlg=true) {\n\t$this->img->SetAlphaBlending($aFlg);\n    }\n\n    // Shortcut to image margin\n    function SetMargin($lm,$rm,$tm,$bm) {\n\t$this->img->SetMargin($lm,$rm,$tm,$bm);\n    }\n\n    function SetY2OrderBack($aBack=true) {\n\t$this->y2orderback = $aBack;\n    }\n\n    // Rotate the graph 90 degrees and set the margin \n    // when we have done a 90 degree rotation\n    function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {\n\t$lm = $lm ==0 ? floor(0.2 * $this->img->width)  : $lm ;\n\t$rm = $rm ==0 ? floor(0.1 * $this->img->width)  : $rm ;\n\t$tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ;\n\t$bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ;\n\n\t$adj = ($this->img->height - $this->img->width)/2;\n\t$this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);\n\t$this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));\n\t$this->SetAngle(90);\n\tif( empty($this->yaxis) || empty($this->xaxis) ) {\n\t    JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');\n\t}\n\t$this->xaxis->SetLabelAlign('right','center');\n\t$this->yaxis->SetLabelAlign('center','bottom');\n    }\n\t\n    function SetClipping($aFlg=true) {\n\t$this->iDoClipping = $aFlg ;\n    }\n\n    // Add a plot object to the graph\n    function Add(&$aPlot) {\n\tif( $aPlot == null )\n\t    JpGraphError::RaiseL(25010);//(\"Graph::Add() You tried to add a null plot to the graph.\");\n\tif( is_array($aPlot) && count($aPlot) > 0 )\n\t    $cl = $aPlot[0];\n\telse\n\t    $cl = $aPlot;\n\n\tif( is_a($cl,'Text') ) \n\t    $this->AddText($aPlot);\n\telseif( is_a($cl,'PlotLine') )\n\t    $this->AddLine($aPlot);\n\telseif( is_a($cl,'PlotBand') )\n\t    $this->AddBand($aPlot);\n\telseif( is_a($cl,'IconPlot') )\n\t    $this->AddIcon($aPlot);\n\telseif( is_a($cl,'GTextTable') )\n\t    $this->AddTable($aPlot);\n\telse\n\t    $this->plots[] = &$aPlot;\n    }\n\n\n    function AddTable(&$aTable) {\n\tif( is_array($aTable) ) {\n\t    for($i=0; $i < count($aTable); ++$i )\n\t\t$this->iTables[]=&$aTable[$i];\n\t}\n\telse {\n\t    $this->iTables[] = &$aTable ;\n\t}\t\n    }\n\n    function AddIcon(&$aIcon) {\n\tif( is_array($aIcon) ) {\n\t    for($i=0; $i < count($aIcon); ++$i )\n\t\t$this->iIcons[]=&$aIcon[$i];\n\t}\n\telse {\n\t    $this->iIcons[] = &$aIcon ;\n\t}\t\n    }\n\n    // Add plot to second Y-scale\n    function AddY2(&$aPlot) {\n\tif( $aPlot == null )\n\t    JpGraphError::RaiseL(25011);//(\"Graph::AddY2() You tried to add a null plot to the graph.\");\t\n\n\tif( is_array($aPlot) && count($aPlot) > 0 )\n\t    $cl = $aPlot[0];\n\telse\n\t    $cl = $aPlot;\n\n\tif( is_a($cl,'Text') ) \n\t    $this->AddText($aPlot,true);\n\telseif( is_a($cl,'PlotLine') )\n\t    $this->AddLine($aPlot,true);\n\telseif( is_a($cl,'PlotBand') )\n\t    $this->AddBand($aPlot,true);\n\telse\n\t    $this->y2plots[] = &$aPlot;\n    }\n\n    // Add plot to second Y-scale\n    function AddY($aN,&$aPlot) {\n\n\tif( $aPlot == null )\n\t    JpGraphError::RaiseL(25012);//(\"Graph::AddYN() You tried to add a null plot to the graph.\");\t\n\n\tif( is_array($aPlot) && count($aPlot) > 0 )\n\t    $cl = $aPlot[0];\n\telse\n\t    $cl = $aPlot;\n\n\tif( is_a($cl,'Text') || is_a($cl,'PlotLine') || is_a($cl,'PlotBand') )\n\t    JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');\n\telse\n\t    $this->ynplots[$aN][] = &$aPlot;\n    }\n    \n    // Add text object to the graph\n    function AddText(&$aTxt,$aToY2=false) {\n\tif( $aTxt == null )\n\t    JpGraphError::RaiseL(25014);//(\"Graph::AddText() You tried to add a null text to the graph.\");\t\t\n\tif( $aToY2 ) {\n\t    if( is_array($aTxt) ) {\n\t\tfor($i=0; $i < count($aTxt); ++$i )\n\t\t    $this->y2texts[]=&$aTxt[$i];\n\t    }\n\t    else\n\t\t$this->y2texts[] = &$aTxt;\n\t}\n\telse {\n\t    if( is_array($aTxt) ) {\n\t\tfor($i=0; $i < count($aTxt); ++$i )\n\t\t    $this->texts[]=&$aTxt[$i];\n\t    }\n\t    else\n\t\t$this->texts[] = &$aTxt;\n\t}\n    }\n\t\n    // Add a line object (class PlotLine) to the graph\n    function AddLine(&$aLine,$aToY2=false) {\n\tif( $aLine == null )\n\t    JpGraphError::RaiseL(25015);//(\"Graph::AddLine() You tried to add a null line to the graph.\");\t\n\n\tif( $aToY2 ) {\n \t    if( is_array($aLine) ) {\n\t\tfor($i=0; $i < count($aLine); ++$i )\n\t\t    $this->y2lines[]=&$aLine[$i];\n\t    }\n\t    else\n\t\t$this->y2lines[] = &$aLine;\n\t}\n\telse {\n \t    if( is_array($aLine) ) {\n\t\tfor($i=0; $i < count($aLine); ++$i )\n\t\t    $this->lines[]=&$aLine[$i];\n\t    }\n\t    else\n\t\t$this->lines[] = &$aLine;\n\t}\n    }\n\n    // Add vertical or horizontal band\n    function AddBand(&$aBand,$aToY2=false) {\n\tif( $aBand == null )\n\t    JpGraphError::RaiseL(25016);//(\" Graph::AddBand() You tried to add a null band to the graph.\");\n\n\tif( $aToY2 ) {\n\t    if( is_array($aBand) ) {\n\t\tfor($i=0; $i < count($aBand); ++$i )\n\t\t    $this->y2bands[] = &$aBand[$i];\n\t    }\n\t    else\n\t\t$this->y2bands[] = &$aBand;\n\t}\n\telse {\n\t    if( is_array($aBand) ) {\n\t\tfor($i=0; $i < count($aBand); ++$i )\n\t\t    $this->bands[] = &$aBand[$i];\n\t    }\n\t    else\n\t\t$this->bands[] = &$aBand;\n\t}\n    }\n\n    function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) {\n\t$this->bkg_gradtype=$aGradType;\n\t$this->bkg_gradstyle=$aStyle;\n\t$this->bkg_gradfrom = $aFrom;\n\t$this->bkg_gradto = $aTo;\n    } \n\t\n    // Set a country flag in the background\n    function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {\n\t$this->background_cflag = $aName;\n\t$this->background_cflag_type = $aBgType;\n\t$this->background_cflag_mix = $aMix;\n    }\n\n    // Alias for the above method\n    function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {\n\t$this->background_cflag = $aName;\n\t$this->background_cflag_type = $aBgType;\n\t$this->background_cflag_mix = $aMix;\n    }\n\n\n    // Specify a background image\n    function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat=\"auto\") {\n\n\tif( $GLOBALS['gd2'] && !USE_TRUECOLOR ) {\n\t    JpGraphError::RaiseL(25017);//(\"You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you <b>must</b> enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.\");\n\t}\n\n\t// Get extension to determine image type\n\tif( $aImgFormat == \"auto\" ) {\n\t    $e = explode('.',$aFileName);\n\t    if( !$e ) {\n\t\tJpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');\n\t    }\n\n\t    $valid_formats = array('png', 'jpg', 'gif');\n\t    $aImgFormat = strtolower($e[count($e)-1]);\n\t    if ($aImgFormat == 'jpeg')  {\n\t\t$aImgFormat = 'jpg';\n\t    }\n\t    elseif (!in_array($aImgFormat, $valid_formats) )  {\n\t\tJpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);\n\t    }    \n\t}\n\n\t$this->background_image = $aFileName;\n\t$this->background_image_type=$aBgType;\n\t$this->background_image_format=$aImgFormat;\n    }\n\n    function SetBackgroundImageMix($aMix) {\n\t$this->background_image_mix = $aMix ;\n    }\n\t\n    // Adjust brightness and constrast for background image\n    function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) {\n\t$this->background_image_bright=$aBright;\n\t$this->background_image_contr=$aContr;\n\t$this->background_image_sat=$aSat;\n    }\n\t\n    // Adjust brightness and constrast for image\n    function AdjImage($aBright,$aContr=0,$aSat=0) {\n\t$this->image_bright=$aBright;\n\t$this->image_contr=$aContr;\n\t$this->image_sat=$aSat;\n    }\n\n    // Specify axis style (boxed or single)\n    function SetAxisStyle($aStyle) {\n        $this->iAxisStyle = $aStyle ;\n    }\n\t\n    // Set a frame around the plot area\n    function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {\n\t$this->boxed = $aDrawPlotFrame;\n\t$this->box_weight = $aPlotFrameWeight;\n\t$this->box_color = $aPlotFrameColor;\n    }\n\t\n    // Specify color for the plotarea (not the margins)\n    function SetColor($aColor) {\n\t$this->plotarea_color=$aColor;\n    }\n\t\n    // Specify color for the margins (all areas outside the plotarea)\n    function SetMarginColor($aColor) {\n\t$this->margin_color=$aColor;\n    }\n\t\n    // Set a frame around the entire image\n    function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {\n\t$this->doframe = $aDrawImgFrame;\n\t$this->frame_color = $aImgFrameColor;\n\t$this->frame_weight = $aImgFrameWeight;\n    }\n\n    function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {\n\t$this->framebevel = $aFlg ;\n\t$this->framebeveldepth = $aDepth ;\n\t$this->framebevelborder = $aBorder ;\n\t$this->framebevelbordercolor = $aBorderColor ;\n\t$this->framebevelcolor1 = $aColor1 ;\n\t$this->framebevelcolor2 = $aColor2 ;\n\n\t$this->doshadow = false ;\n    }\n\n    // Set the shadow around the whole image\n    function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) {\n\t$this->doshadow = $aShowShadow;\n\t$this->shadow_color = $aShadowColor;\n\t$this->shadow_width = $aShadowWidth;\n\t$this->footer->iBottomMargin += $aShadowWidth;\n\t$this->footer->iRightMargin += $aShadowWidth;\n    }\n\n    // Specify x,y scale. Note that if you manually specify the scale\n    // you must also specify the tick distance with a call to Ticks::Set()\n    function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {\n\t$this->axtype = $aAxisType;\n\n\tif( $aYMax < $aYMin || $aXMax < $aXMin )\n\t    JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');\n\n\t$yt=substr($aAxisType,-3,3);\n\tif( $yt==\"lin\" )\n\t    $this->yscale = new LinearScale($aYMin,$aYMax);\n\telseif( $yt == \"int\" ) {\n\t    $this->yscale = new LinearScale($aYMin,$aYMax);\n\t    $this->yscale->SetIntScale();\n\t}\n\telseif( $yt==\"log\" )\n\t    $this->yscale = new LogScale($aYMin,$aYMax);\n\telse\n\t    JpGraphError::RaiseL(25021,$aAxisType);//(\"Unknown scale specification for Y-scale. ($aAxisType)\");\n\t\t\t\n\t$xt=substr($aAxisType,0,3);\n\tif( $xt == \"lin\" || $xt == \"tex\" ) {\n\t    $this->xscale = new LinearScale($aXMin,$aXMax,\"x\");\n\t    $this->xscale->textscale = ($xt == \"tex\");\n\t}\n\telseif( $xt == \"int\" ) {\n\t    $this->xscale = new LinearScale($aXMin,$aXMax,\"x\");\n\t    $this->xscale->SetIntScale();\n\t}\n\telseif( $xt == \"dat\" ) {\n\t    $this->xscale = new DateScale($aXMin,$aXMax,\"x\");\n\t}\n\telseif( $xt == \"log\" )\n\t    $this->xscale = new LogScale($aXMin,$aXMax,\"x\");\n\telse\n\t    JpGraphError::RaiseL(25022,$aAxisType);//(\" Unknown scale specification for X-scale. ($aAxisType)\");\n\n\t$this->xaxis = new Axis($this->img,$this->xscale);\n\t$this->yaxis = new Axis($this->img,$this->yscale);\n\t$this->xgrid = new Grid($this->xaxis);\n\t$this->ygrid = new Grid($this->yaxis);\t\n\t$this->ygrid->Show();\t\t\t\n    }\n\t\n    // Specify secondary Y scale\n    function SetY2Scale($aAxisType=\"lin\",$aY2Min=1,$aY2Max=1) {\n\tif( $aAxisType==\"lin\" ) \n\t    $this->y2scale = new LinearScale($aY2Min,$aY2Max);\n\telseif( $aAxisType == \"int\" ) {\n\t    $this->y2scale = new LinearScale($aY2Min,$aY2Max);\n\t    $this->y2scale->SetIntScale();\n\t}\n\telseif( $aAxisType==\"log\" ) {\n\t    $this->y2scale = new LogScale($aY2Min,$aY2Max);\n\t}\n\telse JpGraphError::RaiseL(25023,$aAxisType);//(\"JpGraph: Unsupported Y2 axis type: $aAxisType\\nMust be one of (lin,log,int)\");\n\t\t\t\n\t$this->y2axis = new Axis($this->img,$this->y2scale);\n\t$this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); \n\t$this->y2axis->SetLabelSide(SIDE_RIGHT); \n\t$this->y2axis->SetPos('max');\n\t$this->y2axis->SetTitleSide(SIDE_RIGHT);\n\t\t\n\t// Deafult position is the max x-value\n\t$this->y2grid = new Grid($this->y2axis);\t\t\t\t\t\t\t\n    }\n\n    // Set the delta position (in pixels) between the multiple Y-axis\n    function SetYDeltaDist($aDist) {\n\t$this->iYAxisDeltaPos = $aDist;\n    }\n\t\n    // Specify secondary Y scale\n    function SetYScale($aN,$aAxisType=\"lin\",$aYMin=1,$aYMax=1) {\n\n\tif( $aAxisType==\"lin\" ) \n\t    $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);\n\telseif( $aAxisType == \"int\" ) {\n\t    $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);\n\t    $this->ynscale[$aN]->SetIntScale();\n\t}\n\telseif( $aAxisType==\"log\" ) {\n\t    $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);\n\t}\n\telse JpGraphError::RaiseL(25024,$aAxisType);//(\"JpGraph: Unsupported Y axis type: $aAxisType\\nMust be one of (lin,log,int)\");\n\t\t\t\n\t$this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);\n\t$this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); \n\t$this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); \n    }\n\n\t\n    // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'\n    // The dividing factor have been determined heuristically according to my aesthetic \n    // sense (or lack off) y.m.m.v !\n    function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {\n\t$this->xtick_factor=30;\n\t$this->ytick_factor=25;\t\t\n\tswitch( $aYDensity ) {\n\t    case TICKD_DENSE:\n\t\t$this->ytick_factor=12;\t\t\t\n\t\tbreak;\n\t    case TICKD_NORMAL:\n\t\t$this->ytick_factor=25;\t\t\t\n\t\tbreak;\n\t    case TICKD_SPARSE:\n\t\t$this->ytick_factor=40;\t\t\t\n\t\tbreak;\n\t    case TICKD_VERYSPARSE:\n\t\t$this->ytick_factor=100;\t\t\t\n\t\tbreak;\t\t\n\t    default:\n\t\tJpGraphError::RaiseL(25025,$densy);//(\"JpGraph: Unsupported Tick density: $densy\");\n\t}\n\tswitch( $aXDensity ) {\n\t    case TICKD_DENSE:\n\t\t$this->xtick_factor=15;\t\t\t\t\t\t\t\n\t\tbreak;\n\t    case TICKD_NORMAL:\n\t\t$this->xtick_factor=30;\t\t\t\n\t\tbreak;\n\t    case TICKD_SPARSE:\n\t\t$this->xtick_factor=45;\t\t\t\t\t\n\t\tbreak;\n\t    case TICKD_VERYSPARSE:\n\t\t$this->xtick_factor=60;\t\t\t\t\t\t\t\t\n\t\tbreak;\t\t\n\t    default:\n\t\tJpGraphError::RaiseL(25025,$densx);//(\"JpGraph: Unsupported Tick density: $densx\");\n\t}\t\t\n    }\n\t\n\n    // Get a string of all image map areas\t\n    function GetCSIMareas() {\n\tif( !$this->iHasStroked )\n\t    $this->Stroke(_CSIM_SPECIALFILE);\n\n\t$csim = $this->title->GetCSIMAreas();\n\t$csim .= $this->subtitle->GetCSIMAreas();\n\t$csim .= $this->subsubtitle->GetCSIMAreas();\n\t$csim .= $this->legend->GetCSIMAreas();\n\n\tif( $this->y2axis != NULL ) {\n\t    $csim .= $this->y2axis->title->GetCSIMAreas();\n\t}\n\n\tif( $this->texts != null ) {\n\t    $n = count($this->texts);\n\t    for($i=0; $i < $n; ++$i ) {\n\t\t$csim .= $this->texts[$i]->GetCSIMAreas();\n\t    }\n\t}\n\n\tif( $this->y2texts != null && $this->y2scale != null ) {\n\t    $n = count($this->y2texts);\n\t    for($i=0; $i < $n; ++$i ) {\n\t\t$csim .= $this->y2texts[$i]->GetCSIMAreas();\n\t    }\n\t}\n\n\tif( $this->yaxis != null && $this->xaxis != null ) {\n\t    $csim .= $this->yaxis->title->GetCSIMAreas();\t\n\t    $csim .= $this->xaxis->title->GetCSIMAreas();\n\t}\n\n\t$n = count($this->plots);\n\tfor( $i=0; $i < $n; ++$i ) \n\t    $csim .= $this->plots[$i]->GetCSIMareas();\n\n\t$n = count($this->y2plots);\n\tfor( $i=0; $i < $n; ++$i ) \n\t    $csim .= $this->y2plots[$i]->GetCSIMareas();\n\n\t$n = count($this->ynaxis);\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $m = count($this->ynplots[$i]); \n\t    for($j=0; $j < $m; ++$j ) {\n\t\t$csim .= $this->ynplots[$i][$j]->GetCSIMareas();\n\t    }\n\t}\n\n\t$n = count($this->iTables);\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $csim .= $this->iTables[$i]->GetCSIMareas();\n\t}\n\n\treturn $csim;\n    }\n\t\n    // Get a complete <MAP>..</MAP> tag for the final image map\n    function GetHTMLImageMap($aMapName) {\n\t//$im = \"<map name=\\\"$aMapName\\\" id=\\\"$aMapName\\\">\\n\";\n\t$im = \"<map name=\\\"$aMapName\\\" />\\n\";\n\t$im .= $this->GetCSIMareas();\n\t$im .= \"</map>\"; \n\treturn $im;\n    }\n\n    function CheckCSIMCache($aCacheName,$aTimeOut=60) {\n\tglobal $_SERVER;\n\n\tif( $aCacheName=='auto' )\n\t    $aCacheName=basename($_SERVER['PHP_SELF']);\n\n\t$this->csimcachename = CSIMCACHE_DIR.$aCacheName;\n\t$this->csimcachetimeout = $aTimeOut;\n\n\t// First determine if we need to check for a cached version\n\t// This differs from the standard cache in the sense that the\n\t// image and CSIM map HTML file is written relative to the directory\n\t// the script executes in and not the specified cache directory.\n\t// The reason for this is that the cache directory is not necessarily\n\t// accessible from the HTTP server.\n\tif( $this->csimcachename != '' ) {\n\t    $dir = dirname($this->csimcachename);\n\t    $base = basename($this->csimcachename);\n\t    $base = strtok($base,'.');\n\t    $suffix = strtok('.');\n\t    $basecsim = $dir.'/'.$base.'_csim_.html';\n\t    $baseimg = $dir.'/'.$base.'.'.$this->img->img_format;\n\n\t    $timedout=false;\n\t\t\n\t    // Does it exist at all ?\n\t    \n\t    if( file_exists($basecsim) && file_exists($baseimg) ) {\n\t\t// Check that it hasn't timed out\n\t\t$diff=time()-filemtime($basecsim);\n\t\tif( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {\n\t\t    $timedout=true;\n\t\t    @unlink($basecsim);\n\t\t    @unlink($baseimg);\n\t\t}\n\t\telse {\n\t\t    if ($fh = @fopen($basecsim, \"r\")) {\n\t\t\tfpassthru($fh);\n\t\t\treturn true;\n\t\t    }\n\t\t    else\n\t\t\tJpGraphError::RaiseL(25027,$basecsim);//(\" Can't open cached CSIM \\\"$basecsim\\\" for reading.\");\n\t\t}\n\t    }\n\t}\n\treturn false;\n    }\n\n    function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) {\n\tif( $aCSIMName=='' ) {\n\t    // create a random map name\n\t    srand ((double) microtime() * 1000000);\n\t    $r = rand(0,100000);\n\t    $aCSIMName='__mapname'.$r.'__';\n\t}\n\n\tif( $aScriptName=='auto' )\n\t    $aScriptName=basename($_SERVER['PHP_SELF']);\n\n\tif( empty($_GET[_CSIM_DISPLAY]) ) {\n\t    // First determine if we need to check for a cached version\n\t    // This differs from the standard cache in the sense that the\n\t    // image and CSIM map HTML file is written relative to the directory\n\t    // the script executes in and not the specified cache directory.\n\t    // The reason for this is that the cache directory is not necessarily\n\t    // accessible from the HTTP server.\n\t    if( $this->csimcachename != '' ) {\n\t\t$dir = dirname($this->csimcachename);\n\t\t$base = basename($this->csimcachename);\n\t\t$base = strtok($base,'.');\n\t\t$suffix = strtok('.');\n\t\t$basecsim = $dir.'/'.$base.'_csim_.html';\n\t\t$baseimg = $base.'.'.$this->img->img_format;\n\n\t\t// Check that apache can write to directory specified\n\n\t\tif( file_exists($dir) && !is_writeable($dir) ) {\n\t\t    JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');\n\t\t}\n\t\t\n\t\t// Make sure directory exists\n\t\t$this->cache->MakeDirs($dir);\n\n\t\t// Write the image file\n\t\t$this->Stroke(CSIMCACHE_DIR.$baseimg);\n\n\t\t// Construct wrapper HTML and write to file and send it back to browser\n\t\t$htmlwrap = $this->GetHTMLImageMap($aCSIMName).\"\\n\".\n\t\t    '<img src=\"'.htmlentities(CSIMCACHE_HTTP_DIR.$baseimg).'\" ismap usemap=\"#'.$aCSIMName.'\" border='.$aBorder.' width='.$this->img->width.' height='.$this->img->height.\" alt=\\\"\\\" />\\n\";\n\t\tif($fh =  @fopen($basecsim,'w') ) {\n\t\t    fwrite($fh,$htmlwrap);\n\t\t    fclose($fh);\n\t\t    echo $htmlwrap;\n\t\t}\n\t\telse\n\t\t    JpGraphError::RaiseL(25029,$basecsim);//(\" Can't write CSIM \\\"$basecsim\\\" for writing. Check free space and permissions.\");\n\t    }\n\t    else {\n\n\t\tif( $aScriptName=='' ) {\n\t\t    JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().');\n\t\t    exit();\n\t\t}\n\n\t\t\n\t\t// This is a JPGRAPH internal defined that prevents\n\t\t// us from recursively coming here again\n\t\t$urlarg='?'._CSIM_DISPLAY.'=1';\n\n\t\t// Now reconstruct any user URL argument\n\t\treset($_GET);\n\t\twhile( list($key,$value) = each($_GET) ) {\n\t\t    if( is_array($value) ) {\n\t\t\t$n = count($value);\n\t\t\tfor( $i=0; $i < $n; ++$i ) {\n\t\t\t    $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);\n\t\t\t}\n\t\t    }\n\t\t    else {\n\t\t\t$urlarg .= '&'.$key.'='.urlencode($value);\n\t\t    }\n\t\t}\n\n\t\t// It's not ideal to convert POST argument to GET arguments\n\t\t// but there is little else we can do. One idea for the \n\t\t// future might be recreate the POST header in case.\n\t\treset($_POST);\n\t\twhile( list($key,$value) = each($_POST) ) {\n\t\t    if( is_array($value) ) {\n\t\t\t$n = count($value);\n\t\t\tfor( $i=0; $i < $n; ++$i ) {\n\t\t\t    $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);\n\t\t\t}\n\t\t    }\n\t\t    else {\n\t\t\t$urlarg .= '&'.$key.'='.urlencode($value);\n\t\t    }\n\t\t}\n\n\t\techo $this->GetHTMLImageMap($aCSIMName);\n\n\t\techo \"<img src='\".htmlentities($aScriptName.$urlarg).\"' ismap usemap='#\".$aCSIMName.'\\' border='.$aBorder.'  width='.$this->img->width.' height='.$this->img->height.\" alt=\\\"\\\" />\\n\";\n\t    }\n\t}\n\telse {\n\t    $this->Stroke();\n\t}\n    }\n\n    function GetTextsYMinMax($aY2=false) {\n\tif( $aY2 ) \n\t    $txts = $this->y2texts;\n\telse\n\t    $txts = $this->texts;\n\t$n = count($txts);\n\t$min=null;\n\t$max=null;\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    if( $txts[$i]->iScalePosY !== null && \n\t\t$txts[$i]->iScalePosX !== null  ) {\n\t\tif( $min === null  ) {\n\t\t    $min = $max = $txts[$i]->iScalePosY ;\n\t\t}\n\t\telse {\n\t\t    $min = min($min,$txts[$i]->iScalePosY);\n\t\t    $max = max($max,$txts[$i]->iScalePosY);\n\t\t}\n\t    }\n\t}\n\tif( $min !== null ) {\n\t    return array($min,$max);\n\t}\n\telse\n\t    return null;\n    }\n\n    function GetTextsXMinMax($aY2=false) {\n\tif( $aY2 ) \n\t    $txts = $this->y2texts;\n\telse\n\t    $txts = $this->texts;\n\t$n = count($txts);\n\t$min=null;\n\t$max=null;\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    if( $txts[$i]->iScalePosY !== null && \n\t\t$txts[$i]->iScalePosX !== null  ) {\n\t\tif( $min === null  ) {\n\t\t    $min = $max = $txts[$i]->iScalePosX ;\n\t\t}\n\t\telse {\n\t\t    $min = min($min,$txts[$i]->iScalePosX);\n\t\t    $max = max($max,$txts[$i]->iScalePosX);\n\t\t}\n\t    }\n\t}\n\tif( $min !== null ) {\n\t    return array($min,$max);\n\t}\n\telse\n\t    return null;\n    }\n\n    function GetXMinMax() {\n\tlist($min,$ymin) = $this->plots[0]->Min();\n\tlist($max,$ymax) = $this->plots[0]->Max();\n\tforeach( $this->plots as $p ) {\n\t    list($xmin,$ymin) = $p->Min();\n\t    list($xmax,$ymax) = $p->Max();\t\t\t\n\t    $min = Min($xmin,$min);\n\t    $max = Max($xmax,$max);\n\t}\n\tif( $this->y2axis != null ) {\n\t    foreach( $this->y2plots as $p ) {\n\t\tlist($xmin,$ymin) = $p->Min();\n\t\tlist($xmax,$ymax) = $p->Max();\t\t\t\n\t\t$min = Min($xmin,$min);\n\t\t$max = Max($xmax,$max);\n\t    }\t\t    \n\t}\n\n\t$n = count($this->ynaxis);\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    if( $this->ynaxis[$i] != null) {\n\t\tforeach( $this->ynplots[$i] as $p ) {\n\t\t    list($xmin,$ymin) = $p->Min();\n\t\t    list($xmax,$ymax) = $p->Max();\t\t\t\n\t\t    $min = Min($xmin,$min);\n\t\t    $max = Max($xmax,$max);\n\t\t}\t\t    \n\t    }\n\t}\n\n\treturn array($min,$max);\n    }\n\n    function AdjustMarginsForTitles() {\n\t$totrequired = \n\t    ($this->title->t != '' ? \n\t     $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) +\n\t    ($this->subtitle->t != '' ? \n\t     $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + \n\t    ($this->subsubtitle->t != '' ? \n\t     $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ;\n\t\n\n\t$btotrequired = 0;\n\tif($this->xaxis != null &&  !$this->xaxis->hide && !$this->xaxis->hide_labels ) {\n\t    // Minimum bottom margin\n\t    if( $this->xaxis->title->t != '' ) {\n\t\tif( $this->img->a == 90 ) \n\t\t    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ;\n\t\telse\n\t\t    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ;\n\t    }\n\t    else\n\t\t$btotrequired = 0;\n\t    \n\t    if( $this->img->a == 90 ) {\n\t\t$this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style,\n\t\t\t\t    $this->yaxis->font_size);\n\t\t$lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle);\n\t    }\n\t    else {\n\t\t$this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style,\n\t\t\t\t    $this->xaxis->font_size);\n\t\t$lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle);\n\t    }\n\t    \n\t    $btotrequired += $lh + 5;\n\t}\n\n\tif( $this->img->a == 90 ) {\n\t    // DO Nothing. It gets too messy to do this properly for 90 deg...\n\t}\n\telse{\n\t    if( $this->img->top_margin < $totrequired ) {\n\t\t$this->SetMargin($this->img->left_margin,$this->img->right_margin,\n\t\t\t\t $totrequired,$this->img->bottom_margin);\n\t    }\n\t    if( $this->img->bottom_margin < $btotrequired ) {\n\t\t$this->SetMargin($this->img->left_margin,$this->img->right_margin,\n\t\t\t\t $this->img->top_margin,$btotrequired);\n\t    }\n\t}\n    }\n\n    // Stroke the graph\n    // $aStrokeFileName\tIf != \"\" the image will be written to this file and NOT\n    // streamed back to the browser\n    function Stroke($aStrokeFileName=\"\") {\t\t\n\n\t// Fist make a sanity check that user has specified a scale\n\tif( empty($this->yscale) ) {\n\t    JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().');\n\t}\n\n\t// Start by adjusting the margin so that potential titles will fit.\n\t$this->AdjustMarginsForTitles();\n\n\t// Setup scale constants\n\tif( $this->yscale ) $this->yscale->InitConstants($this->img);\n\tif( $this->xscale ) $this->xscale->InitConstants($this->img);\n\tif( $this->y2scale ) $this->y2scale->InitConstants($this->img);\n\t\n\t$n=count($this->ynscale);\n\tfor($i=0; $i < $n; ++$i) {\n\t  if( $this->ynscale[$i] ) $this->ynscale[$i]->InitConstants($this->img);\n\t}\n\n\t// If the filename is the predefined value = '_csim_special_'\n\t// we assume that the call to stroke only needs to do enough\n\t// to correctly generate the CSIM maps.\n\t// We use this variable to skip things we don't strictly need\n\t// to do to generate the image map to improve performance\n\t// a best we can. Therefor you will see a lot of tests !$_csim in the\n\t// code below.\n\t$_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);\n\n\t// We need to know if we have stroked the plot in the\n\t// GetCSIMareas. Otherwise the CSIM hasn't been generated\n\t// and in the case of GetCSIM called before stroke to generate\n\t// CSIM without storing an image to disk GetCSIM must call Stroke.\n\t$this->iHasStroked = true;\n\n\t// Do any pre-stroke adjustment that is needed by the different plot types\n\t// (i.e bar plots want's to add an offset to the x-labels etc)\n\tfor($i=0; $i < count($this->plots) ; ++$i ) {\n\t    $this->plots[$i]->PreStrokeAdjust($this);\n\t    $this->plots[$i]->DoLegend($this);\n\t}\n\t\t\n\t// Any plots on the second Y scale?\n\tif( $this->y2scale != null ) {\n\t    for($i=0; $i<count($this->y2plots)\t; ++$i ) {\n\t\t$this->y2plots[$i]->PreStrokeAdjust($this);\n\t\t$this->y2plots[$i]->DoLegend($this);\n\t    }\n\t}\n\n\t// Any plots on the extra Y axises?\n\t$n = count($this->ynaxis);\n\tfor($i=0; $i<$n\t; ++$i ) {\n\t    if( $this->ynplots == null || $this->ynplots[$i] == null) {\n\t\tJpGraphError::RaiseL(25032,$i);//(\"No plots for Y-axis nbr:$i\");\n\t    } \n\t    $m = count($this->ynplots[$i]); \n\t    for($j=0; $j < $m; ++$j ) {\n\t\t$this->ynplots[$i][$j]->PreStrokeAdjust($this);\n\t\t$this->ynplots[$i][$j]->DoLegend($this);\n\t    }\n\t}\n\n\t\t\n\t// Bail out if any of the Y-axis not been specified and\n\t// has no plots. (This means it is impossible to do autoscaling and\n\t// no other scale was given so we can't possible draw anything). If you use manual\n\t// scaling you also have to supply the tick steps as well.\n\tif( (!$this->yscale->IsSpecified() && count($this->plots)==0) ||\n\t    ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) {\n\t    //$e = \"n=\".count($this->y2plots).\"\\n\";\n\t    // $e = \"Can't draw unspecified Y-scale.<br>\\nYou have either:<br>\\n\";\n\t    // $e .= \"1. Specified an Y axis for autoscaling but have not supplied any plots<br>\\n\";\n\t    // $e .= \"2. Specified a scale manually but have forgot to specify the tick steps\";\n\t    JpGraphError::RaiseL(25026);\n\t}\n\t\t\n\t// Bail out if no plots and no specified X-scale\n\tif( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) )\n\t    JpGraphError::RaiseL(25034);//(\"<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>\");\n\n\t//Check if we should autoscale y-axis\n\tif( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {\n\t    list($min,$max) = $this->GetPlotsYMinMax($this->plots);\n \t    $lres = $this->GetLinesYMinMax($this->lines);\n\t    if( is_array($lres) ) {\n\t\tlist($linmin,$linmax) = $lres ;\n\t\t$min = min($min,$linmin);\n\t\t$max = max($max,$linmax);\n\t    }\n\t    $tres = $this->GetTextsYMinMax();\n\t    if( is_array($tres) ) {\n\t\tlist($tmin,$tmax) = $tres ;\n\t\t$min = min($min,$tmin);\n\t\t$max = max($max,$tmax);\n\t    }\n\t    $this->yscale->AutoScale($this->img,$min,$max,\n\t\t\t\t     $this->img->plotheight/$this->ytick_factor);\n\t}\n\telseif( $this->yscale->IsSpecified() && \n\t\t( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) {\n\t    // The tick calculation will use the user suplied min/max values to determine\n\t    // the ticks. If auto_ticks is false the exact user specifed min and max\n\t    // values will be used for the scale. \n\t    // If auto_ticks is true then the scale might be slightly adjusted\n\t    // so that the min and max values falls on an even major step.\n\t    $min = $this->yscale->scale[0];\n\t    $max = $this->yscale->scale[1];\n\t    $this->yscale->AutoScale($this->img,$min,$max,\n\t\t\t\t     $this->img->plotheight/$this->ytick_factor,\n\t\t\t\t     $this->yscale->auto_ticks);\n\t}\n\n\tif( $this->y2scale != null) {\n\t  \n\t    if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) {\n\t\tlist($min,$max) = $this->GetPlotsYMinMax($this->y2plots);\n\t\t$lres = $this->GetLinesYMinMax($this->y2lines);\n\t\tif( is_array($lres) ) {\n\t\t    list($linmin,$linmax) = $lres ;\n\t\t    $min = min($min,$linmin);\n\t\t    $max = max($max,$linmax);\n\t\t}\n\t\t$tres = $this->GetTextsYMinMax(true);\n\t\tif( is_array($tres) ) {\n\t\t    list($tmin,$tmax) = $tres ;\n\t\t    $min = min($min,$tmin);\n\t\t    $max = max($max,$tmax);\n\t\t}\n\t\t$this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);\n\t    }\t\t\t\n\t    elseif( $this->y2scale->IsSpecified() && \n\t\t    ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) {\n\t\t// The tick calculation will use the user suplied min/max values to determine\n\t\t// the ticks. If auto_ticks is false the exact user specifed min and max\n\t\t// values will be used for the scale. \n\t\t// If auto_ticks is true then the scale might be slightly adjusted\n\t\t// so that the min and max values falls on an even major step.\n\t\t$min = $this->y2scale->scale[0];\n\t\t$max = $this->y2scale->scale[1];\n\t\t$this->y2scale->AutoScale($this->img,$min,$max,\n\t\t\t\t\t  $this->img->plotheight/$this->ytick_factor,\n\t\t\t\t\t  $this->y2scale->auto_ticks);\n\t    }\n\t}\n\n\t//\n\t// Autoscale the multiple Y-axis\n\t//\n\t$n = count($this->ynaxis);\n\tfor( $i=0; $i < $n; ++$i ) {\n\t  if( $this->ynscale[$i] != null) {\n\t    if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) {\n\t      list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]);\n\t      $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);\n\t    }\t\t\t\n\t    elseif( $this->ynscale[$i]->IsSpecified() && \n\t\t    ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) {\n\t\t// The tick calculation will use the user suplied min/max values to determine\n\t\t// the ticks. If auto_ticks is false the exact user specifed min and max\n\t\t// values will be used for the scale. \n\t\t// If auto_ticks is true then the scale might be slightly adjusted\n\t\t// so that the min and max values falls on an even major step.\n\t      $min = $this->ynscale[$i]->scale[0];\n\t      $max = $this->ynscale[$i]->scale[1];\n\t      $this->ynscale[$i]->AutoScale($this->img,$min,$max,\n\t\t\t\t\t    $this->img->plotheight/$this->ytick_factor,\n\t\t\t\t\t    $this->ynscale[$i]->auto_ticks);\n\t    }\n\t  }\n\t}\n\t\t\n\n\t//Check if we should autoscale x-axis\n\tif( !$this->xscale->IsSpecified() ) {\n\t    if( substr($this->axtype,0,4) == \"text\" ) {\n\t\t$max=0;\n\t\t$n = count($this->plots);\n\t\tfor($i=0; $i < $n; ++$i ) {\n\t\t    $p = $this->plots[$i];\n\t\t    // We need some unfortunate sub class knowledge here in order\n\t\t    // to increase number of data points in case it is a line plot\n\t\t    // which has the barcenter set. If not it could mean that the\n\t\t    // last point of the data is outside the scale since the barcenter\n\t\t    // settings means that we will shift the entire plot half a tick step\n\t\t    // to the right in oder to align with the center of the bars.\n\t\t    if( is_a($p,'BarPlot') || empty($p->barcenter)) {\n\t\t\t$max=max($max,$p->numpoints-1);\n\t\t    }\n\t\t    else {\n\t\t\t$max=max($max,$p->numpoints);\n\t\t    }\n\t\t}\n\t\t$min=0;\n\t\tif( $this->y2axis != null ) {\n\t\t    foreach( $this->y2plots as $p ) {\n\t\t\t$max=max($max,$p->numpoints-1);\n\t\t    }\t\t    \n\t\t}\n\t\t$n = count($this->ynaxis);\n\t\tfor( $i=0; $i < $n; ++$i ) {\n\t\t    if( $this->ynaxis[$i] != null) {\n\t\t\tforeach( $this->ynplots[$i] as $p ) {\n\t\t\t    $max=max($max,$p->numpoints-1);\n\t\t\t}\t\t    \n\t\t    }\n\t\t}\n\t\t\n\t\t$this->xscale->Update($this->img,$min,$max);\n\t\t$this->xscale->ticks->Set($this->xaxis->tick_step,1);\n\t\t$this->xscale->ticks->SupressMinorTickMarks();\n\t    }\n\t    else {\n\t\tlist($min,$max) = $this->GetXMinMax();\n\t\t$lres = $this->GetLinesXMinMax($this->lines);\n\t\tif( $lres ) {\n\t\t    list($linmin,$linmax) = $lres ;\n\t\t    $min = min($min,$linmin);\n\t\t    $max = max($max,$linmax);\n\t\t}\n\t\t$lres = $this->GetLinesXMinMax($this->y2lines);\n\t\tif( $lres ) {\n\t\t    list($linmin,$linmax) = $lres ;\n\t\t    $min = min($min,$linmin);\n\t\t    $max = max($max,$linmax);\n\t\t}\n\n\t\t$tres = $this->GetTextsXMinMax();\n\t\tif( $tres ) {\n\t\t    list($tmin,$tmax) = $tres ;\n\t\t    $min = min($min,$tmin);\n\t\t    $max = max($max,$tmax);\n\t\t}\n\n\t\t$tres = $this->GetTextsXMinMax(true);\n\t\tif( $tres ) {\n\t\t    list($tmin,$tmax) = $tres ;\n\t\t    $min = min($min,$tmin);\n\t\t    $max = max($max,$tmax);\n\t\t}\n\n\t\t$this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor));\n\t    }\n\t\t\t\n\t    //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale\n\t    if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) )\n\t    \t$this->yaxis->SetPos($this->xscale->GetMinVal());\n\t    if( $this->y2axis != null ) {\n\t\tif( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )\n\t\t    $this->y2axis->SetPos($this->xscale->GetMaxVal());\n\t\t$this->y2axis->SetTitleSide(SIDE_RIGHT);\n\t    }\n\n\t    $n = count($this->ynaxis);\n\t    $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;\n\t    for( $i=0; $i < $n; ++$i ) { \n\t\tif( $this->ynaxis[$i] != null ) {\n\t\t    if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) {\n\t\t\t$this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());\n\t\t  $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj);\n\t\t    }\n\t\t    $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);\n\t\t}\n\t    }\n\t}\t\n\telseif( $this->xscale->IsSpecified() &&  \n\t\t( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) {\n\t    // The tick calculation will use the user suplied min/max values to determine\n\t    // the ticks. If auto_ticks is false the exact user specifed min and max\n\t    // values will be used for the scale. \n\t    // If auto_ticks is true then the scale might be slightly adjusted\n\t    // so that the min and max values falls on an even major step.\n\t    $min = $this->xscale->scale[0];\n\t    $max = $this->xscale->scale[1];\n\n\n\t    $this->xscale->AutoScale($this->img,$min,$max,\n\t\t\t\t     $this->img->plotwidth/$this->xtick_factor,\n\t\t\t\t     false);\n\n\t    if( $this->y2axis != null ) {\n\t\tif( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )\n\t\t    $this->y2axis->SetPos($this->xscale->GetMaxVal());\n\t\t$this->y2axis->SetTitleSide(SIDE_RIGHT);\n\t    }\n\n\t}\n\t\t\n\t// If we have a negative values and x-axis position is at 0\n\t// we need to supress the first and possible the last tick since\n\t// they will be drawn on top of the y-axis (and possible y2 axis)\n\t// The test below might seem strange the reasone being that if\n\t// the user hasn't specified a value for position this will not\n\t// be set until we do the stroke for the axis so as of now it\n\t// is undefined.\n\t// For X-text scale we ignore all this since the tick are usually\n\t// much further in and not close to the Y-axis. Hence the test \n\t// for 'text'\t\n\n\tif( ($this->yaxis->pos==$this->xscale->GetMinVal() || \n\t     (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) &&  \n\t    !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && \n\t    substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!=\"min\" ) {\n\n\t    //$this->yscale->ticks->SupressZeroLabel(false);\n\t    $this->xscale->ticks->SupressFirst();\n\t    if( $this->y2axis != null ) {\n\t\t$this->xscale->ticks->SupressLast();\n\t    }\n\t}\n\telseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) {\n\t    $this->xscale->ticks->SupressLast();\n\t}\n\t\n\n\tif( !$_csim ) {\n\t    $this->StrokePlotArea();\n\t    if( $this->iIconDepth == DEPTH_BACK ) {\n\t\t$this->StrokeIcons();\n\t    }\n\t}\n\t$this->StrokeAxis();\n\n\t// Stroke bands\n\tif( $this->bands != null && !$_csim) \n\t    for($i=0; $i < count($this->bands); ++$i) {\n\t\t// Stroke all bands that asks to be in the background\n\t\tif( $this->bands[$i]->depth == DEPTH_BACK )\n\t\t    $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);\n\t    }\n\n\tif( $this->y2bands != null && $this->y2scale != null && !$_csim )\n\t    for($i=0; $i < count($this->y2bands); ++$i) {\n\t\t// Stroke all bands that asks to be in the foreground\n\t\tif( $this->y2bands[$i]->depth == DEPTH_BACK )\n\t\t    $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);\n\t    }\n\n\n\tif( $this->grid_depth == DEPTH_BACK && !$_csim) {\n\t    $this->ygrid->Stroke();\n\t    $this->xgrid->Stroke();\n\t}\n\t\t\t\t\n\t// Stroke Y2-axis \n\tif( $this->y2axis != null && !$_csim) {\t\t\n\t    $this->y2axis->Stroke($this->xscale); \t\t\t\t\n\t    $this->y2grid->Stroke();\n\t}\n\n\t// Stroke yn-axis\n\t$n = count($this->ynaxis); \n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $this->ynaxis[$i]->Stroke($this->xscale); \t\t\t\t\n\t}\n\t\n\t$oldoff=$this->xscale->off;\n\tif(substr($this->axtype,0,4)==\"text\") {\n\t    if( $this->text_scale_abscenteroff > -1 ) {\n\t\t// For a text scale the scale factor is the number of pixel per step. \n\t\t// Hence we can use the scale factor as a substitute for number of pixels\n\t\t// per major scale step and use that in order to adjust the offset so that\n\t\t// an object of width \"abscenteroff\" becomes centered.\n\t\t$this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2);\n\t    }\n\t    else {\n\t\t$this->xscale->off += \n\t\t    ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step);\n\t    }\n\t}\n\n\tif( $this->iDoClipping ) {\n\t    $oldimage = $this->img->CloneCanvasH();\n\t}\n\n\tif( ! $this->y2orderback ) {\n\t    // Stroke all plots for Y axis\n\t    for($i=0; $i < count($this->plots); ++$i) {\n\t\t$this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);\n\t\t$this->plots[$i]->StrokeMargin($this->img);\n\t    }\t\t\t\t\t\t\n\t}\n\n\t// Stroke all plots for Y2 axis\n\tif( $this->y2scale != null )\n\t    for($i=0; $i< count($this->y2plots); ++$i ) {\t\n\t\t$this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale);\n\t    }\t\t\n\n\tif( $this->y2orderback ) {\n\t    // Stroke all plots for Y1 axis\n\t    for($i=0; $i < count($this->plots); ++$i) {\n\t\t$this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);\n\t\t$this->plots[$i]->StrokeMargin($this->img);\n\t    }\t\t\t\t\t\t\n\t}\n\n\t$n = count($this->ynaxis); \n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $m = count($this->ynplots[$i]);\n\t    for( $j=0; $j < $m; ++$j ) { \n\t\t$this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]);\n\t\t$this->ynplots[$i][$j]->StrokeMargin($this->img);\n\t    }\n\t}\n\n\tif( $this->iIconDepth == DEPTH_FRONT) {\n\t    $this->StrokeIcons();\n\t}\n\t\n\tif( $this->iDoClipping ) {\n\t    // Clipping only supports graphs at 0 and 90 degrees\n\t    if( $this->img->a == 0 ) {\n\t\t$this->img->CopyCanvasH($oldimage,$this->img->img,\n\t\t\t\t\t$this->img->left_margin,$this->img->top_margin,\n\t\t\t\t\t$this->img->left_margin,$this->img->top_margin,\n\t\t\t\t\t$this->img->plotwidth+1,$this->img->plotheight);\n\t    }\n\t    elseif( $this->img->a == 90 ) {\n\t\t$adj = ($this->img->height - $this->img->width)/2;\n\t\t$this->img->CopyCanvasH($oldimage,$this->img->img,\n\t\t\t\t\t$this->img->bottom_margin-$adj,$this->img->left_margin+$adj,\n\t\t\t\t\t$this->img->bottom_margin-$adj,$this->img->left_margin+$adj,\n\t\t\t\t\t$this->img->plotheight+1,$this->img->plotwidth);\n\t    }\n\t    else {\n\t\tJpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');\n\t    }\n\t    $this->img->Destroy();\n\t    $this->img->SetCanvasH($oldimage);\n\t}\n\n\t$this->xscale->off=$oldoff;\n\t\t\n\tif( $this->grid_depth == DEPTH_FRONT && !$_csim ) {\n\t    $this->ygrid->Stroke();\n\t    $this->xgrid->Stroke();\n\t}\n\n\t// Stroke bands\n\tif( $this->bands!= null )\n\t    for($i=0; $i < count($this->bands); ++$i) {\n\t\t// Stroke all bands that asks to be in the foreground\n\t\tif( $this->bands[$i]->depth == DEPTH_FRONT )\n\t\t    $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);\n\t    }\n\n\tif( $this->y2bands!= null && $this->y2scale != null )\n\t    for($i=0; $i < count($this->y2bands); ++$i) {\n\t\t// Stroke all bands that asks to be in the foreground\n\t\tif( $this->y2bands[$i]->depth == DEPTH_FRONT )\n\t\t    $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);\n\t    }\n\n\n\t// Stroke any lines added\n\tif( $this->lines != null ) {\n\t    for($i=0; $i < count($this->lines); ++$i) {\n\t\t$this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale);\n\t    }\n\t}\n\n\tif( $this->y2lines != null && $this->y2scale != null ) {\n\t    for($i=0; $i < count($this->y2lines); ++$i) {\n\t\t$this->y2lines[$i]->Stroke($this->img,$this->xscale,$this->y2scale);\n\t    }\n\t}\n\n\t// Finally draw the axis again since some plots may have nagged\n\t// the axis in the edges.However we do no stroke the labels again\n\t// since any user defined callback would be called twice. It also\n\t// enhances performance.\n\n\tif( !$_csim )\n\t    $this->StrokeAxis(false);\n\n\tif( $this->y2scale != null && !$_csim ) \n\t    $this->y2axis->Stroke($this->xscale,false); \t\n\t\t\n\tif( !$_csim ) {\n\t    $this->StrokePlotBox();\n\t}\n\t\t\n\t// The titles and legends never gets rotated so make sure\n\t// that the angle is 0 before stroking them\t\t\t\t\n\t$aa = $this->img->SetAngle(0);\n\t$this->StrokeTitles();\n\t$this->footer->Stroke($this->img);\n\t$this->legend->Stroke($this->img);\t\t\n\t$this->img->SetAngle($aa);\t\n\t$this->StrokeTexts();\t\n\t$this->StrokeTables();\n\n\tif( !$_csim ) {\n\n\t    $this->img->SetAngle($aa);\t\n\t\t\t\n\t    // Draw an outline around the image map\t\n\t    if(_JPG_DEBUG) {\n\t\t$this->DisplayClientSideaImageMapAreas();\t\t\n\t    }\n\t    \n\t    // Adjust the appearance of the image\n\t    $this->AdjustSaturationBrightnessContrast();\n\n\t    // Should we do any final image transformation\n\t    if( $this->iImgTrans ) {\n\t\tif( !class_exists('ImgTrans') ) {\n\t\t    require_once('jpgraph_imgtrans.php');\n\t\t    //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');\n\t\t}\n\t       \n\t\t$tform = new ImgTrans($this->img->img);\n\t\t$this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,\n\t\t\t\t\t\t $this->iImgTransDirection,$this->iImgTransHighQ,\n\t\t\t\t\t\t $this->iImgTransMinSize,$this->iImgTransFillColor,\n\t\t\t\t\t\t $this->iImgTransBorder);\n\t    }\n\n\t    // If the filename is given as the special \"__handle\"\n\t    // then the image handler is returned and the image is NOT\n\t    // streamed back\n\t    if( $aStrokeFileName == _IMG_HANDLER ) {\n\t\treturn $this->img->img;\n\t    }\n\t    else {\n\t\t// Finally stream the generated picture\t\t\t\t\t\n\t\t$this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);\t\t\n\t    }\n\t}\n    }\n\n    function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') {\n\t$this->iAxisLblBgType = $aType;\n\t$this->iXAxisLblBgFillColor = $aXFColor;\n\t$this->iXAxisLblBgColor = $aXColor;\n\t$this->iYAxisLblBgFillColor = $aYFColor;\n\t$this->iYAxisLblBgColor = $aYColor;\n    }\n\n//---------------\n// PRIVATE METHODS\t\n\n    function StrokeAxisLabelBackground() {\n\t// Types \n\t// 0 = No background\n\t// 1 = Only X-labels, length of axis\n\t// 2 = Only Y-labels, length of axis\n\t// 3 = As 1 but extends to width of graph\n\t// 4 = As 2 but extends to height of graph\n\t// 5 = Combination of 3 & 4\n\t// 6 = Combination of 1 & 2\n \n\t$t = $this->iAxisLblBgType ;\n\tif( $t < 1 ) return;\n\t// Stroke optional X-axis label background color\n\tif( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) {\n\t    $this->img->PushColor($this->iXAxisLblBgFillColor);\n\t    if( $t == 1 || $t == 6 ) {\n\t\t$xl = $this->img->left_margin;\n\t\t$yu = $this->img->height - $this->img->bottom_margin + 1;\n\t\t$xr = $this->img->width - $this->img->right_margin ;\n\t\t$yl = $this->img->height-1-$this->frame_weight;\n\t    }\n\t    else { // t==3 || t==5\n\t\t$xl = $this->frame_weight;\n\t\t$yu = $this->img->height - $this->img->bottom_margin + 1;\n\t\t$xr = $this->img->width - 1 - $this->frame_weight;\n\t\t$yl = $this->img->height-1-$this->frame_weight;\n\t    }\n\n\t    $this->img->FilledRectangle($xl,$yu,$xr,$yl);\n\t    $this->img->PopColor();\n\n\t    // Check if we should add the vertical lines at left and right edge\n\t    if( $this->iXAxisLblBgColor !== '' ) {\n\t\t$this->img->PushColor($this->iXAxisLblBgColor);\n\t\tif( $t == 1 || $t == 6 ) {\n\t\t    $this->img->Line($xl,$yu,$xl,$yl);\n\t\t    $this->img->Line($xr,$yu,$xr,$yl);\n\t\t}\n\t\telse {\n\t\t    $xl = $this->img->width - $this->img->right_margin ;\n\t\t    $this->img->Line($xl,$yu-1,$xr,$yu-1);\n\t\t}\n\t\t$this->img->PopColor();\n\t    }\n\t}\n\n\tif( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) {\n\t    $this->img->PushColor($this->iYAxisLblBgFillColor);\n\t    if( $t == 2 || $t == 6 ) {\t    \n\t\t$xl = $this->frame_weight;\n\t\t$yu = $this->frame_weight+$this->img->top_margin;\n\t\t$xr = $this->img->left_margin - 1;\n\t\t$yl = $this->img->height - $this->img->bottom_margin + 1;\n\t    }\n\t    else {\n\t\t$xl = $this->frame_weight;\n\t\t$yu = $this->frame_weight;\n\t\t$xr = $this->img->left_margin - 1;\n\t\t$yl = $this->img->height-1-$this->frame_weight;\n\t    }\n\n\t    $this->img->FilledRectangle($xl,$yu,$xr,$yl);\n\t    $this->img->PopColor();\n\n\t    // Check if we should add the vertical lines at left and right edge\n\t    if( $this->iXAxisLblBgColor !== '' ) {\n\t\t$this->img->PushColor($this->iXAxisLblBgColor);\n\t\tif( $t == 2 || $t == 6 ) {\n\t\t    $this->img->Line($xl,$yu-1,$xr,$yu-1);\n\t\t    $this->img->Line($xl,$yl-1,$xr,$yl-1);\t\t    \n\t\t}\n\t\telse {\n\t\t    $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin);\t\t    \n\t\t}\n\t\t$this->img->PopColor();\n\t    }\n\n\t}\n    }\n\n    function StrokeAxis($aStrokeLabels=true) {\n\t\n\tif( $aStrokeLabels ) {\n\t    $this->StrokeAxisLabelBackground();\n\t}\n\n\t// Stroke axis\n\tif( $this->iAxisStyle != AXSTYLE_SIMPLE ) {\n\t    switch( $this->iAxisStyle ) {\n\t        case AXSTYLE_BOXIN :\n\t            $toppos = SIDE_DOWN;\n\t\t    $bottompos = SIDE_UP;\n\t            $leftpos = SIDE_RIGHT;\n\t            $rightpos = SIDE_LEFT;\n\t            break;\n\t\tcase AXSTYLE_BOXOUT :\n\t\t    $toppos = SIDE_UP;\n\t            $bottompos = SIDE_DOWN;\t    \n\t            $leftpos = SIDE_LEFT;\n\t\t    $rightpos = SIDE_RIGHT;\n\t            break;\n\t\tcase AXSTYLE_YBOXIN:\n\t            $toppos = -100;\n\t\t    $bottompos = SIDE_UP;\n\t            $leftpos = SIDE_RIGHT;\n\t            $rightpos = SIDE_LEFT;\n\t\t    break;\n\t\tcase AXSTYLE_YBOXOUT:\n\t\t    $toppos = -100;\n\t            $bottompos = SIDE_DOWN;\t    \n\t            $leftpos = SIDE_LEFT;\n\t\t    $rightpos = SIDE_RIGHT;\n\t\t    break;\n\t\tdefault:\n\t            JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);\n\t            break;\n\t    }\n\t    $this->xaxis->SetPos('min');\n\t    \n\t    // By default we hide the first label so it doesn't cross the\n\t    // Y-axis in case the positon hasn't been set by the user.\n\t    // However, if we use a box we always want the first value\n\t    // displayed so we make sure it will be displayed.\n\t    $this->xscale->ticks->SupressFirst(false);\n\t    \n\t    $this->xaxis->SetLabelSide(SIDE_DOWN);\n\t    $this->xaxis->scale->ticks->SetSide($bottompos);\n\t    $this->xaxis->Stroke($this->yscale);\n\n\t    if( $toppos != -100 ) {\n\t\t// To avoid side effects we work on a new copy\n\t\t$maxis = $this->xaxis;\n\t\t$maxis->SetPos('max');\n\t\t$maxis->SetLabelSide(SIDE_UP);\n\t\t$maxis->SetLabelMargin(7);\n\t\t$this->xaxis->scale->ticks->SetSide($toppos);\n\t\t$maxis->Stroke($this->yscale);\n\t    }\n\n\t    $this->yaxis->SetPos('min');\n\t    $this->yaxis->SetLabelMargin(10);\n\t    $this->yaxis->SetLabelSide(SIDE_LEFT);\n\t    $this->yaxis->scale->ticks->SetSide($leftpos);\n\t    $this->yaxis->Stroke($this->xscale);\n\n\t    $myaxis = $this->yaxis;\n\t    $myaxis->SetPos('max');\n\t    $myaxis->SetLabelMargin(10);\n\t    $myaxis->SetLabelSide(SIDE_RIGHT);\n\t    $myaxis->title->Set('');\n\t    $myaxis->scale->ticks->SetSide($rightpos);\n\t    $myaxis->Stroke($this->xscale);\n\t    \n\t}\n\telse {\n\t    $this->xaxis->Stroke($this->yscale,$aStrokeLabels);\n\t    $this->yaxis->Stroke($this->xscale,$aStrokeLabels);\t\t\n\t}\n    }\n\n\n    // Private helper function for backgound image\n    function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') {\n\tif( $aImgStr != '' ) {\n\t    return Image::CreateFromString($aImgStr);\n\t}\n\tif( $aFile == '' )\n\t    $aFile = $this->background_image;\n\t// Remove case sensitivity and setup appropriate function to create image\n\t// Get file extension. This should be the LAST '.' separated part of the filename\n\t$e = explode('.',$aFile);\n\t$ext = strtolower($e[count($e)-1]);\n\tif ($ext == \"jpeg\")  {\n\t    $ext = \"jpg\";\n\t}\n\t\n\tif( trim($ext) == '' ) \n\t    $ext = 'png';  // Assume PNG if no extension specified\n\n\tif( $aImgFormat == '' )\n\t    $imgtag = $ext;\n\telse\n\t    $imgtag = $aImgFormat;\n\n\t$supported = imagetypes();\n\tif( ( $ext == 'jpg' && !($supported & IMG_JPG) ) ||\n\t    ( $ext == 'gif' && !($supported & IMG_GIF) ) ||\n\t    ( $ext == 'png' && !($supported & IMG_PNG) ) ) {\n\t    JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');\n\t}\n\n\n\tif( $imgtag == \"jpg\" || $imgtag == \"jpeg\")\n\t{\n\t    $f = \"imagecreatefromjpeg\";\n\t    $imgtag = \"jpg\";\n\t}\n\telse\n\t{\n\t    $f = \"imagecreatefrom\".$imgtag;\n\t}\n\n\t// Compare specified image type and file extension\n\tif( $imgtag != $ext ) {\n\t    //$t = \"Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '\".$aImgFormat.\"'File: '\".$aFile.\"'\";\n\t    JpGraphError::RaiseL(25038, $aImgFormat, $aFile);\n\t}\n\n\t$img = @$f($aFile);\n\tif( !$img ) {\n\t    JpGraphError::RaiseL(25039,$aFile);//(\" Can't read background image: '\".$aFile.\"'\");   \n\t}\n\treturn $img;\n    }\t\n\n    function StrokeBackgroundGrad() {\n\tif( $this->bkg_gradtype < 0  ) \n\t    return;\n\t$grad = new Gradient($this->img);\n\tif( $this->bkg_gradstyle == BGRAD_PLOT ) {\n\t    $xl = $this->img->left_margin;\n\t    $yt = $this->img->top_margin;\n\t    $xr = $xl + $this->img->plotwidth+1 ;\n\t    $yb = $yt + $this->img->plotheight ;\n\t    $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);\n\t}\n\telse {\n\t    $xl = 0;\n\t    $yt = 0;\n\t    $xr = $xl + $this->img->width - 1;\n\t    $yb = $yt + $this->img->height;\n\t    if( $this->doshadow  ) {\n\t\t$xr -= $this->shadow_width; \n\t\t$yb -= $this->shadow_width; \n\t    }\n\t    if( $this->doframe ) {\n\t\t$yt += $this->frame_weight;\n\t\t$yb -= $this->frame_weight;\n\t\t$xl += $this->frame_weight;\n\t\t$xr -= $this->frame_weight;\n\t    }\n\t    $aa = $this->img->SetAngle(0);\n\t    $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);\n\t    $aa = $this->img->SetAngle($aa);\n\t}\n    }\n\n    function StrokeFrameBackground() {\n\tif( $this->background_image != \"\" && $this->background_cflag != \"\" ) {\n\t    JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.');\n\t}\n\tif( $this->background_image != \"\" ) {\n\t    $bkgimg = $this->LoadBkgImage($this->background_image_format);\n\t    $this->img->_AdjBrightContrast($bkgimg,$this->background_image_bright,\n\t\t\t\t\t   $this->background_image_contr);\n\t    $this->img->_AdjSat($bkgimg,$this->background_image_sat);\n\t}\n\telseif( $this->background_cflag != \"\" ) {\n\t    if( ! class_exists('FlagImages') ) {\n\t\tJpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the \"jpgraph_flags.php\" file.');\n\t    }\n\t    $fobj = new FlagImages(FLAGSIZE4);\n\t    $dummy='';\n\t    $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy);\n\t    $this->background_image_mix = $this->background_cflag_mix;\n\t    $this->background_image_type = $this->background_cflag_type;\n\t}\n\telse {\n\t    return ;\n\t}\n\n\t$bw = ImageSX($bkgimg);\n\t$bh = ImageSY($bkgimg);\n\n\t// No matter what the angle is we always stroke the image and frame\n\t// assuming it is 0 degree\n\t$aa = $this->img->SetAngle(0);\n\t\t\n\tswitch( $this->background_image_type ) {\n\t    case BGIMG_FILLPLOT: // Resize to just fill the plotarea\n\t\t$this->FillMarginArea();\n\t\t$this->StrokeFrame();\n\t\t$this->FillPlotArea();\n\t\t$this->img->CopyMerge($bkgimg,\n\t\t\t\t $this->img->left_margin,$this->img->top_margin,\n\t\t\t\t 0,0,$this->img->plotwidth+1,$this->img->plotheight,\n\t\t\t\t $bw,$bh,$this->background_image_mix);\n\t\tbreak;\n\t    case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit\n\t\t$hadj=0; $vadj=0;\n\t\tif( $this->doshadow ) {\n\t\t    $hadj = $this->shadow_width;\n\t\t    $vadj = $this->shadow_width;\n\t\t}\n\t\t$this->FillMarginArea();\n\t\t$this->FillPlotArea();\n\t\t$this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj,\n\t\t\t\t      $bw,$bh,$this->background_image_mix);\n\t\t$this->StrokeFrame();\n\t\tbreak;\n\t    case BGIMG_COPY: // Just copy the image from left corner, no resizing\n\t\t$this->FillMarginArea();\n\t\t$this->FillPlotArea();\n\t\t$this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh,\n\t\t\t\t      $bw,$bh,$this->background_image_mix);\n\t\t$this->StrokeFrame();\n\t\tbreak;\n\t    case BGIMG_CENTER: // Center original image in the plot area\n\t\t$this->FillMarginArea();\n\t\t$this->FillPlotArea();\n\t\t$centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2);\n\t\t$centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2);\n\t\t$this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh,\n\t\t\t\t      $bw,$bh,$this->background_image_mix);\n\t\t$this->StrokeFrame();\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(25042);//(\" Unknown background image layout\");\n\t}\t\t\t\n\t$this->img->SetAngle($aa);\t\t\n    }\n\n    // Private\n    // Draw a frame around the image\n    function StrokeFrame() {\n\tif( !$this->doframe ) return;\n\n\tif( $this->background_image_type <= 1 && \n\t    ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { \n\t    $c = $this->margin_color;\n\t}\n\telse {\n\t    $c = false;\n\t}\n\t\n\tif( $this->doshadow ) {\n\t    $this->img->SetColor($this->frame_color);\t\t\t\n\t    $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,\n\t\t\t\t\t$c,$this->shadow_width,$this->shadow_color);\n\t}\n\telseif( $this->framebevel ) {\n\t    if( $c ) {\n\t\t$this->img->SetColor($this->margin_color);\n\t\t$this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); \n\t    }\n\t    $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,\n\t\t\t      $this->framebeveldepth,\n\t\t\t      $this->framebevelcolor1,$this->framebevelcolor2);\n\t    if( $this->framebevelborder ) {\n\t\t$this->img->SetColor($this->framebevelbordercolor);\n\t\t$this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);\n\t    }\n\t}\n\telse {\n\t    $this->img->SetLineWeight($this->frame_weight);\n\t    if( $c ) {\n\t\t$this->img->SetColor($this->margin_color);\n\t\t$this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); \n\t    }\n\t    $this->img->SetColor($this->frame_color);\n\t    $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);\t\t\n\t}\n    }\n\n    function FillMarginArea() {\n\t$hadj=0; $vadj=0;\n\tif( $this->doshadow ) {\n\t    $hadj = $this->shadow_width;\n\t    $vadj = $this->shadow_width;\n\t}\n\n\t$this->img->SetColor($this->margin_color);\n//\t$this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); \n\n\t$this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); \n\t$this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); \n\t$this->img->FilledRectangle($this->img->left_margin+1,\n\t\t\t\t    $this->img->height-$this->img->bottom_margin,\n\t\t\t\t    $this->img->width-1-$hadj,\n\t\t\t\t    $this->img->height-1-$hadj); \n\t$this->img->FilledRectangle($this->img->width-$this->img->right_margin,\n\t\t\t\t    $this->img->top_margin+1,\n\t\t\t\t    $this->img->width-1-$hadj,\n\t\t\t\t    $this->img->height-$this->img->bottom_margin-1); \n    }\n\n    function FillPlotArea() {\n\t$this->img->PushColor($this->plotarea_color);\n\t$this->img->FilledRectangle($this->img->left_margin,\n\t\t\t\t    $this->img->top_margin,\n\t\t\t\t    $this->img->width-$this->img->right_margin,\n\t\t\t\t    $this->img->height-$this->img->bottom_margin);\t\n\t$this->img->PopColor();\n    }\n    \n    // Stroke the plot area with either a solid color or a background image\n    function StrokePlotArea() {\n\t// Note: To be consistent we really should take a possible shadow\n\t// into account. However, that causes some problem for the LinearScale class\n\t// since in the current design it does not have any links to class Graph which\n\t// means it has no way of compensating for the adjusted plotarea in case of a \n\t// shadow. So, until I redesign LinearScale we can't compensate for this.\n\t// So just set the two adjustment parameters to zero for now.\n\t$boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;\n\t$adj = 0; //$this->doshadow ? $this->shadow_width : 0 ;\n\n\tif( $this->background_image != \"\" || $this->background_cflag != \"\" ) {\n\t    $this->StrokeFrameBackground();\n\t}\n\telse {\n\t    $aa = $this->img->SetAngle(0);\n\t    $this->StrokeFrame();\n\t    $aa = $this->img->SetAngle($aa);\n\t    $this->StrokeBackgroundGrad();\n\t    if( $this->bkg_gradtype < 0 || \n\t\t($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) {\n\t\t$this->FillPlotArea();\n\t    }\n\t}\t\n    }\t\n\n    function StrokeIcons() {\n\t$n = count($this->iIcons);\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);\n\t}\n    }\n\t\n    function StrokePlotBox() {\n\t// Should we draw a box around the plot area?\n\tif( $this->boxed ) {\n\t    $this->img->SetLineWeight(1);\n\t    $this->img->SetLineStyle('solid');\n\t    $this->img->SetColor($this->box_color);\n\t    for($i=0; $i < $this->box_weight; ++$i ) {\n\t\t$this->img->Rectangle(\n\t\t    $this->img->left_margin-$i,$this->img->top_margin-$i,\n\t\t    $this->img->width-$this->img->right_margin+$i,\n\t\t    $this->img->height-$this->img->bottom_margin+$i);\n\t    }\n\t}\t\t\t\t\t\t\n    }\t\t\n\n    function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') {\n\t$this->titlebkg_fillstyle = $aStyle;\n\t$this->titlebkg_scolor1 = $aColor1;\n\t$this->titlebkg_scolor2 = $aColor2;\n    }\n\n    function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) {\n\t$this->titlebackground = $aEnable;\n\t$this->titlebackground_color = $aBackColor;\n\t$this->titlebackground_style = $aStyle;\n\t$this->titlebackground_framecolor = $aFrameColor;\n\t$this->titlebackground_framestyle = $aFrameStyle;\n\t$this->titlebackground_frameweight = $aFrameWeight;\t\n\t$this->titlebackground_bevelheight = $aBevelHeight ;\n    }\n\n\n    function StrokeTitles() {\n\n\t$margin=3;\n\n\tif( $this->titlebackground ) {\n\n\t    // Find out height\n\t    $this->title->margin += 2 ;\n\t    $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin;\n\t    if( $this->subtitle->t != \"\" && !$this->subtitle->hide ) {\n\t\t$h += $this->subtitle->GetTextHeight($this->img)+$margin+\n\t\t    $this->subtitle->margin;\n\t\t$h += 2;\n\t    }\n\t    if( $this->subsubtitle->t != \"\" && !$this->subsubtitle->hide ) {\n\t\t$h += $this->subsubtitle->GetTextHeight($this->img)+$margin+\n\t\t    $this->subsubtitle->margin;\n\t\t$h += 2;\n\t    }\n\t    $this->img->PushColor($this->titlebackground_color);\n\t    if( $this->titlebackground_style === TITLEBKG_STYLE1 ) {\n\t\t// Inside the frame\n\t\tif( $this->framebevel ) {\n\t\t    $x1 = $y1 = $this->framebeveldepth + 1 ;\n\t\t    $x2 = $this->img->width - $this->framebeveldepth - 2 ; \n\t\t    $this->title->margin += $this->framebeveldepth + 1 ;\n\t\t    $h += $y1 ;\n\t\t    $h += 2;\n\t\t}\n\t\telse {\n\t\t    $x1 = $y1 = $this->frame_weight;\n\t\t    $x2 = $this->img->width - 2*$x1;\n\t\t}\n\t    }\n\t    elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) {\n\t\t// Cover the frame as well\n\t\t$x1 = $y1 = 0;\n\t\t$x2 = $this->img->width - 1 ;\n\t    }\n\t    elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) {\n\t\t// Cover the frame as well (the difference is that\n\t\t// for style==3 a bevel frame border is on top\n\t\t// of the title background)\n\t\t$x1 = $y1 = 0;\n\t\t$x2 = $this->img->width - 1 ;\n\t\t$h += $this->framebeveldepth ;\n\t\t$this->title->margin += $this->framebeveldepth ;\n\t    }\n\t    else {\n\t\tJpGraphError::RaiseL(25043);//('Unknown title background style.');\n\t    }\n\n\t    if( $this->titlebackground_framestyle === 3 ) {\n\t\t$h += $this->titlebackground_bevelheight*2 + 1  ;\n\t\t$this->title->margin += $this->titlebackground_bevelheight ;\n\t    }\n\n\t    if( $this->doshadow ) {\n\t\t$x2 -= $this->shadow_width ;\n\t    }\n\t    \n\t    $indent=0;\n\t    if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {\n\t\t$ind = $this->titlebackground_bevelheight;\n\t    }\n\n\t    if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) {\n\t\t$this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind,\n\t\t\t\t\t     $this->titlebkg_scolor1,\n\t\t\t\t\t     $this->titlebkg_scolor2);\n\t    }\n\t    elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) {\n\t\t$this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind,\n\t\t\t\t\t     $this->titlebkg_scolor1,\n\t\t\t\t\t     $this->titlebkg_scolor2,2);\n\t    }\n\t    else {\n\t\t// Solid fill\n\t\t$this->img->FilledRectangle($x1,$y1,$x2,$h);\n\t    }\n\t    $this->img->PopColor();\n\n\t    $this->img->PushColor($this->titlebackground_framecolor);\n\t    $this->img->SetLineWeight($this->titlebackground_frameweight);\n\t    if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) {\n\t\t// Frame background\n\t\t$this->img->Rectangle($x1,$y1,$x2,$h);\n\t    }\n\t    elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) {\n\t\t// Bottom line only\n\t\t$this->img->Line($x1,$h,$x2,$h);\n\t    }\n\t    elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {\n\t\t$this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight);\n\t    }\n\t    $this->img->PopColor();\n\n\t    // This is clumsy. But we neeed to stroke the whole graph frame if it is\n\t    // set to bevel to get the bevel shading on top of the text background\n\t    if( $this->framebevel && $this->doframe && \n\t\t$this->titlebackground_style === 3 ) {\n\t\t$this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,\n\t\t\t\t  $this->framebeveldepth,\n\t\t\t\t  $this->framebevelcolor1,$this->framebevelcolor2);\n\t\tif( $this->framebevelborder ) {\n\t\t    $this->img->SetColor($this->framebevelbordercolor);\n\t\t    $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);\n\t\t}\n\t    }\n\t}\n\n\t// Stroke title\n\t$y = $this->title->margin; \n\tif( $this->title->halign == 'center' ) \n\t    $this->title->Center(0,$this->img->width,$y);\n\telseif( $this->title->halign == 'left' ) {\n\t    $this->title->SetPos($this->title->margin+2,$y);\n\t}\n\telseif( $this->title->halign == 'right' ) {\n\t    $indent = 0;\n\t    if( $this->doshadow ) \n\t\t$indent = $this->shadow_width+2;\n\t    $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right');\t    \n\t}\n\t$this->title->Stroke($this->img);\n\t\t\n\t// ... and subtitle\n\t$y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;\n\tif( $this->subtitle->halign == 'center' ) \n\t    $this->subtitle->Center(0,$this->img->width,$y);\n\telseif( $this->subtitle->halign == 'left' ) {\n\t    $this->subtitle->SetPos($this->subtitle->margin+2,$y);\n\t}\n\telseif( $this->subtitle->halign == 'right' ) {\n\t    $indent = 0;\n\t    if( $this->doshadow ) \n\t\t$indent = $this->shadow_width+2;\n\t    $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); \n\t}\n\t$this->subtitle->Stroke($this->img);\n\n\t// ... and subsubtitle\n\t$y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;\n\tif( $this->subsubtitle->halign == 'center' ) \n\t    $this->subsubtitle->Center(0,$this->img->width,$y);\n\telseif( $this->subsubtitle->halign == 'left' ) {\n\t    $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y);\n\t}\n\telseif( $this->subsubtitle->halign == 'right' ) {\n\t    $indent = 0;\n\t    if( $this->doshadow ) \n\t\t$indent = $this->shadow_width+2;\n\t    $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); \n\t}\n\t$this->subsubtitle->Stroke($this->img);\n\n\t// ... and fancy title\n\t$this->tabtitle->Stroke($this->img);\n\n    }\n\n    function StrokeTexts() {\n\t// Stroke any user added text objects\n\tif( $this->texts != null ) {\n\t    for($i=0; $i < count($this->texts); ++$i) {\n\t\t$this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);\n\t    }\n\t}\n\n\tif( $this->y2texts != null && $this->y2scale != null ) {\n\t    for($i=0; $i < count($this->y2texts); ++$i) {\n\t\t$this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale);\n\t    }\n\t}\n\n    }\n\n    function StrokeTables() {\n\tif( $this->iTables != null ) {\n\t    $n = count($this->iTables);\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);\n\t    }\n\t}\n    }\n\n    function DisplayClientSideaImageMapAreas() {\n\t// Debug stuff - display the outline of the image map areas\n\t$csim='';\n\tforeach ($this->plots as $p) {\n\t    $csim.= $p->GetCSIMareas();\n\t}\n\t$csim .= $this->legend->GetCSIMareas();\n\tif (preg_match_all(\"/area shape=\\\"(\\w+)\\\" coords=\\\"([0-9\\, ]+)\\\"/\", $csim, $coords)) {\n\t    $this->img->SetColor($this->csimcolor);\n\t    $n = count($coords[0]);\n\t    for ($i=0; $i < $n; $i++) {\n\t\tif ($coords[1][$i]==\"poly\") {\n\t\t    preg_match_all('/\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,*/',$coords[2][$i],$pts);\n\t\t    $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);\n\t\t    $m = count($pts[0]);\n\t\t    for ($j=0; $j < $m; $j++) {\n\t\t\t$this->img->LineTo($pts[1][$j],$pts[2][$j]);\n\t\t    }\n\t\t} else if ($coords[1][$i]==\"rect\") {\n\t\t    $pts = preg_split('/,/', $coords[2][$i]);\n\t\t    $this->img->SetStartPoint($pts[0],$pts[1]);\n\t\t    $this->img->LineTo($pts[2],$pts[1]);\n\t\t    $this->img->LineTo($pts[2],$pts[3]);\n\t\t    $this->img->LineTo($pts[0],$pts[3]);\n\t\t    $this->img->LineTo($pts[0],$pts[1]);\t\t\t\t\t\n\t\t}\n\t    }\n\t}\n    }\n\n    function AdjustSaturationBrightnessContrast() {\n\t// Adjust the brightness and contrast of the image\n\tif( $this->image_contr || $this->image_bright )\n\t    $this->img->AdjBrightContrast($this->image_bright,$this->image_contr);\n\tif( $this->image_sat )\t\t\t\t\t\t\t\t\t\t\t \n\t    $this->img->AdjSat($this->image_sat);\n    }\n\n    // Text scale offset in fractions of a major scale step\n    function SetTextScaleOff($aOff) {\n\t$this->text_scale_off = $aOff;\n\t$this->xscale->text_scale_off = $aOff;\n    }\n\n    // Text width of bar to be centered in absolute pixels\n    function SetTextScaleAbsCenterOff($aOff) {\n\t$this->text_scale_abscenteroff = $aOff;\n    }\n\n    // Get Y min and max values for added lines\n    function GetLinesYMinMax( $aLines ) {\n\t$n = count($aLines);\n\tif( $n == 0 ) return false;\n\t$min = $aLines[0]->scaleposition ;\n\t$max = $min ;\n\t$flg = false;\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    if( $aLines[$i]->direction == HORIZONTAL ) {\n\t\t$flg = true ;\n\t\t$v = $aLines[$i]->scaleposition ;\n\t\tif( $min > $v ) $min = $v ;\n\t\tif( $max < $v ) $max = $v ;\n\t    }\n\t}\n\treturn $flg ? array($min,$max) : false ;\n    }\n\n    // Get X min and max values for added lines\n    function GetLinesXMinMax( $aLines ) {\n\t$n = count($aLines);\n\tif( $n == 0 ) return false ;\n\t$min = $aLines[0]->scaleposition ;\n\t$max = $min ;\n\t$flg = false;\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    if( $aLines[$i]->direction == VERTICAL ) {\n\t\t$flg = true ;\n\t\t$v = $aLines[$i]->scaleposition ;\n\t\tif( $min > $v ) $min = $v ;\n\t\tif( $max < $v ) $max = $v ;\n\t    }\n\t}\n\treturn $flg ? array($min,$max) : false ;\n    }\n\n    // Get min and max values for all included plots\n    function GetPlotsYMinMax(&$aPlots) {\n\t$n = count($aPlots);\n\t$i=0;\n\tdo {\n\t    list($xmax,$max) = $aPlots[$i]->Max();\n\t} while( ++$i < $n && !is_numeric($max) );\n\t\n\t$i=0;\n\tdo {\n           list($xmin,$min) = $aPlots[$i]->Min();\n       } while( ++$i < $n && !is_numeric($min) );\n\t\n\tif( !is_numeric($min) || !is_numeric($max) ) {\n\t    JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value  of the Y-axis (only null values).');\n\t}\n\n\tlist($xmax,$max) = $aPlots[0]->Max();\n\tlist($xmin,$min) = $aPlots[0]->Min();\n\tfor($i=0; $i < count($aPlots); ++$i ) {\n\t    list($xmax,$ymax)=$aPlots[$i]->Max();\n\t    list($xmin,$ymin)=$aPlots[$i]->Min();\n\t    if (is_numeric($ymax)) $max=max($max,$ymax);\n\t    if (is_numeric($ymin)) $min=min($min,$ymin);\n\t}\n\tif( $min == '' ) $min = 0;\n\tif( $max == '' ) $max = 0;\n\tif( $min == 0 && $max == 0 ) {\n\t    // Special case if all values are 0\n\t    $min=0;$max=1;\t\t\t\n\t}\n\treturn array($min,$max);\n    }\n\n} // Class\n\n\n//===================================================\n// CLASS TTF\n// Description: Handle TTF font names\n//===================================================\nclass TTF {\n    var $font_files,$style_names;\n//---------------\n// CONSTRUCTOR\n    function TTF() {\n\t$this->style_names=array(FS_NORMAL=>'normal',FS_BOLD=>'bold',FS_ITALIC=>'italic',FS_BOLDITALIC=>'bolditalic');\n\t// File names for available fonts\n\t$this->font_files=array(\n\t    FF_COURIER => array(FS_NORMAL=>'cour.ttf', FS_BOLD=>'courbd.ttf', FS_ITALIC=>'couri.ttf', FS_BOLDITALIC=>'courbi.ttf' ),\n\t    FF_GEORGIA => array(FS_NORMAL=>'georgia.ttf', FS_BOLD=>'georgiab.ttf', FS_ITALIC=>'georgiai.ttf', FS_BOLDITALIC=>'' ),\n\t    FF_TREBUCHE =>array(FS_NORMAL=>'trebuc.ttf', FS_BOLD=>'trebucbd.ttf',   FS_ITALIC=>'trebucit.ttf', FS_BOLDITALIC=>'trebucbi.ttf' ),\n\t    FF_VERDANA => array(FS_NORMAL=>'verdana.ttf', FS_BOLD=>'verdanab.ttf',  FS_ITALIC=>'verdanai.ttf', FS_BOLDITALIC=>'' ),\n\t    FF_TIMES =>   array(FS_NORMAL=>'times.ttf',   FS_BOLD=>'timesbd.ttf',   FS_ITALIC=>'timesi.ttf',   FS_BOLDITALIC=>'timesbi.ttf' ),\n\t    FF_COMIC =>   array(FS_NORMAL=>'comic.ttf',   FS_BOLD=>'comicbd.ttf',   FS_ITALIC=>'',         FS_BOLDITALIC=>'' ),\n\t    FF_ARIAL =>   array(FS_NORMAL=>'arial.ttf',   FS_BOLD=>'arialbd.ttf',   FS_ITALIC=>'ariali.ttf',   FS_BOLDITALIC=>'arialbi.ttf' ) ,\n\t    FF_VERA =>    array(FS_NORMAL=>'Vera.ttf',   FS_BOLD=>'VeraBd.ttf',   FS_ITALIC=>'VeraIt.ttf',   FS_BOLDITALIC=>'VeraBI.ttf' ),\n\t    FF_VERAMONO => array(FS_NORMAL=>'VeraMono.ttf', FS_BOLD=>'VeraMoBd.ttf', FS_ITALIC=>'VeraMoIt.ttf', FS_BOLDITALIC=>'VeraMoBI.ttf' ),\n\t    FF_VERASERIF => array(FS_NORMAL=>'VeraSe.ttf', FS_BOLD=>'VeraSeBd.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' ) ,\n\t    FF_SIMSUN =>  array(FS_NORMAL=>'simsun.ttc',  FS_BOLD=>'simhei.ttf',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' ),\n\t    FF_CHINESE => array(FS_NORMAL=>CHINESE_TTF_FONT, FS_BOLD=>'', FS_ITALIC=>'', FS_BOLDITALIC=>'' ),\n \t    FF_MINCHO =>  array(FS_NORMAL=>MINCHO_TTF_FONT,  FS_BOLD=>'',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' ),\n \t    FF_PMINCHO => array(FS_NORMAL=>PMINCHO_TTF_FONT,  FS_BOLD=>'',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' ),    \n \t    FF_GOTHIC  => array(FS_NORMAL=>GOTHIC_TTF_FONT,  FS_BOLD=>'',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' ),    \n \t    FF_PGOTHIC => array(FS_NORMAL=>PGOTHIC_TTF_FONT,  FS_BOLD=>'',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' ),    \n \t    FF_MINCHO =>  array(FS_NORMAL=>PMINCHO_TTF_FONT,  FS_BOLD=>'',   FS_ITALIC=>'',   FS_BOLDITALIC=>'' )   \n);\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    // Create the TTF file from the font specification\n    function File($family,$style=FS_NORMAL) {\n\t\n\tif( $family == FF_HANDWRT || $family==FF_BOOK ) {\n\t    JpGraphError::RaiseL(25045);//('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/');\n\t}\n\n\t$fam = @$this->font_files[$family];\n\tif( !$fam ) {\n\t    JpGraphError::RaiseL(25046,$family);//(\"Specified TTF font family (id=$family) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/\");\n\t}\n\t$f = @$fam[$style];\n\n\tif( $f==='' )\n\t    JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style \"'.$this->style_names[$style].'\" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.');\n\tif( !$f ) {\n\t    JpGraphError::RaiseL(25048,$fam);//(\"Unknown font style specification [$fam].\");\n\t}\n\n\tif ($family >= FF_MINCHO && $family <= FF_PGOTHIC) {\n\t    $f = MBTTF_DIR.$f;\n\t} else {\n\t    $f = TTF_DIR.$f;\n\t}\n\n\tif( file_exists($f) === false || is_readable($f) === false ) {\n\t    JpGraphError::RaiseL(25049,$f);//(\"Font file \\\"$f\\\" is not readable or does not exist.\");\n\t}\n\treturn $f;\n    }\n} // Class\n\n//===================================================\n// CLASS LineProperty\n// Description: Holds properties for a line\n//===================================================\nclass LineProperty {\n    var $iWeight=1, $iColor=\"black\",$iStyle=\"solid\";\n    var $iShow=true;\n\t\n//---------------\n// PUBLIC METHODS\t\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\t\n    function SetWeight($aWeight) {\n\t$this->iWeight = $aWeight;\n    }\n\t\n    function SetStyle($aStyle) {\n\t$this->iStyle = $aStyle;\n    }\n\t\t\n    function Show($aShow=true) {\n\t$this->iShow=$aShow;\n    }\n\t\n    function Stroke(&$aImg,$aX1,$aY1,$aX2,$aY2) {\n\tif( $this->iShow ) {\n\t    $aImg->PushColor($this->iColor);\n\t    $oldls = $aImg->line_style;\n\t    $oldlw = $aImg->line_weight;\n\t    $aImg->SetLineWeight($this->iWeight);\n\t    $aImg->SetLineStyle($this->iStyle);\t\t\t\n\t    $aImg->StyleLine($aX1,$aY1,$aX2,$aY2);\n\t    $aImg->PopColor($this->iColor);\n\t    $aImg->line_style = $oldls;\n\t    $aImg->line_weight = $oldlw;\n\n\t}\n    }\n}\n\n\n//===================================================\n// CLASS Text\n// Description: Arbitrary text object that can be added to the graph\n//===================================================\nclass Text {\n    var $t,$x=0,$y=0,$halign=\"left\",$valign=\"top\",$color=array(0,0,0);\n    var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12;\n    var $hide=false, $dir=0;\n    var $boxed=false;\t// Should the text be boxed\n    var $paragraph_align=\"left\";\n    var $margin=0;\n    var $icornerradius=0,$ishadowwidth=3;\n    var $iScalePosY=null,$iScalePosX=null;\n    var $iWordwrap=0;\n    var $fcolor='white',$bcolor='black',$shadow=false;\n    var $iCSIMarea='',$iCSIMalt='',$iCSIMtarget='';\n\n//---------------\n// CONSTRUCTOR\n\n    // Create new text at absolute pixel coordinates\n    function Text($aTxt=\"\",$aXAbsPos=0,$aYAbsPos=0) {\n\tif( ! is_string($aTxt) ) {\n\t    JpGraphError::RaiseL(25050);//('First argument to Text::Text() must be s atring.');\n\t}\n\t$this->t = $aTxt;\n\t$this->x = round($aXAbsPos);\n\t$this->y = round($aYAbsPos);\n\t$this->margin = 0;\n    }\n//---------------\n// PUBLIC METHODS\t\n    // Set the string in the text object\n    function Set($aTxt) {\n\t$this->t = $aTxt;\n    }\n\t\n    // Alias for Pos()\n    function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign=\"left\",$aVAlign=\"top\") {\n\t$this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign);\n    }\n    \n    // Specify the position and alignment for the text object\n    function Pos($aXAbsPos=0,$aYAbsPos=0,$aHAlign=\"left\",$aVAlign=\"top\") {\n\t$this->x = $aXAbsPos;\n\t$this->y = $aYAbsPos;\n\t$this->halign = $aHAlign;\n\t$this->valign = $aVAlign;\n    }\n\n    function SetScalePos($aX,$aY) {\n\t$this->iScalePosX = $aX;\n\t$this->iScalePosY = $aY;\n    }\n\t\n    // Specify alignment for the text\n    function Align($aHAlign,$aVAlign=\"top\",$aParagraphAlign=\"\") {\n\t$this->halign = $aHAlign;\n\t$this->valign = $aVAlign;\n\tif( $aParagraphAlign != \"\" )\n\t    $this->paragraph_align = $aParagraphAlign;\n    }\t\t\n    \n    // Alias\n    function SetAlign($aHAlign,$aVAlign=\"top\",$aParagraphAlign=\"\") {\n\t$this->Align($aHAlign,$aVAlign,$aParagraphAlign);\n    }\n\n    // Specifies the alignment for a multi line text\n    function ParagraphAlign($aAlign) {\n\t$this->paragraph_align = $aAlign;\n    }\n\n    // Specifies the alignment for a multi line text\n    function SetParagraphAlign($aAlign) {\n\t$this->paragraph_align = $aAlign;\n    }\n\n    function SetShadow($aShadowColor='gray',$aShadowWidth=3) {\n\t$this->ishadowwidth=$aShadowWidth;\n\t$this->shadow=$aShadowColor;\n\t$this->boxed=true;\n    }\n\n    function SetWordWrap($aCol) {\n\t$this->iWordwrap = $aCol ;\n    }\n\t\n    // Specify that the text should be boxed. fcolor=frame color, bcolor=border color,\n    // $shadow=drop shadow should be added around the text.\n    function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) {\n\tif( $aFrameColor==false )\n\t    $this->boxed=false;\n\telse\n\t    $this->boxed=true;\n\t$this->fcolor=$aFrameColor;\n\t$this->bcolor=$aBorderColor;\n\t// For backwards compatibility when shadow was just true or false\n\tif( $aShadowColor === true )\n\t    $aShadowColor = 'gray';\n\t$this->shadow=$aShadowColor;\n\t$this->icornerradius=$aCornerRadius;\n\t$this->ishadowwidth=$aShadowWidth;\n    }\n\t\n    // Hide the text\n    function Hide($aHide=true) {\n\t$this->hide=$aHide;\n    }\n\t\n    // This looks ugly since it's not a very orthogonal design \n    // but I added this \"inverse\" of Hide() to harmonize\n    // with some classes which I designed more recently (especially) \n    // jpgraph_gantt\n    function Show($aShow=true) {\n\t$this->hide=!$aShow;\n    }\n\t\n    // Specify font\n    function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {\n\t$this->font_family=$aFamily;\n\t$this->font_style=$aStyle;\n\t$this->font_size=$aSize;\n    }\n\t\t\t\n    // Center the text between $left and $right coordinates\n    function Center($aLeft,$aRight,$aYAbsPos=false) {\n\t$this->x = $aLeft + ($aRight-$aLeft\t)/2;\n\t$this->halign = \"center\";\n\tif( is_numeric($aYAbsPos) )\n\t    $this->y = $aYAbsPos;\t\t\n    }\n\t\n    // Set text color\n    function SetColor($aColor) {\n\t$this->color = $aColor;\n    }\n\t\n    function SetAngle($aAngle) {\n\t$this->SetOrientation($aAngle);\n    }\n\t\n    // Orientation of text. Note only TTF fonts can have an arbitrary angle\n    function SetOrientation($aDirection=0) {\n\tif( is_numeric($aDirection) )\n\t    $this->dir=$aDirection;\t\n\telseif( $aDirection==\"h\" )\n\t    $this->dir = 0;\n\telseif( $aDirection==\"v\" )\n\t    $this->dir = 90;\n\telse JpGraphError::RaiseL(25051);//(\" Invalid direction specified for text.\");\n    }\n\t\n    // Total width of text\n    function GetWidth(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$w = $aImg->GetTextWidth($this->t,$this->dir);\n\treturn $w;\t\n    }\n\t\n    // Hight of font\n    function GetFontHeight(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$h = $aImg->GetFontHeight();\n\treturn $h;\n\n    }\n\n    function GetTextHeight(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\t\n\t$h = $aImg->GetTextHeight($this->t,$this->dir);\n\treturn $h;\n    }\n\n    function GetHeight(&$aImg) {\n\t// Synonym for GetTextHeight()\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\t\n\t$h = $aImg->GetTextHeight($this->t,$this->dir);\n\treturn $h;\n    }\n\n    // Set the margin which will be interpretated differently depending\n    // on the context.\n    function SetMargin($aMarg) {\n\t$this->margin = $aMarg;\n    }\n\n    function StrokeWithScale(&$aImg,$axscale,$ayscale) {\n\tif( $this->iScalePosX === null ||\n\t    $this->iScalePosY === null ) {\n\t    $this->Stroke($aImg);\n\t}\n\telse {\n\t    $this->Stroke($aImg,\n\t\t\t  round($axscale->Translate($this->iScalePosX)),\n\t\t\t  round($ayscale->Translate($this->iScalePosY)));\n\t}\n    }\n\n    function SetCSIMTarget($aTarget,$aAlt=null) {\n\t$this->iCSIMtarget = $aTarget;\n\t$this->iCSIMalt = $aAlt;\n    }\n\n    function GetCSIMareas() {\n\tif( $this->iCSIMtarget !== '' ) \n\t    return $this->iCSIMarea;\n\telse\n\t    return '';\n    }\n\n    // Display text in image\n    function Stroke(&$aImg,$x=null,$y=null) {\n\n\tif( !empty($x) ) $this->x = round($x);\n\tif( !empty($y) ) $this->y = round($y);\n\n\t// Insert newlines\n\tif( $this->iWordwrap > 0 ) {\n\t    $this->t = wordwrap($this->t,$this->iWordwrap,\"\\n\");\n\t}\n\n\t// If position been given as a fraction of the image size\n\t// calculate the absolute position\n\tif( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width;\n\tif( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height;\n\n\t$aImg->PushColor($this->color);\t\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$aImg->SetTextAlign($this->halign,$this->valign);\n\tif( $this->boxed ) {\n\t    if( $this->fcolor==\"nofill\" ) \n\t\t$this->fcolor=false;\t\t\n\t    $aImg->SetLineWeight(1);\n\t    $bbox = $aImg->StrokeBoxedText($this->x,$this->y,$this->t,\n\t\t\t\t   $this->dir,$this->fcolor,$this->bcolor,$this->shadow,\n\t\t\t\t   $this->paragraph_align,5,5,$this->icornerradius,\n\t\t\t\t   $this->ishadowwidth);\n\t}\n\telse {\n\t    $bbox = $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,$this->paragraph_align);\n\t}\n\n\t// Create CSIM targets\n\t$coords = $bbox[0].','.$bbox[1].','.$bbox[2].','.$bbox[3].','.$bbox[4].','.$bbox[5].','.$bbox[6].','.$bbox[7];\n\t$this->iCSIMarea = \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->iCSIMtarget.\"\\\"\";\n\t$this->iCSIMarea .= \" alt=\\\"\".$this->iCSIMalt.\"\\\" title=\\\"\".$this->iCSIMalt.\"\\\" />\\n\";\n\n\t$aImg->PopColor($this->color);\t\n\n    }\n} // Class\n\nclass GraphTabTitle extends Text{\n    var $corner = 6 , $posx = 7, $posy = 4;\n    var $color='darkred',$fillcolor='lightyellow',$bordercolor='black';\n    var $align = 'left', $width=TABTITLE_WIDTHFIT;\n    function GraphTabTitle() {\n\t$this->t = '';\n\t$this->font_style = FS_BOLD;\n\t$this->hide = true;\n    }\n\n    function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') {\n\t$this->color = $aTxtColor;\n\t$this->fillcolor = $aFillColor;\n\t$this->bordercolor = $aBorderColor;\n    }\n\n    function SetFillColor($aFillColor) {\n\t$this->fillcolor = $aFillColor;\n    }\n\n    function SetTabAlign($aAlign) {\n\t// Synonym for SetPos\n\t$this->align = $aAlign;\n    }\n\n    function SetPos($aAlign) {\n\t$this->align = $aAlign;\n    }\n    \n    function SetWidth($aWidth) {\n\t$this->width = $aWidth ;\n    }\n\n    function Set($t) {\n\t$this->t = $t;\n\t$this->hide = false;\n    }\n\n    function SetCorner($aD) {\n\t$this->corner = $aD ;\n    }\n\n    function Stroke(&$aImg) {\n\tif( $this->hide ) \n\t    return;\n\t$this->boxed = false;\n\t$w = $this->GetWidth($aImg) + 2*$this->posx;\n\t$h = $this->GetTextHeight($aImg) + 2*$this->posy;\n\n\t$x = $aImg->left_margin;\n\t$y = $aImg->top_margin;\n\n\tif( $this->width === TABTITLE_WIDTHFIT ) {\n\t    if( $this->align == 'left' ) {\n\t\t$p = array($x,                $y,\n\t\t\t   $x,                $y-$h+$this->corner,\n\t\t\t   $x + $this->corner,$y-$h,\n\t\t\t   $x + $w - $this->corner, $y-$h,\n\t\t\t   $x + $w, $y-$h+$this->corner,\n\t\t\t   $x + $w, $y);\n\t    }\n\t    elseif( $this->align == 'center' ) {\n\t\t$x += round($aImg->plotwidth/2) - round($w/2);\n\t\t$p = array($x, $y,\n\t\t\t   $x, $y-$h+$this->corner,\n\t\t\t   $x + $this->corner, $y-$h,\n\t\t\t   $x + $w - $this->corner, $y-$h,\n\t\t\t   $x + $w, $y-$h+$this->corner,\n\t\t\t   $x + $w, $y);\n\t    }\n\t    else {\n\t\t$x += $aImg->plotwidth -$w;\n\t\t$p = array($x, $y,\n\t\t\t   $x, $y-$h+$this->corner,\n\t\t\t   $x + $this->corner,$y-$h,\n\t\t\t   $x + $w - $this->corner, $y-$h,\n\t\t\t   $x + $w, $y-$h+$this->corner,\n\t\t\t   $x + $w, $y);\n\t    }\n\t}\n\telse {\n\t    if( $this->width === TABTITLE_WIDTHFULL )\n\t\t$w = $aImg->plotwidth ;\n\t    else\n\t\t$w = $this->width ;\n\n\t    // Make the tab fit the width of the plot area\n\t    $p = array($x,                $y,\n\t\t       $x,                $y-$h+$this->corner,\n\t\t       $x + $this->corner,$y-$h,\n\t\t       $x + $w - $this->corner, $y-$h,\n\t\t       $x + $w, $y-$h+$this->corner,\n\t\t       $x + $w, $y);\n\t    \n\t}\n\tif( $this->halign == 'left' ) {\n\t    $aImg->SetTextAlign('left','bottom');\n\t    $x += $this->posx;\n\t    $y -= $this->posy;\n\t}\n\telseif( $this->halign == 'center' ) {\n\t    $aImg->SetTextAlign('center','bottom');\n\t    $x += $w/2; \n\t    $y -= $this->posy;\n\t}\n\telse {\n\t    $aImg->SetTextAlign('right','bottom');\n\t    $x += $w - $this->posx;\n\t    $y -= $this->posy;\n\t}\n\n\t$aImg->SetColor($this->fillcolor);\n\t$aImg->FilledPolygon($p);\n\n\t$aImg->SetColor($this->bordercolor);\n\t$aImg->Polygon($p,true);\n\t\n\t$aImg->SetColor($this->color);\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$aImg->StrokeText($x,$y,$this->t,0,'center');\n    }\n\n}\n\n//===================================================\n// CLASS SuperScriptText\n// Description: Format a superscript text\n//===================================================\nclass SuperScriptText extends Text {\n    var $iSuper=\"\";\n    var $sfont_family=\"\",$sfont_style=\"\",$sfont_size=8;\n    var $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65;\n    var $iSDir=0;\n    var $iSimple=false;\n\n    function SuperScriptText($aTxt=\"\",$aSuper=\"\",$aXAbsPos=0,$aYAbsPos=0) {\n\tparent::Text($aTxt,$aXAbsPos,$aYAbsPos);\n\t$this->iSuper = $aSuper;\n    }\n\n    function FromReal($aVal,$aPrecision=2) {\n\t// Convert a floating point number to scientific notation\n\t$neg=1.0;\n\tif( $aVal < 0 ) {\n\t    $neg = -1.0;\n\t    $aVal = -$aVal;\n\t}\n\t\t\n\t$l = floor(log10($aVal));\n\t$a = sprintf(\"%0.\".$aPrecision.\"f\",round($aVal / pow(10,$l),$aPrecision));\n\t$a *= $neg;\n\tif( $this->iSimple && ($a == 1 || $a==-1) ) $a = '';\n\t\n\tif( $a != '' )\n\t    $this->t = $a.' * 10';\n\telse {\n\t    if( $neg == 1 )\n\t\t$this->t = '10';\n\t    else\n\t\t$this->t = '-10';\n\t}\n\t$this->iSuper = $l;\n    }\n\n    function Set($aTxt,$aSuper=\"\") {\n\t$this->t = $aTxt;\n\t$this->iSuper = $aSuper;\n    }\n\n    function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) {\n\t$this->sfont_family = $aFontFam;\n\t$this->sfont_style = $aFontStyle;\n\t$this->sfont_size = $aFontSize;\n    }\n\n    // Total width of text\n    function GetWidth(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$w = $aImg->GetTextWidth($this->t);\n\t$aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);\n\t$w += $aImg->GetTextWidth($this->iSuper);\n\t$w += $this->iSuperMargin;\n\treturn $w;\n    }\n\t\n    // Hight of font (approximate the height of the text)\n    function GetFontHeight(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\t\n\t$h = $aImg->GetFontHeight();\n\t$aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);\n\t$h += $aImg->GetFontHeight();\n\treturn $h;\n    }\n\n    // Hight of text\n    function GetTextHeight(&$aImg) {\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$h = $aImg->GetTextHeight($this->t);\n\t$aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);\n\t$h += $aImg->GetTextHeight($this->iSuper);\n\treturn $h;\n    }\n\n    function Stroke(&$aImg,$ax=-1,$ay=-1) {\n\t\n        // To position the super script correctly we need different\n\t// cases to handle the alignmewnt specified since that will\n\t// determine how we can interpret the x,y coordinates\n\t\n\t$w = parent::GetWidth($aImg);\n\t$h = parent::GetTextHeight($aImg);\n\tswitch( $this->valign ) {\n\t    case 'top':\n\t\t$sy = $this->y;\n\t\tbreak;\n\t    case 'center':\n\t\t$sy = $this->y - $h/2;\n\t\tbreak;\n\t    case 'bottom':\n\t\t$sy = $this->y - $h;\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text');\n\t\texit();\n\t}\n\n\tswitch( $this->halign ) {\n\t    case 'left':\n\t\t$sx = $this->x + $w;\n\t\tbreak;\n\t    case 'center':\n\t\t$sx = $this->x + $w/2;\n\t\tbreak;\n\t    case 'right':\n\t\t$sx = $this->x;\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text');\n\t\texit();\n\t}\n\n\t$sx += $this->iSuperMargin;\n\t$sy += $this->iVertOverlap;\n\n\t// Should we automatically determine the font or\n\t// has the user specified it explicetly?\n\tif( $this->sfont_family == \"\" ) {\n\t    if( $this->font_family <= FF_FONT2 ) {\n\t\tif( $this->font_family == FF_FONT0 ) {\n\t\t    $sff = FF_FONT0;\n\t\t}\n\t\telseif( $this->font_family == FF_FONT1 ) {\n\t\t    if( $this->font_style == FS_NORMAL )\n\t\t\t$sff = FF_FONT0;\n\t\t    else\n\t\t\t$sff = FF_FONT1;\n\t\t}\n\t\telse {\n\t\t    $sff = FF_FONT1;\n\t\t}\n\t\t$sfs = $this->font_style;\n\t\t$sfz = $this->font_size;\n\t    }\n\t    else {\n\t\t// TTF fonts\n\t\t$sff = $this->font_family;\n\t\t$sfs = $this->font_style;\n\t\t$sfz = floor($this->font_size*$this->iSuperScale);\t\t\n\t\tif( $sfz < 8 ) $sfz = 8;\n\t    }\t    \n\t    $this->sfont_family = $sff;\n\t    $this->sfont_style = $sfs;\n\t    $this->sfont_size = $sfz;\t    \n\t} \n\telse {\n\t    $sff = $this->sfont_family;\n\t    $sfs = $this->sfont_style;\n\t    $sfz = $this->sfont_size;\t    \n\t}\n\n\tparent::Stroke($aImg,$ax,$ay);\n\n\n\t// For the builtin fonts we need to reduce the margins\n\t// since the bounding bx reported for the builtin fonts\n\t// are much larger than for the TTF fonts.\n\tif( $sff <= FF_FONT2 ) {\n\t    $sx -= 2;\n\t    $sy += 3;\n\t}\n\n\t$aImg->SetTextAlign('left','bottom');\t\n\t$aImg->SetFont($sff,$sfs,$sfz);\n\t$aImg->PushColor($this->color);\t\n\t$aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left');\n\t$aImg->PopColor();\t\n    }\n}\n\n\n//===================================================\n// CLASS Grid\n// Description: responsible for drawing grid lines in graph\n//===================================================\nclass Grid {\n    var $img;\n    var $scale;\n    var $grid_color='#DDDDDD',$grid_mincolor='#DDDDDD';\n    var $type=\"solid\";\n    var $show=false, $showMinor=false,$weight=1;\n    var $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF');\n//---------------\n// CONSTRUCTOR\n    function Grid(&$aAxis) {\n\t$this->scale = &$aAxis->scale;\n\t$this->img = &$aAxis->img;\n    }\n//---------------\n// PUBLIC METHODS\n    function SetColor($aMajColor,$aMinColor=false) {\n\t$this->grid_color=$aMajColor;\n\tif( $aMinColor === false ) \n\t    $aMinColor = $aMajColor ;\n\t$this->grid_mincolor = $aMinColor;\n    }\n\t\n    function SetWeight($aWeight) {\n\t$this->weight=$aWeight;\n    }\n\t\n    // Specify if grid should be dashed, dotted or solid\n    function SetLineStyle($aType) {\n\t$this->type = $aType;\n    }\n\t\n    // Decide if both major and minor grid should be displayed\n    function Show($aShowMajor=true,$aShowMinor=false) {\n\t$this->show=$aShowMajor;\n\t$this->showMinor=$aShowMinor;\n    }\n    \n    function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') {\n\t$this->fill = $aFlg;\n\t$this->fillcolor = array( $aColor1, $aColor2 );\n    }\n\t\n    // Display the grid\n    function Stroke() {\n\tif( $this->showMinor ) {\n\t    $tmp = $this->grid_color;\n\t    $this->grid_color = $this->grid_mincolor;\n\t    $this->DoStroke($this->scale->ticks->ticks_pos);\n\n\t    $this->grid_color = $tmp;\n\t    $this->DoStroke($this->scale->ticks->maj_ticks_pos);\n\t}\n\telse {\n\t    $this->DoStroke($this->scale->ticks->maj_ticks_pos);\n\t}\n    }\n\t\n//--------------\n// Private methods\t\n    // Draw the grid\n    function DoStroke(&$aTicksPos) {\n\tif( !$this->show )\n\t    return;\t\n\t$nbrgrids = count($aTicksPos);\t\n\n\tif( $this->scale->type==\"y\" ) {\n\t    $xl=$this->img->left_margin;\n\t    $xr=$this->img->width-$this->img->right_margin;\n\t    \n\t    if( $this->fill ) {\n\t\t// Draw filled areas\n\t\t$y2 = $aTicksPos[0];\n\t\t$i=1;\n\t\twhile( $i < $nbrgrids ) {\n\t\t    $y1 = $y2;\n\t\t    $y2 = $aTicksPos[$i++];\n\t\t    $this->img->SetColor($this->fillcolor[$i & 1]);\n\t\t    $this->img->FilledRectangle($xl,$y1,$xr,$y2);\n\t\t}\n\t    }\n\n\t    $this->img->SetColor($this->grid_color);\n\t    $this->img->SetLineWeight($this->weight);\n\n\t    // Draw grid lines\n\t    for($i=0; $i<$nbrgrids; ++$i) {\n\t\t$y=$aTicksPos[$i];\n\t\tif( $this->type == \"solid\" )\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\telseif( $this->type == \"dotted\" )\n\t\t    $this->img->DashedLine($xl,$y,$xr,$y,1,6);\n\t\telseif( $this->type == \"dashed\" )\n\t\t    $this->img->DashedLine($xl,$y,$xr,$y,2,4);\n\t\telseif( $this->type == \"longdashed\" )\n\t\t    $this->img->DashedLine($xl,$y,$xr,$y,8,6);\n\t    }\n\t}\n\telseif( $this->scale->type==\"x\" ) {\t\n\t    $yu=$this->img->top_margin;\n\t    $yl=$this->img->height-$this->img->bottom_margin;\n\t    $limit=$this->img->width-$this->img->right_margin;\n\n\t    if( $this->fill ) {\n\t\t// Draw filled areas\n\t\t$x2 = $aTicksPos[0];\n\t\t$i=1;\n\t\twhile( $i < $nbrgrids ) {\n\t\t    $x1 = $x2;\n\t\t    $x2 = min($aTicksPos[$i++],$limit) ;\n\t\t    $this->img->SetColor($this->fillcolor[$i & 1]);\n\t\t    $this->img->FilledRectangle($x1,$yu,$x2,$yl);\n\t\t}\n\t    }\n\n\t    $this->img->SetColor($this->grid_color);\n\t    $this->img->SetLineWeight($this->weight);\n\n\t    // We must also test for limit since we might have\n\t    // an offset and the number of ticks is calculated with\n\t    // assumption offset==0 so we might end up drawing one\n\t    // to many gridlines\n\t    $i=0;\n\t    $x=$aTicksPos[$i];\t    \n\t    while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) {\n\t\tif( $this->type == \"solid\" )\t\t\t\t\n\t\t    $this->img->Line($x,$yl,$x,$yu);\n\t\telseif( $this->type == \"dotted\" )\n\t\t    $this->img->DashedLine($x,$yl,$x,$yu,1,6);\n\t\telseif( $this->type == \"dashed\" )\n\t\t    $this->img->DashedLine($x,$yl,$x,$yu,2,4);\n\t\telseif( $this->type == \"longdashed\" )\n\t\t    $this->img->DashedLine($x,$yl,$x,$yu,8,6);\t\n\t\t++$i;  \n\t    }\n\t}\t\n\telse {\n\t    JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']');\n\t}\n\treturn true;\n    }\n} // Class\n\n//===================================================\n// CLASS Axis\n// Description: Defines X and Y axis. Notes that at the\n// moment the code is not really good since the axis on\n// several occasion must know wheter it's an X or Y axis.\n// This was a design decision to make the code easier to\n// follow. \n//===================================================\nclass Axis {\n    var $pos = false;\n    var $weight=1;\n    var $color=array(0,0,0),$label_color=array(0,0,0);\n    var $img=null,$scale=null; \n    var $hide=false;\n    var $ticks_label=false, $ticks_label_colors=null;\n    var $show_first_label=true,$show_last_label=true;\n    var $label_step=1; // Used by a text axis to specify what multiple of major steps\n    // should be labeled.\n    var $tick_step=1;\n    var $labelPos=0;   // Which side of the axis should the labels be?\n    var $title=null,$title_adjust,$title_margin,$title_side=SIDE_LEFT;\n    var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0;\n    var $tick_label_margin=5;\n    var $label_halign = '',$label_valign = '', $label_para_align='left';\n    var $hide_line=false,$hide_labels=false;\n    var $iDeltaAbsPos=0;\n    //var $hide_zero_label=false;\n\n//---------------\n// CONSTRUCTOR\n    function Axis(&$img,&$aScale,$color=array(0,0,0)) {\n\t$this->img = &$img;\n\t$this->scale = &$aScale;\n\t$this->color = $color;\n\t$this->title=new Text(\"\");\n\t\t\n\tif( $aScale->type==\"y\" ) {\n\t    $this->title_margin = 25;\n\t    $this->title_adjust=\"middle\";\n\t    $this->title->SetOrientation(90);\n\t    $this->tick_label_margin=7;\n\t    $this->labelPos=SIDE_LEFT;\n\t    //$this->SetLabelFormat('%.1f');\n\t}\n\telse {\n\t    $this->title_margin = 5;\n\t    $this->title_adjust=\"high\";\n\t    $this->title->SetOrientation(0);\t\t\t\n\t    $this->tick_label_margin=5;\n\t    $this->labelPos=SIDE_DOWN;\n\t    $this->title_side=SIDE_DOWN;\n\t    //$this->SetLabelFormat('%.0f');\n\t}\n    }\n//---------------\n// PUBLIC METHODS\t\n\t\n    function SetLabelFormat($aFormStr) {\n\t$this->scale->ticks->SetLabelFormat($aFormStr);\n    }\n\t\n    function SetLabelFormatString($aFormStr,$aDate=false) {\n\t$this->scale->ticks->SetLabelFormat($aFormStr,$aDate);\n    }\n\t\n    function SetLabelFormatCallback($aFuncName) {\n\t$this->scale->ticks->SetFormatCallback($aFuncName);\n    }\n\n    function SetLabelAlign($aHAlign,$aVAlign=\"top\",$aParagraphAlign='left') {\n\t$this->label_halign = $aHAlign;\n\t$this->label_valign = $aVAlign;\n\t$this->label_para_align = $aParagraphAlign;\n    }\t\t\n\n    // Don't display the first label\n    function HideFirstTickLabel($aShow=false) {\n\t$this->show_first_label=$aShow;\n    }\n\n    function HideLastTickLabel($aShow=false) {\n\t$this->show_last_label=$aShow;\n    }\n\n    // Manually specify the major and (optional) minor tick position and labels\n    function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {\n\t$this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels);\n    }\n\n    // Manually specify major tick positions and optional labels\n    function SetMajTickPositions($aMajPos,$aLabels=NULL) {\n\t$this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels);\n    }\n\n    // Hide minor or major tick marks\n    function HideTicks($aHideMinor=true,$aHideMajor=true) {\n\t$this->scale->ticks->SupressMinorTickMarks($aHideMinor);\n\t$this->scale->ticks->SupressTickMarks($aHideMajor);\n    }\n\n    // Hide zero label\n    function HideZeroLabel($aFlag=true) {\n\t$this->scale->ticks->SupressZeroLabel();\n\t//$this->hide_zero_label = $aFlag;\n    }\n\t\n    function HideFirstLastLabel() {\n\t// The two first calls to ticks method will supress \n\t// automatically generated scale values. However, that\n\t// will not affect manually specified value, e.g text-scales.\n\t// therefor we also make a kludge here to supress manually\n\t// specified scale labels.\n\t$this->scale->ticks->SupressLast();\n\t$this->scale->ticks->SupressFirst();\n\t$this->show_first_label\t= false;\n\t$this->show_last_label = false;\n    }\n\t\n    // Hide the axis\n    function Hide($aHide=true) {\n\t$this->hide=$aHide;\n    }\n\n    // Hide the actual axis-line, but still print the labels\n    function HideLine($aHide=true) {\n\t$this->hide_line = $aHide;\n    }\n\n    function HideLabels($aHide=true) {\n\t$this->hide_labels = $aHide;\n    }\n    \n\n    // Weight of axis\n    function SetWeight($aWeight) {\n\t$this->weight = $aWeight;\n    }\n\n    // Axis color\n    function SetColor($aColor,$aLabelColor=false) {\n\t$this->color = $aColor;\n\tif( !$aLabelColor ) $this->label_color = $aColor;\n\telse $this->label_color = $aLabelColor;\n    }\n\t\n    // Title on axis\n    function SetTitle($aTitle,$aAdjustAlign=\"high\") {\n\t$this->title->Set($aTitle);\n\t$this->title_adjust=$aAdjustAlign;\n    }\n\t\n    // Specify distance from the axis\n    function SetTitleMargin($aMargin) {\n\t$this->title_margin=$aMargin;\n    }\n\t\n    // Which side of the axis should the axis title be?\n    function SetTitleSide($aSideOfAxis) {\n\t$this->title_side = $aSideOfAxis;\n    }\n\n    // Utility function to set the direction for tick marks\n    function SetTickDirection($aDir) {\n    \t// Will be deprecated from 1.7    \t\n    \tif( ERR_DEPRECATED )\n\t    JpGraphError::RaiseL(25055);//('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead');\n\t$this->scale->ticks->SetSide($aDir);\n    }\n    \n    function SetTickSide($aDir) {\n\t$this->scale->ticks->SetSide($aDir);\n    }\n\t\n    // Specify text labels for the ticks. One label for each data point\n    function SetTickLabels($aLabelArray,$aLabelColorArray=null) {\n\t$this->ticks_label = $aLabelArray;\n\t$this->ticks_label_colors = $aLabelColorArray;\n    }\n\t\n    // How far from the axis should the labels be drawn\n    function SetTickLabelMargin($aMargin) {\n\tif( ERR_DEPRECATED )    \t\n\t    JpGraphError::RaiseL(25056);//('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.');\n      \t$this->tick_label_margin=$aMargin;\n    }\n\n    function SetLabelMargin($aMargin) {\n\t$this->tick_label_margin=$aMargin;\n    }\n\t\n    // Specify that every $step of the ticks should be displayed starting\n    // at $start\n    // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD\n    function SetTextTicks($step,$start=0) {\n\tJpGraphError::RaiseL(25057);//(\" SetTextTicks() is deprecated. Use SetTextTickInterval() instead.\");\t\t\n    }\n\n    // Specify that every $step of the ticks should be displayed starting\n    // at $start\t\n    function SetTextTickInterval($aStep,$aStart=0) {\n\t$this->scale->ticks->SetTextLabelStart($aStart);\n\t$this->tick_step=$aStep;\n    }\n\t \n    // Specify that every $step tick mark should have a label \n    // should be displayed starting\n    function SetTextLabelInterval($aStep,$aStart=0) {\n\tif( $aStep < 1 )\n\t    JpGraphError::RaiseL(25058);//(\" Text label interval must be specified >= 1.\");\n\t$this->scale->ticks->SetTextLabelStart($aStart);\n\t$this->label_step=$aStep;\n    }\n\t\n    // Which side of the axis should the labels be on?\n    function SetLabelPos($aSidePos) {\n    \t// This will be deprecated from 1.7\n\tif( ERR_DEPRECATED )    \t\n\t    JpGraphError::RaiseL(25059);//('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.');\n\t$this->labelPos=$aSidePos;\n    }\n    \n    function SetLabelSide($aSidePos) {\n\t$this->labelPos=$aSidePos;\n    }\n\n    // Set the font\n    function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {\n\t$this->font_family = $aFamily;\n\t$this->font_style = $aStyle;\n\t$this->font_size = $aSize;\n    }\n\n    // Position for axis line on the \"other\" scale\n    function SetPos($aPosOnOtherScale) {\n\t$this->pos=$aPosOnOtherScale;\n    }\n\n    // Set the position of the axis to be X-pixels delta to the right \n    // of the max X-position (used to position the multiple Y-axis)\n    function SetPosAbsDelta($aDelta) {\n      $this->iDeltaAbsPos=$aDelta;\n    }\n\t\n    // Specify the angle for the tick labels\n    function SetLabelAngle($aAngle) {\n\t$this->label_angle = $aAngle;\n    }\t\n\t\n    // Stroke the axis.\n    function Stroke($aOtherAxisScale,$aStrokeLabels=true) {\t\t\n\tif( $this->hide ) return;\t\t\n\tif( is_numeric($this->pos) ) {\n\t    $pos=$aOtherAxisScale->Translate($this->pos);\n\t}\n\telse {\t// Default to minimum of other scale if pos not set\t\t\n\t    if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos==\"min\" ) {\n\t\t$pos = $aOtherAxisScale->scale_abs[0];\n\t    }\n\t    elseif($this->pos == \"max\") {\n\t\t$pos = $aOtherAxisScale->scale_abs[1];\n\t    }\n\t    else { // If negative set x-axis at 0\n\t\t$this->pos=0;\n\t\t$pos=$aOtherAxisScale->Translate(0);\n\t    }\n\t}\t\n\t$pos += $this->iDeltaAbsPos;\n\t$this->img->SetLineWeight($this->weight);\n\t$this->img->SetColor($this->color);\t\t\n\t$this->img->SetFont($this->font_family,$this->font_style,$this->font_size);\n\tif( $this->scale->type == \"x\" ) {\n\t    if( !$this->hide_line ) \n\t\t$this->img->FilledRectangle($this->img->left_margin,$pos,\n\t\t\t\t\t    $this->img->width-$this->img->right_margin,$pos+$this->weight-1);\n\t    if( $this->title_side == SIDE_DOWN ) {\n\t\t$y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin;\n\t\t$yalign = 'top';\n\t    }\n\t    else {\n\t\t$y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin;\n\t\t$yalign = 'bottom';\n\t    }\n\n\t    if( $this->title_adjust==\"high\" )\n\t\t$this->title->Pos($this->img->width-$this->img->right_margin,$y,\"right\",$yalign);\n\t    elseif( $this->title_adjust==\"middle\" || $this->title_adjust==\"center\" ) \n\t\t$this->title->Pos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,\"center\",$yalign);\n\t    elseif($this->title_adjust==\"low\")\n\t\t$this->title->Pos($this->img->left_margin,$y,\"left\",$yalign);\n\t    else {\t\n\t\tJpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');\n\t    }\n\t}\n\telseif( $this->scale->type == \"y\" ) {\n\t    // Add line weight to the height of the axis since\n\t    // the x-axis could have a width>1 and we want the axis to fit nicely together.\n\t    if( !$this->hide_line ) \n\t\t$this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,\n\t\t\t\t\t    $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1);\n\t    $x=$pos ;\n\t    if( $this->title_side == SIDE_LEFT ) {\n\t\t$x -= $this->title_margin;\n\t\t$x -= $this->title->margin;\n\t\t$halign=\"right\";\n\t    }\n\t    else {\n\t\t$x += $this->title_margin;\n\t\t$x += $this->title->margin;\n\t\t$halign=\"left\";\n\t    }\n\t    // If the user has manually specified an hor. align\n\t    // then we override the automatic settings with this\n\t    // specifed setting. Since default is 'left' we compare\n\t    // with that. (This means a manually set 'left' align\n\t    // will have no effect.)\n\t    if( $this->title->halign != 'left' ) \n\t\t$halign = $this->title->halign;\n\t    if( $this->title_adjust==\"high\" ) \n\t\t$this->title->Pos($x,$this->img->top_margin,$halign,\"top\"); \n\t    elseif($this->title_adjust==\"middle\" || $this->title_adjust==\"center\")  \n\t\t$this->title->Pos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,\"center\");\n\t    elseif($this->title_adjust==\"low\")\n\t\t$this->title->Pos($x,$this->img->height-$this->img->bottom_margin,$halign,\"bottom\");\n\t    else\t\n\t\tJpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')');\n\t\t\n\t}\n\t$this->scale->ticks->Stroke($this->img,$this->scale,$pos);\n\tif( $aStrokeLabels ) {\n\t    if( !$this->hide_labels )\n\t\t$this->StrokeLabels($pos);\n\t    $this->title->Stroke($this->img);\n\t}\n    }\n\n//---------------\n// PRIVATE METHODS\t\n    // Draw all the tick labels on major tick marks\n    function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) {\n\n\t$this->img->SetColor($this->label_color);\n\t$this->img->SetFont($this->font_family,$this->font_style,$this->font_size);\n\t$yoff=$this->img->GetFontHeight()/2;\n\n\t// Only draw labels at major tick marks\n\t$nbr = count($this->scale->ticks->maj_ticks_label);\n\n\t// We have the option to not-display the very first mark\n\t// (Usefull when the first label might interfere with another\n\t// axis.)\n\t$i = $this->show_first_label ? 0 : 1 ;\n\tif( !$this->show_last_label ) --$nbr;\n\t// Now run through all labels making sure we don't overshoot the end\n\t// of the scale.\t\n\t$ncolor=0;\n\tif( isset($this->ticks_label_colors) )\n\t    $ncolor=count($this->ticks_label_colors);\n\t\n\twhile( $i<$nbr ) {\n\t    // $tpos holds the absolute text position for the label\n\t    $tpos=$this->scale->ticks->maj_ticklabels_pos[$i];\n\n\t    // Note. the $limit is only used for the x axis since we\n\t    // might otherwise overshoot if the scale has been centered\n\t    // This is due to us \"loosing\" the last tick mark if we center.\n\t    if( $this->scale->type==\"x\" && $tpos > $this->img->width-$this->img->right_margin+1 ) {\n\t    \treturn; \n\t    }\n\t    // we only draw every $label_step label\n\t    if( ($i % $this->label_step)==0 ) {\n\n\t\t// Set specific label color if specified\n\t\tif( $ncolor > 0 )\n\t\t    $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]);\n\t\t\n\t\t// If the label has been specified use that and in other case\n\t\t// just label the mark with the actual scale value \n\t\t$m=$this->scale->ticks->GetMajor();\n\t\t\t\t\n\t\t// ticks_label has an entry for each data point and is the array\n\t\t// that holds the labels set by the user. If the user hasn't \n\t\t// specified any values we use whats in the automatically asigned\n\t\t// labels in the maj_ticks_label\n\t\tif( isset($this->ticks_label[$i*$m]) )\n\t\t    $label=$this->ticks_label[$i*$m];\n\t\telse {\n\t\t    if( $aAbsLabel ) \n\t\t\t$label=abs($this->scale->ticks->maj_ticks_label[$i]);\n\t\t    else\n\t\t\t$label=$this->scale->ticks->maj_ticks_label[$i];\n\t\t    if( $this->scale->textscale && $this->scale->ticks->label_formfunc == '' ) {\n\t\t\t++$label;\n\t\t    }\n\t\t}\n\t\t\t\t\t\n\t\t//if( $this->hide_zero_label && $label==0.0 ) {\n\t\t//\t++$i;\n\t\t//\tcontinue;\n\t\t//}\t\t\t\t\t\n\t\t\t\t\t\n\t\tif( $this->scale->type == \"x\" ) {\n\t\t    if( $this->labelPos == SIDE_DOWN ) {\n\t\t\tif( $this->label_angle==0 || $this->label_angle==90 ) {\n\t\t\t    if( $this->label_halign=='' && $this->label_valign=='')\n\t\t\t\t$this->img->SetTextAlign('center','top');\n\t\t\t    else\n\t\t\t    \t$this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t    \n\t\t\t}\n\t\t\telse {\n\t\t\t    if( $this->label_halign=='' && $this->label_valign=='')\n\t\t\t\t$this->img->SetTextAlign(\"right\",\"top\");\n\t\t\t    else\n\t\t\t\t$this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t}\n\n\t\t\t$this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label,\n\t\t\t\t\t       $this->label_angle,$this->label_para_align);\n\t\t    }\n\t\t    else {\n\t\t\tif( $this->label_angle==0 || $this->label_angle==90 ) {\n\t\t\t    if( $this->label_halign=='' && $this->label_valign=='')\n\t\t\t\t$this->img->SetTextAlign(\"center\",\"bottom\");\n\t\t\t    else\n\t\t\t    \t$this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t}\n\t\t\telse {\n\t\t\t    if( $this->label_halign=='' && $this->label_valign=='')\n\t\t\t\t$this->img->SetTextAlign(\"right\",\"bottom\");\n\t\t\t    else\n\t\t\t    \t$this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t}\n\t\t\t$this->img->StrokeText($tpos,$aPos-$this->tick_label_margin,$label,\n\t\t\t\t\t       $this->label_angle,$this->label_para_align);\n\t\t    }\n\t\t}\n\t\telse {\n\t\t    // scale->type == \"y\"\n\t\t    //if( $this->label_angle!=0 ) \n\t\t    //JpGraphError::Raise(\" Labels at an angle are not supported on Y-axis\");\n\t\t    if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis\t\t\t\t\t\n\t\t\tif( $this->label_halign=='' && $this->label_valign=='')\t\n\t\t\t    $this->img->SetTextAlign(\"right\",\"center\");\n\t\t\telse\n\t\t\t    $this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t$this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);\t\n\t\t    }\n\t\t    else { // To the right of the y-axis\n\t\t\tif( $this->label_halign=='' && $this->label_valign=='')\t\n\t\t\t    $this->img->SetTextAlign(\"left\",\"center\");\n\t\t\telse\n\t\t\t    $this->img->SetTextAlign($this->label_halign,$this->label_valign);\n\t\t\t$this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);\t\n\t\t    }\n\t\t}\n\t    }\n\t    ++$i;\t\n\t}\t\t\t\t\t\t\t\t\n    }\t\t\t\n\n} // Class\n\n//===================================================\n// CLASS Ticks\n// Description: Abstract base class for drawing linear and logarithmic\n// tick marks on axis\n//===================================================\nclass Ticks {\n    var $minor_abs_size=3, $major_abs_size=5;\n    var $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)?\n    var $scale;\n    var $is_set=false;\n    var $precision;\n    var $supress_zerolabel=false,$supress_first=false;\n    var $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false;\n    var $mincolor=\"\",$majcolor=\"\";\n    var $weight=1;\n    var $label_formatstr='';   // C-style format string to use for labels\n    var $label_formfunc='';\n    var $label_dateformatstr='';\n    var $label_usedateformat=FALSE;\n\n\n//---------------\n// CONSTRUCTOR\n    function Ticks(&$aScale) {\n\t$this->scale=&$aScale;\n\t$this->precision = -1;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    // Set format string for automatic labels\n    function SetLabelFormat($aFormatString,$aDate=FALSE) {\n\t$this->label_formatstr=$aFormatString;\n\t$this->label_usedateformat=$aDate;\n    }\n\n    function SetLabelDateFormat($aFormatString) {\n\t$this->label_dateformatstr=$aFormatString;\n    }\n\t\n    function SetFormatCallback($aCallbackFuncName) {\n\t$this->label_formfunc = $aCallbackFuncName;\n    }\n\t\n    // Don't display the first zero label\n    function SupressZeroLabel($aFlag=true) {\n\t$this->supress_zerolabel=$aFlag;\n    }\n\t\n    // Don't display minor tick marks\n    function SupressMinorTickMarks($aHide=true) {\n\t$this->supress_minor_tickmarks=$aHide;\n    }\n\t\n    // Don't display major tick marks\n    function SupressTickMarks($aHide=true) {\n\t$this->supress_tickmarks=$aHide;\n    }\n\t\n    // Hide the first tick mark\n    function SupressFirst($aHide=true) {\n\t$this->supress_first=$aHide;\n    }\n\t\n    // Hide the last tick mark\n    function SupressLast($aHide=true) {\n\t$this->supress_last=$aHide;\n    }\n\n    // Size (in pixels) of minor tick marks\n    function GetMinTickAbsSize() {\n\treturn $this->minor_abs_size;\n    }\n\t\n    // Size (in pixels) of major tick marks\n    function GetMajTickAbsSize() {\n\treturn $this->major_abs_size;\t\t\n    }\n\t\n    function SetSize($aMajSize,$aMinSize=3) {\n\t$this->major_abs_size = $aMajSize;\t\t\n\t$this->minor_abs_size = $aMinSize;\t\t\n    }\n\n    // Have the ticks been specified\n    function IsSpecified() {\n\treturn $this->is_set;\n    }\n\t\n    // Set the distance between major and minor tick marks\n    function Set($aMaj,$aMin) {\n\t// \"Virtual method\"\n\t// Should be implemented by the concrete subclass\n\t// if any action is wanted.\n    }\n\t\n    // Specify number of decimals in automatic labels\n    // Deprecated from 1.4. Use SetFormatString() instead\n    function SetPrecision($aPrecision) { \t\n    \tif( ERR_DEPRECATED )\n\t    JpGraphError::RaiseL(25063);//('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead');\n\t$this->precision=$aPrecision;\n    }\n\n    function SetSide($aSide) {\n\t$this->direction=$aSide;\n    }\n\t\n    // Which side of the axis should the ticks be on\n    function SetDirection($aSide=SIDE_RIGHT) {\n\t$this->direction=$aSide;\n    }\n\t\n    // Set colors for major and minor tick marks\n    function SetMarkColor($aMajorColor,$aMinorColor=\"\") {\n\t$this->SetColor($aMajorColor,$aMinorColor);\n    }\n    \n    function SetColor($aMajorColor,$aMinorColor=\"\") {\n\t$this->majcolor=$aMajorColor;\n\t\t\n\t// If not specified use same as major\n\tif( $aMinorColor==\"\" ) \n\t    $this->mincolor=$aMajorColor;\n\telse\n\t    $this->mincolor=$aMinorColor;\n    }\n\t\n    function SetWeight($aWeight) {\n\t$this->weight=$aWeight;\n    }\n\t\n} // Class\n\n//===================================================\n// CLASS LinearTicks\n// Description: Draw linear ticks on axis\n//===================================================\nclass LinearTicks extends Ticks {\n    var $minor_step=1, $major_step=2;\n    var $xlabel_offset=0,$xtick_offset=0;\n    var $label_offset=0; // What offset should the displayed label have\n    // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc\n    var $text_label_start=0;\n    var $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL;\n    var $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), \n\t$ticks_pos = array(), $maj_ticks_label = array();\n\n//---------------\n// CONSTRUCTOR\n    function LinearTicks() {\n\t$this->precision = -1;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\t\n\t\n    // Return major step size in world coordinates\n    function GetMajor() {\n\treturn $this->major_step;\n    }\n\t\n    // Return minor step size in world coordinates\n    function GetMinor() {\n\treturn $this->minor_step;\n    }\n\t\n    // Set Minor and Major ticks (in world coordinates)\n    function Set($aMajStep,$aMinStep=false) {\n\tif( $aMinStep==false ) \n\t    $aMinStep=$aMajStep;\n    \t\n\tif( $aMajStep <= 0 || $aMinStep <= 0 ) {\n\t    JpGraphError::RaiseL(25064);\n//(\" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem.\");\n\t}\n\t\t\n\t$this->major_step=$aMajStep;\n\t$this->minor_step=$aMinStep;\n\t$this->is_set = true;\n    }\n\n    function SetMajTickPositions($aMajPos,$aLabels=NULL) {\n\t$this->SetTickPositions($aMajPos,NULL,$aLabels);\n    }\n\n    function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {\n\tif( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) {\n\t    JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()');\n\t    return;\n\t}\n\t$n=count($aMajPos);\n\tif( is_array($aLabels) && (count($aLabels) != $n) ) {\n\t    JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.');\n\t    return;\n\t}\n\t$this->iManualTickPos = $aMajPos;\n\t$this->iManualMinTickPos = $aMinPos;\n\t$this->iManualTickLabels = $aLabels;\n    }\n\n    // Specify all the tick positions manually and possible also the exact labels \n    function _doManualTickPos($aScale) { \n\t$n=count($this->iManualTickPos);\n\t$m=count($this->iManualMinTickPos);\n\t$doLbl=count($this->iManualTickLabels) > 0;\n\t$this->use_manualtickpos=true;\n\n\t$this->maj_ticks_pos = array();\n\t$this->maj_ticklabels_pos = array();\n\t$this->ticks_pos = array();\n\n\t// Now loop through the supplied positions and translate them to screen coordinates\n\t// and store them in the maj_label_positions\n\t$minScale = $aScale->scale[0];\n\t$maxScale = $aScale->scale[1];\n\t$j=0;\n\tfor($i=0; $i < $n ; ++$i ) {\n\t    // First make sure that the first tick is not lower than the lower scale value\n\t    if( !isset($this->iManualTickPos[$i])  || \n\t\t$this->iManualTickPos[$i] < $minScale  || $this->iManualTickPos[$i] > $maxScale) {\n\t\tcontinue;\n\t    }\n\n\n\t    $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]);\n\t    $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j];\t\n\n\t    // Set the minor tick marks the same as major if not specified\n\t    if( $m <= 0 ) {\n\t\t$this->ticks_pos[$j] = $this->maj_ticks_pos[$j];\n\t    }\n\n\t    if( $doLbl ) { \n\t\t$this->maj_ticks_label[$j] = $this->iManualTickLabels[$i];\n\t    }\n\t    else {\n\t\t$this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n);\n\t    }\n\t    ++$j;\n\t}\n\n\t// Some sanity check\n\tif( count($this->maj_ticks_pos) < 2 ) {\n\t    JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.');\n\t}\n\n\t// Setup the minor tick marks\n\t$j=0;\n\tfor($i=0; $i < $m; ++$i ) {\n\t    if(  empty($this->iManualMinTickPos[$i]) || \n\t\t $this->iManualMinTickPos[$i] < $minScale  || $this->iManualMinTickPos[$i] > $maxScale) \n\t\tcontinue;\n\t    $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]);\n\t    ++$j;\n\t}\n    }\n\n    function _doAutoTickPos($aScale) {\n\t$maj_step_abs = $aScale->scale_factor*$this->major_step;\t\t\n\t$min_step_abs = $aScale->scale_factor*$this->minor_step;\t\t\n\n\tif( $min_step_abs==0 || $maj_step_abs==0 ) {\n\t    JpGraphError::RaiseL(25068);//(\"A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')\");\n\t}\n\t// We need to make this an int since comparing it below\n\t// with the result from round() can give wrong result, such that\n\t// (40 < 40) == TRUE !!!\n\t$limit = (int)$aScale->scale_abs[1];\t\n\n\tif( $aScale->textscale ) {\n\t    // This can only be true for a X-scale (horizontal)\n\t    // Define ticks for a text scale. This is slightly different from a \n\t    // normal linear type of scale since the position might be adjusted\n\t    // and the labels start at on\n\t    $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset;\t\n\t    $start_abs=$aScale->scale_factor*$this->text_label_start;\n\t    $nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;\t\n\t    $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs;\t\n\t    for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) {\n\t\t// Apply format to label\n\t\t$this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks);\n\t\t$label+=$this->major_step;\n\n\t\t// The x-position of the tick marks can be different from the labels.\n\t\t// Note that we record the tick position (not the label) so that the grid\n\t\t// happen upon tick marks and not labels.\n\t\t$xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs;\n\t\t$this->maj_ticks_pos[$i]=$xtick;\n\t\t$this->maj_ticklabels_pos[$i] = round($x);\t\t\t\t\n\t\t$x += $maj_step_abs;\n\t    }\n\t}\n\telse {\n\t    $label = $aScale->GetMinVal();\t\n\t    $abs_pos = $aScale->scale_abs[0];\n\t    $j=0; $i=0;\n\t    $step = round($maj_step_abs/$min_step_abs);\n\t    if( $aScale->type == \"x\" ) {\n\t\t// For a normal linear type of scale the major ticks will always be multiples\n\t\t// of the minor ticks. In order to avoid any rounding issues the major ticks are\n\t\t// defined as every \"step\" minor ticks and not calculated separately\n\t\t$nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; \n\t\twhile( round($abs_pos) <= $limit ) {\n\t\t    $this->ticks_pos[] = round($abs_pos);\n\t\t    $this->ticks_label[] = $label;\n\t\t    if( $i % $step == 0 && $j < $nbrmajticks ) {\n\t\t\t$this->maj_ticks_pos[$j] = round($abs_pos);\n\t\t\t$this->maj_ticklabels_pos[$j] = round($abs_pos);\n\t\t\t$this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);\n\t\t\t++$j;\n\t\t    }\n\t\t    ++$i;\n\t\t    $abs_pos += $min_step_abs;\n\t\t    $label+=$this->minor_step;\n\t\t}\n\t    }\n\t    elseif( $aScale->type == \"y\" ) {\n\t\t$nbrmajticks=floor(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1;\n\t\twhile( round($abs_pos) >= $limit ) {\n\t\t    $this->ticks_pos[$i] = round($abs_pos); \n\t\t    $this->ticks_label[$i]=$label;\n\t\t    if( $i % $step == 0 && $j < $nbrmajticks) {\n\t\t\t$this->maj_ticks_pos[$j] = round($abs_pos);\n\t\t\t$this->maj_ticklabels_pos[$j] = round($abs_pos);\n\t\t\t$this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);\n\t\t\t++$j;\n\t\t    }\n\t\t    ++$i;\n\t\t    $abs_pos += $min_step_abs;\n\t\t    $label += $this->minor_step;\n\t\t}\t\n\t    }\n\t}\t\n    }\n\n    function _doLabelFormat($aVal,$aIdx,$aNbrTicks) {\n\n\t// If precision hasn't been specified set it to a sensible value\n\tif( $this->precision==-1 ) { \n\t    $t = log10($this->minor_step);\n\t    if( $t > 0 )\n\t\t$precision = 0;\n\t    else\n\t\t$precision = -floor($t);\n\t}\n\telse\n\t    $precision = $this->precision;\n\n\tif( $this->label_formfunc != '' ) {\n\t    $f=$this->label_formfunc;\n\t    $l = call_user_func($f,$aVal);\n\t}\t\n\telseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) {\n\t    if( $this->label_usedateformat ) {\n\t\t$l = date($this->label_formatstr,$aVal);\n\t    }\n\t    else {\n\t\tif( $this->label_dateformatstr !== '' )\n\t\t    $l = date($this->label_dateformatstr,$aVal);\n\t\telse\n\t\t    $l = sprintf($this->label_formatstr,$aVal);\n\t    }\n\t}\n\telse {\n\t    $l = sprintf('%01.'.$precision.'f',round($aVal,$precision));\n\t}\n\t\n\tif( ($this->supress_zerolabel && $l==0) ||  ($this->supress_first && $aIdx==0) ||\n\t    ($this->supress_last  && $aIdx==$aNbrTicks-1) ) {\n\t    $l='';\n\t}\n\treturn $l;\n    }\n\n    // Stroke ticks on either X or Y axis\n    function _StrokeTicks(&$aImg,$aScale,$aPos) {\n\t$hor = $aScale->type == 'x';\n\t$aImg->SetLineWeight($this->weight);\t\n\n\t// We need to make this an int since comparing it below\n\t// with the result from round() can give wrong result, such that\n\t// (40 < 40) == TRUE !!!\n\t$limit = (int)$aScale->scale_abs[1];\n\t\t\n\t// A text scale doesn't have any minor ticks\n\tif( !$aScale->textscale ) {\n\t    // Stroke minor ticks\n\t    $yu = $aPos - $this->direction*$this->GetMinTickAbsSize();\n\t    $xr = $aPos + $this->direction*$this->GetMinTickAbsSize();\n\t    $n = count($this->ticks_pos);\n\t    for($i=0; $i < $n; ++$i ) {\n\t\tif( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {\n\t\t    if( $this->mincolor!=\"\" ) $aImg->PushColor($this->mincolor);\n\t\t    if( $hor ) {\n\t\t\t//if( $this->ticks_pos[$i] <= $limit ) \n\t\t\t$aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); \n\t\t    }\n\t\t    else {\n\t\t\t//if( $this->ticks_pos[$i] >= $limit ) \n\t\t\t$aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); \n\t\t    }\n\t\t    if( $this->mincolor!=\"\" ) $aImg->PopColor();\n\t\t}\n\t    }\n\t}\n\n\t// Stroke major ticks\n\t$yu = $aPos - $this->direction*$this->GetMajTickAbsSize();\n\t$xr = $aPos + $this->direction*$this->GetMajTickAbsSize();\n\t$nbrmajticks=ceil(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;\n\t$n = count($this->maj_ticks_pos);\n\tfor($i=0; $i < $n ; ++$i ) {\n\t    if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) {\n\t\tif( $this->majcolor!=\"\" ) $aImg->PushColor($this->majcolor);\n\t\tif( $hor ) {\n\t\t    //if( $this->maj_ticks_pos[$i] <= $limit ) \n\t\t    $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); \n\t\t}\n\t\telse {\n\t\t    //if( $this->maj_ticks_pos[$i] >= $limit ) \n\t\t    $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); \n\t\t}\n\t\tif( $this->majcolor!=\"\" ) $aImg->PopColor();\n\t    }\n\t}\n\t\n    }\n\n    // Draw linear ticks\n    function Stroke(&$aImg,$aScale,$aPos) {\n\tif( $this->iManualTickPos != NULL ) \n\t    $this->_doManualTickPos($aScale);\n\telse \n\t    $this->_doAutoTickPos($aScale);\n\t$this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' );\n    }\n\n//---------------\n// PRIVATE METHODS\n    // Spoecify the offset of the displayed tick mark with the tick \"space\"\n    // Legal values for $o is [0,1] used to adjust where the tick marks and label \n    // should be positioned within the major tick-size\n    // $lo specifies the label offset and $to specifies the tick offset\n    // this comes in handy for example in bar graphs where we wont no offset for the\n    // tick but have the labels displayed halfway under the bars.\n    function SetXLabelOffset($aLabelOff,$aTickOff=-1) {\n\t$this->xlabel_offset=$aLabelOff;\n\tif( $aTickOff==-1 )\t// Same as label offset\n\t    $this->xtick_offset=$aLabelOff;\n\telse\n\t    $this->xtick_offset=$aTickOff;\n\tif( $aLabelOff>0 )\n\t    $this->SupressLast();\t// The last tick wont fit\n    }\n\n    // Which tick label should we start with?\n    function SetTextLabelStart($aTextLabelOff) {\n\t$this->text_label_start=$aTextLabelOff;\n    }\n\t\n} // Class\n\n//===================================================\n// CLASS LinearScale\n// Description: Handle linear scaling between screen and world \n//===================================================\nclass LinearScale {\n    var $scale=array(0,0);\n    var $scale_abs=array(0,0);\n    var $scale_factor; // Scale factor between world and screen\n    var $world_size;\t// Plot area size in world coordinates\n    var $world_abs_size; // Plot area size in pixels\n    var $off; // Offset between image edge and plot area\n    var $type; // is this x or y scale ?\n    var $ticks=null; // Store ticks\n    var $text_scale_off = 0;\n    var $autoscale_min=false; // Forced minimum value, auto determine max\n    var $autoscale_max=false; // Forced maximum value, auto determine min\n    var $gracetop=0,$gracebottom=0;\n    var $intscale=false; // Restrict autoscale to integers\n    var $textscale=false; // Just a flag to let the Plot class find out if\n    // we are a textscale or not. This is a cludge since\n    // this ionformatyion is availabale in Graph::axtype but\n    // we don't have access to the graph object in the Plots\n    // stroke method. So we let graph store the status here\n    // when the linear scale is created. A real cludge...\n    var $auto_ticks=false; // When using manual scale should the ticks be automatically set?\n    var $name = 'lin';\n//---------------\n// CONSTRUCTOR\n    function LinearScale($aMin=0,$aMax=0,$aType=\"y\") {\n\tassert($aType==\"x\" || $aType==\"y\" );\n\tassert($aMin<=$aMax);\n\t\t\n\t$this->type=$aType;\n\t$this->scale=array($aMin,$aMax);\t\t\n\t$this->world_size=$aMax-$aMin;\t\n\t$this->ticks = new LinearTicks();\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    // Check if scale is set or if we should autoscale\n    // We should do this is either scale or ticks has not been set\n    function IsSpecified() {\n\tif( $this->GetMinVal()==$this->GetMaxVal() ) {\t\t// Scale not set\n\t    return false;\n\t}\n\treturn true;\n    }\n\t\n    // Set the minimum data value when the autoscaling is used. \n    // Usefull if you want a fix minimum (like 0) but have an\n    // automatic maximum\n    function SetAutoMin($aMin) {\n\t$this->autoscale_min=$aMin;\n    }\n\n    // Set the minimum data value when the autoscaling is used. \n    // Usefull if you want a fix minimum (like 0) but have an\n    // automatic maximum\n    function SetAutoMax($aMax) {\n\t$this->autoscale_max=$aMax;\n    }\n\n    // If the user manually specifies a scale should the ticks\n    // still be set automatically?\n    function SetAutoTicks($aFlag=true) {\n\t$this->auto_ticks = $aFlag;\n    }\n\n    // Specify scale \"grace\" value (top and bottom)\n    function SetGrace($aGraceTop,$aGraceBottom=0) {\n\tif( $aGraceTop<0 || $aGraceBottom < 0  )\n\t    JpGraphError::RaiseL(25069);//(\" Grace must be larger then 0\");\n\t$this->gracetop=$aGraceTop;\n\t$this->gracebottom=$aGraceBottom;\n    }\n\t\n    // Get the minimum value in the scale\n    function GetMinVal() {\n\treturn $this->scale[0];\n    }\n\t\n    // get maximum value for scale\n    function GetMaxVal() {\n\treturn $this->scale[1];\n    }\n\t\t\n    // Specify a new min/max value for sclae\t\n    function Update(&$aImg,$aMin,$aMax) {\n\t$this->scale=array($aMin,$aMax);\t\t\n\t$this->world_size=$aMax-$aMin;\t\t\n\t$this->InitConstants($aImg);\t\t\t\t\t\n    }\n\t\n    // Translate between world and screen\n    function Translate($aCoord) {\n\tif( !is_numeric($aCoord) ) {\n\t    if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) \n\t\tJpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');\n\t    return 0;\n\t}\n\telse {\n\t    return $this->off + ($aCoord - $this->scale[0])*$this->scale_factor;\n\t}\n    }\n\t\n    // Relative translate (don't include offset) usefull when we just want\n    // to know the relative position (in pixels) on the axis\n    function RelTranslate($aCoord) {\n\tif( !is_numeric($aCoord) ) {\n\t    if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x'  ) \n\t\tJpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');\n\t    return 0;\n\t}\n\telse { \n\t    return ($aCoord - $this->scale[0]) * $this->scale_factor; \n\t}\n    }\n\t\n    // Restrict autoscaling to only use integers\n    function SetIntScale($aIntScale=true) {\n\t$this->intscale=$aIntScale;\n    }\n\t\n    // Calculate an integer autoscale\n    function IntAutoScale(&$img,$min,$max,$maxsteps,$majend=true) {\n\t// Make sure limits are integers\n\t$min=floor($min);\n\t$max=ceil($max);\n\tif( abs($min-$max)==0 ) {\n\t    --$min; ++$max;\n\t}\n\t$maxsteps = floor($maxsteps);\n\t\t\n\t$gracetop=round(($this->gracetop/100.0)*abs($max-$min));\n\t$gracebottom=round(($this->gracebottom/100.0)*abs($max-$min));\n\tif( is_numeric($this->autoscale_min) ) {\n\t    $min = ceil($this->autoscale_min);\n\t    if( $min >= $max ) {\n\t\tJpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');\n\t    }\n\t}\n\n\tif( is_numeric($this->autoscale_max) ) {\n\t    $max = ceil($this->autoscale_max);\n\t    if( $min >= $max ) {\n\t\tJpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');\n\t    }\n\t}\n\n\tif( abs($min-$max ) == 0 ) {\n\t    ++$max;\n\t    --$min;\n\t}\n\t\t\t\n\t$min -= $gracebottom;\n\t$max += $gracetop;\t\t\n\n\t// First get tickmarks as multiples of 1, 10, ...\t\n\tif( $majend ) {\n\t    list($num1steps,$adj1min,$adj1max,$maj1step) = \n\t\t$this->IntCalcTicks($maxsteps,$min,$max,1);\n\t}\n\telse {\n\t    $adj1min = $min;\n\t    $adj1max = $max;\n\t    list($num1steps,$maj1step) = \n\t\t$this->IntCalcTicksFreeze($maxsteps,$min,$max,1);\n\t}\n\n\tif( abs($min-$max) > 2 ) {\n\t    // Then get tick marks as 2:s 2, 20, ...\n\t    if( $majend ) {\n\t\tlist($num2steps,$adj2min,$adj2max,$maj2step) = \n\t\t    $this->IntCalcTicks($maxsteps,$min,$max,5);\n\t    }\n\t    else {\n\t\t$adj2min = $min;\n\t\t$adj2max = $max;\n\t\tlist($num2steps,$maj2step) = \n\t\t    $this->IntCalcTicksFreeze($maxsteps,$min,$max,5);\n\t    }\n\t}\n\telse {\n\t    $num2steps = 10000;\t// Dummy high value so we don't choose this\n\t}\n\t\n\tif( abs($min-$max) > 5 ) {\t\n\t    // Then get tickmarks as 5:s 5, 50, 500, ...\n\t    if( $majend ) {\n\t\tlist($num5steps,$adj5min,$adj5max,$maj5step) = \n\t\t    $this->IntCalcTicks($maxsteps,$min,$max,2);\n\t    }\n\t    else {\n\t\t$adj5min = $min;\n\t\t$adj5max = $max;\n\t\tlist($num5steps,$maj5step) = \n\t\t    $this->IntCalcTicksFreeze($maxsteps,$min,$max,2);\n\t    }\n\t}\n\telse {\n\t    $num5steps = 10000;\t// Dummy high value so we don't choose this\t\t\n\t}\n\t\n\t// Check to see whichof 1:s, 2:s or 5:s fit better with\n\t// the requested number of major ticks\t\t\n\t$match1=abs($num1steps-$maxsteps);\t\t\n\t$match2=abs($num2steps-$maxsteps);\n\tif( !empty($maj5step) && $maj5step > 1 )\n\t    $match5=abs($num5steps-$maxsteps);\n\telse\n\t    $match5=10000; \t// Dummy high value \n\t\t\n\t// Compare these three values and see which is the closest match\n\t// We use a 0.6 weight to gravitate towards multiple of 5:s \n\tif( $match1 < $match2 ) {\n\t    if( $match1 < $match5 )\n\t\t$r=1;\t\t\t\n\t    else \n\t\t$r=3;\n\t}\n\telse {\n\t    if( $match2 < $match5 )\n\t\t$r=2;\t\t\t\n\t    else \n\t\t$r=3;\t\t\n\t}\t\n\t// Minsteps are always the same as maxsteps for integer scale\n\tswitch( $r ) {\n\t    case 1:\n\t\t$this->ticks->Set($maj1step,$maj1step);\n\t\t$this->Update($img,$adj1min,$adj1max);\n\t\tbreak;\t\t\t\n\t    case 2:\n\t\t$this->ticks->Set($maj2step,$maj2step);\n\t\t$this->Update($img,$adj2min,$adj2max);\t\t\n\t\tbreak;\t\t\t\t\t\t\t\t\t\n\t    case 3:\n\t\t$this->ticks->Set($maj5step,$maj5step);\t\t\n\t\t$this->Update($img,$adj5min,$adj5max);\n\t\tbreak;\t\n\t    default:\n\t\tJpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)');\n\t}\t\t\n    }\n\t\n\t\n    // Calculate autoscale. Used if user hasn't given a scale and ticks\n    // $maxsteps is the maximum number of major tickmarks allowed.\n    function AutoScale(&$img,$min,$max,$maxsteps,$majend=true) {\n\tif( $this->intscale ) {\t\n\t    $this->IntAutoScale($img,$min,$max,$maxsteps,$majend);\n\t    return;\n\t}\n\tif( abs($min-$max) < 0.00001 ) {\n\t    // We need some difference to be able to autoscale\n\t    // make it 5% above and 5% below value\n\t    if( $min==0 && $max==0 ) {\t\t// Special case\n\t\t$min=-1; $max=1;\n\t    }\n\t    else {\n\t\t$delta = (abs($max)+abs($min))*0.005;\n\t\t$min -= $delta;\n\t\t$max += $delta;\n\t    }\n\t}\n\t\t\n\t$gracetop=($this->gracetop/100.0)*abs($max-$min);\n\t$gracebottom=($this->gracebottom/100.0)*abs($max-$min);\n\tif( is_numeric($this->autoscale_min) ) {\n\t    $min = $this->autoscale_min;\n\t    if( $min >= $max ) {\n\t\tJpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');\n\t    }\n\t    if( abs($min-$max ) < 0.00001 )\n\t\t$max *= 1.2;\n\t}\n\n\tif( is_numeric($this->autoscale_max) ) {\n\t    $max = $this->autoscale_max;\n\t    if( $min >= $max ) {\n\t\tJpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');\n\t    }\n\t    if( abs($min-$max ) < 0.00001 )\n\t\t$min *= 0.8;\n\t}\n\n\t\n\t$min -= $gracebottom;\n\t$max += $gracetop;\n\n\t// First get tickmarks as multiples of 0.1, 1, 10, ...\t\n\tif( $majend ) {\n\t    list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = \n\t\t$this->CalcTicks($maxsteps,$min,$max,1,2);\n\t}\n\telse {\n\t    $adj1min=$min;\n\t    $adj1max=$max;\n\t    list($num1steps,$min1step,$maj1step) = \n\t\t$this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false);\n\t}\n\t\t\n\t// Then get tick marks as 2:s 0.2, 2, 20, ...\n\tif( $majend ) {\n\t    list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = \n\t\t$this->CalcTicks($maxsteps,$min,$max,5,2);\n\t}\n\telse {\n\t    $adj2min=$min;\n\t    $adj2max=$max;\n\t    list($num2steps,$min2step,$maj2step) = \n\t\t$this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false);\n\t}\n\t\t\n\t// Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ...\n\tif( $majend ) {\n\t    list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = \n\t\t$this->CalcTicks($maxsteps,$min,$max,2,5);\t\t\n\t}\n\telse {\n\t    $adj5min=$min;\n\t    $adj5max=$max;\n\t    list($num5steps,$min5step,$maj5step) = \n\t\t$this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false);\n\t}\n\n\t// Check to see whichof 1:s, 2:s or 5:s fit better with\n\t// the requested number of major ticks\t\t\n\t$match1=abs($num1steps-$maxsteps);\t\t\n\t$match2=abs($num2steps-$maxsteps);\n\t$match5=abs($num5steps-$maxsteps);\n\t// Compare these three values and see which is the closest match\n\t// We use a 0.8 weight to gravitate towards multiple of 5:s \n\t$r=$this->MatchMin3($match1,$match2,$match5,0.8);\n\tswitch( $r ) {\n\t    case 1:\n\t\t$this->Update($img,$adj1min,$adj1max);\n\t\t$this->ticks->Set($maj1step,$min1step);\n\t\tbreak;\t\t\t\n\t    case 2:\n\t\t$this->Update($img,$adj2min,$adj2max);\t\t\n\t\t$this->ticks->Set($maj2step,$min2step);\n\t\tbreak;\t\t\t\t\t\t\t\t\t\n\t    case 3:\n\t\t$this->Update($img,$adj5min,$adj5max);\n\t\t$this->ticks->Set($maj5step,$min5step);\t\t\n\t\tbreak;\t\t\t\n\t}\n    }\n\n//---------------\n// PRIVATE METHODS\t\n\n    // This method recalculates all constants that are depending on the\n    // margins in the image. If the margins in the image are changed\n    // this method should be called for every scale that is registred with\n    // that image. Should really be installed as an observer of that image.\n    function InitConstants(&$img) {\n\tif( $this->type==\"x\" ) {\n\t    $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin;\n\t    $this->off=$img->left_margin;\n\t    $this->scale_factor = 0;\n\t    if( $this->world_size > 0 )\n\t\t$this->scale_factor=$this->world_abs_size/($this->world_size*1.0);\n\t}\n\telse { // y scale\n\t    $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; \n\t    $this->off=$img->top_margin+$this->world_abs_size;\t\t\t\n\t    $this->scale_factor = 0;\t\t\t\n\t    if( $this->world_size > 0 ) {\n\t\t$this->scale_factor=-$this->world_abs_size/($this->world_size*1.0);\t\n\t    }\n\t}\n\t$size = $this->world_size * $this->scale_factor;\n\t$this->scale_abs=array($this->off,$this->off + $size);\t\n    }\n\t\n    // Initialize the conversion constants for this scale\n    // This tries to pre-calculate as much as possible to speed up the\n    // actual conversion (with Translate()) later on\n    // $start\t=scale start in absolute pixels (for x-scale this is an y-position\n    //\t\t\t\t and for an y-scale this is an x-position\n    // $len \t\t=absolute length in pixels of scale \t\t\t\n    function SetConstants($aStart,$aLen) {\n\t$this->world_abs_size=$aLen;\n\t$this->off=$aStart;\n\t\t\n\tif( $this->world_size<=0 ) {\n\t    // This should never ever happen !!\n\t    JpGraphError::RaiseL(25074);\n//(\"You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is \".$this->world_size.\" [for \".$this->type.\" scale] <br> Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \\\"illegal\\\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail.\");\n\n\t}\n\t\t\n\t// scale_factor = number of pixels per world unit\n\t$this->scale_factor=$this->world_abs_size/($this->world_size*1.0);\n\t\t\n\t// scale_abs = start and end points of scale in absolute pixels\n\t$this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor);\t\t\n    }\n\t\n\t\n    // Calculate number of ticks steps with a specific division\n    // $a is the divisor of 10**x to generate the first maj tick intervall\n    // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,...\n    // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,...\n    // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,...\n    // We return a vector of\n    // \t[$numsteps,$adjmin,$adjmax,$minstep,$majstep]\n    // If $majend==true then the first and last marks on the axis will be major\n    // labeled tick marks otherwise it will be adjusted to the closest min tick mark\n    function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) {\n\t$diff=$max-$min; \n\tif( $diff==0 )\n\t    $ld=0;\n\telse\n\t    $ld=floor(log10($diff));\n\n\t// Gravitate min towards zero if we are close\t\t\n\tif( $min>0 && $min < pow(10,$ld) ) $min=0;\n\t\t\n\t//$majstep=pow(10,$ld-1)/$a; \n\t$majstep=pow(10,$ld)/$a; \n\t$minstep=$majstep/$b;\n\t\n\t$adjmax=ceil($max/$minstep)*$minstep;\n\t$adjmin=floor($min/$minstep)*$minstep;\t\n\t$adjdiff = $adjmax-$adjmin;\n\t$numsteps=$adjdiff/$majstep; \n\t\n\twhile( $numsteps>$maxsteps ) {\n\t    $majstep=pow(10,$ld)/$a; \n\t    $numsteps=$adjdiff/$majstep;\n\t    ++$ld;\n\t}\n\n\t$minstep=$majstep/$b;\n\t$adjmin=floor($min/$minstep)*$minstep;\t\n\t$adjdiff = $adjmax-$adjmin;\t\t\n\tif( $majend ) {\n\t    $adjmin = floor($min/$majstep)*$majstep;\t\n\t    $adjdiff = $adjmax-$adjmin;\t\t\n\t    $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;\n\t}\n\telse\n\t    $adjmax=ceil($max/$minstep)*$minstep;\n\n\treturn array($numsteps,$adjmin,$adjmax,$minstep,$majstep);\n    }\n\n    function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) {\n\t// Same as CalcTicks but don't adjust min/max values\n\t$diff=$max-$min; \n\tif( $diff==0 )\n\t    $ld=0;\n\telse\n\t    $ld=floor(log10($diff));\n\n\t//$majstep=pow(10,$ld-1)/$a; \n\t$majstep=pow(10,$ld)/$a; \n\t$minstep=$majstep/$b;\n\t$numsteps=floor($diff/$majstep); \n\t\n\twhile( $numsteps > $maxsteps ) {\n\t    $majstep=pow(10,$ld)/$a; \n\t    $numsteps=floor($diff/$majstep);\n\t    ++$ld;\n\t}\n\t$minstep=$majstep/$b;\n\treturn array($numsteps,$minstep,$majstep);\n    }\n\n\t\n    function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) {\n\t$diff=$max-$min; \n\tif( $diff==0 )\n\t    JpGraphError::RaiseL(25075);//('Can\\'t automatically determine ticks since min==max.');\n\telse\n\t    $ld=floor(log10($diff));\n\t\t\n\t// Gravitate min towards zero if we are close\t\t\n\tif( $min>0 && $min < pow(10,$ld) ) $min=0;\n\t\t\n\tif( $ld == 0 ) $ld=1;\n\t\n\tif( $a == 1 ) \n\t    $majstep = 1;\n\telse\n\t    $majstep=pow(10,$ld)/$a; \n\t$adjmax=ceil($max/$majstep)*$majstep;\n\n\t$adjmin=floor($min/$majstep)*$majstep;\t\n\t$adjdiff = $adjmax-$adjmin;\n\t$numsteps=$adjdiff/$majstep; \n\twhile( $numsteps>$maxsteps ) {\n\t    $majstep=pow(10,$ld)/$a; \n\t    $numsteps=$adjdiff/$majstep;\n\t    ++$ld;\n\t}\n\t\t\n\t$adjmin=floor($min/$majstep)*$majstep;\t\n\t$adjdiff = $adjmax-$adjmin;\t\t\n\tif( $majend ) {\n\t    $adjmin = floor($min/$majstep)*$majstep;\t\n\t    $adjdiff = $adjmax-$adjmin;\t\t\n\t    $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;\n\t}\n\telse\n\t    $adjmax=ceil($max/$majstep)*$majstep;\n\t\t\t\n\treturn array($numsteps,$adjmin,$adjmax,$majstep);\t\t\n    }\n\n\n    function IntCalcTicksFreeze($maxsteps,$min,$max,$a) {\n\t// Same as IntCalcTick but don't change min/max values\n\t$diff=$max-$min; \n\tif( $diff==0 )\n\t    JpGraphError::RaiseL(25075);//('Can\\'t automatically determine ticks since min==max.');\n\telse\n\t    $ld=floor(log10($diff));\n\t\t\n\tif( $ld == 0 ) $ld=1;\n\t\n\tif( $a == 1 ) \n\t    $majstep = 1;\n\telse\n\t    $majstep=pow(10,$ld)/$a; \n\n\t$numsteps=floor($diff/$majstep); \n\twhile( $numsteps > $maxsteps ) {\n\t    $majstep=pow(10,$ld)/$a; \n\t    $numsteps=floor($diff/$majstep);\n\t    ++$ld;\n\t}\n\t\t\t\t\t\n\treturn array($numsteps,$majstep);\t\t\n    }\n\n\n\t\n    // Determine the minimum of three values witha  weight for last value\n    function MatchMin3($a,$b,$c,$weight) {\n\tif( $a < $b ) {\n\t    if( $a < ($c*$weight) ) \n\t\treturn 1; // $a smallest\n\t    else \n\t\treturn 3; // $c smallest\n\t}\n\telseif( $b < ($c*$weight) ) \n\t    return 2; // $b smallest\n\treturn 3; // $c smallest\n    }\n} // Class\n\n//===================================================\n// CLASS RGB\n// Description: Color definitions as RGB triples\n//===================================================\nclass RGB {\n    var $rgb_table;\n    var $img;\n    function RGB(&$aImg) {\n\t$this->img = &$aImg;\n\t\t\n\t// Conversion array between color names and RGB\n\t$this->rgb_table = array(\n\t    \"aqua\"=> array(0,255,255),\t\t\n\t    \"lime\"=> array(0,255,0),\t\t\n\t    \"teal\"=> array(0,128,128),\n\t    \"whitesmoke\"=>array(245,245,245),\n\t    \"gainsboro\"=>array(220,220,220),\n\t    \"oldlace\"=>array(253,245,230),\n\t    \"linen\"=>array(250,240,230),\n\t    \"antiquewhite\"=>array(250,235,215),\n\t    \"papayawhip\"=>array(255,239,213),\n\t    \"blanchedalmond\"=>array(255,235,205),\n\t    \"bisque\"=>array(255,228,196),\n\t    \"peachpuff\"=>array(255,218,185),\n\t    \"navajowhite\"=>array(255,222,173),\n\t    \"moccasin\"=>array(255,228,181),\n\t    \"cornsilk\"=>array(255,248,220),\n\t    \"ivory\"=>array(255,255,240),\n\t    \"lemonchiffon\"=>array(255,250,205),\n\t    \"seashell\"=>array(255,245,238),\n\t    \"mintcream\"=>array(245,255,250),\n\t    \"azure\"=>array(240,255,255),\n\t    \"aliceblue\"=>array(240,248,255),\n\t    \"lavender\"=>array(230,230,250),\n\t    \"lavenderblush\"=>array(255,240,245),\n\t    \"mistyrose\"=>array(255,228,225),\n\t    \"white\"=>array(255,255,255),\n\t    \"black\"=>array(0,0,0),\n\t    \"darkslategray\"=>array(47,79,79),\n\t    \"dimgray\"=>array(105,105,105),\n\t    \"slategray\"=>array(112,128,144),\n\t    \"lightslategray\"=>array(119,136,153),\n\t    \"gray\"=>array(190,190,190),\n\t    \"lightgray\"=>array(211,211,211),\n\t    \"midnightblue\"=>array(25,25,112),\n\t    \"navy\"=>array(0,0,128),\n\t    \"cornflowerblue\"=>array(100,149,237),\n\t    \"darkslateblue\"=>array(72,61,139),\n\t    \"slateblue\"=>array(106,90,205),\n\t    \"mediumslateblue\"=>array(123,104,238),\n\t    \"lightslateblue\"=>array(132,112,255),\n\t    \"mediumblue\"=>array(0,0,205),\n\t    \"royalblue\"=>array(65,105,225),\n\t    \"blue\"=>array(0,0,255),\n\t    \"dodgerblue\"=>array(30,144,255),\n\t    \"deepskyblue\"=>array(0,191,255),\n\t    \"skyblue\"=>array(135,206,235),\n\t    \"lightskyblue\"=>array(135,206,250),\n\t    \"steelblue\"=>array(70,130,180),\n\t    \"lightred\"=>array(211,167,168),\n\t    \"lightsteelblue\"=>array(176,196,222),\n\t    \"lightblue\"=>array(173,216,230),\n\t    \"powderblue\"=>array(176,224,230),\n\t    \"paleturquoise\"=>array(175,238,238),\n\t    \"darkturquoise\"=>array(0,206,209),\n\t    \"mediumturquoise\"=>array(72,209,204),\n\t    \"turquoise\"=>array(64,224,208),\n\t    \"cyan\"=>array(0,255,255),\n\t    \"lightcyan\"=>array(224,255,255),\n\t    \"cadetblue\"=>array(95,158,160),\n\t    \"mediumaquamarine\"=>array(102,205,170),\n\t    \"aquamarine\"=>array(127,255,212),\n\t    \"darkgreen\"=>array(0,100,0),\n\t    \"darkolivegreen\"=>array(85,107,47),\n\t    \"darkseagreen\"=>array(143,188,143),\n\t    \"seagreen\"=>array(46,139,87),\n\t    \"mediumseagreen\"=>array(60,179,113),\n\t    \"lightseagreen\"=>array(32,178,170),\n\t    \"palegreen\"=>array(152,251,152),\n\t    \"springgreen\"=>array(0,255,127),\n\t    \"lawngreen\"=>array(124,252,0),\n\t    \"green\"=>array(0,255,0),\n\t    \"chartreuse\"=>array(127,255,0),\n\t    \"mediumspringgreen\"=>array(0,250,154),\n\t    \"greenyellow\"=>array(173,255,47),\n\t    \"limegreen\"=>array(50,205,50),\n\t    \"yellowgreen\"=>array(154,205,50),\n\t    \"forestgreen\"=>array(34,139,34),\n\t    \"olivedrab\"=>array(107,142,35),\n\t    \"darkkhaki\"=>array(189,183,107),\n\t    \"khaki\"=>array(240,230,140),\n\t    \"palegoldenrod\"=>array(238,232,170),\n\t    \"lightgoldenrodyellow\"=>array(250,250,210),\n\t    \"lightyellow\"=>array(255,255,200),\n\t    \"yellow\"=>array(255,255,0),\n\t    \"gold\"=>array(255,215,0),\n\t    \"lightgoldenrod\"=>array(238,221,130),\n\t    \"goldenrod\"=>array(218,165,32),\n\t    \"darkgoldenrod\"=>array(184,134,11),\n\t    \"rosybrown\"=>array(188,143,143),\n\t    \"indianred\"=>array(205,92,92),\n\t    \"saddlebrown\"=>array(139,69,19),\n\t    \"sienna\"=>array(160,82,45),\n\t    \"peru\"=>array(205,133,63),\n\t    \"burlywood\"=>array(222,184,135),\n\t    \"beige\"=>array(245,245,220),\n\t    \"wheat\"=>array(245,222,179),\n\t    \"sandybrown\"=>array(244,164,96),\n\t    \"tan\"=>array(210,180,140),\n\t    \"chocolate\"=>array(210,105,30),\n\t    \"firebrick\"=>array(178,34,34),\n\t    \"brown\"=>array(165,42,42),\n\t    \"darksalmon\"=>array(233,150,122),\n\t    \"salmon\"=>array(250,128,114),\n\t    \"lightsalmon\"=>array(255,160,122),\n\t    \"orange\"=>array(255,165,0),\n\t    \"darkorange\"=>array(255,140,0),\n\t    \"coral\"=>array(255,127,80),\n\t    \"lightcoral\"=>array(240,128,128),\n\t    \"tomato\"=>array(255,99,71),\n\t    \"orangered\"=>array(255,69,0),\n\t    \"red\"=>array(255,0,0),\n\t    \"hotpink\"=>array(255,105,180),\n\t    \"deeppink\"=>array(255,20,147),\n\t    \"pink\"=>array(255,192,203),\n\t    \"lightpink\"=>array(255,182,193),\n\t    \"palevioletred\"=>array(219,112,147),\n\t    \"maroon\"=>array(176,48,96),\n\t    \"mediumvioletred\"=>array(199,21,133),\n\t    \"violetred\"=>array(208,32,144),\n\t    \"magenta\"=>array(255,0,255),\n\t    \"violet\"=>array(238,130,238),\n\t    \"plum\"=>array(221,160,221),\n\t    \"orchid\"=>array(218,112,214),\n\t    \"mediumorchid\"=>array(186,85,211),\n\t    \"darkorchid\"=>array(153,50,204),\n\t    \"darkviolet\"=>array(148,0,211),\n\t    \"blueviolet\"=>array(138,43,226),\n\t    \"purple\"=>array(160,32,240),\n\t    \"mediumpurple\"=>array(147,112,219),\n\t    \"thistle\"=>array(216,191,216),\n\t    \"snow1\"=>array(255,250,250),\n\t    \"snow2\"=>array(238,233,233),\n\t    \"snow3\"=>array(205,201,201),\n\t    \"snow4\"=>array(139,137,137),\n\t    \"seashell1\"=>array(255,245,238),\n\t    \"seashell2\"=>array(238,229,222),\n\t    \"seashell3\"=>array(205,197,191),\n\t    \"seashell4\"=>array(139,134,130),\n\t    \"AntiqueWhite1\"=>array(255,239,219),\n\t    \"AntiqueWhite2\"=>array(238,223,204),\n\t    \"AntiqueWhite3\"=>array(205,192,176),\n\t    \"AntiqueWhite4\"=>array(139,131,120),\n\t    \"bisque1\"=>array(255,228,196),\n\t    \"bisque2\"=>array(238,213,183),\n\t    \"bisque3\"=>array(205,183,158),\n\t    \"bisque4\"=>array(139,125,107),\n\t    \"peachPuff1\"=>array(255,218,185),\n\t    \"peachpuff2\"=>array(238,203,173),\n\t    \"peachpuff3\"=>array(205,175,149),\n\t    \"peachpuff4\"=>array(139,119,101),\n\t    \"navajowhite1\"=>array(255,222,173),\n\t    \"navajowhite2\"=>array(238,207,161),\n\t    \"navajowhite3\"=>array(205,179,139),\n\t    \"navajowhite4\"=>array(139,121,94),\n\t    \"lemonchiffon1\"=>array(255,250,205),\n\t    \"lemonchiffon2\"=>array(238,233,191),\n\t    \"lemonchiffon3\"=>array(205,201,165),\n\t    \"lemonchiffon4\"=>array(139,137,112),\n\t    \"ivory1\"=>array(255,255,240),\n\t    \"ivory2\"=>array(238,238,224),\n\t    \"ivory3\"=>array(205,205,193),\n\t    \"ivory4\"=>array(139,139,131),\n\t    \"honeydew\"=>array(193,205,193),\n\t    \"lavenderblush1\"=>array(255,240,245),\n\t    \"lavenderblush2\"=>array(238,224,229),\n\t    \"lavenderblush3\"=>array(205,193,197),\n\t    \"lavenderblush4\"=>array(139,131,134),\n\t    \"mistyrose1\"=>array(255,228,225),\n\t    \"mistyrose2\"=>array(238,213,210),\n\t    \"mistyrose3\"=>array(205,183,181),\n\t    \"mistyrose4\"=>array(139,125,123),\n\t    \"azure1\"=>array(240,255,255),\n\t    \"azure2\"=>array(224,238,238),\n\t    \"azure3\"=>array(193,205,205),\n\t    \"azure4\"=>array(131,139,139),\n\t    \"slateblue1\"=>array(131,111,255),\n\t    \"slateblue2\"=>array(122,103,238),\n\t    \"slateblue3\"=>array(105,89,205),\n\t    \"slateblue4\"=>array(71,60,139),\n\t    \"royalblue1\"=>array(72,118,255),\n\t    \"royalblue2\"=>array(67,110,238),\n\t    \"royalblue3\"=>array(58,95,205),\n\t    \"royalblue4\"=>array(39,64,139),\n\t    \"dodgerblue1\"=>array(30,144,255),\n\t    \"dodgerblue2\"=>array(28,134,238),\n\t    \"dodgerblue3\"=>array(24,116,205),\n\t    \"dodgerblue4\"=>array(16,78,139),\n\t    \"steelblue1\"=>array(99,184,255),\n\t    \"steelblue2\"=>array(92,172,238),\n\t    \"steelblue3\"=>array(79,148,205),\n\t    \"steelblue4\"=>array(54,100,139),\n\t    \"deepskyblue1\"=>array(0,191,255),\n\t    \"deepskyblue2\"=>array(0,178,238),\n\t    \"deepskyblue3\"=>array(0,154,205),\n\t    \"deepskyblue4\"=>array(0,104,139),\n\t    \"skyblue1\"=>array(135,206,255),\n\t    \"skyblue2\"=>array(126,192,238),\n\t    \"skyblue3\"=>array(108,166,205),\n\t    \"skyblue4\"=>array(74,112,139),\n\t    \"lightskyblue1\"=>array(176,226,255),\n\t    \"lightskyblue2\"=>array(164,211,238),\n\t    \"lightskyblue3\"=>array(141,182,205),\n\t    \"lightskyblue4\"=>array(96,123,139),\n\t    \"slategray1\"=>array(198,226,255),\n\t    \"slategray2\"=>array(185,211,238),\n\t    \"slategray3\"=>array(159,182,205),\n\t    \"slategray4\"=>array(108,123,139),\n\t    \"lightsteelblue1\"=>array(202,225,255),\n\t    \"lightsteelblue2\"=>array(188,210,238),\n\t    \"lightsteelblue3\"=>array(162,181,205),\n\t    \"lightsteelblue4\"=>array(110,123,139),\n\t    \"lightblue1\"=>array(191,239,255),\n\t    \"lightblue2\"=>array(178,223,238),\n\t    \"lightblue3\"=>array(154,192,205),\n\t    \"lightblue4\"=>array(104,131,139),\n\t    \"lightcyan1\"=>array(224,255,255),\n\t    \"lightcyan2\"=>array(209,238,238),\n\t    \"lightcyan3\"=>array(180,205,205),\n\t    \"lightcyan4\"=>array(122,139,139),\n\t    \"paleturquoise1\"=>array(187,255,255),\n\t    \"paleturquoise2\"=>array(174,238,238),\n\t    \"paleturquoise3\"=>array(150,205,205),\n\t    \"paleturquoise4\"=>array(102,139,139),\n\t    \"cadetblue1\"=>array(152,245,255),\n\t    \"cadetblue2\"=>array(142,229,238),\n\t    \"cadetblue3\"=>array(122,197,205),\n\t    \"cadetblue4\"=>array(83,134,139),\n\t    \"turquoise1\"=>array(0,245,255),\n\t    \"turquoise2\"=>array(0,229,238),\n\t    \"turquoise3\"=>array(0,197,205),\n\t    \"turquoise4\"=>array(0,134,139),\n\t    \"cyan1\"=>array(0,255,255),\n\t    \"cyan2\"=>array(0,238,238),\n\t    \"cyan3\"=>array(0,205,205),\n\t    \"cyan4\"=>array(0,139,139),\n\t    \"darkslategray1\"=>array(151,255,255),\n\t    \"darkslategray2\"=>array(141,238,238),\n\t    \"darkslategray3\"=>array(121,205,205),\n\t    \"darkslategray4\"=>array(82,139,139),\n\t    \"aquamarine1\"=>array(127,255,212),\n\t    \"aquamarine2\"=>array(118,238,198),\n\t    \"aquamarine3\"=>array(102,205,170),\n\t    \"aquamarine4\"=>array(69,139,116),\n\t    \"darkseagreen1\"=>array(193,255,193),\n\t    \"darkseagreen2\"=>array(180,238,180),\n\t    \"darkseagreen3\"=>array(155,205,155),\n\t    \"darkseagreen4\"=>array(105,139,105),\n\t    \"seagreen1\"=>array(84,255,159),\n\t    \"seagreen2\"=>array(78,238,148),\n\t    \"seagreen3\"=>array(67,205,128),\n\t    \"seagreen4\"=>array(46,139,87),\n\t    \"palegreen1\"=>array(154,255,154),\n\t    \"palegreen2\"=>array(144,238,144),\n\t    \"palegreen3\"=>array(124,205,124),\n\t    \"palegreen4\"=>array(84,139,84),\n\t    \"springgreen1\"=>array(0,255,127),\n\t    \"springgreen2\"=>array(0,238,118),\n\t    \"springgreen3\"=>array(0,205,102),\n\t    \"springgreen4\"=>array(0,139,69),\n\t    \"chartreuse1\"=>array(127,255,0),\n\t    \"chartreuse2\"=>array(118,238,0),\n\t    \"chartreuse3\"=>array(102,205,0),\n\t    \"chartreuse4\"=>array(69,139,0),\n\t    \"olivedrab1\"=>array(192,255,62),\n\t    \"olivedrab2\"=>array(179,238,58),\n\t    \"olivedrab3\"=>array(154,205,50),\n\t    \"olivedrab4\"=>array(105,139,34),\n\t    \"darkolivegreen1\"=>array(202,255,112),\n\t    \"darkolivegreen2\"=>array(188,238,104),\n\t    \"darkolivegreen3\"=>array(162,205,90),\n\t    \"darkolivegreen4\"=>array(110,139,61),\n\t    \"khaki1\"=>array(255,246,143),\n\t    \"khaki2\"=>array(238,230,133),\n\t    \"khaki3\"=>array(205,198,115),\n\t    \"khaki4\"=>array(139,134,78),\n\t    \"lightgoldenrod1\"=>array(255,236,139),\n\t    \"lightgoldenrod2\"=>array(238,220,130),\n\t    \"lightgoldenrod3\"=>array(205,190,112),\n\t    \"lightgoldenrod4\"=>array(139,129,76),\n\t    \"yellow1\"=>array(255,255,0),\n\t    \"yellow2\"=>array(238,238,0),\n\t    \"yellow3\"=>array(205,205,0),\n\t    \"yellow4\"=>array(139,139,0),\n\t    \"gold1\"=>array(255,215,0),\n\t    \"gold2\"=>array(238,201,0),\n\t    \"gold3\"=>array(205,173,0),\n\t    \"gold4\"=>array(139,117,0),\n\t    \"goldenrod1\"=>array(255,193,37),\n\t    \"goldenrod2\"=>array(238,180,34),\n\t    \"goldenrod3\"=>array(205,155,29),\n\t    \"goldenrod4\"=>array(139,105,20),\n\t    \"darkgoldenrod1\"=>array(255,185,15),\n\t    \"darkgoldenrod2\"=>array(238,173,14),\n\t    \"darkgoldenrod3\"=>array(205,149,12),\n\t    \"darkgoldenrod4\"=>array(139,101,8),\n\t    \"rosybrown1\"=>array(255,193,193),\n\t    \"rosybrown2\"=>array(238,180,180),\n\t    \"rosybrown3\"=>array(205,155,155),\n\t    \"rosybrown4\"=>array(139,105,105),\n\t    \"indianred1\"=>array(255,106,106),\n\t    \"indianred2\"=>array(238,99,99),\n\t    \"indianred3\"=>array(205,85,85),\n\t    \"indianred4\"=>array(139,58,58),\n\t    \"sienna1\"=>array(255,130,71),\n\t    \"sienna2\"=>array(238,121,66),\n\t    \"sienna3\"=>array(205,104,57),\n\t    \"sienna4\"=>array(139,71,38),\n\t    \"burlywood1\"=>array(255,211,155),\n\t    \"burlywood2\"=>array(238,197,145),\n\t    \"burlywood3\"=>array(205,170,125),\n\t    \"burlywood4\"=>array(139,115,85),\n\t    \"wheat1\"=>array(255,231,186),\n\t    \"wheat2\"=>array(238,216,174),\n\t    \"wheat3\"=>array(205,186,150),\n\t    \"wheat4\"=>array(139,126,102),\n\t    \"tan1\"=>array(255,165,79),\n\t    \"tan2\"=>array(238,154,73),\n\t    \"tan3\"=>array(205,133,63),\n\t    \"tan4\"=>array(139,90,43),\n\t    \"chocolate1\"=>array(255,127,36),\n\t    \"chocolate2\"=>array(238,118,33),\n\t    \"chocolate3\"=>array(205,102,29),\n\t    \"chocolate4\"=>array(139,69,19),\n\t    \"firebrick1\"=>array(255,48,48),\n\t    \"firebrick2\"=>array(238,44,44),\n\t    \"firebrick3\"=>array(205,38,38),\n\t    \"firebrick4\"=>array(139,26,26),\n\t    \"brown1\"=>array(255,64,64),\n\t    \"brown2\"=>array(238,59,59),\n\t    \"brown3\"=>array(205,51,51),\n\t    \"brown4\"=>array(139,35,35),\n\t    \"salmon1\"=>array(255,140,105),\n\t    \"salmon2\"=>array(238,130,98),\n\t    \"salmon3\"=>array(205,112,84),\n\t    \"salmon4\"=>array(139,76,57),\n\t    \"lightsalmon1\"=>array(255,160,122),\n\t    \"lightsalmon2\"=>array(238,149,114),\n\t    \"lightsalmon3\"=>array(205,129,98),\n\t    \"lightsalmon4\"=>array(139,87,66),\n\t    \"orange1\"=>array(255,165,0),\n\t    \"orange2\"=>array(238,154,0),\n\t    \"orange3\"=>array(205,133,0),\n\t    \"orange4\"=>array(139,90,0),\n\t    \"darkorange1\"=>array(255,127,0),\n\t    \"darkorange2\"=>array(238,118,0),\n\t    \"darkorange3\"=>array(205,102,0),\n\t    \"darkorange4\"=>array(139,69,0),\n\t    \"coral1\"=>array(255,114,86),\n\t    \"coral2\"=>array(238,106,80),\n\t    \"coral3\"=>array(205,91,69),\n\t    \"coral4\"=>array(139,62,47),\n\t    \"tomato1\"=>array(255,99,71),\n\t    \"tomato2\"=>array(238,92,66),\n\t    \"tomato3\"=>array(205,79,57),\n\t    \"tomato4\"=>array(139,54,38),\n\t    \"orangered1\"=>array(255,69,0),\n\t    \"orangered2\"=>array(238,64,0),\n\t    \"orangered3\"=>array(205,55,0),\n\t    \"orangered4\"=>array(139,37,0),\n\t    \"deeppink1\"=>array(255,20,147),\n\t    \"deeppink2\"=>array(238,18,137),\n\t    \"deeppink3\"=>array(205,16,118),\n\t    \"deeppink4\"=>array(139,10,80),\n\t    \"hotpink1\"=>array(255,110,180),\n\t    \"hotpink2\"=>array(238,106,167),\n\t    \"hotpink3\"=>array(205,96,144),\n\t    \"hotpink4\"=>array(139,58,98),\n\t    \"pink1\"=>array(255,181,197),\n\t    \"pink2\"=>array(238,169,184),\n\t    \"pink3\"=>array(205,145,158),\n\t    \"pink4\"=>array(139,99,108),\n\t    \"lightpink1\"=>array(255,174,185),\n\t    \"lightpink2\"=>array(238,162,173),\n\t    \"lightpink3\"=>array(205,140,149),\n\t    \"lightpink4\"=>array(139,95,101),\n\t    \"palevioletred1\"=>array(255,130,171),\n\t    \"palevioletred2\"=>array(238,121,159),\n\t    \"palevioletred3\"=>array(205,104,137),\n\t    \"palevioletred4\"=>array(139,71,93),\n\t    \"maroon1\"=>array(255,52,179),\n\t    \"maroon2\"=>array(238,48,167),\n\t    \"maroon3\"=>array(205,41,144),\n\t    \"maroon4\"=>array(139,28,98),\n\t    \"violetred1\"=>array(255,62,150),\n\t    \"violetred2\"=>array(238,58,140),\n\t    \"violetred3\"=>array(205,50,120),\n\t    \"violetred4\"=>array(139,34,82),\n\t    \"magenta1\"=>array(255,0,255),\n\t    \"magenta2\"=>array(238,0,238),\n\t    \"magenta3\"=>array(205,0,205),\n\t    \"magenta4\"=>array(139,0,139),\n\t    \"mediumred\"=>array(140,34,34),         \n\t    \"orchid1\"=>array(255,131,250),\n\t    \"orchid2\"=>array(238,122,233),\n\t    \"orchid3\"=>array(205,105,201),\n\t    \"orchid4\"=>array(139,71,137),\n\t    \"plum1\"=>array(255,187,255),\n\t    \"plum2\"=>array(238,174,238),\n\t    \"plum3\"=>array(205,150,205),\n\t    \"plum4\"=>array(139,102,139),\n\t    \"mediumorchid1\"=>array(224,102,255),\n\t    \"mediumorchid2\"=>array(209,95,238),\n\t    \"mediumorchid3\"=>array(180,82,205),\n\t    \"mediumorchid4\"=>array(122,55,139),\n\t    \"darkorchid1\"=>array(191,62,255),\n\t    \"darkorchid2\"=>array(178,58,238),\n\t    \"darkorchid3\"=>array(154,50,205),\n\t    \"darkorchid4\"=>array(104,34,139),\n\t    \"purple1\"=>array(155,48,255),\n\t    \"purple2\"=>array(145,44,238),\n\t    \"purple3\"=>array(125,38,205),\n\t    \"purple4\"=>array(85,26,139),\n\t    \"mediumpurple1\"=>array(171,130,255),\n\t    \"mediumpurple2\"=>array(159,121,238),\n\t    \"mediumpurple3\"=>array(137,104,205),\n\t    \"mediumpurple4\"=>array(93,71,139),\n\t    \"thistle1\"=>array(255,225,255),\n\t    \"thistle2\"=>array(238,210,238),\n\t    \"thistle3\"=>array(205,181,205),\n\t    \"thistle4\"=>array(139,123,139),\n\t    \"gray1\"=>array(10,10,10),\n\t    \"gray2\"=>array(40,40,30),\n\t    \"gray3\"=>array(70,70,70),\n\t    \"gray4\"=>array(100,100,100),\n\t    \"gray5\"=>array(130,130,130),\n\t    \"gray6\"=>array(160,160,160),\n\t    \"gray7\"=>array(190,190,190),\n\t    \"gray8\"=>array(210,210,210),\n\t    \"gray9\"=>array(240,240,240),\n\t    \"darkgray\"=>array(100,100,100),\n\t    \"darkblue\"=>array(0,0,139),\n\t    \"darkcyan\"=>array(0,139,139),\n\t    \"darkmagenta\"=>array(139,0,139),\n\t    \"darkred\"=>array(139,0,0),\n\t    \"silver\"=>array(192, 192, 192),\n\t    \"eggplant\"=>array(144,176,168),\n\t    \"lightgreen\"=>array(144,238,144));\t\t\n    }\n//----------------\n// PUBLIC METHODS\n    // Colors can be specified as either\n    // 1. #xxxxxx\t\t\tHTML style\n    // 2. \"colorname\" \tas a named color\n    // 3. array(r,g,b)\tRGB triple\n    // This function translates this to a native RGB format and returns an \n    // RGB triple.\n    function Color($aColor) {\n\tif (is_string($aColor)) {\n\t    // Strip of any alpha factor\n\t    $pos = strpos($aColor,'@');\n\t    if( $pos === false ) {\n\t\t$alpha = 0;\n\t    }\n\t    else {\n\t\t$pos2 = strpos($aColor,':');\n\t\tif( $pos2===false ) \n\t\t    $pos2 = $pos-1; // Sentinel\n\t\tif( $pos > $pos2 ) {\n\t\t    $alpha = substr($aColor,$pos+1);\n\t\t    $aColor = substr($aColor,0,$pos);\n\t\t}\n\t\telse {\n\t\t    $alpha = substr($aColor,$pos+1,$pos2-$pos-1);\n\t\t    $aColor = substr($aColor,0,$pos).substr($aColor,$pos2);\n\t\t}\n\t    }\n\n\t    // Extract potential adjustment figure at end of color\n\t    // specification\n\t    $pos = strpos($aColor,\":\");\n\t    if( $pos === false ) {\n\t\t$adj = 1.0;\n\t    }\n\t    else {\n\t\t$adj = 0.0 + substr($aColor,$pos+1);\n\t\t$aColor = substr($aColor,0,$pos);\n\t    }\n\t    if( $adj < 0 )\n\t\tJpGraphError::RaiseL(25077);//('Adjustment factor for color must be > 0');\n\n\t    if (substr($aColor, 0, 1) == \"#\") {\n\t\t$r = hexdec(substr($aColor, 1, 2));\n\t\t$g = hexdec(substr($aColor, 3, 2));\n\t\t$b = hexdec(substr($aColor, 5, 2));\n\t    } else {\n      \t\tif(!isset($this->rgb_table[$aColor]) )\n\t\t    JpGraphError::RaiseL(25078,$aColor);//(\" Unknown color: $aColor\");\n\t\t$tmp=$this->rgb_table[$aColor];\n\t\t$r = $tmp[0];\n\t\t$g = $tmp[1];\n\t\t$b = $tmp[2];\n\t    }\n\t    // Scale adj so that an adj=2 always\n\t    // makes the color 100% white (i.e. 255,255,255. \n\t    // and adj=1 neutral and adj=0 black.\n\t    if( $adj > 1 ) {\n\t\t$m = ($adj-1.0)*(255-min(255,min($r,min($g,$b))));\n\t\treturn array(min(255,$r+$m), min(255,$g+$m), min(255,$b+$m),$alpha);\n\t    }\n\t    elseif( $adj < 1 ) {\n\t\t$m = ($adj-1.0)*max(255,max($r,max($g,$b)));\n\t\treturn array(max(0,$r+$m), max(0,$g+$m), max(0,$b+$m),$alpha);\n\t    }\n\t    else {\n\t\treturn array($r,$g,$b,$alpha);\n\t    }\n\n\t} elseif( is_array($aColor) ) {\n\t    if( count($aColor)==3 ) {\n\t\t$aColor[3]=0;\n\t\treturn $aColor;\n\t    }\n\t    else\n\t\treturn $aColor;\n\t}\n\telse\n\t    JpGraphError::RaiseL(25079,$aColor,count($aColor));//(\" Unknown color specification: $aColor , size=\".count($aColor));\n    }\n\t\n    // Compare two colors\n    // return true if equal\n    function Equal($aCol1,$aCol2) {\n\t$c1 = $this->Color($aCol1);\n\t$c2 = $this->Color($aCol2);\n\tif( $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] )\n\t    return true;\n\telse\n\t    return false;\n    }\n\t\n    // Allocate a new color in the current image\n    // Return new color index, -1 if no more colors could be allocated\n    function Allocate($aColor,$aAlpha=0.0) {\n\tlist ($r, $g, $b, $a) = $this->color($aColor);\n\t// If alpha is specified in the color string then this\n\t// takes precedence over the second argument\n\tif( $a > 0 )\n\t    $aAlpha = $a;\n\tif( $GLOBALS['gd2'] ) {\n\t    if( $aAlpha < 0 || $aAlpha > 1 ) {\n\t\tJpGraphError::RaiseL(25080);//('Alpha parameter for color must be between 0.0 and 1.0');\n\t    }\n\t    return imagecolorresolvealpha($this->img, $r, $g, $b, round($aAlpha * 127));\n\t} else {\n\t    $index = imagecolorexact($this->img, $r, $g, $b);\n\t    if ($index == -1) {\n      \t\t$index = imagecolorallocate($this->img, $r, $g, $b);\n      \t\tif( USE_APPROX_COLORS && $index == -1 )\n\t\t    $index = imagecolorresolve($this->img, $r, $g, $b);\n\t    } \n\t    return $index;\n\t}\n    }\n} // Class\n\n\t\n//===================================================\n// CLASS Image\n// Description: Wrapper class with some goodies to form the\n// Interface to low level image drawing routines.\n//===================================================\nclass Image {\n    var $img_format;\n    var $expired=true;\n    var $img=null;\n    var $left_margin=30,$right_margin=20,$top_margin=20,$bottom_margin=30;\n    var $plotwidth=0,$plotheight=0;\n    var $rgb=null;\n    var $current_color,$current_color_name;\n    var $lastx=0, $lasty=0;\n    var $width=0, $height=0;\n    var $line_weight=1;\n    var $line_style=1;\t// Default line style is solid\n    var $obs_list=array();\n    var $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL;\n    var $font_file='';\n    var $text_halign=\"left\",$text_valign=\"bottom\";\n    var $ttf=null;\n    var $use_anti_aliasing=false;\n    var $quality=null;\n    var $colorstack=array(),$colorstackidx=0;\n    var $canvascolor = 'white' ;\n    var $langconv = null ;\n\n    //---------------\n    // CONSTRUCTOR\n    function Image($aWidth,$aHeight,$aFormat=DEFAULT_GFORMAT) {\n\t$this->CreateImgCanvas($aWidth,$aHeight);\n\t$this->SetAutoMargin();\t\t\n\n\tif( !$this->SetImgFormat($aFormat) ) {\n\t    JpGraphError::RaiseL(25081,$aFormat);//(\"JpGraph: Selected graphic format is either not supported or unknown [$aFormat]\");\n\t}\n\t$this->ttf = new TTF();\n\t$this->langconv = new LanguageConv();\n    }\n\n    // Should we use anti-aliasing. Note: This really slows down graphics!\n    function SetAntiAliasing() {\n\t$this->use_anti_aliasing=true;\n    }\n\n    function CreateRawCanvas($aWidth=0,$aHeight=0) {\n\tif( $aWidth <= 1 || $aHeight <= 1 ) {\n\t    JpGraphError::RaiseL(25082,$aWidth,$aHeight);//(\"Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)\");\n\t}\n\tif( @$GLOBALS['gd2']==true && USE_TRUECOLOR ) {\n\t    $this->img = @imagecreatetruecolor($aWidth, $aHeight);\n\t    if( $this->img < 1 ) {\n\t\tJpGraphError::RaiseL(25126);\n\t\t//die(\"Can't create truecolor image. Check that you really have GD2 library installed.\");\n\t    }\n\t    $this->SetAlphaBlending();\n\t} else {\n\t    $this->img = @imagecreate($aWidth, $aHeight);\t\n\t    if( $this->img < 1 ) {\n\t\tJpGraphError::RaiseL(25126);\n\t\t//die(\"<b>JpGraph Error:</b> Can't create image. Check that you really have the GD library installed.\");\n\t    }\n\t}\n\tif( $this->rgb != null ) \n\t    $this->rgb->img = $this->img ;\n\telse\n\t    $this->rgb = new RGB($this->img);\t\t\t\t\n    }\n\n    function CloneCanvasH() {\n\t$oldimage = $this->img;\n\t$this->CreateRawCanvas($this->width,$this->height);\n\timagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height);\n\treturn $oldimage;\n    }\n    \n    function CreateImgCanvas($aWidth=0,$aHeight=0) {\n\n\t$old = array($this->img,$this->width,$this->height);\n\t\n\t$aWidth = round($aWidth);\n\t$aHeight = round($aHeight);\n\n\t$this->width=$aWidth;\n\t$this->height=$aHeight;\t\t\n\n\t\n\tif( $aWidth==0 || $aHeight==0 ) {\n\t    // We will set the final size later. \n\t    // Note: The size must be specified before any other\n\t    // img routines that stroke anything are called.\n\t    $this->img = null;\n\t    $this->rgb = null;\n\t    return $old;\n\t}\n\t\n\t$this->CreateRawCanvas($aWidth,$aHeight);\n\t\t\n\t// Set canvas color (will also be the background color for a \n\t// a pallett image\n\t$this->SetColor($this->canvascolor);\t\n\t$this->FilledRectangle(0,0,$aWidth,$aHeight);\n\n\treturn $old ;\n    }\n\n    function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) {\n\tif( $aw === -1 ) {\n\t    $aw = $aWidth;\n\t    $ah = $aHeight;\n\t    $f = 'imagecopyresized';\n\t}\n\telse {\n\t    $f = $GLOBALS['copyfunc'] ;\n\t}\n\t$f($aToHdl,$aFromHdl,\n\t   $aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah);\n    }\n\n    function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) {\n\t$this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY,\n\t\t\t   $toWidth,$toHeight,$fromWidth,$fromHeight);\n    }\n\n    function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) {\n\tif( $aMix == 100 ) {\n\t    $this->CopyCanvasH($this->img,$fromImg,\n\t\t\t       $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight);\n\t}\n\telse {\n\t    if( ($fromWidth  != -1 && ($fromWidth != $toWidth))  ||\n\t\t($fromHeight != -1 && ($fromHeight != $fromHeight)) ) {\n\t\t// Create a new canvas that will hold the re-scaled original from image\n\t\tif( $toWidth <= 1 || $toHeight <= 1 ) {\n\t\t    JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.');\n\t\t}\n\t\tif( @$GLOBALS['gd2']==true && USE_TRUECOLOR ) {\n\t\t    $tmpimg = @imagecreatetruecolor($toWidth, $toHeight);\n\t\t} else {\n\t\t    $tmpimg = @imagecreate($toWidth, $toHeight);\t\n\t\t}\t    \n\t\tif( $tmpimg < 1 ) {\n\t\t    JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?');\n\t\t}\n\t\t$this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0,\n\t\t\t\t   $toWidth,$toHeight,$fromWidth,$fromHeight);\n\t\t$fromImg = $tmpimg;\n\t    }\n\t    imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix);\n\t}\n    }\n\n    function GetWidth($aImg=null) {\n\tif( $aImg === null ) \n\t    $aImg = $this->img;\n\treturn imagesx($aImg);\n    }\n\n    function GetHeight($aImg=null) {\n\tif( $aImg === null ) \n\t    $aImg = $this->img;\n\treturn imagesy($aImg);\n    }\n    \n    function CreateFromString($aStr) {\n\t$img = imagecreatefromstring($aStr);\n\tif( $img === false ) {\n\t    JpGraphError::RaiseL(25085);//('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.');\n\t}\n\treturn $img;\n    }\n\n    function SetCanvasH($aHdl) {\n\t$this->img = $aHdl;\n\t$this->rgb->img = $aHdl;\n    }\n\n    function SetCanvasColor($aColor) {\n\t$this->canvascolor = $aColor ;\n    }\n\n    function SetAlphaBlending($aFlg=true) {\n\tif( $GLOBALS['gd2'] )\n\t    ImageAlphaBlending($this->img,$aFlg);\n\telse \n\t    JpGraphError::RaiseL(25086);//('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to autodetect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.');\n    }\n\n\t\n    function SetAutoMargin() {\t\n\tGLOBAL $gJpgBrandTiming;\n\t$min_bm=10;\n\t/*\n\tif( $gJpgBrandTiming )\n\t    $min_bm=15;\t\t\n\t*/\n\t$lm = min(40,$this->width/7);\n\t$rm = min(20,$this->width/10);\n\t$tm = max(20,$this->height/7);\n\t$bm = max($min_bm,$this->height/7);\n\t$this->SetMargin($lm,$rm,$tm,$bm);\t\t\n    }\n\n\t\t\t\t\n    //---------------\n    // PUBLIC METHODS\t\n\t\n    function SetFont($family,$style=FS_NORMAL,$size=10) {\n\t$this->font_family=$family;\n\t$this->font_style=$style;\n\t$this->font_size=$size;\n\t$this->font_file='';\n\tif( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){\n\t    ++$this->font_family;\n\t}\n\tif( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file\n\n\t    // Check that this PHP has support for TTF fonts\n\t    if( !function_exists('imagettfbbox') ) {\n\t\tJpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.');\n\t\texit();\n\t    }\n\t    $this->font_file = $this->ttf->File($this->font_family,$this->font_style);\n\t}\n    }\n\n    // Get the specific height for a text string\n    function GetTextHeight($txt=\"\",$angle=0) {\n\t$tmp = split(\"\\n\",$txt);\n\t$n = count($tmp);\n\t$m=0;\n\tfor($i=0; $i< $n; ++$i)\n\t    $m = max($m,strlen($tmp[$i]));\n\n\tif( $this->font_family <= FF_FONT2+1 ) {\n\t    if( $angle==0 ) {\n\t\t$h = imagefontheight($this->font_family);\n\t\tif( $h === false ) {\n\t\t    JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');\n\t\t}\n\n\t\treturn $n*$h;\n\t    }\n\t    else {\n\t\t$w = @imagefontwidth($this->font_family);\n\t\tif( $w === false ) {\n\t\t    JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');\n\t\t}\n\n\t\treturn $m*$w;\n\t    }\n\t}\n\telse {\n\t    $bbox = $this->GetTTFBBox($txt,$angle);\n\t    return $bbox[1]-$bbox[5];\n\t}\n    }\n\t\n    // Estimate font height\n    function GetFontHeight($angle=0) {\n\t$txt = \"XOMg\";\n\treturn $this->GetTextHeight($txt,$angle);\n    }\n\t\n    // Approximate font width with width of letter \"O\"\n    function GetFontWidth($angle=0) {\n\t$txt = 'O';\n\treturn $this->GetTextWidth($txt,$angle);\n    }\n\t\n    // Get actual width of text in absolute pixels\n    function GetTextWidth($txt,$angle=0) {\n\n\t$tmp = split(\"\\n\",$txt);\n\t$n = count($tmp);\n\tif( $this->font_family <= FF_FONT2+1 ) {\n\n\t    $m=0;\n\t    for($i=0; $i < $n; ++$i) {\n\t\t$l=strlen($tmp[$i]);\n\t\tif( $l > $m ) {\n\t\t    $m = $l;\n\t\t}\n\t    }\n\n\t    if( $angle==0 ) {\n\t\t$w = @imagefontwidth($this->font_family);\n\t\tif( $w === false ) {\n\t\t    JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.');\n\t\t}\n\t\treturn $m*$w;\n\t    }\n\t    else {\n\t\t// 90 degrees internal so height becomes width\n\t\t$h = @imagefontheight($this->font_family); \n\t\tif( $h === false ) {\n\t\t    JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.');\n\t\t}\n\t\treturn $n*$h;\n\t    }\n\t}\n\telse {\n\t    // For TTF fonts we must walk through a lines and find the \n\t    // widest one which we use as the width of the multi-line\n\t    // paragraph\n\t    $m=0;\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$bbox = $this->GetTTFBBox($tmp[$i],$angle);\n\t\t$mm =  $bbox[2] - $bbox[0];\n\t\tif( $mm > $m ) \n\t\t    $m = $mm;\n\t    }\n\t    return $m;\n\t}\n    }\n\t\n    // Draw text with a box around it\n    function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor=\"white\",$bcolor=\"black\",\n\t\t\t     $shadowcolor=false,$paragraph_align=\"left\",\n\t\t\t     $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) {\n\n\tif( !is_numeric($dir) ) {\n\t    if( $dir==\"h\" ) $dir=0;\n\t    elseif( $dir==\"v\" ) $dir=90;\n\t    else JpGraphError::RaiseL(25090,$dir);//(\" Unknown direction specified in call to StrokeBoxedText() [$dir]\");\n\t}\n\t\t\n\tif( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) {\t\n\t    $width=$this->GetTextWidth($txt,$dir) ;\n\t    $height=$this->GetTextHeight($txt,$dir) ;\n\t}\n\telse {\n\t    $width=$this->GetBBoxWidth($txt,$dir) ;\n\t    $height=$this->GetBBoxHeight($txt,$dir) ;\n\t}\n\n\t$height += 2*$ymarg;\n\t$width  += 2*$xmarg;\n\n\tif( $this->text_halign==\"right\" ) $x -= $width;\n\telseif( $this->text_halign==\"center\" ) $x -= $width/2;\n\tif( $this->text_valign==\"bottom\" ) $y -= $height;\n\telseif( $this->text_valign==\"center\" ) $y -= $height/2;\n\t\n\tif( $shadowcolor ) {\n\t    $this->PushColor($shadowcolor);\n\t    $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth,\n\t\t\t\t\t  $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth,\n\t\t\t\t\t  $cornerradius);\n\t    $this->PopColor();\n\t    $this->PushColor($fcolor);\n\t    $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,\n\t\t\t\t\t  $x+$width,$y+$height-$ymarg,\n\t\t\t\t\t  $cornerradius);\t\t\n\t    $this->PopColor();\n\t    $this->PushColor($bcolor);\n\t    $this->RoundedRectangle($x-$xmarg,$y-$ymarg,\n\t\t\t\t    $x+$width,$y+$height-$ymarg,$cornerradius);\n\t    $this->PopColor();\n\t}\n\telse {\n\t    if( $fcolor ) {\n\t\t$oc=$this->current_color;\n\t\t$this->SetColor($fcolor);\n\t\t$this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius);\n\t\t$this->current_color=$oc;\n\t    }\n\t    if( $bcolor ) {\n\t\t$oc=$this->current_color;\n\t\t$this->SetColor($bcolor);\t\t\t\n\t\t$this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius);\n\t\t$this->current_color=$oc;\t\t\t\n\t    }\n\t}\n\t\t\n\t$h=$this->text_halign;\n\t$v=$this->text_valign;\n\t$this->SetTextAlign(\"left\",\"top\");\n\t$this->StrokeText($x, $y, $txt, $dir, $paragraph_align);\n\t$bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg,\n\t\t    $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg);\n\t$this->SetTextAlign($h,$v);\n\treturn $bb;\n    }\n\n    // Set text alignment\t\n    function SetTextAlign($halign,$valign=\"bottom\") {\n\t$this->text_halign=$halign;\n\t$this->text_valign=$valign;\n    }\n\t\n\n    function _StrokeBuiltinFont($x,$y,$txt,$dir=0,$paragraph_align=\"left\",&$aBoundingBox,$aDebug=false) {\n\n\tif( is_numeric($dir) && $dir!=90 && $dir!=0) \n\t    JpGraphError::RaiseL(25091);//(\" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.\");\n\n\t$h=$this->GetTextHeight($txt);\n\t$fh=$this->GetFontHeight();\n\t$w=$this->GetTextWidth($txt);\n\t\n\tif( $this->text_halign==\"right\") \t\t\t\t\n\t    $x -= $dir==0 ? $w : $h;\n\telseif( $this->text_halign==\"center\" ) {\n\t    // For center we subtract 1 pixel since this makes the middle\n\t    // be prefectly in the middle\n\t    $x -= $dir==0 ? $w/2-1 : $h/2;\n\t}\n\tif( $this->text_valign==\"top\" )\n\t    $y += $dir==0 ? $h : $w;\n\telseif( $this->text_valign==\"center\" ) \t\t\t\t\n\t    $y += $dir==0 ? $h/2 : $w/2;\n\t\n\tif( $dir==90 ) {\n\t    imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color);\n\t    $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y));\n            if( $aDebug ) {\n\t\t// Draw bounding box\n\t\t$this->PushColor('green');\n\t\t$this->Polygon($aBoundingBox,true);\n\t\t$this->PopColor();\n\t    }\n\t}\n\telse {\n\t    if( ereg(\"\\n\",$txt) ) { \n\t\t$tmp = split(\"\\n\",$txt);\n\t\tfor($i=0; $i < count($tmp); ++$i) {\n\t\t    $w1 = $this->GetTextWidth($tmp[$i]);\n\t\t    if( $paragraph_align==\"left\" ) {\n\t\t\timagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color);\n\t\t    }\n\t\t    elseif( $paragraph_align==\"right\" ) {\n\t\t\timagestring($this->img,$this->font_family,$x+($w-$w1),\n\t\t\t\t    $y-$h+1+$i*$fh,$tmp[$i],$this->current_color);\n\t\t    }\n\t\t    else {\n\t\t\timagestring($this->img,$this->font_family,$x+$w/2-$w1/2,\n\t\t\t\t    $y-$h+1+$i*$fh,$tmp[$i],$this->current_color);\n\t\t    }\n\t\t}\n\t    } \n\t    else {\n\t\t//Put the text\n\t\timagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color);\n\t    }\n            if( $aDebug ) {\n\t\t// Draw the bounding rectangle and the bounding box\n\t\t$p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y));\n\t\t\n\t\t// Draw bounding box\n\t\t$this->PushColor('green');\n\t\t$this->Polygon($p1,true);\n\t\t$this->PopColor();\n\n            }\n\t    $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y));\n\t}\n    }\n\n    function AddTxtCR($aTxt) {\n\t// If the user has just specified a '\\n'\n\t// instead of '\\n\\t' we have to add '\\r' since\n\t// the width will be too muchy otherwise since when\n\t// we print we stroke the individually lines by hand.\n\t$e = explode(\"\\n\",$aTxt);\n\t$n = count($e);\n\tfor($i=0; $i<$n; ++$i) {\n\t    $e[$i]=str_replace(\"\\r\",\"\",$e[$i]);\n\t}\n\treturn implode(\"\\n\\r\",$e);\n    }\n\n    function GetTTFBBox($aTxt,$aAngle=0) {\n\t$bbox = @ImageTTFBBox($this->font_size,$aAngle,$this->font_file,$aTxt);\n\tif( $bbox === false ) {\n\t    JpGraphError::RaiseL(25092,$this->font_file);\n//(\"There is either a configuration problem with TrueType or a problem reading font file (\".$this->font_file.\"). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.\");\n\t}\n\treturn $bbox;\n    }\n\n    function GetBBoxTTF($aTxt,$aAngle=0) {\n\t// Normalize the bounding box to become a minimum\n\t// enscribing rectangle\n\n\t$aTxt = $this->AddTxtCR($aTxt);\n\n\tif( !is_readable($this->font_file) ) {\n\t    JpGraphError::RaiseL(25093,$this->font_file);\n//('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.');\n\t}\n\t$bbox = $this->GetTTFBBox($aTxt,$aAngle);\n\n\tif( $aAngle==0 ) \n\t    return $bbox;\n\tif( $aAngle >= 0 ) {\n\t    if(  $aAngle <= 90 ) { //<=0\t\t\n\t\t$bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1],\n\t\t\t      $bbox[2],$bbox[5],$bbox[6],$bbox[5]);\n\t    }\n\t    elseif(  $aAngle <= 180 ) { //<= 2\n\t\t$bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7],\n\t\t\t      $bbox[0],$bbox[3],$bbox[4],$bbox[3]);\n\t    }\n\t    elseif(  $aAngle <= 270 )  { //<= 3\n\t\t$bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5],\n\t\t\t      $bbox[6],$bbox[1],$bbox[2],$bbox[1]);\n\t    }\n\t    else {\n\t\t$bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],\n\t\t\t      $bbox[4],$bbox[7],$bbox[0],$bbox[7]);\n\t    }\n\t}\n\telseif(  $aAngle < 0 ) {\n\t    if( $aAngle <= -270 ) { // <= -3\n\t\t$bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1],\n\t\t\t      $bbox[2],$bbox[5],$bbox[6],$bbox[5]);\n\t    }\n\t    elseif( $aAngle <= -180 ) { // <= -2\n\t\t$bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],\n\t\t\t      $bbox[4],$bbox[7],$bbox[0],$bbox[7]);\n\t    }\n\t    elseif( $aAngle <= -90 ) { // <= -1\n\t\t$bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5],\n\t\t\t      $bbox[6],$bbox[1],$bbox[2],$bbox[1]);\n\t    }\n\t    else {\n\t\t$bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3],\n\t\t\t      $bbox[4],$bbox[7],$bbox[0],$bbox[7]);\n\t    }\n\t}\t\n\treturn $bbox;\n    }\n\n    function GetBBoxHeight($aTxt,$aAngle=0) {\n\t$box = $this->GetBBoxTTF($aTxt,$aAngle);\n\treturn $box[1]-$box[7]+1;\n    }\n\n    function GetBBoxWidth($aTxt,$aAngle=0) {\n\t$box = $this->GetBBoxTTF($aTxt,$aAngle);\n\treturn $box[2]-$box[0]+1;\t\n    }\n\n    function _StrokeTTF($x,$y,$txt,$dir=0,$paragraph_align=\"left\",&$aBoundingBox,$debug=false) {\n\n\t// Setupo default inter line margin for paragraphs to\n\t// 25% of the font height.\n\t$ConstLineSpacing = 0.25 ;\n\n\t// Remember the anchor point before adjustment\n\tif( $debug ) {\n\t    $ox=$x;\n\t    $oy=$y;\n\t}\n\n\tif( !ereg(\"\\n\",$txt) || ($dir>0 && ereg(\"\\n\",$txt)) ) {\n\t    // Format a single line\n\n\t    $txt = $this->AddTxtCR($txt);\n\n\t    $bbox=$this->GetBBoxTTF($txt,$dir);\n\t    \n\t    // Align x,y ot lower left corner of bbox\n\t    $x -= $bbox[0];\n\t    $y -= $bbox[1];\n\n\t    // Note to self: \"topanchor\" is deprecated after we changed the\n\t    // bopunding box stuff. \n\t    if( $this->text_halign==\"right\" || $this->text_halign==\"topanchor\" ) \n\t\t$x -= $bbox[2]-$bbox[0];\n\t    elseif( $this->text_halign==\"center\" ) $x -= ($bbox[2]-$bbox[0])/2; \n\t    \n\t    if( $this->text_valign==\"top\" ) $y += abs($bbox[5])+$bbox[1];\n\t    elseif( $this->text_valign==\"center\" ) $y -= ($bbox[5]-$bbox[1])/2; \n\n\t    ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, \n\t\t\t  $this->current_color,$this->font_file,$txt); \n\n\t    // Calculate and return the co-ordinates for the bounding box\n\t    $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt);\n\t    $p1 = array();\n\n\n\t    for($i=0; $i < 4; ++$i) {\n\t\t$p1[] = round($box[$i*2]+$x);\n\t\t$p1[] = round($box[$i*2+1]+$y);\n\t    }\n\t    $aBoundingBox = $p1;\n\n\t    // Debugging code to highlight the bonding box and bounding rectangle\n\t    // For text at 0 degrees the bounding box and bounding rectangle are the\n\t    // same\n            if( $debug ) {\n\t\t// Draw the bounding rectangle and the bounding box\n\t\t$box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt);\n\t\t$p = array();\n\t\t$p1 = array();\n\t\tfor($i=0; $i < 4; ++$i) {\n\t\t    $p[] = $bbox[$i*2]+$x;\n\t\t    $p[] = $bbox[$i*2+1]+$y;\n\t\t    $p1[] = $box[$i*2]+$x;\n\t\t    $p1[] = $box[$i*2+1]+$y;\n\t\t}\n\n\t\t// Draw bounding box\n\t\t$this->PushColor('green');\n\t\t$this->Polygon($p1,true);\n\t\t$this->PopColor();\n\t\t\n\t\t// Draw bounding rectangle\n\t\t$this->PushColor('darkgreen');\n\t\t$this->Polygon($p,true);\n\t\t$this->PopColor();\n\t\t\n\t\t// Draw a cross at the anchor point\n\t\t$this->PushColor('red');\n\t\t$this->Line($ox-15,$oy,$ox+15,$oy);\n\t\t$this->Line($ox,$oy-15,$ox,$oy+15);\n\t\t$this->PopColor();\n            }\n\t}\n\telse {\n\t    // Format a text paragraph\n\t    $fh=$this->GetFontHeight();\n\n\t    // Line margin is 25% of font height\n\t    $linemargin=round($fh*$ConstLineSpacing);\n\t    $fh += $linemargin;\n\t    $w=$this->GetTextWidth($txt);\n\n\t    $y -= $linemargin/2;\n\t    $tmp = split(\"\\n\",$txt);\n\t    $nl = count($tmp);\n\t    $h = $nl * $fh;\n\n\t    if( $this->text_halign==\"right\") \t\t\t\t\n\t\t$x -= $dir==0 ? $w : $h;\n\t    elseif( $this->text_halign==\"center\" ) {\n\t\t$x -= $dir==0 ? $w/2 : $h/2;\n\t    }\n\t    \n\t    if( $this->text_valign==\"top\" )\n\t\t$y +=\t$dir==0 ? $h : $w;\n\t    elseif( $this->text_valign==\"center\" ) \t\t\t\t\n\t\t$y +=\t$dir==0 ? $h/2 : $w/2;\n\n\t    // Here comes a tricky bit. \n\t    // Since we have to give the position for the string at the\n\t    // baseline this means thaht text will move slightly up\n\t    // and down depending on any of it's character descend below\n\t    // the baseline, for example a 'g'. To adjust the Y-position\n\t    // we therefore adjust the text with the baseline Y-offset\n\t    // as used for the current font and size. This will keep the\n\t    // baseline at a fixed positoned disregarding the actual \n\t    // characters in the string. \n\t    $standardbox = $this->GetTTFBBox('Gg',$dir);\n\t    $yadj = $standardbox[1];\n\t    $xadj = $standardbox[0];\n\t    $aBoundingBox = array();\n\t    for($i=0; $i < $nl; ++$i) {\n\t\t$wl = $this->GetTextWidth($tmp[$i]);\n\t\t$bbox = $this->GetTTFBBox($tmp[$i],$dir);\n\t\tif( $paragraph_align==\"left\" ) {\n\t\t    $xl = $x; \n\t\t}\n\t\telseif( $paragraph_align==\"right\" ) {\n\t\t    $xl = $x + ($w-$wl);\n\t\t}\n\t\telse {\n\t\t    // Center\n\t\t    $xl = $x + $w/2 - $wl/2 ;\n\t\t}\n\n\t\t$xl -= $bbox[0];\n\t\t$yl = $y - $yadj; \n\t\t$xl = $xl - $xadj; \n\t\tImageTTFText ($this->img, $this->font_size, $dir, \n\t\t\t      $xl, $yl-($h-$fh)+$fh*$i,\n\t\t\t      $this->current_color,$this->font_file,$tmp[$i]); \n\n\t\tif( $debug  ) {\n\t\t    // Draw the bounding rectangle around each line\n\t\t    $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]);\n\t\t    $p = array();\n\t\t    for($j=0; $j < 4; ++$j) {\n\t\t\t$p[] = $bbox[$j*2]+$xl;\n\t\t\t$p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i;\n\t\t    }\n\t\t    \n\t\t    // Draw bounding rectangle\n\t\t    $this->PushColor('darkgreen');\n\t\t    $this->Polygon($p,true);\n\t\t    $this->PopColor();\n\t\t}\n\t    }\n\n\t    // Get the bounding box\n\t    $bbox = $this->GetBBoxTTF($txt,$dir);\n\t    for($j=0; $j < 4; ++$j) {\n\t\t$bbox[$j*2]+= round($x);\n\t\t$bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj);\n\t    }\n\t    $aBoundingBox = $bbox;\n\n\t    if( $debug ) {\t\n\t\t// Draw a cross at the anchor point\n\t\t$this->PushColor('red');\n\t\t$this->Line($ox-25,$oy,$ox+25,$oy);\n\t\t$this->Line($ox,$oy-25,$ox,$oy+25);\n\t\t$this->PopColor();\n\t    }\n\n\t}\n    }\n\t\n    function StrokeText($x,$y,$txt,$dir=0,$paragraph_align=\"left\",$debug=false) {\n\n\t$x = round($x);\n\t$y = round($y);\n\n\t// Do special language encoding\n\t$txt = $this->langconv->Convert($txt,$this->font_family);\n\n\tif( !is_numeric($dir) )\n\t    JpGraphError::RaiseL(25094);//(\" Direction for text most be given as an angle between 0 and 90.\");\n\t\t\t\n\tif( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) {\t\n\t    $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug);\n\t}\n\telseif($this->font_family >= _FF_FIRST && $this->font_family <= _FF_LAST)  {\n\t    $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug);\n\t}\n\telse\n\t    JpGraphError::RaiseL(25095);//(\" Unknown font font family specification. \");\n\treturn $boundingbox;\n    }\n\t\n    function SetMargin($lm,$rm,$tm,$bm) {\n\t$this->left_margin=$lm;\n\t$this->right_margin=$rm;\n\t$this->top_margin=$tm;\n\t$this->bottom_margin=$bm;\n\t$this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; \n\t$this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ;\n\tif( $this->width  > 0 && $this->height > 0 ) {\n\t    if( $this->plotwidth < 0  || $this->plotheight < 0 )\n\t\tJpGraphError::raise(\"Too small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins.\");\n\t}\n    }\n\n    function SetTransparent($color) {\n\timagecolortransparent ($this->img,$this->rgb->allocate($color));\n    }\n\t\n    function SetColor($color,$aAlpha=0) {\n\t$this->current_color_name = $color;\n\t$this->current_color=$this->rgb->allocate($color,$aAlpha);\n\tif( $this->current_color == -1 ) {\n\t    $tc=imagecolorstotal($this->img);\n\t    JpGraphError::RaiseL(25096);\n//(\"Can't allocate any more colors. Image has already allocated maximum of <b>$tc colors</b>. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\\\"USE_APPROX_COLORS\\\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports.\"); \n\t}\n\treturn $this->current_color;\n    }\n\t\n    function PushColor($color) {\n\tif( $color != \"\" ) {\n\t    $this->colorstack[$this->colorstackidx]=$this->current_color_name;\n\t    $this->colorstack[$this->colorstackidx+1]=$this->current_color;\n\t    $this->colorstackidx+=2;\n\t    $this->SetColor($color);\n\t}\n\telse {\n\t    JpGraphError::RaiseL(25097);//(\"Color specified as empty string in PushColor().\");\n\t}\n    }\n\t\n    function PopColor() {\n\tif($this->colorstackidx<1)\n\t    JpGraphError::RaiseL(25098);//(\" Negative Color stack index. Unmatched call to PopColor()\");\n\t$this->current_color=$this->colorstack[--$this->colorstackidx];\n\t$this->current_color_name=$this->colorstack[--$this->colorstackidx];\n    }\n\t\n\t\n    // Why this duplication? Because this way we can call this method\n    // for any image and not only the current objsct\n    function AdjSat($sat) {\t\n\tif( $GLOBALS['gd2'] && USE_TRUECOLOR )\n\t    return;\n\t$this->_AdjSat($this->img,$sat);\t\n    }\t\n\t\n    function _AdjSat($img,$sat) {\n\t$nbr = imagecolorstotal ($img);\n\tfor( $i=0; $i<$nbr; ++$i ) {\n\t    $colarr = imagecolorsforindex ($img,$i);\n\t    $rgb[0]=$colarr[\"red\"];\n\t    $rgb[1]=$colarr[\"green\"];\n\t    $rgb[2]=$colarr[\"blue\"];\n\t    $rgb = $this->AdjRGBSat($rgb,$sat);\n\t    imagecolorset ($img, $i, $rgb[0], $rgb[1], $rgb[2]);\n\t}\n    }\n\t\n    function AdjBrightContrast($bright,$contr=0) {\n\tif( $GLOBALS['gd2'] && USE_TRUECOLOR )\n\t    return;\n\t$this->_AdjBrightContrast($this->img,$bright,$contr);\n    }\n\n    function _AdjBrightContrast($img,$bright,$contr=0) {\n\tif( $bright < -1 || $bright > 1 || $contr < -1 || $contr > 1 )\n\t    JpGraphError::RaiseL(25099);//(\" Parameters for brightness and Contrast out of range [-1,1]\");\t\t\n\t$nbr = imagecolorstotal ($img);\n\tfor( $i=0; $i<$nbr; ++$i ) {\n\t    $colarr = imagecolorsforindex ($img,$i);\n\t    $r = $this->AdjRGBBrightContrast($colarr[\"red\"],$bright,$contr);\n\t    $g = $this->AdjRGBBrightContrast($colarr[\"green\"],$bright,$contr);\n\t    $b = $this->AdjRGBBrightContrast($colarr[\"blue\"],$bright,$contr);\t\t\n\t    imagecolorset ($img, $i, $r, $g, $b);\n\t}\n    }\n\t\n    // Private helper function for adj sat\n    // Adjust saturation for RGB array $u. $sat is a value between -1 and 1\n    // Note: Due to GD inability to handle true color the RGB values are only between\n    // 8 bit. This makes saturation quite sensitive for small increases in parameter sat.\n    // \n    // Tip: To get a grayscale picture set sat=-100, values <-100 changes the colors\n    // to it's complement.\n    // \n    // Implementation note: The saturation is implemented directly in the RGB space\n    // by adjusting the perpendicular distance between the RGB point and the \"grey\"\n    // line (1,1,1). Setting $sat>0 moves the point away from the line along the perp.\n    // distance and a negative value moves the point closer to the line.\n    // The values are truncated when the color point hits the bounding box along the\n    // RGB axis.\n    // DISCLAIMER: I'm not 100% sure this is he correct way to implement a color \n    // saturation function in RGB space. However, it looks ok and has the expected effect.\n    function AdjRGBSat($rgb,$sat) {\n\t// TODO: Should be moved to the RGB class\n\t// Grey vector\n\t$v=array(1,1,1);\n\n\t// Dot product\n\t$dot = $rgb[0]*$v[0]+$rgb[1]*$v[1]+$rgb[2]*$v[2];\n\n\t// Normalize dot product\n\t$normdot = $dot/3;\t// dot/|v|^2\n\n\t// Direction vector between $u and its projection onto $v\n\tfor($i=0; $i<3; ++$i)\n\t    $r[$i] = $rgb[$i] - $normdot*$v[$i];\n\n\t// Adjustment factor so that sat==1 sets the highest RGB value to 255\n\tif( $sat > 0 ) {\n\t    $m=0;\n\t    for( $i=0; $i<3; ++$i) {\n\t\tif( sign($r[$i]) == 1 && $r[$i]>0)\n\t\t    $m=max($m,(255-$rgb[$i])/$r[$i]);\n\t    }\n\t    $tadj=$m;\n\t}\n\telse\n\t    $tadj=1;\n\t\t\n\t$tadj = $tadj*$sat;\t\n\tfor($i=0; $i<3; ++$i) {\n\t    $un[$i] = round($rgb[$i] + $tadj*$r[$i]);\t\t\n\t    if( $un[$i]<0 ) $un[$i]=0;\t\t// Truncate color when they reach 0\n\t    if( $un[$i]>255 ) $un[$i]=255;// Avoid potential rounding error\n\t}\t\t\n\treturn $un;\t\n    }\t\n\n    // Private helper function for AdjBrightContrast\n    function AdjRGBBrightContrast($rgb,$bright,$contr) {\n\t// TODO: Should be moved to the RGB class\n\t// First handle contrast, i.e change the dynamic range around grey\n\tif( $contr <= 0 ) {\n\t    // Decrease contrast\n\t    $adj = abs($rgb-128) * (-$contr);\n\t    if( $rgb < 128 ) $rgb += $adj;\n\t    else $rgb -= $adj;\n\t}\n\telse { // $contr > 0\n\t    // Increase contrast\n\t    if( $rgb < 128 ) $rgb = $rgb - ($rgb * $contr);\n\t    else $rgb = $rgb + ((255-$rgb) * $contr);\n\t}\n\t\n\t// Add (or remove) various amount of white\n\t$rgb += $bright*255;\t\n\t$rgb=min($rgb,255);\n\t$rgb=max($rgb,0);\n\treturn $rgb;\t\n    }\n\t\n    function SetLineWeight($weight) {\n\t$this->line_weight = $weight;\n    }\n\t\n    function SetStartPoint($x,$y) {\n\t$this->lastx=round($x);\n\t$this->lasty=round($y);\n    }\n\t\n    function Arc($cx,$cy,$w,$h,$s,$e) {\n\t// GD Arc doesn't like negative angles\n\twhile( $s < 0) $s += 360;\n\twhile( $e < 0) $e += 360;\n    \t\n\timagearc($this->img,round($cx),round($cy),round($w),round($h),\n\t\t $s,$e,$this->current_color);\n    }\n    \n    function FilledArc($xc,$yc,$w,$h,$s,$e,$style=\"\") {\n\n\tif( $GLOBALS['gd2'] ) {\n\t    while( $s < 0 ) $s += 360;\n\t    while( $e < 0 ) $e += 360;\n\t    if( $style==\"\" ) \n\t\t$style=IMG_ARC_PIE;\n\t    imagefilledarc($this->img,round($xc),round($yc),round($w),round($h),\n\t\t\t   round($s),round($e),$this->current_color,$style);\n\t    return;\n\t}\n\n\n\t// In GD 1.x we have to do it ourself interesting enough there is surprisingly\n\t// little difference in time between doing it PHP and using the optimised GD \n\t// library (roughly ~20%) I had expected it to be at least 100% slower doing it\n\t// manually with a polygon approximation in PHP.....\n\t$fillcolor = $this->current_color_name;\n\n\t$w /= 2; // We use radius in our calculations instead\n\t$h /= 2;\n\n\t// Setup the angles so we have the same conventions as the builtin\n\t// FilledArc() which is a little bit strange if you ask me....\n\n\t$s = 360-$s;\n\t$e = 360-$e;\n\n\tif( $e > $s ) {\n\t    $e = $e - 360;\n\t    $da = $s - $e; \n\t}\n\t$da = $s-$e;\n\n\t// We use radians\n\t$s *= M_PI/180;\n\t$e *= M_PI/180;\n\t$da *= M_PI/180;\n\n\t// Calculate a polygon approximation\n\t$p[0] = $xc;\n\t$p[1] = $yc;\n\n\t// Heuristic on how many polygons we need to make the\n\t// arc look good\n\t$numsteps = round(8 * abs($da) * ($w+$h)*($w+$h)/1500);\n\n\tif( $numsteps == 0 ) return;\n\tif( $numsteps < 7 ) $numsteps=7;\n\t$delta = abs($da)/$numsteps;\n\t\n\t$pa=array();\n\t$a = $s;\n\tfor($i=1; $i<=$numsteps; ++$i ) {\n\t    $p[2*$i] = round($xc + $w*cos($a));\n\t    $p[2*$i+1] = round($yc - $h*sin($a));\n\t    //$a = $s + $i*$delta; \n\t    $a -= $delta; \n\t    $pa[2*($i-1)] = $p[2*$i];\n\t    $pa[2*($i-1)+1] = $p[2*$i+1];\n\t}\n\n\t// Get the last point at the exact ending angle to avoid\n\t// any rounding errors.\n\t$p[2*$i] = round($xc + $w*cos($e));\n\t$p[2*$i+1] = round($yc - $h*sin($e));\n\t$pa[2*($i-1)] = $p[2*$i];\n\t$pa[2*($i-1)+1] = $p[2*$i+1];\n\t$i++;\n\n\t$p[2*$i] = $xc;\n    \t$p[2*$i+1] = $yc;\n\tif( $fillcolor != \"\" ) {\n\t    $this->PushColor($fillcolor);\n\t    imagefilledpolygon($this->img,$p,count($p)/2,$this->current_color);\n\t    $this->PopColor();\n\t}\n    }\n\n    function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) {\n\t$this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name);\n    }\n\n    function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor=\"\",$arccolor=\"\") {\n\t$s = round($s); $e = round($e);\n\t$w = round($w); $h = round($h);\n\t$xc = round($xc); $yc = round($yc);\n\t$this->PushColor($fillcolor);\n\t$this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e);\n\t$this->PopColor();\n\tif( $arccolor != \"\" ) {\n\t    $this->PushColor($arccolor);\n\t    // We add 2 pixels to make the Arc() better aligned with the filled arc. \n\t    if( $GLOBALS['gd2'] ) {\n\t\timagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ;\n\t    }\n\t    else {\n\t\t$this->Arc($xc,$yc,2*$w+2,2*$h+2,$s,$e);\n\t\t$xx = $w * cos(2*M_PI - $s*M_PI/180) + $xc;\n\t\t$yy = $yc - $h * sin(2*M_PI - $s*M_PI/180);\n\t\t$this->Line($xc,$yc,$xx,$yy);\n\t\t$xx = $w * cos(2*M_PI - $e*M_PI/180) + $xc;\n\t\t$yy = $yc - $h * sin(2*M_PI - $e*M_PI/180);\n\t\t$this->Line($xc,$yc,$xx,$yy);\n\t    }\n\t    $this->PopColor();\n\t}\n    }\n\n    function Ellipse($xc,$yc,$w,$h) {\n\t$this->Arc($xc,$yc,$w,$h,0,360);\n    }\n\t\n    // Breseham circle gives visually better result then using GD\n    // built in arc(). It takes some more time but gives better\n    // accuracy.\n    function BresenhamCircle($xc,$yc,$r) {\n\t$d = 3-2*$r;\n\t$x = 0;\n\t$y = $r;\n\twhile($x<=$y) {\n\t    $this->Point($xc+$x,$yc+$y);\t\t\t\n\t    $this->Point($xc+$x,$yc-$y);\n\t    $this->Point($xc-$x,$yc+$y);\n\t    $this->Point($xc-$x,$yc-$y);\n\t\t\t\n\t    $this->Point($xc+$y,$yc+$x);\n\t    $this->Point($xc+$y,$yc-$x);\n\t    $this->Point($xc-$y,$yc+$x);\n\t    $this->Point($xc-$y,$yc-$x);\n\t\t\t\n\t    if( $d<0 ) $d += 4*$x+6;\n\t    else {\n\t\t$d += 4*($x-$y)+10;\t\t\n\t\t--$y;\n\t    }\n\t    ++$x;\n\t}\n    }\n\t\t\t\n    function Circle($xc,$yc,$r) {\n\tif( USE_BRESENHAM )\n\t    $this->BresenhamCircle($xc,$yc,$r);\n\telse {\n\n\t    /*\n            // Some experimental code snippet to see if we can get a decent \n\t    // result doing a trig-circle\n\t    // Create an approximated circle with 0.05 rad resolution\n\t    $end = 2*M_PI;\n\t    $l = $r/10;\n\t    if( $l < 3 ) $l=3;\n\t    $step_size = 2*M_PI/(2*$r*M_PI/$l);\n\t    $pts = array();\n\t    $pts[] = $r + $xc;\n\t    $pts[] = $yc;\n\t    for( $a=$step_size; $a <= $end; $a += $step_size ) {\n\t\t$pts[] = round($xc + $r*cos($a));\n\t\t$pts[] = round($yc - $r*sin($a));\n\t    }\n\t    imagepolygon($this->img,$pts,count($pts)/2,$this->current_color);\n\t    */\n\n\t    $this->Arc($xc,$yc,$r*2,$r*2,0,360);\t\t\n\n\t    // For some reason imageellipse() isn't in GD 2.0.1, PHP 4.1.1\n\t    //imageellipse($this->img,$xc,$yc,$r,$r,$this->current_color);\n\t}\n    }\n\t\n    function FilledCircle($xc,$yc,$r) {\n\tif( $GLOBALS['gd2'] ) {\n\t    imagefilledellipse($this->img,round($xc),round($yc),\n\t    \t\t       2*$r,2*$r,$this->current_color);\n\t}\n\telse {\n\t    for( $i=1; $i < 2*$r; $i += 2 ) {\n\t\t// To avoid moire patterns we have to draw some\n\t\t// 1 extra \"skewed\" filled circles\n\t\t$this->Arc($xc,$yc,$i,$i,0,360);\n\t\t$this->Arc($xc,$yc,$i+1,$i,0,360);\n\t\t$this->Arc($xc,$yc,$i+1,$i+1,0,360);\n\t    }\n\t}\t\n    }\n\t\n    // Linear Color InterPolation\n    function lip($f,$t,$p) {\n\t$p = round($p,1);\n\t$r = $f[0] + ($t[0]-$f[0])*$p;\n\t$g = $f[1] + ($t[1]-$f[1])*$p;\n\t$b = $f[2] + ($t[2]-$f[2])*$p;\n\treturn array($r,$g,$b);\n    }\n\n    // Anti-aliased line. \n    // Note that this is roughly 8 times slower then a normal line!\n    function WuLine($x1,$y1,$x2,$y2) {\n\t// Get foreground line color\n\t$lc = imagecolorsforindex($this->img,$this->current_color);\n\t$lc = array($lc[\"red\"],$lc[\"green\"],$lc[\"blue\"]);\n\n\t$dx = $x2-$x1;\n\t$dy = $y2-$y1;\n\t\n\tif( abs($dx) > abs($dy) ) {\n\t    if( $dx<0 ) {\n\t\t$dx = -$dx;$dy = -$dy;\n\t\t$tmp=$x2;$x2=$x1;$x1=$tmp;\n\t\t$tmp=$y2;$y2=$y1;$y1=$tmp;\n\t    }\n\t    $x=$x1<<16; $y=$y1<<16;\n\t    $yinc = ($dy*65535)/$dx;\n\t    while( ($x >> 16) < $x2 ) {\n\t\t\t\t\n\t\t$bc = @imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16));\n\t\tif( $bc <= 0 ) {\n\t\t    JpGraphError::RaiseL(25100);//('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and that truecolor is enabled.');\n\t\t}\n\t\t$bc=array($bc[\"red\"],$bc[\"green\"],$bc[\"blue\"]);\n\t\t\t\t\n\t\t$this->SetColor($this->lip($lc,$bc,($y & 0xFFFF)/65535));\n\t\timagesetpixel($this->img,$x>>16,$y>>16,$this->current_color);\n\t\t$this->SetColor($this->lip($lc,$bc,(~$y & 0xFFFF)/65535));\n\t\timagesetpixel($this->img,$x>>16,($y>>16)+1,$this->current_color);\n\t\t$x += 65536; $y += $yinc;\n\t    }\n\t}\n\telse {\n\t    if( $dy<0 ) {\n\t\t$dx = -$dx;$dy = -$dy;\n\t\t$tmp=$x2;$x2=$x1;$x1=$tmp;\n\t\t$tmp=$y2;$y2=$y1;$y1=$tmp;\n\t    }\n\t    $x=$x1<<16; $y=$y1<<16;\n\t    $xinc = ($dx*65535)/$dy;\t\n\t    while( ($y >> 16) < $y2 ) {\n\t\t\t\t\n\t\t$bc = @imagecolorsforindex($this->img,imagecolorat($this->img,$x>>16,$y>>16));\n\t\tif( $bc <= 0 ) {\n\t\t    JpGraphError::RaiseL(25100);//('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.');\n\n\t\t}\n\n\t\t$bc=array($bc[\"red\"],$bc[\"green\"],$bc[\"blue\"]);\t\t\t\t\n\t\t\t\t\n\t\t$this->SetColor($this->lip($lc,$bc,($x & 0xFFFF)/65535));\n\t\timagesetpixel($this->img,$x>>16,$y>>16,$this->current_color);\n\t\t$this->SetColor($this->lip($lc,$bc,(~$x & 0xFFFF)/65535));\n\t\timagesetpixel($this->img,($x>>16)+1,$y>>16,$this->current_color);\n\t\t$y += 65536; $x += $xinc;\n\t    }\n\t}\n\t$this->SetColor($lc);\n\timagesetpixel($this->img,$x2,$y2,$this->current_color);\t\t\n\timagesetpixel($this->img,$x1,$y1,$this->current_color);\t\t\t\n    }\n\n    // Set line style dashed, dotted etc\n    function SetLineStyle($s) {\n\tif( is_numeric($s) ) {\n\t    if( $s<1 || $s>4 ) \n\t\tJpGraphError::RaiseL(25101,$s);//(\" Illegal numeric argument to SetLineStyle(): ($s)\");\n\t}\n\telseif( is_string($s) ) {\n\t    if( $s == \"solid\" ) $s=1;\n\t    elseif( $s == \"dotted\" ) $s=2;\n\t    elseif( $s == \"dashed\" ) $s=3;\n\t    elseif( $s == \"longdashed\" ) $s=4;\n\t    else JpGraphError::RaiseL(25102,$s);//(\" Illegal string argument to SetLineStyle(): $s\");\n\t}\n\telse JpGraphError::RaiseL(25103,$s);//(\" Illegal argument to SetLineStyle $s\");\n\t$this->line_style=$s;\n    }\n\t\n    // Same as Line but take the line_style into account\n    function StyleLine($x1,$y1,$x2,$y2) {\n\tswitch( $this->line_style ) {\n\t    case 1:// Solid\n\t\t$this->Line($x1,$y1,$x2,$y2);\n\t\tbreak;\n\t    case 2: // Dotted\n\t\t$this->DashedLine($x1,$y1,$x2,$y2,1,6);\n\t\tbreak;\n\t    case 3: // Dashed\n\t\t$this->DashedLine($x1,$y1,$x2,$y2,2,4);\n\t\tbreak;\n\t    case 4: // Longdashes\n\t\t$this->DashedLine($x1,$y1,$x2,$y2,8,6);\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(25104,$this->line_style);//(\" Unknown line style: $this->line_style \");\n\t\tbreak;\n\t}\n    }\n\n    function Line($x1,$y1,$x2,$y2) {\n\n\t$x1 = round($x1);\n\t$x2 = round($x2);\n\t$y1 = round($y1);\n\t$y2 = round($y2);\n\n\tif( $this->line_weight==0 ) return;\n\tif( $this->use_anti_aliasing ) {\n\t    $dx = $x2-$x1;\n\t    $dy = $y2-$y1;\n\t    // Vertical, Horizontal or 45 lines don't need anti-aliasing\n\t    if( $dx!=0 && $dy!=0 && $dx!=$dy ) {\n\t\t$this->WuLine($x1,$y1,$x2,$y2);\n\t\treturn;\n\t    }\n\t}\n\tif( $this->line_weight==1 ) {\n\t    imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color);\n\t}\n\telseif( $x1==$x2 ) {\t\t// Special case for vertical lines\n\t    imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color);\n\t    $w1=floor($this->line_weight/2);\n\t    $w2=floor(($this->line_weight-1)/2);\n\t    for($i=1; $i<=$w1; ++$i) \n\t\timageline($this->img,$x1+$i,$y1,$x2+$i,$y2,$this->current_color);\n\t    for($i=1; $i<=$w2; ++$i) \n\t\timageline($this->img,$x1-$i,$y1,$x2-$i,$y2,$this->current_color);\n\t}\n\telseif( $y1==$y2 ) {\t\t// Special case for horizontal lines\n\t    imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color);\n\t    $w1=floor($this->line_weight/2);\n\t    $w2=floor(($this->line_weight-1)/2);\n\t    for($i=1; $i<=$w1; ++$i) \n\t\timageline($this->img,$x1,$y1+$i,$x2,$y2+$i,$this->current_color);\n\t    for($i=1; $i<=$w2; ++$i) \n\t\timageline($this->img,$x1,$y1-$i,$x2,$y2-$i,$this->current_color);\t\t\n\t}\n\telse {\t// General case with a line at an angle\n\t    $a = atan2($y1-$y2,$x2-$x1);\n\t    // Now establish some offsets from the center. This gets a little\n\t    // bit involved since we are dealing with integer functions and we\n\t    // want the apperance to be as smooth as possible and never be thicker\n\t    // then the specified width.\n\t\t\t\n\t    // We do the trig stuff to make sure that the endpoints of the line\n\t    // are perpendicular to the line itself.\n\t    $dx=(sin($a)*$this->line_weight/2);\n\t    $dy=(cos($a)*$this->line_weight/2);\n\n\t    $pnts = array($x2+$dx,$y2+$dy,$x2-$dx,$y2-$dy,$x1-$dx,$y1-$dy,$x1+$dx,$y1+$dy);\n\t    imagefilledpolygon($this->img,$pnts,count($pnts)/2,$this->current_color);\n\t}\t\t\n\t$this->lastx=$x2; $this->lasty=$y2;\t\t\n    }\n\n    function Polygon($p,$closed=FALSE,$fast=FALSE) {\n\tif( $this->line_weight==0 ) return;\n\t$n=count($p);\n\t$oldx = $p[0];\n\t$oldy = $p[1];\n\tif( $fast ) {\n\t    for( $i=2; $i < $n; $i+=2 ) {\n\t\timageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color);\n\t\t$oldx = $p[$i];\n\t\t$oldy = $p[$i+1];\n\t    }\n\t    if( $closed ) {\n\t\timageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color);\n\t    }\n\t}\n\telse {\n\t    for( $i=2; $i < $n; $i+=2 ) {\n\t\t$this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]);\n\t\t$oldx = $p[$i];\n\t\t$oldy = $p[$i+1];\n\t    }\n\t}\n\tif( $closed )\n\t    $this->Line($oldx,$oldy,$p[0],$p[1]);\n    }\n\t\n    function FilledPolygon($pts) {\n\t$n=count($pts);\n\tif( $n == 0 ) {\n\t    JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.');\n\t}\n\tfor($i=0; $i < $n; ++$i) \n\t    $pts[$i] = round($pts[$i]);\n\timagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color);\n    }\n\t\n    function Rectangle($xl,$yu,$xr,$yl) {\n\t$this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu));\n    }\n\t\n    function FilledRectangle($xl,$yu,$xr,$yl) {\n\t$this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl));\n    }\n\n    function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) {\n\t// Fill a rectangle with lines of two colors\n\tif( $style===1 ) {\n\t    // Horizontal stripe\n\t    if( $yl < $yu ) {\n\t\t$t = $yl; $yl=$yu; $yu=$t;\n\t    }\n\t    for( $y=$yu; $y <= $yl; ++$y) {\n\t\t$this->SetColor($color1);\n\t\t$this->Line($xl,$y,$xr,$y);\n\t\t++$y;\n\t\t$this->SetColor($color2);\n\t\t$this->Line($xl,$y,$xr,$y);\n\t    }\n\t}\n\telse {\n\t    if( $xl < $xl ) {\n\t\t$t = $xl; $xl=$xr; $xr=$t;\n\t    }\n\t    for( $x=$xl; $x <= $xr; ++$x) {\n\t\t$this->SetColor($color1);\n\t\t$this->Line($x,$yu,$x,$yl);\n\t\t++$x;\n\t\t$this->SetColor($color2);\n\t\t$this->Line($x,$yu,$x,$yl);\n\t    }\n\t}\n    }\n\n    function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=3,$shadow_color=array(102,102,102)) {\n\t// This is complicated by the fact that we must also handle the case where\n        // the reactangle has no fill color\n\t$this->PushColor($shadow_color);\n\t$this->FilledRectangle($xr-$shadow_width,$yu+$shadow_width,$xr,$yl-$shadow_width-1);\n\t$this->FilledRectangle($xl+$shadow_width,$yl-$shadow_width,$xr,$yl);\n\t//$this->FilledRectangle($xl+$shadow_width,$yu+$shadow_width,$xr,$yl);\n\t$this->PopColor();\n\tif( $fcolor==false )\n\t    $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1);\n\telse {\t\t\n\t    $this->PushColor($fcolor);\n\t    $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1);\n\t    $this->PopColor();\n\t    $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1);\n\t}\n    }\n\n    function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) {\n\tif( $r==0 ) {\n\t    $this->FilledRectangle($xt,$yt,$xr,$yl);\n\t    return;\n\t}\n\n\t// To avoid overlapping fillings (which will look strange\n\t// when alphablending is enabled) we have no choice but \n\t// to fill the five distinct areas one by one.\n\t\n\t// Center square\n\t$this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r);\n\t// Top band\n\t$this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r-1);\n\t// Bottom band\n\t$this->FilledRectangle($xt+$r,$yl-$r+1,$xr-$r,$yl);\n\t// Left band\n\t$this->FilledRectangle($xt,$yt+$r+1,$xt+$r-1,$yl-$r);\n\t// Right band\n\t$this->FilledRectangle($xr-$r+1,$yt+$r,$xr,$yl-$r);\n\n\t// Topleft & Topright arc\n\t$this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270);\n\t$this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t// Bottomleft & Bottom right arc\n\t$this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180);\n\t$this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90);\n\n    }\n\n    function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) {    \n\n\tif( $r==0 ) {\n\t    $this->Rectangle($xt,$yt,$xr,$yl);\n\t    return;\n\t}\n\n\t// Top & Bottom line\n\t$this->Line($xt+$r,$yt,$xr-$r,$yt);\n\t$this->Line($xt+$r,$yl,$xr-$r,$yl);\n\n\t// Left & Right line\n\t$this->Line($xt,$yt+$r,$xt,$yl-$r);\n\t$this->Line($xr,$yt+$r,$xr,$yl-$r);\n\n\t// Topleft & Topright arc\n\t$this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270);\n\t$this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t// Bottomleft & Bottomright arc\n\t$this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180);\n\t$this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90);\n    }\n\n    function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') {\n\t$this->FilledRectangle($x1,$y1,$x2,$y2);\n\t$this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2);\n    }\n\n    function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') {\n\t$this->PushColor($color1);\n\tfor( $i=0; $i < $depth; ++$i ) {\n\t    $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i);\n\t    $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i);\n\t}\n\t$this->PopColor();\n\t\n\t$this->PushColor($color2);\n\tfor( $i=0; $i < $depth; ++$i ) {\n\t    $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i);\n\t    $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1);\n\t}\n\t$this->PopColor();\n    }\n\n    function StyleLineTo($x,$y) {\n\t$this->StyleLine($this->lastx,$this->lasty,$x,$y);\n\t$this->lastx=$x;\n\t$this->lasty=$y;\n    }\n\t\n    function LineTo($x,$y) {\n\t$this->Line($this->lastx,$this->lasty,$x,$y);\n\t$this->lastx=$x;\n\t$this->lasty=$y;\n    }\n\t\n    function Point($x,$y) {\n\timagesetpixel($this->img,round($x),round($y),$this->current_color);\n    }\n\t\n    function Fill($x,$y) {\n\timagefill($this->img,round($x),round($y),$this->current_color);\n    }\n\n    function FillToBorder($x,$y,$aBordColor) {\n\t$bc = $this->rgb->allocate($aBordColor);\n\tif( $bc == -1 ) {\n\t    JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors');\n\t    exit();\n\t}\n\timagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color);\n    }\n\t\n    function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) {\n\n\t$x1 = round($x1);\n\t$x2 = round($x2);\n\t$y1 = round($y1);\n\t$y2 = round($y2);\n\n\t// Code based on, but not identical to, work by Ariel Garza and James Pine\n\t$line_length = ceil (sqrt(pow(($x2 - $x1),2) + pow(($y2 - $y1),2)) );\n\t$dx = ($line_length) ? ($x2 - $x1) / $line_length : 0;\n\t$dy = ($line_length) ? ($y2 - $y1) / $line_length : 0;\n\t$lastx = $x1; $lasty = $y1;\n\t$xmax = max($x1,$x2);\n\t$xmin = min($x1,$x2);\n\t$ymax = max($y1,$y2);\n\t$ymin = min($y1,$y2);\n\tfor ($i = 0; $i < $line_length; $i += ($dash_length + $dash_space)) {\n\t    $x = ($dash_length * $dx) + $lastx;\n\t    $y = ($dash_length * $dy) + $lasty;\n\t\t\t\n\t    // The last section might overshoot so we must take a computational hit\n\t    // and check this.\n\t    if( $x>$xmax ) $x=$xmax;\n\t    if( $y>$ymax ) $y=$ymax;\n\t\t\t\n\t    if( $x<$xmin ) $x=$xmin;\n\t    if( $y<$ymin ) $y=$ymin;\n\n\t    $this->Line($lastx,$lasty,$x,$y);\n\t    $lastx = $x + ($dash_space * $dx);\n\t    $lasty = $y + ($dash_space * $dy);\n\t} \n    } \n\n    function SetExpired($aFlg=true) {\n\t$this->expired = $aFlg;\n    }\n\t\n    // Generate image header\n    function Headers() {\n\t\n\t// In case we are running from the command line with the client version of\n\t// PHP we can't send any headers.\n\t$sapi = php_sapi_name();\n\tif( $sapi == 'cli' )\n\t    return;\n\t\n\tif( headers_sent($file,$lineno) ) {\n\t    $file=basename($file);\n\t    $t = new ErrMsgText();\n\t    $msg = $t->Get(10,$file,$lineno);\n\t    die($msg);\n\t}\t\n\t\n\tif ($this->expired) {\n\t    header(\"Expires: Mon, 26 Jul 1997 05:00:00 GMT\");\n\t    header(\"Last-Modified: \" . gmdate(\"D, d M Y H:i:s\") . \"GMT\");\n\t    header(\"Cache-Control: no-cache, must-revalidate\");\n\t    header(\"Pragma: no-cache\");\n\t}\n\theader(\"Content-type: image/$this->img_format\");\n    }\n\n    // Adjust image quality for formats that allow this\n    function SetQuality($q) {\n\t$this->quality = $q;\n    }\n\t\n    // Stream image to browser or to file\n    function Stream($aFile=\"\") {\n\t$func=\"image\".$this->img_format;\n\tif( $this->img_format==\"jpeg\" && $this->quality != null ) {\n\t    $res = @$func($this->img,$aFile,$this->quality);\n\t}\n\telse {\n\t    if( $aFile != \"\" ) {\n\t\t$res = @$func($this->img,$aFile);\n\t\tif( !$res )\n\t\t    JpGraphError::RaiseL(25107,$aFile);//(\"Can't write to file '$aFile'. Check that the process running PHP has enough permission.\");\n\t    }\n\t    else {\n\t\t$res = @$func($this->img);\n\t\tif( !$res )\n\t\t    JpGraphError::RaiseL(25108);//(\"Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.\");\n\t\t\n\t    }\n\t}\n    }\n\t\t\n    // Clear resource tide up by image\n    function Destroy() {\n\timagedestroy($this->img);\n    }\n\t\n    // Specify image format. Note depending on your installation\n    // of PHP not all formats may be supported.\n    function SetImgFormat($aFormat,$aQuality=75) {\t\t\n\t$this->quality = $aQuality;\n\t$aFormat = strtolower($aFormat);\n\t$tst = true;\n\t$supported = imagetypes();\n\tif( $aFormat==\"auto\" ) {\n\t    if( $supported & IMG_PNG )\n\t\t$this->img_format=\"png\";\n\t    elseif( $supported & IMG_JPG )\n\t\t$this->img_format=\"jpeg\";\n\t    elseif( $supported & IMG_GIF )\n\t\t$this->img_format=\"gif\";\n\t    else\n\t\tJpGraphError::RaiseL(25109);//(\"Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.\");\n\t\t\t\t\n\t    return true;\n\t}\n\telse {\n\t    if( $aFormat==\"jpeg\" || $aFormat==\"png\" || $aFormat==\"gif\" ) {\n\t\tif( $aFormat==\"jpeg\" && !($supported & IMG_JPG) )\n\t\t    $tst=false;\n\t\telseif( $aFormat==\"png\" && !($supported & IMG_PNG) ) \n\t\t    $tst=false;\n\t\telseif( $aFormat==\"gif\" && !($supported & IMG_GIF) ) \t\n\t\t    $tst=false;\n\t\telse {\n\t\t    $this->img_format=$aFormat;\n\t\t    return true;\n\t\t}\n\t    }\n\t    else \n\t\t$tst=false;\n\t    if( !$tst )\n\t\tJpGraphError::RaiseL(25110,$aFormat);//(\" Your PHP installation does not support the chosen graphic format: $aFormat\");\n\t}\n    }\t\n} // CLASS\n\n//===================================================\n// CLASS RotImage\n// Description: Exactly as Image but draws the image at\n// a specified angle around a specified rotation point.\n//===================================================\nclass RotImage extends Image {\n    var $m=array();\n    var $a=0;\n    var $dx=0,$dy=0,$transx=0,$transy=0; \n\t\n    function RotImage($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT) {\n\t$this->Image($aWidth,$aHeight,$aFormat);\n\t$this->dx=$this->left_margin+$this->plotwidth/2;\n\t$this->dy=$this->top_margin+$this->plotheight/2;\n\t$this->SetAngle($a);\t\n    }\n\t\n    function SetCenter($dx,$dy) {\n\t$old_dx = $this->dx;\n\t$old_dy = $this->dy;\n\t$this->dx=$dx;\n\t$this->dy=$dy;\n\t$this->SetAngle($this->a);\n\treturn array($old_dx,$old_dy);\n    }\n\t\n    function SetTranslation($dx,$dy) {\n\t$old = array($this->transx,$this->transy);\n\t$this->transx = $dx;\n\t$this->transy = $dy;\n\treturn $old;\n    }\n\n    function UpdateRotMatrice()  {\n\t$a = $this->a;\n\t$a *= M_PI/180;\n\t$sa=sin($a); $ca=cos($a);\t\t\n\t// Create the rotation matrix\n\t$this->m[0][0] = $ca;\n\t$this->m[0][1] = -$sa;\n\t$this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ;\n\t$this->m[1][0] = $sa;\n\t$this->m[1][1] = $ca;\n\t$this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ;\n    }\n\n    function SetAngle($a) {\n\t$tmp = $this->a;\n\t$this->a = $a;\n\t$this->UpdateRotMatrice();\n\treturn $tmp;\n    }\n\n    function Circle($xc,$yc,$r) {\n\t// Circle get's rotated through the Arc() call\n\t// made in the parent class\n\tparent::Circle($xc,$yc,$r);\n    }\n\n    function FilledCircle($xc,$yc,$r) {\n\t// If we use GD1 then Image::FilledCircle will use a \n\t// call to Arc so it will get rotated through the Arc\n\t// call.\n\tif( $GLOBALS['gd2'] ) {\n\t    list($xc,$yc) = $this->Rotate($xc,$yc);\n\t}\n\tparent::FilledCircle($xc,$yc,$r);\n    }\n\t\n    function Arc($xc,$yc,$w,$h,$s,$e) {\n\tlist($xc,$yc) = $this->Rotate($xc,$yc);\n\t$s += $this->a;\n\t$e += $this->a;\n\tparent::Arc($xc,$yc,$w,$h,$s,$e);\n    }\n\n    function FilledArc($xc,$yc,$w,$h,$s,$e) {\n\tlist($xc,$yc) = $this->Rotate($xc,$yc);\n\t$s += $this->a;\n\t$e += $this->a;\n\tparent::FilledArc($xc,$yc,$w,$h,$s,$e);\n    }\n\n    function SetMargin($lm,$rm,$tm,$bm) {\n\tparent::SetMargin($lm,$rm,$tm,$bm);\n\t$this->dx=$this->left_margin+$this->plotwidth/2;\n\t$this->dy=$this->top_margin+$this->plotheight/2;\n\t$this->UpdateRotMatrice();\n    }\n\t\n    function Rotate($x,$y) {\n\t// Optimization. Ignore rotation if Angle==0 || ANgle==360\n\tif( $this->a == 0 || $this->a == 360 ) {\n\t    return array($x + $this->transx, $y + $this->transy );\n\t}\n\telse {\n\t    $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx;\n\t    $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy;\n\t    return array($x1,$y1);\n\t}\n    }\n\n    function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) {\n\tlist($toX,$toY) = $this->Rotate($toX,$toY);\n\tparent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix);\n\n    }\n\t\n    function ArrRotate($pnts) {\n\t$n = count($pnts)-1;\n\tfor($i=0; $i < $n; $i+=2) {\n\t    list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]);\n\t    $pnts[$i] = $x; $pnts[$i+1] = $y;\n\t}\n\treturn $pnts;\n    }\n\t\n    function Line($x1,$y1,$x2,$y2) {\n\tlist($x1,$y1) = $this->Rotate($x1,$y1);\n\tlist($x2,$y2) = $this->Rotate($x2,$y2);\n\tparent::Line($x1,$y1,$x2,$y2);\n    }\n\n    function Rectangle($x1,$y1,$x2,$y2) {\n\t// Rectangle uses Line() so it will be rotated through that call\n\tparent::Rectangle($x1,$y1,$x2,$y2);\n    }\n\t\n    function FilledRectangle($x1,$y1,$x2,$y2) {\n\tif( $y1==$y2 || $x1==$x2 )\n\t    $this->Line($x1,$y1,$x2,$y2);\n\telse \n\t    $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2));\n    }\n\t\n    function Polygon($pnts,$closed=FALSE,$fast=false) {\n\t//Polygon uses Line() so it will be rotated through that call\n\tparent::Polygon($pnts,$closed,$fast);\n    }\n\t\n    function FilledPolygon($pnts) {\n\tparent::FilledPolygon($this->ArrRotate($pnts));\n    }\n\t\n    function Point($x,$y) {\n\tlist($xp,$yp) = $this->Rotate($x,$y);\n\tparent::Point($xp,$yp);\n    }\n\t\n    function StrokeText($x,$y,$txt,$dir=0,$paragraph_align=\"left\",$debug=false) {\n\tlist($xp,$yp) = $this->Rotate($x,$y);\n\treturn parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug);\n    }\n}\n\n//===================================================\n// CLASS ImgStreamCache\n// Description: Handle caching of graphs to files\n//===================================================\nclass ImgStreamCache {\n    var $cache_dir;\n    var $img=null;\n    var $timeout=0; \t// Infinite timeout\n    //---------------\n    // CONSTRUCTOR\n    function ImgStreamCache(&$aImg, $aCacheDir=CACHE_DIR) {\n\t$this->img = &$aImg;\n\t$this->cache_dir = $aCacheDir;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    // Specify a timeout (in minutes) for the file. If the file is older then the\n    // timeout value it will be overwritten with a newer version.\n    // If timeout is set to 0 this is the same as infinite large timeout and if\n    // timeout is set to -1 this is the same as infinite small timeout\n    function SetTimeout($aTimeout) {\n\t$this->timeout=$aTimeout;\t\n    }\n\t\n    // Output image to browser and also write it to the cache\n    function PutAndStream(&$aImage,$aCacheFileName,$aInline,$aStrokeFileName) {\n\t// Some debugging code to brand the image with numbe of colors\n\t// used\n\tGLOBAL $gJpgBrandTiming;\n\t\n\tif( $gJpgBrandTiming ) {\n\t    global $tim;\n\t    $t=$tim->Pop()/1000.0;\n\t    $c=$aImage->SetColor(\"black\");\n\t    $t=sprintf(BRAND_TIME_FORMAT,round($t,3));\n\t    imagestring($this->img->img,2,5,$this->img->height-20,$t,$c);\t\t\t\n\t}\n\n\t// Check if we should stroke the image to an arbitrary file\n\tif( _FORCE_IMGTOFILE ) {\n\t    $aStrokeFileName = _FORCE_IMGDIR.GenImgName();\n\t}\n\n\tif( $aStrokeFileName!=\"\" ) {\n\t    if( $aStrokeFileName == \"auto\" )\n\t\t$aStrokeFileName = GenImgName();\n\t    if( file_exists($aStrokeFileName) ) {\n\t\t// Delete the old file\n\t\tif( !@unlink($aStrokeFileName) )\n\t\t    JpGraphError::RaiseL(25111,$aStrokeFileName);//(\" Can't delete cached image $aStrokeFileName. Permission problem?\");\n\t    }\n\t    $aImage->Stream($aStrokeFileName);\n\t    return;\n\t}\n\n\tif( $aCacheFileName != \"\" && USE_CACHE) {\n\n\t    $aCacheFileName = $this->cache_dir . $aCacheFileName;\n\t    if( file_exists($aCacheFileName) ) {\n\t\tif( !$aInline ) {\n\t\t    // If we are generating image off-line (just writing to the cache)\n\t\t    // and the file exists and is still valid (no timeout)\n\t\t    // then do nothing, just return.\n\t\t    $diff=time()-filemtime($aCacheFileName);\n\t\t    if( $diff < 0 )\n\t\t\tJpGraphError::RaiseL(25112,$aCacheFileName);//(\" Cached imagefile ($aCacheFileName) has file date in the future!!\");\n\t\t    if( $this->timeout>0 && ($diff <= $this->timeout*60) ) \n\t\t\treturn;\t\t\n\t\t}\t\t\t\n\t\tif( !@unlink($aCacheFileName) )\n\t\t    JpGraphError::RaiseL(25113,$aStrokeFileName);//(\" Can't delete cached image $aStrokeFileName. Permission problem?\");\n\t\t$aImage->Stream($aCacheFileName);\t\n\t    }\n\t    else {\n\t\t$this->MakeDirs(dirname($aCacheFileName));\n\t\tif( !is_writeable(dirname($aCacheFileName)) ) {\n\t\t    JpGraphError::RaiseL(25114,$aCacheFileName);//('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.');\n\t\t}\n\t\t$aImage->Stream($aCacheFileName);\n\t    }\n\t\t\t\n\t    $res=true;\n\t    // Set group to specified\n\t    if( CACHE_FILE_GROUP != \"\" )\n\t\t$res = @chgrp($aCacheFileName,CACHE_FILE_GROUP);\n\t    if( CACHE_FILE_MOD != \"\" )\n\t\t$res = @chmod($aCacheFileName,CACHE_FILE_MOD);\n\t    if( !$res )\n\t\tJpGraphError::RaiseL(25115,$aStrokeFileName);//(\" Can't set permission for cached image $aStrokeFileName. Permission problem?\");\n\t\t\t\n\t    $aImage->Destroy();\n\t    if( $aInline ) {\n\t\tif ($fh = @fopen($aCacheFileName, \"rb\") ) {\n\t\t    $this->img->Headers();\n\t\t    fpassthru($fh);\n\t\t    return;\n\t\t}\n\t\telse\n\t\t    JpGraphError::RaiseL(25116,$aFile);//(\" Cant open file from cache [$aFile]\"); \n\t    }\n\t}\n\telseif( $aInline ) {\n\t    $this->img->Headers();\t \t\t\n\t    $aImage->Stream();\t\n\t    return;\n\t}\n    }\n\t\n    // Check if a given image is in cache and in that case\n    // pass it directly on to web browser. Return false if the\n    // image file doesn't exist or exists but is to old\n    function GetAndStream($aCacheFileName) {\n\t$aCacheFileName = $this->cache_dir.$aCacheFileName;\t\t \n\tif ( USE_CACHE && file_exists($aCacheFileName) && $this->timeout>=0 ) {\n\t    $diff=time()-filemtime($aCacheFileName);\n\t    if( $this->timeout>0 && ($diff > $this->timeout*60) ) {\n\t\treturn false;\t\t\n\t    }\n\t    else {\n\t\tif ($fh = @fopen($aCacheFileName, \"rb\")) {\n\t\t    $this->img->Headers();\n\t\t    fpassthru($fh);\n\t\t    return true;\n\t\t}\n\t\telse\n\t\t    JpGraphError::RaiseL(25117,$aCacheFileName);//(\" Can't open cached image \\\"$aCacheFileName\\\" for reading.\");\n\t    }\n\t} \n\treturn false;\n    }\n\t\n    //---------------\n    // PRIVATE METHODS\t\n    // Create all necessary directories in a path\n    function MakeDirs($aFile) {\n\t$dirs = array();\n\twhile ( !(file_exists($aFile)) ) {\n\t    $dirs[] = $aFile;\n\t    $aFile = dirname($aFile);\n\t}\n\tfor ($i = sizeof($dirs)-1; $i>=0; $i--) {\n\t    if(! @mkdir($dirs[$i],0777) )\n\t\tJpGraphError::RaiseL(25118,$aFile);//(\" Can't create directory $aFile. Make sure PHP has write permission to this directory.\");\n\t    // We also specify mode here after we have changed group. \n\t    // This is necessary if Apache user doesn't belong the\n\t    // default group and hence can't specify group permission\n\t    // in the previous mkdir() call\n\t    if( CACHE_FILE_GROUP != \"\" ) {\n\t\t$res=true;\n\t\t$res =@chgrp($dirs[$i],CACHE_FILE_GROUP);\n\t\t$res &= @chmod($dirs[$i],0777);\n\t\tif( !$res )\n\t\t    JpGraphError::RaiseL(25119,$aFile);//(\" Can't set permissions for $aFile. Permission problems?\");\n\t    }\n\t}\n\treturn true;\n    }\t\n} // CLASS Cache\n\t\n//===================================================\n// CLASS Legend\n// Description: Responsible for drawing the box containing\n// all the legend text for the graph\n//===================================================\nDEFINE('_DEFAULT_LPM_SIZE',8);\nclass Legend {\n    var $color=array(0,0,0); // Default fram color\n    var $fill_color=array(235,235,235); // Default fill color\n    var $shadow=true; // Shadow around legend \"box\"\n    var $shadow_color='gray';\n    var $txtcol=array();\n    var $mark_abs_hsize=_DEFAULT_LPM_SIZE, $mark_abs_vsize=_DEFAULT_LPM_SIZE;\n    var $xmargin=5,$ymargin=3,$shadow_width=2;\n    var $xlmargin=2, $ylmargin='';\n    var $xpos=0.05, $ypos=0.15, $xabspos=-1, $yabspos=-1;\n\tvar $halign=\"right\", $valign=\"top\";\n    var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12;\n    var $font_color='black';\n    var $hide=false,$layout_n=1;\n    var $weight=1,$frameweight=1;\n    var $csimareas='';\n    var $reverse = false ;\n//---------------\n// CONSTRUCTOR\n    function Legend() {\n\t// Empty\n    }\n//---------------\n// PUBLIC METHODS\t\n    function Hide($aHide=true) {\n\t$this->hide=$aHide;\n    }\n\t\n    function SetHColMargin($aXMarg) {\n\t$this->xmargin = $aXMarg;\n    }\n\n    function SetVColMargin($aSpacing) {\n\t$this->ymargin = $aSpacing ;\n    }\n\n    function SetLeftMargin($aXMarg) {\n\t$this->xlmargin = $aXMarg;\n    }\n\n    // Synonym\n    function SetLineSpacing($aSpacing) {\n\t$this->ymargin = $aSpacing ;\n    }\n\n    function SetShadow($aShow='gray',$aWidth=2) {\n\tif( is_string($aShow) ) {\n\t    $this->shadow_color = $aShow;\n\t    $this->shadow=true;\n\t}\n\telse\n\t    $this->shadow=$aShow;\n\t$this->shadow_width=$aWidth;\n    }\n\n    function SetMarkAbsSize($aSize) {\n\t$this->mark_abs_vsize = $aSize ;\n\t$this->mark_abs_hsize = $aSize ;\n    }\n\n    function SetMarkAbsVSize($aSize) {\n\t$this->mark_abs_vsize = $aSize ;\n    }\n\n    function SetMarkAbsHSize($aSize) {\n\t$this->mark_abs_hsize = $aSize ;\n    }\n\n    function SetLineWeight($aWeight) {\n\t$this->weight = $aWeight;\n    }\n\n    function SetFrameWeight($aWeight) {\n\t$this->frameweight = $aWeight;\n    }\n\t\n    function SetLayout($aDirection=LEGEND_VERT) {\n\t$this->layout_n = $aDirection==LEGEND_VERT ? 1 : 99 ;\n    }\n\t\n    function SetColumns($aCols) {\n\t$this->layout_n = $aCols ;\n    }\n\n    function SetReverse($f=true) {\n\t$this->reverse = $f ;\n    }\n\n    // Set color on frame around box\n    function SetColor($aFontColor,$aColor='black') {\n\t$this->font_color=$aFontColor;\n\t$this->color=$aColor;\n    }\n\t\n    function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {\n\t$this->font_family = $aFamily;\n\t$this->font_style = $aStyle;\n\t$this->font_size = $aSize;\n    }\n\t\n    function SetPos($aX,$aY,$aHAlign=\"right\",$aVAlign=\"top\") {\n\t$this->Pos($aX,$aY,$aHAlign,$aVAlign);\n    }\n\n    function SetAbsPos($aX,$aY,$aHAlign=\"right\",$aVAlign=\"top\") {\n\t$this->xabspos=$aX;\n\t$this->yabspos=$aY;\n\t$this->halign=$aHAlign;\n\t$this->valign=$aVAlign;\n    }\n\n\n    function Pos($aX,$aY,$aHAlign=\"right\",$aVAlign=\"top\") {\n\tif( !($aX<1 && $aY<1) )\n\t    JpGraphError::RaiseL(25120);//(\" Position for legend must be given as percentage in range 0-1\");\n\t$this->xpos=$aX;\n\t$this->ypos=$aY;\n\t$this->halign=$aHAlign;\n\t$this->valign=$aVAlign;\n    }\n\n    function SetFillColor($aColor) {\n\t$this->fill_color=$aColor;\n    }\n\t\n    function Add($aTxt,$aColor,$aPlotmark=\"\",$aLinestyle=0,$csimtarget=\"\",$csimalt=\"\") {\n\t$this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle,$csimtarget,$csimalt);\n    }\n\n    function GetCSIMAreas() {\n\treturn $this->csimareas;\n    }\n\t\n    function Stroke(&$aImg) {\n\t// Constant\n\t$fillBoxFrameWeight=1;\n\n\tif( $this->hide ) return;\n\n\t$aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\t\t\n\n\tif( $this->reverse ) {\n\t    $this->txtcol = array_reverse($this->txtcol);\n\t}\n\n\t$n=count($this->txtcol);\n\tif( $n == 0 ) return;\n\n\t// Find out the max width and height of each column to be able\n        // to size the legend box.\n\t$numcolumns = ($n > $this->layout_n ? $this->layout_n : $n);\n\tfor( $i=0; $i < $numcolumns; ++$i ) {\n\t    $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) +\n\t\t            2*$this->xmargin + 2*$this->mark_abs_hsize;\n\t    $colheight[$i] = 0;\n\t}\n\n\t// Find our maximum height in each row\n\t$rows = 0 ; $rowheight[0] = 0;\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $h = max($this->mark_abs_vsize,$aImg->GetTextHeight($this->txtcol[$i][0]))+$this->ymargin;\n\t    if( $i % $numcolumns == 0 ) {\n\t\t$rows++;\n\t\t$rowheight[$rows-1] = 0;\n\t    }\n\t    $rowheight[$rows-1] = max($rowheight[$rows-1],$h);\n\t}\n\n\t$abs_height = 0;\n\tfor( $i=0; $i < $rows; ++$i ) {\n\t    $abs_height += $rowheight[$i] ;\n\t}\n\n\t// Make sure that the height is at least as high as mark size + ymargin\n\t$abs_height = max($abs_height,$this->mark_abs_vsize);\n\n\t// We add 3 extra pixels height to compensate for the difficult in\n\t// calculating font height\n\t$abs_height += $this->ymargin+3; \n\t\t\t\t\t\t\n\t// Find out the maximum width in each column\n\tfor( $i=$numcolumns; $i < $n; ++$i ) {\n\t    $colwidth[$i % $numcolumns] = max(\n\t\t$aImg->GetTextWidth($this->txtcol[$i][0])+2*$this->xmargin+2*$this->mark_abs_hsize,$colwidth[$i % $numcolumns]);\n\t}\n\n\t// Get the total width\n\t$mtw = 0;\n\tfor( $i=0; $i < $numcolumns; ++$i ) {\n\t    $mtw += $colwidth[$i] ;\n\t}\n\n\t// Find out maximum width we need for legend box\n\t$abs_width = $mtw+$this->xlmargin;\n\n\tif( $this->xabspos === -1  && $this->yabspos === -1 ) {\n\t    $this->xabspos = $this->xpos*$aImg->width ;\n\t    $this->yabspos = $this->ypos*$aImg->height ;\n\t}\n\n\t// Positioning of the legend box\n\tif( $this->halign==\"left\" )\n\t    $xp = $this->xabspos; \n\telseif( $this->halign==\"center\" )\n\t    $xp = $this->xabspos - $abs_width/2; \n\telse  \n\t    $xp = $aImg->width - $this->xabspos - $abs_width;\n\n\t$yp=$this->yabspos;\n\tif( $this->valign==\"center\" )\n\t    $yp-=$abs_height/2;\n\telseif( $this->valign==\"bottom\" )\n\t    $yp-=$abs_height;\n\t\t\t\n\t// Stroke legend box\n\t$aImg->SetColor($this->color);\t\n\t$aImg->SetLineWeight($this->frameweight);\n\t$aImg->SetLineStyle('solid');\n\n\tif( $this->shadow )\n\t    $aImg->ShadowRectangle($xp,$yp,$xp+$abs_width+$this->shadow_width,\n\t\t\t\t   $yp+$abs_height+$this->shadow_width,\n\t\t\t\t   $this->fill_color,$this->shadow_width,$this->shadow_color);\n\telse {\n\t    $aImg->SetColor($this->fill_color);\t\t\t\t\n\t    $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height);\n\t    $aImg->SetColor($this->color);\t\t\t\t\t\t\t\n\t    $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height);\n\t}\n\n\t// x1,y1 is the position for the legend mark\n\t$x1=$xp+$this->mark_abs_hsize+$this->xlmargin;\n\t$y1=$yp + $this->ymargin;\t\t\n\t\n\t$f2 =  round($aImg->GetTextHeight('X')/2);\n\n\t$grad = new Gradient($aImg);\n\t$patternFactory = null;\n\n\t// Now stroke each legend in turn\n\t// Each plot has added the following information to  the legend\n\t// p[0] = Legend text\n\t// p[1] = Color, \n\t// p[2] = For markers a reference to the PlotMark object\n\t// p[3] = For lines the line style, for gradient the negative gradient style\n\t// p[4] = CSIM target\n\t// p[5] = CSIM Alt text\n\t$i = 1 ; $row = 0;\n\tforeach($this->txtcol as $p) {\n\t \n\t    // STROKE DEBUG BOX\n\t    if( _JPG_DEBUG ) {\n\t        $aImg->SetLineWeight(1);\n\t        $aImg->SetColor('red');\n\t        $aImg->SetLineStyle('solid');\n\t        $aImg->Rectangle($xp,$y1,$xp+$abs_width,$y1+$rowheight[$row]);\n\t    }\n\n\t    $aImg->SetLineWeight($this->weight);\n\t    $x1 = round($x1); $y1=round($y1);\n\t    if ( $p[2] != \"\" && $p[2]->GetType() > -1 ) {\n\t\t// Make a plot mark legend\n\t\t$aImg->SetColor($p[1]);\n\t\tif( is_string($p[3]) || $p[3]>0 ) {\n\t\t    $aImg->SetLineStyle($p[3]);\n\t\t    $aImg->StyleLine($x1-$this->mark_abs_hsize,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2);\n\t\t}\n\t\t// Stroke a mark with the standard size\n\t\t// (As long as it is not an image mark )\n\t\tif( $p[2]->GetType() != MARK_IMG ) {\n\t\t    $p[2]->iFormatCallback = '';\n\n\t\t    // Since size for circles is specified as the radius\n\t\t    // this means that we must half the size to make the total\n\t\t    // width behave as the other marks\n\t\t    if( $p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE ) {\n\t\t        $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)/2);\n\t\t\t$p[2]->Stroke($aImg,$x1,$y1+$f2);\n\t\t    }\n\t\t    else {\n\t\t        $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize));\n\t\t\t$p[2]->Stroke($aImg,$x1,$y1+$f2);\n\t\t    }\n\t\t}\n\t    } \n\t    elseif ( $p[2] != \"\" && (is_string($p[3]) || $p[3]>0 ) ) {\n\t\t// Draw a styled line\n\t\t$aImg->SetColor($p[1]);\n\t\t$aImg->SetLineStyle($p[3]);\n\t\t$aImg->StyleLine($x1-1,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2);\n\t\t$aImg->StyleLine($x1-1,$y1+$f2+1,$x1+$this->mark_abs_hsize,$y1+$f2+1);\n\t    } \n\t    else {\n\t\t// Draw a colored box\n\t\t$color = $p[1] ;\n\t\t// We make boxes slightly larger to better show\n\t\t$boxsize = min($this->mark_abs_vsize,$this->mark_abs_hsize) + 2 ;\n\t\t$ym =  round($y1 + $f2 - $boxsize/2);\n\t\t// We either need to plot a gradient or a \n\t\t// pattern. To differentiate we use a kludge.\n\t\t// Patterns have a p[3] value of < -100\n\t\tif( $p[3] < -100 ) { \n\t\t    // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity\n\t\t    if( $patternFactory == null ) {\n\t\t\t$patternFactory = new RectPatternFactory();\n\t\t    }\n\t\t    $prect = $patternFactory->Create($p[1][0],$p[1][1],1);\n\t\t    $prect->SetBackground($p[1][3]);\n\t\t    $prect->SetDensity($p[1][2]+1);\n\t\t    $prect->SetPos(new Rectangle($x1,$ym,$boxsize,$boxsize));\n\t\t    $prect->Stroke($aImg);\n\t\t    $prect=null;\n\t\t}\n\t\telse {\n\t\t    if( is_array($color) && count($color)==2 ) {\n\t\t\t// The client want a gradient color\n\t\t\t$grad->FilledRectangle($x1,$ym,\n\t\t\t\t\t       $x1+$boxsize,$ym+$boxsize,\n\t\t\t\t\t       $color[0],$color[1],-$p[3]);\n\t\t    }\n\t\t    else {\n\t\t\t$aImg->SetColor($p[1]);\n\t\t\t$aImg->FilledRectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize);\n\t\t    }\n\t\t    $aImg->SetColor($this->color);\n\t\t    $aImg->SetLineWeight($fillBoxFrameWeight);\n\t\t    $aImg->Rectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize);\n\t\t}\n\t    }\n\t    $aImg->SetColor($this->font_color);\n\t    $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);\t\t\n\t    $aImg->SetTextAlign(\"left\",\"top\");\t\t\t\n\t    $aImg->StrokeText(round($x1+$this->mark_abs_hsize+$this->xmargin),$y1,$p[0]);\n\n\t    // Add CSIM for Legend if defined\n\t    if( $p[4] != \"\" ) {\n\t\t$xe = $x1 + $this->xmargin+$this->mark_abs_hsize+$aImg->GetTextWidth($p[0]);\n\t\t$ye = $y1 + max($this->mark_abs_vsize,$aImg->GetTextHeight($p[0]));\n\t\t$coords = \"$x1,$y1,$xe,$y1,$xe,$ye,$x1,$ye\";\n\t\tif( ! empty($p[4]) ) {\n\t\t    $this->csimareas .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$p[4].\"\\\"\";\n\t\t    if( !empty($p[5]) ) {\n\t\t\t$tmp=sprintf($p[5],$p[0]);\n\t\t\t$this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t\t    }\n\t\t    $this->csimareas .= \" alt=\\\"\\\" />\\n\";\n\t\t}\n\t    }\n\t    if( $i >= $this->layout_n ) {\n\t\t$x1 = $xp+$this->mark_abs_hsize+$this->xlmargin;\n\t\t$y1 += $rowheight[$row++];\n\t\t$i = 1;\n\t    }\n\t    else {\n\t\t$x1 += $colwidth[($i-1) % $numcolumns] ;\n\t\t++$i;\n\t    }\n\t}\n    }\n} // Class\n\t\n\n//===================================================\n// CLASS DisplayValue\n// Description: Used to print data values at data points\n//===================================================\nclass DisplayValue {\n    var $show=false,$format=\"%.1f\",$negformat=\"\";\n    var $iFormCallback='';\n    var $angle=0;\n    var $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10;\n    var $color=\"navy\",$negcolor=\"\";\n    var $margin=5,$valign=\"\",$halign=\"center\";\n    var $iHideZero=false;\n\n    function Show($aFlag=true) {\n\t$this->show=$aFlag;\n    }\n\n    function SetColor($aColor,$aNegcolor=\"\") {\n\t$this->color = $aColor;\n\t$this->negcolor = $aNegcolor;\n    }\n\n    function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) {\n\t$this->ff=$aFontFamily;\n\t$this->fs=$aFontStyle;\n\t$this->fsize=$aFontSize;\n    }\n\n    function SetMargin($aMargin) {\n\t$this->margin = $aMargin;\n    }\n\n    function SetAngle($aAngle) {\n\t$this->angle = $aAngle;\n    }\n\n    function SetAlign($aHAlign,$aVAlign='') {\n\t$this->halign = $aHAlign;\n\t$this->valign = $aVAlign;\n    }\n\n    function SetFormat($aFormat,$aNegFormat=\"\") {\n\t$this->format= $aFormat;\n\t$this->negformat= $aNegFormat;\n    }\n\n    function SetFormatCallback($aFunc) {\n\t$this->iFormCallback = $aFunc;\n    }\n\n    function HideZero($aFlag=true) {\n\t$this->iHideZero=$aFlag;\n    }\n\n    function Stroke($img,$aVal,$x,$y) {\n\t\n\tif( $this->show ) \n\t{\n\t    if( $this->negformat==\"\" ) $this->negformat=$this->format;\n\t    if( $this->negcolor==\"\" ) $this->negcolor=$this->color;\n\n\t    if( $aVal===NULL || (is_string($aVal) && ($aVal==\"\" || $aVal==\"-\" || $aVal==\"x\" ) ) ) \n\t\treturn;\n\n\t    if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) {\n\t\treturn;\n\t    }\n\n\t    // Since the value is used in different cirumstances we need to check what\n\t    // kind of formatting we shall use. For example, to display values in a line\n\t    // graph we simply display the formatted value, but in the case where the user\n\t    // has already specified a text string we don't fo anything.\n\t    if( $this->iFormCallback != '' ) {\n\t\t$f = $this->iFormCallback;\n\t\t$sval = call_user_func($f,$aVal);\n\t    }\n\t    elseif( is_numeric($aVal) ) {\n\t\tif( $aVal >= 0 )\n\t\t    $sval=sprintf($this->format,$aVal);\n\t\telse\n\t\t    $sval=sprintf($this->negformat,$aVal);\n\t    }\n\t    else\n\t\t$sval=$aVal;\n\n\t    $y = $y-sign($aVal)*$this->margin;\n\n\t    $txt = new Text($sval,$x,$y);\n\t    $txt->SetFont($this->ff,$this->fs,$this->fsize);\n\t    if( $this->valign == \"\" ) {\n\t\tif( $aVal >= 0 )\n\t\t    $valign = \"bottom\";\n\t\telse\n\t\t    $valign = \"top\";\n\t    }\n\t    else\n\t\t$valign = $this->valign;\n\t    $txt->Align($this->halign,$valign);\n\n\t    $txt->SetOrientation($this->angle);\n\t    if( $aVal > 0 )\n\t\t$txt->SetColor($this->color);\n\t    else\n\t\t$txt->SetColor($this->negcolor);\n\t    $txt->Stroke($img);\n\t}\n    }\n}\n\n//===================================================\n// CLASS Plot\n// Description: Abstract base class for all concrete plot classes\n//===================================================\nclass Plot {\n    var $line_weight=1;\n    var $coords=array();\n    var $legend='',$hidelegend=false;\n    var $csimtargets=array();\t// Array of targets for CSIM\n    var $csimareas=\"\";\t\t\t// Resultant CSIM area tags\t\n    var $csimalts=null;\t\t\t// ALT:s for corresponding target\n    var $color=\"black\";\n    var $numpoints=0;\n    var $weight=1;\t\n    var $value;\n    var $center=false;\n    var $legendcsimtarget='';\n    var $legendcsimalt='';\n//---------------\n// CONSTRUCTOR\n    function Plot(&$aDatay,$aDatax=false) {\n\t$this->numpoints = count($aDatay);\n\tif( $this->numpoints==0 )\n\t    JpGraphError::RaiseL(25121);//(\"Empty input data array specified for plot. Must have at least one data point.\");\n\t$this->coords[0]=$aDatay;\n\tif( is_array($aDatax) )\n\t    $this->coords[1]=$aDatax;\n\t$this->value = new DisplayValue();\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    // Stroke the plot\n    // \"virtual\" function which must be implemented by\n    // the subclasses\n    function Stroke(&$aImg,&$aXScale,&$aYScale) {\n\tJpGraphError::RaiseL(25122);//(\"JpGraph: Stroke() must be implemented by concrete subclass to class Plot\");\n    }\n\n    function HideLegend($f=true) {\n\t$this->hidelegend = $f;\n    }\n\n    function DoLegend(&$graph) {\n\tif( !$this->hidelegend )\n\t    $this->Legend($graph);\n    }\n\n    function StrokeDataValue($img,$aVal,$x,$y) {\n\t$this->value->Stroke($img,$aVal,$x,$y);\n    }\n\t\n    // Set href targets for CSIM\t\n    function SetCSIMTargets($aTargets,$aAlts=null) {\n\t$this->csimtargets=$aTargets;\n\t$this->csimalts=$aAlts;\t\t\n    }\n \t\n    // Get all created areas\n    function GetCSIMareas() {\n\treturn $this->csimareas;\n    }\t\n\t\n    // \"Virtual\" function which gets called before any scale\n    // or axis are stroked used to do any plot specific adjustment\n    function PreStrokeAdjust(&$aGraph) {\n\tif( substr($aGraph->axtype,0,4) == \"text\" && (isset($this->coords[1])) )\n\t    JpGraphError::RaiseL(25123);//(\"JpGraph: You can't use a text X-scale with specified X-coords. Use a \\\"int\\\" or \\\"lin\\\" scale instead.\");\n\treturn true;\t\n    }\n\t\n    // Get minimum values in plot\n    function Min() {\n\tif( isset($this->coords[1]) )\n\t    $x=$this->coords[1];\n\telse\n\t    $x=\"\";\n\tif( $x != \"\" && count($x) > 0 )\n\t    $xm=min($x);\n\telse \n\t    $xm=0;\n\t$y=$this->coords[0];\n\t$cnt = count($y);\n\tif( $cnt > 0 ) {\n\t    /*\n\t    if( ! isset($y[0]) ) {\n\t\tJpGraphError('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)');\n\t    }\n\t    */\n\t    //$ym = $y[0];\n\t    $i=0;\n\t    while( $i<$cnt && !is_numeric($ym=$y[$i]) )\n\t\t$i++;\n\t    while( $i < $cnt) {\n\t\tif( is_numeric($y[$i]) ) \n\t\t    $ym=min($ym,$y[$i]);\n\t\t++$i;\n\t    }\t\t\t\n\t}\n\telse \n\t    $ym=\"\";\n\treturn array($xm,$ym);\n    }\n\t\n    // Get maximum value in plot\n    function Max() {\n\tif( isset($this->coords[1]) )\n\t    $x=$this->coords[1];\n\telse\n\t    $x=\"\";\n\n\tif( $x!=\"\" && count($x) > 0 )\n\t    $xm=max($x);\n\telse {\n\t    $xm = $this->numpoints-1;\n\t}\n\t$y=$this->coords[0];\n\tif( count($y) > 0 ) {\n\t    /*\n\t    if( !isset($y[0]) ) {\n\t\tJpGraphError::Raise('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)');\n\t\t//$y[0] = 0;\n// Change in 1.5.1 Don't treat this as an error any more. Just silently convert to 0\n// Change in 1.17 Treat his as an error again !! This is the right way to do !!\n\t    }\n\t    */\n\t    $cnt = count($y);\n\t    $i=0;\n\t    while( $i<$cnt && !is_numeric($ym=$y[$i]) )\n\t\t$i++;\t\t\t\t\n\t    while( $i < $cnt ) {\n\t\tif( is_numeric($y[$i]) ) \n\t\t    $ym=max($ym,$y[$i]);\n\t\t++$i;\n\t    }\n\t    \n\t}\n\telse \n\t    $ym=\"\";\n\treturn array($xm,$ym);\n    }\n\t\n    function SetColor($aColor) {\n\t$this->color=$aColor;\n    }\n\t\n    function SetLegend($aLegend,$aCSIM=\"\",$aCSIMAlt=\"\") {\n\t$this->legend = $aLegend;\n\t$this->legendcsimtarget = $aCSIM;\n\t$this->legendcsimalt = $aCSIMAlt;\n    }\n\n    function SetWeight($aWeight) {\n\t$this->weight=$aWeight;\n    }\n\t\t\n    function SetLineWeight($aWeight=1) {\n\t$this->line_weight=$aWeight;\n    }\n\t\n    function SetCenter($aCenter=true) {\n\t$this->center = $aCenter;\n    }\n\t\n    // This method gets called by Graph class to plot anything that should go\n    // into the margin after the margin color has been set.\n    function StrokeMargin(&$aImg) {\n\treturn true;\n    }\n\n    // Framework function the chance for each plot class to set a legend\n    function Legend(&$aGraph) {\n\tif( $this->legend != \"\" )\n\t    $aGraph->legend->Add($this->legend,$this->color,\"\",0,$this->legendcsimtarget,$this->legendcsimalt);    \n    }\n\t\n} // Class\n\n\n//===================================================\n// CLASS PlotLine\n// Description: \n// Data container class to hold properties for a static\n// line that is drawn directly in the plot area.\n// Usefull to add static borders inside a plot to show\n// for example set-values\n//===================================================\nclass PlotLine {\n    var $weight=1;\n    var $color=\"black\";\n    var $direction=-1; \n    var $scaleposition;\n\n//---------------\n// CONSTRUCTOR\n    function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor=\"black\",$aWeight=1) {\n\t$this->direction = $aDir;\n\t$this->color=$aColor;\n\t$this->weight=$aWeight;\n\t$this->scaleposition=$aPos;\n    }\n\t\n//---------------\n// PUBLIC METHODS\t\n    function SetPosition($aScalePosition) {\n\t$this->scaleposition=$aScalePosition;\n    }\n\t\n    function SetDirection($aDir) {\n\t$this->direction = $aDir;\n    }\n\t\n    function SetColor($aColor) {\n\t$this->color=$aColor;\n    }\n\t\n    function SetWeight($aWeight) {\n\t$this->weight=$aWeight;\n    }\n\n    function PreStrokeAdjust($aGraph) {\n\t// Nothing to do\n    }\n\t\n    function Stroke(&$aImg,&$aXScale,&$aYScale) {\n\t$aImg->SetColor($this->color);\n\t$aImg->SetLineWeight($this->weight);\t\t\n\tif( $this->direction == VERTICAL ) {\n\t    $ymin_abs=$aYScale->Translate($aYScale->GetMinVal());\n\t    $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal());\n\t    $xpos_abs=$aXScale->Translate($this->scaleposition);\n\t    $aImg->Line($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs);\n\t}\n\telseif( $this->direction == HORIZONTAL ) {\n\t    $xmin_abs=$aXScale->Translate($aXScale->GetMinVal());\n\t    $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal());\n\t    $ypos_abs=$aYScale->Translate($this->scaleposition);\n\t    $aImg->Line($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs);\n\t}\n\telse\n\t    JpGraphError::RaiseL(25125);//(\" Illegal direction for static line\");\n    }\n}\n\n// <EOF>\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_antispam-digits.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_ANTISPAM.PHP\n// Description:\tGenarate anti-spam challenge\n// Created: \t2004-10-07\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_antispam-digits.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass HandDigits {\n    var $digits_thumb30x30 = array();\n    var $iHeight=30, $iWidth=30;\n    function HandDigits() {\n//==========================================================\n// d6-small.jpg\n//==========================================================\n\t$this->digits['6'][0]= 645 ;\n\t$this->digits['6'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'.\n\t    'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'.\n\t    'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'.\n\t    'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'.\n\t    'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'.\n\t    'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'.\n\t    'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; \n\n//==========================================================\n// d2-small.jpg\n//==========================================================\n\t$this->digits['2'][0]= 606 ;\n\t$this->digits['2'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'.\n\t    'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'.\n\t    'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'.\n\t    'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'.\n\t    'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'.\n\t    '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'.\n\t    'DLZ6f//Z' ; \n\n//==========================================================\n// d9-small.jpg\n//==========================================================\n\t$this->digits['9'][0]= 680 ;\n\t$this->digits['9'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'.\n\t    'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'.\n\t    'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'.\n\t    'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'.\n\t    'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'.\n\t    'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'.\n\t    'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'.\n\t    '1V1//9k=' ; \n\n//==========================================================\n// d5-small.jpg\n//==========================================================\n\t$this->digits['5'][0]= 632 ;\n\t$this->digits['5'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'.\n\t    'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'.\n\t    'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'.\n\t    'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'.\n\t    'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'.\n\t    'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'.\n\t    '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; \n\n//==========================================================\n// d1-small.jpg\n//==========================================================\n\t$this->digits['1'][0]= 646 ;\n\t$this->digits['1'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'.\n\t    'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'.\n\t    'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'.\n\t    'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'.\n\t    'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'.\n\t    'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'.\n\t    'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; \n\n//==========================================================\n// d8-small.jpg\n//==========================================================\n\t$this->digits['8'][0]= 694 ;\n\t$this->digits['8'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'.\n\t    'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'.\n\t    'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'.\n\t    'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'.\n\t    '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'.\n\t    'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'.\n\t    'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'.\n\t    'EylmLHQltptPZKQOBo1FzH//2Q==' ; \n\n//==========================================================\n// d4-small.jpg\n//==========================================================\n\t$this->digits['4'][0]= 643 ;\n\t$this->digits['4'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'.\n\t    'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'.\n\t    'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'.\n\t    'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'.\n\t    'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'.\n\t    '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'.\n\t    'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; \n\n//==========================================================\n// d7-small.jpg\n//==========================================================\n\t$this->digits['7'][0]= 658 ;\n\t$this->digits['7'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'.\n\t    'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'.\n\t    'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'.\n\t    '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'.\n\t    'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'.\n\t    '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'.\n\t    'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; \n\n//==========================================================\n// d3-small.jpg\n//==========================================================\n\t$this->digits['3'][0]= 662 ;\n\t$this->digits['3'][1]= \n\t    '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n\t    'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n\t    'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'.\n\t    'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'.\n\t    'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'.\n\t    'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'.\n\t    'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'.\n\t    'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'.\n\t    'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; \n    } \n}\n\nclass AntiSpam {\n\n    var $iNumber='';\n\n    function AntiSpam($aNumber='') {\n\t$this->iNumber = $aNumber;\n    }\n\n    function Rand($aLen) {\n\t$d='';\n\tfor($i=0; $i < $aLen; ++$i) {\n\t    $d .= rand(1,9);\n\t}\n\t$this->iNumber = $d;\n\treturn $d;\n    }\n\n    function Stroke() {\n\n\t$n=strlen($this->iNumber);\n\tfor($i=0; $i < $n; ++$i ) {\n\t    if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) {\n\t\treturn false;\n\t    }\n\t}\n\n\t$dd = new HandDigits();\n\t$n = strlen($this->iNumber);\n\t$img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight);\n\tif( $img < 1 ) {\n\t    return false;\n\t}\n\t$start=0;\n\tfor($i=0; $i < $n; ++$i ) {\n\t    $size = $dd->digits[$this->iNumber[$i]][0];\n\t    $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1]));\n\t    imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight);\n\t    $start += imagesx($dimg);\n\t}\n\t$resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4);\n\tif( $resimg < 1 ) {\n\t    return false;\n\t}\n\timagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight);\n\theader(\"Content-type: image/jpeg\");\n\timagejpeg($resimg);\n\treturn true;\n    }\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_antispam.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_ANTISPAM.PHP\n// Description:\tGenarate anti-spam challenge\n// Created: \t2004-10-07\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_antispam.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\nclass HandDigits {\n    var $chars = array();\n    var $iHeight=30, $iWidth=30;\n    function HandDigits() {\n\n//==========================================================\n// lj-small.jpg\n//==========================================================\n$this->chars['j'][0]= 658 ;\n$this->chars['j'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'.\n'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'.\n'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'.\n'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'.\n'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'.\n'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'.\n'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; \n\n//==========================================================\n// lf-small.jpg\n//==========================================================\n$this->chars['f'][0]= 633 ;\n$this->chars['f'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'.\n'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'.\n'/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'.\n'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'.\n'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'.\n'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'.\n'4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; \n\n//==========================================================\n// lb-small.jpg\n//==========================================================\n$this->chars['b'][0]= 645 ;\n$this->chars['b'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'.\n'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'.\n'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'.\n'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'.\n'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'.\n'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'.\n'8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; \n\n//==========================================================\n// d6-small.jpg\n//==========================================================\n$this->chars['6'][0]= 645 ;\n$this->chars['6'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'.\n'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'.\n'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'.\n'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'.\n'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'.\n'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'.\n'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; \n\n//==========================================================\n// lx-small.jpg\n//==========================================================\n$this->chars['x'][0]= 650 ;\n$this->chars['x'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'.\n'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'.\n'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'.\n'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'.\n'9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'.\n'9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'.\n'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; \n\n//==========================================================\n// d2-small.jpg\n//==========================================================\n$this->chars['2'][0]= 606 ;\n$this->chars['2'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'.\n'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'.\n'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'.\n'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'.\n'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'.\n'7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'.\n'DLZ6f//Z' ; \n\n//==========================================================\n// lm-small.jpg\n//==========================================================\n$this->chars['m'][0]= 649 ;\n$this->chars['m'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'.\n'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'.\n'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'.\n'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'.\n'4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'.\n'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'.\n'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; \n\n//==========================================================\n// lt-small.jpg\n//==========================================================\n$this->chars['t'][0]= 648 ;\n$this->chars['t'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'.\n'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'.\n'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'.\n'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'.\n'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'.\n'+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'.\n'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; \n\n//==========================================================\n// li-small.jpg\n//==========================================================\n$this->chars['i'][0]= 639 ;\n$this->chars['i'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'.\n'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'.\n'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'.\n'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'.\n't2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'.\n'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'.\n'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ;\n \n\n//==========================================================\n// lp-small.jpg\n//==========================================================\n$this->chars['p'][0]= 700 ;\n$this->chars['p'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'.\n'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'.\n'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'.\n'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'.\n'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'.\n'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'.\n'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'.\n'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; \n\n//==========================================================\n// le-small.jpg\n//==========================================================\n$this->chars['e'][0]= 700 ;\n$this->chars['e'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'.\n'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'.\n'/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'.\n'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'.\n'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'.\n'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'.\n'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'.\n'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; \n\n//==========================================================\n// la-small.jpg\n//==========================================================\n$this->chars['a'][0]= 730 ;\n$this->chars['a'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'.\n'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'.\n'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'.\n'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'.\n't+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'.\n'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'.\n'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'.\n'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ;\n\n//==========================================================\n// d9-small.jpg\n//==========================================================\n$this->chars['9'][0]= 680 ;\n$this->chars['9'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'.\n'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'.\n'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'.\n'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'.\n'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'.\n'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'.\n'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'.\n'1V1//9k=' ; \n\n//==========================================================\n// d5-small.jpg\n//==========================================================\n$this->chars['5'][0]= 632 ;\n$this->chars['5'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'.\n'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'.\n'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'.\n'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'.\n'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'.\n'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'.\n'8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; \n\n//==========================================================\n// d1-small.jpg\n//==========================================================\n$this->chars['1'][0]= 646 ;\n$this->chars['1'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'.\n'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'.\n'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'.\n'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'.\n'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'.\n'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'.\n'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; \n\n//==========================================================\n// ll-small.jpg\n//==========================================================\n$this->chars['l'][0]= 626 ;\n$this->chars['l'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'.\n'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'.\n'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'.\n'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'.\n'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'.\n'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'.\n'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ;\n\n\n//==========================================================\n// ls-small.jpg\n//==========================================================\n$this->chars['s'][0]= 701 ;\n$this->chars['s'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'.\n'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'.\n'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'.\n'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'.\n'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'.\n'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'.\n'2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'.\n'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; \n\n//==========================================================\n// lh-small.jpg\n//==========================================================\n$this->chars['h'][0]= 677 ;\n$this->chars['h'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'.\n'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'.\n'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'.\n'5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'.\n'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'.\n'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'.\n'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'.\n'/9k=' ; \n\n\n//==========================================================\n// ld-small.jpg\n//==========================================================\n$this->chars['d'][0]= 681 ;\n$this->chars['d'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'.\n'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'.\n'2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'.\n'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'.\n'688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'.\n'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'.\n'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'.\n'Ia1JX//Z' ;\n\n//==========================================================\n// d8-small.jpg\n//==========================================================\n$this->chars['8'][0]= 694 ;\n$this->chars['8'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'.\n'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'.\n'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'.\n'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'.\n'44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'.\n'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'.\n'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'.\n'EylmLHQltptPZKQOBo1FzH//2Q==' ; \n\n//==========================================================\n// lz-small.jpg\n//==========================================================\n$this->chars['z'][0]= 690 ;\n$this->chars['z'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'.\n'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'.\n'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'.\n'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'.\n'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'.\n'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'.\n'4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'.\n'KrnsKH06I/rVrQKkf//Z' ;\n\n//==========================================================\n// d4-small.jpg\n//==========================================================\n$this->chars['4'][0]= 643 ;\n$this->chars['4'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'.\n'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'.\n'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'.\n'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'.\n'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'.\n'27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'.\n'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; \n\n//==========================================================\n// lv-small.jpg\n//==========================================================\n$this->chars['v'][0]= 648 ;\n$this->chars['v'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'.\n'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'.\n'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'.\n'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'.\n'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'.\n'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'.\n'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ;\n\n//==========================================================\n// lk-small.jpg\n//==========================================================\n$this->chars['k'][0]= 680 ;\n$this->chars['k'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'.\n'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'.\n'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'.\n'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'.\n'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'.\n'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'.\n'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'.\n'k9aP/9k=' ; \n\n//==========================================================\n// lr-small.jpg\n//==========================================================\n$this->chars['r'][0]= 681 ;\n$this->chars['r'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'.\n'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'.\n'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'.\n'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'.\n'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'.\n'7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'.\n'2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'.\n'ZeKZ1//Z' ; \n\n//==========================================================\n// lg-small.jpg\n//==========================================================\n$this->chars['g'][0]= 655 ;\n$this->chars['g'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'.\n'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'.\n'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'.\n'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'.\n'4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'.\n'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'.\n'4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ;\n\n//==========================================================\n// lc-small.jpg\n//==========================================================\n$this->chars['c'][0]= 629 ;\n$this->chars['c'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'.\n'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'.\n'/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'.\n'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'.\n'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'.\n'305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'.\n'3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; \n\n//==========================================================\n// d7-small.jpg\n//==========================================================\n$this->chars['7'][0]= 658 ;\n$this->chars['7'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'.\n'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'.\n'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'.\n'19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'.\n'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'.\n'8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'.\n'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; \n\n//==========================================================\n// ly-small.jpg\n//==========================================================\n$this->chars['y'][0]= 672 ;\n$this->chars['y'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'.\n'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'.\n'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'.\n'76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'.\n'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'.\n'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'.\n'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; \n\n//==========================================================\n// d3-small.jpg\n//==========================================================\n$this->chars['3'][0]= 662 ;\n$this->chars['3'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'.\n'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'.\n'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'.\n'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'.\n'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'.\n'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'.\n'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'.\n'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; \n\n//==========================================================\n// ln-small.jpg\n//==========================================================\n$this->chars['n'][0]= 643 ;\n$this->chars['n'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'.\n'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'.\n'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'.\n'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'.\n'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'.\n'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'.\n'5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; \n\n//==========================================================\n// lu-small.jpg\n//==========================================================\n$this->chars['u'][0]= 671 ;\n$this->chars['u'][1]= \n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'.\n'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'.\n'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'.\n'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'.\n'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'.\n'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'.\n'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; \n\n//==========================================================\n// lw-small.jpg\n//==========================================================\n$this->chars['w'][0]= 673 ;\n$this->chars['w'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'.\n'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'.\n'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'.\n'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'.\n'92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'.\n'7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'.\n'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ;\n\n//==========================================================\n// lq-small.jpg\n//==========================================================\n$this->chars['q'][0]= 671 ;\n$this->chars['q'][1]=\n'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'.\n'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'.\n'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'.\n'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'.\n'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'.\n'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'.\n'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'.\n'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'.\n'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ;\n\n\n\n    } \n}\n\nclass AntiSpam {\n\n    var $iData='';\n    var $iDD=null;\n\n    function AntiSpam($aData='') {\n\t$this->iData = $aData;\n\t$this->iDD = new HandDigits();\t\n    }\n\n    function Set($aData) {\n\t$this->iData = $aData;\n    }\n\n    function Rand($aLen) {\n\t$d='';\n\tfor($i=0; $i < $aLen; ++$i) {\n\t    if( rand(0,9) < 6 ) {\n\t\t// Digits\n\t\t$d .= chr( ord('1') + rand(0,8) );\n\t    }\n\t    else {\n\t\t// Letters\n\t\tdo {\n\t\t    $offset = rand(0,25);\n\t\t} while ( $offset==14 );\n\t\t$d .= chr( ord('a') + $offset );\n\t    }\n\t}\n\t$this->iData = $d;\n\treturn $d;\n    }\n\n    function Stroke($aStrokeFileName=\"\") {\n\n\t$n=strlen($this->iData);\n\tif( $n==0 ) {\n\t    return false;\n\t}\n\n\tfor($i=0; $i < $n; ++$i ) {\n\t    if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') {\n\t\treturn false;\n\t    }\n\t}\n\n\t$img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight);\n\tif( $img < 1 ) {\n\t    return false;\n\t}\n\n\t$start=0;\n\tfor($i=0; $i < $n; ++$i ) {\n\t    $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1]));\n\t    imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight);\n\t    $start += imagesx($dimg);\n\t}\n\t$resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4);\n\tif( $resimg < 1 ) {\n\t    return false;\n\t}\n\n\timagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight);\n\n\tif( $aStrokeFileName!=\"\" ) {\n\t    if( file_exists($aStrokeFileName) ) {\n\t\tif( !@unlink($aStrokeFileName) )\n\t\t    return false;\n\t    }\n\t    imagejpeg($resimg,$aStrokeFileName);\n\t    return;\n\t}\n\n\theader(\"Content-type: image/jpeg\");\n\t$res=imagejpeg($resimg);\n\treturn $res;\n    }\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_bar.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_BAR.PHP\n// Description:\tBar plot extension for JpGraph\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_bar.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nrequire_once('jpgraph_plotband.php');\n\n// Pattern for Bars\nDEFINE('PATTERN_DIAG1',1);\nDEFINE('PATTERN_DIAG2',2);\nDEFINE('PATTERN_DIAG3',3);\nDEFINE('PATTERN_DIAG4',4);\nDEFINE('PATTERN_CROSS1',5);\nDEFINE('PATTERN_CROSS2',6);\nDEFINE('PATTERN_CROSS3',7);\nDEFINE('PATTERN_CROSS4',8);\nDEFINE('PATTERN_STRIPE1',9);\nDEFINE('PATTERN_STRIPE2',10);\n\n//===================================================\n// CLASS BarPlot\n// Description: Main code to produce a bar plot \n//===================================================\nclass BarPlot extends Plot {\n    var $width=0.4; // in percent of major ticks\n    var $abswidth=-1; // Width in absolute pixels\n    var $fill=false,$fill_color=\"lightblue\"; // Default is to fill with light blue\n    var $ybase=0; // Bars start at 0 \n    var $align=\"center\";\n    var $grad=false,$grad_style=1;\n    var $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255);\n    var $bar_shadow=false;\n    var $bar_shadow_color=\"black\";\n    var $bar_shadow_hsize=3,$bar_shadow_vsize=3;\t\n    var $valuepos='top';\n    var $iPattern=-1,$iPatternDensity=80,$iPatternColor='black';\n\t\n//---------------\n// CONSTRUCTOR\n    function BarPlot(&$datay,$datax=false) {\n\t$this->Plot($datay,$datax);\t\t\n\t++$this->numpoints;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\t\n    // Set a drop shadow for the bar (or rather an \"up-right\" shadow)\n    function SetShadow($color=\"black\",$hsize=3,$vsize=3,$show=true) {\n\t$this->bar_shadow=$show;\n\t$this->bar_shadow_color=$color;\n\t$this->bar_shadow_vsize=$vsize;\n\t$this->bar_shadow_hsize=$hsize;\n\t\t\n\t// Adjust the value margin to compensate for shadow\n\t$this->value->margin += $vsize;\n    }\n\t\t\n    // DEPRECATED use SetYBase instead\n    function SetYMin($aYStartValue) {\n\t//die(\"JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead.\");    \t\n\t$this->ybase=$aYStartValue;\n    }\n\n    // Specify the base value for the bars\n    function SetYBase($aYStartValue) {\n\t$this->ybase=$aYStartValue;\n    }\n\t\n    function Legend(&$graph) {\n\tif( $this->grad && $this->legend!=\"\" && !$this->fill ) {\n\t    $color=array($this->grad_fromcolor,$this->grad_tocolor);\n\t    // In order to differentiate between gradients and cooors specified as an RGB triple\n\t    $graph->legend->Add($this->legend,$color,\"\",-$this->grad_style,\n\t\t\t\t$this->legendcsimtarget,$this->legendcsimalt);\n\t}\n\telseif( $this->legend!=\"\" && ($this->iPattern > -1 || is_array($this->iPattern)) ) {\n\t    if( is_array($this->iPattern) ) {\n\t\t$p1 = $this->iPattern[0];\n\t\t$p2 = $this->iPatternColor[0];\n\t\t$p3 = $this->iPatternDensity[0];\n\t    }\n\t    else {\n\t\t$p1 = $this->iPattern;\n\t\t$p2 = $this->iPatternColor;\n\t\t$p3 = $this->iPatternDensity;\n\t    }\n\t    $color = array($p1,$p2,$p3,$this->fill_color);\n\t    // A kludge: Too mark that we add a pattern we use a type value of < 100\n\t    $graph->legend->Add($this->legend,$color,\"\",-101,\n\t\t\t\t$this->legendcsimtarget,$this->legendcsimalt);\n\t}\n\telseif( $this->fill_color && $this->legend!=\"\" ) {\n\t    if( is_array($this->fill_color) ) {\n\t\t$graph->legend->Add($this->legend,$this->fill_color[0],\"\",0,\n\t\t\t\t    $this->legendcsimtarget,$this->legendcsimalt);\n\t    }\n\t    else {\n\t\t$graph->legend->Add($this->legend,$this->fill_color,\"\",0,\n\t\t\t\t    $this->legendcsimtarget,$this->legendcsimalt);\t\n\t    }\n\t}\n    }\n\n    // Gets called before any axis are stroked\n    function PreStrokeAdjust(&$graph) {\n\tparent::PreStrokeAdjust($graph);\n\n\t// If we are using a log Y-scale we want the base to be at the\n\t// minimum Y-value unless the user have specifically set some other\n\t// value than the default.\n\tif( substr($graph->axtype,-3,3)==\"log\" && $this->ybase==0 )\n\t    $this->ybase = $graph->yaxis->scale->GetMinVal();\n\t\t\n\t// For a \"text\" X-axis scale we will adjust the\n\t// display of the bars a little bit.\n\tif( substr($graph->axtype,0,3)==\"tex\" ) {\n\t    // Position the ticks between the bars\n\t    $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0);\n\n\t    // Center the bars \n\t    if( $this->abswidth > -1 ) {\n\t\t$graph->SetTextScaleAbsCenterOff($this->abswidth);\n\t    }\n\t    else {\n\t\tif( $this->align == \"center\" )\n\t\t    $graph->SetTextScaleOff(0.5-$this->width/2);\n\t\telseif( $this->align == \"right\" )\n\t\t    $graph->SetTextScaleOff(1-$this->width);\t\t\t\n\t    }\n\n\t}\n\telseif( is_a($this,'AccBarPlot') || is_a($this,'GroupBarPlot') ) { \n\t    // We only set an absolute width for linear and int scale\n\t    // for text scale the width will be set to a fraction of\n\t    // the majstep width.\n\t    if( $this->abswidth == -1 ) {\n                // Not set\n\t\t// set width to a visuable sensible default\n\t\t$this->abswidth = $graph->img->plotwidth/(2*count($this->coords[0]));\n\t    }\n\t}\n    }\n\n    function Min() {\n\t$m = parent::Min();\n\tif( $m[1] >= $this->ybase )\n\t    $m[1] = $this->ybase;\n\treturn $m;\t\n    }\n\n    function Max() {\n\t$m = parent::Max();\n\tif( $m[1] <= $this->ybase )\n\t    $m[1] = $this->ybase;\n\treturn $m;\t\n    }\t\n\t\n    // Specify width as fractions of the major stepo size\n    function SetWidth($aFractionWidth) {\n\t$this->width=$aFractionWidth;\n    }\n\t\n    // Specify width in absolute pixels. If specified this\n    // overrides SetWidth()\n    function SetAbsWidth($aWidth) {\n\t$this->abswidth=$aWidth;\n    }\n\t\t\n    function SetAlign($aAlign) {\n\t$this->align=$aAlign;\n    }\n\t\n    function SetNoFill() {\n\t$this->grad = false;\n\t$this->fill_color=false;\n\t$this->fill=false;\n    }\n\t\t\n    function SetFillColor($aColor) {\n\t$this->fill = true ;\n\t$this->fill_color=$aColor;\n    }\n\t\n    function SetFillGradient($from_color,$to_color,$style) {\n\t$this->grad=true;\n\t$this->grad_fromcolor=$from_color;\n\t$this->grad_tocolor=$to_color;\n\t$this->grad_style=$style;\n    }\n\t\n    function SetValuePos($aPos) {\n\t$this->valuepos = $aPos;\n    }\n\n    function SetPattern($aPattern, $aColor='black'){\n\tif( is_array($aPattern) ) {\n\t    $n = count($aPattern);\n\t    $this->iPattern = array();\n\t    $this->iPatternDensity = array();\n\t    if( is_array($aColor) ) {\n\t\t$this->iPatternColor = array();\n\t\tif( count($aColor) != $n ) {\n\t\t    JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()');\n\t\t}\n\t    }\n\t    else\n\t\t$this->iPatternColor = $aColor;\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]);\n\t\tif( is_array($aColor) ) {\n\t\t    $this->iPatternColor[$i] = $aColor[$i];\n\t\t}\n\t    }\n\t}\n\telse {\n\t    $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity);\n\t    $this->iPatternColor = $aColor;\n\t}\n    }\n\n    function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){\n\tswitch( $aPattern ) {\n\t    case PATTERN_DIAG1:\n\t\t$aPatternValue= 1;\n\t\t$aDensity = 90;\n\t\tbreak;\n\t    case PATTERN_DIAG2:\n\t\t$aPatternValue= 1;\n\t\t$aDensity = 75;\n\t\tbreak;\n\t    case PATTERN_DIAG3:\n\t\t$aPatternValue= 2;\n\t\t$aDensity = 90;\n\t\tbreak;\n\t    case PATTERN_DIAG4:\n\t\t$aPatternValue= 2;\n\t\t$aDensity = 75;\n\t\tbreak;\n\t    case PATTERN_CROSS1:\n\t\t$aPatternValue= 8;\n\t\t$aDensity = 90;\n\t\tbreak;\n\t    case PATTERN_CROSS2:\n\t\t$aPatternValue= 8;\n\t\t$aDensity = 78;\n\t\tbreak;\n\t    case PATTERN_CROSS3:\n\t\t$aPatternValue= 8;\n\t\t$aDensity = 65;\n\t\tbreak;\n\t    case PATTERN_CROSS4:\n\t\t$aPatternValue= 7;\n\t\t$aDensity = 90;\n\t\tbreak;\n\t    case PATTERN_STRIPE1:\n\t\t$aPatternValue= 5;\n\t\t$aDensity = 95;\n\t\tbreak;\n\t    case PATTERN_STRIPE2:\n\t\t$aPatternValue= 5;\n\t\t$aDensity = 85;\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(2002);//('Unknown pattern specified in call to BarPlot::SetPattern()');\n\t}\n    }\n\n    function Stroke(&$img,&$xscale,&$yscale) { \n\t\t\n\t$numpoints = count($this->coords[0]);\n\tif( isset($this->coords[1]) ) {\n\t    if( count($this->coords[1])!=$numpoints )\n\t\tJpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);\n//(\"Number of X and Y points are not equal. Number of X-points:\".count($this->coords[1]).\"Number of Y-points:$numpoints\");\n\t    else\n\t\t$exist_x = true;\n\t}\n\telse \n\t    $exist_x = false;\n\t\t\n\t\t\n\t$numbars=count($this->coords[0]);\n\n\t// Use GetMinVal() instead of scale[0] directly since in the case\n\t// of log scale we get a correct value. Log scales will have negative\n\t// values for values < 1 while still not representing negative numbers.\n\tif( $yscale->GetMinVal() >= 0 ) \n\t    $zp=$yscale->scale_abs[0]; \n\telse {\n\t    $zp=$yscale->Translate(0);\n\t}\n\n\tif( $this->abswidth > -1 ) {\n\t    $abswidth=$this->abswidth;\n\t}\n\telse\n\t    $abswidth=round($this->width*$xscale->scale_factor,0);\n\n\t// Count potential pattern array to avoid doing the count for each iteration\n\tif( is_array($this->iPattern) ) {\n\t    $np = count($this->iPattern);\n\t}\n\t\t\t\t\t\n\tfor($i=0; $i < $numbars; ++$i) {\n\n \t    // If value is NULL, or 0 then don't draw a bar at all\n \t    if ($this->coords[0][$i] === null ||\n\t\t$this->coords[0][$i] === '' ||\n\t\t$this->coords[0][$i] === 0 ) continue;    \n\n\t    if( $exist_x ) $x=$this->coords[1][$i];\n\t    else $x=$i;\n\t\t\t\n\t    $x=$xscale->Translate($x);\n\n// Comment Note: This confuses the positioning when using acc together with \n// grouped bars. Workaround for fixing #191\n/*\n\t    if( !$xscale->textscale ) {\n\t    \tif($this->align==\"center\")\n\t\t    $x -= $abswidth/2;\n\t\telseif($this->align==\"right\")\n\t\t    $x -= $abswidth;\t\t\t\n\t    }\n\n*/\n\t    // Stroke fill color and fill gradient\n\t    $pts=array(\n\t\t$x,$zp,\n\t\t$x,$yscale->Translate($this->coords[0][$i]),\n\t\t$x+$abswidth,$yscale->Translate($this->coords[0][$i]),\n\t\t$x+$abswidth,$zp);\n\t    if( $this->grad ) {\n\t\t$grad = new Gradient($img);\n\t\t$grad->FilledRectangle($pts[2],$pts[3],\n\t\t\t\t       $pts[6],$pts[7],\n\t\t\t\t       $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); \n\t    }\n\t    elseif( !empty($this->fill_color) ) {\n\t\tif(is_array($this->fill_color)) {\n\t\t    $img->PushColor($this->fill_color[$i % count($this->fill_color)]);\n\t\t} else {\n\t\t    $img->PushColor($this->fill_color);\n\t\t}\n\t\t$img->FilledPolygon($pts);\n\t\t$img->PopColor();\n\t    }\n \n\t\t\t\n\t    // Remember value of this bar\n\t    $val=$this->coords[0][$i];\n\n\t    if( !empty($val) && !is_numeric($val) ) {\n\t\tJpGraphError::RaiseL(2004,$i,$val);\n//('All values for a barplot must be numeric. You have specified value['.$i.'] == \\''.$val.'\\'');\n\t    }\n\n\t    // Determine the shadow\n\t    if( $this->bar_shadow && $val != 0) {\n\n\t\t$ssh = $this->bar_shadow_hsize;\n\t\t$ssv = $this->bar_shadow_vsize;\n\t\t// Create points to create a \"upper-right\" shadow\n\t\tif( $val > 0 ) {\n\t\t    $sp[0]=$pts[6];\t\t$sp[1]=$pts[7];\n\t\t    $sp[2]=$pts[4];\t\t$sp[3]=$pts[5];\n\t\t    $sp[4]=$pts[2];\t\t$sp[5]=$pts[3];\n\t\t    $sp[6]=$pts[2]+$ssh;\t$sp[7]=$pts[3]-$ssv;\n\t\t    $sp[8]=$pts[4]+$ssh;\t$sp[9]=$pts[5]-$ssv;\n\t\t    $sp[10]=$pts[6]+$ssh;\t$sp[11]=$pts[7]-$ssv;\n\t\t} \n\t\telseif( $val < 0 ) {\n\t\t    $sp[0]=$pts[4];\t\t$sp[1]=$pts[5];\n\t\t    $sp[2]=$pts[6];\t\t$sp[3]=$pts[7];\n\t\t    $sp[4]=$pts[0];\t\t$sp[5]=$pts[1];\n\t\t    $sp[6]=$pts[0]+$ssh;\t$sp[7]=$pts[1]-$ssv;\n\t\t    $sp[8]=$pts[6]+$ssh;\t$sp[9]=$pts[7]-$ssv;\n\t\t    $sp[10]=$pts[4]+$ssh;\t$sp[11]=$pts[5]-$ssv;\n\t\t}\n\t\tif( is_array($this->bar_shadow_color) ) {\n\t\t    $numcolors = count($this->bar_shadow_color);\n\t\t    if( $numcolors == 0 ) {\n\t\t\tJpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.');\n\t\t    }\n\t\t    $img->PushColor($this->bar_shadow_color[$i % $numcolors]);\n\t\t}\n\t\telse {\n\t\t    $img->PushColor($this->bar_shadow_color);\n\t\t}\n\t\t$img->FilledPolygon($sp);\n\t\t$img->PopColor();\n\t    }\n\t\t\t\n\t    // Stroke the pattern\n\t    if( is_array($this->iPattern) ) {\n\t\t$f = new RectPatternFactory();\n\t\tif( is_array($this->iPatternColor) ) {\n\t\t    $pcolor = $this->iPatternColor[$i % $np];\n\t\t}\n\t\telse\n\t\t    $pcolor = $this->iPatternColor;\n\t\t$prect = $f->Create($this->iPattern[$i % $np],$pcolor,1);\n\t\t$prect->SetDensity($this->iPatternDensity[$i % $np]);\n\n\t\tif( $val < 0 ) {\n\t\t    $rx = $pts[0];\n\t\t    $ry = $pts[1];\n\t\t}\n\t\telse {\n\t\t    $rx = $pts[2];\n\t\t    $ry = $pts[3];\n\t\t}\n\t\t$width = abs($pts[4]-$pts[0])+1;\n\t\t$height = abs($pts[1]-$pts[3])+1;\n\t\t$prect->SetPos(new Rectangle($rx,$ry,$width,$height));\n\t\t$prect->Stroke($img);\n\t    }\n\t    else {\n\t\tif( $this->iPattern > -1 ) {\n\t\t    $f = new RectPatternFactory();\n\t\t    $prect = $f->Create($this->iPattern,$this->iPatternColor,1);\n\t\t    $prect->SetDensity($this->iPatternDensity);\n\t\t    if( $val < 0 ) {\n\t\t\t$rx = $pts[0];\n\t\t\t$ry = $pts[1];\n\t\t    }\n\t\t    else {\n\t\t\t$rx = $pts[2];\n\t\t\t$ry = $pts[3];\n\t\t    }\n\t\t    $width = abs($pts[4]-$pts[0])+1;\n\t\t    $height = abs($pts[1]-$pts[3])+1;\n\t\t    $prect->SetPos(new Rectangle($rx,$ry,$width,$height));\n\t\t    $prect->Stroke($img);\n\t\t}\n\t    }\n\t    // Stroke the outline of the bar\n\t    if( is_array($this->color) )\n\t\t$img->SetColor($this->color[$i % count($this->color)]);\n\t    else\n\t\t$img->SetColor($this->color);\n\n\t    $pts[] = $pts[0];\n\t    $pts[] = $pts[1];\n\n\t    if( $this->weight > 0 ) {\n\t\t$img->SetLineWeight($this->weight);\n\t\t$img->Polygon($pts);\n\t    }\n\t\t\t\n\t    // Determine how to best position the values of the individual bars\n\t    $x=$pts[2]+($pts[4]-$pts[2])/2;\n\t    if( $this->valuepos=='top' ) {\n\t\t$y=$pts[3];\n\t\tif( $img->a === 90 ) {\n\t\t    if( $val < 0 )\n\t\t\t$this->value->SetAlign('right','center');\t\t\t\n\t\t    else\n\t\t\t$this->value->SetAlign('left','center');\n\t\t\t\n\t\t}\n\t\t$this->value->Stroke($img,$val,$x,$y);\n\t    }\n\t    elseif( $this->valuepos=='max' ) {\n\t\t$y=$pts[3];\n\t\tif( $img->a === 90 ) {\n\t\t    if( $val < 0 )\n\t\t\t$this->value->SetAlign('left','center');\n\t\t    else\n\t\t\t$this->value->SetAlign('right','center');\t\t    \n\t\t}\n\t\telse {\n\t\t    $this->value->SetAlign('center','top');\n\t\t}\n\t\t$this->value->SetMargin(-3);\n\t\t$this->value->Stroke($img,$val,$x,$y);\n\t    }\n\t    elseif( $this->valuepos=='center' ) {\n\t\t$y = ($pts[3] + $pts[1])/2;\n\t\t$this->value->SetAlign('center','center');\n\t\t$this->value->SetMargin(0);\n\t\t$this->value->Stroke($img,$val,$x,$y);\n\t    }\n\t    elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) {\n\t\t$y=$pts[1];\n\t\tif( $img->a === 90 ) {\n\t\t    if( $val < 0 )\n\t\t\t$this->value->SetAlign('right','center');\n\t\t    else\n\t\t\t$this->value->SetAlign('left','center');\t\t    \t\t    \n\t\t}\n\t\t$this->value->SetMargin(3);\n\t\t$this->value->Stroke($img,$val,$x,$y);\n\t    }\n\t    else {\n\t\tJpGraphError::RaiseL(2006,$this->valuepos);\n//('Unknown position for values on bars :'.$this->valuepos);\n\t    }\n\t    // Create the client side image map\n\t    $rpts = $img->ArrRotate($pts);\t\t\n\t    $csimcoord=round($rpts[0]).\", \".round($rpts[1]);\n\t    for( $j=1; $j < 4; ++$j){\n\t\t$csimcoord .= \", \".round($rpts[2*$j]).\", \".round($rpts[2*$j+1]);\n\t    }\t    \t    \n\t    if( !empty($this->csimtargets[$i]) ) {\n\t\t$this->csimareas .= '<area shape=\"poly\" coords=\"'.$csimcoord.'\" ';    \t    \n\t\t$this->csimareas .= \" href=\\\"\".$this->csimtargets[$i].\"\\\"\";\n\t\t$sval='';\n\t\tif( !empty($this->csimalts[$i]) ) {\n\t\t    $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]);\n\t\t    $this->csimareas .= \" title=\\\"$sval\\\" \";\n\t\t}\n\t\t$this->csimareas .= \" alt=\\\"$sval\\\" />\\n\";\n\t    }\n\t}\n\treturn true;\n    }\n} // Class\n\n//===================================================\n// CLASS GroupBarPlot\n// Description: Produce grouped bar plots\n//===================================================\nclass GroupBarPlot extends BarPlot {\n    var $plots;\n    var $width=0.7;\n    var $nbrplots=0;\n    var $numpoints;\n//---------------\n// CONSTRUCTOR\n    function GroupBarPlot($plots) {\n\t$this->plots = $plots;\n\t$this->nbrplots = count($plots);\n\tif( $this->nbrplots < 1 ) {\n\t    JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.');\n\t}\n\tfor($i=0; $i < $this->nbrplots; ++$i ) {\n\t    if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {\n\t\tJpGraphError::RaiseL(2008,$i);//(\"Group bar plot element nbr $i is undefined or empty.\");\n\t    }\n\t}\n\t$this->numpoints = $plots[0]->numpoints;\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Legend(&$graph) {\n\t$n = count($this->plots);\n\tfor($i=0; $i < $n; ++$i) {\n\t    $c = get_class($this->plots[$i]);\n\t    if( !is_a($this->plots[$i],'BarPlot') ) {\n\t\tJpGraphError::RaiseL(2009,$c);//('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')');\n\t    }\n\t    $this->plots[$i]->DoLegend($graph);\n\t}\n    }\n\t\n    function Min() {\n\tlist($xmin,$ymin) = $this->plots[0]->Min();\n\t$n = count($this->plots);\n\tfor($i=0; $i < $n; ++$i) {\n\t    list($xm,$ym) = $this->plots[$i]->Min();\n\t    $xmin = max($xmin,$xm);\n\t    $ymin = min($ymin,$ym);\n\t}\n\treturn array($xmin,$ymin);\t\t\n    }\n\t\n    function Max() {\n\tlist($xmax,$ymax) = $this->plots[0]->Max();\n\t$n = count($this->plots);\n\tfor($i=0; $i < $n; ++$i) {\n\t    list($xm,$ym) = $this->plots[$i]->Max();\n\t    $xmax = max($xmax,$xm);\n\t    $ymax = max($ymax,$ym);\n\t}\n\treturn array($xmax,$ymax);\n    }\n\t\n    function GetCSIMareas() {\n\t$n = count($this->plots);\n\t$csimareas='';\n\tfor($i=0; $i < $n; ++$i) {\n\t    $csimareas .= $this->plots[$i]->csimareas;\n\t}\n\treturn $csimareas;\n    }\n\t\n    // Stroke all the bars next to each other\n    function Stroke(&$img,&$xscale,&$yscale) { \n\t$tmp=$xscale->off;\n\t$n = count($this->plots);\n\t$subwidth = $this->width/$this->nbrplots ; \n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $this->plots[$i]->ymin=$this->ybase;\n\t    $this->plots[$i]->SetWidth($subwidth);\n\t    \n\t    // If the client have used SetTextTickInterval() then\n\t    // major_step will be > 1 and the positioning will fail.\n\t    // If we assume it is always one the positioning will work\n\t    // fine with a text scale but this will not work with\n\t    // arbitrary linear scale\n\t    $xscale->off = $tmp+$i*round(/*$xscale->ticks->major_step* */\n\t\t\t\t\t$xscale->scale_factor* $subwidth);\n\t    $this->plots[$i]->Stroke($img,$xscale,$yscale);\n\t}\n\t$xscale->off=$tmp;\n    }\n} // Class\n\n//===================================================\n// CLASS AccBarPlot\n// Description: Produce accumulated bar plots\n//===================================================\nclass AccBarPlot extends BarPlot {\n    var $plots=null,$nbrplots=0,$numpoints=0;\n//---------------\n// CONSTRUCTOR\n    function AccBarPlot($plots) {\n\t$this->plots = $plots;\n\t$this->nbrplots = count($plots);\n\tif( $this->nbrplots < 1 ) {\n\t    JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.');\n\t}\n\tfor($i=0; $i < $this->nbrplots; ++$i ) {\n\t    if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {\n\t\tJpGraphError::RaiseL(2011,$i);//(\"Acc bar plot element nbr $i is undefined or empty.\");\n\t    }\n\t}\n\t$this->numpoints = $plots[0]->numpoints;\t\t\n\t$this->value = new DisplayValue();\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Legend(&$graph) {\n\t$n = count($this->plots);\n\tfor( $i=$n-1; $i >= 0; --$i ) {\n\t    $c = get_class($this->plots[$i]);\n\t    if( !is_a($this->plots[$i],'BarPlot') ) {\n\t\tJpGraphError::RaiseL(2012,$c);//('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')');\n\t    }\t    \n\t    $this->plots[$i]->DoLegend($graph);\n\t}\n    }\n\n    function Max() {\n\tlist($xmax) = $this->plots[0]->Max();\n\t$nmax=0;\n\tfor($i=0; $i < count($this->plots); ++$i) {\n\t    $n = count($this->plots[$i]->coords[0]);\n\t    $nmax = max($nmax,$n);\n\t    list($x) = $this->plots[$i]->Max();\n\t    $xmax = max($xmax,$x);\n\t}\n\tfor( $i = 0; $i < $nmax; $i++ ) {\n\t    // Get y-value for bar $i by adding the\n\t    // individual bars from all the plots added.\n\t    // It would be wrong to just add the\n\t    // individual plots max y-value since that\n\t    // would in most cases give to large y-value.\n\t    $y=0;\n\t    if( !isset($this->plots[0]->coords[0][$i]) ) {\n\t\tJpGraphError::RaiseL(2014);\n\t    }\n\t    if( $this->plots[0]->coords[0][$i] > 0 )\n\t\t$y=$this->plots[0]->coords[0][$i];\n\t    for( $j = 1; $j < $this->nbrplots; $j++ ) {\n\t\tif( !isset($this->plots[$j]->coords[0][$i]) ) {\n\t\t    JpGraphError::RaiseL(2014);\n\t\t}\n\t\tif( $this->plots[$j]->coords[0][$i] > 0 )\n\t\t    $y += $this->plots[$j]->coords[0][$i];\n\t    }\n\t    $ymax[$i] = $y;\n\t}\n\t$ymax = max($ymax);\n\n\t// Bar always start at baseline\n\tif( $ymax <= $this->ybase ) \n\t    $ymax = $this->ybase;\n\treturn array($xmax,$ymax);\n    }\n\n    function Min() {\n\t$nmax=0;\n\tlist($xmin,$ysetmin) = $this->plots[0]->Min();\n\tfor($i=0; $i < count($this->plots); ++$i) {\n\t    $n = count($this->plots[$i]->coords[0]);\n\t    $nmax = max($nmax,$n);\n\t    list($x,$y) = $this->plots[$i]->Min();\n\t    $xmin = Min($xmin,$x);\n\t    $ysetmin = Min($y,$ysetmin);\n\t}\n\tfor( $i = 0; $i < $nmax; $i++ ) {\n\t    // Get y-value for bar $i by adding the\n\t    // individual bars from all the plots added.\n\t    // It would be wrong to just add the\n\t    // individual plots max y-value since that\n\t    // would in most cases give to large y-value.\n\t    $y=0;\n\t    if( $this->plots[0]->coords[0][$i] < 0 )\n\t\t$y=$this->plots[0]->coords[0][$i];\n\t    for( $j = 1; $j < $this->nbrplots; $j++ ) {\n\t\tif( $this->plots[$j]->coords[0][$i] < 0 )\n\t\t    $y += $this->plots[ $j ]->coords[0][$i];\n\t    }\n\t    $ymin[$i] = $y;\n\t}\n\t$ymin = Min($ysetmin,Min($ymin));\n\t// Bar always start at baseline\n\tif( $ymin >= $this->ybase )\n\t    $ymin = $this->ybase;\n\treturn array($xmin,$ymin);\n    }\n\n    // Stroke acc bar plot\n    function Stroke(&$img,&$xscale,&$yscale) {\n\t$pattern=NULL;\n\t$img->SetLineWeight($this->weight);\n\tfor($i=0; $i < $this->numpoints-1; $i++) {\n\t    $accy = 0;\n\t    $accy_neg = 0; \n\t    for($j=0; $j < $this->nbrplots; ++$j ) {\t\t\t\t\n\t\t$img->SetColor($this->plots[$j]->color);\n\n\t\tif ( $this->plots[$j]->coords[0][$i] >= 0) {\n\t\t    $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);\n\t\t    $accyt=$yscale->Translate($accy);\n\t\t    $accy+=$this->plots[$j]->coords[0][$i];\n\t\t}\n\t\telse {\n\t\t    //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) {\n\t\t    $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);\n\t\t    $accyt=$yscale->Translate($accy_neg);\n\t\t    $accy_neg+=$this->plots[$j]->coords[0][$i];\n\t\t}\t\t\t\t\n\t\t\t\t\n\t\t$xt=$xscale->Translate($i);\n\n\t\tif( $this->abswidth > -1 )\n\t\t    $abswidth=$this->abswidth;\n\t\telse\n\t\t    $abswidth=round($this->width*$xscale->scale_factor,0);\n\t\t\n\t\t$pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt);\n\n\t\tif( $this->bar_shadow ) {\n\t\t    $ssh = $this->bar_shadow_hsize;\n\t\t    $ssv = $this->bar_shadow_vsize;\n\t\t    \n\t\t    // We must also differ if we are a positive or negative bar. \n\t\t    if( $j === 0 ) {\n\t\t\t// This gets extra complicated since we have to\n\t\t\t// see all plots to see if we are negative. It could\n\t\t\t// for example be that all plots are 0 until the very\n\t\t\t// last one. We therefore need to save the initial setup\n\t\t\t// for both the negative and positive case\n\n\t\t\t// In case the final bar is positive\n\t\t\t$sp[0]=$pts[6]+1; $sp[1]=$pts[7];\n\t\t\t$sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv;\n\n\t\t\t// In case the final bar is negative\n\t\t\t$nsp[0]=$pts[0]; $nsp[1]=$pts[1];\n\t\t\t$nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv;\n\t\t\t$nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv;\n\t\t\t$nsp[10]=$pts[6]+1; $nsp[11]=$pts[7];\n\t\t    }\n\n\t\t    if( $j === $this->nbrplots-1 ) {\n\t\t\t// If this is the last plot of the bar and\n\t\t\t// the total value is larger than 0 then we\n\t\t\t// add the shadow.\n\t\t\tif( is_array($this->bar_shadow_color) ) {\n\t\t\t    $numcolors = count($this->bar_shadow_color);\n\t\t\t    if( $numcolors == 0 ) {\n\t\t\t\tJpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.');\n\t\t\t    }\n\t\t\t    $img->PushColor($this->bar_shadow_color[$i % $numcolors]);\n\t\t\t}\n\t\t\telse {\n\t\t\t    $img->PushColor($this->bar_shadow_color);\n\t\t\t}\n\n\t\t\tif( $accy > 0 ) {\n\t\t\t    $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv;\n\t\t\t    $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv;\n\t\t\t    $sp[8]=$pts[2]; $sp[9]=$pts[3]-1;\n\t\t\t    $sp[10]=$pts[4]+1; $sp[11]=$pts[5];\n\t\t\t    $img->FilledPolygon($sp,4);\n\t\t\t}\n\t\t\telseif( $accy_neg < 0 ) {\n\t\t\t    $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv;\n\t\t\t    $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5];\n\t\t\t    $img->FilledPolygon($nsp,4);\n\t\t\t}\n\t\t\t$img->PopColor();\n\t\t    }\n\t\t}\n\n\n\t\t// If value is NULL or 0, then don't draw a bar at all\n\t\tif ($this->plots[$j]->coords[0][$i] == 0 ) continue;\n\n\t\tif( $this->plots[$j]->grad ) {\n\t\t    $grad = new Gradient($img);\n\t\t    $grad->FilledRectangle(\n\t\t\t$pts[2],$pts[3],\n\t\t\t$pts[6],$pts[7],\n\t\t\t$this->plots[$j]->grad_fromcolor,\n\t\t\t$this->plots[$j]->grad_tocolor,\n\t\t\t$this->plots[$j]->grad_style);\t\t\t\t\n\t\t} else {\n\t\t    if (is_array($this->plots[$j]->fill_color) ) {\n\t\t\t$numcolors = count($this->plots[$j]->fill_color);\n\t\t\t$img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]);\n\t\t    }\n\t\t    else {\n\t\t\t$img->SetColor($this->plots[$j]->fill_color);\n\t\t    }\n\t\t    $img->FilledPolygon($pts);\n\t\t    $img->SetColor($this->plots[$j]->color);\n\t\t}\t\t\t\t  \n\n\t\t// Stroke the pattern\n\t\tif( $this->plots[$j]->iPattern > -1 ) {\n\t\t    if( $pattern===NULL ) \n\t\t\t$pattern = new RectPatternFactory();\n\t\t\n\t\t    $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1);\n\t\t    $prect->SetDensity($this->plots[$j]->iPatternDensity);\n\t\t    if( $this->plots[$j]->coords[0][$i] < 0 ) {\n\t\t\t$rx = $pts[0];\n\t\t\t$ry = $pts[1];\n\t\t    }\n\t\t    else {\n\t\t\t$rx = $pts[2];\n\t\t\t$ry = $pts[3];\n\t\t    }\n\t\t    $width = abs($pts[4]-$pts[0])+1;\n\t\t    $height = abs($pts[1]-$pts[3])+1;\n\t\t    $prect->SetPos(new Rectangle($rx,$ry,$width,$height));\n\t\t    $prect->Stroke($img);\n\t\t}\n\n\n\t\t// CSIM array\n\n\t\tif( $i < count($this->plots[$j]->csimtargets) ) {\n\t\t    // Create the client side image map\n\t\t    $rpts = $img->ArrRotate($pts);\t\t\n\t\t    $csimcoord=round($rpts[0]).\", \".round($rpts[1]);\n\t\t    for( $k=1; $k < 4; ++$k){\n\t\t\t$csimcoord .= \", \".round($rpts[2*$k]).\", \".round($rpts[2*$k+1]);\n\t\t    }\t    \t    \n\t\t    if( ! empty($this->plots[$j]->csimtargets[$i]) ) {\n\t\t\t$this->csimareas.= '<area shape=\"poly\" coords=\"'.$csimcoord.'\" '; \n\t\t\t$this->csimareas.= \" href=\\\"\".$this->plots[$j]->csimtargets[$i].\"\\\"\";\n\t\t\tif( !empty($this->plots[$j]->csimalts[$i]) ) {\n\t\t\t    $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]);\n\t\t\t    $this->csimareas .= \" title=\\\"$sval\\\" \";\n\t\t\t}\n\t\t\t$this->csimareas .= \" alt=\\\"$sval\\\" />\\n\";\t\t\t\t\n\t\t    }\n\t\t}\n\n\t\t$pts[] = $pts[0];\n\t\t$pts[] = $pts[1];\n\t\t$img->Polygon($pts);\n\t    }\n\t\t\n\t    // Draw labels for each acc.bar\n\t\n\t    $x=$pts[2]+($pts[4]-$pts[2])/2;\n\t    if($this->bar_shadow) $x += $ssh;\n\n\t    // First stroke the accumulated value for the entire bar\n\t    // This value is always placed at the top/bottom of the bars\n\t    if( $accy_neg < 0 ) {\n\t\t$y=$yscale->Translate($accy_neg);\t\t\t\n\t\t$this->value->Stroke($img,$accy_neg,$x,$y);\n\t    }\n\t    else {\n\t\t$y=$yscale->Translate($accy);\t\t\t\n\t\t$this->value->Stroke($img,$accy,$x,$y);\n\t    }\n\n\t    $accy = 0;\n\t    $accy_neg = 0; \n\t    for($j=0; $j < $this->nbrplots; ++$j ) {\t\n\n\t\t// We don't print 0 values in an accumulated bar plot\n\t\tif( $this->plots[$j]->coords[0][$i] == 0 ) continue;\n\t\t\t\n\t\tif ($this->plots[$j]->coords[0][$i] > 0) {\n\t\t    $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);\n\t\t    $accyt=$yscale->Translate($accy);\n\t\t    if(  $this->plots[$j]->valuepos=='center' ) {\n\t\t\t$y = $accyt-($accyt-$yt)/2;\n\t\t    }\n\t\t    elseif( $this->plots[$j]->valuepos=='bottom' ) {\n\t\t\t$y = $accyt;\n\t\t    }\n\t\t    else { // top or max\n\t\t\t$y = $accyt-($accyt-$yt);\n\t\t    }\n\t\t    $accy+=$this->plots[$j]->coords[0][$i];\n\t\t    if(  $this->plots[$j]->valuepos=='center' ) {\n\t\t\t$this->plots[$j]->value->SetAlign(\"center\",\"center\");\n\t\t\t$this->plots[$j]->value->SetMargin(0);\n\t\t    }\n\t\t    elseif( $this->plots[$j]->valuepos=='bottom' ) {\n\t\t\t$this->plots[$j]->value->SetAlign('center','bottom');\n\t\t\t$this->plots[$j]->value->SetMargin(2);\n\t\t    }\n\t\t    else {\n\t\t\t$this->plots[$j]->value->SetAlign('center','top');\n\t\t\t$this->plots[$j]->value->SetMargin(1);\n\t\t    }\n\t\t} else {\n\t\t    $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);\n\t\t    $accyt=$yscale->Translate($accy_neg);\n\t\t    $accy_neg+=$this->plots[$j]->coords[0][$i];\n\t\t    if(  $this->plots[$j]->valuepos=='center' ) {\n\t\t\t$y = $accyt-($accyt-$yt)/2;\n\t\t    }\n\t\t    elseif( $this->plots[$j]->valuepos=='bottom' ) {\n\t\t\t$y = $accyt;\n\t\t    }\n\t\t    else {\n\t\t\t$y = $accyt-($accyt-$yt);\n\t\t    }\n\t\t    if(  $this->plots[$j]->valuepos=='center' ) {\n\t\t\t$this->plots[$j]->value->SetAlign(\"center\",\"center\");\n\t\t\t$this->plots[$j]->value->SetMargin(0);\n\t\t    }\n\t\t    elseif( $this->plots[$j]->valuepos=='bottom' ) {\n\t\t\t$this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top');\n\t\t\t$this->plots[$j]->value->SetMargin(-2);\n\t\t    }\n\t\t    else {\n\t\t\t$this->plots[$j]->value->SetAlign('center','bottom');\n\t\t\t$this->plots[$j]->value->SetMargin(-1);\n\t\t    }\n\t\t}\t\n\t\t$this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],$x,$y);\n\t    }\n\n\t}\n\treturn true;\n    }\n} // Class\n\n/* EOF */\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_canvas.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_CANVAS.PHP\n// Description:\tCanvas drawing extension for JpGraph\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_canvas.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//===================================================\n// CLASS CanvasGraph\n// Description: Creates a simple canvas graph which\n// might be used together with the basic Image drawing\n// primitives. Useful to auickoly produce some arbitrary\n// graphic which benefits from all the functionality in the\n// graph liek caching for example. \n//===================================================\nclass CanvasGraph extends Graph {\n//---------------\n// CONSTRUCTOR\n    function CanvasGraph($aWidth=300,$aHeight=200,$aCachedName=\"\",$timeout=0,$inline=1) {\n\t$this->Graph($aWidth,$aHeight,$aCachedName,$timeout,$inline);\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    function InitFrame() {\n\t$this->StrokePlotArea();\n    }\n\n    // Method description\n    function Stroke($aStrokeFileName=\"\") {\n\tif( $this->texts != null ) {\n\t    for($i=0; $i < count($this->texts); ++$i) {\n\t\t$this->texts[$i]->Stroke($this->img);\n\t    }\n\t}\t\t\n\tif( $this->iTables !== null ) {\n\t    for($i=0; $i < count($this->iTables); ++$i) {\n\t\t$this->iTables[$i]->Stroke($this->img);\n\t    }   \n\t}\n\t$this->StrokeTitles();\n\n\t// Should we do any final image transformation\n\tif( $this->iImgTrans ) {\n\t    if( !class_exists('ImgTrans') ) {\n\t\trequire_once('jpgraph_imgtrans.php');\n\t    }\n\t    \n\t    $tform = new ImgTrans($this->img->img);\n\t    $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,\n\t\t\t\t\t     $this->iImgTransDirection,$this->iImgTransHighQ,\n\t\t\t\t\t     $this->iImgTransMinSize,$this->iImgTransFillColor,\n\t\t\t\t\t     $this->iImgTransBorder);\n\t}\n\t\n\n\t// If the filename is given as the special _IMG_HANDLER\n\t// then the image handler is returned and the image is NOT\n\t// streamed back\n\tif( $aStrokeFileName == _IMG_HANDLER ) {\n\t    return $this->img->img;\n\t}\n\telse {\n\t    // Finally stream the generated picture\t\t\t\t\t\n\t    $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);\n\t    return true;\n\t}\n    }\n} // Class\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_canvtools.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_CANVTOOLS.PHP\n// Description:\tSome utilities for text and shape drawing on a canvas\n// Created: \t2002-08-23\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_canvtools.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nDEFINE('CORNER_TOPLEFT',0);\nDEFINE('CORNER_TOPRIGHT',1);\nDEFINE('CORNER_BOTTOMRIGHT',2);\nDEFINE('CORNER_BOTTOMLEFT',3);\n\n\n//===================================================\n// CLASS CanvasScale\n// Description: Define a scale for canvas so we\n// can abstract away with absolute pixels\n//===================================================\n \nclass CanvasScale {\n    var $g;\n    var $w,$h;\n    var $ixmin=0,$ixmax=10,$iymin=0,$iymax=10;\n\n    function CanvasScale(&$graph,$xmin=0,$xmax=10,$ymin=0,$ymax=10) {\n\t$this->g = &$graph;\n\t$this->w = $graph->img->width;\n\t$this->h = $graph->img->height;\n\t$this->ixmin = $xmin;\n\t$this->ixmax = $xmax;\n\t$this->iymin = $ymin;\n\t$this->iymax = $ymax;\n    }\n    \n    function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) {\n\t$this->ixmin = $xmin;\n\t$this->ixmax = $xmax;\n\t$this->iymin = $ymin;\n\t$this->iymax = $ymax;\n    }\n\n    function Translate($x,$y) {\n\t$xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w);\n\t$yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h);\n\treturn array($xp,$yp);\n    }\n\n    function TranslateX($x) {\n\t$xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w);\n\treturn $xp;\n    }\n\n    function TranslateY($y) {\n\t$yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h);\n\treturn $yp;\n    }\n\n}\n\n\n//===================================================\n// CLASS Shape\n// Description: Methods to draw shapes on canvas\n//===================================================\nclass Shape {\n    var $img,$scale;\n\n    function Shape(&$aGraph,&$scale) {\n\t$this->img = &$aGraph->img;\n\t$this->img->SetColor('black');\n\t$this->scale = &$scale;\n    }\n\n    function SetColor($aColor) {\n\t$this->img->SetColor($aColor);\n    }\n\n    function Line($x1,$y1,$x2,$y2) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2) = $this->scale->Translate($x2,$y2);\n\t$this->img->Line($x1,$y1,$x2,$y2);\n    }\n\n    function Polygon($p,$aClosed=false) {\n\t$n=count($p);\n\tfor($i=0; $i < $n; $i+=2 ) {\n\t   $p[$i]   = $this->scale->TranslateX($p[$i]);\n\t   $p[$i+1] = $this->scale->TranslateY($p[$i+1]);\n\t}\n\t$this->img->Polygon($p,$aClosed);\n    }\n\n    function FilledPolygon($p) {\n\t$n=count($p);\n\tfor($i=0; $i < $n; $i+=2 ) {\n\t   $p[$i]   = $this->scale->TranslateX($p[$i]);\n\t   $p[$i+1] = $this->scale->TranslateY($p[$i+1]);\n\t}\n\t$this->img->FilledPolygon($p);\n    }\n    \n\n    // Draw a bezier curve with defining points in the $aPnts array\n    // using $aSteps steps.\n    // 0=x0, 1=y0\n    // 2=x1, 3=y1\n    // 4=x2, 5=y2\n    // 6=x3, 7=y3\n    function Bezier($p,$aSteps=40) {\n\t$x0 = $p[0];\n\t$y0 = $p[1];\n\t// Calculate coefficients\n\t$cx = 3*($p[2]-$p[0]);\n\t$bx = 3*($p[4]-$p[2])-$cx;\n\t$ax = $p[6]-$p[0]-$cx-$bx;\n\t$cy = 3*($p[3]-$p[1]);\n\t$by = 3*($p[5]-$p[3])-$cy;\n\t$ay = $p[7]-$p[1]-$cy-$by;\n\n\t// Step size\n\t$delta = 1.0/$aSteps;\n\n\t$x_old = $x0;\n\t$y_old = $y0;\n\tfor($t=$delta; $t<=1.0; $t+=$delta) {\n\t    $tt = $t*$t; $ttt=$tt*$t;\n\t    $x  = $ax*$ttt + $bx*$tt + $cx*$t + $x0;\n\t    $y = $ay*$ttt + $by*$tt + $cy*$t + $y0;\n\t    $this->Line($x_old,$y_old,$x,$y);\n\t    $x_old = $x;\n\t    $y_old = $y;\n\t}\n\t$this->Line($x_old,$y_old,$p[6],$p[7]);\n    }\n\n    function Rectangle($x1,$y1,$x2,$y2) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2)   = $this->scale->Translate($x2,$y2);\n\t$this->img->Rectangle($x1,$y1,$x2,$y2);\n    }\n\n    function FilledRectangle($x1,$y1,$x2,$y2) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2)   = $this->scale->Translate($x2,$y2);\n\t$this->img->FilledRectangle($x1,$y1,$x2,$y2);\n    }\n    \n    function Circle($x1,$y1,$r) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tif( $r >= 0 )\n\t    $r   = $this->scale->TranslateX($r);\n\telse\n\t    $r = -$r;\n\t$this->img->Circle($x1,$y1,$r);\n    }\n\n    function FilledCircle($x1,$y1,$r) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tif( $r >= 0 )\n\t    $r   = $this->scale->TranslateX($r);\n\telse\n\t    $r = -$r;\n\t$this->img->FilledCircle($x1,$y1,$r);\n    }\n\n    function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) {    \n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2)   = $this->scale->Translate($x2,$y2);\n\n\tif( $r == null )\n\t    $r = 5;\n\telseif( $r >= 0 )\n\t    $r = $this->scale->TranslateX($r);\n\telse\n\t    $r = -$r;\n\t$this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r);\n    }\n\n    function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) {    \n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2)   = $this->scale->Translate($x2,$y2);\n\n\tif( $r == null )\n\t    $r = 5;\n\telseif( $r > 0 )\n\t    $r = $this->scale->TranslateX($r);\n\telse\n\t    $r = -$r;\n\t$this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r);    \n    }\n\n    function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\tlist($x2,$y2) = $this->scale->Translate($x2,$y2);\n\tif( $shadow_width == null ) \n\t    $shadow_width=4;\n\telse\n\t    $shadow_width=$this->scale->TranslateX($shadow_width);\n\t$this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color);\n    }\n\n    function SetTextAlign($halign,$valign=\"bottom\") {\n\t$this->img->SetTextAlign($halign,$valign=\"bottom\");\n    }\n\n    function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align=\"left\") {\n\tlist($x1,$y1) = $this->scale->Translate($x1,$y1);\n\t$this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align);\n    }\n\n    // A rounded rectangle where one of the corner has been moved \"into\" the\n    // rectangle 'iw' width and 'ih' height. Corners:\n    // 0=Top left, 1=top right, 2=bottom right, 3=bottom left\n    function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor=\"\",$r=4) {\n    \n\tlist($xt,$yt) = $this->scale->Translate($xt,$yt);\n\tlist($w,$h)   = $this->scale->Translate($w,$h);\n\tlist($iw,$ih) = $this->scale->Translate($iw,$ih);\n\t\n\t$xr = $xt + $w - 0;\n\t$yl = $yt + $h - 0;\n\n\tswitch( $aCorner ) {\n\t    case 0: // Upper left\n\t    \n\t\t// Bottom line, left &  right arc\n\t\t$this->img->Line($xt+$r,$yl,$xr-$r,$yl);\n\t\t$this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180);\n\t\t$this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90);\n\n\t\t// Right line, Top right arc\n\t\t$this->img->Line($xr,$yt+$r,$xr,$yl-$r);\n\t\t$this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t\t// Top line, Top left arc\n\t\t$this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt);\n\t\t$this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270);\n\n\t\t// Left line\n\t\t$this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r);\n\n\t\t// Indent horizontal, Lower left arc\n\t\t$this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih);\n\t\t$this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270);\n\n\t\t// Indent vertical, Indent arc\n\t\t$this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r);\n\t\t$this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90);\n\n\t\tif( $aFillColor != '' ) {\n\t\t    $bc = $this->img->current_color_name;\n\t\t    $this->img->PushColor($aFillColor);\n\t\t    $this->img->FillToBorder($xr-$r,$yl-$r,$bc);\n\t\t    $this->img->PopColor();\n\t\t}\n\n\t\tbreak;\n\n\t    case 1: // Upper right\n\n\t\t// Bottom line, left &  right arc\n\t\t$this->img->Line($xt+$r,$yl,$xr-$r,$yl);\n\t\t$this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180);\n\t\t$this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90);\n\n\t\t// Left line, Top left arc\n\t\t$this->img->Line($xt,$yt+$r,$xt,$yl-$r);\n\t\t$this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270);\n\n\t\t// Top line, Top right arc\n\t\t$this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt);\n\t\t$this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t\t// Right line\n\t\t$this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r);\n\n\t\t// Indent horizontal, Lower right arc\n\t\t$this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih);\n\t\t$this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360);\n\n\t\t// Indent vertical, Indent arc\n\t\t$this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r);\n\t\t$this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180);\n\n\t\tif( $aFillColor != '' ) {\n\t\t    $bc = $this->img->current_color_name;\n\t\t    $this->img->PushColor($aFillColor);\n\t\t    $this->img->FillToBorder($xt+$r,$yl-$r,$bc);\n\t\t    $this->img->PopColor();\n\t\t}\n\n\t\tbreak;\n\n\t    case 2: // Lower right\n\t\t// Top line, Top left & Top right arc\n\t\t$this->img->Line($xt+$r,$yt,$xr-$r,$yt);\n\t\t$this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270);\n\t\t$this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t\t// Left line, Bottom left arc\n\t\t$this->img->Line($xt,$yt+$r,$xt,$yl-$r);\n\t\t$this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180);\n\n\t\t// Bottom line, Bottom right arc\n\t\t$this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl);\n\t\t$this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90);\n\n\t\t// Right line\n\t\t$this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r);\n\t    \n\t\t// Indent horizontal, Lower right arc\n\t\t$this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih);\n\t\t$this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90);\n\n\t\t// Indent vertical, Indent arc\n\t\t$this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r);\n\t\t$this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270);\n\n\t\tif( $aFillColor != '' ) {\n\t\t    $bc = $this->img->current_color_name;\n\t\t    $this->img->PushColor($aFillColor);\n\t\t    $this->img->FillToBorder($xt+$r,$yt+$r,$bc);\n\t\t    $this->img->PopColor();\n\t\t}\n\n\t\tbreak;\n\n\t    case 3: // Lower left\n\t\t// Top line, Top left & Top right arc\n\t\t$this->img->Line($xt+$r,$yt,$xr-$r,$yt);\n\t\t$this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270);\n\t\t$this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360);\n\n\t\t// Right line, Bottom right arc\n\t\t$this->img->Line($xr,$yt+$r,$xr,$yl-$r);\n\t\t$this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90);\n\n\t\t// Bottom line, Bottom left arc\n\t\t$this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl);\n\t\t$this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180);\n\n\t\t// Left line\n\t\t$this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r);\n\t    \n\t\t// Indent horizontal, Lower left arc\n\t\t$this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih);\n\t\t$this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180);\n\n\t\t// Indent vertical, Indent arc\n\t\t$this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r);\n\t\t$this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360);\n\n\t\tif( $aFillColor != '' ) {\n\t\t    $bc = $this->img->current_color_name;\n\t\t    $this->img->PushColor($aFillColor);\n\t\t    $this->img->FillToBorder($xr-$r,$yt+$r,$bc);\n\t\t    $this->img->PopColor();\n\t\t}\n\n\t\tbreak;\n\t}\n    }\n}\n\n\n//===================================================\n// CLASS RectangleText\n// Description: Draws a text paragraph inside a \n// rounded, possible filled, rectangle.\n//===================================================\nclass CanvasRectangleText {\n    var $ix,$iy,$iw,$ih,$ir=4;\n    var $iTxt,$iColor='black',$iFillColor='',$iFontColor='black';\n    var $iParaAlign='center';\n    var $iAutoBoxMargin=5;\n    var $iShadowWidth=3,$iShadowColor='';\n\n    function CanvasRectangleText($aTxt='',$xl=0,$yt=0,$w=0,$h=0) {\n\t$this->iTxt = new Text($aTxt);\n\t$this->ix = $xl;\n\t$this->iy = $yt;\n\t$this->iw = $w;\n\t$this->ih = $h;\n    }\n \n    function SetShadow($aColor='gray',$aWidth=3) {\n\t$this->iShadowColor = $aColor;\n\t$this->iShadowWidth = $aWidth;\n    }\n\n    function SetFont($FontFam,$aFontStyle,$aFontSize=12) {\n\t$this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize);\n    }\n\n    function SetTxt($aTxt) {\n\t$this->iTxt->Set($aTxt);\n    }\n\n    function ParagraphAlign($aParaAlign) {\n\t$this->iParaAlign = $aParaAlign;\n    }\n\n    function SetFillColor($aFillColor) {\n\t$this->iFillColor = $aFillColor;\n    }\n\n    function SetAutoMargin($aMargin) {\n\t$this->iAutoBoxMargin=$aMargin;\n    }\n\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\n    function SetFontColor($aColor) {\n\t$this->iFontColor = $aColor;\n    }\n\n    function SetPos($xl=0,$yt=0,$w=0,$h=0) {\n\t$this->ix = $xl;\n\t$this->iy = $yt;\n\t$this->iw = $w;\n\t$this->ih = $h;\n    }\n\n    function Pos($xl=0,$yt=0,$w=0,$h=0) {\n\t$this->ix = $xl;\n\t$this->iy = $yt;\n\t$this->iw = $w;\n\t$this->ih = $h;\n    }\n\n    function Set($aTxt,$xl,$yt,$w=0,$h=0) {\n\t$this->iTxt->Set($aTxt);\n\t$this->ix = $xl;\n\t$this->iy = $yt;\n\t$this->iw = $w;\n\t$this->ih = $h;\n    }\n\n    function SetCornerRadius($aRad=5) {\n\t$this->ir = $aRad;\n    }\n\n    function Stroke($aImg,$scale) {\n\t\n\t// If coordinates are specifed as negative this means we should\n\t// treat them as abolsute (pixels) coordinates\n\tif( $this->ix > 0 ) {\n\t    $this->ix = $scale->TranslateX($this->ix) ;\n\t}\n\telse {\n\t    $this->ix = -$this->ix;\n\t}\n\n\tif( $this->iy > 0 ) {\n\t    $this->iy = $scale->TranslateY($this->iy) ;\n\t}\n\telse {\n\t    $this->iy = -$this->iy;\n\t}\n\t    \n\tlist($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ;\n\n\tif( $this->iw == 0 ) \n\t    $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin);\n\tif( $this->ih == 0 ) {\n\t    $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin);\n\t}\n\n\tif( $this->iShadowColor != '' ) {\n\t    $aImg->PushColor($this->iShadowColor);\n\t    $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth,\n\t\t\t\t\t  $this->iy+$this->iShadowWidth,\n\t\t\t\t\t  $this->ix+$this->iw-1+$this->iShadowWidth,\n\t\t\t\t\t  $this->iy+$this->ih-1+$this->iShadowWidth,\n\t\t\t\t\t  $this->ir);\n\t    $aImg->PopColor();\t    \n\t}\n\n\tif( $this->iFillColor != '' ) {\n\t    $aImg->PushColor($this->iFillColor);\n\t    $aImg->FilledRoundedRectangle($this->ix,$this->iy,\n\t\t\t\t\t  $this->ix+$this->iw-1,\n\t\t\t\t\t  $this->iy+$this->ih-1,\n\t\t\t\t\t  $this->ir);\n\t    $aImg->PopColor();\n\t}\n\n\tif( $this->iColor != '' ) {\n\t    $aImg->PushColor($this->iColor);\n\t    $aImg->RoundedRectangle($this->ix,$this->iy,\n\t\t\t\t    $this->ix+$this->iw-1,\n\t\t\t\t    $this->iy+$this->ih-1,\n\t\t\t\t    $this->ir);\n\t    $aImg->PopColor();\n\t}\n\t\n\t$this->iTxt->Align('center','center');\n\t$this->iTxt->ParagraphAlign($this->iParaAlign);\n\t$this->iTxt->SetColor($this->iFontColor);\n\t$this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2);\n\n\treturn array($this->iw, $this->ih);\n\n    }\n\n}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_date.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_DATE.PHP\n// Description:\tClasses to handle Date scaling\n// Created: \t2005-05-02\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_date.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nDEFINE('HOURADJ_1',0+30);\nDEFINE('HOURADJ_2',1+30);\nDEFINE('HOURADJ_3',2+30);\nDEFINE('HOURADJ_4',3+30);\nDEFINE('HOURADJ_6',4+30);\nDEFINE('HOURADJ_12',5+30);\n\nDEFINE('MINADJ_1',0+20);\nDEFINE('MINADJ_5',1+20);\nDEFINE('MINADJ_10',2+20);\nDEFINE('MINADJ_15',3+20);\nDEFINE('MINADJ_30',4+20);\n\nDEFINE('SECADJ_1',0);\nDEFINE('SECADJ_5',1);\nDEFINE('SECADJ_10',2);\nDEFINE('SECADJ_15',3);\nDEFINE('SECADJ_30',4);\n\n\nDEFINE('YEARADJ_1',0+30);\nDEFINE('YEARADJ_2',1+30);\nDEFINE('YEARADJ_5',2+30);\n\nDEFINE('MONTHADJ_1',0+20);\nDEFINE('MONTHADJ_6',1+20);\n\nDEFINE('DAYADJ_1',0);\nDEFINE('DAYADJ_WEEK',1);\nDEFINE('DAYADJ_7',1);\n\nDEFINE('SECPERYEAR',31536000);\nDEFINE('SECPERDAY',86400);\nDEFINE('SECPERHOUR',3600);\nDEFINE('SECPERMIN',60);\n\n\nclass DateScale extends LinearScale {\n    var $date_format = '';\n    var $iStartAlign = false, $iEndAlign = false;\n    var $iStartTimeAlign = false, $iEndTimeAlign = false;\n\n//---------------\n// CONSTRUCTOR\n    function DateScale($aMin=0,$aMax=0,$aType='x') {\n\tassert($aType==\"x\");\n\tassert($aMin<=$aMax);\n\t\t\n\t$this->type=$aType;\n\t$this->scale=array($aMin,$aMax);\t\t\n\t$this->world_size=$aMax-$aMin;\t\n\t$this->ticks = new LinearTicks();\n\t$this->intscale=true;\n    }\n\n\n//------------------------------------------------------------------------------------------\n// Utility Function AdjDate()\n// Description: Will round a given time stamp to an even year, month or day \n// argument. \n//------------------------------------------------------------------------------------------\n\n    function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) {\n\t$y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime);\n\t$h=0;$i=0;$s=0;\n\tif( $aYearType !== false ) {\n\t    $yearAdj = array(0=>1, 1=>2, 2=>5);\n\t    if( $aRound == 0 ) {\n\t\t$y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType];\n\t    }\n\t    else {\n\t\t++$y;\n\t\t$y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType];\n\t    }\n\t    $m=1;$d=1;\n\t}\n\telseif( $aMonthType !== false ) {\n\t    $monthAdj = array(0=>1, 1=>6);\n\t    if( $aRound == 0 ) {\n\t\t$m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType];\n\t\t$d=1;\n\t    }\n\t    else {\n\t\t++$m;\n\t\t$m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType];\n\t\t$d=1;\n\t    }\n\t}\n\telseif( $aDayType !== false ) {\n\t    if( $aDayType == 0 ) {\n\t\tif( $aRound == 1 ) {\n\t\t    //++$d;\n\t\t    $h=23;$i=59;$s=59;\n\t\t}\n\t    }\n\t    else {\n\t\t// Adjust to an even week boundary. \n\t\t$w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat\n\t\tif( true ) { // Adjust to start on Mon\n\t\t    if( $w==0 ) $w=6;\n\t\t    else --$w;\n\t\t}\n\t\tif( $aRound == 0 ) {\n\t\t    $d -= $w;\n\t\t}\n\t\telse {\n\t\t    $d += (7-$w);\n\t\t    $h=23;$i=59;$s=59;\n\t\t}\n\t    }\n\t}\n\treturn mktime($h,$i,$s,$m,$d,$y);\n\t\n    }\n\n//------------------------------------------------------------------------------------------\n// Wrapper for AdjDate that will round a timestamp to an even date rounding\n// it downwards.\n//------------------------------------------------------------------------------------------\n    function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) {\n\treturn $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType);\n    }\n\n//------------------------------------------------------------------------------------------\n// Wrapper for AdjDate that will round a timestamp to an even date rounding\n// it upwards\n//------------------------------------------------------------------------------------------\n    function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) {\n\treturn $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType);\n    }\n\n//------------------------------------------------------------------------------------------\n// Utility Function AdjTime()\n// Description: Will round a given time stamp to an even time according to \n// argument. \n//------------------------------------------------------------------------------------------\n\n    function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) {\n\t$y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime);\n\t$h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime);\n\tif( $aHourType !== false ) {\n\t    $aHourType %= 6;\n\t    $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12);\n\t    if( $aRound == 0 )\n\t\t$h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType];\n\t    else {\n\t\tif( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) {\n\t\t    $h++;\n\t\t}\n\t\t$h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType];\n\t\tif( $h >= 24 ) {\n\t\t    $aTime += 86400;\n\t\t    $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime);\n\t\t    $h -= 24; \n\t\t}\n\t    }\n\t    $i=0;$s=0;\n\t}\n\telseif( $aMinType !== false ) {\n\t    $aMinType %= 5;\n\t    $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30);\n\t    if( $aRound == 0 ) {\n\t\t$i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType];\n\t    }\n\t    else {\n\t\tif( ($i % $minAdj[$aMinType]==0) && $s > 0 ) {\n\t\t    $i++;\n\t\t}\n\t\t$i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType];\n\t\tif( $i >= 60) {\n\t\t    $aTime += 3600;\n\t\t    $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime);\n\t\t    $h = (int)date('H',$aTime); $i = 0;\n\t\t}\n\t    }\n\t    $s=0;\n\t}\n\telseif( $aSecType !== false ) {\n\t    $aSecType %= 5;\n\t    $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30);\n\t    if( $aRound == 0 ) {\n\t\t$s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType];\n\t    }\n\t    else {\n\t\t$s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType];\n\t\tif( $s >= 60) {\n\t\t    $s=0;\n\t\t    $aTime += 60;\n\t\t    $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime);\n\t\t    $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); \n\t\t}\n\t    }\n\t}\n\treturn mktime($h,$i,$s,$m,$d,$y);\n    }\n\n//------------------------------------------------------------------------------------------\n// Wrapper for AdjTime that will round a timestamp to an even time rounding\n// it downwards.\n// Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20\n//------------------------------------------------------------------------------------------\n    function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) {\n\treturn $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType);\n    }\n\n//------------------------------------------------------------------------------------------\n// Wrapper for AdjTime that will round a timestamp to an even time rounding\n// it upwards\n// Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30\n//------------------------------------------------------------------------------------------\n    function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) {\n\treturn $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType);\n    }\n\n//------------------------------------------------------------------------------------------\n// DateAutoScale\n// Autoscale a date axis given start and end time\n// Returns an array ($start,$end,$major,$minor,$format)\n//------------------------------------------------------------------------------------------\n    function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) {\n\t// Format of array\n\t// array ( Decision point,  array( array( Major-scale-step-array ),  \n\t//\t\t\t    array( Minor-scale-step-array ), \n\t//\t\t\t    array( 0=date-adjust, 1=time-adjust, adjustment-alignment) )\n\t//\n\t$scalePoints = \n\t    array(\n\t\t/* Intervall larger than 10 years */\n\t\tSECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2),\n\t\t\t\t    array(SECPERYEAR), \n\t\t\t\t    array(0,YEARADJ_1, 0,YEARADJ_1) ),\n\n\t\t/* Intervall larger than 2 years */\n\t\tSECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), \n\t\t\t\t   array(0,YEARADJ_1) ),\n\n\t\t/* Intervall larger than 90 days (approx 3 month) */\n\t\tSECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY),\n\t\t\t\t   array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), \n\t\t\t\t   array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)),\n\n\t\t/* Intervall larger than 30 days (approx 1 month) */\n\t\tSECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY),\n\t\t\t\t   array(SECPERDAY,SECPERDAY.SECPERDAY,SECPERDAY), \n\t\t\t\t   array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)),\n\n\t\t/* Intervall larger than 7 days */\n\t\tSECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2),\n\t\t\t\t  array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR),\n\t\t\t\t  array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)),\n\n\t\t/* Intervall larger than 1 day */\n\t\tSECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR),\n\t\t\t\tarray(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR),\n\t\t\t\tarray(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)),\n\n\t\t/* Intervall larger than 12 hours */\n\t\tSECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600),\n\t\t\t\t    array(1800,1800,900,300,300),\n\t\t\t\t    array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ),\n\n\t\t/* Intervall larger than 2 hours */\n\t\tSECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300),\n\t\t\t\t   array(1800,900,300,120,60),\n\t\t\t\t   array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ),\n\n\t\t/* Intervall larger than 1 hours */\n\t\tSECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60),\n\t\t\t\t array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ),\n\n\t\t/* Intervall larger than 30 min */\n\t\tSECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN),\n\t\t\t\t   array(300,300,60,10),\n\t\t\t\t   array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)),\n\n\t\t/* Intervall larger than 1 min */\n\t\tSECPERMIN,array(array(SECPERMIN,15,10,5),\n\t\t\t\tarray(15,5,2,1),\n\t\t\t\tarray(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)),\n\n\t\t/* Intervall larger than 10 sec */\n\t\t10,array(array(5,2),\n\t\t\t array(1,1),\n\t\t\t array(1,SECADJ_5, 1,SECADJ_1)),\n\n\t\t/* Intervall larger than 1 sec */\n\t\t1,array(array(1),\n\t\t\tarray(1),\n\t\t\tarray(1,SECADJ_1)),\n\t\t);\n\n\t$ns = count($scalePoints);\n\t// Establish major and minor scale units for the date scale\n\t$diff = $aEndTime - $aStartTime;\n\tif( $diff < 1 ) return false;\n\t$done=false;\n\t$i=0;\n\twhile( ! $done ) {\n\t    if( $diff > $scalePoints[2*$i] ) {\n\t\t// Get major and minor scale for this intervall\n\t\t$scaleSteps = $scalePoints[2*$i+1];\n\t\t$major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)];\n\t\t// Try to find out which minor step looks best\n\t\t$minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)];\n\t\tif( $aAdjust ) {\n\t\t    // Find out how we should align the start and end timestamps\n\t\t    $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1);\n\t\t    if( $scaleSteps[2][$idx] === 0 ) { \n\t\t\t// Use date adjustment\n\t\t\t$adj = $scaleSteps[2][$idx+1]; \n\t\t\tif( $adj >= 30 ) {\n\t\t\t    $start = $this->AdjStartDate($aStartTime,$adj-30);\n\t\t\t    $end   = $this->AdjEndDate($aEndTime,$adj-30);\n\t\t\t}\n\t\t\telseif( $adj >= 20 ) {\n\t\t\t    $start = $this->AdjStartDate($aStartTime,false,$adj-20);\n\t\t\t    $end   = $this->AdjEndDate($aEndTime,false,$adj-20);\n\t\t\t}\n\t\t\telse {\n\t\t\t    $start = $this->AdjStartDate($aStartTime,false,false,$adj);\n\t\t\t    $end   = $this->AdjEndDate($aEndTime,false,false,$adj);\n\t\t\t    // We add 1 second for date adjustment to make sure we end on 00:00 the following day\n\t\t\t    // This makes the final major tick be srawn when we step day-by-day instead of ending\n\t\t\t    // on xx:59:59 which would not draw the final major tick\n\t\t\t    $end++;\t\n\t\t\t}\n\t\t    }\n\t\t    else {\n\t\t\t// Use time adjustment\n\t\t\t$adj = $scaleSteps[2][$idx+1]; \n\t\t\tif( $adj >= 30 ) {\n\t\t\t    $start = $this->AdjStartTime($aStartTime,$adj-30);\n\t\t\t    $end   = $this->AdjEndTime($aEndTime,$adj-30);\n\t\t\t}\n\t\t\telseif( $adj >= 20 ) {\n\t\t\t    $start = $this->AdjStartTime($aStartTime,false,$adj-20);\n\t\t\t    $end   = $this->AdjEndTime($aEndTime,false,$adj-20);\n\t\t\t}\n\t\t\telse {\n\t\t\t    $start = $this->AdjStartTime($aStartTime,false,false,$adj);\n\t\t\t    $end   = $this->AdjEndTime($aEndTime,false,false,$adj);\t\t    \n\t\t\t}\n\t\t    }\n\t\t}\n\t\t// If the overall date span is larger than 1 day ten we show date\n\t\t$format = '';\n\t\tif( ($end-$start) > SECPERDAY ) {\n\t\t    $format = 'Y-m-d ';\n\t\t}\n\t\t// If the major step is less than 1 day we need to whow hours + min\n\t\tif( $major < SECPERDAY ) {\n\t\t    $format .= 'H:i';\n\t\t}\n\t\t// If the major step is less than 1 min we need to show sec\n\t\tif( $major < 60 ) {\n\t\t    $format .= ':s';\n\t\t}\n\t\t$done=true;\n\t    }\n\t    ++$i;\n\t}\n\treturn array($start,$end,$major,$minor,$format);\n    }\n\n    // Overrides the automatic determined date format. Must be a valid date() format string\n    function SetDateFormat($aFormat) {\n\t$this->date_format = $aFormat;\n    }\n\n    function SetDateAlign($aStartAlign,$aEndAlign=false) {\n\tif( $aEndAlign === false ) {\n\t    $aEndAlign=$aStartAlign;\n\t}\n\t$this->iStartAlign = $aStartAlign;\n\t$this->iEndAlign = $aEndAlign;\n    }\n\n    function SetTimeAlign($aStartAlign,$aEndAlign=false) {\n\tif( $aEndAlign === false ) {\n\t    $aEndAlign=$aStartAlign;\n\t}\n\t$this->iStartTimeAlign = $aStartAlign;\n\t$this->iEndTimeAlign = $aEndAlign;\n    }\n\n\n    function AutoScale(&$img,$aStartTime,$aEndTime,$aNumSteps) {\n\tif( $aStartTime == $aEndTime ) {\n\t    // Special case when we only have one data point.\n\t    // Create a small artifical intervall to do the autoscaling\n\t    $aStartTime -= 10;\n\t    $aEndTime += 10;\n\t}\n\t$done=false;\n\t$i=0;\n\twhile( ! $done && $i < 5) {\n\t    list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i);\n\t    $n = floor(($adjend-$adjstart)/$maj);\n\t    if( $n * 1.7 > $aNumSteps ) {\n\t\t$done=true;\n\t    }\n\t    $i++;\n\t}\n\t\n\t/*\n\tif( 0 ) { // DEBUG\n\t    echo \"    Start =\".date(\"Y-m-d H:i:s\",$aStartTime).\"<br>\";\n\t    echo \"    End   =\".date(\"Y-m-d H:i:s\",$aEndTime).\"<br>\";\n\t    echo \"Adj Start =\".date(\"Y-m-d H:i:s\",$adjstart).\"<br>\";\n\t    echo \"Adj End   =\".date(\"Y-m-d H:i:s\",$adjend).\"<p>\";\n\t    echo \"Major = $maj s, \".floor($maj/60).\"min, \".floor($maj/3600).\"h, \".floor($maj/86400).\"day<br>\";\n\t    echo \"Min = $min s, \".floor($min/60).\"min, \".floor($min/3600).\"h, \".floor($min/86400).\"day<br>\";\n\t    echo \"Format=$format<p>\";\n\t}\n\t*/\n\t\n\tif( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) {\n\t    JpGraphError::RaiseL(3001);\n//('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both');\n\t}\n\n\tif( $this->iStartTimeAlign !== false ) {\n\t    if( $this->iStartTimeAlign >= 30 ) {\n\t\t$adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30);\n\t    }\n\t    elseif(  $this->iStartTimeAlign >= 20 ) {\n\t\t$adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20);\n\t    }\n\t    else {\n\t\t$adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign);\n\t    }\n\t}\n\tif( $this->iEndTimeAlign !== false ) {\n\t    if( $this->iEndTimeAlign >= 30 ) {\n\t\t$adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30);\n\t    }\n\t    elseif(  $this->iEndTimeAlign >= 20 ) {\n\t\t$adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20);\n\t    }\n\t    else {\n\t\t$adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign);\n\t    }\n\t}\n\n\n\t\n\tif( $this->iStartAlign !== false ) {\n\t    if( $this->iStartAlign >= 30 ) {\n\t\t$adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30);\n\t    }\n\t    elseif(  $this->iStartAlign >= 20 ) {\n\t\t$adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20);\n\t    }\n\t    else {\n\t\t$adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign);\n\t    }\n\t}\n\tif( $this->iEndAlign !== false ) {\n\t    if( $this->iEndAlign >= 30 ) {\n\t\t$adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30);\n\t    }\n\t    elseif(  $this->iEndAlign >= 20 ) {\n\t\t$adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20);\n\t    }\n\t    else {\n\t\t$adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign);\n\t    }\n\t}\n\t$this->Update($img,$adjstart,$adjend);\n\tif( ! $this->ticks->IsSpecified() )\n\t    $this->ticks->Set($maj,$min);\n\tif( $this->date_format == '' ) \n\t    $this->ticks->SetLabelDateFormat($format);\n\telse \n\t    $this->ticks->SetLabelDateFormat($this->date_format);\n    }\n}\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_error.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_ERROR.PHP\n// Description:\tError plot extension for JpGraph\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_error.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//===================================================\n// CLASS ErrorPlot\n// Description: Error plot with min/max value for\n// each datapoint\n//===================================================\nclass ErrorPlot extends Plot {\n    var $errwidth=2;\n//---------------\n// CONSTRUCTOR\n    function ErrorPlot(&$datay,$datax=false) {\n\t$this->Plot($datay,$datax);\n\t$this->numpoints /= 2;\n    }\n//---------------\n// PUBLIC METHODS\n\t\n    // Gets called before any axis are stroked\n    function PreStrokeAdjust(&$graph) {\n\tif( $this->center ) {\n\t    $a=0.5; $b=0.5;\n\t    ++$this->numpoints;\t\t\t\n\t} else {\n\t    $a=0; $b=0;\n\t}\n\t$graph->xaxis->scale->ticks->SetXLabelOffset($a);\n\t$graph->SetTextScaleOff($b);\t\t\t\t\t\t\n\t//$graph->xaxis->scale->ticks->SupressMinorTickMarks();\n    }\n\t\n    // Method description\n    function Stroke(&$img,&$xscale,&$yscale) {\n\t$numpoints=count($this->coords[0])/2;\n\t$img->SetColor($this->color);\n\t$img->SetLineWeight($this->weight);\t\n\n\tif( isset($this->coords[1]) ) {\n\t    if( count($this->coords[1])!=$numpoints )\n\t\tJpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);\n//(\"Number of X and Y points are not equal. Number of X-points:\".count($this->coords[1]).\" Number of Y-points:$numpoints\");\n\t    else\n\t\t$exist_x = true;\n\t}\n\telse \n\t    $exist_x = false;\n\t\t\n\tfor( $i=0; $i<$numpoints; ++$i) {\n\t    if( $exist_x ) \n\t\t$x=$this->coords[1][$i];\n\t    else \n\t\t$x=$i;\n\n\t    if( !is_numeric($x) ||  \n\t\t!is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) {\n\t\tcontinue;\n\t    }\n\t    \n\t    $xt = $xscale->Translate($x);\n\t    $yt1 = $yscale->Translate($this->coords[0][$i*2]);\n\t    $yt2 = $yscale->Translate($this->coords[0][$i*2+1]);\n\t    $img->Line($xt,$yt1,$xt,$yt2);\n\t    $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1);\n\t    $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2);\n\t}\t\t\t\n\treturn true;\n    }\n} // Class\n\n\n//===================================================\n// CLASS ErrorLinePlot\n// Description: Combine a line and error plot\n// THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR\n// BACKWARD COMPATIBILITY\n//===================================================\nclass ErrorLinePlot extends ErrorPlot {\n    var $line=null;\n//---------------\n// CONSTRUCTOR\n    function ErrorLinePlot(&$datay,$datax=false) {\n\t$this->ErrorPlot($datay,$datax);\n\t// Calculate line coordinates as the average of the error limits\n\t$n = count($datay);\n\tfor($i=0; $i < $n; $i+=2 ) {\n\t    $ly[]=($datay[$i]+$datay[$i+1])/2;\n\t}\t\t\n\t$this->line=new LinePlot($ly,$datax);\n    }\n\n//---------------\n// PUBLIC METHODS\n    function Legend(&$graph) {\n\tif( $this->legend != \"\" )\n\t    $graph->legend->Add($this->legend,$this->color);\n\t$this->line->Legend($graph);\n    }\n\t\t\t\n    function Stroke(&$img,&$xscale,&$yscale) {\n\tparent::Stroke($img,$xscale,$yscale);\n\t$this->line->Stroke($img,$xscale,$yscale);\n    }\n} // Class\n\n\n//===================================================\n// CLASS LineErrorPlot\n// Description: Combine a line and error plot\n//===================================================\nclass LineErrorPlot extends ErrorPlot {\n    var $line=null;\n//---------------\n// CONSTRUCTOR\n    // Data is (val, errdeltamin, errdeltamax)\n    function LineErrorPlot(&$datay,$datax=false) {\n\t$ly=array(); $ey=array();\n\t$n = count($datay);\n\tif( $n % 3 != 0 ) {\n\t    JpGraphError::RaiseL(4002);\n//('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3');\n\t}\n\tfor($i=0; $i < $n; $i+=3 ) {\n\t    $ly[]=$datay[$i];\n\t    $ey[]=$datay[$i]+$datay[$i+1];\n\t    $ey[]=$datay[$i]+$datay[$i+2];\n\t}\t\t\n\t$this->ErrorPlot($ey,$datax);\n\t$this->line=new LinePlot($ly,$datax);\n    }\n\n//---------------\n// PUBLIC METHODS\n    function Legend(&$graph) {\n\tif( $this->legend != \"\" )\n\t    $graph->legend->Add($this->legend,$this->color);\n\t$this->line->Legend($graph);\n    }\n\t\t\t\n    function Stroke(&$img,&$xscale,&$yscale) {\n\tparent::Stroke($img,$xscale,$yscale);\n\t$this->line->Stroke($img,$xscale,$yscale);\n    }\n} // Class\n\n\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_flags.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_FLAGS.PHP\n// Description:\tClass Jpfile. Handles plotmarks\n// Created: \t2003-06-28\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_flags.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n//------------------------------------------------------------\n// Defines for the different basic sizes of flags\n//------------------------------------------------------------\nDEFINE('FLAGSIZE1',1);\nDEFINE('FLAGSIZE2',2);\nDEFINE('FLAGSIZE3',3);\nDEFINE('FLAGSIZE4',4);\n\nclass FlagImages {\n\n    var $iCountryNameMap = array(\n    'Afghanistan' => 'afgh',\n    'Republic of Angola' => 'agla',\n    'Republic of Albania' => 'alba',\n    'Alderney' => 'alde',\n    'Democratic and Popular Republic of Algeria' => 'alge',\n    'Territory of American Samoa' => 'amsa',\n    'Principality of Andorra' => 'andr',\n    'British Overseas Territory of Anguilla' => 'angu',\n    'Antarctica' => 'anta',\n    'Argentine Republic' => 'arge',\n    'League of Arab States' => 'arle',\n    'Republic of Armenia' => 'arme',\n    'Aruba' => 'arub',\n    'Commonwealth of Australia' => 'astl',\n    'Republic of Austria' => 'aust',\n    'Azerbaijani Republic' => 'azer',\n    'British Antarctic Territory' => 'bant',\n    'Kingdom of Belgium' => 'belg',\n    'British Overseas Territory of Bermuda' => 'berm',\n    'Commonwealth of the Bahamas' => 'bhms',\n    'Kingdom of Bahrain' => 'bhrn',\n    'Republic of Belarus' => 'blru',\n    'Republic of Bolivia' => 'blva',\n    'Belize' => 'blze',\n    'Republic of Benin' => 'bnin',\n    'Republic of Botswana' => 'bots',\n    'Federative Republic of Brazil' => 'braz',\n    'Barbados' => 'brbd',\n    'British Indian Ocean Territory' => 'brin',\n    'Brunei Darussalam' => 'brun',\n    'Republic of Burkina' => 'bufa',\n    'Republic of Bulgaria' => 'bulg',\n    'Republic of Burundi' => 'buru',\n    'Overseas Territory of the British Virgin Islands' => 'bvis',\n    'Central African Republic' => 'cafr',\n    'Kingdom of Cambodia' => 'camb',\n    'Republic of Cameroon' => 'came',\n    'Dominion of Canada' => 'cana',\n    'Caribbean Community' => 'cari',\n    'Republic of Cape Verde' => 'cave',\n    'Republic of Chad' => 'chad',\n    'Republic of Chile' => 'chil',\n    'Peoples Republic of China' => 'chin',\n    'Territory of Christmas Island' => 'chms',\n    'Commonwealth of Independent States' => 'cins',\n    'Cook Islands' => 'ckis',\n    'Republic of Colombia' => 'clmb',\n    'Territory of Cocos Islands' => 'cois',\n    'Commonwealth' => 'comn',\n    'Union of the Comoros' => 'como',\n    'Republic of the Congo' => 'cong',\n    'Republic of Costa Rica' => 'corc',\n    'Republic of Croatia' => 'croa',\n    'Republic of Cuba' => 'cuba',\n    'British Overseas Territory of the Cayman Islands' => 'cyis',\n    'Republic of Cyprus' => 'cypr',\n    'The Czech Republic' => 'czec',\n    'Kingdom of Denmark' => 'denm',\n    'Republic of Djibouti' => 'djib',\n    'Commonwealth of Dominica' => 'domn',\n    'Dominican Republic' => 'dore',\n    'Republic of Ecuador' => 'ecua',\n    'Arab Republic of Egypt' => 'egyp',\n    'Republic of El Salvador' => 'elsa',\n    'England' => 'engl',\n    'Republic of Equatorial Guinea' => 'eqgu',\n    'State of Eritrea' => 'erit',\n    'Republic of Estonia' => 'estn',\n    'Ethiopia' => 'ethp',\n    'European Union' => 'euun',\n    'British Overseas Territory of the Falkland Islands' => 'fais',\n    'International Federation of Vexillological Associations' => 'fiav',\n    'Republic of Fiji' => 'fiji',\n    'Republic of Finland' => 'finl',\n    'Territory of French Polynesia' => 'fpol',\n    'French Republic' => 'fran',\n    'Overseas Department of French Guiana' => 'frgu',\n    'Gabonese Republic' => 'gabn',\n    'Republic of the Gambia' => 'gamb',\n    'Republic of Georgia' => 'geor',\n    'Federal Republic of Germany' => 'germ',\n    'Republic of Ghana' => 'ghan',\n    'Gibraltar' => 'gibr',\n    'Hellenic Republic' => 'grec',\n    'State of Grenada' => 'gren',\n    'Overseas Department of Guadeloupe' => 'guad',\n    'Territory of Guam' => 'guam',\n    'Republic of Guatemala' => 'guat',\n    'The Bailiwick of Guernsey' => 'guer',\n    'Republic of Guinea' => 'guin',\n    'Republic of Haiti' => 'hait',\n    'Hong Kong Special Administrative Region' => 'hokn',\n    'Republic of Honduras' => 'hond',\n    'Republic of Hungary' => 'hung',\n    'Republic of Iceland' => 'icel',\n    'International Committee of the Red Cross' => 'icrc',\n    'Republic of India' => 'inda',\n    'Republic of Indonesia' => 'indn',\n    'Republic of Iraq' => 'iraq',\n    'Republic of Ireland' => 'irel',\n    'Organization of the Islamic Conference' => 'isco',\n    'Isle of Man' => 'isma',\n    'State of Israel' => 'isra',\n    'Italian Republic' => 'ital',\n    'Jamaica' => 'jama',\n    'Japan' => 'japa',\n    'The Bailiwick of Jersey' => 'jers',\n    'Hashemite Kingdom of Jordan' => 'jord',\n    'Republic of Kazakhstan' => 'kazk',\n    'Republic of Kenya' => 'keny',\n    'Republic of Kiribati' => 'kirb',\n    'State of Kuwait' => 'kuwa',\n    'Kyrgyz Republic' => 'kyrg',\n    'Republic of Latvia' => 'latv',\n    'Lebanese Republic' => 'leba',\n    'Kingdom of Lesotho' => 'lest',\n    'Republic of Liberia' => 'libe',\n    'Principality of Liechtenstein' => 'liec',\n    'Republic of Lithuania' => 'lith',\n    'Grand Duchy of Luxembourg' => 'luxe',\n    'Macao Special Administrative Region' => 'maca',\n    'Republic of Macedonia' => 'mace',\n    'Republic of Madagascar' => 'mada',\n    'Republic of the Marshall Islands' => 'mais',\n    'Republic of Mali' => 'mali',\n    'Federation of Malaysia' => 'mals',\n    'Republic of Malta' => 'malt',\n    'Republic of Malawi' => 'malw',\n    'Overseas Department of Martinique' => 'mart',\n    'Islamic Republic of Mauritania' => 'maur',\n    'Territorial Collectivity of Mayotte' => 'mayt',\n    'United Mexican States' => 'mexc',\n    'Federated States of Micronesia' => 'micr',\n    'Midway Islands' => 'miis',\n    'Republic of Moldova' => 'mold',\n    'Principality of Monaco' => 'mona',\n    'Republic of Mongolia' => 'mong',\n    'British Overseas Territory of Montserrat' => 'mont',\n    'Kingdom of Morocco' => 'morc',\n    'Republic of Mozambique' => 'moza',\n    'Republic of Mauritius' => 'mrts',\n    'Union of Myanmar' => 'myan',\n    'Republic of Namibia' => 'namb',\n    'North Atlantic Treaty Organization' => 'nato',\n    'Republic of Nauru' => 'naur',\n    'Turkish Republic of Northern Cyprus' => 'ncyp',\n    'Netherlands Antilles' => 'nean',\n    'Kingdom of Nepal' => 'nepa',\n    'Kingdom of the Netherlands' => 'neth',\n    'Territory of Norfolk Island' => 'nfis',\n    'Federal Republic of Nigeria' => 'ngra',\n    'Republic of Nicaragua' => 'nica',\n    'Republic of Niger' => 'nigr',\n    'Niue' => 'niue',\n    'Commonwealth of the Northern Mariana Islands' => 'nmar',\n    'Province of Northern Ireland' => 'noir',\n    'Nordic Council' => 'nord',\n    'Kingdom of Norway' => 'norw',\n    'Territory of New Caledonia and Dependencies' => 'nwca',\n    'New Zealand' => 'nwze',\n    'Organization of American States' => 'oast',\n    'Organization of African Unity' => 'oaun',\n    'International Olympic Committee' => 'olym',\n    'Sultanate of Oman' => 'oman',\n    'Islamic Republic of Pakistan' => 'paks',\n    'Republic of Palau' => 'pala',\n    'Independent State of Papua New Guinea' => 'pang',\n    'Republic of Paraguay' => 'para',\n    'Republic of Peru' => 'peru',\n    'Republic of the Philippines' => 'phil',\n    'British Overseas Territory of the Pitcairn Islands' => 'piis',\n    'Republic of Poland' => 'pola',\n    'Republic of Portugal' => 'port',\n    'Commonwealth of Puerto Rico' => 'purc',\n    'State of Qatar' => 'qata',\n    'Russian Federation' => 'russ',\n    'Republic of Rwanda' => 'rwan',\n    'Kingdom of Saudi Arabia' => 'saar',\n    'Republic of San Marino' => 'sama',\n    'Nordic Sami Conference' => 'sami',\n    'Sark' => 'sark',\n    'Scotland' => 'scot',\n    'Principality of Seborga' => 'sebo',\n    'Republic of Sierra Leone' => 'sile',\n    'Republic of Singapore' => 'sing',\n    'Republic of Korea' => 'skor',\n    'Republic of Slovenia' => 'slva',\n    'Somali Republic' => 'smla',\n    'Republic of Somaliland' => 'smld',\n    'Republic of South Africa' => 'soaf',\n    'Solomon Islands' => 'sois',\n    'Kingdom of Spain' => 'span',\n    'Secretariat of the Pacific Community' => 'spco',\n    'Democratic Socialist Republic of Sri Lanka' => 'srla',\n    'Saint Lucia' => 'stlu',\n    'Republic of the Sudan' => 'suda',\n    'Republic of Suriname' => 'surn',\n    'Slovak Republic' => 'svka',\n    'Kingdom of Sweden' => 'swdn',\n    'Swiss Confederation' => 'swit',\n    'Syrian Arab Republic' => 'syra',\n    'Kingdom of Swaziland' => 'szld',\n    'Republic of China' => 'taiw',\n    'Taiwan' => 'taiw',\n    'Republic of Tajikistan' => 'tajk',\n    'United Republic of Tanzania' => 'tanz',\n    'Kingdom of Thailand' => 'thal',\n    'Autonomous Region of Tibet' => 'tibe',\n    'Turkmenistan' => 'tkst',\n    'Togolese Republic' => 'togo',\n    'Tokelau' => 'toke',\n    'Kingdom of Tonga' => 'tong',\n    'Tristan da Cunha' => 'trdc',\n    'Tromelin' => 'tris',\n    'Republic of Tunisia' => 'tuns',\n    'Republic of Turkey' => 'turk',\n    'Tuvalu' => 'tuva',\n    'United Arab Emirates' => 'uaem',\n    'Republic of Uganda' => 'ugan',\n    'Ukraine' => 'ukrn',\n    'United Kingdom of Great Britain' => 'unkg',\n    'United Nations' => 'unna',\n    'United States of America' => 'unst',\n    'Oriental Republic of Uruguay' => 'urgy',\n    'Virgin Islands of the United States' => 'usvs',\n    'Republic of Uzbekistan' => 'uzbk',\n    'State of the Vatican City' => 'vacy',\n    'Republic of Vanuatu' => 'vant',\n    'Bolivarian Republic of Venezuela' => 'venz',\n    'Republic of Yemen' => 'yemn',\n    'Democratic Republic of Congo' => 'zare',\n    'Republic of Zimbabwe' => 'zbwe' ) ;\n\n\n    var $iFlagCount = -1;\n    var $iFlagSetMap = array(\n\tFLAGSIZE1 => 'flags_thumb35x35',\n\tFLAGSIZE2 => 'flags_thumb60x60',\n\tFLAGSIZE3 => 'flags_thumb100x100',\n\tFLAGSIZE4 => 'flags'\n\t);\n\n    var $iFlagData ;\n    var $iOrdIdx=array();\n\n    function FlagImages($aSize=FLAGSIZE1) {\n\tswitch($aSize) {\n\t    case FLAGSIZE1 :\n\t    case FLAGSIZE2 :\n\t    case FLAGSIZE3 :\n\t    case FLAGSIZE4 :\n\t\t$file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat';\n\t\t$fp = fopen($file,'rb');\n\t\t$rawdata = fread($fp,filesize($file));\n\t\t$this->iFlagData = unserialize($rawdata);\n\t    break;\n\t    default:\n\t\tJpGraphError::RaiseL(5001,$aSize);\n//('Unknown flag size. ('.$aSize.')');\n\t}\n\t$this->iFlagCount = count($this->iCountryNameMap);\n    }\n\n    function GetNum() {\n\treturn $this->iFlagCount;\n    }\n\n    function GetImgByName($aName,&$outFullName) {\n\t$idx = $this->GetIdxByName($aName,$outFullName);\n\treturn $this->GetImgByIdx($idx);\n    }\n\n    function GetImgByIdx($aIdx) {\n\tif( array_key_exists($aIdx,$this->iFlagData) ) {\n\t    $d = $this->iFlagData[$aIdx][1];   \n\t    return Image::CreateFromString($d);   \n\t}\n\telse {\n\t    JpGraphError::RaiseL(5002,$aIdx);\n//(\"Flag index \\\"$aIdx\\\" does not exist.\");\n\t}\n    }\n\n    function GetIdxByOrdinal($aOrd,&$outFullName) {\n\t$aOrd--;\n\t$n = count($this->iOrdIdx);\n\tif( $n == 0 ) {\n\t    reset($this->iCountryNameMap);\n\t    $this->iOrdIdx=array();\n\t    $i=0;\n\t    while( list($key,$val) = each($this->iCountryNameMap) ) {\n\t\t$this->iOrdIdx[$i++] = array($val,$key);\n\t    }\n\t    $tmp=$this->iOrdIdx[$aOrd];\n\t    $outFullName = $tmp[1];\n\t    return $tmp[0];\n\t    \n\t}\n\telseif( $aOrd >= 0 && $aOrd < $n ) {\n\t    $tmp=$this->iOrdIdx[$aOrd];\n\t    $outFullName = $tmp[1];\n\t    return $tmp[0];\n\t}\n\telse {\n\t    JpGraphError::RaiseL(5003,$aOrd);\n//('Invalid ordinal number specified for flag index.');\n\t}\n    }\n\n    function GetIdxByName($aName,&$outFullName) {\n\n\tif( is_integer($aName) ) {\n\t    $idx = $this->GetIdxByOrdinal($aName,$outFullName);\n\t    return $idx;\n\t}\n\n\t$found=false;\n\t$aName = strtolower($aName);\n\t$nlen = strlen($aName);\n\treset($this->iCountryNameMap);\n\t// Start by trying to match exact index name\n\twhile( list($key,$val) = each($this->iCountryNameMap) ) {\n\t    if( $nlen == strlen($val) && $val == $aName )  {\n\t\t$found=true;\n\t\tbreak;\n\t    }\n\t}\n\tif( !$found ) {\n\t    reset($this->iCountryNameMap);\n\t    // If the exact index doesn't work try a (partial) full name\n\t    while( list($key,$val) = each($this->iCountryNameMap) ) {\n\t\tif( strpos(strtolower($key), $aName) !== false ) {\n\t\t    $found=true;\n\t\t    break;\n\t\t}\n\t    }\n\t}\n\tif( $found ) {\n\t    $outFullName = $key;\n\t    return $val;   \n\t}\n\telse { \n\t    JpGraphError::RaiseL(5004,$aName);\n//(\"The (partial) country name \\\"$aName\\\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \\\"usa\\\" try \\\"united states\\\".\");\n\t}\n    }\n}\n\n\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_gantt.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_GANTT.PHP\n// Description:\tJpGraph Gantt plot extension\n// Created: \t2001-11-12\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_gantt.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nrequire_once('jpgraph_plotband.php'); \nrequire_once('jpgraph_iconplot.php'); \nrequire_once('jpgraph_plotmark.inc');\n\n// Maximum size for Automatic Gantt chart\nDEFINE('MAX_GANTTIMG_SIZE_W',4000);\nDEFINE('MAX_GANTTIMG_SIZE_H',5000);\n\n// Scale Header types\nDEFINE(\"GANTT_HDAY\",1);\nDEFINE(\"GANTT_HWEEK\",2);\nDEFINE(\"GANTT_HMONTH\",4);\nDEFINE(\"GANTT_HYEAR\",8);\nDEFINE(\"GANTT_HHOUR\",16);\nDEFINE(\"GANTT_HMIN\",32);\n\n// Bar patterns\nDEFINE(\"GANTT_RDIAG\",BAND_RDIAG);\t// Right diagonal lines\nDEFINE(\"GANTT_LDIAG\",BAND_LDIAG); // Left diagonal lines\nDEFINE(\"GANTT_SOLID\",BAND_SOLID); // Solid one color\nDEFINE(\"GANTT_VLINE\",BAND_VLINE); // Vertical lines\nDEFINE(\"GANTT_HLINE\",BAND_HLINE);  // Horizontal lines\nDEFINE(\"GANTT_3DPLANE\",BAND_3DPLANE);  // \"3D\" Plane\nDEFINE(\"GANTT_HVCROSS\",BAND_HVCROSS);  // Vertical/Hor crosses\nDEFINE(\"GANTT_DIAGCROSS\",BAND_DIAGCROSS); // Diagonal crosses\n\n// Conversion constant\nDEFINE(\"SECPERDAY\",3600*24);\n\n// Locales. ONLY KEPT FOR BACKWARDS COMPATIBILITY\n// You should use the proper locale strings directly \n// from now on. \nDEFINE(\"LOCALE_EN\",\"en_UK\");\nDEFINE(\"LOCALE_SV\",\"sv_SE\");\n\n// Layout of bars\nDEFINE(\"GANTT_EVEN\",1);\nDEFINE(\"GANTT_FROMTOP\",2);\n\n// Style for minute header\nDEFINE(\"MINUTESTYLE_MM\",0);\t\t// 15\nDEFINE(\"MINUTESTYLE_CUSTOM\",2);\t\t// Custom format\n\n\n// Style for hour header\nDEFINE(\"HOURSTYLE_HM24\",0);\t\t// 13:10\nDEFINE(\"HOURSTYLE_HMAMPM\",1);\t\t// 1:10pm\nDEFINE(\"HOURSTYLE_H24\",2);\t\t// 13\nDEFINE(\"HOURSTYLE_HAMPM\",3);\t\t// 1pm\nDEFINE(\"HOURSTYLE_CUSTOM\",4);\t\t// User defined\n\n// Style for day header\nDEFINE(\"DAYSTYLE_ONELETTER\",0);\t\t// \"M\"\nDEFINE(\"DAYSTYLE_LONG\",1);\t\t// \"Monday\"\nDEFINE(\"DAYSTYLE_LONGDAYDATE1\",2);\t// \"Monday 23 Jun\"\nDEFINE(\"DAYSTYLE_LONGDAYDATE2\",3);\t// \"Monday 23 Jun 2003\"\nDEFINE(\"DAYSTYLE_SHORT\",4);\t\t// \"Mon\"\nDEFINE(\"DAYSTYLE_SHORTDAYDATE1\",5);\t// \"Mon 23/6\"\nDEFINE(\"DAYSTYLE_SHORTDAYDATE2\",6);\t// \"Mon 23 Jun\"\nDEFINE(\"DAYSTYLE_SHORTDAYDATE3\",7);\t// \"Mon 23\"\nDEFINE(\"DAYSTYLE_SHORTDATE1\",8);\t// \"23/6\"\nDEFINE(\"DAYSTYLE_SHORTDATE2\",9);\t// \"23 Jun\"\nDEFINE(\"DAYSTYLE_SHORTDATE3\",10);\t// \"Mon 23\"\nDEFINE(\"DAYSTYLE_SHORTDATE4\",11);\t// \"23\"\nDEFINE(\"DAYSTYLE_CUSTOM\",12);\t\t// \"M\"\n\n// Styles for week header\nDEFINE(\"WEEKSTYLE_WNBR\",0);\nDEFINE(\"WEEKSTYLE_FIRSTDAY\",1);\nDEFINE(\"WEEKSTYLE_FIRSTDAY2\",2);\nDEFINE(\"WEEKSTYLE_FIRSTDAYWNBR\",3);\nDEFINE(\"WEEKSTYLE_FIRSTDAY2WNBR\",4);\n\n// Styles for month header\nDEFINE(\"MONTHSTYLE_SHORTNAME\",0);\nDEFINE(\"MONTHSTYLE_LONGNAME\",1);\nDEFINE(\"MONTHSTYLE_LONGNAMEYEAR2\",2);\nDEFINE(\"MONTHSTYLE_SHORTNAMEYEAR2\",3);\nDEFINE(\"MONTHSTYLE_LONGNAMEYEAR4\",4);\nDEFINE(\"MONTHSTYLE_SHORTNAMEYEAR4\",5);\nDEFINE(\"MONTHSTYLE_FIRSTLETTER\",6);\n\n\n// Types of constrain links\nDEFINE('CONSTRAIN_STARTSTART',0);\nDEFINE('CONSTRAIN_STARTEND',1);\nDEFINE('CONSTRAIN_ENDSTART',2);\nDEFINE('CONSTRAIN_ENDEND',3);\n\n// Arrow direction for constrain links\nDEFINE('ARROW_DOWN',0);\nDEFINE('ARROW_UP',1);\nDEFINE('ARROW_LEFT',2);\nDEFINE('ARROW_RIGHT',3);\n\n// Arrow type for constrain type\nDEFINE('ARROWT_SOLID',0);\nDEFINE('ARROWT_OPEN',1);\n\n// Arrow size for constrain lines\nDEFINE('ARROW_S1',0);\nDEFINE('ARROW_S2',1);\nDEFINE('ARROW_S3',2);\nDEFINE('ARROW_S4',3);\nDEFINE('ARROW_S5',4);\n\n// Activity types for use with utility method CreateSimple()\nDEFINE('ACTYPE_NORMAL',0);\nDEFINE('ACTYPE_GROUP',1);\nDEFINE('ACTYPE_MILESTONE',2);\n\nDEFINE('ACTINFO_3D',1);\nDEFINE('ACTINFO_2D',0);\n\n\n// Check if array_fill() exists\nif (!function_exists('array_fill')) {\n    function array_fill($iStart, $iLen, $vValue) {\n\t$aResult = array();\n\tfor ($iCount = $iStart; $iCount < $iLen + $iStart; $iCount++) {\n\t    $aResult[$iCount] = $vValue;\n\t}\n\treturn $aResult;\n    }\n}\n\n//===================================================\n// CLASS GanttActivityInfo\n// Description: \n//===================================================\nclass GanttActivityInfo {\n    var $iColor='black';\n    var $iBackgroundColor='lightgray';\n    var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10,$iFontColor='black';\n    var $iTitles=array();\n    var $iWidth=array(),$iHeight=-1;\n    var $iLeftColMargin=4,$iRightColMargin=1,$iTopColMargin=1,$iBottomColMargin=3;\n    var $iTopHeaderMargin = 4;\n    var $vgrid = null;\n    var $iStyle=1;\n    var $iShow=true;\n    var $iHeaderAlign='center';\n\n    function GanttActivityInfo() {\n\t$this->vgrid = new LineProperty();\n    }\n\n    function Hide($aF=true) {\n\t$this->iShow=!$aF;\n    }\n\n    function Show($aF=true) {\n\t$this->iShow=$aF;\n    }\n\n    // Specify font\n    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {\n\t$this->iFFamily = $aFFamily;\n\t$this->iFStyle\t = $aFStyle;\n\t$this->iFSize\t = $aFSize;\n    }\n\n    function SetStyle($aStyle) {\n\t$this->iStyle = $aStyle;\n    }\n\n    function SetColumnMargin($aLeft,$aRight) {\n\t$this->iLeftColMargin = $aLeft;\n\t$this->iRightColMargin = $aRight;\n    }\n\n    function SetFontColor($aFontColor) {\n\t$this->iFontColor = $aFontColor;\n    }\n\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\n    function SetBackgroundColor($aColor) {\n\t$this->iBackgroundColor = $aColor;\n    }\n\n    function SetColTitles($aTitles,$aWidth=null) {\n\t$this->iTitles = $aTitles;\n\t$this->iWidth = $aWidth;\n    }\n\n    function SetMinColWidth($aWidths) {\n\t$n = min(count($this->iTitles),count($aWidths));\n\tfor($i=0; $i < $n; ++$i ) {\n\t    if( !empty($aWidths[$i]) ) {\n\t\tif( empty($this->iWidth[$i]) ) {\n\t\t    $this->iWidth[$i] = $aWidths[$i];\n\t\t}\n\t\telse {\n\t\t    $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]);\n\t\t}\n\t    }\n\t}\n    }\n\n    function GetWidth(&$aImg) {\n\t$txt = new TextProperty();\n\t$txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\t$n = count($this->iTitles) ;\n\t$rm=$this->iRightColMargin;\n\t$w = 0;\n\tfor($h=0, $i=0; $i < $n; ++$i ) {\n\t    $w += $this->iLeftColMargin;\n\t    $txt->Set($this->iTitles[$i]);\n\t    if( !empty($this->iWidth[$i]) ) {\n\t\t$w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]);\n\t    }\n\t    else {\n\t\t$w1 = $txt->GetWidth($aImg)+$rm;\n\t    }\n\t    $this->iWidth[$i] = $w1;\n\t    $w += $w1;\n\t    $h = max($h,$txt->GetHeight($aImg));\n\t}\n\t$this->iHeight = $h+$this->iTopHeaderMargin;\n        $txt='';\n\treturn $w;\n    }\n    \n    function GetColStart(&$aImg,&$ioStart,$aAddLeftMargin=false) {\n\t$n = count($this->iTitles) ;\n\t$adj = $aAddLeftMargin ? $this->iLeftColMargin : 0;\n\t$ioStart=array($aImg->left_margin+$adj);\n\tfor( $i=1; $i < $n; ++$i ) {\n\t    $ioStart[$i] = $ioStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1];\n\t}\n    }\n    \n    // Adjust headers left, right or centered\n    function SetHeaderAlign($aAlign) {\n\t$this->iHeaderAlign=$aAlign;\n    }\n\n    function Stroke(&$aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) {\n\n\tif( !$this->iShow ) return;\n\n\t$txt = new TextProperty();\n\t$txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\t$txt->SetColor($this->iFontColor);\n\t$txt->SetAlign($this->iHeaderAlign,'top');\n\t$n=count($this->iTitles);\n\n\tif( $n == 0 ) \n\t    return;\n\t\n\t$x = $aXLeft;\n\t$h = $this->iHeight;\n\t$yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ;\n\n\tif( $h < 0 ) {\n\t    JpGraphError::RaiseL(6001);\n//('Internal error. Height for ActivityTitles is < 0');\n\t}\n\n\t$aImg->SetLineWeight(1);\n\t// Set background color\n\t$aImg->SetColor($this->iBackgroundColor);\n\t$aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1);\n\n\tif( $this->iStyle == 1 ) {\n\t    // Make a 3D effect\n\t    $aImg->SetColor('white');\n\t    $aImg->Line($aXLeft,$yTop+1,\n\t\t\t$aXRight,$yTop+1);\n\t}\n\t\n\tfor($i=0; $i < $n; ++$i ) {\n\t    if( $this->iStyle == 1 ) {\n\t\t// Make a 3D effect\n\t\t$aImg->SetColor('white');\n\t\t$aImg->Line($x+1,$yTop,$x+1,$aYBottom);\n\t    }\n\t    $x += $this->iLeftColMargin;\n\t    $txt->Set($this->iTitles[$i]);\n\t    \n\t    // Adjust the text anchor position according to the choosen alignment\n\t    $xp = $x;\n\t    if( $this->iHeaderAlign == 'center' ) {\n\t\t$xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2;\n\t    }\n\t    elseif( $this->iHeaderAlign == 'right' ) {\n\t\t$xp = $x +$this->iWidth[$i]-$this->iRightColMargin;\n\t    }\n\t\t    \n\t    $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin);\n\t    $x += $this->iWidth[$i];\n\t    if( $i < $n-1 ) {\n\t\t$aImg->SetColor($this->iColor);\n\t\t$aImg->Line($x,$yTop,$x,$aYBottom);\n\t    }\n\t}\n\n\t$aImg->SetColor($this->iColor);\n\t$aImg->Line($aXLeft,$yTop, $aXRight,$yTop);\n\n\t// Stroke vertical column dividers\n\t$cols=array();\n\t$this->GetColStart($aImg,$cols);\n\t$n=count($cols);\n\tfor( $i=1; $i < $n; ++$i ) {\n\t    $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i],\n\t\t\t\t    $aImg->height - $aImg->bottom_margin);\n\t}\n    }\n}\n\n\n//===================================================\n// CLASS GanttGraph\n// Description: Main class to handle gantt graphs\n//===================================================\nclass GanttGraph extends Graph {\n    var $scale;\t\t\t\t\t\t\t// Public accessible\n    var $iObj=array();\t\t\t\t// Gantt objects\n    var $iLabelHMarginFactor=0.2;\t// 10% margin on each side of the labels\n    var $iLabelVMarginFactor=0.4;\t// 40% margin on top and bottom of label\n    var $iLayout=GANTT_FROMTOP;\t// Could also be GANTT_EVEN\n    var $iSimpleFont = FF_FONT1,$iSimpleFontSize=11;\n    var $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red';\n    var $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen';\n    var $iSimpleProgressStyle=GANTT_SOLID;\n    var $hgrid=null;\n//---------------\n// CONSTRUCTOR\t\n    // Create a new gantt graph\n    function GanttGraph($aWidth=0,$aHeight=0,$aCachedName=\"\",$aTimeOut=0,$aInline=true) {\n\n\t// Backward compatibility\n\tif( $aWidth == -1 ) $aWidth=0;\n\tif( $aHeight == -1 ) $aHeight=0;\n\n\tif( $aWidth<  0 || $aHeight < 0 ) {\n\t    JpgraphError::RaiseL(6002);\n//(\"You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.\");\n\t}\n\tGraph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline);\t\t\n\t$this->scale = new GanttScale($this->img);\n\n\t// Default margins\n\t$this->img->SetMargin(15,17,25,15);\n\n\t$this->hgrid = new HorizontalGridLine();\n\t\t\n\t$this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY);\n\t$this->SetBox();\n    }\n\t\n//---------------\n// PUBLIC METHODS\n\n    // \n\n    function SetSimpleFont($aFont,$aSize) {\n\t$this->iSimpleFont = $aFont;\n\t$this->iSimpleFontSize = $aSize;\n    }\n\n    function SetSimpleStyle($aBand,$aColor,$aBkgColor) {\n\t$this->iSimpleStyle = $aBand;\n\t$this->iSimpleColor = $aColor;\n\t$this->iSimpleBkgColor = $aBkgColor;\n    }\n\n    // A utility function to help create basic Gantt charts\n    function CreateSimple($data,$constrains=array(),$progress=array()) {\n\t$num = count($data);\n\tfor( $i=0; $i < $num; ++$i) {\n\t    switch( $data[$i][1] ) {\n\t\tcase ACTYPE_GROUP:\n\t\t    // Create a slightly smaller height bar since the\n\t\t    // \"wings\" at the end will make it look taller\n\t\t    $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8);\n\t\t    $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize);\t\t\n\t\t    $a->rightMark->Show();\n\t\t    $a->rightMark->SetType(MARK_RIGHTTRIANGLE);\n\t\t    $a->rightMark->SetWidth(8);\n\t\t    $a->rightMark->SetColor('black');\n\t\t    $a->rightMark->SetFillColor('black');\n\t    \n\t\t    $a->leftMark->Show();\n\t\t    $a->leftMark->SetType(MARK_LEFTTRIANGLE);\n\t\t    $a->leftMark->SetWidth(8);\n\t\t    $a->leftMark->SetColor('black');\n\t\t    $a->leftMark->SetFillColor('black');\n\t    \n\t\t    $a->SetPattern(BAND_SOLID,'black');\n\t\t    $csimpos = 6;\n\t\t    break;\n\t\t\n\t\tcase ACTYPE_NORMAL:\n\t\t    $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10);\n\t\t    $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);\n\t\t    $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor);\n\t\t    $a->SetFillColor($this->iSimpleBkgColor);\n\t\t    // Check if this activity should have a constrain line\n\t\t    $n = count($constrains);\n\t\t    for( $j=0; $j < $n; ++$j ) {\n\t\t\tif( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) {\n\t\t\t    JpGraphError::RaiseL(6003,$j);\n//(\"Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)\");\t \n\t\t\t}\n\t\t\tif( $constrains[$j][0]==$data[$i][0] ) {\n\t\t\t    $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID);    \n\t\t\t}\n\t\t    }\n\n\t\t    // Check if this activity have a progress bar\n\t\t    $n = count($progress);\n\t\t    for( $j=0; $j < $n; ++$j ) {\n\t\t\t\n\t\t\tif( empty($progress[$j]) || (count($progress[$j]) != 2) ) {\n\t\t\t    JpGraphError::RaiseL(6004,$j);\n//(\"Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)\");\t\n\t\t\t}\n\t\t\tif( $progress[$j][0]==$data[$i][0] ) {\n\t\t\t    $a->progress->Set($progress[$j][1]);\n\t\t\t    $a->progress->SetHeight(0.5);\n\t\t\t    $a->progress->SetPattern($this->iSimpleProgressStyle,\n\t\t\t\t\t\t     $this->iSimpleProgressColor);\n\t\t\t    $a->progress->SetFillColor($this->iSimpleProgressBkgColor);\n\t\t\t    //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]);\n\t\t\t    break;\n\t\t\t}\n\t\t    }\n\t\t    $csimpos = 6;\n\t\t    break;\n\n\t\tcase ACTYPE_MILESTONE:\n\t\t    $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]);\n\t\t    $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);\n\t\t    $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);\n\t\t    $csimpos = 5;\n\t\t    break;\n\t\tdefault:\n\t\t    die('Unknown activity type');\n\t\t    break;\n\t    }\n\n\t    // Setup caption\n\t    $a->caption->Set($data[$i][$csimpos-1]);\n\n\t    // Check if this activity should have a CSIM target?\n\t    if( !empty($data[$i][$csimpos]) ) {\n\t\t$a->SetCSIMTarget($data[$i][$csimpos]);\n\t\t$a->SetCSIMAlt($data[$i][$csimpos+1]);\n\t    }\n\t    if( !empty($data[$i][$csimpos+2]) ) {\n\t\t$a->title->SetCSIMTarget($data[$i][$csimpos+2]);\n\t\t$a->title->SetCSIMAlt($data[$i][$csimpos+3]);\n\t    }\n\n\t    $this->Add($a);\n\t}\n    }\n\n\t\n    // Set what headers should be shown\n    function ShowHeaders($aFlg) {\n\t$this->scale->ShowHeaders($aFlg);\n    }\n\t\n    // Specify the fraction of the font height that should be added \n    // as vertical margin\n    function SetLabelVMarginFactor($aVal) {\n\t$this->iLabelVMarginFactor = $aVal;\n    }\n\n    // Synonym to the method above\n    function SetVMarginFactor($aVal) {\n\t$this->iLabelVMarginFactor = $aVal;\n    }\n\t\n\t\n    // Add a new Gantt object\n    function Add($aObject) {\n\tif( is_array($aObject) && count($aObject) > 0 ) {\n\t    $cl = $aObject[0];\n\t    if( is_a($cl,'IconPlot') ) {\n\t\t$this->AddIcon($aObject);\n\t    }\n\t    else {\n\t\t$n = count($aObject);\n\t\tfor($i=0; $i < $n; ++$i)\n\t\t    $this->iObj[] = $aObject[$i];\n\t    }\n\t}\n\telse {\n\t    if( is_a($aObject,'IconPlot') ) {\n\t\t$this->AddIcon($aObject);\n\t    }\n\t    else {\t    \n\t\t$this->iObj[] = $aObject;\n\t    }\n\t}\n    }\n\n    // Override inherit method from Graph and give a warning message\n    function SetScale() {\n\tJpGraphError::RaiseL(6005);\n//(\"SetScale() is not meaningfull with Gantt charts.\");\n    }\n\n    // Specify the date range for Gantt graphs (if this is not set it will be\n    // automtically determined from the input data)\n    function SetDateRange($aStart,$aEnd) {\n\t// Adjust the start and end so that the indicate the\n\t// beginning and end of respective start and end days\n\tif( strpos($aStart,':') === false )\n\t    $aStart = date('Y-m-d 00:00',strtotime($aStart));\n\tif( strpos($aEnd,':') === false )\n\t    $aEnd = date('Y-m-d 23:59',strtotime($aEnd));\n\t$this->scale->SetRange($aStart,$aEnd);\n    }\n\t\n    // Get the maximum width of the activity titles columns for the bars\n    // The name is lightly misleading since we from now on can have\n    // multiple columns in the label section. When this was first written\n    // it only supported a single label, hence the name.\n    function GetMaxLabelWidth() {\n\t$m=50;\n\tif( $this->iObj != null ) {\n\t    $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin;\n\t    $m = $this->iObj[0]->title->GetWidth($this->img)+$marg;\n\t    $n = count($this->iObj);\n\t    for($i=1; $i < $n; ++$i) {\n\t\tif( !empty($this->iObj[$i]->title) ) {\n\t\t    if( $this->iObj[$i]->title->HasTabs() ) {\n\t\t\tlist($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true);\n\t\t\t$m=max($m,$tot);\n\t\t    }\n\t\t    else \n\t\t\t$m=max($m,$this->iObj[$i]->title->GetWidth($this->img));\n\t\t}\n\t    }\n\t}\n\treturn $m;\n    }\n\t\n    // Get the maximum height of the titles for the bars\n    function GetMaxLabelHeight() {\n\t$m=0;\n\tif( $this->iObj != null ) {\n\t    $m = $this->iObj[0]->title->GetHeight($this->img);\n\t    $n = count($this->iObj);\n\t    for($i=1; $i < $n; ++$i) {\n\t\tif( !empty($this->iObj[$i]->title) ) {\n\t\t    $m=max($m,$this->iObj[$i]->title->GetHeight($this->img));\n\t\t}\n\t    }\n\t}\n\treturn $m;\n    }\n\n    function GetMaxBarAbsHeight() {\n\t$m=0;\n\tif( $this->iObj != null ) {\n\t    $m = $this->iObj[0]->GetAbsHeight($this->img);\n\t    $n = count($this->iObj);\n\t    for($i=1; $i < $n; ++$i) {\n\t\t$m=max($m,$this->iObj[$i]->GetAbsHeight($this->img));\n\t    }\n\t}\n\treturn $m;\t\t\n    }\n\t\n    // Get the maximum used line number (vertical position) for bars\n    function GetBarMaxLineNumber() {\n\t$m=0;\n\tif( $this->iObj != null ) {\n\t    $m = $this->iObj[0]->GetLineNbr();\n\t    $n = count($this->iObj);\n\t    for($i=1; $i < $n; ++$i) {\n\t\t$m=max($m,$this->iObj[$i]->GetLineNbr());\n\t    }\n\t}\n\treturn $m;\n    }\n\t\n    // Get the minumum and maximum used dates for all bars\n    function GetBarMinMax() {\n\t$start = 0 ;\n\t$n = count($this->iObj);\n\n\twhile( $start < $n && $this->iObj[$start]->GetMaxDate() === false )\n\t    ++$start;\n\tif( $start >= $n ) {\n\t    JpgraphError::RaiseL(6006);\n//('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]');\n\t}\n\n\t$max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate());\n\t$min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate());\n\n\tfor($i=$start+1; $i < $n; ++$i) {\n\t    $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate());\n\t    if( $rmax != false ) \n\t\t$max=Max($max,$rmax);\n\t    $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate());\n\t    if( $rmin != false ) \n\t\t$min=Min($min,$rmin);\n\t}\n\t$minDate = date(\"Y-m-d\",$min);\n\t$min = strtotime($minDate);\n\t$maxDate = date(\"Y-m-d 23:59\",$max);\n\t$max = strtotime($maxDate);\t\n\treturn array($min,$max);\n    }\n\n    // Create a new auto sized canvas if the user hasn't specified a size\n    // The size is determined by what scale the user has choosen and hence\n    // the minimum width needed to display the headers. Some margins are\n    // also added to make it better looking.\n    function AutoSize() {\n\tif( $this->img->img == null ) {\n\t    // The predefined left, right, top, bottom margins.\n\t    // Note that the top margin might incease depending on\n\t    // the title.\n\t    $lm = $this->img->left_margin; \n\t    $rm = $this->img->right_margin; \n\t    $rm += 2 ;\n\t    $tm = $this->img->top_margin; \n\t    $bm = $this->img->bottom_margin; \n\t    $bm += 1; \n\t    if( BRAND_TIMING ) $bm += 10;\n\t\t\t\n\t    // First find out the height\t\t\t\n\t    $n=$this->GetBarMaxLineNumber()+1;\n\t    $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());\n\t    $height=$n*((1+$this->iLabelVMarginFactor)*$m);\t\t\t\n\t\t\t\n\t    // Add the height of the scale titles\t\t\t\n\t    $h=$this->scale->GetHeaderHeight();\n\t    $height += $h;\n\n\t    // Calculate the top margin needed for title and subtitle\n\t    if( $this->title->t != \"\" ) {\n\t\t$tm += $this->title->GetFontHeight($this->img);\n\t    }\n\t    if( $this->subtitle->t != \"\" ) {\n\t\t$tm += $this->subtitle->GetFontHeight($this->img);\n\t    }\n\n\t    // ...and then take the bottom and top plot margins into account\n\t    $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin;\n\t    // Now find the minimum width for the chart required\n\n\t    // If day scale or smaller is shown then we use the day font width\n\t    // as the base size unit.\n\t    // If only weeks or above is displayed we use a modified unit to\n\t    // get a smaller image.\n\t    if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) {\n\t\t// Add 2 pixel margin on each side\n\t\t$fw=$this->scale->day->GetFontWidth($this->img)+4; \n\t    }\n\t    elseif( $this->scale->IsDisplayWeek() ) {\n\t\t$fw = 8;\n\t    }\n\t    elseif( $this->scale->IsDisplayMonth() ) {\n\t\t$fw = 4;\n\t    }\n\t    else {\n\t\t$fw = 2;\n\t    }\n\n\t    $nd=$this->scale->GetNumberOfDays();\n\n\t    if( $this->scale->IsDisplayDay() ) {\n\t\t// If the days are displayed we also need to figure out\n\t\t// how much space each day's title will require.\n\t\tswitch( $this->scale->day->iStyle ) {\n\t\t    case DAYSTYLE_LONG :\n\t\t\t$txt = \"Monday\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_LONGDAYDATE1 :\n\t\t\t$txt =  \"Monday 23 Jun\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_LONGDAYDATE2 :\n\t\t\t$txt =  \"Monday 23 Jun 2003\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORT : \n\t\t\t$txt =  \"Mon\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE1 : \n                        $txt =  \"Mon 23/6\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE2 :\n\t\t\t$txt =  \"Mon 23 Jun\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE3 :\n\t\t\t$txt =  \"Mon 23\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDATE1 :\n                        $txt =  \"23/6\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDATE2 :\n\t\t\t$txt =  \"23 Jun\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDATE3 :\n\t\t\t$txt =  \"Mon 23\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDATE4 :\n\t\t\t$txt =  \"88\";\n\t\t\tbreak;\n\t\t    case DAYSTYLE_CUSTOM :\n\t\t\t$txt = date($this->scale->day->iLabelFormStr,\n\t\t\t\t    strtotime('2003-12-20 18:00'));\n\t\t\tbreak;\n\t\t    case DAYSTYLE_ONELETTER :\n\t\t    default:\n\t\t\t$txt = \"M\";\n\t\t\tbreak;\n\t\t}\n\t\t$fw = $this->scale->day->GetStrWidth($this->img,$txt)+6;\n\t    }\n\n\t    // If we have hours enabled we must make sure that each day has enough\n\t    // space to fit the number of hours to be displayed.\n\t    if( $this->scale->IsDisplayHour() ) {\n\t\t// Depending on what format the user has choose we need different amount\n\t\t// of space. We therefore create a typical string for the choosen format\n\t\t// and determine the length of that string.\n\t\tswitch( $this->scale->hour->iStyle ) {\n\t\t    case HOURSTYLE_HMAMPM:\n\t\t\t$txt = '12:00pm';\n\t\t\tbreak;\n\t\t    case HOURSTYLE_H24:\n\t\t\t// 13\n\t\t\t$txt = '24';\n\t\t\tbreak;\n\t\t    case HOURSTYLE_HAMPM:\n\t\t\t$txt = '12pm';\n\t\t\tbreak;\n\t\t    case HOURSTYLE_CUSTOM:\n\t\t\t$txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00'));\n\t\t\tbreak;\n\t\t    case HOURSTYLE_HM24:\n\t\t    default:\n\t\t\t$txt = '24:00';\n\t\t\tbreak;\n\t\t}\n\n\t\t$hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6;\n\t\t$mw = $hfw;\n\t\tif( $this->scale->IsDisplayMinute() ) {\n\t\t    // Depending on what format the user has choose we need different amount\n\t\t    // of space. We therefore create a typical string for the choosen format\n\t\t    // and determine the length of that string.\n\t\t    switch( $this->scale->minute->iStyle ) {\n\t\t\tcase HOURSTYLE_CUSTOM:\n\t\t\t    $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));\n\t\t\t    break;\n\t\t\tcase MINUTESTYLE_MM:\n\t\t\tdefault:\n\t\t\t    $txt2 = '15';\n\t\t\t    break;\n\t\t    }\n\t\t    \n\t\t    $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6;\n\t\t    $n2 = ceil(60 / $this->scale->minute->GetIntervall() );\n\t\t    $mw = $n2 * $mfw;\n\t\t}\n\t\t$hfw = $hfw < $mw ? $mw : $hfw ;   \n\t\t$n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) );\n\t\t$hw = $n * $hfw;\n\t\t$fw = $fw < $hw ? $hw : $fw ;\n\t    }\n\n\t    // We need to repeat this code block here as well. \n\t    // THIS iS NOT A MISTAKE !\n\t    // We really need it since we need to adjust for minutes both in the case\n\t    // where hour scale is shown and when it is not shown.\n\n\t    if( $this->scale->IsDisplayMinute() ) {\n\t\t// Depending on what format the user has choose we need different amount\n\t\t// of space. We therefore create a typical string for the choosen format\n\t\t// and determine the length of that string.\n\t\tswitch( $this->scale->minute->iStyle ) {\n\t\t    case HOURSTYLE_CUSTOM:\n\t\t\t$txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));\n\t\t\tbreak;\n\t\t    case MINUTESTYLE_MM:\n\t\t    default:\n\t\t\t$txt = '15';\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t$mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6;\n\t\t$n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) );\n\t\t$mw = $n * $mfw;\n\t\t$fw = $fw < $mw ? $mw : $fw ;\n\t    }\n\n\t    // If we display week we must make sure that 7*$fw is enough\n\t    // to fit up to 10 characters of the week font (if the week is enabled)\n\t    if( $this->scale->IsDisplayWeek() ) {\n\t\t// Depending on what format the user has choose we need different amount\n\t\t// of space\n\t\t$fsw = strlen($this->scale->week->iLabelFormStr);\n\t\tif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {\n\t\t    $fsw += 8;\n\t\t}\n\t\telseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) {\n\t\t    $fsw += 7;\n\t\t}\n\t\telse {\n\t\t    $fsw += 4;\n\t\t}\n\t\t    \n\t\t$ww = $fsw*$this->scale->week->GetFontWidth($this->img);\n\t\tif( 7*$fw < $ww ) {\n\t\t    $fw = ceil($ww/7);\n\t\t}\n\t    }\n\n\t    if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() &&\n\t\t!( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || \n\t\t    $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) {\n\t\t// If we don't display the individual days we can shrink the\n\t\t// scale a little bit. This is a little bit pragmatic at the \n\t\t// moment and should be re-written to take into account\n\t\t// a) What scales exactly are shown and \n\t\t// b) what format do they use so we know how wide we need to\n\t\t// make each scale text space at minimum.\n\t\t$fw /= 2;\n\t\tif( !$this->scale->IsDisplayWeek() ) {\n\t\t    $fw /= 1.8;\n\t\t}\n\t    }\n\n\t    // Has the user specified a width or do we need to\n\t    // determine it?\n\t    if( $this->img->width <= 0 ) {\n\t\t// Now determine the width for the activity titles column\n\n\t\t// Firdst find out the maximum width of each object column\n\t\t$cw = $this->GetMaxActInfoColWidth() ;\n\t\t$this->scale->actinfo->SetMinColWidth($cw); \n\t\t$titlewidth = max(max($this->GetMaxLabelWidth(),\n\t\t\t\t      $this->scale->tableTitle->GetWidth($this->img)), \n\t\t\t\t  $this->scale->actinfo->GetWidth($this->img));\n\n\t\t// Add the width of the vertivcal divider line\n\t\t$titlewidth += $this->scale->divider->iWeight*2;\n\n\n\t\t// Now get the total width taking \n\t\t// titlewidth, left and rigt margin, dayfont size \n\t\t// into account\n\t\t$width = $titlewidth + $nd*$fw + $lm+$rm;\n\t    }\n\t    else\n\t\t$width = $this->img->width;\n\n\t    $width = round($width);\n\t    $height = round($height);\n\t    if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) {\n\t\tJpgraphError::RaiseL(6007,$width,$height);\n//(\"Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.\");\n\t    }\n\t\t\t\t\t\t\n\t    $this->img->CreateImgCanvas($width,$height);\t\t\t\n\t    $this->img->SetMargin($lm,$rm,$tm,$bm);\n\t}\n    }\n\n    // Return an array width the maximum width for each activity\n    // column. This is used when we autosize the columns where we need\n    // to find out the maximum width of each column. In order to do that we\n    // must walk through all the objects, sigh...\n    function GetMaxActInfoColWidth() {\n\t$n = count($this->iObj);\n\tif( $n == 0 ) return;\n\t$w = array();\n\t$m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin;\n\t\n\tfor( $i=0; $i < $n; ++$i ) {\n\t    $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m);\n\t    $nn = count($tmp);\n\t    for( $j=0; $j < $nn; ++$j ) {\n\t\tif( empty($w[$j]) ) \n\t\t    $w[$j] = $tmp[$j];\n\t\telse \n\t\t    $w[$j] = max($w[$j],$tmp[$j]);\n\t    }\n\t}\n\treturn $w;\n    }\n\n    // Stroke the gantt chart\n    function Stroke($aStrokeFileName=\"\") {\t\n\n\n\t// If the filename is the predefined value = '_csim_special_'\n\t// we assume that the call to stroke only needs to do enough\n\t// to correctly generate the CSIM maps.\n\t// We use this variable to skip things we don't strictly need\n\t// to do to generate the image map to improve performance\n\t// a best we can. Therefor you will see a lot of tests !$_csim in the\n\t// code below.\n\t$_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);\n\n\t// Should we autoscale dates?\n\tif( !$this->scale->IsRangeSet() ) {\n\t    list($min,$max) = $this->GetBarMinMax();\n\t    $this->scale->SetRange($min,$max);\n\t}\n\n\t$this->scale->AdjustStartEndDay();\n\n\t// Check if we should autoscale the image\n\t$this->AutoSize();\n\t\t\n\t// Should we start from the top or just spread the bars out even over the\n\t// available height\n\t$this->scale->SetVertLayout($this->iLayout);\t\t\t\n\tif( $this->iLayout == GANTT_FROMTOP ) {\n\t    $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());\n\t    $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor));\n\t}\n\t// If it hasn't been set find out the maximum line number\n\tif( $this->scale->iVertLines == -1 ) \n\t    $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; \t\n\t\t\n\t$maxwidth=max($this->scale->actinfo->GetWidth($this->img),\n\t\t      max($this->GetMaxLabelWidth(),\n\t\t      $this->scale->tableTitle->GetWidth($this->img)));\n\n\t$this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor));\n\n\tif( !$_csim ) {\n\t    $this->StrokePlotArea();\n\t    if( $this->iIconDepth == DEPTH_BACK ) {\n\t\t$this->StrokeIcons();\n\t    }\n\t}\n\n\t$this->scale->Stroke();\n\n\tif( !$_csim ) {\n\t    // Due to a minor off by 1 bug we need to temporarily adjust the margin\n\t    $this->img->right_margin--;\n\t    $this->StrokePlotBox();\n\t    $this->img->right_margin++;\n\t}\n\n\t// Stroke Grid line\n\t$this->hgrid->Stroke($this->img,$this->scale);\n\n\t$n = count($this->iObj);\n\tfor($i=0; $i < $n; ++$i) {\n\t    //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2));\n\t    $this->iObj[$i]->Stroke($this->img,$this->scale);\n\t}\n\n\t$this->StrokeTitles();\n\n\tif( !$_csim ) {\n\t    $this->StrokeConstrains();\n\t    $this->footer->Stroke($this->img);\n\n\t    if( $this->iIconDepth == DEPTH_FRONT) {\n\t\t$this->StrokeIcons();\n\t    }\n\n\t    // Should we do any final image transformation\n\t    if( $this->iImgTrans ) {\n\t\tif( !class_exists('ImgTrans') ) {\n\t\t    require_once('jpgraph_imgtrans.php');\n\t\t}\n\t    \n\t\t$tform = new ImgTrans($this->img->img);\n\t\t$this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,\n\t\t\t\t\t\t $this->iImgTransDirection,$this->iImgTransHighQ,\n\t\t\t\t\t\t $this->iImgTransMinSize,$this->iImgTransFillColor,\n\t\t\t\t\t\t $this->iImgTransBorder);\n\t    }\n\t    \n\t    \n\t    // If the filename is given as the special \"__handle\"\n\t    // then the image handler is returned and the image is NOT\n\t    // streamed back\n\t    if( $aStrokeFileName == _IMG_HANDLER ) {\n\t\treturn $this->img->img;\n\t    }\n\t    else {\n\t\t// Finally stream the generated picture\t\t\t\t\t\n\t\t$this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,\n\t\t\t\t\t   $aStrokeFileName);\t\t\n\t    }\n\t}\n    }\n\n    function StrokeConstrains() {\n\t$n = count($this->iObj);\n\n\t// Stroke all constrains\n\tfor($i=0; $i < $n; ++$i) {\n\n\t    // Some gantt objects may not have constraints associated with them\n\t    // for example we can add IconPlots which doesn't have this property.\n\t    if( empty($this->iObj[$i]->constraints) ) continue;\n\n\t    $numConstrains = count($this->iObj[$i]->constraints);\n\n\t    for( $k = 0; $k < $numConstrains; $k++ ) {\n\t\t$vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow;\n\t\tif( $vpos >= 0 ) {\n\t\t    $c1 = $this->iObj[$i]->iConstrainPos;\n\n\t\t    // Find out which object is on the target row\n\t\t    $targetobj = -1;\n\t\t    for( $j=0; $j < $n && $targetobj == -1; ++$j ) {\n\t\t\tif( $this->iObj[$j]->iVPos == $vpos ) {\n\t\t\t    $targetobj = $j;\n\t\t\t}\n\t\t    }\n\t\t    if( $targetobj == -1 ) {\n\t\t\tJpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos);\n//('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.');\n\t\t    }\n\t\t    $c2 = $this->iObj[$targetobj]->iConstrainPos;\n\t\t    if( count($c1) == 4 && count($c2 ) == 4) {\n\t\t\tswitch( $this->iObj[$i]->constraints[$k]->iConstrainType ) {\n\t\t\t    case CONSTRAIN_ENDSTART:\n\t\t\t\tif( $c1[1] < $c2[1] ) {\n\t\t\t\t    $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t    $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]);\n\t\t\t\t}\n\t\t\t\t$link->SetPath(3);\n\t\t\t\tbreak;\n\t\t\t    case CONSTRAIN_STARTEND:\n\t\t\t\tif( $c1[1] < $c2[1] ) {\n\t\t\t\t    $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t    $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]);\n\t\t\t\t}\n\t\t\t\t$link->SetPath(0);\n\t\t\t\tbreak;\n\t\t\t    case CONSTRAIN_ENDEND:\n\t\t\t\tif( $c1[1] < $c2[1] ) {\n\t\t\t\t    $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t    $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]);\n\t\t\t\t}\n\t\t\t\t$link->SetPath(1);\n\t\t\t\tbreak;\n\t\t\t    case CONSTRAIN_STARTSTART:\n\t\t\t\tif( $c1[1] < $c2[1] ) {\n\t\t\t\t    $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t    $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]);\n\t\t\t\t}\n\t\t\t\t$link->SetPath(3);\n\t\t\t\tbreak;\n\t\t\t    default:\n\t\t\t\tJpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos);\n//('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor);\n\t\t\t$link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize,\n\t\t\t\t\t$this->iObj[$i]->constraints[$k]->iConstrainArrowType);\n \n\t\t\t$link->Stroke($this->img);\n\t\t    }\n\t\t}\n\t    }\n\t}\n    }\n\n    function GetCSIMAreas() {\n\tif( !$this->iHasStroked )\n\t    $this->Stroke(_CSIM_SPECIALFILE);\n\n\t$csim = $this->title->GetCSIMAreas();\n\t$csim .= $this->subtitle->GetCSIMAreas();\n\t$csim .= $this->subsubtitle->GetCSIMAreas();\n\n\t$n = count($this->iObj);\n\tfor( $i=$n-1; $i >= 0; --$i ) \n\t    $csim .= $this->iObj[$i]->GetCSIMArea();\n\treturn $csim;\n    }\n}\n\n//===================================================\n// CLASS PredefIcons\n// Description: Predefined icons for use with Gantt charts\n//===================================================\nDEFINE('GICON_WARNINGRED',0);\nDEFINE('GICON_TEXT',1);\nDEFINE('GICON_ENDCONS',2);\nDEFINE('GICON_MAIL',3);\nDEFINE('GICON_STARTCONS',4);\nDEFINE('GICON_CALC',5);\nDEFINE('GICON_MAGNIFIER',6);\nDEFINE('GICON_LOCK',7);\nDEFINE('GICON_STOP',8);\nDEFINE('GICON_WARNINGYELLOW',9);\nDEFINE('GICON_FOLDEROPEN',10);\nDEFINE('GICON_FOLDER',11);\nDEFINE('GICON_TEXTIMPORTANT',12);\n\nclass PredefIcons {\n    var $iBuiltinIcon = null;\n    var $iLen = -1 ;\n\n    function GetLen() {\n\treturn $this->iLen ; \n    }\n\n    function GetImg($aIdx) {\n\tif( $aIdx < 0 || $aIdx >= $this->iLen ) {\n\t    JpGraphError::RaiseL(6010,$aIdx);\n//('Illegal icon index for Gantt builtin icon ['.$aIdx.']');\n\t}\n\treturn Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1]));   \n    }\n\n    function PredefIcons() {\n\t//==========================================================\n\t// warning.png\n\t//==========================================================\n\t$this->iBuiltinIcon[0][0]= 1043 ;\n\t$this->iBuiltinIcon[0][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.\n\t    'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'.\n\t    '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'.\n\t    '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'.\n\t    'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'.\n\t    'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'.\n\t    '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'.\n\t    'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'.\n\t    'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'.\n\t    'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'.\n\t    'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'.\n\t    'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'.\n\t    'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'.\n\t    'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; \n\n\t//==========================================================\n\t// edit.png\n\t//==========================================================\n\t$this->iBuiltinIcon[1][0]= 959 ;\n\t$this->iBuiltinIcon[1][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'.\n\t    'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'.\n\t    'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'.\n\t    'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'.\n\t    'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'.\n\t    'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'.\n\t    'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'.\n\t    'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'.\n\t    'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'.\n\t    'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'.\n\t    'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'.\n\t    'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'.\n\t    'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; \n\n\t//==========================================================\n\t// endconstrain.png\n\t//==========================================================\n\t$this->iBuiltinIcon[2][0]= 666 ;\n\t$this->iBuiltinIcon[2][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.\n\t    'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'.\n\t    'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'.\n\t    'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'.\n\t    'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'.\n\t    '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'.\n\t    '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'.\n\t    'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'.\n\t    'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; \n\n\t//==========================================================\n\t// mail.png\n\t//==========================================================\n\t$this->iBuiltinIcon[3][0]= 1122 ;\n\t$this->iBuiltinIcon[3][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.\n\t    'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'.\n\t    'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'.\n\t    'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'.\n\t    'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'.\n\t    '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'.\n\t    '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'.\n\t    'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'.\n\t    'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'.\n\t    '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'.\n\t    'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'.\n\t    'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'.\n\t    'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'.\n\t    'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'.\n\t    'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; \n\n\t//==========================================================\n\t// startconstrain.png\n\t//==========================================================\n\t$this->iBuiltinIcon[4][0]= 725 ;\n\t$this->iBuiltinIcon[4][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.\n\t    'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'.\n\t    'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'.\n\t    'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'.\n\t    'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'.\n\t    '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'.\n\t    'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'.\n\t    'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'.\n\t    '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'.\n\t    'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; \n\n\t//==========================================================\n\t// calc.png\n\t//==========================================================\n\t$this->iBuiltinIcon[5][0]= 589 ;\n\t$this->iBuiltinIcon[5][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'.\n\t    'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'.\n\t    'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'.\n\t    '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'.\n\t    'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'.\n\t    'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'.\n\t    'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'.\n\t    'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; \n\n\t//==========================================================\n\t// mag.png\n\t//==========================================================\n\t$this->iBuiltinIcon[6][0]= 1415 ;\n\t$this->iBuiltinIcon[6][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.\n\t    'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'.\n\t    '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'.\n\t    'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'.\n\t    'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'.\n\t    'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'.\n\t    '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'.\n\t    'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'.\n\t    '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'.\n\t    'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'.\n\t    'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'.\n\t    'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'.\n\t    'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'.\n\t    'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'.\n\t    'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'.\n\t    'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'.\n\t    'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'.\n\t    'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'.\n\t    'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; \n\n\t//==========================================================\n\t// lock.png\n\t//==========================================================\n\t$this->iBuiltinIcon[7][0]= 963 ;\n\t$this->iBuiltinIcon[7][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.\n\t    'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'.\n\t    'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'.\n\t    'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'.\n\t    'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'.\n\t    'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'.\n\t    'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'.\n\t    'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'.\n\t    'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'.\n\t    'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'.\n\t    'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'.\n\t    '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'.\n\t    'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; \n\n\t//==========================================================\n\t// stop.png\n\t//==========================================================\n\t$this->iBuiltinIcon[8][0]= 889 ;\n\t$this->iBuiltinIcon[8][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.\n\t    'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'.\n\t    'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'.\n\t    'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'.\n\t    'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'.\n\t    'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'.\n\t    'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'.\n\t    'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'.\n\t    'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'.\n\t    'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'.\n\t    'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'.\n\t    'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; \n\n\t//==========================================================\n\t// error.png\n\t//==========================================================\n\t$this->iBuiltinIcon[9][0]= 541 ;\n\t$this->iBuiltinIcon[9][1]= \n\t    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.\n\t    'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.\n\t    'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'.\n\t    '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'.\n\t    'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'.\n\t    'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'.\n\t    'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'.\n\t    'iOsCHgAAAABJRU5ErkJggg==' ; \n\n\t//==========================================================\n\t// openfolder.png\n\t//==========================================================\n\t$this->iBuiltinIcon[10][0]= 2040 ;\n\t$this->iBuiltinIcon[10][1]=\n\t    'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'.\n\t    'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'.\n\t    'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'.\n\t    'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'.\n\t    'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'.\n\t    'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'.\n\t    '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'.\n\t    'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'.\n\t    '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'.\n\t    'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'.\n\t    'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'.\n\t    'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'.\n\t    'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'.\n\t    'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'.\n\t    'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'.\n\t    'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'.\n\t    'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'.\n\t    'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'.\n\t    'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'.\n\t    'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'.\n\t    'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'.\n\t    'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'.\n\t    'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'.\n\t    'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'.\n\t    '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'.\n\t    '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'.\n\t    'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'.\n\t    'dBntAAAAAElFTkSuQmCC' ;\n\n\t//==========================================================\n\t// folder.png\n\t//==========================================================\n        $this->iBuiltinIcon[11][0]= 1824 ;\n\t$this->iBuiltinIcon[11][1]=\n\t    'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.\n\t    'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'.\n\t    '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'.\n\t    'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'.\n\t    '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'.\n\t    'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'.\n\t    'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'.\n\t    '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'.\n\t    'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'.\n\t    'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'.\n\t    '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'.\n\t    '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'.\n\t    'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'.\n\t    'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'.\n\t    'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'.\n\t    'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'.\n\t    'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'.\n\t    'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'.\n\t    'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'.\n\t    'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'.\n\t    'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'.\n\t    'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'.\n\t    'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'.\n\t    'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'.\n\t    'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ;\n\n\t//==========================================================\n\t// file_important.png\n\t//==========================================================\n\t$this->iBuiltinIcon[12][0]= 1785 ;\n\t$this->iBuiltinIcon[12][1]=\n\t    'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.\n\t    'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'.\n\t    'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'.\n\t    'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'.\n\t    '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'.\n\t    's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'.\n\t    'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'.\n\t    'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'.\n\t    'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'.\n\t    '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'.\n\t    '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'.\n\t    'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'.\n\t    'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'.\n\t    'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'.\n\t    'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'.\n\t    't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'.\n\t    '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'.\n\t    'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'.\n\t    'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'.\n\t    'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'.\n\t    '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'.\n\t    'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'.\n\t    'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'.\n\t    '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ;\n\n\t$this->iLen = count($this->iBuiltinIcon);\n    }\n}\n\n//===================================================\n// Global cache for builtin images\n//===================================================\n$_gPredefIcons = new PredefIcons();\n\n//===================================================\n// CLASS IconImage\n// Description: Holds properties for an icon image \n//===================================================\nclass IconImage {\n    var $iGDImage=null;\n    var $iWidth,$iHeight;\n    var $ixalign='left',$iyalign='center';\n    var $iScale=1.0;\n\n    function IconImage($aIcon,$aScale=1) {\n\tGLOBAL $_gPredefIcons ; \n\tif( is_string($aIcon) ) {\n\t    $this->iGDImage = Graph::LoadBkgImage('',$aIcon);\n\t}\n\telseif( is_integer($aIcon) ) {\n\t    // Builtin image\n\t    $this->iGDImage = $_gPredefIcons->GetImg($aIcon);\n\t}\n\telse {\n\t    JpGraphError::RaiseL(6011);\n//('Argument to IconImage must be string or integer');\n\t}\n\t$this->iScale = $aScale;\n\t$this->iWidth = Image::GetWidth($this->iGDImage);\n\t$this->iHeight = Image::GetHeight($this->iGDImage);\n    }\n\n    function GetWidth() {\n\treturn round($this->iScale*$this->iWidth);\n    }\n\n    function GetHeight() {\n\treturn round($this->iScale*$this->iHeight);\n    }\n\n    function SetAlign($aX='left',$aY='center') {\n\n\t$this->ixalign = $aX;\n\t$this->iyalign = $aY;\n\n    }\n\n    function Stroke(&$aImg,$x,$y) {\n\n\tif( $this->ixalign == 'right' ) {\n\t    $x -= $this->iWidth;\n\t}\n\telseif( $this->ixalign == 'center' ) {\n\t    $x -= round($this->iWidth/2*$this->iScale);\n\t}\n\n\tif( $this->iyalign == 'bottom' ) {\n\t    $y -= $this->iHeight;\n\t}\n\telseif( $this->iyalign == 'center' ) {\n\t    $y -= round($this->iHeight/2*$this->iScale);\n\t}\n\n\t$aImg->Copy($this->iGDImage,\n\t\t    $x,$y,0,0,\n\t\t    round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale),\n\t\t    $this->iWidth,$this->iHeight);\n    }\n}\n\n\n//===================================================\n// CLASS TextProperty\n// Description: Holds properties for a text\n//===================================================\nclass TextProperty {\n    var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10;\n    var $iColor=\"black\";\n    var $iShow=true;\n    var $iText=\"\";\n    var $iHAlign=\"left\",$iVAlign=\"bottom\";\n    var $csimtarget='',$csimalt='';\n\t\n//---------------\n// CONSTRUCTOR\t\n    function TextProperty($aTxt='') {\n\t$this->iText = $aTxt;\n    }\t\t\n\t\n//---------------\n// PUBLIC METHODS\t\n    function Set($aTxt) {\n\t$this->iText = $aTxt;\n    }\n\n    function SetCSIMTarget($aTarget,$aAltText='') {\n\tif( is_string($aTarget) )\n\t    $aTarget = array($aTarget);\n\t$this->csimtarget=$aTarget;\n\tif( is_string($aAltText) )\n\t    $aAltText = array($aAltText);\n        $this->csimalt=$aAltText;\n    }\n    \n    function SetCSIMAlt($aAltText) {\n\tif( is_string($aAltText) )\n\t    $aAltText = array($aAltText);\n        $this->csimalt=$aAltText;\n    }\n\n    // Set text color\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\t\n    function HasTabs() {\n\tif( is_string($this->iText) ) {\n\t    return substr_count($this->iText,\"\\t\") > 0;\n\t}\n\telseif( is_array($this->iText) ) {\n\t    return false;\n\t}\n    }\n\t\n    // Get number of tabs in string\n    function GetNbrTabs() {\n\tif( is_string($this->iText) ) {\n\t    return substr_count($this->iText,\"\\t\") ;\n\t}\n\telse{\n\t    return 0;\n\t}\n    }\n\t\n    // Set alignment\n    function Align($aHAlign,$aVAlign=\"bottom\") {\n\t$this->iHAlign=$aHAlign;\n\t$this->iVAlign=$aVAlign;\n    }\n\t\n    // Synonym\n    function SetAlign($aHAlign,$aVAlign=\"bottom\") {\n\t$this->iHAlign=$aHAlign;\n\t$this->iVAlign=$aVAlign;\n    }\n\t\n    // Specify font\n    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {\n\t$this->iFFamily = $aFFamily;\n\t$this->iFStyle\t = $aFStyle;\n\t$this->iFSize\t = $aFSize;\n    }\n\n    function IsColumns() {\n\treturn is_array($this->iText) ; \n    }\n\t\n    // Get width of text. If text contains several columns separated by\n    // tabs then return both the total width as well as an array with a \n    // width for each column.\n    function GetWidth(&$aImg,$aUseTabs=false,$aTabExtraMargin=1.1) {\n\t$extra_margin=4;\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\tif( is_string($this->iText) ) {\n\t    if( strlen($this->iText) == 0 ) return 0;\n\t    $tmp = split(\"\\t\",$this->iText);\n\t    if( count($tmp) <= 1 || !$aUseTabs ) {\n\t\treturn $aImg->GetTextWidth($this->iText)+2*$extra_margin;\n\t    }\n\t    else {\n\t\t$tot=0;\n\t\t$n = count($tmp);\n\t\tfor($i=0; $i < $n; ++$i) {\n\t\t    $res[$i] = $aImg->GetTextWidth($tmp[$i]);\n\t\t    $tot += $res[$i]*$aTabExtraMargin;\n\t\t}\n\t\treturn array(round($tot),$res);\n\t    }\n\t}\n\telseif( is_object($this->iText) ) {\n\t    // A single icon\n\t    return $this->iText->GetWidth()+2*$extra_margin;\n\t}\n\telseif( is_array($this->iText) ) {\n\t    // Must be an array of texts. In this case we return the sum of the\n\t    // length + a fixed margin of 4 pixels on each text string\n\t    $n = count($this->iText);\n\t    for( $i=0, $w=0; $i < $n; ++$i ) {\n\t\t$tmp = $this->iText[$i];\n\t\tif( is_string($tmp) ) {\n\t\t    $w += $aImg->GetTextWidth($tmp)+$extra_margin;\n\t\t}\n\t\telse {\n\t\t    if( is_object($tmp) === false ) {\n\t\t\tJpGraphError::RaiseL(6012);\n\t\t    }\n\t\t    $w += $tmp->GetWidth()+$extra_margin;\n\t\t}\n\t    }\n\t    return $w;\n\t}\n\telse {\n\t    JpGraphError::RaiseL(6012);\n\t}\n    }\n\n    // for the case where we have multiple columns this function returns the width of each\n    // column individually. If there is no columns just return the width of the single\n    // column as an array of one\n    function GetColWidth(&$aImg,$aMargin=0) {\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\tif( is_array($this->iText) ) {\n\t    $n = count($this->iText);\n\t    for( $i=0, $w=array(); $i < $n; ++$i ) {\n\t\t$tmp = $this->iText[$i];\n\t\tif( is_string($tmp) ) {\n\t\t    $w[$i] = $aImg->GetTextWidth($this->iText[$i])+$aMargin;\n\t\t}\n\t\telse {\n\t\t    if( is_object($tmp) === false ) {\n\t\t\tJpGraphError::RaiseL(6012);\n\t\t    }\n\t\t    $w[$i] = $tmp->GetWidth()+$aMargin;\n\t\t}\n\t    }\n\t    return $w;\t\n\t}\n\telse {\n\t    return array($this->GetWidth($aImg));\n\t}\n    }\n\t\n    // Get total height of text\n    function GetHeight(&$aImg) {\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\treturn $aImg->GetFontHeight();\n    }\n\t\n    // Unhide/hide the text\t\n    function Show($aShow=true) {\n\t$this->iShow=$aShow;\n    }\n\t\n    // Stroke text at (x,y) coordinates. If the text contains tabs then the\n    // x parameter should be an array of positions to be used for each successive\n    // tab mark. If no array is supplied then the tabs will be ignored.\n    function Stroke(&$aImg,$aX,$aY) {\n\tif( $this->iShow ) {\n\t    $aImg->SetColor($this->iColor);\n\t    $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\t    $aImg->SetTextAlign($this->iHAlign,$this->iVAlign);\t\t\t\n\t    if( $this->GetNbrTabs() <= 1 ) {\n\t\tif( is_string($this->iText) ) {\n\t\t    // Get rid of any \"\\t\" characters and stroke string\n\t\t    if( is_array($aX) ) $aX=$aX[0];\n\t\t    if( is_array($aY) ) $aY=$aY[0];\n\t\t    $aImg->StrokeText($aX,$aY,str_replace(\"\\t\",\" \",$this->iText));\n\t\t}\n\t\telse {\n\t\t    $n = count($this->iText);\n\t\t    $ax = is_array($aX) ;\n\t\t    $ay = is_array($aY) ;\n\t\t    if( $ax && $ay ) {\n\t\t\t// Nothing; both are already arrays\n\t\t    }\n\t\t    elseif( $ax ) {\n\t\t\t$aY = array_fill(0,$n,$aY);\n\t\t    }\n\t\t    elseif( $ay ) {\n\t\t\t$aX = array_fill(0,$n,$aX);\n\t\t    }\n\t\t    else {\n\t\t\t$aX = array_fill(0,$n,$aX);\n\t\t\t$aY = array_fill(0,$n,$aY);\n\t\t    }\n\t\t    $n = min($n, count($aX) ) ;\n\t\t    $n = min($n, count($aY) ) ;\n\t\t    for($i=0; $i < $n; ++$i ) {\n\t\t\t$tmp = $this->iText[$i];\n\t\t\tif( is_object($tmp) ) {\n\t\t\t    $tmp->Stroke($aImg,$aX[$i],$aY[$i]);\n\t\t\t}\n\t\t\telse\n\t\t\t    $aImg->StrokeText($aX[$i],$aY[$i],str_replace(\"\\t\",\" \",$tmp));\n\t\t    }\n\t\t}\n\t    }\n\t    else {\n\t\t$tmp = split(\"\\t\",$this->iText);\n\t\t$n = min(count($tmp),count($aX));\n\t\tfor($i=0; $i < $n; ++$i) {\n\t\t    $aImg->StrokeText($aX[$i],$aY,$tmp[$i]);\n\t\t}\t\n\t    }\n\t}\n    }\n}\n\n//===================================================\n// CLASS HeaderProperty\n// Description: Data encapsulating class to hold property \n// for each type of the scale headers\n//===================================================\nclass HeaderProperty {\n    var $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8;\n    var $iFrameColor=\"black\",$iFrameWeight=1;\n    var $iShowLabels=true,$iShowGrid=true;\n    var $iBackgroundColor=\"white\";\n    var $iWeekendBackgroundColor=\"lightgray\",$iSundayTextColor=\"red\"; // these are only used with day scale\n    var $iTextColor=\"black\";\n    var $iLabelFormStr=\"%d\";\n    var $grid,$iStyle=0;\n    var $iIntervall = 1;\n\n//---------------\n// CONSTRUCTOR\t\n    function HeaderProperty() {\n\t$this->grid = new LineProperty();\n    }\n\n//---------------\n// PUBLIC METHODS\t\t\n    function Show($aShow=true) {\n\t$this->iShowLabels = $aShow;\n    }\n\n    function SetIntervall($aInt) {\n\t$this->iIntervall = $aInt;\n    }\n\n    function GetIntervall() {\n\treturn $this->iIntervall ;\n    }\n\t\n    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {\n\t$this->iFFamily = $aFFamily;\n\t$this->iFStyle\t = $aFStyle;\n\t$this->iFSize\t = $aFSize;\n    }\n\n    function SetFontColor($aColor) {\n\t$this->iTextColor = $aColor;\n    }\n\t\n    function GetFontHeight(&$aImg) {\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\treturn $aImg->GetFontHeight();\n    }\n\n    function GetFontWidth(&$aImg) {\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\treturn $aImg->GetFontWidth();\n    }\n\n    function GetStrWidth(&$aImg,$aStr) {\n\t$aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);\n\treturn $aImg->GetTextWidth($aStr);\n    }\n\t\n    function SetStyle($aStyle) {\n\t$this->iStyle = $aStyle;\n    }\n\t\n    function SetBackgroundColor($aColor) {\n\t$this->iBackgroundColor=$aColor;\n    }\n\n    function SetFrameWeight($aWeight) {\n\t$this->iFrameWeight=$aWeight;\n    }\n\n    function SetFrameColor($aColor) {\n\t$this->iFrameColor=$aColor;\n    }\n\t\n    // Only used by day scale\n    function SetWeekendColor($aColor) {\n\t$this->iWeekendBackgroundColor=$aColor;\n    }\n\t\n    // Only used by day scale\n    function SetSundayFontColor($aColor) {\n\t$this->iSundayTextColor=$aColor;\n    }\n\t\n    function SetTitleVertMargin($aMargin) {\n\t$this->iTitleVertMargin=$aMargin;\n    }\n\t\n    function SetLabelFormatString($aStr) {\n\t$this->iLabelFormStr=$aStr;\n    }\n\n    function SetFormatString($aStr) {\n\t$this->SetLabelFormatString($aStr);\n    }\n\n\n}\n\n//===================================================\n// CLASS GanttScale\n// Description: Responsible for calculating and showing\n// the scale in a gantt chart. This includes providing methods for\n// converting dates to position in the chart as well as stroking the\n// date headers (days, week, etc).\n//===================================================\nclass GanttScale {\n    var $minute,$hour,$day,$week,$month,$year;\n    var $divider,$dividerh,$tableTitle;\n    var $iStartDate=-1,$iEndDate=-1;\n    // Number of gantt bar position (n.b not necessariliy the same as the number of bars)\n    // we could have on bar in position 1, and one bar in position 5 then there are two\n    // bars but the number of bar positions is 5\n    var $iVertLines=-1;\t\n    // The width of the labels (defaults to the widest of all labels)\n    var $iLabelWidth;\t\n    // Out image to stroke the scale to\n    var $iImg;\t\n    var $iTableHeaderBackgroundColor=\"white\",$iTableHeaderFrameColor=\"black\";\n    var $iTableHeaderFrameWeight=1;\n    var $iAvailableHeight=-1,$iVertSpacing=-1,$iVertHeaderSize=-1;\n    var $iDateLocale;\n    var $iVertLayout=GANTT_EVEN;\n    var $iTopPlotMargin=10,$iBottomPlotMargin=15;\n    var $iUsePlotWeekendBackground=true;\n    var $iWeekStart = 1;\t// Default to have weekends start on Monday\n    var $actinfo;\n\t\n//---------------\n// CONSTRUCTOR\t\n    function GanttScale(&$aImg) {\n\t$this->iImg = &$aImg;\t\t\n\t$this->iDateLocale = new DateLocale();\n\n\t$this->minute = new HeaderProperty();\n\t$this->minute->SetIntervall(15);\n\t$this->minute->SetLabelFormatString('i');\n\t$this->minute->SetFont(FF_FONT0);\n\t$this->minute->grid->SetColor(\"gray\");\n\n\t$this->hour = new HeaderProperty();\n\t$this->hour->SetFont(FF_FONT0);\n\t$this->hour->SetIntervall(6);\n\t$this->hour->SetStyle(HOURSTYLE_HM24);\n\t$this->hour->SetLabelFormatString('H:i');\n\t$this->hour->grid->SetColor(\"gray\");\n\n\t$this->day = new HeaderProperty();\n\t$this->day->grid->SetColor(\"gray\");\n\t$this->day->SetLabelFormatString('l');\n\n\t$this->week = new HeaderProperty();\n\t$this->week->SetLabelFormatString(\"w%d\");\n\t$this->week->SetFont(FF_FONT1);\n\n\t$this->month = new HeaderProperty();\n\t$this->month->SetFont(FF_FONT1,FS_BOLD);\n\n\t$this->year = new HeaderProperty();\n\t$this->year->SetFont(FF_FONT1,FS_BOLD);\t\t\n\t\t\n\t$this->divider=new LineProperty();\n\t$this->dividerh=new LineProperty();\t\t\n\t$this->dividerh->SetWeight(2);\n\t$this->divider->SetWeight(6);\n\t$this->divider->SetColor('gray');\n\t$this->divider->SetStyle('fancy');\n\n\t$this->tableTitle=new TextProperty();\n\t$this->tableTitle->Show(false);\n\t$this->actinfo = new GanttActivityInfo();\n    }\n\t\n//---------------\n// PUBLIC METHODS\t\n    // Specify what headers should be visible\n    function ShowHeaders($aFlg) {\n\t$this->day->Show($aFlg & GANTT_HDAY);\n\t$this->week->Show($aFlg & GANTT_HWEEK);\n\t$this->month->Show($aFlg & GANTT_HMONTH);\n\t$this->year->Show($aFlg & GANTT_HYEAR);\n\t$this->hour->Show($aFlg & GANTT_HHOUR);\n\t$this->minute->Show($aFlg & GANTT_HMIN);\n\n\t// Make some default settings of gridlines whihc makes sense\n\tif( $aFlg & GANTT_HWEEK ) {\n\t    $this->month->grid->Show(false);\n\t    $this->year->grid->Show(false);\n\t}\n\tif( $aFlg & GANTT_HHOUR ) {\n\t    $this->day->grid->SetColor(\"black\");\n\t}\n    }\n\t\n    // Should the weekend background stretch all the way down in the plotarea\n    function UseWeekendBackground($aShow) {\n\t$this->iUsePlotWeekendBackground = $aShow;\n    }\n\t\n    // Have a range been specified?\n    function IsRangeSet() {\n\treturn $this->iStartDate!=-1 && $this->iEndDate!=-1;\n    }\n\t\n    // Should the layout be from top or even?\n    function SetVertLayout($aLayout) {\n\t$this->iVertLayout = $aLayout;\n    }\n\t\n    // Which locale should be used?\n    function SetDateLocale($aLocale) {\n\t$this->iDateLocale->Set($aLocale);\n    }\n\t\n    // Number of days we are showing\n    function GetNumberOfDays() {\n\treturn round(($this->iEndDate-$this->iStartDate)/SECPERDAY);\n    }\n\t\n    // The width of the actual plot area\n    function GetPlotWidth() {\n\t$img=$this->iImg;\n\treturn $img->width - $img->left_margin - $img->right_margin;\n    }\n\n    // Specify the width of the titles(labels) for the activities\n    // (This is by default set to the minimum width enought for the\n    // widest title)\n    function SetLabelWidth($aLabelWidth) {\n\t$this->iLabelWidth=$aLabelWidth;\n    }\n\n\t// Which day should the week start?\n\t// 0==Sun, 1==Monday, 2==Tuesday etc\n    function SetWeekStart($aStartDay) {\n\t$this->iWeekStart = $aStartDay % 7;\n\t\n\t//Recalculate the startday since this will change the week start\n\t$this->SetRange($this->iStartDate,$this->iEndDate);\n    }\n\n    // Do we show min scale?\n    function IsDisplayMinute() {\n\treturn $this->minute->iShowLabels;\n    }\n\n    // Do we show day scale?\n    function IsDisplayHour() {\n\treturn $this->hour->iShowLabels;\n    }\n\n\t\n    // Do we show day scale?\n    function IsDisplayDay() {\n\treturn $this->day->iShowLabels;\n    }\n\t\n    // Do we show week scale?\n    function IsDisplayWeek() {\n\treturn $this->week->iShowLabels;\n    }\n\t\n    // Do we show month scale?\n    function IsDisplayMonth() {\n\treturn $this->month->iShowLabels;\n    }\n\t\n    // Do we show year scale?\n    function IsDisplayYear() {\n\treturn $this->year->iShowLabels;\n    }\n\n    // Specify spacing (in percent of bar height) between activity bars\n    function SetVertSpacing($aSpacing) {\n\t$this->iVertSpacing = $aSpacing;\n    }\n\n    // Specify scale min and max date either as timestamp or as date strings\n    // Always round to the nearest week boundary\n    function SetRange($aMin,$aMax) {\n\t$this->iStartDate = $this->NormalizeDate($aMin);\n\t$this->iEndDate = $this->NormalizeDate($aMax);\t\n    }\n\n\n    // Adjust the start and end date so they fit to beginning/ending\n    // of the week taking the specified week start day into account.\n    function AdjustStartEndDay() {\n\n\tif( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) {\n\t    // Don't adjust\n\t    return;\n\t}\n\n\t// Get day in week for start and ending date (Sun==0)\n\t$ds=strftime(\"%w\",$this->iStartDate);\n\t$de=strftime(\"%w\",$this->iEndDate);\t\n\t\n\t// We want to start on iWeekStart day. But first we subtract a week\n\t// if the startdate is \"behind\" the day the week start at. \n\t// This way we ensure that the given start date is always included \n\t// in the range. If we don't do this the nearest correct weekday in the week \n\t// to start at might be later than the start date.\n\tif( $ds < $this->iWeekStart )\n\t    $d = strtotime('-7 day',$this->iStartDate);\n\telse\n\t    $d = $this->iStartDate;\n\t$adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ );\n\t$this->iStartDate = $adjdate;\n\t\n\t// We want to end on the last day of the week\n\t$preferredEndDay = ($this->iWeekStart+6)%7;\n\tif( $preferredEndDay != $de ) { \n\t    // Solve equivalence eq:    $de + x ~ $preferredDay (mod 7)\n\t    $adj = (7+($preferredEndDay - $de)) % 7;\n\t    $adjdate = strtotime(\"+$adj day\",$this->iEndDate);\n\t    $this->iEndDate = $adjdate;\t\n\t}\t\n    }\n\n    // Specify background for the table title area (upper left corner of the table)\t\n    function SetTableTitleBackground($aColor) {\n\t$this->iTableHeaderBackgroundColor = $aColor;\n    }\n\n///////////////////////////////////////\n// PRIVATE Methods\n\t\n    // Determine the height of all the scale headers combined\n    function GetHeaderHeight() {\n\t$img=$this->iImg;\n\t$height=1;\n\tif( $this->minute->iShowLabels ) {\n\t    $height += $this->minute->GetFontHeight($img);\n\t    $height += $this->minute->iTitleVertMargin;\n\t}\n\tif( $this->hour->iShowLabels ) {\n\t    $height += $this->hour->GetFontHeight($img);\n\t    $height += $this->hour->iTitleVertMargin;\n\t}\n\tif( $this->day->iShowLabels ) {\n\t    $height += $this->day->GetFontHeight($img);\n\t    $height += $this->day->iTitleVertMargin;\n\t}\n\tif( $this->week->iShowLabels ) {\n\t    $height += $this->week->GetFontHeight($img);\n\t    $height += $this->week->iTitleVertMargin;\n\t}\n\tif( $this->month->iShowLabels ) {\n\t    $height += $this->month->GetFontHeight($img);\n\t    $height += $this->month->iTitleVertMargin;\n\t}\n\tif( $this->year->iShowLabels ) {\n\t    $height += $this->year->GetFontHeight($img);\n\t    $height += $this->year->iTitleVertMargin;\n\t}\n\treturn $height;\n    }\n\t\n    // Get width (in pixels) for a single day\n    function GetDayWidth() {\n\treturn ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays();\t\n    }\n\n    // Get width (in pixels) for a single hour\n    function GetHourWidth() {\n\treturn $this->GetDayWidth() / 24 ;\n    }\n\n    function GetMinuteWidth() {\n\treturn $this->GetHourWidth() / 60 ;\n    }\n\n    // Nuber of days in a year\n    function GetNumDaysInYear($aYear) {\n\tif( $this->IsLeap($aYear) )\n\t    return 366;\n\telse\n\t    return 365;\n    }\n\t\n    // Get week number \n    function GetWeekNbr($aDate,$aSunStart=true) {\n\t// We can't use the internal strftime() since it gets the weeknumber\n\t// wrong since it doesn't follow ISO on all systems since this is\n\t// system linrary dependent.\n\t// Even worse is that this works differently if we are on a Windows\n\t// or UNIX box (it even differs between UNIX boxes how strftime()\n\t// is natively implemented)\n\t//\n\t// Credit to Nicolas Hoizey <nhoizey@phpheaven.net> for this elegant\n\t// version of Week Nbr calculation. \n\n\t$day = $this->NormalizeDate($aDate) ;\n\tif( $aSunStart )\n\t    $day += 60*60*24;\n\t\t\n\t/*-------------------------------------------------------------------------\n\t  According to ISO-8601 :\n\t  \"Week 01 of a year is per definition the first week that has the Thursday in this year,\n\t  which is equivalent to the week that contains the fourth day of January.\n\t  In other words, the first week of a new year is the week that has the majority of its\n\t  days in the new year.\"\n\t\t  \n\t  Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!!\n\t\t  \n\t  day of year             = date(\"z\", $day) + 1\n\t  offset to thursday      = 3 - (date(\"w\", $day) + 6) % 7\n\t  first thursday of year  = 1 + (11 - date(\"w\", mktime(0, 0, 0, 1, 1, date(\"Y\", $day)))) % 7\n\t  week number             = (thursday's day of year - first thursday's day of year) / 7 + 1\n\t  ---------------------------------------------------------------------------*/\n\t\t \n\t$thursday = $day + 60 * 60 * 24 * (3 - (date(\"w\", $day) + 6) % 7);              // take week's thursday\n\t$week = 1 + (date(\"z\", $thursday) - (11 - date(\"w\", mktime(0, 0, 0, 1, 1, date(\"Y\", $thursday)))) % 7) / 7;\n\t\t  \n\treturn $week;\n    }\n\t\n    // Is year a leap year?\n    function IsLeap($aYear) {\n\t// Is the year a leap year?\n\t//$year = 0+date(\"Y\",$aDate);\n\tif( $aYear % 4 == 0)\n\t    if( !($aYear % 100 == 0) || ($aYear % 400 == 0) )\n\t\treturn true;\n\treturn false;\n    }\n\n    // Get current year\n    function GetYear($aDate) {\n\treturn 0+Date(\"Y\",$aDate);\n    }\n\t\n    // Return number of days in a year\n    function GetNumDaysInMonth($aMonth,$aYear) {\n\t$days=array(31,28,31,30,31,30,31,31,30,31,30,31);\n\t$daysl=array(31,29,31,30,31,30,31,31,30,31,30,31);\n\tif( $this->IsLeap($aYear))\n\t    return $daysl[$aMonth];\n\telse\n\t    return $days[$aMonth];\n    }\n\t\n    // Get day in month\n    function GetMonthDayNbr($aDate) {\n\treturn 0+strftime(\"%d\",$aDate);\n    }\n\n    // Get day in year\n    function GetYearDayNbr($aDate) {\n\treturn 0+strftime(\"%j\",$aDate);\n    }\n\t\n    // Get month number\n    function GetMonthNbr($aDate) {\n\treturn 0+strftime(\"%m\",$aDate);\n    }\n\t\n    // Translate a date to screen coordinates\t(horizontal scale)\n    function TranslateDate($aDate) {\n\t//\n\t// In order to handle the problem with Daylight savings time\n\t// the scale written with equal number of seconds per day beginning\n\t// with the start date. This means that we \"cement\" the state of\n\t// DST as it is in the start date. If later the scale includes the\n\t// switchover date (depends on the locale) we need to adjust back\n\t// if the date we try to translate has a different DST status since\n\t// we would otherwise be off by one hour.\n\t$aDate = $this->NormalizeDate($aDate);\n\t$tmp = localtime($aDate);\n\t$cloc = $tmp[8];\n\t$tmp = localtime($this->iStartDate);\n\t$sloc = $tmp[8];\n\t$offset = 0;\n\tif( $sloc != $cloc) {\n\t    if( $sloc ) \n\t\t$offset = 3600;\n\t    else\n\t\t$offset = -3600;\n\t}\n\t$img=$this->iImg;\t\t\n\treturn ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;;\n    }\n\n    // Get screen coordinatesz for the vertical position for a bar\t\t\n    function TranslateVertPos($aPos) {\n\t$img=$this->iImg;\n\t$ph=$this->iAvailableHeight;\n\tif( $aPos > $this->iVertLines ) \n\t    JpGraphError::RaiseL(6015,$aPos);\n// 'Illegal vertical position %d'\n\tif( $this->iVertLayout == GANTT_EVEN ) {\n\t    // Position the top bar at 1 vert spacing from the scale\n\t    return round($img->top_margin + $this->iVertHeaderSize +  ($aPos+1)*$this->iVertSpacing);\n\t}\n\telse {\n\t    // position the top bar at 1/2 a vert spacing from the scale\n\t    return round($img->top_margin + $this->iVertHeaderSize  + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing);\t\t\n\t}\n    }\n\t\n    // What is the vertical spacing?\n    function GetVertSpacing() {\n\treturn $this->iVertSpacing;\n    }\n\t\t\t\t\t\n    // Convert a date to timestamp\n    function NormalizeDate($aDate) {\n\tif( $aDate === false ) return false; \n\tif( is_string($aDate) ) {\n\t    $t = strtotime($aDate);\n\t    if( $t === FALSE || $t === -1 ) {\t    \n\t\tJpGraphError::RaiseL(6016,$aDate);\n//(\"Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30\");\n\t    }\n\t    return $t;\n\t}\n\telseif( is_int($aDate) || is_float($aDate) )\n\t    return $aDate;\n\telse\n\t    JpGraphError::RaiseL(6017,$aDate);\n//Unknown date format in GanttScale ($aDate).\");\n    }\n\n    \n    // Convert a time string to minutes\n\n    function TimeToMinutes($aTimeString) {\n\t// Split in hours and minutes\n\t$pos=strpos($aTimeString,':');\n\t$minint=60;\n\tif( $pos === false ) {\n\t    $hourint = $aTimeString;\n\t    $minint = 0;\n\t}\n\telse {\n\t    $hourint = floor(substr($aTimeString,0,$pos));\n\t    $minint = floor(substr($aTimeString,$pos+1));\n\t}\n\t$minint += 60 * $hourint;\n\treturn $minint;\n    }\n\n    // Stroke the day scale (including gridlines)\t\t\t\n    function StrokeMinutes($aYCoord,$getHeight=false) {\n\t$img=$this->iImg;\t\n\t$xt=$img->left_margin+$this->iLabelWidth;\n\t$yt=$aYCoord+$img->top_margin;\t\t\n\tif( $this->minute->iShowLabels ) {\n\t    $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize);\n\t    $yb = $yt + $img->GetFontHeight() + \n\t\t  $this->minute->iTitleVertMargin + $this->minute->iFrameWeight;\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;\n\t    }\n\t    $xb = $img->width-$img->right_margin+1;\n\t    $img->SetColor($this->minute->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\n\t    $x = $xt;   \n\t    $img->SetTextAlign(\"center\");\n\t    $day = date('w',$this->iStartDate);\n\t    $minint = $this->minute->GetIntervall() ;\n\t    \n\t    if( 60 % $minint !== 0 ) { \n                JpGraphError::RaiseL(6018,$minint);\n//'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.');\n            } \n\n\n\t    $n = 60 / $minint;\n\t    $datestamp = $this->iStartDate;\n\t    $width = $this->GetHourWidth() / $n ;\n\t    if( $width < 8 ) {\n\t\t// TO small width to draw minute scale\n\t\tJpGraphError::RaiseL(6019,$width);\n//('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.');\n\t    }\n\n\t    $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) );\n\t    $nd = $this->GetNumberOfDays();\n\t    // Convert to intervall to seconds\n\t    $minint *= 60;\n\t    for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) {\n\t\tfor( $k=0; $k < $nh; ++$k ) {\n\t\t    for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) {   \n\t\t\tif( $day==6 || $day==0 ) {\n\t\t\t\n\t\t\t    $img->PushColor($this->day->iWeekendBackgroundColor);\n\t\t\t    if( $this->iUsePlotWeekendBackground )\n\t\t\t\t$img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);\t\t\t\t\t\t\n\t\t\t    else\n\t\t\t\t$img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);\n\t\t\t    $img->PopColor();\n\n\t\t\t}\n\n\t\t\tif( $day==0 ) \n\t\t\t    $img->SetColor($this->day->iSundayTextColor);\n\t\t\telse\n\t\t\t    $img->SetColor($this->day->iTextColor);\n\n\t\t\tswitch( $this->minute->iStyle ) {\n\t\t\t    case MINUTESTYLE_CUSTOM:\n\t\t\t\t$txt = date($this->minute->iLabelFormStr,$datestamp);\n\t\t\t\tbreak;\n\t\t\t    case MINUTESTYLE_MM:\n\t\t\t    default:\n\t\t\t\t// 15\n\t\t\t\t$txt = date('i',$datestamp);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t$img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt);\n\n\t\t\t// FIXME: The rounding problem needs to be solved properly ...\n\t\t\t//\n\t\t\t// Fix a rounding problem the wrong way ..\n\t\t\t// If we also have hour scale then don't draw the firsta or last\n\t\t\t// gridline since that will be overwritten by the hour scale gridline if such exists.\n\t\t\t// However, due to the propagation of rounding of the 'x+=width' term in the loop\n\t\t\t// this might sometimes be one pixel of so we fix this by not drawing it.\n\t\t\t// The proper way to fix it would be to re-calculate the scale for each step and\n\t\t\t// not using the additive term.\n\t\t\tif( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) {\n\t\t\t    $img->SetColor($this->minute->grid->iColor);\n\t\t\t    $img->SetLineWeight($this->minute->grid->iWeight);\n\t\t\t    $img->Line($x,$yt,$x,$yb);\n\t\t\t    $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t\t\t}\n\t\t    }\t\t\n\t\t}\t\n\t    }\n\t    $img->SetColor($this->minute->iFrameColor);\n\t    $img->SetLineWeight($this->minute->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\n\t    return $yb - $img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\n\n    // Stroke the day scale (including gridlines)\t\t\t\n    function StrokeHours($aYCoord,$getHeight=false) {\n\t$img=$this->iImg;\t\n\t$xt=$img->left_margin+$this->iLabelWidth;\n\t$yt=$aYCoord+$img->top_margin;\t\t\n\tif( $this->hour->iShowLabels ) {\n\t    $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize);\n\t    $yb = $yt + $img->GetFontHeight() + \n\t\t  $this->hour->iTitleVertMargin + $this->hour->iFrameWeight;\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;\n\t    }\n\t    $xb = $img->width-$img->right_margin+1;\n\t    $img->SetColor($this->hour->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\n\t    $x = $xt;   \n\t    $img->SetTextAlign(\"center\");\n\t    $tmp = $this->hour->GetIntervall() ;\n\t    $minint = $this->TimeToMinutes($tmp);\n\t    if( 1440 % $minint !== 0 ) { \n                JpGraphError::RaiseL(6020,$tmp);\n//('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp);\n            } \n\n\t    $n = ceil(24*60 / $minint );\n\t    $datestamp = $this->iStartDate;\n\t    $day = date('w',$this->iStartDate);\n\t    $doback = !$this->minute->iShowLabels;\n\t    $width = $this->GetDayWidth() / $n ;\n\t    for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) {\n\t\tfor($i=0; $i < $n ;++$i, $x+=$width) {   \n\t\t    if( $day==6 || $day==0 ) {\n\t\t\t\n\t\t\t$img->PushColor($this->day->iWeekendBackgroundColor);\n\t\t\tif( $this->iUsePlotWeekendBackground && $doback )\n\t\t\t    $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);\t\t\t\t\t\t\n\t\t\telse\n\t\t\t    $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);\n\t\t\t$img->PopColor();\n\n\t\t    }\n\n\t\t    if( $day==0 ) \n\t\t\t$img->SetColor($this->day->iSundayTextColor);\n\t\t    else\n\t\t\t$img->SetColor($this->day->iTextColor);\n\n\t\t    switch( $this->hour->iStyle ) {\n\t\t\tcase HOURSTYLE_HMAMPM:\n\t\t\t    // 1:35pm\n\t\t\t    $txt = date('g:ia',$datestamp);\n\t\t\t    break;\n\t\t\tcase HOURSTYLE_H24:\n\t\t\t    // 13\n\t\t\t    $txt = date('H',$datestamp);\n\t\t\t    break;\n\t\t\tcase HOURSTYLE_HAMPM:\n\t\t\t    $txt = date('ga',$datestamp);\n\t\t\t    break;\n\t\t\tcase HOURSTYLE_CUSTOM:\n\t\t\t    $txt = date($this->hour->iLabelFormStr,$datestamp);\n\t\t\t    break;\n\t\t\tcase HOURSTYLE_HM24:\n\t\t\tdefault:\n\t\t\t    $txt = date('H:i',$datestamp);\n\t\t\t    break;\n\t\t    }\n\t\t    $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt);\n\t\t    $img->SetColor($this->hour->grid->iColor);\n\t\t    $img->SetLineWeight($this->hour->grid->iWeight);\n\t\t    $img->Line($x,$yt,$x,$yb);\n\t\t    $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t\t    //$datestamp += $minint*60\n\t\t    $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0,\n\t\t\t\t\tdate(\"m\",$datestamp),date(\"d\",$datestamp)+1,date(\"Y\",$datestamp));\n\t\t    \n\t\t}\t\t\t\n\t    }\n\t    $img->SetColor($this->hour->iFrameColor);\n\t    $img->SetLineWeight($this->hour->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\n\t    return $yb - $img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\n\n\n    // Stroke the day scale (including gridlines)\t\t\t\n    function StrokeDays($aYCoord,$getHeight=false) {\n\t$img=$this->iImg;\t\n\t$daywidth=$this->GetDayWidth();\n\t$xt=$img->left_margin+$this->iLabelWidth;\n\t$yt=$aYCoord+$img->top_margin;\t\t\n\tif( $this->day->iShowLabels ) {\n\t    $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize);\n\t    $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight;\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;\n\t    }\n\t    $xb=$img->width-$img->right_margin+1;\n\t    $img->SetColor($this->day->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\n\t    $x = $xt;   \n\t    $img->SetTextAlign(\"center\");\n\t    $day = date('w',$this->iStartDate);\n\t    $datestamp = $this->iStartDate;\n\t    \n\t    $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels);\n\n\t    setlocale(LC_TIME,$this->iDateLocale->iLocale);\n\t    \n\t    for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) {\n\t\tif( $day==6 || $day==0 ) {\n\t\t    $img->SetColor($this->day->iWeekendBackgroundColor);\n\t\t    if( $this->iUsePlotWeekendBackground && $doback)\n\t\t\t$img->FilledRectangle($x,$yt+$this->day->iFrameWeight,\n\t\t\t\t\t      $x+$daywidth,$img->height-$img->bottom_margin);\t\n\t\t    else\n\t\t\t$img->FilledRectangle($x,$yt+$this->day->iFrameWeight,\n\t\t\t\t\t      $x+$daywidth,$yb-$this->day->iFrameWeight);\n\t\t}\n\n\t\t$mn = strftime('%m',$datestamp);\n\t\tif( $mn[0]=='0' ) \n\t\t    $mn = $mn[1];\n\n\t\tswitch( $this->day->iStyle ) {\n\t\t    case DAYSTYLE_LONG:\n\t\t\t// \"Monday\"\n\t\t\t$txt = strftime('%A',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORT:\n\t\t\t// \"Mon\"\n\t\t\t$txt = strftime('%a',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE1:\n\t\t\t// \"Mon 23/6\"\n\t\t\t$txt = strftime('%a %d/'.$mn,$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE2:\n\t\t\t// \"Mon 23 Jun\"\n\t\t\t$txt = strftime('%a %d %b',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDAYDATE3:\n\t\t\t// \"Mon 23 Jun 2003\"\n\t\t\t$txt = strftime('%a %d %b %Y',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_LONGDAYDATE1:\n\t\t\t// \"Monday 23 Jun\"\n\t\t\t$txt = strftime('%A %d %b',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_LONGDAYDATE2:\n\t\t\t// \"Monday 23 Jun 2003\"\n\t\t\t$txt = strftime('%A %d %b %Y',$datestamp);\n\t\t\tbreak;\n\t\t    case DAYSTYLE_SHORTDATE1:\n\t\t\t// \"23/6\"\n\t\t\t$txt = strftime('%d/'.$mn,$datestamp);\n\t\t\tbreak;\t\t\t\n\t\t    case DAYSTYLE_SHORTDATE2:\n\t\t\t// \"23 Jun\"\n\t\t\t$txt = strftime('%d %b',$datestamp);\n\t\t\tbreak;\t\t\t\n\t\t    case DAYSTYLE_SHORTDATE3:\n\t\t\t// \"Mon 23\"\n\t\t\t$txt = strftime('%a %d',$datestamp);\n\t\t\tbreak;\t\n\t\t    case DAYSTYLE_SHORTDATE4:\n\t\t\t// \"23\"\n\t\t\t$txt = strftime('%d',$datestamp);\n\t\t\tbreak;\t\n\t\t    case DAYSTYLE_CUSTOM:\n\t\t\t// Custom format\n\t\t\t$txt = strftime($this->day->iLabelFormStr,$datestamp);\n\t\t\tbreak;\t\n\t\t    case DAYSTYLE_ONELETTER:\n\t\t    default:\n\t\t\t// \"M\"\n\t\t\t$txt = strftime('%A',$datestamp);\n\t\t\t$txt = strtoupper($txt[0]);\n\t\t\tbreak;\n\t\t}\n\n\t\tif( $day==0 ) \n\t\t    $img->SetColor($this->day->iSundayTextColor);\n\t\telse\n\t\t    $img->SetColor($this->day->iTextColor);\n\t\t$img->StrokeText(round($x+$daywidth/2+1),\n\t\t\t\t round($yb-$this->day->iTitleVertMargin),$txt);\n\t\t$img->SetColor($this->day->grid->iColor);\n\t\t$img->SetLineWeight($this->day->grid->iWeight);\n\t\t$img->Line($x,$yt,$x,$yb);\n\t\t$this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t\t$datestamp = mktime(0,0,0,date(\"m\",$datestamp),date(\"d\",$datestamp)+1,date(\"Y\",$datestamp));\n\t\t//$datestamp += SECPERDAY;\n\t\t\n\t    }\t\t\t\n\t    $img->SetColor($this->day->iFrameColor);\n\t    $img->SetLineWeight($this->day->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\n\t    return $yb - $img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\n\t\n    // Stroke week header and grid\n    function StrokeWeeks($aYCoord,$getHeight=false) {\n\tif( $this->week->iShowLabels ) {\n\t    $img=$this->iImg;\t\n\t    $yt=$aYCoord+$img->top_margin;\t\t\n\t    $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize);\n\t    $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight;\n\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;  \n\t    }\n\n\t    $xt=$img->left_margin+$this->iLabelWidth;\n\t    $weekwidth=$this->GetDayWidth()*7;\n\t    $wdays=$this->iDateLocale->GetDayAbb();\t\n\t    $xb=$img->width-$img->right_margin+1;\n\t    $week = $this->iStartDate;\n\t    $weeknbr=$this->GetWeekNbr($week);\n\t    $img->SetColor($this->week->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\t    $img->SetColor($this->week->grid->iColor);\n\t    $x = $xt;\n\t    if( $this->week->iStyle==WEEKSTYLE_WNBR ) {\n\t\t$img->SetTextAlign(\"center\");\n\t\t$txtOffset = $weekwidth/2+1;\n\t    }\n\t    elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY  || \n\t\t    $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ||\n\t\t    $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||\n\t\t    $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {\n\t\t$img->SetTextAlign(\"left\");\n\t\t$txtOffset = 3;\n\t    }\n\t    else\n\t\tJpGraphError::RaiseL(6021);\n//(\"Unknown formatting style for week.\");\n\t\t\t\t\n\t    for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) {\n\t\t$img->PushColor($this->week->iTextColor);\n\t\t\t\t\n\t\tif( $this->week->iStyle==WEEKSTYLE_WNBR )\n\t\t    $txt = sprintf($this->week->iLabelFormStr,$weeknbr);\n\t\telseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || \n\t\t\t$this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) \n\t\t    $txt = date(\"j/n\",$week);\n\t\telseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || \n\t\t\t$this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {\n\t\t    $monthnbr = date(\"n\",$week)-1;\n\t\t    $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr);\n\t\t    $txt = Date(\"j\",$week).\" \".$shortmonth;\n\t\t}\n\n\t\tif( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||\n\t\t    $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {\n\t\t    $w = sprintf($this->week->iLabelFormStr,$weeknbr);\n\t\t    $txt .= ' '.$w;\n\t\t}\n\t\t\t\t\n\t\t$img->StrokeText(round($x+$txtOffset),\n\t\t\t\t round($yb-$this->week->iTitleVertMargin),$txt);\n\t\t\t\t\n\t\t$week = strtotime('+7 day',$week); \n\t\t$weeknbr = $this->GetWeekNbr($week);\n\t\t$img->PopColor();\t\n\t\t$img->SetLineWeight($this->week->grid->iWeight);\n\t\t$img->Line($x,$yt,$x,$yb);\n\t\t$this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t    }\t\t\t\n\t    $img->SetColor($this->week->iFrameColor);\n\t    $img->SetLineWeight($this->week->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\n\t    return $yb-$img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\t\n\t\n    // Format the mont scale header string\n    function GetMonthLabel($aMonthNbr,$year) {\n\t$sn = $this->iDateLocale->GetShortMonthName($aMonthNbr);\n\t$ln = $this->iDateLocale->GetLongMonthName($aMonthNbr);\n\tswitch($this->month->iStyle) {\n\t    case MONTHSTYLE_SHORTNAME:\n\t\t$m=$sn;\n\t\tbreak;\n\t    case MONTHSTYLE_LONGNAME:\n\t\t$m=$ln;\n\t\tbreak;\n\t    case MONTHSTYLE_SHORTNAMEYEAR2:\n\t\t$m=$sn.\" '\".substr(\"\".$year,2);\n\t\tbreak;\n\t    case MONTHSTYLE_SHORTNAMEYEAR4:\n\t\t$m=$sn.\" \".$year;\n\t\tbreak;\n\t    case MONTHSTYLE_LONGNAMEYEAR2:\n\t\t$m=$ln.\" '\".substr(\"\".$year,2);\n\t\tbreak;\n\t    case MONTHSTYLE_LONGNAMEYEAR4:\n\t\t$m=$ln.\" \".$year;\n\t\tbreak;\n\t    case MONTHSTYLE_FIRSTLETTER:\n\t\t$m=$sn[0];\n\t\tbreak;\n\t}\n\treturn $m;\n    }\n\t\n    // Stroke month scale and gridlines\n    function StrokeMonths($aYCoord,$getHeight=false) {\n\tif( $this->month->iShowLabels ) {\n\t    $img=$this->iImg;\t\t\n\t    $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize);\n\t    $yt=$aYCoord+$img->top_margin;\t\t\n\t    $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight;\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;  \n\t    }\n\t    $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; \n\t    $xt=$img->left_margin+$this->iLabelWidth;\n\t    $xb=$img->width-$img->right_margin+1;\n\t\t\t\n\t    $img->SetColor($this->month->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\n\t    $img->SetLineWeight($this->month->grid->iWeight);\n\t    $img->SetColor($this->month->iTextColor);\n\t    $year = 0+strftime(\"%Y\",$this->iStartDate);\n\t    $img->SetTextAlign(\"center\");\n\t    if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate)  \n\t\t&& $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) {\n\t    \t$monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1);\n\t    } \n\t    else {\n\t    \t$monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1);\n\t    }\n\t    // Is it enough space to stroke the first month?\n\t    $monthName = $this->GetMonthLabel($monthnbr,$year);\n\t    if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) {\n\t\t$img->SetColor($this->month->iTextColor);\t\t\t\t\n\t\t$img->StrokeText(round($xt+$monthwidth/2+1),\n\t\t\t\t round($yb-$this->month->iTitleVertMargin),\n\t\t\t\t $monthName);\n\t    }\n\t    $x = $xt + $monthwidth;\n\t    while( $x < $xb ) {\n\t\t$img->SetColor($this->month->grid->iColor);\t\t\t\t\n\t\t$img->Line($x,$yt,$x,$yb);\n\t\t$this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t\t$monthnbr++;\n\t\tif( $monthnbr==12 ) {\n\t\t    $monthnbr=0;\n\t\t    $year++;\n\t\t}\n\t\t$monthName = $this->GetMonthLabel($monthnbr,$year);\n\t\t$monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year);\t\t\t\t\n\t\tif( $x + $monthwidth < $xb )\n\t\t    $w = $monthwidth;\n\t\telse\n\t\t    $w = $xb-$x;\n\t\tif( $w >= 1.2*$img->GetTextWidth($monthName) ) {\n\t\t    $img->SetColor($this->month->iTextColor);\t\t\t\t\n\t\t    $img->StrokeText(round($x+$w/2+1),\n\t\t\t\t     round($yb-$this->month->iTitleVertMargin),$monthName);\n\t\t}\n\t\t$x += $monthwidth;\n\t    }\t\n\t    $img->SetColor($this->month->iFrameColor);\n\t    $img->SetLineWeight($this->month->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\t\t\t\n\t    return $yb-$img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\n\n    // Stroke year scale and gridlines\n    function StrokeYears($aYCoord,$getHeight=false) {\n\tif( $this->year->iShowLabels ) {\n\t    $img=$this->iImg;\t\n\t    $yt=$aYCoord+$img->top_margin;\t\t\n\t    $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize);\n\t    $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight;\n\n\t    if( $getHeight ) {\n\t\treturn $yb - $img->top_margin;  \n\t    }\n\n\t    $xb=$img->width-$img->right_margin+1;\n\t    $xt=$img->left_margin+$this->iLabelWidth;\n\t    $year = $this->GetYear($this->iStartDate); \t\t\t\n\t    $img->SetColor($this->year->iBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\t    $img->SetLineWeight($this->year->grid->iWeight);\n\t    $img->SetTextAlign(\"center\");\n\t    if( $year == $this->GetYear($this->iEndDate) )\n\t\t$yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1);\n\t    else\n\t\t$yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1);\n\t\t\t\n\t    // The space for a year must be at least 20% bigger than the actual text \n\t    // so we allow 10% margin on each side\n\t    if( $yearwidth >= 1.20*$img->GetTextWidth(\"\".$year) ) {\n\t\t$img->SetColor($this->year->iTextColor);\t\t\t\t\n\t\t$img->StrokeText(round($xt+$yearwidth/2+1),\n\t\t\t\t round($yb-$this->year->iTitleVertMargin),\n\t\t\t\t $year);\n\t    }\n\t    $x = $xt + $yearwidth;\n\t    while( $x < $xb ) {\n\t\t$img->SetColor($this->year->grid->iColor);\t\t\t\t\n\t\t$img->Line($x,$yt,$x,$yb);\n\t\t$this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);\n\t\t$year += 1;\n\t\t$yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year);\t\t\t\t\n\t\tif( $x + $yearwidth < $xb )\n\t\t    $w = $yearwidth;\n\t\telse\n\t\t    $w = $xb-$x;\n\t\tif( $w >= 1.2*$img->GetTextWidth(\"\".$year) ) {\n\t\t    $img->SetColor($this->year->iTextColor);\n\t\t    $img->StrokeText(round($x+$w/2+1),\n\t\t\t\t     round($yb-$this->year->iTitleVertMargin),\n\t\t\t\t     $year);\n\t\t}\n\t\t$x += $yearwidth;\n\t    }\n\t    $img->SetColor($this->year->iFrameColor);\n\t    $img->SetLineWeight($this->year->iFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\t\t\t\n\t    return $yb-$img->top_margin;\n\t}\n\treturn $aYCoord;\n    }\n\t\n    // Stroke table title (upper left corner)\n    function StrokeTableHeaders($aYBottom) {\n\t$img=$this->iImg;\n\t$xt=$img->left_margin;\n\t$yt=$img->top_margin;\n\t$xb=$xt+$this->iLabelWidth;\n\t$yb=$aYBottom+$img->top_margin;\n\n\tif( $this->tableTitle->iShow ) {\n\t    $img->SetColor($this->iTableHeaderBackgroundColor);\n\t    $img->FilledRectangle($xt,$yt,$xb,$yb);\n\t    $this->tableTitle->Align(\"center\",\"top\");\n\t    $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2);\t\t\n\t    $img->SetColor($this->iTableHeaderFrameColor);\n\t    $img->SetLineWeight($this->iTableHeaderFrameWeight);\n\t    $img->Rectangle($xt,$yt,$xb,$yb);\n\t}\n\n\t$this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow);\n\n\n\t// Draw the horizontal dividing line\t\t\n\t$this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb);\t\t\n\t\t\n\t// Draw the vertical dividing line\n\t// We do the width \"manually\" since we want the line only to grow\n\t// to the left\n\t$fancy = $this->divider->iStyle == 'fancy' ;\n\tif( $fancy ) {\n\t    $this->divider->iStyle = 'solid';\n\t}\n\n\t$tmp = $this->divider->iWeight;\t\n\t$this->divider->iWeight=1;\n\t$y = $img->height-$img->bottom_margin;\n\tfor($i=0; $i < $tmp; ++$i ) {\n\t    $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y);\n\t}\n\n\t// Should we draw \"fancy\" divider\n\tif( $fancy ) {\n\t    $img->SetLineWeight(1);\n\t    $img->SetColor($this->iTableHeaderFrameColor);\n\t    $img->Line($xb,$yt,$xb,$y);\n\t    $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y);\n\t    $img->SetColor('white');\n\t    $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y);\n\t}\n    }\n\n    // Main entry point to stroke scale\n    function Stroke() {\n\tif( !$this->IsRangeSet() )\n\t    JpGraphError::RaiseL(6022);\n//(\"Gantt scale has not been specified.\");\n\t$img=$this->iImg;\n\n\t// If minutes are displayed then hour interval must be 1\n\tif( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) {\n\t    JpGraphError::RaiseL(6023);\n//('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\\' make sense to display minutes).');\n\t}\n\t\t\n\t// Stroke all headers. As argument we supply the offset from the\n\t// top which depends on any previous headers\n\t\n\t// First find out the height of each header\n\t$offy=$this->StrokeYears(0,true);\n\t$offm=$this->StrokeMonths($offy,true);\n\t$offw=$this->StrokeWeeks($offm,true);\n\t$offd=$this->StrokeDays($offw,true);\n\t$offh=$this->StrokeHours($offd,true);\n\t$offmin=$this->StrokeMinutes($offh,true);\n\n\n\t// ... then we can stroke them in the \"backwards order to ensure that\n\t// the larger scale gridlines is stroked over the smaller scale gridline\n\t$this->StrokeMinutes($offh);\n\t$this->StrokeHours($offd);\n\t$this->StrokeDays($offw);\n\t$this->StrokeWeeks($offm);\t\t\n\t$this->StrokeMonths($offy);\t\t\n\t$this->StrokeYears(0);\n\n\t// Now when we now the oaverall size of the scale headers\n\t// we can stroke the overall table headers\n\t$this->StrokeTableHeaders($offmin);\n\t\t\n\t// Now we can calculate the correct scaling factor for each vertical position\n\t$this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd;\t\t\n\t$this->iVertHeaderSize = $offmin;\n\tif( $this->iVertSpacing == -1 )\n\t    $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines;\n    }\t\n}\n\n\n//===================================================\n// CLASS GanttConstraint\n// Just a structure to store all the values for a constraint\n//===================================================\nclass GanttConstraint {\n    var $iConstrainType;\n    var $iConstrainRow;\n    var $iConstrainColor;\n    var $iConstrainArrowSize;\n    var $iConstrainArrowType;\n\n//---------------\n// CONSTRUCTOR\n    function GanttConstraint($aRow,$aType,$aColor,$aArrowSize,$aArrowType){\n\t$this->iConstrainType = $aType;\n\t$this->iConstrainRow = $aRow;\n\t$this->iConstrainColor=$aColor;\n\t$this->iConstrainArrowSize=$aArrowSize;\n\t$this->iConstrainArrowType=$aArrowType;\n    }\n}\n\n\n//===================================================\n// CLASS GanttPlotObject\n// The common signature for a Gantt object\n//===================================================\nclass GanttPlotObject {\n    var $iVPos=0;\t\t\t\t\t// Vertical position\n    var $iLabelLeftMargin=2;\t// Title margin\n    var $iStart=\"\";\t\t\t\t// Start date\n    var $title,$caption;\n    var $iCaptionMargin=5;\n    var $csimarea='',$csimtarget='',$csimalt='';\n\n    var $constraints = array();    \n    var $iConstrainPos=array();\n\t\t\n    function GanttPlotObject() {\n \t$this->title = new TextProperty();\n\t$this->title->Align(\"left\",\"center\");\n\t$this->caption = new TextProperty();\n    }\n\n    function GetCSIMArea() {\n\treturn $this->csimarea;\n    }\n\n    function SetCSIMTarget($aTarget,$aAlt='') {\n\tif( !is_string($aTarget) ) {\n\t    $tv = substr(var_export($aTarget,true),0,40);\n\t    JpGraphError::RaiseL(6024,$tv);\n//('CSIM Target must be specified as a string.'.\"\\nStart of target is:\\n$tv\");\n\t}\n\tif( !is_string($aAlt) ) {\n\t    $tv = substr(var_export($aAlt,true),0,40);\n\t    JpGraphError::RaiseL(6025,$tv);\n//('CSIM Alt text must be specified as a string.'.\"\\nStart of alt text is:\\n$tv\");\n\t}\n\n        $this->csimtarget=$aTarget;\n        $this->csimalt=$aAlt;\n    }\n    \n    function SetCSIMAlt($aAlt) {\n\tif( !is_string($aAlt) ) {\n\t    $tv = substr(var_export($aAlt,true),0,40);\n\t    JpGraphError::RaiseL(6025,$tv);\n//('CSIM Alt text must be specified as a string.'.\"\\nStart of alt text is:\\n$tv\");\n\t}\n        $this->csimalt=$aAlt;\n    }\n\n    function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) {\n\t$this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType);\n    }\n\n    function SetConstrainPos($xt,$yt,$xb,$yb) {\n\t$this->iConstrainPos = array($xt,$yt,$xb,$yb);\n    }\n\n    /*\n    function GetConstrain() {\n\treturn array($this->iConstrainRow,$this->iConstrainType);\n    }\n    */\n\t\n    function GetMinDate() {\n\treturn $this->iStart;\n    }\n\n    function GetMaxDate() {\n\treturn $this->iStart;\n    }\n\t\n    function SetCaptionMargin($aMarg) {\n\t$this->iCaptionMargin=$aMarg;\n    }\n\n    function GetAbsHeight(&$aImg) {\n\treturn 0; \n    }\n\t\n    function GetLineNbr() {\n\treturn $this->iVPos;\n    }\n\n    function SetLabelLeftMargin($aOff) {\n\t$this->iLabelLeftMargin=$aOff;\n    }\t\t\n\n    function StrokeActInfo(&$aImg,$aScale,$aYPos) {\n\t$cols=array();\n\t$aScale->actinfo->GetColStart($aImg,$cols,true);\n\t$this->title->Stroke($aImg,$cols,$aYPos);\t\t\n    }\n}\n\n//===================================================\n// CLASS Progress\n// Holds parameters for the progress indicator \n// displyed within a bar\n//===================================================\nclass Progress {\n    var $iProgress=-1, $iColor=\"black\", $iFillColor='black';\n    var $iPattern=GANTT_SOLID;\n    var $iDensity=98, $iHeight=0.65; \n\t\n    function Set($aProg) {\n\tif( $aProg < 0.0 || $aProg > 1.0 )\n\t    JpGraphError::RaiseL(6027);\n//(\"Progress value must in range [0, 1]\");\n\t$this->iProgress = $aProg;\n    }\n\n    function SetPattern($aPattern,$aColor=\"blue\",$aDensity=98) {\t\t\n\t$this->iPattern = $aPattern;\n\t$this->iColor = $aColor;\n\t$this->iDensity = $aDensity;\n    }\n\n    function SetFillColor($aColor) {\n\t$this->iFillColor = $aColor;\n    }\n\t\n    function SetHeight($aHeight) {\n\t$this->iHeight = $aHeight;\n    }\n}\n\nDEFINE('GANTT_HGRID1',0);\nDEFINE('GANTT_HGRID2',1);\n\n//===================================================\n// CLASS HorizontalGridLine\n// Responsible for drawinf horizontal gridlines and filled alternatibg rows\n//===================================================\nclass HorizontalGridLine {\n    var $iGraph=NULL;\n    var $iRowColor1 = '', $iRowColor2 = '';\n    var $iShow=false;\n    var $line=null;\n    var $iStart=0; // 0=from left margin, 1=just along header\n\n    function HorizontalGridLine() {\n\t$this->line = new LineProperty();\n\t$this->line->SetColor('gray@0.4');\n\t$this->line->SetStyle('dashed');\n    }\n    \n    function Show($aShow=true) {\n\t$this->iShow = $aShow;\n    }\n\n    function SetRowFillColor($aColor1,$aColor2='') {\n\t$this->iRowColor1 = $aColor1;\n\t$this->iRowColor2 = $aColor2;\n    }\n\n    function SetStart($aStart) {\n\t$this->iStart = $aStart;\n    }\n\n    function Stroke(&$aImg,$aScale) {\n\t\n\tif( ! $this->iShow ) return;\n\n\t// Get horizontal width of line\n\t/*\n\t$limst = $aScale->iStartDate;\n\t$limen = $aScale->iEndDate;\n\t$xt = round($aScale->TranslateDate($aScale->iStartDate));\n\t$xb = round($aScale->TranslateDate($limen)); \n\t*/\n\n\tif( $this->iStart === 0 ) {\n\t    $xt = $aImg->left_margin-1;\n\t}\n\telse {\n\t    $xt = round($aScale->TranslateDate($aScale->iStartDate))+1;\n\t}\n\n\t$xb = $aImg->width-$aImg->right_margin;\n\n\t$yt = round($aScale->TranslateVertPos(0));\n\t$yb = round($aScale->TranslateVertPos(1));\t    \n\t$height = $yb - $yt;\n\n\t// Loop around for all lines in the chart\n\tfor($i=0; $i < $aScale->iVertLines; ++$i ) {\n\t    $yb = $yt - $height;\n\t    $this->line->Stroke($aImg,$xt,$yb,$xb,$yb);\n\t    if( $this->iRowColor1 !== '' ) {\n\t\tif( $i % 2 == 0 ) {\n\t\t    $aImg->PushColor($this->iRowColor1);\n\t\t    $aImg->FilledRectangle($xt,$yt,$xb,$yb);\n\t\t    $aImg->PopColor();\n\t\t}\n\t\telseif( $this->iRowColor2 !== '' ) {\n\t\t    $aImg->PushColor($this->iRowColor2);\n\t\t    $aImg->FilledRectangle($xt,$yt,$xb,$yb);\n\t\t    $aImg->PopColor();\n\t\t}\n\t    }\n\t    $yt = round($aScale->TranslateVertPos($i+1));\n\t}\n\t$yb = $yt - $height;\n\t$this->line->Stroke($aImg,$xt,$yb,$xb,$yb);\n    }\n}\n\n\n//===================================================\n// CLASS GanttBar\n// Responsible for formatting individual gantt bars\n//===================================================\nclass GanttBar extends GanttPlotObject {\n    var $iEnd;\n    var $iHeightFactor=0.5;\n    var $iFillColor=\"white\",$iFrameColor=\"black\";\n    var $iShadow=false,$iShadowColor=\"darkgray\",$iShadowWidth=1,$iShadowFrame=\"black\";\n    var $iPattern=GANTT_RDIAG,$iPatternColor=\"blue\",$iPatternDensity=95;\n    var $leftMark,$rightMark;\n    var $progress;\n//---------------\n// CONSTRUCTOR\t\n    function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption=\"\",$aHeightFactor=0.6) {\n\tparent::GanttPlotObject();\t\n\t$this->iStart = $aStart;\t\n\t// Is the end date given as a date or as number of days added to start date?\n\tif( is_string($aEnd) ) {\n\t    // If end date has been specified without a time we will asssume\n\t    // end date is at the end of that date\n\t    if( strpos($aEnd,':') === false )\n\t\t$this->iEnd = strtotime($aEnd)+SECPERDAY-1;\n\t    else \n\t\t$this->iEnd = $aEnd;\n\t}\n\telseif(is_int($aEnd) || is_float($aEnd) ) \n\t    $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY);\n\t$this->iVPos = $aPos;\n\t$this->iHeightFactor = $aHeightFactor;\n\t$this->title->Set($aLabel);\n\t$this->caption = new TextProperty($aCaption);\n\t$this->caption->Align(\"left\",\"center\");\n\t$this->leftMark =new PlotMark();\n\t$this->leftMark->Hide();\n\t$this->rightMark=new PlotMark();\n\t$this->rightMark->Hide();\n\t$this->progress = new Progress();\n    }\n\t\n//---------------\n// PUBLIC METHODS\t\n    function SetShadow($aShadow=true,$aColor=\"gray\") {\n\t$this->iShadow=$aShadow;\n\t$this->iShadowColor=$aColor;\n    }\n    \n    function GetMaxDate() {\n\treturn $this->iEnd;\n    }\n\t\n    function SetHeight($aHeight) {\n\t$this->iHeightFactor = $aHeight;\n    }\n\n    function SetColor($aColor) {\n\t$this->iFrameColor = $aColor;\n    }\n\n    function SetFillColor($aColor) {\n\t$this->iFillColor = $aColor;\n    }\n\n    function GetAbsHeight(&$aImg) {\n\tif( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) {\n\t    $m=-1;\n\t    if( is_int($this->iHeightFactor) )\n\t\t$m = $this->iHeightFactor;\n\t    if( $this->leftMark->show ) \n\t\t$m = max($m,$this->leftMark->width*2);\n\t    if( $this->rightMark->show ) \n\t\t$m = max($m,$this->rightMark->width*2);\n\t    return $m;\n\t}\n\telse\n\t    return -1;\n    }\n\t\n    function SetPattern($aPattern,$aColor=\"blue\",$aDensity=95) {\t\t\n\t$this->iPattern = $aPattern;\n\t$this->iPatternColor = $aColor;\n\t$this->iPatternDensity = $aDensity;\n    }\n\n    function Stroke(&$aImg,$aScale) {\n\t$factory = new RectPatternFactory();\n\t$prect = $factory->Create($this->iPattern,$this->iPatternColor);\n\t$prect->SetDensity($this->iPatternDensity);\n\n\t// If height factor is specified as a float between 0,1 then we take it as meaning\n\t// percetage of the scale width between horizontal line.\n\t// If it is an integer > 1 we take it to mean the absolute height in pixels\n\tif( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1)\n\t    $vs = $aScale->GetVertSpacing()*$this->iHeightFactor;\n\telseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 )\n\t    $vs = $this->iHeightFactor;\n\telse\n\t    JpGraphError::RaiseL(6028,$this->iHeightFactor);\n//(\"Specified height (\".$this->iHeightFactor.\") for gantt bar is out of range.\");\n\t\n\t// Clip date to min max dates to show\n\t$st = $aScale->NormalizeDate($this->iStart);\n\t$en = $aScale->NormalizeDate($this->iEnd);\n\t\n\n\t$limst = max($st,$aScale->iStartDate);\n\t$limen = min($en,$aScale->iEndDate);\n\t\t\t\n\t$xt = round($aScale->TranslateDate($limst));\n\t$xb = round($aScale->TranslateDate($limen)); \n\t$yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2));\n\t$yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2));\n\t$middle = round($yt+($yb-$yt)/2);\n\t$this->StrokeActInfo($aImg,$aScale,$middle);\n\n\t// CSIM for title\n\tif( ! empty($this->title->csimtarget) ) {\n\t    $colwidth = $this->title->GetColWidth($aImg);\n\t    $colstarts=array();\n\t    $aScale->actinfo->GetColStart($aImg,$colstarts,true);\n\t    $n = min(count($colwidth),count($this->title->csimtarget));\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$title_xt = $colstarts[$i];\n\t\t$title_xb = $title_xt + $colwidth[$i];\n\t\t$coords = \"$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb\";\n\t\t$this->csimarea .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->title->csimtarget[$i].\"\\\"\";\n\t\tif( ! empty($this->title->csimalt[$i]) ) {\n\t\t    $tmp = $this->title->csimalt[$i];\n\t\t    $this->csimarea .= \" title=\\\"$tmp\\\"\";\n\t\t}\n\t\t$this->csimarea .= \" alt=\\\"$tmp\\\" />\\n\";\n\t    }\n\t}\n\n\t// Check if the bar is totally outside the current scale range\n\tif( $en <  $aScale->iStartDate || $st > $aScale->iEndDate )\n\t\treturn;\n\t\t\t\n\n\t// Remember the positions for the bar\n\t$this->SetConstrainPos($xt,$yt,$xb,$yb);\n\t\t\n\t$prect->ShowFrame(false);\n\t$prect->SetBackground($this->iFillColor);\n\tif( $this->iShadow ) {\n\t    $aImg->SetColor($this->iFrameColor);\n\t    $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor);\t\t\t\t\n\t    $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2));\t\t\t\t\n\t    $prect->Stroke($aImg);\n\t}\n\telse {\t\n\t    $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1));\t\t\t\t\n\t    $prect->Stroke($aImg);\n\t    $aImg->SetColor($this->iFrameColor);\n\t    $aImg->Rectangle($xt,$yt,$xb,$yb);\n\t}\n\n\t// CSIM for bar\n\tif( $this->csimtarget != '' ) {\n\n\t    $coords = \"$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb\";\n\t    $this->csimarea .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".\n\t\t              $this->csimtarget.\"\\\"\";\n\t    if( $this->csimalt != '' ) {\n\t\t$tmp = $this->csimalt;\n\t\t$this->csimarea .= \" title=\\\"$tmp\\\"\";\n\t    }\n\t    $this->csimarea .= \" alt=\\\"$tmp\\\" />\\n\";\n\t}\n\n\t// Draw progress bar inside activity bar\n\tif( $this->progress->iProgress > 0 ) {\n\t\t\n\t    $xtp = $aScale->TranslateDate($st);\n\t    $xbp = $aScale->TranslateDate($en);\n\t    $len = ($xbp-$xtp)*$this->progress->iProgress;\n\n\t    $endpos = $xtp+$len;\n\t    if( $endpos > $xt ) {\n\t\t$len -= ($xt-$xtp); \n\n\t\t// Make sure that the progess bar doesn't extend over the end date\n\t\tif( $xtp+$len-1 > $xb )\n\t\t    $len = $xb - $xtp + 1;\n\t\t\n\t\tif( $xtp < $xt ) \n\t\t    $xtp = $xt;\n\t\t\n\t\t$prog = $factory->Create($this->progress->iPattern,$this->progress->iColor);\n\t\t$prog->SetDensity($this->progress->iDensity);\n\t\t$prog->SetBackground($this->progress->iFillColor);\n\t    \t$barheight = ($yb-$yt+1);\n\t\tif( $this->iShadow ) \n\t\t    $barheight -= $this->iShadowWidth;\n\t\t$progressheight = floor($barheight*$this->progress->iHeight);\n\t\t$marg = ceil(($barheight-$progressheight)/2);\n\t    \t$pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg);\n\t\t$prog->SetPos($pos);\n\t\t$prog->Stroke($aImg);\n\t    }\n\t}\n\t\n\t// We don't plot the end mark if the bar has been capped\n\tif( $limst == $st ) {\n\t    $y = $middle;\n\t    // We treat the RIGHT and LEFT triangle mark a little bi\n\t    // special so that these marks are placed right under the\n\t    // bar.\n\t    if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) {\n\t\t$y = $yb ; \n\t    }\n\t    $this->leftMark->Stroke($aImg,$xt,$y);\n\t}\n\tif( $limen == $en ) {\n\t    $y = $middle;\n\t    // We treat the RIGHT and LEFT triangle mark a little bi\n\t    // special so that these marks are placed right under the\n\t    // bar.\n\t    if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) {\n\t\t$y = $yb ; \n\t    }\n\t    $this->rightMark->Stroke($aImg,$xb,$y);\n\t    \n\t    $margin = $this->iCaptionMargin;\n\t    if( $this->rightMark->show ) \n\t    \t$margin += $this->rightMark->GetWidth();\n\t    $this->caption->Stroke($aImg,$xb+$margin,$middle);\t\t\n\t}\n    }\n}\n\n//===================================================\n// CLASS MileStone\n// Responsible for formatting individual milestones\n//===================================================\nclass MileStone extends GanttPlotObject {\n    var $mark;\n\t\n//---------------\n// CONSTRUCTOR\t\n    function MileStone($aVPos,$aLabel,$aDate,$aCaption=\"\") {\n\tGanttPlotObject::GanttPlotObject();\n\t$this->caption->Set($aCaption);\n\t$this->caption->Align(\"left\",\"center\");\n\t$this->caption->SetFont(FF_FONT1,FS_BOLD);\n\t$this->title->Set($aLabel);\n\t$this->title->SetColor(\"darkred\");\n\t$this->mark = new PlotMark();\n\t$this->mark->SetWidth(10);\n\t$this->mark->SetType(MARK_DIAMOND);\n\t$this->mark->SetColor(\"darkred\");\n\t$this->mark->SetFillColor(\"darkred\");\n\t$this->iVPos = $aVPos;\n\t$this->iStart = $aDate;\n    }\n\t\n//---------------\n// PUBLIC METHODS\t\n\t\n    function GetAbsHeight(&$aImg) {\n\treturn max($this->title->GetHeight($aImg),$this->mark->GetWidth());\n    }\n\t\t\n    function Stroke(&$aImg,$aScale) {\n\t// Put the mark in the middle at the middle of the day\n\t$d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2;\n\t$x = $aScale->TranslateDate($d);\n\t$y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2);\n\n\t$this->StrokeActInfo($aImg,$aScale,$y);\n\n\t// CSIM for title\n\tif( ! empty($this->title->csimtarget) ) {\n\t    \n\t    $yt = round($y - $this->title->GetHeight($aImg)/2);\n\t    $yb = round($y + $this->title->GetHeight($aImg)/2);\n\n\t    $colwidth = $this->title->GetColWidth($aImg);\n\t    $colstarts=array();\n\t    $aScale->actinfo->GetColStart($aImg,$colstarts,true);\n\t    $n = min(count($colwidth),count($this->title->csimtarget));\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$title_xt = $colstarts[$i];\n\t\t$title_xb = $title_xt + $colwidth[$i];\n\t\t$coords = \"$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb\";\n\t\t$this->csimarea .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->title->csimtarget[$i].\"\\\"\";\n\t\tif( ! empty($this->title->csimalt[$i]) ) {\n\t\t    $tmp = $this->title->csimalt[$i];\n\t\t    $this->csimarea .= \" title=\\\"$tmp\\\"\";\n\t\t}\n\t\t$this->csimarea .= \" alt=\\\"$tmp\\\" />\\n\";\n\t    }\n\t}\n\n\tif( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )\n\t\treturn;\n\n\t// Remember the coordinates for any constrains linking to\n\t// this milestone\n\t$w = $this->mark->GetWidth()/2;\n\t$this->SetConstrainPos($x,round($y-$w),$x,round($y+$w));\n\t\n\t// Setup CSIM\n\tif( $this->csimtarget != '' ) {\n\t    $this->mark->SetCSIMTarget( $this->csimtarget );\n\t    $this->mark->SetCSIMAlt( $this->csimalt );\n\t}\n\t\t\n\t$this->mark->Stroke($aImg,$x,$y);\t\t\n\t$this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y);\n\n\t$this->csimarea .= $this->mark->GetCSIMAreas();\n    }\n}\n\n\n//===================================================\n// CLASS GanttVLine\n// Responsible for formatting individual milestones\n//===================================================\n\nclass TextPropertyBelow extends TextProperty {\n    function TextPropertyBelow($aTxt='') {\n\tparent::TextProperty($aTxt);\n    }\n\n    function GetColWidth(&$aImg,$margin) {\n\t// Since we are not stroking the title in the columns\n\t// but rather under the graph we want this to return 0.\n\treturn array(0);\n    }\n}\n\nclass GanttVLine extends GanttPlotObject {\n\n    var $iLine,$title_margin=3;\n    var $iDayOffset=1;\t// Defult to right edge of day\n\t\n//---------------\n// CONSTRUCTOR\t\n    function GanttVLine($aDate,$aTitle=\"\",$aColor=\"black\",$aWeight=3,$aStyle=\"dashed\") {\n\tGanttPlotObject::GanttPlotObject();\n\t$this->iLine = new LineProperty();\n\t$this->iLine->SetColor($aColor);\n\t$this->iLine->SetWeight($aWeight);\n\t$this->iLine->SetStyle($aStyle);\n\t$this->iStart = $aDate;\n\t$this->title = new TextPropertyBelow();\n\t$this->title->Set($aTitle);\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    function SetDayOffset($aOff=0.5) {\n\tif( $aOff < 0.0 || $aOff > 1.0 )\n\t    JpGraphError::RaiseL(6029);\n//(\"Offset for vertical line must be in range [0,1]\");\n\t$this->iDayOffset = $aOff;\n    }\n\t\n    function SetTitleMargin($aMarg) {\n\t$this->title_margin = $aMarg;\n    }\n\t\n    function Stroke(&$aImg,$aScale) {\n\t$d = $aScale->NormalizeDate($this->iStart);\n\tif( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )\n\t    return;\t\n\tif($this->iDayOffset != 0.0)\n\t    $d += 24*60*60*$this->iDayOffset;\t\n\t$x = $aScale->TranslateDate($d);\t\n\t$y1 = $aScale->iVertHeaderSize+$aImg->top_margin;\n\t$y2 = $aImg->height - $aImg->bottom_margin;\t\n\t$this->iLine->Stroke($aImg,$x,$y1,$x,$y2);\n\t$this->title->Align(\"center\",\"top\");\n\t$this->title->Stroke($aImg,$x,$y2+$this->title_margin);\n    }\t\n}\n\n//===================================================\n// CLASS LinkArrow\n// Handles the drawing of a an arrow \n//===================================================\nclass LinkArrow {\n    var $ix,$iy;\n    var $isizespec = array(\n\tarray(2,3),array(3,5),array(3,8),array(6,15),array(8,22));\n    var $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2;\n    var $iColor='black';\n\n    function LinkArrow($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) {\n\t$this->iDirection = $aDirection;\n\t$this->iType = $aType;\n\t$this->iSize = $aSize;\n\t$this->ix = $x;\n\t$this->iy = $y;\n    }\n    \n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\n    function SetSize($aSize) {\n\t$this->iSize = $aSize;\n    }\n\n    function SetType($aType) {\n\t$this->iType = $aType;\n    }\n\n    function Stroke(&$aImg) {\n\tlist($dx,$dy) = $this->isizespec[$this->iSize];\n\t$x = $this->ix;\n\t$y = $this->iy;\n\tswitch ( $this->iDirection ) {\n\t    case ARROW_DOWN:\n\t\t$c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y);\n\t\tbreak;\n\t    case ARROW_UP:\n\t\t$c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y);\n\t\tbreak;\n\t    case ARROW_LEFT:\n\t\t$c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y);\n\t\tbreak;\n\t    case ARROW_RIGHT:\n\t\t$c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y);\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(6030);\n//('Unknown arrow direction for link.');\n\t\tdie();\n\t\tbreak;\n\t}\n\t$aImg->SetColor($this->iColor);\n\tswitch( $this->iType ) {\n\t    case ARROWT_SOLID:\n\t\t$aImg->FilledPolygon($c);\n\t\tbreak;\n\t    case ARROWT_OPEN:\n\t\t$aImg->Polygon($c);\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(6031);\n//('Unknown arrow type for link.');\n\t\tdie();\n\t\tbreak;\t\t\n\t}\n    }\n}\n\n//===================================================\n// CLASS GanttLink\n// Handles the drawing of a link line between 2 points\n//===================================================\n\nclass GanttLink {\n    var $ix1,$ix2,$iy1,$iy2;\n    var $iPathType=2,$iPathExtend=15;\n    var $iColor='black',$iWeight=1;\n    var $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID;\n\n    function GanttLink($x1=0,$y1=0,$x2=0,$y2=0) {\n\t$this->ix1 = $x1;\n\t$this->ix2 = $x2;\n\t$this->iy1 = $y1;\n\t$this->iy2 = $y2;\n    }\n\n    function SetPos($x1,$y1,$x2,$y2) {\n\t$this->ix1 = $x1;\n\t$this->ix2 = $x2;\n\t$this->iy1 = $y1;\n\t$this->iy2 = $y2;\n    }\n\n    function SetPath($aPath) {\n\t$this->iPathType = $aPath;\n    }\n\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\n    function SetArrow($aSize,$aType=ARROWT_SOLID) {\n\t$this->iArrowSize = $aSize;\n\t$this->iArrowType = $aType;\n    }\n    \n    function SetWeight($aWeight) {\n\t$this->iWeight = $aWeight;\n    }\n\n    function Stroke(&$aImg) {\n\t// The way the path for the arrow is constructed is partly based\n\t// on some heuristics. This is not an exact science but draws the\n\t// path in a way that, for me, makes esthetic sence. For example\n\t// if the start and end activities are very close we make a small\n\t// detour to endter the target horixontally. If there are more\n\t// space between axctivities then no suh detour is made and the \n\t// target is \"hit\" directly vertical. I have tried to keep this\n\t// simple. no doubt this could become almost infinitive complex\n\t// and have some real AI. Feel free to modify this.\n\t// This will no-doubt be tweaked as times go by. One design aim\n\t// is to avoid having the user choose what types of arrow\n\t// he wants.\n\n\t// The arrow is drawn between (x1,y1) to (x2,y2)\n\t$x1 = $this->ix1 ;\n\t$x2 = $this->ix2 ;\n\t$y1 = $this->iy1 ;\n\t$y2 = $this->iy2 ;\n\n\t// Depending on if the target is below or above we have to\n\t// handle thi different.\n\tif( $y2 > $y1 ) {\n\t    $arrowtype = ARROW_DOWN;\n\t    $midy = round(($y2-$y1)/2+$y1);\n\t    if( $x2 > $x1 ) {\n\t\tswitch ( $this->iPathType  ) {\n\t\t    case 0:\n\t\t\t$c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 1:\n\t\t    case 2:\n\t\t    case 3:\n\t\t\t$c = array($x1,$y1,$x2,$y1,$x2,$y2);\n\t\t\tbreak;\n\t\t    default:\n\t\t\tJpGraphError::RaiseL(6032,$this->iPathType);\n//('Internal error: Unknown path type (='.$this->iPathType .') specified for link.');\n\t\t\texit(1);\n\t\t\tbreak;\n\t\t}\n\t    }\n\t    else {\n\t\tswitch ( $this->iPathType  ) {\n\t\t    case 0:\n\t\t    case 1:\n\t\t\t$c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 2:\n\t\t\t// Always extend out horizontally a bit from the first point\n\t\t\t// If we draw a link back in time (end to start) and the bars \n\t\t\t// are very close we also change the path so it comes in from \n\t\t\t// the left on the activity\n\t\t\t$c = array($x1,$y1,$x1+$this->iPathExtend,$y1,\n\t\t\t\t   $x1+$this->iPathExtend,$midy,\n\t\t\t\t   $x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 3:\n\t\t\tif( $y2-$midy < 6 ) {\n\t\t\t    $c = array($x1,$y1,$x1,$midy,\n\t\t\t\t       $x2-$this->iPathExtend,$midy,\n\t\t\t\t       $x2-$this->iPathExtend,$y2,\n\t\t\t\t       $x2,$y2);\n\t\t\t    $arrowtype = ARROW_RIGHT;\n\t\t\t}\n\t\t\telse {\n\t\t\t    $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\t}\n\t\t\tbreak;\n\t\t    default:\n\t\t\tJpGraphError::RaiseL(6032,$this->iPathType);\n//('Internal error: Unknown path type specified for link.');\n\t\t\texit(1);\n\t\t\tbreak;\n\t\t}\n\t    }\n\t    $arrow = new LinkArrow($x2,$y2,$arrowtype);\n\t}\n\telse {\n\t    // Y2 < Y1\n\t    $arrowtype = ARROW_UP;\n\t    $midy = round(($y1-$y2)/2+$y2);\n\t    if( $x2 > $x1 ) {\n\t\tswitch ( $this->iPathType  ) {\n\t\t    case 0:\n\t\t    case 1:\n\t\t\t$c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 3:\n\t\t\tif( $midy-$y2 < 8 ) {\n\t\t\t    $arrowtype = ARROW_RIGHT;\n\t\t\t    $c = array($x1,$y1,$x1,$y2,$x2,$y2);\n\t\t\t}\n\t\t\telse {\n\t\t\t    $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\t}\n\t\t\tbreak;\n\t\t    default:\n\t\t\tJpGraphError::RaiseL(6032,$this->iPathType);\n//('Internal error: Unknown path type specified for link.');\n\t\t\tbreak;\n\t\t}\n\t    }\n\t    else {\n\t\tswitch ( $this->iPathType  ) {\n\t\t    case 0:\n\t\t    case 1:\n\t\t\t$c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 2:\n\t\t\t// Always extend out horizontally a bit from the first point\n\t\t\t$c = array($x1,$y1,$x1+$this->iPathExtend,$y1,\n\t\t\t\t   $x1+$this->iPathExtend,$midy,\n\t\t\t\t   $x2,$midy,$x2,$y2);\n\t\t\tbreak;\n\t\t    case 3:\n\t\t\tif( $midy-$y2 < 16 ) {\n\t\t\t    $arrowtype = ARROW_RIGHT;\n\t\t\t    $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy,\n\t\t\t\t       $x2-$this->iPathExtend,$y2,\n\t\t\t\t       $x2,$y2);\n\t\t\t}\n\t\t\telse {\n\t\t\t    $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);\n\t\t\t}\n\t\t\tbreak;\n\t\t    default:\n\t\t\tJpGraphError::RaiseL(6032,$this->iPathType);\n//('Internal error: Unknown path type specified for link.');\n\t\t\tbreak;\n\t\t}\n\t    }\n\t    $arrow = new LinkArrow($x2,$y2,$arrowtype);\n\t}\n\t$aImg->SetColor($this->iColor);\n\t$aImg->SetLineWeight($this->iWeight);\n\t$aImg->Polygon($c);\n\t$aImg->SetLineWeight(1);\n\t$arrow->SetColor($this->iColor);\n\t$arrow->SetSize($this->iArrowSize);\n\t$arrow->SetType($this->iArrowType);\n\t$arrow->Stroke($aImg);\n    }\n}\n\n// <EOF>\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_gb2312.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_GB2312.PHP\n// Description:\tPHP4 Graph Plotting library. Chinese font conversions\n// Created: \t2003-05-30\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_gb2312.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n\nclass GB2312toUTF8 {\n// --------------------------------------------------------------------\n// This code table is used to translate GB2312 code (key) to \n// it's corresponding Unicode value (data)\n// --------------------------------------------------------------------\n    var $codetable = array( \n\t8481 => 12288, 8482 => 12289, 8483 => 12290, 8484 => 12539, 8485 => 713,\n\t8486 => 711, 8487 => 168, 8488 => 12291, 8489 => 12293, 8490 => 8213,\n\t8491 => 65374, 8492 => 8214, 8493 => 8230, 8494 => 8216, 8495 => 8217,\n\t8496 => 8220, 8497 => 8221, 8498 => 12308, 8499 => 12309, 8500 => 12296,\n\t8501 => 12297, 8502 => 12298, 8503 => 12299, 8504 => 12300, 8505 => 12301,\n\t8506 => 12302, 8507 => 12303, 8508 => 12310, 8509 => 12311, 8510 => 12304,\n\t8511 => 12305, 8512 => 177, 8513 => 215, 8514 => 247, 8515 => 8758,\n\t8516 => 8743, 8517 => 8744, 8518 => 8721, 8519 => 8719, 8520 => 8746,\n\t8521 => 8745, 8522 => 8712, 8523 => 8759, 8524 => 8730, 8525 => 8869,\n\t8526 => 8741, 8527 => 8736, 8528 => 8978, 8529 => 8857, 8530 => 8747,\n\t8531 => 8750, 8532 => 8801, 8533 => 8780, 8534 => 8776, 8535 => 8765,\n\t8536 => 8733, 8537 => 8800, 8538 => 8814, 8539 => 8815, 8540 => 8804,\n\t8541 => 8805, 8542 => 8734, 8543 => 8757, 8544 => 8756, 8545 => 9794,\n\t8546 => 9792, 8547 => 176, 8548 => 8242, 8549 => 8243, 8550 => 8451,\n\t8551 => 65284, 8552 => 164, 8553 => 65504, 8554 => 65505, 8555 => 8240,\n\t8556 => 167, 8557 => 8470, 8558 => 9734, 8559 => 9733, 8560 => 9675,\n\t8561 => 9679, 8562 => 9678, 8563 => 9671, 8564 => 9670, 8565 => 9633,\n\t8566 => 9632, 8567 => 9651, 8568 => 9650, 8569 => 8251, 8570 => 8594,\n\t8571 => 8592, 8572 => 8593, 8573 => 8595, 8574 => 12307, 8753 => 9352,\n\t8754 => 9353, 8755 => 9354, 8756 => 9355, 8757 => 9356, 8758 => 9357,\n\t8759 => 9358, 8760 => 9359, 8761 => 9360, 8762 => 9361, 8763 => 9362,\n\t8764 => 9363, 8765 => 9364, 8766 => 9365, 8767 => 9366, 8768 => 9367,\n\t8769 => 9368, 8770 => 9369, 8771 => 9370, 8772 => 9371, 8773 => 9332,\n\t8774 => 9333, 8775 => 9334, 8776 => 9335, 8777 => 9336, 8778 => 9337,\n\t8779 => 9338, 8780 => 9339, 8781 => 9340, 8782 => 9341, 8783 => 9342,\n\t8784 => 9343, 8785 => 9344, 8786 => 9345, 8787 => 9346, 8788 => 9347,\n\t8789 => 9348, 8790 => 9349, 8791 => 9350, 8792 => 9351, 8793 => 9312,\n\t8794 => 9313, 8795 => 9314, 8796 => 9315, 8797 => 9316, 8798 => 9317,\n\t8799 => 9318, 8800 => 9319, 8801 => 9320, 8802 => 9321, 8805 => 12832,\n\t8806 => 12833, 8807 => 12834, 8808 => 12835, 8809 => 12836, 8810 => 12837,\n\t8811 => 12838, 8812 => 12839, 8813 => 12840, 8814 => 12841, 8817 => 8544,\n\t8818 => 8545, 8819 => 8546, 8820 => 8547, 8821 => 8548, 8822 => 8549,\n\t8823 => 8550, 8824 => 8551, 8825 => 8552, 8826 => 8553, 8827 => 8554,\n\t8828 => 8555, 8993 => 65281, 8994 => 65282, 8995 => 65283, 8996 => 65509,\n\t8997 => 65285, 8998 => 65286, 8999 => 65287, 9000 => 65288, 9001 => 65289,\n\t9002 => 65290, 9003 => 65291, 9004 => 65292, 9005 => 65293, 9006 => 65294,\n\t9007 => 65295, 9008 => 65296, 9009 => 65297, 9010 => 65298, 9011 => 65299,\n\t9012 => 65300, 9013 => 65301, 9014 => 65302, 9015 => 65303, 9016 => 65304,\n\t9017 => 65305, 9018 => 65306, 9019 => 65307, 9020 => 65308, 9021 => 65309,\n\t9022 => 65310, 9023 => 65311, 9024 => 65312, 9025 => 65313, 9026 => 65314,\n\t9027 => 65315, 9028 => 65316, 9029 => 65317, 9030 => 65318, 9031 => 65319,\n\t9032 => 65320, 9033 => 65321, 9034 => 65322, 9035 => 65323, 9036 => 65324,\n\t9037 => 65325, 9038 => 65326, 9039 => 65327, 9040 => 65328, 9041 => 65329,\n\t9042 => 65330, 9043 => 65331, 9044 => 65332, 9045 => 65333, 9046 => 65334,\n\t9047 => 65335, 9048 => 65336, 9049 => 65337, 9050 => 65338, 9051 => 65339,\n\t9052 => 65340, 9053 => 65341, 9054 => 65342, 9055 => 65343, 9056 => 65344,\n\t9057 => 65345, 9058 => 65346, 9059 => 65347, 9060 => 65348, 9061 => 65349,\n\t9062 => 65350, 9063 => 65351, 9064 => 65352, 9065 => 65353, 9066 => 65354,\n\t9067 => 65355, 9068 => 65356, 9069 => 65357, 9070 => 65358, 9071 => 65359,\n\t9072 => 65360, 9073 => 65361, 9074 => 65362, 9075 => 65363, 9076 => 65364,\n\t9077 => 65365, 9078 => 65366, 9079 => 65367, 9080 => 65368, 9081 => 65369,\n\t9082 => 65370, 9083 => 65371, 9084 => 65372, 9085 => 65373, 9086 => 65507,\n\t9249 => 12353, 9250 => 12354, 9251 => 12355, 9252 => 12356, 9253 => 12357,\n\t9254 => 12358, 9255 => 12359, 9256 => 12360, 9257 => 12361, 9258 => 12362,\n\t9259 => 12363, 9260 => 12364, 9261 => 12365, 9262 => 12366, 9263 => 12367,\n\t9264 => 12368, 9265 => 12369, 9266 => 12370, 9267 => 12371, 9268 => 12372,\n\t9269 => 12373, 9270 => 12374, 9271 => 12375, 9272 => 12376, 9273 => 12377,\n\t9274 => 12378, 9275 => 12379, 9276 => 12380, 9277 => 12381, 9278 => 12382,\n\t9279 => 12383, 9280 => 12384, 9281 => 12385, 9282 => 12386, 9283 => 12387,\n\t9284 => 12388, 9285 => 12389, 9286 => 12390, 9287 => 12391, 9288 => 12392,\n\t9289 => 12393, 9290 => 12394, 9291 => 12395, 9292 => 12396, 9293 => 12397,\n\t9294 => 12398, 9295 => 12399, 9296 => 12400, 9297 => 12401, 9298 => 12402,\n\t9299 => 12403, 9300 => 12404, 9301 => 12405, 9302 => 12406, 9303 => 12407,\n\t9304 => 12408, 9305 => 12409, 9306 => 12410, 9307 => 12411, 9308 => 12412,\n\t9309 => 12413, 9310 => 12414, 9311 => 12415, 9312 => 12416, 9313 => 12417,\n\t9314 => 12418, 9315 => 12419, 9316 => 12420, 9317 => 12421, 9318 => 12422,\n\t9319 => 12423, 9320 => 12424, 9321 => 12425, 9322 => 12426, 9323 => 12427,\n\t9324 => 12428, 9325 => 12429, 9326 => 12430, 9327 => 12431, 9328 => 12432,\n\t9329 => 12433, 9330 => 12434, 9331 => 12435, 9505 => 12449, 9506 => 12450,\n\t9507 => 12451, 9508 => 12452, 9509 => 12453, 9510 => 12454, 9511 => 12455,\n\t9512 => 12456, 9513 => 12457, 9514 => 12458, 9515 => 12459, 9516 => 12460,\n\t9517 => 12461, 9518 => 12462, 9519 => 12463, 9520 => 12464, 9521 => 12465,\n\t9522 => 12466, 9523 => 12467, 9524 => 12468, 9525 => 12469, 9526 => 12470,\n\t9527 => 12471, 9528 => 12472, 9529 => 12473, 9530 => 12474, 9531 => 12475,\n\t9532 => 12476, 9533 => 12477, 9534 => 12478, 9535 => 12479, 9536 => 12480,\n\t9537 => 12481, 9538 => 12482, 9539 => 12483, 9540 => 12484, 9541 => 12485,\n\t9542 => 12486, 9543 => 12487, 9544 => 12488, 9545 => 12489, 9546 => 12490,\n\t9547 => 12491, 9548 => 12492, 9549 => 12493, 9550 => 12494, 9551 => 12495,\n\t9552 => 12496, 9553 => 12497, 9554 => 12498, 9555 => 12499, 9556 => 12500,\n\t9557 => 12501, 9558 => 12502, 9559 => 12503, 9560 => 12504, 9561 => 12505,\n\t9562 => 12506, 9563 => 12507, 9564 => 12508, 9565 => 12509, 9566 => 12510,\n\t9567 => 12511, 9568 => 12512, 9569 => 12513, 9570 => 12514, 9571 => 12515,\n\t9572 => 12516, 9573 => 12517, 9574 => 12518, 9575 => 12519, 9576 => 12520,\n\t9577 => 12521, 9578 => 12522, 9579 => 12523, 9580 => 12524, 9581 => 12525,\n\t9582 => 12526, 9583 => 12527, 9584 => 12528, 9585 => 12529, 9586 => 12530,\n\t9587 => 12531, 9588 => 12532, 9589 => 12533, 9590 => 12534, 9761 => 913,\n\t9762 => 914, 9763 => 915, 9764 => 916, 9765 => 917, 9766 => 918,\n\t9767 => 919, 9768 => 920, 9769 => 921, 9770 => 922, 9771 => 923,\n\t9772 => 924, 9773 => 925, 9774 => 926, 9775 => 927, 9776 => 928,\n\t9777 => 929, 9778 => 931, 9779 => 932, 9780 => 933, 9781 => 934,\n\t9782 => 935, 9783 => 936, 9784 => 937, 9793 => 945, 9794 => 946,\n\t9795 => 947, 9796 => 948, 9797 => 949, 9798 => 950, 9799 => 951,\n\t9800 => 952, 9801 => 953, 9802 => 954, 9803 => 955, 9804 => 956,\n\t9805 => 957, 9806 => 958, 9807 => 959, 9808 => 960, 9809 => 961,\n\t9810 => 963, 9811 => 964, 9812 => 965, 9813 => 966, 9814 => 967,\n\t9815 => 968, 9816 => 969, 10017 => 1040, 10018 => 1041, 10019 => 1042,\n\t10020 => 1043, 10021 => 1044, 10022 => 1045, 10023 => 1025, 10024 => 1046,\n\t10025 => 1047, 10026 => 1048, 10027 => 1049, 10028 => 1050, 10029 => 1051,\n\t10030 => 1052, 10031 => 1053, 10032 => 1054, 10033 => 1055, 10034 => 1056,\n\t10035 => 1057, 10036 => 1058, 10037 => 1059, 10038 => 1060, 10039 => 1061,\n\t10040 => 1062, 10041 => 1063, 10042 => 1064, 10043 => 1065, 10044 => 1066,\n\t10045 => 1067, 10046 => 1068, 10047 => 1069, 10048 => 1070, 10049 => 1071,\n\t10065 => 1072, 10066 => 1073, 10067 => 1074, 10068 => 1075, 10069 => 1076,\n\t10070 => 1077, 10071 => 1105, 10072 => 1078, 10073 => 1079, 10074 => 1080,\n\t10075 => 1081, 10076 => 1082, 10077 => 1083, 10078 => 1084, 10079 => 1085,\n\t10080 => 1086, 10081 => 1087, 10082 => 1088, 10083 => 1089, 10084 => 1090,\n\t10085 => 1091, 10086 => 1092, 10087 => 1093, 10088 => 1094, 10089 => 1095,\n\t10090 => 1096, 10091 => 1097, 10092 => 1098, 10093 => 1099, 10094 => 1100,\n\t10095 => 1101, 10096 => 1102, 10097 => 1103, 10273 => 257, 10274 => 225,\n\t10275 => 462, 10276 => 224, 10277 => 275, 10278 => 233, 10279 => 283,\n\t10280 => 232, 10281 => 299, 10282 => 237, 10283 => 464, 10284 => 236,\n\t10285 => 333, 10286 => 243, 10287 => 466, 10288 => 242, 10289 => 363,\n\t10290 => 250, 10291 => 468, 10292 => 249, 10293 => 470, 10294 => 472,\n\t10295 => 474, 10296 => 476, 10297 => 252, 10298 => 234, 10309 => 12549,\n\t10310 => 12550, 10311 => 12551, 10312 => 12552, 10313 => 12553, 10314 => 12554,\n\t10315 => 12555, 10316 => 12556, 10317 => 12557, 10318 => 12558, 10319 => 12559,\n\t10320 => 12560, 10321 => 12561, 10322 => 12562, 10323 => 12563, 10324 => 12564,\n\t10325 => 12565, 10326 => 12566, 10327 => 12567, 10328 => 12568, 10329 => 12569,\n\t10330 => 12570, 10331 => 12571, 10332 => 12572, 10333 => 12573, 10334 => 12574,\n\t10335 => 12575, 10336 => 12576, 10337 => 12577, 10338 => 12578, 10339 => 12579,\n\t10340 => 12580, 10341 => 12581, 10342 => 12582, 10343 => 12583, 10344 => 12584,\n\t10345 => 12585, 10532 => 9472, 10533 => 9473, 10534 => 9474, 10535 => 9475,\n\t10536 => 9476, 10537 => 9477, 10538 => 9478, 10539 => 9479, 10540 => 9480,\n\t10541 => 9481, 10542 => 9482, 10543 => 9483, 10544 => 9484, 10545 => 9485,\n\t10546 => 9486, 10547 => 9487, 10548 => 9488, 10549 => 9489, 10550 => 9490,\n\t10551 => 9491, 10552 => 9492, 10553 => 9493, 10554 => 9494, 10555 => 9495,\n\t10556 => 9496, 10557 => 9497, 10558 => 9498, 10559 => 9499, 10560 => 9500,\n\t10561 => 9501, 10562 => 9502, 10563 => 9503, 10564 => 9504, 10565 => 9505,\n\t10566 => 9506, 10567 => 9507, 10568 => 9508, 10569 => 9509, 10570 => 9510,\n\t10571 => 9511, 10572 => 9512, 10573 => 9513, 10574 => 9514, 10575 => 9515,\n\t10576 => 9516, 10577 => 9517, 10578 => 9518, 10579 => 9519, 10580 => 9520,\n\t10581 => 9521, 10582 => 9522, 10583 => 9523, 10584 => 9524, 10585 => 9525,\n\t10586 => 9526, 10587 => 9527, 10588 => 9528, 10589 => 9529, 10590 => 9530,\n\t10591 => 9531, 10592 => 9532, 10593 => 9533, 10594 => 9534, 10595 => 9535,\n\t10596 => 9536, 10597 => 9537, 10598 => 9538, 10599 => 9539, 10600 => 9540,\n\t10601 => 9541, 10602 => 9542, 10603 => 9543, 10604 => 9544, 10605 => 9545,\n\t10606 => 9546, 10607 => 9547, 12321 => 21834, 12322 => 38463, 12323 => 22467,\n\t12324 => 25384, 12325 => 21710, 12326 => 21769, 12327 => 21696, 12328 => 30353,\n\t12329 => 30284, 12330 => 34108, 12331 => 30702, 12332 => 33406, 12333 => 30861,\n\t12334 => 29233, 12335 => 38552, 12336 => 38797, 12337 => 27688, 12338 => 23433,\n\t12339 => 20474, 12340 => 25353, 12341 => 26263, 12342 => 23736, 12343 => 33018,\n\t12344 => 26696, 12345 => 32942, 12346 => 26114, 12347 => 30414, 12348 => 20985,\n\t12349 => 25942, 12350 => 29100, 12351 => 32753, 12352 => 34948, 12353 => 20658,\n\t12354 => 22885, 12355 => 25034, 12356 => 28595, 12357 => 33453, 12358 => 25420,\n\t12359 => 25170, 12360 => 21485, 12361 => 21543, 12362 => 31494, 12363 => 20843,\n\t12364 => 30116, 12365 => 24052, 12366 => 25300, 12367 => 36299, 12368 => 38774,\n\t12369 => 25226, 12370 => 32793, 12371 => 22365, 12372 => 38712, 12373 => 32610,\n\t12374 => 29240, 12375 => 30333, 12376 => 26575, 12377 => 30334, 12378 => 25670,\n\t12379 => 20336, 12380 => 36133, 12381 => 25308, 12382 => 31255, 12383 => 26001,\n\t12384 => 29677, 12385 => 25644, 12386 => 25203, 12387 => 33324, 12388 => 39041,\n\t12389 => 26495, 12390 => 29256, 12391 => 25198, 12392 => 25292, 12393 => 20276,\n\t12394 => 29923, 12395 => 21322, 12396 => 21150, 12397 => 32458, 12398 => 37030,\n\t12399 => 24110, 12400 => 26758, 12401 => 27036, 12402 => 33152, 12403 => 32465,\n\t12404 => 26834, 12405 => 30917, 12406 => 34444, 12407 => 38225, 12408 => 20621,\n\t12409 => 35876, 12410 => 33502, 12411 => 32990, 12412 => 21253, 12413 => 35090,\n\t12414 => 21093, 12577 => 34180, 12578 => 38649, 12579 => 20445, 12580 => 22561,\n\t12581 => 39281, 12582 => 23453, 12583 => 25265, 12584 => 25253, 12585 => 26292,\n\t12586 => 35961, 12587 => 40077, 12588 => 29190, 12589 => 26479, 12590 => 30865,\n\t12591 => 24754, 12592 => 21329, 12593 => 21271, 12594 => 36744, 12595 => 32972,\n\t12596 => 36125, 12597 => 38049, 12598 => 20493, 12599 => 29384, 12600 => 22791,\n\t12601 => 24811, 12602 => 28953, 12603 => 34987, 12604 => 22868, 12605 => 33519,\n\t12606 => 26412, 12607 => 31528, 12608 => 23849, 12609 => 32503, 12610 => 29997,\n\t12611 => 27893, 12612 => 36454, 12613 => 36856, 12614 => 36924, 12615 => 40763,\n\t12616 => 27604, 12617 => 37145, 12618 => 31508, 12619 => 24444, 12620 => 30887,\n\t12621 => 34006, 12622 => 34109, 12623 => 27605, 12624 => 27609, 12625 => 27606,\n\t12626 => 24065, 12627 => 24199, 12628 => 30201, 12629 => 38381, 12630 => 25949,\n\t12631 => 24330, 12632 => 24517, 12633 => 36767, 12634 => 22721, 12635 => 33218,\n\t12636 => 36991, 12637 => 38491, 12638 => 38829, 12639 => 36793, 12640 => 32534,\n\t12641 => 36140, 12642 => 25153, 12643 => 20415, 12644 => 21464, 12645 => 21342,\n\t12646 => 36776, 12647 => 36777, 12648 => 36779, 12649 => 36941, 12650 => 26631,\n\t12651 => 24426, 12652 => 33176, 12653 => 34920, 12654 => 40150, 12655 => 24971,\n\t12656 => 21035, 12657 => 30250, 12658 => 24428, 12659 => 25996, 12660 => 28626,\n\t12661 => 28392, 12662 => 23486, 12663 => 25672, 12664 => 20853, 12665 => 20912,\n\t12666 => 26564, 12667 => 19993, 12668 => 31177, 12669 => 39292, 12670 => 28851,\n\t12833 => 30149, 12834 => 24182, 12835 => 29627, 12836 => 33760, 12837 => 25773,\n\t12838 => 25320, 12839 => 38069, 12840 => 27874, 12841 => 21338, 12842 => 21187,\n\t12843 => 25615, 12844 => 38082, 12845 => 31636, 12846 => 20271, 12847 => 24091,\n\t12848 => 33334, 12849 => 33046, 12850 => 33162, 12851 => 28196, 12852 => 27850,\n\t12853 => 39539, 12854 => 25429, 12855 => 21340, 12856 => 21754, 12857 => 34917,\n\t12858 => 22496, 12859 => 19981, 12860 => 24067, 12861 => 27493, 12862 => 31807,\n\t12863 => 37096, 12864 => 24598, 12865 => 25830, 12866 => 29468, 12867 => 35009,\n\t12868 => 26448, 12869 => 25165, 12870 => 36130, 12871 => 30572, 12872 => 36393,\n\t12873 => 37319, 12874 => 24425, 12875 => 33756, 12876 => 34081, 12877 => 39184,\n\t12878 => 21442, 12879 => 34453, 12880 => 27531, 12881 => 24813, 12882 => 24808,\n\t12883 => 28799, 12884 => 33485, 12885 => 33329, 12886 => 20179, 12887 => 27815,\n\t12888 => 34255, 12889 => 25805, 12890 => 31961, 12891 => 27133, 12892 => 26361,\n\t12893 => 33609, 12894 => 21397, 12895 => 31574, 12896 => 20391, 12897 => 20876,\n\t12898 => 27979, 12899 => 23618, 12900 => 36461, 12901 => 25554, 12902 => 21449,\n\t12903 => 33580, 12904 => 33590, 12905 => 26597, 12906 => 30900, 12907 => 25661,\n\t12908 => 23519, 12909 => 23700, 12910 => 24046, 12911 => 35815, 12912 => 25286,\n\t12913 => 26612, 12914 => 35962, 12915 => 25600, 12916 => 25530, 12917 => 34633,\n\t12918 => 39307, 12919 => 35863, 12920 => 32544, 12921 => 38130, 12922 => 20135,\n\t12923 => 38416, 12924 => 39076, 12925 => 26124, 12926 => 29462, 13089 => 22330,\n\t13090 => 23581, 13091 => 24120, 13092 => 38271, 13093 => 20607, 13094 => 32928,\n\t13095 => 21378, 13096 => 25950, 13097 => 30021, 13098 => 21809, 13099 => 20513,\n\t13100 => 36229, 13101 => 25220, 13102 => 38046, 13103 => 26397, 13104 => 22066,\n\t13105 => 28526, 13106 => 24034, 13107 => 21557, 13108 => 28818, 13109 => 36710,\n\t13110 => 25199, 13111 => 25764, 13112 => 25507, 13113 => 24443, 13114 => 28552,\n\t13115 => 37108, 13116 => 33251, 13117 => 36784, 13118 => 23576, 13119 => 26216,\n\t13120 => 24561, 13121 => 27785, 13122 => 38472, 13123 => 36225, 13124 => 34924,\n\t13125 => 25745, 13126 => 31216, 13127 => 22478, 13128 => 27225, 13129 => 25104,\n\t13130 => 21576, 13131 => 20056, 13132 => 31243, 13133 => 24809, 13134 => 28548,\n\t13135 => 35802, 13136 => 25215, 13137 => 36894, 13138 => 39563, 13139 => 31204,\n13140 => 21507, 13141 => 30196, 13142 => 25345, 13143 => 21273, 13144 => 27744,\n13145 => 36831, 13146 => 24347, 13147 => 39536, 13148 => 32827, 13149 => 40831,\n13150 => 20360, 13151 => 23610, 13152 => 36196, 13153 => 32709, 13154 => 26021,\n13155 => 28861, 13156 => 20805, 13157 => 20914, 13158 => 34411, 13159 => 23815,\n13160 => 23456, 13161 => 25277, 13162 => 37228, 13163 => 30068, 13164 => 36364,\n13165 => 31264, 13166 => 24833, 13167 => 31609, 13168 => 20167, 13169 => 32504,\n13170 => 30597, 13171 => 19985, 13172 => 33261, 13173 => 21021, 13174 => 20986,\n13175 => 27249, 13176 => 21416, 13177 => 36487, 13178 => 38148, 13179 => 38607,\n13180 => 28353, 13181 => 38500, 13182 => 26970, 13345 => 30784, 13346 => 20648,\n13347 => 30679, 13348 => 25616, 13349 => 35302, 13350 => 22788, 13351 => 25571,\n13352 => 24029, 13353 => 31359, 13354 => 26941, 13355 => 20256, 13356 => 33337,\n13357 => 21912, 13358 => 20018, 13359 => 30126, 13360 => 31383, 13361 => 24162,\n13362 => 24202, 13363 => 38383, 13364 => 21019, 13365 => 21561, 13366 => 28810,\n13367 => 25462, 13368 => 38180, 13369 => 22402, 13370 => 26149, 13371 => 26943,\n13372 => 37255, 13373 => 21767, 13374 => 28147, 13375 => 32431, 13376 => 34850,\n13377 => 25139, 13378 => 32496, 13379 => 30133, 13380 => 33576, 13381 => 30913,\n13382 => 38604, 13383 => 36766, 13384 => 24904, 13385 => 29943, 13386 => 35789,\n13387 => 27492, 13388 => 21050, 13389 => 36176, 13390 => 27425, 13391 => 32874,\n13392 => 33905, 13393 => 22257, 13394 => 21254, 13395 => 20174, 13396 => 19995,\n13397 => 20945, 13398 => 31895, 13399 => 37259, 13400 => 31751, 13401 => 20419,\n13402 => 36479, 13403 => 31713, 13404 => 31388, 13405 => 25703, 13406 => 23828,\n13407 => 20652, 13408 => 33030, 13409 => 30209, 13410 => 31929, 13411 => 28140,\n13412 => 32736, 13413 => 26449, 13414 => 23384, 13415 => 23544, 13416 => 30923,\n13417 => 25774, 13418 => 25619, 13419 => 25514, 13420 => 25387, 13421 => 38169,\n13422 => 25645, 13423 => 36798, 13424 => 31572, 13425 => 30249, 13426 => 25171,\n13427 => 22823, 13428 => 21574, 13429 => 27513, 13430 => 20643, 13431 => 25140,\n13432 => 24102, 13433 => 27526, 13434 => 20195, 13435 => 36151, 13436 => 34955,\n13437 => 24453, 13438 => 36910, 13601 => 24608, 13602 => 32829, 13603 => 25285,\n13604 => 20025, 13605 => 21333, 13606 => 37112, 13607 => 25528, 13608 => 32966,\n13609 => 26086, 13610 => 27694, 13611 => 20294, 13612 => 24814, 13613 => 28129,\n13614 => 35806, 13615 => 24377, 13616 => 34507, 13617 => 24403, 13618 => 25377,\n13619 => 20826, 13620 => 33633, 13621 => 26723, 13622 => 20992, 13623 => 25443,\n13624 => 36424, 13625 => 20498, 13626 => 23707, 13627 => 31095, 13628 => 23548,\n13629 => 21040, 13630 => 31291, 13631 => 24764, 13632 => 36947, 13633 => 30423,\n13634 => 24503, 13635 => 24471, 13636 => 30340, 13637 => 36460, 13638 => 28783,\n13639 => 30331, 13640 => 31561, 13641 => 30634, 13642 => 20979, 13643 => 37011,\n13644 => 22564, 13645 => 20302, 13646 => 28404, 13647 => 36842, 13648 => 25932,\n13649 => 31515, 13650 => 29380, 13651 => 28068, 13652 => 32735, 13653 => 23265,\n13654 => 25269, 13655 => 24213, 13656 => 22320, 13657 => 33922, 13658 => 31532,\n13659 => 24093, 13660 => 24351, 13661 => 36882, 13662 => 32532, 13663 => 39072,\n13664 => 25474, 13665 => 28359, 13666 => 30872, 13667 => 28857, 13668 => 20856,\n13669 => 38747, 13670 => 22443, 13671 => 30005, 13672 => 20291, 13673 => 30008,\n13674 => 24215, 13675 => 24806, 13676 => 22880, 13677 => 28096, 13678 => 27583,\n13679 => 30857, 13680 => 21500, 13681 => 38613, 13682 => 20939, 13683 => 20993,\n13684 => 25481, 13685 => 21514, 13686 => 38035, 13687 => 35843, 13688 => 36300,\n13689 => 29241, 13690 => 30879, 13691 => 34678, 13692 => 36845, 13693 => 35853,\n13694 => 21472, 13857 => 19969, 13858 => 30447, 13859 => 21486, 13860 => 38025,\n13861 => 39030, 13862 => 40718, 13863 => 38189, 13864 => 23450, 13865 => 35746,\n13866 => 20002, 13867 => 19996, 13868 => 20908, 13869 => 33891, 13870 => 25026,\n13871 => 21160, 13872 => 26635, 13873 => 20375, 13874 => 24683, 13875 => 20923,\n13876 => 27934, 13877 => 20828, 13878 => 25238, 13879 => 26007, 13880 => 38497,\n13881 => 35910, 13882 => 36887, 13883 => 30168, 13884 => 37117, 13885 => 30563,\n13886 => 27602, 13887 => 29322, 13888 => 29420, 13889 => 35835, 13890 => 22581,\n13891 => 30585, 13892 => 36172, 13893 => 26460, 13894 => 38208, 13895 => 32922,\n13896 => 24230, 13897 => 28193, 13898 => 22930, 13899 => 31471, 13900 => 30701,\n13901 => 38203, 13902 => 27573, 13903 => 26029, 13904 => 32526, 13905 => 22534,\n13906 => 20817, 13907 => 38431, 13908 => 23545, 13909 => 22697, 13910 => 21544,\n13911 => 36466, 13912 => 25958, 13913 => 39039, 13914 => 22244, 13915 => 38045,\n13916 => 30462, 13917 => 36929, 13918 => 25479, 13919 => 21702, 13920 => 22810,\n13921 => 22842, 13922 => 22427, 13923 => 36530, 13924 => 26421, 13925 => 36346,\n13926 => 33333, 13927 => 21057, 13928 => 24816, 13929 => 22549, 13930 => 34558,\n13931 => 23784, 13932 => 40517, 13933 => 20420, 13934 => 39069, 13935 => 35769,\n13936 => 23077, 13937 => 24694, 13938 => 21380, 13939 => 25212, 13940 => 36943,\n13941 => 37122, 13942 => 39295, 13943 => 24681, 13944 => 32780, 13945 => 20799,\n13946 => 32819, 13947 => 23572, 13948 => 39285, 13949 => 27953, 13950 => 20108,\n14113 => 36144, 14114 => 21457, 14115 => 32602, 14116 => 31567, 14117 => 20240,\n14118 => 20047, 14119 => 38400, 14120 => 27861, 14121 => 29648, 14122 => 34281,\n14123 => 24070, 14124 => 30058, 14125 => 32763, 14126 => 27146, 14127 => 30718,\n14128 => 38034, 14129 => 32321, 14130 => 20961, 14131 => 28902, 14132 => 21453,\n14133 => 36820, 14134 => 33539, 14135 => 36137, 14136 => 29359, 14137 => 39277,\n14138 => 27867, 14139 => 22346, 14140 => 33459, 14141 => 26041, 14142 => 32938,\n14143 => 25151, 14144 => 38450, 14145 => 22952, 14146 => 20223, 14147 => 35775,\n14148 => 32442, 14149 => 25918, 14150 => 33778, 14151 => 38750, 14152 => 21857,\n14153 => 39134, 14154 => 32933, 14155 => 21290, 14156 => 35837, 14157 => 21536,\n14158 => 32954, 14159 => 24223, 14160 => 27832, 14161 => 36153, 14162 => 33452,\n14163 => 37210, 14164 => 21545, 14165 => 27675, 14166 => 20998, 14167 => 32439,\n14168 => 22367, 14169 => 28954, 14170 => 27774, 14171 => 31881, 14172 => 22859,\n14173 => 20221, 14174 => 24575, 14175 => 24868, 14176 => 31914, 14177 => 20016,\n14178 => 23553, 14179 => 26539, 14180 => 34562, 14181 => 23792, 14182 => 38155,\n14183 => 39118, 14184 => 30127, 14185 => 28925, 14186 => 36898, 14187 => 20911,\n14188 => 32541, 14189 => 35773, 14190 => 22857, 14191 => 20964, 14192 => 20315,\n14193 => 21542, 14194 => 22827, 14195 => 25975, 14196 => 32932, 14197 => 23413,\n14198 => 25206, 14199 => 25282, 14200 => 36752, 14201 => 24133, 14202 => 27679,\n14203 => 31526, 14204 => 20239, 14205 => 20440, 14206 => 26381, 14369 => 28014,\n14370 => 28074, 14371 => 31119, 14372 => 34993, 14373 => 24343, 14374 => 29995,\n14375 => 25242, 14376 => 36741, 14377 => 20463, 14378 => 37340, 14379 => 26023,\n14380 => 33071, 14381 => 33105, 14382 => 24220, 14383 => 33104, 14384 => 36212,\n14385 => 21103, 14386 => 35206, 14387 => 36171, 14388 => 22797, 14389 => 20613,\n14390 => 20184, 14391 => 38428, 14392 => 29238, 14393 => 33145, 14394 => 36127,\n14395 => 23500, 14396 => 35747, 14397 => 38468, 14398 => 22919, 14399 => 32538,\n14400 => 21648, 14401 => 22134, 14402 => 22030, 14403 => 35813, 14404 => 25913,\n14405 => 27010, 14406 => 38041, 14407 => 30422, 14408 => 28297, 14409 => 24178,\n14410 => 29976, 14411 => 26438, 14412 => 26577, 14413 => 31487, 14414 => 32925,\n14415 => 36214, 14416 => 24863, 14417 => 31174, 14418 => 25954, 14419 => 36195,\n14420 => 20872, 14421 => 21018, 14422 => 38050, 14423 => 32568, 14424 => 32923,\n14425 => 32434, 14426 => 23703, 14427 => 28207, 14428 => 26464, 14429 => 31705,\n14430 => 30347, 14431 => 39640, 14432 => 33167, 14433 => 32660, 14434 => 31957,\n14435 => 25630, 14436 => 38224, 14437 => 31295, 14438 => 21578, 14439 => 21733,\n14440 => 27468, 14441 => 25601, 14442 => 25096, 14443 => 40509, 14444 => 33011,\n14445 => 30105, 14446 => 21106, 14447 => 38761, 14448 => 33883, 14449 => 26684,\n14450 => 34532, 14451 => 38401, 14452 => 38548, 14453 => 38124, 14454 => 20010,\n14455 => 21508, 14456 => 32473, 14457 => 26681, 14458 => 36319, 14459 => 32789,\n14460 => 26356, 14461 => 24218, 14462 => 32697, 14625 => 22466, 14626 => 32831,\n14627 => 26775, 14628 => 24037, 14629 => 25915, 14630 => 21151, 14631 => 24685,\n14632 => 40858, 14633 => 20379, 14634 => 36524, 14635 => 20844, 14636 => 23467,\n14637 => 24339, 14638 => 24041, 14639 => 27742, 14640 => 25329, 14641 => 36129,\n14642 => 20849, 14643 => 38057, 14644 => 21246, 14645 => 27807, 14646 => 33503,\n14647 => 29399, 14648 => 22434, 14649 => 26500, 14650 => 36141, 14651 => 22815,\n14652 => 36764, 14653 => 33735, 14654 => 21653, 14655 => 31629, 14656 => 20272,\n14657 => 27837, 14658 => 23396, 14659 => 22993, 14660 => 40723, 14661 => 21476,\n14662 => 34506, 14663 => 39592, 14664 => 35895, 14665 => 32929, 14666 => 25925,\n14667 => 39038, 14668 => 22266, 14669 => 38599, 14670 => 21038, 14671 => 29916,\n14672 => 21072, 14673 => 23521, 14674 => 25346, 14675 => 35074, 14676 => 20054,\n14677 => 25296, 14678 => 24618, 14679 => 26874, 14680 => 20851, 14681 => 23448,\n14682 => 20896, 14683 => 35266, 14684 => 31649, 14685 => 39302, 14686 => 32592,\n14687 => 24815, 14688 => 28748, 14689 => 36143, 14690 => 20809, 14691 => 24191,\n14692 => 36891, 14693 => 29808, 14694 => 35268, 14695 => 22317, 14696 => 30789,\n14697 => 24402, 14698 => 40863, 14699 => 38394, 14700 => 36712, 14701 => 39740,\n14702 => 35809, 14703 => 30328, 14704 => 26690, 14705 => 26588, 14706 => 36330,\n14707 => 36149, 14708 => 21053, 14709 => 36746, 14710 => 28378, 14711 => 26829,\n14712 => 38149, 14713 => 37101, 14714 => 22269, 14715 => 26524, 14716 => 35065,\n14717 => 36807, 14718 => 21704, 14881 => 39608, 14882 => 23401, 14883 => 28023,\n14884 => 27686, 14885 => 20133, 14886 => 23475, 14887 => 39559, 14888 => 37219,\n14889 => 25000, 14890 => 37039, 14891 => 38889, 14892 => 21547, 14893 => 28085,\n14894 => 23506, 14895 => 20989, 14896 => 21898, 14897 => 32597, 14898 => 32752,\n14899 => 25788, 14900 => 25421, 14901 => 26097, 14902 => 25022, 14903 => 24717,\n14904 => 28938, 14905 => 27735, 14906 => 27721, 14907 => 22831, 14908 => 26477,\n14909 => 33322, 14910 => 22741, 14911 => 22158, 14912 => 35946, 14913 => 27627,\n14914 => 37085, 14915 => 22909, 14916 => 32791, 14917 => 21495, 14918 => 28009,\n14919 => 21621, 14920 => 21917, 14921 => 33655, 14922 => 33743, 14923 => 26680,\n14924 => 31166, 14925 => 21644, 14926 => 20309, 14927 => 21512, 14928 => 30418,\n14929 => 35977, 14930 => 38402, 14931 => 27827, 14932 => 28088, 14933 => 36203,\n14934 => 35088, 14935 => 40548, 14936 => 36154, 14937 => 22079, 14938 => 40657,\n14939 => 30165, 14940 => 24456, 14941 => 29408, 14942 => 24680, 14943 => 21756,\n14944 => 20136, 14945 => 27178, 14946 => 34913, 14947 => 24658, 14948 => 36720,\n14949 => 21700, 14950 => 28888, 14951 => 34425, 14952 => 40511, 14953 => 27946,\n14954 => 23439, 14955 => 24344, 14956 => 32418, 14957 => 21897, 14958 => 20399,\n14959 => 29492, 14960 => 21564, 14961 => 21402, 14962 => 20505, 14963 => 21518,\n14964 => 21628, 14965 => 20046, 14966 => 24573, 14967 => 29786, 14968 => 22774,\n14969 => 33899, 14970 => 32993, 14971 => 34676, 14972 => 29392, 14973 => 31946,\n14974 => 28246, 15137 => 24359, 15138 => 34382, 15139 => 21804, 15140 => 25252,\n15141 => 20114, 15142 => 27818, 15143 => 25143, 15144 => 33457, 15145 => 21719,\n15146 => 21326, 15147 => 29502, 15148 => 28369, 15149 => 30011, 15150 => 21010,\n15151 => 21270, 15152 => 35805, 15153 => 27088, 15154 => 24458, 15155 => 24576,\n15156 => 28142, 15157 => 22351, 15158 => 27426, 15159 => 29615, 15160 => 26707,\n15161 => 36824, 15162 => 32531, 15163 => 25442, 15164 => 24739, 15165 => 21796,\n15166 => 30186, 15167 => 35938, 15168 => 28949, 15169 => 28067, 15170 => 23462,\n15171 => 24187, 15172 => 33618, 15173 => 24908, 15174 => 40644, 15175 => 30970,\n15176 => 34647, 15177 => 31783, 15178 => 30343, 15179 => 20976, 15180 => 24822,\n15181 => 29004, 15182 => 26179, 15183 => 24140, 15184 => 24653, 15185 => 35854,\n15186 => 28784, 15187 => 25381, 15188 => 36745, 15189 => 24509, 15190 => 24674,\n15191 => 34516, 15192 => 22238, 15193 => 27585, 15194 => 24724, 15195 => 24935,\n15196 => 21321, 15197 => 24800, 15198 => 26214, 15199 => 36159, 15200 => 31229,\n15201 => 20250, 15202 => 28905, 15203 => 27719, 15204 => 35763, 15205 => 35826,\n15206 => 32472, 15207 => 33636, 15208 => 26127, 15209 => 23130, 15210 => 39746,\n15211 => 27985, 15212 => 28151, 15213 => 35905, 15214 => 27963, 15215 => 20249,\n15216 => 28779, 15217 => 33719, 15218 => 25110, 15219 => 24785, 15220 => 38669,\n15221 => 36135, 15222 => 31096, 15223 => 20987, 15224 => 22334, 15225 => 22522,\n15226 => 26426, 15227 => 30072, 15228 => 31293, 15229 => 31215, 15230 => 31637,\n15393 => 32908, 15394 => 39269, 15395 => 36857, 15396 => 28608, 15397 => 35749,\n15398 => 40481, 15399 => 23020, 15400 => 32489, 15401 => 32521, 15402 => 21513,\n15403 => 26497, 15404 => 26840, 15405 => 36753, 15406 => 31821, 15407 => 38598,\n15408 => 21450, 15409 => 24613, 15410 => 30142, 15411 => 27762, 15412 => 21363,\n15413 => 23241, 15414 => 32423, 15415 => 25380, 15416 => 20960, 15417 => 33034,\n15418 => 24049, 15419 => 34015, 15420 => 25216, 15421 => 20864, 15422 => 23395,\n15423 => 20238, 15424 => 31085, 15425 => 21058, 15426 => 24760, 15427 => 27982,\n15428 => 23492, 15429 => 23490, 15430 => 35745, 15431 => 35760, 15432 => 26082,\n15433 => 24524, 15434 => 38469, 15435 => 22931, 15436 => 32487, 15437 => 32426,\n15438 => 22025, 15439 => 26551, 15440 => 22841, 15441 => 20339, 15442 => 23478,\n15443 => 21152, 15444 => 33626, 15445 => 39050, 15446 => 36158, 15447 => 30002,\n15448 => 38078, 15449 => 20551, 15450 => 31292, 15451 => 20215, 15452 => 26550,\n15453 => 39550, 15454 => 23233, 15455 => 27516, 15456 => 30417, 15457 => 22362,\n15458 => 23574, 15459 => 31546, 15460 => 38388, 15461 => 29006, 15462 => 20860,\n15463 => 32937, 15464 => 33392, 15465 => 22904, 15466 => 32516, 15467 => 33575,\n15468 => 26816, 15469 => 26604, 15470 => 30897, 15471 => 30839, 15472 => 25315,\n15473 => 25441, 15474 => 31616, 15475 => 20461, 15476 => 21098, 15477 => 20943,\n15478 => 33616, 15479 => 27099, 15480 => 37492, 15481 => 36341, 15482 => 36145,\n15483 => 35265, 15484 => 38190, 15485 => 31661, 15486 => 20214, 15649 => 20581,\n15650 => 33328, 15651 => 21073, 15652 => 39279, 15653 => 28176, 15654 => 28293,\n15655 => 28071, 15656 => 24314, 15657 => 20725, 15658 => 23004, 15659 => 23558,\n15660 => 27974, 15661 => 27743, 15662 => 30086, 15663 => 33931, 15664 => 26728,\n15665 => 22870, 15666 => 35762, 15667 => 21280, 15668 => 37233, 15669 => 38477,\n15670 => 34121, 15671 => 26898, 15672 => 30977, 15673 => 28966, 15674 => 33014,\n15675 => 20132, 15676 => 37066, 15677 => 27975, 15678 => 39556, 15679 => 23047,\n15680 => 22204, 15681 => 25605, 15682 => 38128, 15683 => 30699, 15684 => 20389,\n15685 => 33050, 15686 => 29409, 15687 => 35282, 15688 => 39290, 15689 => 32564,\n15690 => 32478, 15691 => 21119, 15692 => 25945, 15693 => 37237, 15694 => 36735,\n15695 => 36739, 15696 => 21483, 15697 => 31382, 15698 => 25581, 15699 => 25509,\n15700 => 30342, 15701 => 31224, 15702 => 34903, 15703 => 38454, 15704 => 25130,\n15705 => 21163, 15706 => 33410, 15707 => 26708, 15708 => 26480, 15709 => 25463,\n15710 => 30571, 15711 => 31469, 15712 => 27905, 15713 => 32467, 15714 => 35299,\n15715 => 22992, 15716 => 25106, 15717 => 34249, 15718 => 33445, 15719 => 30028,\n15720 => 20511, 15721 => 20171, 15722 => 30117, 15723 => 35819, 15724 => 23626,\n15725 => 24062, 15726 => 31563, 15727 => 26020, 15728 => 37329, 15729 => 20170,\n15730 => 27941, 15731 => 35167, 15732 => 32039, 15733 => 38182, 15734 => 20165,\n15735 => 35880, 15736 => 36827, 15737 => 38771, 15738 => 26187, 15739 => 31105,\n15740 => 36817, 15741 => 28908, 15742 => 28024, 15905 => 23613, 15906 => 21170,\n15907 => 33606, 15908 => 20834, 15909 => 33550, 15910 => 30555, 15911 => 26230,\n15912 => 40120, 15913 => 20140, 15914 => 24778, 15915 => 31934, 15916 => 31923,\n15917 => 32463, 15918 => 20117, 15919 => 35686, 15920 => 26223, 15921 => 39048,\n15922 => 38745, 15923 => 22659, 15924 => 25964, 15925 => 38236, 15926 => 24452,\n15927 => 30153, 15928 => 38742, 15929 => 31455, 15930 => 31454, 15931 => 20928,\n15932 => 28847, 15933 => 31384, 15934 => 25578, 15935 => 31350, 15936 => 32416,\n15937 => 29590, 15938 => 38893, 15939 => 20037, 15940 => 28792, 15941 => 20061,\n15942 => 37202, 15943 => 21417, 15944 => 25937, 15945 => 26087, 15946 => 33276,\n15947 => 33285, 15948 => 21646, 15949 => 23601, 15950 => 30106, 15951 => 38816,\n15952 => 25304, 15953 => 29401, 15954 => 30141, 15955 => 23621, 15956 => 39545,\n15957 => 33738, 15958 => 23616, 15959 => 21632, 15960 => 30697, 15961 => 20030,\n15962 => 27822, 15963 => 32858, 15964 => 25298, 15965 => 25454, 15966 => 24040,\n15967 => 20855, 15968 => 36317, 15969 => 36382, 15970 => 38191, 15971 => 20465,\n15972 => 21477, 15973 => 24807, 15974 => 28844, 15975 => 21095, 15976 => 25424,\n15977 => 40515, 15978 => 23071, 15979 => 20518, 15980 => 30519, 15981 => 21367,\n15982 => 32482, 15983 => 25733, 15984 => 25899, 15985 => 25225, 15986 => 25496,\n15987 => 20500, 15988 => 29237, 15989 => 35273, 15990 => 20915, 15991 => 35776,\n15992 => 32477, 15993 => 22343, 15994 => 33740, 15995 => 38055, 15996 => 20891,\n15997 => 21531, 15998 => 23803, 16161 => 20426, 16162 => 31459, 16163 => 27994,\n16164 => 37089, 16165 => 39567, 16166 => 21888, 16167 => 21654, 16168 => 21345,\n16169 => 21679, 16170 => 24320, 16171 => 25577, 16172 => 26999, 16173 => 20975,\n16174 => 24936, 16175 => 21002, 16176 => 22570, 16177 => 21208, 16178 => 22350,\n16179 => 30733, 16180 => 30475, 16181 => 24247, 16182 => 24951, 16183 => 31968,\n16184 => 25179, 16185 => 25239, 16186 => 20130, 16187 => 28821, 16188 => 32771,\n16189 => 25335, 16190 => 28900, 16191 => 38752, 16192 => 22391, 16193 => 33499,\n16194 => 26607, 16195 => 26869, 16196 => 30933, 16197 => 39063, 16198 => 31185,\n16199 => 22771, 16200 => 21683, 16201 => 21487, 16202 => 28212, 16203 => 20811,\n16204 => 21051, 16205 => 23458, 16206 => 35838, 16207 => 32943, 16208 => 21827,\n16209 => 22438, 16210 => 24691, 16211 => 22353, 16212 => 21549, 16213 => 31354,\n16214 => 24656, 16215 => 23380, 16216 => 25511, 16217 => 25248, 16218 => 21475,\n16219 => 25187, 16220 => 23495, 16221 => 26543, 16222 => 21741, 16223 => 31391,\n16224 => 33510, 16225 => 37239, 16226 => 24211, 16227 => 35044, 16228 => 22840,\n16229 => 22446, 16230 => 25358, 16231 => 36328, 16232 => 33007, 16233 => 22359,\n16234 => 31607, 16235 => 20393, 16236 => 24555, 16237 => 23485, 16238 => 27454,\n16239 => 21281, 16240 => 31568, 16241 => 29378, 16242 => 26694, 16243 => 30719,\n16244 => 30518, 16245 => 26103, 16246 => 20917, 16247 => 20111, 16248 => 30420,\n16249 => 23743, 16250 => 31397, 16251 => 33909, 16252 => 22862, 16253 => 39745,\n16254 => 20608, 16417 => 39304, 16418 => 24871, 16419 => 28291, 16420 => 22372,\n16421 => 26118, 16422 => 25414, 16423 => 22256, 16424 => 25324, 16425 => 25193,\n16426 => 24275, 16427 => 38420, 16428 => 22403, 16429 => 25289, 16430 => 21895,\n16431 => 34593, 16432 => 33098, 16433 => 36771, 16434 => 21862, 16435 => 33713,\n16436 => 26469, 16437 => 36182, 16438 => 34013, 16439 => 23146, 16440 => 26639,\n16441 => 25318, 16442 => 31726, 16443 => 38417, 16444 => 20848, 16445 => 28572,\n16446 => 35888, 16447 => 25597, 16448 => 35272, 16449 => 25042, 16450 => 32518,\n16451 => 28866, 16452 => 28389, 16453 => 29701, 16454 => 27028, 16455 => 29436,\n16456 => 24266, 16457 => 37070, 16458 => 26391, 16459 => 28010, 16460 => 25438,\n16461 => 21171, 16462 => 29282, 16463 => 32769, 16464 => 20332, 16465 => 23013,\n16466 => 37226, 16467 => 28889, 16468 => 28061, 16469 => 21202, 16470 => 20048,\n16471 => 38647, 16472 => 38253, 16473 => 34174, 16474 => 30922, 16475 => 32047,\n16476 => 20769, 16477 => 22418, 16478 => 25794, 16479 => 32907, 16480 => 31867,\n16481 => 27882, 16482 => 26865, 16483 => 26974, 16484 => 20919, 16485 => 21400,\n16486 => 26792, 16487 => 29313, 16488 => 40654, 16489 => 31729, 16490 => 29432,\n16491 => 31163, 16492 => 28435, 16493 => 29702, 16494 => 26446, 16495 => 37324,\n16496 => 40100, 16497 => 31036, 16498 => 33673, 16499 => 33620, 16500 => 21519,\n16501 => 26647, 16502 => 20029, 16503 => 21385, 16504 => 21169, 16505 => 30782,\n16506 => 21382, 16507 => 21033, 16508 => 20616, 16509 => 20363, 16510 => 20432,\n16673 => 30178, 16674 => 31435, 16675 => 31890, 16676 => 27813, 16677 => 38582,\n16678 => 21147, 16679 => 29827, 16680 => 21737, 16681 => 20457, 16682 => 32852,\n16683 => 33714, 16684 => 36830, 16685 => 38256, 16686 => 24265, 16687 => 24604,\n16688 => 28063, 16689 => 24088, 16690 => 25947, 16691 => 33080, 16692 => 38142,\n16693 => 24651, 16694 => 28860, 16695 => 32451, 16696 => 31918, 16697 => 20937,\n16698 => 26753, 16699 => 31921, 16700 => 33391, 16701 => 20004, 16702 => 36742,\n16703 => 37327, 16704 => 26238, 16705 => 20142, 16706 => 35845, 16707 => 25769,\n16708 => 32842, 16709 => 20698, 16710 => 30103, 16711 => 29134, 16712 => 23525,\n16713 => 36797, 16714 => 28518, 16715 => 20102, 16716 => 25730, 16717 => 38243,\n16718 => 24278, 16719 => 26009, 16720 => 21015, 16721 => 35010, 16722 => 28872,\n16723 => 21155, 16724 => 29454, 16725 => 29747, 16726 => 26519, 16727 => 30967,\n16728 => 38678, 16729 => 20020, 16730 => 37051, 16731 => 40158, 16732 => 28107,\n16733 => 20955, 16734 => 36161, 16735 => 21533, 16736 => 25294, 16737 => 29618,\n16738 => 33777, 16739 => 38646, 16740 => 40836, 16741 => 38083, 16742 => 20278,\n16743 => 32666, 16744 => 20940, 16745 => 28789, 16746 => 38517, 16747 => 23725,\n16748 => 39046, 16749 => 21478, 16750 => 20196, 16751 => 28316, 16752 => 29705,\n16753 => 27060, 16754 => 30827, 16755 => 39311, 16756 => 30041, 16757 => 21016,\n16758 => 30244, 16759 => 27969, 16760 => 26611, 16761 => 20845, 16762 => 40857,\n16763 => 32843, 16764 => 21657, 16765 => 31548, 16766 => 31423, 16929 => 38534,\n16930 => 22404, 16931 => 25314, 16932 => 38471, 16933 => 27004, 16934 => 23044,\n16935 => 25602, 16936 => 31699, 16937 => 28431, 16938 => 38475, 16939 => 33446,\n16940 => 21346, 16941 => 39045, 16942 => 24208, 16943 => 28809, 16944 => 25523,\n16945 => 21348, 16946 => 34383, 16947 => 40065, 16948 => 40595, 16949 => 30860,\n16950 => 38706, 16951 => 36335, 16952 => 36162, 16953 => 40575, 16954 => 28510,\n16955 => 31108, 16956 => 24405, 16957 => 38470, 16958 => 25134, 16959 => 39540,\n16960 => 21525, 16961 => 38109, 16962 => 20387, 16963 => 26053, 16964 => 23653,\n16965 => 23649, 16966 => 32533, 16967 => 34385, 16968 => 27695, 16969 => 24459,\n16970 => 29575, 16971 => 28388, 16972 => 32511, 16973 => 23782, 16974 => 25371,\n16975 => 23402, 16976 => 28390, 16977 => 21365, 16978 => 20081, 16979 => 25504,\n16980 => 30053, 16981 => 25249, 16982 => 36718, 16983 => 20262, 16984 => 20177,\n16985 => 27814, 16986 => 32438, 16987 => 35770, 16988 => 33821, 16989 => 34746,\n16990 => 32599, 16991 => 36923, 16992 => 38179, 16993 => 31657, 16994 => 39585,\n16995 => 35064, 16996 => 33853, 16997 => 27931, 16998 => 39558, 16999 => 32476,\n17000 => 22920, 17001 => 40635, 17002 => 29595, 17003 => 30721, 17004 => 34434,\n17005 => 39532, 17006 => 39554, 17007 => 22043, 17008 => 21527, 17009 => 22475,\n17010 => 20080, 17011 => 40614, 17012 => 21334, 17013 => 36808, 17014 => 33033,\n17015 => 30610, 17016 => 39314, 17017 => 34542, 17018 => 28385, 17019 => 34067,\n17020 => 26364, 17021 => 24930, 17022 => 28459, 17185 => 35881, 17186 => 33426,\n17187 => 33579, 17188 => 30450, 17189 => 27667, 17190 => 24537, 17191 => 33725,\n17192 => 29483, 17193 => 33541, 17194 => 38170, 17195 => 27611, 17196 => 30683,\n17197 => 38086, 17198 => 21359, 17199 => 33538, 17200 => 20882, 17201 => 24125,\n17202 => 35980, 17203 => 36152, 17204 => 20040, 17205 => 29611, 17206 => 26522,\n17207 => 26757, 17208 => 37238, 17209 => 38665, 17210 => 29028, 17211 => 27809,\n17212 => 30473, 17213 => 23186, 17214 => 38209, 17215 => 27599, 17216 => 32654,\n17217 => 26151, 17218 => 23504, 17219 => 22969, 17220 => 23194, 17221 => 38376,\n17222 => 38391, 17223 => 20204, 17224 => 33804, 17225 => 33945, 17226 => 27308,\n17227 => 30431, 17228 => 38192, 17229 => 29467, 17230 => 26790, 17231 => 23391,\n17232 => 30511, 17233 => 37274, 17234 => 38753, 17235 => 31964, 17236 => 36855,\n17237 => 35868, 17238 => 24357, 17239 => 31859, 17240 => 31192, 17241 => 35269,\n17242 => 27852, 17243 => 34588, 17244 => 23494, 17245 => 24130, 17246 => 26825,\n17247 => 30496, 17248 => 32501, 17249 => 20885, 17250 => 20813, 17251 => 21193,\n17252 => 23081, 17253 => 32517, 17254 => 38754, 17255 => 33495, 17256 => 25551,\n17257 => 30596, 17258 => 34256, 17259 => 31186, 17260 => 28218, 17261 => 24217,\n17262 => 22937, 17263 => 34065, 17264 => 28781, 17265 => 27665, 17266 => 25279,\n17267 => 30399, 17268 => 25935, 17269 => 24751, 17270 => 38397, 17271 => 26126,\n17272 => 34719, 17273 => 40483, 17274 => 38125, 17275 => 21517, 17276 => 21629,\n17277 => 35884, 17278 => 25720, 17441 => 25721, 17442 => 34321, 17443 => 27169,\n17444 => 33180, 17445 => 30952, 17446 => 25705, 17447 => 39764, 17448 => 25273,\n17449 => 26411, 17450 => 33707, 17451 => 22696, 17452 => 40664, 17453 => 27819,\n17454 => 28448, 17455 => 23518, 17456 => 38476, 17457 => 35851, 17458 => 29279,\n17459 => 26576, 17460 => 25287, 17461 => 29281, 17462 => 20137, 17463 => 22982,\n17464 => 27597, 17465 => 22675, 17466 => 26286, 17467 => 24149, 17468 => 21215,\n17469 => 24917, 17470 => 26408, 17471 => 30446, 17472 => 30566, 17473 => 29287,\n17474 => 31302, 17475 => 25343, 17476 => 21738, 17477 => 21584, 17478 => 38048,\n17479 => 37027, 17480 => 23068, 17481 => 32435, 17482 => 27670, 17483 => 20035,\n17484 => 22902, 17485 => 32784, 17486 => 22856, 17487 => 21335, 17488 => 30007,\n17489 => 38590, 17490 => 22218, 17491 => 25376, 17492 => 33041, 17493 => 24700,\n17494 => 38393, 17495 => 28118, 17496 => 21602, 17497 => 39297, 17498 => 20869,\n17499 => 23273, 17500 => 33021, 17501 => 22958, 17502 => 38675, 17503 => 20522,\n17504 => 27877, 17505 => 23612, 17506 => 25311, 17507 => 20320, 17508 => 21311,\n17509 => 33147, 17510 => 36870, 17511 => 28346, 17512 => 34091, 17513 => 25288,\n17514 => 24180, 17515 => 30910, 17516 => 25781, 17517 => 25467, 17518 => 24565,\n17519 => 23064, 17520 => 37247, 17521 => 40479, 17522 => 23615, 17523 => 25423,\n17524 => 32834, 17525 => 23421, 17526 => 21870, 17527 => 38218, 17528 => 38221,\n17529 => 28037, 17530 => 24744, 17531 => 26592, 17532 => 29406, 17533 => 20957,\n17534 => 23425, 17697 => 25319, 17698 => 27870, 17699 => 29275, 17700 => 25197,\n17701 => 38062, 17702 => 32445, 17703 => 33043, 17704 => 27987, 17705 => 20892,\n17706 => 24324, 17707 => 22900, 17708 => 21162, 17709 => 24594, 17710 => 22899,\n17711 => 26262, 17712 => 34384, 17713 => 30111, 17714 => 25386, 17715 => 25062,\n17716 => 31983, 17717 => 35834, 17718 => 21734, 17719 => 27431, 17720 => 40485,\n17721 => 27572, 17722 => 34261, 17723 => 21589, 17724 => 20598, 17725 => 27812,\n17726 => 21866, 17727 => 36276, 17728 => 29228, 17729 => 24085, 17730 => 24597,\n17731 => 29750, 17732 => 25293, 17733 => 25490, 17734 => 29260, 17735 => 24472,\n17736 => 28227, 17737 => 27966, 17738 => 25856, 17739 => 28504, 17740 => 30424,\n17741 => 30928, 17742 => 30460, 17743 => 30036, 17744 => 21028, 17745 => 21467,\n17746 => 20051, 17747 => 24222, 17748 => 26049, 17749 => 32810, 17750 => 32982,\n17751 => 25243, 17752 => 21638, 17753 => 21032, 17754 => 28846, 17755 => 34957,\n17756 => 36305, 17757 => 27873, 17758 => 21624, 17759 => 32986, 17760 => 22521,\n17761 => 35060, 17762 => 36180, 17763 => 38506, 17764 => 37197, 17765 => 20329,\n17766 => 27803, 17767 => 21943, 17768 => 30406, 17769 => 30768, 17770 => 25256,\n17771 => 28921, 17772 => 28558, 17773 => 24429, 17774 => 34028, 17775 => 26842,\n17776 => 30844, 17777 => 31735, 17778 => 33192, 17779 => 26379, 17780 => 40527,\n17781 => 25447, 17782 => 30896, 17783 => 22383, 17784 => 30738, 17785 => 38713,\n17786 => 25209, 17787 => 25259, 17788 => 21128, 17789 => 29749, 17790 => 27607,\n17953 => 21860, 17954 => 33086, 17955 => 30130, 17956 => 30382, 17957 => 21305,\n17958 => 30174, 17959 => 20731, 17960 => 23617, 17961 => 35692, 17962 => 31687,\n17963 => 20559, 17964 => 29255, 17965 => 39575, 17966 => 39128, 17967 => 28418,\n17968 => 29922, 17969 => 31080, 17970 => 25735, 17971 => 30629, 17972 => 25340,\n17973 => 39057, 17974 => 36139, 17975 => 21697, 17976 => 32856, 17977 => 20050,\n17978 => 22378, 17979 => 33529, 17980 => 33805, 17981 => 24179, 17982 => 20973,\n17983 => 29942, 17984 => 35780, 17985 => 23631, 17986 => 22369, 17987 => 27900,\n17988 => 39047, 17989 => 23110, 17990 => 30772, 17991 => 39748, 17992 => 36843,\n17993 => 31893, 17994 => 21078, 17995 => 25169, 17996 => 38138, 17997 => 20166,\n17998 => 33670, 17999 => 33889, 18000 => 33769, 18001 => 33970, 18002 => 22484,\n18003 => 26420, 18004 => 22275, 18005 => 26222, 18006 => 28006, 18007 => 35889,\n18008 => 26333, 18009 => 28689, 18010 => 26399, 18011 => 27450, 18012 => 26646,\n18013 => 25114, 18014 => 22971, 18015 => 19971, 18016 => 20932, 18017 => 28422,\n18018 => 26578, 18019 => 27791, 18020 => 20854, 18021 => 26827, 18022 => 22855,\n18023 => 27495, 18024 => 30054, 18025 => 23822, 18026 => 33040, 18027 => 40784,\n18028 => 26071, 18029 => 31048, 18030 => 31041, 18031 => 39569, 18032 => 36215,\n18033 => 23682, 18034 => 20062, 18035 => 20225, 18036 => 21551, 18037 => 22865,\n18038 => 30732, 18039 => 22120, 18040 => 27668, 18041 => 36804, 18042 => 24323,\n18043 => 27773, 18044 => 27875, 18045 => 35755, 18046 => 25488, 18209 => 24688,\n18210 => 27965, 18211 => 29301, 18212 => 25190, 18213 => 38030, 18214 => 38085,\n18215 => 21315, 18216 => 36801, 18217 => 31614, 18218 => 20191, 18219 => 35878,\n18220 => 20094, 18221 => 40660, 18222 => 38065, 18223 => 38067, 18224 => 21069,\n18225 => 28508, 18226 => 36963, 18227 => 27973, 18228 => 35892, 18229 => 22545,\n18230 => 23884, 18231 => 27424, 18232 => 27465, 18233 => 26538, 18234 => 21595,\n18235 => 33108, 18236 => 32652, 18237 => 22681, 18238 => 34103, 18239 => 24378,\n18240 => 25250, 18241 => 27207, 18242 => 38201, 18243 => 25970, 18244 => 24708,\n18245 => 26725, 18246 => 30631, 18247 => 20052, 18248 => 20392, 18249 => 24039,\n18250 => 38808, 18251 => 25772, 18252 => 32728, 18253 => 23789, 18254 => 20431,\n18255 => 31373, 18256 => 20999, 18257 => 33540, 18258 => 19988, 18259 => 24623,\n18260 => 31363, 18261 => 38054, 18262 => 20405, 18263 => 20146, 18264 => 31206,\n18265 => 29748, 18266 => 21220, 18267 => 33465, 18268 => 25810, 18269 => 31165,\n18270 => 23517, 18271 => 27777, 18272 => 38738, 18273 => 36731, 18274 => 27682,\n18275 => 20542, 18276 => 21375, 18277 => 28165, 18278 => 25806, 18279 => 26228,\n18280 => 27696, 18281 => 24773, 18282 => 39031, 18283 => 35831, 18284 => 24198,\n18285 => 29756, 18286 => 31351, 18287 => 31179, 18288 => 19992, 18289 => 37041,\n18290 => 29699, 18291 => 27714, 18292 => 22234, 18293 => 37195, 18294 => 27845,\n18295 => 36235, 18296 => 21306, 18297 => 34502, 18298 => 26354, 18299 => 36527,\n18300 => 23624, 18301 => 39537, 18302 => 28192, 18465 => 21462, 18466 => 23094,\n18467 => 40843, 18468 => 36259, 18469 => 21435, 18470 => 22280, 18471 => 39079,\n18472 => 26435, 18473 => 37275, 18474 => 27849, 18475 => 20840, 18476 => 30154,\n18477 => 25331, 18478 => 29356, 18479 => 21048, 18480 => 21149, 18481 => 32570,\n18482 => 28820, 18483 => 30264, 18484 => 21364, 18485 => 40522, 18486 => 27063,\n18487 => 30830, 18488 => 38592, 18489 => 35033, 18490 => 32676, 18491 => 28982,\n18492 => 29123, 18493 => 20873, 18494 => 26579, 18495 => 29924, 18496 => 22756,\n18497 => 25880, 18498 => 22199, 18499 => 35753, 18500 => 39286, 18501 => 25200,\n18502 => 32469, 18503 => 24825, 18504 => 28909, 18505 => 22764, 18506 => 20161,\n18507 => 20154, 18508 => 24525, 18509 => 38887, 18510 => 20219, 18511 => 35748,\n18512 => 20995, 18513 => 22922, 18514 => 32427, 18515 => 25172, 18516 => 20173,\n18517 => 26085, 18518 => 25102, 18519 => 33592, 18520 => 33993, 18521 => 33635,\n18522 => 34701, 18523 => 29076, 18524 => 28342, 18525 => 23481, 18526 => 32466,\n18527 => 20887, 18528 => 25545, 18529 => 26580, 18530 => 32905, 18531 => 33593,\n18532 => 34837, 18533 => 20754, 18534 => 23418, 18535 => 22914, 18536 => 36785,\n18537 => 20083, 18538 => 27741, 18539 => 20837, 18540 => 35109, 18541 => 36719,\n18542 => 38446, 18543 => 34122, 18544 => 29790, 18545 => 38160, 18546 => 38384,\n18547 => 28070, 18548 => 33509, 18549 => 24369, 18550 => 25746, 18551 => 27922,\n18552 => 33832, 18553 => 33134, 18554 => 40131, 18555 => 22622, 18556 => 36187,\n18557 => 19977, 18558 => 21441, 18721 => 20254, 18722 => 25955, 18723 => 26705,\n18724 => 21971, 18725 => 20007, 18726 => 25620, 18727 => 39578, 18728 => 25195,\n18729 => 23234, 18730 => 29791, 18731 => 33394, 18732 => 28073, 18733 => 26862,\n18734 => 20711, 18735 => 33678, 18736 => 30722, 18737 => 26432, 18738 => 21049,\n18739 => 27801, 18740 => 32433, 18741 => 20667, 18742 => 21861, 18743 => 29022,\n18744 => 31579, 18745 => 26194, 18746 => 29642, 18747 => 33515, 18748 => 26441,\n18749 => 23665, 18750 => 21024, 18751 => 29053, 18752 => 34923, 18753 => 38378,\n18754 => 38485, 18755 => 25797, 18756 => 36193, 18757 => 33203, 18758 => 21892,\n18759 => 27733, 18760 => 25159, 18761 => 32558, 18762 => 22674, 18763 => 20260,\n18764 => 21830, 18765 => 36175, 18766 => 26188, 18767 => 19978, 18768 => 23578,\n18769 => 35059, 18770 => 26786, 18771 => 25422, 18772 => 31245, 18773 => 28903,\n18774 => 33421, 18775 => 21242, 18776 => 38902, 18777 => 23569, 18778 => 21736,\n18779 => 37045, 18780 => 32461, 18781 => 22882, 18782 => 36170, 18783 => 34503,\n18784 => 33292, 18785 => 33293, 18786 => 36198, 18787 => 25668, 18788 => 23556,\n18789 => 24913, 18790 => 28041, 18791 => 31038, 18792 => 35774, 18793 => 30775,\n18794 => 30003, 18795 => 21627, 18796 => 20280, 18797 => 36523, 18798 => 28145,\n18799 => 23072, 18800 => 32453, 18801 => 31070, 18802 => 27784, 18803 => 23457,\n18804 => 23158, 18805 => 29978, 18806 => 32958, 18807 => 24910, 18808 => 28183,\n18809 => 22768, 18810 => 29983, 18811 => 29989, 18812 => 29298, 18813 => 21319,\n18814 => 32499, 18977 => 30465, 18978 => 30427, 18979 => 21097, 18980 => 32988,\n18981 => 22307, 18982 => 24072, 18983 => 22833, 18984 => 29422, 18985 => 26045,\n18986 => 28287, 18987 => 35799, 18988 => 23608, 18989 => 34417, 18990 => 21313,\n18991 => 30707, 18992 => 25342, 18993 => 26102, 18994 => 20160, 18995 => 39135,\n18996 => 34432, 18997 => 23454, 18998 => 35782, 18999 => 21490, 19000 => 30690,\n19001 => 20351, 19002 => 23630, 19003 => 39542, 19004 => 22987, 19005 => 24335,\n19006 => 31034, 19007 => 22763, 19008 => 19990, 19009 => 26623, 19010 => 20107,\n19011 => 25325, 19012 => 35475, 19013 => 36893, 19014 => 21183, 19015 => 26159,\n19016 => 21980, 19017 => 22124, 19018 => 36866, 19019 => 20181, 19020 => 20365,\n19021 => 37322, 19022 => 39280, 19023 => 27663, 19024 => 24066, 19025 => 24643,\n19026 => 23460, 19027 => 35270, 19028 => 35797, 19029 => 25910, 19030 => 25163,\n19031 => 39318, 19032 => 23432, 19033 => 23551, 19034 => 25480, 19035 => 21806,\n19036 => 21463, 19037 => 30246, 19038 => 20861, 19039 => 34092, 19040 => 26530,\n19041 => 26803, 19042 => 27530, 19043 => 25234, 19044 => 36755, 19045 => 21460,\n19046 => 33298, 19047 => 28113, 19048 => 30095, 19049 => 20070, 19050 => 36174,\n19051 => 23408, 19052 => 29087, 19053 => 34223, 19054 => 26257, 19055 => 26329,\n19056 => 32626, 19057 => 34560, 19058 => 40653, 19059 => 40736, 19060 => 23646,\n19061 => 26415, 19062 => 36848, 19063 => 26641, 19064 => 26463, 19065 => 25101,\n19066 => 31446, 19067 => 22661, 19068 => 24246, 19069 => 25968, 19070 => 28465,\n19233 => 24661, 19234 => 21047, 19235 => 32781, 19236 => 25684, 19237 => 34928,\n19238 => 29993, 19239 => 24069, 19240 => 26643, 19241 => 25332, 19242 => 38684,\n19243 => 21452, 19244 => 29245, 19245 => 35841, 19246 => 27700, 19247 => 30561,\n19248 => 31246, 19249 => 21550, 19250 => 30636, 19251 => 39034, 19252 => 33308,\n19253 => 35828, 19254 => 30805, 19255 => 26388, 19256 => 28865, 19257 => 26031,\n19258 => 25749, 19259 => 22070, 19260 => 24605, 19261 => 31169, 19262 => 21496,\n19263 => 19997, 19264 => 27515, 19265 => 32902, 19266 => 23546, 19267 => 21987,\n19268 => 22235, 19269 => 20282, 19270 => 20284, 19271 => 39282, 19272 => 24051,\n19273 => 26494, 19274 => 32824, 19275 => 24578, 19276 => 39042, 19277 => 36865,\n19278 => 23435, 19279 => 35772, 19280 => 35829, 19281 => 25628, 19282 => 33368,\n19283 => 25822, 19284 => 22013, 19285 => 33487, 19286 => 37221, 19287 => 20439,\n19288 => 32032, 19289 => 36895, 19290 => 31903, 19291 => 20723, 19292 => 22609,\n19293 => 28335, 19294 => 23487, 19295 => 35785, 19296 => 32899, 19297 => 37240,\n19298 => 33948, 19299 => 31639, 19300 => 34429, 19301 => 38539, 19302 => 38543,\n19303 => 32485, 19304 => 39635, 19305 => 30862, 19306 => 23681, 19307 => 31319,\n19308 => 36930, 19309 => 38567, 19310 => 31071, 19311 => 23385, 19312 => 25439,\n19313 => 31499, 19314 => 34001, 19315 => 26797, 19316 => 21766, 19317 => 32553,\n19318 => 29712, 19319 => 32034, 19320 => 38145, 19321 => 25152, 19322 => 22604,\n19323 => 20182, 19324 => 23427, 19325 => 22905, 19326 => 22612, 19489 => 29549,\n19490 => 25374, 19491 => 36427, 19492 => 36367, 19493 => 32974, 19494 => 33492,\n19495 => 25260, 19496 => 21488, 19497 => 27888, 19498 => 37214, 19499 => 22826,\n19500 => 24577, 19501 => 27760, 19502 => 22349, 19503 => 25674, 19504 => 36138,\n19505 => 30251, 19506 => 28393, 19507 => 22363, 19508 => 27264, 19509 => 30192,\n19510 => 28525, 19511 => 35885, 19512 => 35848, 19513 => 22374, 19514 => 27631,\n19515 => 34962, 19516 => 30899, 19517 => 25506, 19518 => 21497, 19519 => 28845,\n19520 => 27748, 19521 => 22616, 19522 => 25642, 19523 => 22530, 19524 => 26848,\n19525 => 33179, 19526 => 21776, 19527 => 31958, 19528 => 20504, 19529 => 36538,\n19530 => 28108, 19531 => 36255, 19532 => 28907, 19533 => 25487, 19534 => 28059,\n19535 => 28372, 19536 => 32486, 19537 => 33796, 19538 => 26691, 19539 => 36867,\n19540 => 28120, 19541 => 38518, 19542 => 35752, 19543 => 22871, 19544 => 29305,\n19545 => 34276, 19546 => 33150, 19547 => 30140, 19548 => 35466, 19549 => 26799,\n19550 => 21076, 19551 => 36386, 19552 => 38161, 19553 => 25552, 19554 => 39064,\n19555 => 36420, 19556 => 21884, 19557 => 20307, 19558 => 26367, 19559 => 22159,\n19560 => 24789, 19561 => 28053, 19562 => 21059, 19563 => 23625, 19564 => 22825,\n19565 => 28155, 19566 => 22635, 19567 => 30000, 19568 => 29980, 19569 => 24684,\n19570 => 33300, 19571 => 33094, 19572 => 25361, 19573 => 26465, 19574 => 36834,\n19575 => 30522, 19576 => 36339, 19577 => 36148, 19578 => 38081, 19579 => 24086,\n19580 => 21381, 19581 => 21548, 19582 => 28867, 19745 => 27712, 19746 => 24311,\n19747 => 20572, 19748 => 20141, 19749 => 24237, 19750 => 25402, 19751 => 33351,\n19752 => 36890, 19753 => 26704, 19754 => 37230, 19755 => 30643, 19756 => 21516,\n19757 => 38108, 19758 => 24420, 19759 => 31461, 19760 => 26742, 19761 => 25413,\n19762 => 31570, 19763 => 32479, 19764 => 30171, 19765 => 20599, 19766 => 25237,\n19767 => 22836, 19768 => 36879, 19769 => 20984, 19770 => 31171, 19771 => 31361,\n19772 => 22270, 19773 => 24466, 19774 => 36884, 19775 => 28034, 19776 => 23648,\n19777 => 22303, 19778 => 21520, 19779 => 20820, 19780 => 28237, 19781 => 22242,\n19782 => 25512, 19783 => 39059, 19784 => 33151, 19785 => 34581, 19786 => 35114,\n19787 => 36864, 19788 => 21534, 19789 => 23663, 19790 => 33216, 19791 => 25302,\n19792 => 25176, 19793 => 33073, 19794 => 40501, 19795 => 38464, 19796 => 39534,\n19797 => 39548, 19798 => 26925, 19799 => 22949, 19800 => 25299, 19801 => 21822,\n19802 => 25366, 19803 => 21703, 19804 => 34521, 19805 => 27964, 19806 => 23043,\n19807 => 29926, 19808 => 34972, 19809 => 27498, 19810 => 22806, 19811 => 35916,\n19812 => 24367, 19813 => 28286, 19814 => 29609, 19815 => 39037, 19816 => 20024,\n19817 => 28919, 19818 => 23436, 19819 => 30871, 19820 => 25405, 19821 => 26202,\n19822 => 30358, 19823 => 24779, 19824 => 23451, 19825 => 23113, 19826 => 19975,\n19827 => 33109, 19828 => 27754, 19829 => 29579, 19830 => 20129, 19831 => 26505,\n19832 => 32593, 19833 => 24448, 19834 => 26106, 19835 => 26395, 19836 => 24536,\n19837 => 22916, 19838 => 23041, 20001 => 24013, 20002 => 24494, 20003 => 21361,\n20004 => 38886, 20005 => 36829, 20006 => 26693, 20007 => 22260, 20008 => 21807,\n20009 => 24799, 20010 => 20026, 20011 => 28493, 20012 => 32500, 20013 => 33479,\n20014 => 33806, 20015 => 22996, 20016 => 20255, 20017 => 20266, 20018 => 23614,\n20019 => 32428, 20020 => 26410, 20021 => 34074, 20022 => 21619, 20023 => 30031,\n20024 => 32963, 20025 => 21890, 20026 => 39759, 20027 => 20301, 20028 => 28205,\n20029 => 35859, 20030 => 23561, 20031 => 24944, 20032 => 21355, 20033 => 30239,\n20034 => 28201, 20035 => 34442, 20036 => 25991, 20037 => 38395, 20038 => 32441,\n20039 => 21563, 20040 => 31283, 20041 => 32010, 20042 => 38382, 20043 => 21985,\n20044 => 32705, 20045 => 29934, 20046 => 25373, 20047 => 34583, 20048 => 28065,\n20049 => 31389, 20050 => 25105, 20051 => 26017, 20052 => 21351, 20053 => 25569,\n20054 => 27779, 20055 => 24043, 20056 => 21596, 20057 => 38056, 20058 => 20044,\n20059 => 27745, 20060 => 35820, 20061 => 23627, 20062 => 26080, 20063 => 33436,\n20064 => 26791, 20065 => 21566, 20066 => 21556, 20067 => 27595, 20068 => 27494,\n20069 => 20116, 20070 => 25410, 20071 => 21320, 20072 => 33310, 20073 => 20237,\n20074 => 20398, 20075 => 22366, 20076 => 25098, 20077 => 38654, 20078 => 26212,\n20079 => 29289, 20080 => 21247, 20081 => 21153, 20082 => 24735, 20083 => 35823,\n20084 => 26132, 20085 => 29081, 20086 => 26512, 20087 => 35199, 20088 => 30802,\n20089 => 30717, 20090 => 26224, 20091 => 22075, 20092 => 21560, 20093 => 38177,\n20094 => 29306, 20257 => 31232, 20258 => 24687, 20259 => 24076, 20260 => 24713,\n20261 => 33181, 20262 => 22805, 20263 => 24796, 20264 => 29060, 20265 => 28911,\n20266 => 28330, 20267 => 27728, 20268 => 29312, 20269 => 27268, 20270 => 34989,\n20271 => 24109, 20272 => 20064, 20273 => 23219, 20274 => 21916, 20275 => 38115,\n20276 => 27927, 20277 => 31995, 20278 => 38553, 20279 => 25103, 20280 => 32454,\n20281 => 30606, 20282 => 34430, 20283 => 21283, 20284 => 38686, 20285 => 36758,\n20286 => 26247, 20287 => 23777, 20288 => 20384, 20289 => 29421, 20290 => 19979,\n20291 => 21414, 20292 => 22799, 20293 => 21523, 20294 => 25472, 20295 => 38184,\n20296 => 20808, 20297 => 20185, 20298 => 40092, 20299 => 32420, 20300 => 21688,\n20301 => 36132, 20302 => 34900, 20303 => 33335, 20304 => 38386, 20305 => 28046,\n20306 => 24358, 20307 => 23244, 20308 => 26174, 20309 => 38505, 20310 => 29616,\n20311 => 29486, 20312 => 21439, 20313 => 33146, 20314 => 39301, 20315 => 32673,\n20316 => 23466, 20317 => 38519, 20318 => 38480, 20319 => 32447, 20320 => 30456,\n20321 => 21410, 20322 => 38262, 20323 => 39321, 20324 => 31665, 20325 => 35140,\n20326 => 28248, 20327 => 20065, 20328 => 32724, 20329 => 31077, 20330 => 35814,\n20331 => 24819, 20332 => 21709, 20333 => 20139, 20334 => 39033, 20335 => 24055,\n20336 => 27233, 20337 => 20687, 20338 => 21521, 20339 => 35937, 20340 => 33831,\n20341 => 30813, 20342 => 38660, 20343 => 21066, 20344 => 21742, 20345 => 22179,\n20346 => 38144, 20347 => 28040, 20348 => 23477, 20349 => 28102, 20350 => 26195,\n20513 => 23567, 20514 => 23389, 20515 => 26657, 20516 => 32918, 20517 => 21880,\n20518 => 31505, 20519 => 25928, 20520 => 26964, 20521 => 20123, 20522 => 27463,\n20523 => 34638, 20524 => 38795, 20525 => 21327, 20526 => 25375, 20527 => 25658,\n20528 => 37034, 20529 => 26012, 20530 => 32961, 20531 => 35856, 20532 => 20889,\n20533 => 26800, 20534 => 21368, 20535 => 34809, 20536 => 25032, 20537 => 27844,\n20538 => 27899, 20539 => 35874, 20540 => 23633, 20541 => 34218, 20542 => 33455,\n20543 => 38156, 20544 => 27427, 20545 => 36763, 20546 => 26032, 20547 => 24571,\n20548 => 24515, 20549 => 20449, 20550 => 34885, 20551 => 26143, 20552 => 33125,\n20553 => 29481, 20554 => 24826, 20555 => 20852, 20556 => 21009, 20557 => 22411,\n20558 => 24418, 20559 => 37026, 20560 => 34892, 20561 => 37266, 20562 => 24184,\n20563 => 26447, 20564 => 24615, 20565 => 22995, 20566 => 20804, 20567 => 20982,\n20568 => 33016, 20569 => 21256, 20570 => 27769, 20571 => 38596, 20572 => 29066,\n20573 => 20241, 20574 => 20462, 20575 => 32670, 20576 => 26429, 20577 => 21957,\n20578 => 38152, 20579 => 31168, 20580 => 34966, 20581 => 32483, 20582 => 22687,\n20583 => 25100, 20584 => 38656, 20585 => 34394, 20586 => 22040, 20587 => 39035,\n20588 => 24464, 20589 => 35768, 20590 => 33988, 20591 => 37207, 20592 => 21465,\n20593 => 26093, 20594 => 24207, 20595 => 30044, 20596 => 24676, 20597 => 32110,\n20598 => 23167, 20599 => 32490, 20600 => 32493, 20601 => 36713, 20602 => 21927,\n20603 => 23459, 20604 => 24748, 20605 => 26059, 20606 => 29572, 20769 => 36873,\n20770 => 30307, 20771 => 30505, 20772 => 32474, 20773 => 38772, 20774 => 34203,\n20775 => 23398, 20776 => 31348, 20777 => 38634, 20778 => 34880, 20779 => 21195,\n20780 => 29071, 20781 => 24490, 20782 => 26092, 20783 => 35810, 20784 => 23547,\n20785 => 39535, 20786 => 24033, 20787 => 27529, 20788 => 27739, 20789 => 35757,\n20790 => 35759, 20791 => 36874, 20792 => 36805, 20793 => 21387, 20794 => 25276,\n20795 => 40486, 20796 => 40493, 20797 => 21568, 20798 => 20011, 20799 => 33469,\n20800 => 29273, 20801 => 34460, 20802 => 23830, 20803 => 34905, 20804 => 28079,\n20805 => 38597, 20806 => 21713, 20807 => 20122, 20808 => 35766, 20809 => 28937,\n20810 => 21693, 20811 => 38409, 20812 => 28895, 20813 => 28153, 20814 => 30416,\n20815 => 20005, 20816 => 30740, 20817 => 34578, 20818 => 23721, 20819 => 24310,\n20820 => 35328, 20821 => 39068, 20822 => 38414, 20823 => 28814, 20824 => 27839,\n20825 => 22852, 20826 => 25513, 20827 => 30524, 20828 => 34893, 20829 => 28436,\n20830 => 33395, 20831 => 22576, 20832 => 29141, 20833 => 21388, 20834 => 30746,\n20835 => 38593, 20836 => 21761, 20837 => 24422, 20838 => 28976, 20839 => 23476,\n20840 => 35866, 20841 => 39564, 20842 => 27523, 20843 => 22830, 20844 => 40495,\n20845 => 31207, 20846 => 26472, 20847 => 25196, 20848 => 20335, 20849 => 30113,\n20850 => 32650, 20851 => 27915, 20852 => 38451, 20853 => 27687, 20854 => 20208,\n20855 => 30162, 20856 => 20859, 20857 => 26679, 20858 => 28478, 20859 => 36992,\n20860 => 33136, 20861 => 22934, 20862 => 29814, 21025 => 25671, 21026 => 23591,\n21027 => 36965, 21028 => 31377, 21029 => 35875, 21030 => 23002, 21031 => 21676,\n21032 => 33280, 21033 => 33647, 21034 => 35201, 21035 => 32768, 21036 => 26928,\n21037 => 22094, 21038 => 32822, 21039 => 29239, 21040 => 37326, 21041 => 20918,\n21042 => 20063, 21043 => 39029, 21044 => 25494, 21045 => 19994, 21046 => 21494,\n21047 => 26355, 21048 => 33099, 21049 => 22812, 21050 => 28082, 21051 => 19968,\n21052 => 22777, 21053 => 21307, 21054 => 25558, 21055 => 38129, 21056 => 20381,\n21057 => 20234, 21058 => 34915, 21059 => 39056, 21060 => 22839, 21061 => 36951,\n21062 => 31227, 21063 => 20202, 21064 => 33008, 21065 => 30097, 21066 => 27778,\n21067 => 23452, 21068 => 23016, 21069 => 24413, 21070 => 26885, 21071 => 34433,\n21072 => 20506, 21073 => 24050, 21074 => 20057, 21075 => 30691, 21076 => 20197,\n21077 => 33402, 21078 => 25233, 21079 => 26131, 21080 => 37009, 21081 => 23673,\n21082 => 20159, 21083 => 24441, 21084 => 33222, 21085 => 36920, 21086 => 32900,\n21087 => 30123, 21088 => 20134, 21089 => 35028, 21090 => 24847, 21091 => 27589,\n21092 => 24518, 21093 => 20041, 21094 => 30410, 21095 => 28322, 21096 => 35811,\n21097 => 35758, 21098 => 35850, 21099 => 35793, 21100 => 24322, 21101 => 32764,\n21102 => 32716, 21103 => 32462, 21104 => 33589, 21105 => 33643, 21106 => 22240,\n21107 => 27575, 21108 => 38899, 21109 => 38452, 21110 => 23035, 21111 => 21535,\n21112 => 38134, 21113 => 28139, 21114 => 23493, 21115 => 39278, 21116 => 23609,\n21117 => 24341, 21118 => 38544, 21281 => 21360, 21282 => 33521, 21283 => 27185,\n21284 => 23156, 21285 => 40560, 21286 => 24212, 21287 => 32552, 21288 => 33721,\n21289 => 33828, 21290 => 33829, 21291 => 33639, 21292 => 34631, 21293 => 36814,\n21294 => 36194, 21295 => 30408, 21296 => 24433, 21297 => 39062, 21298 => 30828,\n21299 => 26144, 21300 => 21727, 21301 => 25317, 21302 => 20323, 21303 => 33219,\n21304 => 30152, 21305 => 24248, 21306 => 38605, 21307 => 36362, 21308 => 34553,\n21309 => 21647, 21310 => 27891, 21311 => 28044, 21312 => 27704, 21313 => 24703,\n21314 => 21191, 21315 => 29992, 21316 => 24189, 21317 => 20248, 21318 => 24736,\n21319 => 24551, 21320 => 23588, 21321 => 30001, 21322 => 37038, 21323 => 38080,\n21324 => 29369, 21325 => 27833, 21326 => 28216, 21327 => 37193, 21328 => 26377,\n21329 => 21451, 21330 => 21491, 21331 => 20305, 21332 => 37321, 21333 => 35825,\n21334 => 21448, 21335 => 24188, 21336 => 36802, 21337 => 28132, 21338 => 20110,\n21339 => 30402, 21340 => 27014, 21341 => 34398, 21342 => 24858, 21343 => 33286,\n21344 => 20313, 21345 => 20446, 21346 => 36926, 21347 => 40060, 21348 => 24841,\n21349 => 28189, 21350 => 28180, 21351 => 38533, 21352 => 20104, 21353 => 23089,\n21354 => 38632, 21355 => 19982, 21356 => 23679, 21357 => 31161, 21358 => 23431,\n21359 => 35821, 21360 => 32701, 21361 => 29577, 21362 => 22495, 21363 => 33419,\n21364 => 37057, 21365 => 21505, 21366 => 36935, 21367 => 21947, 21368 => 23786,\n21369 => 24481, 21370 => 24840, 21371 => 27442, 21372 => 29425, 21373 => 32946,\n21374 => 35465, 21537 => 28020, 21538 => 23507, 21539 => 35029, 21540 => 39044,\n21541 => 35947, 21542 => 39533, 21543 => 40499, 21544 => 28170, 21545 => 20900,\n21546 => 20803, 21547 => 22435, 21548 => 34945, 21549 => 21407, 21550 => 25588,\n21551 => 36757, 21552 => 22253, 21553 => 21592, 21554 => 22278, 21555 => 29503,\n21556 => 28304, 21557 => 32536, 21558 => 36828, 21559 => 33489, 21560 => 24895,\n21561 => 24616, 21562 => 38498, 21563 => 26352, 21564 => 32422, 21565 => 36234,\n21566 => 36291, 21567 => 38053, 21568 => 23731, 21569 => 31908, 21570 => 26376,\n21571 => 24742, 21572 => 38405, 21573 => 32792, 21574 => 20113, 21575 => 37095,\n21576 => 21248, 21577 => 38504, 21578 => 20801, 21579 => 36816, 21580 => 34164,\n21581 => 37213, 21582 => 26197, 21583 => 38901, 21584 => 23381, 21585 => 21277,\n21586 => 30776, 21587 => 26434, 21588 => 26685, 21589 => 21705, 21590 => 28798,\n21591 => 23472, 21592 => 36733, 21593 => 20877, 21594 => 22312, 21595 => 21681,\n21596 => 25874, 21597 => 26242, 21598 => 36190, 21599 => 36163, 21600 => 33039,\n21601 => 33900, 21602 => 36973, 21603 => 31967, 21604 => 20991, 21605 => 34299,\n21606 => 26531, 21607 => 26089, 21608 => 28577, 21609 => 34468, 21610 => 36481,\n21611 => 22122, 21612 => 36896, 21613 => 30338, 21614 => 28790, 21615 => 29157,\n21616 => 36131, 21617 => 25321, 21618 => 21017, 21619 => 27901, 21620 => 36156,\n21621 => 24590, 21622 => 22686, 21623 => 24974, 21624 => 26366, 21625 => 36192,\n21626 => 25166, 21627 => 21939, 21628 => 28195, 21629 => 26413, 21630 => 36711,\n21793 => 38113, 21794 => 38392, 21795 => 30504, 21796 => 26629, 21797 => 27048,\n21798 => 21643, 21799 => 20045, 21800 => 28856, 21801 => 35784, 21802 => 25688,\n21803 => 25995, 21804 => 23429, 21805 => 31364, 21806 => 20538, 21807 => 23528,\n21808 => 30651, 21809 => 27617, 21810 => 35449, 21811 => 31896, 21812 => 27838,\n21813 => 30415, 21814 => 26025, 21815 => 36759, 21816 => 23853, 21817 => 23637,\n21818 => 34360, 21819 => 26632, 21820 => 21344, 21821 => 25112, 21822 => 31449,\n21823 => 28251, 21824 => 32509, 21825 => 27167, 21826 => 31456, 21827 => 24432,\n21828 => 28467, 21829 => 24352, 21830 => 25484, 21831 => 28072, 21832 => 26454,\n21833 => 19976, 21834 => 24080, 21835 => 36134, 21836 => 20183, 21837 => 32960,\n21838 => 30260, 21839 => 38556, 21840 => 25307, 21841 => 26157, 21842 => 25214,\n21843 => 27836, 21844 => 36213, 21845 => 29031, 21846 => 32617, 21847 => 20806,\n21848 => 32903, 21849 => 21484, 21850 => 36974, 21851 => 25240, 21852 => 21746,\n21853 => 34544, 21854 => 36761, 21855 => 32773, 21856 => 38167, 21857 => 34071,\n21858 => 36825, 21859 => 27993, 21860 => 29645, 21861 => 26015, 21862 => 30495,\n21863 => 29956, 21864 => 30759, 21865 => 33275, 21866 => 36126, 21867 => 38024,\n21868 => 20390, 21869 => 26517, 21870 => 30137, 21871 => 35786, 21872 => 38663,\n21873 => 25391, 21874 => 38215, 21875 => 38453, 21876 => 33976, 21877 => 25379,\n21878 => 30529, 21879 => 24449, 21880 => 29424, 21881 => 20105, 21882 => 24596,\n21883 => 25972, 21884 => 25327, 21885 => 27491, 21886 => 25919, 22049 => 24103,\n22050 => 30151, 22051 => 37073, 22052 => 35777, 22053 => 33437, 22054 => 26525,\n22055 => 25903, 22056 => 21553, 22057 => 34584, 22058 => 30693, 22059 => 32930,\n22060 => 33026, 22061 => 27713, 22062 => 20043, 22063 => 32455, 22064 => 32844,\n22065 => 30452, 22066 => 26893, 22067 => 27542, 22068 => 25191, 22069 => 20540,\n22070 => 20356, 22071 => 22336, 22072 => 25351, 22073 => 27490, 22074 => 36286,\n22075 => 21482, 22076 => 26088, 22077 => 32440, 22078 => 24535, 22079 => 25370,\n22080 => 25527, 22081 => 33267, 22082 => 33268, 22083 => 32622, 22084 => 24092,\n22085 => 23769, 22086 => 21046, 22087 => 26234, 22088 => 31209, 22089 => 31258,\n22090 => 36136, 22091 => 28825, 22092 => 30164, 22093 => 28382, 22094 => 27835,\n22095 => 31378, 22096 => 20013, 22097 => 30405, 22098 => 24544, 22099 => 38047,\n22100 => 34935, 22101 => 32456, 22102 => 31181, 22103 => 32959, 22104 => 37325,\n22105 => 20210, 22106 => 20247, 22107 => 33311, 22108 => 21608, 22109 => 24030,\n22110 => 27954, 22111 => 35788, 22112 => 31909, 22113 => 36724, 22114 => 32920,\n22115 => 24090, 22116 => 21650, 22117 => 30385, 22118 => 23449, 22119 => 26172,\n22120 => 39588, 22121 => 29664, 22122 => 26666, 22123 => 34523, 22124 => 26417,\n22125 => 29482, 22126 => 35832, 22127 => 35803, 22128 => 36880, 22129 => 31481,\n22130 => 28891, 22131 => 29038, 22132 => 25284, 22133 => 30633, 22134 => 22065,\n22135 => 20027, 22136 => 33879, 22137 => 26609, 22138 => 21161, 22139 => 34496,\n22140 => 36142, 22141 => 38136, 22142 => 31569, 22305 => 20303, 22306 => 27880,\n22307 => 31069, 22308 => 39547, 22309 => 25235, 22310 => 29226, 22311 => 25341,\n22312 => 19987, 22313 => 30742, 22314 => 36716, 22315 => 25776, 22316 => 36186,\n22317 => 31686, 22318 => 26729, 22319 => 24196, 22320 => 35013, 22321 => 22918,\n22322 => 25758, 22323 => 22766, 22324 => 29366, 22325 => 26894, 22326 => 38181,\n22327 => 36861, 22328 => 36184, 22329 => 22368, 22330 => 32512, 22331 => 35846,\n22332 => 20934, 22333 => 25417, 22334 => 25305, 22335 => 21331, 22336 => 26700,\n22337 => 29730, 22338 => 33537, 22339 => 37196, 22340 => 21828, 22341 => 30528,\n22342 => 28796, 22343 => 27978, 22344 => 20857, 22345 => 21672, 22346 => 36164,\n22347 => 23039, 22348 => 28363, 22349 => 28100, 22350 => 23388, 22351 => 32043,\n22352 => 20180, 22353 => 31869, 22354 => 28371, 22355 => 23376, 22356 => 33258,\n22357 => 28173, 22358 => 23383, 22359 => 39683, 22360 => 26837, 22361 => 36394,\n22362 => 23447, 22363 => 32508, 22364 => 24635, 22365 => 32437, 22366 => 37049,\n22367 => 36208, 22368 => 22863, 22369 => 25549, 22370 => 31199, 22371 => 36275,\n22372 => 21330, 22373 => 26063, 22374 => 31062, 22375 => 35781, 22376 => 38459,\n22377 => 32452, 22378 => 38075, 22379 => 32386, 22380 => 22068, 22381 => 37257,\n22382 => 26368, 22383 => 32618, 22384 => 23562, 22385 => 36981, 22386 => 26152,\n22387 => 24038, 22388 => 20304, 22389 => 26590, 22390 => 20570, 22391 => 20316,\n22392 => 22352, 22393 => 24231, 22561 => 20109, 22562 => 19980, 22563 => 20800,\n22564 => 19984, 22565 => 24319, 22566 => 21317, 22567 => 19989, 22568 => 20120,\n22569 => 19998, 22570 => 39730, 22571 => 23404, 22572 => 22121, 22573 => 20008,\n22574 => 31162, 22575 => 20031, 22576 => 21269, 22577 => 20039, 22578 => 22829,\n22579 => 29243, 22580 => 21358, 22581 => 27664, 22582 => 22239, 22583 => 32996,\n22584 => 39319, 22585 => 27603, 22586 => 30590, 22587 => 40727, 22588 => 20022,\n22589 => 20127, 22590 => 40720, 22591 => 20060, 22592 => 20073, 22593 => 20115,\n22594 => 33416, 22595 => 23387, 22596 => 21868, 22597 => 22031, 22598 => 20164,\n22599 => 21389, 22600 => 21405, 22601 => 21411, 22602 => 21413, 22603 => 21422,\n22604 => 38757, 22605 => 36189, 22606 => 21274, 22607 => 21493, 22608 => 21286,\n22609 => 21294, 22610 => 21310, 22611 => 36188, 22612 => 21350, 22613 => 21347,\n22614 => 20994, 22615 => 21000, 22616 => 21006, 22617 => 21037, 22618 => 21043,\n22619 => 21055, 22620 => 21056, 22621 => 21068, 22622 => 21086, 22623 => 21089,\n22624 => 21084, 22625 => 33967, 22626 => 21117, 22627 => 21122, 22628 => 21121,\n22629 => 21136, 22630 => 21139, 22631 => 20866, 22632 => 32596, 22633 => 20155,\n22634 => 20163, 22635 => 20169, 22636 => 20162, 22637 => 20200, 22638 => 20193,\n22639 => 20203, 22640 => 20190, 22641 => 20251, 22642 => 20211, 22643 => 20258,\n22644 => 20324, 22645 => 20213, 22646 => 20261, 22647 => 20263, 22648 => 20233,\n22649 => 20267, 22650 => 20318, 22651 => 20327, 22652 => 25912, 22653 => 20314,\n22654 => 20317, 22817 => 20319, 22818 => 20311, 22819 => 20274, 22820 => 20285,\n22821 => 20342, 22822 => 20340, 22823 => 20369, 22824 => 20361, 22825 => 20355,\n22826 => 20367, 22827 => 20350, 22828 => 20347, 22829 => 20394, 22830 => 20348,\n22831 => 20396, 22832 => 20372, 22833 => 20454, 22834 => 20456, 22835 => 20458,\n22836 => 20421, 22837 => 20442, 22838 => 20451, 22839 => 20444, 22840 => 20433,\n22841 => 20447, 22842 => 20472, 22843 => 20521, 22844 => 20556, 22845 => 20467,\n22846 => 20524, 22847 => 20495, 22848 => 20526, 22849 => 20525, 22850 => 20478,\n22851 => 20508, 22852 => 20492, 22853 => 20517, 22854 => 20520, 22855 => 20606,\n22856 => 20547, 22857 => 20565, 22858 => 20552, 22859 => 20558, 22860 => 20588,\n22861 => 20603, 22862 => 20645, 22863 => 20647, 22864 => 20649, 22865 => 20666,\n22866 => 20694, 22867 => 20742, 22868 => 20717, 22869 => 20716, 22870 => 20710,\n22871 => 20718, 22872 => 20743, 22873 => 20747, 22874 => 20189, 22875 => 27709,\n22876 => 20312, 22877 => 20325, 22878 => 20430, 22879 => 40864, 22880 => 27718,\n22881 => 31860, 22882 => 20846, 22883 => 24061, 22884 => 40649, 22885 => 39320,\n22886 => 20865, 22887 => 22804, 22888 => 21241, 22889 => 21261, 22890 => 35335,\n22891 => 21264, 22892 => 20971, 22893 => 22809, 22894 => 20821, 22895 => 20128,\n22896 => 20822, 22897 => 20147, 22898 => 34926, 22899 => 34980, 22900 => 20149,\n22901 => 33044, 22902 => 35026, 22903 => 31104, 22904 => 23348, 22905 => 34819,\n22906 => 32696, 22907 => 20907, 22908 => 20913, 22909 => 20925, 22910 => 20924,\n23073 => 20935, 23074 => 20886, 23075 => 20898, 23076 => 20901, 23077 => 35744,\n23078 => 35750, 23079 => 35751, 23080 => 35754, 23081 => 35764, 23082 => 35765,\n23083 => 35767, 23084 => 35778, 23085 => 35779, 23086 => 35787, 23087 => 35791,\n23088 => 35790, 23089 => 35794, 23090 => 35795, 23091 => 35796, 23092 => 35798,\n23093 => 35800, 23094 => 35801, 23095 => 35804, 23096 => 35807, 23097 => 35808,\n23098 => 35812, 23099 => 35816, 23100 => 35817, 23101 => 35822, 23102 => 35824,\n23103 => 35827, 23104 => 35830, 23105 => 35833, 23106 => 35836, 23107 => 35839,\n23108 => 35840, 23109 => 35842, 23110 => 35844, 23111 => 35847, 23112 => 35852,\n23113 => 35855, 23114 => 35857, 23115 => 35858, 23116 => 35860, 23117 => 35861,\n23118 => 35862, 23119 => 35865, 23120 => 35867, 23121 => 35864, 23122 => 35869,\n23123 => 35871, 23124 => 35872, 23125 => 35873, 23126 => 35877, 23127 => 35879,\n23128 => 35882, 23129 => 35883, 23130 => 35886, 23131 => 35887, 23132 => 35890,\n23133 => 35891, 23134 => 35893, 23135 => 35894, 23136 => 21353, 23137 => 21370,\n23138 => 38429, 23139 => 38434, 23140 => 38433, 23141 => 38449, 23142 => 38442,\n23143 => 38461, 23144 => 38460, 23145 => 38466, 23146 => 38473, 23147 => 38484,\n23148 => 38495, 23149 => 38503, 23150 => 38508, 23151 => 38514, 23152 => 38516,\n23153 => 38536, 23154 => 38541, 23155 => 38551, 23156 => 38576, 23157 => 37015,\n23158 => 37019, 23159 => 37021, 23160 => 37017, 23161 => 37036, 23162 => 37025,\n23163 => 37044, 23164 => 37043, 23165 => 37046, 23166 => 37050, 23329 => 37048,\n23330 => 37040, 23331 => 37071, 23332 => 37061, 23333 => 37054, 23334 => 37072,\n23335 => 37060, 23336 => 37063, 23337 => 37075, 23338 => 37094, 23339 => 37090,\n23340 => 37084, 23341 => 37079, 23342 => 37083, 23343 => 37099, 23344 => 37103,\n23345 => 37118, 23346 => 37124, 23347 => 37154, 23348 => 37150, 23349 => 37155,\n23350 => 37169, 23351 => 37167, 23352 => 37177, 23353 => 37187, 23354 => 37190,\n23355 => 21005, 23356 => 22850, 23357 => 21154, 23358 => 21164, 23359 => 21165,\n23360 => 21182, 23361 => 21759, 23362 => 21200, 23363 => 21206, 23364 => 21232,\n23365 => 21471, 23366 => 29166, 23367 => 30669, 23368 => 24308, 23369 => 20981,\n23370 => 20988, 23371 => 39727, 23372 => 21430, 23373 => 24321, 23374 => 30042,\n23375 => 24047, 23376 => 22348, 23377 => 22441, 23378 => 22433, 23379 => 22654,\n23380 => 22716, 23381 => 22725, 23382 => 22737, 23383 => 22313, 23384 => 22316,\n23385 => 22314, 23386 => 22323, 23387 => 22329, 23388 => 22318, 23389 => 22319,\n23390 => 22364, 23391 => 22331, 23392 => 22338, 23393 => 22377, 23394 => 22405,\n23395 => 22379, 23396 => 22406, 23397 => 22396, 23398 => 22395, 23399 => 22376,\n23400 => 22381, 23401 => 22390, 23402 => 22387, 23403 => 22445, 23404 => 22436,\n23405 => 22412, 23406 => 22450, 23407 => 22479, 23408 => 22439, 23409 => 22452,\n23410 => 22419, 23411 => 22432, 23412 => 22485, 23413 => 22488, 23414 => 22490,\n23415 => 22489, 23416 => 22482, 23417 => 22456, 23418 => 22516, 23419 => 22511,\n23420 => 22520, 23421 => 22500, 23422 => 22493, 23585 => 22539, 23586 => 22541,\n23587 => 22525, 23588 => 22509, 23589 => 22528, 23590 => 22558, 23591 => 22553,\n23592 => 22596, 23593 => 22560, 23594 => 22629, 23595 => 22636, 23596 => 22657,\n23597 => 22665, 23598 => 22682, 23599 => 22656, 23600 => 39336, 23601 => 40729,\n23602 => 25087, 23603 => 33401, 23604 => 33405, 23605 => 33407, 23606 => 33423,\n23607 => 33418, 23608 => 33448, 23609 => 33412, 23610 => 33422, 23611 => 33425,\n23612 => 33431, 23613 => 33433, 23614 => 33451, 23615 => 33464, 23616 => 33470,\n23617 => 33456, 23618 => 33480, 23619 => 33482, 23620 => 33507, 23621 => 33432,\n23622 => 33463, 23623 => 33454, 23624 => 33483, 23625 => 33484, 23626 => 33473,\n23627 => 33449, 23628 => 33460, 23629 => 33441, 23630 => 33450, 23631 => 33439,\n23632 => 33476, 23633 => 33486, 23634 => 33444, 23635 => 33505, 23636 => 33545,\n23637 => 33527, 23638 => 33508, 23639 => 33551, 23640 => 33543, 23641 => 33500,\n23642 => 33524, 23643 => 33490, 23644 => 33496, 23645 => 33548, 23646 => 33531,\n23647 => 33491, 23648 => 33553, 23649 => 33562, 23650 => 33542, 23651 => 33556,\n23652 => 33557, 23653 => 33504, 23654 => 33493, 23655 => 33564, 23656 => 33617,\n23657 => 33627, 23658 => 33628, 23659 => 33544, 23660 => 33682, 23661 => 33596,\n23662 => 33588, 23663 => 33585, 23664 => 33691, 23665 => 33630, 23666 => 33583,\n23667 => 33615, 23668 => 33607, 23669 => 33603, 23670 => 33631, 23671 => 33600,\n23672 => 33559, 23673 => 33632, 23674 => 33581, 23675 => 33594, 23676 => 33587,\n23677 => 33638, 23678 => 33637, 23841 => 33640, 23842 => 33563, 23843 => 33641,\n23844 => 33644, 23845 => 33642, 23846 => 33645, 23847 => 33646, 23848 => 33712,\n23849 => 33656, 23850 => 33715, 23851 => 33716, 23852 => 33696, 23853 => 33706,\n23854 => 33683, 23855 => 33692, 23856 => 33669, 23857 => 33660, 23858 => 33718,\n23859 => 33705, 23860 => 33661, 23861 => 33720, 23862 => 33659, 23863 => 33688,\n23864 => 33694, 23865 => 33704, 23866 => 33722, 23867 => 33724, 23868 => 33729,\n23869 => 33793, 23870 => 33765, 23871 => 33752, 23872 => 22535, 23873 => 33816,\n23874 => 33803, 23875 => 33757, 23876 => 33789, 23877 => 33750, 23878 => 33820,\n23879 => 33848, 23880 => 33809, 23881 => 33798, 23882 => 33748, 23883 => 33759,\n23884 => 33807, 23885 => 33795, 23886 => 33784, 23887 => 33785, 23888 => 33770,\n23889 => 33733, 23890 => 33728, 23891 => 33830, 23892 => 33776, 23893 => 33761,\n23894 => 33884, 23895 => 33873, 23896 => 33882, 23897 => 33881, 23898 => 33907,\n23899 => 33927, 23900 => 33928, 23901 => 33914, 23902 => 33929, 23903 => 33912,\n23904 => 33852, 23905 => 33862, 23906 => 33897, 23907 => 33910, 23908 => 33932,\n23909 => 33934, 23910 => 33841, 23911 => 33901, 23912 => 33985, 23913 => 33997,\n23914 => 34000, 23915 => 34022, 23916 => 33981, 23917 => 34003, 23918 => 33994,\n23919 => 33983, 23920 => 33978, 23921 => 34016, 23922 => 33953, 23923 => 33977,\n23924 => 33972, 23925 => 33943, 23926 => 34021, 23927 => 34019, 23928 => 34060,\n23929 => 29965, 23930 => 34104, 23931 => 34032, 23932 => 34105, 23933 => 34079,\n23934 => 34106, 24097 => 34134, 24098 => 34107, 24099 => 34047, 24100 => 34044,\n24101 => 34137, 24102 => 34120, 24103 => 34152, 24104 => 34148, 24105 => 34142,\n24106 => 34170, 24107 => 30626, 24108 => 34115, 24109 => 34162, 24110 => 34171,\n24111 => 34212, 24112 => 34216, 24113 => 34183, 24114 => 34191, 24115 => 34169,\n24116 => 34222, 24117 => 34204, 24118 => 34181, 24119 => 34233, 24120 => 34231,\n24121 => 34224, 24122 => 34259, 24123 => 34241, 24124 => 34268, 24125 => 34303,\n24126 => 34343, 24127 => 34309, 24128 => 34345, 24129 => 34326, 24130 => 34364,\n24131 => 24318, 24132 => 24328, 24133 => 22844, 24134 => 22849, 24135 => 32823,\n24136 => 22869, 24137 => 22874, 24138 => 22872, 24139 => 21263, 24140 => 23586,\n24141 => 23589, 24142 => 23596, 24143 => 23604, 24144 => 25164, 24145 => 25194,\n24146 => 25247, 24147 => 25275, 24148 => 25290, 24149 => 25306, 24150 => 25303,\n24151 => 25326, 24152 => 25378, 24153 => 25334, 24154 => 25401, 24155 => 25419,\n24156 => 25411, 24157 => 25517, 24158 => 25590, 24159 => 25457, 24160 => 25466,\n24161 => 25486, 24162 => 25524, 24163 => 25453, 24164 => 25516, 24165 => 25482,\n24166 => 25449, 24167 => 25518, 24168 => 25532, 24169 => 25586, 24170 => 25592,\n24171 => 25568, 24172 => 25599, 24173 => 25540, 24174 => 25566, 24175 => 25550,\n24176 => 25682, 24177 => 25542, 24178 => 25534, 24179 => 25669, 24180 => 25665,\n24181 => 25611, 24182 => 25627, 24183 => 25632, 24184 => 25612, 24185 => 25638,\n24186 => 25633, 24187 => 25694, 24188 => 25732, 24189 => 25709, 24190 => 25750,\n24353 => 25722, 24354 => 25783, 24355 => 25784, 24356 => 25753, 24357 => 25786,\n24358 => 25792, 24359 => 25808, 24360 => 25815, 24361 => 25828, 24362 => 25826,\n24363 => 25865, 24364 => 25893, 24365 => 25902, 24366 => 24331, 24367 => 24530,\n24368 => 29977, 24369 => 24337, 24370 => 21343, 24371 => 21489, 24372 => 21501,\n24373 => 21481, 24374 => 21480, 24375 => 21499, 24376 => 21522, 24377 => 21526,\n24378 => 21510, 24379 => 21579, 24380 => 21586, 24381 => 21587, 24382 => 21588,\n24383 => 21590, 24384 => 21571, 24385 => 21537, 24386 => 21591, 24387 => 21593,\n24388 => 21539, 24389 => 21554, 24390 => 21634, 24391 => 21652, 24392 => 21623,\n24393 => 21617, 24394 => 21604, 24395 => 21658, 24396 => 21659, 24397 => 21636,\n24398 => 21622, 24399 => 21606, 24400 => 21661, 24401 => 21712, 24402 => 21677,\n24403 => 21698, 24404 => 21684, 24405 => 21714, 24406 => 21671, 24407 => 21670,\n24408 => 21715, 24409 => 21716, 24410 => 21618, 24411 => 21667, 24412 => 21717,\n24413 => 21691, 24414 => 21695, 24415 => 21708, 24416 => 21721, 24417 => 21722,\n24418 => 21724, 24419 => 21673, 24420 => 21674, 24421 => 21668, 24422 => 21725,\n24423 => 21711, 24424 => 21726, 24425 => 21787, 24426 => 21735, 24427 => 21792,\n24428 => 21757, 24429 => 21780, 24430 => 21747, 24431 => 21794, 24432 => 21795,\n24433 => 21775, 24434 => 21777, 24435 => 21799, 24436 => 21802, 24437 => 21863,\n24438 => 21903, 24439 => 21941, 24440 => 21833, 24441 => 21869, 24442 => 21825,\n24443 => 21845, 24444 => 21823, 24445 => 21840, 24446 => 21820, 24609 => 21815,\n24610 => 21846, 24611 => 21877, 24612 => 21878, 24613 => 21879, 24614 => 21811,\n24615 => 21808, 24616 => 21852, 24617 => 21899, 24618 => 21970, 24619 => 21891,\n24620 => 21937, 24621 => 21945, 24622 => 21896, 24623 => 21889, 24624 => 21919,\n24625 => 21886, 24626 => 21974, 24627 => 21905, 24628 => 21883, 24629 => 21983,\n24630 => 21949, 24631 => 21950, 24632 => 21908, 24633 => 21913, 24634 => 21994,\n24635 => 22007, 24636 => 21961, 24637 => 22047, 24638 => 21969, 24639 => 21995,\n24640 => 21996, 24641 => 21972, 24642 => 21990, 24643 => 21981, 24644 => 21956,\n24645 => 21999, 24646 => 21989, 24647 => 22002, 24648 => 22003, 24649 => 21964,\n24650 => 21965, 24651 => 21992, 24652 => 22005, 24653 => 21988, 24654 => 36756,\n24655 => 22046, 24656 => 22024, 24657 => 22028, 24658 => 22017, 24659 => 22052,\n24660 => 22051, 24661 => 22014, 24662 => 22016, 24663 => 22055, 24664 => 22061,\n24665 => 22104, 24666 => 22073, 24667 => 22103, 24668 => 22060, 24669 => 22093,\n24670 => 22114, 24671 => 22105, 24672 => 22108, 24673 => 22092, 24674 => 22100,\n24675 => 22150, 24676 => 22116, 24677 => 22129, 24678 => 22123, 24679 => 22139,\n24680 => 22140, 24681 => 22149, 24682 => 22163, 24683 => 22191, 24684 => 22228,\n24685 => 22231, 24686 => 22237, 24687 => 22241, 24688 => 22261, 24689 => 22251,\n24690 => 22265, 24691 => 22271, 24692 => 22276, 24693 => 22282, 24694 => 22281,\n24695 => 22300, 24696 => 24079, 24697 => 24089, 24698 => 24084, 24699 => 24081,\n24700 => 24113, 24701 => 24123, 24702 => 24124, 24865 => 24119, 24866 => 24132,\n24867 => 24148, 24868 => 24155, 24869 => 24158, 24870 => 24161, 24871 => 23692,\n24872 => 23674, 24873 => 23693, 24874 => 23696, 24875 => 23702, 24876 => 23688,\n24877 => 23704, 24878 => 23705, 24879 => 23697, 24880 => 23706, 24881 => 23708,\n24882 => 23733, 24883 => 23714, 24884 => 23741, 24885 => 23724, 24886 => 23723,\n24887 => 23729, 24888 => 23715, 24889 => 23745, 24890 => 23735, 24891 => 23748,\n24892 => 23762, 24893 => 23780, 24894 => 23755, 24895 => 23781, 24896 => 23810,\n24897 => 23811, 24898 => 23847, 24899 => 23846, 24900 => 23854, 24901 => 23844,\n24902 => 23838, 24903 => 23814, 24904 => 23835, 24905 => 23896, 24906 => 23870,\n24907 => 23860, 24908 => 23869, 24909 => 23916, 24910 => 23899, 24911 => 23919,\n24912 => 23901, 24913 => 23915, 24914 => 23883, 24915 => 23882, 24916 => 23913,\n24917 => 23924, 24918 => 23938, 24919 => 23961, 24920 => 23965, 24921 => 35955,\n24922 => 23991, 24923 => 24005, 24924 => 24435, 24925 => 24439, 24926 => 24450,\n24927 => 24455, 24928 => 24457, 24929 => 24460, 24930 => 24469, 24931 => 24473,\n24932 => 24476, 24933 => 24488, 24934 => 24493, 24935 => 24501, 24936 => 24508,\n24937 => 34914, 24938 => 24417, 24939 => 29357, 24940 => 29360, 24941 => 29364,\n24942 => 29367, 24943 => 29368, 24944 => 29379, 24945 => 29377, 24946 => 29390,\n24947 => 29389, 24948 => 29394, 24949 => 29416, 24950 => 29423, 24951 => 29417,\n24952 => 29426, 24953 => 29428, 24954 => 29431, 24955 => 29441, 24956 => 29427,\n24957 => 29443, 24958 => 29434, 25121 => 29435, 25122 => 29463, 25123 => 29459,\n25124 => 29473, 25125 => 29450, 25126 => 29470, 25127 => 29469, 25128 => 29461,\n25129 => 29474, 25130 => 29497, 25131 => 29477, 25132 => 29484, 25133 => 29496,\n25134 => 29489, 25135 => 29520, 25136 => 29517, 25137 => 29527, 25138 => 29536,\n25139 => 29548, 25140 => 29551, 25141 => 29566, 25142 => 33307, 25143 => 22821,\n25144 => 39143, 25145 => 22820, 25146 => 22786, 25147 => 39267, 25148 => 39271,\n25149 => 39272, 25150 => 39273, 25151 => 39274, 25152 => 39275, 25153 => 39276,\n25154 => 39284, 25155 => 39287, 25156 => 39293, 25157 => 39296, 25158 => 39300,\n25159 => 39303, 25160 => 39306, 25161 => 39309, 25162 => 39312, 25163 => 39313,\n25164 => 39315, 25165 => 39316, 25166 => 39317, 25167 => 24192, 25168 => 24209,\n25169 => 24203, 25170 => 24214, 25171 => 24229, 25172 => 24224, 25173 => 24249,\n25174 => 24245, 25175 => 24254, 25176 => 24243, 25177 => 36179, 25178 => 24274,\n25179 => 24273, 25180 => 24283, 25181 => 24296, 25182 => 24298, 25183 => 33210,\n25184 => 24516, 25185 => 24521, 25186 => 24534, 25187 => 24527, 25188 => 24579,\n25189 => 24558, 25190 => 24580, 25191 => 24545, 25192 => 24548, 25193 => 24574,\n25194 => 24581, 25195 => 24582, 25196 => 24554, 25197 => 24557, 25198 => 24568,\n25199 => 24601, 25200 => 24629, 25201 => 24614, 25202 => 24603, 25203 => 24591,\n25204 => 24589, 25205 => 24617, 25206 => 24619, 25207 => 24586, 25208 => 24639,\n25209 => 24609, 25210 => 24696, 25211 => 24697, 25212 => 24699, 25213 => 24698,\n25214 => 24642, 25377 => 24682, 25378 => 24701, 25379 => 24726, 25380 => 24730,\n25381 => 24749, 25382 => 24733, 25383 => 24707, 25384 => 24722, 25385 => 24716,\n25386 => 24731, 25387 => 24812, 25388 => 24763, 25389 => 24753, 25390 => 24797,\n25391 => 24792, 25392 => 24774, 25393 => 24794, 25394 => 24756, 25395 => 24864,\n25396 => 24870, 25397 => 24853, 25398 => 24867, 25399 => 24820, 25400 => 24832,\n25401 => 24846, 25402 => 24875, 25403 => 24906, 25404 => 24949, 25405 => 25004,\n25406 => 24980, 25407 => 24999, 25408 => 25015, 25409 => 25044, 25410 => 25077,\n25411 => 24541, 25412 => 38579, 25413 => 38377, 25414 => 38379, 25415 => 38385,\n25416 => 38387, 25417 => 38389, 25418 => 38390, 25419 => 38396, 25420 => 38398,\n25421 => 38403, 25422 => 38404, 25423 => 38406, 25424 => 38408, 25425 => 38410,\n25426 => 38411, 25427 => 38412, 25428 => 38413, 25429 => 38415, 25430 => 38418,\n25431 => 38421, 25432 => 38422, 25433 => 38423, 25434 => 38425, 25435 => 38426,\n25436 => 20012, 25437 => 29247, 25438 => 25109, 25439 => 27701, 25440 => 27732,\n25441 => 27740, 25442 => 27722, 25443 => 27811, 25444 => 27781, 25445 => 27792,\n25446 => 27796, 25447 => 27788, 25448 => 27752, 25449 => 27753, 25450 => 27764,\n25451 => 27766, 25452 => 27782, 25453 => 27817, 25454 => 27856, 25455 => 27860,\n25456 => 27821, 25457 => 27895, 25458 => 27896, 25459 => 27889, 25460 => 27863,\n25461 => 27826, 25462 => 27872, 25463 => 27862, 25464 => 27898, 25465 => 27883,\n25466 => 27886, 25467 => 27825, 25468 => 27859, 25469 => 27887, 25470 => 27902,\n25633 => 27961, 25634 => 27943, 25635 => 27916, 25636 => 27971, 25637 => 27976,\n25638 => 27911, 25639 => 27908, 25640 => 27929, 25641 => 27918, 25642 => 27947,\n25643 => 27981, 25644 => 27950, 25645 => 27957, 25646 => 27930, 25647 => 27983,\n25648 => 27986, 25649 => 27988, 25650 => 27955, 25651 => 28049, 25652 => 28015,\n25653 => 28062, 25654 => 28064, 25655 => 27998, 25656 => 28051, 25657 => 28052,\n25658 => 27996, 25659 => 28000, 25660 => 28028, 25661 => 28003, 25662 => 28186,\n25663 => 28103, 25664 => 28101, 25665 => 28126, 25666 => 28174, 25667 => 28095,\n25668 => 28128, 25669 => 28177, 25670 => 28134, 25671 => 28125, 25672 => 28121,\n25673 => 28182, 25674 => 28075, 25675 => 28172, 25676 => 28078, 25677 => 28203,\n25678 => 28270, 25679 => 28238, 25680 => 28267, 25681 => 28338, 25682 => 28255,\n25683 => 28294, 25684 => 28243, 25685 => 28244, 25686 => 28210, 25687 => 28197,\n25688 => 28228, 25689 => 28383, 25690 => 28337, 25691 => 28312, 25692 => 28384,\n25693 => 28461, 25694 => 28386, 25695 => 28325, 25696 => 28327, 25697 => 28349,\n25698 => 28347, 25699 => 28343, 25700 => 28375, 25701 => 28340, 25702 => 28367,\n25703 => 28303, 25704 => 28354, 25705 => 28319, 25706 => 28514, 25707 => 28486,\n25708 => 28487, 25709 => 28452, 25710 => 28437, 25711 => 28409, 25712 => 28463,\n25713 => 28470, 25714 => 28491, 25715 => 28532, 25716 => 28458, 25717 => 28425,\n25718 => 28457, 25719 => 28553, 25720 => 28557, 25721 => 28556, 25722 => 28536,\n25723 => 28530, 25724 => 28540, 25725 => 28538, 25726 => 28625, 25889 => 28617,\n25890 => 28583, 25891 => 28601, 25892 => 28598, 25893 => 28610, 25894 => 28641,\n25895 => 28654, 25896 => 28638, 25897 => 28640, 25898 => 28655, 25899 => 28698,\n25900 => 28707, 25901 => 28699, 25902 => 28729, 25903 => 28725, 25904 => 28751,\n25905 => 28766, 25906 => 23424, 25907 => 23428, 25908 => 23445, 25909 => 23443,\n25910 => 23461, 25911 => 23480, 25912 => 29999, 25913 => 39582, 25914 => 25652,\n25915 => 23524, 25916 => 23534, 25917 => 35120, 25918 => 23536, 25919 => 36423,\n25920 => 35591, 25921 => 36790, 25922 => 36819, 25923 => 36821, 25924 => 36837,\n25925 => 36846, 25926 => 36836, 25927 => 36841, 25928 => 36838, 25929 => 36851,\n25930 => 36840, 25931 => 36869, 25932 => 36868, 25933 => 36875, 25934 => 36902,\n25935 => 36881, 25936 => 36877, 25937 => 36886, 25938 => 36897, 25939 => 36917,\n25940 => 36918, 25941 => 36909, 25942 => 36911, 25943 => 36932, 25944 => 36945,\n25945 => 36946, 25946 => 36944, 25947 => 36968, 25948 => 36952, 25949 => 36962,\n25950 => 36955, 25951 => 26297, 25952 => 36980, 25953 => 36989, 25954 => 36994,\n25955 => 37000, 25956 => 36995, 25957 => 37003, 25958 => 24400, 25959 => 24407,\n25960 => 24406, 25961 => 24408, 25962 => 23611, 25963 => 21675, 25964 => 23632,\n25965 => 23641, 25966 => 23409, 25967 => 23651, 25968 => 23654, 25969 => 32700,\n25970 => 24362, 25971 => 24361, 25972 => 24365, 25973 => 33396, 25974 => 24380,\n25975 => 39739, 25976 => 23662, 25977 => 22913, 25978 => 22915, 25979 => 22925,\n25980 => 22953, 25981 => 22954, 25982 => 22947, 26145 => 22935, 26146 => 22986,\n26147 => 22955, 26148 => 22942, 26149 => 22948, 26150 => 22994, 26151 => 22962,\n26152 => 22959, 26153 => 22999, 26154 => 22974, 26155 => 23045, 26156 => 23046,\n26157 => 23005, 26158 => 23048, 26159 => 23011, 26160 => 23000, 26161 => 23033,\n26162 => 23052, 26163 => 23049, 26164 => 23090, 26165 => 23092, 26166 => 23057,\n26167 => 23075, 26168 => 23059, 26169 => 23104, 26170 => 23143, 26171 => 23114,\n26172 => 23125, 26173 => 23100, 26174 => 23138, 26175 => 23157, 26176 => 33004,\n26177 => 23210, 26178 => 23195, 26179 => 23159, 26180 => 23162, 26181 => 23230,\n26182 => 23275, 26183 => 23218, 26184 => 23250, 26185 => 23252, 26186 => 23224,\n26187 => 23264, 26188 => 23267, 26189 => 23281, 26190 => 23254, 26191 => 23270,\n26192 => 23256, 26193 => 23260, 26194 => 23305, 26195 => 23319, 26196 => 23318,\n26197 => 23346, 26198 => 23351, 26199 => 23360, 26200 => 23573, 26201 => 23580,\n26202 => 23386, 26203 => 23397, 26204 => 23411, 26205 => 23377, 26206 => 23379,\n26207 => 23394, 26208 => 39541, 26209 => 39543, 26210 => 39544, 26211 => 39546,\n26212 => 39551, 26213 => 39549, 26214 => 39552, 26215 => 39553, 26216 => 39557,\n26217 => 39560, 26218 => 39562, 26219 => 39568, 26220 => 39570, 26221 => 39571,\n26222 => 39574, 26223 => 39576, 26224 => 39579, 26225 => 39580, 26226 => 39581,\n26227 => 39583, 26228 => 39584, 26229 => 39586, 26230 => 39587, 26231 => 39589,\n26232 => 39591, 26233 => 32415, 26234 => 32417, 26235 => 32419, 26236 => 32421,\n26237 => 32424, 26238 => 32425, 26401 => 32429, 26402 => 32432, 26403 => 32446,\n26404 => 32448, 26405 => 32449, 26406 => 32450, 26407 => 32457, 26408 => 32459,\n26409 => 32460, 26410 => 32464, 26411 => 32468, 26412 => 32471, 26413 => 32475,\n26414 => 32480, 26415 => 32481, 26416 => 32488, 26417 => 32491, 26418 => 32494,\n26419 => 32495, 26420 => 32497, 26421 => 32498, 26422 => 32525, 26423 => 32502,\n26424 => 32506, 26425 => 32507, 26426 => 32510, 26427 => 32513, 26428 => 32514,\n26429 => 32515, 26430 => 32519, 26431 => 32520, 26432 => 32523, 26433 => 32524,\n26434 => 32527, 26435 => 32529, 26436 => 32530, 26437 => 32535, 26438 => 32537,\n26439 => 32540, 26440 => 32539, 26441 => 32543, 26442 => 32545, 26443 => 32546,\n26444 => 32547, 26445 => 32548, 26446 => 32549, 26447 => 32550, 26448 => 32551,\n26449 => 32554, 26450 => 32555, 26451 => 32556, 26452 => 32557, 26453 => 32559,\n26454 => 32560, 26455 => 32561, 26456 => 32562, 26457 => 32563, 26458 => 32565,\n26459 => 24186, 26460 => 30079, 26461 => 24027, 26462 => 30014, 26463 => 37013,\n26464 => 29582, 26465 => 29585, 26466 => 29614, 26467 => 29602, 26468 => 29599,\n26469 => 29647, 26470 => 29634, 26471 => 29649, 26472 => 29623, 26473 => 29619,\n26474 => 29632, 26475 => 29641, 26476 => 29640, 26477 => 29669, 26478 => 29657,\n26479 => 39036, 26480 => 29706, 26481 => 29673, 26482 => 29671, 26483 => 29662,\n26484 => 29626, 26485 => 29682, 26486 => 29711, 26487 => 29738, 26488 => 29787,\n26489 => 29734, 26490 => 29733, 26491 => 29736, 26492 => 29744, 26493 => 29742,\n26494 => 29740, 26657 => 29723, 26658 => 29722, 26659 => 29761, 26660 => 29788,\n26661 => 29783, 26662 => 29781, 26663 => 29785, 26664 => 29815, 26665 => 29805,\n26666 => 29822, 26667 => 29852, 26668 => 29838, 26669 => 29824, 26670 => 29825,\n26671 => 29831, 26672 => 29835, 26673 => 29854, 26674 => 29864, 26675 => 29865,\n26676 => 29840, 26677 => 29863, 26678 => 29906, 26679 => 29882, 26680 => 38890,\n26681 => 38891, 26682 => 38892, 26683 => 26444, 26684 => 26451, 26685 => 26462,\n26686 => 26440, 26687 => 26473, 26688 => 26533, 26689 => 26503, 26690 => 26474,\n26691 => 26483, 26692 => 26520, 26693 => 26535, 26694 => 26485, 26695 => 26536,\n26696 => 26526, 26697 => 26541, 26698 => 26507, 26699 => 26487, 26700 => 26492,\n26701 => 26608, 26702 => 26633, 26703 => 26584, 26704 => 26634, 26705 => 26601,\n26706 => 26544, 26707 => 26636, 26708 => 26585, 26709 => 26549, 26710 => 26586,\n26711 => 26547, 26712 => 26589, 26713 => 26624, 26714 => 26563, 26715 => 26552,\n26716 => 26594, 26717 => 26638, 26718 => 26561, 26719 => 26621, 26720 => 26674,\n26721 => 26675, 26722 => 26720, 26723 => 26721, 26724 => 26702, 26725 => 26722,\n26726 => 26692, 26727 => 26724, 26728 => 26755, 26729 => 26653, 26730 => 26709,\n26731 => 26726, 26732 => 26689, 26733 => 26727, 26734 => 26688, 26735 => 26686,\n26736 => 26698, 26737 => 26697, 26738 => 26665, 26739 => 26805, 26740 => 26767,\n26741 => 26740, 26742 => 26743, 26743 => 26771, 26744 => 26731, 26745 => 26818,\n26746 => 26990, 26747 => 26876, 26748 => 26911, 26749 => 26912, 26750 => 26873,\n26913 => 26916, 26914 => 26864, 26915 => 26891, 26916 => 26881, 26917 => 26967,\n26918 => 26851, 26919 => 26896, 26920 => 26993, 26921 => 26937, 26922 => 26976,\n26923 => 26946, 26924 => 26973, 26925 => 27012, 26926 => 26987, 26927 => 27008,\n26928 => 27032, 26929 => 27000, 26930 => 26932, 26931 => 27084, 26932 => 27015,\n26933 => 27016, 26934 => 27086, 26935 => 27017, 26936 => 26982, 26937 => 26979,\n26938 => 27001, 26939 => 27035, 26940 => 27047, 26941 => 27067, 26942 => 27051,\n26943 => 27053, 26944 => 27092, 26945 => 27057, 26946 => 27073, 26947 => 27082,\n26948 => 27103, 26949 => 27029, 26950 => 27104, 26951 => 27021, 26952 => 27135,\n26953 => 27183, 26954 => 27117, 26955 => 27159, 26956 => 27160, 26957 => 27237,\n26958 => 27122, 26959 => 27204, 26960 => 27198, 26961 => 27296, 26962 => 27216,\n26963 => 27227, 26964 => 27189, 26965 => 27278, 26966 => 27257, 26967 => 27197,\n26968 => 27176, 26969 => 27224, 26970 => 27260, 26971 => 27281, 26972 => 27280,\n26973 => 27305, 26974 => 27287, 26975 => 27307, 26976 => 29495, 26977 => 29522,\n26978 => 27521, 26979 => 27522, 26980 => 27527, 26981 => 27524, 26982 => 27538,\n26983 => 27539, 26984 => 27533, 26985 => 27546, 26986 => 27547, 26987 => 27553,\n26988 => 27562, 26989 => 36715, 26990 => 36717, 26991 => 36721, 26992 => 36722,\n26993 => 36723, 26994 => 36725, 26995 => 36726, 26996 => 36728, 26997 => 36727,\n26998 => 36729, 26999 => 36730, 27000 => 36732, 27001 => 36734, 27002 => 36737,\n27003 => 36738, 27004 => 36740, 27005 => 36743, 27006 => 36747, 27169 => 36749,\n27170 => 36750, 27171 => 36751, 27172 => 36760, 27173 => 36762, 27174 => 36558,\n27175 => 25099, 27176 => 25111, 27177 => 25115, 27178 => 25119, 27179 => 25122,\n27180 => 25121, 27181 => 25125, 27182 => 25124, 27183 => 25132, 27184 => 33255,\n27185 => 29935, 27186 => 29940, 27187 => 29951, 27188 => 29967, 27189 => 29969,\n27190 => 29971, 27191 => 25908, 27192 => 26094, 27193 => 26095, 27194 => 26096,\n27195 => 26122, 27196 => 26137, 27197 => 26482, 27198 => 26115, 27199 => 26133,\n27200 => 26112, 27201 => 28805, 27202 => 26359, 27203 => 26141, 27204 => 26164,\n27205 => 26161, 27206 => 26166, 27207 => 26165, 27208 => 32774, 27209 => 26207,\n27210 => 26196, 27211 => 26177, 27212 => 26191, 27213 => 26198, 27214 => 26209,\n27215 => 26199, 27216 => 26231, 27217 => 26244, 27218 => 26252, 27219 => 26279,\n27220 => 26269, 27221 => 26302, 27222 => 26331, 27223 => 26332, 27224 => 26342,\n27225 => 26345, 27226 => 36146, 27227 => 36147, 27228 => 36150, 27229 => 36155,\n27230 => 36157, 27231 => 36160, 27232 => 36165, 27233 => 36166, 27234 => 36168,\n27235 => 36169, 27236 => 36167, 27237 => 36173, 27238 => 36181, 27239 => 36185,\n27240 => 35271, 27241 => 35274, 27242 => 35275, 27243 => 35276, 27244 => 35278,\n27245 => 35279, 27246 => 35280, 27247 => 35281, 27248 => 29294, 27249 => 29343,\n27250 => 29277, 27251 => 29286, 27252 => 29295, 27253 => 29310, 27254 => 29311,\n27255 => 29316, 27256 => 29323, 27257 => 29325, 27258 => 29327, 27259 => 29330,\n27260 => 25352, 27261 => 25394, 27262 => 25520, 27425 => 25663, 27426 => 25816,\n27427 => 32772, 27428 => 27626, 27429 => 27635, 27430 => 27645, 27431 => 27637,\n27432 => 27641, 27433 => 27653, 27434 => 27655, 27435 => 27654, 27436 => 27661,\n27437 => 27669, 27438 => 27672, 27439 => 27673, 27440 => 27674, 27441 => 27681,\n27442 => 27689, 27443 => 27684, 27444 => 27690, 27445 => 27698, 27446 => 25909,\n27447 => 25941, 27448 => 25963, 27449 => 29261, 27450 => 29266, 27451 => 29270,\n27452 => 29232, 27453 => 34402, 27454 => 21014, 27455 => 32927, 27456 => 32924,\n27457 => 32915, 27458 => 32956, 27459 => 26378, 27460 => 32957, 27461 => 32945,\n27462 => 32939, 27463 => 32941, 27464 => 32948, 27465 => 32951, 27466 => 32999,\n27467 => 33000, 27468 => 33001, 27469 => 33002, 27470 => 32987, 27471 => 32962,\n27472 => 32964, 27473 => 32985, 27474 => 32973, 27475 => 32983, 27476 => 26384,\n27477 => 32989, 27478 => 33003, 27479 => 33009, 27480 => 33012, 27481 => 33005,\n27482 => 33037, 27483 => 33038, 27484 => 33010, 27485 => 33020, 27486 => 26389,\n27487 => 33042, 27488 => 35930, 27489 => 33078, 27490 => 33054, 27491 => 33068,\n27492 => 33048, 27493 => 33074, 27494 => 33096, 27495 => 33100, 27496 => 33107,\n27497 => 33140, 27498 => 33113, 27499 => 33114, 27500 => 33137, 27501 => 33120,\n27502 => 33129, 27503 => 33148, 27504 => 33149, 27505 => 33133, 27506 => 33127,\n27507 => 22605, 27508 => 23221, 27509 => 33160, 27510 => 33154, 27511 => 33169,\n27512 => 28373, 27513 => 33187, 27514 => 33194, 27515 => 33228, 27516 => 26406,\n27517 => 33226, 27518 => 33211, 27681 => 33217, 27682 => 33190, 27683 => 27428,\n27684 => 27447, 27685 => 27449, 27686 => 27459, 27687 => 27462, 27688 => 27481,\n27689 => 39121, 27690 => 39122, 27691 => 39123, 27692 => 39125, 27693 => 39129,\n27694 => 39130, 27695 => 27571, 27696 => 24384, 27697 => 27586, 27698 => 35315,\n27699 => 26000, 27700 => 40785, 27701 => 26003, 27702 => 26044, 27703 => 26054,\n27704 => 26052, 27705 => 26051, 27706 => 26060, 27707 => 26062, 27708 => 26066,\n27709 => 26070, 27710 => 28800, 27711 => 28828, 27712 => 28822, 27713 => 28829,\n27714 => 28859, 27715 => 28864, 27716 => 28855, 27717 => 28843, 27718 => 28849,\n27719 => 28904, 27720 => 28874, 27721 => 28944, 27722 => 28947, 27723 => 28950,\n27724 => 28975, 27725 => 28977, 27726 => 29043, 27727 => 29020, 27728 => 29032,\n27729 => 28997, 27730 => 29042, 27731 => 29002, 27732 => 29048, 27733 => 29050,\n27734 => 29080, 27735 => 29107, 27736 => 29109, 27737 => 29096, 27738 => 29088,\n27739 => 29152, 27740 => 29140, 27741 => 29159, 27742 => 29177, 27743 => 29213,\n27744 => 29224, 27745 => 28780, 27746 => 28952, 27747 => 29030, 27748 => 29113,\n27749 => 25150, 27750 => 25149, 27751 => 25155, 27752 => 25160, 27753 => 25161,\n27754 => 31035, 27755 => 31040, 27756 => 31046, 27757 => 31049, 27758 => 31067,\n27759 => 31068, 27760 => 31059, 27761 => 31066, 27762 => 31074, 27763 => 31063,\n27764 => 31072, 27765 => 31087, 27766 => 31079, 27767 => 31098, 27768 => 31109,\n27769 => 31114, 27770 => 31130, 27771 => 31143, 27772 => 31155, 27773 => 24529,\n27774 => 24528, 27937 => 24636, 27938 => 24669, 27939 => 24666, 27940 => 24679,\n27941 => 24641, 27942 => 24665, 27943 => 24675, 27944 => 24747, 27945 => 24838,\n27946 => 24845, 27947 => 24925, 27948 => 25001, 27949 => 24989, 27950 => 25035,\n27951 => 25041, 27952 => 25094, 27953 => 32896, 27954 => 32895, 27955 => 27795,\n27956 => 27894, 27957 => 28156, 27958 => 30710, 27959 => 30712, 27960 => 30720,\n27961 => 30729, 27962 => 30743, 27963 => 30744, 27964 => 30737, 27965 => 26027,\n27966 => 30765, 27967 => 30748, 27968 => 30749, 27969 => 30777, 27970 => 30778,\n27971 => 30779, 27972 => 30751, 27973 => 30780, 27974 => 30757, 27975 => 30764,\n27976 => 30755, 27977 => 30761, 27978 => 30798, 27979 => 30829, 27980 => 30806,\n27981 => 30807, 27982 => 30758, 27983 => 30800, 27984 => 30791, 27985 => 30796,\n27986 => 30826, 27987 => 30875, 27988 => 30867, 27989 => 30874, 27990 => 30855,\n27991 => 30876, 27992 => 30881, 27993 => 30883, 27994 => 30898, 27995 => 30905,\n27996 => 30885, 27997 => 30932, 27998 => 30937, 27999 => 30921, 28000 => 30956,\n28001 => 30962, 28002 => 30981, 28003 => 30964, 28004 => 30995, 28005 => 31012,\n28006 => 31006, 28007 => 31028, 28008 => 40859, 28009 => 40697, 28010 => 40699,\n28011 => 40700, 28012 => 30449, 28013 => 30468, 28014 => 30477, 28015 => 30457,\n28016 => 30471, 28017 => 30472, 28018 => 30490, 28019 => 30498, 28020 => 30489,\n28021 => 30509, 28022 => 30502, 28023 => 30517, 28024 => 30520, 28025 => 30544,\n28026 => 30545, 28027 => 30535, 28028 => 30531, 28029 => 30554, 28030 => 30568,\n28193 => 30562, 28194 => 30565, 28195 => 30591, 28196 => 30605, 28197 => 30589,\n28198 => 30592, 28199 => 30604, 28200 => 30609, 28201 => 30623, 28202 => 30624,\n28203 => 30640, 28204 => 30645, 28205 => 30653, 28206 => 30010, 28207 => 30016,\n28208 => 30030, 28209 => 30027, 28210 => 30024, 28211 => 30043, 28212 => 30066,\n28213 => 30073, 28214 => 30083, 28215 => 32600, 28216 => 32609, 28217 => 32607,\n28218 => 35400, 28219 => 32616, 28220 => 32628, 28221 => 32625, 28222 => 32633,\n28223 => 32641, 28224 => 32638, 28225 => 30413, 28226 => 30437, 28227 => 34866,\n28228 => 38021, 28229 => 38022, 28230 => 38023, 28231 => 38027, 28232 => 38026,\n28233 => 38028, 28234 => 38029, 28235 => 38031, 28236 => 38032, 28237 => 38036,\n28238 => 38039, 28239 => 38037, 28240 => 38042, 28241 => 38043, 28242 => 38044,\n28243 => 38051, 28244 => 38052, 28245 => 38059, 28246 => 38058, 28247 => 38061,\n28248 => 38060, 28249 => 38063, 28250 => 38064, 28251 => 38066, 28252 => 38068,\n28253 => 38070, 28254 => 38071, 28255 => 38072, 28256 => 38073, 28257 => 38074,\n28258 => 38076, 28259 => 38077, 28260 => 38079, 28261 => 38084, 28262 => 38088,\n28263 => 38089, 28264 => 38090, 28265 => 38091, 28266 => 38092, 28267 => 38093,\n28268 => 38094, 28269 => 38096, 28270 => 38097, 28271 => 38098, 28272 => 38101,\n28273 => 38102, 28274 => 38103, 28275 => 38105, 28276 => 38104, 28277 => 38107,\n28278 => 38110, 28279 => 38111, 28280 => 38112, 28281 => 38114, 28282 => 38116,\n28283 => 38117, 28284 => 38119, 28285 => 38120, 28286 => 38122, 28449 => 38121,\n28450 => 38123, 28451 => 38126, 28452 => 38127, 28453 => 38131, 28454 => 38132,\n28455 => 38133, 28456 => 38135, 28457 => 38137, 28458 => 38140, 28459 => 38141,\n28460 => 38143, 28461 => 38147, 28462 => 38146, 28463 => 38150, 28464 => 38151,\n28465 => 38153, 28466 => 38154, 28467 => 38157, 28468 => 38158, 28469 => 38159,\n28470 => 38162, 28471 => 38163, 28472 => 38164, 28473 => 38165, 28474 => 38166,\n28475 => 38168, 28476 => 38171, 28477 => 38173, 28478 => 38174, 28479 => 38175,\n28480 => 38178, 28481 => 38186, 28482 => 38187, 28483 => 38185, 28484 => 38188,\n28485 => 38193, 28486 => 38194, 28487 => 38196, 28488 => 38198, 28489 => 38199,\n28490 => 38200, 28491 => 38204, 28492 => 38206, 28493 => 38207, 28494 => 38210,\n28495 => 38197, 28496 => 38212, 28497 => 38213, 28498 => 38214, 28499 => 38217,\n28500 => 38220, 28501 => 38222, 28502 => 38223, 28503 => 38226, 28504 => 38227,\n28505 => 38228, 28506 => 38230, 28507 => 38231, 28508 => 38232, 28509 => 38233,\n28510 => 38235, 28511 => 38238, 28512 => 38239, 28513 => 38237, 28514 => 38241,\n28515 => 38242, 28516 => 38244, 28517 => 38245, 28518 => 38246, 28519 => 38247,\n28520 => 38248, 28521 => 38249, 28522 => 38250, 28523 => 38251, 28524 => 38252,\n28525 => 38255, 28526 => 38257, 28527 => 38258, 28528 => 38259, 28529 => 38202,\n28530 => 30695, 28531 => 30700, 28532 => 38601, 28533 => 31189, 28534 => 31213,\n28535 => 31203, 28536 => 31211, 28537 => 31238, 28538 => 23879, 28539 => 31235,\n28540 => 31234, 28541 => 31262, 28542 => 31252, 28705 => 31289, 28706 => 31287,\n28707 => 31313, 28708 => 40655, 28709 => 39333, 28710 => 31344, 28711 => 30344,\n28712 => 30350, 28713 => 30355, 28714 => 30361, 28715 => 30372, 28716 => 29918,\n28717 => 29920, 28718 => 29996, 28719 => 40480, 28720 => 40482, 28721 => 40488,\n28722 => 40489, 28723 => 40490, 28724 => 40491, 28725 => 40492, 28726 => 40498,\n28727 => 40497, 28728 => 40502, 28729 => 40504, 28730 => 40503, 28731 => 40505,\n28732 => 40506, 28733 => 40510, 28734 => 40513, 28735 => 40514, 28736 => 40516,\n28737 => 40518, 28738 => 40519, 28739 => 40520, 28740 => 40521, 28741 => 40523,\n28742 => 40524, 28743 => 40526, 28744 => 40529, 28745 => 40533, 28746 => 40535,\n28747 => 40538, 28748 => 40539, 28749 => 40540, 28750 => 40542, 28751 => 40547,\n28752 => 40550, 28753 => 40551, 28754 => 40552, 28755 => 40553, 28756 => 40554,\n28757 => 40555, 28758 => 40556, 28759 => 40561, 28760 => 40557, 28761 => 40563,\n28762 => 30098, 28763 => 30100, 28764 => 30102, 28765 => 30112, 28766 => 30109,\n28767 => 30124, 28768 => 30115, 28769 => 30131, 28770 => 30132, 28771 => 30136,\n28772 => 30148, 28773 => 30129, 28774 => 30128, 28775 => 30147, 28776 => 30146,\n28777 => 30166, 28778 => 30157, 28779 => 30179, 28780 => 30184, 28781 => 30182,\n28782 => 30180, 28783 => 30187, 28784 => 30183, 28785 => 30211, 28786 => 30193,\n28787 => 30204, 28788 => 30207, 28789 => 30224, 28790 => 30208, 28791 => 30213,\n28792 => 30220, 28793 => 30231, 28794 => 30218, 28795 => 30245, 28796 => 30232,\n28797 => 30229, 28798 => 30233, 28961 => 30235, 28962 => 30268, 28963 => 30242,\n28964 => 30240, 28965 => 30272, 28966 => 30253, 28967 => 30256, 28968 => 30271,\n28969 => 30261, 28970 => 30275, 28971 => 30270, 28972 => 30259, 28973 => 30285,\n28974 => 30302, 28975 => 30292, 28976 => 30300, 28977 => 30294, 28978 => 30315,\n28979 => 30319, 28980 => 32714, 28981 => 31462, 28982 => 31352, 28983 => 31353,\n28984 => 31360, 28985 => 31366, 28986 => 31368, 28987 => 31381, 28988 => 31398,\n28989 => 31392, 28990 => 31404, 28991 => 31400, 28992 => 31405, 28993 => 31411,\n28994 => 34916, 28995 => 34921, 28996 => 34930, 28997 => 34941, 28998 => 34943,\n28999 => 34946, 29000 => 34978, 29001 => 35014, 29002 => 34999, 29003 => 35004,\n29004 => 35017, 29005 => 35042, 29006 => 35022, 29007 => 35043, 29008 => 35045,\n29009 => 35057, 29010 => 35098, 29011 => 35068, 29012 => 35048, 29013 => 35070,\n29014 => 35056, 29015 => 35105, 29016 => 35097, 29017 => 35091, 29018 => 35099,\n29019 => 35082, 29020 => 35124, 29021 => 35115, 29022 => 35126, 29023 => 35137,\n29024 => 35174, 29025 => 35195, 29026 => 30091, 29027 => 32997, 29028 => 30386,\n29029 => 30388, 29030 => 30684, 29031 => 32786, 29032 => 32788, 29033 => 32790,\n29034 => 32796, 29035 => 32800, 29036 => 32802, 29037 => 32805, 29038 => 32806,\n29039 => 32807, 29040 => 32809, 29041 => 32808, 29042 => 32817, 29043 => 32779,\n29044 => 32821, 29045 => 32835, 29046 => 32838, 29047 => 32845, 29048 => 32850,\n29049 => 32873, 29050 => 32881, 29051 => 35203, 29052 => 39032, 29053 => 39040,\n29054 => 39043, 29217 => 39049, 29218 => 39052, 29219 => 39053, 29220 => 39055,\n29221 => 39060, 29222 => 39066, 29223 => 39067, 29224 => 39070, 29225 => 39071,\n29226 => 39073, 29227 => 39074, 29228 => 39077, 29229 => 39078, 29230 => 34381,\n29231 => 34388, 29232 => 34412, 29233 => 34414, 29234 => 34431, 29235 => 34426,\n29236 => 34428, 29237 => 34427, 29238 => 34472, 29239 => 34445, 29240 => 34443,\n29241 => 34476, 29242 => 34461, 29243 => 34471, 29244 => 34467, 29245 => 34474,\n29246 => 34451, 29247 => 34473, 29248 => 34486, 29249 => 34500, 29250 => 34485,\n29251 => 34510, 29252 => 34480, 29253 => 34490, 29254 => 34481, 29255 => 34479,\n29256 => 34505, 29257 => 34511, 29258 => 34484, 29259 => 34537, 29260 => 34545,\n29261 => 34546, 29262 => 34541, 29263 => 34547, 29264 => 34512, 29265 => 34579,\n29266 => 34526, 29267 => 34548, 29268 => 34527, 29269 => 34520, 29270 => 34513,\n29271 => 34563, 29272 => 34567, 29273 => 34552, 29274 => 34568, 29275 => 34570,\n29276 => 34573, 29277 => 34569, 29278 => 34595, 29279 => 34619, 29280 => 34590,\n29281 => 34597, 29282 => 34606, 29283 => 34586, 29284 => 34622, 29285 => 34632,\n29286 => 34612, 29287 => 34609, 29288 => 34601, 29289 => 34615, 29290 => 34623,\n29291 => 34690, 29292 => 34594, 29293 => 34685, 29294 => 34686, 29295 => 34683,\n29296 => 34656, 29297 => 34672, 29298 => 34636, 29299 => 34670, 29300 => 34699,\n29301 => 34643, 29302 => 34659, 29303 => 34684, 29304 => 34660, 29305 => 34649,\n29306 => 34661, 29307 => 34707, 29308 => 34735, 29309 => 34728, 29310 => 34770,\n29473 => 34758, 29474 => 34696, 29475 => 34693, 29476 => 34733, 29477 => 34711,\n29478 => 34691, 29479 => 34731, 29480 => 34789, 29481 => 34732, 29482 => 34741,\n29483 => 34739, 29484 => 34763, 29485 => 34771, 29486 => 34749, 29487 => 34769,\n29488 => 34752, 29489 => 34762, 29490 => 34779, 29491 => 34794, 29492 => 34784,\n29493 => 34798, 29494 => 34838, 29495 => 34835, 29496 => 34814, 29497 => 34826,\n29498 => 34843, 29499 => 34849, 29500 => 34873, 29501 => 34876, 29502 => 32566,\n29503 => 32578, 29504 => 32580, 29505 => 32581, 29506 => 33296, 29507 => 31482,\n29508 => 31485, 29509 => 31496, 29510 => 31491, 29511 => 31492, 29512 => 31509,\n29513 => 31498, 29514 => 31531, 29515 => 31503, 29516 => 31559, 29517 => 31544,\n29518 => 31530, 29519 => 31513, 29520 => 31534, 29521 => 31537, 29522 => 31520,\n29523 => 31525, 29524 => 31524, 29525 => 31539, 29526 => 31550, 29527 => 31518,\n29528 => 31576, 29529 => 31578, 29530 => 31557, 29531 => 31605, 29532 => 31564,\n29533 => 31581, 29534 => 31584, 29535 => 31598, 29536 => 31611, 29537 => 31586,\n29538 => 31602, 29539 => 31601, 29540 => 31632, 29541 => 31654, 29542 => 31655,\n29543 => 31672, 29544 => 31660, 29545 => 31645, 29546 => 31656, 29547 => 31621,\n29548 => 31658, 29549 => 31644, 29550 => 31650, 29551 => 31659, 29552 => 31668,\n29553 => 31697, 29554 => 31681, 29555 => 31692, 29556 => 31709, 29557 => 31706,\n29558 => 31717, 29559 => 31718, 29560 => 31722, 29561 => 31756, 29562 => 31742,\n29563 => 31740, 29564 => 31759, 29565 => 31766, 29566 => 31755, 29729 => 31775,\n29730 => 31786, 29731 => 31782, 29732 => 31800, 29733 => 31809, 29734 => 31808,\n29735 => 33278, 29736 => 33281, 29737 => 33282, 29738 => 33284, 29739 => 33260,\n29740 => 34884, 29741 => 33313, 29742 => 33314, 29743 => 33315, 29744 => 33325,\n29745 => 33327, 29746 => 33320, 29747 => 33323, 29748 => 33336, 29749 => 33339,\n29750 => 33331, 29751 => 33332, 29752 => 33342, 29753 => 33348, 29754 => 33353,\n29755 => 33355, 29756 => 33359, 29757 => 33370, 29758 => 33375, 29759 => 33384,\n29760 => 34942, 29761 => 34949, 29762 => 34952, 29763 => 35032, 29764 => 35039,\n29765 => 35166, 29766 => 32669, 29767 => 32671, 29768 => 32679, 29769 => 32687,\n29770 => 32688, 29771 => 32690, 29772 => 31868, 29773 => 25929, 29774 => 31889,\n29775 => 31901, 29776 => 31900, 29777 => 31902, 29778 => 31906, 29779 => 31922,\n29780 => 31932, 29781 => 31933, 29782 => 31937, 29783 => 31943, 29784 => 31948,\n29785 => 31949, 29786 => 31944, 29787 => 31941, 29788 => 31959, 29789 => 31976,\n29790 => 33390, 29791 => 26280, 29792 => 32703, 29793 => 32718, 29794 => 32725,\n29795 => 32741, 29796 => 32737, 29797 => 32742, 29798 => 32745, 29799 => 32750,\n29800 => 32755, 29801 => 31992, 29802 => 32119, 29803 => 32166, 29804 => 32174,\n29805 => 32327, 29806 => 32411, 29807 => 40632, 29808 => 40628, 29809 => 36211,\n29810 => 36228, 29811 => 36244, 29812 => 36241, 29813 => 36273, 29814 => 36199,\n29815 => 36205, 29816 => 35911, 29817 => 35913, 29818 => 37194, 29819 => 37200,\n29820 => 37198, 29821 => 37199, 29822 => 37220, 29985 => 37218, 29986 => 37217,\n29987 => 37232, 29988 => 37225, 29989 => 37231, 29990 => 37245, 29991 => 37246,\n29992 => 37234, 29993 => 37236, 29994 => 37241, 29995 => 37260, 29996 => 37253,\n29997 => 37264, 29998 => 37261, 29999 => 37265, 30000 => 37282, 30001 => 37283,\n30002 => 37290, 30003 => 37293, 30004 => 37294, 30005 => 37295, 30006 => 37301,\n30007 => 37300, 30008 => 37306, 30009 => 35925, 30010 => 40574, 30011 => 36280,\n30012 => 36331, 30013 => 36357, 30014 => 36441, 30015 => 36457, 30016 => 36277,\n30017 => 36287, 30018 => 36284, 30019 => 36282, 30020 => 36292, 30021 => 36310,\n30022 => 36311, 30023 => 36314, 30024 => 36318, 30025 => 36302, 30026 => 36303,\n30027 => 36315, 30028 => 36294, 30029 => 36332, 30030 => 36343, 30031 => 36344,\n30032 => 36323, 30033 => 36345, 30034 => 36347, 30035 => 36324, 30036 => 36361,\n30037 => 36349, 30038 => 36372, 30039 => 36381, 30040 => 36383, 30041 => 36396,\n30042 => 36398, 30043 => 36387, 30044 => 36399, 30045 => 36410, 30046 => 36416,\n30047 => 36409, 30048 => 36405, 30049 => 36413, 30050 => 36401, 30051 => 36425,\n30052 => 36417, 30053 => 36418, 30054 => 36433, 30055 => 36434, 30056 => 36426,\n30057 => 36464, 30058 => 36470, 30059 => 36476, 30060 => 36463, 30061 => 36468,\n30062 => 36485, 30063 => 36495, 30064 => 36500, 30065 => 36496, 30066 => 36508,\n30067 => 36510, 30068 => 35960, 30069 => 35970, 30070 => 35978, 30071 => 35973,\n30072 => 35992, 30073 => 35988, 30074 => 26011, 30075 => 35286, 30076 => 35294,\n30077 => 35290, 30078 => 35292, 30241 => 35301, 30242 => 35307, 30243 => 35311,\n30244 => 35390, 30245 => 35622, 30246 => 38739, 30247 => 38633, 30248 => 38643,\n30249 => 38639, 30250 => 38662, 30251 => 38657, 30252 => 38664, 30253 => 38671,\n30254 => 38670, 30255 => 38698, 30256 => 38701, 30257 => 38704, 30258 => 38718,\n30259 => 40832, 30260 => 40835, 30261 => 40837, 30262 => 40838, 30263 => 40839,\n30264 => 40840, 30265 => 40841, 30266 => 40842, 30267 => 40844, 30268 => 40702,\n30269 => 40715, 30270 => 40717, 30271 => 38585, 30272 => 38588, 30273 => 38589,\n30274 => 38606, 30275 => 38610, 30276 => 30655, 30277 => 38624, 30278 => 37518,\n30279 => 37550, 30280 => 37576, 30281 => 37694, 30282 => 37738, 30283 => 37834,\n30284 => 37775, 30285 => 37950, 30286 => 37995, 30287 => 40063, 30288 => 40066,\n30289 => 40069, 30290 => 40070, 30291 => 40071, 30292 => 40072, 30293 => 31267,\n30294 => 40075, 30295 => 40078, 30296 => 40080, 30297 => 40081, 30298 => 40082,\n30299 => 40084, 30300 => 40085, 30301 => 40090, 30302 => 40091, 30303 => 40094,\n30304 => 40095, 30305 => 40096, 30306 => 40097, 30307 => 40098, 30308 => 40099,\n30309 => 40101, 30310 => 40102, 30311 => 40103, 30312 => 40104, 30313 => 40105,\n30314 => 40107, 30315 => 40109, 30316 => 40110, 30317 => 40112, 30318 => 40113,\n30319 => 40114, 30320 => 40115, 30321 => 40116, 30322 => 40117, 30323 => 40118,\n30324 => 40119, 30325 => 40122, 30326 => 40123, 30327 => 40124, 30328 => 40125,\n30329 => 40132, 30330 => 40133, 30331 => 40134, 30332 => 40135, 30333 => 40138,\n30334 => 40139, 30497 => 40140, 30498 => 40141, 30499 => 40142, 30500 => 40143,\n30501 => 40144, 30502 => 40147, 30503 => 40148, 30504 => 40149, 30505 => 40151,\n30506 => 40152, 30507 => 40153, 30508 => 40156, 30509 => 40157, 30510 => 40159,\n30511 => 40162, 30512 => 38780, 30513 => 38789, 30514 => 38801, 30515 => 38802,\n30516 => 38804, 30517 => 38831, 30518 => 38827, 30519 => 38819, 30520 => 38834,\n30521 => 38836, 30522 => 39601, 30523 => 39600, 30524 => 39607, 30525 => 40536,\n30526 => 39606, 30527 => 39610, 30528 => 39612, 30529 => 39617, 30530 => 39616,\n30531 => 39621, 30532 => 39618, 30533 => 39627, 30534 => 39628, 30535 => 39633,\n30536 => 39749, 30537 => 39747, 30538 => 39751, 30539 => 39753, 30540 => 39752,\n30541 => 39757, 30542 => 39761, 30543 => 39144, 30544 => 39181, 30545 => 39214,\n30546 => 39253, 30547 => 39252, 30548 => 39647, 30549 => 39649, 30550 => 39654,\n30551 => 39663, 30552 => 39659, 30553 => 39675, 30554 => 39661, 30555 => 39673,\n30556 => 39688, 30557 => 39695, 30558 => 39699, 30559 => 39711, 30560 => 39715,\n30561 => 40637, 30562 => 40638, 30563 => 32315, 30564 => 40578, 30565 => 40583,\n30566 => 40584, 30567 => 40587, 30568 => 40594, 30569 => 37846, 30570 => 40605,\n30571 => 40607, 30572 => 40667, 30573 => 40668, 30574 => 40669, 30575 => 40672,\n30576 => 40671, 30577 => 40674, 30578 => 40681, 30579 => 40679, 30580 => 40677,\n30581 => 40682, 30582 => 40687, 30583 => 40738, 30584 => 40748, 30585 => 40751,\n30586 => 40761, 30587 => 40759, 30588 => 40765, 30589 => 40766, 30590 => 40772,\n0 => 0 );\n\n    function gb2utf8($gb) {\n\tif( !trim($gb) ) return $gb;\n\t$utf8='';\n\twhile($gb) {\n\t    if( ord(substr($gb,0,1)) > 127 ) {\n\t\t$t=substr($gb,0,2);\n\t\t$gb=substr($gb,2);\n\t\t$utf8 .= $this->u2utf8($this->codetable[hexdec(bin2hex($t))-0x8080]);\n\t    }\n\t    else { \n\t\t$t=substr($gb,0,1);\n\t\t$gb=substr($gb,1);\n\t\t$utf8 .= $this->u2utf8($t);\n\t    }\n\t}\n\treturn $utf8;\n    }\n    \n    function u2utf8($c) {\n\t$str='';\n\tif ($c < 0x80) {\n\t    $str.=$c;\n\t    }\n\telse if ($c < 0x800) {\n\t    $str.=chr(0xC0 | $c>>6);\n\t    $str.=chr(0x80 | $c & 0x3F);\n\t    }\n\telse if ($c < 0x10000) {\n\t    $str.=chr(0xE0 | $c>>12);\n\t    $str.=chr(0x80 | $c>>6 & 0x3F);\n\t\t$str.=chr(0x80 | $c & 0x3F);\n\t}\n\telse if ($c < 0x200000) {\n\t    $str.=chr(0xF0 | $c>>18);\n\t    $str.=chr(0x80 | $c>>12 & 0x3F);\n\t    $str.=chr(0x80 | $c>>6 & 0x3F);\n\t    $str.=chr(0x80 | $c & 0x3F);\n\t}\n\treturn $str;\n    }\n\n} // END Class \n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_gradient.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_GRADIENT.PHP\n// Description:\tCreate a color gradient\n// Created: \t2003-02-01\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_gradient.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n// Styles for gradient color fill\nDEFINE(\"GRAD_VER\",1);\nDEFINE(\"GRAD_VERT\",1);\nDEFINE(\"GRAD_HOR\",2);\nDEFINE(\"GRAD_MIDHOR\",3);\nDEFINE(\"GRAD_MIDVER\",4);\nDEFINE(\"GRAD_CENTER\",5);\nDEFINE(\"GRAD_WIDE_MIDVER\",6);\nDEFINE(\"GRAD_WIDE_MIDHOR\",7);\nDEFINE(\"GRAD_LEFT_REFLECTION\",8);\nDEFINE(\"GRAD_RIGHT_REFLECTION\",9);\nDEFINE(\"GRAD_RAISED_PANEL\",10);\n\n  \n//===================================================\n// CLASS Gradient\n// Description: Handles gradient fills. This is to be\n// considered a \"friend\" class of Class Image.\n//===================================================\nclass Gradient {\n    var $img=null;\n    var $numcolors=100;\n//---------------\n// CONSTRUCTOR\n    function Gradient(&$img) {\n\t$this->img = &$img;\n    }\n\n\n    function SetNumColors($aNum) {\n\t$this->numcolors=$aNum;\n    }\n//---------------\n// PUBLIC METHODS\t\n    // Produce a gradient filled rectangle with a smooth transition between\n    // two colors.\n    // ($xl,$yt) \tTop left corner\n    // ($xr,$yb)\tBottom right\n    // $from_color\tStarting color in gradient\n    // $to_color\tEnd color in the gradient\n    // $style\t\tWhich way is the gradient oriented?\n    function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) {\n\tswitch( $style ) {\t\n\t    case GRAD_VER:  \n\t\t$steps = round(abs($xr-$xl));\n\t\t$delta = $xr>=$xl ? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);\n\t\tfor( $i=0, $x=$xl; $i < $steps; ++$i ) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yt,$x,$yb);\n\t\t    $x += $delta;\n\t\t}\n\t\tbreak;\n\n\t    case GRAD_HOR: \n\t\t$steps = round(abs($yb-$yt));\n\t\t$delta = $yb>=$yt ? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);\n\t\tfor($i=0,$y=$yt; $i < $steps; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\n\t\tbreak;\n\n\t    case GRAD_MIDHOR: \n\t\t$steps = round(abs($yb-$yt)/2);\n\t\t$delta = $yb >= $yt ? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);\n\t\tfor($y=$yt, $i=0; $i < $steps;  ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\n\t\t--$i;\n\t\tif( abs($yb-$yt) % 2 == 1 ) --$steps;\n\t\tfor($j=0; $j < $steps; ++$j, --$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\n\t\t$this->img->Line($xl,$y,$xr,$y);\n\t\tbreak;\n\n\t    case GRAD_MIDVER: \n\t\t$steps = round(abs($xr-$xl)/2);\n\t\t$delta = $xr>=$xl ? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);\n\t\tfor($x=$xl, $i=0; $i < $steps; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t--$i;\n\t\tif( abs($xr-$xl) % 2 == 1 ) --$steps;\n\t\tfor($j=0; $j < $steps; ++$j, --$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t$this->img->Line($x,$yb,$x,$yt);\t\t\n\t\tbreak;\n\n\t    case GRAD_WIDE_MIDVER: \n\t\t$diff = round(abs($xr-$xl));\n\t\t$steps = floor(abs($diff)/3);\n\t\t$firststep = $diff - 2*$steps ; \n\t\t$delta = $xr >= $xl ? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors);\n\t\tfor($x=$xl, $i=0; $i < $firststep; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t--$i;\n\t\t$this->img->current_color = $colors[$i];\n\t\tfor($j=0; $j< $steps; ++$j) {\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t\n\t\tfor($j=0; $j < $steps; ++$j, --$i) {\n\t\t    $this->img->current_color = $colors[$i];\t\t\t\t\n\t\t    $this->img->Line($x,$yb,$x,$yt);\t\n\t\t    $x += $delta;\n\t\t}\t\t\t\t\n\t\tbreak;\n\n\t    case GRAD_WIDE_MIDHOR:\n\t\t$diff = round(abs($yb-$yt));\n\t\t$steps = floor(abs($diff)/3);\n\t\t$firststep = $diff - 2*$steps ; \n\t\t$delta = $yb >= $yt? 1 : -1;\n\t\t$this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors);\n\t\tfor($y=$yt, $i=0; $i < $firststep;  ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\n\t\t--$i;\n\t\t$this->img->current_color = $colors[$i];\n\t\tfor($j=0; $j < $steps; ++$j) {\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\n\t\tfor($j=0; $j < $steps; ++$j, --$i) {\n\t\t    $this->img->current_color = $colors[$i];\t\t\t\t\n\t\t    $this->img->Line($xl,$y,$xr,$y);\n\t\t    $y += $delta;\n\t\t}\t\t\t\t\n\t\tbreak;\t    \n\n\t    case GRAD_LEFT_REFLECTION: \n\t\t$steps1 = round(0.3*abs($xr-$xl));\n\t\t$delta = $xr>=$xl ? 1 : -1;\t\t\n\n\t\t$from_color = $this->img->rgb->Color($from_color);\n\t\t$adj = 1.4;\n\t\t$m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));\n\t\t$from_color2 = array(min(255,$from_color[0]+$m), \n\t\t\t\t    min(255,$from_color[1]+$m), min(255,$from_color[2]+$m));\t\t\n\n\t\t$this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors);\n\t\t$n = count($colors);\n\t\tfor($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t$steps2 = max(1,round(0.08*abs($xr-$xl)));\n\t\t$this->img->SetColor($to_color);\n\t\tfor($j=0; $j< $steps2; ++$j) {\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t$steps = abs($xr-$xl)-$steps1-$steps2;\n\t\t$this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors);   \n\t\t$n = count($colors);\n\t\tfor($i=0; $i < $steps && $i < $n; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\tbreak;\n\n\t    case GRAD_RIGHT_REFLECTION: \n\t\t$steps1 = round(0.7*abs($xr-$xl));\n\t\t$delta = $xr>=$xl ? 1 : -1;\n\n\t\t$this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors);\n\t\t$n = count($colors);\n\t\tfor($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\t$steps2 = max(1,round(0.08*abs($xr-$xl)));\n\t\t$this->img->SetColor($to_color);\n\t\tfor($j=0; $j< $steps2; ++$j) {\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\n\t\t$from_color = $this->img->rgb->Color($from_color);\n\t\t$adj = 1.4;\n\t\t$m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));\n\t\t$from_color = array(min(255,$from_color[0]+$m), \n\t\t\t\t    min(255,$from_color[1]+$m), min(255,$from_color[2]+$m));\t\t\n\n\t\t$steps = abs($xr-$xl)-$steps1-$steps2;\n\t\t$this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors);   \n\t\t$n = count($colors);\n\t\tfor($i=0; $i < $steps && $i < $n; ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\n\t\t    $this->img->Line($x,$yb,$x,$yt);\n\t\t    $x += $delta;\n\t\t}\n\t\tbreak;\n\n\t    case GRAD_CENTER: \n\t\t$steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2);\t\n\t\t$this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);\n\t\t$dx = ($xr-$xl)/2;\n\t\t$dy = ($yb-$yt)/2;\n\t\t$x=$xl;$y=$yt;$x2=$xr;$y2=$yb;\n\t\t$n = count($colors);\n\t\tfor($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) {\n\t\t    $this->img->current_color = $colors[$i];\t\t\t\n\t\t    $this->img->Rectangle($x,$y,$x2,$y2);\n\t\t}\n\t\t$this->img->Line($x,$y,$x2,$y2);\n\t\tbreak;\n\t\t\n\t    case GRAD_RAISED_PANEL:\n\t\t// right to left \n\t\t$steps1 = $xr-$xl; \n\t\t$delta = $xr>=$xl ? 1 : -1; \n\t\t$this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors); \n\t\t$n = count($colors);\n\t\tfor($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { \n\t\t    $this->img->current_color = $colors[$i]; \n\t\t    $this->img->Line($x,$yb,$x,$yt); \n\t\t    $x += $delta; \n\t\t} \n\t\t\n\t\t// left to right \n\t\t$xr -= 3; \n\t\t$xl += 3; \n\t\t$yb -= 3; \n\t\t$yt += 3; \n\t\t$steps2 = $xr-$xl; \n\t\t$delta = $xr>=$xl ? 1 : -1; \n\t\tfor($x=$xl, $j=$steps2; $j >= 0; --$j) { \n\t\t    $this->img->current_color = $colors[$j]; \n\t\t    $this->img->Line($x,$yb,$x,$yt); \n\t\t    $x += $delta; \n\t\t} \n\t\tbreak;\n\n\t    default:\n\t\tJpGraphError::RaiseL(7001,$style);\n//(\"Unknown gradient style (=$style).\");\n\t\tbreak;\n\t}\n    }\n\n    // Fill a special case of a polygon with a flat bottom\n    // with a gradient. Can be used for filled line plots.\n    // Please note that this is NOT a generic gradient polygon fill\n    // routine. It assumes that the bottom is flat (like a drawing\n    // of a mountain)\n    function FilledFlatPolygon($pts,$from_color,$to_color) {\n\tif( count($pts) == 0 ) return;\n\t\n\t$maxy=$pts[1];\n\t$miny=$pts[1];\t\t\n\t$n = count($pts) ;\n\tfor( $i=0, $idx=0; $i < $n; $i += 2) {\n\t    $x = round($pts[$i]);\n\t    $y = round($pts[$i+1]);\n\t    $miny = min($miny,$y);\n\t    $maxy = max($maxy,$y);\n\t}\n\t    \n\t$colors = array();\n\t$this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors);\n\tfor($i=$miny, $idx=0; $i <= $maxy; ++$i ) {\n\t    $colmap[$i] = $colors[$idx++]; \n\t}\n\n\t$n = count($pts)/2 ;\n\t$idx = 0 ;\n\twhile( $idx < $n-1 ) {\n\t    $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1]));\n\t    $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1]));\n\t\t\n\t    // Find the largest rectangle we can fill\n\t    $y = max($p1[1],$p2[1]) ;\n\t    for($yy=$maxy; $yy > $y; --$yy) {\n\t\t$this->img->current_color = $colmap[$yy];\n\t\t$this->img->Line($p1[0],$yy,$p2[0]-1,$yy);\n\t    }\n\t    \n\t    if( $p1[1] == $p2[1] ) continue; \n\n\t    // Fill the rest using lines (slow...)\n\t    $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]);\n\t    $x1 = $p1[0];\n\t    $x2 = $p2[0]; //-1;\n\t    $start = $y;\n\t    if( $p1[1] > $p2[1] ) {\n\t\twhile( $y >= $p2[1] ) {\n\t\t    $x1=$slope*($start-$y)+$p1[0];\n\t\t    $this->img->current_color = $colmap[$y];\n\t\t    $this->img->Line($x1,$y,$x2,$y);\n\t\t    --$y;\n\t\t} \n\t    }\n\t    else {\n\t\twhile( $y >= $p1[1] ) {\n\t\t    $x2=$p2[0]+$slope*($start-$y);\n\t\t    $this->img->current_color = $colmap[$y];\n\t\t    $this->img->Line($x1,$y,$x2,$y);\n\t\t    --$y;\n\t\t} \n\t    }\n\t}\n    }\n\n//---------------\n// PRIVATE METHODS\t\n    // Add to the image color map the necessary colors to do the transition\n    // between the two colors using $numcolors intermediate colors\n    function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) {\n\tif( $arr_size==0 ) return;\n\t// If color is given as text get it's corresponding r,g,b values\n\t$from_color = $this->img->rgb->Color($from_color);\n\t$to_color = $this->img->rgb->Color($to_color);\n\t\t\n\t$rdelta=($to_color[0]-$from_color[0])/$numcols;\n\t$gdelta=($to_color[1]-$from_color[1])/$numcols;\n\t$bdelta=($to_color[2]-$from_color[2])/$numcols;\n\t$colorsperstep\t= $numcols/$arr_size;\n\t$prevcolnum\t= -1;\n\t$from_alpha = $from_color[3];\n\t$to_alpha = $to_color[3];\n\t$adelta = ( $to_alpha - $from_alpha ) / $numcols ;\n\tfor ($i=0; $i < $arr_size; ++$i) {\n\t    $colnum = floor($colorsperstep*$i);\n\t    if ( $colnum == $prevcolnum ) \n\t\t$colors[$i]\t= $colidx;\n\t    else {\n\t\t$r = floor($from_color[0] + $colnum*$rdelta);\n\t\t$g = floor($from_color[1] + $colnum*$gdelta);\n\t\t$b = floor($from_color[2] + $colnum*$bdelta);\n\t\t$alpha = $from_alpha + $colnum*$adelta;\n\t\t$colidx = $this->img->rgb->Allocate(sprintf(\"#%02x%02x%02x\",$r,$g,$b),$alpha);\n\t\t$colors[$i] = $colidx;\n\t    }\n\t    $prevcolnum = $colnum;\n\t}\n    }\t\n} // Class\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_iconplot.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_ICONPLOT.PHP\n// Description:\tPHP4 Graph Plotting library. Extension module.\n// Created: \t2004-02-18\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_iconplot.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n\n//===================================================\n// CLASS IconPlot\n// Description: Make it possible to add a (small) image\n// to the graph\n//===================================================\nclass IconPlot {\n    var $iHorAnchor='left',$iVertAnchor='top';\n    var $iX=0,$iY=0;\n    var $iFile='';\n    var $iScale=1.0,$iMix=100;\n    var $iAnchors = array('left','right','top','bottom','center');\n    var $iCountryFlag='',$iCountryStdSize=3;\n    var $iScalePosY=null,$iScalePosX=null;\n    var $iImgString='';\n\n    function IconPlot($aFile=\"\",$aX=0,$aY=0,$aScale=1.0,$aMix=100) {\n\t$this->iFile = $aFile;\n\t$this->iX=$aX;\n\t$this->iY=$aY;\n\t$this->iScale= $aScale;\n\tif( $aMix < 0 || $aMix > 100 ) {\n\t    JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.');\n\t}\n\t$this->iMix = $aMix ;\n    }\n\n    function CreateFromString($aStr) {\n\t$this->iImgString = $aStr;\n    }\n\n    function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) {\n\t$this->iCountryFlag = $aFlag;\n\t$this->iX=$aX;\n\t$this->iY=$aY;\n\t$this->iScale= $aScale;\n\tif( $aMix < 0 || $aMix > 100 ) {\n\t    JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.');\n\t}\n\t$this->iMix = $aMix;\n\t$this->iCountryStdSize = $aStdSize;\n    }\n\n    function SetPos($aX,$aY) {\n\t$this->iX=$aX;\n\t$this->iY=$aY;\n    }\n\n    function SetScalePos($aX,$aY) {\n\t$this->iScalePosX = $aX;\n\t$this->iScalePosY = $aY;\n    }\n\n    function SetScale($aScale) {\n\t$this->iScale = $aScale;\n    }\n\n    function SetMix($aMix) {\n\tif( $aMix < 0 || $aMix > 100 ) {\n\t    JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.');\n\t}\n\t$this->iMix = $aMix ;\n    }\n\n    function SetAnchor($aXAnchor='left',$aYAnchor='center') {\n\tif( !in_array($aXAnchor,$this->iAnchors) ||\n\t    !in_array($aYAnchor,$this->iAnchors) ) {\n\t    JpGraphError::RaiseL(8002);//(\"Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'\");\n\t}\n\t$this->iHorAnchor=$aXAnchor;\n\t$this->iVertAnchor=$aYAnchor;\n    }\n    \n    function PreStrokeAdjust($aGraph) {\n\t// Nothing to do ...\n    }\n\n    function DoLegend($aGraph) {\n\t// Nothing to do ...\n    }\n\n    function Max() {\n\treturn array(false,false);\n    }\n\n\n    // The next four function are framework function tht gets called\n    // from Gantt and is not menaiungfull in the context of Icons but\n    // they must be implemented to avoid errors.\n    function GetMaxDate() { return false;   }\n    function GetMinDate() { return false;   }\n    function GetLineNbr() { return 0;   }\n    function GetAbsHeight() {return 0;  }\n\n\n    function Min() {\n\treturn array(false,false);\n    }\n\n    function StrokeMargin(&$aImg) {\n\treturn true;\n    }\n\n    function Stroke(&$aImg,$axscale,$ayscale) {\n\t$this->StrokeWithScale($aImg,$axscale,$ayscale);\n    }\n\n    function StrokeWithScale(&$aImg,$axscale,$ayscale) {\n\tif( $this->iScalePosX === null ||\n\t    $this->iScalePosY === null ) {\n\t    $this->_Stroke($aImg);\n\t}\n\telse {\n\t    $this->_Stroke($aImg,\n\t\t\t  round($axscale->Translate($this->iScalePosX)),\n\t\t\t  round($ayscale->Translate($this->iScalePosY)));\n\t}\n    }\n\n    function GetWidthHeight() {\n\t$dummy=0;\n\treturn $this->_Stroke($dummy,null,null,true);\n    }\n\n    function _Stroke(&$aImg,$x=null,$y=null,$aReturnWidthHeight=false) {\n\tif( $this->iFile != '' && $this->iCountryFlag != '' ) {\n\t    JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.');\t\n\t}\n\tif( $this->iFile != '' ) {\n\t    $gdimg = Graph::LoadBkgImage('',$this->iFile);\n\t}\n\telseif( $this->iImgString != '') {\n\t    $gdimg = Image::CreateFromString($this->iImgString);\n\t}\n\telse {\n\t    if( ! class_exists('FlagImages') ) {\n\t\tJpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the \"jpgraph_flags.php\" file.');\n\t    }\n\t    $fobj = new FlagImages($this->iCountryStdSize);\n\t    $dummy='';\n\t    $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy);\n\t}\n\n\t$iconw = imagesx($gdimg);\n\t$iconh = imagesy($gdimg);\n\t\n\tif( $aReturnWidthHeight ) {\n\t    return array(round($iconw*$this->iScale),round($iconh*$this->iScale));\n\t}\n\n\tif( $x !== null && $y !== null ) {\n\t    $this->iX = $x; $this->iY = $y;\n\t}\n\tif( $this->iX >= 0  && $this->iX <= 1.0 ) {\n\t    $w = imagesx($aImg->img);\n\t    $this->iX = round($w*$this->iX);\n\t}\n\tif( $this->iY >= 0  && $this->iY <= 1.0 ) {\n\t    $h = imagesy($aImg->img);\n\t    $this->iY = round($h*$this->iY);\n\t}\n\n\tif( $this->iHorAnchor == 'center' ) \n\t    $this->iX -= round($iconw*$this->iScale/2);\n\tif( $this->iHorAnchor == 'right' ) \n\t    $this->iX -= round($iconw*$this->iScale);\n\tif( $this->iVertAnchor == 'center' ) \n\t    $this->iY -= round($iconh*$this->iScale/2);\n\tif( $this->iVertAnchor == 'bottom' ) \n\t    $this->iY -= round($iconh*$this->iScale);\n\n\t$aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0,\n\t\t\t round($iconw*$this->iScale),round($iconh*$this->iScale),\n\t\t\t $iconw,$iconh,\n\t\t\t $this->iMix);\n    }\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_imgtrans.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_IMGTRANS.PHP\n// Description:\tExtension for JpGraph to do some simple img transformations\n// Created: \t2003-09-06\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_imgtrans.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n//------------------------------------------------------------------------\n// Class ImgTrans\n// Perform some simple image transformations. \n//------------------------------------------------------------------------\nclass ImgTrans {\n    var $gdImg=null;\n\n    function ImgTrans($aGdImg) {\n\t// Constructor\n\t$this->gdImg = $aGdImg;\n    }\n\n    // --------------------------------------------------------------------\n    // _TransVert3D() and _TransHor3D() are helper methods to \n    // Skew3D(). \n    // --------------------------------------------------------------------\n    function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) {\n\n\n\t// Parameter check\n\tif( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) {\n\t    JpGraphError::RaiseL(9001);\n//(\"Value for image transformation out of bounds.\\nVanishing point on horizon must be specified as a value between 0 and 1.\");\n\t}\n\n\t$w = imagesx($aGdImg);\n\t$h = imagesy($aGdImg);\n\n\t// Create new image\n\t$ww = $w;\n\tif( $aMinSize ) \n\t    $hh = ceil($h * $aHorizon / ($aSkewDist+$h));\n\telse \n\t    $hh = $h;\n\t\n\t$newgdh = imagecreatetruecolor($ww,$hh);\n\t$crgb = new RGB( $newgdh );\n\t$fillColor = $crgb->Allocate($aFillColor);\n\timagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor);\n\n\tif( $aBorder ) {\n\t    $colidx = $crgb->Allocate($aBorder);\n\t    imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx);\n\t}\n\n\t$mid = round($w * $aHorizonPos);\n    \n\t$last=$h;\n\tfor($y=0; $y < $h; ++$y) {\t\n\n\t    $yp = $h-$y-1;\n\t    $yt = floor($yp * $aHorizon / ($aSkewDist + $yp));\t    \n\n\t    if( !$aQuality ) {\n\t\tif( $last <= $yt ) continue ;\n\t\t$last = $yt;\n\t    }\n\n\t    for($x=0; $x < $w; ++$x) {\t    \n\t\t$xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp);\n\t\tif( $aDir == SKEW3D_UP ) \n\t\t    $rgb = imagecolorat($aGdImg,$x,$h-$y-1);\n\t\telse\n\t\t    $rgb = imagecolorat($aGdImg,$x,$y);\n\t\t$r = ($rgb >> 16) & 0xFF;\n\t\t$g = ($rgb >> 8) & 0xFF;\n\t\t$b = $rgb & 0xFF;    \n\t\t$colidx = imagecolorallocate($newgdh,$r,$g,$b);\t\n\t\t$xt = round($xt+$mid);\n\t\tif( $aDir == SKEW3D_UP ) {\n\t\t    $syt = $yt;\n\t\t}\n\t\telse {\n\t\t    $syt = $hh-$yt-1;\n\t\t}\n\n\t\tif( !empty($set[$yt]) ) {\n\t\t    $nrgb = imagecolorat($newgdh,$xt,$syt);\n\t\t    $nr = ($nrgb >> 16) & 0xFF;\n\t\t    $ng = ($nrgb >> 8) & 0xFF;\n\t\t    $nb = $nrgb & 0xFF;    \n\t\t    $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2),\n\t\t\t\t\t\t floor(($g+$ng)/2),floor(($b+$nb)/2));\t\n\t\t}\t\n\n\t\timagesetpixel($newgdh,$xt,$syt,$colidx);\t\n\t    }\n\n\t    $set[$yt] = true;\t\n\t}\n\n\treturn $newgdh;\n    }\n\n    // --------------------------------------------------------------------\n    // _TransVert3D() and _TransHor3D() are helper methods to \n    // Skew3D(). \n    // --------------------------------------------------------------------\n    function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) {\n\n\t$w = imagesx($aGdImg);\n\t$h = imagesy($aGdImg);\n\n\t// Create new image\n\t$hh = $h;\n\tif( $aMinSize ) \n\t    $ww = ceil($w * $aHorizon / ($aSkewDist+$w));\n\telse \n\t    $ww = $w;\n\t\n\t$newgdh = imagecreatetruecolor($ww,$hh);\n\t$crgb = new RGB( $newgdh );\n\t$fillColor = $crgb->Allocate($aFillColor);\n\timagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor);\n\n\tif( $aBorder ) {\n\t    $colidx = $crgb->Allocate($aBorder);\n\t    imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx);\n\t}\n\n\t$mid = round($h * $aHorizonPos);\n\n\t$last = -1; \n\tfor($x=0; $x < $w-1; ++$x) {\t    \n\t    $xt = floor($x * $aHorizon / ($aSkewDist + $x));\n\t    if( !$aQuality ) {\n\t\tif( $last >= $xt ) continue ;\n\t\t$last = $xt;\n\t    }\n\n\t    for($y=0; $y < $h; ++$y) {\t\n\t\t$yp = $h-$y-1;\n\t\t$yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x);\n\n\t\tif( $aDir == SKEW3D_RIGHT ) \n\t\t    $rgb = imagecolorat($aGdImg,$w-$x-1,$y);\n\t\telse\n\t\t    $rgb = imagecolorat($aGdImg,$x,$y);\n\t\t$r = ($rgb >> 16) & 0xFF;\n\t\t$g = ($rgb >> 8) & 0xFF;\n\t\t$b = $rgb & 0xFF;    \n\t\t$colidx = imagecolorallocate($newgdh,$r,$g,$b);\t\n\t\t$yt = floor($hh-$yt-$mid-1);\n\t\tif( $aDir == SKEW3D_RIGHT ) {\n\t\t    $sxt = $ww-$xt-1;\n\t\t}\n\t\telse\n\t\t    $sxt = $xt ;\n\n\t\tif( !empty($set[$xt]) ) {\n\t\t    $nrgb = imagecolorat($newgdh,$sxt,$yt);\n\t\t    $nr = ($nrgb >> 16) & 0xFF;\n\t\t    $ng = ($nrgb >> 8) & 0xFF;\n\t\t    $nb = $nrgb & 0xFF;    \n\t\t    $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2),\n\t\t\t\t\t\t floor(($g+$ng)/2),floor(($b+$nb)/2));\t\n\t\t}\n\t\timagesetpixel($newgdh,$sxt,$yt,$colidx);\t\n\t    }\n\n\t    $set[$xt] = true;\n\t}\n\n\treturn $newgdh;\n    }\n\n    // --------------------------------------------------------------------\n    // Skew image for the apperance of a 3D effect\n    // This transforms an image into a 3D-skewed version\n    // of the image. The transformation is specified by giving the height\n    // of the artificial horizon and specifying a \"skew\" factor which\n    // is the distance on the horizon line between the point of \n    // convergence and perspective line.\n    //\n    // The function returns the GD handle of the transformed image\n    // leaving the original image untouched.\n    //\n    // Parameters:\n    // * $aGdImg, GD handle to the image to be transformed\n    // * $aHorizon, Distance to the horizon \n    // * $aSkewDist, Distance from the horizon point of convergence\n    //   on the horizon line to the perspective points. A larger \n    //   value will fore-shorten the image more\n    // * $aDir, parameter specifies type of convergence. This of this \n    //   as the walls in a room you are looking at. This specifies if the\n    //   image should be applied on the left,right,top or bottom walls.\n    // * $aMinSize, true=make the new image just as big as needed,\n    //   false = keep the image the same size as the original image\n    // * $aFillColor, Background fill color in the image\n    // * $aHiQuality, true=performa some interpolation that improves\n    //   the image quality but at the expense of performace. Enabling\n    //   high quality will have a dramatic effect on the time it takes\n    //   to transform an image.\n    // * $aBorder, if set to anything besides false this will draw a \n    //   a border of the speciied color around the image\n    // --------------------------------------------------------------------\n    function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) {\n\treturn $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality,\n\t\t\t      $aMinSize,$aFillColor,$aBorder);\n    }\n\n    function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) {\n\tif( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP )\n\t    return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder);\n\telse\n\t    return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder);\n\n    }\n    \n}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_line.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_LINE.PHP\n// Description:\tLine plot extension for JpGraph\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_line.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nrequire_once ('jpgraph_plotmark.inc');\n\n// constants for the (filled) area\nDEFINE(\"LP_AREA_FILLED\", true);\nDEFINE(\"LP_AREA_NOT_FILLED\", false);\nDEFINE(\"LP_AREA_BORDER\",false);\nDEFINE(\"LP_AREA_NO_BORDER\",true);\n\n//===================================================\n// CLASS LinePlot\n// Description: \n//===================================================\nclass LinePlot extends Plot{\n    var $filled=false;\n    var $fill_color='blue';\n    var $mark=null;\n    var $step_style=false, $center=false;\n    var $line_style=1;\t// Default to solid\n    var $filledAreas = array(); // array of arrays(with min,max,col,filled in them)\n    var $barcenter=false;  // When we mix line and bar. Should we center the line in the bar.\n    var $fillFromMin = false ;\n    var $fillgrad=false,$fillgrad_fromcolor='navy',$fillgrad_tocolor='silver',$fillgrad_numcolors=100;\n    var $iFastStroke=false;\n\n//---------------\n// CONSTRUCTOR\n    function LinePlot(&$datay,$datax=false) {\n\t$this->Plot($datay,$datax);\n\t$this->mark = new PlotMark();\n    }\n//---------------\n// PUBLIC METHODS\t\n\n    // Set style, filled or open\n    function SetFilled($aFlag=true) {\n    \tJpGraphError::RaiseL(10001);//('LinePlot::SetFilled() is deprecated. Use SetFillColor()');\n    }\n\t\n    function SetBarCenter($aFlag=true) {\n\t$this->barcenter=$aFlag;\n    }\n\n    function SetStyle($aStyle) {\n\t$this->line_style=$aStyle;\n    }\n\t\n    function SetStepStyle($aFlag=true) {\n\t$this->step_style = $aFlag;\n    }\n\t\n    function SetColor($aColor) {\n\tparent::SetColor($aColor);\n    }\n\t\n    function SetFillFromYMin($f=true) {\n\t$this->fillFromMin = $f ;\n    }\n    \n    function SetFillColor($aColor,$aFilled=true) {\n\t$this->fill_color=$aColor;\n\t$this->filled=$aFilled;\n    }\n\n    function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) {\n\t$this->fillgrad_fromcolor = $aFromColor;\n\t$this->fillgrad_tocolor   = $aToColor;\n\t$this->fillgrad_numcolors = $aNumColors;\n\t$this->filled = $aFilled;\n\t$this->fillgrad = true;\n    }\n\t\n    function Legend(&$graph) {\n\tif( $this->legend!=\"\" ) {\n\t    if( $this->filled && !$this->fillgrad ) {\n\t\t$graph->legend->Add($this->legend,\n\t\t\t\t    $this->fill_color,$this->mark,0,\n\t\t\t\t    $this->legendcsimtarget,$this->legendcsimalt);\n\t    } \n\t    elseif( $this->fillgrad ) {\n\t\t$color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor);\n\t\t// In order to differentiate between gradients and cooors specified as an RGB triple\n\t\t$graph->legend->Add($this->legend,$color,\"\",-2 /* -GRAD_HOR */,\n\t\t\t\t    $this->legendcsimtarget,$this->legendcsimalt);\n\t    }\t\n\t    else {\n\t\t$graph->legend->Add($this->legend,\n\t\t\t\t    $this->color,$this->mark,$this->line_style,\n\t\t\t\t    $this->legendcsimtarget,$this->legendcsimalt);\n\t    }\n\t}\t\n    }\n\n    function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor=\"gray9\",$aBorder=LP_AREA_BORDER) {\n\tif($aMin > $aMax) {\n\t    // swap\n\t    $tmp = $aMin;\n\t    $aMin = $aMax;\n\t    $aMax = $tmp;\n\t} \n\t$this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder);\n    }\n\t\n    // Gets called before any axis are stroked\n    function PreStrokeAdjust(&$graph) {\n\n\t// If another plot type have already adjusted the\n\t// offset we don't touch it.\n\t// (We check for empty in case the scale is  a log scale \n\t// and hence doesn't contain any xlabel_offset)\n\tif( empty($graph->xaxis->scale->ticks->xlabel_offset) ||\n\t    $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {\n\t    if( $this->center ) {\n\t\t++$this->numpoints;\n\t\t$a=0.5; $b=0.5;\n\t    } else {\n\t\t$a=0; $b=0;\n\t    }\n\t    $graph->xaxis->scale->ticks->SetXLabelOffset($a);\n\t    $graph->SetTextScaleOff($b);\t\t\t\t\t\t\n\t    //$graph->xaxis->scale->ticks->SupressMinorTickMarks();\n\t}\n    }\n\n    function SetFastStroke($aFlg=true) {\n\t$this->iFastStroke = $aFlg;\n    }\n\n    function FastStroke(&$img,&$xscale,&$yscale,$aStartPoint=0,$exist_x=true) {\n\t// An optimized stroke for many data points with no extra \n\t// features but 60% faster. You can't have values or line styles, or null\n\t// values in plots.\n\t$numpoints=count($this->coords[0]);\n\tif( $this->barcenter ) \n\t    $textadj = 0.5-$xscale->text_scale_off;\n\telse\n\t    $textadj = 0;\n\n\t$img->SetColor($this->color);\n\t$img->SetLineWeight($this->weight);\n\t$pnts=$aStartPoint;\n\twhile( $pnts < $numpoints ) {\t    \n\t    if( $exist_x ) $x=$this->coords[1][$pnts];\n\t    else $x=$pnts+$textadj;\n\t    $xt = $xscale->Translate($x);\n\t    $y=$this->coords[0][$pnts];\n\t    $yt = $yscale->Translate($y);    \n\t    if( is_numeric($y) ) {\n\t\t$cord[] = $xt;\n\t\t$cord[] = $yt;\n\t    }\n\t    elseif( $y == '-' && $pnts > 0 ) {\n\t\t// Just ignore\n\t    }\n\t    else {\n\t\tJpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()');\n\t\treturn;\n\t    }\n\t    ++$pnts;\n\t} // WHILE\n\n\t$img->Polygon($cord,false,true);\n\n    }\n\t\n    function Stroke(&$img,&$xscale,&$yscale) {\n\t$idx=0;\n\t$numpoints=count($this->coords[0]);\n\tif( isset($this->coords[1]) ) {\n\t    if( count($this->coords[1])!=$numpoints )\n\t\tJpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);\n//(\"Number of X and Y points are not equal. Number of X-points:\".count($this->coords[1]).\" Number of Y-points:$numpoints\");\n\t    else\n\t\t$exist_x = true;\n\t}\n\telse \n\t    $exist_x = false;\n\n\tif( $this->barcenter ) \n\t    $textadj = 0.5-$xscale->text_scale_off;\n\telse\n\t    $textadj = 0;\n\n\t// Find the first numeric data point\n\t$startpoint=0;\n\twhile( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) )\n\t    ++$startpoint;\n\n\t// Bail out if no data points\n\tif( $startpoint == $numpoints ) \n\t    return;\n\n\tif( $this->iFastStroke ) {\n\t    $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x);\n\t    return;\n\t}\n\n\tif( $exist_x )\n\t    $xs=$this->coords[1][$startpoint];\n\telse\n\t    $xs= $textadj+$startpoint;\n\n\t$img->SetStartPoint($xscale->Translate($xs),\n\t\t\t    $yscale->Translate($this->coords[0][$startpoint]));\n\n\tif( $this->filled ) {\n\t    $min = $yscale->GetMinVal();\n\t    if( $min > 0 || $this->fillFromMin )\n\t\t$fillmin = $yscale->scale_abs[0];//Translate($min);\n\t    else\n\t\t$fillmin = $yscale->Translate(0);\n\n\t    $cord[$idx++] = $xscale->Translate($xs);\n\t    $cord[$idx++] = $fillmin;\n\t}\n\t$xt = $xscale->Translate($xs);\n\t$yt = $yscale->Translate($this->coords[0][$startpoint]);\n\t$cord[$idx++] = $xt;\n\t$cord[$idx++] = $yt;\n\t$yt_old = $yt;\n\t$xt_old = $xt;\n\t$y_old = $this->coords[0][$startpoint];\n\n\t$this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt);\n\n\t$img->SetColor($this->color);\n\t$img->SetLineWeight($this->weight);\n\t$img->SetLineStyle($this->line_style);\n\t$pnts=$startpoint+1;\n\t$firstnonumeric = false;\n\twhile( $pnts < $numpoints ) {\n\t    \n\t    if( $exist_x ) $x=$this->coords[1][$pnts];\n\t    else $x=$pnts+$textadj;\n\t    $xt = $xscale->Translate($x);\n\t    $yt = $yscale->Translate($this->coords[0][$pnts]);\n\t    \n\t    $y=$this->coords[0][$pnts];\n\t    if( $this->step_style ) {\n\t\t// To handle null values within step style we need to record the\n\t\t// first non numeric value so we know from where to start if the\n\t\t// non value is '-'. \n\t\tif( is_numeric($y) ) {\n\t\t    $firstnonumeric = false;\n\t\t    if( is_numeric($y_old) ) {\n\t\t\t$img->StyleLine($xt_old,$yt_old,$xt,$yt_old);\n\t\t\t$img->StyleLine($xt,$yt_old,$xt,$yt);\n\t\t    }\n\t\t    elseif( $y_old == '-' ) {\n\t\t\t$img->StyleLine($xt_first,$yt_first,$xt,$yt_first);\n\t\t\t$img->StyleLine($xt,$yt_first,$xt,$yt);\t\t\t\n\t\t    }\n\t\t    else {\n\t\t\t$yt_old = $yt;\n\t\t\t$xt_old = $xt;\n\t\t    }\n\t\t    $cord[$idx++] = $xt;\n\t\t    $cord[$idx++] = $yt_old;\n\t\t    $cord[$idx++] = $xt;\n\t\t    $cord[$idx++] = $yt;\n\t\t}\n\t\telseif( $firstnonumeric==false ) {\n\t\t    $firstnonumeric = true;\n\t\t    $yt_first = $yt_old;\n\t\t    $xt_first = $xt_old;\n\t\t}\n\t    }\n\t    else {\n\t\t$tmp1=$y;\n\t\t$prev=$this->coords[0][$pnts-1]; \t\t \t\t\t\n\t\tif( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x';\n\t\tif( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x';\n\n\t\tif( is_numeric($y) || (is_string($y) && $y != '-') ) {\n\t\t    if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { \n\t\t\t$img->StyleLineTo($xt,$yt);\n\t\t    } \n\t\t    else {\n\t\t\t$img->SetStartPoint($xt,$yt);\n\t\t    }\n\t\t}\n\t\tif( $this->filled && $tmp1 !== '-' ) {\n\t\t    if( $tmp1 === 'x' ) { \n\t\t\t$cord[$idx++] = $cord[$idx-3];\n\t\t\t$cord[$idx++] = $fillmin;\n\t\t    }\n\t\t    elseif( $prev === 'x' ) {\n\t\t\t$cord[$idx++] = $xt;\n\t\t\t$cord[$idx++] = $fillmin;\n\t\t\t$cord[$idx++] = $xt;\n\t\t\t$cord[$idx++] = $yt; \t\t\t    \n\t\t    }\n\t\t    else {\n\t\t\t$cord[$idx++] = $xt;\n\t\t\t$cord[$idx++] = $yt;\n\t\t    }\n\t\t}\n\t\telse {\n\t\t    if( is_numeric($tmp1)  && (is_numeric($prev) || $prev === '-' ) ) {\n\t\t\t$cord[$idx++] = $xt;\n\t\t\t$cord[$idx++] = $yt;\n\t\t    } \n\t\t}\n\t    }\n\t    $yt_old = $yt;\n\t    $xt_old = $xt;\n\t    $y_old = $y;\n\n\t    $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);\n\n\t    ++$pnts;\n\t}\t\n\n\tif( $this->filled  ) {\n\t    $cord[$idx++] = $xt;\n\t    if( $min > 0 || $this->fillFromMin )\n\t\t$cord[$idx++] = $yscale->Translate($min);\n\t    else\n\t\t$cord[$idx++] = $yscale->Translate(0);\n\t    if( $this->fillgrad ) {\n\t\t$img->SetLineWeight(1);\n\t\t$grad = new Gradient($img);\n\t\t$grad->SetNumColors($this->fillgrad_numcolors);\n\t\t$grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor);\n\t\t$img->SetLineWeight($this->weight);\n\t    }\n\t    else {\n\t\t$img->SetColor($this->fill_color);\t\n\t\t$img->FilledPolygon($cord);\n\t    }\n\t    if( $this->line_weight > 0 ) {\n\t\t$img->SetColor($this->color);\n\t\t$img->Polygon($cord);\n\t    }\n\t}\n\n\tif(!empty($this->filledAreas)) {\n\n\t    $minY = $yscale->Translate($yscale->GetMinVal());\n\t    $factor = ($this->step_style ? 4 : 2);\n\n\t    for($i = 0; $i < sizeof($this->filledAreas); ++$i) {\n\t\t// go through all filled area elements ordered by insertion\n\t\t// fill polygon array\n\t\t$areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];\n\t\t$areaCoords[] = $minY;\n\n\t\t$areaCoords =\n\t\t    array_merge($areaCoords,\n\t\t\t\tarray_slice($cord,\n\t\t\t\t\t    $this->filledAreas[$i][0] * $factor,\n\t\t\t\t\t    ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1))  * $factor));\n\t\t$areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x\n\t\t$areaCoords[] = $minY; // last y\n\t    \n\t\tif($this->filledAreas[$i][3]) {\n\t\t    $img->SetColor($this->filledAreas[$i][2]);\n\t\t    $img->FilledPolygon($areaCoords);\n\t\t    $img->SetColor($this->color);\n\t\t}\n\t\t// Check if we should draw the frame.\n\t\t// If not we still re-draw the line since it might have been\n\t\t// partially overwritten by the filled area and it doesn't look\n\t\t// very good.\n\t\t// TODO: The behaviour is undefined if the line does not have\n\t\t// any line at the position of the area.\n\t\tif( $this->filledAreas[$i][4] )\n\t\t    $img->Polygon($areaCoords);\n\t\telse\n\t    \t    $img->Polygon($cord);\n\n\t\t$areaCoords = array();\n\t    }\n\t}\t\n\n\tif( $this->mark->type == -1 || $this->mark->show == false )\n\t    return;\n\n\tfor( $pnts=0; $pnts<$numpoints; ++$pnts) {\n\n\t    if( $exist_x ) $x=$this->coords[1][$pnts];\n\t    else $x=$pnts+$textadj;\n\t    $xt = $xscale->Translate($x);\n\t    $yt = $yscale->Translate($this->coords[0][$pnts]);\n\n\t    if( is_numeric($this->coords[0][$pnts]) ) {\n\t\tif( !empty($this->csimtargets[$pnts]) ) {\n\t\t    $this->mark->SetCSIMTarget($this->csimtargets[$pnts]);\n\t\t    $this->mark->SetCSIMAlt($this->csimalts[$pnts]);\n\t\t}\n\t\tif( $exist_x )\n\t\t    $x=$this->coords[1][$pnts];\n\t\telse\n\t\t    $x=$pnts;\n\t\t$this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x);\n\t\t$this->mark->Stroke($img,$xt,$yt);\t\n\t\t$this->csimareas .= $this->mark->GetCSIMAreas();\n\t\t$this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);\n\t    }\n\t}\n\n\n    }\n} // Class\n\n\n//===================================================\n// CLASS AccLinePlot\n// Description: \n//===================================================\nclass AccLinePlot extends Plot {\n    var $plots=null,$nbrplots=0,$numpoints=0;\n    var $iStartEndZero=true;\n//---------------\n// CONSTRUCTOR\n    function AccLinePlot($plots) {\n        $this->plots = $plots;\n\t$this->nbrplots = count($plots);\n\t$this->numpoints = $plots[0]->numpoints;\n\n\tfor($i=0; $i < $this->nbrplots; ++$i ) {\n\t    $this->LineInterpolate($this->plots[$i]->coords[0]);\n\t}\t\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Legend(&$graph) {\n\t$n=count($this->plots);\n\tfor($i=0; $i < $n; ++$i )\n\t    $this->plots[$i]->DoLegend($graph);\n    }\n\t\n    function Max() {\n\tlist($xmax) = $this->plots[0]->Max();\n\t$nmax=0;\n\t$n = count($this->plots);\n\tfor($i=0; $i < $n; ++$i) {\n\t    $nc = count($this->plots[$i]->coords[0]);\n\t    $nmax = max($nmax,$nc);\n\t    list($x) = $this->plots[$i]->Max();\n\t    $xmax = Max($xmax,$x);\n\t}\n\tfor( $i = 0; $i < $nmax; $i++ ) {\n\t    // Get y-value for line $i by adding the\n\t    // individual bars from all the plots added.\n\t    // It would be wrong to just add the\n\t    // individual plots max y-value since that\n\t    // would in most cases give to large y-value.\n\t    $y=$this->plots[0]->coords[0][$i];\n\t    for( $j = 1; $j < $this->nbrplots; $j++ ) {\n\t\t$y += $this->plots[ $j ]->coords[0][$i];\n\t    }\n\t    $ymax[$i] = $y;\n\t}\n\t$ymax = max($ymax);\n\treturn array($xmax,$ymax);\n    }\t\n\n    function Min() {\n\t$nmax=0;\n\tlist($xmin,$ysetmin) = $this->plots[0]->Min();\n\t$n = count($this->plots);\n\tfor($i=0; $i < $n; ++$i) {\n\t    $nc = count($this->plots[$i]->coords[0]);\n\t    $nmax = max($nmax,$nc);\n\t    list($x,$y) = $this->plots[$i]->Min();\n\t    $xmin = Min($xmin,$x);\n\t    $ysetmin = Min($y,$ysetmin);\n\t}\n\tfor( $i = 0; $i < $nmax; $i++ ) {\n\t    // Get y-value for line $i by adding the\n\t    // individual bars from all the plots added.\n\t    // It would be wrong to just add the\n\t    // individual plots min y-value since that\n\t    // would in most cases give to small y-value.\n\t    $y=$this->plots[0]->coords[0][$i];\n\t    for( $j = 1; $j < $this->nbrplots; $j++ ) {\n\t\t$y += $this->plots[ $j ]->coords[0][$i];\n\t    }\n\t    $ymin[$i] = $y;\n\t}\n\t$ymin = Min($ysetmin,Min($ymin));\n\treturn array($xmin,$ymin);\n    }\n\n    // Gets called before any axis are stroked\n    function PreStrokeAdjust(&$graph) {\n\n\t// If another plot type have already adjusted the\n\t// offset we don't touch it.\n\t// (We check for empty in case the scale is  a log scale \n\t// and hence doesn't contain any xlabel_offset)\n\t\n\tif( empty($graph->xaxis->scale->ticks->xlabel_offset) ||\n\t    $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {\n\t    if( $this->center ) {\n\t\t++$this->numpoints;\n\t\t$a=0.5; $b=0.5;\n\t    } else {\n\t\t$a=0; $b=0;\n\t    }\n\t    $graph->xaxis->scale->ticks->SetXLabelOffset($a);\n\t    $graph->SetTextScaleOff($b);\t\t\t\t\t\t\n\t    $graph->xaxis->scale->ticks->SupressMinorTickMarks();\n\t}\n\t\n    }\n\n    function SetInterpolateMode($aIntMode) {\n\t$this->iStartEndZero=$aIntMode;\n    }\n\n    // Replace all '-' with an interpolated value. We use straightforward\n    // linear interpolation. If the data starts with one or several '-' they\n    // will be replaced by the the first valid data point\n    function LineInterpolate(&$aData) {\n\n\t$n=count($aData);\n\t$i=0;\n    \n\t// If first point is undefined we will set it to the same as the first \n\t// valid data\n\tif( $aData[$i]==='-' ) {\n\t    // Find the first valid data\n\t    while( $i < $n && $aData[$i]==='-' ) {\n\t\t++$i;\n\t    }\n\t    if( $i < $n ) {\n\t\tfor($j=0; $j < $i; ++$j ) {\n\t\t    if( $this->iStartEndZero )\n\t\t\t$aData[$i] = 0;\n\t\t    else\n\t\t\t$aData[$j] = $aData[$i];\n\t\t}\n\t    }\n\t    else {\n\t\t// All '-' => Error\n\t\treturn false;\n\t    }\n\t}\n\n\twhile($i < $n) {\n\t    while( $i < $n && $aData[$i] !== '-' ) {\n\t\t++$i;\n\t    }\n\t    if( $i < $n ) {\n\t\t$pstart=$i-1;\n\n\t\t// Now see how long this segment of '-' are\n\t\twhile( $i < $n && $aData[$i] === '-' )\n\t\t    ++$i;\n\t\tif( $i < $n ) {\n\t\t    $pend=$i;\n\t\t    $size=$pend-$pstart;\n\t\t    $k=($aData[$pend]-$aData[$pstart])/$size;\n\t\t    // Replace the segment of '-' with a linear interpolated value.\n\t\t    for($j=1; $j < $size; ++$j ) {\n\t\t\t$aData[$pstart+$j] = $aData[$pstart] + $j*$k ;\n\t\t    }\n\t\t}\n\t\telse {\n\t\t    // There are no valid end point. The '-' goes all the way to the end\n\t\t    // In that case we just set all the remaining values the the same as the\n\t\t    // last valid data point.\n\t\t    for( $j=$pstart+1; $j < $n; ++$j ) \n\t\t\tif( $this->iStartEndZero )\n\t\t\t    $aData[$j] = 0;\n\t\t\telse\n\t\t\t    $aData[$j] = $aData[$pstart] ;\t\t\n\t\t}\n\t    }\n\t}\n\treturn true;\n    }\n\n\n\n    // To avoid duplicate of line drawing code here we just\n    // change the y-values for each plot and then restore it\n    // after we have made the stroke. We must do this copy since\n    // it wouldn't be possible to create an acc line plot\n    // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));\n    // since this method would have a side effect.\n    function Stroke(&$img,&$xscale,&$yscale) {\n\t$img->SetLineWeight($this->weight);\n\t$this->numpoints = count($this->plots[0]->coords[0]);\n\t// Allocate array\n\t$coords[$this->nbrplots][$this->numpoints]=0;\n\tfor($i=0; $i<$this->numpoints; $i++) {\n\t    $coords[0][$i]=$this->plots[0]->coords[0][$i]; \n\t    $accy=$coords[0][$i];\n\t    for($j=1; $j<$this->nbrplots; ++$j ) {\n\t\t$coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; \n\t\t$accy = $coords[$j][$i];\n\t    }\n\t}\n\tfor($j=$this->nbrplots-1; $j>=0; --$j) {\n\t    $p=$this->plots[$j];\n\t    for( $i=0; $i<$this->numpoints; ++$i) {\n\t\t$tmp[$i]=$p->coords[0][$i];\n\t\t$p->coords[0][$i]=$coords[$j][$i];\n\t    }\n\t    $p->Stroke($img,$xscale,$yscale);\n\t    for( $i=0; $i<$this->numpoints; ++$i) \n\t\t$p->coords[0][$i]=$tmp[$i];\n\t    $p->coords[0][]=$tmp;\n\t}\n    }\n} // Class\n\n\n/* EOF */\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_log.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_LOG.PHP\n// Description:\tLog scale plot extension for JpGraph\n// Created: \t2001-01-08\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_log.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n\nDEFINE('LOGLABELS_PLAIN',0);\nDEFINE('LOGLABELS_MAGNITUDE',1);\n\n//===================================================\n// CLASS LogScale\n// Description: Logarithmic scale between world and screen\n//===================================================\nclass LogScale extends LinearScale {\n//---------------\n// CONSTRUCTOR\n\n    // Log scale is specified using the log of min and max\n    function LogScale($min,$max,$type=\"y\") {\n\t$this->LinearScale($min,$max,$type);\n\t$this->ticks = new LogTicks();\n\t$this->name = 'log';\n    }\n\n//----------------\n// PUBLIC METHODS\t\n\n    // Translate between world and screen\n    function Translate($a) {\n\tif( !is_numeric($a) ) {\n\t    if( $a != '' && $a != '-' && $a != 'x' ) \n\t\tJpGraphError::RaiseL(11001);\n//('Your data contains non-numeric values.');\n\t    return 1;\n\t}\n\tif( $a < 0 ) {\n\t    JpGraphError::RaiseL(11002);\n//(\"Negative data values can not be used in a log scale.\");\n\t    exit(1);\n\t}\n\tif( $a==0 ) $a=1;\n\t$a=log10($a);\n\treturn ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); \n    }\n\n    // Relative translate (don't include offset) usefull when we just want\n    // to know the relative position (in pixels) on the axis\t\n    function RelTranslate($a) {\n\tif( !is_numeric($a) ) {\n\t    if( $a != '' && $a != '-' && $a != 'x' ) \n\t\tJpGraphError::RaiseL(11001);\n//('Your data contains non-numeric values.');\n\t    return 1;\n\t}\n\tif( $a==0 ) $a=1;\n\t$a=log10($a);\n\treturn round(($a*1.0 - $this->scale[0]) * $this->scale_factor); \n    }\n\t\t\n    // Use bcpow() for increased precision\n    function GetMinVal() {\n\tif( function_exists(\"bcpow\") )\n\t    return round(bcpow(10,$this->scale[0],15),14);\n\telse\n\t    return round(pow(10,$this->scale[0]),14);\n    }\n\t\n    function GetMaxVal() {\n\tif( function_exists(\"bcpow\") )\n\t    return round(bcpow(10,$this->scale[1],15),14);\n\telse\n\t    return round(pow(10,$this->scale[1]),14);\n    }\n\t\n    // Logarithmic autoscaling is much simplier since we just\n    // set the min and max to logs of the min and max values.\n    // Note that for log autoscale the \"maxstep\" the fourth argument\n    // isn't used. This is just included to give the method the same\n    // signature as the linear counterpart.\n    function AutoScale(&$img,$min,$max,$dummy) {\n\tif( $min==0 ) $min=1;\n\t\n\tif( $max <= 0 ) {\n\t    JpGraphError::RaiseL(11004);\n//('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.');\n\t}\n\t$smin = floor(log10($min));\n\t$smax = ceil(log10($max));\n\t$this->Update($img,$smin,$smax);\t\t\t\t\t\n    }\n//---------------\n// PRIVATE METHODS\t\n} // Class\n\n//===================================================\n// CLASS LogTicks\n// Description: \n//===================================================\nclass LogTicks extends Ticks{\n    var $label_logtype=LOGLABELS_MAGNITUDE;\n//---------------\n// CONSTRUCTOR\n    function LogTicks() {\n    }\n//---------------\n// PUBLIC METHODS\t\n    function IsSpecified() {\n\treturn true;\n    }\n\n    function SetLabelLogType($aType) {\n\t$this->label_logtype = $aType;\n    }\n\t\n    // For log scale it's meaningless to speak about a major step\n    // We just return -1 to make the framework happy (specifically\n    // StrokeLabels() )\n    function GetMajor() {\n\treturn -1;\n    }\n\n    function SetTextLabelStart($aStart) {\n\tJpGraphError::RaiseL(11005);\n//('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.');\n    }\n\n    function SetXLabelOffset($dummy) {\n\t// For log scales we dont care about XLabel offset\n    }\n\n    // Draw ticks on image \"img\" using scale \"scale\". The axis absolute\n    // position in the image is specified in pos, i.e. for an x-axis\n    // it specifies the absolute y-coord and for Y-ticks it specified the\n    // absolute x-position.\n    function Stroke(&$img,&$scale,$pos) {\n\t$start = $scale->GetMinVal();\n\t$limit = $scale->GetMaxVal();\n\t$nextMajor = 10*$start;\n\t$step = $nextMajor / 10.0;\n\t\t\n\t\t\n\t$img->SetLineWeight($this->weight);\t\t\t\n\t\t\n\tif( $scale->type == \"y\" ) {\n\t    // member direction specified if the ticks should be on\n\t    // left or right side.\n\t    $a=$pos + $this->direction*$this->GetMinTickAbsSize();\n\t    $a2=$pos + $this->direction*$this->GetMajTickAbsSize();\t\n\t\t\t\n\t    $count=1; \n\t    $this->maj_ticks_pos[0]=$scale->Translate($start);\n\t    $this->maj_ticklabels_pos[0]=$scale->Translate($start);\n\t    if( $this->supress_first )\n\t\t$this->maj_ticks_label[0]=\"\";\n\t    else {\n\t\tif( $this->label_formfunc != '' ) {\n\t\t    $f = $this->label_formfunc;\n\t\t    $this->maj_ticks_label[0]=call_user_func($f,$start);\t\n\t\t}\n\t\telseif( $this->label_logtype == LOGLABELS_PLAIN )\n\t\t    $this->maj_ticks_label[0]=$start;\t\n\t\telse\n\t\t    $this->maj_ticks_label[0]='10^'.round(log10($start));\n\t    }\n\t    $i=1;\n\t    for($y=$start; $y<=$limit; $y+=$step,++$count  ) {\n\t\t$ys=$scale->Translate($y);\t\n\t\t$this->ticks_pos[]=$ys;\n\t\t$this->ticklabels_pos[]=$ys;\n\t\tif( $count % 10 == 0 ) {\n\t\t    if( !$this->supress_tickmarks ) {\n\t\t\tif( $this->majcolor!=\"\" ) {\n\t\t\t    $img->PushColor($this->majcolor);\n\t\t\t    $img->Line($pos,$ys,$a2,$ys);\n\t\t\t    $img->PopColor();\n\t\t\t}\n\t\t\telse\n\t\t\t    $img->Line($pos,$ys,$a2,$ys);\n\t\t    }\n\n\t\t    $this->maj_ticks_pos[$i]=$ys;\n\t\t    $this->maj_ticklabels_pos[$i]=$ys;\n\t\t    \n\t\t    if( $this->label_formfunc != '' ) {\n\t\t\t$f = $this->label_formfunc;\n\t\t\t$this->maj_ticks_label[$i]=call_user_func($f,$nextMajor);\t\n\t\t    }\n\t\t    elseif( $this->label_logtype == 0 )\n\t\t\t$this->maj_ticks_label[$i]=$nextMajor;\t\n\t\t    else\n\t\t\t$this->maj_ticks_label[$i]='10^'.round(log10($nextMajor));\n\t\t    ++$i;\t\t\t\t\t\t\n\t\t    $nextMajor *= 10;\n\t\t    $step *= 10;\t\n\t\t    $count=1; \t\t\t\t\n\t\t}\n\t\telse {\n\t\t    if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {\n\t\t\tif( $this->mincolor!=\"\" ) $img->PushColor($this->mincolor);\n\t\t\t$img->Line($pos,$ys,$a,$ys);\t\t\n\t\t\tif( $this->mincolor!=\"\" ) $img->PopColor();\n\t\t    }\n\t\t}\n\t    }\t\t\n\t}\n\telse {\n\t    $a=$pos - $this->direction*$this->GetMinTickAbsSize();\n\t    $a2=$pos - $this->direction*$this->GetMajTickAbsSize();\t\n\t    $count=1; \n\t    $this->maj_ticks_pos[0]=$scale->Translate($start);\n\t    $this->maj_ticklabels_pos[0]=$scale->Translate($start);\n\t    if( $this->supress_first )\n\t\t$this->maj_ticks_label[0]=\"\";\n\t    else {\n\t\tif( $this->label_formfunc != '' ) {\n\t\t    $f = $this->label_formfunc;\n\t\t    $this->maj_ticks_label[0]=call_user_func($f,$start);\t\n\t\t}\n\t\telseif( $this->label_logtype == 0 )\n\t\t    $this->maj_ticks_label[0]=$start;\t\n\t\telse\n\t\t    $this->maj_ticks_label[0]='10^'.round(log10($start));\n\t    }\n\t    $i=1;\t\t\t\n\t    for($x=$start; $x<=$limit; $x+=$step,++$count  ) {\n\t\t$xs=$scale->Translate($x);\t\n\t\t$this->ticks_pos[]=$xs;\n\t\t$this->ticklabels_pos[]=$xs;\n\t\tif( $count % 10 == 0 ) {\n\t\t    if( !$this->supress_tickmarks ) {\n\t\t\t$img->Line($xs,$pos,$xs,$a2);\n\t\t    }\n\t\t    $this->maj_ticks_pos[$i]=$xs;\n\t\t    $this->maj_ticklabels_pos[$i]=$xs;\n\n\t\t    if( $this->label_formfunc != '' ) {\n\t\t\t$f = $this->label_formfunc;\n\t\t\t$this->maj_ticks_label[$i]=call_user_func($f,$nextMajor);\t\n\t\t    }\n\t\t    elseif( $this->label_logtype == 0 )\n\t\t\t$this->maj_ticks_label[$i]=$nextMajor;\t\n\t\t    else\n\t\t\t$this->maj_ticks_label[$i]='10^'.round(log10($nextMajor));\n\t\t    ++$i;\n\t\t    $nextMajor *= 10;\n\t\t    $step *= 10;\t\n\t\t    $count=1; \t\t\t\t\n\t\t}\n\t\telse {\n\t\t    if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {\n\t\t\t$img->Line($xs,$pos,$xs,$a);\t\t\n\t\t    }\n\t\t}\n\t    }\t\t\n\t}\n\treturn true;\n    }\n} // Class\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_pie.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_PIE.PHP\n// Description:\tPie plot extension for JpGraph\n// Created: \t2001-02-14\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_pie.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n\n// Defines for PiePlot::SetLabelType()\nDEFINE(\"PIE_VALUE_ABS\",1);\nDEFINE(\"PIE_VALUE_PER\",0);\nDEFINE(\"PIE_VALUE_PERCENTAGE\",0);\nDEFINE(\"PIE_VALUE_ADJPERCENTAGE\",2);\nDEFINE(\"PIE_VALUE_ADJPER\",2);\n\n//===================================================\n// CLASS PiePlot\n// Description: Draws a pie plot\n//===================================================\nclass PiePlot {\n    var $posx=0.5,$posy=0.5;\n    var $radius=0.3;\n    var $explode_radius=array(),$explode_all=false,$explode_r=20;\n    var $labels=null, $legends=null;\n    var $csimtargets=null;  // Array of targets for CSIM\n    var $csimareas='';\t\t// Generated CSIM text\t\n    var $csimalts=null;\t\t// ALT tags for corresponding target\n    var $data=null;\n    var $title;\n    var $startangle=0;\n    var $weight=1, $color=\"black\";\n    var $legend_margin=6,$show_labels=true;\n    var $themearr = array(\n\t\"earth\" \t=> array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430),\n\t\"pastel\" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38),\n\t\"water\"  => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388),\n\t\"sand\"   => array(27,168,34,170,19,50,65,72,131,209,46,393));\n    var $theme=\"earth\";\n    var $setslicecolors=array();\n    var $labeltype=0; // Default to percentage\n    var $pie_border=true,$pie_interior_border=true;\n    var $value;\n    var $ishadowcolor='',$ishadowdrop=4;\n    var $ilabelposadj=1;\n    var $legendcsimtargets = array();\n    var $legendcsimalts = array();\n    var $adjusted_data = array();\n    var $guideline = null,$guidelinemargin=10;\n    var $iShowGuideLineForSingle = false;\n    var $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8;\n//---------------\n// CONSTRUCTOR\n    function PiePlot($data) {\n\t$this->data = array_reverse($data);\n\t$this->title = new Text(\"\");\n\t$this->title->SetFont(FF_FONT1,FS_BOLD);\n\t$this->value = new DisplayValue();\n\t$this->value->Show();\n\t$this->value->SetFormat('%.1f%%');\n\t$this->guideline = new LineProperty();\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function SetCenter($x,$y=0.5) {\n\t$this->posx = $x;\n\t$this->posy = $y;\n    }\n\n    // Enable guideline and set drwaing policy\n    function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) {\n\t$this->guideline->Show($aFlg);\n\t$this->iShowGuideLineForSingle = $aAlways;\n\t$this->iGuideLineCurve = $aCurved;\n    }\n\n    // Adjuste the distance between labels and labels and pie\n    function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) {\n\t$this->iGuideVFactor=$aVFactor;\n\t$this->iGuideLineRFactor=$aRFactor;\n    }\n\n    function SetColor($aColor) {\n\t$this->color = $aColor;\n    }\n\t\n    function SetSliceColors($aColors) {\n\t$this->setslicecolors = $aColors;\n    }\n\t\n    function SetShadow($aColor='darkgray',$aDropWidth=4) {\n\t$this->ishadowcolor = $aColor;\n\t$this->ishadowdrop = $aDropWidth;\n    }\n\n    function SetCSIMTargets($targets,$alts=null) {\n\t$this->csimtargets=array_reverse($targets);\n\tif( is_array($alts) )\n\t    $this->csimalts=array_reverse($alts);\n    }\n\t\n    function GetCSIMareas() {\n\treturn $this->csimareas;\n    }\n\n    function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {  \n\n        //Slice number, ellipse centre (x,y), height, width, start angle, end angle\n\twhile( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;\n\twhile( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;\n\n\t$sa = 2*M_PI - $sa;\n\t$ea = 2*M_PI - $ea;\n\n\t// Special case when we have only one slice since then both start and end\n\t// angle will be == 0\n\tif( abs($sa - $ea) < 0.0001 ) {\n\t    $sa=2*M_PI; $ea=0;\n\t}\n\n\t//add coordinates of the centre to the map\n\t$xc = floor($xc);$yc=floor($yc);\n\t$coords = \"$xc, $yc\";\n\n\t//add coordinates of the first point on the arc to the map\n\t$xp = floor(($radius*cos($ea))+$xc);\n\t$yp = floor($yc-$radius*sin($ea));\n\t$coords.= \", $xp, $yp\";\n\t//add coordinates every 0.2 radians\n\t$a=$ea+0.2;\n\n\t// If we cross the 260-limit with a slice we need to handle\n\t// the fact that end angle is smaller than start\n\tif( $sa < $ea ) {\n\t    while ($a <= 2*M_PI) {\n\t\t$xp = floor($radius*cos($a)+$xc);\n\t\t$yp = floor($yc-$radius*sin($a));\n\t\t$coords.= \", $xp, $yp\";\n\t\t$a += 0.2;\n\t    }\n\t    $a -= 2*M_PI;\n\t}\n\n\twhile ($a < $sa) {\n\t    $xp = floor($radius*cos($a)+$xc);\n\t    $yp = floor($yc-$radius*sin($a));\n\t    $coords.= \", $xp, $yp\";\n\t    $a += 0.2;\n\t}\n\t\t\n\t//Add the last point on the arc\n\t$xp = floor($radius*cos($sa)+$xc);\n\t$yp = floor($yc-$radius*sin($sa));\n\t$coords.= \", $xp, $yp\";\n\tif( !empty($this->csimtargets[$i]) ) {\n\t    $this->csimareas .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->csimtargets[$i].\"\\\"\";\n\t    $tmp=\"\";\n\t    if( !empty($this->csimalts[$i]) ) {\n\t\t$tmp=sprintf($this->csimalts[$i],$this->data[$i]);\n\t\t$this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t    }\n\t    $this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";\n\t}\n    }\n\n\t\n    function SetTheme($aTheme) {\n\tif( in_array($aTheme,array_keys($this->themearr)) )\n\t    $this->theme = $aTheme;\n\telse\n\t    JpGraphError::RaiseL(15001,$aTheme);//(\"PiePLot::SetTheme() Unknown theme: $aTheme\");\n    }\n\t\n    function ExplodeSlice($e,$radius=20) {\n\tif( ! is_integer($e) ) \n\t    JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer');\n\t$this->explode_radius[$e]=$radius;\n    }\n\n    function ExplodeAll($radius=20) {\n\t$this->explode_all=true;\n\t$this->explode_r = $radius;\n    }\n\n    function Explode($aExplodeArr) {\n\tif( !is_array($aExplodeArr) ) {\n\t    JpGraphError::RaiseL(15003);\n//(\"Argument to PiePlot::Explode() must be an array with integer distances.\");\n\t}\n\t$this->explode_radius = $aExplodeArr;\n    }\n\n    function SetStartAngle($aStart) {\n\tif( $aStart < 0 || $aStart > 360 ) {\n\t    JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.');\n\t}\n\t$this->startangle = 360-$aStart;\n\t$this->startangle *= M_PI/180;\n    }\n\t\n    function SetFont($family,$style=FS_NORMAL,$size=10) {\n\tJpGraphError::RaiseL(15005);//('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.');\n    }\n\t\n    // Size in percentage\n    function SetSize($aSize) {\n\tif( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) )\n\t    $this->radius = $aSize;\n\telse\n\t    JpGraphError::RaiseL(15006);\n//(\"PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels  in the range [10, 1000]\");\n    }\n\t\n    function SetFontColor($aColor) {\n\tJpGraphError::RaiseL(15007);\n//('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.');\n    }\n\t\n    // Set label arrays\n    function SetLegends($aLegend) {\n\t$this->legends = $aLegend;\n    }\n\n    // Set text labels for slices \n    function SetLabels($aLabels,$aLblPosAdj=\"auto\") {\n\t$this->labels = array_reverse($aLabels);\n\t$this->ilabelposadj=$aLblPosAdj;\n    }\n\n    function SetLabelPos($aLblPosAdj) {\n\t$this->ilabelposadj=$aLblPosAdj;\n    }\n\t\n    // Should we display actual value or percentage?\n    function SetLabelType($t) {\n\tif( $t < 0 || $t > 2 ) \n\t    JpGraphError::RaiseL(15008,$t);\n//(\"PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).\");\n\t$this->labeltype=$t;\n    }\n\n    // Deprecated. \n    function SetValueType($aType) {\n\t$this->SetLabelType($aType);\n    }\n\n    // Should the circle around a pie plot be displayed\n    function ShowBorder($exterior=true,$interior=true) {\n\t$this->pie_border = $exterior;\n\t$this->pie_interior_border = $interior;\n    }\n\t\n    // Setup the legends (Framework method)\n    function Legend(&$graph) {\n\t$colors = array_keys($graph->img->rgb->rgb_table);\n   \tsort($colors);\t\n   \t$ta=$this->themearr[$this->theme];\t\n   \t$n = count($this->data);\n\n   \tif( $this->setslicecolors==null ) {\n\t    $numcolors=count($ta);\n\t    if( is_a($this,'PiePlot3D') ) {\n\t\t$ta = array_reverse(array_slice($ta,0,$n));\n\t    }\n\t}\n   \telse {\n\t    $this->setslicecolors = array_slice($this->setslicecolors,0,$n);\n\t    $numcolors=count($this->setslicecolors); \n\t    if( $graph->pieaa && is_a($this,'PiePlot') ) { \n\t\t$this->setslicecolors = array_reverse($this->setslicecolors);\n\t    }\n\t}\n\t\t\n\t$sum=0;\n\tfor($i=0; $i < $n; ++$i)\n\t    $sum += $this->data[$i];\n\n\t// Bail out with error if the sum is 0\n\tif( $sum==0 )\n\t    JpGraphError::RaiseL(15009);//(\"Illegal pie plot. Sum of all data is zero for Pie!\");\n\n\t// Make sure we don't plot more values than data points\n\t// (in case the user added more legends than data points)\n\t$n = min(count($this->legends),count($this->data));\n\tif( $this->legends != \"\" ) {\n\t    $this->legends = array_reverse(array_slice($this->legends,0,$n));\n\t}\n\tfor( $i=$n-1; $i >= 0; --$i ) {\n\t    $l = $this->legends[$i];\n\t    // Replace possible format with actual values\n\t    if( count($this->csimalts) > $i ) {\n\t\t$fmt = $this->csimalts[$i];\n\t    }\n\t    else {\n\t\t$fmt = \"%d\"; // Deafult Alt if no other has been specified\n\t    }\n\t    if( $this->labeltype==0 ) {\n\t\t$l = sprintf($l,100*$this->data[$i]/$sum);\n\t\t$alt = sprintf($fmt,$this->data[$i]);\n\t\t\n\t    }\n\t    elseif( $this->labeltype == 1)  {\n\t\t$l = sprintf($l,$this->data[$i]);\n\t\t$alt = sprintf($fmt,$this->data[$i]);\n\t\t\n\t    }\n\t    else {\n\t\t$l = sprintf($l,$this->adjusted_data[$i]);\n\t\t$alt = sprintf($fmt,$this->adjusted_data[$i]);\n\t    }\n\n\t    if( $this->setslicecolors==null ) {\n\t\t$graph->legend->Add($l,$colors[$ta[$i%$numcolors]],\"\",0,$this->csimtargets[$i],$alt);\n\t    }\n\t    else {\n\t\t$graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],\"\",0,$this->csimtargets[$i],$alt);\n\t    }\n\t}\n    }\n\t\n    // Adjust the rounded percetage value so that the sum of\n    // of the pie slices are always 100%\n    // Using the Hare/Niemeyer method\n    function AdjPercentage($aData,$aPrec=0) {\n\t$mul=100;\n\tif( $aPrec > 0 && $aPrec < 3 ) {\n\t    if( $aPrec == 1 ) \n\t\t$mul=1000;\n\t\telse\n\t\t    $mul=10000;\n\t}\n\t\n\t$tmp = array();\n\t$result = array();\n\t$quote_sum=0;\n\t$n = count($aData) ;\n\tfor( $i=0, $sum=0; $i < $n; ++$i )\n\t    $sum+=$aData[$i];\n\tforeach($aData as $index => $value) {\n\t    $tmp_percentage=$value/$sum*$mul;\n\t    $result[$index]=floor($tmp_percentage);\n\t    $tmp[$index]=$tmp_percentage-$result[$index];\n\t    $quote_sum+=$result[$index];\n\t}\n\tif( $quote_sum == $mul) {\n\t    if( $mul > 100 ) {\n\t\t$tmp = $mul / 100;\n\t\tfor( $i=0; $i < $n; ++$i ) {\n\t\t    $result[$i] /= $tmp ;\n\t\t}\n\t    }\n\t    return $result;\n\t}\n\tarsort($tmp,SORT_NUMERIC);\n\treset($tmp);\n\tfor($i=0; $i < $mul-$quote_sum; $i++)\n\t{\n\t    $result[key($tmp)]++;\n\t    next($tmp);\n\t}\n\tif( $mul > 100 ) {\n\t    $tmp = $mul / 100;\n\t    for( $i=0; $i < $n; ++$i ) {\n\t\t$result[$i] /= $tmp ;\n\t    }\n\t}\n\treturn $result;\n    }\n\n\n    function Stroke(&$img,$aaoption=0) {\n\t// aaoption is used to handle antialias\n\t// aaoption == 0 a normal pie\n\t// aaoption == 1 just the body\n\t// aaoption == 2 just the values\n\n\t// Explode scaling. If anti anti alias we scale the image\n\t// twice and we also need to scale the exploding distance\n\t$expscale = $aaoption === 1 ? 2 : 1;\n\n\tif( $this->labeltype == 2 ) {\n\t    // Adjust the data so that it will add up to 100%\n\t    $this->adjusted_data = $this->AdjPercentage($this->data);\n\t}\n\n\t$colors = array_keys($img->rgb->rgb_table);\n   \tsort($colors);\t\n   \t$ta=$this->themearr[$this->theme];\t\n\t$n = count($this->data);\n   \t\n   \tif( $this->setslicecolors==null ) {\n\t    $numcolors=count($ta);\n\t}\n   \telse {\n\t    $this->setslicecolors = array_reverse(array_slice($this->setslicecolors,0,$n));\n\t    $numcolors=count($this->setslicecolors); \n\t    $tt = array_slice($this->setslicecolors,$n % $numcolors);\n\t    $tt2 = array_slice($this->setslicecolors,0,$n % $numcolors);\n\t    $tt2 = array_merge($tt, $tt2);\n\t    $this->setslicecolors = $tt + $tt2;\n\t}\n\n\t// Draw the slices\n\t$sum=0;\n\tfor($i=0; $i < $n; ++$i)\n\t    $sum += $this->data[$i];\n\t\n\t// Bail out with error if the sum is 0\n\tif( $sum==0 )\n\t    JpGraphError::RaiseL(15009);//(\"Sum of all data is 0 for Pie.\");\n\t\n\t// Set up the pie-circle\n\tif( $this->radius <= 1 )\n\t    $radius = floor($this->radius*min($img->width,$img->height));\n\telse {\n\t    $radius = $aaoption === 1 ? $this->radius*2 : $this->radius;\n\t}\n\n\tif( $this->posx <= 1 && $this->posx > 0 )\n\t    $xc = round($this->posx*$img->width);\n\telse\n\t    $xc = $this->posx ;\n\t\n\tif( $this->posy <= 1 && $this->posy > 0 )\n\t    $yc = round($this->posy*$img->height);\n\telse\n\t    $yc = $this->posy ;\n\t\t\n\t$n = count($this->data);\n\n\tif( $this->explode_all )\n\t    for($i=0; $i < $n; ++$i)\n\t\t$this->explode_radius[$i]=$this->explode_r;\n\n\tif( $this->ishadowcolor != \"\" && $aaoption !== 2) {\n\t    $accsum=0;\n\t    $angle2 = $this->startangle;\n\t    $img->SetColor($this->ishadowcolor);\n\t    for($i=0; $sum > 0 && $i < $n; ++$i) {\n\t\t$j = $n-$i-1;\n\t\t$d = $this->data[$i];\n\t\t$angle1 = $angle2;\n\t\t$accsum += $d;\n\t\t$angle2 = $this->startangle+2*M_PI*$accsum/$sum;\n\t\tif( empty($this->explode_radius[$j]) )\n\t\t    $this->explode_radius[$j]=0;\n\n\t\t$la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);\n\n\t\t$xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale;\n\t\t$ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale;\n\t\t\n\t\t$xcm += $this->ishadowdrop*$expscale;\n\t\t$ycm += $this->ishadowdrop*$expscale;\n\n\t\t$img->CakeSlice($xcm,$ycm,$radius,$radius,\n\t\t\t\t$angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor);\n\t\t\n\t    }\n\t}\n\n\t$accsum=0;\n\t$angle2 = $this->startangle;\n\t$img->SetColor($this->color);\n\tfor($i=0; $sum>0 && $i < $n; ++$i) {\n\t    $j = $n-$i-1;\n\t    if( empty($this->explode_radius[$j]) )\n\t\t$this->explode_radius[$j]=0;\n\t    $d = $this->data[$i];\n\t    $angle1 = $angle2;\n\t    $accsum += $d;\n\t    $angle2 = $this->startangle+2*M_PI*$accsum/$sum;\n\t    $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);\n\n\t    if( $d == 0 ) continue;\n\n\t    if( $this->setslicecolors==null )\n\t\t$slicecolor=$colors[$ta[$i%$numcolors]];\n\t    else\n\t\t$slicecolor=$this->setslicecolors[$i%$numcolors];\n\n\t    if( $this->pie_interior_border && $aaoption===0 )\n\t\t$img->SetColor($this->color);\n\t    else\n\t\t$img->SetColor($slicecolor);\n\n\t    $arccolor = $this->pie_border && $aaoption===0 ? $this->color : \"\";\n\n\t    $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale;\n\t    $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale;\n\n\t    if( $aaoption !== 2 ) {\n\t\t$img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,\n\t\t\t\t$angle1*180/M_PI,$angle2*180/M_PI,$slicecolor,$arccolor);\n\t    }\n\n\t    if( $this->csimtargets && $aaoption !== 1 ) {\n\t\t$this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2);\n\t    }\n\t}\n\n\t// Format the titles for each slice\n\tif( $aaoption!==2) {\n\t    for( $i=0; $i < $n; ++$i) {\n\t\tif( $this->labeltype==0 ) {\n\t\t    if( $sum != 0 )\n\t\t\t$l = 100.0*$this->data[$i]/$sum;\n\t\t    else\n\t\t\t$l = 0.0;\n\t\t}\n\t\telseif( $this->labeltype==1 ) {\n\t\t    $l = $this->data[$i]*1.0;\n\t\t}\n\t\telse {\n\t\t    $l = $this->adjusted_data[$i];\n\t\t}\n\t\tif( isset($this->labels[$i]) && is_string($this->labels[$i]) )\n\t\t    $this->labels[$i]=sprintf($this->labels[$i],$l);\n\t\telse\n\t\t    $this->labels[$i]=$l;\n\t    }\n\t}\n\n\tIf( $this->value->show && $aaoption !== 1 ) {\n\t    $this->StrokeAllLabels($img,$xc,$yc,$radius);\n\t}\n\n\t// Adjust title position\n\tif( $aaoption !== 1 ) {\n\t    $this->title->Pos($xc,\n\t\t\t  $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin,\n\t\t\t  \"center\",\"bottom\");\n\t    $this->title->Stroke($img);\n\t}\n\n    }\n\n//---------------\n// PRIVATE METHODS\t\n\n    function NormAngle($a) {\n\twhile( $a < 0 ) $a += 2*M_PI;\n\twhile( $a > 2*M_PI ) $a -= 2*M_PI;\n\treturn $a;\n    }\n\n    function Quadrant($a) {\n\t$a=$this->NormAngle($a);\n\tif( $a > 0 && $a <= M_PI/2 )\n\t    return 0;\n\tif( $a > M_PI/2 && $a <= M_PI )\n\t    return 1;\n\tif( $a > M_PI && $a <= 1.5*M_PI )\n\t    return 2;\n\tif( $a > 1.5*M_PI )\n\t    return 3;\n    }\n\n    function StrokeGuideLabels($img,$xc,$yc,$radius) {\n\t$n = count($this->labels);\n\n\t//-----------------------------------------------------------------------\n\t// Step 1 of the algorithm is to construct a number of clusters\n\t// a cluster is defined as all slices within the same quadrant (almost)\n\t// that has an angular distance less than the threshold\n\t//-----------------------------------------------------------------------\n\t$tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster\n\t$incluster=false;\t// flag if we are currently in a cluster or not\n\t$clusters = array();\t// array of clusters\n\t$cidx=-1;\t\t// running cluster index\n\n\t// Go through all the labels and construct a number of clusters\n\tfor($i=0; $i < $n-1; ++$i) {\n\t    // Calc the angle distance between two consecutive slices\n\t    $a1=$this->la[$i];\n\t    $a2=$this->la[$i+1];\n\t    $q1 = $this->Quadrant($a1);\n\t    $q2 = $this->Quadrant($a2);\n\t    $diff = abs($a1-$a2);\n\t    if( $diff < $tresh_hold ) {\n\t\tif( $incluster ) {\n\t\t    $clusters[$cidx][1]++;\n\t\t    // Each cluster can only cover one quadrant\n\t\t    // Do we cross a quadrant ( and must break the cluster)\n\t\t    if( $q1 !=  $q2 ) {\n\t\t\t// If we cross a quadrant boundary we normally start a \n\t\t\t// new cluster. However we need to take the 12'a clock\n\t\t\t// and 6'a clock positions into a special consideration.\n\t\t\t// Case 1: WE go from q=1 to q=2 if the last slice on\n\t\t\t// the cluster for q=1 is close to 12'a clock and the \n\t\t\t// first slice in q=0 is small we extend the previous\n\t\t\t// cluster\n\t\t\tif( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) {\n\t\t\t    if( $i < $n-2 ) {\n\t\t\t\t$a3 = $this->la[$i+2];\n\t\t\t\t// If there isn't a cluster coming up with the next-next slice\n\t\t\t\t// we extend the previous cluster to cover this slice as well\n\t\t\t\tif( abs($a3-$a2) >= $tresh_hold ) {\n\t\t\t\t    $clusters[$cidx][1]++;\n\t\t\t\t    $i++;\n\t\t\t\t}\n\t\t\t    }\n\t\t\t}\n\t\t\telseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) {\n\t\t\t    if( $i < $n-2 ) {\n\t\t\t\t$a3 = $this->la[$i+2];\n\t\t\t\t// If there isn't a cluster coming up with the next-next slice\n\t\t\t\t// we extend the previous cluster to cover this slice as well\n\t\t\t\tif( abs($a3-$a2) >= $tresh_hold ) {\n\t\t\t\t    $clusters[$cidx][1]++;\n\t\t\t\t    $i++;\n\t\t\t\t}\n\t\t\t    }\n\t\t\t}\n\n\t\t\tif( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) {\n\t\t\t    $clusters[$cidx][1]++;\n\t\t\t    $i++;\t\t\t    \n\t\t\t}\n\t\t\t\n\t\t\t$incluster = false;\n\t\t    }\n\t\t}\n\t\telseif( $q1 == $q2)  {\n\t\t    $incluster = true;\n\t\t    // Now we have a special case for quadrant 0. If we previously\n\t\t    // have a cluster of one in quadrant 0 we just extend that\n\t\t    // cluster. If we don't do this then we risk that the label\n\t\t    // for the cluster of one will cross the guide-line\n\t\t    if( $q1 == 0 && $cidx > -1 && \n\t\t\t$clusters[$cidx][1] == 1 && \n\t\t\t$this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) {\n\t\t\t$clusters[$cidx][1]++;\n\t\t    }\n\t\t    else {\n\t\t\t$cidx++;\n\t\t\t$clusters[$cidx][0] = $i;\n\t\t\t$clusters[$cidx][1] = 1;\n\t\t    }\n\t\t}\n\t\telse {  \n\t\t    // Create a \"cluster\" of one since we are just crossing\n\t\t    // a quadrant\n\t\t    $cidx++;\n\t\t    $clusters[$cidx][0] = $i;\n\t\t    $clusters[$cidx][1] = 1;\t    \n\t\t}\n\t    }\n\t    else {\n\t\tif( $incluster ) {\n\t\t    // Add the last slice\n\t\t    $clusters[$cidx][1]++;\n\t\t    $incluster = false;\n\t\t}\n\t\telse { // Create a \"cluster\" of one\n\t\t    $cidx++;\n\t\t    $clusters[$cidx][0] = $i;\n\t\t    $clusters[$cidx][1] = 1;\t    \n\t\t}\n\t    }\n\t}\n\t// Handle the very last slice\n\tif( $incluster ) {\n\t    $clusters[$cidx][1]++;\n\t}\n\telse { // Create a \"cluster\" of one\n\t    $cidx++;\n\t    $clusters[$cidx][0] = $i;\n\t    $clusters[$cidx][1] = 1;\t    \n\t}\n\n\t/*\n\tif( true ) { \n\t    // Debug printout in labels\n\t    for( $i=0; $i <= $cidx; ++$i ) {\n\t\tfor( $j=0; $j < $clusters[$i][1]; ++$j ) {\n\t\t    $a = $this->la[$clusters[$i][0]+$j];\n\t\t    $aa = round($a*180/M_PI);\n\t\t    $q = $this->Quadrant($a);\n\t\t    $this->labels[$clusters[$i][0]+$j]=\"[$q:$aa] $i:$j\";\n\t\t}\n\t    }\n\t}\n\t*/\n\n\t//-----------------------------------------------------------------------\n\t// Step 2 of the algorithm is use the clusters and draw the labels\n\t// and guidelines\n\t//-----------------------------------------------------------------------\n\n\t// We use the font height as the base factor for how far we need to\n\t// spread the labels in the Y-direction.\n\t$img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize);\n\t$fh = $img->GetFontHeight();\n\t$origvstep=$fh*$this->iGuideVFactor;\n\t$this->value->SetMargin(0);\n\n\t// Number of clusters found\n\t$nc = count($clusters);\n\n\t// Walk through all the clusters\n\tfor($i=0; $i < $nc; ++$i) {\n\n\t    // Start angle and number of slices in this cluster\n\t    $csize = $clusters[$i][1];\n\t    $a = $this->la[$clusters[$i][0]];\n\t    $q = $this->Quadrant($a);\n\n\t    // Now set up the start and end conditions to make sure that\n\t    // in each cluster we walk through the all the slices starting with the slice\n\t    // closest to the equator. Since all slices are numbered clockwise from \"3'a clock\"\n\t    // we have different conditions depending on in which quadrant the slice lies within.\n\t    if( $q == 0 ) {\n\t\t$start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep;\n\t    }\n\t    elseif( $q == 1 ) {\n\t\t$start = 0; $idx = $start; $step = 1; $vstep = -$origvstep;\n\t    }\n\t    elseif( $q == 2 ) {\n\t\t$start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep;\n\t    }\n\t    elseif( $q == 3 ) {\n\t\t$start = 0; $idx = $start; $step = 1; $vstep = $origvstep;\n\t    }\n\n\t    // Walk through all slices within this cluster\n\t    for($j=0; $j < $csize; ++$j) {   \n\t\t// Now adjust the position of the labels in each cluster starting\n\t\t// with the slice that is closest to the equator of the pie\n\t\t$a = $this->la[$clusters[$i][0]+$idx];\n\t\t    \n\t\t// Guide line start in the center of the arc of the slice\n\t\t$r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];\n\t\t$x = round($r*cos($a)+$xc);\n\t\t$y = round($yc-$r*sin($a));\n\t\t\n\t\t// The distance from the arc depends on chosen font and the \"R-Factor\"\n\t\t$r += $fh*$this->iGuideLineRFactor;\n\n\t\t// Should the labels be placed curved along the pie or in straight columns\n\t\t// outside the pie?\n\t\tif( $this->iGuideLineCurve )\n\t\t    $xt=round($r*cos($a)+$xc);\n\n\t\t// If this is the first slice in the cluster we need some first time\n\t\t// proessing\n\t\tif( $idx == $start ) {\n\t\t    if( ! $this->iGuideLineCurve )\n\t\t\t$xt=round($r*cos($a)+$xc);\n\t\t    $yt=round($yc-$r*sin($a));\n\n\t\t    // Some special consideration in case this cluster starts\n\t\t    // in quadrant 1 or 3 very close to the \"equator\" (< 20 degrees) \n\t\t    // and the previous clusters last slice is within the tolerance. \n\t\t    // In that case we add a font height to this labels Y-position \n\t\t    // so it doesn't collide with\n\t\t    // the slice in the previous cluster\n\t\t    $prevcluster = ($i + ($nc-1) ) % $nc;\n\t\t    $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1;\n\t\t    if( $q == 1 && $a > 160*M_PI/180 ) {\n\t\t\t// Get the angle for the previous clusters last slice\n\t\t\t$diff = abs($a-$this->la[$previdx]);\n\t\t\t if( $diff < $tresh_hold ) {\n\t\t\t     $yt -= $fh;\n\t\t\t }\n\t\t    }\n\t\t    elseif( $q == 3 && $a > 340*M_PI/180 ) {\n\t\t\t// We need to subtract 360 to compare angle distance between\n\t\t\t// q=0 and q=3\n\t\t\t$diff = abs($a-$this->la[$previdx]-360*M_PI/180);\n\t\t\tif( $diff < $tresh_hold ) {\n\t\t\t     $yt += $fh;\n\t\t\t}\n\t\t    }\n\n\t\t}\n\t\telse {\n\t\t    // The step is at minimum $vstep but if the slices are relatively large\n\t\t    // we make sure that we add at least a step that corresponds to the vertical\n\t\t    // distance between the centers at the arc on the slice\n\t\t    $prev_a = $this->la[$clusters[$i][0]+($idx-$step)];\n\t\t    $dy = abs($radius*(sin($a)-sin($prev_a))*1.2);\n\t\t    if( $vstep > 0 )\n\t\t\t$yt += max($vstep,$dy);\n\t\t    else\n\t\t\t$yt += min($vstep,-$dy);\n\t\t}\n\n\t\t$label = $this->labels[$clusters[$i][0]+$idx];\n\n\t\tif( $csize == 1 ) {\n\t\t    // A \"meta\" cluster with only one slice\n\t\t    $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];\n\t\t    $rr = $r+$img->GetFontHeight()/2;\n\t\t    $xt=round($rr*cos($a)+$xc);\n\t\t    $yt=round($yc-$rr*sin($a));\n\t\t    $this->StrokeLabel($label,$img,$xc,$yc,$a,$r); \n\t\t    if( $this->iShowGuideLineForSingle ) \n\t\t\t$this->guideline->Stroke($img,$x,$y,$xt,$yt);\n\t\t}\n\t\telse {\n\t\t    $this->guideline->Stroke($img,$x,$y,$xt,$yt);\n\t\t    if( $q==1 || $q==2 ) {\n\t\t\t// Left side of Pie\n\t\t\t$this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt);\n\t\t\t$lbladj = -$this->guidelinemargin-5;\n\t\t\t$this->value->halign = \"right\";\n\t\t\t$this->value->valign = \"center\";\n\t\t    }\n\t\t    else {\n\t\t\t// Right side of pie\n\t\t\t$this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt);\n\t\t\t$lbladj = $this->guidelinemargin+5;\n\t\t\t$this->value->halign = \"left\";\n\t\t\t$this->value->valign = \"center\";\n\t\t    }\n\t\t    $this->value->Stroke($img,$label,$xt+$lbladj,$yt);\n\t\t}\n\n\t\t// Udate idx to point to next slice in the cluster to process\n\t\t$idx += $step;\n\t    }\n\t}\n    }\n\n    function StrokeAllLabels($img,$xc,$yc,$radius) {\n\t// First normalize all angles for labels\n\t$n = count($this->la);\n\tfor($i=0; $i < $n; ++$i) {\n\t    $this->la[$i] = $this->NormAngle($this->la[$i]);\n\t}\n\tif( $this->guideline->iShow ) {\n\t    $this->StrokeGuideLabels($img,$xc,$yc,$radius);\n\t}\n\telse {\n\t    $n = count($this->labels);\n\t    for($i=0; $i < $n; ++$i) {\n\t\t$this->StrokeLabel($this->labels[$i],$img,$xc,$yc,\n\t\t\t\t   $this->la[$i],\n\t\t\t\t   $radius + $this->explode_radius[$n-1-$i]); \n\t    }\n\t}\n    }\n\n    // Position the labels of each slice\n    function StrokeLabel($label,$img,$xc,$yc,$a,$radius) {\n\n\t// Default value\n\tif( $this->ilabelposadj === 'auto' )\n\t    $this->ilabelposadj = 0.65;\n\t$r = $radius;\n\n\t// We position the values diferently depending on if they are inside\n\t// or outside the pie\n\tif( $this->ilabelposadj < 1.0 ) {\n\n\t    $this->value->SetAlign('center','center');\n\t    $this->value->margin = 0;\n\t    \n\t    $xt=round($this->ilabelposadj*$r*cos($a)+$xc);\n\t    $yt=round($yc-$this->ilabelposadj*$r*sin($a));\n\t    \n\t    $this->value->Stroke($img,$label,$xt,$yt);\n\t}\n\telse {\n\n\t    $this->value->halign = \"left\";\n\t    $this->value->valign = \"top\";\n\t    $this->value->margin = 0;\n\t    \t    \n\t    // Position the axis title. \n\t    // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text\n\t    // that intersects with the extension of the corresponding axis. The code looks a little\n\t    // bit messy but this is really the only way of having a reasonable position of the\n\t    // axis titles.\n\t    $img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize);\n\t    $h=$img->GetTextHeight($label);\n\t    // For numeric values the format of the display value\n\t    // must be taken into account\n\t    if( is_numeric($label) ) {\n\t\tif( $label > 0 )\n\t\t    $w=$img->GetTextWidth(sprintf($this->value->format,$label));\n\t\telse\n\t\t    $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));\n\t    }\n\t    else\n\t\t$w=$img->GetTextWidth($label);\n\t    if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) {\n\t\t$r *= $this->ilabelposadj;\n\t    }\n\t    \n\t    $r += $img->GetFontHeight()/1.5;\n\n\t    $xt=round($r*cos($a)+$xc);\n\t    $yt=round($yc-$r*sin($a));\n\n\t    // Normalize angle\n\t    while( $a < 0 ) $a += 2*M_PI;\n\t    while( $a > 2*M_PI ) $a -= 2*M_PI;\n\t\t\n\t    if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;\n\t    if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; \n\t    if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;\n\t    if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);\n\t    \n\t    if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;\n\t    if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);\n\t    if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;\n\t    if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);\n\t    if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;\n\t    \n\t    $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h);\n\t}\n    }\t\n} // Class\n\n\n//===================================================\n// CLASS PiePlotC\n// Description: Same as a normal pie plot but with a \n// filled circle in the center\n//===================================================\nclass PiePlotC extends PiePlot {\n    var $imidsize=0.5;\t\t// Fraction of total width\n    var $imidcolor='white';\n    var $midtitle='';\n    var $middlecsimtarget=\"\",$middlecsimalt=\"\";\n\n    function PiePlotC($data,$aCenterTitle='') {\n\tparent::PiePlot($data);\n\t$this->midtitle = new Text();\n\t$this->midtitle->ParagraphAlign('center');\n    }\n\n    function SetMid($aTitle,$aColor='white',$aSize=0.5) {\n\t$this->midtitle->Set($aTitle);\n\n\t$this->imidsize = $aSize ; \n\t$this->imidcolor = $aColor ; \n    }\n\n    function SetMidTitle($aTitle) {\n\t$this->midtitle->Set($aTitle);\n    }\n\n    function SetMidSize($aSize) {\n\t$this->imidsize = $aSize ; \n    }\n\n    function SetMidColor($aColor) {\n\t$this->imidcolor = $aColor ; \n    }\n\n    function SetMidCSIM($aTarget,$aAlt) {\n\t$this->middlecsimtarget = $aTarget;\n\t$this->middlecsimalt = $aAlt;\n    }\n\n    function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {  \n\n        //Slice number, ellipse centre (x,y), radius, start angle, end angle\n\twhile( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;\n\twhile( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;\n\n\t$sa = 2*M_PI - $sa;\n\t$ea = 2*M_PI - $ea;\n\n\t// Special case when we have only one slice since then both start and end\n\t// angle will be == 0\n\tif( abs($sa - $ea) < 0.0001 ) {\n\t    $sa=2*M_PI; $ea=0;\n\t}\n\n\t// Add inner circle first point\n\t$xp = floor(($this->imidsize*$radius*cos($ea))+$xc);\n\t$yp = floor($yc-($this->imidsize*$radius*sin($ea)));\n\t$coords = \"$xp, $yp\";\n\t\n\t//add coordinates every 0.25 radians\n\t$a=$ea+0.25;\n\n\t// If we cross the 260-limit with a slice we need to handle\n\t// the fact that end angle is smaller than start\n\tif( $sa < $ea ) {\n\t    while ($a <= 2*M_PI) {\n\t\t$xp = floor($radius*cos($a)+$xc);\n\t\t$yp = floor($yc-$radius*sin($a));\n\t\t$coords.= \", $xp, $yp\";\n\t\t$a += 0.25;\n\t    }\n\t    $a -= 2*M_PI;\n\t}\n\n\twhile ($a < $sa) {\n\t    $xp = floor(($this->imidsize*$radius*cos($a)+$xc));\n\t    $yp = floor($yc-($this->imidsize*$radius*sin($a)));\n\t    $coords.= \", $xp, $yp\";\n\t    $a += 0.25;\n\t}\n\n\t// Make sure we end at the last point\n\t$xp = floor(($this->imidsize*$radius*cos($sa)+$xc));\n\t$yp = floor($yc-($this->imidsize*$radius*sin($sa)));\n\t$coords.= \", $xp, $yp\";\n\n\t// Straight line to outer circle\n\t$xp = floor($radius*cos($sa)+$xc);\n\t$yp = floor($yc-$radius*sin($sa));\n\t$coords.= \", $xp, $yp\";\t\n\n\t//add coordinates every 0.25 radians\n\t$a=$sa - 0.25;\n\twhile ($a > $ea) {\n\t    $xp = floor($radius*cos($a)+$xc);\n\t    $yp = floor($yc-$radius*sin($a));\n\t    $coords.= \", $xp, $yp\";\n\t    $a -= 0.25;\n\t}\n\t\t\n\t//Add the last point on the arc\n\t$xp = floor($radius*cos($ea)+$xc);\n\t$yp = floor($yc-$radius*sin($ea));\n\t$coords.= \", $xp, $yp\";\n\n\t// Close the arc\n\t$xp = floor(($this->imidsize*$radius*cos($ea))+$xc);\n\t$yp = floor($yc-($this->imidsize*$radius*sin($ea)));\n\t$coords .= \", $xp, $yp\";\n\n\tif( !empty($this->csimtargets[$i]) ) {\n\t    $this->csimareas .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".\n\t\t$this->csimtargets[$i].\"\\\"\";\n\t    if( !empty($this->csimalts[$i]) ) {\n\t\t$tmp=sprintf($this->csimalts[$i],$this->data[$i]);\n\t\t$this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t    }\n\t    $this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";\n\t}\n    }\n\n\n    function Stroke($img,$aaoption=0) {\n\n\t// Stroke the pie but don't stroke values\n\t$tmp =  $this->value->show;\n\t$this->value->show = false;\n\tparent::Stroke($img,$aaoption);\n\t$this->value->show = $tmp;\n\n \t$xc = round($this->posx*$img->width);\n\t$yc = round($this->posy*$img->height);\n\n\t$radius = floor($this->radius * min($img->width,$img->height)) ;\n\n\n\tif( $this->imidsize > 0 && $aaoption !== 2 ) {\n\n\t    if( $this->ishadowcolor != \"\" ) {\n\t\t$img->SetColor($this->ishadowcolor);\n\t\t$img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop,\n\t\t\t\t   round($radius*$this->imidsize));\n\t    }\n\n\t    $img->SetColor($this->imidcolor);\n\t    $img->FilledCircle($xc,$yc,round($radius*$this->imidsize));\n\n\t    if(  $this->pie_border && $aaoption === 0 ) {\n\t\t$img->SetColor($this->color);\n\t\t$img->Circle($xc,$yc,round($radius*$this->imidsize));\n\t    }\n\n\t    if( !empty($this->middlecsimtarget) )\n\t\t$this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize));\n\n\t}\n\n\tif( $this->value->show && $aaoption !== 1) {\n\t    $this->StrokeAllLabels($img,$xc,$yc,$radius);\n\t    $this->midtitle->Pos($xc,$yc,'center','center');\n\t    $this->midtitle->Stroke($img);\n\t}\n\n    }\n\n    function AddMiddleCSIM($xc,$yc,$r) {\n\t$xc=round($xc);$yc=round($yc);$r=round($r);\n\t$this->csimareas .= \"<area shape=\\\"circle\\\" coords=\\\"$xc,$yc,$r\\\" href=\\\"\".\n\t    $this->middlecsimtarget.\"\\\"\";\n\tif( !empty($this->middlecsimalt) ) {\n\t    $tmp = $this->middlecsimalt;\n\t    $this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t}\n\t$this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";\n    }\n\n    function StrokeLabel($label,$img,$xc,$yc,$a,$r) {\n\n\tif( $this->ilabelposadj === 'auto' )\n\t    $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize;\n\n\tparent::StrokeLabel($label,$img,$xc,$yc,$a,$r);\n\n    }\n\n}\n\n\n//===================================================\n// CLASS PieGraph\n// Description: \n//===================================================\nclass PieGraph extends Graph {\n    var $posx, $posy, $radius;\t\t\n    var $legends=array();\t\n    var $plots=array();\n    var $pieaa = false ;\n//---------------\n// CONSTRUCTOR\n    function PieGraph($width=300,$height=200,$cachedName=\"\",$timeout=0,$inline=1) {\n\t$this->Graph($width,$height,$cachedName,$timeout,$inline);\n\t$this->posx=$width/2;\n\t$this->posy=$height/2;\n\t$this->SetColor(array(255,255,255));\t\t\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Add($aObj) {\n\n\tif( is_array($aObj) && count($aObj) > 0 )\n\t    $cl = $aObj[0];\n\telse\n\t    $cl = $aObj;\n\n\tif( is_a($cl,'Text') ) \n\t    $this->AddText($aObj);\n\telseif( is_a($cl,'IconPlot') ) \n\t    $this->AddIcon($aObj);\n\telse {\n\t    if( is_array($aObj) ) {\n\t\t$n = count($aObj);\n\t\tfor($i=0; $i < $n; ++$i ) {\n\t\t    $this->plots[] = $aObj[$i];\n\t\t}\n\t    }\n\t    else {\n\t\t$this->plots[] = $aObj;\n\t    }\n\t}\n    }\n\n    function SetAntiAliasing($aFlg=true) {\n\t$this->pieaa = $aFlg;\n    }\n\t\n    function SetColor($c) {\n\t$this->SetMarginColor($c);\n    }\n\n    function DisplayCSIMAreas() {\n\t    $csim=\"\";\n\t    foreach($this->plots as $p ) {\n\t\t$csim .= $p->GetCSIMareas();\n\t    }\n\t    //$csim.= $this->legend->GetCSIMareas();\n\t    if (preg_match_all(\"/area shape=\\\"(\\w+)\\\" coords=\\\"([0-9\\, ]+)\\\"/\", $csim, $coords)) {\n\t\t$this->img->SetColor($this->csimcolor);\n\t\t$n = count($coords[0]);\n\t\tfor ($i=0; $i < $n; $i++) {\n\t\t    if ($coords[1][$i]==\"poly\") {\n\t\t\tpreg_match_all('/\\s*([0-9]+)\\s*,\\s*([0-9]+)\\s*,*/',$coords[2][$i],$pts);\n\t\t\t$this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);\n\t\t\t$m = count($pts[0]);\n\t\t\tfor ($j=0; $j < $m; $j++) {\n\t\t\t    $this->img->LineTo($pts[1][$j],$pts[2][$j]);\n\t\t\t}\n\t\t    } else if ($coords[1][$i]==\"rect\") {\n\t\t\t$pts = preg_split('/,/', $coords[2][$i]);\n\t\t\t$this->img->SetStartPoint($pts[0],$pts[1]);\n\t\t\t$this->img->LineTo($pts[2],$pts[1]);\n\t\t\t$this->img->LineTo($pts[2],$pts[3]);\n\t\t\t$this->img->LineTo($pts[0],$pts[3]);\n\t\t\t$this->img->LineTo($pts[0],$pts[1]);\n\t\t\t\t\t\t\n\t\t    }\n\t\t}\n\t    }\n    }\n\n    // Method description\n    function Stroke($aStrokeFileName=\"\") {\n\t// If the filename is the predefined value = '_csim_special_'\n\t// we assume that the call to stroke only needs to do enough\n\t// to correctly generate the CSIM maps.\n\t// We use this variable to skip things we don't strictly need\n\t// to do to generate the image map to improve performance\n\t// a best we can. Therefor you will see a lot of tests !$_csim in the\n\t// code below.\n\t$_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);\n\n\t// We need to know if we have stroked the plot in the\n\t// GetCSIMareas. Otherwise the CSIM hasn't been generated\n\t// and in the case of GetCSIM called before stroke to generate\n\t// CSIM without storing an image to disk GetCSIM must call Stroke.\n\t$this->iHasStroked = true;\n\t\t\n\t$n = count($this->plots);\n\n\tif( $this->pieaa ) {\n\n\t    if( !$_csim ) {\n\t\tif( $this->background_image != \"\" ) {\n\t\t    $this->StrokeFrameBackground();\t\t\n\t\t}\n\t\telse {\n\t\t    $this->StrokeFrame();\t\t\n\t\t}\n\t    }\n\n\n\t    $w = $this->img->width;\n\t    $h = $this->img->height;\n\t    $oldimg = $this->img->img;\n\n\t    $this->img->CreateImgCanvas(2*$w,2*$h);\n\t    \n\t    $this->img->SetColor( $this->margin_color );\n\t    $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1);\n\n\t    // Make all icons *2 i size since we will be scaling down the\n\t    // image to do the anti aliasing\n\t    $ni = count($this->iIcons);\n\t    for($i=0; $i < $ni; ++$i) {\n\t\t$this->iIcons[$i]->iScale *= 2 ;\n\t    }\n\t    $this->StrokeIcons();\n\n\t    for($i=0; $i < $n; ++$i) {\n\t\tif( $this->plots[$i]->posx > 1 ) \n\t\t    $this->plots[$i]->posx *= 2 ;\n\t\tif( $this->plots[$i]->posy > 1 ) \n\t\t    $this->plots[$i]->posy *= 2 ;\n\n\t\t$this->plots[$i]->Stroke($this->img,1);\n\n\t\tif( $this->plots[$i]->posx > 1 ) \n\t\t    $this->plots[$i]->posx /= 2 ;\n\t\tif( $this->plots[$i]->posy > 1 ) \n\t\t    $this->plots[$i]->posy /= 2 ;\n\t    }\n\n\t    $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ;\n\t    $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ;\n\t    $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent,\n\t\t\t\t    $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent));\n\n\t    $this->img->img = $oldimg ;\n\t    $this->img->width = $w ;\n\t    $this->img->height = $h ;\n\n\t    for($i=0; $i < $n; ++$i) {\n\t\t$this->plots[$i]->Stroke($this->img,2); // Stroke labels\n\t\t$this->plots[$i]->Legend($this);\n\t    }\n\n\t}\n\telse {\n\t    // No antialias\n\t    if( !$_csim ) {\n\t\tif( $this->background_image != \"\" ) {\n\t\t    $this->StrokeFrameBackground();\t\t\n\t\t}\n\t\telse {\n\t\t    $this->StrokeFrame();\n\t\t    $this->StrokeBackgroundGrad();\t\t\n\t\t}\n\t    }\n\n\t    $this->StrokeIcons();\n\n\t    for($i=0; $i < $n; ++$i) {\n\t\t$this->plots[$i]->Stroke($this->img);\n\t\t$this->plots[$i]->Legend($this);\n\t    }\n\t}\n\n\t$this->legend->Stroke($this->img);\n\t$this->footer->Stroke($this->img);\n\t$this->StrokeTitles();\n\n\tif( !$_csim ) {\t\n\n\t    // Stroke texts\n\t    if( $this->texts != null ) {\n\t\t$n = count($this->texts);\n\t\tfor($i=0; $i < $n; ++$i ) {\n\t\t    $this->texts[$i]->Stroke($this->img);\n\t\t}\n\t    }\n\n\t    if( _JPG_DEBUG ) {\n\t\t$this->DisplayCSIMAreas();\n\t    }\n\n\t    // Should we do any final image transformation\n\t    if( $this->iImgTrans ) {\n\t\tif( !class_exists('ImgTrans') ) {\n\t\t    require_once('jpgraph_imgtrans.php');\n\t\t    //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');\n\t\t}\n\t       \n\t\t$tform = new ImgTrans($this->img->img);\n\t\t$this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,\n\t\t\t\t\t\t $this->iImgTransDirection,$this->iImgTransHighQ,\n\t\t\t\t\t\t $this->iImgTransMinSize,$this->iImgTransFillColor,\n\t\t\t\t\t\t $this->iImgTransBorder);\n\t    }\n\n\n\t    // If the filename is given as the special \"__handle\"\n\t    // then the image handler is returned and the image is NOT\n\t    // streamed back\n\t    if( $aStrokeFileName == _IMG_HANDLER ) {\n\t\treturn $this->img->img;\n\t    }\n\t    else {\n\t\t// Finally stream the generated picture\t\t\t\t\t\n\t\t$this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,\n\t\t\t\t\t   $aStrokeFileName);\t\t\n\t    }\n\t}\n    }\n} // Class\n\n/* EOF */\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_pie3d.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_PIE3D.PHP\n// Description: 3D Pie plot extension for JpGraph\n// Created: \t2001-03-24\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_pie3d.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//===================================================\n// CLASS PiePlot3D\n// Description: Plots a 3D pie with a specified projection \n// angle between 20 and 70 degrees.\n//===================================================\nclass PiePlot3D extends PiePlot {\n    var $labelhintcolor=\"red\",$showlabelhint=true;\n    var $angle=50;\t\n    var $edgecolor=\"\", $edgeweight=1;\n    var $iThickness=false;\n\t\n//---------------\n// CONSTRUCTOR\n    function PiePlot3d(&$data) {\n\t$this->radius = 0.5;\n\t$this->data = $data;\n\t$this->title = new Text(\"\");\n\t$this->title->SetFont(FF_FONT1,FS_BOLD);\n\t$this->value = new DisplayValue();\n\t$this->value->Show();\n\t$this->value->SetFormat('%.0f%%');\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\t\n    // Set label arrays\n    function SetLegends($aLegend) {\n\t$this->legends = array_reverse(array_slice($aLegend,0,count($this->data)));\n    }\n\n    function SetSliceColors($aColors) {\n\t$this->setslicecolors = $aColors;\n    }\n\n    function Legend(&$aGraph) {\n\tparent::Legend($aGraph);\n\t$aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol);\n    }\n\n    function SetCSIMTargets($targets,$alts=null) {\n\t$this->csimtargets = $targets;\n\t$this->csimalts = $alts;\n    }\n\n    // Should the slices be separated by a line? If color is specified as \"\" no line\n    // will be used to separate pie slices.\n    function SetEdge($aColor='black',$aWeight=1) {\n\t$this->edgecolor = $aColor;\n\t$this->edgeweight = $aWeight;\n    }\n\n    // Dummy function to make Pie3D behave in a similair way to 2D\n    function ShowBorder($exterior=true,$interior=true) {\n\tJpGraphError::RaiseL(14001);\n//('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.');\n    }\n\n    // Specify projection angle for 3D in degrees\n    // Must be between 20 and 70 degrees\n    function SetAngle($a) {\n\tif( $a<5 || $a>90 )\n\t    JpGraphError::RaiseL(14002);\n//(\"PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.\");\n\telse\n\t    $this->angle = $a;\n    }\n\n    function AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) {  //Slice number, ellipse centre (x,y), height, width, start angle, end angle\n\n\t$sa *= M_PI/180;\n\t$ea *= M_PI/180;\n\n\t//add coordinates of the centre to the map\n\t$coords = \"$xc, $yc\";\n\n\t//add coordinates of the first point on the arc to the map\n\t$xp = floor($width*cos($sa)/2+$xc);\n\t$yp = floor($yc-$height*sin($sa)/2);\n\t$coords.= \", $xp, $yp\";\n\n\t//If on the front half, add the thickness offset\n\tif ($sa >= M_PI && $sa <= 2*M_PI*1.01) {\n\t    $yp = floor($yp+$thick);\n\t    $coords.= \", $xp, $yp\";\n\t}\n\t\t\n\t//add coordinates every 0.2 radians\n\t$a=$sa+0.2;\n\twhile ($a<$ea) {\n\t    $xp = floor($width*cos($a)/2+$xc);\n\t    if ($a >= M_PI && $a <= 2*M_PI*1.01) {\n\t\t$yp = floor($yc-($height*sin($a)/2)+$thick);\n\t    } else {\n\t\t$yp = floor($yc-$height*sin($a)/2);\n\t    }\n\t    $coords.= \", $xp, $yp\";\n\t    $a += 0.2;\n\t}\n\t\t\n\t//Add the last point on the arc\n\t$xp = floor($width*cos($ea)/2+$xc);\n\t$yp = floor($yc-$height*sin($ea)/2);\n\n\n\tif ($ea >= M_PI && $ea <= 2*M_PI*1.01) {\n\t    $coords.= \", $xp, \".floor($yp+$thick);\n\t}\n\t$coords.= \", $xp, $yp\";\n\t$alt='';\n\tif( !empty($this->csimalts[$i]) ) {\t\t\t\t\t\t\t\t\t\t\n\t    $tmp=sprintf($this->csimalts[$i],$this->data[$i]);\n\t    $alt=\"alt=\\\"$tmp\\\" title=\\\"$tmp\\\"\";\n\t}\n\tif( !empty($this->csimtargets[$i]) )\n\t    $this->csimareas .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->csimtargets[$i].\"\\\" $alt />\\n\";\n    }\n\n    function SetLabels($aLabels,$aLblPosAdj=\"auto\") {\n\t$this->labels = $aLabels;\n\t$this->ilabelposadj=$aLblPosAdj;\n    }\n\n\t\n    // Distance from the pie to the labels\n    function SetLabelMargin($m) {\n\t$this->value->SetMargin($m);\n    }\n\t\n    // Show a thin line from the pie to the label for a specific slice\n    function ShowLabelHint($f=true) {\n\t$this->showlabelhint=$f;\n    }\n\t\n    // Set color of hint line to label for each slice\n    function SetLabelHintColor($c) {\n\t$this->labelhintcolor=$c;\n    }\n\n    function SetHeight($aHeight) {\n      $this->iThickness = $aHeight;\n    }\n\n\n// Normalize Angle between 0-360\n    function NormAngle($a) {\n\t// Normalize anle to 0 to 2M_PI\n\t// \n\tif( $a > 0 ) {\n\t    while($a > 360) $a -= 360;\n\t}\n\telse {\n\t    while($a < 0) $a += 360;\n\t}\n\tif( $a < 0 )\n\t    $a = 360 + $a;\n\n\tif( $a == 360 ) $a=0;\n\treturn $a;\n    }\n\n    \n\n// Draw one 3D pie slice at position ($xc,$yc) with height $z\n    function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) {\n\t\n\t// Due to the way the 3D Pie algorithm works we are\n\t// guaranteed that any slice we get into this method\n\t// belongs to either the left or right side of the\n\t// pie ellipse. Hence, no slice will cross 90 or 270\n\t// point.\n\tif( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) {\n\t    JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice');\n\t    exit(1);\n\t}\n\n\t$p[] = array();\n\n\t// Setup pre-calculated values\n\t$rsa = $sa/180*M_PI;\t// to Rad\n\t$rea = $ea/180*M_PI;\t// to Rad\n\t$sinsa = sin($rsa);\n\t$cossa = cos($rsa);\n\t$sinea = sin($rea);\n\t$cosea = cos($rea);\n\n\t// p[] is the points for the overall slice and\n\t// pt[] is the points for the top pie\n\n\t// Angular step when approximating the arc with a polygon train.\n\t$step = 0.05;\n\n\tif( $sa >= 270 ) {\n\t    if( $ea > 360 || ($ea > 0 && $ea <= 90) ) {\n\t\tif( $ea > 0 && $ea <= 90 ) {\n\t\t    // Adjust angle to simplify conditions in loops\n\t\t    $rea += 2*M_PI;\n\t\t}\n\n\t\t$p = array($xc,$yc,$xc,$yc+$z,\n\t\t\t   $xc+$w*$cossa,$z+$yc-$h*$sinsa);\n\t\t$pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);\n\n\t\tfor( $a=$rsa; $a < 2*M_PI; $a += $step ) {\n\t\t    $tca = cos($a);\n\t\t    $tsa = sin($a);\n\t\t    $p[] = $xc+$w*$tca;\n\t\t    $p[] = $z+$yc-$h*$tsa;\n\t\t    $pt[] = $xc+$w*$tca;\n\t\t    $pt[] = $yc-$h*$tsa;\n\t\t}\n\n\t\t$pt[] = $xc+$w;\n\t\t$pt[] = $yc;\n\n\t\t$p[] = $xc+$w;\n\t\t$p[] = $z+$yc;\n\t\t$p[] = $xc+$w;\n\t\t$p[] = $yc;\n\t\t$p[] = $xc;\n\t\t$p[] = $yc;\n\n\t\tfor( $a=2*M_PI+$step; $a < $rea; $a += $step ) {\n\t\t    $pt[] = $xc + $w*cos($a);\n\t\t    $pt[] = $yc - $h*sin($a);\n\t\t}\n\t\t    \n\t\t$pt[] = $xc+$w*$cosea;\n\t\t$pt[] = $yc-$h*$sinea;\n\t\t$pt[] = $xc;\n\t\t$pt[] = $yc;\n\n\t    }\n\t    else {\n\t\t$p = array($xc,$yc,$xc,$yc+$z,\n\t\t\t   $xc+$w*$cossa,$z+$yc-$h*$sinsa);\n\t\t$pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);\n\t\t    \n\t\t$rea = $rea == 0.0 ? 2*M_PI : $rea;\n\t\tfor( $a=$rsa; $a < $rea; $a += $step ) {\n\t\t    $tca = cos($a);\n\t\t    $tsa = sin($a);\n\t\t    $p[] = $xc+$w*$tca;\n\t\t    $p[] = $z+$yc-$h*$tsa;\n\t\t    $pt[] = $xc+$w*$tca;\n\t\t    $pt[] = $yc-$h*$tsa;\n\t\t}\n\n\t\t$pt[] = $xc+$w*$cosea;\n\t\t$pt[] = $yc-$h*$sinea;\n\t\t$pt[] = $xc;\n\t\t$pt[] = $yc;\n\t\t    \n\t\t$p[] = $xc+$w*$cosea;\n\t\t$p[] = $z+$yc-$h*$sinea;\n\t\t$p[] = $xc+$w*$cosea;\n\t\t$p[] = $yc-$h*$sinea;\n\t\t$p[] = $xc;\n\t\t$p[] = $yc;\n\t    }\n\t}\n\telseif( $sa >= 180 ) {\n\t    $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);\n\t    $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);\n\t\t\n\t    for( $a=$rea; $a>$rsa; $a -= $step ) {\n\t\t$tca = cos($a);\n\t\t$tsa = sin($a);\n\t\t$p[] = $xc+$w*$tca;\n\t\t$p[] = $z+$yc-$h*$tsa;\n\t\t$pt[] = $xc+$w*$tca;\n\t\t$pt[] = $yc-$h*$tsa;\n\t    }\n\n\t    $pt[] = $xc+$w*$cossa;\n\t    $pt[] = $yc-$h*$sinsa;\n\t    $pt[] = $xc;\n\t    $pt[] = $yc;\n\t\t\n\t    $p[] = $xc+$w*$cossa;\n\t    $p[] = $z+$yc-$h*$sinsa;\n\t    $p[] = $xc+$w*$cossa;\n\t    $p[] = $yc-$h*$sinsa;\n\t    $p[] = $xc;\n\t    $p[] = $yc;\n\t\n\t}\n\telseif( $sa >= 90 ) {\n\t    if( $ea > 180 ) {\n\t\t$p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);\n\t\t$pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);\n\n\t\tfor( $a=$rea; $a > M_PI; $a -= $step ) {\n\t\t    $tca = cos($a);\n\t\t    $tsa = sin($a);\t\t    \n\t\t    $p[] = $xc+$w*$tca;\n\t\t    $p[] = $z + $yc - $h*$tsa;\n\t\t    $pt[] = $xc+$w*$tca;\n\t\t    $pt[] = $yc-$h*$tsa;\n\t\t}\n\n\t\t$p[] = $xc-$w;\n\t\t$p[] = $z+$yc;\n\t\t$p[] = $xc-$w;\n\t\t$p[] = $yc;\n\t\t$p[] = $xc;\n\t\t$p[] = $yc;\n\n\t\t$pt[] = $xc-$w;\n\t\t$pt[] = $z+$yc;\n\t\t$pt[] = $xc-$w;\n\t\t$pt[] = $yc;\n\n\t\tfor( $a=M_PI-$step; $a > $rsa; $a -= $step ) {\n\t\t    $pt[] = $xc + $w*cos($a);\n\t\t    $pt[] = $yc - $h*sin($a);\n\t\t}\n\n\t\t$pt[] = $xc+$w*$cossa;\n\t\t$pt[] = $yc-$h*$sinsa;\n\t\t$pt[] = $xc;\n\t\t$pt[] = $yc;\n\n\t    }\n\t    else { // $sa >= 90 && $ea <= 180\n\t\t$p = array($xc,$yc,$xc,$yc+$z,\n\t\t\t   $xc+$w*$cosea,$z+$yc-$h*$sinea,\n\t\t\t   $xc+$w*$cosea,$yc-$h*$sinea,\n\t\t\t   $xc,$yc);\n\n\t\t$pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);\n\n\t\tfor( $a=$rea; $a>$rsa; $a -= $step ) {\n\t\t    $pt[] = $xc + $w*cos($a);\n\t\t    $pt[] = $yc - $h*sin($a);\n\t\t}\n\n\t\t$pt[] = $xc+$w*$cossa;\n\t\t$pt[] = $yc-$h*$sinsa;\n\t\t$pt[] = $xc;\n\t\t$pt[] = $yc;\n\n\t    }\n\t}\n\telse { // sa > 0 && ea < 90\n\n\t    $p = array($xc,$yc,$xc,$yc+$z,\n\t\t       $xc+$w*$cossa,$z+$yc-$h*$sinsa,\n\t\t       $xc+$w*$cossa,$yc-$h*$sinsa,\n\t\t       $xc,$yc);\n\n\t    $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);\n\n\t    for( $a=$rsa; $a < $rea; $a += $step ) {\n\t\t$pt[] = $xc + $w*cos($a);\n\t\t$pt[] = $yc - $h*sin($a);\n\t    }\n\n\t    $pt[] = $xc+$w*$cosea;\n\t    $pt[] = $yc-$h*$sinea;\n\t    $pt[] = $xc;\n\t    $pt[] = $yc;\n\t}\n\t    \n\t$img->PushColor($fillcolor.\":\".$shadow);\n\t$img->FilledPolygon($p);\n\t$img->PopColor();\n\n\t$img->PushColor($fillcolor);\n\t$img->FilledPolygon($pt);\n\t$img->PopColor();\n    }\n\n    function SetStartAngle($aStart) {\n\tif( $aStart < 0 || $aStart > 360 ) {\n\t    JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.');\n\t}\n\t$this->startangle = $aStart;\n    }\n    \n// Draw a 3D Pie\n    function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z,\n\t\t   $shadow=0.65,$startangle=0,$edgecolor=\"\",$edgeweight=1) {\n\n\t//---------------------------------------------------------------------------\n\t// As usual the algorithm get more complicated than I originally\n\t// envisioned. I believe that this is as simple as it is possible\n\t// to do it with the features I want. It's a good exercise to start\n\t// thinking on how to do this to convince your self that all this\n\t// is really needed for the general case.\n\t//\n\t// The algorithm two draw 3D pies without \"real 3D\" is done in\n\t// two steps.\n\t// First imagine the pie cut in half through a thought line between\n\t// 12'a clock and 6'a clock. It now easy to imagine that we can plot \n\t// the individual slices for each half by starting with the topmost\n\t// pie slice and continue down to 6'a clock.\n\t// \n\t// In the algortithm this is done in three principal steps\n\t// Step 1. Do the knife cut to ensure by splitting slices that extends \n\t// over the cut line. This is done by splitting the original slices into\n\t// upto 3 subslices.\n\t// Step 2. Find the top slice for each half\n\t// Step 3. Draw the slices from top to bottom\n\t//\n\t// The thing that slightly complicates this scheme with all the\n\t// angle comparisons below is that we can have an arbitrary start\n\t// angle so we must take into account the different equivalence classes.\n\t// For the same reason we must walk through the angle array in a \n\t// modulo fashion.\n\t//\n\t// Limitations of algorithm: \n\t// * A small exploded slice which crosses the 270 degree point\n\t//   will get slightly nagged close to the center due to the fact that\n\t//   we print the slices in Z-order and that the slice left part\n\t//   get printed first and might get slightly nagged by a larger\n\t//   slice on the right side just before the right part of the small\n\t//   slice. Not a major problem though. \n\t//---------------------------------------------------------------------------\n\n    \n\t// Determine the height of the ellippse which gives an\n\t// indication of the inclination angle\n\t$h = ($angle/90.0)*$d;\n\t$sum = 0;\n\tfor($i=0; $i<count($data); ++$i ) {\n\t    $sum += $data[$i];\n\t}\n\t\n\t// Special optimization\n\tif( $sum==0 ) return;\n\n\tif( $this->labeltype == 2 ) {\n\t    $this->adjusted_data = $this->AdjPercentage($data);\n\t}\n\n\t// Setup the start\n\t$accsum = 0;\n\t$a = $startangle;\n\t$a = $this->NormAngle($a);\n\n\t// \n\t// Step 1 . Split all slices that crosses 90 or 270\n\t//\n\t$idx=0;\n\t$adjexplode=array(); \n\t$numcolors = count($colors);\n\tfor($i=0; $i<count($data); ++$i, ++$idx ) {\n\t    $da = $data[$i]/$sum * 360;\n\n\t    if( empty($this->explode_radius[$i]) )\n\t\t$this->explode_radius[$i]=0;\n\n\t    $expscale=1;\n\t    if( $aaoption == 1 ) \n\t\t$expscale=2;\n\n\t    $la = $a + $da/2;\n\t    $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale,\n\t\t              $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale );\n\t    $adjexplode[$idx] = $explode;\n\t    $labeldata[$i] = array($la,$explode[0],$explode[1]);\n\t    $originalangles[$i] = array($a,$a+$da);\n\n\t    $ne = $this->NormAngle($a+$da);\n\t    if( $da <= 180 ) {\n\t\t// If the slice size is <= 90 it can at maximum cut across\n\t\t// one boundary (either 90 or 270) where it needs to be split\n\t\t$split=-1; // no split\n\t\tif( ($da<=90 && ($a <= 90 && $ne > 90)) ||\n\t\t    (($da <= 180 && $da >90)  && (($a < 90 || $a >= 270) && $ne > 90)) ) {\n\t\t    $split = 90;\n\t\t}\n\t\telseif( ($da<=90 && ($a <= 270 && $ne > 270)) ||\n\t\t        (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) {\n\t\t    $split = 270;\n\t\t} \n\t\tif( $split > 0 ) { // split in two\n\t\t    $angles[$idx] = array($a,$split);\n\t\t    $adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\n\t\t    $angles[++$idx] = array($split,$ne);\n\t\t    $adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\n\t\t}\n\t\telse { // no split\n\t\t    $angles[$idx] = array($a,$ne);\n\t\t    $adjcolors[$idx] = $colors[$i  % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\t\n\t\t}\n\t    }\n\t    else { \n\t\t// da>180\n\t\t// Slice may, depending on position, cross one or two\n\t\t// bonudaries\n\n\t\tif( $a < 90 ) \n\t\t    $split = 90;\n\t\telseif( $a <= 270 )\n\t\t    $split = 270;\n\t\telse \n\t\t    $split = 90;\n\n\t\t$angles[$idx] = array($a,$split);\n\t\t$adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t$adjexplode[$idx] = $explode;\n\t\t//if( $a+$da > 360-$split ) { \n\t\t// For slices larger than 270 degrees we might cross\n\t\t// another boundary as well. This means that we must\n\t\t// split the slice further. The comparison gets a little\n\t\t// bit complicated since we must take into accound that\n\t\t// a pie might have a startangle >0 and hence a slice might\n\t\t// wrap around the 0 angle.\n\t\t// Three cases:\n\t\t//  a) Slice starts before 90 and hence gets a split=90, but \n\t\t//     we must also check if we need to split at 270\n\t\t//  b) Slice starts after 90 but before 270 and slices\n\t\t//     crosses 90 (after a wrap around of 0)\n\t\t//  c) If start is > 270 (hence the firstr split is at 90)\n\t\t//     and the slice is so large that it goes all the way\n\t\t//     around 270.\n\t\tif( ($a < 90 && ($a+$da > 270)) ||\n\t\t    ($a > 90 && $a<=270 && ($a+$da>360+90) ) ||\n\t\t    ($a > 270 && $this->NormAngle($a+$da)>270) ) { \n\t\t    $angles[++$idx] = array($split,360-$split);\n\t\t    $adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\n\t\t    $angles[++$idx] = array(360-$split,$ne);\n\t\t    $adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\n\t\t}\t\n\t\telse {\n\t\t    // Just a simple split to the previous decided\n\t\t    // angle.\n\t\t    $angles[++$idx] = array($split,$ne);\n\t\t    $adjcolors[$idx] = $colors[$i % $numcolors];\n\t\t    $adjexplode[$idx] = $explode;\n\t\t}\n\t    }\n\t    $a += $da;\n\t    $a = $this->NormAngle($a);\n\t}\n\n\t// Total number of slices \n\t$n = count($angles);\n\n\tfor($i=0; $i<$n; ++$i) {\n\t    list($dbgs,$dbge) = $angles[$i];\n\t}\n\n\t// \n\t// Step 2. Find start index (first pie that starts in upper left quadrant)\n\t//\n\t$minval = $angles[0][0];\n\t$min = 0;\n\tfor( $i=0; $i<$n; ++$i ) {\n\t    if( $angles[$i][0] < $minval ) {\n\t\t$minval = $angles[$i][0];\n\t\t$min = $i;\n\t    }\n\t}\n\t$j = $min;\n\t$cnt = 0;\n\twhile( $angles[$j][1] <= 90 ) {\n\t    $j++;\n\t    if( $j>=$n) {\n\t\t$j=0;\n\t    }\n\t    if( $cnt > $n ) {\n\t\tJpGraphError::RaiseL(14005);\n//(\"Pie3D Internal error (#1). Trying to wrap twice when looking for start index\");\n\t    }\n\t    ++$cnt;\n\t}\n\t$start = $j;\n\n\t// \n\t// Step 3. Print slices in z-order\n\t//\n\t$cnt = 0;\n\t\n\t// First stroke all the slices between 90 and 270 (left half circle)\n\t// counterclockwise\n\t    \n\twhile( $angles[$j][0] < 270  && $aaoption !== 2 ) {\n\n\t    list($x,$y) = $adjexplode[$j];\n\n\t    $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],\n\t\t\t      $z,$adjcolors[$j],$shadow);\n\t\n\t    $last = array($x,$y,$j);\n\n\t    $j++;\n\t    if( $j >= $n ) $j=0;\n\t    if( $cnt > $n ) {\n\t\tJpGraphError::RaiseL(14006);\n//(\"Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.\");\n\t    }\n\t    ++$cnt;\n\t}\n     \n\t$slice_left = $n-$cnt;\n\t$j=$start-1;\n\tif($j<0) $j=$n-1;\n\t$cnt = 0;\n\t\n\t// The stroke all slices from 90 to -90 (right half circle)\n\t// clockwise\n\twhile( $cnt < $slice_left  && $aaoption !== 2 ) {\n\n\t    list($x,$y) = $adjexplode[$j];\n\n\t    $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],\n\t\t\t      $z,$adjcolors[$j],$shadow);\n\t    $j--;\n\t    if( $cnt > $n ) {\n\t\tJpGraphError::RaiseL(14006);\n//(\"Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.\");\n\t    }\n\t    if($j<0) $j=$n-1;\n\t    $cnt++;\n\t}\n\t\n\t// Now do a special thing. Stroke the last slice on the left\n\t// halfcircle one more time.  This is needed in the case where \n\t// the slice close to 270 have been exploded. In that case the\n\t// part of the slice close to the center of the pie might be \n\t// slightly nagged.\n\tif( $aaoption !== 2 )\n\t    $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0],\n\t\t\t      $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow);\n\n\n\tif( $aaoption !== 1 ) {\n\t    // Now print possible labels and add csim\n\t    $img->SetFont($this->value->ff,$this->value->fs);\n\t    $margin = $img->GetFontHeight()/2 + $this->value->margin ;\n\t    for($i=0; $i < count($data); ++$i ) {\n\t\t$la = $labeldata[$i][0];\n\t\t$x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin);\n\t\t$y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin);\n\t\tif( $la > 180 && $la < 360 ) $y += $z;\n\t\tif( $this->labeltype == 0 ) {\n\t\t    if( $sum > 0 )\n\t\t\t$l = 100*$data[$i]/$sum;\n\t\t    else\n\t\t\t$l = 0;\n\t\t}\n\t\telseif( $this->labeltype == 1 ) {\n\t\t    $l = $data[$i];\n\t\t}\n\t\telse {\n\t\t    $l = $this->adjusted_data[$i];\n\t\t}\n\t\tif( isset($this->labels[$i]) && is_string($this->labels[$i]) )\n\t\t    $l=sprintf($this->labels[$i],$l);\n\n\t\t$this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z);\n\t    \n\t\t$this->AddSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z,\n\t\t\t\t      $originalangles[$i][0],$originalangles[$i][1]);\n\t    }\t\n\t}\n\n\t// \n\t// Finally add potential lines in pie\n\t//\n\n\tif( $edgecolor==\"\" || $aaoption !== 0 ) return;\n\n\t$accsum = 0;\n\t$a = $startangle;\n\t$a = $this->NormAngle($a);\n\n\t$a *= M_PI/180.0;\n\n\t$idx=0;\n\t$img->PushColor($edgecolor);\n\t$img->SetLineWeight($edgeweight);\n\t\n\t$fulledge = true;\n\tfor($i=0; $i < count($data) && $fulledge; ++$i ) {\n\t    if( empty($this->explode_radius[$i]) )\n\t\t$this->explode_radius[$i]=0;\n\t    if( $this->explode_radius[$i] > 0 ) {\n\t\t$fulledge = false;\n\t    }\n\t}\n\t    \n\n\tfor($i=0; $i < count($data); ++$i, ++$idx ) {\n\n\t    $da = $data[$i]/$sum * 2*M_PI;\n\t    $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor,\n\t\t\t\t\t$this->explode_radius[$i],$fulledge);\n\t    $a += $da;\n\t}\n\t$img->PopColor();\n    }\n\n    function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) {\n\t$step = 0.02;\n\n\tif( $exploderadius > 0 ) {\n\t    $la = ($sa+$ea)/2;\n\t    $xc += $exploderadius*cos($la);\n\t    $yc -= $exploderadius*sin($la) * ($h/$w) ;\n\t    \n\t}\n\n\t$p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa));\n\n\tfor($a=$sa; $a < $ea; $a += $step ) {\n\t    $p[] = $xc + $w*cos($a);\n\t    $p[] = $yc - $h*sin($a);\n\t}\n\n\t$p[] = $xc+$w*cos($ea);\n\t$p[] = $yc-$h*sin($ea);\n\t$p[] = $xc;\n\t$p[] = $yc;\n\n\t$img->SetColor($edgecolor);\n\t$img->Polygon($p);\n\n\t// Unfortunately we can't really draw the full edge around the whole of\n\t// of the slice if any of the slices are exploded. The reason is that\n\t// this algorithm is to simply. There are cases where the edges will\n\t// \"overwrite\" other slices when they have been exploded.\n\t// Doing the full, proper 3D hidden lines stiff is actually quite\n\t// tricky. So for exploded pies we only draw the top edge. Not perfect\n\t// but the \"real\" solution is much more complicated.\n\tif( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) { \n\n\t    if($sa < M_PI && $ea > M_PI) \n\t\t$sa = M_PI;\n \n\t    if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) )\n\t\t$ea = 2*M_PI;\n\n\t    if( $sa >= M_PI && $ea <= 2*M_PI ) {\n\t\t$p = array($xc + $w*cos($sa),$yc - $h*sin($sa),\n\t\t\t   $xc + $w*cos($sa),$z + $yc - $h*sin($sa));\n\t\t\n\t\tfor($a=$sa+$step; $a < $ea; $a += $step ) {\n\t\t    $p[] = $xc + $w*cos($a);\n\t\t    $p[] = $z + $yc - $h*sin($a);\n\t\t}\n\t\t$p[] = $xc + $w*cos($ea);\n\t\t$p[] = $z + $yc - $h*sin($ea);\n\t\t$p[] = $xc + $w*cos($ea);\n\t\t$p[] = $yc - $h*sin($ea);\n\t\t$img->SetColor($edgecolor);\n\t\t$img->Polygon($p);\t    \n\t    }\n\t}\n    }\n\n    function Stroke($img,$aaoption=0) {\n\t$n = count($this->data);\n\n\t// If user hasn't set the colors use the theme array\n   \tif( $this->setslicecolors==null ) {\n\t    $colors = array_keys($img->rgb->rgb_table);\n\t    sort($colors);\t\n\t    $idx_a=$this->themearr[$this->theme];\t\n\t    $ca = array();\n\t    $m = count($idx_a);\n\t    for($i=0; $i < $m; ++$i)\n\t\t$ca[$i] = $colors[$idx_a[$i]];\n\t    $ca = array_reverse(array_slice($ca,0,$n));\n\t}\n   \telse {\n\t    $ca = $this->setslicecolors;\n\t}\n\t\n\n\tif( $this->posx <= 1 && $this->posx > 0 )\n\t    $xc = round($this->posx*$img->width);\n\telse\n\t    $xc = $this->posx ;\n\t\n\tif( $this->posy <= 1 && $this->posy > 0 )\n\t    $yc = round($this->posy*$img->height);\n\telse\n\t    $yc = $this->posy ;\n   \t\t\t\n\tif( $this->radius <= 1 ) {\n\t    $width = floor($this->radius*min($img->width,$img->height));\n\t    // Make sure that the pie doesn't overflow the image border\n\t    // The 0.9 factor is simply an extra margin to leave some space\n\t    // between the pie an the border of the image.\n\t    $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9));\n\t}\n\telse {\n\t    $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ;\n\t}\n\n\t// Add a sanity check for width\n\tif( $width < 1 ) { \n\t    JpGraphError::RaiseL(14007);//(\"Width for 3D Pie is 0. Specify a size > 0\");\n\t}\n\n\t// Establish a thickness. By default the thickness is a fifth of the\n\t// pie slice width (=pie radius) but since the perspective depends\n\t// on the inclination angle we use some heuristics to make the edge\n\t// slightly thicker the less the angle.\n\t\n\t// Has user specified an absolute thickness? In that case use\n\t// that instead\n\n\tif( $this->iThickness ) {\n\t  $thick = $this->iThickness;\n\t  $thick *= ($aaoption === 1 ? 2 : 1 );\n\t}\n\telse\n\t  $thick = $width/12;\n\t$a = $this->angle;\n\tif( $a <= 30 ) $thick *= 1.6;\n\telseif( $a <= 40 ) $thick *= 1.4;\n\telseif( $a <= 50 ) $thick *= 1.2;\n\telseif( $a <= 60 ) $thick *= 1.0;\n\telseif( $a <= 70 ) $thick *= 0.8;\n\telseif( $a <= 80 ) $thick *= 0.7;\n\telse $thick *= 0.6;\n\n\t$thick = floor($thick);\n\n\tif( $this->explode_all )\n\t    for($i=0; $i < $n; ++$i)\n\t\t$this->explode_radius[$i]=$this->explode_r;\n\n\t$this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle, \n\t             $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight);\n\n\t// Adjust title position\n\tif( $aaoption != 1 ) {\n\t    $this->title->Pos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin,\t\t\t      \"center\",\"bottom\");\n\t    $this->title->Stroke($img);\n\t}\n    }\n\n//---------------\n// PRIVATE METHODS\t\n\n    // Position the labels of each slice\n    function StrokeLabels($label,$img,$a,$xp,$yp,$z) {\n\t$this->value->halign=\"left\";\n\t$this->value->valign=\"top\";\n\n\t// Position the axis title. \n\t// dx, dy is the offset from the top left corner of the bounding box that sorrounds the text\n\t// that intersects with the extension of the corresponding axis. The code looks a little\n\t// bit messy but this is really the only way of having a reasonable position of the\n\t// axis titles.\n\t$img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize);\n\t$h=$img->GetTextHeight($label);\n\t// For numeric values the format of the display value\n\t// must be taken into account\n\tif( is_numeric($label) ) {\n\t    if( $label >= 0 )\n\t\t$w=$img->GetTextWidth(sprintf($this->value->format,$label));\n\t    else\n\t\t$w=$img->GetTextWidth(sprintf($this->value->negformat,$label));\n\t}\n\telse\n\t    $w=$img->GetTextWidth($label);\n\twhile( $a > 2*M_PI ) $a -= 2*M_PI;\n\tif( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;\n\tif( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; \n\tif( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;\n\tif( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);\n\t\t\n\tif( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;\n\tif( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);\n\tif( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;\n\tif( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);\n\tif( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;\n\t\n\t$x = round($xp-$dx*$w);\n\t$y = round($yp-$dy*$h);\n\n\t\n        // Mark anchor point for debugging \n\t/*\n\t$img->SetColor('red');\n\t$img->Line($xp-10,$yp,$xp+10,$yp);\n\t$img->Line($xp,$yp-10,$xp,$yp+10);\n\t*/\n\t$oldmargin = $this->value->margin;\n\t$this->value->margin=0;\n\t$this->value->Stroke($img,$label,$x,$y);\n\t$this->value->margin=$oldmargin;\n\n    }\t\n} // Class\n\n/* EOF */\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_plotband.php",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_PLOTBAND.PHP\n// Description:\tPHP4 Graph Plotting library. Extension module.\n// Created: \t2004-02-18\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_plotband.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n// Constants for types of static bands in plot area\nDEFINE(\"BAND_RDIAG\",1);\t// Right diagonal lines\nDEFINE(\"BAND_LDIAG\",2); // Left diagonal lines\nDEFINE(\"BAND_SOLID\",3); // Solid one color\nDEFINE(\"BAND_VLINE\",4); // Vertical lines\nDEFINE(\"BAND_HLINE\",5);  // Horizontal lines\nDEFINE(\"BAND_3DPLANE\",6);  // \"3D\" Plane\nDEFINE(\"BAND_HVCROSS\",7);  // Vertical/Hor crosses\nDEFINE(\"BAND_DIAGCROSS\",8); // Diagonal crosses\n\n\n// Utility class to hold coordinates for a rectangle\nclass Rectangle {\n    var $x,$y,$w,$h;\n    var $xe, $ye;\n    function Rectangle($aX,$aY,$aWidth,$aHeight) {\n\t$this->x=$aX;\n\t$this->y=$aY;\n\t$this->w=$aWidth;\n\t$this->h=$aHeight;\n\t$this->xe=$aX+$aWidth-1;\n\t$this->ye=$aY+$aHeight-1;\n    }\n}\n\n//=====================================================================\n// Class RectPattern\n// Base class for pattern hierarchi that is used to display patterned\n// bands on the graph. Any subclass that doesn't override Stroke()\n// must at least implement method DoPattern(&$aImg) which is responsible\n// for drawing the pattern onto the graph.\n//=====================================================================\nclass RectPattern {\n    var $color;\n    var $weight;\n    var $rect=null;\n    var $doframe=true;\n    var $linespacing;\t// Line spacing in pixels\n    var $iBackgroundColor=-1;  // Default is no background fill\n\t\n    function RectPattern($aColor,$aWeight=1) {\n\t$this->color = $aColor;\n\t$this->weight = $aWeight;\t\t\n    }\n\n    function SetBackground($aBackgroundColor) {\n\t$this->iBackgroundColor=$aBackgroundColor;\n    }\n\n    function SetPos(&$aRect) {\n\t$this->rect = $aRect;\n    }\n\t\n    function ShowFrame($aShow=true) {\n\t$this->doframe=$aShow;\n    }\n\n    function SetDensity($aDens) {\n\tif( $aDens < 1 || $aDens > 100 )\n\t    JpGraphError::RaiseL(16001,$aDens);\n//(\" Desity for pattern must be between 1 and 100. (You tried $aDens)\");\n\t// 1% corresponds to linespacing=50\n\t// 100 % corresponds to linespacing 1\n\t$this->linespacing = floor(((100-$aDens)/100.0)*50)+1;\n\n    }\n\n    function Stroke(&$aImg) {\n\tif( $this->rect == null )\n\t    JpGraphError::RaiseL(16002);\n//(\" No positions specified for pattern.\");\n\n\tif( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) {\n\t    $aImg->SetColor($this->iBackgroundColor);\n\t    $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); \n\t}\n\n\t$aImg->SetColor($this->color);\n\t$aImg->SetLineWeight($this->weight);\n\n\t// Virtual function implemented by subclass\n\t$this->DoPattern($aImg);\n\n\t// Frame around the pattern area\n\tif( $this->doframe ) \n\t    $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye);\n    }\n\n}\n\n\n//=====================================================================\n// Class RectPatternSolid\n// Implements a solid band\n//=====================================================================\nclass RectPatternSolid extends RectPattern {\n\n    function RectPatternSolid($aColor=\"black\",$aWeight=1) {\n\tparent::RectPattern($aColor,$aWeight);\n    }\n\n    function DoPattern(&$aImg) {\n\t$aImg->SetColor($this->color);\n\t$aImg->FilledRectangle($this->rect->x,$this->rect->y,\n\t\t\t       $this->rect->xe,$this->rect->ye);\n    }\n}\n\n//=====================================================================\n// Class RectPatternHor\n// Implements horizontal line pattern\n//=====================================================================\nclass RectPatternHor extends RectPattern {\n\t\t\n    function RectPatternHor($aColor=\"black\",$aWeight=1,$aLineSpacing=7) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->linespacing = $aLineSpacing;\n    }\n\t\t\n    function DoPattern(&$aImg) {\n\t$x0 = $this->rect->x;\t\t\n\t$x1 = $this->rect->xe;\n\t$y = $this->rect->y;\n\twhile( $y < $this->rect->ye ) {\n\t    $aImg->Line($x0,$y,$x1,$y);\n\t    $y += $this->linespacing;\n\t}\n    }\n}\n\n//=====================================================================\n// Class RectPatternVert\n// Implements vertical line pattern\n//=====================================================================\nclass RectPatternVert extends RectPattern {\n    var $linespacing=10;\t// Line spacing in pixels\n\t\t\n    function RectPatternVert($aColor=\"black\",$aWeight=1,$aLineSpacing=7) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->linespacing = $aLineSpacing;\n    }\n\n    //--------------------\n    // Private methods\n    //\n    function DoPattern(&$aImg) {\n\t$x = $this->rect->x;\t\t\n\t$y0 = $this->rect->y;\n\t$y1 = $this->rect->ye;\n\twhile( $x < $this->rect->xe ) {\n\t    $aImg->Line($x,$y0,$x,$y1);\n\t    $x += $this->linespacing;\n\t}\n    }\n}\n\n\n//=====================================================================\n// Class RectPatternRDiag\n// Implements right diagonal pattern\n//=====================================================================\nclass RectPatternRDiag extends RectPattern {\n    var $linespacing;\t// Line spacing in pixels\n\t\t\n    function RectPatternRDiag($aColor=\"black\",$aWeight=1,$aLineSpacing=12) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->linespacing = $aLineSpacing;\n    }\n\n    function DoPattern(&$aImg) {\n\t//  --------------------\n\t//  | /   /   /   /   /|\n\t//  |/   /   /   /   / |\n\t//  |   /   /   /   /  |\n\t//  --------------------\n\t$xe = $this->rect->xe;\n\t$ye = $this->rect->ye;\n\t$x0 = $this->rect->x + round($this->linespacing/2); \n\t$y0 = $this->rect->y;\n\t$x1 = $this->rect->x; \n\t$y1 = $this->rect->y + round($this->linespacing/2);\n\n\twhile($x0<=$xe && $y1<=$ye) {\n\t    $aImg->Line($x0,$y0,$x1,$y1);\n\t    $x0 += $this->linespacing;\n\t    $y1 += $this->linespacing;\n\t}\n\n\tif( $xe-$x1 > $ye-$y0 ) { \n\t    // Width larger than height\n\t    $x1 = $this->rect->x + ($y1-$ye);\n\t    $y1 = $ye; \n\t    $y0 = $this->rect->y; \n\t    while( $x0 <= $xe ) {\n\t\t$aImg->Line($x0,$y0,$x1,$y1);\n\t\t$x0 += $this->linespacing;\n\t\t$x1 += $this->linespacing;\n\t    }\n\t    \n\t    $y0=$this->rect->y + ($x0-$xe);\n\t    $x0=$xe;\n\t}\n\telse {\n\t    // Height larger than width\n\t    $diff = $x0-$xe;\n\t    $y0 = $diff+$this->rect->y;\n\t    $x0 = $xe;\n\t    $x1 = $this->rect->x;\n\t    while( $y1 <= $ye ) {\n\t\t$aImg->Line($x0,$y0,$x1,$y1);\n\t\t$y1 += $this->linespacing;\n\t\t$y0 += $this->linespacing;\n\t    }\n\t    \n\t    $diff = $y1-$ye;\n\t    $y1 = $ye;\n\t    $x1 = $diff + $this->rect->x;\n\t}\n\n\twhile( $y0 <= $ye ) {\n\t    $aImg->Line($x0,$y0,$x1,$y1);\n\t    $y0 += $this->linespacing;\t\t\n\t    $x1 += $this->linespacing;\n\t}\n    }\n}\n \n//=====================================================================\n// Class RectPatternLDiag\n// Implements left diagonal pattern\n//=====================================================================\nclass RectPatternLDiag extends RectPattern {\n    var $linespacing;\t// Line spacing in pixels\n\t\t\n    function RectPatternLDiag($aColor=\"black\",$aWeight=1,$aLineSpacing=12) {\n\t$this->linespacing = $aLineSpacing;\n\tparent::RectPattern($aColor,$aWeight);\n    }\n\n    function DoPattern(&$aImg) {\n\t//  --------------------\n\t//  |\\   \\   \\   \\   \\ |\n\t//  | \\   \\   \\   \\   \\|\n\t//  |  \\   \\   \\   \\   |\n\t//  |------------------|\n\t$xe = $this->rect->xe;\n\t$ye = $this->rect->ye;\n\t$x0 = $this->rect->x + round($this->linespacing/2); \n\t$y0 = $this->rect->ye;\n\t$x1 = $this->rect->x; \n\t$y1 = $this->rect->ye - round($this->linespacing/2);\n\n\twhile($x0<=$xe && $y1>=$this->rect->y) {\n\t    $aImg->Line($x0,$y0,$x1,$y1);\n\t    $x0 += $this->linespacing;\n\t    $y1 -= $this->linespacing;\n\t}\n\tif( $xe-$x1 > $ye-$this->rect->y ) { \n\t    // Width larger than height\n\t    $x1 = $this->rect->x + ($this->rect->y-$y1);\n\t    $y0=$ye; $y1=$this->rect->y; \n\t    while( $x0 <= $xe ) {\n\t\t$aImg->Line($x0,$y0,$x1,$y1);\n\t\t$x0 += $this->linespacing;\n\t\t$x1 += $this->linespacing;\n\t    }\n\t    \n\t    $y0=$this->rect->ye - ($x0-$xe);\n\t    $x0=$xe;\n\t}\n\telse {\n\t    // Height larger than width\n\t    $diff = $x0-$xe;\n\t    $y0 = $ye-$diff;\n\t    $x0 = $xe;\n\t    while( $y1 >= $this->rect->y ) {\n\t\t$aImg->Line($x0,$y0,$x1,$y1);\n\t\t$y0 -= $this->linespacing;\n\t\t$y1 -= $this->linespacing;\n\t    }\t    \n\t    $diff = $this->rect->y - $y1;\n\t    $x1 = $this->rect->x + $diff;\n\t    $y1 = $this->rect->y;\n\t}\n\twhile( $y0 >= $this->rect->y ) {\n\t    $aImg->Line($x0,$y0,$x1,$y1);\n\t    $y0 -= $this->linespacing;\n\t    $x1 += $this->linespacing;\n\t}\n    }\n}\n\n//=====================================================================\n// Class RectPattern3DPlane\n// Implements \"3D\" plane pattern\n//=====================================================================\nclass RectPattern3DPlane extends RectPattern {\n    var $alpha=50;  // Parameter that specifies the distance\n    // to \"simulated\" horizon in pixel from the\n    // top of the band. Specifies how fast the lines\n    // converge.\n\n    function RectPattern3DPlane($aColor=\"black\",$aWeight=1) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->SetDensity(10);  // Slightly larger default\n    }\n\n    function SetHorizon($aHorizon) {\n\t$this->alpha=$aHorizon;\n    }\n\t\n    function DoPattern(&$aImg) {\n\t// \"Fake\" a nice 3D grid-effect. \n\t$x0 = $this->rect->x + $this->rect->w/2;\n\t$y0 = $this->rect->y;\n\t$x1 = $x0;\n\t$y1 = $this->rect->ye;\n\t$x0_right = $x0;\n\t$x1_right = $x1;\n\n\t// BTW \"apa\" means monkey in Swedish but is really a shortform for\n\t// \"alpha+a\" which was the labels I used on paper when I derived the\n\t// geometric to get the 3D perspective right. \n\t// $apa is the height of the bounding rectangle plus the distance to the\n\t// artifical horizon (alpha)\n\t$apa = $this->rect->h + $this->alpha;\n\n\t// Three cases and three loops\n\t// 1) The endpoint of the line ends on the bottom line\n\t// 2) The endpoint ends on the side\n\t// 3) Horizontal lines\n\n\t// Endpoint falls on bottom line\n\t$middle=$this->rect->x + $this->rect->w/2;\n\t$dist=$this->linespacing;\n\t$factor=$this->alpha /($apa);\n\twhile($x1>$this->rect->x) {\n\t    $aImg->Line($x0,$y0,$x1,$y1);\n\t    $aImg->Line($x0_right,$y0,$x1_right,$y1);\n\t    $x1 = $middle - $dist;\n\t    $x0 = $middle - $dist * $factor;\n\t    $x1_right = $middle + $dist;\n\t    $x0_right =  $middle + $dist * $factor;\n\t    $dist += $this->linespacing;\n\t}\n\n\t// Endpoint falls on sides\n\t$dist -= $this->linespacing;\n\t$d=$this->rect->w/2;\n\t$c = $apa - $d*$apa/$dist;\n\twhile( $x0>$this->rect->x ) {\n\t    $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c);\n\t    $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c);\n\t    $dist += $this->linespacing;\t\t\t\n\t    $x0 = $middle - $dist * $factor;\n\t    $x1 = $middle - $dist;\n\t    $x0_right =  $middle + $dist * $factor;\t\t\t\n\t    $c = $apa - $d*$apa/$dist;\n\t}\t\t\n\t\t\n\t// Horizontal lines\n\t// They need some serious consideration since they are a function\n\t// of perspective depth (alpha) and density (linespacing)\n\t$x0=$this->rect->x;\n\t$x1=$this->rect->xe;\n\t$y=$this->rect->ye;\n\t\t\n\t// The first line is drawn directly. Makes the loop below slightly\n\t// more readable.\n\t$aImg->Line($x0,$y,$x1,$y);\n\t$hls = $this->linespacing;\n\t\t\n\t// A correction factor for vertical \"brick\" line spacing to account for\n\t// a) the difference in number of pixels hor vs vert\n\t// b) visual apperance to make the first layer of \"bricks\" look more\n\t// square.\n\t$vls = $this->linespacing*0.6;\n\t\t\n\t$ds = $hls*($apa-$vls)/$apa;\n\t// Get the slope for the \"perspective line\" going from bottom right\n\t// corner to top left corner of the \"first\" brick.\n\t\t\n\t// Uncomment the following lines if you want to get a visual understanding\n\t// of what this helpline does. BTW this mimics the way you would get the\n\t// perspective right when drawing on paper.\n\t/*\n\t  $x0 = $middle;\n\t  $y0 = $this->rect->ye;\n\t  $len=floor(($this->rect->ye-$this->rect->y)/$vls);\n\t  $x1 = $middle+round($len*$ds);\n\t  $y1 = $this->rect->ye-$len*$vls;\n\t  $aImg->PushColor(\"red\");\n\t  $aImg->Line($x0,$y0,$x1,$y1);\n\t  $aImg->PopColor();\n\t*/\n\t\t\n\t$y -= $vls;\t\t\n\t$k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds));\n\t$dist = $hls;\n\twhile( $y>$this->rect->y ) {\n\t    $aImg->Line($this->rect->x,$y,$this->rect->xe,$y);\n\t    $adj = $k*$dist/(1+$dist*$k/$apa);\n\t    if( $adj < 2 ) $adj=1;\n\t    $y = $this->rect->ye - round($adj);\n\t    $dist += $hls;\n\t}\n    }\n}\n\n//=====================================================================\n// Class RectPatternCross\n// Vert/Hor crosses\n//=====================================================================\nclass RectPatternCross extends RectPattern {\n    var $vert=null;\n    var $hor=null;\n    function RectPatternCross($aColor=\"black\",$aWeight=1) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->vert = new RectPatternVert($aColor,$aWeight);\n\t$this->hor  = new RectPatternHor($aColor,$aWeight);\n    }\n\n    function SetOrder($aDepth) {\n\t$this->vert->SetOrder($aDepth);\n\t$this->hor->SetOrder($aDepth);\n    }\n\n    function SetPos(&$aRect) {\n\tparent::SetPos($aRect);\n\t$this->vert->SetPos($aRect);\n\t$this->hor->SetPos($aRect);\n    }\n\n    function SetDensity($aDens) {\n\t$this->vert->SetDensity($aDens);\n\t$this->hor->SetDensity($aDens);\n    }\n\n    function DoPattern(&$aImg) {\n\t$this->vert->DoPattern($aImg);\n\t$this->hor->DoPattern($aImg);\n    }\n}\n\n//=====================================================================\n// Class RectPatternDiagCross\n// Vert/Hor crosses\n//=====================================================================\n\nclass RectPatternDiagCross extends RectPattern {\n    var $left=null;\n    var $right=null;\n    function RectPatternDiagCross($aColor=\"black\",$aWeight=1) {\n\tparent::RectPattern($aColor,$aWeight);\n\t$this->right = new RectPatternRDiag($aColor,$aWeight);\n\t$this->left  = new RectPatternLDiag($aColor,$aWeight);\n    }\n\n    function SetOrder($aDepth) {\n\t$this->left->SetOrder($aDepth);\n\t$this->right->SetOrder($aDepth);\n    }\n\n    function SetPos(&$aRect) {\n\tparent::SetPos($aRect);\n\t$this->left->SetPos($aRect);\n\t$this->right->SetPos($aRect);\n    }\n\n    function SetDensity($aDens) {\n\t$this->left->SetDensity($aDens);\n\t$this->right->SetDensity($aDens);\n    }\n\n    function DoPattern(&$aImg) {\n\t$this->left->DoPattern($aImg);\n\t$this->right->DoPattern($aImg);\n    }\n\n}\n\n//=====================================================================\n// Class RectPatternFactory\n// Factory class for rectangular pattern \n//=====================================================================\nclass RectPatternFactory {\n    function RectPatternFactory() {\n\t// Empty\n    }\n    function Create($aPattern,$aColor,$aWeight=1) {\n\tswitch($aPattern) {\n\t    case BAND_RDIAG:\n\t\t$obj =  new RectPatternRDiag($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_LDIAG:\n\t\t$obj =  new RectPatternLDiag($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_SOLID:\n\t\t$obj =  new RectPatternSolid($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_VLINE:\n\t\t$obj =  new RectPatternVert($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_HLINE:\n\t\t$obj =  new RectPatternHor($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_3DPLANE:\n\t\t$obj =  new RectPattern3DPlane($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_HVCROSS:\n\t\t$obj =  new RectPatternCross($aColor,$aWeight);\n\t\tbreak;\n\t    case BAND_DIAGCROSS:\n\t\t$obj =  new RectPatternDiagCross($aColor,$aWeight);\n\t\tbreak;\n\t    default:\n\t\tJpGraphError::RaiseL(16003,$aPattern);\n//(\" Unknown pattern specification ($aPattern)\");\n\t}\n\treturn $obj;\n    }\n}\n\n\n//=====================================================================\n// Class PlotBand\n// Factory class which is used by the client.\n// It is responsible for factoring the corresponding pattern\n// concrete class.\n//=====================================================================\nclass PlotBand {\n    var $prect=null;\n    var $depth;\n    var $dir, $min, $max;\n\n    function PlotBand($aDir,$aPattern,$aMin,$aMax,$aColor=\"black\",$aWeight=1,$aDepth=DEPTH_BACK) {\n\t$f =  new RectPatternFactory();\n\t$this->prect = $f->Create($aPattern,$aColor,$aWeight);\n\tif( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) \n\t    JpGraphError::RaiseL(16004);\n//('Min value for plotband is larger than specified max value. Please correct.');\n\t$this->dir = $aDir;\n\t$this->min = $aMin;\n\t$this->max = $aMax;\n\t$this->depth=$aDepth;\n    }\n\t\n    // Set position. aRect contains absolute image coordinates\n    function SetPos(&$aRect) {\n\tassert( $this->prect != null ) ;\n\t$this->prect->SetPos($aRect);\n    }\n\t\n    function ShowFrame($aFlag=true) {\n\t$this->prect->ShowFrame($aFlag);\n    }\n\n    // Set z-order. In front of pplot or in the back\n    function SetOrder($aDepth) {\n\t$this->depth=$aDepth;\n    }\n\t\n    function SetDensity($aDens) {\n\t$this->prect->SetDensity($aDens);\n    }\n\t\n    function GetDir() {\n\treturn $this->dir;\n    }\n\t\n    function GetMin() {\n\treturn $this->min;\n    }\n\t\n    function GetMax() {\n\treturn $this->max;\n    }\n\t\n    // Display band\n    function Stroke(&$aImg,&$aXScale,&$aYScale) {\n\tassert( $this->prect != null ) ;\n\tif( $this->dir == HORIZONTAL ) {\n\t    if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal();\n\t    if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal();\n\n            // Only draw the bar if it actually appears in the range\n            if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) {\n\t    \n\t    // Trucate to limit of axis\n\t    $this->min = max($this->min, $aYScale->GetMinVal());\n\t    $this->max = min($this->max, $aYScale->GetMaxVal());\n\n\t    $x=$aXScale->scale_abs[0];\n\t    $y=$aYScale->Translate($this->max);\n\t    $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1;\n\t    $height=abs($y-$aYScale->Translate($this->min))+1;\n\t    $this->prect->SetPos(new Rectangle($x,$y,$width,$height));\n\t    $this->prect->Stroke($aImg);\n            }\n\t}\n\telse {\t// VERTICAL\n\t    if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal();\n\t    if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal();\n            \n            // Only draw the bar if it actually appears in the range\n\t    if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) {\n\t    \n\t    // Trucate to limit of axis\n\t    $this->min = max($this->min, $aXScale->GetMinVal());\n\t    $this->max = min($this->max, $aXScale->GetMaxVal());\n\n\t    $y=$aYScale->scale_abs[1];\n\t    $x=$aXScale->Translate($this->min);\n\t    $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]);\n\t    $width=abs($x-$aXScale->Translate($this->max));\n\t    $this->prect->SetPos(new Rectangle($x,$y,$width,$height));\n\t    $this->prect->Stroke($aImg);\n            }\n\t}\n    }\n}\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_plotmark.inc",
    "content": "<?php\n//=======================================================================\n// File:\tJPGRAPH_PLOTMARK.PHP\n// Description:\tClass file. Handles plotmarks\n// Created: \t2003-03-21\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_plotmark.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n\n\n//========================================================================\n// CLASS ImgData\n// Description: Base class for all image data classes that contains the \n// real image data.\n//========================================================================\nclass ImgData {\n    var $name = '';\t\t// Each subclass gives a name\n    var $an = array();\t\t// Data array names\n    var $colors = array();\t// Available colors\n    var $index  = array();\t// Index for colors\n    var $maxidx = 0 ;\t\t// Max color index\n    var $anchor_x=0.5, $anchor_y=0.5 ;    // Where is the center of the image\n    // Create a GD image from the data and return a GD handle\n    function GetImg($aMark,$aIdx) {\n\t$n = $this->an[$aMark];\n\tif( is_string($aIdx) ) {\n\t    if( !in_array($aIdx,$this->colors) ) {\n\t\tJpGraphError::RaiseL(23001,$this->name,$aIdx); //('This marker \"'.($this->name).'\" does not exist in color: '.$aIdx);\n\t    }\n\t    $idx = $this->index[$aIdx];\n\t}\n\telseif( !is_integer($aIdx) || \n\t\t(is_integer($aIdx) && $aIdx > $this->maxidx ) ) {\n\t    JpGraphError::RaiseL(23002,$this->name);\n//('Mark color index too large for marker \"'.($this->name).'\"');\n\t}\n\telse\n\t    $idx = $aIdx ;\n\treturn Image::CreateFromString(base64_decode($this->{$n}[$idx][1]));   \n    }\n    function GetAnchor() {\n\treturn array($this->anchor_x,$this->anchor_y);\n    }\n}\n\n\n// Keep a global flag cache to reduce memory usage\n$_gFlagCache=array(\n    1 => null,\n    2 => null,\n    3 => null,\n    4 => null,\n);\n// Only supposed to b called as statics\nclass FlagCache {\n    function GetFlagImgByName($aSize,$aName) {\n\tglobal $_gFlagCache;\n\trequire_once('jpgraph_flags.php');\n\tif( $_gFlagCache[$aSize] === null ) {\n\t    $_gFlagCache[$aSize] =& new FlagImages($aSize);\n\t}\n\t$f =& $_gFlagCache[$aSize];\n\t$idx = $f->GetIdxByName($aName,$aFullName);\n\treturn $f->GetImgByIdx($idx);\n    }\n}\n\n//===================================================\n// CLASS PlotMark\n// Description: Handles the plot marks in graphs\n//===================================================\nclass PlotMark {\n    var $title, $show=true;\n    var $type,$weight=1;\n    var $color=\"black\", $width=4, $fill_color=\"blue\";\n    var $yvalue,$xvalue='',$csimtarget,$csimalt,$csimareas;\n    var $iFormatCallback=\"\";\n    var $iFormatCallback2=\"\";\n    var $markimg='',$iScale=1.0;\n    var $oldfilename='',$iFileName='';\n    var $imgdata_balls = null;\n    var $imgdata_diamonds = null;\n    var $imgdata_squares = null;\n    var $imgdata_bevels = null;\n    var $imgdata_stars = null;\n    var $imgdata_pushpins = null;\n\n//--------------\n// CONSTRUCTOR\n    function PlotMark() {\n\t$this->title = new Text();\n\t$this->title->Hide();\n\t$this->csimareas = '';\n\t$this->csimalt = '';\n\t$this->type=-1;\n    }\n//---------------\n// PUBLIC METHODS\t\n    function SetType($aType,$aFileName='',$aScale=1.0) {\n\t$this->type = $aType;\n\tif( $aType == MARK_IMG && $aFileName=='' ) {\n\t    JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.');\n\t}\n\t$this->iFileName = $aFileName;\n\t$this->iScale = $aScale;\n    }\n\t\n    function SetCallback($aFunc) {\n\t$this->iFormatCallback = $aFunc;\n    }\n\n    function SetCallbackYX($aFunc) {\n\t$this->iFormatCallback2 = $aFunc;\n    }\n    \n    function GetType() {\n\treturn $this->type;\n    }\n\t\n    function SetColor($aColor) {\n\t$this->color=$aColor;\n    }\n\t\n    function SetFillColor($aFillColor) {\n\t$this->fill_color = $aFillColor;\n    }\n\n    function SetWeight($aWeight) {\n\t$this->weight = $aWeight;\n    }\n\n    // Synonym for SetWidth()\n    function SetSize($aWidth) {\n\t$this->width=$aWidth;\n    }\n\t\n    function SetWidth($aWidth) {\n\t$this->width=$aWidth;\n    }\n\n    function SetDefaultWidth() {\n\tswitch( $this->type ) {\n\t    case MARK_CIRCLE: \n\t    case MARK_FILLEDCIRCLE: \n\t\t$this->width=4;\n\t\tbreak;\n\t    default:\n\t\t$this->width=7;\n\t}\n    }\n\t\n    function GetWidth() {\n\treturn $this->width;\n    }\n\t\n    function Hide($aHide=true) {\n\t$this->show = !$aHide;\n    }\n\t\n    function Show($aShow=true) {\n\t$this->show = $aShow;\n    }\n\n    function SetCSIMAltVal($aY,$aX='') {\n        $this->yvalue=$aY; \n        $this->xvalue=$aX; \n    }\n    \n    function SetCSIMTarget($aTarget) {\n        $this->csimtarget=$aTarget;\n    }\n    \n    function SetCSIMAlt($aAlt) {\n        $this->csimalt=$aAlt;\n    }\n    \n    function GetCSIMAreas(){\n        return $this->csimareas;\n    }\n        \n    function AddCSIMPoly($aPts) {\n        $coords = round($aPts[0]).\", \".round($aPts[1]);\n        $n = count($aPts)/2;\n        for( $i=1; $i < $n; ++$i){\n            $coords .= \", \".round($aPts[2*$i]).\", \".round($aPts[2*$i+1]);\n        }\n        $this->csimareas=\"\";    \n        if( !empty($this->csimtarget) ) {\n\t    $this->csimareas .= \"<area shape=\\\"poly\\\" coords=\\\"$coords\\\" href=\\\"\".$this->csimtarget.\"\\\"\";\n\t    if( !empty($this->csimalt) ) {\t\t\t\t\t\t\t\t\t\t\n\t\t$tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);\n\t\t$this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t    }\n\t    $this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";\n\t}\n    }\n    \n    function AddCSIMCircle($x,$y,$r) {\n    \t$x = round($x); $y=round($y); $r=round($r);\n        $this->csimareas=\"\";    \n        if( !empty($this->csimtarget) ) {\n\t    $this->csimareas .= \"<area shape=\\\"circle\\\" coords=\\\"$x,$y,$r\\\" href=\\\"\".$this->csimtarget.\"\\\"\";\n    \t    if( !empty($this->csimalt) ) {\t\t\t\t\t\t\t\t\t\t\n\t\t$tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);\n\t\t$this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t    }\n            $this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";        \n        }\n    }\n    \t\n    function Stroke(&$img,$x,$y) {\n\tif( !$this->show ) return;\n\n\tif( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) {\n\n\t    if( $this->iFormatCallback != '' ) {\n\t\t$f = $this->iFormatCallback;\n\t\tlist($width,$color,$fcolor) = call_user_func($f,$this->yvalue);\n\t\t$filename = $this->iFileName;\n\t\t$imgscale = $this->iScale;\n\t    }\n\t    else {\n\t\t$f = $this->iFormatCallback2;\n\t\tlist($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue);\n\t\tif( $filename==\"\" ) $filename = $this->iFileName;\n\t\tif( $imgscale==\"\" ) $imgscale = $this->iScale;\n\t    }\n\n\t    if( $width==\"\" ) $width = $this->width;\n\t    if( $color==\"\" ) $color = $this->color;\n\t    if( $fcolor==\"\" ) $fcolor = $this->fill_color;\n\n\t}\n\telse {\n\t    $fcolor = $this->fill_color;\n\t    $color = $this->color;\n\t    $width = $this->width;\n\t    $filename = $this->iFileName;\n\t    $imgscale = $this->iScale;\n\t}\n\n\tif( $this->type == MARK_IMG ||\n\t    ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) ||\n\t    $this->type >= MARK_IMG_PUSHPIN ) {\n\n\t    // Note: For the builtin images we use the \"filename\" parameter\n\t    // to denote the color\n\t    $anchor_x = 0.5;\n\t    $anchor_y = 0.5; \n\t    switch( $this->type ) {\n\t\tcase MARK_FLAG1:\n\t\tcase MARK_FLAG2:\n\t\tcase MARK_FLAG3:\n\t\tcase MARK_FLAG4:\n\t\t    $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename);\n\t\t    break;\n\n\t\tcase MARK_IMG :\n\t\t    // Load an image and use that as a marker\n\t\t    // Small optimization, if we have already read an image don't\n\t\t    // waste time reading it again.\n\t\t    if( $this->markimg == '' || !($this->oldfilename === $filename) ) {\n\t\t\t$this->markimg = Graph::LoadBkgImage('',$filename);\n\t\t\t$this->oldfilename = $filename ;\n\t\t    }\n\t\t    break;\n\n\t\tcase MARK_IMG_PUSHPIN:\n\t\tcase MARK_IMG_SPUSHPIN:\n\t\tcase MARK_IMG_LPUSHPIN:\n\t\t    if( $this->imgdata_pushpins == null ) {\n\t\t\trequire_once 'imgdata_pushpins.inc';\n\t\t\t$this->imgdata_pushpins = new ImgData_PushPins();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor();\n\t\t    break;\n\n\t\tcase MARK_IMG_SQUARE:\n\t\t    if( $this->imgdata_squares == null ) {\n\t\t\trequire_once 'imgdata_squares.inc';\n\t\t\t$this->imgdata_squares = new ImgData_Squares();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor();\n\t\t    break;\n\n\t\tcase MARK_IMG_STAR:\n\t\t    if( $this->imgdata_stars == null ) {\n\t\t\trequire_once 'imgdata_stars.inc';\n\t\t\t$this->imgdata_stars = new ImgData_Stars();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor();\n\t\t    break;\n\n\t\tcase MARK_IMG_BEVEL:\n\t\t    if( $this->imgdata_bevels == null ) {\n\t\t\trequire_once 'imgdata_bevels.inc';\n\t\t\t$this->imgdata_bevels = new ImgData_Bevels();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor();\n\t\t    break;\n\n\t\tcase MARK_IMG_DIAMOND:\n\t\t    if( $this->imgdata_diamonds == null ) {\n\t\t\trequire_once 'imgdata_diamonds.inc';\n\t\t\t$this->imgdata_diamonds = new ImgData_Diamonds();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor();\n\t\t    break;\n\n\t\tcase MARK_IMG_BALL:\t\t    \n\t\tcase MARK_IMG_SBALL:\t\t    \n\t\tcase MARK_IMG_MBALL:\t\t    \n\t\tcase MARK_IMG_LBALL:\t\t    \n\t\t    if( $this->imgdata_balls == null ) {\n\t\t\trequire_once 'imgdata_balls.inc';\n\t\t\t$this->imgdata_balls = new ImgData_Balls();\n\t\t    }\n\t\t    $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename);\n\t\t    list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor();\n\t\t    break;\n\t    }\n\n\t    $w = $img->GetWidth($this->markimg);\n\t    $h = $img->GetHeight($this->markimg);\n\t    \n\t    $dw = round($imgscale * $w );\n\t    $dh = round($imgscale * $h );\n\n\t    // Do potential rotation\n\t    list($x,$y) = $img->Rotate($x,$y);\n\n\t    $dx = round($x-$dw*$anchor_x);\n\t    $dy = round($y-$dh*$anchor_y);\n\t    \n\t    $this->width = max($dx,$dy);\n\t    \n\t    $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h);\n\t    if( !empty($this->csimtarget) ) {\n\t\t$this->csimareas = \"<area shape=\\\"rect\\\" coords=\\\"\".\n\t\t    $dx.','.$dy.','.round($dx+$dw).','.round($dy+$dh).'\" '.\n\t\t    \"href=\\\"\".$this->csimtarget.\"\\\"\";\n\t\tif( !empty($this->csimalt) ) {\n\t\t    $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);\n\t\t    $this->csimareas .= \" title=\\\"$tmp\\\"\";\n\t\t}\n\t\t$this->csimareas .= \" alt=\\\"$tmp\\\" />\\n\";\n\t    }\n\t    \n\t    // Stroke title\n\t    $this->title->Align(\"center\",\"top\");\n\t    $this->title->Stroke($img,$x,$y+round($dh/2));\t\t\t\n\t    return;\n\t}\n\n\t$weight = $this->weight;\n\t$dx=round($width/2,0);\n\t$dy=round($width/2,0);\n\t$pts=0;\t\t\n\n\tswitch( $this->type ) {\n\t    case MARK_SQUARE:\n\t\t$c[]=$x-$dx;$c[]=$y-$dy;\n\t\t$c[]=$x+$dx;$c[]=$y-$dy;\n\t\t$c[]=$x+$dx;$c[]=$y+$dy;\n\t\t$c[]=$x-$dx;$c[]=$y+$dy;\n\t\t$c[]=$x-$dx;$c[]=$y-$dy;\n\t\t$pts=5;\n\t\tbreak;\n\t    case MARK_UTRIANGLE:\n\t\t++$dx;++$dy;\n\t\t$c[]=$x-$dx;$c[]=$y+0.87*$dy;\t// tan(60)/2*$dx\n\t\t$c[]=$x;$c[]=$y-0.87*$dy;\n\t\t$c[]=$x+$dx;$c[]=$y+0.87*$dy;\n\t\t$c[]=$x-$dx;$c[]=$y+0.87*$dy;\t// tan(60)/2*$dx\n\t\t$pts=4;\n\t\tbreak;\n\t    case MARK_DTRIANGLE:\n\t\t++$dx;++$dy;\t\t\t\n\t\t$c[]=$x;$c[]=$y+0.87*$dy;\t// tan(60)/2*$dx\n\t\t$c[]=$x-$dx;$c[]=$y-0.87*$dy;\n\t\t$c[]=$x+$dx;$c[]=$y-0.87*$dy;\n\t\t$c[]=$x;$c[]=$y+0.87*$dy;\t// tan(60)/2*$dx\n\t\t$pts=4;\n\t\tbreak;\t\t\t\t\n\t    case MARK_DIAMOND:\n\t\t$c[]=$x;$c[]=$y+$dy;\n\t\t$c[]=$x-$dx;$c[]=$y;\n\t\t$c[]=$x;$c[]=$y-$dy;\n\t\t$c[]=$x+$dx;$c[]=$y;\n\t\t$c[]=$x;$c[]=$y+$dy;\n\t\t$pts=5;\n\t\tbreak;\t\n\t    case MARK_LEFTTRIANGLE:\n\t\t$c[]=$x;$c[]=$y;\n\t\t$c[]=$x;$c[]=$y+2*$dy;\n\t\t$c[]=$x+$dx*2;$c[]=$y;\n\t\t$c[]=$x;$c[]=$y;\n\t\t$pts=4;\n\t\tbreak;\n\t    case MARK_RIGHTTRIANGLE:\n\t\t$c[]=$x-$dx*2;$c[]=$y;\n\t\t$c[]=$x;$c[]=$y+2*$dy;\n\t\t$c[]=$x;$c[]=$y;\n\t\t$c[]=$x-$dx*2;$c[]=$y;\n\t\t$pts=4;\n\t\tbreak;\n\t    case MARK_FLASH:\n\t\t$dy *= 2;\n\t\t$c[]=$x+$dx/2; $c[]=$y-$dy;\n\t\t$c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy;\n\t\t$c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy;\n\t\t$c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy;\n\t\t$img->SetLineWeight($weight);\n\t\t$img->SetColor($color);\t\t\t\t\t\n\t\t$img->Polygon($c);\n\t\t$img->SetLineWeight(1);\n\t\t$this->AddCSIMPoly($c);\n\t\tbreak;\n\t}\n\n\tif( $pts>0 ) {\n\t    $this->AddCSIMPoly($c);\n\t    $img->SetLineWeight($weight);\n\t    $img->SetColor($fcolor);\t\t\t\t\t\t\t\t\n\t    $img->FilledPolygon($c);\n\t    $img->SetColor($color);\t\t\t\t\t\n\t    $img->Polygon($c);\n\t    $img->SetLineWeight(1);\n\t}\n\telseif( $this->type==MARK_CIRCLE ) {\n\t    $img->SetColor($color);\t\t\t\t\t\n\t    $img->Circle($x,$y,$width);\n\t    $this->AddCSIMCircle($x,$y,$width);\n\t}\n\telseif( $this->type==MARK_FILLEDCIRCLE ) {\n\t    $img->SetColor($fcolor);\t\t\n\t    $img->FilledCircle($x,$y,$width);\n\t    $img->SetColor($color);\t\n\t    $img->Circle($x,$y,$width);\n\t    $this->AddCSIMCircle($x,$y,$width);\n\t}\n\telseif( $this->type==MARK_CROSS ) {\n\t    // Oversize by a pixel to match the X\n\t    $img->SetColor($color);\n\t    $img->SetLineWeight($weight);\n\t    $img->Line($x,$y+$dy+1,$x,$y-$dy-1);\n\t    $img->Line($x-$dx-1,$y,$x+$dx+1,$y);\n\t    $this->AddCSIMCircle($x,$y,$dx);\t    \n\t}\n\telseif( $this->type==MARK_X ) {\n\t    $img->SetColor($color);\n\t    $img->SetLineWeight($weight);\n\t    $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);\n\t    $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);\t\t\n\t    $this->AddCSIMCircle($x,$y,$dx+$dy);\t    \t    \n\t}\t\t\t\n\telseif( $this->type==MARK_STAR ) {\n\t    $img->SetColor($color);\n\t    $img->SetLineWeight($weight);\n\t    $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);\n\t    $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);\n\t    // Oversize by a pixel to match the X\t\t\t\t\n\t    $img->Line($x,$y+$dy+1,$x,$y-$dy-1);\n\t    $img->Line($x-$dx-1,$y,$x+$dx+1,$y);\n\t    $this->AddCSIMCircle($x,$y,$dx+$dy);\t    \n\t}\n\t\t\n\t// Stroke title\n\t$this->title->Align(\"center\",\"center\");\n\t$this->title->Stroke($img,$x,$y);\t\t\t\n    }\n} // Class\n\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_polar.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_POLAR.PHP\n// Description:\tPolar plot extension for JpGraph\n// Created: \t2003-02-02\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_polar.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nrequire_once ('jpgraph_plotmark.inc');\n\n\nrequire_once \"jpgraph_log.php\";\n\n\nDEFINE('POLAR_360',1);\nDEFINE('POLAR_180',2);\n\n//\n// Note. Don't attempt to make sense of this code.\n// In order not to have to be able to inherit the scaling code\n// from the main graph package we have had to make some \"tricks\" since\n// the original scaling and axis was not designed to do what is\n// required here.\n// There were two option. 1: Re-implement everything and get a clean design\n// and 2: do some \"small\" trickery and be able to inherit most of\n// the functionlity from the main graph package. \n// We choose 2: here in order to save some time.\n// \n\n//--------------------------------------------------------------------------\n// class PolarPlot\n//--------------------------------------------------------------------------\nclass PolarPlot {\n    var $numpoints=0;\n    var $iColor='navy',$iFillColor='';\n    var $iLineWeight=1;\n    var $coord=null;\n    var $legendcsimtarget='';\n    var $legendcsimalt='';\n    var $legend=\"\";\n    var $csimtargets=array();\t// Array of targets for CSIM\n    var $csimareas=\"\";\t\t\t// Resultant CSIM area tags\t\n    var $csimalts=null;\t\t\t// ALT:s for corresponding target\n    var $line_style='solid',$mark;\n\n    function PolarPlot($aData) {\n\t$n = count($aData);\n\tif( $n & 1 ) {\n\t    JpGraphError::RaiseL(17001);\n//('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).');\n\t}\n\t$this->numpoints = $n/2;\n\t$this->coord = $aData;\n\t$this->mark = new PlotMark();\n    }\n\n    function SetWeight($aWeight) {\n\t$this->iLineWeight = $aWeight;\n    }\n\n    function SetColor($aColor){\n\t$this->iColor = $aColor;\n    }\n\n    function SetFillColor($aColor){\n\t$this->iFillColor = $aColor;\n    }\n\n    function Max() {\n\t$m = $this->coord[1];\n\t$i=1;\n\twhile( $i < $this->numpoints ) {\n\t    $m = max($m,$this->coord[2*$i+1]);  \n\t    ++$i;\n\t} \n\treturn $m;\n    }\n    // Set href targets for CSIM\t\n    function SetCSIMTargets($aTargets,$aAlts=null) {\n\t$this->csimtargets=$aTargets;\n\t$this->csimalts=$aAlts;\t\t\n    }\n \t\n    // Get all created areas\n    function GetCSIMareas() {\n\treturn $this->csimareas;\n    }\t\n\t\n    function SetLegend($aLegend,$aCSIM=\"\",$aCSIMAlt=\"\") {\n\t$this->legend = $aLegend;\n\t$this->legendcsimtarget = $aCSIM;\n\t$this->legendcsimalt = $aCSIMAlt;\n    }\n\n    // Private methods\n\n    function Legend(&$aGraph) {\n\t$color = $this->iColor ;\n\tif( $this->legend != \"\" ) {\n\t    if( $this->iFillColor!='' ) {\n\t\t$color = $this->iFillColor;\n\t\t$aGraph->legend->Add($this->legend,$color,$this->mark,0,\n\t\t\t\t     $this->legendcsimtarget,$this->legendcsimalt);    \n\t    }\n\t    else {\n\t\t$aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style,\n\t\t\t\t     $this->legendcsimtarget,$this->legendcsimalt);    \n\t    }\n\t}\n    }\n\n    function Stroke(&$img,$scale) {\n\n\t$i=0;\n\t$p=array();\n\t$this->csimareas='';\n\twhile($i < $this->numpoints) {\n\t    list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]);\n\t    $p[2*$i] = $x1;\n\t    $p[2*$i+1] = $y1;\n\t\n\t    if( isset($this->csimtargets[$i]) ) {\n\t        $this->mark->SetCSIMTarget($this->csimtargets[$i]);\n\t        $this->mark->SetCSIMAlt($this->csimalts[$i]);\n\t\t$this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]);\n\t\t$this->mark->Stroke($img,$x1,$y1);\n\t\t$this->csimareas .= $this->mark->GetCSIMAreas();\n\t    }\n\t    else\n\t\t$this->mark->Stroke($img,$x1,$y1);\n\n\t    ++$i;\n\t}\n\n\tif( $this->iFillColor != '' ) {\n\t    $img->SetColor($this->iFillColor);\n\t    $img->FilledPolygon($p);\n\t}\n\t$img->SetLineWeight($this->iLineWeight);\n\t$img->SetColor($this->iColor);\n\t$img->Polygon($p,$this->iFillColor!='');\n    }\n}\n\n//--------------------------------------------------------------------------\n// class PolarAxis\n//--------------------------------------------------------------------------\nclass PolarAxis extends Axis {\n    var $angle_step=15,$angle_color='lightgray',$angle_label_color='black';\n    var $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10;\n    var $angle_fontcolor = 'navy';\n    var $gridminor_color='lightgray',$gridmajor_color='lightgray';\n    var $show_minor_grid = false, $show_major_grid = true ;\n    var $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true;\n    var $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black';\n    var $show_angle_tick=true;\n    var $radius_tick_color='black';\n\n    function PolarAxis(&$img,&$aScale) {\n\tparent::Axis($img,$aScale);\n    }\n\n    function ShowAngleDegreeMark($aFlg=true) {\n\t$this->show_angle_mark = $aFlg;\n    }\n\n    function SetAngleStep($aStep) {\n\t$this->angle_step=$aStep;\n    }\n\n    function HideTicks($aFlg=true,$aAngleFlg=true) {\n\tparent::HideTicks($aFlg,$aFlg);\n\t$this->show_angle_tick = !$aAngleFlg;\n    }\n\n    function ShowAngleLabel($aFlg=true) {\n\t$this->show_angle_label = $aFlg;\n    }\n\n    function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) {\n\t$this->show_minor_grid = $aMinor;\n\t$this->show_major_grid = $aMajor;\n\t$this->show_angle_grid = $aAngle ;\n    }\n\n    function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) {\n\t$this->angle_fontfam = $aFontFam;\n\t$this->angle_fontstyle = $aFontStyle;\n\t$this->angle_fontsize = $aFontSize;\n    }\n\n    function SetColor($aColor,$aRadColor='',$aAngleColor='') {\n\tif( $aAngleColor == '' )\n\t    $aAngleColor=$aColor;\n\tparent::SetColor($aColor,$aRadColor);\n\t$this->angle_fontcolor = $aAngleColor;\n    }\n\n    function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') {\n\tif( $aMinorColor == '' ) \n\t    $aMinorColor = $aMajorColor;\n\tif( $aAngleColor == '' ) \n\t    $aAngleColor = $aMajorColor;\n\n\t$this->gridminor_color = $aMinorColor;\n\t$this->gridmajor_color = $aMajorColor;\n\t$this->angle_color = $aAngleColor;\n    }\n\n    function SetTickColors($aRadColor,$aAngleColor='') {\n\t$this->radius_tick_color = $aRadColor;\n\t$this->angle_tick_color = $aAngleColor;\n    }\n    \n    // Private methods\n    function StrokeGrid($pos) {\n\t$x = round($this->img->left_margin + $this->img->plotwidth/2);\n\t$this->scale->ticks->Stroke($this->img,$this->scale,$pos);\n\n\t// Stroke the minor arcs \n\t$pmin = array();\n\t$p = $this->scale->ticks->ticks_pos;\n\t$n = count($p);\n\t$i = 0;\n\t$this->img->SetColor($this->gridminor_color);\n\twhile( $i < $n ) {\n\t    $r = $p[$i]-$x+1;\n\t    $pmin[]=$r;\n\t    if( $this->show_minor_grid ) {\n\t\t$this->img->Circle($x,$pos,$r);\n\t    }\n\t    $i++;\n\t}\n\t\n\t$limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ;\n\twhile( $r < $limit ) {\n\t    $off = $r;\n\t    $i=1;\n\t    $r = $off + round($p[$i]-$x+1);\n\t    while( $r < $limit && $i < $n ) {\n\t\t$r = $off+$p[$i]-$x;\n\t\t$pmin[]=$r;\n\t\tif( $this->show_minor_grid ) {\n\t\t    $this->img->Circle($x,$pos,$r);\n\t\t}\n\t\t$i++;\n\t    }\n\t}\n\n\t// Stroke the major arcs \n\tif( $this->show_major_grid ) {\n\t    // First determine how many minor step on\n\t    // every major step. We have recorded the minor radius\n\t    // in pmin and use these values. This is done in order\n\t    // to avoid rounding errors if we were to recalculate the\n\t    // different major radius.\n\t    $pmaj = $this->scale->ticks->maj_ticks_pos;\n\t    $p = $this->scale->ticks->ticks_pos;\n\t    if( $this->scale->name == 'lin' ) {\n\t\t$step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0]));\n\t    }\n\t    else {\n\t\t$step=9;\n\t    }\n\t    $n = round(count($pmin)/$step);\n\t    $i = 0;\n\t    $this->img->SetColor($this->gridmajor_color);\n\t    $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ;\n\t    $off = $r;\n\t    $i=0;\n\t    $r = $pmin[$i*$step];\n\t    while( $r < $limit && $i < $n ) {\n\t\t$r = $pmin[$i*$step];\n\t\t$this->img->Circle($x,$pos,$r);\n\t\t$i++;\n\t    }\n\t}\n\n\t// Draw angles\n\tif( $this->show_angle_grid ) {\n\t    $this->img->SetColor($this->angle_color);\n\t    $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ;\n\t    $a = 0;\n\t    $p = $this->scale->ticks->ticks_pos;\n\t    $start_radius = $p[1]-$x;\n\t    while( $a < 360 ) {\n\t\tif( $a == 90 || $a == 270 ) {\n\t\t    // Make sure there are no rounding problem with\n\t\t    // exactly vertical lines\n\t\t    $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1,\n\t\t\t\t     $pos-$start_radius*sin($a/180*M_PI),\n\t\t\t\t     $x+$start_radius*cos($a/180*M_PI)+1,\n\t\t\t\t     $pos-$d*sin($a/180*M_PI));\n\t\t    \n\t\t}\n\t\telse {\n\t\t    $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1,\n\t\t\t\t     $pos-$start_radius*sin($a/180*M_PI),\n\t\t\t\t     $x+$d*cos($a/180*M_PI),\n\t\t\t\t     $pos-$d*sin($a/180*M_PI));\n\t\t}\n\t\t$a += $this->angle_step;\n\t    }\n\t}\n    }\n\n    function StrokeAngleLabels($pos,$type) {\n\n\tif( !$this->show_angle_label ) \n\t    return;\n\t\n\t$x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1;\n\n\t$d = max($this->img->plotwidth,$this->img->plotheight)*1.42;\n\t$a = $this->angle_step;\n\t$t = new Text();\n\t$t->SetColor($this->angle_fontcolor);\n\t$t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize);\n\t$xright = $this->img->width - $this->img->right_margin;\n\t$ytop = $this->img->top_margin;\n\t$xleft = $this->img->left_margin;\n\t$ybottom = $this->img->height - $this->img->bottom_margin;\n\t$ha = 'left';\n\t$va = 'center';\n\t$w = $this->img->plotwidth/2;\n\t$h = $this->img->plotheight/2;\n\t$xt = $x0; $yt = $pos;\n\t$margin=5;\n\n\t$tl  = $this->angle_tick_len ; // Outer len\n\t$tl2 = $this->angle_tick_len2 ; // Interior len\n\n\t$this->img->SetColor($this->angle_tick_color);\n\t$rot90 = $this->img->a == 90 ;\n\n\tif( $type == POLAR_360 ) {\n\t    $ca1 = atan($h/$w)/M_PI*180;\n\t    $ca2 = 180-$ca1;\n\t    $ca3 = $ca1+180;\n\t    $ca4 = 360-$ca1;\n\t    $end = 360;\n\t    while( $a < $end ) {\n\t\t$ca = cos($a/180*M_PI);\n\t\t$sa = sin($a/180*M_PI);\n\t\t$x = $d*$ca;\n\t\t$y = $d*$sa;\n\t\t$xt=1000;$yt=1000;\n\t\tif( $a <= $ca1 || $a >= $ca4 ) {\n\t\t    $yt = $pos - $w * $y/$x;\n\t\t    $xt = $xright + $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'top';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'left';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    $x1=$xright-$tl2; $x2=$xright+$tl;\n\t\t    $y1=$y2=$yt;\n\t\t}\n\t\telseif( $a > $ca1 && $a < $ca2 ) { \n\t\t    $xt = $x0 + $h * $x/$y;\n\t\t    $yt = $ytop - $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'left';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'bottom';\n\t\t    }\n\t\t    $y1=$ytop+$tl2;$y2=$ytop-$tl;\n\t\t    $x1=$x2=$xt;\n\t\t}\n\t\telseif( $a >= $ca2 && $a <= $ca3 ) { \n\t\t    $yt = $pos + $w * $y/$x;\n\t\t    $xt = $xleft - $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'bottom';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'right';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    $x1=$xleft+$tl2;$x2=$xleft-$tl;\n\t\t    $y1=$y2=$yt;\n\t\t}\n\t\telse { \n\t\t    $xt = $x0 - $h * $x/$y;\n\t\t    $yt = $ybottom + $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'right';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'top';\n\t\t    }\n\t\t    $y1=$ybottom-$tl2;$y2=$ybottom+$tl;\n\t\t    $x1=$x2=$xt;\n\t\t}\n\t\tif( $a != 0 && $a != 180 ) {\n\t\t    $t->Align($ha,$va);\n\t\t    if( $this->show_angle_mark )\n\t\t\t$a .= '';\n\t\t    $t->Set($a);\n\t\t    $t->Stroke($this->img,$xt,$yt);   \n\t\t    if( $this->show_angle_tick )\n\t\t\t$this->img->Line($x1,$y1,$x2,$y2);\n\t\t}\n\t\t$a += $this->angle_step;\n\t    }\n\t}\n\telse {\n\t    // POLAR_HALF\n\t    $ca1 = atan($h/$w*2)/M_PI*180;\n\t    $ca2 = 180-$ca1;\n\t    $end = 180;\t    \n\t    while( $a < $end ) {\n\t\t$ca = cos($a/180*M_PI);\n\t\t$sa = sin($a/180*M_PI);\n\t\t$x = $d*$ca;\n\t\t$y = $d*$sa;\n\t\tif( $a <= $ca1 ) {\n\t\t    $yt = $pos - $w * $y/$x;\n\t\t    $xt = $xright + $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'top';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'left';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    $x1=$xright-$tl2; $x2=$xright+$tl;\n\t\t    $y1=$y2=$yt;\n\t\t}\n\t\telseif( $a > $ca1 && $a < $ca2 ) { \n\t\t    $xt = $x0 + 2*$h * $x/$y;\n\t\t    $yt = $ytop - $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'left';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'bottom';\n\t\t    }\n\t\t    $y1=$ytop+$tl2;$y2=$ytop-$tl;\n\t\t    $x1=$x2=$xt;\n\t\t}\n\t\telseif( $a >= $ca2 ) { \n\t\t    $yt = $pos + $w * $y/$x;\n\t\t    $xt = $xleft - $margin;\n \t\t    if( $rot90 ) {\n\t\t\t$ha = 'center';\n\t\t\t$va = 'bottom';\n\t\t    }\n\t\t    else {\n\t\t\t$ha = 'right';\n\t\t\t$va = 'center';\n\t\t    }\n\t\t    $x1=$xleft+$tl2;$x2=$xleft-$tl;\n\t\t    $y1=$y2=$yt;\n\t\t}\n\t\t$t->Align($ha,$va);\n\t\tif( $this->show_angle_mark )\n\t\t    $a .= '';\n\t\t$t->Set($a);\n\t\t$t->Stroke($this->img,$xt,$yt);  \n\t\tif( $this->show_angle_tick )\n\t\t    $this->img->Line($x1,$y1,$x2,$y2);  \n\t\t$a += $this->angle_step;\n\t    }\n\t}\n    }\n\n    function Stroke($pos) {\n\n\t$this->img->SetLineWeight($this->weight);\n\t$this->img->SetColor($this->color);\t\t\n\t$this->img->SetFont($this->font_family,$this->font_style,$this->font_size);\n\tif( !$this->hide_line ) \n\t    $this->img->FilledRectangle($this->img->left_margin,$pos,\n\t\t     $this->img->width-$this->img->right_margin,$pos+$this->weight-1);\n\t$y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin;\n\tif( $this->title_adjust==\"high\" )\n\t    $this->title->Pos($this->img->width-$this->img->right_margin,$y,\"right\",\"top\");\n\telseif( $this->title_adjust==\"middle\" || $this->title_adjust==\"center\" ) \n\t    $this->title->Pos(($this->img->width-$this->img->left_margin-\n\t\t\t       $this->img->right_margin)/2+$this->img->left_margin,\n\t\t\t      $y,\"center\",\"top\");\n\telseif($this->title_adjust==\"low\")\n\t    $this->title->Pos($this->img->left_margin,$y,\"left\",\"top\");\n\telse {\t\n\t    JpGraphError::RaiseL(17002,$this->title_adjust);\n//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');\n\t}\n\n\t\n\tif (!$this->hide_labels) {\n\t    $this->StrokeLabels($pos,false);\n\t}\n\t$this->img->SetColor($this->radius_tick_color);\n\t$this->scale->ticks->Stroke($this->img,$this->scale,$pos);\n\n\t//\n\t// Mirror the positions for the left side of the scale\n        //\n\t$mid = 2*($this->img->left_margin+$this->img->plotwidth/2);\n\t$n = count($this->scale->ticks->ticks_pos);\n\t$i=0;\n\twhile( $i < $n ) {\n\t    $this->scale->ticks->ticks_pos[$i] = \n\t\t$mid-$this->scale->ticks->ticks_pos[$i] ;\n\t    ++$i;\n\t}\n\n\t$n = count($this->scale->ticks->maj_ticks_pos);\n\t$i=0;\n\twhile( $i < $n ) {\n\t    $this->scale->ticks->maj_ticks_pos[$i] = \n\t\t$mid-$this->scale->ticks->maj_ticks_pos[$i] ;\n\t    ++$i;\n\t}\n\t\n\t$n = count($this->scale->ticks->maj_ticklabels_pos);\n\t$i=1;\n\twhile( $i < $n ) {\n\t    $this->scale->ticks->maj_ticklabels_pos[$i] =\n\t\t$mid-$this->scale->ticks->maj_ticklabels_pos[$i] ;\n\t    ++$i;\n\t}\n\n\t// Draw the left side of the scale\n\t$n = count($this->scale->ticks->ticks_pos);\n\t$yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize();\n\n\n\t// Minor ticks\n\tif( ! $this->scale->ticks->supress_minor_tickmarks ) {\n\t    $i=1;\n\t    while( $i < $n/2 ) {\n\t\t$x = round($this->scale->ticks->ticks_pos[$i]) ;\n\t\t$this->img->Line($x,$pos,$x,$yu);\n\t\t++$i;\n\t    }\n\t}\n\n\t$n = count($this->scale->ticks->maj_ticks_pos);\n\t$yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize();\n\n\n\t// Major ticks\n\tif( ! $this->scale->ticks->supress_tickmarks ) {\n\t    $i=1;\n\t    while( $i < $n/2 ) {\n\t\t$x = round($this->scale->ticks->maj_ticks_pos[$i]) ;\n\t\t$this->img->Line($x,$pos,$x,$yu);\n\t\t++$i;\n\t    }\n\t}\n\tif (!$this->hide_labels) {\n\t    $this->StrokeLabels($pos,false);\n\t}\n\t$this->title->Stroke($this->img);\t\n    }\n}\n\nclass PolarScale extends LinearScale {\n    var $graph;\n    function PolarScale($aMax=0,&$graph) {\n\tparent::LinearScale(0,$aMax,'x');\n\t$this->graph = &$graph;\n    }\n\n    function _Translate($v) {\n\treturn parent::Translate($v);\n    }\n\n    function PTranslate($aAngle,$aRad) {\n\t\n\t$m = $this->scale[1];\n\t$w = $this->graph->img->plotwidth/2;\n\t$aRad = $aRad/$m*$w;\n\n\t$x = cos( $aAngle/180 * M_PI ) * $aRad;\n\t$y = sin( $aAngle/180 * M_PI ) * $aRad;\n\n\t$x += $this->_Translate(0);\n\n\tif( $this->graph->iType == POLAR_360 ) {\n\t    $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y;\n\t}\n\telse {\n\t    $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y;\n\t}\n\treturn array($x,$y);\n    }\n}\n\nclass PolarLogScale extends LogScale {\n    var $graph;\n    function PolarLogScale($aMax=1,&$graph) {\n\tparent::LogScale(0,$aMax,'x');\n\t$this->graph = &$graph;\n\t$this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE);\n\n    }\n\n    function PTranslate($aAngle,$aRad) {\n\n\tif( $aRad == 0 ) \n\t    $aRad = 1;\n\t$aRad = log10($aRad);\n\t$m = $this->scale[1];\n\t$w = $this->graph->img->plotwidth/2;\n\t$aRad = $aRad/$m*$w;\n\n\t$x = cos( $aAngle/180 * M_PI ) * $aRad;\n\t$y = sin( $aAngle/180 * M_PI ) * $aRad;\n\n\t$x += $w+$this->graph->img->left_margin;//$this->_Translate(0);\n\tif( $this->graph->iType == POLAR_360 ) {\n\t    $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y;\n\t}\n\telse {\n\t    $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y;\n\t}\n\treturn array($x,$y);\n    }\n}\n\nclass PolarGraph extends Graph {\n    var $scale;\n    var $iType=POLAR_360;\n    var $axis;\n    \n    function PolarGraph($aWidth=300,$aHeight=200,$aCachedName=\"\",$aTimeOut=0,$aInline=true) {\n\tparent::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ;\n\t$this->SetDensity(TICKD_DENSE);\n\t$this->SetBox();\n\t$this->SetMarginColor('white');\n    }\n\n    function SetDensity($aDense) {\n\t$this->SetTickDensity(TICKD_NORMAL,$aDense);\n    }\n\n    function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {\n\t$adj = ($this->img->height - $this->img->width)/2;\n\t$this->SetAngle(90);\n\t$this->img->SetMargin($lm-$adj,$rm-$adj,$tm+$adj,$bm+$adj);\n\t$this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));\n\t$this->axis->SetLabelAlign('right','center');\n\t//JpGraphError::Raise('Set90AndMargin() is not supported for polar graphs.');\n    }\n\n    function SetScale($aScale,$rmax=0) {\n\tif( $aScale == 'lin' ) \n\t    $this->scale = new PolarScale($rmax,$this);\n\telseif( $aScale == 'log' ) {\n\t    $this->scale = new PolarLogScale($rmax,$this);\n\t}\n\telse {\n\t    JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be \"lin\" or \"log\"');\n\t}\n\n\t$this->axis = new PolarAxis($this->img,$this->scale);\n\t$this->SetMargin(40,40,50,40);\n    }\n\n    function SetType($aType) {\n\t$this->iType = $aType;\n    }\n\n    function SetPlotSize($w,$h) {\n\t$this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2,\n\t\t\t ($this->img->height-$h)/2,($this->img->height-$h)/2);\n    }\n\n    // Private methods\n    function GetPlotsMax() {\n\t$n = count($this->plots);\n\t$m = $this->plots[0]->Max();\n\t$i=1;\n\twhile($i < $n) {\n\t    $m = max($this->plots[$i]->Max(),$m);\n\t    ++$i;\n\t}\n\treturn $m;\n    }\n\n    function Stroke($aStrokeFileName=\"\") {\n\n\t// Start by adjusting the margin so that potential titles will fit.\n\t$this->AdjustMarginsForTitles();\n\t    \n\t// If the filename is the predefined value = '_csim_special_'\n\t// we assume that the call to stroke only needs to do enough\n\t// to correctly generate the CSIM maps.\n\t// We use this variable to skip things we don't strictly need\n\t// to do to generate the image map to improve performance\n\t// a best we can. Therefor you will see a lot of tests !$_csim in the\n\t// code below.\n\t$_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);\n\n\t// We need to know if we have stroked the plot in the\n\t// GetCSIMareas. Otherwise the CSIM hasn't been generated\n\t// and in the case of GetCSIM called before stroke to generate\n\t// CSIM without storing an image to disk GetCSIM must call Stroke.\n\t$this->iHasStroked = true;\n\n\t//Check if we should autoscale axis\n\tif( !$this->scale->IsSpecified() && count($this->plots)>0 ) {\n\t    $max = $this->GetPlotsMax();\n\t    $t1 = $this->img->plotwidth;\n\t    $this->img->plotwidth /= 2;\n\t    $t2 = $this->img->left_margin;\n\t    $this->img->left_margin += $this->img->plotwidth+1;\n\t    $this->scale->AutoScale($this->img,0,$max,\n\t\t\t\t     $this->img->plotwidth/$this->xtick_factor/2);\n\t    $this->img->plotwidth = $t1;\n\t    $this->img->left_margin = $t2;\n\t}\n\telse {\n\t    // The tick calculation will use the user suplied min/max values to determine\n\t    // the ticks. If auto_ticks is false the exact user specifed min and max\n\t    // values will be used for the scale. \n\t    // If auto_ticks is true then the scale might be slightly adjusted\n\t    // so that the min and max values falls on an even major step.\n\t    //$min = 0;\n\t    $max = $this->scale->scale[1];\n\t    $t1 = $this->img->plotwidth;\n\t    $this->img->plotwidth /= 2;\n\t    $t2 = $this->img->left_margin;\n\t    $this->img->left_margin += $this->img->plotwidth+1;\n\t    $this->scale->AutoScale($this->img,0,$max,\n\t\t\t\t     $this->img->plotwidth/$this->xtick_factor/2);\n\t    $this->img->plotwidth = $t1;\n\t    $this->img->left_margin = $t2;\n\t}\n\n\tif( $this->iType ==  POLAR_180 ) \n\t    $pos = $this->img->height - $this->img->bottom_margin;\n\telse\n\t    $pos = $this->img->plotheight/2 + $this->img->top_margin;\n\n\n\tif( !$_csim ) {\n\t    $this->StrokePlotArea();\n\t}\n\n\t$this->iDoClipping = true;\n\n\tif( $this->iDoClipping ) {\n\t    $oldimage = $this->img->CloneCanvasH();\n\t}\n\n\tif( !$_csim ) {\n\t    $this->axis->StrokeGrid($pos);\n\t}\n\n\t// Stroke all plots for Y1 axis\n\tfor($i=0; $i < count($this->plots); ++$i) {\n\t    $this->plots[$i]->Stroke($this->img,$this->scale);\n\t}\t\t\t\t\t\t\n\n\n\tif( $this->iDoClipping ) {\n\t    // Clipping only supports graphs at 0 and 90 degrees\n\t    if( $this->img->a == 0  ) {\n\t\t$this->img->CopyCanvasH($oldimage,$this->img->img,\n\t\t\t\t\t$this->img->left_margin,$this->img->top_margin,\n\t\t\t\t\t$this->img->left_margin,$this->img->top_margin,\n\t\t\t\t\t$this->img->plotwidth+1,$this->img->plotheight+1);\n\t    }\n\t    elseif( $this->img->a == 90 ) {\n\t\t$adj = round(($this->img->height - $this->img->width)/2);\n\t\t$this->img->CopyCanvasH($oldimage,$this->img->img,\n\t\t\t\t\t$this->img->bottom_margin-$adj,$this->img->left_margin+$adj,\n\t\t\t\t\t$this->img->bottom_margin-$adj,$this->img->left_margin+$adj,\n\t\t\t\t\t$this->img->plotheight,$this->img->plotwidth);\n\t    }\n\t    $this->img->Destroy();\n\t    $this->img->SetCanvasH($oldimage);\n\t}\n\n\tif( !$_csim ) {\n\t    $this->axis->Stroke($pos);\n\t    $this->axis->StrokeAngleLabels($pos,$this->iType);\n\t}\n\n\tif( !$_csim ) {\n\t    $this->StrokePlotBox();\n\t    $this->footer->Stroke($this->img);\n\n\t    // The titles and legends never gets rotated so make sure\n\t    // that the angle is 0 before stroking them\t\t\t\t\n\t    $aa = $this->img->SetAngle(0);\n\t    $this->StrokeTitles();\n\t}\n\n\tfor($i=0; $i < count($this->plots) ; ++$i ) {\n\t    $this->plots[$i]->Legend($this);\n\t}\n\n\t$this->legend->Stroke($this->img);\t\t\n\n\tif( !$_csim ) {\n\n\t    $this->StrokeTexts();\t\n\t    $this->img->SetAngle($aa);\t\n\t\t\t\n\t    // Draw an outline around the image map\t\n\t    if(_JPG_DEBUG)\n\t\t$this->DisplayClientSideaImageMapAreas();\t\t\n\t    \n\t    // Adjust the appearance of the image\n\t    $this->AdjustSaturationBrightnessContrast();\n\n\t    // If the filename is given as the special \"__handle\"\n\t    // then the image handler is returned and the image is NOT\n\t    // streamed back\n\t    if( $aStrokeFileName == _IMG_HANDLER ) {\n\t\treturn $this->img->img;\n\t    }\n\t    else {\n\t\t// Finally stream the generated picture\t\t\t\t\t\n\t\t$this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,\n\t\t\t\t\t   $aStrokeFileName);\t\t\n\t    }\n\t}\n    }\n}\n\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_radar.php",
    "content": "<?php\n/*=======================================================================\n// File:\tJPGRAPH_RADAR.PHP\n// Description: Radar plot extension for JpGraph\n// Created: \t2001-02-04\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_radar.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\nrequire_once('jpgraph_plotmark.inc');\n\nclass RadarLogTicks extends Ticks {\n//---------------\n// CONSTRUCTOR\n    function RadarLogTicks() {\n    }\n//---------------\n// PUBLIC METHODS\t\n\n    // TODO: Add Argument grid\n    function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) {\n\t$start = $aScale->GetMinVal();\n\t$limit = $aScale->GetMaxVal();\n\t$nextMajor = 10*$start;\n\t$step = $nextMajor / 10.0;\n\t$count=1; \n\t\t\t\t\n\t$ticklen_maj=5;\n\t$dx_maj=round(sin($aAxisAngle)*$ticklen_maj);\n\t$dy_maj=round(cos($aAxisAngle)*$ticklen_maj);\n\t$ticklen_min=3;\n\t$dx_min=round(sin($aAxisAngle)*$ticklen_min);\n\t$dy_min=round(cos($aAxisAngle)*$ticklen_min);\n\t\t\t\n\t$aMajPos=array();\n\t$aMajLabel=array();\n\t\t\t\n\tif( $this->supress_first )\n\t    $aMajLabel[]=\"\";\n\telse\n\t    $aMajLabel[]=$start;\t\n\t$yr=$aScale->RelTranslate($start);\t\n\t$xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0];\n\t$yt=$aPos-round($yr*sin($aAxisAngle));\n\t$aMajPos[]=$xt+2*$dx_maj;\n\t$aMajPos[]=$yt-$aImg->GetFontheight()/2;\n\t$grid[]=$xt;\n\t$grid[]=$yt;\n\n\t$aImg->SetLineWeight($this->weight);\t\t\t\n\t\t\n\tfor($y=$start; $y<=$limit; $y+=$step,++$count  ) {\n\t    $yr=$aScale->RelTranslate($y);\t\n\t    $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0];\n\t    $yt=$aPos-round($yr*sin($aAxisAngle));\n\t    if( $count % 10 == 0 ) {\n\t\t$grid[]=$xt;\n\t\t$grid[]=$yt;\n\t\t$aMajPos[]=$xt+2*$dx_maj;\n\t\t$aMajPos[]=$yt-$aImg->GetFontheight()/2;\t\t\t\t\t\t\t\n\t\tif( !$this->supress_tickmarks )\t{\t\t\n\t\t    if( $this->majcolor!=\"\" ) $aImg->PushColor($this->majcolor);\n\t\t    $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj);\n\t\t    if( $this->majcolor!=\"\" ) $aImg->PopColor();\n\t\t}\n\t\tif( $this->label_formfunc != \"\" ) {\n\t\t    $f=$this->label_formfunc;\n\t\t    $l = call_user_func($f,$nextMajor);\n\t\t}\n\t\telse\n\t\t    $l = $nextMajor;\n\t\t$aMajLabel[]=$l;\t\n\t\t$nextMajor *= 10;\n\t\t$step *= 10;\t\n\t\t$count=1; \t\t\t\t\n\t    }\n\t    else\n\t\tif( !$this->supress_minor_tickmarks )\t{\n\t\t    if( $this->mincolor!=\"\" ) $aImg->PushColor($this->mincolor);\n\t\t    $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min);\n\t\t    if( $this->mincolor!=\"\" ) $aImg->PopColor();\n\t\t}\n\t}\t\t\n    }\t\t\n}\n\t\nclass RadarLinearTicks extends LinearTicks {\n//---------------\n// CONSTRUCTOR\n    function RadarLinearTicks() {\n\t// Empty\n    }\n\n//---------------\n// PUBLIC METHODS\t\n\n    // TODO: Add argument grid\n    function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) {\n\t// Prepare to draw linear ticks\n\t$maj_step_abs = abs($aScale->scale_factor*$this->major_step);\t\n\t$min_step_abs = abs($aScale->scale_factor*$this->minor_step);\t\n\t$nbrmaj = floor(($aScale->world_abs_size)/$maj_step_abs);\n\t$nbrmin = floor(($aScale->world_abs_size)/$min_step_abs);\n\t$skip = round($nbrmin/$nbrmaj); // Don't draw minor ontop of major\n\n\t// Draw major ticks\n\t$ticklen2=$this->major_abs_size;\n\t$dx=round(sin($aAxisAngle)*$ticklen2);\n\t$dy=round(cos($aAxisAngle)*$ticklen2);\n\t$label=$aScale->scale[0]+$this->major_step;\n\t\t\n\t$aImg->SetLineWeight($this->weight);\n\t\t\n\tfor($i=1; $i<=$nbrmaj; ++$i) {\n\t    $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0];\n\t    $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle));\n\n\t    if( $this->label_formfunc != \"\" ) {\n\t\t$f=$this->label_formfunc;\n\t\t$l = call_user_func($f,$label);\n\t    }\n\t    else\n\t\t$l = $label;\n\n\t    $aMajLabel[]=$l;\n\t    $label += $this->major_step;\n\t    $grid[]=$xt;\n\t    $grid[]=$yt;\n\t    $aMajPos[($i-1)*2]=$xt+2*$dx;\n\t    $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2;\t\t\t\t\n\t    if( !$this->supress_tickmarks ) {\n\t\tif( $this->majcolor!=\"\" ) $aImg->PushColor($this->majcolor);\n\t\t$aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy);\n\t\tif( $this->majcolor!=\"\" ) $aImg->PopColor();\n\t    }\n\t}\n\n\t// Draw minor ticks\n\t$ticklen2=$this->minor_abs_size;\n\t$dx=round(sin($aAxisAngle)*$ticklen2);\n\t$dy=round(cos($aAxisAngle)*$ticklen2);\n\tif( !$this->supress_tickmarks && !$this->supress_minor_tickmarks)\t{\n\t    if( $this->mincolor!=\"\" ) $aImg->PushColor($this->mincolor);\t\t\t\t\t\t\n\t    for($i=1; $i<=$nbrmin; ++$i) {\n\t\tif( ($i % $skip) == 0 ) continue;\n\t\t$xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0];\n\t\t$yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle));\n\t\t$aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy);\n\t    }\n\t    if( $this->mincolor!=\"\" ) $aImg->PopColor();\n\t}\n    }\n}\n\n\t\n\n//===================================================\n// CLASS RadarAxis\n// Description: Implements axis for the radar graph\n//===================================================\nclass RadarAxis extends Axis {\n    var $title_color=\"navy\";\n    var $title=null;\n//---------------\n// CONSTRUCTOR\n    function RadarAxis(&$img,&$aScale,$color=array(0,0,0)) {\n\tparent::Axis($img,$aScale,$color);\n\t$this->len=$img->plotheight;\n\t$this->title = new Text();\n\t$this->title->SetFont(FF_FONT1,FS_BOLD);\n\t$this->color = array(0,0,0);\n    }\n//---------------\n// PUBLIC METHODS\t\n    function SetTickLabels($l) {\n\t$this->ticks_label = $l;\n    }\n\t\n\t\n    // Stroke the axis \n    // $pos \t\t\t= Vertical position of axis\n    // $aAxisAngle = Axis angle\n    // $grid\t\t\t= Returns an array with positions used to draw the grid\n    //\t$lf\t\t\t= Label flag, TRUE if the axis should have labels\n    function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) {\n\t$this->img->SetColor($this->color);\n\t\t\n\t// Determine end points for the axis\n\t$x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]);\n\t$y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle));\n\t\t\n\t// Draw axis\n\t$this->img->SetColor($this->color);\n\t$this->img->SetLineWeight($this->weight);\n\tif( !$this->hide )\n\t    $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y);\n\t\n\t$this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel);\n\t\t\n\t// Draw labels\n\tif( $lf && !$this->hide ) {\n\t    $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);\t\n\t    $this->img->SetTextAlign(\"left\",\"top\");\n\t    $this->img->SetColor($this->label_color);\n\t\t\t\n\t    // majpos contains (x,y) coordinates for labels\n\t    if( ! $this->hide_labels ) {\n\t\t$n = floor(count($majpos)/2);\n\t\tfor($i=0; $i < $n; ++$i) {\n\t\t    if( $this->ticks_label != null && isset($this->ticks_label[$i]) )\n\t\t\t$this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]);\n\t\t    else\n\t\t\t$this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]);\n\t\t}\n\t    }\n\t}\n\t$this->_StrokeAxisTitle($pos,$aAxisAngle,$title);\n    }\n//---------------\n// PRIVATE METHODS\t\n\t\n    function _StrokeAxisTitle($pos,$aAxisAngle,$title) {\n\t$this->title->Set($title);\n\t$marg=6+$this->title->margin;\n\t$xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]);\n\t$yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle));\n\n\t// Position the axis title. \n\t// dx, dy is the offset from the top left corner of the bounding box that sorrounds the text\n\t// that intersects with the extension of the corresponding axis. The code looks a little\n\t// bit messy but this is really the only way of having a reasonable position of the\n\t// axis titles.\n\tif( $this->title->iWordwrap > 0 ) {\n\t    $title = wordwrap($title,$this->title->iWordwrap,\"\\n\");\n\t}\n\n\t$h=$this->img->GetTextHeight($title)*1.2;\n\t$w=$this->img->GetTextWidth($title)*1.2;\n\twhile( $aAxisAngle > 2*M_PI ) $aAxisAngle -= 2*M_PI;\n\n\tif( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=0;\n\tif( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; \n\tif( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1;\n\tif( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI);\n\t\t\n\tif( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI;\n\tif( $aAxisAngle<=M_PI/4 ) $dy=(1-$aAxisAngle*2/M_PI);\n\tif( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1;\n\tif( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI);\n\tif( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0;\n\t\t\n\tif( !$this->hide ) {\n\t    $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title);\n\t}\n    }\n\t\t\n\t\n} // Class\n\n\n//===================================================\n// CLASS RadarGrid\n// Description: Draws grid for the radar graph\n//===================================================\nclass RadarGrid extends Grid {\n//------------\n// CONSTRUCTOR\n    function RadarGrid() {\n    }\n\n//----------------\n// PRIVATE METHODS\t\n    function Stroke(&$img,&$grid) {\n\tif( !$this->show ) return;\n\t$nbrticks = count($grid[0])/2;\n\t$nbrpnts = count($grid);\n\t$img->SetColor($this->grid_color);\n\t$img->SetLineWeight($this->weight);\n\tfor($i=0; $i<$nbrticks; ++$i) {\n\t    for($j=0; $j<$nbrpnts; ++$j) {\n\t\t$pnts[$j*2]=$grid[$j][$i*2];\n\t\t$pnts[$j*2+1]=$grid[$j][$i*2+1];\n\t    }\n\t    for($k=0; $k<$nbrpnts; ++$k ){\n\t\t$l=($k+1)%$nbrpnts;\n\t\tif( $this->type == \"solid\" )\n\t\t    $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]);\n\t\telseif( $this->type == \"dotted\" )\n\t\t    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6);\n\t\telseif( $this->type == \"dashed\" )\n\t\t    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4);\n\t\telseif( $this->type == \"longdashed\" )\n\t\t    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6);\n\t    }\n\t    $pnts=array();\n\t}\n    }\n} // Class\n\n\n//===================================================\n// CLASS RadarPlot\n// Description: Plot a radarplot\n//===================================================\nclass RadarPlot {\n    var $data=array();\n    var $fill=false, $fill_color=array(200,170,180);\n    var $color=array(0,0,0);\n    var $legend=\"\";\n    var $weight=1;\n    var $linestyle='solid';\n    var $mark=null;\n//---------------\n// CONSTRUCTOR\n    function RadarPlot($data) {\n\t$this->data = $data;\n\t$this->mark = new PlotMark();\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function Min() {\n\treturn Min($this->data);\n    }\n\t\n    function Max() {\n\treturn Max($this->data);\n    }\n\t\n    function SetLegend($legend) {\n\t$this->legend=$legend;\n    }\n\n    function SetLineStyle($aStyle) {\n\t$this->linestyle=$aStyle;\n    }\n\t\n    function SetLineWeight($w) {\n\t$this->weight=$w;\n    }\n\t\t\n    function SetFillColor($aColor) {\n\t$this->fill_color = $aColor;\n\t$this->fill = true;\t\t\n    }\n    \n    function SetFill($f=true) {\n\t$this->fill = $f;\n    }\n    \n    function SetColor($aColor,$aFillColor=false) {\n\t$this->color = $aColor;\n\tif( $aFillColor ) {\n\t    $this->SetFillColor($aFillColor);\n\t    $this->fill = true;\n\t}\n    }\n\t\n    function GetCSIMareas() {\n\tJpGraphError::RaiseL(18001);\n//(\"Client side image maps not supported for RadarPlots.\");\n    }\n\t\n    function Stroke(&$img, $pos, &$scale, $startangle) {\n\t$nbrpnts = count($this->data);\n\t$astep=2*M_PI/$nbrpnts;\t\t\n\t$a=$startangle;\n\t\t\n\t// Rotate each point to the correct axis-angle\n\t// TODO: Update for LogScale\n\tfor($i=0; $i<$nbrpnts; ++$i) {\n\t    //$c=$this->data[$i];\n\t    $cs=$scale->RelTranslate($this->data[$i]);\n\t    $x=round($cs*cos($a)+$scale->scale_abs[0]);\n\t    $y=round($pos-$cs*sin($a));\n\t    /*\n\t      $c=log10($c);\n\t      $x=round(($c-$scale->scale[0])*$scale->scale_factor*cos($a)+$scale->scale_abs[0]);\n\t      $y=round($pos-($c-$scale->scale[0])*$scale->scale_factor*sin($a));\t\t\n\t    */\n\t    $pnts[$i*2]=$x;\n\t    $pnts[$i*2+1]=$y;\n\t    $a += $astep;\n\t}\n\tif( $this->fill ) {\n\t    $img->SetColor($this->fill_color);\n\t    $img->FilledPolygon($pnts);\n\t}\n\t$img->SetLineWeight($this->weight);\n\t$img->SetColor($this->color);\n\t$img->SetLineStyle($this->linestyle);\n\t$pnts[]=$pnts[0];\n\t$pnts[]=$pnts[1];\n\t$img->Polygon($pnts);\n\t$img->SetLineStyle('solid'); // Reset line style to default\n\t// Add plotmarks on top\n\tif( $this->mark->show ) {\n\t    for($i=0; $i < $nbrpnts; ++$i) {\n\t\t$this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); \n\t    }\n\t}\n\n    }\n\t\n//---------------\n// PRIVATE METHODS\n    function GetCount() {\n\treturn count($this->data);\n    }\n\t\n    function Legend(&$graph) {\n\tif( $this->legend==\"\" ) return;\n\tif( $this->fill )\n\t    $graph->legend->Add($this->legend,$this->fill_color,$this->mark);\n\telse\n\t    $graph->legend->Add($this->legend,$this->color,$this->mark);\t\n    }\n\t\n} // Class\n\n//===================================================\n// CLASS RadarGraph\n// Description: Main container for a radar graph\n//===================================================\nclass RadarGraph extends Graph {\n    var $posx;\n    var $posy;\n    var $len;\t\t\n    var $plots=null, $axis_title=null;\n    var $grid,$axis=null;\n//---------------\n// CONSTRUCTOR\n    function RadarGraph($width=300,$height=200,$cachedName=\"\",$timeout=0,$inline=1) {\n\t$this->Graph($width,$height,$cachedName,$timeout,$inline);\n\t$this->posx=$width/2;\n\t$this->posy=$height/2;\n\t$this->len=min($width,$height)*0.35;\n\t$this->SetColor(array(255,255,255));\n\t$this->SetTickDensity(TICKD_NORMAL);\n\t$this->SetScale(\"lin\");\n\t$this->SetGridDepth(DEPTH_FRONT);\n\n    }\n\n//---------------\n// PUBLIC METHODS\n    function SupressTickMarks($f=true) {\n    \tif( ERR_DEPRECATED )\n\t    JpGraphError::RaiseL(18002);\n//('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.');\n\t$this->axis->scale->ticks->SupressTickMarks($f);\n    }\n\n    function HideTickMarks($aFlag=true) {\n\t\t$this->axis->scale->ticks->SupressTickMarks($aFlag);\n    }\n    \n    function ShowMinorTickmarks($aFlag=true) {\n    \t$this->yscale->ticks->SupressMinorTickMarks(!$aFlag);\n    }\n\t\n    function SetScale($axtype,$ymin=1,$ymax=1) {\n\tif( $axtype != \"lin\" && $axtype != \"log\" ) {\n\t    JpGraphError::RaiseL(18003,$axtype);\n//(\"Illegal scale for radarplot ($axtype). Must be \\\"lin\\\" or \\\"log\\\"\");\n\t}\n\tif( $axtype==\"lin\" ) {\n\t    $this->yscale = & new LinearScale($ymin,$ymax);\n\t    $this->yscale->ticks = & new RadarLinearTicks();\n\t    $this->yscale->ticks->SupressMinorTickMarks();\n\t}\n\telseif( $axtype==\"log\" ) {\n\t    $this->yscale = & new LogScale($ymin,$ymax);\n\t    $this->yscale->ticks = & new RadarLogTicks();\n\t}\n\t\t\n\t$this->axis = & new RadarAxis($this->img,$this->yscale);\n\t$this->grid = & new RadarGrid();\t\t\n    }\n\n    function SetSize($aSize) {\n\tif( $aSize < 0.1 || $aSize>1 )\n\t    JpGraphError::RaiseL(18004,$aSize);\n//(\"Radar Plot size must be between 0.1 and 1. (Your value=$s)\");\n\t$this->len=min($this->img->width,$this->img->height)*$aSize/2;\n    }\n\n    function SetPlotSize($aSize) {\n\t$this->SetSize($aSize);\n    }\n\n    function SetTickDensity($densy=TICKD_NORMAL) {\n\t$this->ytick_factor=25;\t\t\n\tswitch( $densy ) {\n\t    case TICKD_DENSE:\n\t\t$this->ytick_factor=12;\t\t\t\n\t    break;\n\t    case TICKD_NORMAL:\n\t\t$this->ytick_factor=25;\t\t\t\n\t    break;\n\t    case TICKD_SPARSE:\n\t\t$this->ytick_factor=40;\t\t\t\n\t    break;\n\t    case TICKD_VERYSPARSE:\n\t\t$this->ytick_factor=70;\t\t\t\n\t    break;\t\t\n\t    default:\n\t\tJpGraphError::RaiseL(18005,$densy);\n//(\"RadarPlot Unsupported Tick density: $densy\");\n\t}\n    }\n\n    function SetPos($px,$py=0.5) {\n\t$this->SetCenter($px,$py);\n    }\n\n    function SetCenter($px,$py=0.5) {\n\tassert($px > 0 && $py > 0 );\n\t$this->posx=$this->img->width*$px;\n\t$this->posy=$this->img->height*$py;\n    }\n\n    function SetColor($c) {\n\t$this->SetMarginColor($c);\n    }\n\t\t\t\n    function SetTitles($title) {\n\t$this->axis_title = $title;\n    }\n\n    function Add(&$splot) {\n\t$this->plots[]=$splot;\n    }\n\t\n    function GetPlotsYMinMax() {\n\t$min=$this->plots[0]->Min();\n\t$max=$this->plots[0]->Max();\n\tforeach( $this->plots as $p ) {\n\t    $max=max($max,$p->Max());\n\t    $min=min($min,$p->Min());\n\t}\n\tif( $min < 0 ) \n\t    JpGraphError::RaiseL(18006,$min);\n//(\"Minimum data $min (Radar plots should only be used when all data points > 0)\");\n\treturn array($min,$max);\n    }\t\n\n    // Stroke the Radar graph\n    function Stroke($aStrokeFileName=\"\") {\n\t$n = count($this->plots);\n\t// Set Y-scale\n\tif( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {\n\t    list($min,$max) = $this->GetPlotsYMinMax();\n\t    $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor);\n\t}\n\t// Set start position end length of scale (in absolute pixels)\n\t$this->yscale->SetConstants($this->posx,$this->len);\n\t\t\n\t// We need as many axis as there are data points\n\t$nbrpnts=$this->plots[0]->GetCount();\n\t\t\n\t// If we have no titles just number the axis 1,2,3,...\n\tif( $this->axis_title==null ) {\n\t    for($i=0; $i < $nbrpnts; ++$i ) \n\t\t$this->axis_title[$i] = $i+1;\n\t}\n\telseif(count($this->axis_title)<$nbrpnts) \n\t    JpGraphError::RaiseL(18007);\n//(\"Number of titles does not match number of points in plot.\");\n\tfor($i=0; $i < $n; ++$i )\n\t    if( $nbrpnts != $this->plots[$i]->GetCount() )\n\t\tJpGraphError::RaiseL(18008);\n//(\"Each radar plot must have the same number of data points.\");\n\n\tif( $this->background_image != \"\" ) {\n\t    $this->StrokeFrameBackground();\n\t}\n\telse {\t\n\t    $this->StrokeFrame();\n\t}\n\t$astep=2*M_PI/$nbrpnts;\n\n\t// Prepare legends\n\tfor($i=0; $i < $n; ++$i)\n\t    $this->plots[$i]->Legend($this);\n\t$this->legend->Stroke($this->img);\t\t\t\n\t$this->footer->Stroke($this->img);\t\t\t\n\n\tif( $this->grid_depth == DEPTH_BACK ) {\n\t    // Draw axis and grid\n\t    for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) {\n\t\t$this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0);\n\t    }\t\n\t}\n\t\t\n\t// Plot points\n\t$a=M_PI/2;\n\tfor($i=0; $i < $n; ++$i )\n\t    $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a);\n\t\t\n\tif( $this->grid_depth != DEPTH_BACK ) {\n\t    // Draw axis and grid\n\t    for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) {\n\t\t$this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0);\n\t    }\t\n\t}\n\t$this->grid->Stroke($this->img,$grid);\n\t$this->StrokeTitles();\n\t\n\t// Stroke texts\n\tif( $this->texts != null ) {\n\t    foreach( $this->texts as $t) \n\t\t$t->Stroke($this->img);\n\t}\n\n\t// Should we do any final image transformation\n\tif( $this->iImgTrans ) {\n\t    if( !class_exists('ImgTrans') ) {\n\t\trequire_once('jpgraph_imgtrans.php');\n\t    }\n\t       \n\t    $tform = new ImgTrans($this->img->img);\n\t    $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,\n\t\t\t\t\t     $this->iImgTransDirection,$this->iImgTransHighQ,\n\t\t\t\t\t     $this->iImgTransMinSize,$this->iImgTransFillColor,\n\t\t\t\t\t     $this->iImgTransBorder);\n\t}\n\t\n\t// If the filename is given as the special \"__handle\"\n\t// then the image handler is returned and the image is NOT\n\t// streamed back\n\tif( $aStrokeFileName == _IMG_HANDLER ) {\n\t    return $this->img->img;\n\t    }\n\telse {\n\t    // Finally stream the generated picture\t\t\t\t\t\n\t    $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,\n\t\t\t\t       $aStrokeFileName);\t\t\n\t}\n    }\n} // Class\n\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_regstat.php",
    "content": "<?php \n/*=======================================================================\n// File:\tJPGRAPH_REGSTAT.PHP\n// Description: Regression and statistical analysis helper classes\n// Created: \t2002-12-01\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_regstat.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//------------------------------------------------------------------------\n// CLASS Spline\n// Create a new data array from an existing data array but with more points.\n// The new points are interpolated using a cubic spline algorithm\n//------------------------------------------------------------------------\nclass Spline {\n    // 3:rd degree polynom approximation\n\n    var $xdata,$ydata;   // Data vectors\n    var $y2;\t\t // 2:nd derivate of ydata\t\n    var $n=0;\n\n    function Spline($xdata,$ydata) {\n\t$this->y2 = array();\n\t$this->xdata = $xdata;\n\t$this->ydata = $ydata;\n\n\t$n = count($ydata);\n\t$this->n = $n;\n\tif( $this->n !== count($xdata) ) {\n\t    JpGraphError::RaiseL(19001);\n//('Spline: Number of X and Y coordinates must be the same');\n\t}\n\n\t// Natural spline 2:derivate == 0 at endpoints\n\t$this->y2[0]    = 0.0;\n\t$this->y2[$n-1] = 0.0;\n\t$delta[0] = 0.0;\n\n\t// Calculate 2:nd derivate\n\tfor($i=1; $i < $n-1; ++$i) {\n\t    $d = ($xdata[$i+1]-$xdata[$i-1]);\n\t    if( $d == 0  ) {\n\t\tJpGraphError::RaiseL(19002);\n//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.');\n\t    }\n\t    $s = ($xdata[$i]-$xdata[$i-1])/$d;\n\t    $p = $s*$this->y2[$i-1]+2.0;\n\t    $this->y2[$i] = ($s-1.0)/$p;\n\t    $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - \n\t\t         ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]);\n\t    $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p;\n\t}\n\n\t// Backward substitution\n\tfor( $j=$n-2; $j >= 0; --$j ) {\n\t    $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j];\n\t}\n    }\n\n    // Return the two new data vectors\n    function Get($num=50) {\n\t$n = $this->n ;\n\t$step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1);\n\t$xnew=array();\n\t$ynew=array();\n\t$xnew[0] = $this->xdata[0];\n\t$ynew[0] = $this->ydata[0];\n\tfor( $j=1; $j < $num; ++$j ) {\n\t    $xnew[$j] = $xnew[0]+$j*$step;\n\t    $ynew[$j] = $this->Interpolate($xnew[$j]);\n\t}\n\treturn array($xnew,$ynew);\n    }\n\n    // Return a single interpolated Y-value from an x value\n    function Interpolate($xpoint) {\n\n\t$max = $this->n-1;\n\t$min = 0;\n\n\t// Binary search to find interval\n\twhile( $max-$min > 1 ) {\n\t    $k = ($max+$min) / 2;\n\t    if( $this->xdata[$k] > $xpoint ) \n\t\t$max=$k;\n\t    else \n\t\t$min=$k;\n\t}\t\n\n\t// Each interval is interpolated by a 3:degree polynom function\n\t$h = $this->xdata[$max]-$this->xdata[$min];\n\n\tif( $h == 0  ) {\n\t    JpGraphError::RaiseL(19002);\n//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.');\n\t}\n\n\n\t$a = ($this->xdata[$max]-$xpoint)/$h;\n\t$b = ($xpoint-$this->xdata[$min])/$h;\n\treturn $a*$this->ydata[$min]+$b*$this->ydata[$max]+\n\t     (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0;\n    }\n}\n\n//------------------------------------------------------------------------\n// CLASS Bezier\n// Create a new data array from a number of control points\n//------------------------------------------------------------------------\nclass Bezier {\n/**\n * @author Thomas Despoix, openXtrem company\n * @license released under QPL\n * @abstract Bezier interoplated point generation,\n * computed from control points data sets, based on Paul Bourke algorithm :\n * http://astronomy.swin.edu.au/~pbourke/curves/bezier/\n */\n    var $datax = array();\n    var $datay = array();\n    var $n=0;\n \n    function Bezier($datax, $datay, $attraction_factor = 1) {\n\t// Adding control point multiple time will raise their attraction power over the curve   \n\t$this->n = count($datax);\n\tif( $this->n !== count($datay) ) {\n\t    JpGraphError::RaiseL(19003);\n//('Bezier: Number of X and Y coordinates must be the same');\n\t}\n\t$idx=0;\n\tforeach($datax as $datumx) {\n\t    for ($i = 0; $i < $attraction_factor; $i++) {\n\t\t$this->datax[$idx++] = $datumx;\n\t    }\n\t}\n   \t$idx=0;\n\tforeach($datay as $datumy) {\n\t    for ($i = 0; $i < $attraction_factor; $i++) {\n\t\t$this->datay[$idx++] = $datumy;\n\t    }\n\t}\n    }\n\n    function Get($steps) {\n\t$datax = array();\n\t$datay = array();\n\tfor ($i = 0; $i < $steps; $i++) {\n\t    list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps);       \n\t    $datax[] = $datumx;\n\t    $datay[] = $datumy;\n\t}\n   \n\t$datax[] = end($this->datax);\n\t$datay[] = end($this->datay);\n   \n\treturn array($datax, $datay);\n    }\n \n    function GetPoint($mu) {\n\t$n = $this->n - 1;\n\t$k = 0;\n\t$kn = 0;\n\t$nn = 0;\n\t$nkn = 0;\n\t$blend = 0.0;\n\t$newx = 0.0;\n\t$newy = 0.0;\n\n\t$muk = 1.0;\n\t$munk = (double) pow(1-$mu,(double) $n);\n\n\tfor ($k = 0; $k <= $n; $k++) {\n\t    $nn = $n;\n\t    $kn = $k;\n\t    $nkn = $n - $k;\n\t    $blend = $muk * $munk;\n\t    $muk *= $mu;\n\t    $munk /= (1-$mu);\n\t    while ($nn >= 1) {\n\t\t$blend *= $nn;\n\t\t$nn--;\n\t\tif ($kn > 1) {\n\t\t    $blend /= (double) $kn;\n\t\t    $kn--;\n\t\t}\n\t\tif ($nkn > 1) {\n\t\t    $blend /= (double) $nkn;\n\t\t    $nkn--;\n\t\t}\n\t    }\n\t    $newx += $this->datax[$k] * $blend;\n\t    $newy += $this->datay[$k] * $blend;\n\t}\n\n\treturn array($newx, $newy);\n    }\n}\n\n// EOF\n?>\n"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_scatter.php",
    "content": "<?php \n/*=======================================================================\n// File:\tJPGRAPH_SCATTER.PHP\n// Description: Scatter (and impuls) plot extension for JpGraph\n// Created: \t2001-02-11\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_scatter.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\nrequire_once ('jpgraph_plotmark.inc');\n\n//===================================================\n// CLASS FieldArrow\n// Description: Draw an arrow at (x,y) with angle a\n//===================================================\nclass FieldArrow {\n    var $iSize=10;  // Length in pixels for  arrow\n    var $iArrowSize = 2;\n    var $iColor='black';\n    var $isizespec = array(\n\tarray(2,1),array(3,2),array(4,3),array(6,4),array(7,4),array(8,5),array(10,6),array(12,7),array(16,8),array(20,10));\n    function FieldArrow() {\n    }\n\n    function SetSize($aSize,$aArrowSize=2) {\n\t$this->iSize = $aSize;\n\t$this->iArrowSize = $aArrowSize;\n    }\n\n    function SetColor($aColor) {\n\t$this->iColor = $aColor;\n    }\n\n    function Stroke(&$aImg,$x,$y,$a) {\n\t// First rotate the center coordinates\n\tlist($x,$y) = $aImg->Rotate($x,$y);\n\n\t$old_origin = $aImg->SetCenter($x,$y);\n\t$old_a = $aImg->a;\n\t$aImg->SetAngle(-$a+$old_a);\n\n\t$dx = round($this->iSize/2);\n\t$c = array($x-$dx,$y,$x+$dx,$y);\n\t$x += $dx;\n\n\tlist($dx,$dy) = $this->isizespec[$this->iArrowSize];\n\t$ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y);\n\n\t$aImg->SetColor($this->iColor);\n\t$aImg->Polygon($c);\n\t$aImg->FilledPolygon($ca);\n\n\t$aImg->SetCenter($old_origin[0],$old_origin[1]);\n\t$aImg->SetAngle($old_a);\n    }\n}\n\n//===================================================\n// CLASS FieldPlot\n// Description: Render a field plot\n//===================================================\nclass FieldPlot extends Plot {\n    var $iAngles;\n    var $iCallback='';\n    function FieldPlot($datay,$datax,$angles) {\n\tif( (count($datax) != count($datay)) )\n\t    JpGraphError::RaiseL(20001);//(\"Fieldplots must have equal number of X and Y points.\");\n\tif( (count($datax) != count($angles)) )\n\t    JpGraphError::RaiseL(20002);//(\"Fieldplots must have an angle specified for each X and Y points.\");\n\t\n\t$this->iAngles = $angles;\n\n\t$this->Plot($datay,$datax);\n\t$this->value->SetAlign('center','center');\n\t$this->value->SetMargin(15);\n\n\t$this->arrow = new FieldArrow();\n    }\n\n    function SetCallback($aFunc) {\n\t$this->iCallback = $aFunc;\n    }\n\n    function Stroke(&$img,&$xscale,&$yscale) {\n\n\t// Remeber base color and size\n\t$bc = $this->arrow->iColor;\n\t$bs = $this->arrow->iSize;\n\t$bas = $this->arrow->iArrowSize;\n\n\tfor( $i=0; $i<$this->numpoints; ++$i ) {\n\t    // Skip null values\n\t    if( $this->coords[0][$i]===\"\" )\n\t\tcontinue;\n\n\t    $f = $this->iCallback;\n\t    if( $f != \"\" ) {\n\t\tlist($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]);\n\t\t// Fall back on global data if the callback isn't set\n\t\tif( $cc  == \"\" ) $cc = $bc;\n\t\tif( $cs  == \"\" ) $cs = $bs;\n\t\tif( $cas == \"\" ) $cas = $bas;\n\t\t//echo \"f=$f, cc=$cc, cs=$cs, cas=$cas<br>\";\n\t\t$this->arrow->SetColor($cc);\t    \n\t\t$this->arrow->SetSize($cs,$cas);\n\t    }\n\n\t    $xt = $xscale->Translate($this->coords[1][$i]);\n\t    $yt = $yscale->Translate($this->coords[0][$i]);\t\n\n\t    $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]);\n\t    $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt);\n\t}\n    }\n\t\n    // Framework function\n    function Legend(&$aGraph) {\n\tif( $this->legend != \"\" ) {\n\t    $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0,\n\t\t\t\t $this->legendcsimtarget,$this->legendcsimalt);\n\t}\n    }\t\n}\n\n//===================================================\n// CLASS ScatterPlot\n// Description: Render X and Y plots\n//===================================================\nclass ScatterPlot extends Plot {\n    var $impuls = false;\n    var $linkpoints = false, $linkpointweight=1, $linkpointcolor=\"black\";\n//---------------\n// CONSTRUCTOR\n    function ScatterPlot($datay,$datax=false) {\n\tif( (count($datax) != count($datay)) && is_array($datax))\n\t    JpGraphError::RaiseL(20003);//(\"Scatterplot must have equal number of X and Y points.\");\n\t$this->Plot($datay,$datax);\n\t$this->mark = new PlotMark();\n\t$this->mark->SetType(MARK_SQUARE);\n\t$this->mark->SetColor($this->color);\n\t$this->value->SetAlign('center','center');\n\t$this->value->SetMargin(0);\n    }\n\n//---------------\n// PUBLIC METHODS\t\n    function SetImpuls($f=true) {\n\t$this->impuls = $f;\n    }   \n\n    // Combine the scatter plot points with a line\n    function SetLinkPoints($aFlag=true,$aColor=\"black\",$aWeight=1) {\n\t$this->linkpoints=$aFlag;\n\t$this->linkpointcolor=$aColor;\n\t$this->linkpointweight=$aWeight;\n    }\n\n    function Stroke(&$img,&$xscale,&$yscale) {\n\n\t$ymin=$yscale->scale_abs[0];\n\tif( $yscale->scale[0] < 0 )\n\t    $yzero=$yscale->Translate(0);\n\telse\n\t    $yzero=$yscale->scale_abs[0];\n\t    \n\t$this->csimareas = '';\n\tfor( $i=0; $i<$this->numpoints; ++$i ) {\n\n\t    // Skip null values\n\t    if( $this->coords[0][$i]===\"\" || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x')\n\t\tcontinue;\n\n\t    if( isset($this->coords[1]) )\n\t\t$xt = $xscale->Translate($this->coords[1][$i]);\n\t    else\n\t\t$xt = $xscale->Translate($i);\n\t    $yt = $yscale->Translate($this->coords[0][$i]);\t\n\n\n\t    if( $this->linkpoints && isset($yt_old) ) {\n\t\t$img->SetColor($this->linkpointcolor);\n\t\t$img->SetLineWeight($this->linkpointweight);\n\t\t$img->Line($xt_old,$yt_old,$xt,$yt);\n\t    }\n\n\t    if( $this->impuls ) {\n\t\t$img->SetColor($this->color);\n\t\t$img->SetLineWeight($this->weight);\n\t\t$img->Line($xt,$yzero,$xt,$yt);\n\t    }\n\t\n\t    if( !empty($this->csimtargets[$i]) ) {\n\t        $this->mark->SetCSIMTarget($this->csimtargets[$i]);\n\t        $this->mark->SetCSIMAlt($this->csimalts[$i]);\n\t    }\n\t    \n\t    if( isset($this->coords[1]) ) {\n\t\t$this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]);\n\t    }\n\t    else {\n\t\t$this->mark->SetCSIMAltVal($this->coords[0][$i],$i);\n\t    }\n\n\t    $this->mark->Stroke($img,$xt,$yt);\n\t\n\t    $this->csimareas .= $this->mark->GetCSIMAreas();\n\t    $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt);\n\n\t    $xt_old = $xt;\n\t    $yt_old = $yt;\n\t}\n    }\n\t\n    // Framework function\n    function Legend(&$aGraph) {\n\tif( $this->legend != \"\" ) {\n\t    $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0,\n\t\t\t\t $this->legendcsimtarget,$this->legendcsimalt);\n\t}\n    }\t\n} // Class\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_stock.php",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_STOCK.PHP\n// Description:\tStock plot extension for JpGraph\n// Created: \t2003-01-27\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_stock.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//===================================================\n// CLASS StockPlot\n//===================================================\nclass StockPlot extends Plot {\n    var $iTupleSize = 4;\n    var $iWidth=9;\n    var $iEndLines=1;\n    var $iStockColor1='white',$iStockColor2='darkred',$iStockColor3='darkred';\n//---------------\n// CONSTRUCTOR\n    function StockPlot(&$datay,$datax=false) {\n\tif( count($datay) % $this->iTupleSize ) {\n\t    JpGraphError::RaiseL(21001,$this->iTupleSize);//('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.');\n\t}\n\t$this->Plot($datay,$datax);\n\t$this->numpoints /= $this->iTupleSize;\n    }\n//---------------\n// PUBLIC METHODS\n\t\n    function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') {\n\t$this->color = $aColor;\n\t$this->iStockColor1 = $aColor1;\n\t$this->iStockColor2 = $aColor2;\n\t$this->iStockColor3 = $aColor3;\n    }\n\n    function SetWidth($aWidth) {\n\t// Make sure it's odd\n\t$this->iWidth = 2*floor($aWidth/2)+1;\n    }\n\n    function HideEndLines($aHide=true) {\n\t$this->iEndLines = !$aHide;\n    }\n\n    // Gets called before any axis are stroked\n    function PreStrokeAdjust(&$graph) {\n\tif( $this->center ) {\n\t    $a=0.5; $b=0.5;\n\t    $this->numpoints++;\n\t} else {\n\t    $a=0; $b=0;\n\t}\n\t$graph->xaxis->scale->ticks->SetXLabelOffset($a);\n\t$graph->SetTextScaleOff($b);\t\t\t\t\t\t\n    }\n\t\n    // Stroke stock plot\n    function Stroke(&$img,$xscale,$yscale) {\n\t$n=$this->numpoints;\n\tif( $this->center ) $n--;\n\tif( isset($this->coords[1]) ) {\n\t    if( count($this->coords[1])!=$n )\n\t\tJpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);\n//(\"Number of X and Y points are not equal. Number of X-points:\".count($this->coords[1]).\" Number of Y-points:$numpoints\");\n\t    else\n\t\t$exist_x = true;\n\t}\n\telse \n\t    $exist_x = false;\n\n\tif( $exist_x )\n\t    $xs=$this->coords[1][0];\n\telse\n\t    $xs=0;\n\t\t\n\t$ts = $this->iTupleSize;\n\t$this->csimareas = '';\n\tfor( $i=0; $i<$n; ++$i) {\n\n\t    //If value is NULL, then don't draw a bar at all\n \t    if ($this->coords[0][$i] === null) continue;\n\n\t    if( $exist_x ) $x=$this->coords[1][$i];\n\t    else $x=$i;\n\t    $xt = $xscale->Translate($x);\n\t    \n\t    $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ;\n\t    $yopen  = $yscale->Translate($this->coords[0][$i*$ts]);\n\t    $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]);\n\t    $ymin   = $yscale->Translate($this->coords[0][$i*$ts+2]);\n\t    $ymax   = $yscale->Translate($this->coords[0][$i*$ts+3]);\n\n\t    $dx = floor($this->iWidth/2);\n\t    $xl = $xt - $dx;\n\t    $xr = $xt + $dx;\n\n\t    if( $neg ) \n\t\t$img->SetColor($this->iStockColor3);\n\t    else\n\t\t$img->SetColor($this->iStockColor1);\n\t    $img->FilledRectangle($xl,$yopen,$xr,$yclose);\n\t    $img->SetLineWeight($this->weight);\n\t    if( $neg ) \n\t\t$img->SetColor($this->iStockColor2);\n\t    else\n\t\t$img->SetColor($this->color);\n\t\n\t    $img->Rectangle($xl,$yopen,$xr,$yclose);\n\n\t    if( $yopen < $yclose ) {\n\t\t$ytop = $yopen ;\n\t\t$ybottom = $yclose ;\n\t    }\n\t    else {\n\t\t$ytop = $yclose ;\n\t\t$ybottom = $yopen ;\n\t    }\n\t    $img->SetColor($this->color);\n\t    $img->Line($xt,$ytop,$xt,$ymax);\n\t    $img->Line($xt,$ybottom,$xt,$ymin);\n\n\t    if( $this->iEndLines ) {\n\t\t$img->Line($xl,$ymax,$xr,$ymax);\n\t\t$img->Line($xl,$ymin,$xr,$ymin);\n\t    }\n\n\t    // A chance for subclasses to add things to the bar\n\t    // for data point i\n\t    $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg);\n\n\t    // Setup image maps\n\t    if( !empty($this->csimtargets[$i]) ) {\n\t\t$this->csimareas.= '<area shape=\"rect\" coords=\"'.\n\t\t    round($xl).','.round($ytop).','.\n\t\t    round($xr).','.round($ybottom).'\" ';   \n\t\t$this->csimareas .= ' href=\"'.$this->csimtargets[$i].'\"';\n\t\tif( !empty($this->csimalts[$i]) ) {\n\t\t    $sval=$this->csimalts[$i];\n\t\t    $this->csimareas .= \" title=\\\"$sval\\\" \";\n\t\t}\n\t\t$this->csimareas.= \" alt=\\\"$sval\\\" />\\n\";\n\t    }\n\t}\t\t\t\n\treturn true;\n    }\n\n    // A hook for subclasses to modify the plot\n    function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {}\n\n} // Class\n\n//===================================================\n// CLASS BoxPlot\n//===================================================\nclass BoxPlot extends StockPlot {\n    var $iPColor='black',$iNColor='white';\n    function BoxPlot($datay,$datax=false) {\n\t$this->iTupleSize=5;\n\tparent::StockPlot($datay,$datax);\n    }\n\n    function SetMedianColor($aPos,$aNeg) {\n\t$this->iPColor = $aPos;\n\t$this->iNColor = $aNeg;\n    }\n\n    function ModBox(&$img,$xscale,$yscale,$i,$xl,$xr,$neg) {\n\tif( $neg ) \n\t    $img->SetColor($this->iNColor);\n\telse\n\t    $img->SetColor($this->iPColor);\n\t\n\t$y = $yscale->Translate($this->coords[0][$i*5+4]);\n\t$img->Line($xl,$y,$xr,$y);\n    }\n}\n\n/* EOF */\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/jpgraph_utils.inc",
    "content": "<?php\n/*=======================================================================\n// File: \tJPGRAPH_UTILS.INC\n// Description: Collection of non-essential \"nice to have\" utilities \n// Created: \t2005-11-20\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: jpgraph_utils.inc,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n//===================================================\n// CLASS FuncGenerator\n// Description: Utility class to help generate data for function plots. \n// The class supports both parametric and regular functions.\n//===================================================\nclass FuncGenerator {\n    var $iFunc='',$iXFunc='',$iMin,$iMax,$iStepSize;\n\t\n    function FuncGenerator($aFunc,$aXFunc='') {\n\t$this->iFunc = $aFunc;\n\t$this->iXFunc = $aXFunc;\n    }\n\t\n    function E($aXMin,$aXMax,$aSteps=50) {\n\t$this->iMin = $aXMin;\n\t$this->iMax = $aXMax;\n\t$this->iStepSize = ($aXMax-$aXMin)/$aSteps;\n\n\tif( $this->iXFunc != '' )\n\t    $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}';\n\telseif( $this->iFunc != '' )\n\t    $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;';\n\telse\n\t    JpGraphError::RaiseL(24001);//('FuncGenerator : No function specified. ');\n\t\t\t\n\t@eval($t);\n\t\t\n\t// If there is an error in the function specifcation this is the only\n\t// way we can discover that.\n\tif( empty($xa) || empty($ya) )\n\t    JpGraphError::RaiseL(24002);//('FuncGenerator : Syntax error in function specification ');\n\t\t\t\t\n\treturn array($xa,$ya);\n    }\n}\n\n//=============================================================================\n// CLASS SymChar\n// Description: Code values for some commonly used characters that \n//              normally isn't available directly on the keyboard, for example\n//              mathematical and greek symbols.\n//=============================================================================\nclass  SymChar {\n    function Get($aSymb,$aCapital=FALSE) {\n        static $iSymbols = array(\n    /* Greek */\n\tarray('alpha','03B1','0391'),\n\tarray('beta','03B2','0392'),\n\tarray('gamma','03B3','0393'),\n\tarray('delta','03B4','0394'),\n\tarray('epsilon','03B5','0395'),\n\tarray('zeta','03B6','0396'),\n\tarray('ny','03B7','0397'),\n\tarray('eta','03B8','0398'),\n\tarray('theta','03B8','0398'),\n\tarray('iota','03B9','0399'),\n\tarray('kappa','03BA','039A'),\n\tarray('lambda','03BB','039B'),\n\tarray('mu','03BC','039C'),\n\tarray('nu','03BD','039D'),\n\tarray('xi','03BE','039E'),\n\tarray('omicron','03BF','039F'),\n\tarray('pi','03C0','03A0'),\n\tarray('rho','03C1','03A1'),\n\tarray('sigma','03C3','03A3'),\n\tarray('tau','03C4','03A4'),\n\tarray('upsilon','03C5','03A5'),\n\tarray('phi','03C6','03A6'),\n\tarray('chi','03C7','03A7'),\n\tarray('psi','03C8','03A8'),\n\tarray('omega','03C9','03A9'),\n    /* Money */\n\tarray('euro','20AC'),\n\tarray('yen','00A5'),\n\tarray('pound','20A4'),\n    /* Math */\n\tarray('approx','2248'),\n\tarray('neq','2260'),\n\tarray('not','2310'),\n\tarray('def','2261'),\n\tarray('inf','221E'),\n\tarray('sqrt','221A'),\n\tarray('int','222B'),\n    /* Misc */\n\tarray('copy','00A9'),\n\tarray('para','00A7'));\n\n\t$n = count($iSymbols);\n\t$i=0;\n\t$found = false;\n\t$aSymb = strtolower($aSymb);\n\twhile( $i < $n && !$found ) {\n\t    $found = $aSymb === $iSymbols[$i++][0];\n\t}\n\tif( $found ) {\n\t    $ca = $iSymbols[--$i];\n\t    if( $aCapital && count($ca)==3 ) \n\t\t$s = $ca[2];\n\t    else\n\t\t$s = $ca[1];\n\t    return sprintf('&#%04d;',hexdec($s));\n\t}\n\telse\n\t    return '';\n    }\n}\n\n\n//=============================================================================\n// CLASS DateScaleUtils\n// Description: Help to create a manual date scale\n//=============================================================================\nDEFINE('DSUTILS_MONTH1',1); // Major and minor ticks on a monthly basis\n\nclass DateScaleUtils {\n\n    function GetTicks($aData,$aType=1) {\n\n\t//\n\t// Find out the range of the data in order to get the limits for the loops\n\t// that creates the position for the labels. This code is generic and can be \n\t// used for any ranges of the data.\n\t//\n\t$n = count($aData);\n\t$startmonth = date('n',$aData[0]);\n\t$startday = date('j',$aData[0]);\n\t$startyear = date('Y',$aData[0]);\n\t$endmonth = date('n',$aData[$n-1]);\n\t$endyear = date('Y',$aData[$n-1]);\n\t$endday = date('j',$aData[$n-1]);\n\n\t//\n\t// Now create the positions for all the ticks. In this example we\n\t// put a tick at the start of every month and also on the very \n\t// first and last X-position.\n\t// \n\t$tickPositions = array();\n\t$minTickPositions = array();\n\t$i=0;$j=0;\n\n\t// Uncomment this line to put a label at the very left data pos\n\t// $tickPositions[$i++] = $datax[0];\n\n\t$m = $startmonth;\n\t$y = $startyear;\n\t// Skip the first month label if it is before the startdate\n\tif( $startday == 1 ) {\n\t    $tickPositions[$i++] = mktime(0,0,0,$m,1,$y);\n\t}\n\tif( $startday < 15 ) {\n\t    $minTickPositions[$j++] = mktime(0,0,0,$m,15,$y);\n\t}\n\t++$m;\n\n\t// Loop through all the years included in the scale\n\tfor($y=$startyear; $y <= $endyear; ++$y ) {\n\t    // Loop through all the months. There are three cases to consider:\n\t    // 1. We are in the first year and must start with the startmonth\n\t    // 2. We are in the end year and we must stop at last month of the scale\n\t    // 3. A year in between where we run through all the 12 months\n\t    $stopmonth = $y == $endyear ? $endmonth : 12;\n\t    while( $m <= $stopmonth ) {\n\t\tswitch( $aType ) {\n\t\t    case 1: \n\t\t\t// Set minor tick at the middle of the month\n\t\t\tif( $m <= $stopmonth ) {\n\t\t\t    if( !($y==$endyear && $m==$stopmonth && $endday < 15) ) \n\t\t\t\t$minTickPositions[$j++] = mktime(0,0,0,$m,15,$y);\n\t\t\t}\n\t\t\t// Major at month \n\t\t\t// Get timestamp of first hour of first day in each month\n\t\t\t$tickPositions[$i++] = mktime(0,0,0,$m,1,$y);\n\n\t\t\tbreak;\n\t\t}\n\t\t++$m;\n\t    }\n\t    $m=1;\n\t}\n\n\t// For the case where all dates are within the same month\n\t// we want to make sure we have at least two ticks on the scale\n\t// since the scale want work properly otherwise\n\tif($startmonth == $endmonth && $startyear == $endyear && $aType==1 ) {\n\t    $tickPositions[$i++] = mktime(0 ,0 ,0, $startmonth + 1, 1, $startyear);\n\t} \n\n\t// Uncomment this line to put a label at the very right data pos\n\t// $tickPositions[$i] = $datax[$n-1];\n\n\treturn array($tickPositions,$minTickPositions);\n    }\n\n}\n\n//=============================================================================\n// Class ReadFileData\n//=============================================================================\nClass ReadFileData {\n\n    //----------------------------------------------------------------------------\n    // Desciption:\n    // Read numeric data from a file. \n    // Each value should be separated by either a new line or by a specified \n    // separator character (default is ',').\n    // Before returning the data each value is converted to a proper float \n    // value. The routine is robust in the sense that non numeric data in the \n    // file will be discarded.\n    //\n    // Returns: \n    // The number of data values read on success, FALSE on failure\n    //----------------------------------------------------------------------------\n    function FromCSV($aFile,&$aData,$aSepChar=',',$aMaxLineLength=1024) {\n\t$rh = fopen($aFile,'r');\n\tif( $rh === false )\n\t    return false;\n\t$tmp = array();\n\t$lineofdata = fgetcsv($rh, 1000, ',');\n\twhile ( $lineofdata !== FALSE) {\n\t    $tmp = array_merge($tmp,$lineofdata);\n\t    $lineofdata = fgetcsv($rh, $aMaxLineLength, $aSepChar);\n\t}\n\tfclose($rh);\n\n\t// Now make sure that all data is numeric. By default\n\t// all data is read as strings\n\t$n = count($tmp);\n\t$aData = array();\n\t$cnt=0;\n\tfor($i=0; $i < $n; ++$i) {\n\t    if( $tmp[$i] !== \"\" ) {\n\t\t$aData[$cnt++] = floatval($tmp[$i]);\n\t    }\n\t}\n\treturn $cnt;\n    }\n}\n\n?>"
  },
  {
    "path": "tools/server/admin/jpgraph/lang/en.inc.php",
    "content": "<?php\n/*=======================================================================\n// File: \tERRMSG_EN.INC.PHP\n// Description: English language file for error messages\n// Created: \t2006-01-25\n// Author:\tJohan Persson (johanp@aditus.nu)\n// Ver:\t\t$Id: en.inc.php,v 1.1 2006/07/07 13:37:14 powles Exp $\n//\n// Copyright (c) Aditus Consulting. All rights reserved.\n//========================================================================\n*/\n\n// Note: Format of each error message is array(<error message>,<number of arguments>)\n$_jpg_messages = array(\n\n/*\n** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text\n*/\n10  => array('<table border=1><tr><td><font color=darkred size=4><b>JpGraph Error:</b> \nHTTP headers have already been sent.<br>Caused by output from file <b>%s</b> at line <b>%d</b>.</font></td></tr><tr><td><b>Explanation:</b><br>HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).<p>Most likely you have some text in your script before the call to <i>Graph::Stroke()</i>. If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser. <p>For example it is a common mistake to leave a blank line before the opening \"<b>&lt;?php</b>\".</td></tr></table>',2),\n\n/*\n** Setup errors\n*/\n11 => array('No path specified for CACHE_DIR. Please specify CACHE_DIR manually in jpg-config.inc',0),\n12 => array('No path specified for TTF_DIR and path can not be determined automatically. Please specify TTF_DIR manually (in jpg-config.inc).',0),\n\n/*\n**  jpgraph_bar\n*/\n\n2001 => array('Number of colors is not the same as the number of patterns in BarPlot::SetPattern()',0),\n2002 => array('Unknown pattern specified in call to BarPlot::SetPattern()',0),\n2003 => array('Number of X and Y points are not equal. Number of X-points: %d Number of Y-points: %d',2),\n2004 => array('All values for a barplot must be numeric. You have specified value nr [%d] == %s',2),\n2005 => array('You have specified an empty array for shadow colors in the bar plot.',0),\n2006 => array('Unknown position for values on bars : %s',1),\n2007 => array('Cannot create GroupBarPlot from empty plot array.',0),\n2008 => array('Group bar plot element nbr %d is undefined or empty.',0),\n2009 => array('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the GroupBar plot from an array of BarPlot or AccBarPlot objects. (Class = %s)',1),\n2010 => array('Cannot create AccBarPlot from empty plot array.',0),\n2011 => array('Acc bar plot element nbr %d is undefined or empty.',1),\n2012 => array('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects. (Class=%s)',1),\n2013 => array('You have specified an empty array for shadow colors in the bar plot.',0),\n2014 => array('Number of datapoints for each data set in accbarplot must be the same',0),\n\n\n/*\n**  jpgraph_date\n*/\n\n3001 => array('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both',0),\n\n/*\n**  jpgraph_error\n*/\n\n4002 => array('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3',0),\n\n/*\n**  jpgraph_flags\n*/\n\n5001 => array('Unknown flag size (%d).',1),\n5002 => array('Flag index %s does not exist.',1),\n5003 => array('Invalid ordinal number (%d) specified for flag index.',1),\n5004 => array('The (partial) country name %s does not have a corresponding flag image. The flag may still exist but under another name, e.g. instead of \"usa\" try \"united states\".',1),\n\n\n/*\n**  jpgraph_gantt\n*/\n\n6001 => array('Internal error. Height for ActivityTitles is < 0',0),\n6002 => array('You can\\'t specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.',0),\n6003 => array('Invalid format for Constrain parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)',1), \n6004 => array('Invalid format for Progress parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)',1), \n6005 => array('SetScale() is not meaningful with Gantt charts.',0),\n6006 => array('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]',0),\n6007 => array('Sanity check for automatic Gantt chart size failed. Either the width (=%d) or height (=%d) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.',2),\n6008 => array('You have specified a constrain from row=%d to row=%d which does not have any activity',2),\n6009 => array('Unknown constrain type specified from row=%d to row=%d',2),\n6010 => array('Illegal icon index for Gantt builtin icon [%d]',1),\n6011 => array('Argument to IconImage must be string or integer',0),\n6012 => array('Unknown type in Gantt object title specification',0),\n6015 => array('Illegal vertical position %d',1),\n6016 => array('Date string (%s) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30',1),\n6017 => array('Unknown date format in GanttScale (%s).',1),\n6018 => array('Interval for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an interval of %d minutes.',1),\n6019 => array('The available width (%d) for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.',1),\n6020 => array('Interval for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an interval of %d',1),\n6021 => array('Unknown formatting style for week.',0),\n6022 => array('Gantt scale has not been specified.',0),\n6023 => array('If you display both hour and minutes the hour interval must be 1 (Otherwise it doesn\\'t make sense to display minutes).',0),\n6024 => array('CSIM Target must be specified as a string. Start of target is: %d',1),\n6025 => array('CSIM Alt text must be specified as a string. Start of alt text is: %d',1),\n6027 => array('Progress value must in range [0, 1]',0),\n6028 => array('Specified height (%d) for gantt bar is out of range.',1),\n6029 => array('Offset for vertical line must be in range [0,1]',0),\n6030 => array('Unknown arrow direction for link.',0),\n6031 => array('Unknown arrow type for link.',0),\n6032 => array('Internal error: Unknown path type (=%d) specified for link.',1),\n\n/*\n**  jpgraph_gradient\n*/\n\n7001 => array('Unknown gradient style (=%d).',1),\n\n/*\n**  jpgraph_iconplot\n*/\n\n8001 => array('Mix value for icon must be between 0 and 100.',0),\n8002 => array('Anchor position for icons must be one of \"top\", \"bottom\", \"left\", \"right\" or \"center\"',0),\n8003 => array('It is not possible to specify both an image file and a country flag for the same icon.',0),\n8004 => array('In order to use Country flags as icons you must include the \"jpgraph_flags.php\" file.',0),\n\n/*\n**  jpgraph_imgtrans\n*/\n\n9001 => array('Value for image transformation out of bounds. Vanishing point on horizon must be specified as a value between 0 and 1.',0),\n\n/*\n**  jpgraph_lineplot\n*/\n\n10001 => array('LinePlot::SetFilled() is deprecated. Use SetFillColor()',0),\n10002 => array('Plot too complicated for fast line Stroke. Use standard Stroke()',0),\n\n/*\n**  jpgraph_log\n*/\n\n11001 => array('Your data contains non-numeric values.',0),\n11002 => array('Negative data values can not be used in a log scale.',0),\n11003 => array('Your data contains non-numeric values.',0),\n11004 => array('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.',0),\n11005 => array('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.',0),\n\n/*\n**  jpgraph_mgraph\n*/\n\n12001 => array(\"You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.\",0),\n12002 => array('Incorrect file name for MGraph::SetBackgroundImage() : %s Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1),\n12003 => array('Unknown file extension (%s) in MGraph::SetBackgroundImage() for filename: %s',2),\n12004 => array('The image format of your background image (%s) is not supported in your system configuration. ',1),\n12005 => array('Can\\'t read background image: %s',1),\n12006 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2),\n12007 => array('Argument to MGraph::Add() is not a valid GD image handle.',0),\n12008 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats.',0),\n12009 => array('Your PHP installation does not support the chosen graphic format: %s',1),\n12010 => array('Can\\'t create or stream image to file %s Check that PHP has enough permission to write a file to the current directory.',1),\n12011 => array('Can\\'t create truecolor image. Check that you really have GD2 library installed.',0),\n12012 => array('Can\\'t create image. Check that you really have GD2 library installed.',0),\n\n/*\n**  jpgraph_pie3d\n*/\n\n14001 => array('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.',0),\n14002 => array('PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.',0),\n14003 => array('Internal assertion failed. Pie3D::Pie3DSlice',0),\n14004 => array('Slice start angle must be between 0 and 360 degrees.',0),\n14005 => array('Pie3D Internal error: Trying to wrap twice when looking for start index',0,),\n14006 => array('Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.',0),\n14007 => array('Width for 3D Pie is 0. Specify a size > 0',0),\n\n/*\n**  jpgraph_pie\n*/\n\n15001 => array('PiePLot::SetTheme() Unknown theme: %s',1),\n15002 => array('Argument to PiePlot::ExplodeSlice() must be an integer',0),\n15003 => array('Argument to PiePlot::Explode() must be an array with integer distances.',0),\n15004 => array('Slice start angle must be between 0 and 360 degrees.',0),\n15005 => array('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.',0),\n15006 => array('PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels  in the range [10, 1000]',0),\n15007 => array('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.',0),\n15008 => array('PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not %d).',1),\n15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0),\n15010 => array('Sum of all data is 0 for Pie.',0),\n15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0),\n\n/*\n**  jpgraph_plotband\n*/\n\n16001 => array('Density for pattern must be between 1 and 100. (You tried %f)',1),\n16002 => array('No positions specified for pattern.',0),\n16003 => array('Unknown pattern specification (%d)',0),\n16004 => array('Min value for plotband is larger than specified max value. Please correct.',0),\n\n\n/*\n**  jpgraph_polar\n*/\n\n17001 => array('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).',0),\n17002 => array('Unknown alignment specified for X-axis title. (%s)',1),\n//17003 => array('Set90AndMargin() is not supported for polar graphs.',0),\n17004 => array('Unknown scale type for polar graph. Must be \"lin\" or \"log\"',0),\n\n/*\n**  jpgraph_radar\n*/\n\n18001 => array('Client side image maps not supported for RadarPlots.',0),\n18002 => array('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.',0),\n18003 => array('Illegal scale for radarplot (%s). Must be \\'lin\\' or \\'log\\'',1),\n18004 => array('Radar Plot size must be between 0.1 and 1. (Your value=%f)',1),\n18005 => array('RadarPlot Unsupported Tick density: %d',1),\n18006 => array('Minimum data %f (Radar plots should only be used when all data points > 0)',1),\n18007 => array('Number of titles does not match number of points in plot.',0),\n18008 => array('Each radar plot must have the same number of data points.',0),\n\n/*\n**  jpgraph_regstat\n*/\n\n19001 => array('Spline: Number of X and Y coordinates must be the same',0),\n19002 => array('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.',0),\n19003 => array('Bezier: Number of X and Y coordinates must be the same',0),\n\n/*\n**  jpgraph_scatter\n*/\n\n20001 => array('Fieldplots must have equal number of X and Y points.',0),\n20002 => array('Fieldplots must have an angle specified for each X and Y points.',0),\n20003 => array('Scatterplot must have equal number of X and Y points.',0),\n\n/*\n**  jpgraph_stock\n*/\n\n21001 => array('Data values for Stock charts must contain an even multiple of %d data points.',1),\n\n/*\n**  jpgraph_plotmark\n*/\n\n23001 => array('This marker \"%s\" does not exist in color with index: %d',2),\n23002 => array('Mark color index too large for marker \"%s\"',1),\n23003 => array('A filename must be specified if you set the mark type to MARK_IMG.',0),\n\n/*\n**  jpgraph_utils\n*/\n\n24001 => array('FuncGenerator : No function specified. ',0),\n24002 => array('FuncGenerator : Syntax error in function specification ',0),\n\n/*\n**  jpgraph\n*/\n\n25001 => array('This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)',0),\n25002 => array('Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.',0),\n25003 => array('General PHP error : At %s:%d : %s',3),\n25004 => array('General PHP error : %s ',1),\n25005 => array('Can\\'t access PHP_SELF, PHP global variable. You can\\'t run PHP from command line if you want to use the \\'auto\\' naming of cache or image files.',0),\n25006 => array('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the \"--width-iconv\" when configured).',0),\n25007 => array('You are trying to use the locale (%s) which your PHP installation does not support. Hint: Use \\'\\' to indicate the default locale for this geographic region.',1),\n25008 => array('Image width/height argument in Graph::Graph() must be numeric',0),\n25009 => array('You must specify what scale to use with a call to Graph::SetScale()',0),\n\n25010 => array('Graph::Add() You tried to add a null plot to the graph.',0),\n25011 => array('Graph::AddY2() You tried to add a null plot to the graph.',0), \n25012 => array('Graph::AddYN() You tried to add a null plot to the graph.',0), \n25013 => array('You can only add standard plots to multiple Y-axis',0),\n25014 => array('Graph::AddText() You tried to add a null text to the graph.',0), \n25015 => array('Graph::AddLine() You tried to add a null line to the graph.',0), \n25016 => array('Graph::AddBand() You tried to add a null band to the graph.',0),\n25017 => array('You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.',0),\n25018 => array('Incorrect file name for Graph::SetBackgroundImage() : \"%s\" Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1),\n25019 => array('Unknown file extension (%s) in Graph::SetBackgroundImage() for filename: \"%s\"',2),\n\n25020 => array('Graph::SetScale(): Specified Max value must be larger than the specified Min value.',0),\n25021 => array('Unknown scale specification for Y-scale. (%s)',1),\n25022 => array('Unknown scale specification for X-scale. (%s)',1),\n25023 => array('Unsupported Y2 axis type: \"%s\" Must be one of (lin,log,int)',1),\n25024 => array('Unsupported Y axis type:  \"%s\" Must be one of (lin,log,int)',1),\n25025 => array('Unsupported Tick density: %d',1),\n25026 => array('Can\\'t draw unspecified Y-scale. You have either: 1. Specified an Y axis for auto scaling but have not supplied any plots. 2. Specified a scale manually but have forgot to specify the tick steps',0),\n25027 => array('Can\\'t open cached CSIM \"%s\" for reading.',1),\n25028 => array('Apache/PHP does not have permission to write to the CSIM cache directory (%s). Check permissions.',1),\n25029 => array('Can\\'t write CSIM \"%s\" for writing. Check free space and permissions.',1),\n\n25030 => array('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().',0),\n25031 => array('You must specify what scale to use with a call to Graph::SetScale().',0),\n25032 => array('No plots for Y-axis nbr:%d',1),\n25033 => array('',0),\n25034 => array('Can\\'t draw unspecified X-scale. No plots specified.',0),\n25035 => array('You have enabled clipping. Clipping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (=%d degrees) or disable clipping.',1),\n25036 => array('Unknown AxisStyle() : %s',1),\n25037 => array('The image format of your background image (%s) is not supported in your system configuration. ',1),\n25038 => array('Background image seems to be of different type (has different file extension) than specified imagetype. Specified: %s File: %s',2),\n25039 => array('Can\\'t read background image: \"%s\"',1), \n\n25040 => array('It is not possible to specify both a background image and a background country flag.',0),\n25041 => array('In order to use Country flags as backgrounds you must include the \"jpgraph_flags.php\" file.',0),\n25042 => array('Unknown background image layout',0),\n25043 => array('Unknown title background style.',0),\n25044 => array('Cannot use auto scaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).',0),\n25045 => array('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/',0),\n25046 => array('Specified TTF font family (id=%d) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/',1),\n25047 => array('Style %s is not available for font family %s',2),\n25048 => array('Unknown font style specification [%s].',1),\n25049 => array('Font file \"%s\" is not readable or does not exist.',1),\n\n25050 => array('First argument to Text::Text() must be a string.',0),\n25051 => array('Invalid direction specified for text.',0),\n25052 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text',0),\n25053 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text',0),\n25054 => array('Internal error: Unknown grid axis %s',1),\n25055 => array('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead',0),\n25056 => array('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.',0),\n25057 => array('SetTextTicks() is deprecated. Use SetTextTickInterval() instead.',0), \n25058 => array('Text label interval must be specified >= 1.',0),\n25059 => array('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.',0),\n\n25060 => array('Unknown alignment specified for X-axis title. (%s)',1),\n25061 => array('Unknown alignment specified for Y-axis title. (%s)',1),\n25062 => array('Labels at an angle are not supported on Y-axis',0),\n25063 => array('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead',0),\n25064 => array('Minor or major step size is 0. Check that you haven\\'t got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem',0),\n25065 => array('Tick positions must be specified as an array()',0),\n25066 => array('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.',0),\n25067 => array('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tick marks.',0),\n25068 => array('A plot has an illegal scale. This could for example be that you are trying to use text auto scaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only \\'-\\' or \\'x\\')',0),\n25069 => array('Grace must be larger then 0',0),\n\n25070 => array('Your data contains non-numeric values.',0),\n25071 => array('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.',0),\n25072 => array('You have specified a max value with SetAutoMax() which is smaller than the minimum value used for the scale. This is not possible.',0),\n25073 => array('Internal error. Integer scale algorithm comparison out of bound (r=%f)',1),\n25074 => array('Internal error. The scale range is negative (%f) [for %s scale] This problem could potentially be caused by trying to use \\\"illegal\\\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the auto scaling to fail.',2),\n25075 => array('Can\\'t automatically determine ticks since min==max.',0),\n25077 => array('Adjustment factor for color must be > 0',0),\n25078 => array('Unknown color: %s',1),\n25079 => array('Unknown color specification: %s, size=%d',2),\n\n25080 => array('Alpha parameter for color must be between 0.0 and 1.0',0),\n25081 => array('Selected graphic format is either not supported or unknown [%s]',1),\n25082 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2),\n25083 => array('Illegal image size when copying image. Size for copied to image is 1 pixel or less.',0),\n25084 => array('Failed to create temporary GD canvas. Possible Out of memory problem.',0),\n25085 => array('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.',0),\n25086 => array('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to auto detect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.',0),\n25087 => array('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.',0),\n25088 => array('You have a misconfigured GD font support. The call to imagefontwidth() fails.',0),\n25089 => array('You have a misconfigured GD font support. The call to imagefontheight() fails.',0),\n\n25090 => array('Unknown direction specified in call to StrokeBoxedText() [%s]',1),\n25091 => array('Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.',0),\n25092 => array('There is either a configuration problem with TrueType or a problem reading font file \"%s\" Make sure file exists and is in a readable place for the HTTP process. (If \\'basedir\\' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try upgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.',1),\n25093 => array('Can not read font file \"%s\" in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.',1),\n25094 => array('Direction for text most be given as an angle between 0 and 90.',0),\n25095 => array('Unknown font font family specification. ',0),\n25096 => array('Can\\'t allocate any more colors in palette image. Image has already allocated maximum of %d colors and the palette  is now full. Change to a truecolor image instead',0),\n25097 => array('Color specified as empty string in PushColor().',0),\n25098 => array('Negative Color stack index. Unmatched call to PopColor()',0),\n25099 => array('Parameters for brightness and Contrast out of range [-1,1]',0), \n\n25100 => array('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.',0),\n25101 => array('Illegal numeric argument to SetLineStyle(): (%d)',1),\n25102 => array('Illegal string argument to SetLineStyle(): %s',1),\n25103 => array('Illegal argument to SetLineStyle %s',1),\n25104 => array('Unknown line style: %s',1),\n25105 => array('NULL data specified for a filled polygon. Check that your data is not NULL.',0),\n25106 => array('Image::FillToBorder : Can not allocate more colors',0),\n25107 => array('Can\\'t write to file \"%s\". Check that the process running PHP has enough permission.',1),\n25108 => array('Can\\'t stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.',0),\n25109 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.',0),\n\n25110 => array('Your PHP installation does not support the chosen graphic format: %s',1),\n25111 => array('Can\\'t delete cached image %s. Permission problem?',1),\n25112 => array('Cached imagefile (%s) has file date in the future.',1),\n25113 => array('Can\\'t delete cached image \"%s\". Permission problem?',1),\n25114 => array('PHP has not enough permissions to write to the cache file \"%s\". Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.',1),\n25115 => array('Can\\'t set permission for cached image \"%s\". Permission problem?',1),\n25116 => array('Cant open file from cache \"%s\"',1), \n25117 => array('Can\\'t open cached image \"%s\" for reading.',1),\n25118 => array('Can\\'t create directory \"%s\". Make sure PHP has write permission to this directory.',1),\n25119 => array('Can\\'t set permissions for \"%s\". Permission problems?',1),\n\n25120 => array('Position for legend must be given as percentage in range 0-1',0),\n25121 => array('Empty input data array specified for plot. Must have at least one data point.',0),\n25122 => array('Stroke() must be implemented by concrete subclass to class Plot',0),\n25123 => array('You can\\'t use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead.',0),\n25124 => array('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)',0),\n25125 => array('Illegal direction for static line',0),\n25126 => array('Can\\'t create truecolor image. Check that the GD2 library is properly setup with PHP.',0),\n\n/*\n**---------------------------------------------------------------------------------------------\n** Pro-version strings\n**---------------------------------------------------------------------------------------------\n*/\n\n/*\n**  jpgraph_table \n*/\n\n24001 => array('GTextTable: Invalid argument to Set(). Array argument must be 2 dimensional',0),\n24002 => array('GTextTable: Invalid argument to Set()',0),\n24003 => array('GTextTable: Wrong number of arguments to GTextTable::SetColor()',0),\n24004 => array('GTextTable: Specified cell range to be merged is not valid.',0),\n24005 => array('GTextTable: Cannot merge already merged cells in the range: (%d,%d) to (%d,%d)',4),\n24006 => array('GTextTable: Column argument = %d is outside specified table size.',1),\n24007 => array('GTextTable: Row argument = %d is outside specified table size.',1),\n24008 => array('GTextTable: Column and row size arrays must match the dimensions of the table',0),\n24009 => array('GTextTable: Number of table columns or rows are 0. Make sure Init() or Set() is called.',0),\n24010 => array('GTextTable: No alignment specified in call to SetAlign()',0),\n24011 => array('GTextTable: Unknown alignment specified in SetAlign(). Horizontal=%s, Vertical=%s',2),\n24012 => array('GTextTable: Internal error. Invalid alignment specified =%s',1),\n24013 => array('GTextTable: Argument to FormatNumber() must be a string.',0),\n24014 => array('GTextTable: Table is not initilaized with either a call to Set() or Init()',0),\n24015 => array('GTextTable: Cell image constrain type must be TIMG_WIDTH or TIMG_HEIGHT',0),\n\n/*\n**  jpgraph_windrose\n*/\n\n22001 => array('Total percentage for all windrose legs in a windrose plot can not exceed 100% !\\n(Current max is: %d)',1),\n22002 => array('Graph is too small to have a scale. Please make the graph larger.',0),\n22004 => array('Label specification for windrose directions must have 16 values (one for each compass direction).',0),\n22005 => array('Line style for radial lines must be on of (\"solid\",\"dotted\",\"dashed\",\"longdashed\") ',0),\n22006 => array('Illegal windrose type specified.',0),\n22007 => array('To few values for the range legend.',0),\n22008 => array('Internal error: Trying to plot free Windrose even though type is not a free windrose',0),\n22009 => array('You have specified the same direction twice, once with an angle and once with a compass direction (%f degrees)',0),\n22010 => array('Direction must either be a numeric value or one of the 16 compass directions',0),\n22011 => array('Windrose index must be numeric or direction label. You have specified index=%d',1),\n22012 => array('Windrose radial axis specification contains a direction which is not enabled.',0),\n22013 => array('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index=%d)',1),\n22014 => array('Index for compass direction must be between 0 and 15.',0),\n22015 => array('You have specified an undefined Windrose plot type.',0),\n22016 => array('Windrose leg index must be numeric or direction label.',0),\n22017 => array('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.',0),\n22018 => array('You have specified data for the same compass direction twice, once with text and once with index (Index=%d)',1),\n22019 => array('Index for direction must be between 0 and 15. You can\\'t specify angles for a Regular Windplot, only index and compass directions.',0),\n22020 => array('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.',0),\n\n/*\n**  jpgraph_odometer\n*/\n\n13001 => array('Unknown needle style (%d).',1),\n13002 => array('Value for odometer (%f) is outside specified scale [%f,%f]',3),\n\n/*\n**  jpgraph_barcode\n*/\n\n1001 => array('Unknown encoder specification: %s',1),\n1002 => array('Data validation failed. Can\\'t encode [%s] using encoding \"%s\"',2),\n1003 => array('Internal encoding error. Trying to encode %s is not possible in Code 128',1),\n1004 => array('Internal barcode error. Unknown UPC-E encoding type: %s',1),\n1005 => array('Internal error. Can\\'t encode character tuple (%s, %s) in Code-128 charset C',2),\n1006 => array('Internal encoding error for CODE 128. Trying to encode control character in CHARSET != A',0),\n1007 => array('Internal encoding error for CODE 128. Trying to encode DEL in CHARSET != B',0),\n1008 => array('Internal encoding error for CODE 128. Trying to encode small letters in CHARSET != B',0),\n1009 => array('Encoding using CODE 93 is not yet supported.',0),\n1010 => array('Encoding using POSTNET is not yet supported.',0),\n1011 => array('Non supported barcode backend for type %s',1),\n\n/*\n** PDF417\n*/\n\n26001 => array('PDF417: Number of Columns must be >= 1 and <= 30',0),\n26002 => array('PDF417: Error level must be between 0 and 8',0),\n26003 => array('PDF417: Invalid format for input data to encode with PDF417',0),\n26004 => array('PDF417: Can\\'t encode given data with error level %d and %d columns since it results in too many symbols or more than 90 rows.',2),\n26005 => array('PDF417: Can\\'t open file \"%s\" for writing',1),\n26006 => array('PDF417: Internal error. Data files for PDF417 cluster %d is corrupted.',1),\n26007 => array('PDF417: Internal error. GetPattern: Illegal Code Value = %d (row=%d)',2),\n26008 => array('PDF417: Internal error. Mode not found in mode list!! mode=%d',1),\n26009 => array('PDF417: Encode error: Illegal character. Can\\'t encode character with ASCII code=%d',1),\n26010 => array('PDF417: Internal error: No input data in decode.',0),\n26011 => array('PDF417: Encoding error. Can\\'t use numeric encoding on non-numeric data.',0),\n26012 => array('PDF417: Internal error. No input data to decode for Binary compressor.',0),\n26013 => array('PDF417: Internal error. Checksum error. Coefficient tables corrupted.',0),\n26014 => array('PDF417: Internal error. No data to calculate codewords on.',0),\n26015 => array('PDF417: Internal error. State transition table entry 0 is NULL. Entry 1 = (%s)',1),\n26016 => array('PDF417: Internal error: Unrecognized state transition mode in decode.',0),\n\n\n);\n\n?>\n"
  },
  {
    "path": "tools/server/admin/logs/empty.txt",
    "content": "Empty file, just to keep directory alive!"
  },
  {
    "path": "tools/server/admin/nel/admin_modules_itf.php",
    "content": "<?php\n\t/////////////////////////////////////////////////////////////////\n\t// WARNING : this is a generated file, don't change it !\n\t/////////////////////////////////////////////////////////////////\n\n\trequire_once('nel_message.php');\n\n\tclass CAdminServiceWeb extends CCallbackClient\n\t{\n\n\t\tfunction globalCmd($command)\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"GCMD\");\n\n\n\t\t\t$msg->serialString($command);\n\n\t\t\treturn parent::sendMessage($msg);\n\n\n\t\t}\n\n\t\tfunction controlCmd($serviceAlias, $command)\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"CCMD\");\n\n\n\t\t\t$msg->serialString($serviceAlias);\n\t\t\t\t$msg->serialString($command);\n\n\t\t\treturn parent::sendMessage($msg);\n\n\n\t\t}\n\n\t\tfunction serviceCmd($serviceAlias, $command)\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"SCMD\");\n\n\n\t\t\t$msg->serialString($serviceAlias);\n\t\t\t\t$msg->serialString($command);\n\n\t\t\treturn parent::sendMessage($msg);\n\n\n\t\t}\n\n\t\tfunction getShardOrders()\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"GSO\");\n\n\n\n\t\t\t$ret = \"\";\n\t\t\t$ret = parent::sendMessage($msg);\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getShardOrders\", \"Error in 'sendMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t$retMsg = parent::waitMessage();\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getShardOrders\", \"Error in 'waitMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!($retMsg->MsgName === \"R_GSO\"))\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getShardOrders\", \"Invalid response, awaited 'R_GSO', received '\".$retMsg->MsgName.\"'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// serial the return value\n\t\t\t\t\t\t$nbElem = 0;\n\t\t\t$retMsg->serialUInt32($nbElem);\n\t\t\t$retValue = array();\n\t\t\tfor ($i=0; $i<$nbElem;$i++)\n\t\t\t{\n\t\t\t\t$retMsg->serialString($item);\n\t\t\t\t$retValue[] = $item;\n\t\t\t}\n\n\n\t\t\t// return the return value\n\t\t\treturn $retValue;\n\n\n\t\t}\n\n\t\tfunction getStates()\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"GS\");\n\n\n\n\t\t\t$ret = \"\";\n\t\t\t$ret = parent::sendMessage($msg);\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getStates\", \"Error in 'sendMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t$retMsg = parent::waitMessage();\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getStates\", \"Error in 'waitMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!($retMsg->MsgName === \"R_GS\"))\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getStates\", \"Invalid response, awaited 'R_GS', received '\".$retMsg->MsgName.\"'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// serial the return value\n\t\t\t\t\t\t$nbElem = 0;\n\t\t\t$retMsg->serialUInt32($nbElem);\n\t\t\t$retValue = array();\n\t\t\tfor ($i=0; $i<$nbElem;$i++)\n\t\t\t{\n\t\t\t\t$retMsg->serialString($item);\n\t\t\t\t$retValue[] = $item;\n\t\t\t}\n\n\n\t\t\t// return the return value\n\t\t\treturn $retValue;\n\n\n\t\t}\n\n\t\tfunction getHighRezGraph($varAddr, $startDate, $endDate, $milliStep)\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"GHRG\");\n\n\n\t\t\t$msg->serialString($varAddr);\n\t\t\t\t$msg->serialUint32($startDate);\n\t\t\t\t$msg->serialUint32($endDate);\n\t\t\t\t$msg->serialUint32($milliStep);\n\n\t\t\t$ret = \"\";\n\t\t\t$ret = parent::sendMessage($msg);\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getHighRezGraph\", \"Error in 'sendMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t$retMsg = parent::waitMessage();\n\t\t\tif ($ret == false)\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getHighRezGraph\", \"Error in 'waitMessage'\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!($retMsg->MsgName === \"R_GHRG\"))\n\t\t\t{\n\t\t\t\t// error during send\n\t\t\t\t$this->invokeError(\"getHighRezGraph\", \"Invalid response, awaited 'R_GHRG', received '\".$retMsg->MsgName.\"'\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// serial the return value\n\t\t\t\t\t\t$nbElem = 0;\n\t\t\t$retMsg->serialUInt32($nbElem);\n\t\t\t$retValue = array();\n\t\t\tfor ($i=0; $i<$nbElem;$i++)\n\t\t\t{\n\t\t\t\t$retMsg->serialString($item);\n\t\t\t\t$retValue[] = $item;\n\t\t\t}\n\n\n\t\t\t// return the return value\n\t\t\treturn $retValue;\n\n\n\t\t}\n\n\n\t\tfunction waitCallback()\n\t\t{\n\t\t\t$message = parent::waitMessage();\n\n\t\t\tif ($message == false)\n\t\t\t\treturn false;\n\n\t\t\tswitch($message->MsgName)\n\t\t\t{\n\t\t\tcase \"CMDR\":\n\t\t\t\t$this->commandResult_skel($message);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\n\t\tfunction commandResult_skel(&$message)\n\t\t{\n$message->serialString($serviceAlias);\n\t$message->serialString($result);\n\n\t\t\t$this->commandResult($serviceAlias, $result);\n\t\t}\n\n\n\t\t/////////////////////////////////////////////////////////////////\n\t\t// Copy paste this part of code in your derived class\n\t\t//\tand implement code to ract to incoming message\n\t\t/////////////////////////////////////////////////////////////////\n\n\t\tfunction commandResult($serviceAlias, $result)\n\t\t{\n\t\t}\n\n\t}\n?>\n"
  },
  {
    "path": "tools/server/admin/nel/nel_message.php",
    "content": "<?php\n\t\n\t$SockTimeOut = 10;\n\t\n\tfunction debug($text)\n\t{\n//\t\tflush();\n//\t\techo $text;\n\n//\t\t$file = \"logs/debug.txt\";\n//\t\t$str = file_get_contents($file);\n//\t\t$str .= $text.\"\\n\";\n//\t\tfile_put_contents($file, $str);\n\t}\n\n\tclass CMemStream\n\t{\n\t\tvar $Buffer;\n\t\tvar $InputStream;\n\t\tvar $Pos;\n\n\t\tfunction CMemStream ()\n\t\t{\n\t\t\t$this->InputStream = false;\n\t\t\t$this->Pos = 0;\n\t\t\t$this->Buffer = \"\";\n\t\t\tdebug(\"A : \".gettype($this->Buffer).\"<br>\");\n\t\t}\n\n\t\tfunction setBuffer ($Buffer)\n\t\t{\n\t\t\t$this->InputStream = true;\n\t\t\t$this->Buffer = $Buffer;\n\t\t\t$this->Pos = 0;\n\t\t}\n\n\t\tfunction isReading () { return $this->InputStream; }\n\n\t\tfunction serialUInt8 (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$val = ord($this->Buffer{$this->Pos++});\n\t\t\t\tdebug(sprintf (\"read uint8 '%d'<br>\\n\", $val));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\tdebug(\"B\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint8 Buffer size before = %u<br>\\n\", strlen($this->Buffer)));\n\t\t\t\t$this->Buffer = $this->Buffer . chr($val & 0xFF);\n\t\t\t\t$this->Pos++;\n\t\t\tdebug(\"C\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint8 '%d' %d<br>\\n\", $val, $this->Pos));\n\t\t\tdebug(sprintf (\"write uint8 Buffer size after = %u<br>\\n\", strlen($this->Buffer)));\n\t\t\t}\n\t\t}\n\n\t\tfunction serialUInt32 (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$val = ord($this->Buffer{$this->Pos++});\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*256;\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*(double)256*256;\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*(double)256*256*256;\n\t\t\t\tdebug(sprintf (\"read uint32 '%d'<br>\\n\", $val));\n//\t\t\t\tvar_dump($val);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\tdebug(\"D\".gettype($this->Buffer).\"<br>\");\n\t\t\t\t$this->Buffer .= chr($val & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>8) & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>16) & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>24) & 0xFF);\n\t\t\t\t$this->Pos += 4;\n\t\t\tdebug(\"E\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint32 '%d' %d<br>\\n\", $val, $this->Pos));\n\t\t\t}\n\t\t}\n\n\t\tfunction serialString (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$this->serialUInt32($size);\n\t\t\t\tdebug(sprintf (\"read string : size = %u<br>\\n\", $size));\n\t\t\t\t$val = substr ($this->Buffer, $this->Pos, $size);\n\t\t\t\tdebug(sprintf (\"read string '%s'<br>\\n\", $val));\n\t\t\t\t$this->Pos += strlen($val);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$lentmp = strlen($val);\n\t\t\t\t$this->serialUInt32($lentmp);\n\t\t\t\t$this->Buffer .= $val;\n\t\t\t\t$this->Pos += strlen($val);\n\t\t\t\tdebug(sprintf (\"write string '%s' %d<br>\\n\", $val, $this->Pos));\n\t\t\t}\n\t\t}\n\t}\n\t\n\tclass CMessage extends CMemStream\n\t{\n\t\tvar $MsgName;\n\t\t\n\t\tfunction CMessage()\n\t\t{\n\t\t\t$this->CMemStream();\n\t\t}\n\t\t\n\t\tfunction setName($name)\n\t\t{\n\t\t\t$this->MsgName = $name;\n\t\t}\n\t}\n\t\n\tclass CCallbackClient\n\t{\n\t\tvar\t$ConSock = false;\n\n\t\tvar $MsgNum = 0;\n\t\t\n\t\tfunction connect($addr, $port, &$res)\n\t\t{\n\t\t\tglobal $SockTimeOut;\n\t\t\t\n\t\t\tdebug(sprintf(\"Connect<br>\"));\n\t\t\t$this->MsgNum = 0;\n\t\t\t\n\t\t\t$this->ConSock = fsockopen ($addr, $port, $errno, $errstr, $SockTimeOut);\n\t\t\tdebug(\"H\".gettype($this->ConSock).\"<br>\");\n\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\t$errmsg = iconv('GBK', 'UTF-8', $errstr);\n\t\t\t\t$res = \"Can't connect to the callback server '$addr:$port' ($errno: $errmsg)\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// set time out on the socket to 2 secondes\n\t\t\t\tstream_set_timeout($this->ConSock, $SockTimeOut);\t\n\t\t\t\t$res = \"\";\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfunction close()\n\t\t{\n\t\t\tif ($this->ConSock)\n\t\t\t{\n\t\t\t\tfclose($this->ConSock);\n\t\t\t\tdebug(sprintf(\"Close<br>\"));\n\t\t\t}\n\t\t\telse\n\t\t\t\tdebug(sprintf(\"Already Closed !<br>\"));\n\t\t}\n\t\t\n\t\tfunction sendMessage(&$message)\n\t\t{\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Socket is not valid\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdebug(sprintf (\"sendMessage : message Buffer is '%d'<br>\\n\", $message->Pos));\n\t\t\tdebug(sprintf (\"sendMessage : message Buffer is '%d'<br>\\n\", strlen($message->Buffer)));\n\t\t\t$hd = new CMemStream;\n\t\t\tdebug(sprintf(\"SendMessage number %u<br>\", $this->MsgNum));\n\t\t\t$hd->serialUInt32 ($this->MsgNum);\t\t\t// number the packet\n\t\t\t$this->MsgNum += 1;\n\t\t\tdebug(sprintf(\"After SendMessage, number %u<br>\", $this->MsgNum));\n\t\t\t$messageType = 0;\n\t\t\t$hd->serialUInt8 ($messageType);\n\t\t\t$hd->serialString ($message->MsgName);\n\n\t\t\tdebug(sprintf (\"sendMessage : header size is '%d'<br>\\n\", $hd->Pos));\n\t\t\t\n//\t\t\t$sb .= $message->Buffer;\n\n\t\t\t$size = $hd->Pos + $message->Pos;\n\t\t\t$Buffer = (string) chr(($size>>24)&0xFF);\n\t\t\t$Buffer .= chr(($size>>16)&0xFF);\n\t\t\t$Buffer .= chr(($size>>8)&0xFF);\n\t\t\t$Buffer .= chr($size&0xFF);\n\t\t\tdebug( \"E\".gettype($hd->Buffer).\"<br>\");\n\t\t\tdebug(\"F\".gettype($message->Buffer).\"<br>\");\n\t\t\t$Buffer .= (string) $hd->Buffer;\n\t\t\t$Buffer .= (string) $message->Buffer;\n\t\t\t\n\t\t\tdebug(\"G\".gettype($this->ConSock).\"<br>\");\n\n\t\t\tif (!fwrite ($this->ConSock, $Buffer))\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Error writing to socket\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdebug(sprintf (\"sent packet size '%d' (written size = %d) <br>\\n\", strlen($Buffer), $size));\n\t\t\tfflush ($this->ConSock);\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tfunction waitMessage()\n\t\t{\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Socket is not valid\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\n\t\t\t$size = 0;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size = ord($val) << 24;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size = ord($val) << 16;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size += ord($val) << 8;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size += ord($val);\n\t\t\tdebug(sprintf (\"receive packet size '%d'<br>\\n\", $size));\n\t\t\t$fake = fread ($this->ConSock, 5);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size -= 5; // remove the fake\n\n\t\t\t$Buffer = \"\";\n\t\t\twhile ($size > 0 && strlen($Buffer) != $size)\n\t\t\t{\n\t\t\t\t$Buffer .= fread ($this->ConSock, $size - strlen($Buffer));\n\t\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\t\tif ($info['timed_out']) \n\t\t\t\t{\n\t\t\t\t\tdebug('Connection timed out!');\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$msgin = new CMemStream;\n\t\t\t$msgin->setBuffer ($Buffer);\n\t\t\t\n\t\t\t// decode msg name\n\t\t\t$msgin->serialString($name);\n\t\t\t\n\t\t\tdebug(sprintf(\"Message name = '%s'<BR>\", $name));\n\t\t\t$message = new CMessage;\n\t\t\t$message->setBuffer(substr($msgin->Buffer, $msgin->Pos));\n\t\t\t$message->setName($name);\n\t\t\t\n\t\t\tdebug(sprintf(\"In message name = '%s'<br>\", $message->MsgName));\n\t\t\t\n\t\t\treturn $message;\n\t\t}\n\t}\n\t\n\t\n//\tclass CSessionManagerProxy\n//\t{\n//\t\tfunction createSession($userId, $sessionType, $callbackClient)\n//\t\t{\n//\t\t\tdebug(sprintf(\"Creating session for user %u, type %s<BR>\", $userId, $sessionType));\n//\t\t\t$msg = new CMessage;\n//\t\t\t$msg->setName(\"CSS\");\n//\t\t\t$msg->serialUInt32($userId);\n//\t\t\t$msg->serialString($sessionType);\n//\t\t\t\n//\t\t\t$callbackClient->sendMessage($msg);\n//\t\t}\n//\t}\n\t\n//\tclass CSessionManagerClientSkel\n//\t{\t\n//\t\tfunction waitCallback($callbackClient)\n//\t\t{\n//\t\t\t$message = $callbackClient->waitMessage();\n//\n//\t\t\tdebug(sprintf(\"Received message '%s'<BR>\", $message->MsgName));\n//\t\t\t\n//\t\t\tswitch($message->MsgName)\n//\t\t\t{\n//\t\t\tcase \"CSSR\":\n//\t\t\t\tdebug(sprintf(\"Create session result<BR>\"));\n//\t\t\t\t$this->createSessionResult_skel($message);\n//\t\t\t\tbreak;\n//\t\t\t\t\t\n//\t\t\tcase \"CSNR\":\n//\t\t\t\tdebug(sprintf(\"Create scenario result<BR>\"));\n//\t\t\t\t$this->createScenarioResult_skel($message);\n//\t\t\t\tbreak;\n//\t\t\t};\n//\t\t}\n//\t\t\n//\t\tfunction createSessionResult_skel($message)\n//\t\t{\n//\t\t\t$userId = 0;\n//\t\t\t$sessionId = 0;\n//\t\t\t$result = false;\n//\t\t\t\n//\t\t\t$message->serialUInt32($userId);\n//\t\t\t$message->serialUInt32($sessionId);\n//\t\t\t$message->serialUInt8($result);\n//\t\t\t\n//\t\t\tcreateSessionResult($userId, $sessionId, $result);\n//\t\t}\n//\t}\n\t\n//\tprintf(\"creating callback client...<BR>\");\n//\t\n//\t$cb = new CCallbackClient;\n//\t$ret = \"\";\n//\t$cb->connect(\"192.168.0.1\", \"8060\", $ret);\n//\t\n//\t$smp = new CSessionManagerProxy;\n//\t\n//\tprintf(\"creating a new sessions...<BR>\");\n//\t$smp->createSession(10, \"st_edit\", $cb);\n//\t\n//\t$smcs = new CSessionManagerClientSkel;\n//\t$smcs->waitCallback($cb);\n//\t\n//\n//\tfunction createSessionResult($userId, $sessionId, $result)\n//\t{\n//\t\techo \"The session result for user $userId is the session $sessionId with a result of $result\\n\";\n//\t}\n//\t\n\n\t// This function connect to the AS.\n\t// If true, $res contains the url to connect.\n\t// If false, $res contains the reason why it s not okay.\n\n//\tfunction connectToAS(&$fp, &$res)\n//\t{\n//\t\tglobal\t$ASHost, $ASPort;\n///*\n//\t\t$sid = session_id();\n//\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket\");\n//\t\tif (!$result || sqlnumrows($result) == 0)\n//\t\t{\n//\t\t\t$fp = pfsockopen ($ASHost, $ASPort, $errno, $errstr, 30);\n//\t\t\techo \"opened resident socket '$fp'\\n\";\n//\t\t\t\n//\t\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket WHERE socket_id='$fp'\");\n//\t\t\tif ($result && sqlnumrows($result)>0)\n//\t\t\t\tsqlquery(\"DELETE FROM resident_socket WHERE socket_id='$fp'\");\n//\t\t\t\n//\t\t\tsqlquery(\"INSERT INTO resident_socket SET socket_id='$fp', session_id='$sid', last_access=NOW()\");\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t$result = sqlfetch($result);\n//\t\t\t$fp = $result[\"socket_id\"];\n//\t\t}\n//\t\t\n//\t\t// remove too old sockets\n//\t\tsqlquery(\"SELECT socket_id FROM resident_socket WHERE NOW()-last_access > 1800\");\n//\t\twhile ($result && ($arr=sqlfetch($result)))\n//\t\t{\n//\t\t\tfclose((int)($arr[\"socket_id\"]));\n//\t\t\tsqlquery(\"DELETE FROM resident_socket WHERE socket_id='\".$arr[\"socket_id\"].\"'\");\n//\t\t}\n//\n//\t\t// update current socket last access\n//\t\tsqlquery(\"UPDATE resident_socket SET last_access=NOW() WHERE socket_id='$fp' AND session_id='$sid'\");\n//*/\n//\n//\t\t// connect to the login service that must be $ASHost:$ASPort\n//\t\t$fp = fsockopen ($ASHost, $ASPort, $errno, $errstr, 30);\n//\t\tif (!$fp)\n//\t\t{\n//\t\t\t$res = \"Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)\";\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t$res = \"\";\n//\t\t}\n//\n//\t}\n//\t\n//\tfunction disconnectFromAS(&$fp)\n//\t{\n///*\n//\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket WHERE socket_id='$fp'\");\n//\t\tif (!$result || sqlnumrows($socket)==0)\n//\t\t\tfclose($fp);\n//*/\n//\t\tfclose($fp);\n//\t}\n//\n//\tfunction sendMessage ($fp, $msgout)\n//\t{\n//\t\t$size = $msgout->Pos;\n//\t\t$Buffer = chr(($size>>24)&0xFF);\n//\t\t$Buffer .= chr(($size>>16)&0xFF);\n//\t\t$Buffer .= chr(($size>>8)&0xFF);\n//\t\t$Buffer .= chr($size&0xFF);\n//\t\t$Buffer .= $msgout->Buffer;\n//\n//\t\tfwrite ($fp, $Buffer);\n//\n//\t\t//printf (\"sent packet size '%d'<br>\", strlen($Buffer));\n//\t\t\n//\t\tfflush ($fp);\n//\t}\n//\n//\tfunction waitMessage ($fp, &$msgin)\n//\t{\n//\t\t//echo \"waiting a message\";\n//\t\t$size = 0;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size = ord($val) << 24;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size = ord($val) << 16;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size += ord($val) << 8;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size += ord($val);\n//\t\t//printf (\"receive packet size '%d'<br>\", $size);\n//\t\t$fake = fread ($fp, 4);\n//\t\t$size -= 4; // remove the fake\n//\n//\t\t$Buffer = fread ($fp, $size);\n//\t\t$msgin = new CMemStream;\n//\t\t$msgin->setBuffer ($Buffer);\n//\t}\n//\t\n//\tfunction logNelQuery($query)\n//\t{\n//\t\tglobal\t$uid;\n///*\n//\t\t$f = fopen(\"./nel_queries.log\", \"a\");\n//\t\tfwrite($f, date(\"Y/m/d H:i:s\").\" \".sprintf(\"%-16s\", $admlogin).\" $query\\n\");\n//\t\tfclose($f);\n//*/\n//\n//\t\tlogUser($uid, \"QUERY=\".$query);\n//\t}\n//\n//\tfunction nel_query($rawvarpath, &$result)\n//\t{\n//\t\tglobal\t\t\t$nel_queries;\n//\n//\t\t$nel_queries[] = $rawvarpath;\n//\t\t$ok = false;\n//\t\t//echo \"rawvarpath=$rawvarpath<br>\\n\";\n//\t\t\n//\t\t//logNelQuery($rawvarpath);\n//\n//\t\tconnectToAS($fp, $result);\n//\t\tif(strlen($result) != 0)\n//\t\t\treturn $ok;\n//\n//\t\t// send the message that say that we want to add a user\n//\t\t$msgout = new CMemStream;\n//\t\t$fake = 0;\n//\t\t$msgout->serialuint32 ($fake);\t\t\t// fake used to number the packet\n//\t\t$messageType = 0;\n//\t\t$msgout->serialuint8 ($messageType);\n//\t\t$msgout->serialstring ($rawvarpath);\n//\n//\t\tsendMessage ($fp, $msgout);\n//\n//\t\twaitMessage ($fp, $msgin);\n//\n//\t\t$msgin->serialstring($result);\n//\t\t\t\n//\t\tif(strlen($result) == 0)\n//\t\t{\n//\t\t\t// it failed\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t// it's ok\n//\t\t\t$ok = true;\n//\t\t}\n//\n//\t\t//printf(\"receive response '$result'<br>\\n\");\n//\n//\t\tdisconnectFromAS(&$fp);\n//\t\t//echo \"sent OK.<br><br>\\n\";\n//\n//\t\treturn $ok;\n//\t}\n?>\n"
  },
  {
    "path": "tools/server/admin/neltool.css",
    "content": "\nbody        {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n\tbackground-color: #FFFFFF;\n}\n\ntd          {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n}\n\ntable       {\n\tmargin: 0px;\n\tpadding: 0px;\n\tborder-collapse: collapse;\n\tborder-spacing: 0;\n}\n\nth          {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n\tbackground-color: #999999;\n}\n\ninput       {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n}\n\ninput.small\t{\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 9px;\n\twidth: 45px;\n}\n\ntextarea    {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n\twidth:98%;\n\tborder-left: 1px solid #000000;\n\tborder-right: 1px solid #000000;\n\tborder-top: 1px solid #000000;\n\tborder-bottom: 1px solid #000000;\n}\n\ntextarea.command {\n\tfont-family: Terminal, Courier;\n\tfont-size: 10pt;\n}\n\na:link { color: #000088; text-decoration: none; }\na:visited { color: #000088; text-decoration: none; }\na:active { color: #000033; text-decoration: none; }\na:hover { color: #8800CC; text-decoration: underline; }\n\ntd.boxed {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n\tborder-left: 1px solid #000000;\n\tborder-right: 1px solid #000000;\n\tborder-top: 1px solid #000000;\n\tborder-bottom: 1px solid #000000;\n\tbackground-color: #eeeeee;\n\tpadding-left: 5px;\n\tpadding-right: 5px;\n\ttext-align: center;\n\tvertical-align: middle;\n}\n\ntd.line_left   { border-left: 1px solid #000000;   }\ntd.line_right  { border-right: 1px solid #000000;  }\ntd.line_top    { border-top: 1px solid #000000;    }\ntd.line_bottom { border-bottom: 1px solid #000000; }\n\n\ntable.viewlist { height:100%; }\ntable.view {\n\tborder-left: 1px solid #000000;\n\tborder-right: 1px solid #000000;\n\tborder-top: 1px solid #000000;\n\tborder-bottom: 1px solid #000000;\n}\n\ntd.offline { background-color: #FF0000; }\ntd.unknown { background-color: #FFAA00; }\n\ntr.row0 \t\t\t{ background-color: #CCCCCC; }\ntr.row1 \t\t\t{ background-color: #DDDDDD; }\n\ntr.row0_static\t\t{ background-color: #CCCCCC; }\ntr.row1_static\t\t{ background-color: #DDDDDD; }\n\ntr.row_red\t\t\t{ background-color: #C83C3C; }\ntr.row_orange_dark\t{ background-color: #E4916F; }\ntr.row_orange_light\t{ background-color: #F2D079; }\n\ntr.row_stopped\t\t{ background-color: #AAAAAA; }\ntr.row_starting\t\t{ background-color: #75D5A8; }\n\ntr.row0:hover, tr.row1:hover, tr.row_stopped:hover, tr.row_starting:hover, tr.row_red:hover, tr.row_orange_dark:hover, tr.row_orange_light:hover {\n\tbackground-color: #99BBDD;\n}\n\ntr.row_restart_active {\n\tbackground-color: #CC8899;\n\tborder-left: 1px solid #000000;\n\tborder-right: 1px solid #000000;\n\tborder-top: 1px solid #000000;\n\tborder-bottom: 1px solid #000000;\n}\n\ntd.cell_inactive1\t{ color: #666666; }\ntd.cell_inactive2\t{ color: #666666; font-style: italic; }\n\ntd.heads {\n\tfont-family: Verdana, Arial, Helvetica, sans-serif;\n\tfont-size: 12px;\n\tbackground-color: #999999;\n\tfont-weight: bold;\n}\n\ninput {\n\tborder-left: 1px solid #000000;\n\tborder-right: 1px solid #000000;\n\tborder-top: 1px solid #000000;\n\tborder-bottom: 1px solid #000000;\n}\n\ninput.check {\n\tborder-left: 0px solid #000000;\n\tborder-right: 0px solid #000000;\n\tborder-top: 0px solid #000000;\n\tborder-bottom: 0px solid #000000;\n}\n\ninput.refresh_counter {\n\tborder-left: 0px solid #000000;\n\tborder-right: 0px solid #000000;\n\tborder-top: 0px solid #000000;\n\tborder-bottom: 0px solid #000000;\n\tbackground-color: #cccccc;\n\ttext-align: center;\n\twidth: 100%;\n}\n\ninput.restart {\n\tbackground-color: #CC8899;\n}\n\nspan.alert {\n\tcolor: #FF0000;\n\tfont-weight: bold;\n\ttext-decoration: underline;\n}\n\nspan.basicbold {\n\tcolor: #000000;\n\tfont-weight: bold;\n}\n\nspan.running {\n\tcolor: #38A167;\n\tfont-weight: bold;\n}\n\nspan.autostart_on {\n\tcolor: #38A167;\n\tfont-weight: bold;\n}\n\nspan.autostart_off {\n\tcolor: #C83C3C;\n\tfont-weight: bold;\n}\n\nspan.stopped {\n\tcolor: #C83C3C;\n\tfont-weight: bold;\n}\n\n\ntd.domainlist:hover {\n\tbackground-color: #7799BB;\n}\n\ntd.domainlistselected {\n\tbackground-color: #99BBDD;\n\tfont-weight: bold;\n}\n\ntd.shardlist:hover {\n\tbackground-color: #7799BB;\n}\n\ntd.shardlistselected {\n\tbackground-color: #99BBDD;\n\tfont-weight: bold;\n}\n\ntr.varlist:hover {\n\tbackground-color: #7799BB;\n}\n\ntr.varlistselected {\n\tbackground-color: #99BBDD;\n}\n\n.ws_close {\n\tbackground-color: #888888;\n}\n\n.ws_dev {\n\tbackground-color: #DD8888;\n}\n\n.ws_restricted {\n\tbackground-color: #DDDD88;\n}\n\n.ws_open {\n\tbackground-color: #88DD88;\n}\n\n"
  },
  {
    "path": "tools/server/admin/overlib/makemini.pl",
    "content": "#!/usr/bin/perl\n\nmy $doPlugin = 0;\nmy $x = shift(@ARGV);\nif ($x !~ /^-p/) { unshift(@ARGV, $x); }\nelse { $doPlugin=1; }\nmy $injs = shift(@ARGV);\nmy $outjs = shift(@ARGV);\n\nif ($injs eq '' or $outjs eq '') {\n\tprint \"Please use this script like this: makemini.pl [-p] in.js out.js\\n\";\t\n\texit(0);\n}\n\n\nopen(INJS, $injs);\nopen(OUTJS, \">$outjs\");\n\nmy $output = '';\n\nwhile (<INJS>) {\n\tmy $line = $_;\n\t\n\tif ($line =~ /^\\/\\//) {\n\t\t# Remove lines that aren't important: //\\\n\t\t$line = \"\" if ($line !~ /^\\/\\/\\\\/);\n\t\t$line = \"\\n//\\\\  THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL!\\n\\n\" if ($line =~ /\\/\\/\\\\mini/);\n\t} else {\n\t\tchop $line;\n\n\t\t$line =~ s/, /,/g unless ($line =~ /'\\], '/);           # ,{sp} -> ,\n\t\t$line =~ s/; /;/g;           # ;{sp} -> ;\n\t\t$line =~ s/ = /=/g;          # {sp}={sp} -> =\n\t\t$line =~ s/ == /==/g;        # {sp}=={sp} -> ==\n\t\t$line =~ s/ < /</g;          # {sp}<{sp} -> <\n\t\t$line =~ s/ > />/g;          # {sp}>{sp} -> >\n\t\t$line =~ s/ & /&/g;          # {sp}&{sp} -> &\n\t\t$line =~ s/ \\| /\\|/g;        # {sp}|{sp} -> |\n\t\t$line =~ s/ <= /<=/g;        # {sp}<={sp} -> <=\n\t\t$line =~ s/ >= />=/g;        # {sp}>={sp} -> >=\n\t\t$line =~ s/ \\+ /\\+/g;        # {sp}+{sp} -> +\n\t\t$line =~ s/ - /-/g;          # {sp}-{sp} -> -\n\t\t$line =~ s/ \\/ /\\//g;\n\t\t$line =~ s/ \\|\\| /\\|\\|/g;    # {sp}||{sp} -> ||\n\t\t$line =~ s/ && /&&/g;        # {sp}&&{sp} -> &&\n\t\t$line =~ s/ \\? /\\?/g;        # {sp?{sp} -> ?\n\t\t$line =~ s/ \\: /\\:/g;        # {sp}:{sp} -> :\n\t\t$line =~ s/ != /!=/g;        # {sp}!={sp} -> !=\n\t\t$line =~ s/ += /+=/g;        # {sp}+={sp} -> +=\n\t\t$line =~ s/ -= /-=/g;        # {sp}-={sp} -> -=\n\t\t$line =~ s/ \\*= /\\*=/g;      # {sp}*={sp} -> *=\n\t\t$line =~ s/ \\|= /\\|=/g;       # {sp}|={sp} -> |=\n\t\t$line =~ s/ \\^= /\\^=/g;       # {sp}^={sp} -> ^=\n\t\t$line =~ s/= /=/g;           # ={sp} -> =\n\t\t$line =~ s/ =/=/g;           # {sp}= -> =\n\t\t$line =~ s/\\+ /\\+/g;\n\t\t$line =~ s/ \\+/\\+/g;\n\t\t$line =~ s/- /-/g;\n\t\t$line =~ s/ -/-/g;\n\n\t\t$line =~ s/\\/\\/(.*)$//g if ($line !~ /\\/\\/-->(.*)$/ && $line !~ /http:\\/\\/(.*)$/); # remove trailing comments unless its part of a javascript insert or web address\n\t\t$line = '' if $line =~ /^[\\n|\\/\\/]/; # skip blank lines or any line starting with //\n\n\t\t$line =~ s/^\\s+//g;\n\t\t$line =~ s/\\s+$//g;\n\t\t$line =~ s/(.+)\\s+(.+)/$1 $2/g;\n\t\t$line =~ s/\\{ (\\w)/\\{$1/g;\n\t\t$line =~ s/\\) (\\w)/\\)$1/g;\n\t\t$line =~ s/\\) var/\\)var/g;\n\t\t$line =~ s/[ ]+\\(/\\(/g;\n\t\t$line =~ s/\\) \\{/\\)\\{/g;\n\t\t$line =~ s/\\} else/\\}else/g;\n\t\t$line =~ s/else \\{/else\\{/g;\n\t\tif ($line =~ /^\\}$/) {\n\t\t\tif ($output =~ /;$/) {\n\t\t\t\t$output .= \"}\";\n\t\t\t} else {\n\t\t\t\t$output = substr($output,0,length($output)-1) . \"}\";\n\t\t\t}\n\t\t\t$line = '';\n\t\t}\n\t}\n\n\t$output .= $line if ($line ne '');\n\t$output .= \"\\n\" unless ($line =~ /;\\n*$/ or $line =~ /{\\n*$/);\n}\n\n$output =~ s/\\n+/\\n/g;\n$output .= \"}\\n\" if ($doPlugin && $output !~ /\\}\\s+$/);\n# replace multiple ;var xx to ,xx if the line contains var\n@lines = split(/^/,$output);\nforeach $line (@lines) {\n\t$line =~ s/;var /,/g if ($line =~ /^\\s*var / && $line !~ /(turn|ment|Capture\\(\\)|Div'\\)|1000\\));var /);\n\tprint OUTJS $line;\n}\n"
  },
  {
    "path": "tools/server/admin/overlib/overlib.js",
    "content": "//\\/////\n//\\  overLIB 4.21 - You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2004. All rights reserved.\n//\\\n//\\  Contributors are listed on the homepage.\n//\\  This file might be old, always check for the latest version at:\n//\\  http://www.bosrup.com/web/overlib/\n//\\\n//\\  Please read the license agreement (available through the link above)\n//\\  before using overLIB. Direct any licensing questions to erik@bosrup.com.\n//\\\n//\\  Do not sell this as your own work or remove this copyright notice.\n//\\  For full details on copying or changing this script please read the\n//\\  license agreement at the link above. Please give credit on sites that\n//\\  use overLIB and submit changes of the script so other people can use\n//\\  them as well.\n//   $Revision: 1.1 $                $Date: 2006/05/29 16:38:21 $\n//\\/////\n//\\mini\n\n////////\n// PRE-INIT\n// Ignore these lines, configuration is below.\n////////\nvar olLoaded = 0;var pmStart = 10000000; var pmUpper = 10001000; var pmCount = pmStart+1; var pmt=''; var pms = new Array(); var olInfo = new Info('4.21', 1);\nvar FREPLACE = 0; var FBEFORE = 1; var FAFTER = 2; var FALTERNATE = 3; var FCHAIN=4;\nvar olHideForm=0;  // parameter for hiding SELECT and ActiveX elements in IE5.5+\nvar olHautoFlag = 0;  // flags for over-riding VAUTO and HAUTO if corresponding\nvar olVautoFlag = 0;  // positioning commands are used on the command line\nvar hookPts = new Array(), postParse = new Array(), cmdLine = new Array(), runTime = new Array();\n// for plugins\nregisterCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass');\n\n////////\n// DEFAULT CONFIGURATION\n// Settings you want everywhere are set here. All of this can also be\n// changed on your html page or through an overLIB call.\n////////\nif (typeof ol_fgcolor=='undefined') var ol_fgcolor=\"#99BBDD\";\nif (typeof ol_bgcolor=='undefined') var ol_bgcolor=\"#7799BB\";\nif (typeof ol_textcolor=='undefined') var ol_textcolor=\"#000000\";\nif (typeof ol_capcolor=='undefined') var ol_capcolor=\"#000033\";\nif (typeof ol_closecolor=='undefined') var ol_closecolor=\"#000000\";\nif (typeof ol_textfont=='undefined') var ol_textfont=\"Verdana,Arial,Helvetica\";\nif (typeof ol_captionfont=='undefined') var ol_captionfont=\"Verdana,Arial,Helvetica\";\nif (typeof ol_closefont=='undefined') var ol_closefont=\"Verdana,Arial,Helvetica\";\nif (typeof ol_textsize=='undefined') var ol_textsize=\"1\";\nif (typeof ol_captionsize=='undefined') var ol_captionsize=\"1\";\nif (typeof ol_closesize=='undefined') var ol_closesize=\"1\";\nif (typeof ol_width=='undefined') var ol_width=\"200\";\nif (typeof ol_border=='undefined') var ol_border=\"1\";\nif (typeof ol_cellpad=='undefined') var ol_cellpad=2;\nif (typeof ol_offsetx=='undefined') var ol_offsetx=10;\nif (typeof ol_offsety=='undefined') var ol_offsety=10;\nif (typeof ol_text=='undefined') var ol_text=\"Default Text\";\nif (typeof ol_cap=='undefined') var ol_cap=\"\";\nif (typeof ol_sticky=='undefined') var ol_sticky=0;\nif (typeof ol_background=='undefined') var ol_background=\"\";\nif (typeof ol_close=='undefined') var ol_close=\"Close\";\nif (typeof ol_hpos=='undefined') var ol_hpos=RIGHT;\nif (typeof ol_status=='undefined') var ol_status=\"\";\nif (typeof ol_autostatus=='undefined') var ol_autostatus=0;\nif (typeof ol_height=='undefined') var ol_height=-1;\nif (typeof ol_snapx=='undefined') var ol_snapx=0;\nif (typeof ol_snapy=='undefined') var ol_snapy=0;\nif (typeof ol_fixx=='undefined') var ol_fixx=-1;\nif (typeof ol_fixy=='undefined') var ol_fixy=-1;\nif (typeof ol_relx=='undefined') var ol_relx=null;\nif (typeof ol_rely=='undefined') var ol_rely=null;\nif (typeof ol_fgbackground=='undefined') var ol_fgbackground=\"\";\nif (typeof ol_bgbackground=='undefined') var ol_bgbackground=\"\";\nif (typeof ol_padxl=='undefined') var ol_padxl=1;\nif (typeof ol_padxr=='undefined') var ol_padxr=1;\nif (typeof ol_padyt=='undefined') var ol_padyt=1;\nif (typeof ol_padyb=='undefined') var ol_padyb=1;\nif (typeof ol_fullhtml=='undefined') var ol_fullhtml=0;\nif (typeof ol_vpos=='undefined') var ol_vpos=BELOW;\nif (typeof ol_aboveheight=='undefined') var ol_aboveheight=0;\nif (typeof ol_capicon=='undefined') var ol_capicon=\"\";\nif (typeof ol_frame=='undefined') var ol_frame=self;\nif (typeof ol_timeout=='undefined') var ol_timeout=0;\nif (typeof ol_function=='undefined') var ol_function=null;\nif (typeof ol_delay=='undefined') var ol_delay=0;\nif (typeof ol_hauto=='undefined') var ol_hauto=0;\nif (typeof ol_vauto=='undefined') var ol_vauto=0;\nif (typeof ol_closeclick=='undefined') var ol_closeclick=0;\nif (typeof ol_wrap=='undefined') var ol_wrap=0;\nif (typeof ol_followmouse=='undefined') var ol_followmouse=1;\nif (typeof ol_mouseoff=='undefined') var ol_mouseoff=0;\nif (typeof ol_closetitle=='undefined') var ol_closetitle='Close';\nif (typeof ol_compatmode=='undefined') var ol_compatmode=0;\nif (typeof ol_css=='undefined') var ol_css=CSSOFF;\nif (typeof ol_fgclass=='undefined') var ol_fgclass=\"\";\nif (typeof ol_bgclass=='undefined') var ol_bgclass=\"\";\nif (typeof ol_textfontclass=='undefined') var ol_textfontclass=\"\";\nif (typeof ol_captionfontclass=='undefined') var ol_captionfontclass=\"\";\nif (typeof ol_closefontclass=='undefined') var ol_closefontclass=\"\";\n\n////////\n// ARRAY CONFIGURATION\n////////\n\n// You can use these arrays to store popup text here instead of in the html.\nif (typeof ol_texts=='undefined') var ol_texts = new Array(\"Text 0\", \"Text 1\");\nif (typeof ol_caps=='undefined') var ol_caps = new Array(\"Caption 0\", \"Caption 1\");\n\n////////\n// END OF CONFIGURATION\n// Don't change anything below this line, all configuration is above.\n////////\n\n\n\n\n\n////////\n// INIT\n////////\n// Runtime variables init. Don't change for config!\nvar o3_text=\"\";\nvar o3_cap=\"\";\nvar o3_sticky=0;\nvar o3_background=\"\";\nvar o3_close=\"Close\";\nvar o3_hpos=RIGHT;\nvar o3_offsetx=2;\nvar o3_offsety=2;\nvar o3_fgcolor=\"\";\nvar o3_bgcolor=\"\";\nvar o3_textcolor=\"\";\nvar o3_capcolor=\"\";\nvar o3_closecolor=\"\";\nvar o3_width=100;\nvar o3_border=1;\nvar o3_cellpad=2;\nvar o3_status=\"\";\nvar o3_autostatus=0;\nvar o3_height=-1;\nvar o3_snapx=0;\nvar o3_snapy=0;\nvar o3_fixx=-1;\nvar o3_fixy=-1;\nvar o3_relx=null;\nvar o3_rely=null;\nvar o3_fgbackground=\"\";\nvar o3_bgbackground=\"\";\nvar o3_padxl=0;\nvar o3_padxr=0;\nvar o3_padyt=0;\nvar o3_padyb=0;\nvar o3_fullhtml=0;\nvar o3_vpos=BELOW;\nvar o3_aboveheight=0;\nvar o3_capicon=\"\";\nvar o3_textfont=\"Verdana,Arial,Helvetica\";\nvar o3_captionfont=\"Verdana,Arial,Helvetica\";\nvar o3_closefont=\"Verdana,Arial,Helvetica\";\nvar o3_textsize=\"1\";\nvar o3_captionsize=\"1\";\nvar o3_closesize=\"1\";\nvar o3_frame=self;\nvar o3_timeout=0;\nvar o3_timerid=0;\nvar o3_allowmove=0;\nvar o3_function=null;\nvar o3_delay=0;\nvar o3_delayid=0;\nvar o3_hauto=0;\nvar o3_vauto=0;\nvar o3_closeclick=0;\nvar o3_wrap=0;\nvar o3_followmouse=1;\nvar o3_mouseoff=0;\nvar o3_closetitle='';\nvar o3_compatmode=0;\nvar o3_css=CSSOFF;\nvar o3_fgclass=\"\";\nvar o3_bgclass=\"\";\nvar o3_textfontclass=\"\";\nvar o3_captionfontclass=\"\";\nvar o3_closefontclass=\"\";\n\n// Display state variables\nvar o3_x = 0;\nvar o3_y = 0;\nvar o3_showingsticky = 0;\nvar o3_removecounter = 0;\n\n// Our layer\nvar over = null;\nvar fnRef, hoveringSwitch = false;\nvar olHideDelay;\n\n// Decide browser version\nvar isMac = (navigator.userAgent.indexOf(\"Mac\") != -1);\nvar olOp = (navigator.userAgent.toLowerCase().indexOf('opera') > -1 && document.createTextNode);  // Opera 7\nvar olNs4 = (navigator.appName=='Netscape' && parseInt(navigator.appVersion) == 4);\nvar olNs6 = (document.getElementById) ? true : false;\nvar olKq = (olNs6 && /konqueror/i.test(navigator.userAgent));\nvar olIe4 = (document.all) ? true : false;\nvar olIe5 = false;\nvar olIe55 = false; // Added additional variable to identify IE5.5+\nvar docRoot = 'document.body';\n\n// Resize fix for NS4.x to keep track of layer\nif (olNs4) {\n\tvar oW = window.innerWidth;\n\tvar oH = window.innerHeight;\n\twindow.onresize = function() { if (oW != window.innerWidth || oH != window.innerHeight) location.reload(); }\n}\n\n// Microsoft Stupidity Check(tm).\nif (olIe4) {\n\tvar agent = navigator.userAgent;\n\tif (/MSIE/.test(agent)) {\n\t\tvar versNum = parseFloat(agent.match(/MSIE[ ](\\d\\.\\d+)\\.*/i)[1]);\n\t\tif (versNum >= 5){\n\t\t\tolIe5=true;\n\t\t\tolIe55=(versNum>=5.5&&!olOp) ? true : false;\n\t\t\tif (olNs6) olNs6=false;\n\t\t}\n\t}\n\tif (olNs6) olIe4 = false;\n}\n\n// Check for compatability mode.\nif (document.compatMode && document.compatMode == 'CSS1Compat') {\n\tdocRoot= ((olIe4 && !olOp) ? 'document.documentElement' : docRoot);\n}\n\n// Add window onload handlers to indicate when all modules have been loaded\n// For Netscape 6+ and Mozilla, uses addEventListener method on the window object\n// For IE it uses the attachEvent method of the window object and for Netscape 4.x\n// it sets the window.onload handler to the OLonload_handler function for Bubbling\nif(window.addEventListener) window.addEventListener(\"load\",OLonLoad_handler,false);\nelse if (window.attachEvent) window.attachEvent(\"onload\",OLonLoad_handler);\n\nvar capExtent;\n\n////////\n// PUBLIC FUNCTIONS\n////////\n\n// overlib(arg0,...,argN)\n// Loads parameters into global runtime variables.\nfunction overlib() {\n\tif (!olLoaded || isExclusive(overlib.arguments)) return true;\n\tif (olCheckMouseCapture) olMouseCapture();\n\tif (over) {\n\t\tover = (typeof over.id != 'string') ? o3_frame.document.all['overDiv'] : over;\n\t\tcClick();\n\t}\n\n\t// Load defaults to runtime.\n  olHideDelay=0;\n\to3_text=ol_text;\n\to3_cap=ol_cap;\n\to3_sticky=ol_sticky;\n\to3_background=ol_background;\n\to3_close=ol_close;\n\to3_hpos=ol_hpos;\n\to3_offsetx=ol_offsetx;\n\to3_offsety=ol_offsety;\n\to3_fgcolor=ol_fgcolor;\n\to3_bgcolor=ol_bgcolor;\n\to3_textcolor=ol_textcolor;\n\to3_capcolor=ol_capcolor;\n\to3_closecolor=ol_closecolor;\n\to3_width=ol_width;\n\to3_border=ol_border;\n\to3_cellpad=ol_cellpad;\n\to3_status=ol_status;\n\to3_autostatus=ol_autostatus;\n\to3_height=ol_height;\n\to3_snapx=ol_snapx;\n\to3_snapy=ol_snapy;\n\to3_fixx=ol_fixx;\n\to3_fixy=ol_fixy;\n\to3_relx=ol_relx;\n\to3_rely=ol_rely;\n\to3_fgbackground=ol_fgbackground;\n\to3_bgbackground=ol_bgbackground;\n\to3_padxl=ol_padxl;\n\to3_padxr=ol_padxr;\n\to3_padyt=ol_padyt;\n\to3_padyb=ol_padyb;\n\to3_fullhtml=ol_fullhtml;\n\to3_vpos=ol_vpos;\n\to3_aboveheight=ol_aboveheight;\n\to3_capicon=ol_capicon;\n\to3_textfont=ol_textfont;\n\to3_captionfont=ol_captionfont;\n\to3_closefont=ol_closefont;\n\to3_textsize=ol_textsize;\n\to3_captionsize=ol_captionsize;\n\to3_closesize=ol_closesize;\n\to3_timeout=ol_timeout;\n\to3_function=ol_function;\n\to3_delay=ol_delay;\n\to3_hauto=ol_hauto;\n\to3_vauto=ol_vauto;\n\to3_closeclick=ol_closeclick;\n\to3_wrap=ol_wrap;\n\to3_followmouse=ol_followmouse;\n\to3_mouseoff=ol_mouseoff;\n\to3_closetitle=ol_closetitle;\n\to3_css=ol_css;\n\to3_compatmode=ol_compatmode;\n\to3_fgclass=ol_fgclass;\n\to3_bgclass=ol_bgclass;\n\to3_textfontclass=ol_textfontclass;\n\to3_captionfontclass=ol_captionfontclass;\n\to3_closefontclass=ol_closefontclass;\n\n\tsetRunTimeVariables();\n\n\tfnRef = '';\n\n\t// Special for frame support, over must be reset...\n\to3_frame = ol_frame;\n\n\tif(!(over=createDivContainer())) return false;\n\n\tparseTokens('o3_', overlib.arguments);\n\tif (!postParseChecks()) return false;\n\n\tif (o3_delay == 0) {\n\t\treturn runHook(\"olMain\", FREPLACE);\n \t} else {\n\t\to3_delayid = setTimeout(\"runHook('olMain', FREPLACE)\", o3_delay);\n\t\treturn false;\n\t}\n}\n\n// Clears popups if appropriate\nfunction nd(time) {\n\tif (olLoaded && !isExclusive()) {\n\t\thideDelay(time);  // delay popup close if time specified\n\n\t\tif (o3_removecounter >= 1) { o3_showingsticky = 0 };\n\n\t\tif (o3_showingsticky == 0) {\n\t\t\to3_allowmove = 0;\n\t\t\tif (over != null && o3_timerid == 0) runHook(\"hideObject\", FREPLACE, over);\n\t\t} else {\n\t\t\to3_removecounter++;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n// The Close onMouseOver function for stickies\nfunction cClick() {\n\tif (olLoaded) {\n\t\trunHook(\"hideObject\", FREPLACE, over);\n\t\to3_showingsticky = 0;\n\t}\n\treturn false;\n}\n\n// Method for setting page specific defaults.\nfunction overlib_pagedefaults() {\n\tparseTokens('ol_', overlib_pagedefaults.arguments);\n}\n\n\n////////\n// OVERLIB MAIN FUNCTION\n////////\n\n// This function decides what it is we want to display and how we want it done.\nfunction olMain() {\n\tvar layerhtml, styleType;\n \trunHook(\"olMain\", FBEFORE);\n\n\tif (o3_background!=\"\" || o3_fullhtml) {\n\t\t// Use background instead of box.\n\t\tlayerhtml = runHook('ol_content_background', FALTERNATE, o3_css, o3_text, o3_background, o3_fullhtml);\n\t} else {\n\t\t// They want a popup box.\n\t\tstyleType = (pms[o3_css-1-pmStart] == \"cssoff\" || pms[o3_css-1-pmStart] == \"cssclass\");\n\n\t\t// Prepare popup background\n\t\tif (o3_fgbackground != \"\") o3_fgbackground = \"background=\\\"\"+o3_fgbackground+\"\\\"\";\n\t\tif (o3_bgbackground != \"\") o3_bgbackground = (styleType ? \"background=\\\"\"+o3_bgbackground+\"\\\"\" : o3_bgbackground);\n\n\t\t// Prepare popup colors\n\t\tif (o3_fgcolor != \"\") o3_fgcolor = (styleType ? \"bgcolor=\\\"\"+o3_fgcolor+\"\\\"\" : o3_fgcolor);\n\t\tif (o3_bgcolor != \"\") o3_bgcolor = (styleType ? \"bgcolor=\\\"\"+o3_bgcolor+\"\\\"\" : o3_bgcolor);\n\n\t\t// Prepare popup height\n\t\tif (o3_height > 0) o3_height = (styleType ? \"height=\\\"\"+o3_height+\"\\\"\" : o3_height);\n\t\telse o3_height = \"\";\n\n\t\t// Decide which kinda box.\n\t\tif (o3_cap==\"\") {\n\t\t\t// Plain\n\t\t\tlayerhtml = runHook('ol_content_simple', FALTERNATE, o3_css, o3_text);\n\t\t} else {\n\t\t\t// With caption\n\t\t\tif (o3_sticky) {\n\t\t\t\t// Show close text\n\t\t\t\tlayerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, o3_close);\n\t\t\t} else {\n\t\t\t\t// No close text\n\t\t\t\tlayerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, \"\");\n\t\t\t}\n\t\t}\n\t}\n\n\t// We want it to stick!\n\tif (o3_sticky) {\n\t\tif (o3_timerid > 0) {\n\t\t\tclearTimeout(o3_timerid);\n\t\t\to3_timerid = 0;\n\t\t}\n\t\to3_showingsticky = 1;\n\t\to3_removecounter = 0;\n\t}\n\n\t// Created a separate routine to generate the popup to make it easier\n\t// to implement a plugin capability\n\tif (!runHook(\"createPopup\", FREPLACE, layerhtml)) return false;\n\n\t// Prepare status bar\n\tif (o3_autostatus > 0) {\n\t\to3_status = o3_text;\n\t\tif (o3_autostatus > 1) o3_status = o3_cap;\n\t}\n\n\t// When placing the layer the first time, even stickies may be moved.\n\to3_allowmove = 0;\n\n\t// Initiate a timer for timeout\n\tif (o3_timeout > 0) {\n\t\tif (o3_timerid > 0) clearTimeout(o3_timerid);\n\t\to3_timerid = setTimeout(\"cClick()\", o3_timeout);\n\t}\n\n\t// Show layer\n\trunHook(\"disp\", FREPLACE, o3_status);\n\trunHook(\"olMain\", FAFTER);\n\n\treturn (olOp && event && event.type == 'mouseover' && !o3_status) ? '' : (o3_status != '');\n}\n\n////////\n// LAYER GENERATION FUNCTIONS\n////////\n// These functions just handle popup content with tags that should adhere to the W3C standards specification.\n\n// Makes simple table without caption\nfunction ol_content_simple(text) {\n\tvar cpIsMultiple = /,/.test(o3_cellpad);\n\tvar txt = '<table width=\"'+o3_width+ '\" border=\"0\" cellpadding=\"'+o3_border+'\" cellspacing=\"0\" '+(o3_bgclass ? 'class=\"'+o3_bgclass+'\"' : o3_bgcolor+' '+o3_height)+'><tr><td><table width=\"100%\" border=\"0\" '+((olNs4||!cpIsMultiple) ? 'cellpadding=\"'+o3_cellpad+'\" ' : '')+'cellspacing=\"0\" '+(o3_fgclass ? 'class=\"'+o3_fgclass+'\"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign=\"TOP\"'+(o3_textfontclass ? ' class=\"'+o3_textfontclass+'\">' : ((!olNs4&&cpIsMultiple) ? ' style=\"'+setCellPadStr(o3_cellpad)+'\">' : '>'))+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';\n\n\tset_background(\"\");\n\treturn txt;\n}\n\n// Makes table with caption and optional close link\nfunction ol_content_caption(text,title,close) {\n\tvar nameId, txt, cpIsMultiple = /,/.test(o3_cellpad);\n\tvar closing, closeevent;\n\n\tclosing = \"\";\n\tcloseevent = \"onmouseover\";\n\tif (o3_closeclick == 1) closeevent = (o3_closetitle ? \"title='\" + o3_closetitle +\"'\" : \"\") + \" onclick\";\n\tif (o3_capicon != \"\") {\n\t  nameId = ' hspace = \\\"5\\\"'+' align = \\\"middle\\\" alt = \\\"\\\"';\n\t  if (typeof o3_dragimg != 'undefined' && o3_dragimg) nameId =' hspace=\\\"5\\\"'+' name=\\\"'+o3_dragimg+'\\\" id=\\\"'+o3_dragimg+'\\\" align=\\\"middle\\\" alt=\\\"Drag Enabled\\\" title=\\\"Drag Enabled\\\"';\n\t  o3_capicon = '<img src=\\\"'+o3_capicon+'\\\"'+nameId+' />';\n\t}\n\n\tif (close != \"\")\n\t\tclosing = '<td '+(!o3_compatmode && o3_closefontclass ? 'class=\"'+o3_closefontclass : 'align=\"RIGHT')+'\"><a href=\"javascript:return '+fnRef+'cClick();\"'+((o3_compatmode && o3_closefontclass) ? ' class=\"' + o3_closefontclass + '\" ' : ' ')+closeevent+'=\"return '+fnRef+'cClick();\">'+(o3_closefontclass ? '' : wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass ? '' : wrapStr(1,o3_closesize,'close'))+'</a></td>';\n\ttxt = '<table width=\"'+o3_width+ '\" border=\"0\" cellpadding=\"'+o3_border+'\" cellspacing=\"0\" '+(o3_bgclass ? 'class=\"'+o3_bgclass+'\"' : o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\"><tr><td'+(o3_captionfontclass ? ' class=\"'+o3_captionfontclass+'\">' : '>')+(o3_captionfontclass ? '' : '<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass ? '' : wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closing+'</tr></table><table width=\"100%\" border=\"0\" '+((olNs4||!cpIsMultiple) ? 'cellpadding=\"'+o3_cellpad+'\" ' : '')+'cellspacing=\"0\" '+(o3_fgclass ? 'class=\"'+o3_fgclass+'\"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign=\"TOP\"'+(o3_textfontclass ? ' class=\"'+o3_textfontclass+'\">' :((!olNs4&&cpIsMultiple) ? ' style=\"'+setCellPadStr(o3_cellpad)+'\">' : '>'))+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize)) + '</td></tr></table></td></tr></table>';\n\n\tset_background(\"\");\n\treturn txt;\n}\n\n// Sets the background picture,padding and lots more. :)\nfunction ol_content_background(text,picture,hasfullhtml) {\n\tif (hasfullhtml) {\n\t\ttxt=text;\n\t} else {\n\t\ttxt='<table width=\"'+o3_width+'\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"'+o3_height+'\"><tr><td colspan=\"3\" height=\"'+o3_padyt+'\"></td></tr><tr><td width=\"'+o3_padxl+'\"></td><td valign=\"TOP\" width=\"'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass ? '\" class=\"'+o3_textfontclass : '')+'\">'+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td><td width=\"'+o3_padxr+'\"></td></tr><tr><td colspan=\"3\" height=\"'+o3_padyb+'\"></td></tr></table>';\n\t}\n\n\tset_background(picture);\n\treturn txt;\n}\n\n// Loads a picture into the div.\nfunction set_background(pic) {\n\tif (pic == \"\") {\n\t\tif (olNs4) {\n\t\t\tover.background.src = null;\n\t\t} else if (over.style) {\n\t\t\tover.style.backgroundImage = \"none\";\n\t\t}\n\t} else {\n\t\tif (olNs4) {\n\t\t\tover.background.src = pic;\n\t\t} else if (over.style) {\n\t\t\tover.style.width=o3_width + 'px';\n\t\t\tover.style.backgroundImage = \"url(\"+pic+\")\";\n\t\t}\n\t}\n}\n\n////////\n// HANDLING FUNCTIONS\n////////\nvar olShowId=-1;\n\n// Displays the popup\nfunction disp(statustext) {\n\trunHook(\"disp\", FBEFORE);\n\n\tif (o3_allowmove == 0) {\n\t\trunHook(\"placeLayer\", FREPLACE);\n\t\t(olNs6&&olShowId<0) ? olShowId=setTimeout(\"runHook('showObject', FREPLACE, over)\", 1) : runHook(\"showObject\", FREPLACE, over);\n\t\to3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;\n\t}\n\n\trunHook(\"disp\", FAFTER);\n\n\tif (statustext != \"\") self.status = statustext;\n}\n\n// Creates the actual popup structure\nfunction createPopup(lyrContent){\n\trunHook(\"createPopup\", FBEFORE);\n\n\tif (o3_wrap) {\n\t\tvar wd,ww,theObj = (olNs4 ? over : over.style);\n\t\ttheObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);\n\t\tlayerWrite(lyrContent);\n\t\twd = (olNs4 ? over.clip.width : over.offsetWidth);\n\t\tif (wd > (ww=windowWidth())) {\n\t\t\tlyrContent=lyrContent.replace(/\\&nbsp;/g, ' ');\n\t\t\to3_width=ww;\n\t\t\to3_wrap=0;\n\t\t}\n\t}\n\n\tlayerWrite(lyrContent);\n\n\t// Have to set o3_width for placeLayer() routine if o3_wrap is turned on\n\tif (o3_wrap) o3_width=(olNs4 ? over.clip.width : over.offsetWidth);\n\n\trunHook(\"createPopup\", FAFTER, lyrContent);\n\n\treturn true;\n}\n\n// Decides where we want the popup.\nfunction placeLayer() {\n\tvar placeX, placeY, widthFix = 0;\n\n\t// HORIZONTAL PLACEMENT, re-arranged to work in Safari\n\tif (o3_frame.innerWidth) widthFix=18;\n\tiwidth = windowWidth();\n\n\t// Horizontal scroll offset\n\twinoffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollLeft') : o3_frame.pageXOffset;\n\n\tplaceX = runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);\n\n\t// VERTICAL PLACEMENT, re-arranged to work in Safari\n\tif (o3_frame.innerHeight) {\n\t\tiheight=o3_frame.innerHeight;\n\t} else if (eval('o3_frame.'+docRoot)&&eval(\"typeof o3_frame.\"+docRoot+\".clientHeight=='number'\")&&eval('o3_frame.'+docRoot+'.clientHeight')) {\n\t\tiheight=eval('o3_frame.'+docRoot+'.clientHeight');\n\t}\n\n\t// Vertical scroll offset\n\tscrolloffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollTop') : o3_frame.pageYOffset;\n\tplaceY = runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);\n\n\t// Actually move the object.\n\trepositionTo(over, placeX, placeY);\n}\n\n// Moves the layer\nfunction olMouseMove(e) {\n\tvar e = (e) ? e : event;\n\n\tif (e.pageX) {\n\t\to3_x = e.pageX;\n\t\to3_y = e.pageY;\n\t} else if (e.clientX) {\n\t\to3_x = eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');\n\t\to3_y = eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');\n\t}\n\n\tif (o3_allowmove == 1) runHook(\"placeLayer\", FREPLACE);\n\n\t// MouseOut handler\n\tif (hoveringSwitch && !olNs4 && runHook(\"cursorOff\", FREPLACE)) {\n\t\t(olHideDelay ? hideDelay(olHideDelay) : cClick());\n\t\thoveringSwitch = !hoveringSwitch;\n\t}\n}\n\n// Fake function for 3.0 users.\nfunction no_overlib() { return ver3fix; }\n\n// Capture the mouse and chain other scripts.\nfunction olMouseCapture() {\n\tcapExtent = document;\n\tvar fN, str = '', l, k, f, wMv, sS, mseHandler = olMouseMove;\n\tvar re = /function[ ]*(\\w*)\\(/;\n\n\twMv = (!olIe4 && window.onmousemove);\n\tif (document.onmousemove || wMv) {\n\t\tif (wMv) capExtent = window;\n\t\tf = capExtent.onmousemove.toString();\n\t\tfN = f.match(re);\n\t\tif (fN == null) {\n\t\t\tstr = f+'(e); ';\n\t\t} else if (fN[1] == 'anonymous' || fN[1] == 'olMouseMove' || (wMv && fN[1] == 'onmousemove')) {\n\t\t\tif (!olOp && wMv) {\n\t\t\t\tl = f.indexOf('{')+1;\n\t\t\t\tk = f.lastIndexOf('}');\n\t\t\t\tsS = f.substring(l,k);\n\t\t\t\tif ((l = sS.indexOf('(')) != -1) {\n\t\t\t\t\tsS = sS.substring(0,l).replace(/^\\s+/,'').replace(/\\s+$/,'');\n\t\t\t\t\tif (eval(\"typeof \" + sS + \" == 'undefined'\")) window.onmousemove = null;\n\t\t\t\t\telse str = sS + '(e);';\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!str) {\n\t\t\t\tolCheckMouseCapture = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tif (fN[1]) str = fN[1]+'(e); ';\n\t\t\telse {\n\t\t\t\tl = f.indexOf('{')+1;\n\t\t\t\tk = f.lastIndexOf('}');\n\t\t\t\tstr = f.substring(l,k) + '\\n';\n\t\t\t}\n\t\t}\n\t\tstr += 'olMouseMove(e); ';\n\t\tmseHandler = new Function('e', str);\n\t}\n\n\tcapExtent.onmousemove = mseHandler;\n\tif (olNs4) capExtent.captureEvents(Event.MOUSEMOVE);\n}\n\n////////\n// PARSING FUNCTIONS\n////////\n\n// Does the actual command parsing.\nfunction parseTokens(pf, ar) {\n\t// What the next argument is expected to be.\n\tvar v, i, mode=-1, par = (pf != 'ol_');\n\tvar fnMark = (par && !ar.length ? 1 : 0);\n\n\tfor (i = 0; i < ar.length; i++) {\n\t\tif (mode < 0) {\n\t\t\t// Arg is maintext,unless its a number between pmStart and pmUpper\n\t\t\t// then its a command.\n\t\t\tif (typeof ar[i] == 'number' && ar[i] > pmStart && ar[i] < pmUpper) {\n\t\t\t\tfnMark = (par ? 1 : 0);\n\t\t\t\ti--;   // backup one so that the next block can parse it\n\t\t\t} else {\n\t\t\t\tswitch(pf) {\n\t\t\t\t\tcase 'ol_':\n\t\t\t\t\t\tol_text = ar[i].toString();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\to3_text=ar[i].toString();\n\t\t\t\t}\n\t\t\t}\n\t\t\tmode = 0;\n\t\t} else {\n\t\t\t// Note: NS4 doesn't like switch cases with vars.\n\t\t\tif (ar[i] >= pmCount || ar[i]==DONOTHING) { continue; }\n\t\t\tif (ar[i]==INARRAY) { fnMark = 0; eval(pf+'text=ol_texts['+ar[++i]+'].toString()'); continue; }\n\t\t\tif (ar[i]==CAPARRAY) { eval(pf+'cap=ol_caps['+ar[++i]+'].toString()'); continue; }\n\t\t\tif (ar[i]==STICKY) { if (pf!='ol_') eval(pf+'sticky=1'); continue; }\n\t\t\tif (ar[i]==BACKGROUND) { eval(pf+'background=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==NOCLOSE) { if (pf!='ol_') opt_NOCLOSE(); continue; }\n\t\t\tif (ar[i]==CAPTION) { eval(pf+\"cap='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==CENTER || ar[i]==LEFT || ar[i]==RIGHT) { eval(pf+'hpos='+ar[i]); if(pf!='ol_') olHautoFlag=1; continue; }\n\t\t\tif (ar[i]==OFFSETX) { eval(pf+'offsetx='+ar[++i]); continue; }\n\t\t\tif (ar[i]==OFFSETY) { eval(pf+'offsety='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FGCOLOR) { eval(pf+'fgcolor=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==BGCOLOR) { eval(pf+'bgcolor=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==TEXTCOLOR) { eval(pf+'textcolor=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CAPCOLOR) { eval(pf+'capcolor=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CLOSECOLOR) { eval(pf+'closecolor=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==WIDTH) { eval(pf+'width='+ar[++i]); continue; }\n\t\t\tif (ar[i]==BORDER) { eval(pf+'border='+ar[++i]); continue; }\n\t\t\tif (ar[i]==CELLPAD) { i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad')); continue; }\n\t\t\tif (ar[i]==STATUS) { eval(pf+\"status='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==AUTOSTATUS) { eval(pf +'autostatus=('+pf+'autostatus == 1) ? 0 : 1'); continue; }\n\t\t\tif (ar[i]==AUTOSTATUSCAP) { eval(pf +'autostatus=('+pf+'autostatus == 2) ? 0 : 2'); continue; }\n\t\t\tif (ar[i]==HEIGHT) { eval(pf+'height='+pf+'aboveheight='+ar[++i]); continue; } // Same param again.\n\t\t\tif (ar[i]==CLOSETEXT) { eval(pf+\"close='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==SNAPX) { eval(pf+'snapx='+ar[++i]); continue; }\n\t\t\tif (ar[i]==SNAPY) { eval(pf+'snapy='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FIXX) { eval(pf+'fixx='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FIXY) { eval(pf+'fixy='+ar[++i]); continue; }\n\t\t\tif (ar[i]==RELX) { eval(pf+'relx='+ar[++i]); continue; }\n\t\t\tif (ar[i]==RELY) { eval(pf+'rely='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FGBACKGROUND) { eval(pf+'fgbackground=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==BGBACKGROUND) { eval(pf+'bgbackground=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==PADX) { eval(pf+'padxl='+ar[++i]); eval(pf+'padxr='+ar[++i]); continue; }\n\t\t\tif (ar[i]==PADY) { eval(pf+'padyt='+ar[++i]); eval(pf+'padyb='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FULLHTML) { if (pf!='ol_') eval(pf+'fullhtml=1'); continue; }\n\t\t\tif (ar[i]==BELOW || ar[i]==ABOVE) { eval(pf+'vpos='+ar[i]); if (pf!='ol_') olVautoFlag=1; continue; }\n\t\t\tif (ar[i]==CAPICON) { eval(pf+'capicon=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==TEXTFONT) { eval(pf+\"textfont='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==CAPTIONFONT) { eval(pf+\"captionfont='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==CLOSEFONT) { eval(pf+\"closefont='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==TEXTSIZE) { eval(pf+'textsize=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CAPTIONSIZE) { eval(pf+'captionsize=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CLOSESIZE) { eval(pf+'closesize=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==TIMEOUT) { eval(pf+'timeout='+ar[++i]); continue; }\n\t\t\tif (ar[i]==FUNCTION) { if (pf=='ol_') { if (typeof ar[i+1]!='number') { v=ar[++i]; ol_function=(typeof v=='function' ? v : null); }} else {fnMark = 0; v = null; if (typeof ar[i+1]!='number') v = ar[++i];  opt_FUNCTION(v); } continue; }\n\t\t\tif (ar[i]==DELAY) { eval(pf+'delay='+ar[++i]); continue; }\n\t\t\tif (ar[i]==HAUTO) { eval(pf+'hauto=('+pf+'hauto == 0) ? 1 : 0'); continue; }\n\t\t\tif (ar[i]==VAUTO) { eval(pf+'vauto=('+pf+'vauto == 0) ? 1 : 0'); continue; }\n\t\t\tif (ar[i]==CLOSECLICK) { eval(pf +'closeclick=('+pf+'closeclick == 0) ? 1 : 0'); continue; }\n\t\t\tif (ar[i]==WRAP) { eval(pf +'wrap=('+pf+'wrap == 0) ? 1 : 0'); continue; }\n\t\t\tif (ar[i]==FOLLOWMOUSE) { eval(pf +'followmouse=('+pf+'followmouse == 1) ? 0 : 1'); continue; }\n\t\t\tif (ar[i]==MOUSEOFF) { eval(pf +'mouseoff=('+pf+'mouseoff==0) ? 1 : 0'); v=ar[i+1]; if (pf != 'ol_' && eval(pf+'mouseoff') && typeof v == 'number' && (v < pmStart || v > pmUpper)) olHideDelay=ar[++i]; continue; }\n\t\t\tif (ar[i]==CLOSETITLE) { eval(pf+\"closetitle='\"+escSglQuote(ar[++i])+\"'\"); continue; }\n\t\t\tif (ar[i]==CSSOFF||ar[i]==CSSCLASS) { eval(pf+'css='+ar[i]); continue; }\n\t\t\tif (ar[i]==COMPATMODE) { eval(pf+'compatmode=('+pf+'compatmode==0) ? 1 : 0'); continue; }\n\t\t\tif (ar[i]==FGCLASS) { eval(pf+'fgclass=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==BGCLASS) { eval(pf+'bgclass=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==TEXTFONTCLASS) { eval(pf+'textfontclass=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CAPTIONFONTCLASS) { eval(pf+'captionfontclass=\"'+ar[++i]+'\"'); continue; }\n\t\t\tif (ar[i]==CLOSEFONTCLASS) { eval(pf+'closefontclass=\"'+ar[++i]+'\"'); continue; }\n\t\t\ti = parseCmdLine(pf, i, ar);\n\t\t}\n\t}\n\n\tif (fnMark && o3_function) o3_text = o3_function();\n\n\tif ((pf == 'o3_') && o3_wrap) {\n\t\to3_width = 0;\n\n\t\tvar tReg=/<.*\\n*>/ig;\n\t\tif (!tReg.test(o3_text)) o3_text = o3_text.replace(/[ ]+/g, '&nbsp;');\n\t\tif (!tReg.test(o3_cap))o3_cap = o3_cap.replace(/[ ]+/g, '&nbsp;');\n\t}\n\tif ((pf == 'o3_') && o3_sticky) {\n\t\tif (!o3_close && (o3_frame != ol_frame)) o3_close = ol_close;\n\t\tif (o3_mouseoff && (o3_frame == ol_frame)) opt_NOCLOSE(' ');\n\t}\n}\n\n\n////////\n// LAYER FUNCTIONS\n////////\n\n// Writes to a layer\nfunction layerWrite(txt) {\n\ttxt += \"\\n\";\n\tif (olNs4) {\n\t\tvar lyr = o3_frame.document.layers['overDiv'].document\n\t\tlyr.write(txt)\n\t\tlyr.close()\n\t} else if (typeof over.innerHTML != 'undefined') {\n\t\tif (olIe5 && isMac) over.innerHTML = '';\n\t\tover.innerHTML = txt;\n\t} else {\n\t\trange = o3_frame.document.createRange();\n\t\trange.setStartAfter(over);\n\t\tdomfrag = range.createContextualFragment(txt);\n\n\t\twhile (over.hasChildNodes()) {\n\t\t\tover.removeChild(over.lastChild);\n\t\t}\n\n\t\tover.appendChild(domfrag);\n\t}\n}\n\n// Make an object visible\nfunction showObject(obj) {\n\trunHook(\"showObject\", FBEFORE);\n\n\tvar theObj=(olNs4 ? obj : obj.style);\n\ttheObj.visibility = 'visible';\n\n\trunHook(\"showObject\", FAFTER);\n}\n\n// Hides an object\nfunction hideObject(obj) {\n\trunHook(\"hideObject\", FBEFORE);\n\n\tvar theObj=(olNs4 ? obj : obj.style);\n\tif (olNs6 && olShowId>0) { clearTimeout(olShowId); olShowId=0; }\n\ttheObj.visibility = 'hidden';\n\ttheObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);\n\n\tif (o3_timerid > 0) clearTimeout(o3_timerid);\n\tif (o3_delayid > 0) clearTimeout(o3_delayid);\n\n\to3_timerid = 0;\n\to3_delayid = 0;\n\tself.status = \"\";\n\n\tif (obj.onmouseout||obj.onmouseover) {\n\t\tif (olNs4) obj.releaseEvents(Event.MOUSEOUT || Event.MOUSEOVER);\n\t\tobj.onmouseout = obj.onmouseover = null;\n\t}\n\n\trunHook(\"hideObject\", FAFTER);\n}\n\n// Move a layer\nfunction repositionTo(obj, xL, yL) {\n\tvar theObj=(olNs4 ? obj : obj.style);\n\ttheObj.left = xL + (!olNs4 ? 'px' : 0);\n\ttheObj.top = yL + (!olNs4 ? 'px' : 0);\n}\n\n// Check position of cursor relative to overDiv DIVision; mouseOut function\nfunction cursorOff() {\n\tvar left = parseInt(over.style.left);\n\tvar top = parseInt(over.style.top);\n\tvar right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));\n\tvar bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);\n\n\tif (o3_x < left || o3_x > right || o3_y < top || o3_y > bottom) return true;\n\n\treturn false;\n}\n\n\n////////\n// COMMAND FUNCTIONS\n////////\n\n// Calls callme or the default function.\nfunction opt_FUNCTION(callme) {\n\to3_text = (callme ? (typeof callme=='string' ? (/.+\\(.*\\)/.test(callme) ? eval(callme) : callme) : callme()) : (o3_function ? o3_function() : 'No Function'));\n\n\treturn 0;\n}\n\n// Handle hovering\nfunction opt_NOCLOSE(unused) {\n\tif (!unused) o3_close = \"\";\n\n\tif (olNs4) {\n\t\tover.captureEvents(Event.MOUSEOUT || Event.MOUSEOVER);\n\t\tover.onmouseover = function () { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } }\n\t\tover.onmouseout = function (e) { if (olHideDelay) hideDelay(olHideDelay); else cClick(e); }\n\t} else {\n\t\tover.onmouseover = function () {hoveringSwitch = true; if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid =0; } }\n\t}\n\n\treturn 0;\n}\n\n// Function to scan command line arguments for multiples\nfunction opt_MULTIPLEARGS(i, args, parameter) {\n  var k=i, re, pV, str='';\n\n  for(k=i; k<args.length; k++) {\n\t\tif(typeof args[k] == 'number' && args[k]>pmStart) break;\n\t\tstr += args[k] + ',';\n\t}\n\tif (str) str = str.substring(0,--str.length);\n\n\tk--;  // reduce by one so the for loop this is in works correctly\n\tpV=(olNs4 && /cellpad/i.test(parameter)) ? str.split(',')[0] : str;\n\teval(parameter + '=\"' + pV + '\"');\n\n\treturn k;\n}\n\n// Remove &nbsp; in texts when done.\nfunction nbspCleanup() {\n\tif (o3_wrap) {\n\t\to3_text = o3_text.replace(/\\&nbsp;/g, ' ');\n\t\to3_cap = o3_cap.replace(/\\&nbsp;/g, ' ');\n\t}\n}\n\n// Escape embedded single quotes in text strings\nfunction escSglQuote(str) {\n  return str.toString().replace(/'/g,\"\\\\'\");\n}\n\n// Onload handler for window onload event\nfunction OLonLoad_handler(e) {\n\tvar re = /\\w+\\(.*\\)[;\\s]+/g, olre = /overlib\\(|nd\\(|cClick\\(/, fn, l, i;\n\n\tif(!olLoaded) olLoaded=1;\n\n  // Remove it for Gecko based browsers\n\tif(window.removeEventListener && e.eventPhase == 3) window.removeEventListener(\"load\",OLonLoad_handler,false);\n\telse if(window.detachEvent) { // and for IE and Opera 4.x but execute calls to overlib, nd, or cClick()\n\t\twindow.detachEvent(\"onload\",OLonLoad_handler);\n\t\tvar fN = document.body.getAttribute('onload');\n\t\tif (fN) {\n\t\t\tfN=fN.toString().match(re);\n\t\t\tif (fN && fN.length) {\n\t\t\t\tfor (i=0; i<fN.length; i++) {\n\t\t\t\t\tif (/anonymous/.test(fN[i])) continue;\n\t\t\t\t\twhile((l=fN[i].search(/\\)[;\\s]+/)) != -1) {\n\t\t\t\t\t\tfn=fN[i].substring(0,l+1);\n\t\t\t\t\t\tfN[i] = fN[i].substring(l+2);\n\t\t\t\t\t\tif (olre.test(fn)) eval(fn);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Wraps strings in Layer Generation Functions with the correct tags\n//    endWrap true(if end tag) or false if start tag\n//    fontSizeStr - font size string such as '1' or '10px'\n//    whichString is being wrapped -- 'text', 'caption', or 'close'\nfunction wrapStr(endWrap,fontSizeStr,whichString) {\n\tvar fontStr, fontColor, isClose=((whichString=='close') ? 1 : 0), hasDims=/[%\\-a-z]+$/.test(fontSizeStr);\n\tfontSizeStr = (olNs4) ? (!hasDims ? fontSizeStr : '1') : fontSizeStr;\n\tif (endWrap) return (hasDims&&!olNs4) ? (isClose ? '</span>' : '</div>') : '</font>';\n\telse {\n\t\tfontStr='o3_'+whichString+'font';\n\t\tfontColor='o3_'+((whichString=='caption')? 'cap' : whichString)+'color';\n\t\treturn (hasDims&&!olNs4) ? (isClose ? '<span style=\"font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';\">' : '<div style=\"font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';\">') : '<font face=\"'+eval(fontStr)+'\" color=\"'+eval(fontColor)+'\" size=\"'+(parseInt(fontSizeStr)>7 ? '7' : fontSizeStr)+'\">';\n\t}\n}\n\n// Quotes Multi word font names; needed for CSS Standards adherence in font-family\nfunction quoteMultiNameFonts(theFont) {\n\tvar v, pM=theFont.split(',');\n\tfor (var i=0; i<pM.length; i++) {\n\t\tv=pM[i];\n\t\tv=v.replace(/^\\s+/,'').replace(/\\s+$/,'');\n\t\tif(/\\s/.test(v) && !/['\"]/.test(v)) {\n\t\t\tv=\"\\'\"+v+\"\\'\";\n\t\t\tpM[i]=v;\n\t\t}\n\t}\n\treturn pM.join();\n}\n\n// dummy function which will be overridden\nfunction isExclusive(args) {\n\treturn false;\n}\n\n// Sets cellpadding style string value\nfunction setCellPadStr(parameter) {\n\tvar Str='', j=0, ary = new Array(), top, bottom, left, right;\n\n\tStr+='padding: ';\n\tary=parameter.replace(/\\s+/g,'').split(',');\n\n\tswitch(ary.length) {\n\t\tcase 2:\n\t\t\ttop=bottom=ary[j];\n\t\t\tleft=right=ary[++j];\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\ttop=ary[j];\n\t\t\tleft=right=ary[++j];\n\t\t\tbottom=ary[++j];\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\ttop=ary[j];\n\t\t\tright=ary[++j];\n\t\t\tbottom=ary[++j];\n\t\t\tleft=ary[++j];\n\t\t\tbreak;\n\t}\n\n\tStr+= ((ary.length==1) ? ary[0] + 'px;' : top + 'px ' + right + 'px ' + bottom + 'px ' + left + 'px;');\n\n\treturn Str;\n}\n\n// function will delay close by time milliseconds\nfunction hideDelay(time) {\n\tif (time&&!o3_delay) {\n\t\tif (o3_timerid > 0) clearTimeout(o3_timerid);\n\n\t\to3_timerid=setTimeout(\"cClick()\",(o3_timeout=time));\n\t}\n}\n\n// Was originally in the placeLayer() routine; separated out for future ease\nfunction horizontalPlacement(browserWidth, horizontalScrollAmount, widthFix) {\n\tvar placeX, iwidth=browserWidth, winoffset=horizontalScrollAmount;\n\tvar parsedWidth = parseInt(o3_width);\n\n\tif (o3_fixx > -1 || o3_relx != null) {\n\t\t// Fixed position\n\t\tplaceX=(o3_relx != null ? ( o3_relx < 0 ? winoffset +o3_relx+ iwidth - parsedWidth - widthFix : winoffset+o3_relx) : o3_fixx);\n\t} else {\n\t\t// If HAUTO, decide what to use.\n\t\tif (o3_hauto == 1) {\n\t\t\tif ((o3_x - winoffset) > (iwidth / 2)) {\n\t\t\t\to3_hpos = LEFT;\n\t\t\t} else {\n\t\t\t\to3_hpos = RIGHT;\n\t\t\t}\n\t\t}\n\n\t\t// From mouse\n\t\tif (o3_hpos == CENTER) { // Center\n\t\t\tplaceX = o3_x+o3_offsetx-(parsedWidth/2);\n\n\t\t\tif (placeX < winoffset) placeX = winoffset;\n\t\t}\n\n\t\tif (o3_hpos == RIGHT) { // Right\n\t\t\tplaceX = o3_x+o3_offsetx;\n\n\t\t\tif ((placeX+parsedWidth) > (winoffset+iwidth - widthFix)) {\n\t\t\t\tplaceX = iwidth+winoffset - parsedWidth - widthFix;\n\t\t\t\tif (placeX < 0) placeX = 0;\n\t\t\t}\n\t\t}\n\t\tif (o3_hpos == LEFT) { // Left\n\t\t\tplaceX = o3_x-o3_offsetx-parsedWidth;\n\t\t\tif (placeX < winoffset) placeX = winoffset;\n\t\t}\n\n\t\t// Snapping!\n\t\tif (o3_snapx > 1) {\n\t\t\tvar snapping = placeX % o3_snapx;\n\n\t\t\tif (o3_hpos == LEFT) {\n\t\t\t\tplaceX = placeX - (o3_snapx+snapping);\n\t\t\t} else {\n\t\t\t\t// CENTER and RIGHT\n\t\t\t\tplaceX = placeX+(o3_snapx - snapping);\n\t\t\t}\n\n\t\t\tif (placeX < winoffset) placeX = winoffset;\n\t\t}\n\t}\n\n\treturn placeX;\n}\n\n// was originally in the placeLayer() routine; separated out for future ease\nfunction verticalPlacement(browserHeight,verticalScrollAmount) {\n\tvar placeY, iheight=browserHeight, scrolloffset=verticalScrollAmount;\n\tvar parsedHeight=(o3_aboveheight ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight));\n\n\tif (o3_fixy > -1 || o3_rely != null) {\n\t\t// Fixed position\n\t\tplaceY=(o3_rely != null ? (o3_rely < 0 ? scrolloffset+o3_rely+iheight - parsedHeight : scrolloffset+o3_rely) : o3_fixy);\n\t} else {\n\t\t// If VAUTO, decide what to use.\n\t\tif (o3_vauto == 1) {\n\t\t\tif ((o3_y - scrolloffset) > (iheight / 2) && o3_vpos == BELOW && (o3_y + parsedHeight + o3_offsety - (scrolloffset + iheight) > 0)) {\n\t\t\t\to3_vpos = ABOVE;\n\t\t\t} else if (o3_vpos == ABOVE && (o3_y - (parsedHeight + o3_offsety) - scrolloffset < 0)) {\n\t\t\t\to3_vpos = BELOW;\n\t\t\t}\n\t\t}\n\n\t\t// From mouse\n\t\tif (o3_vpos == ABOVE) {\n\t\t\tif (o3_aboveheight == 0) o3_aboveheight = parsedHeight;\n\n\t\t\tplaceY = o3_y - (o3_aboveheight+o3_offsety);\n\t\t\tif (placeY < scrolloffset) placeY = scrolloffset;\n\t\t} else {\n\t\t\t// BELOW\n\t\t\tplaceY = o3_y+o3_offsety;\n\t\t}\n\n\t\t// Snapping!\n\t\tif (o3_snapy > 1) {\n\t\t\tvar snapping = placeY % o3_snapy;\n\n\t\t\tif (o3_aboveheight > 0 && o3_vpos == ABOVE) {\n\t\t\t\tplaceY = placeY - (o3_snapy+snapping);\n\t\t\t} else {\n\t\t\t\tplaceY = placeY+(o3_snapy - snapping);\n\t\t\t}\n\n\t\t\tif (placeY < scrolloffset) placeY = scrolloffset;\n\t\t}\n\t}\n\n\treturn placeY;\n}\n\n// checks positioning flags\nfunction checkPositionFlags() {\n\tif (olHautoFlag) olHautoFlag = o3_hauto=0;\n\tif (olVautoFlag) olVautoFlag = o3_vauto=0;\n\treturn true;\n}\n\n// get Browser window width\nfunction windowWidth() {\n\tvar w;\n\tif (o3_frame.innerWidth) w=o3_frame.innerWidth;\n\telse if (eval('o3_frame.'+docRoot)&&eval(\"typeof o3_frame.\"+docRoot+\".clientWidth=='number'\")&&eval('o3_frame.'+docRoot+'.clientWidth'))\n\t\tw=eval('o3_frame.'+docRoot+'.clientWidth');\n\treturn w;\n}\n\n// create the div container for popup content if it doesn't exist\nfunction createDivContainer(id,frm,zValue) {\n\tid = (id || 'overDiv'), frm = (frm || o3_frame), zValue = (zValue || 1000);\n\tvar objRef, divContainer = layerReference(id);\n\n\tif (divContainer == null) {\n\t\tif (olNs4) {\n\t\t\tdivContainer = frm.document.layers[id] = new Layer(window.innerWidth, frm);\n\t\t\tobjRef = divContainer;\n\t\t} else {\n\t\t\tvar body = (olIe4 ? frm.document.all.tags('BODY')[0] : frm.document.getElementsByTagName(\"BODY\")[0]);\n\t\t\tif (olIe4&&!document.getElementById) {\n\t\t\t\tbody.insertAdjacentHTML(\"beforeEnd\",'<div id=\"'+id+'\"></div>');\n\t\t\t\tdivContainer=layerReference(id);\n\t\t\t} else {\n\t\t\t\tdivContainer = frm.document.createElement(\"DIV\");\n\t\t\t\tdivContainer.id = id;\n\t\t\t\tbody.appendChild(divContainer);\n\t\t\t}\n\t\t\tobjRef = divContainer.style;\n\t\t}\n\n\t\tobjRef.position = 'absolute';\n\t\tobjRef.visibility = 'hidden';\n\t\tobjRef.zIndex = zValue;\n\t\tif (olIe4&&!olOp) objRef.left = objRef.top = '0px';\n\t\telse objRef.left = objRef.top =  -10000 + (!olNs4 ? 'px' : 0);\n\t}\n\n\treturn divContainer;\n}\n\n// get reference to a layer with ID=id\nfunction layerReference(id) {\n\treturn (olNs4 ? o3_frame.document.layers[id] : (document.all ? o3_frame.document.all[id] : o3_frame.document.getElementById(id)));\n}\n////////\n//  UTILITY FUNCTIONS\n////////\n\n// Checks if something is a function.\nfunction isFunction(fnRef) {\n\tvar rtn = true;\n\n\tif (typeof fnRef == 'object') {\n\t\tfor (var i = 0; i < fnRef.length; i++) {\n\t\t\tif (typeof fnRef[i]=='function') continue;\n\t\t\trtn = false;\n\t\t\tbreak;\n\t\t}\n\t} else if (typeof fnRef != 'function') {\n\t\trtn = false;\n\t}\n\n\treturn rtn;\n}\n\n// Converts an array into an argument string for use in eval.\nfunction argToString(array, strtInd, argName) {\n\tvar jS = strtInd, aS = '', ar = array;\n\targName=(argName ? argName : 'ar');\n\n\tif (ar.length > jS) {\n\t\tfor (var k = jS; k < ar.length; k++) aS += argName+'['+k+'], ';\n\t\taS = aS.substring(0, aS.length-2);\n\t}\n\n\treturn aS;\n}\n\n// Places a hook in the correct position in a hook point.\nfunction reOrder(hookPt, fnRef, order) {\n\tvar newPt = new Array(), match, i, j;\n\n\tif (!order || typeof order == 'undefined' || typeof order == 'number') return hookPt;\n\n\tif (typeof order=='function') {\n\t\tif (typeof fnRef=='object') {\n\t\t\tnewPt = newPt.concat(fnRef);\n\t\t} else {\n\t\t\tnewPt[newPt.length++]=fnRef;\n\t\t}\n\n\t\tfor (i = 0; i < hookPt.length; i++) {\n\t\t\tmatch = false;\n\t\t\tif (typeof fnRef == 'function' && hookPt[i] == fnRef) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tfor(j = 0; j < fnRef.length; j++) if (hookPt[i] == fnRef[j]) {\n\t\t\t\t\tmatch = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!match) newPt[newPt.length++] = hookPt[i];\n\t\t}\n\n\t\tnewPt[newPt.length++] = order;\n\n\t} else if (typeof order == 'object') {\n\t\tif (typeof fnRef == 'object') {\n\t\t\tnewPt = newPt.concat(fnRef);\n\t\t} else {\n\t\t\tnewPt[newPt.length++] = fnRef;\n\t\t}\n\n\t\tfor (j = 0; j < hookPt.length; j++) {\n\t\t\tmatch = false;\n\t\t\tif (typeof fnRef == 'function' && hookPt[j] == fnRef) {\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\tfor (i = 0; i < fnRef.length; i++) if (hookPt[j] == fnRef[i]) {\n\t\t\t\t\tmatch = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!match) newPt[newPt.length++]=hookPt[j];\n\t\t}\n\n\t\tfor (i = 0; i < newPt.length; i++) hookPt[i] = newPt[i];\n\t\tnewPt.length = 0;\n\n\t\tfor (j = 0; j < hookPt.length; j++) {\n\t\t\tmatch = false;\n\t\t\tfor (i = 0; i < order.length; i++) {\n\t\t\t\tif (hookPt[j] == order[i]) {\n\t\t\t\t\tmatch = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!match) newPt[newPt.length++] = hookPt[j];\n\t\t}\n\t\tnewPt = newPt.concat(order);\n\t}\n\n\thookPt = newPt;\n\n\treturn hookPt;\n}\n\n////////\n//  PLUGIN ACTIVATION FUNCTIONS\n////////\n\n// Runs plugin functions to set runtime variables.\nfunction setRunTimeVariables(){\n\tif (typeof runTime != 'undefined' && runTime.length) {\n\t\tfor (var k = 0; k < runTime.length; k++) {\n\t\t\trunTime[k]();\n\t\t}\n\t}\n}\n\n// Runs plugin functions to parse commands.\nfunction parseCmdLine(pf, i, args) {\n\tif (typeof cmdLine != 'undefined' && cmdLine.length) {\n\t\tfor (var k = 0; k < cmdLine.length; k++) {\n\t\t\tvar j = cmdLine[k](pf, i, args);\n\t\t\tif (j >- 1) {\n\t\t\t\ti = j;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn i;\n}\n\n// Runs plugin functions to do things after parse.\nfunction postParseChecks(pf,args){\n\tif (typeof postParse != 'undefined' && postParse.length) {\n\t\tfor (var k = 0; k < postParse.length; k++) {\n\t\t\tif (postParse[k](pf,args)) continue;\n\t\t\treturn false;  // end now since have an error\n\t\t}\n\t}\n\treturn true;\n}\n\n\n////////\n//  PLUGIN REGISTRATION FUNCTIONS\n////////\n\n// Registers commands and creates constants.\nfunction registerCommands(cmdStr) {\n\tif (typeof cmdStr!='string') return;\n\n\tvar pM = cmdStr.split(',');\n\tpms = pms.concat(pM);\n\n\tfor (var i = 0; i< pM.length; i++) {\n\t\teval(pM[i].toUpperCase()+'='+pmCount++);\n\t}\n}\n\n// Registers no-parameter commands\nfunction registerNoParameterCommands(cmdStr) {\n\tif (!cmdStr && typeof cmdStr != 'string') return;\n\tpmt=(!pmt) ? cmdStr : pmt + ',' + cmdStr;\n}\n\n// Register a function to hook at a certain point.\nfunction registerHook(fnHookTo, fnRef, hookType, optPm) {\n\tvar hookPt, last = typeof optPm;\n\n\tif (fnHookTo == 'plgIn'||fnHookTo == 'postParse') return;\n\tif (typeof hookPts[fnHookTo] == 'undefined') hookPts[fnHookTo] = new FunctionReference();\n\n\thookPt = hookPts[fnHookTo];\n\n\tif (hookType != null) {\n\t\tif (hookType == FREPLACE) {\n\t\t\thookPt.ovload = fnRef;  // replace normal overlib routine\n\t\t\tif (fnHookTo.indexOf('ol_content_') > -1) hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef;\n\n\t\t} else if (hookType == FBEFORE || hookType == FAFTER) {\n\t\t\tvar hookPt=(hookType == 1 ? hookPt.before : hookPt.after);\n\n\t\t\tif (typeof fnRef == 'object') {\n\t\t\t\thookPt = hookPt.concat(fnRef);\n\t\t\t} else {\n\t\t\t\thookPt[hookPt.length++] = fnRef;\n\t\t\t}\n\n\t\t\tif (optPm) hookPt = reOrder(hookPt, fnRef, optPm);\n\n\t\t} else if (hookType == FALTERNATE) {\n\t\t\tif (last=='number') hookPt.alt[pms[optPm-1-pmStart]] = fnRef;\n\t\t} else if (hookType == FCHAIN) {\n\t\t\thookPt = hookPt.chain;\n\t\t\tif (typeof fnRef=='object') hookPt=hookPt.concat(fnRef); // add other functions\n\t\t\telse hookPt[hookPt.length++]=fnRef;\n\t\t}\n\n\t\treturn;\n\t}\n}\n\n// Register a function that will set runtime variables.\nfunction registerRunTimeFunction(fn) {\n\tif (isFunction(fn)) {\n\t\tif (typeof fn == 'object') {\n\t\t\trunTime = runTime.concat(fn);\n\t\t} else {\n\t\t\trunTime[runTime.length++] = fn;\n\t\t}\n\t}\n}\n\n// Register a function that will handle command parsing.\nfunction registerCmdLineFunction(fn){\n\tif (isFunction(fn)) {\n\t\tif (typeof fn == 'object') {\n\t\t\tcmdLine = cmdLine.concat(fn);\n\t\t} else {\n\t\t\tcmdLine[cmdLine.length++] = fn;\n\t\t}\n\t}\n}\n\n// Register a function that does things after command parsing.\nfunction registerPostParseFunction(fn){\n\tif (isFunction(fn)) {\n\t\tif (typeof fn == 'object') {\n\t\t\tpostParse = postParse.concat(fn);\n\t\t} else {\n\t\t\tpostParse[postParse.length++] = fn;\n\t\t}\n\t}\n}\n\n////////\n//  PLUGIN REGISTRATION FUNCTIONS\n////////\n\n// Runs any hooks registered.\nfunction runHook(fnHookTo, hookType) {\n\tvar l = hookPts[fnHookTo], k, rtnVal = null, optPm, arS, ar = runHook.arguments;\n\n\tif (hookType == FREPLACE) {\n\t\tarS = argToString(ar, 2);\n\n\t\tif (typeof l == 'undefined' || !(l = l.ovload)) rtnVal = eval(fnHookTo+'('+arS+')');\n\t\telse rtnVal = eval('l('+arS+')');\n\n\t} else if (hookType == FBEFORE || hookType == FAFTER) {\n\t\tif (typeof l != 'undefined') {\n\t\t\tl=(hookType == 1 ? l.before : l.after);\n\n\t\t\tif (l.length) {\n\t\t\t\tarS = argToString(ar, 2);\n\t\t\t\tfor (var k = 0; k < l.length; k++) eval('l[k]('+arS+')');\n\t\t\t}\n\t\t}\n\t} else if (hookType == FALTERNATE) {\n\t\toptPm = ar[2];\n\t\tarS = argToString(ar, 3);\n\n\t\tif (typeof l == 'undefined' || (l = l.alt[pms[optPm-1-pmStart]]) == 'undefined') {\n\t\t\trtnVal = eval(fnHookTo+'('+arS+')');\n\t\t} else {\n\t\t\trtnVal = eval('l('+arS+')');\n\t\t}\n\t} else if (hookType == FCHAIN) {\n\t\tarS=argToString(ar,2);\n\t\tl=l.chain;\n\n\t\tfor (k=l.length; k > 0; k--) if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0)) break;\n\t}\n\n\treturn rtnVal;\n}\n\n////////\n// OBJECT CONSTRUCTORS\n////////\n\n// Object for handling hooks.\nfunction FunctionReference() {\n\tthis.ovload = null;\n\tthis.before = new Array();\n\tthis.after = new Array();\n\tthis.alt = new Array();\n\tthis.chain = new Array();\n}\n\n// Object for simple access to the overLIB version used.\n// Examples: simpleversion:351 major:3 minor:5 revision:1\nfunction Info(version, prerelease) {\n\tthis.version = version;\n\tthis.prerelease = prerelease;\n\n\tthis.simpleversion = Math.round(this.version*100);\n\tthis.major = parseInt(this.simpleversion / 100);\n\tthis.minor = parseInt(this.simpleversion / 10) - this.major * 10;\n\tthis.revision = parseInt(this.simpleversion) - this.major * 100 - this.minor * 10;\n\tthis.meets = meets;\n}\n\n// checks for Core Version required\nfunction meets(reqdVersion) {\n\treturn (!reqdVersion) ? false : this.simpleversion >= Math.round(100*parseFloat(reqdVersion));\n}\n\n\n////////\n// STANDARD REGISTRATIONS\n////////\nregisterHook(\"ol_content_simple\", ol_content_simple, FALTERNATE, CSSOFF);\nregisterHook(\"ol_content_caption\", ol_content_caption, FALTERNATE, CSSOFF);\nregisterHook(\"ol_content_background\", ol_content_background, FALTERNATE, CSSOFF);\nregisterHook(\"ol_content_simple\", ol_content_simple, FALTERNATE, CSSCLASS);\nregisterHook(\"ol_content_caption\", ol_content_caption, FALTERNATE, CSSCLASS);\nregisterHook(\"ol_content_background\", ol_content_background, FALTERNATE, CSSCLASS);\nregisterPostParseFunction(checkPositionFlags);\nregisterHook(\"hideObject\", nbspCleanup, FAFTER);\nregisterHook(\"horizontalPlacement\", horizontalPlacement, FCHAIN);\nregisterHook(\"verticalPlacement\", verticalPlacement, FCHAIN);\nif (olNs4||(olIe5&&isMac)||olKq) olLoaded=1;\nregisterNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');\n///////\n// ESTABLISH MOUSECAPTURING\n///////\n\n// Capture events, alt. diffuses the overlib function.\nvar olCheckMouseCapture=true;\nif ((olNs4 || olNs6 || olIe4)) {\n\tolMouseCapture();\n} else {\n\toverlib = no_overlib;\n\tnd = no_overlib;\n\tver3fix = true;\n}\n"
  },
  {
    "path": "tools/server/admin/overlib/overlib_anchor.js",
    "content": "//\\/////\n//\\  overLIB Anchor Plugin\n//\\  This file requires overLIB 4.10 or later.\n//\\\n//\\  overLIB 4.10 - You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2004. All rights reserved.\n//\\  Contributors are listed on the homepage.\n//\\  See http://www.bosrup.com/web/overlib/ for details.\n//   $Revision: 1.1 $                      $Date: 2006/05/29 16:38:21 $\n//\\/////\n//\\mini\n\n\n////////\n// PRE-INIT\n// Ignore these lines, configuration is below.\n////////\nif (typeof olInfo == 'undefined' || typeof olInfo.meets == 'undefined' || !olInfo.meets(4.10)) alert('overLIB 4.10 or later is required for the Anchor Plugin.');\nelse {\nregisterCommands('anchor,anchorx,anchory,noanchorwarn,anchoralign');\n\n\n\n////////\n// DEFAULT CONFIGURATION\n// Settings you want everywhere are set here. All of this can also be\n// changed on your html page or through an overLIB call.\n////////\nif (typeof ol_anchor ==  'undefined') var ol_anchor = '';\nif (typeof ol_anchorx ==  'undefined') var ol_anchorx = 0;\nif (typeof ol_anchory ==  'undefined') var ol_anchory = 0;\nif (typeof ol_noanchorwarn ==  'undefined') var ol_noanchorwarn = 1;\nif (typeof ol_anchoralign ==  'undefined') var ol_anchoralign = 'UL';\n\n////////\n// END OF CONFIGURATION\n// Don't change anything below this line, all configuration is above.\n////////\n\n\n\n\n\n////////\n// INIT\n////////\n// Runtime variables init. Don't change for config!\nvar o3_anchor = \"\";\nvar o3_anchorx = 0;\nvar o3_anchory = 0;\nvar o3_noanchorwarn = 1;\nvar o3_anchoralign = 'UL';\nvar mrkObj, rmrkPosition;  //reference mark object, reference mark position, an array;\n\n\n////////\n// PLUGIN FUNCTIONS\n////////\nfunction setAnchorVariables() {\n\to3_anchor = ol_anchor;\n\to3_anchorx = ol_anchorx;\n\to3_anchory = ol_anchory;\n\to3_noanchorwarn = ol_noanchorwarn;\n\to3_anchoralign = ol_anchoralign;\n\tmrkObj = null;  // initialize this variable\n}\n\n// Parses Reference Mark commands\nfunction parseAnchorExtras(pf,i,ar) {\n\tvar v, k=i;\n\n\tif (k < ar.length) {\n\t\tif (ar[k] ==  ANCHOR) { eval(pf + \"anchor = '\" + escSglQuote(ar[++k]) + \"'\"); return k; }\n\t\tif (ar[k] ==  ANCHORX) { eval(pf + 'anchorx = ' + ar[++k]); return k; }\n\t\tif (ar[k] ==  ANCHORY) { eval(pf + 'anchory = ' + ar[++k]); return k; }\n\t\tif (ar[k] ==  NOANCHORWARN) { eval(pf + 'noanchorwarn = (' + pf + 'noanchorwarn==1) ? 0 : 1'); return k; }\n\t\tif (ar[k] ==  ANCHORALIGN) { k = opt_MULTIPLEARGS(++k, ar, (pf + 'anchoralign'));  return k; }\n\t}\n\n\treturn -1;\n}\n\n\n///////\n//  FUNCTION WHICH CHECKS FOR THE EXISTENCE OF A REFERENCE MARKER\n///////\nfunction checkAnchorObject() {\n\tvar w = o3_anchor;\n\n\tif (w) {\n\t\tif (!(mrkObj = getAnchorObjectRef(w))) {\n\t\t\tif (o3_noanchorwarn) {\n\t\t\t\talert('WARNING!  Reference mark \"' + w + '\" not found.');\n\t\t\t\treturn false;\n\t\t\t} else w = '';\n\t\t}\n\t}\n\n\treturn true;\n}\n\n///////\n// EXTERNAL SUPPORT FUNCTIONS TO HANDLE ANCHOR PROPERTIES\n///////\n\n// Horizontal placement routine with anchors\nfunction anchorHorizontal(browserWidth, horizontalScrollAmount, widthFix) {\n\tvar hasAnchor = (typeof o3_anchor != 'undefined' && o3_anchor);\n\tif (!hasAnchor) return void(0);\n\n\t// set o3_relx for follow scroll if defined\n\tif (typeof o3_followscroll != 'undefined' && o3_followscroll && o3_sticky) o3_relx = rmrkPosition[0];\n\n\treturn rmrkPosition[0];\n}\n\n// Vertical placement routine with anchors\nfunction anchorVertical(browserHeight,verticalScrollAmount) {\n\tvar hasAnchor = (typeof o3_anchor != 'undefined' && o3_anchor);\t\n\tif (!hasAnchor) return void(0);\n\n\t// set o3_rely for follow scroll if defined\n\tif (typeof o3_followscroll != 'undefined' && o3_followscroll && o3_sticky) o3_rely = rmrkPosition[1];\n\n\treturn rmrkPosition[1];\n}\n\n// Stub function for the runHook routine\nfunction anchorPreface() {\n\tif (!mrkObj) return;\n\trmrkPosition = getAnchorLocation(mrkObj);\n}\n\n// Get Reference Mark object \nfunction getAnchorObjectRef(aObj) {\n\treturn getRefById(aObj, o3_frame.document) || getRefByName(aObj, o3_frame.document)\n}\n\n// Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com\nfunction getAnchorLocation(objRef){\n\tvar mkObj, of, offsets, mlyr\n\t\n\tmkObj = mlyr = objRef\n\toffsets = [o3_anchorx, o3_anchory]\n\t\n\tif (document.layers){\n\t\tif (typeof mlyr.length != 'undefined' &&  mlyr.length > 1) {\n\t\t\t\tmkObj = mlyr[0]\n\t\t\t\toffsets[0] += mlyr[0].x + mlyr[1].pageX\n\t\t\t\toffsets[1] += mlyr[0].y + mlyr[1].pageY\n\t\t\t} else {\n\t\t\t\tif(mlyr.toString().indexOf('Image') != -1 || mlyr.toString().indexOf('Anchor') != -1){\n\t\t\t\t\toffsets[0] += mlyr.x\n\t\t\t\t\toffsets[1] += mlyr.y\n\t\t\t\t} else {\n\t\t\t\t\toffsets[0] += mlyr.pageX\n\t\t\t\t\toffsets[1] += mlyr.pageY\n\t\t\t\t}\n\t\t\t}          \n\t} else {\n\t\toffsets[0] += pageLocation(mlyr, 'Left')\n\t\toffsets[1] += pageLocation(mlyr, 'Top')\n\t}\n\t\n\tof = getAnchorOffsets(mkObj)\n\t\n\tif (typeof o3_dragimg != 'undefined' &&  o3_dragimg) {\n\t\tolImgLeft = offsets[0];\n\t\tolImgTop = offsets[1];\n\t}\n\t\n\toffsets[0] += of[0]                    \n\toffsets[1] += of[1]\n\t\n\tif (typeof o3_dragimg != 'undefined' &&  o3_dragimg) {\n\t\tolImgRight = offsets[0]; \n\t\tolImgBottom = offsets[1];\n\t\treturn;\n\t}\n\t\n\treturn offsets;\n}\n\n// Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com\nfunction getAnchorOffsets(mkObj){\n\tvar fx = fy = 0,  mp, puc, mkAry, sx = sy = 0, w = o3_anchoralign  \n\tvar mW = mH = pW = pH = 0\n\tvar off = [0, 0]\n\n\tmkAry = w.split(',');\n\n\tif (mkAry.length < 3) {\n\t\tmp = mkAry[0].toUpperCase();\n\t\tpuc = (mkAry.length == 1) ? mp : mkAry[1].toUpperCase();\n\t} else if (mkAry.length == 3) {\n\t\tif (!isNaN(mkAry[0])) {\n\t\t\tmp = mkAry.slice(0, 2);\n\t\t\tpuc = mkAry[2].toUpperCase();\n\t\t } else {\n\t\t\tmp = mkAry[0].toUpperCase();\n\t\t\tpuc = mkAry.slice(1);\n\t\t }\n\t} else {\n\t\tmp = mkAry.slice(0, 2);\n\t\tpuc = mkAry.slice(2);\n\t}\n\n\tvar shdwPresent = typeof o3_shadow != 'undefined' &&  o3_shadow\n\n\tif (shdwPresent) {\n\t\tsx = Math.abs(o3_shadowx);\n\t\tsy = Math.abs(o3_shadowy);\n\t}\n\n\tpW = (shdwPresent ? parseInt(o3_width) : (olNs4 ? over.clip.width : over.offsetWidth))\n\tpH = (shdwPresent ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight))\n\n\tif (olOp &&  o3_wrap) {\n\t\tpW = (shdwPresent ? parseInt(o3_width) : (olNs4 ? over.clip.width : over.offsetWidth))\n\t\tpH = (shdwPresent ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight))\n\t}\n\n\tif (!olOp &&  mkObj.toString().indexOf('Image') != -1){\n\t\tmW = mkObj.width\n\t\tmH = mkObj.height\n\t} else if (!olOp &&  mkObj.toString().indexOf('Anchor') != -1) {  // enforced only for NS4\n\t\tmp = 'UL'\n\t} else {\n\t\tmW = (olNs4) ? mkObj.clip.width : mkObj.offsetWidth\n\t\tmH = (olNs4) ? mkObj.clip.height : mkObj.offsetHeight\n\t}\n\n\tif (!isNaN(mp) || typeof mp == 'object') {\n\t\tif (typeof mp == 'object') {\n\t\t\tfx = parseFloat(mp[0]);\n\t\t\tfy = parseFloat(mp[1]);\n\t\t} else\n\t\t\tfx = fy = parseFloat(mp);\n\t\toff = [Math.round(fx*mW), Math.round(fy*mH)];\n\t} else {\n\t\t if (mp == 'UR') off = [mW, 0]\n\t\t else if (mp == 'LL') off = [0, mH]\n\t\t else if (mp == 'LR') off = [mW, mH]\n\t}\n\n\tif (typeof o3_dragimg != 'undefined' &&  o3_dragimg) return off;\n\telse {\n\t\tif (!isNaN(puc) || typeof puc == 'object' ) {\n\t\t\tif (typeof puc == 'object') {\n\t\t\t\tfx = parseFloat(puc[0]);\n\t\t\t\tfy = parseFloat(puc[1]);\n\t\t\t} else\n\t\t\t\tfx = fy = parseFloat(puc);\n\t\t\toff[0] -= Math.round(fx*(pW - sx));\n\t\t\toff[1] -= Math.round(fy*(pH - sy));\n\t\t} else {\n\t\t\tif (puc == 'UR') {\n\t\t\t\toff[0] -= (pW - sx); \n\t\t\t\toff[1] -= sy\n\t\t\t} else if (puc == 'LL') {\n\t\t\t\toff[0] -= sx;\n\t\t\t\toff[1] -= (pH - sy)\n\t\t\t} else if (puc == 'LR') {\n\t\t\t\toff[0] -= (pW-sx);\n\t\t\t\toff[1] -= (pH - sy)\n\t\t\t}\n\t\t}\n\t\treturn off\n\t}\n}\n\n// Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com\nfunction pageLocation(o, t){\n\tvar x = 0\n\n\twhile(o.offsetParent){\n\t\tx += o['offset' + t]\n\t\to = o.offsetParent\n\t}\n\tx += o['offset' + t]\n\n\treturn x\n} \n\n// Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com\nfunction getRefById(l, d){\n\tvar r = \"\", j\n\n\td = (d || document)\n\tif (d.all) return d.all[l]    \n\telse if (d.getElementById) return d.getElementById(l)\n\telse if (d.layers &&  d.layers.length > 0) {\n\t\tif (d.layers[l]) return d.layers[l]\n\t\t\n\t\tfor (j=0; j < d.layers.length; j++) {\n\t\t\tr = getRefById(l, d.layers[j].document)\n\t\t\tif(r) return r               \n\t\t}\n\t}\n\n\treturn false\n}\n\n// Adapted to overlib from jwin by Jason Anderson -- http://www.jwinlib.com\nfunction getRefByName(l, d) {\n\tvar r = null, j\n\n\td = (d || document)\n\n\tif (d.images[l]) return d.images[l]\n\telse if (d.anchors[l]) return d.anchors[l];\n\telse if (d.layers &&  d.layers.length > 0) {\n\t\tfor (j=0; j < d.layers.length; j++) {\n\t\t\tr = getRefByName(l, d.layers[j].document)\n\t\t\tif (r &&  r.length > 0) return r\n\t\t\telse if (r) return [r, d.layers[j]]\n\t\t}\n\t}\n\n\treturn null\n}\n\n////////\n// PLUGIN REGISTRATIONS\n////////\nregisterRunTimeFunction(setAnchorVariables);\nregisterCmdLineFunction(parseAnchorExtras);\nregisterPostParseFunction(checkAnchorObject);\nregisterHook(\"createPopup\", anchorPreface, FAFTER);\nregisterHook(\"horizontalPlacement\", anchorHorizontal, FCHAIN);\nregisterHook(\"verticalPlacement\", anchorVertical, FCHAIN);\nif(olInfo.meets(4.10)) registerNoParameterCommands('noanchorwarn');\n}"
  },
  {
    "path": "tools/server/admin/overlib/overlib_anchor_mini.js",
    "content": "//\\/////\n//\\  overLIB Anchor Plugin\n//\\  This file requires overLIB 4.10 or later.\n//\\\n//\\  overLIB 4.10 - You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2004. All rights reserved.\n//\\  Contributors are listed on the homepage.\n//\\  See http://www.bosrup.com/web/overlib/ for details.\n//\\/////\n//\\  THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL!\nif(typeof olInfo=='undefined'||typeof olInfo.meets=='undefined'||!olInfo.meets(4.10))alert('overLIB 4.10 or later is required for the Anchor Plugin.');else{registerCommands('anchor,anchorx,anchory,noanchorwarn,anchoralign');\nif(typeof ol_anchor=='undefined')var ol_anchor='';if(typeof ol_anchorx=='undefined')var ol_anchorx=0;if(typeof ol_anchory=='undefined')var ol_anchory=0;if(typeof ol_noanchorwarn=='undefined')var ol_noanchorwarn=1;if(typeof ol_anchoralign=='undefined')var ol_anchoralign='UL';\nvar o3_anchor=\"\",o3_anchorx=0,o3_anchory=0,o3_noanchorwarn=1,o3_anchoralign='UL',mrkObj,rmrkPosition;\nfunction setAnchorVariables(){o3_anchor=ol_anchor;o3_anchorx=ol_anchorx;o3_anchory=ol_anchory;o3_noanchorwarn=ol_noanchorwarn;o3_anchoralign=ol_anchoralign;mrkObj=null;}\nfunction parseAnchorExtras(pf,i,ar){var v,k=i;\nif(k<ar.length){if(ar[k]==ANCHOR){eval(pf+\"anchor='\"+escSglQuote(ar[++k])+\"'\");return k;}\nif(ar[k]==ANCHORX){eval(pf+'anchorx='+ar[++k]);return k;}\nif(ar[k]==ANCHORY){eval(pf+'anchory='+ar[++k]);return k;}\nif(ar[k]==NOANCHORWARN){eval(pf+'noanchorwarn=('+pf+'noanchorwarn==1)?0:1');return k;}\nif(ar[k]==ANCHORALIGN){k=opt_MULTIPLEARGS(++k,ar,(pf+'anchoralign')); return k;}}\nreturn-1;}\nfunction checkAnchorObject(){var w=o3_anchor;\nif(w){if(!(mrkObj=getAnchorObjectRef(w))){if(o3_noanchorwarn){alert('WARNING!  Reference mark \"'+w+'\" not found.');return false;}else w='';}}\nreturn true;}\nfunction anchorHorizontal(browserWidth,horizontalScrollAmount,widthFix){var hasAnchor=(typeof o3_anchor!='undefined'&&o3_anchor);if(!hasAnchor)return void(0);\nif(typeof o3_followscroll!='undefined'&&o3_followscroll&&o3_sticky)o3_relx=rmrkPosition[0];\nreturn rmrkPosition[0];}\nfunction anchorVertical(browserHeight,verticalScrollAmount){var hasAnchor=(typeof o3_anchor!='undefined'&&o3_anchor);if(!hasAnchor)return void(0);\nif(typeof o3_followscroll!='undefined'&&o3_followscroll&&o3_sticky)o3_rely=rmrkPosition[1];\nreturn rmrkPosition[1];}\nfunction anchorPreface(){if(!mrkObj)return;rmrkPosition=getAnchorLocation(mrkObj);}\nfunction getAnchorObjectRef(aObj){return getRefById(aObj,o3_frame.document)||getRefByName(aObj,o3_frame.document)}\nfunction getAnchorLocation(objRef){var mkObj,of,offsets,mlyr\nmkObj=mlyr=objRef\noffsets=[o3_anchorx,o3_anchory]\nif(document.layers){if(typeof mlyr.length!='undefined'&& mlyr.length>1){mkObj=mlyr[0]\noffsets[0]+=mlyr[0].x+mlyr[1].pageX\noffsets[1]+=mlyr[0].y+mlyr[1].pageY\n}else{if(mlyr.toString().indexOf('Image')!=-1||mlyr.toString().indexOf('Anchor')!=-1){offsets[0]+=mlyr.x\noffsets[1]+=mlyr.y\n}else{offsets[0]+=mlyr.pageX\noffsets[1]+=mlyr.pageY}}\n}else{offsets[0]+=pageLocation(mlyr,'Left')\noffsets[1]+=pageLocation(mlyr,'Top')}\nof=getAnchorOffsets(mkObj)\nif(typeof o3_dragimg!='undefined'&& o3_dragimg){olImgLeft=offsets[0];olImgTop=offsets[1];}\noffsets[0]+=of[0]\noffsets[1]+=of[1]\nif(typeof o3_dragimg!='undefined'&& o3_dragimg){olImgRight=offsets[0];olImgBottom=offsets[1];return;}\nreturn offsets;}\nfunction getAnchorOffsets(mkObj){var fx=fy=0, mp,puc,mkAry,sx=sy=0,w=o3_anchoralign\nvar mW=mH=pW=pH=0\nvar off=[0,0]\nmkAry=w.split(',');\nif(mkAry.length<3){mp=mkAry[0].toUpperCase();puc=(mkAry.length==1)?mp:mkAry[1].toUpperCase();}else if(mkAry.length==3){if(!isNaN(mkAry[0])){mp=mkAry.slice(0,2);puc=mkAry[2].toUpperCase();}else{mp=mkAry[0].toUpperCase();puc=mkAry.slice(1);}\n}else{mp=mkAry.slice(0,2);puc=mkAry.slice(2);}\nvar shdwPresent=typeof o3_shadow!='undefined'&& o3_shadow\nif(shdwPresent){sx=Math.abs(o3_shadowx);sy=Math.abs(o3_shadowy);}\npW=(shdwPresent?parseInt(o3_width):(olNs4?over.clip.width:over.offsetWidth))\npH=(shdwPresent?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight))\nif(olOp&& o3_wrap){pW=(shdwPresent?parseInt(o3_width):(olNs4?over.clip.width:over.offsetWidth))\npH=(shdwPresent?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight))}\nif(!olOp&& mkObj.toString().indexOf('Image')!=-1){mW=mkObj.width\nmH=mkObj.height\n}else if(!olOp&& mkObj.toString().indexOf('Anchor')!=-1){mp='UL'\n}else{mW=(olNs4)?mkObj.clip.width:mkObj.offsetWidth\nmH=(olNs4)?mkObj.clip.height:mkObj.offsetHeight}\nif(!isNaN(mp)||typeof mp=='object'){if(typeof mp=='object'){fx=parseFloat(mp[0]);fy=parseFloat(mp[1]);}else\nfx=fy=parseFloat(mp);off=[Math.round(fx*mW),Math.round(fy*mH)];}else{if(mp=='UR')off=[mW,0]\nelse if(mp=='LL')off=[0,mH]\nelse if(mp=='LR')off=[mW,mH]}\nif(typeof o3_dragimg!='undefined'&& o3_dragimg)return off;else{if(!isNaN(puc)||typeof puc=='object' ){if(typeof puc=='object'){fx=parseFloat(puc[0]);fy=parseFloat(puc[1]);}else\nfx=fy=parseFloat(puc);off[0]-=Math.round(fx*(pW-sx));off[1]-=Math.round(fy*(pH-sy));}else{if(puc=='UR'){off[0]-=(pW-sx);off[1]-=sy\n}else if(puc=='LL'){off[0]-=sx;off[1]-=(pH-sy)\n}else if(puc=='LR'){off[0]-=(pW-sx);off[1]-=(pH-sy)}}\nreturn off}}\nfunction pageLocation(o,t){var x=0\nwhile(o.offsetParent){x+=o['offset'+t]\no=o.offsetParent}\nx+=o['offset'+t]\nreturn x}\nfunction getRefById(l,d){var r=\"\",j\nd=(d||document)\nif(d.all)return d.all[l]\nelse if(d.getElementById)return d.getElementById(l)\nelse if(d.layers&& d.layers.length>0){if(d.layers[l])return d.layers[l]\nfor(j=0;j<d.layers.length;j++){r=getRefById(l,d.layers[j].document)\nif(r)return r}}\nreturn false}\nfunction getRefByName(l,d){var r=null,j\nd=(d||document)\nif(d.images[l])return d.images[l]\nelse if(d.anchors[l])return d.anchors[l];else if(d.layers&& d.layers.length>0){for(j=0;j<d.layers.length;j++){r=getRefByName(l,d.layers[j].document)\nif(r&& r.length>0)return r\nelse if(r)return [r,d.layers[j]]}}\nreturn null}\nregisterRunTimeFunction(setAnchorVariables);registerCmdLineFunction(parseAnchorExtras);registerPostParseFunction(checkAnchorObject);registerHook(\"createPopup\",anchorPreface,FAFTER);registerHook(\"horizontalPlacement\",anchorHorizontal,FCHAIN);registerHook(\"verticalPlacement\",anchorVertical,FCHAIN);if(olInfo.meets(4.10))registerNoParameterCommands('noanchorwarn');\n}\n"
  },
  {
    "path": "tools/server/admin/overlib/overlib_draggable.js",
    "content": "//\\/////\n//\\  overLIB Draggable Plugin\n//\\\n//\\  You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2003. All rights reserved.\n//\\  Contributors are listed on the homepage.\n//\\  See http://www.bosrup.com/web/overlib/ for details.\n//\\/////\n////////\n// PRE-INIT\n// Ignore these lines, configuration is below.\n////////\nif (typeof olInfo == 'undefined' || typeof olInfo.meets == 'undefined' || !olInfo.meets(4.14)) alert('overLIB 4.14 or later is required for the Draggable Plugin.');\nelse {\nregisterCommands('draggable,altcut,dragimg');\n////////\n// DEFAULT CONFIGURATION\n// Settings you want everywhere are set here. All of this can also be\n// changed on your html page or through an overLIB call.\n////////\nif (typeof ol_draggable=='undefined') var ol_draggable=0;\nif (typeof ol_altcut=='undefined') var ol_altcut=0;\nif (typeof ol_dragimg=='undefined') var ol_dragimg='';\n////////\n// END OF CONFIGURATION\n// Don't change anything below this line, all configuration is above.\n////////\n////////\n// INIT\n////////\n// Runtime variables init. Don't change for config!\nvar o3_draggable=0;\nvar o3_altcut=0;\nvar o3_dragimg='';\nvar olImgLeft,olImgTop;\nvar olImgObj;\nvar olMseMv;  // hold old mouseMove routine\n////////\n// PLUGIN FUNCTIONS\n////////\nfunction setDragVariables() {\n\to3_draggable=ol_draggable;\n\to3_altcut=ol_altcut;\n\to3_dragimg=ol_dragimg;\n\tolImgObj=null;\n}\n// Parses Draggable commands\nfunction parseDragExtras(pf,i,ar) {\n\tvar k=i;\n\tif (k < ar.length) {\n\t\tif (ar[k]==DRAGGABLE) { eval(pf+'draggable=('+pf+'draggable==0) ? 1 : 0'); return k; }\n\t\tif (ar[k]==ALTCUT) { eval(pf+'altcut=('+pf+'altcut==0) ? 1 : 0'); return k; }\n\t\tif (ar[k]==DRAGIMG) { eval(pf+'dragimg=\"'+ar[++k]+'\"'); return k; }\n\t}\n\treturn -1;\n}\n//////\n//  PRESHOW PROCESSING FOR DRAGGABLE POPUPS\n//////\nfunction startDrag() {\n // Initiate dragging if in same frame and its a sticky\n\tif (o3_draggable) {\n\t\tif (o3_sticky&&(o3_frame==ol_frame)) initDrag();\n\t\telse o3_draggable=0;\n\t}\n}\n//////\n//  POSTHIDE PROCESSING FOR DRAGGABLE POPUPS\n//////\nfunction stopDrag() {\n\tif (o3_draggable) endDrag();\n}\n//////\n// DRAGGABLE FUNCTIONS\n//////\nfunction initDrag() {\n\tolMseMv=capExtent.onmousemove;\n\tif(olNs4) {\n\t\tdocument.captureEvents(Event.MOUSEDOWN | Event.CLICK);\n\t\tdocument.onmousedown=grabEl;\n\t\tdocument.onclick=function(e) {return routeEvent(e);}\n\t} else {\n\t\tover.onmousedown=grabEl;\n\t}\n\tif (o3_dragimg) chkForImgSupport(o3_dragimg);\n\treturn true;\n}\n// Checks for image for dragging\nfunction chkForImgSupport(dragImg) {\n\tif (dragImg) {\n\t\tif (typeof getAnchorObjRef!='undefined') olImgObj=getAnchorObjRef(dragImg);\n\t\tif (olImgObj==null) o3_dragimg='';\n\t}\n}\n// Sets cursor symbol\nfunction setCursor(on) {\n\tif (olNs4) return;\n\tover.style.cursor=(on ? 'move' : 'auto');\n}\n// Checks cursor position relative to image\nfunction chkCursorPosition(Obj,XPos,YPos) {\n\tif (Obj) {\n\t\to3_anchorx=o3_anchory=0;\n\t\to3_anchoralign='UL';\n\t\tgetAnchorLocation(Obj);\n\t\tif (XPos < olImgLeft||XPos > (olImgLeft+Obj.width)||YPos < olImgTop||YPos > (olImgTop+Obj.height)) return false;\n\t}\n\treturn true;\n}\n// Sets up mouse grab for moving\nfunction grabEl(e) {\n\tvar e=(e) ? e : event;\n\tvar X,Y;\n\tvar cKy=(olNs4 ? e.modifiers & Event.ALT_MASK : (!olOp ? e.altKey : e.ctrlKey));\n\tif ((o3_altcut ? !cKy : cKy)) {\n\t\t//   get mouse's current x,y location\n\t\tX=(e.pageX || eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));\n\t\tY=(e.pageY || eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));\n\t  if (chkCursorPosition(olImgObj,X,Y)) {\n\t \t\tif (olNs4) document.captureEvents(Event.MOUSEUP);\n\t \t\tcapExtent.onmousemove=moveEl;\n\t \t\tdocument.onmouseup=function() {setCursor(0); if (olIe4) over.onselectstart=null; capExtent.onmousemove=olMseMv;}\n\t \t\tsetCursor(1);\n\t \t\tif (olIe4) over.onselectstart=function() {return false;}\n\t \t\tif (olNs4) {\n\t  \t\tcX=X\n\t  \t\tcY=Y\n\t \t\t} else {\n\t  \t\t// get offsets from upper left hand corner of popup to keep popup from jummping\n\t  \t\t// when first starting to drag\n\t  \t\tcX=X-(olNs4 ? over.left : parseInt(over.style.left));\n\t  \t\tcY=Y-(olNs4 ? over.top : parseInt(over.style.top)); \n\t \t\t}\n\t \t\treturn (olNs4 ? routeEvent(e) : false);\n\t  }\n\t} else setCursor(0);\n}\n// Moves popup to follow mouse\nfunction moveEl(e) {\n\tvar e=(e) ? e : event;\n\tvar dX,dY,X,Y;\n\t//  get new mouse location\n\tX=(e.pageX || eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));\n\tY=(e.pageY || eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));\n\tif (chkCursorPosition(olImgObj,X,Y)){\n\t\tif (olNs4) {\n\t\t\tdX=X-cX; cX=X;\n\t\t\tdY=Y-cY; cY=Y;\n\t\t\tover.moveBy(dX,dY);\n\t\t} else \n\t\t\trepositionTo(over,X-cX,Y-cY);  // move popup to that position\n\t}\n}\n// Cleanup for Drag end\nfunction endDrag(obj) {\n\tif (olNs4) {\n\t\tdocument.releaseEvents(Event.MOUSEDOWN | Event.MOUSEUP | Event.CLICK);\n\t\tdocument.onmousedown=document.onclick=null;\n\t} else {\n\t\tif(!obj) obj=over;\n\t\tobj.onmousedown=null;\n\t}\n\tdocument.onmouseup= null;\n}\n////////\n// PLUGIN REGISTRATIONS\n////////\nregisterRunTimeFunction(setDragVariables);\nregisterCmdLineFunction(parseDragExtras);\nregisterHook(\"disp\",startDrag,FBEFORE);\nregisterHook(\"hideObject\",stopDrag,FAFTER);\nif (olInfo.meets(4.14)) registerNoParameterCommands('draggable,altcut');\n}\n//end \n"
  },
  {
    "path": "tools/server/admin/overlib/overlib_draggable_mini.js",
    "content": "//\\/////\n//\\  overLIB Draggable Plugin\n//\\\n//\\  You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2003. All rights reserved.\n//\\  Contributors are listed on the homepage.\n//\\  See http://www.bosrup.com/web/overlib/ for details.\n//\\/////\nif(typeof olInfo=='undefined'||typeof olInfo.meets=='undefined'||!olInfo.meets(4.14))alert('overLIB 4.14 or later is required for the Draggable Plugin.');else{registerCommands('draggable,altcut,dragimg');\nif(typeof ol_draggable=='undefined')var ol_draggable=0;if(typeof ol_altcut=='undefined')var ol_altcut=0;if(typeof ol_dragimg=='undefined')var ol_dragimg='';\nvar o3_draggable=0,o3_altcut=0,o3_dragimg='',olImgLeft,olImgTop,olImgObj,olMseMv;\nfunction setDragVariables(){o3_draggable=ol_draggable;o3_altcut=ol_altcut;o3_dragimg=ol_dragimg;olImgObj=null;}\nfunction parseDragExtras(pf,i,ar){var k=i;if(k<ar.length){if(ar[k]==DRAGGABLE){eval(pf+'draggable=('+pf+'draggable==0)?1:0');return k;}\nif(ar[k]==ALTCUT){eval(pf+'altcut=('+pf+'altcut==0)?1:0');return k;}\nif(ar[k]==DRAGIMG){eval(pf+'dragimg=\"'+ar[++k]+'\"');return k;}}\nreturn-1;}\nfunction startDrag(){\nif(o3_draggable){if(o3_sticky&&(o3_frame==ol_frame))initDrag();else o3_draggable=0;}}\nfunction stopDrag(){if(o3_draggable)endDrag();}\nfunction initDrag(){olMseMv=capExtent.onmousemove;if(olNs4){document.captureEvents(Event.MOUSEDOWN|Event.CLICK);document.onmousedown=grabEl;document.onclick=function(e){return routeEvent(e);}\n}else{over.onmousedown=grabEl;}\nif(o3_dragimg)chkForImgSupport(o3_dragimg);return true;}\nfunction chkForImgSupport(dragImg){if(dragImg){if(typeof getAnchorObjRef!='undefined')olImgObj=getAnchorObjRef(dragImg);if(olImgObj==null)o3_dragimg='';}}\nfunction setCursor(on){if(olNs4)return;over.style.cursor=(on?'move':'auto');}\nfunction chkCursorPosition(Obj,XPos,YPos){if(Obj){o3_anchorx=o3_anchory=0;o3_anchoralign='UL';getAnchorLocation(Obj);if(XPos<olImgLeft||XPos>(olImgLeft+Obj.width)||YPos<olImgTop||YPos>(olImgTop+Obj.height))return false;}\nreturn true;}\nfunction grabEl(e){var e=(e)?e:event;var X,Y;var cKy=(olNs4?e.modifiers&Event.ALT_MASK:(!olOp?e.altKey:e.ctrlKey));if((o3_altcut?!cKy:cKy)){\nX=(e.pageX||eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));Y=(e.pageY||eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));if(chkCursorPosition(olImgObj,X,Y)){if(olNs4)document.captureEvents(Event.MOUSEUP);capExtent.onmousemove=moveEl;document.onmouseup=function(){setCursor(0);if(olIe4)over.onselectstart=null;capExtent.onmousemove=olMseMv;}\nsetCursor(1);if(olIe4)over.onselectstart=function(){return false;}\nif(olNs4){cX=X\ncY=Y\n}else{\ncX=X-(olNs4?over.left:parseInt(over.style.left));cY=Y-(olNs4?over.top:parseInt(over.style.top));}\nreturn(olNs4?routeEvent(e):false);}\n}else setCursor(0);}\nfunction moveEl(e){var e=(e)?e:event;var dX,dY,X,Y;\nX=(e.pageX||eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft'));Y=(e.pageY||eval('e.clientY+o3_frame.'+docRoot+'.scrollTop'));if(chkCursorPosition(olImgObj,X,Y)){if(olNs4){dX=X-cX;cX=X;dY=Y-cY;cY=Y;over.moveBy(dX,dY);}else\nrepositionTo(over,X-cX,Y-cY);}}\nfunction endDrag(obj){if(olNs4){document.releaseEvents(Event.MOUSEDOWN|Event.MOUSEUP|Event.CLICK);document.onmousedown=document.onclick=null;}else{if(!obj)obj=over;obj.onmousedown=null;}\ndocument.onmouseup=null;}\nregisterRunTimeFunction(setDragVariables);registerCmdLineFunction(parseDragExtras);registerHook(\"disp\",startDrag,FBEFORE);registerHook(\"hideObject\",stopDrag,FAFTER);if(olInfo.meets(4.14))registerNoParameterCommands('draggable,altcut');}\n"
  },
  {
    "path": "tools/server/admin/overlib/overlib_mini.js",
    "content": "//\\/////\n//\\  overLIB 4.21 - You may not remove or change this notice.\n//\\  Copyright Erik Bosrup 1998-2004. All rights reserved.\n//\\\n//\\  Contributors are listed on the homepage.\n//\\  This file might be old, always check for the latest version at:\n//\\  http://www.bosrup.com/web/overlib/\n//\\\n//\\  Please read the license agreement (available through the link above)\n//\\  before using overLIB. Direct any licensing questions to erik@bosrup.com.\n//\\\n//\\  Do not sell this as your own work or remove this copyright notice.\n//\\  For full details on copying or changing this script please read the\n//\\  license agreement at the link above. Please give credit on sites that\n//\\  use overLIB and submit changes of the script so other people can use\n//\\  them as well.\n//\\/////\n//\\  THIS IS A VERY MODIFIED VERSION. DO NOT EDIT OR PUBLISH. GET THE ORIGINAL!\nvar olLoaded=0,pmStart=10000000,pmUpper=10001000,pmCount=pmStart+1,pmt='',pms=new Array(),olInfo=new Info('4.21',1),FREPLACE=0,FBEFORE=1,FAFTER=2,FALTERNATE=3,FCHAIN=4,olHideForm=0,olHautoFlag=0,olVautoFlag=0,hookPts=new Array(),postParse=new Array(),cmdLine=new Array(),runTime=new Array();\nregisterCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,cssclass,fgclass,bgclass,textfontclass,captionfontclass,closefontclass');\nif(typeof ol_fgcolor=='undefined')var ol_fgcolor=\"#99BBDD\";if(typeof ol_bgcolor=='undefined')var ol_bgcolor=\"#7799BB\";if(typeof ol_textcolor=='undefined')var ol_textcolor=\"#000000\";if(typeof ol_capcolor=='undefined')var ol_capcolor=\"#000033\";if(typeof ol_closecolor=='undefined')var ol_closecolor=\"#000000\";if(typeof ol_textfont=='undefined')var ol_textfont=\"Verdana,Arial,Helvetica\";if(typeof ol_captionfont=='undefined')var ol_captionfont=\"Verdana,Arial,Helvetica\";if(typeof ol_closefont=='undefined')var ol_closefont=\"Verdana,Arial,Helvetica\";if(typeof ol_textsize=='undefined')var ol_textsize=\"1\";if(typeof ol_captionsize=='undefined')var ol_captionsize=\"1\";if(typeof ol_closesize=='undefined')var ol_closesize=\"1\";if(typeof ol_width=='undefined')var ol_width=\"200\";if(typeof ol_border=='undefined')var ol_border=\"1\";if(typeof ol_cellpad=='undefined')var ol_cellpad=2;if(typeof ol_offsetx=='undefined')var ol_offsetx=10;if(typeof ol_offsety=='undefined')var ol_offsety=10;if(typeof ol_text=='undefined')var ol_text=\"Default Text\";if(typeof ol_cap=='undefined')var ol_cap=\"\";if(typeof ol_sticky=='undefined')var ol_sticky=0;if(typeof ol_background=='undefined')var ol_background=\"\";if(typeof ol_close=='undefined')var ol_close=\"Close\";if(typeof ol_hpos=='undefined')var ol_hpos=RIGHT;if(typeof ol_status=='undefined')var ol_status=\"\";if(typeof ol_autostatus=='undefined')var ol_autostatus=0;if(typeof ol_height=='undefined')var ol_height=-1;if(typeof ol_snapx=='undefined')var ol_snapx=0;if(typeof ol_snapy=='undefined')var ol_snapy=0;if(typeof ol_fixx=='undefined')var ol_fixx=-1;if(typeof ol_fixy=='undefined')var ol_fixy=-1;if(typeof ol_relx=='undefined')var ol_relx=null;if(typeof ol_rely=='undefined')var ol_rely=null;if(typeof ol_fgbackground=='undefined')var ol_fgbackground=\"\";if(typeof ol_bgbackground=='undefined')var ol_bgbackground=\"\";if(typeof ol_padxl=='undefined')var ol_padxl=1;if(typeof ol_padxr=='undefined')var ol_padxr=1;if(typeof ol_padyt=='undefined')var ol_padyt=1;if(typeof ol_padyb=='undefined')var ol_padyb=1;if(typeof ol_fullhtml=='undefined')var ol_fullhtml=0;if(typeof ol_vpos=='undefined')var ol_vpos=BELOW;if(typeof ol_aboveheight=='undefined')var ol_aboveheight=0;if(typeof ol_capicon=='undefined')var ol_capicon=\"\";if(typeof ol_frame=='undefined')var ol_frame=self;if(typeof ol_timeout=='undefined')var ol_timeout=0;if(typeof ol_function=='undefined')var ol_function=null;if(typeof ol_delay=='undefined')var ol_delay=0;if(typeof ol_hauto=='undefined')var ol_hauto=0;if(typeof ol_vauto=='undefined')var ol_vauto=0;if(typeof ol_closeclick=='undefined')var ol_closeclick=0;if(typeof ol_wrap=='undefined')var ol_wrap=0;if(typeof ol_followmouse=='undefined')var ol_followmouse=1;if(typeof ol_mouseoff=='undefined')var ol_mouseoff=0;if(typeof ol_closetitle=='undefined')var ol_closetitle='Close';if(typeof ol_compatmode=='undefined')var ol_compatmode=0;if(typeof ol_css=='undefined')var ol_css=CSSOFF;if(typeof ol_fgclass=='undefined')var ol_fgclass=\"\";if(typeof ol_bgclass=='undefined')var ol_bgclass=\"\";if(typeof ol_textfontclass=='undefined')var ol_textfontclass=\"\";if(typeof ol_captionfontclass=='undefined')var ol_captionfontclass=\"\";if(typeof ol_closefontclass=='undefined')var ol_closefontclass=\"\";\nif(typeof ol_texts=='undefined')var ol_texts=new Array(\"Text 0\",\"Text 1\");if(typeof ol_caps=='undefined')var ol_caps=new Array(\"Caption 0\",\"Caption 1\");\nvar o3_text=\"\",o3_cap=\"\",o3_sticky=0,o3_background=\"\",o3_close=\"Close\",o3_hpos=RIGHT,o3_offsetx=2,o3_offsety=2,o3_fgcolor=\"\",o3_bgcolor=\"\",o3_textcolor=\"\",o3_capcolor=\"\",o3_closecolor=\"\",o3_width=100,o3_border=1,o3_cellpad=2,o3_status=\"\",o3_autostatus=0,o3_height=-1,o3_snapx=0,o3_snapy=0,o3_fixx=-1,o3_fixy=-1,o3_relx=null,o3_rely=null,o3_fgbackground=\"\",o3_bgbackground=\"\",o3_padxl=0,o3_padxr=0,o3_padyt=0,o3_padyb=0,o3_fullhtml=0,o3_vpos=BELOW,o3_aboveheight=0,o3_capicon=\"\",o3_textfont=\"Verdana,Arial,Helvetica\",o3_captionfont=\"Verdana,Arial,Helvetica\",o3_closefont=\"Verdana,Arial,Helvetica\",o3_textsize=\"1\",o3_captionsize=\"1\",o3_closesize=\"1\",o3_frame=self,o3_timeout=0,o3_timerid=0,o3_allowmove=0,o3_function=null,o3_delay=0,o3_delayid=0,o3_hauto=0,o3_vauto=0,o3_closeclick=0,o3_wrap=0,o3_followmouse=1,o3_mouseoff=0,o3_closetitle='',o3_compatmode=0,o3_css=CSSOFF,o3_fgclass=\"\",o3_bgclass=\"\",o3_textfontclass=\"\",o3_captionfontclass=\"\",o3_closefontclass=\"\";\nvar o3_x=0,o3_y=0,o3_showingsticky=0,o3_removecounter=0;\nvar over=null,fnRef,hoveringSwitch=false,olHideDelay;\nvar isMac=(navigator.userAgent.indexOf(\"Mac\")!=-1),olOp=(navigator.userAgent.toLowerCase().indexOf('opera')>-1&&document.createTextNode),olNs4=(navigator.appName=='Netscape'&&parseInt(navigator.appVersion)==4),olNs6=(document.getElementById)?true:false,olKq=(olNs6&&/konqueror/i.test(navigator.userAgent)),olIe4=(document.all)?true:false,olIe5=false,olIe55=false,docRoot='document.body';\nif(olNs4){var oW=window.innerWidth;var oH=window.innerHeight;window.onresize=function(){if(oW!=window.innerWidth||oH!=window.innerHeight)location.reload();}}\nif(olIe4){var agent=navigator.userAgent;if(/MSIE/.test(agent)){var versNum=parseFloat(agent.match(/MSIE[ ](\\d\\.\\d+)\\.*/i)[1]);if(versNum>=5){olIe5=true;olIe55=(versNum>=5.5&&!olOp)?true:false;if(olNs6)olNs6=false;}}\nif(olNs6)olIe4=false;}\nif(document.compatMode&&document.compatMode=='CSS1Compat'){docRoot=((olIe4&&!olOp)?'document.documentElement':docRoot);}\nif(window.addEventListener)window.addEventListener(\"load\",OLonLoad_handler,false);else if(window.attachEvent)window.attachEvent(\"onload\",OLonLoad_handler);\nvar capExtent;\nfunction overlib(){if(!olLoaded||isExclusive(overlib.arguments))return true;if(olCheckMouseCapture)olMouseCapture();if(over){over=(typeof over.id!='string')?o3_frame.document.all['overDiv']:over;cClick();}\nolHideDelay=0;o3_text=ol_text;o3_cap=ol_cap;o3_sticky=ol_sticky;o3_background=ol_background;o3_close=ol_close;o3_hpos=ol_hpos;o3_offsetx=ol_offsetx;o3_offsety=ol_offsety;o3_fgcolor=ol_fgcolor;o3_bgcolor=ol_bgcolor;o3_textcolor=ol_textcolor;o3_capcolor=ol_capcolor;o3_closecolor=ol_closecolor;o3_width=ol_width;o3_border=ol_border;o3_cellpad=ol_cellpad;o3_status=ol_status;o3_autostatus=ol_autostatus;o3_height=ol_height;o3_snapx=ol_snapx;o3_snapy=ol_snapy;o3_fixx=ol_fixx;o3_fixy=ol_fixy;o3_relx=ol_relx;o3_rely=ol_rely;o3_fgbackground=ol_fgbackground;o3_bgbackground=ol_bgbackground;o3_padxl=ol_padxl;o3_padxr=ol_padxr;o3_padyt=ol_padyt;o3_padyb=ol_padyb;o3_fullhtml=ol_fullhtml;o3_vpos=ol_vpos;o3_aboveheight=ol_aboveheight;o3_capicon=ol_capicon;o3_textfont=ol_textfont;o3_captionfont=ol_captionfont;o3_closefont=ol_closefont;o3_textsize=ol_textsize;o3_captionsize=ol_captionsize;o3_closesize=ol_closesize;o3_timeout=ol_timeout;o3_function=ol_function;o3_delay=ol_delay;o3_hauto=ol_hauto;o3_vauto=ol_vauto;o3_closeclick=ol_closeclick;o3_wrap=ol_wrap;o3_followmouse=ol_followmouse;o3_mouseoff=ol_mouseoff;o3_closetitle=ol_closetitle;o3_css=ol_css;o3_compatmode=ol_compatmode;o3_fgclass=ol_fgclass;o3_bgclass=ol_bgclass;o3_textfontclass=ol_textfontclass;o3_captionfontclass=ol_captionfontclass;o3_closefontclass=ol_closefontclass;\nsetRunTimeVariables();\nfnRef='';\no3_frame=ol_frame;\nif(!(over=createDivContainer()))return false;\nparseTokens('o3_',overlib.arguments);if(!postParseChecks())return false;\nif(o3_delay==0){return runHook(\"olMain\",FREPLACE);}else{o3_delayid=setTimeout(\"runHook('olMain',FREPLACE)\",o3_delay);return false;}}\nfunction nd(time){if(olLoaded&&!isExclusive()){hideDelay(time);\nif(o3_removecounter>=1){o3_showingsticky=0 };\nif(o3_showingsticky==0){o3_allowmove=0;if(over!=null&&o3_timerid==0)runHook(\"hideObject\",FREPLACE,over);}else{o3_removecounter++;}}\nreturn true;}\nfunction cClick(){if(olLoaded){runHook(\"hideObject\",FREPLACE,over);o3_showingsticky=0;}\nreturn false;}\nfunction overlib_pagedefaults(){parseTokens('ol_',overlib_pagedefaults.arguments);}\nfunction olMain(){var layerhtml,styleType;runHook(\"olMain\",FBEFORE);\nif(o3_background!=\"\"||o3_fullhtml){\nlayerhtml=runHook('ol_content_background',FALTERNATE,o3_css,o3_text,o3_background,o3_fullhtml);}else{\nstyleType=(pms[o3_css-1-pmStart]==\"cssoff\"||pms[o3_css-1-pmStart]==\"cssclass\");\nif(o3_fgbackground!=\"\")o3_fgbackground=\"background=\\\"\"+o3_fgbackground+\"\\\"\";if(o3_bgbackground!=\"\")o3_bgbackground=(styleType?\"background=\\\"\"+o3_bgbackground+\"\\\"\":o3_bgbackground);\nif(o3_fgcolor!=\"\")o3_fgcolor=(styleType?\"bgcolor=\\\"\"+o3_fgcolor+\"\\\"\":o3_fgcolor);if(o3_bgcolor!=\"\")o3_bgcolor=(styleType?\"bgcolor=\\\"\"+o3_bgcolor+\"\\\"\":o3_bgcolor);\nif(o3_height>0)o3_height=(styleType?\"height=\\\"\"+o3_height+\"\\\"\":o3_height);else o3_height=\"\";\nif(o3_cap==\"\"){\nlayerhtml=runHook('ol_content_simple',FALTERNATE,o3_css,o3_text);}else{\nif(o3_sticky){\nlayerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,o3_close);}else{\nlayerhtml=runHook('ol_content_caption',FALTERNATE,o3_css,o3_text,o3_cap,\"\");}}}\nif(o3_sticky){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;}\no3_showingsticky=1;o3_removecounter=0;}\nif(!runHook(\"createPopup\",FREPLACE,layerhtml))return false;\nif(o3_autostatus>0){o3_status=o3_text;if(o3_autostatus>1)o3_status=o3_cap;}\no3_allowmove=0;\nif(o3_timeout>0){if(o3_timerid>0)clearTimeout(o3_timerid);o3_timerid=setTimeout(\"cClick()\",o3_timeout);}\nrunHook(\"disp\",FREPLACE,o3_status);runHook(\"olMain\",FAFTER);\nreturn(olOp&&event&&event.type=='mouseover'&&!o3_status)?'':(o3_status!='');}\nfunction ol_content_simple(text){var cpIsMultiple=/,/.test(o3_cellpad);var txt='<table width=\"'+o3_width+'\" border=\"0\" cellpadding=\"'+o3_border+'\" cellspacing=\"0\" '+(o3_bgclass?'class=\"'+o3_bgclass+'\"':o3_bgcolor+' '+o3_height)+'><tr><td><table width=\"100%\" border=\"0\" '+((olNs4||!cpIsMultiple)?'cellpadding=\"'+o3_cellpad+'\" ':'')+'cellspacing=\"0\" '+(o3_fgclass?'class=\"'+o3_fgclass+'\"':o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign=\"TOP\"'+(o3_textfontclass?' class=\"'+o3_textfontclass+'\">':((!olNs4&&cpIsMultiple)?' style=\"'+setCellPadStr(o3_cellpad)+'\">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';\nset_background(\"\");return txt;}\nfunction ol_content_caption(text,title,close){var nameId,txt,cpIsMultiple=/,/.test(o3_cellpad);var closing,closeevent;\nclosing=\"\";closeevent=\"onmouseover\";if(o3_closeclick==1)closeevent=(o3_closetitle?\"title='\"+o3_closetitle+\"'\":\"\")+\" onclick\";if(o3_capicon!=\"\"){nameId=' hspace=\\\"5\\\"'+' align=\\\"middle\\\" alt=\\\"\\\"';if(typeof o3_dragimg!='undefined'&&o3_dragimg)nameId=' hspace=\\\"5\\\"'+' name=\\\"'+o3_dragimg+'\\\" id=\\\"'+o3_dragimg+'\\\" align=\\\"middle\\\" alt=\\\"Drag Enabled\\\" title=\\\"Drag Enabled\\\"';o3_capicon='<img src=\\\"'+o3_capicon+'\\\"'+nameId+' />';}\nif(close!=\"\")\nclosing='<td '+(!o3_compatmode&&o3_closefontclass?'class=\"'+o3_closefontclass:'align=\"RIGHT')+'\"><a href=\"javascript:return '+fnRef+'cClick();\"'+((o3_compatmode&&o3_closefontclass)?' class=\"'+o3_closefontclass+'\" ':' ')+closeevent+'=\"return '+fnRef+'cClick();\">'+(o3_closefontclass?'':wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass?'':wrapStr(1,o3_closesize,'close'))+'</a></td>';txt='<table width=\"'+o3_width+'\" border=\"0\" cellpadding=\"'+o3_border+'\" cellspacing=\"0\" '+(o3_bgclass?'class=\"'+o3_bgclass+'\"':o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\"><tr><td'+(o3_captionfontclass?' class=\"'+o3_captionfontclass+'\">':'>')+(o3_captionfontclass?'':'<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass?'':wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closing+'</tr></table><table width=\"100%\" border=\"0\" '+((olNs4||!cpIsMultiple)?'cellpadding=\"'+o3_cellpad+'\" ':'')+'cellspacing=\"0\" '+(o3_fgclass?'class=\"'+o3_fgclass+'\"':o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign=\"TOP\"'+(o3_textfontclass?' class=\"'+o3_textfontclass+'\">' :((!olNs4&&cpIsMultiple)?' style=\"'+setCellPadStr(o3_cellpad)+'\">':'>'))+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td></tr></table></td></tr></table>';\nset_background(\"\");return txt;}\nfunction ol_content_background(text,picture,hasfullhtml){if(hasfullhtml){txt=text;}else{txt='<table width=\"'+o3_width+'\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"'+o3_height+'\"><tr><td colspan=\"3\" height=\"'+o3_padyt+'\"></td></tr><tr><td width=\"'+o3_padxl+'\"></td><td valign=\"TOP\" width=\"'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass?'\" class=\"'+o3_textfontclass:'')+'\">'+(o3_textfontclass?'':wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass?'':wrapStr(1,o3_textsize))+'</td><td width=\"'+o3_padxr+'\"></td></tr><tr><td colspan=\"3\" height=\"'+o3_padyb+'\"></td></tr></table>';}\nset_background(picture);return txt;}\nfunction set_background(pic){if(pic==\"\"){if(olNs4){over.background.src=null;}else if(over.style){over.style.backgroundImage=\"none\";}\n}else{if(olNs4){over.background.src=pic;}else if(over.style){over.style.width=o3_width+'px';over.style.backgroundImage=\"url(\"+pic+\")\";}}}\nvar olShowId=-1;\nfunction disp(statustext){runHook(\"disp\",FBEFORE);\nif(o3_allowmove==0){runHook(\"placeLayer\",FREPLACE);(olNs6&&olShowId<0)?olShowId=setTimeout(\"runHook('showObject',FREPLACE,over)\",1):runHook(\"showObject\",FREPLACE,over);o3_allowmove=(o3_sticky||o3_followmouse==0)?0:1;}\nrunHook(\"disp\",FAFTER);\nif(statustext!=\"\")self.status=statustext;}\nfunction createPopup(lyrContent){runHook(\"createPopup\",FBEFORE);\nif(o3_wrap){var wd,ww,theObj=(olNs4?over:over.style);theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0);layerWrite(lyrContent);wd=(olNs4?over.clip.width:over.offsetWidth);if(wd>(ww=windowWidth())){lyrContent=lyrContent.replace(/\\&nbsp;/g,' ');o3_width=ww;o3_wrap=0;}}\nlayerWrite(lyrContent);\nif(o3_wrap)o3_width=(olNs4?over.clip.width:over.offsetWidth);\nrunHook(\"createPopup\",FAFTER,lyrContent);\nreturn true;}\nfunction placeLayer(){var placeX,placeY,widthFix=0;\nif(o3_frame.innerWidth)widthFix=18;iwidth=windowWidth();\nwinoffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollLeft'):o3_frame.pageXOffset;\nplaceX=runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);\nif(o3_frame.innerHeight){iheight=o3_frame.innerHeight;}else if(eval('o3_frame.'+docRoot)&&eval(\"typeof o3_frame.\"+docRoot+\".clientHeight=='number'\")&&eval('o3_frame.'+docRoot+'.clientHeight')){iheight=eval('o3_frame.'+docRoot+'.clientHeight');}\nscrolloffset=(olIe4)?eval('o3_frame.'+docRoot+'.scrollTop'):o3_frame.pageYOffset;placeY=runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);\nrepositionTo(over,placeX,placeY);}\nfunction olMouseMove(e){var e=(e)?e:event;\nif(e.pageX){o3_x=e.pageX;o3_y=e.pageY;}else if(e.clientX){o3_x=eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');o3_y=eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');}\nif(o3_allowmove==1)runHook(\"placeLayer\",FREPLACE);\nif(hoveringSwitch&&!olNs4&&runHook(\"cursorOff\",FREPLACE)){(olHideDelay?hideDelay(olHideDelay):cClick());hoveringSwitch=!hoveringSwitch;}}\nfunction no_overlib(){return ver3fix;}\nfunction olMouseCapture(){capExtent=document;var fN,str='',l,k,f,wMv,sS,mseHandler=olMouseMove;var re=/function[ ]*(\\w*)\\(/;\nwMv=(!olIe4&&window.onmousemove);if(document.onmousemove||wMv){if(wMv)capExtent=window;f=capExtent.onmousemove.toString();fN=f.match(re);if(fN==null){str=f+'(e);';}else if(fN[1]=='anonymous'||fN[1]=='olMouseMove'||(wMv&&fN[1]=='onmousemove')){if(!olOp&&wMv){l=f.indexOf('{')+1;k=f.lastIndexOf('}');sS=f.substring(l,k);if((l=sS.indexOf('('))!=-1){sS=sS.substring(0,l).replace(/^\\s+/,'').replace(/\\s+$/,'');if(eval(\"typeof \"+sS+\"=='undefined'\"))window.onmousemove=null;else str=sS+'(e);';}}\nif(!str){olCheckMouseCapture=false;return;}\n}else{if(fN[1])str=fN[1]+'(e);';else{l=f.indexOf('{')+1;k=f.lastIndexOf('}');str=f.substring(l,k)+'\\n';}}\nstr+='olMouseMove(e);';mseHandler=new Function('e',str);}\ncapExtent.onmousemove=mseHandler;if(olNs4)capExtent.captureEvents(Event.MOUSEMOVE);}\nfunction parseTokens(pf,ar){\nvar v,i,mode=-1,par=(pf!='ol_'),fnMark=(par&&!ar.length?1:0);\nfor(i=0;i<ar.length;i++){if(mode<0){\nif(typeof ar[i]=='number'&&ar[i]>pmStart&&ar[i]<pmUpper){fnMark=(par?1:0);i--;}else{switch(pf){case 'ol_':\nol_text=ar[i].toString();break;default:\no3_text=ar[i].toString();}}\nmode=0;}else{\nif(ar[i]>=pmCount||ar[i]==DONOTHING){continue;}\nif(ar[i]==INARRAY){fnMark=0;eval(pf+'text=ol_texts['+ar[++i]+'].toString()');continue;}\nif(ar[i]==CAPARRAY){eval(pf+'cap=ol_caps['+ar[++i]+'].toString()');continue;}\nif(ar[i]==STICKY){if(pf!='ol_')eval(pf+'sticky=1');continue;}\nif(ar[i]==BACKGROUND){eval(pf+'background=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==NOCLOSE){if(pf!='ol_')opt_NOCLOSE();continue;}\nif(ar[i]==CAPTION){eval(pf+\"cap='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==CENTER||ar[i]==LEFT||ar[i]==RIGHT){eval(pf+'hpos='+ar[i]);if(pf!='ol_')olHautoFlag=1;continue;}\nif(ar[i]==OFFSETX){eval(pf+'offsetx='+ar[++i]);continue;}\nif(ar[i]==OFFSETY){eval(pf+'offsety='+ar[++i]);continue;}\nif(ar[i]==FGCOLOR){eval(pf+'fgcolor=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==BGCOLOR){eval(pf+'bgcolor=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==TEXTCOLOR){eval(pf+'textcolor=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CAPCOLOR){eval(pf+'capcolor=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CLOSECOLOR){eval(pf+'closecolor=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==WIDTH){eval(pf+'width='+ar[++i]);continue;}\nif(ar[i]==BORDER){eval(pf+'border='+ar[++i]);continue;}\nif(ar[i]==CELLPAD){i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad'));continue;}\nif(ar[i]==STATUS){eval(pf+\"status='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==AUTOSTATUS){eval(pf+'autostatus=('+pf+'autostatus==1)?0:1');continue;}\nif(ar[i]==AUTOSTATUSCAP){eval(pf+'autostatus=('+pf+'autostatus==2)?0:2');continue;}\nif(ar[i]==HEIGHT){eval(pf+'height='+pf+'aboveheight='+ar[++i]);continue;}\nif(ar[i]==CLOSETEXT){eval(pf+\"close='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==SNAPX){eval(pf+'snapx='+ar[++i]);continue;}\nif(ar[i]==SNAPY){eval(pf+'snapy='+ar[++i]);continue;}\nif(ar[i]==FIXX){eval(pf+'fixx='+ar[++i]);continue;}\nif(ar[i]==FIXY){eval(pf+'fixy='+ar[++i]);continue;}\nif(ar[i]==RELX){eval(pf+'relx='+ar[++i]);continue;}\nif(ar[i]==RELY){eval(pf+'rely='+ar[++i]);continue;}\nif(ar[i]==FGBACKGROUND){eval(pf+'fgbackground=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==BGBACKGROUND){eval(pf+'bgbackground=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==PADX){eval(pf+'padxl='+ar[++i]);eval(pf+'padxr='+ar[++i]);continue;}\nif(ar[i]==PADY){eval(pf+'padyt='+ar[++i]);eval(pf+'padyb='+ar[++i]);continue;}\nif(ar[i]==FULLHTML){if(pf!='ol_')eval(pf+'fullhtml=1');continue;}\nif(ar[i]==BELOW||ar[i]==ABOVE){eval(pf+'vpos='+ar[i]);if(pf!='ol_')olVautoFlag=1;continue;}\nif(ar[i]==CAPICON){eval(pf+'capicon=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==TEXTFONT){eval(pf+\"textfont='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==CAPTIONFONT){eval(pf+\"captionfont='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==CLOSEFONT){eval(pf+\"closefont='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==TEXTSIZE){eval(pf+'textsize=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CAPTIONSIZE){eval(pf+'captionsize=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CLOSESIZE){eval(pf+'closesize=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==TIMEOUT){eval(pf+'timeout='+ar[++i]);continue;}\nif(ar[i]==FUNCTION){if(pf=='ol_'){if(typeof ar[i+1]!='number'){v=ar[++i];ol_function=(typeof v=='function'?v:null);}}else{fnMark=0;v=null;if(typeof ar[i+1]!='number')v=ar[++i]; opt_FUNCTION(v);} continue;}\nif(ar[i]==DELAY){eval(pf+'delay='+ar[++i]);continue;}\nif(ar[i]==HAUTO){eval(pf+'hauto=('+pf+'hauto==0)?1:0');continue;}\nif(ar[i]==VAUTO){eval(pf+'vauto=('+pf+'vauto==0)?1:0');continue;}\nif(ar[i]==CLOSECLICK){eval(pf+'closeclick=('+pf+'closeclick==0)?1:0');continue;}\nif(ar[i]==WRAP){eval(pf+'wrap=('+pf+'wrap==0)?1:0');continue;}\nif(ar[i]==FOLLOWMOUSE){eval(pf+'followmouse=('+pf+'followmouse==1)?0:1');continue;}\nif(ar[i]==MOUSEOFF){eval(pf+'mouseoff=('+pf+'mouseoff==0)?1:0');v=ar[i+1];if(pf!='ol_'&&eval(pf+'mouseoff')&&typeof v=='number'&&(v<pmStart||v>pmUpper))olHideDelay=ar[++i];continue;}\nif(ar[i]==CLOSETITLE){eval(pf+\"closetitle='\"+escSglQuote(ar[++i])+\"'\");continue;}\nif(ar[i]==CSSOFF||ar[i]==CSSCLASS){eval(pf+'css='+ar[i]);continue;}\nif(ar[i]==COMPATMODE){eval(pf+'compatmode=('+pf+'compatmode==0)?1:0');continue;}\nif(ar[i]==FGCLASS){eval(pf+'fgclass=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==BGCLASS){eval(pf+'bgclass=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==TEXTFONTCLASS){eval(pf+'textfontclass=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CAPTIONFONTCLASS){eval(pf+'captionfontclass=\"'+ar[++i]+'\"');continue;}\nif(ar[i]==CLOSEFONTCLASS){eval(pf+'closefontclass=\"'+ar[++i]+'\"');continue;}\ni=parseCmdLine(pf,i,ar);}}\nif(fnMark&&o3_function)o3_text=o3_function();\nif((pf=='o3_')&&o3_wrap){o3_width=0;\nvar tReg=/<.*\\n*>/ig;if(!tReg.test(o3_text))o3_text=o3_text.replace(/[ ]+/g,'&nbsp;');if(!tReg.test(o3_cap))o3_cap=o3_cap.replace(/[ ]+/g,'&nbsp;');}\nif((pf=='o3_')&&o3_sticky){if(!o3_close&&(o3_frame!=ol_frame))o3_close=ol_close;if(o3_mouseoff&&(o3_frame==ol_frame))opt_NOCLOSE(' ');}}\nfunction layerWrite(txt){txt+=\"\\n\";if(olNs4){var lyr=o3_frame.document.layers['overDiv'].document\nlyr.write(txt)\nlyr.close()\n}else if(typeof over.innerHTML!='undefined'){if(olIe5&&isMac)over.innerHTML='';over.innerHTML=txt;}else{range=o3_frame.document.createRange();range.setStartAfter(over);domfrag=range.createContextualFragment(txt);\nwhile(over.hasChildNodes()){over.removeChild(over.lastChild);}\nover.appendChild(domfrag);}}\nfunction showObject(obj){runHook(\"showObject\",FBEFORE);\nvar theObj=(olNs4?obj:obj.style);theObj.visibility='visible';\nrunHook(\"showObject\",FAFTER);}\nfunction hideObject(obj){runHook(\"hideObject\",FBEFORE);\nvar theObj=(olNs4?obj:obj.style);if(olNs6&&olShowId>0){clearTimeout(olShowId);olShowId=0;}\ntheObj.visibility='hidden';theObj.top=theObj.left=((olIe4&&!olOp)?0:-10000)+(!olNs4?'px':0);\nif(o3_timerid>0)clearTimeout(o3_timerid);if(o3_delayid>0)clearTimeout(o3_delayid);\no3_timerid=0;o3_delayid=0;self.status=\"\";\nif(obj.onmouseout||obj.onmouseover){if(olNs4)obj.releaseEvents(Event.MOUSEOUT||Event.MOUSEOVER);obj.onmouseout=obj.onmouseover=null;}\nrunHook(\"hideObject\",FAFTER);}\nfunction repositionTo(obj,xL,yL){var theObj=(olNs4?obj:obj.style);theObj.left=xL+(!olNs4?'px':0);theObj.top=yL+(!olNs4?'px':0);}\nfunction cursorOff(){var left=parseInt(over.style.left);var top=parseInt(over.style.top);var right=left+(over.offsetWidth>=parseInt(o3_width)?over.offsetWidth:parseInt(o3_width));var bottom=top+(over.offsetHeight>=o3_aboveheight?over.offsetHeight:o3_aboveheight);\nif(o3_x<left||o3_x>right||o3_y<top||o3_y>bottom)return true;\nreturn false;}\nfunction opt_FUNCTION(callme){o3_text=(callme?(typeof callme=='string'?(/.+\\(.*\\)/.test(callme)?eval(callme):callme):callme()):(o3_function?o3_function():'No Function'));\nreturn 0;}\nfunction opt_NOCLOSE(unused){if(!unused)o3_close=\"\";\nif(olNs4){over.captureEvents(Event.MOUSEOUT||Event.MOUSEOVER);over.onmouseover=function(){if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} }\nover.onmouseout=function(e){if(olHideDelay)hideDelay(olHideDelay);else cClick(e);}\n}else{over.onmouseover=function(){hoveringSwitch=true;if(o3_timerid>0){clearTimeout(o3_timerid);o3_timerid=0;} }}\nreturn 0;}\nfunction opt_MULTIPLEARGS(i,args,parameter){var k=i,re,pV,str='';\nfor(k=i;k<args.length;k++){if(typeof args[k]=='number'&&args[k]>pmStart)break;str+=args[k]+',';}\nif(str)str=str.substring(0,--str.length);\nk--;pV=(olNs4&&/cellpad/i.test(parameter))?str.split(',')[0]:str;eval(parameter+'=\"'+pV+'\"');\nreturn k;}\nfunction nbspCleanup(){if(o3_wrap){o3_text=o3_text.replace(/\\&nbsp;/g,' ');o3_cap=o3_cap.replace(/\\&nbsp;/g,' ');}}\nfunction escSglQuote(str){return str.toString().replace(/'/g,\"\\\\'\");}\nfunction OLonLoad_handler(e){var re=/\\w+\\(.*\\)[;\\s]+/g,olre=/overlib\\(|nd\\(|cClick\\(/,fn,l,i;\nif(!olLoaded)olLoaded=1;\nif(window.removeEventListener&&e.eventPhase==3)window.removeEventListener(\"load\",OLonLoad_handler,false);else if(window.detachEvent){window.detachEvent(\"onload\",OLonLoad_handler);var fN=document.body.getAttribute('onload');if(fN){fN=fN.toString().match(re);if(fN&&fN.length){for(i=0;i<fN.length;i++){if(/anonymous/.test(fN[i]))continue;while((l=fN[i].search(/\\)[;\\s]+/))!=-1){fn=fN[i].substring(0,l+1);fN[i]=fN[i].substring(l+2);if(olre.test(fn))eval(fn);}}}}}}\nfunction wrapStr(endWrap,fontSizeStr,whichString){var fontStr,fontColor,isClose=((whichString=='close')?1:0),hasDims=/[%\\-a-z]+$/.test(fontSizeStr);fontSizeStr=(olNs4)?(!hasDims?fontSizeStr:'1'):fontSizeStr;if(endWrap)return(hasDims&&!olNs4)?(isClose?'</span>':'</div>'):'</font>';else{fontStr='o3_'+whichString+'font';fontColor='o3_'+((whichString=='caption')? 'cap':whichString)+'color';return(hasDims&&!olNs4)?(isClose?'<span style=\"font-family: '+quoteMultiNameFonts(eval(fontStr))+';color: '+eval(fontColor)+';font-size: '+fontSizeStr+';\">':'<div style=\"font-family: '+quoteMultiNameFonts(eval(fontStr))+';color: '+eval(fontColor)+';font-size: '+fontSizeStr+';\">'):'<font face=\"'+eval(fontStr)+'\" color=\"'+eval(fontColor)+'\" size=\"'+(parseInt(fontSizeStr)>7?'7':fontSizeStr)+'\">';}}\nfunction quoteMultiNameFonts(theFont){var v,pM=theFont.split(',');for(var i=0;i<pM.length;i++){v=pM[i];v=v.replace(/^\\s+/,'').replace(/\\s+$/,'');if(/\\s/.test(v)&&!/['\"]/.test(v)){v=\"\\'\"+v+\"\\'\";pM[i]=v;}}\nreturn pM.join();}\nfunction isExclusive(args){return false;}\nfunction setCellPadStr(parameter){var Str='',j=0,ary=new Array(),top,bottom,left,right;\nStr+='padding: ';ary=parameter.replace(/\\s+/g,'').split(',');\nswitch(ary.length){case 2:\ntop=bottom=ary[j];left=right=ary[++j];break;case 3:\ntop=ary[j];left=right=ary[++j];bottom=ary[++j];break;case 4:\ntop=ary[j];right=ary[++j];bottom=ary[++j];left=ary[++j];break;}\nStr+=((ary.length==1)?ary[0]+'px;':top+'px '+right+'px '+bottom+'px '+left+'px;');\nreturn Str;}\nfunction hideDelay(time){if(time&&!o3_delay){if(o3_timerid>0)clearTimeout(o3_timerid);\no3_timerid=setTimeout(\"cClick()\",(o3_timeout=time));}}\nfunction horizontalPlacement(browserWidth,horizontalScrollAmount,widthFix){var placeX,iwidth=browserWidth,winoffset=horizontalScrollAmount;var parsedWidth=parseInt(o3_width);\nif(o3_fixx>-1||o3_relx!=null){\nplaceX=(o3_relx!=null?( o3_relx<0?winoffset+o3_relx+iwidth-parsedWidth-widthFix:winoffset+o3_relx):o3_fixx);}else{\nif(o3_hauto==1){if((o3_x-winoffset)>(iwidth/2)){o3_hpos=LEFT;}else{o3_hpos=RIGHT;}}\nif(o3_hpos==CENTER){placeX=o3_x+o3_offsetx-(parsedWidth/2);\nif(placeX<winoffset)placeX=winoffset;}\nif(o3_hpos==RIGHT){placeX=o3_x+o3_offsetx;\nif((placeX+parsedWidth)>(winoffset+iwidth-widthFix)){placeX=iwidth+winoffset-parsedWidth-widthFix;if(placeX<0)placeX=0;}}\nif(o3_hpos==LEFT){placeX=o3_x-o3_offsetx-parsedWidth;if(placeX<winoffset)placeX=winoffset;}\nif(o3_snapx>1){var snapping=placeX % o3_snapx;\nif(o3_hpos==LEFT){placeX=placeX-(o3_snapx+snapping);}else{\nplaceX=placeX+(o3_snapx-snapping);}\nif(placeX<winoffset)placeX=winoffset;}}\nreturn placeX;}\nfunction verticalPlacement(browserHeight,verticalScrollAmount){var placeY,iheight=browserHeight,scrolloffset=verticalScrollAmount;var parsedHeight=(o3_aboveheight?parseInt(o3_aboveheight):(olNs4?over.clip.height:over.offsetHeight));\nif(o3_fixy>-1||o3_rely!=null){\nplaceY=(o3_rely!=null?(o3_rely<0?scrolloffset+o3_rely+iheight-parsedHeight:scrolloffset+o3_rely):o3_fixy);}else{\nif(o3_vauto==1){if((o3_y-scrolloffset)>(iheight/2)&&o3_vpos==BELOW&&(o3_y+parsedHeight+o3_offsety-(scrolloffset+iheight)>0)){o3_vpos=ABOVE;}else if(o3_vpos==ABOVE&&(o3_y-(parsedHeight+o3_offsety)-scrolloffset<0)){o3_vpos=BELOW;}}\nif(o3_vpos==ABOVE){if(o3_aboveheight==0)o3_aboveheight=parsedHeight;\nplaceY=o3_y-(o3_aboveheight+o3_offsety);if(placeY<scrolloffset)placeY=scrolloffset;}else{\nplaceY=o3_y+o3_offsety;}\nif(o3_snapy>1){var snapping=placeY % o3_snapy;\nif(o3_aboveheight>0&&o3_vpos==ABOVE){placeY=placeY-(o3_snapy+snapping);}else{placeY=placeY+(o3_snapy-snapping);}\nif(placeY<scrolloffset)placeY=scrolloffset;}}\nreturn placeY;}\nfunction checkPositionFlags(){if(olHautoFlag)olHautoFlag=o3_hauto=0;if(olVautoFlag)olVautoFlag=o3_vauto=0;return true;}\nfunction windowWidth(){var w;if(o3_frame.innerWidth)w=o3_frame.innerWidth;else if(eval('o3_frame.'+docRoot)&&eval(\"typeof o3_frame.\"+docRoot+\".clientWidth=='number'\")&&eval('o3_frame.'+docRoot+'.clientWidth'))\nw=eval('o3_frame.'+docRoot+'.clientWidth');return w;}\nfunction createDivContainer(id,frm,zValue){id=(id||'overDiv'),frm=(frm||o3_frame),zValue=(zValue||1000);var objRef,divContainer=layerReference(id);\nif(divContainer==null){if(olNs4){divContainer=frm.document.layers[id]=new Layer(window.innerWidth,frm);objRef=divContainer;}else{var body=(olIe4?frm.document.all.tags('BODY')[0]:frm.document.getElementsByTagName(\"BODY\")[0]);if(olIe4&&!document.getElementById){body.insertAdjacentHTML(\"beforeEnd\",'<div id=\"'+id+'\"></div>');divContainer=layerReference(id);}else{divContainer=frm.document.createElement(\"DIV\");divContainer.id=id;body.appendChild(divContainer);}\nobjRef=divContainer.style;}\nobjRef.position='absolute';objRef.visibility='hidden';objRef.zIndex=zValue;if(olIe4&&!olOp)objRef.left=objRef.top='0px';else objRef.left=objRef.top=-10000+(!olNs4?'px':0);}\nreturn divContainer;}\nfunction layerReference(id){return(olNs4?o3_frame.document.layers[id]:(document.all?o3_frame.document.all[id]:o3_frame.document.getElementById(id)));}\nfunction isFunction(fnRef){var rtn=true;\nif(typeof fnRef=='object'){for(var i=0;i<fnRef.length;i++){if(typeof fnRef[i]=='function')continue;rtn=false;break;}\n}else if(typeof fnRef!='function'){rtn=false;}\nreturn rtn;}\nfunction argToString(array,strtInd,argName){var jS=strtInd,aS='',ar=array;argName=(argName?argName:'ar');\nif(ar.length>jS){for(var k=jS;k<ar.length;k++)aS+=argName+'['+k+'], ';aS=aS.substring(0,aS.length-2);}\nreturn aS;}\nfunction reOrder(hookPt,fnRef,order){var newPt=new Array(),match,i,j;\nif(!order||typeof order=='undefined'||typeof order=='number')return hookPt;\nif(typeof order=='function'){if(typeof fnRef=='object'){newPt=newPt.concat(fnRef);}else{newPt[newPt.length++]=fnRef;}\nfor(i=0;i<hookPt.length;i++){match=false;if(typeof fnRef=='function'&&hookPt[i]==fnRef){continue;}else{for(j=0;j<fnRef.length;j++)if(hookPt[i]==fnRef[j]){match=true;break;}}\nif(!match)newPt[newPt.length++]=hookPt[i];}\nnewPt[newPt.length++]=order;\n}else if(typeof order=='object'){if(typeof fnRef=='object'){newPt=newPt.concat(fnRef);}else{newPt[newPt.length++]=fnRef;}\nfor(j=0;j<hookPt.length;j++){match=false;if(typeof fnRef=='function'&&hookPt[j]==fnRef){continue;}else{for(i=0;i<fnRef.length;i++)if(hookPt[j]==fnRef[i]){match=true;break;}}\nif(!match)newPt[newPt.length++]=hookPt[j];}\nfor(i=0;i<newPt.length;i++)hookPt[i]=newPt[i];newPt.length=0;\nfor(j=0;j<hookPt.length;j++){match=false;for(i=0;i<order.length;i++){if(hookPt[j]==order[i]){match=true;break;}}\nif(!match)newPt[newPt.length++]=hookPt[j];}\nnewPt=newPt.concat(order);}\nhookPt=newPt;\nreturn hookPt;}\nfunction setRunTimeVariables(){if(typeof runTime!='undefined'&&runTime.length){for(var k=0;k<runTime.length;k++){runTime[k]();}}}\nfunction parseCmdLine(pf,i,args){if(typeof cmdLine!='undefined'&&cmdLine.length){for(var k=0;k<cmdLine.length;k++){var j=cmdLine[k](pf,i,args);if(j >-1){i=j;break;}}}\nreturn i;}\nfunction postParseChecks(pf,args){if(typeof postParse!='undefined'&&postParse.length){for(var k=0;k<postParse.length;k++){if(postParse[k](pf,args))continue;return false;}}\nreturn true;}\nfunction registerCommands(cmdStr){if(typeof cmdStr!='string')return;\nvar pM=cmdStr.split(',');pms=pms.concat(pM);\nfor(var i=0;i< pM.length;i++){eval(pM[i].toUpperCase()+'='+pmCount++);}}\nfunction registerNoParameterCommands(cmdStr){if(!cmdStr&&typeof cmdStr!='string')return;pmt=(!pmt)?cmdStr:pmt+','+cmdStr;}\nfunction registerHook(fnHookTo,fnRef,hookType,optPm){var hookPt,last=typeof optPm;\nif(fnHookTo=='plgIn'||fnHookTo=='postParse')return;if(typeof hookPts[fnHookTo]=='undefined')hookPts[fnHookTo]=new FunctionReference();\nhookPt=hookPts[fnHookTo];\nif(hookType!=null){if(hookType==FREPLACE){hookPt.ovload=fnRef;if(fnHookTo.indexOf('ol_content_')>-1)hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef;\n}else if(hookType==FBEFORE||hookType==FAFTER){var hookPt=(hookType==1?hookPt.before:hookPt.after);\nif(typeof fnRef=='object'){hookPt=hookPt.concat(fnRef);}else{hookPt[hookPt.length++]=fnRef;}\nif(optPm)hookPt=reOrder(hookPt,fnRef,optPm);\n}else if(hookType==FALTERNATE){if(last=='number')hookPt.alt[pms[optPm-1-pmStart]]=fnRef;}else if(hookType==FCHAIN){hookPt=hookPt.chain;if(typeof fnRef=='object')hookPt=hookPt.concat(fnRef);else hookPt[hookPt.length++]=fnRef;}\nreturn;}}\nfunction registerRunTimeFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){runTime=runTime.concat(fn);}else{runTime[runTime.length++]=fn;}}}\nfunction registerCmdLineFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){cmdLine=cmdLine.concat(fn);}else{cmdLine[cmdLine.length++]=fn;}}}\nfunction registerPostParseFunction(fn){if(isFunction(fn)){if(typeof fn=='object'){postParse=postParse.concat(fn);}else{postParse[postParse.length++]=fn;}}}\nfunction runHook(fnHookTo,hookType){var l=hookPts[fnHookTo],k,rtnVal=null,optPm,arS,ar=runHook.arguments;\nif(hookType==FREPLACE){arS=argToString(ar,2);\nif(typeof l=='undefined'||!(l=l.ovload))rtnVal=eval(fnHookTo+'('+arS+')');else rtnVal=eval('l('+arS+')');\n}else if(hookType==FBEFORE||hookType==FAFTER){if(typeof l!='undefined'){l=(hookType==1?l.before:l.after);\nif(l.length){arS=argToString(ar,2);for(var k=0;k<l.length;k++)eval('l[k]('+arS+')');}}\n}else if(hookType==FALTERNATE){optPm=ar[2];arS=argToString(ar,3);\nif(typeof l=='undefined'||(l=l.alt[pms[optPm-1-pmStart]])=='undefined'){rtnVal=eval(fnHookTo+'('+arS+')');}else{rtnVal=eval('l('+arS+')');}\n}else if(hookType==FCHAIN){arS=argToString(ar,2);l=l.chain;\nfor(k=l.length;k>0;k--)if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0))break;}\nreturn rtnVal;}\nfunction FunctionReference(){this.ovload=null;this.before=new Array();this.after=new Array();this.alt=new Array();this.chain=new Array();}\nfunction Info(version,prerelease){this.version=version;this.prerelease=prerelease;\nthis.simpleversion=Math.round(this.version*100);this.major=parseInt(this.simpleversion/100);this.minor=parseInt(this.simpleversion/10)-this.major * 10;this.revision=parseInt(this.simpleversion)-this.major * 100-this.minor * 10;this.meets=meets;}\nfunction meets(reqdVersion){return(!reqdVersion)?false:this.simpleversion>=Math.round(100*parseFloat(reqdVersion));}\nregisterHook(\"ol_content_simple\",ol_content_simple,FALTERNATE,CSSOFF);registerHook(\"ol_content_caption\",ol_content_caption,FALTERNATE,CSSOFF);registerHook(\"ol_content_background\",ol_content_background,FALTERNATE,CSSOFF);registerHook(\"ol_content_simple\",ol_content_simple,FALTERNATE,CSSCLASS);registerHook(\"ol_content_caption\",ol_content_caption,FALTERNATE,CSSCLASS);registerHook(\"ol_content_background\",ol_content_background,FALTERNATE,CSSCLASS);registerPostParseFunction(checkPositionFlags);registerHook(\"hideObject\",nbspCleanup,FAFTER);registerHook(\"horizontalPlacement\",horizontalPlacement,FCHAIN);registerHook(\"verticalPlacement\",verticalPlacement,FCHAIN);if(olNs4||(olIe5&&isMac)||olKq)olLoaded=1;registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');\nvar olCheckMouseCapture=true;if((olNs4||olNs6||olIe4)){olMouseCapture();}else{overlib=no_overlib;nd=no_overlib;ver3fix=true;}\n"
  },
  {
    "path": "tools/server/admin/scripts/index.html",
    "content": ""
  },
  {
    "path": "tools/server/admin/scripts/restart_sequence.php",
    "content": "<?php\n\n\tset_time_limit(900); // should not exceed 15 minutes\n\n\tdefine('NELTOOL_NO_USER_NEEDED',    true);\n\n\trequire_once('../common.php');\n\trequire_once('../functions_tool_main.php');\n\n\t$params = array();\n\n\treset($argv);\n\tforeach($argv as $sValue)\n\t{\n\t\tif (strpos($sValue, '=') !== false)\n\t\t{\n\t\t\t$aData = explode('=', $sValue);\n\t\t\t$params[$aData[0]] = $aData[1];\n\t\t}\n\t}\n\n\tif (isset($params['restart_id']) && isset($params['services']))\n\t{\n\t\twhile (true)\n\t\t{\n\t\t\tprint_r($params);\n\t\t\tsleep(10);\n\t\t}\n\t}\n\n?>"
  },
  {
    "path": "tools/server/admin/scripts/run_script.sh",
    "content": "#!/bin/bash\n\n# we might want to add some security here, in order to check the parameters\n\ncd /home/atrium-admin/public_html/scripts\nnohup /usr/bin/php4 $* >/dev/null &\n"
  },
  {
    "path": "tools/server/admin/smarty/Config_File.class.php",
    "content": "<?php\n\n/**\n * Config_File class.\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * @link http://smarty.php.net/\n * @version 2.6.9\n * @copyright Copyright: 2001-2005 New Digital Group, Inc.\n * @author Andrei Zmievski <andrei@php.net>\n * @access public\n * @package Smarty\n */\n\n/* $Id: Config_File.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */\n\n/**\n * Config file reading class\n * @package Smarty\n */\nclass Config_File {\n    /**#@+\n     * Options\n     * @var boolean\n     */\n    /**\n     * Controls whether variables with the same name overwrite each other.\n     */\n    var $overwrite        =    true;\n\n    /**\n     * Controls whether config values of on/true/yes and off/false/no get\n     * converted to boolean values automatically.\n     */\n    var $booleanize        =    true;\n\n    /**\n     * Controls whether hidden config sections/vars are read from the file.\n     */\n    var $read_hidden     =    true;\n\n    /**\n     * Controls whether or not to fix mac or dos formatted newlines.\n     * If set to true, \\r or \\r\\n will be changed to \\n.\n     */\n    var $fix_newlines =    true;\n    /**#@-*/\n\n    /** @access private */\n    var $_config_path    = \"\";\n    var $_config_data    = array();\n    /**#@-*/\n\n    /**\n     * Constructs a new config file class.\n     *\n     * @param string $config_path (optional) path to the config files\n     */\n    function Config_File($config_path = NULL)\n    {\n        if (isset($config_path))\n            $this->set_path($config_path);\n    }\n\n\n    /**\n     * Set the path where configuration files can be found.\n     *\n     * @param string $config_path path to the config files\n     */\n    function set_path($config_path)\n    {\n        if (!empty($config_path)) {\n            if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) {\n                $this->_trigger_error_msg(\"Bad config file path '$config_path'\");\n                return;\n            }\n            if(substr($config_path, -1) != DIRECTORY_SEPARATOR) {\n                $config_path .= DIRECTORY_SEPARATOR;\n            }\n\n            $this->_config_path = $config_path;\n        }\n    }\n\n\n    /**\n     * Retrieves config info based on the file, section, and variable name.\n     *\n     * @param string $file_name config file to get info for\n     * @param string $section_name (optional) section to get info for\n     * @param string $var_name (optional) variable to get info for\n     * @return string|array a value or array of values\n     */\n    function &get($file_name, $section_name = NULL, $var_name = NULL)\n    {\n        if (empty($file_name)) {\n            $this->_trigger_error_msg('Empty config file name');\n            return;\n        } else {\n            $file_name = $this->_config_path . $file_name;\n            if (!isset($this->_config_data[$file_name]))\n                $this->load_file($file_name, false);\n        }\n\n        if (!empty($var_name)) {\n            if (empty($section_name)) {\n                return $this->_config_data[$file_name][\"vars\"][$var_name];\n            } else {\n                if(isset($this->_config_data[$file_name][\"sections\"][$section_name][\"vars\"][$var_name]))\n                    return $this->_config_data[$file_name][\"sections\"][$section_name][\"vars\"][$var_name];\n                else\n                    return array();\n            }\n        } else {\n            if (empty($section_name)) {\n                return (array)$this->_config_data[$file_name][\"vars\"];\n            } else {\n                if(isset($this->_config_data[$file_name][\"sections\"][$section_name][\"vars\"]))\n                    return (array)$this->_config_data[$file_name][\"sections\"][$section_name][\"vars\"];\n                else\n                    return array();\n            }\n        }\n    }\n\n\n    /**\n     * Retrieves config info based on the key.\n     *\n     * @param $file_name string config key (filename/section/var)\n     * @return string|array same as get()\n     * @uses get() retrieves information from config file and returns it\n     */\n    function &get_key($config_key)\n    {\n        list($file_name, $section_name, $var_name) = explode('/', $config_key, 3);\n        $result = &$this->get($file_name, $section_name, $var_name);\n        return $result;\n    }\n\n    /**\n     * Get all loaded config file names.\n     *\n     * @return array an array of loaded config file names\n     */\n    function get_file_names()\n    {\n        return array_keys($this->_config_data);\n    }\n\n\n    /**\n     * Get all section names from a loaded file.\n     *\n     * @param string $file_name config file to get section names from\n     * @return array an array of section names from the specified file\n     */\n    function get_section_names($file_name)\n    {\n        $file_name = $this->_config_path . $file_name;\n        if (!isset($this->_config_data[$file_name])) {\n            $this->_trigger_error_msg(\"Unknown config file '$file_name'\");\n            return;\n        }\n\n        return array_keys($this->_config_data[$file_name][\"sections\"]);\n    }\n\n\n    /**\n     * Get all global or section variable names.\n     *\n     * @param string $file_name config file to get info for\n     * @param string $section_name (optional) section to get info for\n     * @return array an array of variables names from the specified file/section\n     */\n    function get_var_names($file_name, $section = NULL)\n    {\n        if (empty($file_name)) {\n            $this->_trigger_error_msg('Empty config file name');\n            return;\n        } else if (!isset($this->_config_data[$file_name])) {\n            $this->_trigger_error_msg(\"Unknown config file '$file_name'\");\n            return;\n        }\n\n        if (empty($section))\n            return array_keys($this->_config_data[$file_name][\"vars\"]);\n        else\n            return array_keys($this->_config_data[$file_name][\"sections\"][$section][\"vars\"]);\n    }\n\n\n    /**\n     * Clear loaded config data for a certain file or all files.\n     *\n     * @param string $file_name file to clear config data for\n     */\n    function clear($file_name = NULL)\n    {\n        if ($file_name === NULL)\n            $this->_config_data = array();\n        else if (isset($this->_config_data[$file_name]))\n            $this->_config_data[$file_name] = array();\n    }\n\n\n    /**\n     * Load a configuration file manually.\n     *\n     * @param string $file_name file name to load\n     * @param boolean $prepend_path whether current config path should be\n     *                              prepended to the filename\n     */\n    function load_file($file_name, $prepend_path = true)\n    {\n        if ($prepend_path && $this->_config_path != \"\")\n            $config_file = $this->_config_path . $file_name;\n        else\n            $config_file = $file_name;\n\n        ini_set('track_errors', true);\n        $fp = @fopen($config_file, \"r\");\n        if (!is_resource($fp)) {\n            $this->_trigger_error_msg(\"Could not open config file '$config_file'\");\n            return false;\n        }\n\n        $contents = ($size = filesize($config_file)) ? fread($fp, $size) : '';\n        fclose($fp);\n\n        $this->_config_data[$config_file] = $this->parse_contents($contents);\n        return true;\n    }\n\n    /**\n     * Store the contents of a file manually.\n     *\n     * @param string $config_file file name of the related contents\n     * @param string $contents the file-contents to parse\n     */\n    function set_file_contents($config_file, $contents)\n    {\n        $this->_config_data[$config_file] = $this->parse_contents($contents);\n        return true;\n    }\n\n    /**\n     * parse the source of a configuration file manually.\n     *\n     * @param string $contents the file-contents to parse\n     */\n    function parse_contents($contents)\n    {\n        if($this->fix_newlines) {\n            // fix mac/dos formatted newlines\n            $contents = preg_replace('!\\r\\n?!', \"\\n\", $contents);\n        }\n\n        $config_data = array();\n        $config_data['sections'] = array();\n        $config_data['vars'] = array();\n\n        /* reference to fill with data */\n        $vars =& $config_data['vars'];\n\n        /* parse file line by line */\n        preg_match_all('!^.*\\r?\\n?!m', $contents, $match);\n        $lines = $match[0];\n        for ($i=0, $count=count($lines); $i<$count; $i++) {\n            $line = $lines[$i];\n            if (empty($line)) continue;\n\n            if ( $line{0} == '[' && preg_match('!^\\[(.*?)\\]!', $line, $match) ) {\n                /* section found */\n                if ($match[1]{0} == '.') {\n                    /* hidden section */\n                    if ($this->read_hidden) {\n                        $section_name = substr($match[1], 1);\n                    } else {\n                        /* break reference to $vars to ignore hidden section */\n                        unset($vars);\n                        $vars = array();\n                        continue;\n                    }\n                } else {                    \n                    $section_name = $match[1];\n                }\n                if (!isset($config_data['sections'][$section_name]))\n                    $config_data['sections'][$section_name] = array('vars' => array());\n                $vars =& $config_data['sections'][$section_name]['vars'];\n                continue;\n            }\n\n            if (preg_match('/^\\s*(\\.?\\w+)\\s*=\\s*(.*)/s', $line, $match)) {\n                /* variable found */\n                $var_name = rtrim($match[1]);\n                if (strpos($match[2], '\"\"\"') === 0) {\n                    /* handle multiline-value */\n                    $lines[$i] = substr($match[2], 3);\n                    $var_value = '';\n                    while ($i<$count) {\n                        if (($pos = strpos($lines[$i], '\"\"\"')) === false) {\n                            $var_value .= $lines[$i++];\n                        } else {\n                            /* end of multiline-value */\n                            $var_value .= substr($lines[$i], 0, $pos);\n                            break;\n                        }\n                    }\n                    $booleanize = false;\n\n                } else {\n                    /* handle simple value */\n                    $var_value = preg_replace('/^([\\'\"])(.*)\\1$/', '\\2', rtrim($match[2]));\n                    $booleanize = $this->booleanize;\n\n                }\n                $this->_set_config_var($vars, $var_name, $var_value, $booleanize);\n            }\n            /* else unparsable line / means it is a comment / means ignore it */\n        }\n        return $config_data;\n    }\n\n    /**#@+ @access private */\n    /**\n     * @param array &$container\n     * @param string $var_name\n     * @param mixed $var_value\n     * @param boolean $booleanize determines whether $var_value is converted to\n     *                            to true/false\n     */\n    function _set_config_var(&$container, $var_name, $var_value, $booleanize)\n    {\n        if ($var_name{0} == '.') {\n            if (!$this->read_hidden)\n                return;\n            else\n                $var_name = substr($var_name, 1);\n        }\n\n        if (!preg_match(\"/^[a-zA-Z_]\\w*$/\", $var_name)) {\n            $this->_trigger_error_msg(\"Bad variable name '$var_name'\");\n            return;\n        }\n\n        if ($booleanize) {\n            if (preg_match(\"/^(on|true|yes)$/i\", $var_value))\n                $var_value = true;\n            else if (preg_match(\"/^(off|false|no)$/i\", $var_value))\n                $var_value = false;\n        }\n\n        if (!isset($container[$var_name]) || $this->overwrite)\n            $container[$var_name] = $var_value;\n        else {\n            settype($container[$var_name], 'array');\n            $container[$var_name][] = $var_value;\n        }\n    }\n\n    /**\n     * @uses trigger_error() creates a PHP warning/error\n     * @param string $error_msg\n     * @param integer $error_type one of\n     */\n    function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING)\n    {\n        trigger_error(\"Config_File error: $error_msg\", $error_type);\n    }\n    /**#@-*/\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/Smarty.class.php",
    "content": "<?php\n\n/**\n * Project:     Smarty: the PHP compiling template engine\n * File:        Smarty.class.php\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * For questions, help, comments, discussion, etc., please join the\n * Smarty mailing list. Send a blank e-mail to\n * smarty-general-subscribe@lists.php.net\n *\n * @link http://smarty.php.net/\n * @copyright 2001-2005 New Digital Group, Inc.\n * @author Monte Ohrt <monte at ohrt dot com>\n * @author Andrei Zmievski <andrei@php.net>\n * @package Smarty\n * @version 2.6.9\n */\n\n/* $Id: Smarty.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */\n\n/**\n * DIR_SEP isn't used anymore, but third party apps might\n */\nif(!defined('DIR_SEP')) {\n    define('DIR_SEP', DIRECTORY_SEPARATOR);\n}\n\n/**\n * set SMARTY_DIR to absolute path to Smarty library files.\n * if not defined, include_path will be used. Sets SMARTY_DIR only if user\n * application has not already defined it.\n */\n\nif (!defined('SMARTY_DIR')) {\n    define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR);\n}\n\nif (!defined('SMARTY_CORE_DIR')) {\n    define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR);\n}\n\ndefine('SMARTY_PHP_PASSTHRU',   0);\ndefine('SMARTY_PHP_QUOTE',      1);\ndefine('SMARTY_PHP_REMOVE',     2);\ndefine('SMARTY_PHP_ALLOW',      3);\n\n/**\n * @package Smarty\n */\nclass Smarty\n{\n    /**#@+\n     * Smarty Configuration Section\n     */\n\n    /**\n     * The name of the directory where templates are located.\n     *\n     * @var string\n     */\n    var $template_dir    =  'templates';\n\n    /**\n     * The directory where compiled templates are located.\n     *\n     * @var string\n     */\n    var $compile_dir     =  'templates_c';\n\n    /**\n     * The directory where config files are located.\n     *\n     * @var string\n     */\n    var $config_dir      =  'configs';\n\n    /**\n     * An array of directories searched for plugins.\n     *\n     * @var array\n     */\n    var $plugins_dir     =  array('plugins');\n\n    /**\n     * If debugging is enabled, a debug console window will display\n     * when the page loads (make sure your browser allows unrequested\n     * popup windows)\n     *\n     * @var boolean\n     */\n    var $debugging       =  false;\n\n    /**\n     * When set, smarty does uses this value as error_reporting-level.\n     *\n     * @var boolean\n     */\n    var $error_reporting  =  null;\n\n    /**\n     * This is the path to the debug console template. If not set,\n     * the default one will be used.\n     *\n     * @var string\n     */\n    var $debug_tpl       =  '';\n\n    /**\n     * This determines if debugging is enable-able from the browser.\n     * <ul>\n     *  <li>NONE => no debugging control allowed</li>\n     *  <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li>\n     * </ul>\n     * @link http://www.foo.dom/index.php?SMARTY_DEBUG\n     * @var string\n     */\n    var $debugging_ctrl  =  'NONE';\n\n    /**\n     * This tells Smarty whether to check for recompiling or not. Recompiling\n     * does not need to happen unless a template or config file is changed.\n     * Typically you enable this during development, and disable for\n     * production.\n     *\n     * @var boolean\n     */\n    var $compile_check   =  true;\n\n    /**\n     * This forces templates to compile every time. Useful for development\n     * or debugging.\n     *\n     * @var boolean\n     */\n    var $force_compile   =  false;\n\n    /**\n     * This enables template caching.\n     * <ul>\n     *  <li>0 = no caching</li>\n     *  <li>1 = use class cache_lifetime value</li>\n     *  <li>2 = use cache_lifetime in cache file</li>\n     * </ul>\n     * @var integer\n     */\n    var $caching         =  0;\n\n    /**\n     * The name of the directory for cache files.\n     *\n     * @var string\n     */\n    var $cache_dir       =  'cache';\n\n    /**\n     * This is the number of seconds cached content will persist.\n     * <ul>\n     *  <li>0 = always regenerate cache</li>\n     *  <li>-1 = never expires</li>\n     * </ul>\n     *\n     * @var integer\n     */\n    var $cache_lifetime  =  3600;\n\n    /**\n     * Only used when $caching is enabled. If true, then If-Modified-Since headers\n     * are respected with cached content, and appropriate HTTP headers are sent.\n     * This way repeated hits to a cached page do not send the entire page to the\n     * client every time.\n     *\n     * @var boolean\n     */\n    var $cache_modified_check = false;\n\n    /**\n     * This determines how Smarty handles \"<?php ... ?>\" tags in templates.\n     * possible values:\n     * <ul>\n     *  <li>SMARTY_PHP_PASSTHRU -> print tags as plain text</li>\n     *  <li>SMARTY_PHP_QUOTE    -> escape tags as entities</li>\n     *  <li>SMARTY_PHP_REMOVE   -> remove php tags</li>\n     *  <li>SMARTY_PHP_ALLOW    -> execute php tags</li>\n     * </ul>\n     *\n     * @var integer\n     */\n    var $php_handling    =  SMARTY_PHP_PASSTHRU;\n\n    /**\n     * This enables template security. When enabled, many things are restricted\n     * in the templates that normally would go unchecked. This is useful when\n     * untrusted parties are editing templates and you want a reasonable level\n     * of security. (no direct execution of PHP in templates for example)\n     *\n     * @var boolean\n     */\n    var $security       =   false;\n\n    /**\n     * This is the list of template directories that are considered secure. This\n     * is used only if {@link $security} is enabled. One directory per array\n     * element.  {@link $template_dir} is in this list implicitly.\n     *\n     * @var array\n     */\n    var $secure_dir     =   array();\n\n    /**\n     * These are the security settings for Smarty. They are used only when\n     * {@link $security} is enabled.\n     *\n     * @var array\n     */\n    var $security_settings  = array(\n                                    'PHP_HANDLING'    => false,\n                                    'IF_FUNCS'        => array('array', 'list',\n                                                               'isset', 'empty',\n                                                               'count', 'sizeof',\n                                                               'in_array', 'is_array',\n                                                               'true', 'false', 'null'),\n                                    'INCLUDE_ANY'     => false,\n                                    'PHP_TAGS'        => false,\n                                    'MODIFIER_FUNCS'  => array('count'),\n                                    'ALLOW_CONSTANTS'  => false\n                                   );\n\n    /**\n     * This is an array of directories where trusted php scripts reside.\n     * {@link $security} is disabled during their inclusion/execution.\n     *\n     * @var array\n     */\n    var $trusted_dir        = array();\n\n    /**\n     * The left delimiter used for the template tags.\n     *\n     * @var string\n     */\n    var $left_delimiter  =  '{';\n\n    /**\n     * The right delimiter used for the template tags.\n     *\n     * @var string\n     */\n    var $right_delimiter =  '}';\n\n    /**\n     * The order in which request variables are registered, similar to\n     * variables_order in php.ini E = Environment, G = GET, P = POST,\n     * C = Cookies, S = Server\n     *\n     * @var string\n     */\n    var $request_vars_order    = 'EGPCS';\n\n    /**\n     * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false)\n     * are uses as request-vars or $_*[]-vars. note: if\n     * request_use_auto_globals is true, then $request_vars_order has\n     * no effect, but the php-ini-value \"gpc_order\"\n     *\n     * @var boolean\n     */\n    var $request_use_auto_globals      = true;\n\n    /**\n     * Set this if you want different sets of compiled files for the same\n     * templates. This is useful for things like different languages.\n     * Instead of creating separate sets of templates per language, you\n     * set different compile_ids like 'en' and 'de'.\n     *\n     * @var string\n     */\n    var $compile_id            = null;\n\n    /**\n     * This tells Smarty whether or not to use sub dirs in the cache/ and\n     * templates_c/ directories. sub directories better organized, but\n     * may not work well with PHP safe mode enabled.\n     *\n     * @var boolean\n     *\n     */\n    var $use_sub_dirs          = false;\n\n    /**\n     * This is a list of the modifiers to apply to all template variables.\n     * Put each modifier in a separate array element in the order you want\n     * them applied. example: <code>array('escape:\"htmlall\"');</code>\n     *\n     * @var array\n     */\n    var $default_modifiers        = array();\n\n    /**\n     * This is the resource type to be used when not specified\n     * at the beginning of the resource path. examples:\n     * $smarty->display('file:index.tpl');\n     * $smarty->display('db:index.tpl');\n     * $smarty->display('index.tpl'); // will use default resource type\n     * {include file=\"file:index.tpl\"}\n     * {include file=\"db:index.tpl\"}\n     * {include file=\"index.tpl\"} {* will use default resource type *}\n     *\n     * @var array\n     */\n    var $default_resource_type    = 'file';\n\n    /**\n     * The function used for cache file handling. If not set, built-in caching is used.\n     *\n     * @var null|string function name\n     */\n    var $cache_handler_func   = null;\n\n    /**\n     * This indicates which filters are automatically loaded into Smarty.\n     *\n     * @var array array of filter names\n     */\n    var $autoload_filters = array();\n\n    /**#@+\n     * @var boolean\n     */\n    /**\n     * This tells if config file vars of the same name overwrite each other or not.\n     * if disabled, same name variables are accumulated in an array.\n     */\n    var $config_overwrite = true;\n\n    /**\n     * This tells whether or not to automatically booleanize config file variables.\n     * If enabled, then the strings \"on\", \"true\", and \"yes\" are treated as boolean\n     * true, and \"off\", \"false\" and \"no\" are treated as boolean false.\n     */\n    var $config_booleanize = true;\n\n    /**\n     * This tells whether hidden sections [.foobar] are readable from the\n     * tempalates or not. Normally you would never allow this since that is\n     * the point behind hidden sections: the application can access them, but\n     * the templates cannot.\n     */\n    var $config_read_hidden = false;\n\n    /**\n     * This tells whether or not automatically fix newlines in config files.\n     * It basically converts \\r (mac) or \\r\\n (dos) to \\n\n     */\n    var $config_fix_newlines = true;\n    /**#@-*/\n\n    /**\n     * If a template cannot be found, this PHP function will be executed.\n     * Useful for creating templates on-the-fly or other special action.\n     *\n     * @var string function name\n     */\n    var $default_template_handler_func = '';\n\n    /**\n     * The file that contains the compiler class. This can a full\n     * pathname, or relative to the php_include path.\n     *\n     * @var string\n     */\n    var $compiler_file        =    'Smarty_Compiler.class.php';\n\n    /**\n     * The class used for compiling templates.\n     *\n     * @var string\n     */\n    var $compiler_class        =   'Smarty_Compiler';\n\n    /**\n     * The class used to load config vars.\n     *\n     * @var string\n     */\n    var $config_class          =   'Config_File';\n\n/**#@+\n * END Smarty Configuration Section\n * There should be no need to touch anything below this line.\n * @access private\n */\n    /**\n     * where assigned template vars are kept\n     *\n     * @var array\n     */\n    var $_tpl_vars             = array();\n\n    /**\n     * stores run-time $smarty.* vars\n     *\n     * @var null|array\n     */\n    var $_smarty_vars          = null;\n\n    /**\n     * keeps track of sections\n     *\n     * @var array\n     */\n    var $_sections             = array();\n\n    /**\n     * keeps track of foreach blocks\n     *\n     * @var array\n     */\n    var $_foreach              = array();\n\n    /**\n     * keeps track of tag hierarchy\n     *\n     * @var array\n     */\n    var $_tag_stack            = array();\n\n    /**\n     * configuration object\n     *\n     * @var Config_file\n     */\n    var $_conf_obj             = null;\n\n    /**\n     * loaded configuration settings\n     *\n     * @var array\n     */\n    var $_config               = array(array('vars'  => array(), 'files' => array()));\n\n    /**\n     * md5 checksum of the string 'Smarty'\n     *\n     * @var string\n     */\n    var $_smarty_md5           = 'f8d698aea36fcbead2b9d5359ffca76f';\n\n    /**\n     * Smarty version number\n     *\n     * @var string\n     */\n    var $_version              = '2.6.9';\n\n    /**\n     * current template inclusion depth\n     *\n     * @var integer\n     */\n    var $_inclusion_depth      = 0;\n\n    /**\n     * for different compiled templates\n     *\n     * @var string\n     */\n    var $_compile_id           = null;\n\n    /**\n     * text in URL to enable debug mode\n     *\n     * @var string\n     */\n    var $_smarty_debug_id      = 'SMARTY_DEBUG';\n\n    /**\n     * debugging information for debug console\n     *\n     * @var array\n     */\n    var $_smarty_debug_info    = array();\n\n    /**\n     * info that makes up a cache file\n     *\n     * @var array\n     */\n    var $_cache_info           = array();\n\n    /**\n     * default file permissions\n     *\n     * @var integer\n     */\n    var $_file_perms           = 0644;\n\n    /**\n     * default dir permissions\n     *\n     * @var integer\n     */\n    var $_dir_perms               = 0771;\n\n    /**\n     * registered objects\n     *\n     * @var array\n     */\n    var $_reg_objects           = array();\n\n    /**\n     * table keeping track of plugins\n     *\n     * @var array\n     */\n    var $_plugins              = array(\n                                       'modifier'      => array(),\n                                       'function'      => array(),\n                                       'block'         => array(),\n                                       'compiler'      => array(),\n                                       'prefilter'     => array(),\n                                       'postfilter'    => array(),\n                                       'outputfilter'  => array(),\n                                       'resource'      => array(),\n                                       'insert'        => array());\n\n\n    /**\n     * cache serials\n     *\n     * @var array\n     */\n    var $_cache_serials = array();\n\n    /**\n     * name of optional cache include file\n     *\n     * @var string\n     */\n    var $_cache_include = null;\n\n    /**\n     * indicate if the current code is used in a compiled\n     * include\n     *\n     * @var string\n     */\n    var $_cache_including = false;\n\n    /**#@-*/\n    /**\n     * The class constructor.\n     */\n    function Smarty()\n    {\n      $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME']\n                    : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']);\n    }\n\n    /**\n     * assigns values to template variables\n     *\n     * @param array|string $tpl_var the template variable name(s)\n     * @param mixed $value the value to assign\n     */\n    function assign($tpl_var, $value = null)\n    {\n        if (is_array($tpl_var)){\n            foreach ($tpl_var as $key => $val) {\n                if ($key != '') {\n                    $this->_tpl_vars[$key] = $val;\n                }\n            }\n        } else {\n            if ($tpl_var != '')\n                $this->_tpl_vars[$tpl_var] = $value;\n        }\n    }\n\n    /**\n     * assigns values to template variables by reference\n     *\n     * @param string $tpl_var the template variable name\n     * @param mixed $value the referenced value to assign\n     */\n    function assign_by_ref($tpl_var, &$value)\n    {\n        if ($tpl_var != '')\n            $this->_tpl_vars[$tpl_var] = &$value;\n    }\n\n    /**\n     * appends values to template variables\n     *\n     * @param array|string $tpl_var the template variable name(s)\n     * @param mixed $value the value to append\n     */\n    function append($tpl_var, $value=null, $merge=false)\n    {\n        if (is_array($tpl_var)) {\n            // $tpl_var is an array, ignore $value\n            foreach ($tpl_var as $_key => $_val) {\n                if ($_key != '') {\n                    if(!@is_array($this->_tpl_vars[$_key])) {\n                        settype($this->_tpl_vars[$_key],'array');\n                    }\n                    if($merge && is_array($_val)) {\n                        foreach($_val as $_mkey => $_mval) {\n                            $this->_tpl_vars[$_key][$_mkey] = $_mval;\n                        }\n                    } else {\n                        $this->_tpl_vars[$_key][] = $_val;\n                    }\n                }\n            }\n        } else {\n            if ($tpl_var != '' && isset($value)) {\n                if(!@is_array($this->_tpl_vars[$tpl_var])) {\n                    settype($this->_tpl_vars[$tpl_var],'array');\n                }\n                if($merge && is_array($value)) {\n                    foreach($value as $_mkey => $_mval) {\n                        $this->_tpl_vars[$tpl_var][$_mkey] = $_mval;\n                    }\n                } else {\n                    $this->_tpl_vars[$tpl_var][] = $value;\n                }\n            }\n        }\n    }\n\n    /**\n     * appends values to template variables by reference\n     *\n     * @param string $tpl_var the template variable name\n     * @param mixed $value the referenced value to append\n     */\n    function append_by_ref($tpl_var, &$value, $merge=false)\n    {\n        if ($tpl_var != '' && isset($value)) {\n            if(!@is_array($this->_tpl_vars[$tpl_var])) {\n             settype($this->_tpl_vars[$tpl_var],'array');\n            }\n            if ($merge && is_array($value)) {\n                foreach($value as $_key => $_val) {\n                    $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key];\n                }\n            } else {\n                $this->_tpl_vars[$tpl_var][] = &$value;\n            }\n        }\n    }\n\n\n    /**\n     * clear the given assigned template variable.\n     *\n     * @param string $tpl_var the template variable to clear\n     */\n    function clear_assign($tpl_var)\n    {\n        if (is_array($tpl_var))\n            foreach ($tpl_var as $curr_var)\n                unset($this->_tpl_vars[$curr_var]);\n        else\n            unset($this->_tpl_vars[$tpl_var]);\n    }\n\n\n    /**\n     * Registers custom function to be used in templates\n     *\n     * @param string $function the name of the template function\n     * @param string $function_impl the name of the PHP function to register\n     */\n    function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null)\n    {\n        $this->_plugins['function'][$function] =\n            array($function_impl, null, null, false, $cacheable, $cache_attrs);\n\n    }\n\n    /**\n     * Unregisters custom function\n     *\n     * @param string $function name of template function\n     */\n    function unregister_function($function)\n    {\n        unset($this->_plugins['function'][$function]);\n    }\n\n    /**\n     * Registers object to be used in templates\n     *\n     * @param string $object name of template object\n     * @param object &$object_impl the referenced PHP object to register\n     * @param null|array $allowed list of allowed methods (empty = all)\n     * @param boolean $smarty_args smarty argument format, else traditional\n     * @param null|array $block_functs list of methods that are block format\n     */\n    function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())\n    {\n        settype($allowed, 'array');\n        settype($smarty_args, 'boolean');\n        $this->_reg_objects[$object] =\n            array(&$object_impl, $allowed, $smarty_args, $block_methods);\n    }\n\n    /**\n     * Unregisters object\n     *\n     * @param string $object name of template object\n     */\n    function unregister_object($object)\n    {\n        unset($this->_reg_objects[$object]);\n    }\n\n\n    /**\n     * Registers block function to be used in templates\n     *\n     * @param string $block name of template block\n     * @param string $block_impl PHP function to register\n     */\n    function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null)\n    {\n        $this->_plugins['block'][$block] =\n            array($block_impl, null, null, false, $cacheable, $cache_attrs);\n    }\n\n    /**\n     * Unregisters block function\n     *\n     * @param string $block name of template function\n     */\n    function unregister_block($block)\n    {\n        unset($this->_plugins['block'][$block]);\n    }\n\n    /**\n     * Registers compiler function\n     *\n     * @param string $function name of template function\n     * @param string $function_impl name of PHP function to register\n     */\n    function register_compiler_function($function, $function_impl, $cacheable=true)\n    {\n        $this->_plugins['compiler'][$function] =\n            array($function_impl, null, null, false, $cacheable);\n    }\n\n    /**\n     * Unregisters compiler function\n     *\n     * @param string $function name of template function\n     */\n    function unregister_compiler_function($function)\n    {\n        unset($this->_plugins['compiler'][$function]);\n    }\n\n    /**\n     * Registers modifier to be used in templates\n     *\n     * @param string $modifier name of template modifier\n     * @param string $modifier_impl name of PHP function to register\n     */\n    function register_modifier($modifier, $modifier_impl)\n    {\n        $this->_plugins['modifier'][$modifier] =\n            array($modifier_impl, null, null, false);\n    }\n\n    /**\n     * Unregisters modifier\n     *\n     * @param string $modifier name of template modifier\n     */\n    function unregister_modifier($modifier)\n    {\n        unset($this->_plugins['modifier'][$modifier]);\n    }\n\n    /**\n     * Registers a resource to fetch a template\n     *\n     * @param string $type name of resource\n     * @param array $functions array of functions to handle resource\n     */\n    function register_resource($type, $functions)\n    {\n        if (count($functions)==4) {\n            $this->_plugins['resource'][$type] =\n                array($functions, false);\n\n        } elseif (count($functions)==5) {\n            $this->_plugins['resource'][$type] =\n                array(array(array(&$functions[0], $functions[1])\n                            ,array(&$functions[0], $functions[2])\n                            ,array(&$functions[0], $functions[3])\n                            ,array(&$functions[0], $functions[4]))\n                      ,false);\n\n        } else {\n            $this->trigger_error(\"malformed function-list for '$type' in register_resource\");\n\n        }\n    }\n\n    /**\n     * Unregisters a resource\n     *\n     * @param string $type name of resource\n     */\n    function unregister_resource($type)\n    {\n        unset($this->_plugins['resource'][$type]);\n    }\n\n    /**\n     * Registers a prefilter function to apply\n     * to a template before compiling\n     *\n     * @param string $function name of PHP function to register\n     */\n    function register_prefilter($function)\n    {\n    $_name = (is_array($function)) ? $function[1] : $function;\n        $this->_plugins['prefilter'][$_name]\n            = array($function, null, null, false);\n    }\n\n    /**\n     * Unregisters a prefilter function\n     *\n     * @param string $function name of PHP function\n     */\n    function unregister_prefilter($function)\n    {\n        unset($this->_plugins['prefilter'][$function]);\n    }\n\n    /**\n     * Registers a postfilter function to apply\n     * to a compiled template after compilation\n     *\n     * @param string $function name of PHP function to register\n     */\n    function register_postfilter($function)\n    {\n    $_name = (is_array($function)) ? $function[1] : $function;\n        $this->_plugins['postfilter'][$_name]\n            = array($function, null, null, false);\n    }\n\n    /**\n     * Unregisters a postfilter function\n     *\n     * @param string $function name of PHP function\n     */\n    function unregister_postfilter($function)\n    {\n        unset($this->_plugins['postfilter'][$function]);\n    }\n\n    /**\n     * Registers an output filter function to apply\n     * to a template output\n     *\n     * @param string $function name of PHP function\n     */\n    function register_outputfilter($function)\n    {\n    $_name = (is_array($function)) ? $function[1] : $function;\n        $this->_plugins['outputfilter'][$_name]\n            = array($function, null, null, false);\n    }\n\n    /**\n     * Unregisters an outputfilter function\n     *\n     * @param string $function name of PHP function\n     */\n    function unregister_outputfilter($function)\n    {\n        unset($this->_plugins['outputfilter'][$function]);\n    }\n\n    /**\n     * load a filter of specified type and name\n     *\n     * @param string $type filter type\n     * @param string $name filter name\n     */\n    function load_filter($type, $name)\n    {\n        switch ($type) {\n            case 'output':\n                $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false)));\n                require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\n                smarty_core_load_plugins($_params, $this);\n                break;\n\n            case 'pre':\n            case 'post':\n                if (!isset($this->_plugins[$type . 'filter'][$name]))\n                    $this->_plugins[$type . 'filter'][$name] = false;\n                break;\n        }\n    }\n\n    /**\n     * clear cached content for the given template and cache id\n     *\n     * @param string $tpl_file name of template file\n     * @param string $cache_id name of cache_id\n     * @param string $compile_id name of compile_id\n     * @param string $exp_time expiration time\n     * @return boolean\n     */\n    function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)\n    {\n\n        if (!isset($compile_id))\n            $compile_id = $this->compile_id;\n\n        if (!isset($tpl_file))\n            $compile_id = null;\n\n        $_auto_id = $this->_get_auto_id($cache_id, $compile_id);\n\n        if (!empty($this->cache_handler_func)) {\n            return call_user_func_array($this->cache_handler_func,\n                                  array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time));\n        } else {\n            $_params = array('auto_base' => $this->cache_dir,\n                            'auto_source' => $tpl_file,\n                            'auto_id' => $_auto_id,\n                            'exp_time' => $exp_time);\n            require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');\n            return smarty_core_rm_auto($_params, $this);\n        }\n\n    }\n\n\n    /**\n     * clear the entire contents of cache (all templates)\n     *\n     * @param string $exp_time expire time\n     * @return boolean results of {@link smarty_core_rm_auto()}\n     */\n    function clear_all_cache($exp_time = null)\n    {\n        return $this->clear_cache(null, null, null, $exp_time);\n    }\n\n\n    /**\n     * test to see if valid cache exists for this template\n     *\n     * @param string $tpl_file name of template file\n     * @param string $cache_id\n     * @param string $compile_id\n     * @return string|false results of {@link _read_cache_file()}\n     */\n    function is_cached($tpl_file, $cache_id = null, $compile_id = null)\n    {\n        if (!$this->caching)\n            return false;\n\n        if (!isset($compile_id))\n            $compile_id = $this->compile_id;\n\n        $_params = array(\n            'tpl_file' => $tpl_file,\n            'cache_id' => $cache_id,\n            'compile_id' => $compile_id\n        );\n        require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');\n        return smarty_core_read_cache_file($_params, $this);\n    }\n\n\n    /**\n     * clear all the assigned template variables.\n     *\n     */\n    function clear_all_assign()\n    {\n        $this->_tpl_vars = array();\n    }\n\n    /**\n     * clears compiled version of specified template resource,\n     * or all compiled template files if one is not specified.\n     * This function is for advanced use only, not normally needed.\n     *\n     * @param string $tpl_file\n     * @param string $compile_id\n     * @param string $exp_time\n     * @return boolean results of {@link smarty_core_rm_auto()}\n     */\n    function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null)\n    {\n        if (!isset($compile_id)) {\n            $compile_id = $this->compile_id;\n        }\n        $_params = array('auto_base' => $this->compile_dir,\n                        'auto_source' => $tpl_file,\n                        'auto_id' => $compile_id,\n                        'exp_time' => $exp_time,\n                        'extensions' => array('.inc', '.php'));\n        require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');\n        return smarty_core_rm_auto($_params, $this);\n    }\n\n    /**\n     * Checks whether requested template exists.\n     *\n     * @param string $tpl_file\n     * @return boolean\n     */\n    function template_exists($tpl_file)\n    {\n        $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false);\n        return $this->_fetch_resource_info($_params);\n    }\n\n    /**\n     * Returns an array containing template variables\n     *\n     * @param string $name\n     * @param string $type\n     * @return array\n     */\n    function &get_template_vars($name=null)\n    {\n        if(!isset($name)) {\n            return $this->_tpl_vars;\n        }\n        if(isset($this->_tpl_vars[$name])) {\n            return $this->_tpl_vars[$name];\n        }\n    }\n\n    /**\n     * Returns an array containing config variables\n     *\n     * @param string $name\n     * @param string $type\n     * @return array\n     */\n    function &get_config_vars($name=null)\n    {\n        if(!isset($name) && is_array($this->_config[0])) {\n            return $this->_config[0]['vars'];\n        } else if(isset($this->_config[0]['vars'][$name])) {\n            return $this->_config[0]['vars'][$name];\n        }\n    }\n\n    /**\n     * trigger Smarty error\n     *\n     * @param string $error_msg\n     * @param integer $error_type\n     */\n    function trigger_error($error_msg, $error_type = E_USER_WARNING)\n    {\n        trigger_error(\"Smarty error: $error_msg\", $error_type);\n    }\n\n\n    /**\n     * executes & displays the template results\n     *\n     * @param string $resource_name\n     * @param string $cache_id\n     * @param string $compile_id\n     */\n    function display($resource_name, $cache_id = null, $compile_id = null)\n    {\n        $this->fetch($resource_name, $cache_id, $compile_id, true);\n    }\n\n    /**\n     * executes & returns or displays the template results\n     *\n     * @param string $resource_name\n     * @param string $cache_id\n     * @param string $compile_id\n     * @param boolean $display\n     */\n    function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false)\n    {\n        static $_cache_info = array();\n        \n        $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting)\n               ? $this->error_reporting : error_reporting() & ~E_NOTICE);\n\n        if (!$this->debugging && $this->debugging_ctrl == 'URL') {\n            $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];\n            if (@strstr($_query_string, $this->_smarty_debug_id)) {\n                if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) {\n                    // enable debugging for this browser session\n                    @setcookie('SMARTY_DEBUG', true);\n                    $this->debugging = true;\n                } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) {\n                    // disable debugging for this browser session\n                    @setcookie('SMARTY_DEBUG', false);\n                    $this->debugging = false;\n                } else {\n                    // enable debugging for this page\n                    $this->debugging = true;\n                }\n            } else {\n                $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']);\n            }\n        }\n\n        if ($this->debugging) {\n            // capture time for debugging info\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $_debug_start_time = smarty_core_get_microtime($_params, $this);\n            $this->_smarty_debug_info[] = array('type'      => 'template',\n                                                'filename'  => $resource_name,\n                                                'depth'     => 0);\n            $_included_tpls_idx = count($this->_smarty_debug_info) - 1;\n        }\n\n        if (!isset($compile_id)) {\n            $compile_id = $this->compile_id;\n        }\n\n        $this->_compile_id = $compile_id;\n        $this->_inclusion_depth = 0;\n\n        if ($this->caching) {\n            // save old cache_info, initialize cache_info\n            array_push($_cache_info, $this->_cache_info);\n            $this->_cache_info = array();\n            $_params = array(\n                'tpl_file' => $resource_name,\n                'cache_id' => $cache_id,\n                'compile_id' => $compile_id,\n                'results' => null\n            );\n            require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');\n            if (smarty_core_read_cache_file($_params, $this)) {\n                $_smarty_results = $_params['results'];\n                if (!empty($this->_cache_info['insert_tags'])) {\n                    $_params = array('plugins' => $this->_cache_info['insert_tags']);\n                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\n                    smarty_core_load_plugins($_params, $this);\n                    $_params = array('results' => $_smarty_results);\n                    require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');\n                    $_smarty_results = smarty_core_process_cached_inserts($_params, $this);\n                }\n                if (!empty($this->_cache_info['cache_serials'])) {\n                    $_params = array('results' => $_smarty_results);\n                    require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php');\n                    $_smarty_results = smarty_core_process_compiled_include($_params, $this);\n                }\n\n\n                if ($display) {\n                    if ($this->debugging)\n                    {\n                        // capture time for debugging info\n                        $_params = array();\n                        require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n                        $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time;\n                        require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');\n                        $_smarty_results .= smarty_core_display_debug_console($_params, $this);\n                    }\n                    if ($this->cache_modified_check) {\n                        $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];\n                        $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);\n                        $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT';\n                        if (@count($this->_cache_info['insert_tags']) == 0\n                            && !$this->_cache_serials\n                            && $_gmt_mtime == $_last_modified_date) {\n                            if (php_sapi_name()=='cgi')\n                                header('Status: 304 Not Modified');\n                            else\n                                header('HTTP/1.1 304 Not Modified');\n\n                        } else {\n                            header('Last-Modified: '.$_gmt_mtime);\n                            echo $_smarty_results;\n                        }\n                    } else {\n                            echo $_smarty_results;\n                    }\n                    error_reporting($_smarty_old_error_level);\n                    // restore initial cache_info\n                    $this->_cache_info = array_pop($_cache_info);\n                    return true;\n                } else {\n                    error_reporting($_smarty_old_error_level);\n                    // restore initial cache_info\n                    $this->_cache_info = array_pop($_cache_info);\n                    return $_smarty_results;\n                }\n            } else {\n                $this->_cache_info['template'][$resource_name] = true;\n                if ($this->cache_modified_check && $display) {\n                    header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');\n                }\n            }\n        }\n\n        // load filters that are marked as autoload\n        if (count($this->autoload_filters)) {\n            foreach ($this->autoload_filters as $_filter_type => $_filters) {\n                foreach ($_filters as $_filter) {\n                    $this->load_filter($_filter_type, $_filter);\n                }\n            }\n        }\n\n        $_smarty_compile_path = $this->_get_compile_path($resource_name);\n\n        // if we just need to display the results, don't perform output\n        // buffering - for speed\n        $_cache_including = $this->_cache_including;\n        $this->_cache_including = false;\n        if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) {\n            if ($this->_is_compiled($resource_name, $_smarty_compile_path)\n                    || $this->_compile_resource($resource_name, $_smarty_compile_path))\n            {\n                include($_smarty_compile_path);\n            }\n        } else {\n            ob_start();\n            if ($this->_is_compiled($resource_name, $_smarty_compile_path)\n                    || $this->_compile_resource($resource_name, $_smarty_compile_path))\n            {\n                include($_smarty_compile_path);\n            }\n            $_smarty_results = ob_get_contents();\n            ob_end_clean();\n\n            foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) {\n                $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this));\n            }\n        }\n\n        if ($this->caching) {\n            $_params = array('tpl_file' => $resource_name,\n                        'cache_id' => $cache_id,\n                        'compile_id' => $compile_id,\n                        'results' => $_smarty_results);\n            require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php');\n            smarty_core_write_cache_file($_params, $this);\n            require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');\n            $_smarty_results = smarty_core_process_cached_inserts($_params, $this);\n\n            if ($this->_cache_serials) {\n                // strip nocache-tags from output\n                $_smarty_results = preg_replace('!(\\{/?nocache\\:[0-9a-f]{32}#\\d+\\})!s'\n                                                ,''\n                                                ,$_smarty_results);\n            }\n            // restore initial cache_info\n            $this->_cache_info = array_pop($_cache_info);\n        }\n        $this->_cache_including = $_cache_including;\n\n        if ($display) {\n            if (isset($_smarty_results)) { echo $_smarty_results; }\n            if ($this->debugging) {\n                // capture time for debugging info\n                $_params = array();\n                require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n                $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time);\n                require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');\n                echo smarty_core_display_debug_console($_params, $this);\n            }\n            error_reporting($_smarty_old_error_level);\n            return;\n        } else {\n            error_reporting($_smarty_old_error_level);\n            if (isset($_smarty_results)) { return $_smarty_results; }\n        }\n    }\n\n    /**\n     * load configuration values\n     *\n     * @param string $file\n     * @param string $section\n     * @param string $scope\n     */\n    function config_load($file, $section = null, $scope = 'global')\n    {\n        require_once($this->_get_plugin_filepath('function', 'config_load'));\n        smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this);\n    }\n\n    /**\n     * return a reference to a registered object\n     *\n     * @param string $name\n     * @return object\n     */\n    function &get_registered_object($name) {\n        if (!isset($this->_reg_objects[$name]))\n        $this->_trigger_fatal_error(\"'$name' is not a registered object\");\n\n        if (!is_object($this->_reg_objects[$name][0]))\n        $this->_trigger_fatal_error(\"registered '$name' is not an object\");\n\n        return $this->_reg_objects[$name][0];\n    }\n\n    /**\n     * clear configuration values\n     *\n     * @param string $var\n     */\n    function clear_config($var = null)\n    {\n        if(!isset($var)) {\n            // clear all values\n            $this->_config = array(array('vars'  => array(),\n                                         'files' => array()));\n        } else {\n            unset($this->_config[0]['vars'][$var]);\n        }\n    }\n\n    /**\n     * get filepath of requested plugin\n     *\n     * @param string $type\n     * @param string $name\n     * @return string|false\n     */\n    function _get_plugin_filepath($type, $name)\n    {\n        $_params = array('type' => $type, 'name' => $name);\n        require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php');\n        return smarty_core_assemble_plugin_filepath($_params, $this);\n    }\n\n   /**\n     * test if resource needs compiling\n     *\n     * @param string $resource_name\n     * @param string $compile_path\n     * @return boolean\n     */\n    function _is_compiled($resource_name, $compile_path)\n    {\n        if (!$this->force_compile && file_exists($compile_path)) {\n            if (!$this->compile_check) {\n                // no need to check compiled file\n                return true;\n            } else {\n                // get file source and timestamp\n                $_params = array('resource_name' => $resource_name, 'get_source'=>false);\n                if (!$this->_fetch_resource_info($_params)) {\n                    return false;\n                }\n                if ($_params['resource_timestamp'] <= filemtime($compile_path)) {\n                    // template not expired, no recompile\n                    return true;\n                } else {\n                    // compile template\n                    return false;\n                }\n            }\n        } else {\n            // compiled template does not exist, or forced compile\n            return false;\n        }\n    }\n\n   /**\n     * compile the template\n     *\n     * @param string $resource_name\n     * @param string $compile_path\n     * @return boolean\n     */\n    function _compile_resource($resource_name, $compile_path)\n    {\n\n        $_params = array('resource_name' => $resource_name);\n        if (!$this->_fetch_resource_info($_params)) {\n            return false;\n        }\n\n        $_source_content = $_params['source_content'];\n        $_cache_include    = substr($compile_path, 0, -4).'.inc';\n\n        if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) {\n            // if a _cache_serial was set, we also have to write an include-file:\n            if ($this->_cache_include_info) {\n                require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php');\n                smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)),  $this);\n            }\n\n            $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content);\n            require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');\n            smarty_core_write_compiled_resource($_params, $this);\n\n            return true;\n        } else {\n            return false;\n        }\n\n    }\n\n   /**\n     * compile the given source\n     *\n     * @param string $resource_name\n     * @param string $source_content\n     * @param string $compiled_content\n     * @return boolean\n     */\n    function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null)\n    {\n        if (file_exists(SMARTY_DIR . $this->compiler_file)) {\n            require_once(SMARTY_DIR . $this->compiler_file);\n        } else {\n            // use include_path\n            require_once($this->compiler_file);\n        }\n\n\n        $smarty_compiler = new $this->compiler_class;\n\n        $smarty_compiler->template_dir      = $this->template_dir;\n        $smarty_compiler->compile_dir       = $this->compile_dir;\n        $smarty_compiler->plugins_dir       = $this->plugins_dir;\n        $smarty_compiler->config_dir        = $this->config_dir;\n        $smarty_compiler->force_compile     = $this->force_compile;\n        $smarty_compiler->caching           = $this->caching;\n        $smarty_compiler->php_handling      = $this->php_handling;\n        $smarty_compiler->left_delimiter    = $this->left_delimiter;\n        $smarty_compiler->right_delimiter   = $this->right_delimiter;\n        $smarty_compiler->_version          = $this->_version;\n        $smarty_compiler->security          = $this->security;\n        $smarty_compiler->secure_dir        = $this->secure_dir;\n        $smarty_compiler->security_settings = $this->security_settings;\n        $smarty_compiler->trusted_dir       = $this->trusted_dir;\n        $smarty_compiler->use_sub_dirs      = $this->use_sub_dirs;\n        $smarty_compiler->_reg_objects      = &$this->_reg_objects;\n        $smarty_compiler->_plugins          = &$this->_plugins;\n        $smarty_compiler->_tpl_vars         = &$this->_tpl_vars;\n        $smarty_compiler->default_modifiers = $this->default_modifiers;\n        $smarty_compiler->compile_id        = $this->_compile_id;\n        $smarty_compiler->_config            = $this->_config;\n        $smarty_compiler->request_use_auto_globals  = $this->request_use_auto_globals;\n\n        if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) {\n            $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path];\n        }\n        $smarty_compiler->_cache_include = $cache_include_path;\n\n\n        $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content);\n\n        if ($smarty_compiler->_cache_serial) {\n            $this->_cache_include_info = array(\n                'cache_serial'=>$smarty_compiler->_cache_serial\n                ,'plugins_code'=>$smarty_compiler->_plugins_code\n                ,'include_file_path' => $cache_include_path);\n\n        } else {\n            $this->_cache_include_info = null;\n\n        }\n\n        return $_results;\n    }\n\n    /**\n     * Get the compile path for this resource\n     *\n     * @param string $resource_name\n     * @return string results of {@link _get_auto_filename()}\n     */\n    function _get_compile_path($resource_name)\n    {\n        return $this->_get_auto_filename($this->compile_dir, $resource_name,\n                                         $this->_compile_id) . '.php';\n    }\n\n    /**\n     * fetch the template info. Gets timestamp, and source\n     * if get_source is true\n     *\n     * sets $source_content to the source of the template, and\n     * $resource_timestamp to its time stamp\n     * @param string $resource_name\n     * @param string $source_content\n     * @param integer $resource_timestamp\n     * @param boolean $get_source\n     * @param boolean $quiet\n     * @return boolean\n     */\n\n    function _fetch_resource_info(&$params)\n    {\n        if(!isset($params['get_source'])) { $params['get_source'] = true; }\n        if(!isset($params['quiet'])) { $params['quiet'] = false; }\n\n        $_return = false;\n        $_params = array('resource_name' => $params['resource_name']) ;\n        if (isset($params['resource_base_path']))\n            $_params['resource_base_path'] = $params['resource_base_path'];\n        else\n            $_params['resource_base_path'] = $this->template_dir;\n\n        if ($this->_parse_resource_name($_params)) {\n            $_resource_type = $_params['resource_type'];\n            $_resource_name = $_params['resource_name'];\n            switch ($_resource_type) {\n                case 'file':\n                    if ($params['get_source']) {\n                        $params['source_content'] = $this->_read_file($_resource_name);\n                    }\n                    $params['resource_timestamp'] = filemtime($_resource_name);\n                    $_return = is_file($_resource_name);\n                    break;\n\n                default:\n                    // call resource functions to fetch the template source and timestamp\n                    if ($params['get_source']) {\n                        $_source_return = isset($this->_plugins['resource'][$_resource_type]) &&\n                            call_user_func_array($this->_plugins['resource'][$_resource_type][0][0],\n                                                 array($_resource_name, &$params['source_content'], &$this));\n                    } else {\n                        $_source_return = true;\n                    }\n\n                    $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) &&\n                        call_user_func_array($this->_plugins['resource'][$_resource_type][0][1],\n                                             array($_resource_name, &$params['resource_timestamp'], &$this));\n\n                    $_return = $_source_return && $_timestamp_return;\n                    break;\n            }\n        }\n\n        if (!$_return) {\n            // see if we can get a template with the default template handler\n            if (!empty($this->default_template_handler_func)) {\n                if (!is_callable($this->default_template_handler_func)) {\n                    $this->trigger_error(\"default template handler function \\\"$this->default_template_handler_func\\\" doesn't exist.\");\n                } else {\n                    $_return = call_user_func_array(\n                        $this->default_template_handler_func,\n                        array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this));\n                }\n            }\n        }\n\n        if (!$_return) {\n            if (!$params['quiet']) {\n                $this->trigger_error('unable to read resource: \"' . $params['resource_name'] . '\"');\n            }\n        } else if ($_return && $this->security) {\n            require_once(SMARTY_CORE_DIR . 'core.is_secure.php');\n            if (!smarty_core_is_secure($_params, $this)) {\n                if (!$params['quiet'])\n                    $this->trigger_error('(secure mode) accessing \"' . $params['resource_name'] . '\" is not allowed');\n                $params['source_content'] = null;\n                $params['resource_timestamp'] = null;\n                return false;\n            }\n        }\n        return $_return;\n    }\n\n\n    /**\n     * parse out the type and name from the resource\n     *\n     * @param string $resource_base_path\n     * @param string $resource_name\n     * @param string $resource_type\n     * @param string $resource_name\n     * @return boolean\n     */\n\n    function _parse_resource_name(&$params)\n    {\n\n        // split tpl_path by the first colon\n        $_resource_name_parts = explode(':', $params['resource_name'], 2);\n\n        if (count($_resource_name_parts) == 1) {\n            // no resource type given\n            $params['resource_type'] = $this->default_resource_type;\n            $params['resource_name'] = $_resource_name_parts[0];\n        } else {\n            if(strlen($_resource_name_parts[0]) == 1) {\n                // 1 char is not resource type, but part of filepath\n                $params['resource_type'] = $this->default_resource_type;\n                $params['resource_name'] = $params['resource_name'];\n            } else {\n                $params['resource_type'] = $_resource_name_parts[0];\n                $params['resource_name'] = $_resource_name_parts[1];\n            }\n        }\n\n        if ($params['resource_type'] == 'file') {\n            if (!preg_match('/^([\\/\\\\\\\\]|[a-zA-Z]:[\\/\\\\\\\\])/', $params['resource_name'])) {\n                // relative pathname to $params['resource_base_path']\n                // use the first directory where the file is found\n                foreach ((array)$params['resource_base_path'] as $_curr_path) {\n                    $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name'];\n                    if (file_exists($_fullpath) && is_file($_fullpath)) {\n                        $params['resource_name'] = $_fullpath;\n                        return true;\n                    }\n                    // didn't find the file, try include_path\n                    $_params = array('file_path' => $_fullpath);\n                    require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');\n                    if(smarty_core_get_include_path($_params, $this)) {\n                        $params['resource_name'] = $_params['new_file_path'];\n                        return true;\n                    }\n                }\n                return false;\n            } else {\n                /* absolute path */\n                return file_exists($params['resource_name']);\n            }\n        } elseif (empty($this->_plugins['resource'][$params['resource_type']])) {\n            $_params = array('type' => $params['resource_type']);\n            require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php');\n            smarty_core_load_resource_plugin($_params, $this);\n        }\n\n        return true;\n    }\n\n\n    /**\n     * Handle modifiers\n     *\n     * @param string|null $modifier_name\n     * @param array|null $map_array\n     * @return string result of modifiers\n     */\n    function _run_mod_handler()\n    {\n        $_args = func_get_args();\n        list($_modifier_name, $_map_array) = array_splice($_args, 0, 2);\n        list($_func_name, $_tpl_file, $_tpl_line) =\n            $this->_plugins['modifier'][$_modifier_name];\n\n        $_var = $_args[0];\n        foreach ($_var as $_key => $_val) {\n            $_args[0] = $_val;\n            $_var[$_key] = call_user_func_array($_func_name, $_args);\n        }\n        return $_var;\n    }\n\n    /**\n     * Remove starting and ending quotes from the string\n     *\n     * @param string $string\n     * @return string\n     */\n    function _dequote($string)\n    {\n        if (($string{0} == \"'\" || $string{0} == '\"') &&\n            $string{strlen($string)-1} == $string{0})\n            return substr($string, 1, -1);\n        else\n            return $string;\n    }\n\n\n    /**\n     * read in a file\n     *\n     * @param string $filename\n     * @return string\n     */\n    function _read_file($filename)\n    {\n        if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) {\n            $contents = ($size = filesize($filename)) ? fread($fd, $size) : '';\n            fclose($fd);\n            return $contents;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * get a concrete filename for automagically created content\n     *\n     * @param string $auto_base\n     * @param string $auto_source\n     * @param string $auto_id\n     * @return string\n     * @staticvar string|null\n     * @staticvar string|null\n     */\n    function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null)\n    {\n        $_compile_dir_sep =  $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^';\n        $_return = $auto_base . DIRECTORY_SEPARATOR;\n\n        if(isset($auto_id)) {\n            // make auto_id safe for directory names\n            $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id)));\n            // split into separate directories\n            $_return .= $auto_id . $_compile_dir_sep;\n        }\n\n        if(isset($auto_source)) {\n            // make source name safe for filename\n            $_filename = urlencode(basename($auto_source));\n            $_crc32 = sprintf('%08X', crc32($auto_source));\n            // prepend %% to avoid name conflicts with\n            // with $params['auto_id'] names\n            $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep .\n                      substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32;\n            $_return .= '%%' . $_crc32 . '%%' . $_filename;\n        }\n\n        return $_return;\n    }\n\n    /**\n     * unlink a file, possibly using expiration time\n     *\n     * @param string $resource\n     * @param integer $exp_time\n     */\n    function _unlink($resource, $exp_time = null)\n    {\n        if(isset($exp_time)) {\n            if(time() - @filemtime($resource) >= $exp_time) {\n                return @unlink($resource);\n            }\n        } else {\n            return @unlink($resource);\n        }\n    }\n\n    /**\n     * returns an auto_id for auto-file-functions\n     *\n     * @param string $cache_id\n     * @param string $compile_id\n     * @return string|null\n     */\n    function _get_auto_id($cache_id=null, $compile_id=null) {\n    if (isset($cache_id))\n        return (isset($compile_id)) ? $cache_id . '|' . $compile_id  : $cache_id;\n    elseif(isset($compile_id))\n        return $compile_id;\n    else\n        return null;\n    }\n\n    /**\n     * trigger Smarty plugin error\n     *\n     * @param string $error_msg\n     * @param string $tpl_file\n     * @param integer $tpl_line\n     * @param string $file\n     * @param integer $line\n     * @param integer $error_type\n     */\n    function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null,\n            $file = null, $line = null, $error_type = E_USER_ERROR)\n    {\n        if(isset($file) && isset($line)) {\n            $info = ' ('.basename($file).\", line $line)\";\n        } else {\n            $info = '';\n        }\n        if (isset($tpl_line) && isset($tpl_file)) {\n            $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . \"]: $error_msg$info\", $error_type);\n        } else {\n            $this->trigger_error($error_msg . $info, $error_type);\n        }\n    }\n\n\n    /**\n     * callback function for preg_replace, to call a non-cacheable block\n     * @return string\n     */\n    function _process_compiled_include_callback($match) {\n        $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3];\n        ob_start();\n        $_func($this);\n        $_ret = ob_get_contents();\n        ob_end_clean();\n        return $_ret;\n    }\n\n\n    /**\n     * called for included templates\n     *\n     * @param string $_smarty_include_tpl_file\n     * @param string $_smarty_include_vars\n     */\n\n    // $_smarty_include_tpl_file, $_smarty_include_vars\n\n    function _smarty_include($params)\n    {\n        if ($this->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $debug_start_time = smarty_core_get_microtime($_params, $this);\n            $this->_smarty_debug_info[] = array('type'      => 'template',\n                                                  'filename'  => $params['smarty_include_tpl_file'],\n                                                  'depth'     => ++$this->_inclusion_depth);\n            $included_tpls_idx = count($this->_smarty_debug_info) - 1;\n        }\n\n        $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']);\n\n        // config vars are treated as local, so push a copy of the\n        // current ones onto the front of the stack\n        array_unshift($this->_config, $this->_config[0]);\n\n        $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']);\n\n\n        if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path)\n            || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path))\n        {\n            include($_smarty_compile_path);\n        }\n\n        // pop the local vars off the front of the stack\n        array_shift($this->_config);\n\n        $this->_inclusion_depth--;\n\n        if ($this->debugging) {\n            // capture time for debugging info\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time;\n        }\n\n        if ($this->caching) {\n            $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true;\n        }\n    }\n\n\n    /**\n     * get or set an array of cached attributes for function that is\n     * not cacheable\n     * @return array\n     */\n    function &_smarty_cache_attrs($cache_serial, $count) {\n        $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count];\n\n        if ($this->_cache_including) {\n            /* return next set of cache_attrs */\n            $_return =& current($_cache_attrs);\n            next($_cache_attrs);\n            return $_return;\n\n        } else {\n            /* add a reference to a new set of cache_attrs */\n            $_cache_attrs[] = array();\n            return $_cache_attrs[count($_cache_attrs)-1];\n\n        }\n\n    }\n\n\n    /**\n     * wrapper for include() retaining $this\n     * @return mixed\n     */\n    function _include($filename, $once=false, $params=null)\n    {\n        if ($once) {\n            return include_once($filename);\n        } else {\n            return include($filename);\n        }\n    }\n\n\n    /**\n     * wrapper for eval() retaining $this\n     * @return mixed\n     */\n    function _eval($code, $params=null)\n    {\n        return eval($code);\n    }\n    /**#@-*/\n\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/Smarty_Compiler.class.php",
    "content": "<?php\n\n/**\n * Project:     Smarty: the PHP compiling template engine\n * File:        Smarty_Compiler.class.php\n *\n * This library is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * This library is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n *\n * @link http://smarty.php.net/\n * @author Monte Ohrt <monte at ohrt dot com>\n * @author Andrei Zmievski <andrei@php.net>\n * @version 2.6.9\n * @copyright 2001-2005 New Digital Group, Inc.\n * @package Smarty\n */\n\n/* $Id: Smarty_Compiler.class.php,v 1.1 2006/05/29 16:38:21 powles Exp $ */\n\n/**\n * Template compiling class\n * @package Smarty\n */\nclass Smarty_Compiler extends Smarty {\n\n    // internal vars\n    /**#@+\n     * @access private\n     */\n    var $_folded_blocks         =   array();    // keeps folded template blocks\n    var $_current_file          =   null;       // the current template being compiled\n    var $_current_line_no       =   1;          // line number for error messages\n    var $_capture_stack         =   array();    // keeps track of nested capture buffers\n    var $_plugin_info           =   array();    // keeps track of plugins to load\n    var $_init_smarty_vars      =   false;\n    var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');\n    var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor\n    var $_si_qstr_regexp        =   null;\n    var $_qstr_regexp           =   null;\n    var $_func_regexp           =   null;\n    var $_reg_obj_regexp        =   null;\n    var $_var_bracket_regexp    =   null;\n    var $_num_const_regexp      =   null;\n    var $_dvar_guts_regexp      =   null;\n    var $_dvar_regexp           =   null;\n    var $_cvar_regexp           =   null;\n    var $_svar_regexp           =   null;\n    var $_avar_regexp           =   null;\n    var $_mod_regexp            =   null;\n    var $_var_regexp            =   null;\n    var $_parenth_param_regexp  =   null;\n    var $_func_call_regexp      =   null;\n    var $_obj_ext_regexp        =   null;\n    var $_obj_start_regexp      =   null;\n    var $_obj_params_regexp     =   null;\n    var $_obj_call_regexp       =   null;\n    var $_cacheable_state       =   0;\n    var $_cache_attrs_count     =   0;\n    var $_nocache_count         =   0;\n    var $_cache_serial          =   null;\n    var $_cache_include         =   null;\n\n    var $_strip_depth           =   0;\n    var $_additional_newline    =   \"\\n\";\n\n    /**#@-*/\n    /**\n     * The class constructor.\n     */\n    function Smarty_Compiler()\n    {\n        // matches double quoted strings:\n        // \"foobar\"\n        // \"foo\\\"bar\"\n        $this->_db_qstr_regexp = '\"[^\"\\\\\\\\]*(?:\\\\\\\\.[^\"\\\\\\\\]*)*\"';\n\n        // matches single quoted strings:\n        // 'foobar'\n        // 'foo\\'bar'\n        $this->_si_qstr_regexp = '\\'[^\\'\\\\\\\\]*(?:\\\\\\\\.[^\\'\\\\\\\\]*)*\\'';\n\n        // matches single or double quoted strings\n        $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';\n\n        // matches bracket portion of vars\n        // [0]\n        // [foo]\n        // [$bar]\n        $this->_var_bracket_regexp = '\\[\\$?[\\w\\.]+\\]';\n\n        // matches numerical constants\n        // 30\n        // -12\n        // 13.22\n        $this->_num_const_regexp = '(?:\\-?\\d+(?:\\.\\d+)?)';\n\n        // matches $ vars (not objects):\n        // $foo\n        // $foo.bar\n        // $foo.bar.foobar\n        // $foo[0]\n        // $foo[$bar]\n        // $foo[5][blah]\n        // $foo[5].bar[$foobar][4]\n        $this->_dvar_math_regexp = '(?:[\\+\\*\\/\\%]|(?:-(?!>)))';\n        $this->_dvar_math_var_regexp = '[\\$\\w\\.\\+\\-\\*\\/\\%\\d\\>\\[\\]]';\n        $this->_dvar_guts_regexp = '\\w+(?:' . $this->_var_bracket_regexp\n                . ')*(?:\\.\\$?\\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';\n        $this->_dvar_regexp = '\\$' . $this->_dvar_guts_regexp;\n\n        // matches config vars:\n        // #foo#\n        // #foobar123_foo#\n        $this->_cvar_regexp = '\\#\\w+\\#';\n\n        // matches section vars:\n        // %foo.bar%\n        $this->_svar_regexp = '\\%\\w+\\.\\w+\\%';\n\n        // matches all valid variables (no quotes, no modifiers)\n        $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'\n           . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';\n\n        // matches valid variable syntax:\n        // $foo\n        // $foo\n        // #foo#\n        // #foo#\n        // \"text\"\n        // \"text\"\n        $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';\n\n        // matches valid object call (one level of object nesting allowed in parameters):\n        // $foo->bar\n        // $foo->bar()\n        // $foo->bar(\"text\")\n        // $foo->bar($foo, $bar, \"text\")\n        // $foo->bar($foo, \"foo\")\n        // $foo->bar->foo()\n        // $foo->bar->foo->bar()\n        // $foo->bar($foo->bar)\n        // $foo->bar($foo->bar())\n        // $foo->bar($foo->bar($blah,$foo,44,\"foo\",$foo[0].bar))\n        $this->_obj_ext_regexp = '\\->(?:\\$?' . $this->_dvar_guts_regexp . ')';\n        $this->_obj_restricted_param_regexp = '(?:'\n                . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'\n                . '(?:\\s*,\\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\\))?)*)';\n        $this->_obj_single_param_regexp = '(?:\\w+|' . $this->_obj_restricted_param_regexp . '(?:\\s*,\\s*(?:(?:\\w+|'\n                . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';\n        $this->_obj_params_regexp = '\\((?:' . $this->_obj_single_param_regexp\n                . '(?:\\s*,\\s*' . $this->_obj_single_param_regexp . ')*)?\\)';\n        $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';\n        $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)';\n        \n        // matches valid modifier syntax:\n        // |foo\n        // |@foo\n        // |foo:\"bar\"\n        // |foo:$bar\n        // |foo:\"bar\":$foobar\n        // |foo|bar\n        // |foo:$foo->bar\n        $this->_mod_regexp = '(?:\\|@?\\w+(?::(?:\\w+|' . $this->_num_const_regexp . '|'\n           . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';\n\n        // matches valid function name:\n        // foo123\n        // _foo_bar\n        $this->_func_regexp = '[a-zA-Z_]\\w*';\n\n        // matches valid registered object:\n        // foo->bar\n        $this->_reg_obj_regexp = '[a-zA-Z_]\\w*->[a-zA-Z_]\\w*';\n\n        // matches valid parameter values:\n        // true\n        // $foo\n        // $foo|bar\n        // #foo#\n        // #foo#|bar\n        // \"text\"\n        // \"text\"|bar\n        // $foo->bar\n        $this->_param_regexp = '(?:\\s*(?:' . $this->_obj_call_regexp . '|'\n           . $this->_var_regexp . '|' . $this->_num_const_regexp  . '|\\w+)(?>' . $this->_mod_regexp . '*)\\s*)';\n\n        // matches valid parenthesised function parameters:\n        //\n        // \"text\"\n        //    $foo, $bar, \"text\"\n        // $foo|bar, \"foo\"|bar, $foo->bar($foo)|bar\n        $this->_parenth_param_regexp = '(?:\\((?:\\w+|'\n                . $this->_param_regexp . '(?:\\s*,\\s*(?:(?:\\w+|'\n                . $this->_param_regexp . ')))*)?\\))';\n\n        // matches valid function call:\n        // foo()\n        // foo_bar($foo)\n        // _foo_bar($foo,\"bar\")\n        // foo123($foo,$foo->bar(),\"foo\")\n        $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\\s*(?:'\n           . $this->_parenth_param_regexp . '))';\n    }\n\n    /**\n     * compile a resource\n     *\n     * sets $compiled_content to the compiled source\n     * @param string $resource_name\n     * @param string $source_content\n     * @param string $compiled_content\n     * @return true\n     */\n    function _compile_file($resource_name, $source_content, &$compiled_content)\n    {\n\n        if ($this->security) {\n            // do not allow php syntax to be executed unless specified\n            if ($this->php_handling == SMARTY_PHP_ALLOW &&\n                !$this->security_settings['PHP_HANDLING']) {\n                $this->php_handling = SMARTY_PHP_PASSTHRU;\n            }\n        }\n\n        $this->_load_filters();\n\n        $this->_current_file = $resource_name;\n        $this->_current_line_no = 1;\n        $ldq = preg_quote($this->left_delimiter, '~');\n        $rdq = preg_quote($this->right_delimiter, '~');\n\n        // run template source through prefilter functions\n        if (count($this->_plugins['prefilter']) > 0) {\n            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {\n                if ($prefilter === false) continue;\n                if ($prefilter[3] || is_callable($prefilter[0])) {\n                    $source_content = call_user_func_array($prefilter[0],\n                                                            array($source_content, &$this));\n                    $this->_plugins['prefilter'][$filter_name][3] = true;\n                } else {\n                    $this->_trigger_fatal_error(\"[plugin] prefilter '$filter_name' is not implemented\");\n                }\n            }\n        }\n\n        /* fetch all special blocks */\n        $search = \"~{$ldq}\\*(.*?)\\*{$rdq}|{$ldq}\\s*literal\\s*{$rdq}(.*?){$ldq}\\s*/literal\\s*{$rdq}|{$ldq}\\s*php\\s*{$rdq}(.*?){$ldq}\\s*/php\\s*{$rdq}~s\";\n\n        preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);\n        $this->_folded_blocks = $match;\n        reset($this->_folded_blocks);\n\n        /* replace special blocks by \"{php}\" */\n        $source_content = preg_replace($search.'e', \"'\"\n                                       . $this->_quote_replace($this->left_delimiter) . 'php'\n                                       . \"' . str_repeat(\\\"\\n\\\", substr_count('\\\\0', \\\"\\n\\\")) .'\"\n                                       . $this->_quote_replace($this->right_delimiter)\n                                       . \"'\"\n                                       , $source_content);\n\n        /* Gather all template tags. */\n        preg_match_all(\"~{$ldq}\\s*(.*?)\\s*{$rdq}~s\", $source_content, $_match);\n        $template_tags = $_match[1];\n        /* Split content by template tags to obtain non-template content. */\n        $text_blocks = preg_split(\"~{$ldq}.*?{$rdq}~s\", $source_content);\n\n        /* loop through text blocks */\n        for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {\n            /* match anything resembling php tags */\n            if (preg_match_all('~(<\\?(?:\\w+|=)?|\\?>|language\\s*=\\s*[\\\"\\']?php[\\\"\\']?)~is', $text_blocks[$curr_tb], $sp_match)) {\n                /* replace tags with placeholders to prevent recursive replacements */\n                $sp_match[1] = array_unique($sp_match[1]);\n                usort($sp_match[1], '_smarty_sort_length');\n                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {\n                    $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);\n                }\n                /* process each one */\n                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {\n                    if ($this->php_handling == SMARTY_PHP_PASSTHRU) {\n                        /* echo php contents */\n                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \\''.str_replace(\"'\", \"\\'\", $sp_match[1][$curr_sp]).'\\'; ?>'.\"\\n\", $text_blocks[$curr_tb]);\n                    } else if ($this->php_handling == SMARTY_PHP_QUOTE) {\n                        /* quote php tags */\n                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);\n                    } else if ($this->php_handling == SMARTY_PHP_REMOVE) {\n                        /* remove php tags */\n                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);\n                    } else {\n                        /* SMARTY_PHP_ALLOW, but echo non php starting tags */\n                        $sp_match[1][$curr_sp] = preg_replace('~(<\\?(?!php|=|$))~i', '<?php echo \\'\\\\1\\'?>'.\"\\n\", $sp_match[1][$curr_sp]);\n                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);\n                    }\n                }\n            }\n        }\n\n        /* Compile the template tags into PHP code. */\n        $compiled_tags = array();\n        for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {\n            $this->_current_line_no += substr_count($text_blocks[$i], \"\\n\");\n            $compiled_tags[] = $this->_compile_tag($template_tags[$i]);\n            $this->_current_line_no += substr_count($template_tags[$i], \"\\n\");\n        }\n        if (count($this->_tag_stack)>0) {\n            list($_open_tag, $_line_no) = end($this->_tag_stack);\n            $this->_syntax_error(\"unclosed tag \\{$_open_tag} (opened line $_line_no).\", E_USER_ERROR, __FILE__, __LINE__);\n            return;\n        }\n\n        /* Reformat $text_blocks between 'strip' and '/strip' tags,\n           removing spaces, tabs and newlines. */\n        $strip = false;\n        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {\n            if ($compiled_tags[$i] == '{strip}') {\n                $compiled_tags[$i] = '';\n                $strip = true;\n                /* remove leading whitespaces */\n                $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);\n            }\n            if ($strip) {\n                /* strip all $text_blocks before the next '/strip' */\n                for ($j = $i + 1; $j < $for_max; $j++) {\n                    /* remove leading and trailing whitespaces of each line */\n                    $text_blocks[$j] = preg_replace('![\\t ]*[\\r\\n]+[\\t ]*!', '', $text_blocks[$j]);\n                    if ($compiled_tags[$j] == '{/strip}') {                       \n                        /* remove trailing whitespaces from the last text_block */\n                        $text_blocks[$j] = rtrim($text_blocks[$j]);\n                    }\n                    $text_blocks[$j] = \"<?php echo '\" . strtr($text_blocks[$j], array(\"'\"=>\"\\'\", \"\\\\\"=>\"\\\\\\\\\")) . \"'; ?>\";\n                    if ($compiled_tags[$j] == '{/strip}') {\n                        $compiled_tags[$j] = \"\\n\"; /* slurped by php, but necessary\n                                    if a newline is following the closing strip-tag */\n                        $strip = false;\n                        $i = $j;\n                        break;\n                    }\n                }\n            }\n        }\n        $compiled_content = '';\n\n        /* Interleave the compiled contents and text blocks to get the final result. */\n        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {\n            if ($compiled_tags[$i] == '') {\n                // tag result empty, remove first newline from following text block\n                $text_blocks[$i+1] = preg_replace('~^(\\r\\n|\\r|\\n)~', '', $text_blocks[$i+1]);\n            }\n            $compiled_content .= $text_blocks[$i].$compiled_tags[$i];\n        }\n        $compiled_content .= $text_blocks[$i];\n\n        // remove \\n from the end of the file, if any\n        if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == \"\\n\" )) {\n            $compiled_content = substr($compiled_content, 0, -1);\n        }\n\n        if (!empty($this->_cache_serial)) {\n            $compiled_content = \"<?php \\$this->_cache_serials['\".$this->_cache_include.\"'] = '\".$this->_cache_serial.\"'; ?>\" . $compiled_content;\n        }\n\n        // remove unnecessary close/open tags\n        $compiled_content = preg_replace('~\\?>\\n?<\\?php~', '', $compiled_content);\n\n        // run compiled template through postfilter functions\n        if (count($this->_plugins['postfilter']) > 0) {\n            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {\n                if ($postfilter === false) continue;\n                if ($postfilter[3] || is_callable($postfilter[0])) {\n                    $compiled_content = call_user_func_array($postfilter[0],\n                                                              array($compiled_content, &$this));\n                    $this->_plugins['postfilter'][$filter_name][3] = true;\n                } else {\n                    $this->_trigger_fatal_error(\"Smarty plugin error: postfilter '$filter_name' is not implemented\");\n                }\n            }\n        }\n\n        // put header at the top of the compiled template\n        $template_header = \"<?php /* Smarty version \".$this->_version.\", created on \".strftime(\"%Y-%m-%d %H:%M:%S\").\"\\n\";\n        $template_header .= \"         compiled from \".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':')).\" */ ?>\\n\";\n\n        /* Emit code to load needed plugins. */\n        $this->_plugins_code = '';\n        if (count($this->_plugin_info)) {\n            $_plugins_params = \"array('plugins' => array(\";\n            foreach ($this->_plugin_info as $plugin_type => $plugins) {\n                foreach ($plugins as $plugin_name => $plugin_info) {\n                    $_plugins_params .= \"array('$plugin_type', '$plugin_name', '\" . strtr($plugin_info[0], array(\"'\" => \"\\\\'\", \"\\\\\" => \"\\\\\\\\\")) . \"', $plugin_info[1], \";\n                    $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';\n                }\n            }\n            $_plugins_params .= '))';\n            $plugins_code = \"<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\\nsmarty_core_load_plugins($_plugins_params, \\$this); ?>\\n\";\n            $template_header .= $plugins_code;\n            $this->_plugin_info = array();\n            $this->_plugins_code = $plugins_code;\n        }\n\n        if ($this->_init_smarty_vars) {\n            $template_header .= \"<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\\nsmarty_core_assign_smarty_interface(null, \\$this); ?>\\n\";\n            $this->_init_smarty_vars = false;\n        }\n\n        $compiled_content = $template_header . $compiled_content;\n        return true;\n    }\n\n    /**\n     * Compile a template tag\n     *\n     * @param string $template_tag\n     * @return string\n     */\n    function _compile_tag($template_tag)\n    {\n        /* Matched comment. */\n        if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')\n            return '';\n        \n        /* Split tag into two three parts: command, command modifiers and the arguments. */\n        if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp\n                . '|\\/?' . $this->_reg_obj_regexp . '|\\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))\n                      (?:\\s+(.*))?$\n                    ~xs', $template_tag, $match)) {\n            $this->_syntax_error(\"unrecognized tag: $template_tag\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n        \n        $tag_command = $match[1];\n        $tag_modifier = isset($match[2]) ? $match[2] : null;\n        $tag_args = isset($match[3]) ? $match[3] : null;\n\n        if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {\n            /* tag name is a variable or object */\n            $_return = $this->_parse_var_props($tag_command . $tag_modifier);\n            return \"<?php echo $_return; ?>\" . $this->_additional_newline;\n        }\n\n        /* If the tag name is a registered object, we process it. */\n        if (preg_match('~^\\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {\n            return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);\n        }\n\n        switch ($tag_command) {\n            case 'include':\n                return $this->_compile_include_tag($tag_args);\n\n            case 'include_php':\n                return $this->_compile_include_php_tag($tag_args);\n\n            case 'if':\n                $this->_push_tag('if');\n                return $this->_compile_if_tag($tag_args);\n\n            case 'else':\n                list($_open_tag) = end($this->_tag_stack);\n                if ($_open_tag != 'if' && $_open_tag != 'elseif')\n                    $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);\n                else\n                    $this->_push_tag('else');\n                return '<?php else: ?>';\n\n            case 'elseif':\n                list($_open_tag) = end($this->_tag_stack);\n                if ($_open_tag != 'if' && $_open_tag != 'elseif')\n                    $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);\n                if ($_open_tag == 'if')\n                    $this->_push_tag('elseif');\n                return $this->_compile_if_tag($tag_args, true);\n\n            case '/if':\n                $this->_pop_tag('if');\n                return '<?php endif; ?>';\n\n            case 'capture':\n                return $this->_compile_capture_tag(true, $tag_args);\n\n            case '/capture':\n                return $this->_compile_capture_tag(false);\n\n            case 'ldelim':\n                return $this->left_delimiter;\n\n            case 'rdelim':\n                return $this->right_delimiter;\n\n            case 'section':\n                $this->_push_tag('section');\n                return $this->_compile_section_start($tag_args);\n\n            case 'sectionelse':\n                $this->_push_tag('sectionelse');\n                return \"<?php endfor; else: ?>\";\n                break;\n\n            case '/section':\n                $_open_tag = $this->_pop_tag('section');\n                if ($_open_tag == 'sectionelse')\n                    return \"<?php endif; ?>\";\n                else\n                    return \"<?php endfor; endif; ?>\";\n\n            case 'foreach':\n                $this->_push_tag('foreach');\n                return $this->_compile_foreach_start($tag_args);\n                break;\n\n            case 'foreachelse':\n                $this->_push_tag('foreachelse');\n                return \"<?php endforeach; else: ?>\";\n\n            case '/foreach':\n                $_open_tag = $this->_pop_tag('foreach');\n                if ($_open_tag == 'foreachelse')\n                    return \"<?php endif; unset(\\$_from); ?>\";\n                else\n                    return \"<?php endforeach; endif; unset(\\$_from); ?>\";\n                break;\n\n            case 'strip':\n            case '/strip':\n                if ($tag_command{0}=='/') {\n                    $this->_pop_tag('strip');\n                    if (--$this->_strip_depth==0) { /* outermost closing {/strip} */\n                        $this->_additional_newline = \"\\n\";\n                        return '{' . $tag_command . '}';\n                    }\n                } else {\n                    $this->_push_tag('strip');\n                    if ($this->_strip_depth++==0) { /* outermost opening {strip} */\n                        $this->_additional_newline = \"\";\n                        return '{' . $tag_command . '}';\n                    }\n                }\n                return '';\n\n            case 'php':\n                /* handle folded tags replaced by {php} */\n                list(, $block) = each($this->_folded_blocks);\n                $this->_current_line_no += substr_count($block[0], \"\\n\");\n                /* the number of matched elements in the regexp in _compile_file()\n                   determins the type of folded tag that was found */\n                switch (count($block)) {\n                    case 2: /* comment */\n                        return '';\n\n                    case 3: /* literal */\n                        return \"<?php echo '\" . strtr($block[2], array(\"'\"=>\"\\'\", \"\\\\\"=>\"\\\\\\\\\")) . \"'; ?>\" . $this->_additional_newline;\n\n                    case 4: /* php */\n                        if ($this->security && !$this->security_settings['PHP_TAGS']) {\n                            $this->_syntax_error(\"(secure mode) php tags not permitted\", E_USER_WARNING, __FILE__, __LINE__);\n                            return;\n                        }\n                        return '<?php ' . $block[3] .' ?>';\n                }\n                break;\n\n            case 'insert':\n                return $this->_compile_insert_tag($tag_args);\n\n            default:\n                if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {\n                    return $output;\n                } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {\n                    return $output;\n                } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {\n                    return $output;                    \n                } else {\n                    $this->_syntax_error(\"unrecognized tag '$tag_command'\", E_USER_ERROR, __FILE__, __LINE__);\n                }\n\n        }\n    }\n\n\n    /**\n     * compile the custom compiler tag\n     *\n     * sets $output to the compiled custom compiler tag\n     * @param string $tag_command\n     * @param string $tag_args\n     * @param string $output\n     * @return boolean\n     */\n    function _compile_compiler_tag($tag_command, $tag_args, &$output)\n    {\n        $found = false;\n        $have_function = true;\n\n        /*\n         * First we check if the compiler function has already been registered\n         * or loaded from a plugin file.\n         */\n        if (isset($this->_plugins['compiler'][$tag_command])) {\n            $found = true;\n            $plugin_func = $this->_plugins['compiler'][$tag_command][0];\n            if (!is_callable($plugin_func)) {\n                $message = \"compiler function '$tag_command' is not implemented\";\n                $have_function = false;\n            }\n        }\n        /*\n         * Otherwise we need to load plugin file and look for the function\n         * inside it.\n         */\n        else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {\n            $found = true;\n\n            include_once $plugin_file;\n\n            $plugin_func = 'smarty_compiler_' . $tag_command;\n            if (!is_callable($plugin_func)) {\n                $message = \"plugin function $plugin_func() not found in $plugin_file\\n\";\n                $have_function = false;\n            } else {\n                $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);\n            }\n        }\n\n        /*\n         * True return value means that we either found a plugin or a\n         * dynamically registered function. False means that we didn't and the\n         * compiler should now emit code to load custom function plugin for this\n         * tag.\n         */\n        if ($found) {\n            if ($have_function) {\n                $output = call_user_func_array($plugin_func, array($tag_args, &$this));\n                if($output != '') {\n                $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)\n                                   . $output\n                                   . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';\n                }\n            } else {\n                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);\n            }\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n\n    /**\n     * compile block function tag\n     *\n     * sets $output to compiled block function tag\n     * @param string $tag_command\n     * @param string $tag_args\n     * @param string $tag_modifier\n     * @param string $output\n     * @return boolean\n     */\n    function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)\n    {\n        if ($tag_command{0} == '/') {\n            $start_tag = false;\n            $tag_command = substr($tag_command, 1);\n        } else\n            $start_tag = true;\n\n        $found = false;\n        $have_function = true;\n\n        /*\n         * First we check if the block function has already been registered\n         * or loaded from a plugin file.\n         */\n        if (isset($this->_plugins['block'][$tag_command])) {\n            $found = true;\n            $plugin_func = $this->_plugins['block'][$tag_command][0];\n            if (!is_callable($plugin_func)) {\n                $message = \"block function '$tag_command' is not implemented\";\n                $have_function = false;\n            }\n        }\n        /*\n         * Otherwise we need to load plugin file and look for the function\n         * inside it.\n         */\n        else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {\n            $found = true;\n\n            include_once $plugin_file;\n\n            $plugin_func = 'smarty_block_' . $tag_command;\n            if (!function_exists($plugin_func)) {\n                $message = \"plugin function $plugin_func() not found in $plugin_file\\n\";\n                $have_function = false;\n            } else {\n                $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);\n\n            }\n        }\n\n        if (!$found) {\n            return false;\n        } else if (!$have_function) {\n            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);\n            return true;\n        }\n\n        /*\n         * Even though we've located the plugin function, compilation\n         * happens only once, so the plugin will still need to be loaded\n         * at runtime for future requests.\n         */\n        $this->_add_plugin('block', $tag_command);\n\n        if ($start_tag)\n            $this->_push_tag($tag_command);\n        else\n            $this->_pop_tag($tag_command);\n\n        if ($start_tag) {\n            $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);\n            $attrs = $this->_parse_attrs($tag_args);\n            $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs='');\n            $output .= \"$_cache_attrs\\$this->_tag_stack[] = array('$tag_command', array(\".implode(',', $arg_list).')); ';\n            $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);';\n            $output .= 'while ($_block_repeat) { ob_start(); ?>';\n        } else {\n            $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';\n            $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)';\n            if ($tag_modifier != '') {\n                $this->_parse_modifiers($_out_tag_text, $tag_modifier);\n            }\n            $output .= 'echo '.$_out_tag_text.'; } ';\n            $output .= \" array_pop(\\$this->_tag_stack); \" . $this->_pop_cacheable_state('block', $tag_command) . '?>';\n        }\n\n        return true;\n    }\n\n\n    /**\n     * compile custom function tag\n     *\n     * @param string $tag_command\n     * @param string $tag_args\n     * @param string $tag_modifier\n     * @return string\n     */\n    function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)\n    {\n        $found = false;\n        $have_function = true;\n\n        /*\n         * First we check if the custom function has already been registered\n         * or loaded from a plugin file.\n         */\n        if (isset($this->_plugins['function'][$tag_command])) {\n            $found = true;\n            $plugin_func = $this->_plugins['function'][$tag_command][0];\n            if (!is_callable($plugin_func)) {\n                $message = \"custom function '$tag_command' is not implemented\";\n                $have_function = false;\n            }\n        }\n        /*\n         * Otherwise we need to load plugin file and look for the function\n         * inside it.\n         */\n        else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {\n            $found = true;\n\n            include_once $plugin_file;\n\n            $plugin_func = 'smarty_function_' . $tag_command;\n            if (!function_exists($plugin_func)) {\n                $message = \"plugin function $plugin_func() not found in $plugin_file\\n\";\n                $have_function = false;\n            } else {\n                $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);\n\n            }\n        }\n\n        if (!$found) {\n            return false;\n        } else if (!$have_function) {\n            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);\n            return true;\n        }\n\n        /* declare plugin to be loaded on display of the template that\n           we compile right now */\n        $this->_add_plugin('function', $tag_command);\n\n        $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);\n        $attrs = $this->_parse_attrs($tag_args);\n        $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs='');\n\n        $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list).\"), \\$this)\";\n        if($tag_modifier != '') {\n            $this->_parse_modifiers($output, $tag_modifier);\n        }\n\n        if($output != '') {\n            $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'\n                . $this->_pop_cacheable_state('function', $tag_command) . \"?>\" . $this->_additional_newline;\n        }\n\n        return true;\n    }\n\n    /**\n     * compile a registered object tag\n     *\n     * @param string $tag_command\n     * @param array $attrs\n     * @param string $tag_modifier\n     * @return string\n     */\n    function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)\n    {\n        if ($tag_command{0} == '/') {\n            $start_tag = false;\n            $tag_command = substr($tag_command, 1);\n        } else {\n            $start_tag = true;\n        }\n\n        list($object, $obj_comp) = explode('->', $tag_command);\n\n        $arg_list = array();\n        if(count($attrs)) {\n            $_assign_var = false;\n            foreach ($attrs as $arg_name => $arg_value) {\n                if($arg_name == 'assign') {\n                    $_assign_var = $arg_value;\n                    unset($attrs['assign']);\n                    continue;\n                }\n                if (is_bool($arg_value))\n                    $arg_value = $arg_value ? 'true' : 'false';\n                $arg_list[] = \"'$arg_name' => $arg_value\";\n            }\n        }\n\n        if($this->_reg_objects[$object][2]) {\n            // smarty object argument format\n            $args = \"array(\".implode(',', (array)$arg_list).\"), \\$this\";\n        } else {\n            // traditional argument format\n            $args = implode(',', array_values($attrs));\n            if (empty($args)) {\n                $args = 'null';\n            }\n        }\n\n        $prefix = '';\n        $postfix = '';\n        $newline = '';\n        if(!is_object($this->_reg_objects[$object][0])) {\n            $this->_trigger_fatal_error(\"registered '$object' is not an object\" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);\n        } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {\n            $this->_trigger_fatal_error(\"'$obj_comp' is not a registered component of object '$object'\", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);\n        } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {\n            // method\n            if(in_array($obj_comp, $this->_reg_objects[$object][3])) {\n                // block method\n                if ($start_tag) {\n                    $prefix = \"\\$this->_tag_stack[] = array('$obj_comp', $args); \";\n                    $prefix .= \"\\$this->_reg_objects['$object'][0]->$obj_comp(\\$this->_tag_stack[count(\\$this->_tag_stack)-1][1], null, \\$this, \\$_block_repeat=true); \";\n                    $prefix .= \"while (\\$_block_repeat) { ob_start();\";\n                    $return = null;\n                    $postfix = '';\n            } else {\n                    $prefix = \"\\$_obj_block_content = ob_get_contents(); ob_end_clean(); \";\n                    $return = \"\\$this->_reg_objects['$object'][0]->$obj_comp(\\$this->_tag_stack[count(\\$this->_tag_stack)-1][1], \\$_obj_block_content, \\$this, \\$_block_repeat=false)\";\n                    $postfix = \"} array_pop(\\$this->_tag_stack);\";\n                }\n            } else {\n                // non-block method\n                $return = \"\\$this->_reg_objects['$object'][0]->$obj_comp($args)\";\n            }\n        } else {\n            // property\n            $return = \"\\$this->_reg_objects['$object'][0]->$obj_comp\";\n        }\n\n        if($return != null) {\n            if($tag_modifier != '') {\n                $this->_parse_modifiers($return, $tag_modifier);\n            }\n\n            if(!empty($_assign_var)) {\n                $output = \"\\$this->assign('\" . $this->_dequote($_assign_var) .\"',  $return);\";\n            } else {\n                $output = 'echo ' . $return . ';';\n                $newline = $this->_additional_newline;\n            }\n        } else {\n            $output = '';\n        }\n\n        return '<?php ' . $prefix . $output . $postfix . \"?>\" . $newline;\n    }\n\n    /**\n     * Compile {insert ...} tag\n     *\n     * @param string $tag_args\n     * @return string\n     */\n    function _compile_insert_tag($tag_args)\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n        $name = $this->_dequote($attrs['name']);\n\n        if (empty($name)) {\n            $this->_syntax_error(\"missing insert name\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        if (!empty($attrs['script'])) {\n            $delayed_loading = true;\n        } else {\n            $delayed_loading = false;\n        }\n\n        foreach ($attrs as $arg_name => $arg_value) {\n            if (is_bool($arg_value))\n                $arg_value = $arg_value ? 'true' : 'false';\n            $arg_list[] = \"'$arg_name' => $arg_value\";\n        }\n\n        $this->_add_plugin('insert', $name, $delayed_loading);\n\n        $_params = \"array('args' => array(\".implode(', ', (array)$arg_list).\"))\";\n\n        return \"<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\\necho smarty_core_run_insert_handler($_params, \\$this); ?>\" . $this->_additional_newline;\n    }\n\n    /**\n     * Compile {include ...} tag\n     *\n     * @param string $tag_args\n     * @return string\n     */\n    function _compile_include_tag($tag_args)\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n        $arg_list = array();\n\n        if (empty($attrs['file'])) {\n            $this->_syntax_error(\"missing 'file' attribute in include tag\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        foreach ($attrs as $arg_name => $arg_value) {\n            if ($arg_name == 'file') {\n                $include_file = $arg_value;\n                continue;\n            } else if ($arg_name == 'assign') {\n                $assign_var = $arg_value;\n                continue;\n            }\n            if (is_bool($arg_value))\n                $arg_value = $arg_value ? 'true' : 'false';\n            $arg_list[] = \"'$arg_name' => $arg_value\";\n        }\n\n        $output = '<?php ';\n\n        if (isset($assign_var)) {\n            $output .= \"ob_start();\\n\";\n        }\n\n        $output .=\n            \"\\$_smarty_tpl_vars = \\$this->_tpl_vars;\\n\";\n\n\n        $_params = \"array('smarty_include_tpl_file' => \" . $include_file . \", 'smarty_include_vars' => array(\".implode(',', (array)$arg_list).\"))\";\n        $output .= \"\\$this->_smarty_include($_params);\\n\" .\n        \"\\$this->_tpl_vars = \\$_smarty_tpl_vars;\\n\" .\n        \"unset(\\$_smarty_tpl_vars);\\n\";\n\n        if (isset($assign_var)) {\n            $output .= \"\\$this->assign(\" . $assign_var . \", ob_get_contents()); ob_end_clean();\\n\";\n        }\n\n        $output .= ' ?>';\n\n        return $output;\n\n    }\n\n    /**\n     * Compile {include ...} tag\n     *\n     * @param string $tag_args\n     * @return string\n     */\n    function _compile_include_php_tag($tag_args)\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n\n        if (empty($attrs['file'])) {\n            $this->_syntax_error(\"missing 'file' attribute in include_php tag\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);\n        $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';\n\n        $arg_list = array();\n        foreach($attrs as $arg_name => $arg_value) {\n            if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {\n                if(is_bool($arg_value))\n                    $arg_value = $arg_value ? 'true' : 'false';\n                $arg_list[] = \"'$arg_name' => $arg_value\";\n            }\n        }\n\n        $_params = \"array('smarty_file' => \" . $attrs['file'] . \", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(\".implode(',', $arg_list).\"))\";\n\n        return \"<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\\nsmarty_core_smarty_include_php($_params, \\$this); ?>\" . $this->_additional_newline;\n    }\n\n\n    /**\n     * Compile {section ...} tag\n     *\n     * @param string $tag_args\n     * @return string\n     */\n    function _compile_section_start($tag_args)\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n        $arg_list = array();\n\n        $output = '<?php ';\n        $section_name = $attrs['name'];\n        if (empty($section_name)) {\n            $this->_syntax_error(\"missing section name\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        $output .= \"unset(\\$this->_sections[$section_name]);\\n\";\n        $section_props = \"\\$this->_sections[$section_name]\";\n\n        foreach ($attrs as $attr_name => $attr_value) {\n            switch ($attr_name) {\n                case 'loop':\n                    $output .= \"{$section_props}['loop'] = is_array(\\$_loop=$attr_value) ? count(\\$_loop) : max(0, (int)\\$_loop); unset(\\$_loop);\\n\";\n                    break;\n\n                case 'show':\n                    if (is_bool($attr_value))\n                        $show_attr_value = $attr_value ? 'true' : 'false';\n                    else\n                        $show_attr_value = \"(bool)$attr_value\";\n                    $output .= \"{$section_props}['show'] = $show_attr_value;\\n\";\n                    break;\n\n                case 'name':\n                    $output .= \"{$section_props}['$attr_name'] = $attr_value;\\n\";\n                    break;\n\n                case 'max':\n                case 'start':\n                    $output .= \"{$section_props}['$attr_name'] = (int)$attr_value;\\n\";\n                    break;\n\n                case 'step':\n                    $output .= \"{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\\n\";\n                    break;\n\n                default:\n                    $this->_syntax_error(\"unknown section attribute - '$attr_name'\", E_USER_ERROR, __FILE__, __LINE__);\n                    break;\n            }\n        }\n\n        if (!isset($attrs['show']))\n            $output .= \"{$section_props}['show'] = true;\\n\";\n\n        if (!isset($attrs['loop']))\n            $output .= \"{$section_props}['loop'] = 1;\\n\";\n\n        if (!isset($attrs['max']))\n            $output .= \"{$section_props}['max'] = {$section_props}['loop'];\\n\";\n        else\n            $output .= \"if ({$section_props}['max'] < 0)\\n\" .\n                       \"    {$section_props}['max'] = {$section_props}['loop'];\\n\";\n\n        if (!isset($attrs['step']))\n            $output .= \"{$section_props}['step'] = 1;\\n\";\n\n        if (!isset($attrs['start']))\n            $output .= \"{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\\n\";\n        else {\n            $output .= \"if ({$section_props}['start'] < 0)\\n\" .\n                       \"    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\\n\" .\n                       \"else\\n\" .\n                       \"    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\\n\";\n        }\n\n        $output .= \"if ({$section_props}['show']) {\\n\";\n        if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {\n            $output .= \"    {$section_props}['total'] = {$section_props}['loop'];\\n\";\n        } else {\n            $output .= \"    {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\\n\";\n        }\n        $output .= \"    if ({$section_props}['total'] == 0)\\n\" .\n                   \"        {$section_props}['show'] = false;\\n\" .\n                   \"} else\\n\" .\n                   \"    {$section_props}['total'] = 0;\\n\";\n\n        $output .= \"if ({$section_props}['show']):\\n\";\n        $output .= \"\n            for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;\n                 {$section_props}['iteration'] <= {$section_props}['total'];\n                 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\\n\";\n        $output .= \"{$section_props}['rownum'] = {$section_props}['iteration'];\\n\";\n        $output .= \"{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\\n\";\n        $output .= \"{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\\n\";\n        $output .= \"{$section_props}['first']      = ({$section_props}['iteration'] == 1);\\n\";\n        $output .= \"{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\\n\";\n\n        $output .= \"?>\";\n\n        return $output;\n    }\n\n\n    /**\n     * Compile {foreach ...} tag.\n     *\n     * @param string $tag_args\n     * @return string\n     */\n    function _compile_foreach_start($tag_args)\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n        $arg_list = array();\n\n        if (empty($attrs['from'])) {\n            return $this->_syntax_error(\"foreach: missing 'from' attribute\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n        $from = $attrs['from'];\n\n        if (empty($attrs['item'])) {\n            return $this->_syntax_error(\"foreach: missing 'item' attribute\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n        $item = $this->_dequote($attrs['item']);\n        if (!preg_match('~^\\w+$~', $item)) {\n            return $this->_syntax_error(\"'foreach: item' must be a variable name (literal string)\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        if (isset($attrs['key'])) {\n            $key  = $this->_dequote($attrs['key']);\n            if (!preg_match('~^\\w+$~', $key)) {\n                return $this->_syntax_error(\"foreach: 'key' must to be a variable name (literal string)\", E_USER_ERROR, __FILE__, __LINE__);\n            }\n            $key_part = \"\\$this->_tpl_vars['$key'] => \";\n        } else {\n            $key = null;\n            $key_part = '';\n        }\n\n        if (isset($attrs['name'])) {\n            $name = $attrs['name'];\n        } else {\n            $name = null;\n        }\n\n        $output = '<?php ';\n        $output .= \"\\$_from = $from; if (!is_array(\\$_from) && !is_object(\\$_from)) { settype(\\$_from, 'array'); }\";\n        if (isset($name)) {\n            $foreach_props = \"\\$this->_foreach[$name]\";\n            $output .= \"{$foreach_props} = array('total' => count(\\$_from), 'iteration' => 0);\\n\";\n            $output .= \"if ({$foreach_props}['total'] > 0):\\n\";\n            $output .= \"    foreach (\\$_from as $key_part\\$this->_tpl_vars['$item']):\\n\";\n            $output .= \"        {$foreach_props}['iteration']++;\\n\";\n        } else {\n            $output .= \"if (count(\\$_from)):\\n\";\n            $output .= \"    foreach (\\$_from as $key_part\\$this->_tpl_vars['$item']):\\n\";\n        }\n        $output .= '?>';\n\n        return $output;\n    }\n\n\n    /**\n     * Compile {capture} .. {/capture} tags\n     *\n     * @param boolean $start true if this is the {capture} tag\n     * @param string $tag_args\n     * @return string\n     */\n\n    function _compile_capture_tag($start, $tag_args = '')\n    {\n        $attrs = $this->_parse_attrs($tag_args);\n\n        if ($start) {\n            if (isset($attrs['name']))\n                $buffer = $attrs['name'];\n            else\n                $buffer = \"'default'\";\n\n            if (isset($attrs['assign']))\n                $assign = $attrs['assign'];\n            else\n                $assign = null;\n            $output = \"<?php ob_start(); ?>\";\n            $this->_capture_stack[] = array($buffer, $assign);\n        } else {\n            list($buffer, $assign) = array_pop($this->_capture_stack);\n            $output = \"<?php \\$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); \";\n            if (isset($assign)) {\n                $output .= \" \\$this->assign($assign, ob_get_contents());\";\n            }\n            $output .= \"ob_end_clean(); ?>\";\n        }\n\n        return $output;\n    }\n\n    /**\n     * Compile {if ...} tag\n     *\n     * @param string $tag_args\n     * @param boolean $elseif if true, uses elseif instead of if\n     * @return string\n     */\n    function _compile_if_tag($tag_args, $elseif = false)\n    {\n\n        /* Tokenize args for 'if' tag. */\n        preg_match_all('~(?>\n                ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call\n                ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string\n                \\-?0[xX][0-9a-fA-F]+|\\-?\\d+(?:\\.\\d+)?|\\.\\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\\&\\&|\\|\\||\\(|\\)|,|\\!|\\^|=|\\&|\\~|<|>|\\||\\%|\\+|\\-|\\/|\\*|\\@    | # valid non-word token\n                \\b\\w+\\b                                                        | # valid word token\n                \\S+                                                           # anything else\n                )~x', $tag_args, $match);\n\n        $tokens = $match[0];\n\n        // make sure we have balanced parenthesis\n        $token_count = array_count_values($tokens);\n        if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {\n            $this->_syntax_error(\"unbalanced parenthesis in if statement\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        $is_arg_stack = array();\n\n        for ($i = 0; $i < count($tokens); $i++) {\n\n            $token = &$tokens[$i];\n\n            switch (strtolower($token)) {\n                case '!':\n                case '%':\n                case '!==':\n                case '==':\n                case '===':\n                case '>':\n                case '<':\n                case '!=':\n                case '<>':\n                case '<<':\n                case '>>':\n                case '<=':\n                case '>=':\n                case '&&':\n                case '||':\n                case '|':\n                case '^':\n                case '&':\n                case '~':\n                case ')':\n                case ',':\n                case '+':\n                case '-':\n                case '*':\n                case '/':\n                case '@':\n                    break;\n\n                case 'eq':\n                    $token = '==';\n                    break;\n\n                case 'ne':\n                case 'neq':\n                    $token = '!=';\n                    break;\n\n                case 'lt':\n                    $token = '<';\n                    break;\n\n                case 'le':\n                case 'lte':\n                    $token = '<=';\n                    break;\n\n                case 'gt':\n                    $token = '>';\n                    break;\n\n                case 'ge':\n                case 'gte':\n                    $token = '>=';\n                    break;\n\n                case 'and':\n                    $token = '&&';\n                    break;\n\n                case 'or':\n                    $token = '||';\n                    break;\n\n                case 'not':\n                    $token = '!';\n                    break;\n\n                case 'mod':\n                    $token = '%';\n                    break;\n\n                case '(':\n                    array_push($is_arg_stack, $i);\n                    break;\n\n                case 'is':\n                    /* If last token was a ')', we operate on the parenthesized\n                       expression. The start of the expression is on the stack.\n                       Otherwise, we operate on the last encountered token. */\n                    if ($tokens[$i-1] == ')')\n                        $is_arg_start = array_pop($is_arg_stack);\n                    else\n                        $is_arg_start = $i-1;\n                    /* Construct the argument for 'is' expression, so it knows\n                       what to operate on. */\n                    $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));\n\n                    /* Pass all tokens from next one until the end to the\n                       'is' expression parsing function. The function will\n                       return modified tokens, where the first one is the result\n                       of the 'is' expression and the rest are the tokens it\n                       didn't touch. */\n                    $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));\n\n                    /* Replace the old tokens with the new ones. */\n                    array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);\n\n                    /* Adjust argument start so that it won't change from the\n                       current position for the next iteration. */\n                    $i = $is_arg_start;\n                    break;\n\n                default:\n                    if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {\n                            // function call\n                            if($this->security &&\n                               !in_array($token, $this->security_settings['IF_FUNCS'])) {\n                                $this->_syntax_error(\"(secure mode) '$token' not allowed in if statement\", E_USER_ERROR, __FILE__, __LINE__);\n                            }\n                    } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {\n                        // variable function call\n                        $this->_syntax_error(\"variable function call '$token' not allowed in if statement\", E_USER_ERROR, __FILE__, __LINE__);                      \n                    } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {\n                        // object or variable\n                        $token = $this->_parse_var_props($token);\n                    } elseif(is_numeric($token)) {\n                        // number, skip it\n                    } else {\n                        $this->_syntax_error(\"unidentified token '$token'\", E_USER_ERROR, __FILE__, __LINE__);\n                    }\n                    break;\n            }\n        }\n\n        if ($elseif)\n            return '<?php elseif ('.implode(' ', $tokens).'): ?>';\n        else\n            return '<?php if ('.implode(' ', $tokens).'): ?>';\n    }\n\n\n    function _compile_arg_list($type, $name, $attrs, &$cache_code) {\n        $arg_list = array();\n\n        if (isset($type) && isset($name)\n            && isset($this->_plugins[$type])\n            && isset($this->_plugins[$type][$name])\n            && empty($this->_plugins[$type][$name][4])\n            && is_array($this->_plugins[$type][$name][5])\n            ) {\n            /* we have a list of parameters that should be cached */\n            $_cache_attrs = $this->_plugins[$type][$name][5];\n            $_count = $this->_cache_attrs_count++;\n            $cache_code = \"\\$_cache_attrs =& \\$this->_smarty_cache_attrs('$this->_cache_serial','$_count');\";\n\n        } else {\n            /* no parameters are cached */\n            $_cache_attrs = null;\n        }\n\n        foreach ($attrs as $arg_name => $arg_value) {\n            if (is_bool($arg_value))\n                $arg_value = $arg_value ? 'true' : 'false';\n            if (is_null($arg_value))\n                $arg_value = 'null';\n            if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {\n                $arg_list[] = \"'$arg_name' => (\\$this->_cache_including) ? \\$_cache_attrs['$arg_name'] : (\\$_cache_attrs['$arg_name']=$arg_value)\";\n            } else {\n                $arg_list[] = \"'$arg_name' => $arg_value\";\n            }\n        }\n        return $arg_list;\n    }\n\n    /**\n     * Parse is expression\n     *\n     * @param string $is_arg\n     * @param array $tokens\n     * @return array\n     */\n    function _parse_is_expr($is_arg, $tokens)\n    {\n        $expr_end = 0;\n        $negate_expr = false;\n\n        if (($first_token = array_shift($tokens)) == 'not') {\n            $negate_expr = true;\n            $expr_type = array_shift($tokens);\n        } else\n            $expr_type = $first_token;\n\n        switch ($expr_type) {\n            case 'even':\n                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {\n                    $expr_end++;\n                    $expr_arg = $tokens[$expr_end++];\n                    $expr = \"!(1 & ($is_arg / \" . $this->_parse_var_props($expr_arg) . \"))\";\n                } else\n                    $expr = \"!(1 & $is_arg)\";\n                break;\n\n            case 'odd':\n                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {\n                    $expr_end++;\n                    $expr_arg = $tokens[$expr_end++];\n                    $expr = \"(1 & ($is_arg / \" . $this->_parse_var_props($expr_arg) . \"))\";\n                } else\n                    $expr = \"(1 & $is_arg)\";\n                break;\n\n            case 'div':\n                if (@$tokens[$expr_end] == 'by') {\n                    $expr_end++;\n                    $expr_arg = $tokens[$expr_end++];\n                    $expr = \"!($is_arg % \" . $this->_parse_var_props($expr_arg) . \")\";\n                } else {\n                    $this->_syntax_error(\"expecting 'by' after 'div'\", E_USER_ERROR, __FILE__, __LINE__);\n                }\n                break;\n\n            default:\n                $this->_syntax_error(\"unknown 'is' expression - '$expr_type'\", E_USER_ERROR, __FILE__, __LINE__);\n                break;\n        }\n\n        if ($negate_expr) {\n            $expr = \"!($expr)\";\n        }\n\n        array_splice($tokens, 0, $expr_end, $expr);\n\n        return $tokens;\n    }\n\n\n    /**\n     * Parse attribute string\n     *\n     * @param string $tag_args\n     * @return array\n     */\n    function _parse_attrs($tag_args)\n    {\n\n        /* Tokenize tag attributes. */\n        preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^\"\\'=\\s]+)\n                         )+ |\n                         [=]\n                        ~x', $tag_args, $match);\n        $tokens       = $match[0];\n\n        $attrs = array();\n        /* Parse state:\n            0 - expecting attribute name\n            1 - expecting '='\n            2 - expecting attribute value (not '=') */\n        $state = 0;\n\n        foreach ($tokens as $token) {\n            switch ($state) {\n                case 0:\n                    /* If the token is a valid identifier, we set attribute name\n                       and go to state 1. */\n                    if (preg_match('~^\\w+$~', $token)) {\n                        $attr_name = $token;\n                        $state = 1;\n                    } else\n                        $this->_syntax_error(\"invalid attribute name: '$token'\", E_USER_ERROR, __FILE__, __LINE__);\n                    break;\n\n                case 1:\n                    /* If the token is '=', then we go to state 2. */\n                    if ($token == '=') {\n                        $state = 2;\n                    } else\n                        $this->_syntax_error(\"expecting '=' after attribute name '$last_token'\", E_USER_ERROR, __FILE__, __LINE__);\n                    break;\n\n                case 2:\n                    /* If token is not '=', we set the attribute value and go to\n                       state 0. */\n                    if ($token != '=') {\n                        /* We booleanize the token if it's a non-quoted possible\n                           boolean value. */\n                        if (preg_match('~^(on|yes|true)$~', $token)) {\n                            $token = 'true';\n                        } else if (preg_match('~^(off|no|false)$~', $token)) {\n                            $token = 'false';\n                        } else if ($token == 'null') {\n                            $token = 'null';\n                        } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {\n                            /* treat integer literally */\n                        } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {\n                            /* treat as a string, double-quote it escaping quotes */\n                            $token = '\"'.addslashes($token).'\"';\n                        }\n\n                        $attrs[$attr_name] = $token;\n                        $state = 0;\n                    } else\n                        $this->_syntax_error(\"'=' cannot be an attribute value\", E_USER_ERROR, __FILE__, __LINE__);\n                    break;\n            }\n            $last_token = $token;\n        }\n\n        if($state != 0) {\n            if($state == 1) {\n                $this->_syntax_error(\"expecting '=' after attribute name '$last_token'\", E_USER_ERROR, __FILE__, __LINE__);\n            } else {\n                $this->_syntax_error(\"missing attribute value\", E_USER_ERROR, __FILE__, __LINE__);\n            }\n        }\n\n        $this->_parse_vars_props($attrs);\n\n        return $attrs;\n    }\n\n    /**\n     * compile multiple variables and section properties tokens into\n     * PHP code\n     *\n     * @param array $tokens\n     */\n    function _parse_vars_props(&$tokens)\n    {\n        foreach($tokens as $key => $val) {\n            $tokens[$key] = $this->_parse_var_props($val);\n        }\n    }\n\n    /**\n     * compile single variable and section properties token into\n     * PHP code\n     *\n     * @param string $val\n     * @param string $tag_attrs\n     * @return string\n     */\n    function _parse_var_props($val)\n    {\n        $val = trim($val);\n\n        if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {\n            // $ variable or object\n            $return = $this->_parse_var($match[1]);\n            $modifiers = $match[2];\n            if (!empty($this->default_modifiers) && !preg_match('~(^|\\|)smarty:nodefaults($|\\|)~',$modifiers)) {\n                $_default_mod_string = implode('|',(array)$this->default_modifiers);\n                $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;\n            }\n            $this->_parse_modifiers($return, $modifiers);\n            return $return;\n        } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {\n                // double quoted text\n                preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);\n                $return = $this->_expand_quoted_text($match[1]);\n                if($match[2] != '') {\n                    $this->_parse_modifiers($return, $match[2]);\n                }\n                return $return;\n            }\n        elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {\n                // numerical constant\n                preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);\n                if($match[2] != '') {\n                    $this->_parse_modifiers($match[1], $match[2]);\n                    return $match[1];\n                }\n            }\n        elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {\n                // single quoted text\n                preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);\n                if($match[2] != '') {\n                    $this->_parse_modifiers($match[1], $match[2]);\n                    return $match[1];\n                }\n            }\n        elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {\n                // config var\n                return $this->_parse_conf_var($val);\n            }\n        elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {\n                // section var\n                return $this->_parse_section_prop($val);\n            }\n        elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {\n            // literal string\n            return $this->_expand_quoted_text('\"' . $val .'\"');\n        }\n        return $val;\n    }\n\n    /**\n     * expand quoted text with embedded variables\n     *\n     * @param string $var_expr\n     * @return string\n     */\n    function _expand_quoted_text($var_expr)\n    {\n        // if contains unescaped $, expand it\n        if(preg_match_all('~(?:\\`(?<!\\\\\\\\)\\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\\`)|(?:(?<!\\\\\\\\)\\$\\w+(\\[[a-zA-Z0-9]+\\])*)~', $var_expr, $_match)) {\n            $_match = $_match[0];\n            rsort($_match);\n            reset($_match);\n            foreach($_match as $_var) {\n                $var_expr = str_replace ($_var, '\".(' . $this->_parse_var(str_replace('`','',$_var)) . ').\"', $var_expr);\n            }\n            $_return = preg_replace('~\\.\"\"|(?<!\\\\\\\\)\"\"\\.~', '', $var_expr);\n        } else {\n            $_return = $var_expr;\n        }\n        // replace double quoted literal string with single quotes\n        $_return = preg_replace('~^\"([\\s\\w]+)\"$~',\"'\\\\1'\",$_return);\n        return $_return;\n    }\n\n    /**\n     * parse variable expression into PHP code\n     *\n     * @param string $var_expr\n     * @param string $output\n     * @return string\n     */\n    function _parse_var($var_expr)\n    {\n        $_has_math = false;\n        $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);\n\n        if(count($_math_vars) > 1) {\n            $_first_var = \"\";\n            $_complete_var = \"\";\n            $_output = \"\";\n            // simple check if there is any math, to stop recursion (due to modifiers with \"xx % yy\" as parameter)\n            foreach($_math_vars as $_k => $_math_var) {\n                $_math_var = $_math_vars[$_k];\n\n                if(!empty($_math_var) || is_numeric($_math_var)) {\n                    // hit a math operator, so process the stuff which came before it\n                    if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {\n                        $_has_math = true;\n                        if(!empty($_complete_var) || is_numeric($_complete_var)) {\n                            $_output .= $this->_parse_var($_complete_var);\n                        }\n\n                        // just output the math operator to php\n                        $_output .= $_math_var;\n\n                        if(empty($_first_var))\n                            $_first_var = $_complete_var;\n\n                        $_complete_var = \"\";\n                    } else {\n                        $_complete_var .= $_math_var;\n                    }\n                }\n            }\n            if($_has_math) {\n                if(!empty($_complete_var) || is_numeric($_complete_var))\n                    $_output .= $this->_parse_var($_complete_var);\n\n                // get the modifiers working (only the last var from math + modifier is left)\n                $var_expr = $_complete_var;\n            }\n        }\n\n        // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)\n        if(is_numeric($var_expr{0}))\n            $_var_ref = $var_expr;\n        else\n            $_var_ref = substr($var_expr, 1);\n        \n        if(!$_has_math) {\n            \n            // get [foo] and .foo and ->foo and (...) pieces\n            preg_match_all('~(?:^\\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\\$?\\w+|\\.\\$?\\w+|\\S+~', $_var_ref, $match);\n                        \n            $_indexes = $match[0];\n            $_var_name = array_shift($_indexes);\n\n            /* Handle $smarty.* variable references as a special case. */\n            if ($_var_name == 'smarty') {\n                /*\n                 * If the reference could be compiled, use the compiled output;\n                 * otherwise, fall back on the $smarty variable generated at\n                 * run-time.\n                 */\n                if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {\n                    $_output = $smarty_ref;\n                } else {\n                    $_var_name = substr(array_shift($_indexes), 1);\n                    $_output = \"\\$this->_smarty_vars['$_var_name']\";\n                }\n            } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) {\n                // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers\n                if(count($_indexes) > 0)\n                {\n                    $_var_name .= implode(\"\", $_indexes);\n                    $_indexes = array();\n                }\n                $_output = $_var_name;\n            } else {\n                $_output = \"\\$this->_tpl_vars['$_var_name']\";\n            }\n\n            foreach ($_indexes as $_index) {\n                if ($_index{0} == '[') {\n                    $_index = substr($_index, 1, -1);\n                    if (is_numeric($_index)) {\n                        $_output .= \"[$_index]\";\n                    } elseif ($_index{0} == '$') {\n                        if (strpos($_index, '.') !== false) {\n                            $_output .= '[' . $this->_parse_var($_index) . ']';\n                        } else {\n                            $_output .= \"[\\$this->_tpl_vars['\" . substr($_index, 1) . \"']]\";\n                        }\n                    } else {\n                        $_var_parts = explode('.', $_index);\n                        $_var_section = $_var_parts[0];\n                        $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';\n                        $_output .= \"[\\$this->_sections['$_var_section']['$_var_section_prop']]\";\n                    }\n                } else if ($_index{0} == '.') {\n                    if ($_index{1} == '$')\n                        $_output .= \"[\\$this->_tpl_vars['\" . substr($_index, 2) . \"']]\";\n                    else\n                        $_output .= \"['\" . substr($_index, 1) . \"']\";\n                } else if (substr($_index,0,2) == '->') {\n                    if(substr($_index,2,2) == '__') {\n                        $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);\n                    } elseif($this->security && substr($_index, 2, 1) == '_') {\n                        $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);\n                    } elseif ($_index{2} == '$') {\n                        if ($this->security) {\n                            $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);\n                        } else {\n                            $_output .= '->{(($_var=$this->_tpl_vars[\\''.substr($_index,3).'\\']) && substr($_var,0,2)!=\\'__\\') ? $_var : $this->trigger_error(\"cannot access property \\\\\"$_var\\\\\"\")}';\n                        }\n                    } else {\n                        $_output .= $_index;\n                    }\n                } elseif ($_index{0} == '(') {\n                    $_index = $this->_parse_parenth_args($_index);\n                    $_output .= $_index;\n                } else {\n                    $_output .= $_index;\n                }\n            }\n        }\n\n        return $_output;\n    }\n\n    /**\n     * parse arguments in function call parenthesis\n     *\n     * @param string $parenth_args\n     * @return string\n     */\n    function _parse_parenth_args($parenth_args)\n    {\n        preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);\n        $orig_vals = $match = $match[0];\n        $this->_parse_vars_props($match);\n        $replace = array();\n        for ($i = 0, $count = count($match); $i < $count; $i++) {\n            $replace[$orig_vals[$i]] = $match[$i];\n        }\n        return strtr($parenth_args, $replace);\n    }\n\n    /**\n     * parse configuration variable expression into PHP code\n     *\n     * @param string $conf_var_expr\n     */\n    function _parse_conf_var($conf_var_expr)\n    {\n        $parts = explode('|', $conf_var_expr, 2);\n        $var_ref = $parts[0];\n        $modifiers = isset($parts[1]) ? $parts[1] : '';\n\n        $var_name = substr($var_ref, 1, -1);\n\n        $output = \"\\$this->_config[0]['vars']['$var_name']\";\n\n        $this->_parse_modifiers($output, $modifiers);\n\n        return $output;\n    }\n\n    /**\n     * parse section property expression into PHP code\n     *\n     * @param string $section_prop_expr\n     * @return string\n     */\n    function _parse_section_prop($section_prop_expr)\n    {\n        $parts = explode('|', $section_prop_expr, 2);\n        $var_ref = $parts[0];\n        $modifiers = isset($parts[1]) ? $parts[1] : '';\n\n        preg_match('!%(\\w+)\\.(\\w+)%!', $var_ref, $match);\n        $section_name = $match[1];\n        $prop_name = $match[2];\n\n        $output = \"\\$this->_sections['$section_name']['$prop_name']\";\n\n        $this->_parse_modifiers($output, $modifiers);\n\n        return $output;\n    }\n\n\n    /**\n     * parse modifier chain into PHP code\n     *\n     * sets $output to parsed modified chain\n     * @param string $output\n     * @param string $modifier_string\n     */\n    function _parse_modifiers(&$output, $modifier_string)\n    {\n        preg_match_all('~\\|(@?\\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);\n        list(, $_modifiers, $modifier_arg_strings) = $_match;\n\n        for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {\n            $_modifier_name = $_modifiers[$_i];\n\n            if($_modifier_name == 'smarty') {\n                // skip smarty modifier\n                continue;\n            }\n\n            preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);\n            $_modifier_args = $_match[1];\n\n            if ($_modifier_name{0} == '@') {\n                $_map_array = false;\n                $_modifier_name = substr($_modifier_name, 1);\n            } else {\n                $_map_array = true;\n            }\n\n            if (empty($this->_plugins['modifier'][$_modifier_name])\n                && !$this->_get_plugin_filepath('modifier', $_modifier_name)\n                && function_exists($_modifier_name)) {\n                if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {\n                    $this->_trigger_fatal_error(\"[plugin] (secure mode) modifier '$_modifier_name' is not allowed\" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);\n                } else {\n                    $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);\n                }\n            }\n            $this->_add_plugin('modifier', $_modifier_name);\n\n            $this->_parse_vars_props($_modifier_args);\n\n            if($_modifier_name == 'default') {\n                // supress notifications of default modifier vars and args\n                if($output{0} == '$') {\n                    $output = '@' . $output;\n                }\n                if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') {\n                    $_modifier_args[0] = '@' . $_modifier_args[0];\n                }\n            }\n            if (count($_modifier_args) > 0)\n                $_modifier_args = ', '.implode(', ', $_modifier_args);\n            else\n                $_modifier_args = '';\n\n            if ($_map_array) {\n                $output = \"((is_array(\\$_tmp=$output)) ? \\$this->_run_mod_handler('$_modifier_name', true, \\$_tmp$_modifier_args) : \" . $this->_compile_plugin_call('modifier', $_modifier_name) . \"(\\$_tmp$_modifier_args))\";\n\n            } else {\n\n                $output = $this->_compile_plugin_call('modifier', $_modifier_name).\"($output$_modifier_args)\";\n\n            }\n        }\n    }\n\n\n    /**\n     * add plugin\n     *\n     * @param string $type\n     * @param string $name\n     * @param boolean? $delayed_loading\n     */\n    function _add_plugin($type, $name, $delayed_loading = null)\n    {\n        if (!isset($this->_plugin_info[$type])) {\n            $this->_plugin_info[$type] = array();\n        }\n        if (!isset($this->_plugin_info[$type][$name])) {\n            $this->_plugin_info[$type][$name] = array($this->_current_file,\n                                                      $this->_current_line_no,\n                                                      $delayed_loading);\n        }\n    }\n\n\n    /**\n     * Compiles references of type $smarty.foo\n     *\n     * @param string $indexes\n     * @return string\n     */\n    function _compile_smarty_ref(&$indexes)\n    {\n        /* Extract the reference name. */\n        $_ref = substr($indexes[0], 1);\n        foreach($indexes as $_index_no=>$_index) {\n            if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\\.|\\[|->)~', $_index)) {\n                $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);\n            }\n        }\n\n        switch ($_ref) {\n            case 'now':\n                $compiled_ref = 'time()';\n                $_max_index = 1;\n                break;\n\n            case 'foreach':\n                array_shift($indexes);\n                $_var = $this->_parse_var_props(substr($indexes[0], 1));\n                $_propname = substr($indexes[1], 1);\n                $_max_index = 1;\n                switch ($_propname) {\n                    case 'index':\n                        array_shift($indexes);\n                        $compiled_ref = \"(\\$this->_foreach[$_var]['iteration']-1)\";\n                        break;\n                        \n                    case 'first':\n                        array_shift($indexes);\n                        $compiled_ref = \"(\\$this->_foreach[$_var]['iteration'] <= 1)\";\n                        break;\n\n                    case 'last':\n                        array_shift($indexes);\n                        $compiled_ref = \"(\\$this->_foreach[$_var]['iteration'] == \\$this->_foreach[$_var]['total'])\";\n                        break;\n                        \n                    case 'show':\n                        array_shift($indexes);\n                        $compiled_ref = \"(\\$this->_foreach[$_var]['total'] > 0)\";\n                        break;\n                        \n                    default:\n                        unset($_max_index);\n                        $compiled_ref = \"\\$this->_foreach[$_var]\";\n                }\n                break;\n\n            case 'section':\n                array_shift($indexes);\n                $_var = $this->_parse_var_props(substr($indexes[0], 1));\n                $compiled_ref = \"\\$this->_sections[$_var]\";\n                break;\n\n            case 'get':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : \"\\$GLOBALS['HTTP_GET_VARS']\";\n                break;\n\n            case 'post':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : \"\\$GLOBALS['HTTP_POST_VARS']\";\n                break;\n\n            case 'cookies':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : \"\\$GLOBALS['HTTP_COOKIE_VARS']\";\n                break;\n\n            case 'env':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : \"\\$GLOBALS['HTTP_ENV_VARS']\";\n                break;\n\n            case 'server':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : \"\\$GLOBALS['HTTP_SERVER_VARS']\";\n                break;\n\n            case 'session':\n                $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : \"\\$GLOBALS['HTTP_SESSION_VARS']\";\n                break;\n\n            /*\n             * These cases are handled either at run-time or elsewhere in the\n             * compiler.\n             */\n            case 'request':\n                if ($this->request_use_auto_globals) {\n                    $compiled_ref = '$_REQUEST';\n                    break;\n                } else {\n                    $this->_init_smarty_vars = true;\n                }\n                return null;\n\n            case 'capture':\n                return null;\n\n            case 'template':\n                $compiled_ref = \"'$this->_current_file'\";\n                $_max_index = 1;\n                break;\n\n            case 'version':\n                $compiled_ref = \"'$this->_version'\";\n                $_max_index = 1;\n                break;\n\n            case 'const':\n                if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {\n                    $this->_syntax_error(\"(secure mode) constants not permitted\",\n                                         E_USER_WARNING, __FILE__, __LINE__);\n                    return;\n                }\n                array_shift($indexes);\n                if (preg_match('!^\\.\\w+$!', $indexes[0])) {\n                    $compiled_ref = '@' . substr($indexes[0], 1);\n                } else {\n                    $_val = $this->_parse_var_props(substr($indexes[0], 1));\n                    $compiled_ref = '@constant(' . $_val . ')';\n                }\n                $_max_index = 1;\n                break;\n\n            case 'config':\n                $compiled_ref = \"\\$this->_config[0]['vars']\";\n                $_max_index = 3;\n                break;\n\n            case 'ldelim':\n                $compiled_ref = \"'$this->left_delimiter'\";\n                break;\n\n            case 'rdelim':\n                $compiled_ref = \"'$this->right_delimiter'\";\n                break;\n                \n            default:\n                $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);\n                break;\n        }\n\n        if (isset($_max_index) && count($indexes) > $_max_index) {\n            $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        array_shift($indexes);\n        return $compiled_ref;\n    }\n\n    /**\n     * compiles call to plugin of type $type with name $name\n     * returns a string containing the function-name or method call\n     * without the paramter-list that would have follow to make the\n     * call valid php-syntax\n     *\n     * @param string $type\n     * @param string $name\n     * @return string\n     */\n    function _compile_plugin_call($type, $name) {\n        if (isset($this->_plugins[$type][$name])) {\n            /* plugin loaded */\n            if (is_array($this->_plugins[$type][$name][0])) {\n                return ((is_object($this->_plugins[$type][$name][0][0])) ?\n                        \"\\$this->_plugins['$type']['$name'][0][0]->\"    /* method callback */\n                        : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */\n                       ). $this->_plugins[$type][$name][0][1];\n\n            } else {\n                /* function callback */\n                return $this->_plugins[$type][$name][0];\n\n            }\n        } else {\n            /* plugin not loaded -> auto-loadable-plugin */\n            return 'smarty_'.$type.'_'.$name;\n\n        }\n    }\n\n    /**\n     * load pre- and post-filters\n     */\n    function _load_filters()\n    {\n        if (count($this->_plugins['prefilter']) > 0) {\n            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {\n                if ($prefilter === false) {\n                    unset($this->_plugins['prefilter'][$filter_name]);\n                    $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));\n                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\n                    smarty_core_load_plugins($_params, $this);\n                }\n            }\n        }\n        if (count($this->_plugins['postfilter']) > 0) {\n            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {\n                if ($postfilter === false) {\n                    unset($this->_plugins['postfilter'][$filter_name]);\n                    $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));\n                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\n                    smarty_core_load_plugins($_params, $this);\n                }\n            }\n        }\n    }\n\n\n    /**\n     * Quote subpattern references\n     *\n     * @param string $string\n     * @return string\n     */\n    function _quote_replace($string)\n    {\n        return strtr($string, array('\\\\' => '\\\\\\\\', '$' => '\\\\$'));\n    }\n\n    /**\n     * display Smarty syntax error\n     *\n     * @param string $error_msg\n     * @param integer $error_type\n     * @param string $file\n     * @param integer $line\n     */\n    function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)\n    {\n        $this->_trigger_fatal_error(\"syntax error: $error_msg\", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);\n    }\n\n\n    /**\n     * check if the compilation changes from cacheable to\n     * non-cacheable state with the beginning of the current\n     * plugin. return php-code to reflect the transition.\n     * @return string\n     */\n    function _push_cacheable_state($type, $name) {\n        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];\n        if ($_cacheable\n            || 0<$this->_cacheable_state++) return '';\n        if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));\n        $_ret = 'if ($this->caching && !$this->_cache_including) { echo \\'{nocache:'\n            . $this->_cache_serial . '#' . $this->_nocache_count\n            . '}\\';}';\n        return $_ret;\n    }\n\n\n    /**\n     * check if the compilation changes from non-cacheable to\n     * cacheable state with the end of the current plugin return\n     * php-code to reflect the transition.\n     * @return string\n     */\n    function _pop_cacheable_state($type, $name) {\n        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];\n        if ($_cacheable\n            || --$this->_cacheable_state>0) return '';\n        return 'if ($this->caching && !$this->_cache_including) { echo \\'{/nocache:'\n            . $this->_cache_serial . '#' . ($this->_nocache_count++)\n            . '}\\';}';\n    }\n\n\n    /**\n     * push opening tag-name, file-name and line-number on the tag-stack\n     * @param string the opening tag's name\n     */\n    function _push_tag($open_tag)\n    {\n        array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));\n    }\n\n    /**\n     * pop closing tag-name\n     * raise an error if this stack-top doesn't match with the closing tag\n     * @param string the closing tag's name\n     * @return string the opening tag's name\n     */\n    function _pop_tag($close_tag)\n    {\n        $message = '';\n        if (count($this->_tag_stack)>0) {\n            list($_open_tag, $_line_no) = array_pop($this->_tag_stack);\n            if ($close_tag == $_open_tag) {\n                return $_open_tag;\n            }\n            if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {\n                return $this->_pop_tag($close_tag);\n            }\n            if ($close_tag == 'section' && $_open_tag == 'sectionelse') {\n                $this->_pop_tag($close_tag);\n                return $_open_tag;\n            }\n            if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {\n                $this->_pop_tag($close_tag);\n                return $_open_tag;\n            }\n            if ($_open_tag == 'else' || $_open_tag == 'elseif') {\n                $_open_tag = 'if';\n            } elseif ($_open_tag == 'sectionelse') {\n                $_open_tag = 'section';\n            } elseif ($_open_tag == 'foreachelse') {\n                $_open_tag = 'foreach';\n            }\n            $message = \" expected {/$_open_tag} (opened line $_line_no).\";\n        }\n        $this->_syntax_error(\"mismatched tag {/$close_tag}.$message\",\n                             E_USER_ERROR, __FILE__, __LINE__);\n    }\n\n}\n\n/**\n * compare to values by their string length\n *\n * @access private\n * @param string $a\n * @param string $b\n * @return 0|-1|1\n */\nfunction _smarty_sort_length($a, $b)\n{\n    if($a == $b)\n        return 0;\n\n    if(strlen($a) == strlen($b))\n        return ($a > $b) ? -1 : 1;\n\n    return (strlen($a) > strlen($b)) ? -1 : 1;\n}\n\n\n/* vim: set et: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/debug.tpl",
    "content": "{* Smarty *}\n\n{* debug.tpl, last updated version 2.0.1 *}\n\n{assign_debug_info}\n\n{if isset($_smarty_debug_output) and $_smarty_debug_output eq \"html\"}\n\t<table border=0 width=100%>\n\t<tr bgcolor=#cccccc><th colspan=2>Smarty Debug Console</th></tr>\n\t<tr bgcolor=#cccccc><td colspan=2><b>included templates & config files (load time in seconds):</b></td></tr>\n\t{section name=templates loop=$_debug_tpls}\n\t\t<tr bgcolor={if %templates.index% is even}#eeeeee{else}#fafafa{/if}><td colspan=2><tt>{section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}<font color={if $_debug_tpls[templates].type eq \"template\"}brown{elseif $_debug_tpls[templates].type eq \"insert\"}black{else}green{/if}>{$_debug_tpls[templates].filename|escape:html}</font>{if isset($_debug_tpls[templates].exec_time)} <font size=-1><i>({$_debug_tpls[templates].exec_time|string_format:\"%.5f\"}){if %templates.index% eq 0} (total){/if}</i></font>{/if}</tt></td></tr>\n\t{sectionelse}\n\t\t<tr bgcolor=#eeeeee><td colspan=2><tt><i>no templates included</i></tt></td></tr>\t\n\t{/section}\n\t<tr bgcolor=#cccccc><td colspan=2><b>assigned template variables:</b></td></tr>\n\t{section name=vars loop=$_debug_keys}\n\t\t<tr bgcolor={if %vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=blue>{ldelim}${$_debug_keys[vars]}{rdelim}</font></tt></td><td nowrap><tt><font color=green>{$_debug_vals[vars]|@debug_print_var}</font></tt></td></tr>\n\t{sectionelse}\n\t\t<tr bgcolor=#eeeeee><td colspan=2><tt><i>no template variables assigned</i></tt></td></tr>\t\n\t{/section}\n\t<tr bgcolor=#cccccc><td colspan=2><b>assigned config file variables (outer template scope):</b></td></tr>\n\t{section name=config_vars loop=$_debug_config_keys}\n\t\t<tr bgcolor={if %config_vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=maroon>{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}</font></tt></td><td><tt><font color=green>{$_debug_config_vals[config_vars]|@debug_print_var}</font></tt></td></tr>\n\t{sectionelse}\n\t\t<tr bgcolor=#eeeeee><td colspan=2><tt><i>no config vars assigned</i></tt></td></tr>\t\n\t{/section}\n\t</table>\n</BODY></HTML>\n{else}\n<SCRIPT language=javascript>\n\tif( self.name == '' ) {ldelim}\n\t   var title = 'Console';\n\t{rdelim}\n\telse {ldelim}\n\t   var title = 'Console_' + self.name;\n\t{rdelim}\n\t_smarty_console = window.open(\"\",title.value,\"width=680,height=600,resizable,scrollbars=yes\");\n\t_smarty_console.document.write(\"<HTML><HEAD><TITLE>Smarty Debug Console_\"+self.name+\"</TITLE></HEAD><BODY bgcolor=#ffffff>\");\n\t_smarty_console.document.write(\"<table border=0 width=100%>\");\n\t_smarty_console.document.write(\"<tr bgcolor=#cccccc><th colspan=2>Smarty Debug Console</th></tr>\");\n\t_smarty_console.document.write(\"<tr bgcolor=#cccccc><td colspan=2><b>included templates & config files (load time in seconds):</b></td></tr>\");\n\t{section name=templates loop=$_debug_tpls}\n\t\t_smarty_console.document.write(\"<tr bgcolor={if %templates.index% is even}#eeeeee{else}#fafafa{/if}><td colspan=2><tt>{section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}<font color={if $_debug_tpls[templates].type eq \"template\"}brown{elseif $_debug_tpls[templates].type eq \"insert\"}black{else}green{/if}>{$_debug_tpls[templates].filename|escape:html|escape:javascript}</font>{if isset($_debug_tpls[templates].exec_time)} <font size=-1><i>({$_debug_tpls[templates].exec_time|string_format:\"%.5f\"}){if %templates.index% eq 0} (total){/if}</i></font>{/if}</tt></td></tr>\");\n\t{sectionelse}\n\t\t_smarty_console.document.write(\"<tr bgcolor=#eeeeee><td colspan=2><tt><i>no templates included</i></tt></td></tr>\");\t\n\t{/section}\n\t_smarty_console.document.write(\"<tr bgcolor=#cccccc><td colspan=2><b>assigned template variables:</b></td></tr>\");\n\t{section name=vars loop=$_debug_keys}\n\t\t_smarty_console.document.write(\"<tr bgcolor={if %vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=blue>{ldelim}${$_debug_keys[vars]}{rdelim}</font></tt></td><td nowrap><tt><font color=green>{$_debug_vals[vars]|@debug_print_var|escape:javascript}</font></tt></td></tr>\");\n\t{sectionelse}\n\t\t_smarty_console.document.write(\"<tr bgcolor=#eeeeee><td colspan=2><tt><i>no template variables assigned</i></tt></td></tr>\");\t\n\t{/section}\n\t_smarty_console.document.write(\"<tr bgcolor=#cccccc><td colspan=2><b>assigned config file variables (outer template scope):</b></td></tr>\");\n\t{section name=config_vars loop=$_debug_config_keys}\n\t\t_smarty_console.document.write(\"<tr bgcolor={if %config_vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=maroon>{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}</font></tt></td><td><tt><font color=green>{$_debug_config_vals[config_vars]|@debug_print_var|escape:javascript}</font></tt></td></tr>\");\n\t{sectionelse}\n\t\t_smarty_console.document.write(\"<tr bgcolor=#eeeeee><td colspan=2><tt><i>no config vars assigned</i></tt></td></tr>\");\t\n\t{/section}\n\t_smarty_console.document.write(\"</table>\");\n\t_smarty_console.document.write(\"</BODY></HTML>\");\n\t_smarty_console.document.close();\n</SCRIPT>\n{/if}\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.assemble_plugin_filepath.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * assemble filepath of requested plugin\n *\n * @param string $type\n * @param string $name\n * @return string|false\n */\nfunction smarty_core_assemble_plugin_filepath($params, &$smarty)\n{\n    static $_filepaths_cache = array();\n\n    $_plugin_filename = $params['type'] . '.' . $params['name'] . '.php';\n    if (isset($_filepaths_cache[$_plugin_filename])) {\n        return $_filepaths_cache[$_plugin_filename];\n    }\n    $_return = false;\n\n    foreach ((array)$smarty->plugins_dir as $_plugin_dir) {\n\n        $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;\n\n        // see if path is relative\n        if (!preg_match(\"/^([\\/\\\\\\\\]|[a-zA-Z]:[\\/\\\\\\\\])/\", $_plugin_dir)) {\n            $_relative_paths[] = $_plugin_dir;\n            // relative path, see if it is in the SMARTY_DIR\n            if (@is_readable(SMARTY_DIR . $_plugin_filepath)) {\n                $_return = SMARTY_DIR . $_plugin_filepath;\n                break;\n            }\n        }\n        // try relative to cwd (or absolute)\n        if (@is_readable($_plugin_filepath)) {\n            $_return = $_plugin_filepath;\n            break;\n        }\n    }\n\n    if($_return === false) {\n        // still not found, try PHP include_path\n        if(isset($_relative_paths)) {\n            foreach ((array)$_relative_paths as $_plugin_dir) {\n\n                $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;\n\n                $_params = array('file_path' => $_plugin_filepath);\n                require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');\n                if(smarty_core_get_include_path($_params, $smarty)) {\n                    $_return = $_params['new_file_path'];\n                    break;\n                }\n            }\n        }\n    }\n    $_filepaths_cache[$_plugin_filename] = $_return;\n    return $_return;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.assign_smarty_interface.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty assign_smarty_interface core plugin\n *\n * Type:     core<br>\n * Name:     assign_smarty_interface<br>\n * Purpose:  assign the $smarty interface variable\n * @param array Format: null\n * @param Smarty\n */\nfunction smarty_core_assign_smarty_interface($params, &$smarty)\n{\n        if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) {\n            return;\n        }\n\n        $_globals_map = array('g'  => 'HTTP_GET_VARS',\n                             'p'  => 'HTTP_POST_VARS',\n                             'c'  => 'HTTP_COOKIE_VARS',\n                             's'  => 'HTTP_SERVER_VARS',\n                             'e'  => 'HTTP_ENV_VARS');\n\n        $_smarty_vars_request  = array();\n\n        foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) {\n            if (isset($_globals_map[$_c])) {\n                $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]);\n            }\n        }\n        $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']);\n\n        $smarty->_smarty_vars['request'] = $_smarty_vars_request;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.create_dir_structure.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * create full directory structure\n *\n * @param string $dir\n */\n\n// $dir\n\nfunction smarty_core_create_dir_structure($params, &$smarty)\n{\n    if (!file_exists($params['dir'])) {\n        $_open_basedir_ini = ini_get('open_basedir');\n\n        if (DIRECTORY_SEPARATOR=='/') {\n            /* unix-style paths */\n            $_dir = $params['dir'];\n            $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);\n            $_new_dir = ($_dir{0}=='/') ? '/' : getcwd().'/';\n            if($_use_open_basedir = !empty($_open_basedir_ini)) {\n                $_open_basedirs = explode(':', $_open_basedir_ini);\n            }\n\n        } else {\n            /* other-style paths */\n            $_dir = str_replace('\\\\','/', $params['dir']);\n            $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);\n            if (preg_match('!^((//)|([a-zA-Z]:/))!', $_dir, $_root_dir)) {\n                /* leading \"//\" for network volume, or \"[letter]:/\" for full path */\n                $_new_dir = $_root_dir[1];\n                /* remove drive-letter from _dir_parts */\n                if (isset($_root_dir[3])) array_shift($_dir_parts);\n\n            } else {\n                $_new_dir = str_replace('\\\\', '/', getcwd()).'/';\n\n            }\n\n            if($_use_open_basedir = !empty($_open_basedir_ini)) {\n                $_open_basedirs = explode(';', str_replace('\\\\', '/', $_open_basedir_ini));\n            }\n\n        }\n\n        /* all paths use \"/\" only from here */\n        foreach ($_dir_parts as $_dir_part) {\n            $_new_dir .= $_dir_part;\n\n            if ($_use_open_basedir) {\n                // do not attempt to test or make directories outside of open_basedir\n                $_make_new_dir = false;\n                foreach ($_open_basedirs as $_open_basedir) {\n                    if (substr($_new_dir, 0, strlen($_open_basedir)) == $_open_basedir) {\n                        $_make_new_dir = true;\n                        break;\n                    }\n                }\n            } else {\n                $_make_new_dir = true;\n            }\n\n            if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, $smarty->_dir_perms) && !is_dir($_new_dir)) {\n                $smarty->trigger_error(\"problem creating directory '\" . $_new_dir . \"'\");\n                return false;\n            }\n            $_new_dir .= '/';\n        }\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.display_debug_console.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty debug_console function plugin\n *\n * Type:     core<br>\n * Name:     display_debug_console<br>\n * Purpose:  display the javascript debug console window\n * @param array Format: null\n * @param Smarty\n */\nfunction smarty_core_display_debug_console($params, &$smarty)\n{\n    // we must force compile the debug template in case the environment\n    // changed between separate applications.\n\n    if(empty($smarty->debug_tpl)) {\n        // set path to debug template from SMARTY_DIR\n        $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl';\n        if($smarty->security && is_file($smarty->debug_tpl)) {\n            $smarty->secure_dir[] = dirname(realpath($smarty->debug_tpl));\n        }\n        $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl';\n    }\n\n    $_ldelim_orig = $smarty->left_delimiter;\n    $_rdelim_orig = $smarty->right_delimiter;\n\n    $smarty->left_delimiter = '{';\n    $smarty->right_delimiter = '}';\n\n    $_compile_id_orig = $smarty->_compile_id;\n    $smarty->_compile_id = null;\n\n    $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl);\n    if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path))\n    {\n        ob_start();\n        $smarty->_include($_compile_path);\n        $_results = ob_get_contents();\n        ob_end_clean();\n    } else {\n        $_results = '';\n    }\n\n    $smarty->_compile_id = $_compile_id_orig;\n\n    $smarty->left_delimiter = $_ldelim_orig;\n    $smarty->right_delimiter = $_rdelim_orig;\n\n    return $_results;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.get_include_path.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Get path to file from include_path\n *\n * @param string $file_path\n * @param string $new_file_path\n * @return boolean\n * @staticvar array|null\n */\n\n//  $file_path, &$new_file_path\n\nfunction smarty_core_get_include_path(&$params, &$smarty)\n{\n    static $_path_array = null;\n\n    if(!isset($_path_array)) {\n        $_ini_include_path = ini_get('include_path');\n\n        if(strstr($_ini_include_path,';')) {\n            // windows pathnames\n            $_path_array = explode(';',$_ini_include_path);\n        } else {\n            $_path_array = explode(':',$_ini_include_path);\n        }\n    }\n    foreach ($_path_array as $_include_path) {\n        if (@is_readable($_include_path . DIRECTORY_SEPARATOR . $params['file_path'])) {\n               $params['new_file_path'] = $_include_path . DIRECTORY_SEPARATOR . $params['file_path'];\n            return true;\n        }\n    }\n    return false;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.get_microtime.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Get seconds and microseconds\n * @return double\n */\nfunction smarty_core_get_microtime($params, &$smarty)\n{\n    $mtime = microtime();\n    $mtime = explode(\" \", $mtime);\n    $mtime = (double)($mtime[1]) + (double)($mtime[0]);\n    return ($mtime);\n}\n\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.get_php_resource.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Retrieves PHP script resource\n *\n * sets $php_resource to the returned resource\n * @param string $resource\n * @param string $resource_type\n * @param  $php_resource\n * @return boolean\n */\n\nfunction smarty_core_get_php_resource(&$params, &$smarty)\n{\n\n    $params['resource_base_path'] = $smarty->trusted_dir;\n    $smarty->_parse_resource_name($params, $smarty);\n\n    /*\n     * Find out if the resource exists.\n     */\n\n    if ($params['resource_type'] == 'file') {\n        $_readable = false;\n        if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) {\n            $_readable = true;\n        } else {\n            // test for file in include_path\n            $_params = array('file_path' => $params['resource_name']);\n            require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');\n            if(smarty_core_get_include_path($_params, $smarty)) {\n                $_include_path = $_params['new_file_path'];\n                $_readable = true;\n            }\n        }\n    } else if ($params['resource_type'] != 'file') {\n        $_template_source = null;\n        $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0])\n            && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0],\n                                    array($params['resource_name'], &$_template_source, &$smarty));\n    }\n\n    /*\n     * Set the error function, depending on which class calls us.\n     */\n    if (method_exists($smarty, '_syntax_error')) {\n        $_error_funcc = '_syntax_error';\n    } else {\n        $_error_funcc = 'trigger_error';\n    }\n\n    if ($_readable) {\n        if ($smarty->security) {\n            require_once(SMARTY_CORE_DIR . 'core.is_trusted.php');\n            if (!smarty_core_is_trusted($params, $smarty)) {\n                $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted');\n                return false;\n            }\n        }\n    } else {\n        $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable');\n        return false;\n    }\n\n    if ($params['resource_type'] == 'file') {\n        $params['php_resource'] = $params['resource_name'];\n    } else {\n        $params['php_resource'] = $_template_source;\n    }\n    return true;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.is_secure.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * determines if a resource is secure or not.\n *\n * @param string $resource_type\n * @param string $resource_name\n * @return boolean\n */\n\n//  $resource_type, $resource_name\n\nfunction smarty_core_is_secure($params, &$smarty)\n{\n    if (!$smarty->security || $smarty->security_settings['INCLUDE_ANY']) {\n        return true;\n    }\n\n    if ($params['resource_type'] == 'file') {\n        $_rp = realpath($params['resource_name']);\n        if (isset($params['resource_base_path'])) {\n            foreach ((array)$params['resource_base_path'] as $curr_dir) {\n                if ( ($_cd = realpath($curr_dir)) !== false &&\n                     strncmp($_rp, $_cd, strlen($_cd)) == 0 &&\n                     $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {\n                    return true;\n                }\n            }\n        }\n        if (!empty($smarty->secure_dir)) {\n            foreach ((array)$smarty->secure_dir as $curr_dir) {\n                if ( ($_cd = realpath($curr_dir)) !== false &&\n                     strncmp($_rp, $_cd, strlen($_cd)) == 0 &&\n                     $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {\n                    return true;\n                }            \n            }\n        }\n    } else {\n        // resource is not on local file system\n        return call_user_func_array(\n            $smarty->_plugins['resource'][$params['resource_type']][0][2],\n            array($params['resource_name'], &$smarty));\n    }\n\n    return false;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.is_trusted.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * determines if a resource is trusted or not\n *\n * @param string $resource_type\n * @param string $resource_name\n * @return boolean\n */\n\n // $resource_type, $resource_name\n\nfunction smarty_core_is_trusted($params, &$smarty)\n{\n    $_smarty_trusted = false;\n    if ($params['resource_type'] == 'file') {\n        if (!empty($smarty->trusted_dir)) {\n            $_rp = realpath($params['resource_name']);\n            foreach ((array)$smarty->trusted_dir as $curr_dir) {\n                if (!empty($curr_dir) && is_readable ($curr_dir)) {\n                    $_cd = realpath($curr_dir);\n                    if (strncmp($_rp, $_cd, strlen($_cd)) == 0\n                        && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {\n                        $_smarty_trusted = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n    } else {\n        // resource is not on local file system\n        $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3],\n                                                array($params['resource_name'], $smarty));\n    }\n\n    return $_smarty_trusted;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.load_plugins.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Load requested plugins\n *\n * @param array $plugins\n */\n\n// $plugins\n\nfunction smarty_core_load_plugins($params, &$smarty)\n{\n\n    foreach ($params['plugins'] as $_plugin_info) {\n        list($_type, $_name, $_tpl_file, $_tpl_line, $_delayed_loading) = $_plugin_info;\n        $_plugin = &$smarty->_plugins[$_type][$_name];\n\n        /*\n         * We do not load plugin more than once for each instance of Smarty.\n         * The following code checks for that. The plugin can also be\n         * registered dynamically at runtime, in which case template file\n         * and line number will be unknown, so we fill them in.\n         *\n         * The final element of the info array is a flag that indicates\n         * whether the dynamically registered plugin function has been\n         * checked for existence yet or not.\n         */\n        if (isset($_plugin)) {\n            if (empty($_plugin[3])) {\n                if (!is_callable($_plugin[0])) {\n                    $smarty->_trigger_fatal_error(\"[plugin] $_type '$_name' is not implemented\", $_tpl_file, $_tpl_line, __FILE__, __LINE__);\n                } else {\n                    $_plugin[1] = $_tpl_file;\n                    $_plugin[2] = $_tpl_line;\n                    $_plugin[3] = true;\n                    if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */\n                }\n            }\n            continue;\n        } else if ($_type == 'insert') {\n            /*\n             * For backwards compatibility, we check for insert functions in\n             * the symbol table before trying to load them as a plugin.\n             */\n            $_plugin_func = 'insert_' . $_name;\n            if (function_exists($_plugin_func)) {\n                $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false);\n                continue;\n            }\n        }\n\n        $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name);\n\n        if (! $_found = ($_plugin_file != false)) {\n            $_message = \"could not load plugin file '$_type.$_name.php'\\n\";\n        }\n\n        /*\n         * If plugin file is found, it -must- provide the properly named\n         * plugin function. In case it doesn't, simply output the error and\n         * do not fall back on any other method.\n         */\n        if ($_found) {\n            include_once $_plugin_file;\n\n            $_plugin_func = 'smarty_' . $_type . '_' . $_name;\n            if (!function_exists($_plugin_func)) {\n                $smarty->_trigger_fatal_error(\"[plugin] function $_plugin_func() not found in $_plugin_file\", $_tpl_file, $_tpl_line, __FILE__, __LINE__);\n                continue;\n            }\n        }\n        /*\n         * In case of insert plugins, their code may be loaded later via\n         * 'script' attribute.\n         */\n        else if ($_type == 'insert' && $_delayed_loading) {\n            $_plugin_func = 'smarty_' . $_type . '_' . $_name;\n            $_found = true;\n        }\n\n        /*\n         * Plugin specific processing and error checking.\n         */\n        if (!$_found) {\n            if ($_type == 'modifier') {\n                /*\n                 * In case modifier falls back on using PHP functions\n                 * directly, we only allow those specified in the security\n                 * context.\n                 */\n                if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) {\n                    $_message = \"(secure mode) modifier '$_name' is not allowed\";\n                } else {\n                    if (!function_exists($_name)) {\n                        $_message = \"modifier '$_name' is not implemented\";\n                    } else {\n                        $_plugin_func = $_name;\n                        $_found = true;\n                    }\n                }\n            } else if ($_type == 'function') {\n                /*\n                 * This is a catch-all situation.\n                 */\n                $_message = \"unknown tag - '$_name'\";\n            }\n        }\n\n        if ($_found) {\n            $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true);\n        } else {\n            // output error\n            $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__);\n        }\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.load_resource_plugin.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * load a resource plugin\n *\n * @param string $type\n */\n\n// $type\n\nfunction smarty_core_load_resource_plugin($params, &$smarty)\n{\n    /*\n     * Resource plugins are not quite like the other ones, so they are\n     * handled differently. The first element of plugin info is the array of\n     * functions provided by the plugin, the second one indicates whether\n     * all of them exist or not.\n     */\n\n    $_plugin = &$smarty->_plugins['resource'][$params['type']];\n    if (isset($_plugin)) {\n        if (!$_plugin[1] && count($_plugin[0])) {\n            $_plugin[1] = true;\n            foreach ($_plugin[0] as $_plugin_func) {\n                if (!is_callable($_plugin_func)) {\n                    $_plugin[1] = false;\n                    break;\n                }\n            }\n        }\n\n        if (!$_plugin[1]) {\n            $smarty->_trigger_fatal_error(\"[plugin] resource '\" . $params['type'] . \"' is not implemented\", null, null, __FILE__, __LINE__);\n        }\n\n        return;\n    }\n\n    $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']);\n    $_found = ($_plugin_file != false);\n\n    if ($_found) {            /*\n         * If the plugin file is found, it -must- provide the properly named\n         * plugin functions.\n         */\n        include_once($_plugin_file);\n\n        /*\n         * Locate functions that we require the plugin to provide.\n         */\n        $_resource_ops = array('source', 'timestamp', 'secure', 'trusted');\n        $_resource_funcs = array();\n        foreach ($_resource_ops as $_op) {\n            $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op;\n            if (!function_exists($_plugin_func)) {\n                $smarty->_trigger_fatal_error(\"[plugin] function $_plugin_func() not found in $_plugin_file\", null, null, __FILE__, __LINE__);\n                return;\n            } else {\n                $_resource_funcs[] = $_plugin_func;\n            }\n        }\n\n        $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true);\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.process_cached_inserts.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Replace cached inserts with the actual results\n *\n * @param string $results\n * @return string\n */\nfunction smarty_core_process_cached_inserts($params, &$smarty)\n{\n    preg_match_all('!'.$smarty->_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis',\n                   $params['results'], $match);\n    list($cached_inserts, $insert_args) = $match;\n\n    for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {\n        if ($smarty->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $debug_start_time = smarty_core_get_microtime($_params, $smarty);\n        }\n\n        $args = unserialize($insert_args[$i]);\n        $name = $args['name'];\n\n        if (isset($args['script'])) {\n            $_params = array('resource_name' => $smarty->_dequote($args['script']));\n            require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');\n            if(!smarty_core_get_php_resource($_params, $smarty)) {\n                return false;\n            }\n            $resource_type = $_params['resource_type'];\n            $php_resource = $_params['php_resource'];\n\n\n            if ($resource_type == 'file') {\n                $smarty->_include($php_resource, true);\n            } else {\n                $smarty->_eval($php_resource);\n            }\n        }\n\n        $function_name = $smarty->_plugins['insert'][$name][0];\n        if (empty($args['assign'])) {\n            $replace = $function_name($args, $smarty);\n        } else {\n            $smarty->assign($args['assign'], $function_name($args, $smarty));\n            $replace = '';\n        }\n\n        $params['results'] = str_replace($cached_inserts[$i], $replace, $params['results']);\n        if ($smarty->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $smarty->_smarty_debug_info[] = array('type'      => 'insert',\n                                                'filename'  => 'insert_'.$name,\n                                                'depth'     => $smarty->_inclusion_depth,\n                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);\n        }\n    }\n\n    return $params['results'];\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.process_compiled_include.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Replace nocache-tags by results of the corresponding non-cacheable\n * functions and return it\n *\n * @param string $compiled_tpl\n * @param string $cached_source\n * @return string\n */\n\nfunction smarty_core_process_compiled_include($params, &$smarty)\n{\n    $_cache_including = $smarty->_cache_including;\n    $smarty->_cache_including = true;\n\n    $_return = $params['results'];\n    foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) {\n        $_return = preg_replace_callback('!(\\{nocache\\:('.$_cache_serial.')#(\\d+)\\})!s',\n                                         array(&$smarty, '_process_compiled_include_callback'),\n                                         $_return);\n    }\n    $smarty->_cache_including = $_cache_including;\n    return $_return;\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.read_cache_file.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * read a cache file, determine if it needs to be\n * regenerated or not\n *\n * @param string $tpl_file\n * @param string $cache_id\n * @param string $compile_id\n * @param string $results\n * @return boolean\n */\n\n//  $tpl_file, $cache_id, $compile_id, &$results\n\nfunction smarty_core_read_cache_file(&$params, &$smarty)\n{\n    static  $content_cache = array();\n\n    if ($smarty->force_compile) {\n        // force compile enabled, always regenerate\n        return false;\n    }\n\n    if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) {\n        list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']];\n        return true;\n    }\n\n    if (!empty($smarty->cache_handler_func)) {\n        // use cache_handler function\n        call_user_func_array($smarty->cache_handler_func,\n                             array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));\n    } else {\n        // use local cache file\n        $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);\n        $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);\n        $params['results'] = $smarty->_read_file($_cache_file);\n    }\n\n    if (empty($params['results'])) {\n        // nothing to parse (error?), regenerate cache\n        return false;\n    }\n\n    $_contents = $params['results'];\n    $_info_start = strpos($_contents, \"\\n\") + 1;\n    $_info_len = (int)substr($_contents, 0, $_info_start - 1);\n    $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len));\n    $params['results'] = substr($_contents, $_info_start + $_info_len);\n\n    if ($smarty->caching == 2 && isset ($_cache_info['expires'])){\n        // caching by expiration time\n        if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) {\n            // cache expired, regenerate\n            return false;\n        }\n    } else {\n        // caching by lifetime\n        if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) {\n            // cache expired, regenerate\n            return false;\n        }\n    }\n\n    if ($smarty->compile_check) {\n        $_params = array('get_source' => false, 'quiet'=>true);\n        foreach (array_keys($_cache_info['template']) as $_template_dep) {\n            $_params['resource_name'] = $_template_dep;\n            if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {\n                // template file has changed, regenerate cache\n                return false;\n            }\n        }\n\n        if (isset($_cache_info['config'])) {\n            $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true);\n            foreach (array_keys($_cache_info['config']) as $_config_dep) {\n                $_params['resource_name'] = $_config_dep;\n                if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {\n                    // config file has changed, regenerate cache\n                    return false;\n                }\n            }\n        }\n    }\n\n    foreach ($_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) {\n        if (empty($smarty->_cache_serials[$_include_file_path])) {\n            $smarty->_include($_include_file_path, true);\n        }\n\n        if ($smarty->_cache_serials[$_include_file_path] != $_cache_serial) {\n            /* regenerate */\n            return false;\n        }\n    }\n    $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info);\n\n    $smarty->_cache_info = $_cache_info;\n    return true;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.rm_auto.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * delete an automagically created file by name and id\n *\n * @param string $auto_base\n * @param string $auto_source\n * @param string $auto_id\n * @param integer $exp_time\n * @return boolean\n */\n\n// $auto_base, $auto_source = null, $auto_id = null, $exp_time = null\n\nfunction smarty_core_rm_auto($params, &$smarty)\n{\n    if (!@is_dir($params['auto_base']))\n      return false;\n\n    if(!isset($params['auto_id']) && !isset($params['auto_source'])) {\n        $_params = array(\n            'dirname' => $params['auto_base'],\n            'level' => 0,\n            'exp_time' => $params['exp_time']\n        );\n        require_once(SMARTY_CORE_DIR . 'core.rmdir.php');\n        $_res = smarty_core_rmdir($_params, $smarty);\n    } else {\n        $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']);\n\n        if(isset($params['auto_source'])) {\n            if (isset($params['extensions'])) {\n                $_res = false;\n                foreach ((array)$params['extensions'] as $_extension)\n                    $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']);\n            } else {\n                $_res = $smarty->_unlink($_tname, $params['exp_time']);\n            }\n        } elseif ($smarty->use_sub_dirs) {\n            $_params = array(\n                'dirname' => $_tname,\n                'level' => 1,\n                'exp_time' => $params['exp_time']\n            );\n            require_once(SMARTY_CORE_DIR . 'core.rmdir.php');\n            $_res = smarty_core_rmdir($_params, $smarty);\n        } else {\n            // remove matching file names\n            $_handle = opendir($params['auto_base']);\n            $_res = true;\n            while (false !== ($_filename = readdir($_handle))) {\n                if($_filename == '.' || $_filename == '..') {\n                    continue;\n                } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) {\n                    $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']);\n                }\n            }\n        }\n    }\n\n    return $_res;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.rmdir.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * delete a dir recursively (level=0 -> keep root)\n * WARNING: no tests, it will try to remove what you tell it!\n *\n * @param string $dirname\n * @param integer $level\n * @param integer $exp_time\n * @return boolean\n */\n\n//  $dirname, $level = 1, $exp_time = null\n\nfunction smarty_core_rmdir($params, &$smarty)\n{\n   if(!isset($params['level'])) { $params['level'] = 1; }\n   if(!isset($params['exp_time'])) { $params['exp_time'] = null; }\n\n   if($_handle = @opendir($params['dirname'])) {\n\n        while (false !== ($_entry = readdir($_handle))) {\n            if ($_entry != '.' && $_entry != '..') {\n                if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) {\n                    $_params = array(\n                        'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry,\n                        'level' => $params['level'] + 1,\n                        'exp_time' => $params['exp_time']\n                    );\n                    require_once(SMARTY_CORE_DIR . 'core.rmdir.php');\n                    smarty_core_rmdir($_params, $smarty);\n                }\n                else {\n                    $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']);\n                }\n            }\n        }\n        closedir($_handle);\n   }\n\n   if ($params['level']) {\n       return @rmdir($params['dirname']);\n   }\n   return (bool)$_handle;\n\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.run_insert_handler.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Handle insert tags\n *\n * @param array $args\n * @return string\n */\nfunction smarty_core_run_insert_handler($params, &$smarty)\n{\n\n    require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n    if ($smarty->debugging) {\n        $_params = array();\n        $_debug_start_time = smarty_core_get_microtime($_params, $smarty);\n    }\n\n    if ($smarty->caching) {\n        $_arg_string = serialize($params['args']);\n        $_name = $params['args']['name'];\n        if (!isset($smarty->_cache_info['insert_tags'][$_name])) {\n            $smarty->_cache_info['insert_tags'][$_name] = array('insert',\n                                                             $_name,\n                                                             $smarty->_plugins['insert'][$_name][1],\n                                                             $smarty->_plugins['insert'][$_name][2],\n                                                             !empty($params['args']['script']) ? true : false);\n        }\n        return $smarty->_smarty_md5.\"{insert_cache $_arg_string}\".$smarty->_smarty_md5;\n    } else {\n        if (isset($params['args']['script'])) {\n            $_params = array('resource_name' => $smarty->_dequote($params['args']['script']));\n            require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');\n            if(!smarty_core_get_php_resource($_params, $smarty)) {\n                return false;\n            }\n\n            if ($_params['resource_type'] == 'file') {\n                $smarty->_include($_params['php_resource'], true);\n            } else {\n                $smarty->_eval($_params['php_resource']);\n            }\n            unset($params['args']['script']);\n        }\n\n        $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0];\n        $_content = $_funcname($params['args'], $smarty);\n        if ($smarty->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $smarty->_smarty_debug_info[] = array('type'      => 'insert',\n                                                'filename'  => 'insert_'.$params['args']['name'],\n                                                'depth'     => $smarty->_inclusion_depth,\n                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);\n        }\n\n        if (!empty($params['args'][\"assign\"])) {\n            $smarty->assign($params['args'][\"assign\"], $_content);\n        } else {\n            return $_content;\n        }\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.smarty_include_php.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * called for included php files within templates\n *\n * @param string $smarty_file\n * @param string $smarty_assign variable to assign the included template's\n *               output into\n * @param boolean $smarty_once uses include_once if this is true\n * @param array $smarty_include_vars associative array of vars from\n *              {include file=\"blah\" var=$var}\n */\n\n//  $file, $assign, $once, $_smarty_include_vars\n\nfunction smarty_core_smarty_include_php($params, &$smarty)\n{\n    $_params = array('resource_name' => $params['smarty_file']);\n    require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');\n    smarty_core_get_php_resource($_params, $smarty);\n    $_smarty_resource_type = $_params['resource_type'];\n    $_smarty_php_resource = $_params['php_resource'];\n\n    if (!empty($params['smarty_assign'])) {\n        ob_start();\n        if ($_smarty_resource_type == 'file') {\n            $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);\n        } else {\n            $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);\n        }\n        $smarty->assign($params['smarty_assign'], ob_get_contents());\n        ob_end_clean();\n    } else {\n        if ($_smarty_resource_type == 'file') {\n            $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);\n        } else {\n            $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);\n        }\n    }\n}\n\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.write_cache_file.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Prepend the cache information to the cache file\n * and write it\n *\n * @param string $tpl_file\n * @param string $cache_id\n * @param string $compile_id\n * @param string $results\n * @return true|null\n */\n\n // $tpl_file, $cache_id, $compile_id, $results\n\nfunction smarty_core_write_cache_file($params, &$smarty)\n{\n\n    // put timestamp in cache header\n    $smarty->_cache_info['timestamp'] = time();\n    if ($smarty->cache_lifetime > -1){\n        // expiration set\n        $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime;\n    } else {\n        // cache will never expire\n        $smarty->_cache_info['expires'] = -1;\n    }\n\n    // collapse nocache.../nocache-tags\n    if (preg_match_all('!\\{(/?)nocache\\:[0-9a-f]{32}#\\d+\\}!', $params['results'], $match, PREG_PATTERN_ORDER)) {\n        // remove everything between every pair of outermost noache.../nocache-tags\n        // and replace it by a single nocache-tag\n        // this new nocache-tag will be replaced by dynamic contents in\n        // smarty_core_process_compiled_includes() on a cache-read\n        \n        $match_count = count($match[0]);\n        $results = preg_split('!(\\{/?nocache\\:[0-9a-f]{32}#\\d+\\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE);\n        \n        $level = 0;\n        $j = 0;\n        for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) {\n            if ($results[$i] == $match[0][$j]) {\n                // nocache tag\n                if ($match[1][$j]) { // closing tag\n                    $level--;\n                    unset($results[$i]);\n                } else { // opening tag\n                    if ($level++ > 0) unset($results[$i]);\n                }\n                $j++;\n            } elseif ($level > 0) {\n                unset($results[$i]);\n            }\n        }\n        $params['results'] = implode('', $results);\n    }\n    $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials;\n\n    // prepend the cache header info into cache file\n    $_cache_info = serialize($smarty->_cache_info);\n    $params['results'] = strlen($_cache_info) . \"\\n\" . $_cache_info . $params['results'];\n\n    if (!empty($smarty->cache_handler_func)) {\n        // use cache_handler function\n        call_user_func_array($smarty->cache_handler_func,\n                             array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));\n    } else {\n        // use local cache file\n\n        if(!@is_writable($smarty->cache_dir)) {\n            // cache_dir not writable, see if it exists\n            if(!@is_dir($smarty->cache_dir)) {\n                $smarty->trigger_error('the $cache_dir \\'' . $smarty->cache_dir . '\\' does not exist, or is not a directory.', E_USER_ERROR);\n                return false;\n            }\n            $smarty->trigger_error('unable to write to $cache_dir \\'' . realpath($smarty->cache_dir) . '\\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR);\n            return false;\n        }\n\n        $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);\n        $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);\n        $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true);\n        require_once(SMARTY_CORE_DIR . 'core.write_file.php');\n        smarty_core_write_file($_params, $smarty);\n        return true;\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.write_compiled_include.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Extract non-cacheable parts out of compiled template and write it\n *\n * @param string $compile_path\n * @param string $template_compiled\n * @return boolean\n */\n\nfunction smarty_core_write_compiled_include($params, &$smarty)\n{\n    $_tag_start = 'if \\(\\$this->caching && \\!\\$this->_cache_including\\) \\{ echo \\'\\{nocache\\:('.$params['cache_serial'].')#(\\d+)\\}\\';\\}';\n    $_tag_end   = 'if \\(\\$this->caching && \\!\\$this->_cache_including\\) \\{ echo \\'\\{/nocache\\:(\\\\2)#(\\\\3)\\}\\';\\}';\n\n    preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us',\n                   $params['compiled_content'], $_match_source, PREG_SET_ORDER);\n\n    // no nocache-parts found: done\n    if (count($_match_source)==0) return;\n\n    // convert the matched php-code to functions\n    $_include_compiled =  \"<?php /* Smarty version \".$smarty->_version.\", created on \".strftime(\"%Y-%m-%d %H:%M:%S\").\"\\n\";\n    $_include_compiled .= \"         compiled from \" . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . \" */\\n\\n\";\n\n    $_compile_path = $params['include_file_path'];\n\n    $smarty->_cache_serials[$_compile_path] = $params['cache_serial'];\n    $_include_compiled .= \"\\$this->_cache_serials['\".$_compile_path.\"'] = '\".$params['cache_serial'].\"';\\n\\n?>\";\n\n    $_include_compiled .= $params['plugins_code'];\n    $_include_compiled .= \"<?php\";\n\n    $this_varname = ((double)phpversion() >= 5.0) ? '_smarty' : 'this';\n    for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) {\n        $_match =& $_match_source[$_i];\n        $source = $_match[4];\n        if ($this_varname == '_smarty') {\n            /* rename $this to $_smarty in the sourcecode */\n            $tokens = token_get_all('<?php ' . $_match[4]);\n\n            /* remove trailing <?php */\n            $open_tag = '';\n            while ($tokens) {\n                $token = array_shift($tokens);\n                if (is_array($token)) {\n                    $open_tag .= $token[1];\n                } else {\n                    $open_tag .= $token;\n                }\n                if ($open_tag == '<?php ') break;\n            }\n\n            for ($i=0, $count = count($tokens); $i < $count; $i++) {\n                if (is_array($tokens[$i])) {\n                    if ($tokens[$i][0] == T_VARIABLE && $tokens[$i][1] == '$this') {\n                        $tokens[$i] = '$' . $this_varname;\n                    } else {\n                        $tokens[$i] = $tokens[$i][1];\n                    }                   \n                }\n            }\n            $source = implode('', $tokens);\n        }\n\n        /* add function to compiled include */\n        $_include_compiled .= \"\nfunction _smarty_tplfunc_$_match[2]_$_match[3](&\\$$this_varname)\n{\n$source\n}\n\n\";\n    }\n    $_include_compiled .= \"\\n\\n?>\\n\";\n\n    $_params = array('filename' => $_compile_path,\n                     'contents' => $_include_compiled, 'create_dirs' => true);\n\n    require_once(SMARTY_CORE_DIR . 'core.write_file.php');\n    smarty_core_write_file($_params, $smarty);\n    return true;\n}\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.write_compiled_resource.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * write the compiled resource\n *\n * @param string $compile_path\n * @param string $compiled_content\n * @return true\n */\nfunction smarty_core_write_compiled_resource($params, &$smarty)\n{\n    if(!@is_writable($smarty->compile_dir)) {\n        // compile_dir not writable, see if it exists\n        if(!@is_dir($smarty->compile_dir)) {\n            $smarty->trigger_error('the $compile_dir \\'' . $smarty->compile_dir . '\\' does not exist, or is not a directory.', E_USER_ERROR);\n            return false;\n        }\n        $smarty->trigger_error('unable to write to $compile_dir \\'' . realpath($smarty->compile_dir) . '\\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR);\n        return false;\n    }\n\n    $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true);\n    require_once(SMARTY_CORE_DIR . 'core.write_file.php');\n    smarty_core_write_file($_params, $smarty);\n    return true;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/internals/core.write_file.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * write out a file to disk\n *\n * @param string $filename\n * @param string $contents\n * @param boolean $create_dirs\n * @return boolean\n */\nfunction smarty_core_write_file($params, &$smarty)\n{\n    $_dirname = dirname($params['filename']);\n\n    if ($params['create_dirs']) {\n        $_params = array('dir' => $_dirname);\n        require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php');\n        smarty_core_create_dir_structure($_params, $smarty);\n    }\n\n    // write to tmp file, then rename it to avoid\n    // file locking race condition\n    $_tmp_file = tempnam($_dirname, 'wrt');\n\n    if (!($fd = @fopen($_tmp_file, 'wb'))) {\n        $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt');\n        if (!($fd = @fopen($_tmp_file, 'wb'))) {\n            $smarty->trigger_error(\"problem writing temporary file '$_tmp_file'\");\n            return false;\n        }\n    }\n\n    fwrite($fd, $params['contents']);\n    fclose($fd);\n\n    // Delete the file if it allready exists (this is needed on Win,\n    // because it cannot overwrite files with rename()\n    if (file_exists($params['filename'])) {\n        @unlink($params['filename']);\n    }\n    @rename($_tmp_file, $params['filename']);\n    @chmod($params['filename'], $smarty->_file_perms);\n\n    return true;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/block.textformat.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {textformat}{/textformat} block plugin\n *\n * Type:     block function<br>\n * Name:     textformat<br>\n * Purpose:  format text a certain way with preset styles\n *           or custom wrap/indent settings<br>\n * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat}\n *       (Smarty online manual)\n * @param array\n * <pre>\n * Params:   style: string (email)\n *           indent: integer (0)\n *           wrap: integer (80)\n *           wrap_char string (\"\\n\")\n *           indent_char: string (\" \")\n *           wrap_boundary: boolean (true)\n * </pre>\n * @param string contents of the block\n * @param Smarty clever simulation of a method\n * @return string string $content re-formatted\n */\nfunction smarty_block_textformat($params, $content, &$smarty)\n{\n    if (is_null($content)) {\n        return;\n    }\n\n    $style = null;\n    $indent = 0;\n    $indent_first = 0;\n    $indent_char = ' ';\n    $wrap = 80;\n    $wrap_char = \"\\n\";\n    $wrap_cut = false;\n    $assign = null;\n    \n    foreach ($params as $_key => $_val) {\n        switch ($_key) {\n            case 'style':\n            case 'indent_char':\n            case 'wrap_char':\n            case 'assign':\n                $$_key = (string)$_val;\n                break;\n\n            case 'indent':\n            case 'indent_first':\n            case 'wrap':\n                $$_key = (int)$_val;\n                break;\n\n            case 'wrap_cut':\n                $$_key = (bool)$_val;\n                break;\n\n            default:\n                $smarty->trigger_error(\"textformat: unknown attribute '$_key'\");\n        }\n    }\n\n    if ($style == 'email') {\n        $wrap = 72;\n    }\n\n    // split into paragraphs\n    $_paragraphs = preg_split('![\\r\\n][\\r\\n]!',$content);\n    $_output = '';\n\n    for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) {\n        if ($_paragraphs[$_x] == '') {\n            continue;\n        }\n        // convert mult. spaces & special chars to single space\n        $_paragraphs[$_x] = preg_replace(array('!\\s+!','!(^\\s+)|(\\s+$)!'), array(' ',''), $_paragraphs[$_x]);\n        // indent first line\n        if($indent_first > 0) {\n            $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x];\n        }\n        // wordwrap sentences\n        $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut);\n        // indent lines\n        if($indent > 0) {\n            $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]);\n        }\n    }\n    $_output = implode($wrap_char . $wrap_char, $_paragraphs);\n\n    return $assign ? $smarty->assign($assign, $_output) : $_output;\n\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/compiler.assign.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {assign} compiler function plugin\n *\n * Type:     compiler function<br>\n * Name:     assign<br>\n * Purpose:  assign a value to a template variable\n * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign}\n *       (Smarty online manual)\n * @param string containing var-attribute and value-attribute\n * @param Smarty_Compiler\n */\nfunction smarty_compiler_assign($tag_attrs, &$compiler)\n{\n    $_params = $compiler->_parse_attrs($tag_attrs);\n\n    if (!isset($_params['var'])) {\n        $compiler->_syntax_error(\"assign: missing 'var' parameter\", E_USER_WARNING);\n        return;\n    }\n\n    if (!isset($_params['value'])) {\n        $compiler->_syntax_error(\"assign: missing 'value' parameter\", E_USER_WARNING);\n        return;\n    }\n\n    return \"\\$this->assign({$_params['var']}, {$_params['value']});\";\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.assign_debug_info.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {assign_debug_info} function plugin\n *\n * Type:     function<br>\n * Name:     assign_debug_info<br>\n * Purpose:  assign debug info to the template<br>\n * @param array unused in this plugin, this plugin uses {@link Smarty::$_config},\n *              {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info}\n * @param Smarty\n */\nfunction smarty_function_assign_debug_info($params, &$smarty)\n{\n    $assigned_vars = $smarty->_tpl_vars;\n    ksort($assigned_vars);\n    if (@is_array($smarty->_config[0])) {\n        $config_vars = $smarty->_config[0];\n        ksort($config_vars);\n        $smarty->assign(\"_debug_config_keys\", array_keys($config_vars));\n        $smarty->assign(\"_debug_config_vals\", array_values($config_vars));\n    }\n    \n    $included_templates = $smarty->_smarty_debug_info;\n    \n    $smarty->assign(\"_debug_keys\", array_keys($assigned_vars));\n    $smarty->assign(\"_debug_vals\", array_values($assigned_vars));\n    \n    $smarty->assign(\"_debug_tpls\", $included_templates);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.config_load.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {config_load} function plugin\n *\n * Type:     function<br>\n * Name:     config_load<br>\n * Purpose:  load config file vars\n * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load}\n *       (Smarty online manual)\n * @param array Format:\n * <pre>\n * array('file' => required config file name,\n *       'section' => optional config file section to load\n *       'scope' => local/parent/global\n *       'global' => overrides scope, setting to parent if true)\n * </pre>\n * @param Smarty\n */\nfunction smarty_function_config_load($params, &$smarty)\n{\n        if ($smarty->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $_debug_start_time = smarty_core_get_microtime($_params, $smarty);\n        }\n\n        $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null;\n        $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null;\n        $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global';\n        $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false;\n\n        if (!isset($_file) || strlen($_file) == 0) {\n            $smarty->trigger_error(\"missing 'file' attribute in config_load tag\", E_USER_ERROR, __FILE__, __LINE__);\n        }\n\n        if (isset($_scope)) {\n            if ($_scope != 'local' &&\n                $_scope != 'parent' &&\n                $_scope != 'global') {\n                $smarty->trigger_error(\"invalid 'scope' attribute value\", E_USER_ERROR, __FILE__, __LINE__);\n            }\n        } else {\n            if ($_global) {\n                $_scope = 'parent';\n            } else {\n                $_scope = 'local';\n            }\n        }\n\n        $_params = array('resource_name' => $_file,\n                         'resource_base_path' => $smarty->config_dir,\n                         'get_source' => false);\n        $smarty->_parse_resource_name($_params);\n        $_file_path = $_params['resource_type'] . ':' . $_params['resource_name'];\n        if (isset($_section))\n            $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section);\n        else\n            $_compile_file = $smarty->_get_compile_path($_file_path);\n\n        if($smarty->force_compile || !file_exists($_compile_file)) {\n            $_compile = true;\n        } elseif ($smarty->compile_check) {\n            $_params = array('resource_name' => $_file,\n                             'resource_base_path' => $smarty->config_dir,\n                             'get_source' => false);\n            $_compile = $smarty->_fetch_resource_info($_params) &&\n                $_params['resource_timestamp'] > filemtime($_compile_file);\n        } else {\n            $_compile = false;\n        }\n\n        if($_compile) {\n            // compile config file\n            if(!is_object($smarty->_conf_obj)) {\n                require_once SMARTY_DIR . $smarty->config_class . '.class.php';\n                $smarty->_conf_obj = new $smarty->config_class();\n                $smarty->_conf_obj->overwrite = $smarty->config_overwrite;\n                $smarty->_conf_obj->booleanize = $smarty->config_booleanize;\n                $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden;\n                $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines;\n            }\n\n            $_params = array('resource_name' => $_file,\n                             'resource_base_path' => $smarty->config_dir,\n                             $_params['get_source'] = true);\n            if (!$smarty->_fetch_resource_info($_params)) {\n                return;\n            }\n            $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']);\n            $_config_vars = array_merge($smarty->_conf_obj->get($_file),\n                    $smarty->_conf_obj->get($_file, $_section));\n            if(function_exists('var_export')) {\n                $_output = '<?php $_config_vars = ' . var_export($_config_vars, true) . '; ?>';\n            } else {\n                $_output = '<?php $_config_vars = unserialize(\\'' . strtr(serialize($_config_vars),array('\\''=>'\\\\\\'', '\\\\'=>'\\\\\\\\')) . '\\'); ?>';\n            }\n            $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp']));\n            require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');\n            smarty_core_write_compiled_resource($_params, $smarty);\n        } else {\n            include($_compile_file);\n        }\n\n        if ($smarty->caching) {\n            $smarty->_cache_info['config'][$_file] = true;\n        }\n\n        $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars);\n        $smarty->_config[0]['files'][$_file] = true;\n\n        if ($_scope == 'parent') {\n                $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars);\n                $smarty->_config[1]['files'][$_file] = true;\n        } else if ($_scope == 'global') {\n            for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) {\n                $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars);\n                $smarty->_config[$i]['files'][$_file] = true;\n            }\n        }\n\n        if ($smarty->debugging) {\n            $_params = array();\n            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');\n            $smarty->_smarty_debug_info[] = array('type'      => 'config',\n                                                'filename'  => $_file.' ['.$_section.'] '.$_scope,\n                                                'depth'     => $smarty->_inclusion_depth,\n                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);\n        }\n\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.counter.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {counter} function plugin\n *\n * Type:     function<br>\n * Name:     counter<br>\n * Purpose:  print out a counter value\n * @link http://smarty.php.net/manual/en/language.function.counter.php {counter}\n *       (Smarty online manual)\n * @param array parameters\n * @param Smarty\n * @return string|null\n */\nfunction smarty_function_counter($params, &$smarty)\n{\n    static $counters = array();\n\n    $name = (isset($params['name'])) ? $params['name'] : 'default';\n    if (!isset($counters[$name])) {\n        $counters[$name] = array(\n            'start'=>1,\n            'skip'=>1,\n            'direction'=>'up',\n            'count'=>1\n            );\n    }\n    $counter =& $counters[$name];\n\n    if (isset($params['start'])) {\n        $counter['start'] = $counter['count'] = (int)$params['start'];\n    }\n\n    if (!empty($params['assign'])) {\n        $counter['assign'] = $params['assign'];\n    }\n\n    if (isset($counter['assign'])) {\n        $smarty->assign($counter['assign'], $counter['count']);\n    }\n    \n    if (isset($params['print'])) {\n        $print = (bool)$params['print'];\n    } else {\n        $print = empty($counter['assign']);\n    }\n\n    if ($print) {\n        $retval = $counter['count'];\n    } else {\n        $retval = null;\n    }\n\n    if (isset($params['skip'])) {\n        $counter['skip'] = $params['skip'];\n    }\n    \n    if (isset($params['direction'])) {\n        $counter['direction'] = $params['direction'];\n    }\n\n    if ($counter['direction'] == \"down\")\n        $counter['count'] -= $counter['skip'];\n    else\n        $counter['count'] += $counter['skip'];\n    \n    return $retval;\n    \n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.cycle.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {cycle} function plugin\n *\n * Type:     function<br>\n * Name:     cycle<br>\n * Date:     May 3, 2002<br>\n * Purpose:  cycle through given values<br>\n * Input:\n *         - name = name of cycle (optional)\n *         - values = comma separated list of values to cycle,\n *                    or an array of values to cycle\n *                    (this can be left out for subsequent calls)\n *         - reset = boolean - resets given var to true\n *         - print = boolean - print var or not. default is true\n *         - advance = boolean - whether or not to advance the cycle\n *         - delimiter = the value delimiter, default is \",\"\n *         - assign = boolean, assigns to template var instead of\n *                    printed.\n *\n * Examples:<br>\n * <pre>\n * {cycle values=\"#eeeeee,#d0d0d0d\"}\n * {cycle name=row values=\"one,two,three\" reset=true}\n * {cycle name=row}\n * </pre>\n * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle}\n *       (Smarty online manual)\n * @author Monte Ohrt <monte at ohrt dot com>\n * @author credit to Mark Priatel <mpriatel@rogers.com>\n * @author credit to Gerard <gerard@interfold.com>\n * @author credit to Jason Sweat <jsweat_php@yahoo.com>\n * @version  1.3\n * @param array\n * @param Smarty\n * @return string|null\n */\nfunction smarty_function_cycle($params, &$smarty)\n{\n    static $cycle_vars;\n    \n    $name = (empty($params['name'])) ? 'default' : $params['name'];\n    $print = (isset($params['print'])) ? (bool)$params['print'] : true;\n    $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;\n    $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;\n            \n    if (!in_array('values', array_keys($params))) {\n        if(!isset($cycle_vars[$name]['values'])) {\n            $smarty->trigger_error(\"cycle: missing 'values' parameter\");\n            return;\n        }\n    } else {\n        if(isset($cycle_vars[$name]['values'])\n            && $cycle_vars[$name]['values'] != $params['values'] ) {\n            $cycle_vars[$name]['index'] = 0;\n        }\n        $cycle_vars[$name]['values'] = $params['values'];\n    }\n\n    $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ',';\n    \n    if(is_array($cycle_vars[$name]['values'])) {\n        $cycle_array = $cycle_vars[$name]['values'];\n    } else {\n        $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']);\n    }\n    \n    if(!isset($cycle_vars[$name]['index']) || $reset ) {\n        $cycle_vars[$name]['index'] = 0;\n    }\n    \n    if (isset($params['assign'])) {\n        $print = false;\n        $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]);\n    }\n        \n    if($print) {\n        $retval = $cycle_array[$cycle_vars[$name]['index']];\n    } else {\n        $retval = null;\n    }\n\n    if($advance) {\n        if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) {\n            $cycle_vars[$name]['index'] = 0;\n        } else {\n            $cycle_vars[$name]['index']++;\n        }\n    }\n    \n    return $retval;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.debug.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {debug} function plugin\n *\n * Type:     function<br>\n * Name:     debug<br>\n * Date:     July 1, 2002<br>\n * Purpose:  popup debug window\n * @link http://smarty.php.net/manual/en/language.function.debug.php {debug}\n *       (Smarty online manual)\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @version  1.0\n * @param array\n * @param Smarty\n * @return string output from {@link Smarty::_generate_debug_output()}\n */\nfunction smarty_function_debug($params, &$smarty)\n{\n    if (isset($params['output'])) {\n        $smarty->assign('_smarty_debug_output', $params['output']);\n    }\n    require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');\n    return smarty_core_display_debug_console(null, $smarty);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.eval.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {eval} function plugin\n *\n * Type:     function<br>\n * Name:     eval<br>\n * Purpose:  evaluate a template variable as a template<br>\n * @link http://smarty.php.net/manual/en/language.function.eval.php {eval}\n *       (Smarty online manual)\n * @param array\n * @param Smarty\n */\nfunction smarty_function_eval($params, &$smarty)\n{\n\n    if (!isset($params['var'])) {\n        $smarty->trigger_error(\"eval: missing 'var' parameter\");\n        return;\n    }\n\n    if($params['var'] == '') {\n        return;\n    }\n\n    $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled);\n\n    ob_start();\n    $smarty->_eval('?>' . $_var_compiled);\n    $_contents = ob_get_contents();\n    ob_end_clean();\n\n    if (!empty($params['assign'])) {\n        $smarty->assign($params['assign'], $_contents);\n    } else {\n        return $_contents;\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.fetch.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {fetch} plugin\n *\n * Type:     function<br>\n * Name:     fetch<br>\n * Purpose:  fetch file, web or ftp data and display results\n * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch}\n *       (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string|null if the assign parameter is passed, Smarty assigns the\n *                     result to a template variable\n */\nfunction smarty_function_fetch($params, &$smarty)\n{\n    if (empty($params['file'])) {\n        $smarty->_trigger_fatal_error(\"[plugin] parameter 'file' cannot be empty\");\n        return;\n    }\n\n    $content = '';\n    if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) {\n        $_params = array('resource_type' => 'file', 'resource_name' => $params['file']);\n        require_once(SMARTY_CORE_DIR . 'core.is_secure.php');\n        if(!smarty_core_is_secure($_params, $smarty)) {\n            $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \\'' . $params['file'] . '\\' is not allowed');\n            return;\n        }\n        \n        // fetch the file\n        if($fp = @fopen($params['file'],'r')) {\n            while(!feof($fp)) {\n                $content .= fgets ($fp,4096);\n            }\n            fclose($fp);\n        } else {\n            $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \\'' . $params['file'] . '\\'');\n            return;\n        }\n    } else {\n        // not a local file\n        if(preg_match('!^http://!i',$params['file'])) {\n            // http fetch\n            if($uri_parts = parse_url($params['file'])) {\n                // set defaults\n                $host = $server_name = $uri_parts['host'];\n                $timeout = 30;\n                $accept = \"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\";\n                $agent = \"Smarty Template Engine \".$smarty->_version;\n                $referer = \"\";\n                $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';\n                $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';\n                $_is_proxy = false;\n                if(empty($uri_parts['port'])) {\n                    $port = 80;\n                } else {\n                    $port = $uri_parts['port'];\n                }\n                if(!empty($uri_parts['user'])) {\n                    $user = $uri_parts['user'];\n                }\n                if(!empty($uri_parts['pass'])) {\n                    $pass = $uri_parts['pass'];\n                }\n                // loop through parameters, setup headers\n                foreach($params as $param_key => $param_value) {\n                    switch($param_key) {\n                        case \"file\":\n                        case \"assign\":\n                        case \"assign_headers\":\n                            break;\n                        case \"user\":\n                            if(!empty($param_value)) {\n                                $user = $param_value;\n                            }\n                            break;\n                        case \"pass\":\n                            if(!empty($param_value)) {\n                                $pass = $param_value;\n                            }\n                            break;\n                        case \"accept\":\n                            if(!empty($param_value)) {\n                                $accept = $param_value;\n                            }\n                            break;\n                        case \"header\":\n                            if(!empty($param_value)) {\n                                if(!preg_match('![\\w\\d-]+: .+!',$param_value)) {\n                                    $smarty->_trigger_fatal_error(\"[plugin] invalid header format '\".$param_value.\"'\");\n                                    return;\n                                } else {\n                                    $extra_headers[] = $param_value;\n                                }\n                            }\n                            break;\n                        case \"proxy_host\":\n                            if(!empty($param_value)) {\n                                $proxy_host = $param_value;\n                            }\n                            break;\n                        case \"proxy_port\":\n                            if(!preg_match('!\\D!', $param_value)) {\n                                $proxy_port = (int) $param_value;\n                            } else {\n                                $smarty->_trigger_fatal_error(\"[plugin] invalid value for attribute '\".$param_key.\"'\");\n                                return;\n                            }\n                            break;\n                        case \"agent\":\n                            if(!empty($param_value)) {\n                                $agent = $param_value;\n                            }\n                            break;\n                        case \"referer\":\n                            if(!empty($param_value)) {\n                                $referer = $param_value;\n                            }\n                            break;\n                        case \"timeout\":\n                            if(!preg_match('!\\D!', $param_value)) {\n                                $timeout = (int) $param_value;\n                            } else {\n                                $smarty->_trigger_fatal_error(\"[plugin] invalid value for attribute '\".$param_key.\"'\");\n                                return;\n                            }\n                            break;\n                        default:\n                            $smarty->_trigger_fatal_error(\"[plugin] unrecognized attribute '\".$param_key.\"'\");\n                            return;\n                    }\n                }\n                if(!empty($proxy_host) && !empty($proxy_port)) {\n                    $_is_proxy = true;\n                    $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);\n                } else {\n                    $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);\n                }\n\n                if(!$fp) {\n\t\t\t\t\t$errmsg = iconv('GBK', 'UTF-8', $errstr);\n                    $smarty->_trigger_fatal_error(\"[plugin] unable to fetch: $errmsg ($errno)\");\n                    return;\n                } else {\n                    if($_is_proxy) {\n                        fputs($fp, 'GET ' . $params['file'] . \" HTTP/1.0\\r\\n\");\n                    } else {\n                        fputs($fp, \"GET $uri HTTP/1.0\\r\\n\");\n                    }\n                    if(!empty($host)) {\n                        fputs($fp, \"Host: $host\\r\\n\");\n                    }\n                    if(!empty($accept)) {\n                        fputs($fp, \"Accept: $accept\\r\\n\");\n                    }\n                    if(!empty($agent)) {\n                        fputs($fp, \"User-Agent: $agent\\r\\n\");\n                    }\n                    if(!empty($referer)) {\n                        fputs($fp, \"Referer: $referer\\r\\n\");\n                    }\n                    if(isset($extra_headers) && is_array($extra_headers)) {\n                        foreach($extra_headers as $curr_header) {\n                            fputs($fp, $curr_header.\"\\r\\n\");\n                        }\n                    }\n                    if(!empty($user) && !empty($pass)) {\n                        fputs($fp, \"Authorization: BASIC \".base64_encode(\"$user:$pass\").\"\\r\\n\");\n                    }\n\n                    fputs($fp, \"\\r\\n\");\n                    while(!feof($fp)) {\n                        $content .= fgets($fp,4096);\n                    }\n                    fclose($fp);\n                    $csplit = split(\"\\r\\n\\r\\n\",$content,2);\n\n                    $content = $csplit[1];\n\n                    if(!empty($params['assign_headers'])) {\n                        $smarty->assign($params['assign_headers'],split(\"\\r\\n\",$csplit[0]));\n                    }\n                }\n            } else {\n                $smarty->_trigger_fatal_error(\"[plugin] unable to parse URL, check syntax\");\n                return;\n            }\n        } else {\n            // ftp fetch\n            if($fp = @fopen($params['file'],'r')) {\n                while(!feof($fp)) {\n                    $content .= fgets ($fp,4096);\n                }\n                fclose($fp);\n            } else {\n                $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \\'' . $params['file'] .'\\'');\n                return;\n            }\n        }\n\n    }\n\n\n    if (!empty($params['assign'])) {\n        $smarty->assign($params['assign'],$content);\n    } else {\n        return $content;\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_checkboxes.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_checkboxes} function plugin\n *\n * File:       function.html_checkboxes.php<br>\n * Type:       function<br>\n * Name:       html_checkboxes<br>\n * Date:       24.Feb.2003<br>\n * Purpose:    Prints out a list of checkbox input types<br>\n * Input:<br>\n *           - name       (optional) - string default \"checkbox\"\n *           - values     (required) - array\n *           - options    (optional) - associative array\n *           - checked    (optional) - array default not set\n *           - separator  (optional) - ie <br> or &nbsp;\n *           - output     (optional) - the output next to each checkbox\n *           - assign     (optional) - assign the output as an array to this variable\n * Examples:\n * <pre>\n * {html_checkboxes values=$ids output=$names}\n * {html_checkboxes values=$ids name='box' separator='<br>' output=$names}\n * {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}\n * </pre>\n * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}\n *      (Smarty online manual)\n * @author     Christopher Kvarme <christopher.kvarme@flashjab.com>\n * @author credits to Monte Ohrt <monte at ohrt dot com>\n * @version    1.0\n * @param array\n * @param Smarty\n * @return string\n * @uses smarty_function_escape_special_chars()\n */\nfunction smarty_function_html_checkboxes($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');\n\n    $name = 'checkbox';\n    $values = null;\n    $options = null;\n    $selected = null;\n    $separator = '';\n    $labels = true;\n    $output = null;\n\n    $extra = '';\n\n    foreach($params as $_key => $_val) {\n        switch($_key) {\n            case 'name':\n            case 'separator':\n                $$_key = $_val;\n                break;\n\n            case 'labels':\n                $$_key = (bool)$_val;\n                break;\n\n            case 'options':\n                $$_key = (array)$_val;\n                break;\n\n            case 'values':\n            case 'output':\n                $$_key = array_values((array)$_val);\n                break;\n\n            case 'checked':\n            case 'selected':\n                $selected = array_map('strval', array_values((array)$_val));\n                break;\n\n            case 'checkboxes':\n                $smarty->trigger_error('html_checkboxes: the use of the \"checkboxes\" attribute is deprecated, use \"options\" instead', E_USER_WARNING);\n                $options = (array)$_val;\n                break;\n\n            case 'assign':\n                break;\n\n            default:\n                if(!is_array($_val)) {\n                    $extra .= ' '.$_key.'=\"'.smarty_function_escape_special_chars($_val).'\"';\n                } else {\n                    $smarty->trigger_error(\"html_checkboxes: extra attribute '$_key' cannot be an array\", E_USER_NOTICE);\n                }\n                break;\n        }\n    }\n\n    if (!isset($options) && !isset($values))\n        return ''; /* raise error here? */\n\n    settype($selected, 'array');\n    $_html_result = array();\n\n    if (isset($options)) {\n\n        foreach ($options as $_key=>$_val)\n            $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);\n\n\n    } else {\n        foreach ($values as $_i=>$_key) {\n            $_val = isset($output[$_i]) ? $output[$_i] : '';\n            $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);\n        }\n\n    }\n\n    if(!empty($params['assign'])) {\n        $smarty->assign($params['assign'], $_html_result);\n    } else {\n        return implode(\"\\n\",$_html_result);\n    }\n\n}\n\nfunction smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) {\n    $_output = '';\n    if ($labels) $_output .= '<label>';\n    $_output .= '<input type=\"checkbox\" name=\"'\n        . smarty_function_escape_special_chars($name) . '[]\" value=\"'\n        . smarty_function_escape_special_chars($value) . '\"';\n\n    if (in_array((string)$value, $selected)) {\n        $_output .= ' checked=\"checked\"';\n    }\n    $_output .= $extra . ' />' . $output;\n    if ($labels) $_output .= '</label>';\n    $_output .=  $separator;\n\n    return $_output;\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_image.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_image} function plugin\n *\n * Type:     function<br>\n * Name:     html_image<br>\n * Date:     Feb 24, 2003<br>\n * Purpose:  format HTML tags for the image<br>\n * Input:<br>\n *         - file = file (and path) of image (required)\n *         - height = image height (optional, default actual height)\n *         - width = image width (optional, default actual width)\n *         - basedir = base directory for absolute paths, default\n *                     is environment variable DOCUMENT_ROOT\n *\n * Examples: {html_image file=\"images/masthead.gif\"}\n * Output:   <img src=\"images/masthead.gif\" width=400 height=23>\n * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image}\n *      (Smarty online manual)\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @author credits to Duda <duda@big.hu> - wrote first image function\n *           in repository, helped with lots of functionality\n * @version  1.0\n * @param array\n * @param Smarty\n * @return string\n * @uses smarty_function_escape_special_chars()\n */\nfunction smarty_function_html_image($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');\n    \n    $alt = '';\n    $file = '';\n    $height = '';\n    $width = '';\n    $extra = '';\n    $prefix = '';\n    $suffix = '';\n    $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];\n    $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : '';\n    foreach($params as $_key => $_val) {\n        switch($_key) {\n            case 'file':\n            case 'height':\n            case 'width':\n            case 'dpi':\n            case 'basedir':\n                $$_key = $_val;\n                break;\n\n            case 'alt':\n                if(!is_array($_val)) {\n                    $$_key = smarty_function_escape_special_chars($_val);\n                } else {\n                    $smarty->trigger_error(\"html_image: extra attribute '$_key' cannot be an array\", E_USER_NOTICE);\n                }\n                break;\n\n            case 'link':\n            case 'href':\n                $prefix = '<a href=\"' . $_val . '\">';\n                $suffix = '</a>';\n                break;\n\n            default:\n                if(!is_array($_val)) {\n                    $extra .= ' '.$_key.'=\"'.smarty_function_escape_special_chars($_val).'\"';\n                } else {\n                    $smarty->trigger_error(\"html_image: extra attribute '$_key' cannot be an array\", E_USER_NOTICE);\n                }\n                break;\n        }\n    }\n\n    if (empty($file)) {\n        $smarty->trigger_error(\"html_image: missing 'file' parameter\", E_USER_NOTICE);\n        return;\n    }\n\n    if (substr($file,0,1) == '/') {\n        $_image_path = $basedir . $file;\n    } else {\n        $_image_path = $file;\n    }\n\n    if(!isset($params['width']) || !isset($params['height'])) {\n        if ($smarty->security &&\n            ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) &&\n            (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) &&\n            (!smarty_core_is_secure($_params, $smarty)) ) {\n            $smarty->trigger_error(\"html_image: (secure) '$_image_path' not in secure directory\", E_USER_NOTICE);\n\n        } elseif (!$_image_data = @getimagesize($_image_path)) {\n            if(!file_exists($_image_path)) {\n                $smarty->trigger_error(\"html_image: unable to find '$_image_path'\", E_USER_NOTICE);\n                return;\n            } else if(!is_readable($_image_path)) {\n                $smarty->trigger_error(\"html_image: unable to read '$_image_path'\", E_USER_NOTICE);\n                return;\n            } else {\n                $smarty->trigger_error(\"html_image: '$_image_path' is not a valid image file\", E_USER_NOTICE);\n                return;\n            }\n        }\n\n        if(!isset($params['width'])) {\n            $width = $_image_data[0];\n        }\n        if(!isset($params['height'])) {\n            $height = $_image_data[1];\n        }\n\n    }\n\n    if(isset($params['dpi'])) {\n        if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) {\n            $dpi_default = 72;\n        } else {\n            $dpi_default = 96;\n        }\n        $_resize = $dpi_default/$params['dpi'];\n        $width = round($width * $_resize);\n        $height = round($height * $_resize);\n    }\n\n    return $prefix . '<img src=\"'.$file.'\" alt=\"'.$alt.'\" width=\"'.$width.'\" height=\"'.$height.'\"'.$extra.' />' . $suffix;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_options.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_options} function plugin\n *\n * Type:     function<br>\n * Name:     html_options<br>\n * Input:<br>\n *           - name       (optional) - string default \"select\"\n *           - values     (required if no options supplied) - array\n *           - options    (required if no values supplied) - associative array\n *           - selected   (optional) - string default not set\n *           - output     (required if not options supplied) - array\n *           - disabled   (optional) - string default not set (added by Yogin)\n * Purpose:  Prints the list of <option> tags generated from\n *           the passed parameters\n * @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image}\n *      (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n * @uses smarty_function_escape_special_chars()\n */\nfunction smarty_function_html_options($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');\n\n    $name = null;\n    $values = null;\n    $options = null;\n    $selected = array();\n    $disabled = array();\n    $output = null;\n\n    $extra = '';\n\n    foreach($params as $_key => $_val) {\n        switch($_key) {\n            case 'name':\n                $$_key = (string)$_val;\n                break;\n\n            case 'options':\n                $$_key = (array)$_val;\n                break;\n\n            case 'values':\n            case 'output':\n                $$_key = array_values((array)$_val);\n                break;\n\n            case 'selected':\n                $$_key = array_map('strval', array_values((array)$_val));\n                break;\n\n            case 'disabled':\n                $$_key = array_map('strval', array_values((array)$_val));\n                break;\n\n\n            default:\n                if(!is_array($_val)) {\n                    $extra .= ' '.$_key.'=\"'.smarty_function_escape_special_chars($_val).'\"';\n                } else {\n                    $smarty->trigger_error(\"html_options: extra attribute '$_key' cannot be an array\", E_USER_NOTICE);\n                }\n                break;\n        }\n    }\n\n    if (!isset($options) && !isset($values))\n        return ''; /* raise error here? */\n\n    $_html_result = '';\n\n    if (isset($options)) {\n\n        foreach ($options as $_key=>$_val)\n            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $disabled);\n\n    } else {\n\n        foreach ($values as $_i=>$_key) {\n            $_val = isset($output[$_i]) ? $output[$_i] : '';\n            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected, $disabled);\n        }\n\n    }\n\n    if(!empty($name)) {\n        $_html_result = '<select name=\"' . $name . '\"' . $extra . '>' . \"\\n\" . $_html_result . '</select>' . \"\\n\";\n    }\n\n    return $_html_result;\n\n}\n\nfunction smarty_function_html_options_optoutput($key, $value, $selected, $disabled) {\n    if(!is_array($value)) {\n        $_html_result = '<option label=\"' . smarty_function_escape_special_chars($value) . '\" value=\"' .\n            smarty_function_escape_special_chars($key) . '\"';\n        if (in_array((string)$key, $selected))\n            $_html_result .= ' selected=\"selected\"';\n\n        if (in_array((string)$key, $disabled))\n            $_html_result .= ' disabled';\n\n        $_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . \"\\n\";\n    } else {\n        $_html_result = smarty_function_html_options_optgroup($key, $value, $selected, $disabled);\n    }\n    return $_html_result;\n}\n\nfunction smarty_function_html_options_optgroup($key, $values, $selected, $disabled) {\n    $optgroup_html = '<optgroup label=\"' . smarty_function_escape_special_chars($key) . '\">' . \"\\n\";\n    foreach ($values as $key => $value) {\n        $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected, $disabled);\n    }\n    $optgroup_html .= \"</optgroup>\\n\";\n    return $optgroup_html;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_radios.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_radios} function plugin\n *\n * File:       function.html_radios.php<br>\n * Type:       function<br>\n * Name:       html_radios<br>\n * Date:       24.Feb.2003<br>\n * Purpose:    Prints out a list of radio input types<br>\n * Input:<br>\n *           - name       (optional) - string default \"radio\"\n *           - values     (required) - array\n *           - options    (optional) - associative array\n *           - checked    (optional) - array default not set\n *           - separator  (optional) - ie <br> or &nbsp;\n *           - output     (optional) - the output next to each radio button\n *           - assign     (optional) - assign the output as an array to this variable\n * Examples:\n * <pre>\n * {html_radios values=$ids output=$names}\n * {html_radios values=$ids name='box' separator='<br>' output=$names}\n * {html_radios values=$ids checked=$checked separator='<br>' output=$names}\n * </pre>\n * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}\n *      (Smarty online manual)\n * @author     Christopher Kvarme <christopher.kvarme@flashjab.com>\n * @author credits to Monte Ohrt <monte at ohrt dot com>\n * @version    1.0\n * @param array\n * @param Smarty\n * @return string\n * @uses smarty_function_escape_special_chars()\n */\nfunction smarty_function_html_radios($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');\n   \n    $name = 'radio';\n    $values = null;\n    $options = null;\n    $selected = null;\n    $separator = '';\n    $labels = true;\n    $output = null;\n    $extra = '';\n\n    foreach($params as $_key => $_val) {\n        switch($_key) {\n            case 'name':\n            case 'separator':\n                $$_key = (string)$_val;\n                break;\n\n            case 'checked':\n            case 'selected':\n                if(is_array($_val)) {\n                    $smarty->trigger_error('html_radios: the \"' . $_key . '\" attribute cannot be an array', E_USER_WARNING);\n                } else {\n                    $selected = (string)$_val;\n                }\n                break;\n\n            case 'labels':\n                $$_key = (bool)$_val;\n                break;\n\n            case 'options':\n                $$_key = (array)$_val;\n                break;\n\n            case 'values':\n            case 'output':\n                $$_key = array_values((array)$_val);\n                break;\n\n            case 'radios':\n                $smarty->trigger_error('html_radios: the use of the \"radios\" attribute is deprecated, use \"options\" instead', E_USER_WARNING);\n                $options = (array)$_val;\n                break;\n\n            case 'assign':\n                break;\n\n            default:\n                if(!is_array($_val)) {\n                    $extra .= ' '.$_key.'=\"'.smarty_function_escape_special_chars($_val).'\"';\n                } else {\n                    $smarty->trigger_error(\"html_radios: extra attribute '$_key' cannot be an array\", E_USER_NOTICE);\n                }\n                break;\n        }\n    }\n\n    if (!isset($options) && !isset($values))\n        return ''; /* raise error here? */\n\n    $_html_result = array();\n\n    if (isset($options)) {\n\n        foreach ($options as $_key=>$_val)\n            $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels);\n\n    } else {\n\n        foreach ($values as $_i=>$_key) {\n            $_val = isset($output[$_i]) ? $output[$_i] : '';\n            $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels);\n        }\n\n    }\n\n    if(!empty($params['assign'])) {\n        $smarty->assign($params['assign'], $_html_result);\n    } else {\n        return implode(\"\\n\",$_html_result);\n    }\n\n}\n\nfunction smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels) {\n    $_output = '';\n    if ($labels) {\n      $_id = smarty_function_escape_special_chars($name . '_' . $value);\n      $_output .= '<label for=\"' . $_id . '\">';\n   }\n   $_output .= '<input type=\"radio\" name=\"'\n        . smarty_function_escape_special_chars($name) . '\" value=\"'\n        . smarty_function_escape_special_chars($value) . '\"';\n\n   if ($labels) $_output .= ' id=\"' . $_id . '\"';\n\n    if ($value==$selected) {\n        $_output .= ' checked=\"checked\"';\n    }\n    $_output .= $extra . ' />' . $output;\n    if ($labels) $_output .= '</label>';\n    $_output .=  $separator;\n\n    return $_output;\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_select_date.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty {html_select_date} plugin\n *\n * Type:     function<br>\n * Name:     html_select_date<br>\n * Purpose:  Prints the dropdowns for date selection.\n *\n * ChangeLog:<br>\n *           - 1.0 initial release\n *           - 1.1 added support for +/- N syntax for begin\n *                and end year values. (Monte)\n *           - 1.2 added support for yyyy-mm-dd syntax for\n *                time value. (Jan Rosier)\n *           - 1.3 added support for choosing format for\n *                month values (Gary Loescher)\n *           - 1.3.1 added support for choosing format for\n *                day values (Marcus Bointon)\n *           - 1.3.2 suppport negative timestamps, force year\n *             dropdown to include given date unless explicitly set (Monte)\n * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date}\n *      (Smarty online manual)\n * @version 1.3.2\n * @author   Andrei Zmievski\n * @param array\n * @param Smarty\n * @return string\n */\nfunction smarty_function_html_select_date($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','make_timestamp');\n    require_once $smarty->_get_plugin_filepath('function','html_options');\n    /* Default values. */\n    $prefix          = \"Date_\";\n    $start_year      = strftime(\"%Y\");\n    $end_year        = $start_year;\n    $display_days    = true;\n    $display_months  = true;\n    $display_years   = true;\n    $month_format    = \"%B\";\n    /* Write months as numbers by default  GL */\n    $month_value_format = \"%m\";\n    $day_format      = \"%02d\";\n    /* Write day values using this format MB */\n    $day_value_format = \"%d\";\n    $year_as_text    = false;\n    /* Display years in reverse order? Ie. 2000,1999,.... */\n    $reverse_years   = false;\n    /* Should the select boxes be part of an array when returned from PHP?\n       e.g. setting it to \"birthday\", would create \"birthday[Day]\",\n       \"birthday[Month]\" & \"birthday[Year]\". Can be combined with prefix */\n    $field_array     = null;\n    /* <select size>'s of the different <select> tags.\n       If not set, uses default dropdown. */\n    $day_size        = null;\n    $month_size      = null;\n    $year_size       = null;\n    /* Unparsed attributes common to *ALL* the <select>/<input> tags.\n       An example might be in the template: all_extra ='class =\"foo\"'. */\n    $all_extra       = null;\n    /* Separate attributes for the tags. */\n    $day_extra       = null;\n    $month_extra     = null;\n    $year_extra      = null;\n    /* Order in which to display the fields.\n       \"D\" -> day, \"M\" -> month, \"Y\" -> year. */\n    $field_order     = 'MDY';\n    /* String printed between the different fields. */\n    $field_separator = \"\\n\";\n    $time = time();\n    $all_empty       = null;\n    $day_empty       = null;\n    $month_empty     = null;\n    $year_empty      = null;\n\n    foreach ($params as $_key=>$_value) {\n        switch ($_key) {\n            case 'prefix':\n            case 'time':\n            case 'start_year':\n            case 'end_year':\n            case 'month_format':\n            case 'day_format':\n            case 'day_value_format':\n            case 'field_array':\n            case 'day_size':\n            case 'month_size':\n            case 'year_size':\n            case 'all_extra':\n            case 'day_extra':\n            case 'month_extra':\n            case 'year_extra':\n            case 'field_order':\n            case 'field_separator':\n            case 'month_value_format':\n            case 'month_empty':\n            case 'day_empty':\n            case 'year_empty':\n                $$_key = (string)$_value;\n                break;\n\n            case 'all_empty':\n                $$_key = (string)$_value;\n                $day_empty = $month_empty = $year_empty = $all_empty;\n                break;\n\n            case 'display_days':\n            case 'display_months':\n            case 'display_years':\n            case 'year_as_text':\n            case 'reverse_years':\n                $$_key = (bool)$_value;\n                break;\n\n            default:\n                $smarty->trigger_error(\"[html_select_date] unknown parameter $_key\", E_USER_WARNING);\n\n        }\n    }\n\n    if(preg_match('!^-\\d+$!',$time)) {\n        // negative timestamp, use date()\n        $time = date('Y-m-d',$time);\n    }\n    // If $time is not in format yyyy-mm-dd\n    if (!preg_match('/^\\d{0,4}-\\d{0,2}-\\d{0,2}$/', $time)) {\n        // use smarty_make_timestamp to get an unix timestamp and\n        // strftime to make yyyy-mm-dd\n        $time = strftime('%Y-%m-%d', smarty_make_timestamp($time));\n    }\n    // Now split this in pieces, which later can be used to set the select\n    $time = explode(\"-\", $time);\n    \n    // make syntax \"+N\" or \"-N\" work with start_year and end_year\n    if (preg_match('!^(\\+|\\-)\\s*(\\d+)$!', $end_year, $match)) {\n        if ($match[1] == '+') {\n            $end_year = strftime('%Y') + $match[2];\n        } else {\n            $end_year = strftime('%Y') - $match[2];\n        }\n    }\n    if (preg_match('!^(\\+|\\-)\\s*(\\d+)$!', $start_year, $match)) {\n        if ($match[1] == '+') {\n            $start_year = strftime('%Y') + $match[2];\n        } else {\n            $start_year = strftime('%Y') - $match[2];\n        }\n    }\n    if (strlen($time[0]) > 0) { \n        if ($start_year > $time[0] && !isset($params['start_year'])) {\n            // force start year to include given date if not explicitly set\n            $start_year = $time[0];\n        }\n        if($end_year < $time[0] && !isset($params['end_year'])) {\n            // force end year to include given date if not explicitly set\n            $end_year = $time[0];\n        }\n    }\n\n    $field_order = strtoupper($field_order);\n\n    $html_result = $month_result = $day_result = $year_result = \"\";\n\n    if ($display_months) {\n        $month_names = array();\n        $month_values = array();\n        if(isset($month_empty)) {\n            $month_names[''] = $month_empty;\n            $month_values[''] = '';\n        }\n        for ($i = 1; $i <= 12; $i++) {\n            $month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000));\n            $month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000));\n        }\n\n        $month_result .= '<select name=';\n        if (null !== $field_array){\n            $month_result .= '\"' . $field_array . '[' . $prefix . 'Month]\"';\n        } else {\n            $month_result .= '\"' . $prefix . 'Month\"';\n        }\n        if (null !== $month_size){\n            $month_result .= ' size=\"' . $month_size . '\"';\n        }\n        if (null !== $month_extra){\n            $month_result .= ' ' . $month_extra;\n        }\n        if (null !== $all_extra){\n            $month_result .= ' ' . $all_extra;\n        }\n        $month_result .= '>'.\"\\n\";\n\n        $month_result .= smarty_function_html_options(array('output'     => $month_names,\n                                                            'values'     => $month_values,\n                                                            'selected'   => $a=$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '',\n                                                            'print_result' => false),\n                                                      $smarty);\n        $month_result .= '</select>';\n    }\n\n    if ($display_days) {\n        $days = array();\n        if (isset($day_empty)) {\n            $days[''] = $day_empty;\n            $day_values[''] = '';\n        }\n        for ($i = 1; $i <= 31; $i++) {\n            $days[] = sprintf($day_format, $i);\n            $day_values[] = sprintf($day_value_format, $i);\n        }\n\n        $day_result .= '<select name=';\n        if (null !== $field_array){\n            $day_result .= '\"' . $field_array . '[' . $prefix . 'Day]\"';\n        } else {\n            $day_result .= '\"' . $prefix . 'Day\"';\n        }\n        if (null !== $day_size){\n            $day_result .= ' size=\"' . $day_size . '\"';\n        }\n        if (null !== $all_extra){\n            $day_result .= ' ' . $all_extra;\n        }\n        if (null !== $day_extra){\n            $day_result .= ' ' . $day_extra;\n        }\n        $day_result .= '>'.\"\\n\";\n        $day_result .= smarty_function_html_options(array('output'     => $days,\n                                                          'values'     => $day_values,\n                                                          'selected'   => $time[2],\n                                                          'print_result' => false),\n                                                    $smarty);\n        $day_result .= '</select>';\n    }\n\n    if ($display_years) {\n        if (null !== $field_array){\n            $year_name = $field_array . '[' . $prefix . 'Year]';\n        } else {\n            $year_name = $prefix . 'Year';\n        }\n        if ($year_as_text) {\n            $year_result .= '<input type=\"text\" name=\"' . $year_name . '\" value=\"' . $time[0] . '\" size=\"4\" maxlength=\"4\"';\n            if (null !== $all_extra){\n                $year_result .= ' ' . $all_extra;\n            }\n            if (null !== $year_extra){\n                $year_result .= ' ' . $year_extra;\n            }\n            $year_result .= '>';\n        } else {\n            $years = range((int)$start_year, (int)$end_year);\n            if ($reverse_years) {\n                rsort($years, SORT_NUMERIC);\n            } else {\n                sort($years, SORT_NUMERIC);\n            }\n            $yearvals = $years;\n            if(isset($year_empty)) {\n                array_unshift($years, $year_empty);\n                array_unshift($yearvals, '');\n            }\n            $year_result .= '<select name=\"' . $year_name . '\"';\n            if (null !== $year_size){\n                $year_result .= ' size=\"' . $year_size . '\"';\n            }\n            if (null !== $all_extra){\n                $year_result .= ' ' . $all_extra;\n            }\n            if (null !== $year_extra){\n                $year_result .= ' ' . $year_extra;\n            }\n            $year_result .= '>'.\"\\n\";\n            $year_result .= smarty_function_html_options(array('output' => $years,\n                                                               'values' => $yearvals,\n                                                               'selected'   => $time[0],\n                                                               'print_result' => false),\n                                                         $smarty);\n            $year_result .= '</select>';\n        }\n    }\n\n    // Loop thru the field_order field\n    for ($i = 0; $i <= 2; $i++){\n        $c = substr($field_order, $i, 1);\n        switch ($c){\n            case 'D':\n                $html_result .= $day_result;\n                break;\n\n            case 'M':\n                $html_result .= $month_result;\n                break;\n\n            case 'Y':\n                $html_result .= $year_result;\n                break;\n        }\n        // Add the field seperator\n        if($i != 2) {\n            $html_result .= $field_separator;\n        }\n    }\n\n    return $html_result;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_select_time.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_select_time} function plugin\n *\n * Type:     function<br>\n * Name:     html_select_time<br>\n * Purpose:  Prints the dropdowns for time selection\n * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time}\n *          (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n * @uses smarty_make_timestamp()\n */\nfunction smarty_function_html_select_time($params, &$smarty)\n{\n    require_once $smarty->_get_plugin_filepath('shared','make_timestamp');\n    require_once $smarty->_get_plugin_filepath('function','html_options');\n    /* Default values. */\n    $prefix             = \"Time_\";\n    $time               = time();\n    $display_hours      = true;\n    $display_minutes    = true;\n    $display_seconds    = true;\n    $display_meridian   = true;\n    $use_24_hours       = true;\n    $minute_interval    = 1;\n    $second_interval    = 1;\n    /* Should the select boxes be part of an array when returned from PHP?\n       e.g. setting it to \"birthday\", would create \"birthday[Hour]\",\n       \"birthday[Minute]\", \"birthday[Seconds]\" & \"birthday[Meridian]\".\n       Can be combined with prefix. */\n    $field_array        = null;\n    $all_extra          = null;\n    $hour_extra         = null;\n    $minute_extra       = null;\n    $second_extra       = null;\n    $meridian_extra     = null;\n\n    foreach ($params as $_key=>$_value) {\n        switch ($_key) {\n            case 'prefix':\n            case 'time':\n            case 'field_array':\n            case 'all_extra':\n            case 'hour_extra':\n            case 'minute_extra':\n            case 'second_extra':\n            case 'meridian_extra':\n                $$_key = (string)$_value;\n                break;\n\n            case 'display_hours':\n            case 'display_minutes':\n            case 'display_seconds':\n            case 'display_meridian':\n            case 'use_24_hours':\n                $$_key = (bool)$_value;\n                break;\n\n            case 'minute_interval':\n            case 'second_interval':\n                $$_key = (int)$_value;\n                break;\n\n            default:\n                $smarty->trigger_error(\"[html_select_time] unknown parameter $_key\", E_USER_WARNING);\n        }\n    }\n\n    $time = smarty_make_timestamp($time);\n\n    $html_result = '';\n\n    if ($display_hours) {\n        $hours       = $use_24_hours ? range(0, 23) : range(1, 12);\n        $hour_fmt = $use_24_hours ? '%H' : '%I';\n        for ($i = 0, $for_max = count($hours); $i < $for_max; $i++)\n            $hours[$i] = sprintf('%02d', $hours[$i]);\n        $html_result .= '<select name=';\n        if (null !== $field_array) {\n            $html_result .= '\"' . $field_array . '[' . $prefix . 'Hour]\"';\n        } else {\n            $html_result .= '\"' . $prefix . 'Hour\"';\n        }\n        if (null !== $hour_extra){\n            $html_result .= ' ' . $hour_extra;\n        }\n        if (null !== $all_extra){\n            $html_result .= ' ' . $all_extra;\n        }\n        $html_result .= '>'.\"\\n\";\n        $html_result .= smarty_function_html_options(array('output'          => $hours,\n                                                           'values'          => $hours,\n                                                           'selected'      => strftime($hour_fmt, $time),\n                                                           'print_result' => false),\n                                                     $smarty);\n        $html_result .= \"</select>\\n\";\n    }\n\n    if ($display_minutes) {\n        $all_minutes = range(0, 59);\n        for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval)\n            $minutes[] = sprintf('%02d', $all_minutes[$i]);\n        $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval);\n        $html_result .= '<select name=';\n        if (null !== $field_array) {\n            $html_result .= '\"' . $field_array . '[' . $prefix . 'Minute]\"';\n        } else {\n            $html_result .= '\"' . $prefix . 'Minute\"';\n        }\n        if (null !== $minute_extra){\n            $html_result .= ' ' . $minute_extra;\n        }\n        if (null !== $all_extra){\n            $html_result .= ' ' . $all_extra;\n        }\n        $html_result .= '>'.\"\\n\";\n        \n        $html_result .= smarty_function_html_options(array('output'          => $minutes,\n                                                           'values'          => $minutes,\n                                                           'selected'      => $selected,\n                                                           'print_result' => false),\n                                                     $smarty);\n        $html_result .= \"</select>\\n\";\n    }\n\n    if ($display_seconds) {\n        $all_seconds = range(0, 59);\n        for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval)\n            $seconds[] = sprintf('%02d', $all_seconds[$i]);\n        $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval);\n        $html_result .= '<select name=';\n        if (null !== $field_array) {\n            $html_result .= '\"' . $field_array . '[' . $prefix . 'Second]\"';\n        } else {\n            $html_result .= '\"' . $prefix . 'Second\"';\n        }\n        \n        if (null !== $second_extra){\n            $html_result .= ' ' . $second_extra;\n        }\n        if (null !== $all_extra){\n            $html_result .= ' ' . $all_extra;\n        }\n        $html_result .= '>'.\"\\n\";\n        \n        $html_result .= smarty_function_html_options(array('output'          => $seconds,\n                                                           'values'          => $seconds,\n                                                           'selected'      => $selected,\n                                                           'print_result' => false),\n                                                     $smarty);\n        $html_result .= \"</select>\\n\";\n    }\n\n    if ($display_meridian && !$use_24_hours) {\n        $html_result .= '<select name=';\n        if (null !== $field_array) {\n            $html_result .= '\"' . $field_array . '[' . $prefix . 'Meridian]\"';\n        } else {\n            $html_result .= '\"' . $prefix . 'Meridian\"';\n        }\n        \n        if (null !== $meridian_extra){\n            $html_result .= ' ' . $meridian_extra;\n        }\n        if (null !== $all_extra){\n            $html_result .= ' ' . $all_extra;\n        }\n        $html_result .= '>'.\"\\n\";\n        \n        $html_result .= smarty_function_html_options(array('output'          => array('AM', 'PM'),\n                                                           'values'          => array('am', 'pm'),\n                                                           'selected'      => strtolower(strftime('%p', $time)),\n                                                           'print_result' => false),\n                                                     $smarty);\n        $html_result .= \"</select>\\n\";\n    }\n\n    return $html_result;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.html_table.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {html_table} function plugin\n *\n * Type:     function<br>\n * Name:     html_table<br>\n * Date:     Feb 17, 2003<br>\n * Purpose:  make an html table from an array of data<br>\n * Input:<br>\n *         - loop = array to loop through\n *         - cols = number of columns\n *         - rows = number of rows\n *         - table_attr = table attributes\n *         - tr_attr = table row attributes (arrays are cycled)\n *         - td_attr = table cell attributes (arrays are cycled)\n *         - trailpad = value to pad trailing cells with\n *         - vdir = vertical direction (default: \"down\", means top-to-bottom)\n *         - hdir = horizontal direction (default: \"right\", means left-to-right)\n *         - inner = inner loop (default \"cols\": print $loop line by line,\n *                   $loop will be printed column by column otherwise)\n *\n *\n * Examples:\n * <pre>\n * {table loop=$data}\n * {table loop=$data cols=4 tr_attr='\"bgcolor=red\"'}\n * {table loop=$data cols=4 tr_attr=$colors}\n * </pre>\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @version  1.0\n * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table}\n *          (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n */\nfunction smarty_function_html_table($params, &$smarty)\n{\n    $table_attr = 'border=\"1\"';\n    $tr_attr = '';\n    $td_attr = '';\n    $cols = 3;\n    $rows = 3;\n    $trailpad = '&nbsp;';\n    $vdir = 'down';\n    $hdir = 'right';\n    $inner = 'cols';\n\n    if (!isset($params['loop'])) {\n        $smarty->trigger_error(\"html_table: missing 'loop' parameter\");\n        return;\n    }\n\n    foreach ($params as $_key=>$_value) {\n        switch ($_key) {\n            case 'loop':\n                $$_key = (array)$_value;\n                break;\n\n            case 'cols':\n            case 'rows':\n                $$_key = (int)$_value;\n                break;\n\n            case 'table_attr':\n            case 'trailpad':\n            case 'hdir':\n            case 'vdir':\n            case 'inner':\n                $$_key = (string)$_value;\n                break;\n\n            case 'tr_attr':\n            case 'td_attr':\n                $$_key = $_value;\n                break;\n        }\n    }\n\n    $loop_count = count($loop);\n    if (empty($params['rows'])) {\n        /* no rows specified */\n        $rows = ceil($loop_count/$cols);\n    } elseif (empty($params['cols'])) {\n        if (!empty($params['rows'])) {\n            /* no cols specified, but rows */\n            $cols = ceil($loop_count/$rows);\n        }\n    }\n\n    $output = \"<table $table_attr>\\n\";\n\n    for ($r=0; $r<$rows; $r++) {\n        $output .= \"<tr\" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . \">\\n\";\n        $rx =  ($vdir == 'down') ? $r*$cols : ($rows-1-$r)*$cols;\n\n        for ($c=0; $c<$cols; $c++) {\n            $x =  ($hdir == 'right') ? $rx+$c : $rx+$cols-1-$c;\n            if ($inner!='cols') {\n                /* shuffle x to loop over rows*/\n                $x = floor($x/$cols) + ($x%$cols)*$rows;\n            }\n\n            if ($x<$loop_count) {\n                $output .= \"<td\" . smarty_function_html_table_cycle('td', $td_attr, $c) . \">\" . $loop[$x] . \"</td>\\n\";\n            } else {\n                $output .= \"<td\" . smarty_function_html_table_cycle('td', $td_attr, $c) . \">$trailpad</td>\\n\";\n            }\n        }\n        $output .= \"</tr>\\n\";\n    }\n    $output .= \"</table>\\n\";\n    \n    return $output;\n}\n\nfunction smarty_function_html_table_cycle($name, $var, $no) {\n    if(!is_array($var)) {\n        $ret = $var;\n    } else {\n        $ret = $var[$no % count($var)];\n    }\n    \n    return ($ret) ? ' '.$ret : '';\n}\n\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.mailto.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {mailto} function plugin\n *\n * Type:     function<br>\n * Name:     mailto<br>\n * Date:     May 21, 2002\n * Purpose:  automate mailto address link creation, and optionally\n *           encode them.<br>\n * Input:<br>\n *         - address = e-mail address\n *         - text = (optional) text to display, default is address\n *         - encode = (optional) can be one of:\n *                * none : no encoding (default)\n *                * javascript : encode with javascript\n *                * javascript_charcode : encode with javascript charcode\n *                * hex : encode with hexidecimal (no javascript)\n *         - cc = (optional) address(es) to carbon copy\n *         - bcc = (optional) address(es) to blind carbon copy\n *         - subject = (optional) e-mail subject\n *         - newsgroups = (optional) newsgroup(s) to post to\n *         - followupto = (optional) address(es) to follow up to\n *         - extra = (optional) extra tags for the href link\n *\n * Examples:\n * <pre>\n * {mailto address=\"me@domain.com\"}\n * {mailto address=\"me@domain.com\" encode=\"javascript\"}\n * {mailto address=\"me@domain.com\" encode=\"hex\"}\n * {mailto address=\"me@domain.com\" subject=\"Hello to you!\"}\n * {mailto address=\"me@domain.com\" cc=\"you@domain.com,they@domain.com\"}\n * {mailto address=\"me@domain.com\" extra='class=\"mailto\"'}\n * </pre>\n * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto}\n *          (Smarty online manual)\n * @version  1.2\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @author   credits to Jason Sweat (added cc, bcc and subject functionality)\n * @param    array\n * @param    Smarty\n * @return   string\n */\nfunction smarty_function_mailto($params, &$smarty)\n{\n    $extra = '';\n\n    if (empty($params['address'])) {\n        $smarty->trigger_error(\"mailto: missing 'address' parameter\");\n        return;\n    } else {\n        $address = $params['address'];\n    }\n\n    $text = $address;\n\n    // netscape and mozilla do not decode %40 (@) in BCC field (bug?)\n    // so, don't encode it.\n    $mail_parms = array();\n    foreach ($params as $var=>$value) {\n        switch ($var) {\n            case 'cc':\n            case 'bcc':\n            case 'followupto':\n                if (!empty($value))\n                    $mail_parms[] = $var.'='.str_replace('%40','@',rawurlencode($value));\n                break;\n                \n            case 'subject':\n            case 'newsgroups':\n                $mail_parms[] = $var.'='.rawurlencode($value);\n                break;\n\n            case 'extra':\n            case 'text':\n                $$var = $value;\n\n            default:\n        }\n    }\n\n    $mail_parm_vals = '';\n    for ($i=0; $i<count($mail_parms); $i++) {\n        $mail_parm_vals .= (0==$i) ? '?' : '&';\n        $mail_parm_vals .= $mail_parms[$i];\n    }\n    $address .= $mail_parm_vals;\n\n    $encode = (empty($params['encode'])) ? 'none' : $params['encode'];\n    if (!in_array($encode,array('javascript','javascript_charcode','hex','none')) ) {\n        $smarty->trigger_error(\"mailto: 'encode' parameter must be none, javascript or hex\");\n        return;\n    }\n\n    if ($encode == 'javascript' ) {\n        $string = 'document.write(\\'<a href=\"mailto:'.$address.'\" '.$extra.'>'.$text.'</a>\\');';\n\n        $js_encode = '';\n        for ($x=0; $x < strlen($string); $x++) {\n            $js_encode .= '%' . bin2hex($string[$x]);\n        }\n\n        return '<script type=\"text/javascript\">eval(unescape(\\''.$js_encode.'\\'))</script>';\n\n    } elseif ($encode == 'javascript_charcode' ) {\n        $string = '<a href=\"mailto:'.$address.'\" '.$extra.'>'.$text.'</a>';\n\n        for($x = 0, $y = strlen($string); $x < $y; $x++ ) {\n            $ord[] = ord($string[$x]);   \n        }\n\n        $_ret = \"<script type=\\\"text/javascript\\\" language=\\\"javascript\\\">\\n\";\n        $_ret .= \"<!--\\n\";\n        $_ret .= \"{document.write(String.fromCharCode(\";\n        $_ret .= implode(',',$ord);\n        $_ret .= \"))\";\n        $_ret .= \"}\\n\";\n        $_ret .= \"//-->\\n\";\n        $_ret .= \"</script>\\n\";\n        \n        return $_ret;\n        \n        \n    } elseif ($encode == 'hex') {\n\n        preg_match('!^(.*)(\\?.*)$!',$address,$match);\n        if(!empty($match[2])) {\n            $smarty->trigger_error(\"mailto: hex encoding does not work with extra attributes. Try javascript.\");\n            return;\n        }\n        $address_encode = '';\n        for ($x=0; $x < strlen($address); $x++) {\n            if(preg_match('!\\w!',$address[$x])) {\n                $address_encode .= '%' . bin2hex($address[$x]);\n            } else {\n                $address_encode .= $address[$x];\n            }\n        }\n        $text_encode = '';\n        for ($x=0; $x < strlen($text); $x++) {\n            $text_encode .= '&#x' . bin2hex($text[$x]).';';\n        }\n\n        $mailto = \"&#109;&#97;&#105;&#108;&#116;&#111;&#58;\";\n        return '<a href=\"'.$mailto.$address_encode.'\" '.$extra.'>'.$text_encode.'</a>';\n\n    } else {\n        // no encoding\n        return '<a href=\"mailto:'.$address.'\" '.$extra.'>'.$text.'</a>';\n\n    }\n\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.math.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {math} function plugin\n *\n * Type:     function<br>\n * Name:     math<br>\n * Purpose:  handle math computations in template<br>\n * @link http://smarty.php.net/manual/en/language.function.math.php {math}\n *          (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n */\nfunction smarty_function_math($params, &$smarty)\n{\n    // be sure equation parameter is present\n    if (empty($params['equation'])) {\n        $smarty->trigger_error(\"math: missing equation parameter\");\n        return;\n    }\n\n    $equation = $params['equation'];\n\n    // make sure parenthesis are balanced\n    if (substr_count($equation,\"(\") != substr_count($equation,\")\")) {\n        $smarty->trigger_error(\"math: unbalanced parenthesis\");\n        return;\n    }\n\n    // match all vars in equation, make sure all are passed\n    preg_match_all(\"!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!\",$equation, $match);\n    $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10',\n                           'max','min','pi','pow','rand','round','sin','sqrt','srand','tan');\n    \n    foreach($match[1] as $curr_var) {\n        if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) {\n            $smarty->trigger_error(\"math: function call $curr_var not allowed\");\n            return;\n        }\n    }\n\n    foreach($params as $key => $val) {\n        if ($key != \"equation\" && $key != \"format\" && $key != \"assign\") {\n            // make sure value is not empty\n            if (strlen($val)==0) {\n                $smarty->trigger_error(\"math: parameter $key is empty\");\n                return;\n            }\n            if (!is_numeric($val)) {\n                $smarty->trigger_error(\"math: parameter $key: is not numeric\");\n                return;\n            }\n            $equation = preg_replace(\"/\\b$key\\b/\",$val, $equation);\n        }\n    }\n\n    eval(\"\\$smarty_math_result = \".$equation.\";\");\n\n    if (empty($params['format'])) {\n        if (empty($params['assign'])) {\n            return $smarty_math_result;\n        } else {\n            $smarty->assign($params['assign'],$smarty_math_result);\n        }\n    } else {\n        if (empty($params['assign'])){\n            printf($params['format'],$smarty_math_result);\n        } else {\n            $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result));\n        }\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.popup.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {popup} function plugin\n *\n * Type:     function<br>\n * Name:     popup<br>\n * Purpose:  make text pop up in windows via overlib\n * @link http://smarty.php.net/manual/en/language.function.popup.php {popup}\n *          (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n */\nfunction smarty_function_popup($params, &$smarty)\n{\n    $append = '';\n    foreach ($params as $_key=>$_value) {\n        switch ($_key) {\n            case 'text':\n            case 'trigger':\n            case 'function':\n            case 'inarray':\n                $$_key = (string)$_value;\n                if ($_key == 'function' || $_key == 'inarray')\n                    $append .= ',' . strtoupper($_key) . \",'$_value'\";\n                break;\n\n            case 'caption':\n            case 'closetext':\n            case 'status':\n                $append .= ',' . strtoupper($_key) . \",'\" . str_replace(\"'\",\"\\'\",$_value) . \"'\";\n                break;\n\n            case 'fgcolor':\n            case 'bgcolor':\n            case 'textcolor':\n            case 'capcolor':\n            case 'closecolor':\n            case 'textfont':\n            case 'captionfont':\n            case 'closefont':\n            case 'fgbackground':\n            case 'bgbackground':\n            case 'caparray':\n            case 'capicon':\n            case 'background':\n            case 'frame':\n                $append .= ',' . strtoupper($_key) . \",'$_value'\";\n                break;\n\n            case 'textsize':\n            case 'captionsize':\n            case 'closesize':\n            case 'width':\n            case 'height':\n            case 'border':\n            case 'offsetx':\n            case 'offsety':\n            case 'snapx':\n            case 'snapy':\n            case 'fixx':\n            case 'fixy':\n            case 'padx':\n            case 'pady':\n            case 'timeout':\n            case 'delay':\n                $append .= ',' . strtoupper($_key) . \",$_value\";\n                break;\n\n            case 'sticky':\n            case 'left':\n            case 'right':\n            case 'center':\n            case 'above':\n            case 'below':\n            case 'noclose':\n            case 'autostatus':\n            case 'autostatuscap':\n            case 'fullhtml':\n            case 'hauto':\n            case 'vauto':\n            case 'mouseoff':\n            case 'followmouse':\n                if ($_value) $append .= ',' . strtoupper($_key);\n                break;\n\n            default:\n                $smarty->trigger_error(\"[popup] unknown parameter $_key\", E_USER_WARNING);\n        }\n    }\n\n    if (empty($text) && !isset($inarray) && empty($function)) {\n        $smarty->trigger_error(\"overlib: attribute 'text' or 'inarray' or 'function' required\");\n        return false;\n    }\n\n    if (empty($trigger)) { $trigger = \"onmouseover\"; }\n\n    $retval = $trigger . '=\"return overlib(\\''.preg_replace(array(\"!'!\",\"![\\r\\n]!\"),array(\"\\'\",'\\r'),$text).'\\'';\n    $retval .= $append . ');\"';\n    if ($trigger == 'onmouseover')\n       $retval .= ' onmouseout=\"nd();\"';\n\n\n    return $retval;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.popup_init.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty {popup_init} function plugin\n *\n * Type:     function<br>\n * Name:     popup_init<br>\n * Purpose:  initialize overlib\n * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init}\n *          (Smarty online manual)\n * @param array\n * @param Smarty\n * @return string\n */\nfunction smarty_function_popup_init($params, &$smarty)\n{\n    $zindex = 1000;\n    \n    if (!empty($params['zindex'])) {\n        $zindex = $params['zindex'];\n    }\n    \n    if (!empty($params['src'])) {\n        return '<div id=\"overDiv\" style=\"position:absolute; visibility:hidden; z-index:'.$zindex.';\"></div>' . \"\\n\"\n         . '<script type=\"text/javascript\" language=\"JavaScript\" src=\"'.$params['src'].'\"></script>' . \"\\n\";\n    } else {\n        $smarty->trigger_error(\"popup_init: missing src parameter\");\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/function.substr.php",
    "content": "<?php\n\n/*\n *\n * usage: {substr src=\"plop\" start=\"0\" length=\"4\" delim=\"/\"}\n *\n */\n\nfunction smarty_function_substr($params, &$smarty)\n{\n\n    if (!isset($params['src'])) {\n        $smarty->trigger_error(\"substr: missing 'src' parameter\");\n        return;\n    }\n\n    if (!isset($params['var'])) {\n        $smarty->trigger_error(\"substr: missing 'var' parameter\");\n        return;\n    }\n\n\t$tmp = \"\";\n\tif (isset($params['start']) && isset($params['length']))\n\t{\n\t\t$tmp = substr($params['src'], $params['start'], $params['length']);\n\t}\n\telseif (isset($params['start']) && isset($params['delim']))\n\t{\n\t\t$tmp = substr($params['src'], $params['start'], strpos($params['src'], $params['delim']));\n\t}\n\telseif (isset($params['delim']))\n\t{\n\t\t$tmp = substr($params['src'], strpos($params['src'], $params['delim']));\n\t}\n\telseif (isset($params['start']))\n\t{\n\t\t$tmp = substr($params['src'], $params['start']);\n\t}\n\telseif (isset($params['length']))\n\t{\n\t\t$tmp = substr($params['src'], 0, $params['length']);\n\t}\n\telse\n\t{\n        $smarty->trigger_error(\"substr: missing start/stop/delim parameters\");\n        return;\n\t}\n\n\n\t$smarty->assign($params['var'], $tmp);\n\n}\n\n\n?>"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.capitalize.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty capitalize modifier plugin\n *\n * Type:     modifier<br>\n * Name:     capitalize<br>\n * Purpose:  capitalize words in the string\n * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE\n *      capitalize (Smarty online manual)\n * @param string\n * @return string\n */\nfunction smarty_modifier_capitalize($string, $uc_digits = false)\n{\n    smarty_modifier_capitalize_ucfirst(null, $uc_digits);\n    return preg_replace_callback('!\\b\\w+\\b!', 'smarty_modifier_capitalize_ucfirst', $string);\n}\n\nfunction smarty_modifier_capitalize_ucfirst($string, $uc_digits = null)\n{\n    static $_uc_digits = false;\n    \n    if(isset($uc_digits)) {\n        $_uc_digits = $uc_digits;\n        return;\n    }\n    \n    if(!preg_match('!\\d!',$string[0]) || $_uc_digits)\n        return ucfirst($string[0]);\n    else\n        return $string[0];\n}\n\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.cat.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty cat modifier plugin\n *\n * Type:     modifier<br>\n * Name:     cat<br>\n * Date:     Feb 24, 2003\n * Purpose:  catenate a value to a variable\n * Input:    string to catenate\n * Example:  {$var|cat:\"foo\"}\n * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat\n *          (Smarty online manual)\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @version 1.0\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_cat($string, $cat)\n{\n    return $string . $cat;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.count_characters.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty count_characters modifier plugin\n *\n * Type:     modifier<br>\n * Name:     count_characteres<br>\n * Purpose:  count the number of characters in a text\n * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php\n *          count_characters (Smarty online manual)\n * @param string\n * @param boolean include whitespace in the character count\n * @return integer\n */\nfunction smarty_modifier_count_characters($string, $include_spaces = false)\n{\n    if ($include_spaces)\n       return(strlen($string));\n\n    return preg_match_all(\"/[^\\s]/\",$string, $match);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.count_paragraphs.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty count_paragraphs modifier plugin\n *\n * Type:     modifier<br>\n * Name:     count_paragraphs<br>\n * Purpose:  count the number of paragraphs in a text\n * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php\n *          count_paragraphs (Smarty online manual)\n * @param string\n * @return integer\n */\nfunction smarty_modifier_count_paragraphs($string)\n{\n    // count \\r or \\n characters\n    return count(preg_split('/[\\r\\n]+/', $string));\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.count_sentences.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty count_sentences modifier plugin\n *\n * Type:     modifier<br>\n * Name:     count_sentences\n * Purpose:  count the number of sentences in a text\n * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php\n *          count_sentences (Smarty online manual)\n * @param string\n * @return integer\n */\nfunction smarty_modifier_count_sentences($string)\n{\n    // find periods with a word before but not after.\n    return preg_match_all('/[^\\s]\\.(?!\\w)/', $string, $match);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.count_words.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty count_words modifier plugin\n *\n * Type:     modifier<br>\n * Name:     count_words<br>\n * Purpose:  count the number of words in a text\n * @link http://smarty.php.net/manual/en/language.modifier.count.words.php\n *          count_words (Smarty online manual)\n * @param string\n * @return integer\n */\nfunction smarty_modifier_count_words($string)\n{\n    // split text by ' ',\\r,\\n,\\f,\\t\n    $split_array = preg_split('/\\s+/',$string);\n    // count matches that contain alphanumerics\n    $word_count = preg_grep('/[a-zA-Z0-9\\\\x80-\\\\xff]/', $split_array);\n\n    return count($word_count);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.date_format.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Include the {@link shared.make_timestamp.php} plugin\n */\nrequire_once $smarty->_get_plugin_filepath('shared','make_timestamp');\n/**\n * Smarty date_format modifier plugin\n *\n * Type:     modifier<br>\n * Name:     date_format<br>\n * Purpose:  format datestamps via strftime<br>\n * Input:<br>\n *         - string: input date string\n *         - format: strftime format for output\n *         - default_date: default date if $string is empty\n * @link http://smarty.php.net/manual/en/language.modifier.date.format.php\n *          date_format (Smarty online manual)\n * @param string\n * @param string\n * @param string\n * @return string|void\n * @uses smarty_make_timestamp()\n */\nfunction smarty_modifier_date_format($string, $format=\"%b %e, %Y\", $default_date=null)\n{\n    if (substr(PHP_OS,0,3) == 'WIN') {\n           $_win_from = array ('%e',  '%T',       '%D');\n           $_win_to   = array ('%#d', '%H:%M:%S', '%m/%d/%y');\n           $format = str_replace($_win_from, $_win_to, $format);\n    }\n    if($string != '') {\n        return strftime($format, smarty_make_timestamp($string));\n    } elseif (isset($default_date) && $default_date != '') {\n        return strftime($format, smarty_make_timestamp($default_date));\n    } else {\n        return;\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.debug_print_var.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty debug_print_var modifier plugin\n *\n * Type:     modifier<br>\n * Name:     debug_print_var<br>\n * Purpose:  formats variable contents for display in the console\n * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php\n *          debug_print_var (Smarty online manual)\n * @param array|object\n * @param integer\n * @param integer\n * @return string\n */\nfunction smarty_modifier_debug_print_var($var, $depth = 0, $length = 40)\n{\n    $_replace = array(\"\\n\"=>'<i>&#92;n</i>', \"\\r\"=>'<i>&#92;r</i>', \"\\t\"=>'<i>&#92;t</i>');\n    if (is_array($var)) {\n        $results = \"<b>Array (\".count($var).\")</b>\";\n        foreach ($var as $curr_key => $curr_val) {\n            $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length);\n            $results .= \"<br>\".str_repeat('&nbsp;', $depth*2).\"<b>\".strtr($curr_key, $_replace).\"</b> =&gt; $return\";\n        }\n    } else if (is_object($var)) {\n        $object_vars = get_object_vars($var);\n        $results = \"<b>\".get_class($var).\" Object (\".count($object_vars).\")</b>\";\n        foreach ($object_vars as $curr_key => $curr_val) {\n            $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length);\n            $results .= \"<br>\".str_repeat('&nbsp;', $depth*2).\"<b>$curr_key</b> =&gt; $return\";\n        }\n    } else if (is_resource($var)) {\n        $results = '<i>'.(string)$var.'</i>';\n    } else if (empty($var) && $var != \"0\") {\n        $results = '<i>empty</i>';\n    } else {\n        if (strlen($var) > $length ) {\n            $results = substr($var, 0, $length-3).'...';\n        } else {\n            $results = $var;\n        }\n        $results = htmlspecialchars($results);\n        $results = strtr($results, $_replace);\n    }\n    return $results;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.default.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty default modifier plugin\n *\n * Type:     modifier<br>\n * Name:     default<br>\n * Purpose:  designate default value for empty variables\n * @link http://smarty.php.net/manual/en/language.modifier.default.php\n *          default (Smarty online manual)\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_default($string, $default = '')\n{\n    if (!isset($string) || $string === '')\n        return $default;\n    else\n        return $string;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.escape.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty escape modifier plugin\n *\n * Type:     modifier<br>\n * Name:     escape<br>\n * Purpose:  Escape the string according to escapement type\n * @link http://smarty.php.net/manual/en/language.modifier.escape.php\n *          escape (Smarty online manual)\n * @param string\n * @param html|htmlall|url|quotes|hex|hexentity|javascript\n * @return string\n */\nfunction smarty_modifier_escape($string, $esc_type = 'html')\n{\n    switch ($esc_type) {\n        case 'html':\n            return htmlspecialchars($string, ENT_QUOTES);\n\n        case 'htmlall':\n            return htmlentities($string, ENT_QUOTES);\n\n        case 'url':\n            return rawurlencode($string);\n\n        case 'quotes':\n            // escape unescaped single quotes\n            return preg_replace(\"%(?<!\\\\\\\\)'%\", \"\\\\'\", $string);\n\n        case 'hex':\n            // escape every character into hex\n            $return = '';\n            for ($x=0; $x < strlen($string); $x++) {\n                $return .= '%' . bin2hex($string[$x]);\n            }\n            return $return;\n            \n        case 'hexentity':\n            $return = '';\n            for ($x=0; $x < strlen($string); $x++) {\n                $return .= '&#x' . bin2hex($string[$x]) . ';';\n            }\n            return $return;\n\n        case 'decentity':\n            $return = '';\n            for ($x=0; $x < strlen($string); $x++) {\n                $return .= '&#' . ord($string[$x]) . ';';\n            }\n            return $return;\n\n        case 'javascript':\n            // escape quotes and backslashes, newlines, etc.\n            return strtr($string, array('\\\\'=>'\\\\\\\\',\"'\"=>\"\\\\'\",'\"'=>'\\\\\"',\"\\r\"=>'\\\\r',\"\\n\"=>'\\\\n','</'=>'<\\/'));\n            \n        case 'mail':\n            // safe way to display e-mail address on a web page\n            return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string);\n            \n        case 'nonstd':\n           // escape non-standard chars, such as ms document quotes\n           $_res = '';\n           for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {\n               $_ord = ord($string{$_i});\n               // non-standard char, escape it\n               if($_ord >= 126){\n                   $_res .= '&#' . $_ord . ';';\n               }\n               else {\n                   $_res .= $string{$_i};\n               }\n           }\n           return $_res;\n\n        default:\n            return $string;\n    }\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.indent.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty indent modifier plugin\n *\n * Type:     modifier<br>\n * Name:     indent<br>\n * Purpose:  indent lines of text\n * @link http://smarty.php.net/manual/en/language.modifier.indent.php\n *          indent (Smarty online manual)\n * @param string\n * @param integer\n * @param string\n * @return string\n */\nfunction smarty_modifier_indent($string,$chars=4,$char=\" \")\n{\n    return preg_replace('!^!m',str_repeat($char,$chars),$string);\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.lower.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty lower modifier plugin\n *\n * Type:     modifier<br>\n * Name:     lower<br>\n * Purpose:  convert string to lowercase\n * @link http://smarty.php.net/manual/en/language.modifier.lower.php\n *          lower (Smarty online manual)\n * @param string\n * @return string\n */\nfunction smarty_modifier_lower($string)\n{\n    return strtolower($string);\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.nl2br.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty plugin\n *\n * Type:     modifier<br>\n * Name:     nl2br<br>\n * Date:     Feb 26, 2003\n * Purpose:  convert \\r\\n, \\r or \\n to <<br>>\n * Input:<br>\n *         - contents = contents to replace\n *         - preceed_test = if true, includes preceeding break tags\n *           in replacement\n * Example:  {$text|nl2br}\n * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php\n *          nl2br (Smarty online manual)\n * @version  1.0\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @param string\n * @return string\n */\nfunction smarty_modifier_nl2br($string)\n{\n    return nl2br($string);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.regex_replace.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty regex_replace modifier plugin\n *\n * Type:     modifier<br>\n * Name:     regex_replace<br>\n * Purpose:  regular epxression search/replace\n * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php\n *          regex_replace (Smarty online manual)\n * @param string\n * @param string|array\n * @param string|array\n * @return string\n */\nfunction smarty_modifier_regex_replace($string, $search, $replace)\n{\n    if (preg_match('!\\W(\\w+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) {\n        /* remove eval-modifier from $search */\n        $search = substr($search, 0, -strlen($match[1])) . str_replace('e', '', $match[1]);\n    }\n    return preg_replace($search, $replace, $string);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.replace.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty replace modifier plugin\n *\n * Type:     modifier<br>\n * Name:     replace<br>\n * Purpose:  simple search/replace\n * @link http://smarty.php.net/manual/en/language.modifier.replace.php\n *          replace (Smarty online manual)\n * @param string\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_replace($string, $search, $replace)\n{\n    return str_replace($search, $replace, $string);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.spacify.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty spacify modifier plugin\n *\n * Type:     modifier<br>\n * Name:     spacify<br>\n * Purpose:  add spaces between characters in a string\n * @link http://smarty.php.net/manual/en/language.modifier.spacify.php\n *          spacify (Smarty online manual)\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_spacify($string, $spacify_char = ' ')\n{\n    return implode($spacify_char,\n                   preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY));\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.string_format.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty string_format modifier plugin\n *\n * Type:     modifier<br>\n * Name:     string_format<br>\n * Purpose:  format strings via sprintf\n * @link http://smarty.php.net/manual/en/language.modifier.string.format.php\n *          string_format (Smarty online manual)\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_string_format($string, $format)\n{\n    return sprintf($format, $string);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.strip.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty strip modifier plugin\n *\n * Type:     modifier<br>\n * Name:     strip<br>\n * Purpose:  Replace all repeated spaces, newlines, tabs\n *           with a single space or supplied replacement string.<br>\n * Example:  {$var|strip} {$var|strip:\"&nbsp;\"}\n * Date:     September 25th, 2002\n * @link http://smarty.php.net/manual/en/language.modifier.strip.php\n *          strip (Smarty online manual)\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @version  1.0\n * @param string\n * @param string\n * @return string\n */\nfunction smarty_modifier_strip($text, $replace = ' ')\n{\n    return preg_replace('!\\s+!', $replace, $text);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.strip_tags.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty strip_tags modifier plugin\n *\n * Type:     modifier<br>\n * Name:     strip_tags<br>\n * Purpose:  strip html tags from text\n * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php\n *          strip_tags (Smarty online manual)\n * @param string\n * @param boolean\n * @return string\n */\nfunction smarty_modifier_strip_tags($string, $replace_with_space = true)\n{\n    if ($replace_with_space)\n        return preg_replace('!<[^>]*?>!', ' ', $string);\n    else\n        return strip_tags($string);\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.truncate.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty truncate modifier plugin\n *\n * Type:     modifier<br>\n * Name:     truncate<br>\n * Purpose:  Truncate a string to a certain length if necessary,\n *           optionally splitting in the middle of a word, and\n *           appending the $etc string.\n * @link http://smarty.php.net/manual/en/language.modifier.truncate.php\n *          truncate (Smarty online manual)\n * @param string\n * @param integer\n * @param string\n * @param boolean\n * @return string\n */\nfunction smarty_modifier_truncate($string, $length = 80, $etc = '...',\n                                  $break_words = false)\n{\n    if ($length == 0)\n        return '';\n\n    if (strlen($string) > $length) {\n        $length -= strlen($etc);\n        if (!$break_words)\n            $string = preg_replace('/\\s+?(\\S+)?$/', '', substr($string, 0, $length+1));\n      \n        return substr($string, 0, $length).$etc;\n    } else\n        return $string;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.upper.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty upper modifier plugin\n *\n * Type:     modifier<br>\n * Name:     upper<br>\n * Purpose:  convert string to uppercase\n * @link http://smarty.php.net/manual/en/language.modifier.upper.php\n *          upper (Smarty online manual)\n * @param string\n * @return string\n */\nfunction smarty_modifier_upper($string)\n{\n    return strtoupper($string);\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/modifier.wordwrap.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Smarty wordwrap modifier plugin\n *\n * Type:     modifier<br>\n * Name:     wordwrap<br>\n * Purpose:  wrap a string of text at a given length\n * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php\n *          wordwrap (Smarty online manual)\n * @param string\n * @param integer\n * @param string\n * @param boolean\n * @return string\n */\nfunction smarty_modifier_wordwrap($string,$length=80,$break=\"\\n\",$cut=false)\n{\n    return wordwrap($string,$length,$break,$cut);\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/outputfilter.trimwhitespace.php",
    "content": "<?php\n/**\n * Smarty plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n/**\n * Smarty trimwhitespace outputfilter plugin\n *\n * File:     outputfilter.trimwhitespace.php<br>\n * Type:     outputfilter<br>\n * Name:     trimwhitespace<br>\n * Date:     Jan 25, 2003<br>\n * Purpose:  trim leading white space and blank lines from\n *           template source after it gets interpreted, cleaning\n *           up code and saving bandwidth. Does not affect\n *           <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br>\n * Install:  Drop into the plugin directory, call\n *           <code>$smarty->load_filter('output','trimwhitespace');</code>\n *           from application.\n * @author   Monte Ohrt <monte at ohrt dot com>\n * @author Contributions from Lars Noschinski <lars@usenet.noschinski.de>\n * @version  1.3\n * @param string\n * @param Smarty\n */\nfunction smarty_outputfilter_trimwhitespace($source, &$smarty)\n{\n    // Pull out the script blocks\n    preg_match_all(\"!<script[^>]+>.*?</script>!is\", $source, $match);\n    $_script_blocks = $match[0];\n    $source = preg_replace(\"!<script[^>]+>.*?</script>!is\",\n                           '@@@SMARTY:TRIM:SCRIPT@@@', $source);\n\n    // Pull out the pre blocks\n    preg_match_all(\"!<pre>.*?</pre>!is\", $source, $match);\n    $_pre_blocks = $match[0];\n    $source = preg_replace(\"!<pre>.*?</pre>!is\",\n                           '@@@SMARTY:TRIM:PRE@@@', $source);\n\n    // Pull out the textarea blocks\n    preg_match_all(\"!<textarea[^>]+>.*?</textarea>!is\", $source, $match);\n    $_textarea_blocks = $match[0];\n    $source = preg_replace(\"!<textarea[^>]+>.*?</textarea>!is\",\n                           '@@@SMARTY:TRIM:TEXTAREA@@@', $source);\n\n    // remove all leading spaces, tabs and carriage returns NOT\n    // preceeded by a php close tag.\n    $source = trim(preg_replace('/((?<!\\?>)\\n)[\\s]+/m', '\\1', $source));\n\n    // replace script blocks\n    smarty_outputfilter_trimwhitespace_replace(\"@@@SMARTY:TRIM:SCRIPT@@@\",$_script_blocks, $source);\n\n    // replace pre blocks\n    smarty_outputfilter_trimwhitespace_replace(\"@@@SMARTY:TRIM:PRE@@@\",$_pre_blocks, $source);\n\n    // replace textarea blocks\n    smarty_outputfilter_trimwhitespace_replace(\"@@@SMARTY:TRIM:TEXTAREA@@@\",$_textarea_blocks, $source);\n\n    return $source;\n}\n\nfunction smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) {\n    $_len = strlen($search_str);\n    $_pos = 0;\n    for ($_i=0, $_count=count($replace); $_i<$_count; $_i++)\n        if (($_pos=strpos($subject, $search_str, $_pos))!==false)\n            $subject = substr_replace($subject, $replace[$_i], $_pos, $_len);\n        else\n            break;\n\n}\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/shared.escape_special_chars.php",
    "content": "<?php\n/**\n * Smarty shared plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * escape_special_chars common function\n *\n * Function: smarty_function_escape_special_chars<br>\n * Purpose:  used by other smarty functions to escape\n *           special chars except for already escaped ones\n * @param string\n * @return string\n */\nfunction smarty_function_escape_special_chars($string)\n{\n    if(!is_array($string)) {\n        $string = preg_replace('!&(#?\\w+);!', '%%%SMARTY_START%%%\\\\1%%%SMARTY_END%%%', $string);\n        $string = htmlspecialchars($string);\n        $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string);\n    }\n    return $string;\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/smarty/plugins/shared.make_timestamp.php",
    "content": "<?php\n/**\n * Smarty shared plugin\n * @package Smarty\n * @subpackage plugins\n */\n\n\n/**\n * Function: smarty_make_timestamp<br>\n * Purpose:  used by other smarty functions to make a timestamp\n *           from a string.\n * @param string\n * @return string\n */\nfunction smarty_make_timestamp($string)\n{\n    if(empty($string)) {\n        $string = \"now\";\n    }\n    $time = strtotime($string);\n    if (is_numeric($time) && $time != -1)\n        return $time;\n\n    // is mysql timestamp format of YYYYMMDDHHMMSS?\n    if (preg_match('/^\\d{14}$/', $string)) {\n        $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2),\n               substr($string,4,2),substr($string,6,2),substr($string,0,4));\n\n        return $time;\n    }\n\n    // couldn't recognize it, try to return a time\n    $time = (int) $string;\n    if ($time > 0)\n        return $time;\n    else\n        return time();\n}\n\n/* vim: set expandtab: */\n\n?>\n"
  },
  {
    "path": "tools/server/admin/templates/default/_index.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction openWindow(w_uri, w_title)\n\t{\n\t\twindow.open(w_uri, w_title, 'width=800,height=600,directories=no,location=no,menubar=no,resizable=yes,scrollbars=no,status=no,toolbar=no');\n\t}\n\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"index.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"index.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"index.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n{if $restriction_tool_notes && $tool_note_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Notes</th>\n\t\t</tr>\n{section name=note loop=$tool_note_list}\n\t\t<tr>\n{if $tool_note_list[note].note_mode == 0}\n\t\t\t<td align=\"center\"><a href=\"javascript:void(0);\" onclick=\"return overlib('{$tool_note_list[note].note_data}', WIDTH, 250, STICKY, DRAGGABLE, CAPTION, '{$tool_note_list[note].note_title2}', CENTER, CLOSECLICK, ANCHOR, 'ol_anchor_right', ANCHORALIGN, 'LL', 'UR');\" onmouseout=\"nd();\">{$tool_note_list[note].note_title}</a></td>\n{elseif $tool_note_list[note].note_mode == 1}\n\t\t\t<td align=\"center\"><a href=\"javascript:openWindow('{$tool_note_list[note].note_popup_uri}','{$tool_note_list[note].note_title}');\">{$tool_note_list[note].note_title}</a></td>\n{/if}\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{if $tool_hd_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">HardDrives</th>\n\t\t</tr>\n{section name=hd loop=$tool_hd_list}\n{if $tool_hd_list[hd].hd_percent >= 85}{assign var=\"hdtrclass\" value=\"row_red\"}\n{elseif $tool_hd_list[hd].hd_percent >= 75}{assign var=\"hdtrclass\" value=\"row_orange_light\"}\n{else}{assign var=\"hdtrclass\" value=\"row0\"}{/if}\n\t\t<tr class=\"{$hdtrclass}\">\n\t\t\t<td align=\"left\" ><a href=\"javascript:void(0);\" onmouseover=\"return overlib('{$tool_hd_list[hd].summary}', OFFSETX, 40, OFFSETY, 10);\" onmouseout=\"return nd();\">{$tool_hd_list[hd].hd_server}</a></td>\n\t\t\t<td align=\"right\">{$tool_hd_list[hd].hd_percent}%</td>\n\t\t</tr>\n{/section}\n\t\t<tr>\n\t\t\t<th colspan=\"10\"><small>{$tool_hd_time|date_format:\"%Y/%m/%d %H:%M:%S\"}</small></th>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n{if tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"index.php\" method=\"post\">\n{if $tool_annotation_info || $tool_has_lock}\n\t\t<tr>\n\t\t\t<th width=\"10%\">Annotation</th>\n\t\t\t<td><input type=\"text\" name=\"annotation\" value=\"{$tool_annotation_info.annotation_data}\" maxlength=\"255\" size=\"80\" {if !$tool_has_lock}readonly{/if}> {if $tool_has_lock}<input type=\"submit\" name=\"lock\" value=\"update annotation\">{/if}\n{if $tool_annotation_info}\n\t\t\t({$tool_annotation_info.annotation_user_name} @ {$tool_annotation_info.annotation_date|date_format:\"%Y/%m/%d %H:%M:%S\"})\n{/if}\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<th width=\"10%\">Lock</th>\n\t\t\t<td>\n{if $tool_no_lock}\n{* if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && ($tool_shard_restart_status == 0) && !$tool_no_domain_lock *}\n{if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && !$tool_no_domain_lock}\n\t\t\t\t{if $restriction_tool_main_lock_shard}<input type=\"submit\" name=\"lock\" value=\"lock shard\">{/if}\n{else}\n\t\t\t\tLock unavailable, a restart sequence is active !\n{/if}\n{if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)}\n\t\t\t\t{if $restriction_tool_main_lock_domain}<input type=\"submit\" name=\"lock\" value=\"lock domain\">{/if}\n{/if}\n{elseif $tool_has_shard_lock}\n{if $tool_shard_restart_status == 0}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"unlock shard\">\n{/if}\n{if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)}\n\t\t\t\t{if $restriction_tool_main_lock_domain}<input type=\"submit\" name=\"lock\" value=\"lock domain\">{/if}\n{elseif $tool_shard_restart_status > 0}\n\t\t\t\tRestart Sequence is active !\n{/if}\n\n{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status == 0)}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"restart sequence\" class=\"restart\" onclick=\"if (confirm('Are you sure you want to engage the RESTART SEQUENCE for this shard ?')) return true; return false;\">\n\t\t\t\t<input type=\"hidden\" name=\"restart_ws_state\" value=\"{$tool_restart_ws_state}\">\n{/if}\n\n{elseif $tool_has_domain_lock}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"unlock domain\">\n{/if}\n{if $tool_lock_info}\n{if $tool_lock_info.lock_domain_id} Domain{elseif $tool_lock_info.lock_shard_id} Shard{/if}\n\t\t\t\tLocked by <b>{$tool_lock_info.lock_user_name}</b> @ {$tool_lock_info.lock_date|date_format:\"%Y/%m/%d %H:%M:%S\"}\n{else}\n\t\t\t\tUnlocked.\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a shard.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<form action=\"index.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n{*<td class=\"heads\">LongName</td>*}\n\t\t\t<td class=\"heads\">ShortName</td>\n{*<td class=\"heads\">ServiceAlias</td>*}\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Orders</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Start Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{* assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\" *}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_red\"}\n{elseif $tool_services_list[service]._flags_.alert_orange_dark && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_orange_dark\"}\n{elseif $tool_services_list[service]._flags_.alert_orange_light && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n{*<td>{$tool_services_list[service].LongName}</td>*}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n{*<td>{$tool_services_list[service].ServiceAlias}</td>*}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningOrders}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0)}\n\n{include file=\"index_restart_sequence.tpl\"}\n\n{else}\n\n{if $restriction_tool_main_ws}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>WS : </b>{if $restriction_tool_main_ws_old}<br><small><a href=\"javascript:toggleBox('ws_old','ws_new');\">new/old</a></small>{/if}</td>\n\t\t\t<td>\n{if $restriction_tool_main_ws_old}\n<div id=\"ws_old\" style=\"display: none;\">\n\t\t\t\t&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"open ws\"\t onclick=\"if (confirm('Are you sure you want to OPEN the selected WS services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"lock ws\"\t onclick=\"if (confirm('Are you sure you want to LOCK the selected WS services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"close ws\" onclick=\"if (confirm('Are you sure you want to CLOSE the selected WS services ?')) return true; return false;\">&nbsp;\n</div>\n{/if}\n<div id=\"ws_new\">\n\t\t\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\">\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_shard_name\" value=\"\">\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_shard_id\" value=\"\">\n\n{section name=shard loop=$tool_shard_run_list}\n{assign var=\"sname\" value=$tool_shard_run_list[shard]}\n{if $tool_shard_infos[$sname] && $tool_shard_su_name}\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td width=\"10%\">&nbsp;<b>{$tool_shard_run_list[shard]}</b></td>\n\t\t\t\t\t\t<td width=\"10%\">\n\t\t\t\t\t\t\t<select name=\"ws_state_{$sname}\">\n{section name=state loop=$tool_shard_ws_states}\n\t\t\t\t\t\t\t\t<option class=\"ws_{$tool_shard_ws_states[state]}\" value=\"{$tool_shard_ws_states[state]}\" {if $tool_shard_infos[$sname].state == $tool_shard_ws_states[state]}selected{/if}>{$tool_shard_ws_states[state]}</option>\n{/section}\n\t\t\t\t\t\t\t</select></td>\n\t\t\t\t\t\t<td width=\"20%\"><input type=\"text\" name=\"ws_motd_{$sname}\" value=\"{$tool_shard_infos[$sname].motd}\" maxlength=\"255\" size=\"40\"></td>\n\t\t\t\t\t\t<td width=\"20%\"><input type=\"submit\" name=\"ws_update\" value=\"update WS\" onclick=\"if (confirm('Are you sure you want to change the WS State for shard &lt;{$sname}&gt; ?')) {ldelim} this.form.ws_shard_name.value='{$sname}'; this.form.ws_shard_id.value='{$tool_shard_infos[$sname].shard_id}'; return true; {rdelim} else {ldelim} return false; {rdelim}\"></td>\n\t\t\t\t\t\t<td>&nbsp;</td>\n\t\t\t\t\t</tr>\n{/if}\n{/section}\n\t\t\t\t</table>\n</div>\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $restriction_tool_main_start || $restriction_tool_main_stop || $restriction_tool_main_restart || $restriction_tool_main_kill || $restriction_tool_main_abort || $restriction_tool_main_reset_counters || $restriction_tool_main_service_autostart}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Services : </b></td>\n\t\t\t<td>&nbsp;\n{if $restriction_tool_main_start}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"start\"\tonclick=\"if (confirm('Are you sure you want to START the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_stop}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"stop\"\tonclick=\"if (confirm('Are you sure you want to STOP the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_restart}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"restart\"\tonclick=\"if (confirm('Are you sure you want to RESTART the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_kill}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"kill\"\tonclick=\"if (confirm('Are you sure you want to KILL the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_abort}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"abort\"\tonclick=\"if (confirm('Are you sure you want to ABORT the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_service_autostart}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"activate\"\tonclick=\"if (confirm('Are you sure you want to ACTIVATE the selected services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"deactivate\"\tonclick=\"if (confirm('Are you sure you want to DEACTIVATE the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_reset_counters}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"reset counters\"\tonclick=\"if (confirm('Are you sure you want to RESET START COUNTERS on the selected services (AES only) ?')) return true; return false;\">&nbsp;\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $restriction_tool_main_shard_autostart && $tool_shard_run_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Shards : </b></td>\n\t\t\t<td><table width=\"100%\" border=\"0\" cellpadding=\"1\">\n\t\t\t\t<input type=\"hidden\" name=\"shards_update_name\" value=\"\">\n{section name=shard loop=$tool_shard_run_list}\n{assign var=\"sname\" value=$tool_shard_run_list[shard]}\n\t\t\t\t<tr>\n\t\t\t\t\t<td width=\"10%\">&nbsp;<b>{$tool_shard_run_list[shard]}</b></td>\n\t\t\t\t\t<td width=\"10%\">{if $sname != \"\"}<span class=\"{$tool_shard_orders[$sname]}\">{$tool_shard_orders[$sname]|replace:'_':'&nbsp;'}</span>{/if}&nbsp;</td>\n\t\t\t\t\t<td width=\"80%\">\n\t\t\t\t\t\t<input type=\"submit\" name=\"shards_update\" value=\"auto restart on\"  onclick=\"if (confirm('Are you sure you want to set AUTO RESTART ON for shard &lt;{$tool_shard_run_list[shard]}&gt; ?')) {ldelim} this.form.shards_update_name.value='{$tool_shard_run_list[shard]}'; return true; {rdelim} else {ldelim} return false; {rdelim}\">&nbsp;\n\t\t\t\t\t\t<input type=\"submit\" name=\"shards_update\" value=\"auto restart off\" onclick=\"if (confirm('Are you sure you want to set AUTO RESTART OFF for shard &lt;{$tool_shard_run_list[shard]}&gt; ?')) {ldelim} this.form.shards_update_name.value='{$tool_shard_run_list[shard]}'; return true; {rdelim} else {ldelim} return false; {rdelim}\">&nbsp;\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n{/section}\n\t\t\t</table></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $restriction_tool_main_execute}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Command : </b></td>\n\t\t\t<td>&nbsp;<input type=\"text\" name=\"service_command\" value=\"{$tool_execute_command}\" size=\"50\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"execute\"\t{* onclick=\"if (confirm('Are you sure you want to EXECUTE this command on the selected services ?')) return true; return false;\" *}>&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n{/if}\n\n{* end of: if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0) *}\n{/if}\n\t\t</form>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/index.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction openWindow(w_uri, w_title)\n\t{\n\t\twindow.open(w_uri, w_title, 'width=800,height=600,directories=no,location=no,menubar=no,resizable=yes,scrollbars=no,status=no,toolbar=no');\n\t}\n\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"index.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"index.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"index.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n{if $restriction_tool_notes && $tool_note_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Notes</th>\n\t\t</tr>\n{section name=note loop=$tool_note_list}\n\t\t<tr>\n{if $tool_note_list[note].note_mode == 0}\n\t\t\t<td align=\"center\"><a href=\"javascript:void(0);\" onclick=\"return overlib('{$tool_note_list[note].note_data}', WIDTH, 250, STICKY, DRAGGABLE, CAPTION, '{$tool_note_list[note].note_title2}', CENTER, CLOSECLICK, ANCHOR, 'ol_anchor_right', ANCHORALIGN, 'LL', 'UR');\" onmouseout=\"nd();\">{$tool_note_list[note].note_title}</a></td>\n{elseif $tool_note_list[note].note_mode == 1}\n\t\t\t<td align=\"center\"><a href=\"javascript:openWindow('{$tool_note_list[note].note_popup_uri}','{$tool_note_list[note].note_title}');\">{$tool_note_list[note].note_title}</a></td>\n{/if}\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{if $tool_hd_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">HardDrives</th>\n\t\t</tr>\n{section name=hd loop=$tool_hd_list}\n{if $tool_hd_list[hd].hd_percent >= 85}{assign var=\"hdtrclass\" value=\"row_red\"}\n{elseif $tool_hd_list[hd].hd_percent >= 75}{assign var=\"hdtrclass\" value=\"row_orange_light\"}\n{else}{assign var=\"hdtrclass\" value=\"row0\"}{/if}\n\t\t<tr class=\"{$hdtrclass}\">\n\t\t\t<td align=\"left\" ><a href=\"javascript:void(0);\" onmouseover=\"return overlib('{$tool_hd_list[hd].summary}', OFFSETX, 40, OFFSETY, 10);\" onmouseout=\"return nd();\">{$tool_hd_list[hd].hd_server}</a></td>\n\t\t\t<td align=\"right\">{$tool_hd_list[hd].hd_percent}%</td>\n\t\t</tr>\n{/section}\n\t\t<tr>\n\t\t\t<th colspan=\"10\"><small>{$tool_hd_time|date_format:\"%Y/%m/%d %H:%M:%S\"}</small></th>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n{if tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"index.php\" method=\"post\">\n{if $tool_annotation_info || $tool_has_lock}\n\t\t<tr>\n\t\t\t<th width=\"10%\">Annotation</th>\n\t\t\t<td><input type=\"text\" name=\"annotation\" value=\"{$tool_annotation_info.annotation_data}\" maxlength=\"255\" size=\"80\" {if !$tool_has_lock}readonly{/if}> {if $tool_has_lock}<input type=\"submit\" name=\"lock\" value=\"update annotation\">{/if}\n{if $tool_annotation_info}\n\t\t\t({$tool_annotation_info.annotation_user_name} @ {$tool_annotation_info.annotation_date|date_format:\"%Y/%m/%d %H:%M:%S\"})\n{/if}\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<th width=\"10%\">Lock</th>\n\t\t\t<td>\n{if $tool_no_lock}\n{* if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && ($tool_shard_restart_status == 0) && !$tool_no_domain_lock *}\n{if (!$tool_lock_info || $tool_lock_info.lock_shard_id) && !$tool_cant_lock && !$tool_no_domain_lock}\n\t\t\t\t{if $restriction_tool_main_lock_shard}<input type=\"submit\" name=\"lock\" value=\"lock shard\">{/if}\n{else}\n\t\t\t\tLock unavailable, a restart sequence is active !\n{/if}\n{if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)}\n\t\t\t\t{if $restriction_tool_main_lock_domain}<input type=\"submit\" name=\"lock\" value=\"lock domain\">{/if}\n{/if}\n{elseif $tool_has_shard_lock}\n{if $tool_shard_restart_status == 0}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"unlock shard\">\n{/if}\n{if ($tool_shard_restart_status == 0) && ($tool_domain_has_shard_restart == 0)}\n\t\t\t\t{if $restriction_tool_main_lock_domain}<input type=\"submit\" name=\"lock\" value=\"lock domain\">{/if}\n{elseif $tool_shard_restart_status > 0}\n\t\t\t\tRestart Sequence is active !\n{/if}\n\n{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status == 0)}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"restart sequence\" class=\"restart\" onclick=\"if (confirm('Are you sure you want to engage the RESTART SEQUENCE for this shard ?')) return true; return false;\">\n\t\t\t\t<input type=\"hidden\" name=\"restart_ws_state\" value=\"{$tool_restart_ws_state}\">\n{/if}\n\n{elseif $tool_has_domain_lock}\n\t\t\t\t<input type=\"submit\" name=\"lock\" value=\"unlock domain\">\n{/if}\n{if $tool_lock_info}\n{if $tool_lock_info.lock_domain_id} Domain{elseif $tool_lock_info.lock_shard_id} Shard{/if}\n\t\t\t\tLocked by <b>{$tool_lock_info.lock_user_name}</b> @ {$tool_lock_info.lock_date|date_format:\"%Y/%m/%d %H:%M:%S\"}\n{else}\n\t\t\t\tUnlocked.\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a shard.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<form action=\"index.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n{if !$iPhone}\n\t\t\t<td class=\"heads\">Shard</td>\n{*<td class=\"heads\">LongName</td>*}\n\t\t\t<td class=\"heads\">ShortName</td>\n{*<td class=\"heads\">ServiceAlias</td>*}\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Orders</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n{/if}\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Rep</td>\n\t\t\t<td class=\"heads\">Start Cntrs</td>\n{if !$iPhone}\n\t\t\t<td class=\"heads\">User SL</td>\n{/if}\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Mem</td>\n\t\t\t<td class=\"heads\">Nb Play</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{* assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\" *}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_red\"}\n{elseif $tool_services_list[service]._flags_.alert_orange_dark && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_orange_dark\"}\n{elseif $tool_services_list[service]._flags_.alert_orange_light && ($tool_services_list[service]._flags_.rs_starting || $tool_services_list[service]._flags_.rs_online)}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n{if !$iPhone}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n{*<td>{$tool_services_list[service].LongName}</td>*}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n{*<td>{$tool_services_list[service].ServiceAlias}</td>*}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningOrders}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n{/if}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n{if !$iPhone}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n{/if}\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td nowrap onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0)}\n\n{include file=\"index_restart_sequence.tpl\"}\n\n{else}\n\n{* if $restriction_tool_main_ws *}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>WS : </b>{if $restriction_tool_main_ws_old && $restriction_tool_main_ws}<br><small><a href=\"javascript:toggleBox('ws_old','ws_new');\">new/old</a></small>{/if}</td>\n\t\t\t<td>\n{if $restriction_tool_main_ws_old && $restriction_tool_main_ws}\n<div id=\"ws_old\" style=\"display: none;\">\n\t\t\t\t&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"open ws\"\t onclick=\"if (confirm('Are you sure you want to OPEN the selected WS services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"lock ws\"\t onclick=\"if (confirm('Are you sure you want to LOCK the selected WS services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"close ws\" onclick=\"if (confirm('Are you sure you want to CLOSE the selected WS services ?')) return true; return false;\">&nbsp;\n</div>\n{/if}\n<div id=\"ws_new\">\n\t\t\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\">\n{if $restriction_tool_main_ws}\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_shard_name\" value=\"\">\n\t\t\t\t\t<input type=\"hidden\" name=\"ws_shard_id\" value=\"\">\n{/if}\n{section name=shard loop=$tool_shard_run_list}\n{assign var=\"sname\" value=$tool_shard_run_list[shard]}\n{if $tool_shard_infos[$sname] && $tool_shard_su_name}\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<td width=\"10%\">&nbsp;<b>{$tool_shard_run_list[shard]}</b></td>\n\t\t\t\t\t\t<td width=\"10%\">\n\t\t\t\t\t\t\t<select name=\"ws_state_{$sname}\" {if !$restriction_tool_main_ws}disabled{/if}>\n{section name=state loop=$tool_shard_ws_states}\n\t\t\t\t\t\t\t\t<option class=\"ws_{$tool_shard_ws_states[state]}\" value=\"{$tool_shard_ws_states[state]}\" {if $tool_shard_infos[$sname].state == $tool_shard_ws_states[state]}selected{/if}>{$tool_shard_ws_states[state]}</option>\n{/section}\n\t\t\t\t\t\t\t</select></td>\n\t\t\t\t\t\t<td width=\"20%\"><input type=\"text\" name=\"ws_motd_{$sname}\" value=\"{$tool_shard_infos[$sname].motd}\" maxlength=\"255\" size=\"40\" {if !$restriction_tool_main_ws}disabled{/if}></td>\n\t\t\t\t\t\t<td width=\"20%\">\n{if $restriction_tool_main_ws}\n\t\t\t\t\t\t\t<input type=\"submit\" name=\"ws_update\" value=\"update WS\" onclick=\"if (confirm('Are you sure you want to change the WS State for shard &lt;{$sname}&gt; ?')) {ldelim} this.form.ws_shard_name.value='{$sname}'; this.form.ws_shard_id.value='{$tool_shard_infos[$sname].shard_id}'; return true; {rdelim} else {ldelim} return false; {rdelim}\">\n{/if}\n\t\t\t\t\t\t&nbsp;</td>\n\t\t\t\t\t\t<td>&nbsp;</td>\n\t\t\t\t\t</tr>\n{/if}\n{/section}\n\t\t\t\t</table>\n</div>\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{* /if *}\n\n{if $restriction_tool_main_start || $restriction_tool_main_stop || $restriction_tool_main_restart || $restriction_tool_main_kill || $restriction_tool_main_abort || $restriction_tool_main_reset_counters || $restriction_tool_main_service_autostart}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Services : </b></td>\n\t\t\t<td>&nbsp;\n{if $restriction_tool_main_start}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"start\"\tonclick=\"if (confirm('Are you sure you want to START the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_stop}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"stop\"\tonclick=\"if (confirm('Are you sure you want to STOP the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_restart}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"restart\"\tonclick=\"if (confirm('Are you sure you want to RESTART the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_kill}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"kill\"\tonclick=\"if (confirm('Are you sure you want to KILL the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_abort}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"abort\"\tonclick=\"if (confirm('Are you sure you want to ABORT the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_service_autostart}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"activate\"\tonclick=\"if (confirm('Are you sure you want to ACTIVATE the selected services ?')) return true; return false;\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"deactivate\"\tonclick=\"if (confirm('Are you sure you want to DEACTIVATE the selected services ?')) return true; return false;\">&nbsp;\n{/if}\n{if $restriction_tool_main_reset_counters}\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"reset counters\"\tonclick=\"if (confirm('Are you sure you want to RESET START COUNTERS on the selected services (AES only) ?')) return true; return false;\">&nbsp;\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $restriction_tool_main_shard_autostart && $tool_shard_run_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Shards : </b></td>\n\t\t\t<td><table width=\"100%\" border=\"0\" cellpadding=\"1\">\n\t\t\t\t<input type=\"hidden\" name=\"shards_update_name\" value=\"\">\n{section name=shard loop=$tool_shard_run_list}\n{assign var=\"sname\" value=$tool_shard_run_list[shard]}\n\t\t\t\t<tr>\n\t\t\t\t\t<td width=\"10%\">&nbsp;<b>{$tool_shard_run_list[shard]}</b></td>\n\t\t\t\t\t<td width=\"10%\">{if $sname != \"\"}<span class=\"{$tool_shard_orders[$sname]}\">{$tool_shard_orders[$sname]|replace:'_':'&nbsp;'}</span>{/if}&nbsp;</td>\n\t\t\t\t\t<td width=\"80%\">\n\t\t\t\t\t\t<input type=\"submit\" name=\"shards_update\" value=\"auto restart on\"  onclick=\"if (confirm('Are you sure you want to set AUTO RESTART ON for shard &lt;{$tool_shard_run_list[shard]}&gt; ?')) {ldelim} this.form.shards_update_name.value='{$tool_shard_run_list[shard]}'; return true; {rdelim} else {ldelim} return false; {rdelim}\">&nbsp;\n\t\t\t\t\t\t<input type=\"submit\" name=\"shards_update\" value=\"auto restart off\" onclick=\"if (confirm('Are you sure you want to set AUTO RESTART OFF for shard &lt;{$tool_shard_run_list[shard]}&gt; ?')) {ldelim} this.form.shards_update_name.value='{$tool_shard_run_list[shard]}'; return true; {rdelim} else {ldelim} return false; {rdelim}\">&nbsp;\n\t\t\t\t\t</td>\n\t\t\t\t</tr>\n{/section}\n\t\t\t</table></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $restriction_tool_main_execute}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Command : </b></td>\n\t\t\t<td>&nbsp;<input type=\"text\" name=\"service_command\" value=\"{$tool_execute_command}\" size=\"50\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_update\" value=\"execute\"\t{* onclick=\"if (confirm('Are you sure you want to EXECUTE this command on the selected services ?')) return true; return false;\" *}>&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n{/if}\n\n{* end of: if $restriction_tool_main_easy_restart && ($tool_shard_restart_status > 0) *}\n{/if}\n\t\t</form>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/index_login.tpl",
    "content": "\n{include file=\"page_header_light.tpl\"}\n\n<h2>Shard Administration Website</h2>\n\n<p>Use login: <b>guest</b> and password: <b>guest</b> to login.</p>\n\n<table width=\"30%\" border=\"0\">\n<form action=\"index.php\" method=\"post\">\n\t<tr>\n\t\t<td>Login:</td>\n\t\t<td><input type=\"text\" name=\"nel_login\" value=\"guest\"></td>\n\t</tr>\n\t<tr>\n\t\t<td>Password:</td>\n\t\t<td><input type=\"password\" name=\"nel_passwd\" value=\"guest\"></td>\n\t</tr>\n\t<tr>\n\t\t<td>&nbsp;</td>\n\t\t<td><input type=\"submit\" name=\"action\" value=\"login\">\n\t</tr>\n</form>\n</table>\n\n{include file=\"page_footer_light.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/index_restart_sequence.tpl",
    "content": "\n{* this closes the global service form *}\n{* due to incompatibilities with jscript functions with moz/ie i need to do individiual forms :( *}\n</form>\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tvar total_secs_restart;\n\tvar total_secs_restart2;\n\n\tfunction TimerDownRestart(secs)\n\t{\n\t\ttotal_secs_restart = secs;\n\t\tCountDownRestart();\n\t}\n\n\tfunction CountDownRestart()\n\t{\n\t\ttotal_secs_restart--;\n\t\tif (total_secs_restart >= 0)\n\t\t{\n\t\t\tdocument.restart1.restart_wait_timer_fake.value = 'Waiting for '+ TimerDisplay(total_secs_restart) +' minutes !';\n\t\t\tdownRestart=setTimeout(\"CountDownRestart()\",1000);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/*document.restart1.restart_wait_timer_fake.disabled = false;*/\n\t\t\tdocument.restart1.submit();\n\t\t}\n\t}\n\n\tfunction TimerDownRestart2(secs)\n\t{\n\t\ttotal_secs_restart2 = secs;\n\t\tCountDownRestart2();\n\t}\n\n\tfunction CountDownRestart2()\n\t{\n\t\ttotal_secs_restart2--;\n\t\tif (total_secs_restart2 >= 0)\n\t\t{\n\t\t\tdocument.restart2.restart_shutdown_timer_fake.value = 'Waiting for '+ TimerDisplay(total_secs_restart2) +' minutes !';\n\t\t\tdownRestart2=setTimeout(\"CountDownRestart2()\",1000);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/*document.restart2.restart_shutdown_timer_fake.disabled = false;*/\n\t\t\tdocument.restart2.submit();\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\n\t\t\t<td align=\"center\" width=\"100px\"><b>Restart Sequence</b></td>\n\t\t\t<td><table width=\"100%\" border=\"0\" cellpadding=\"1\">\n{*\n **** STEP 0 ****\n *}\n\t\t\t<form action=\"index.php\" method=\"post\" name=\"restart0\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\n\t\t\t<tr {if $tool_restart_info.restart_sequence_step == 0}class=\"row_restart_active\"{/if}>\n\t\t\t\t<td><u>Step 0</u></td>\n\t\t\t\t<td>\n\t\t\t\t\t<input type=\"hidden\" name=\"restart_ws_state\" value=\"{$tool_restart_ws_state}\">\n\t\t\t\t\t<input type=\"submit\" name=\"restart_check_ws\" value=\"Stop the Shard\" style=\"width:550px\" {if $tool_restart_info.restart_sequence_step != 0}disabled{/if} onclick=\"if (confirm('Are you sure you want to STOP THIS SHARD ?\\nCancelling the sequence after this point is a bad idea !')) return true; return false;\"><br><br>\n\t\t\t\t\t<select name=\"restart_message_reboot_id\" style=\"width:550px\" {if $tool_restart_info.restart_sequence_step != 0}disabled{/if}>\n{section name=reboot loop=$tool_restart_message_reboot_list}\n\t\t\t\t\t\t<option value=\"{$tool_restart_message_reboot_list[reboot].restart_message_id}\" {if $tool_shard_language == $tool_restart_message_reboot_list[reboot].restart_message_lang}selected{/if}>[{$tool_restart_message_reboot_list[reboot].restart_message_lang}] - {$tool_restart_message_reboot_list[reboot].restart_message_value}</option>\n{/section}\n\t\t\t\t\t</select>\n\n\t\t\t\t</td>\n\t\t\t\t<td align=\"right\">\n{if $tool_restart_info.restart_sequence_step == 0}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_end\" value=\"Cancel\" onclick=\"if (confirm('Are you sure you want to CANCEL the restart sequence ?')) return true; return false;\">\n{/if}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t</form>\n\n{*\n **** STEP 1 ****\n *}\n\n\t\t\t<form action=\"index.php\" method=\"post\" name=\"restart1\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\t\t\t<input type=\"hidden\" name=\"restart_wait_timer\" value=\"1\">\n\n\t\t\t<tr><td colspan=\"3\"><hr size=\"1\"></td></tr>\n\t\t\t<tr {if $tool_restart_info.restart_sequence_step == 1}class=\"row_restart_active\"{/if}>\n\t\t\t\t<td><u>Step 1</u></td>\n\t\t\t\t<td>{if $tool_restart_info.restart_sequence_step == 1}{math assign=\"restart_timer\" equation=\"x - y\" x=$tool_restart_info.restart_sequence_timer y=$system_time}{else}{assign var=restart_timer value='-1'}{/if}\n{if $restart_timer >= 0}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_wait_timer_fake\" value=\"Waiting for 10:00 minutes !\" style=\"width:550px\" disabled>\n\t\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\tTimerDownRestart({$restart_timer});\n\t\t\t\t\t\t-->\n\t\t\t\t\t</script>\n{else}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_wait_timer_fake\" value=\"Nothing to do !\" style=\"width:550px\" disabled>\n{if $tool_restart_info.restart_sequence_step == 1}\n\t\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tdocument.restart1.submit();\n\t\t\t\t\t\t-->\n\t\t\t\t\t</script>\n{/if}\n{/if}\n\t\t\t\t</td>\n\t\t\t\t<td align=\"right\">\n{if $tool_restart_info.restart_sequence_step == 1}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_cancel\" value=\"Cancel\" onclick=\"if (confirm('Are you sure you want to CANCEL the restart sequence ?')) return true; return false;\">\n{/if}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t</form>\n\n{*\n **** STEP 2 ****\n *}\n\n\t\t\t<form action=\"index.php\" method=\"post\" name=\"restart2\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shutdown_timer\" value=\"1\">\n\n\t\t\t<tr><td colspan=\"3\"><hr size=\"1\"></td></tr>\n\t\t\t<tr {if $tool_restart_info.restart_sequence_step == 2}class=\"row_restart_active\"{/if}>\n\t\t\t\t<td><u>Step 2</u></td>\n\t\t\t\t<td>{if $tool_restart_info.restart_sequence_step == 2}{math assign=\"restart_timer2\" equation=\"x - y\" x=$tool_restart_info.restart_sequence_timer y=$system_time}{else}{assign var=restart_timer2 value='-1'}{/if}\n{if $restart_timer2 >= 0}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_shutdown_timer_fake\" value=\"Waiting for 00:30 minutes !\" style=\"width:550px\" disabled>\n\t\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\tTimerDownRestart2({$restart_timer2});\n\t\t\t\t\t\t-->\n\t\t\t\t\t</script>\n{else}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_shutdown_timer_fake\" value=\"Nothing to do !\" style=\"width:550px\" disabled>\n{if $tool_restart_info.restart_sequence_step == 2}\n\t\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t\t<!--\n\t\t\t\t\t\t\tdocument.restart2.submit();\n\t\t\t\t\t\t-->\n\t\t\t\t\t</script>\n{/if}\n\n{/if}\n\t\t\t\t</td>\n\t\t\t\t<td align=\"right\">&nbsp;</td>\n\t\t\t</tr>\n\t\t\t</form>\n\n{*\n **** STEP 3 ****\n *}\n\n\t\t\t<form action=\"index.php\" method=\"post\" name=\"restart3\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\n\t\t\t<tr><td colspan=\"3\"><hr size=\"1\"></td></tr>\n\t\t\t<tr {if $tool_restart_info.restart_sequence_step == 3}class=\"row_restart_active\"{/if}>\n\t\t\t\t<td><u>Step 3</u></td>\n\t\t\t\t<td>\n\t\t\t\t\t<input type=\"hidden\" name=\"restart_start_group_id\" value=\"0\">\n\t\t\t\t\t<input type=\"hidden\" name=\"restart_start_group_list\" value=\"\">\n\t\t\t\t\t<input type=\"hidden\" name=\"restart_stop_group_list\" value=\"\">\n\n\t\t\t\t\t<input type=\"submit\" name=\"restart_stop_group\" value=\"Stop All Services\" style=\"width:200px\" onclick=\"if (confirm('Are you sure you want to STOP these services ?')) {ldelim} document.restart3.restart_stop_group_list.value='{$tool_restart_stop_actions}'; return true; {rdelim} return false;\" {if $tool_restart_info.restart_sequence_step != 3}disabled{/if}>{* The following services will be stopped : {$tool_restart_stop_actions} *}<br><br>\n\n{section name=start loop=$tool_restart_start_actions}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_start_group\" value=\"{$smarty.section.start.iteration}/{$smarty.section.start.total} - Start {$tool_restart_start_actions[start].restart_group_name}\" style=\"width:200px\" onclick=\"if (confirm('Are you sure you want to START these services ?')) {ldelim} document.restart3.restart_start_group_id.value='{$tool_restart_start_actions[start].restart_group_id}'; document.restart3.restart_start_group_list.value='{$tool_restart_start_actions[start].service_list}'; return true; {rdelim} return false;\" {if $tool_restart_info.restart_sequence_step != 3}disabled{/if}> The following services will be started : {$tool_restart_start_actions[start].restart_group_list}<br><br>\n{/section}\n\n\t\t\t\t\t<input type=\"submit\" name=\"restart_over\" value=\"Hand Over to Customer Support Teams\" style=\"width:550px\" {if $tool_restart_info.restart_sequence_step != 3}disabled{/if}>\n\n\t\t\t\t</td>\n\t\t\t\t<td align=\"right\">\n{if $tool_restart_info.restart_sequence_step == 3}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_giveup\" value=\"Give up, Shard cannot be started\" onclick=\"if (confirm('Are you sure you want to GIVE UP the restart sequence ?\\nThis will leave the shard in its current state !')) return true; return false;\">\n{/if}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t</form>\n\n{*\n **** STEP 4 ****\n *}\n\n\t\t\t<form action=\"index.php\" method=\"post\" name=\"restart4\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_id\" value=\"{$tool_restart_info.restart_sequence_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_sequence_step\" value=\"{$tool_restart_info.restart_sequence_step}\">\n\t\t\t<input type=\"hidden\" name=\"restart_shard_id\" value=\"{$tool_restart_shard_id}\">\n\t\t\t<input type=\"hidden\" name=\"restart_su\" value=\"{$tool_shard_su_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_egs\" value=\"{$tool_restart_egs_name}\">\n\t\t\t<input type=\"hidden\" name=\"restart_stop_services\" value=\"{$tool_restart_stop_actions}\">\n\n\t\t\t<tr><td colspan=\"3\"><hr size=\"1\"></td></tr>\n\t\t\t<tr {if $tool_restart_info.restart_sequence_step == 4}class=\"row_restart_active\"{/if}>\n\t\t\t\t<td><u>Step 4</u></td>\n\t\t\t\t<td>\n\t\t\t\t\tSuccess, the Shard is now in the hands of the Customer Support Team.\n\t\t\t\t</td>\n\t\t\t\t<td align=\"right\">\n{if $tool_restart_info.restart_sequence_step == 4}\n\t\t\t\t\t<input type=\"submit\" name=\"restart_end\" value=\"Done\">\n{/if}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t\t</form>\n\n\n\t\t\t</table></td>\n\t\t</tr>\n\t\t</table>\n\n\t\t{* this is just a dummy form to match the global services end form tag *}\n\t\t<form action=\"index.php\" method=\"post\" name=\"restartdummy\">\n"
  },
  {
    "path": "tools/server/admin/templates/default/page_footer.tpl",
    "content": "\n{if !$iPhone}\n\n<br><br>\n\n<br>\n\n{* DEBUG INFORMATION *}\n\n{if $NELTOOL_DEBUG != null}\n<hr size=\"1\">\n<pre>DEBUG\n{php}\nglobal $nel_debug;\nforeach ($nel_debug as $dbgline) echo \"  $dbgline\\n\";\n{/php}</pre>\n{/if}\n\n{/if}\n\n</body>\n</html>\n"
  },
  {
    "path": "tools/server/admin/templates/default/page_footer_light.tpl",
    "content": "</body>\n</html>"
  },
  {
    "path": "tools/server/admin/templates/default/page_header.tpl",
    "content": "<html>\n<head>\n<title>{$nel_tool_title}{if $tool_page_title != ''} - {$tool_page_title}{/if}</title>\n<link rel=\"stylesheet\" href=\"neltool.css\" type=\"text/css\">\n<script type=\"text/javascript\" src=\"overlib/overlib_mini.js\"></script>\n<script type=\"text/javascript\" src=\"overlib/overlib_anchor_mini.js\"></script>\n<script type=\"text/javascript\" src=\"overlib/overlib_draggable_mini.js\"></script>\n{*$nel_tool_notes_meta*}\n{$nel_tool_refresh}\n{$nel_tool_extra_css}\n\n{if $iPhone}\n<meta name = \"viewport\" content = \"width=device-width\">\n{/if}\n\n</head>\n\n<body>\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n{if !$iPhone}\n\t\t<td align=\"left\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"0\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t<td width=\"35\" height=\"22\"><img src=\"imgs/nel.gif\" name=\"ol_anchor_left\"></td>\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><b>{$tool_title}</b></td>\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><b>{$user_info}</b></td>\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n{/if}\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"0\" border=\"0\">\n\t\t\t\t<tr>\n{section name=onemenu loop=$nel_menu}\n\t\t\t\t\t <td height=\"22\" class=\"boxed\">\n{if $menu_style == 1 && !$iPhone}\n\t\t\t\t\t \t<a href=\"{$nel_menu[onemenu].application_uri}\" onmouseover=\"return overlib('{$nel_menu[onemenu].application_name}', LEFT, OFFSETY, 20, BGCOLOR, '#aaaaaa', FGCOLOR, '#cccccc');\" onmouseout=\"return nd();\" >\n\t\t\t\t\t \t<img src=\"{if $nel_menu[onemenu].application_icon != \"\"}{$nel_menu[onemenu].application_icon}{else}{$unknown_menu}{/if}\" border=\"0\">\n\t\t\t\t\t \t</a>\n{elseif $menu_style == 2 && !$iPhone}\n\t\t\t\t\t \t<a href=\"{$nel_menu[onemenu].application_uri}\">\n\t\t\t\t\t \t<img src=\"{if $nel_menu[onemenu].application_icon != \"\"}{$nel_menu[onemenu].application_icon}{else}{$unknown_menu}{/if}\" border=\"0\"><br />{$nel_menu[onemenu].application_name}\n\t\t\t\t\t \t</a>\n{else}\n\t\t\t\t\t \t<a href=\"{$nel_menu[onemenu].application_uri}\">\n\t\t\t\t\t \t{$nel_menu[onemenu].application_name}\n\t\t\t\t\t \t</a>\n{/if}\n\t\t\t\t\t </td>\n{/section}\n\n{if !$iPhone}\n\t\t\t\t\t<td width=\"35\" height=\"22\" align=\"right\"><img src=\"imgs/nel.gif\" name=\"ol_anchor_right\"></td>\n{/if}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n"
  },
  {
    "path": "tools/server/admin/templates/default/page_header_light.tpl",
    "content": "<html>\n<head>\n<title>{$tool_login_title}</title>\n<link rel=\"stylesheet\" href=\"{$nel_web_base_uri}neltool.css\" type=\"text/css\">\n</head>\n\n{if $iPhone}\n<meta name = \"viewport\" content = \"user-scalable=no, width=device-width\">\n{/if}\n\n<body>\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_actions.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<h1>Admin Tool v2.0</h1>\nAuthor: Anthony 'YoGiN' Powles &lt;<a href=\"mailto:yogin@nevrax.com?subject=Nevrax AdminTool Feedback\">yogin@nevrax.com</a>&gt;\n<br>Copyright &#169; Nevrax 2000 - 2006\n<br><br><br>\n\n{if $ie_check}\n<br>\nThis part of the tool uses some features that Internet Explorer does NOT support.<br>\nTherefore, if you need to access them, i would recommend using <a href=\"http://www.mozilla.com/firefox/\">Mozilla Firefox!</a>\n{/if}\n\n<br><br>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_applications.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Applications</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>URI</b></td>\n\t\t\t<td><b>Restriction</b></td>\n\t\t\t<td><b>Icon</b></td>\n\t\t\t<td><b>Order</b></td>\n\t\t\t<td><b>Visible</b></td>\n\t\t</tr>\n{section name=application loop=$tool_application_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_application_list[application].application_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=applications&toolaction=edit&application_id={$tool_application_list[application].application_id}\">{$tool_application_list[application].application_name}</a></td>\n\t\t\t<td>{$tool_application_list[application].application_uri}</td>\n\t\t\t<td>{$tool_application_list[application].application_restriction}</td>\n\t\t\t<td>{$tool_application_list[application].application_icon}</td>\n\t\t\t<td>{$tool_application_list[application].application_order}</td>\n\t\t\t<td>{if $tool_application_list[application].application_visible  == 1}Yes{else}No{/if}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=applications\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Applications Details</th>\n\t\t</tr>\n{if $tool_application_edit_data.application_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_id\" value=\"{$tool_application_edit_data.application_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_name\" value=\"{$tool_application_edit_data.application_name}\" maxlength=\"64\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">URI :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_uri\" value=\"{$tool_application_edit_data.application_uri}\" maxlength=\"255\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Restriction :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_restriction\" value=\"{$tool_application_edit_data.application_restriction}\" maxlength=\"64\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Icon :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_icon\" value=\"{$tool_application_edit_data.application_icon}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Order :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_application_order\" value=\"{$tool_application_edit_data.application_order}\" maxlength=\"6\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Visible :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_application_visible\">\n\t\t\t\t\t<option value=\"1\" {if $tool_application_edit_data.application_visible == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_application_edit_data.application_visible == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_application_edit_data.application_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the application &lt; {$tool_application_edit_data.application_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_domains.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"12\">Domains</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>Application</b></td>\n\t\t\t<td><b>AS Host</b></td>\n\t\t\t<td><b>AS Port</b></td>\n\t\t\t<td><b>MFS Web</b></td>\n\t\t\t<td><b>RRD Path</b></td>\n\t\t\t<td><b>LAS Admin Path</b></td>\n\t\t\t<td><b>LAS Local Path</b></td>\n\t\t\t<td><b>Ring DB</b></td>\n\t\t\t<td><b>CS DB</b></td>\n\t\t\t<td><b>HD Check</b></td>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_domain_list[domain].domain_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=domains&toolaction=edit&domain_id={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t\t<td>{$tool_domain_list[domain].domain_application}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_as_host}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_as_port}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_mfs_web}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_rrd_path}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_las_admin_path}</td>\n\t\t\t<td>{$tool_domain_list[domain].domain_las_local_path}</td>\n\t\t\t<td>{if $tool_domain_list[domain].domain_sql_string != ''}True{else}False{/if}</td>\n\t\t\t<td>{if $tool_domain_list[domain].domain_cs_sql_string != ''}True{else}False{/if}</td>\n\t\t\t<td>{if $tool_domain_list[domain].domain_hd_check == 1}Yes{else}No{/if}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=domains\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain Details</th>\n\t\t</tr>\n{if $tool_domain_edit_data.domain_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_id\" value=\"{$tool_domain_edit_data.domain_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_name\" value=\"{$tool_domain_edit_data.domain_name}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Application :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_application\" value=\"{$tool_domain_edit_data.domain_application}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">AS Host :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_as_host\" value=\"{$tool_domain_edit_data.domain_as_host}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">AS Port :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_as_port\" value=\"{$tool_domain_edit_data.domain_as_port}\" maxlength=\"5\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">MFS Web :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_mfs_web\" value=\"{$tool_domain_edit_data.domain_mfs_web}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">RRD Path :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_rrd_path\" value=\"{$tool_domain_edit_data.domain_rrd_path}\" maxlength=\"255\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">LAS Admin Path :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_las_admin_path\" value=\"{$tool_domain_edit_data.domain_las_admin_path}\" maxlength=\"255\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">LAS Local Path :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_las_local_path\" value=\"{$tool_domain_edit_data.domain_las_local_path}\" maxlength=\"255\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Ring DB String :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_sql_string\" value=\"{$tool_domain_edit_data.domain_sql_string}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">CS DB String :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_cs_sql_string\" value=\"{$tool_domain_edit_data.domain_cs_sql_string}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">HD Check :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_domain_hd_check\">\n\t\t\t\t\t<option value=\"1\" {if $tool_domain_edit_data.domain_hd_check == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_domain_edit_data.domain_hd_check == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_domain_edit_data.domain_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the domain &lt; {$tool_domain_edit_data.domain_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{if $tool_domain_nel_data}\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=domains\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain Data</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">ID :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_nel_id\" value=\"{$tool_domain_nel_data.domain_id}\" maxlength=\"128\" size=\"30\" readonly ></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_nel_name\" value=\"{$tool_domain_nel_data.domain_name}\" maxlength=\"128\" size=\"30\" readonly ></td>\n\t\t</tr>\n\t\t<!--<tr>\n\t\t\t<td align=\"right\">Version :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_domain_nel_version\" value=\"{$tool_domain_nel_data.patch_version}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>-->\n\t\t<tr>\n\t\t\t<td align=\"right\">Status :</td>\n\t\t\t<td><select name=\"tool_form_domain_nel_status\" style=\"width:150px;\">\n{section name=status loop=$tool_domain_nel_status}\n\t\t\t\t\t<option value=\"{$tool_domain_nel_status[status]}\" {if $tool_domain_nel_data.status == $tool_domain_nel_status[status]}selected{/if}>{$tool_domain_nel_status[status]}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update_nel\">\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_domain_id\" value=\"{$tool_domain_edit_data.domain_id}\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n{/if}\n\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_groups.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Groups</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>Level</b></td>\n\t\t\t<td><b>Default</b></td>\n\t\t\t<td><b>Active</b></td>\n\t\t</tr>\n{section name=group loop=$tool_group_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_group_list[group].group_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=groups&toolaction=edit&group_id={$tool_group_list[group].group_id}\">{$tool_group_list[group].group_name}</a></td>\n\t\t\t<td>{$tool_group_list[group].group_level_name}</td>\n\t\t\t<td>{if $tool_group_list[group].group_default == 1}Yes{else}No{/if}</td>\n\t\t\t<td>{if $tool_group_list[group].group_active  == 1}Yes{else}No{/if}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_group_user_list}\n\t\t<br>\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Accounts</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Login</b></td>\n\t\t\t<td><b>Created</b></td>\n\t\t\t<td><b>Last&nbsp;Logged</b></td>\n\t\t\t<td><b>Num&nbsp;Logs</b></td>\n\t\t\t<td><b>Active</b></td>\n\t\t</tr>\n{section name=user loop=$tool_group_user_list}\n{cycle assign=\"trclass2\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass2}\">\n\t\t\t<td>{$tool_group_user_list[user].user_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=users&toolaction=edit&user_id={$tool_group_user_list[user].user_id}\">{$tool_group_user_list[user].user_name}</a></td>\n\t\t\t<td>{$tool_group_user_list[user].user_created|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{if $tool_group_user_list[user].user_logged_last > 0}\n\t\t\t<td>{$tool_group_user_list[user].user_logged_last|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{else}\n\t\t\t<td>never</td>\n{/if}\n\t\t\t<td>{$tool_group_user_list[user].user_logged_count}</td>\n\t\t\t<td>{if $tool_group_user_list[user].user_active == 1}Yes{else}No{/if}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Group Details</th>\n\t\t</tr>\n{if $tool_group_edit_data.group_id}\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_group_name\" value=\"{$tool_group_edit_data.group_name}\" maxlength=\"32\" size=\"30\" {* if $tool_group_edit_data.group_id}readonly{/if *}></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Level :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_group_level\">\n{section name=level loop=$tool_group_level_list}\n\t\t\t\t\t<option value=\"{$tool_group_level_list[level].level_id}\" {if $tool_group_edit_data.group_level == $tool_group_level_list[level].level_id}selected{/if}>{$tool_group_level_list[level].level_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Default :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_group_default\">\n\t\t\t\t\t<option value=\"1\" {if $tool_group_edit_data.group_default == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_group_edit_data.group_default == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Active :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_group_active\">\n\t\t\t\t\t<option value=\"1\" {if $tool_group_edit_data.group_active == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_group_edit_data.group_active == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_group_edit_data.group_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the group &lt; {$tool_group_edit_data.group_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{if $tool_group_edit_data.group_id}\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Default Domain</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Domains :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_domain_default\" style=\"width:150px;\">\n\t\t\t\t\t<option value=\"0\">-- none --</option>\n{section name=domain loop=$tool_domain_list}\n{if $tool_domain_list[domain].domain_selected}\n\t\t\t\t\t<option value=\"{$tool_domain_list[domain].domain_id}\" {if $tool_group_edit_data.group_default_domain_id == $tool_domain_list[domain].domain_id}selected{/if}>{$tool_domain_list[domain].domain_name}</option>\n{/if}\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update default domain\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{if $tool_group_edit_data.group_default_domain_id > 0}\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Default Shard</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Shards :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_default\" style=\"width:150px;\">\n\t\t\t\t\t<option value=\"0\">-- none --</option>\n{section name=domain loop=$tool_shard_list}\n{if $tool_shard_list[domain].domain_id == $tool_group_edit_data.group_default_domain_id}\n\n{if $tool_shard_list[domain].domain_visible}\n{section name=shard loop=$tool_shard_list[domain].shard_list}\n{if $tool_shard_list[domain].shard_list[shard].shard_selected}\n\t\t\t\t\t<option value=\"{$tool_shard_list[domain].shard_list[shard].shard_id}\" {if $tool_group_edit_data.group_default_shard_id == $tool_shard_list[domain].shard_list[shard].shard_id}selected{/if}>{$tool_shard_list[domain].shard_list[shard].shard_name}</option>\n{/if}\n{/section}\n{/if}\n\n{/if}\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update default shard\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n{/if}\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Default Application</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Application :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_application_default\" style=\"width:150px;\">\n\t\t\t\t\t<!--<option value=\"0\">-- none --</option>-->\n{section name=menu loop=$nel_menu}\n{if $nel_menu[menu].application_order != 999999}\n\t\t<option value=\"{$nel_menu[menu].application_id}\" {if $tool_group_edit_data.group_default_application_id == $nel_menu[menu].application_id}selected{/if}>{$nel_menu[menu].application_name}</option>\n{/if}\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update default application\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Application Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Applications :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_application_ids[]\" multiple size=\"10\" style=\"width:150px;\">\n{section name=appl loop=$tool_application_list}\n\t\t\t\t\t<option value=\"{$tool_application_list[appl].application_id}\" {if $tool_application_list[appl].application_restriction == \"\"}disabled{elseif $tool_application_list[appl].application_selected}selected{/if}>{$tool_application_list[appl].application_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update applications\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Domains :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_domain_ids[]\" multiple size=\"5\" style=\"width:150px;\">\n{section name=domain loop=$tool_domain_list}\n\t\t\t\t\t<option value=\"{$tool_domain_list[domain].domain_id}\" {if $tool_domain_list[domain].domain_selected}selected{/if}>{$tool_domain_list[domain].domain_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update domains\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=groups\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shard Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Shards :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_ids[]\" multiple size=\"20\" style=\"width:150px;\">\n{section name=domain loop=$tool_shard_list}\n{if $tool_shard_list[domain].domain_visible}\n\t\t\t\t\t<option disabled >Domain : {$tool_shard_list[domain].domain_name}</option>\n{section name=shard loop=$tool_shard_list[domain].shard_list}\n\t\t\t\t\t<option value=\"{$tool_shard_list[domain].domain_id}_{$tool_shard_list[domain].shard_list[shard].shard_id}\" {if $tool_shard_list[domain].shard_list[shard].shard_disabled}disabled{elseif $tool_shard_list[domain].shard_list[shard].shard_selected}selected{/if}> +-- {$tool_shard_list[domain].shard_list[shard].shard_name}</option>\n{/section}\n\t\t\t\t\t<option disabled></option>\n{/if}\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_group_id\" value=\"{$tool_group_edit_data.group_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update shards\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_logs.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Logs</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>User</b></td>\n\t\t\t<td><b>Date</b></td>\n\t\t\t<td><b>Action</b></td>\n\t\t</tr>\n{section name=log loop=$tool_log_list}\n\t\t<tr class=\"{cycle values=\"row1,row0\"}\">\n\t\t\t<td>{$tool_log_list[log].logs_id}</td>\n\t\t\t<td>{$tool_log_list[log].logs_user_name}</td>\n\t\t\t<td>{$tool_log_list[log].logs_date|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n\t\t\t<td>{$tool_log_list[log].logs_data}</td>\n\t\t</tr>\n{/section}\n\t\t<tr>\n\t\t\t<th colspan=\"4\" align=\"center\">\n<a href=\"tool_administration.php?toolmode=logs&page={$tool_log_page_first}\">|&lt;</a>&nbsp;&nbsp;&nbsp;\n<a href=\"tool_administration.php?toolmode=logs&page={$tool_log_page_previous}\">&lt;</a>&nbsp;&nbsp;&nbsp;\nPage {$tool_log_page_current} / {$tool_log_page_total}&nbsp;&nbsp;&nbsp;\n<a href=\"tool_administration.php?toolmode=logs&page={$tool_log_page_next}\">&gt;</a>&nbsp;&nbsp;&nbsp;\n<a href=\"tool_administration.php?toolmode=logs&page={$tool_log_page_last}\">&gt;|</a>\n\t\t\t</th>\n\t\t</tr>\n\t\t</table>\n\t</td>\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_restarts.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Restart Groups</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>List</b></td>\n\t\t\t<td><b>Order</b></td>\n\t\t</tr>\n{section name=restart loop=$tool_restart_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_restart_list[restart].restart_group_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=restarts&toolaction=edit&restart_id={$tool_restart_list[restart].restart_group_id}\">{$tool_restart_list[restart].restart_group_name}</a></td>\n\t\t\t<td>{$tool_restart_list[restart].restart_group_list}</td>\n\t\t\t<td>{$tool_restart_list[restart].restart_group_order}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=restarts\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Restart Group Details</th>\n\t\t</tr>\n{if $tool_restart_edit_data.restart_group_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_restart_id\" value=\"{$tool_restart_edit_data.restart_group_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_restart_name\" value=\"{$tool_restart_edit_data.restart_group_name}\" maxlength=\"128\" size=\"40\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Services :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_restart_services\" value=\"{$tool_restart_edit_data.restart_group_list}\" maxlength=\"255\" size=\"40\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Order :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_restart_order\" value=\"{$tool_restart_edit_data.restart_group_order}\" maxlength=\"3\" size=\"10\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_restart_edit_data.restart_group_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the restart group &lt; {$tool_restart_edit_data.restart_group_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\t</td>\n\n</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Restart Messages</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Language</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>Value</b></td>\n\t\t</tr>\n{section name=msg loop=$tool_message_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_message_list[msg].restart_message_id}</td>\n\t\t\t<td>{$tool_message_list[msg].restart_message_lang}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=restarts&toolaction=editmsg&msg_id={$tool_message_list[msg].restart_message_id}\">{$tool_message_list[msg].restart_message_name}</a></td>\n\t\t\t<td>{$tool_message_list[msg].restart_message_value}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=restarts\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Restart Message Details</th>\n\t\t</tr>\n{if $tool_message_edit_data.restart_message_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_message_id\" value=\"{$tool_message_edit_data.restart_message_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_message_name\" value=\"{$tool_message_edit_data.restart_message_name}\" maxlength=\"32\" size=\"40\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Value :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_message_value\" value=\"{$tool_message_edit_data.restart_message_value}\" maxlength=\"255\" size=\"40\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Language :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_message_lang\">\n{section name=lang loop=$tool_language_list}\n\t\t\t\t\t<option value=\"{$tool_language_list[lang].lang_id}\" {if $tool_message_edit_data.restart_message_lang == $tool_language_list[lang].lang_id}selected{/if}>{$tool_language_list[lang].lang_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_message_edit_data.restart_message_id }\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update message\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete message\" onclick=\"if (confirm('Are you sure you want to DELETE the restart message &lt; {$tool_message_edit_data.restart_message_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create message\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\t</td>\n\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_shards.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Name</b></td>\n\t\t\t<td><b>Shard ID</b></td>\n\t\t\t<td><b>Domain</b></td>\n\t\t\t<td><b>Language</b></td>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_shard_list[shard].shard_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=shards&toolaction=edit&shard_id={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t\t<td>{$tool_shard_list[shard].shard_as_id}</td>\n\t\t\t<td>{$tool_shard_list[shard].domain_name}</td>\n\t\t\t<td>{$tool_shard_list[shard].shard_lang}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=shards\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shard Details</th>\n\t\t</tr>\n{if $tool_shard_edit_data.shard_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_shard_id\" value=\"{$tool_shard_edit_data.shard_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_shard_name\" value=\"{$tool_shard_edit_data.shard_name}\" maxlength=\"128\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Shard ID :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_shard_as_id\" value=\"{$tool_shard_edit_data.shard_as_id}\" maxlength=\"255\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Domain :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_domain_id\">\n{section name=domain loop=$tool_domain_list}\n\t\t\t\t\t<option value=\"{$tool_domain_list[domain].domain_id}\" {if $tool_shard_edit_data.shard_domain_id == $tool_domain_list[domain].domain_id}selected{/if}>{$tool_domain_list[domain].domain_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Language :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_language\">\n{section name=lang loop=$tool_language_list}\n\t\t\t\t\t<option value=\"{$tool_language_list[lang].lang_id}\" {if $tool_shard_edit_data.shard_lang == $tool_language_list[lang].lang_id}selected{/if}>{$tool_language_list[lang].lang_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_shard_edit_data.shard_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the shard &lt; {$tool_shard_edit_data.shard_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_users.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Accounts</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Login</b></td>\n\t\t\t<td><b>Group</b></td>\n\t\t\t<td><b>Created</b></td>\n\t\t\t<td><b>Last&nbsp;Logged</b></td>\n\t\t\t<td><b>Num&nbsp;Logs</b></td>\n\t\t\t<td><b>Active</b></td>\n\t\t</tr>\n{section name=user loop=$tool_user_list}\n{cycle assign=\"trclass\" values=\"row1,row0\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_user_list[user].user_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=users&toolaction=edit&user_id={$tool_user_list[user].user_id}\">{$tool_user_list[user].user_name}</a></td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=groups&toolaction=edit&group_id={$tool_user_list[user].user_group_id}\">{$tool_user_list[user].user_group_name}</a></td>\n\t\t\t<td>{$tool_user_list[user].user_created|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{if $tool_user_list[user].user_logged_last > 0}\n\t\t\t<td>{$tool_user_list[user].user_logged_last|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{else}\n\t\t\t<td>never</td>\n{/if}\n\t\t\t<td>{$tool_user_list[user].user_logged_count}</td>\n\t\t\t<td>{if $tool_user_list[user].user_active == 1}Yes{else}No{/if}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Account Details</th>\n\t\t</tr>\n{if $tool_user_edit_data.user_id}\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_user_name\" value=\"{$tool_user_edit_data.user_name}\" maxlength=\"32\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Password :</td>\n\t\t\t<td><input type=\"password\" name=\"tool_form_user_password\" value=\"\" maxlength=\"16\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Group :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_user_group\">\n{section name=group loop=$tool_group_list}\n\t\t\t\t\t<option value=\"{$tool_group_list[group].group_id}\" {if $tool_user_edit_data.user_group_id == $tool_group_list[group].group_id}selected{/if}>{$tool_group_list[group].group_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Active :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_user_active\">\n\t\t\t\t\t<option value=\"1\" {if $tool_user_edit_data.user_active == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_user_edit_data.user_active == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_user_edit_data.user_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the user &lt; {$tool_user_edit_data.user_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{if $tool_user_edit_data.user_id}\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Application Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"40%\">Applications :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_application_ids[]\" multiple size=\"10\" style=\"width:150px;\">\n{section name=appl loop=$tool_application_list}\n\t\t\t\t\t<option value=\"{$tool_application_list[appl].application_id}\" {if $tool_application_list[appl].application_restriction == \"\" || $tool_application_list[appl].application_disabled}disabled{elseif $tool_application_list[appl].application_selected}selected{/if}>{$tool_application_list[appl].application_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update applications\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Domains :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_domain_ids[]\" multiple size=\"5\" style=\"width:150px;\">\n{section name=domain loop=$tool_domain_list}\n\t\t\t\t\t<option value=\"{$tool_domain_list[domain].domain_id}\" {if $tool_domain_list[domain].domain_disabled}disabled{elseif $tool_domain_list[domain].domain_selected}selected{/if}>{$tool_domain_list[domain].domain_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update domains\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shard Access {if $tool_domain_list[domain].domain_disabled}(group){/if}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\" align=\"right\">Shards :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_ids[]\" multiple size=\"20\" style=\"width:150px;\">\n{section name=domain loop=$tool_shard_list}\n{if $tool_shard_list[domain].domain_visible}\n\t\t\t\t\t<option value=\"\" disabled >Domain : {$tool_shard_list[domain].domain_name}</option>\n{section name=shard loop=$tool_shard_list[domain].shard_list}\n\t\t\t\t\t<option value=\"{$tool_shard_list[domain].domain_id}_{$tool_shard_list[domain].shard_list[shard].shard_id}\" {if $tool_shard_list[domain].shard_list[shard].shard_disabled}disabled{elseif $tool_shard_list[domain].shard_list[shard].shard_selected}selected{/if}> +-- {$tool_shard_list[domain].shard_list[shard].shard_name}</option>\n{/section}\n\t\t\t\t\t<option disabled></option>\n{/if}\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td width=\"40%\">&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\">\n\t\t\t\t{* <input type=\"hidden\" name=\"tool_form_domain_id\" value=\"{$tool_shard_list[domain].domain_id}\"> *}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update shards\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_administration_users.tpl.backup",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"70%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Accounts</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Login</b></td>\n\t\t\t<td><b>Group</b></td>\n\t\t\t<td><b>Created</b></td>\n\t\t\t<td><b>Last&nbsp;Logged</b></td>\n\t\t\t<td><b>Num&nbsp;Logs</b></td>\n\t\t\t<td><b>Active</b></td>\n\t\t</tr>\n\t\t{section name=user loop=$tool_user_list}\n\t\t<tr>\n\t\t\t<td>{$tool_user_list[user].user_id}</td>\n\t\t\t<td><a href=\"tool_administration.php?toolmode=users&toolaction=edit&user_id={$tool_user_list[user].user_id}\">{$tool_user_list[user].user_name}</a></td>\n\t\t\t<td>{$tool_user_list[user].user_group_name}</td>\n\t\t\t<td>{$tool_user_list[user].user_created|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{if $tool_user_list[user].user_logged_last > 0}\n\t\t\t<td>{$tool_user_list[user].user_logged_last|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n{else}\n\t\t\t<td>never</td>\n{/if}\n\t\t\t<td>{$tool_user_list[user].user_logged_count}</td>\n\t\t\t<td>{$tool_user_list[user].user_active}</td>\n\t\t</tr>\n\t\t{/section}\n\t\t</table>\n\t</td>\n\n\n\t<td align=\"right\" valign=\"top\" width=\"30%\">\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Account Details</th>\n\t\t</tr>\n{if $tool_user_edit_data.user_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Name :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_user_name\" value=\"{$tool_user_edit_data.user_name}\" maxlength=\"32\" size=\"30\" {if $tool_user_edit_data.user_id}readonly{/if}></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Password :</td>\n\t\t\t<td><input type=\"password\" name=\"tool_form_user_password\" value=\"\" maxlength=\"16\" size=\"30\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Group :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_user_group\">\n{section name=group loop=$tool_group_list}\n\t\t\t\t\t<option value=\"{$tool_group_list[group].group_id}\" {if $tool_user_edit_data.user_group_id == $tool_group_list[group].group_id}selected{/if}>{$tool_group_list[group].group_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Active :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_user_active\">\n\t\t\t\t\t<option value=\"1\" {if $tool_user_edit_data.user_active == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_user_edit_data.user_active == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_user_edit_data.user_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE the user &lt; {$tool_user_edit_data.user_name} &gt; ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{if $tool_user_edit_data.user_id}\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain Access</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Domains :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_domain_ids[]\" multiple size=\"5\" style=\"width:150px;\">\n{section name=domain loop=$tool_domain_list}\n\t\t\t\t\t<option value=\"{$tool_domain_list[domain].domain_id}\" {if $tool_domain_list[domain].domain_disabled}disabled{elseif $tool_domain_list[domain].domain_selected}selected{/if}>{$tool_domain_list[domain].domain_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update domains\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\n{section name=domain loop=$tool_shard_list}\n{if $tool_shard_list[domain].domain_selected}\n\t\t<br>\n\t\t<table width=\"90%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_administration.php?toolmode=users\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domain '{$tool_shard_list[domain].domain_name}' {if $tool_domain_list[domain].domain_disabled}(group){/if}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\">Shards :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_shard_ids[]\" multiple size=\"5\" style=\"width:150px;\">\n{section name=shard loop=$tool_shard_list[domain].shard_list}\n\t\t\t\t\t<option value=\"{$tool_shard_list[domain].shard_list[shard].shard_id}\" {if $tool_shard_list[domain].shard_list[shard].shard_disabled}disabled{elseif $tool_shard_list[domain].shard_list[shard].shard_selected}selected{/if}>{$tool_shard_list[domain].shard_list[shard].shard_name}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_user_edit_data.user_id}\">\n\t\t\t\t<input type=\"hidden\" name=\"tool_form_domain_id\" value=\"{$tool_shard_list[domain].domain_id}\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update shards\">\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n{/if}\n{/section}\n\n{/if}\n\n\t</td>\n\n</tr>\n</table>\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_event_entities.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll(checklist)\n\t{\n\t\tfor (var i=0; i<checklist.elements.length; i++)\n\t\t{\n\t\t\tvar e = checklist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = checklist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_event_entities.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_event_entities.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\n\t\t<form action=\"tool_event_entities.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll(document.qlist);\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n\t\t\t<td class=\"heads\">ShortName</td>\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{assign var=\"service_counter\" value=\"0\"}\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red}{assign var=\"trclass\" value=\"row_red\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_dark}{assign var=\"trclass\" value=\"row_orange_dark\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_light}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n{assign var=\"service_counter\" value=\"`$service_counter+1`\"}\n<!-- {$egs_counter} -->\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name || (!$tool_service_select_list && $tool_services_list[service]._flags_.rs_online)}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $service_counter > 0}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Commands : </b></td>\n\t\t\t<td>&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_ee\" value=\"display entities\"\tonclick=\"if (confirm('Are you sure you want to DISPLAY ENTITIES from the selected services ?')) return true; return false;\">&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\t\t</form>\n\n{if $tool_entity_data}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_event_entities.php\" method=\"post\" name=\"elist\">\n\n{assign var=\"entity_service\" value=\"n/a\"}\n{section name=entity loop=$tool_entity_data}\n{if $entity_service != $tool_entity_data[entity].service}\n\t\t{assign var=\"entity_service\" value=$tool_entity_data[entity].service}\n\t\t<tr>\n\t\t\t<th colspan=\"16\">{$entity_service}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"heads\">Service</td>\n\t\t\t<td class=\"heads\">Entity</td>\n\t\t\t<td class=\"heads\">Name</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Param 1</td>\n\t\t\t<td class=\"heads\">Param 2</td>\n\t\t</tr>\n{/if}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_entity_data[entity].service_id}</td>\n\t\t\t<td>{$tool_entity_data[entity].entity}</td>\n\t\t\t<td>{$tool_entity_data[entity].entity_name}</td>\n\t\t\t<td><input type=\"text\" name=\"{$tool_entity_data[entity].service_code}_entity_state_{$tool_entity_data[entity].entity_string}\"  value=\"{$tool_entity_data[entity].entity_state}\"></td>\n\t\t\t<td><input type=\"text\" name=\"{$tool_entity_data[entity].service_code}_entity_param1_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_param1}\"></td>\n\t\t\t<td><input type=\"text\" name=\"{$tool_entity_data[entity].service_code}_entity_param2_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_param2}\"></td>\n\t\t</tr>\n<!-- code: {$tool_entity_data[entity].service} -- {$tool_entity_data[entity].service_code} -->\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_service_{$tool_entity_data[entity].entity_string}\" value=\"{$entity_service}\">\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_entity_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity}\">\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_entity_name_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_name}\">\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_entity_state_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_state}\">\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_entity_param1_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_param1}\">\n\t\t<input type=\"hidden\" name=\"{$tool_entity_data[entity].service_code}_source_entity_param2_{$tool_entity_data[entity].entity_string}\" value=\"{$tool_entity_data[entity].entity_param2}\">\n{/section}\n\t\t<tr>\n\t\t\t<td colspan=\"16\" align=\"center\"><input type=\"submit\" name=\"services_ee\" value=\"update entities\" onclick=\"if (confirm('Are you sure you want to UPDATE the selected entities ?')) this.form.submit(); else return false;\"></td>\n\t\t</tr>\n\n\t\t<input type=\"hidden\" name=\"requested_service_list\" value=\"{$requested_service_list}\">\n\t\t</form>\n\t\t</table>\n{/if}\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{else}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">No AIS to work with!</span></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_graphs.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n{if $tool_frame_list}\n<!--\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Time Frame</th>\n\t\t</tr>\n{section name=frame loop=$tool_frame_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_frame_selected == $tool_frame_list[frame].value}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}&frame={$tool_frame_list[frame].value}\">{$tool_frame_list[frame].title}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>-->\n{/if}\n\n{if $tool_graph_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Graphs</th>\n\t\t</tr>\n{section name=gvar loop=$tool_graph_variables}\n\t\t<tr class=\"row1_static\" style=\"border: 1px solid #000000;\">\n\t\t\t<td align=\"left\"><b>{$tool_graph_variables[gvar]}</b></td>\n\t\t\t<!--<td align=\"center\"><small>Low</small></td>-->\n\t\t\t<td align=\"center\"><small>High</small></td>\n\t\t</tr>\n{assign var=\"var_name\" value=$tool_graph_variables[gvar]}\n{section name=gdata loop=$tool_graph_datas.$var_name}\n\t\t<tr class=\"{if ($tool_graph_variable_selected == $var_name) && ($tool_graph_service_selected == $tool_graph_datas.$var_name[gdata].service)}varlistselected{else}varlist{/if}\">\n\t\t\t<td align=\"left\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}&variable={$var_name}&service={$tool_graph_datas.$var_name[gdata].service}\">{$tool_graph_datas.$var_name[gdata].service}</a></td>\n\t\t\t<!--<td align=\"center\"><small>{if $tool_graph_datas.$var_name[gdata].low_file != ''}Yes{else}No{/if}</small></td>-->\n\t\t\t<td align=\"center\"><small>{if $tool_graph_datas.$var_name[gdata].high_file != ''}Yes{else}No{/if}</small></td>\n\t\t</tr>\n{/section}\n{/section}\n\t\t</table>\n{/if}\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\" width=\"50%\" valign=\"top\">\n{if $tool_rrd_output}\n{section name=rrd loop=$tool_rrd_output}\n\t\t\t\t{$tool_rrd_output[rrd].desc}<br>\n\t\t\t\t<img src=\"{$tool_rrd_output[rrd].img}\" border=\"0\"><br>\n{/section}\n{/if}\n\t\t\t</td>\n\t\t\t<td class=\"row0\" width=\"50%\" valign=\"top\">\n{if $tool_rrd_high_output}\n{section name=rrd loop=$tool_rrd_high_output}\n\t\t\t\t<b>{$tool_rrd_high_output[rrd].desc}</b><br>\n{if $tool_rrd_high_output[rrd].img != ''}\n\t\t\t\t<img src=\"{$tool_rrd_high_output[rrd].img}\" border=\"0\"><br>\n{/if}\n{/section}\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_graphs_ccu.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Time Frame</th>\n\t\t</tr>\n{section name=frame loop=$tool_frame_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_frame_selected == $tool_frame_list[frame].value}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}&lowframe={$tool_frame_list[frame].value}\">{$tool_frame_list[frame].title}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a time frame.</td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\" width=\"100%\" valign=\"top\">\n{if $tool_rrd_output}\n{section name=rrd loop=$tool_rrd_output}\n\t\t\t\t<b>{$tool_rrd_output[rrd].desc}</b><br>\n\t\t\t\t<img src=\"{$tool_rrd_output[rrd].img}\" border=\"0\"><br>\n{/section}\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_graphs_hires.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected && $tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Time Frame</th>\n\t\t</tr>\n{section name=frame loop=$tool_frame_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_frame_selected == $tool_frame_list[frame].value}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}&highframe={$tool_frame_list[frame].value}\">{$tool_frame_list[frame].title}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a shard.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a time frame.</td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\" width=\"100%\" valign=\"top\">\n{if $tool_rrd_high_output}\n{section name=rrd loop=$tool_rrd_high_output}\n\t\t\t\t<b>{$tool_rrd_high_output[rrd].desc}</b><br>\n{if $tool_rrd_high_output[rrd].img != ''}\n\t\t\t\t<img src=\"{$tool_rrd_high_output[rrd].img}\" border=\"0\"><br>\n{/if}\n{/section}\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_graphs_tech.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"right\">\n\t\t\t<table cellpadding=\"1\" cellspacing=\"5\" border=\"0\">\n\t\t\t\t<tr>\n\t\t\t\t\t{section name=onemenu loop=$tool_menu}\n\t\t\t\t\t<td height=\"22\" class=\"boxed\"><a href=\"{$tool_menu[onemenu].uri}\">{$tool_menu[onemenu].title}</a></td>\n\t\t\t\t\t{/section}\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected && $tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Time Frame</th>\n\t\t</tr>\n{section name=frame loop=$tool_frame_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_frame_selected == $tool_frame_list[frame].value}shardlistselected{else}shardlist{/if}\"><a href=\"tool_graphs.php?toolmode={$toolmode}&domain={$tool_domain_selected}&shard={$tool_shard_selected}&lowframe={$tool_frame_list[frame].value}\">{$tool_frame_list[frame].title}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a shard.</td>\n\t\t</tr>\n\t\t</table>\n{elseif !$tool_frame_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a time frame.</td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\" width=\"100%\" valign=\"top\">\n{if $tool_rrd_output}\n{section name=rrd loop=$tool_rrd_output}\n\t\t\t\t<b>{$tool_rrd_output[rrd].desc}</b><br>\n\t\t\t\t<img src=\"{$tool_rrd_output[rrd].img}\" border=\"0\"><br>\n{/section}\n{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_guild_locator.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_guild_locator.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_guild_locator.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_guild_locator.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\n\t\t<form action=\"tool_guild_locator.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n\t\t\t<td class=\"heads\">ShortName</td>\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{assign var=\"egs_counter\" value=\"0\"}\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red}{assign var=\"trclass\" value=\"row_red\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_dark}{assign var=\"trclass\" value=\"row_orange_dark\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_light}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n{assign var=\"egs_counter\" value=\"`$egs_counter+1`\"}\n<!-- {$egs_counter} -->\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name || (!$tool_service_select_list && $tool_services_list[service]._flags_.rs_online)}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $egs_counter > 0}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Commands : </b></td>\n\t\t\t<td>&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_gl\" value=\"display guilds\"\tonclick=\"if (confirm('Are you sure you want to DISPLAY GUILDS from the selected services ?')) return true; return false;\">&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\n{if $tool_guild_data}\n{assign var=\"service_name\" value=\"\"}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n{section name=guild loop=$tool_guild_data}\n{if $service_name != $tool_guild_data[guild].service}\n{assign var=\"service_name\" value=$tool_guild_data[guild].service}\n\t\t<tr>\n\t\t\t<th colspan=\"8\">{$service_name}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Guild Name</th>\n\t\t\t<th>Guild ID</th>\n\t\t\t<th>Guild Members</th>\n\t\t\t<th>Guild EID</th>\n\t\t</tr>\n{/if}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_guild_data[guild].name}</td>\n\t\t\t<td align=\"center\"><a href=\"tool_guild_locator.php?services_gl=dumpguild&servicealias={$service_name|lower}&guildshardid={$tool_guild_data[guild].shardid}&guildid={$tool_guild_data[guild].guildid}\">{$tool_guild_data[guild].shardid} - {$tool_guild_data[guild].guildid}</a></td>\n\t\t\t<td align=\"center\">{$tool_guild_data[guild].members}</td>\n\t\t\t<td align=\"center\">{$tool_guild_data[guild].guildeid}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{if $tool_guild_dump_data}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Guild Name</th>\n\t\t\t<th>ID (EID)</th>\n\t\t\t<th>Money</th>\n\t\t\t<th>Race</th>\n\t\t\t<th>Members</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>{$tool_guild_dump_data.guild_name}</td>\n\t\t\t<td align=\"center\"><a href=\"tool_guild_locator.php?services_gl=dumpguild&servicealias={$tool_service|lower}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}\">{$tool_guild_dump_data.shard_id}:{$tool_guild_dump_data.guild_id} {$tool_guild_dump_data.guild_eid}</a></td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.guild_money}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.guild_race}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.members_count}</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td colspan=\"8\">Description: {$tool_guild_dump_data.guild_description}</td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n\n{if $restriction_tool_guild_locator_manage_guild}\n\t\t<input type=\"hidden\" name=\"servicealias\" value=\"{$tool_service|lower}\">\n\t\t<input type=\"hidden\" name=\"guildshardid\" value=\"{$tool_guild_dump_data.shard_id}\">\n\t\t<input type=\"hidden\" name=\"guildid\" \t value=\"{$tool_guild_dump_data.guild_id}\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"15%\">Rename&nbsp;Guild&nbsp;</td>\n\t\t\t<td><input type=\"text\" name=\"new_guild_name\" value=\"{$tool_guild_dump_data.guild_name}\" size=\"50\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_gl\" value=\"update name\"  style=\"width:150px;\" onclick=\"if (confirm('Are you sure you want to update this guilds name ?')) return true; else return false;\">\n\t\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"15%\">Change&nbsp;Description&nbsp;</td>\n\t\t\t<td><input type=\"text\" name=\"new_guild_description\" value=\"{$tool_guild_dump_data.guild_description}\" size=\"50\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_gl\" value=\"update description\" style=\"width:150px;\" onclick=\"if (confirm('Are you sure you want to update this guilds description ?')) return true; else return false;\">\n\t\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n{if $tool_guild_errors}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n{section name=err loop=$tool_guild_errors}\n\t\t<tr>\n\t\t\t<td>{$tool_guild_errors[err]}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Leader</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Shard</th>\n\t\t\t<th>EntityID</th>\n\t\t\t<th>Index</th>\n\t\t\t<th>Enter Time</th>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<th>&nbsp;</th>\n{/if}\n\t\t</tr>\n{section name=leader loop=$tool_guild_dump_data.Leader}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td>{$tool_guild_dump_data.Leader[leader].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Leader[leader].shard}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Leader[leader].eid}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Leader[leader].index}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Leader[leader].entertime}</td>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<td align=\"right\">&nbsp;</td>\n{/if}\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\n\t\t<tr>\n\t\t\t<th colspan=\"8\">HighOfficers</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Shard</th>\n\t\t\t<th>EntityID</th>\n\t\t\t<th>Index</th>\n\t\t\t<th>Enter Time</th>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<th>&nbsp;</th>\n{/if}\n\t\t</tr>\n{section name=hofficer loop=$tool_guild_dump_data.HighOfficer}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td>{$tool_guild_dump_data.HighOfficer[hofficer].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.HighOfficer[hofficer].shard}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.HighOfficer[hofficer].eid}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.HighOfficer[hofficer].index}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.HighOfficer[hofficer].entertime}</td>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<td align=\"right\">[&nbsp;Set&nbsp;:&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=setleader&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.HighOfficer[hofficer].eid}\" onclick=\"if (confirm('Are you sure you want to promote guild High Officer &lt;{$tool_guild_dump_data.HighOfficer[hofficer].name}&gt; as Leader ?')) return true; else return false;\">Leader</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=demote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.HighOfficer[hofficer].eid}&grade=Officer\" onclick=\"if (confirm('Are you sure you want to demote guild High Officer &lt;{$tool_guild_dump_data.HighOfficer[hofficer].name}&gt; as Officer ?')) return true; else return false;\">Officer</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=demote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.HighOfficer[hofficer].eid}&grade=Member\" onclick=\"if (confirm('Are you sure you want to demote guild High Officer &lt;{$tool_guild_dump_data.HighOfficer[hofficer].name}&gt; as Member ?')) return true; else return false;\">Member</a>&nbsp;]&nbsp;\n\t\t\t</td>\n{/if}\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Officers</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Shard</th>\n\t\t\t<th>EntityID</th>\n\t\t\t<th>Index</th>\n\t\t\t<th>Enter Time</th>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<th>&nbsp;</th>\n{/if}\n\t\t</tr>\n{section name=officer loop=$tool_guild_dump_data.Officer}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td>{$tool_guild_dump_data.Officer[officer].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Officer[officer].shard}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Officer[officer].eid}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Officer[officer].index}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Officer[officer].entertime}</td>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<td align=\"right\">[&nbsp;Set&nbsp;:&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=setleader&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Officer[officer].eid}\" onclick=\"if (confirm('Are you sure you want to promote guild Officer &lt;{$tool_guild_dump_data.Officer[officer].name}&gt; as Leader ?')) return true; else return false;\">Leader</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=promote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Officer[officer].eid}&grade=HighOfficer\" onclick=\"if (confirm('Are you sure you want to promote guild Member &lt;{$tool_guild_dump_data.Officer[officer].name}&gt; as High Officer ?')) return true; else return false;\">HighOfficer</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=demote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Officer[officer].eid}&grade=Member\" onclick=\"if (confirm('Are you sure you want to demote guild Officer &lt;{$tool_guild_dump_data.Officer[officer].name}&gt; as Member ?')) return true; else return false;\">Member</a>&nbsp;]&nbsp;\n\t\t\t</td>\n{/if}\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Members</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Shard</th>\n\t\t\t<th>EntityID</th>\n\t\t\t<th>Index</th>\n\t\t\t<th>Enter Time</th>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<th>&nbsp;</th>\n{/if}\n\t\t</tr>\n{section name=member loop=$tool_guild_dump_data.Member}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td>{$tool_guild_dump_data.Member[member].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Member[member].shard}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Member[member].eid}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Member[member].index}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.Member[member].entertime}</td>\n{if $restriction_tool_guild_locator_manage_members}\n\t\t\t<td align=\"right\">[&nbsp;Set&nbsp;:&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=setleader&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Member[member].eid}\" onclick=\"if (confirm('Are you sure you want to promote guild Member &lt;{$tool_guild_dump_data.Member[member].name}&gt; as Leader ?')) return true; else return false;\">Leader</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=promote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Member[member].eid}&grade=HighOfficer\" onclick=\"if (confirm('Are you sure you want to promote guild Member &lt;{$tool_guild_dump_data.Member[member].name}&gt; as High Officer ?')) return true; else return false;\">HighOfficer</a>&nbsp;|&nbsp;\n\t\t\t\t<a href=\"tool_guild_locator.php?services_gl=promote&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&eid={$tool_guild_dump_data.Member[member].eid}&grade=Officer\" onclick=\"if (confirm('Are you sure you want to promote guild Member &lt;{$tool_guild_dump_data.Member[member].name}&gt; as Officer ?')) return true; else return false;\">Officer</a>&nbsp;]&nbsp;\n\t\t\t</td>\n{/if}\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\t\t</table>\n\t\t<br>\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Owned Outposts</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Alias</th>\n\t\t\t<th>Sheet</th>\n\t\t</tr>\n{section name=outpost loop=$tool_guild_dump_data.outposts}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.outposts[outpost].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.outposts[outpost].alias}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.outposts[outpost].sheet}</td>\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\t\t</table>\n\t\t<br>\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Challenged Outposts</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Alias</th>\n\t\t\t<th>Sheet</th>\n\t\t</tr>\n{section name=outpost loop=$tool_guild_dump_data.challenged_outposts}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.challenged_outposts[outpost].name}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.challenged_outposts[outpost].alias}</td>\n\t\t\t<td align=\"center\">{$tool_guild_dump_data.challenged_outposts[outpost].sheet}</td>\n\t\t</tr>\n{sectionelse}\n\t\t<tr><td colspan=\"8\" align=\"center\"><i>none</i></td></tr>\n{/section}\n\t\t</table>\n\t\t<br>\n\n{if $restriction_tool_guild_locator_manage_forums}\n\t\t<a name=\"forumview\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Guild Forums</th>\n\t\t</tr>\n{if $tool_guild_forums_error}\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_guild_forums_error}</span></td>\n\t\t</tr>\n{elseif $tool_guild_forums}\n\t\t<tr>\n\t\t\t<th>File</th>\n\t\t\t<th>Thread</th>\n\t\t\t<th>Action</th>\n\t\t</tr>\n{section name=line loop=$tool_guild_forums}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\n\t\t\t<td align=\"center\"><a href=\"?services_gl=dumpguild&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&subservices_gl=viewthread&threadid={$tool_guild_forums[line].thread}&recoverable={$tool_guild_forums[line].recover}#threadview\">{$tool_guild_forums[line].file}</a></td>\n\t\t\t<td align=\"center\">{$tool_guild_forums[line].thread}</td>\n\t\t\t<td align=\"center\">{if $tool_guild_forums[line].recover == 1}<a href=\"?services_gl=dumpguild&servicealias={$tool_service}&guildshardid={$tool_guild_dump_data.shard_id}&guildid={$tool_guild_dump_data.guild_id}&subservices_gl=recoverthread&threadid={$tool_guild_forums[line].thread}&recoverable={$tool_guild_forums[line].recover}#forumview\" onclick=\"if (confirm('Are you sure you want to RECOVER this thread ?')) return true; return false;\">Recover</a>{/if}</td>\n\t\t</tr>\n{/section}\n{/if}\n\t\t</table>\n\t\t<br>\n\n{if $tool_guild_thread}\n\t\t<a name=\"threadview\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"8\">Thread View</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td colspan=\"8\">{$tool_guild_thread.topic.raw}</td>\n\t\t</tr>\n{section name=msg loop=$tool_guild_thread.data}\n\t\t<tr class=\"{cycle values=\"row0,row1\"}\">\n\t\t\t<td colspan=\"8\">{$tool_guild_thread.data[msg].raw}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{/if}\n\n{/if}\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{else}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">No EGS to work with!</span></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t\t</form>\n\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_log_analyser.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n{if $tool_file_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Files</th>\n\t\t</tr>\n{section name=file loop=$tool_file_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_file_selected == $tool_file_list[file].name}shardlistselected{else}shardlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&fileview={$tool_file_list[file].code}\" onmouseover=\"return overlib('Date: {$tool_file_list[file].date|date_format:\"%Y/%m/%d %H:%M:%S\"}<br>Size: {math equation=\"x / y\" x=$tool_file_list[file].size y=1024 format=\"%d\"} KB<br>', OFFSETX, 40, OFFSETY, 10);\" onmouseout=\"return nd();\">{$tool_file_list[file].name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\n\t\t<form action=\"tool_log_analyser.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n\t\t\t<td class=\"heads\">ShortName</td>\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{assign var=\"las_counter\" value=\"0\"}\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red}{assign var=\"trclass\" value=\"row_red\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_dark}{assign var=\"trclass\" value=\"row_orange_dark\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_light}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n{assign var=\"las_counter\" value=\"`$las_counter+1`\"}\n<!-- {$egs_counter} -->\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $las_counter > 0}\n\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Database : </b></td>\n\t\t\t<td width=\"25%\"><select name=\"service_search_database\">\n\t\t\t\t\t\t\t\t<option value=\"0\" {if $tool_form_service_search_database == 0}selected{/if} >Action Log (0)</option>\n\t\t\t\t\t\t\t\t<option value=\"1\" {if $tool_form_service_search_database == 1}selected{/if} >Chat Log (1)</option>\n\t\t\t\t\t\t\t</select>\n\t\t\t\t</td>\n\t\t\t<td>&nbsp;</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>File Name : </b></td>\n\t\t\t<td width=\"25%\"><input type=\"text\" name=\"service_search_file_name\" value=\"{$tool_form_service_search_file_name}\" style=\"width:98%;\"></td>\n\t\t\t<td><span class=\"alert\">{$tool_file_name_error_msg}</span></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Start Date : </b></td>\n\t\t\t<td width=\"25%\"><input type=\"text\" name=\"service_search_start_date\" value=\"{$tool_form_service_search_start_date}\" style=\"width:98%;\"></td>\n\t\t\t<td><span class=\"alert\">{$tool_start_date_error_msg}</span></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>End Date : </b></td>\n\t\t\t<td width=\"25%\"><input type=\"text\" name=\"service_search_end_date\" value=\"{$tool_form_service_search_end_date}\" style=\"width:98%;\"></td>\n\t\t\t<td>&nbsp;</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td colspan=\"4\"><hr size=\"1\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>EID Search : </b></td>\n\t\t\t<td width=\"25%\"><textarea name=\"service_eids\" rows=\"3\">{$tool_form_service_eids}</textarea></td>\n\t\t\t<td><input type=\"submit\" name=\"services_las\" value=\"search eids\"></td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Text Search : </b></td>\n\t\t\t<td width=\"25%\"><input type=\"text\" name=\"service_text\" value=\"{$tool_form_service_text}\" style=\"width:98%;\"></td>\n\t\t\t<td><input type=\"submit\" name=\"services_las\" value=\"search text\"></td>\n\t\t</tr>\n\t\t</table>\n\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Command : </b></td>\n\t\t\t<td>&nbsp;<input type=\"text\" name=\"service_command\" value=\"{$tool_execute_command}\" size=\"50\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_las\" value=\"execute\">&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{else}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">No LAS to work with or select a shard on the left!</span></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t\t</form>\n\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_log_analyser_file_view.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n{if $tool_file_list}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Files</th>\n\t\t</tr>\n{section name=file loop=$tool_file_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_file_selected == $tool_file_list[file].name}shardlistselected{else}shardlist{/if}\"><a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&fileview={$tool_file_list[file].code}\" onmouseover=\"return overlib('Date: {$tool_file_list[file].date|date_format:\"%Y/%m/%d %H:%M:%S\"}<br>Size: {math equation=\"x / y\" x=$tool_file_list[file].size y=1024 format=\"%d\"} KB<br>', OFFSETX, 40, OFFSETY, 10);\" onmouseout=\"return nd();\">{$tool_file_list[file].name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if $tool_file_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_file_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{else}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\">Viewing File : {$tool_view_file_data.name}\n\t\t\t\t[ Downloads :\n\t\t\t\t<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&downloadraw=1&fileview={$tool_view_file_data.code}\">RAW</a>\n\t\t\t\t&nbsp;-&nbsp;\n\t\t\t\t<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&downloadparsed=1&fileview={$tool_view_file_data.code}\">PARSED</a>\n\t\t\t\t]\n\t\t\t\t{* [<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&download=1&fileview={$tool_view_file_data.code}\">download</a>] *}\n\t\t\t\t{* [<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&delete=1&fileview={$tool_view_file_data.code}\">delete</a>] *}\n\t\t\t</td>\n\t\t</tr>\n{section name=line loop=$tool_file_output}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_file_output[line]}</td>\n\t\t</tr>\n{/section}\n\t\t<tr>\n\t\t\t<th align=\"center\">\n{if $tool_view_line_start_previous > -1}\n\t\t\t\t<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&viewstart={$tool_view_line_start_previous}&fileview={$tool_view_file_data.code}\">&lt;Previous</a>\n{else}\n\t\t\t\tBeginning\n{/if}\n\t\t\t\t&nbsp;|&nbsp;\n{if $tool_view_line_start_next > -1}\n\t\t\t\t<a href=\"tool_log_analyser.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}&viewstart={$tool_view_line_start_next}&fileview={$tool_view_file_data.code}\">Next&gt;</a>\n{else}\n\t\t\t\tEnd\n{/if}\n\t\t\t</th>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_mfs.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_mfs.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_mfs.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if !$tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a shard.</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n{/if}\n\n\t\t<form action=\"tool_mfs.php\" method=\"post\" name=\"qlist\">\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">\n{$tool_curl_output}\n\t\t\t</td>\n\t\t</table>\n\n\t\t</form>\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_notes.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\n\tfunction toggleLine(myline)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(myline).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(myline).style.display = \"\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(myline).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(myline).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(myline).style.display = \"\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(myline).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n\n{/literal}\n\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">\n\t<tr>\n\t\t<td align=\"left\" valign=\"center\"><span class=\"alert\">{$tool_alert_message}</span></td>\n\t</tr>\n</table>\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"50%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Notes</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><b>ID</b></td>\n\t\t\t<td><b>Title</b></td>\n\t\t\t<td><b>Mode</b></td>\n\t\t\t<td><b>Last Update</b></td>\n\t\t\t<td><b>Active</b></td>\n{if $restriction_tool_notes_global}\n\t\t\t<td><b>Global</b></td>\n{/if}\n\t\t</tr>\n\t\t{section name=note loop=$tool_note_list}\n\t\t<tr class=\"{cycle values=\"row1,row0\"}\">\n\t\t\t<td>{$tool_note_list[note].note_id}</td>\n\t\t\t<td><a href=\"tool_notes.php?note_id={$tool_note_list[note].note_id}\">{$tool_note_list[note].note_title}</a></td>\n\t\t\t<td>{if $tool_note_list[note].note_mode  == 0}Text{else}Popup{/if}</td>\n\t\t\t<td>{$tool_note_list[note].note_date|date_format:\"%Y/%m/%d %H:%M:%S\"}</td>\n\t\t\t<td>{if $tool_note_list[note].note_active  == 1}Yes{else}No{/if}</td>\n{if $restriction_tool_notes_global}\n\t\t\t<td>{if $tool_note_list[note].note_global  == 1}Yes{else}No{/if}</td>\n{/if}\n\t\t</tr>\n\t\t{/section}\n\t\t</table>\n\t</td>\n\n\t<td>&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\" width=\"50%\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<form action=\"tool_notes.php\" method=\"post\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Notes Details</th>\n\t\t</tr>\n{if $tool_note_edit_data.note_id}\n\t\t<tr>\n\t\t\t<td align=\"right\">Id :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_note_id\" value=\"{$tool_note_edit_data.note_id}\" size=\"10\" readonly></td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td align=\"right\">Title :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_note_title\" value=\"{$tool_note_edit_data.note_title}\" maxlength=\"64\" size=\"100%\"></td>\n\t\t</tr>\n\n\t\t<tr>\n\t\t\t<td align=\"right\">Mode : </td>\n\t\t\t<td><select name=\"tool_form_note_mode\" onchange=\"toggleLine('note_mode_text'); toggleLine('note_mode_popup_uri'); toggleLine('note_mode_popup_restriction');\">\n\t\t\t\t<option value=\"text\" {if $tool_note_edit_data.note_mode == 0}selected{/if}>Text</option>\n\t\t\t\t<option value=\"popup\" {if $tool_note_edit_data.note_mode == 1}selected{/if}>Popup</option>\n\t\t\t</select></td>\n\t\t</tr>\n\n\t\t<tr id=\"note_mode_text\" name=\"note_mode_text\" {if $tool_note_edit_data.note_mode == 1}style=\"display: none;\"{/if}>\n\t\t\t<td align=\"right\">Text :</td>\n\t\t\t<td><textarea name=\"tool_form_note_data\" rows=\"15\">{$tool_note_edit_data.note_data}</textarea></td>\n\t\t</tr>\n\n\t\t<tr id=\"note_mode_popup_uri\" name=\"note_mode_popup_uri\" {if $tool_note_edit_data.note_mode == 0}style=\"display: none;\"{/if}>\n\t\t\t<td align=\"right\">URI :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_note_popup_uri\" value=\"{$tool_note_edit_data.note_popup_uri}\" maxlength=\"255\" size=\"100%\"></td>\n\t\t</tr>\n\n\t\t<tr id=\"note_mode_popup_restriction\" name=\"note_mode_popup_restriction\" {if $tool_note_edit_data.note_mode == 0}style=\"display: none;\"{/if}>\n\t\t\t<td align=\"right\">Restriction :</td>\n\t\t\t<td><input type=\"text\" name=\"tool_form_note_popup_restriction\" value=\"{$tool_note_edit_data.note_popup_restriction}\" maxlength=\"64\" size=\"100%\"></td>\n\t\t</tr>\n\n\t\t<tr>\n\t\t\t<td align=\"right\">Active :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_note_active\">\n\t\t\t\t\t<option value=\"1\" {if $tool_note_edit_data.note_active == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_note_edit_data.note_active == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $restriction_tool_notes_global}\n\t\t<tr>\n\t\t\t<td align=\"right\">Global :</td>\n\t\t\t<td>\n\t\t\t\t<select name=\"tool_form_note_global\">\n\t\t\t\t\t<option value=\"1\" {if $tool_note_edit_data.note_global == 1}selected{/if}>Yes</option>\n\t\t\t\t\t<option value=\"0\" {if $tool_note_edit_data.note_global == 0}selected{/if}>No</option>\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t<tr>\n\t\t\t<td>&nbsp;</td>\n\t\t\t<td>\n\n{if $tool_note_edit_data.note_id}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"update\">\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"delete\" onclick=\"if (confirm('Are you sure you want to DELETE this note ?')) return true; return false;\">\n{else}\n\t\t\t\t<input type=\"submit\" name=\"toolaction\" value=\"create\">\n\n{/if}\n\n\t\t\t</td>\n\t\t</tr>\n\t\t</form>\n\t\t</table>\n\t</td>\n\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_player_locator.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\tif (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_player_locator.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_player_locator.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_player_locator.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\n\t\t<form action=\"tool_player_locator.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n\t\t\t<td class=\"heads\">ShortName</td>\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{assign var=\"egs_counter\" value=\"0\"}\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red}{assign var=\"trclass\" value=\"row_red\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_dark}{assign var=\"trclass\" value=\"row_orange_dark\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_light}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n{assign var=\"egs_counter\" value=\"`$egs_counter+1`\"}\n<!-- {$egs_counter} -->\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name || (!$tool_service_select_list && $tool_services_list[service]._flags_.rs_online)}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $egs_counter > 0}\n{if $restriction_tool_player_locator_display_players}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Player Name : </b></td>\n\t\t\t<td>&nbsp;<input type=\"text\" name=\"services_plname_locate\" value=\"{$tool_locate_name_value}\" size=\"20\">&nbsp;\n\t\t\t\t{if $restriction_tool_player_locator_display_players}<input type=\"submit\" name=\"services_pl\" value=\"display players\"\tonclick=\"if (confirm('Are you sure you want to DISPLAY PLAYERS from the selected services ?')) return true; return false;\">&nbsp;{/if}\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n{if $restriction_tool_player_locator_locate}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Locate : </b></td>\n\t\t\t<td>&nbsp;<input type=\"text\" name=\"services_pl_locate\" value=\"{$tool_locate_value}\" size=\"20\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"locate\" onclick=\"if (confirm('Are you sure you want to LOCATE this player on the selected services ?')) return true; return false;\">&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{if $tool_locate_data}\n\n{if $tool_relocate_data && $restriction_tool_player_locator_csr_relocate}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n{if $tool_relocate_data.success == 1}\n\t\t\t<td>Successfully relocated character {$tool_relocate_data.charid} from account {$tool_relocate_data.uid}!</td>\n{else}\n\t\t\t<td><span class=\"alert\">Failed relocating character {$tool_relocate_data.charid} from account {$tool_relocate_data.uid}! Account is online!</span></td>\n{/if}\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{assign var=\"service_name\" value=\"\"}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n{section name=entity loop=$tool_locate_data}\n{if $service_name != $tool_locate_data[entity].service}\n{assign var=\"service_name\" value=$tool_locate_data[entity].service}\n\t\t<tr>\n\t\t\t<th colspan=\"16\">{$service_name}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>UId</th>\n\t\t\t<th>UserName</th>\n\t\t\t<th>EId</th>\n\t\t\t<th>EntityName</th>\n\t\t\t<th>EntitySlot</th>\n\t\t\t<th>SaveFile</th>\n\t\t\t<th>Status</th>\n\t\t\t<th>Session</th>\n\t\t\t<th>X</th>\n\t\t\t<th>Y</th>\n\t\t\t<th>Z</th>\n\t\t</tr>\n{/if}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{if $tool_locate_data[entity].status == \"Online\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$tool_locate_data[entity].uid}</td>\n\t\t\t<td>{$tool_locate_data[entity].user_name}</td>\n\t\t\t<td>{if $tool_locate_data[entity].status == \"Online\"}<a href=\"tool_player_locator.php?refdata={$tool_post_data}&eid={$tool_locate_data[entity].eid}\">{$tool_locate_data[entity].eid}</a>{else}{$tool_locate_data[entity].eid}{/if}</td>\n\t\t\t<td>{$tool_locate_data[entity].entity_name}</td>\n\t\t\t<td>{$tool_locate_data[entity].entity_slot}</td>\n\t\t\t<td>{$tool_locate_data[entity].save_file}</td>\n\t\t\t<td>{$tool_locate_data[entity].status}</td>\n{if $tool_locate_data[entity].status == \"Online\"}\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].session}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posx}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posy}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posz}</td>\n{elseif $restriction_tool_player_locator_csr_relocate}\n\t\t\t<td align=\"center\" colspan=\"4\">relocate:\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"ani\" style=\"height:15px; font-size: 10px;\" onclick=\"if (confirm('Are you sure you want to RELOCATE this character to the ANIRO shard ?')) {ldelim} this.form.relocate_shardid.value='101'; this.form.relocate_eid.value='{$tool_locate_data[entity].eid}'; this.form.submit(); {rdelim} else return false;\">\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"ari\" style=\"height:15px; font-size: 10px;\" onclick=\"if (confirm('Are you sure you want to RELOCATE this character to the ARISPOTLE shard ?')) {ldelim} this.form.relocate_shardid.value='103'; this.form.relocate_eid.value='{$tool_locate_data[entity].eid}'; this.form.submit(); {rdelim} else return false;\">\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"lea\" style=\"height:15px; font-size: 10px;\" onclick=\"if (confirm('Are you sure you want to RELOCATE this character to the LEANON shard ?')) {ldelim} this.form.relocate_shardid.value='102'; this.form.relocate_eid.value='{$tool_locate_data[entity].eid}'; this.form.submit(); {rdelim} else return false;\">\n\t\t\t</td>\n{else}\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].session}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posx}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posy}</td>\n\t\t\t<td align=\"center\">{$tool_locate_data[entity].posz}</td>\n{/if}\n\t\t</tr>\n{/section}\n\t\t</table>\n{elseif $tool_player_data}\n{assign var=\"service_name\" value=\"\"}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n{section name=entity loop=$tool_player_data}\n{if $service_name != $tool_player_data[entity].service}\n{assign var=\"service_name\" value=$tool_player_data[entity].service}\n\t\t<tr>\n\t\t\t<th colspan=\"12\">{$service_name}</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th>Player</th>\n\t\t\t<th>Name</th>\n\t\t\t<th>ID</th>\n\t\t\t<th>FE</th>\n\t\t\t<th>Sheet</th>\n\t\t\t<th>Priv</th>\n\t\t\t<th>Session</th>\n\t\t\t<th>X</th>\n\t\t\t<th>Y</th>\n\t\t\t<th>Z</th>\n\t\t</tr>\n{/if}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><a href=\"tool_player_locator.php\">{$tool_player_data[entity].player}</a></td>\n\t\t\t<td>{$tool_player_data[entity].name}</td>\n\t\t\t<td><a href=\"tool_player_locator.php?refdata={$tool_post_data}&eid={$tool_player_data[entity].id}\">{$tool_player_data[entity].id}</a></td>\n\t\t\t<td>{$tool_player_data[entity].fe}</td>\n\t\t\t<td>{$tool_player_data[entity].sheet}</td>\n\t\t\t<td>{$tool_player_data[entity].priv}</td>\n\t\t\t<td align=\"center\">{$tool_player_data[entity].session}</td>\n\t\t\t<td align=\"center\">{$tool_player_data[entity].posx}</td>\n\t\t\t<td align=\"center\">{$tool_player_data[entity].posy}</td>\n\t\t\t<td align=\"center\">{$tool_player_data[entity].posz}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{if $restriction_tool_player_locator_userid_check}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"16\">Character List (user_id = 0)</th>\n\t\t</tr>\n{if $user_check_list}\n\t\t<tr>\n\t\t\t<th>Character Name</th>\n\t\t\t<th>Character ID</th>\n\t\t\t<th>Best Combat Level</th>\n\t\t\t<th>Ring Access</th>\n\t\t</tr>\n{section name=char loop=$user_check_list}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td>{$user_check_list[char].char_name}</td>\n\t\t\t<td align=\"center\">{$user_check_list[char].char_id}</td>\n\t\t\t<td align=\"center\">{$user_check_list[char].best_combat_level}</td>\n\t\t\t<td align=\"center\">{$user_check_list[char].ring_access}</td>\n\t\t</tr>\n{/section}\n\t\t<tr>\n\t\t\t<th colspan=\"16\">\n\t\t\t\t{* <input type=\"hidden\" name=\"pl_su\" value=\"{$shard_su_name}\"> *}\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"Compute User IDs and Clear SQL Cache\" onclick=\"if (confirm('Are you sure you want to fix empty user_id and clear the SQL cache on the SU ?')) return true; return false;\">&nbsp;\n\t\t\t</th>\n\t\t</tr>\n{else}\n\t\t<tr>\n\t\t\t<td colspan=\"16\" align=\"center\"><i>No characters with user_id=0 were found!</i></td>\n\t\t</tr>\n{/if}\n\t\t</table>\n{/if}\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{else}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">No EGS to work with!</span></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t\t<input type=\"hidden\" name=\"pl_su\" value=\"{$shard_su_name}\">\n\t\t<input type=\"hidden\" name=\"relocate_shardid\" value=\"na\">\n\t\t<input type=\"hidden\" name=\"relocate_eid\" value=\"na\">\n\t\t</form>\n\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_preferences.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n<br>\n\n<table width=\"30%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n<form action=\"tool_preferences.php\" method=\"post\">\n<tr>\n\t<th colspan=\"2\">My Preferences</th>\n</tr>\n<tr>\n\t<td align=\"right\">Login:</td>\n\t<td><b>{$tool_v_login}</b></td>\n</tr>\n<tr>\n\t<td align=\"right\">Old Password:</td>\n\t<td><input type=\"password\" name=\"tool_form_password_old\" maxlength=\"8\"></td>\n</tr>\n<tr>\n\t<td align=\"right\">New Password:</td>\n\t<td><input type=\"password\" name=\"tool_form_password_new\" maxlength=\"8\"></td>\n</tr>\n<tr>\n\t<td align=\"right\">Menu Style:</td>\n\t<td><select name=\"tool_form_menu_style\">\n\t\t<option value=\"0\" {if $tool_v_menu == 0}selected{/if}>Text only</option>\n\t\t<option value=\"1\" {if $tool_v_menu == 1}selected{/if}>Icon only</option>\n\t\t<option value=\"2\" {if $tool_v_menu == 2}selected{/if}>Text and Icon</option>\n\t\t</select>\n\t\t</td>\n</tr>\n<tr>\n\t<td>&nbsp;</td>\n\t<td><input type=\"submit\" name=\"toolaction\" value=\"update\"></td>\n</tr>\n{if $tool_error != null}\n<tr>\n\t<td colspan=\"2\" align=\"center\"><b>{$tool_error}</b></td>\n</tr>\n{/if}\n<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_v_user_id}\">\n</form>\n</table>\n\n<br>\n<table width=\"30%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n<form action=\"tool_preferences.php\" method=\"post\">\n<tr>\n\t<th colspan=\"2\">Default Application</th>\n</tr>\n<tr>\n\t<td align=\"right\">Application :</td>\n\t<td><select name=\"tool_form_application_default\" style=\"width:150px;\">\n\t\t<option value=\"0\"><i>Use Group Default</i></option>\n\t\t<option disabled > --------------- </option>\n{section name=menu loop=$nel_menu}\n{if $nel_menu[menu].application_order != 999999}\n\t\t<option value=\"{$nel_menu[menu].application_id}\" {if $tool_v_application == $nel_menu[menu].application_id}selected{/if}>{$nel_menu[menu].application_name}</option>\n{/if}\n{/section}\n\t</select></td>\n</tr>\n<tr>\n\t<td>&nbsp;</td>\n\t<td><input type=\"submit\" name=\"toolaction\" value=\"update default application\"></td>\n</tr>\n<input type=\"hidden\" name=\"tool_form_user_id\" value=\"{$tool_v_user_id}\">\n</form>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default/tool_shop.tpl",
    "content": "\n{include file=\"page_header.tpl\"}\n\n{literal}\n<script language=\"Javascript\" type=\"text/javascript\">\n<!--\n\tfunction CheckAll()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\t\t\t//if (e.type == 'checkbox' && e.name != 'allbox')\n\t\t\tif (e.type == 'checkbox' && e.name.substring(0,8) == 'service_')\n\t\t\t\te.checked = document.qlist.allbox.checked;\n\t\t}\n\t}\n\t\n\tfunction CheckAllShopList()\n\t{\n\t\tfor (var i=0; i<document.qlist.elements.length; i++)\n\t\t{\n\t\t\tvar e = document.qlist.elements[i];\n\n\t\t\tif (e.type == 'checkbox' && e.name.substring(0,14) == 'checkshoplist_')\n\t\t\t\te.checked = document.qlist.allbox_shoplist.checked;\n\t\t}\n\t}\n\t\n\n\tfunction CheckToggle(checkname)\n\t{\n\t\tcheckname.checked = !checkname.checked;\n\t}\n\n\tvar total_secs;\n\n\tfunction TimerDown(secs)\n\t{\n\t\ttotal_secs = secs;\n\t\tCountDown();\n\t}\n\n\tfunction TimerDisplay(secs)\n\t{\n\t\ttimer_min = Math.floor(secs / 60);\n\t\ttimer_sec = secs % 60;\n\n\t\tif (timer_min < 10) timer_min = '0'+ timer_min;\n\t\tif (timer_sec < 10) timer_sec = '0'+ timer_sec;\n\n\t\treturn timer_min+':'+timer_sec;\n\t}\n\n\tfunction CountDown()\n\t{\n\t\ttotal_secs--;\n\t\tif (total_secs >= 0)\n\t\t{\n\t\t\tdocument.fcounter.counter.value = TimerDisplay(total_secs);\n\t\t\tdown=setTimeout(\"CountDown()\",1000);\n\t\t}\n\t}\n\n\tfunction toggleBox(mybox1, mybox2)\n\t{\n\t\tif (document.all)\n\t\t{\n\t\t\tif (document.all.item(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox1).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.all.item(mybox2).style.display = \"\";\n\t\t\t\tdocument.all.item(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (document.getElementById(mybox1).style.display == \"none\")\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"none\";\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tdocument.getElementById(mybox2).style.display = \"\";\n\t\t\t\tdocument.getElementById(mybox1).style.display = \"none\";\n\t\t\t}\n\t\t}\n\t}\n\n//-->\n</script>\n{/literal}\n\n<br>\n\n<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"10\">\n<tr>\n\t<td align=\"left\" valign=\"top\" width=\"150px\">\n\n{if $tool_domain_selected && $tool_shard_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Refresh</th>\n\t\t</tr>\n\t\t<form action=\"tool_shop.php?domain={$tool_domain_selected}&shard={$tool_shard_selected}\" method=\"post\" name=\"fcounter\">\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<select name=\"services_refresh\" style=\"width:100%;\" onchange=\"this.form.submit();\">\n{section name=refresh loop=$tool_refresh_list}\n\t\t\t\t\t<option value=\"{$tool_refresh_list[refresh].secs}\" {if $tool_refresh_rate == $tool_refresh_list[refresh].secs}selected{/if}>{$tool_refresh_list[refresh].desc}</option>\n{/section}\n\t\t\t\t</select>\n\t\t\t</td>\n\t\t</tr>\n{if $tool_refresh_rate > 0}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t<input type=\"text\" name=\"counter\" value=\"\" readonly class=\"refresh_counter\">\n\t\t\t\t<script language=\"Javascript\" type=\"text/javascript\">\n\t\t\t\t\t<!--\n\t\t\t\t\tTimerDown({$tool_refresh_rate});\n\t\t\t\t\t-->\n\t\t\t\t</script>\n\t\t\t</td>\n\t\t</tr>\n{/if}\n\t\t</form>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Domains</th>\n\t\t</tr>\n{section name=domain loop=$tool_domain_list}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_domain_selected == $tool_domain_list[domain].domain_id}domainlistselected{else}domainlist{/if}\"><a href=\"tool_shop.php?domain={$tool_domain_list[domain].domain_id}\">{$tool_domain_list[domain].domain_name}</a></td>\n\t\t</tr>\n{/section}\n\t\t</table>\n\n{if $tool_domain_selected}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th colspan=\"10\">Shards</th>\n\t\t</tr>\n{section name=shard loop=$tool_shard_list}\n{if $tool_domain_selected == $tool_shard_list[shard].shard_domain_id}\n\t\t<tr>\n\t\t\t<td align=\"center\" class=\"{if $tool_shard_selected == $tool_shard_list[shard].shard_id}shardlistselected{else}shardlist{/if}\"><a href=\"tool_shop.php?domain={$tool_domain_selected}&shard={$tool_shard_list[shard].shard_id}\">{$tool_shard_list[shard].shard_name}</a></td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n{/if}\n\n\t</td>\n\n\t<td width=\"10px\">&nbsp;</td>\n\n\t<td align=\"right\" valign=\"top\">\n\n{if !$tool_domain_selected}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\">You need to select a domain.</td>\n\t\t</tr>\n\t\t</table>\n{elseif $tool_domain_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_domain_error}</span></td>\n\t\t</tr>\n\t\t</table>\n{else}\n{if $tool_as_error}\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">{$tool_as_error}</span></td>\n\t\t</tr>\n\t\t</table>\n\t\t<br>\n{/if}\n\n\n\t\t<form action=\"tool_shop.php\" method=\"post\" name=\"qlist\">\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox\" value=\"1\" onclick=\"CheckAll();\"></td>\n\t\t\t<td class=\"heads\">AliasName</td>\n\t\t\t<td class=\"heads\">Shard</td>\n\t\t\t<td class=\"heads\">ShortName</td>\n\t\t\t<td class=\"heads\">Hostname</td>\n\t\t\t<td class=\"heads\">Running State</td>\n\t\t\t<td class=\"heads\">Running Tags</td>\n\t\t\t<td class=\"heads\">State</td>\n\t\t\t<td class=\"heads\">Report</td>\n\t\t\t<td class=\"heads\">Counters</td>\n\t\t\t<td class=\"heads\">User SL</td>\n\t\t\t<td class=\"heads\">Tick SL</td>\n\t\t\t<td class=\"heads\">Memory</td>\n\t\t\t<td class=\"heads\">NbPlayers</td>\n\t\t\t<td class=\"heads\">UpTime</td>\n\t\t</tr>\n{assign var=\"egs_counter\" value=\"0\"}\n{section name=service loop=$tool_services_list}\n{assign var=\"service_shard_id\" value=$tool_services_list[service].ShardName}\n{if $tool_shard_filters.$service_shard_id || $tool_shard_filters._all_ || ($tool_shard_filters._unknown_ && !$tool_services_list[service].ShardName)}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n{assign var=\"tdclass1\" value=\"\"}\n{assign var=\"tdclass2\" value=\"\"}\n{if $tool_services_list[service]._flags_.rs_stopped}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_stopped\"}{/if}\n{if $tool_services_list[service]._flags_.rs_starting}{assign var=\"tdclass1\" value=\"class=\\\"cell_inactive1\\\"\"}{assign var=\"tdclass2\" value=\"class=\\\"cell_inactive2\\\"\"}{assign var=\"trclass\" value=\"row_starting\"}{/if}\n{if $tool_services_list[service]._flags_.alert_red}{assign var=\"trclass\" value=\"row_red\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_dark}{assign var=\"trclass\" value=\"row_orange_dark\"}{/if}\n{if $tool_services_list[service]._flags_.alert_orange_light}{assign var=\"trclass\" value=\"row_orange_light\"}{/if}\n{assign var=\"check_name\" value=$tool_services_list[service].AliasName}\n{assign var=\"egs_counter\" value=\"`$egs_counter+1`\"}\n<!-- {$egs_counter} -->\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"service_{$tool_services_list[service].AliasName}\" value=\"{$tool_services_list[service].AliasName}\" {if $tool_service_select_list.$check_name || (!$tool_service_select_list && $tool_services_list[service]._flags_.rs_online)}checked{/if}></td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].AliasName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{if $tool_services_list[service].ShardName != \"\"}{$tool_services_list[service].ShardName}{else}?{/if}{if $tool_services_list[service].ShardId != \"\"}/{$tool_services_list[service].ShardId}{/if}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].ShortName}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].Hostname}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningState}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass1}>{$tool_services_list[service].RunningTags}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].State}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NoReportSince}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].StartCounter}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UserSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].TickSpeedLoop}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].ProcessUsedMemory}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].NbPlayers}</td>\n\t\t\t<td onclick=\"CheckToggle(document.qlist.service_{$tool_services_list[service].AliasName})\" {$tdclass2}>{$tool_services_list[service].UpTime}</td>\n\t\t</tr>\n{/if}\n{/section}\n\t\t</table>\n\n\t\t<!-- ugly trick to block the first submit button being triggered when hitting ENTER to send the form -->\n\t\t<div style=\"display: none;\"><input type=\"submit\" name=\"fake\" value=\"fake\" onclick=\"alert('PLEASE DO NOT USE THE &lt;ENTER&gt; KEY !'); return false;\"></div>\n\t\t<!-- end ugly trick :) -->\n\n{if $egs_counter > 0}\n{if $restriction_tool_shop}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td align=\"right\" width=\"100px\"><b>Command : </b></td>\n\t\t\t<td>&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t物品ID：<input type=\"text\" name=\"tpl_item_template_id\" value=\"{$tool_template_id_value}\" size=\"10\">&nbsp;\n\t\t\t\t数量：<input type=\"text\" name=\"tpl_item_num\" value=\"{$tool_item_num_value}\" size=\"10\">&nbsp;\n\t\t\t\t价格：<input type=\"text\" name=\"tpl_item_price\" value=\"{$tool_item_price_value}\" size=\"10\">&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"添加物品\">&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"删除物品\">&nbsp;&nbsp;&nbsp;&nbsp;\n\t\t\t\t<input type=\"submit\" name=\"services_pl\" value=\"刷新物品列表\">&nbsp;\n\t\t\t</td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\n{if $tool_shop_list_data}\n{assign var=\"service_name\" value=\"\"}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n{section name=entity loop=$tool_shop_list_data}\n{if $service_name != $tool_shop_list_data[entity].service}\n{assign var=\"service_name\" value=$tool_shop_list_data[entity].service}\n\t\t<tr>\n\t\t\t<td class=\"heads\"><input class=\"check\" type=\"checkbox\" name=\"allbox_shoplist\" value=\"1\" onclick=\"CheckAllShopList();\"></td>\n\t\t\t<th>ShardID</th>\n\t\t\t<th>IDX</th>\n\t\t\t<th>模板ID</th>\n\t\t\t<th>物品名称</th>\n\t\t\t<th>数量</th>\n\t\t\t<th>价格</th>\n\t\t</tr>\n{/if}\n{cycle assign=\"trclass\" values=\"row0,row1\"}\n\t\t<tr class=\"{$trclass}\">\n\t\t\t<td><input class=\"check\" type=\"checkbox\" name=\"checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx}\" value=\"{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx}\"></td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].shardid}</td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].idx}</td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].tid}</td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].name}</td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].num}</td>\n\t\t\t<td align=\"center\" onclick=\"CheckToggle(document.qlist.checkshoplist_{$tool_shop_list_data[entity].shardid}_{$tool_shop_list_data[entity].idx})\">{$tool_shop_list_data[entity].price}</td>\n\t\t</tr>\n{/section}\n\t\t</table>\n{/if}\n\n{if $tool_execute_command}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<th>Command Results for '{$tool_execute_command}' :</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td><textarea width=\"100%\" rows=\"50\" class=\"command\" readonly >{section name=exe loop=$tool_execute_result}{$tool_execute_result[exe]}{/section}</textarea></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n{else}\n\t\t<br>\n\t\t<table width=\"100%\" border=\"0\" cellpadding=\"1\" bgcolor=\"#cccccc\" class=\"view\">\n\t\t<tr>\n\t\t\t<td class=\"row0\"><span class=\"alert\">No EGS to work with!</span></td>\n\t\t</tr>\n\t\t</table>\n{/if}\n\n\t\t<input type=\"hidden\" name=\"pl_su\" value=\"{$shard_su_name}\">\n\t\t<input type=\"hidden\" name=\"relocate_shardid\" value=\"na\">\n\t\t<input type=\"hidden\" name=\"relocate_eid\" value=\"na\">\n\t\t</form>\n\n{/if}\n\n\t</td>\n</tr>\n</table>\n\n\n{include file=\"page_footer.tpl\"}\n"
  },
  {
    "path": "tools/server/admin/templates/default_c/placeholder",
    "content": ""
  },
  {
    "path": "tools/server/admin/tool_actions.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_actions.php\\'');\n\n\tif (!tool_admin_applications_check('tool_actions'))\tnt_common_redirect('index.php');\n\n\t$tpl->assign('tool_title', \"Actions\");\n\n\n\t$tpl->display('tool_actions.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_administration.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_administration.php');\n\n\t//if (!tool_admin_applications_check('tool_admin')) nt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_administration.php\\'');\n\n\tif (!isset($NELTOOL['GET_VARS']['toolmode']))\t$NELTOOL['GET_VARS']['toolmode'] = 'help';\n\t$tool_menu_item = tool_admin_menu_get_item_from_key($NELTOOL['GET_VARS']['toolmode']);\n\n\t$IE_CHECK = strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE');\n\n\t$tpl->assign('tool_title',\t\t'Administration&nbsp;/&nbsp;'. $tool_menu_item['title']);\n\t$tpl->assign('tool_menu',\t\ttool_admin_menu_get_list($IE_CHECK)); //$tool_admin_menu); // defined in 'functions_tool_administration.php'\n\n\tswitch($NELTOOL['GET_VARS']['toolmode'])\n\t{\n\t\tcase 'help':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Help Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif ($IE_CHECK)\t$tpl->assign('ie_check', true);\n\t\t\telse\t\t\t$tpl->assign('ie_check', false);\n\n\t\t\tbreak;\n\n\t\tcase 'logs':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Logs Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_logs'))\tnt_common_redirect('index.php');\n\n\t\t\t$log_start\t= 0;\n\t\t\t$log_step \t= 30;\n\t\t\t$num_logs\t= tool_admin_logs_get_count();\n\n\t\t\tif (isset($_GET['page']))\t$log_start = $_GET['page'];\n\n\t\t\t$tool_log_list\t= tool_admin_logs_get_list($log_start * $log_step, $log_step);\n\n\t\t\t$log_page_first\t\t= 0;\n\t\t\t$log_page_last\t\t= ceil($num_logs / $log_step);\n\n\t\t\t$log_page_previous\t= $log_start - 1;\n\t\t\t$log_page_next\t\t= $log_start + 1;\n\n\t\t\tif ($log_page_previous < 0)\t\t\t\t$log_page_previous = 0;\n\t\t\tif ($log_page_next >= $log_page_last)\t$log_page_next = $log_page_last - 1;\n\n\t\t\t$tpl->assign('tool_log_page_first',\t\t$log_page_first);\n\t\t\t$tpl->assign('tool_log_page_last',\t\t$log_page_last - 1);\n\t\t\t$tpl->assign('tool_log_page_previous',\t$log_page_previous);\n\t\t\t$tpl->assign('tool_log_page_next',\t\t$log_page_next);\n\n\t\t\t$tpl->assign('tool_log_page_current',\t$log_start + 1);\n\t\t\t$tpl->assign('tool_log_page_total',\t\t$log_page_last);\n\t\t\t$tpl->assign('tool_log_list',\t\t\t$tool_log_list);\n\n\t\t\tbreak;\n\n\t\tcase 'users':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  User Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_user'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update applications':\n\n\t\t\t\t\tif ($tool_action == 'update applications')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_user_update_id\t\t\t= $_POST['tool_form_user_id'];\n\t\t\t\t\t\t$tool_user_update_appl_ids\t\t= $_POST['tool_form_application_ids'];\n\n\t\t\t\t\t\ttool_admin_users_applications_update($tool_user_update_id, $tool_user_update_appl_ids);\n\n\t\t\t\t\t\t$_GET['user_id'] = $tool_user_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t// break;\n\n\t\t\t\tcase 'update domains':\n\n\t\t\t\t\tif ($tool_action == 'update domains')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_user_update_id\t\t\t= $_POST['tool_form_user_id'];\n\t\t\t\t\t\t$tool_user_update_domain_ids\t= $_POST['tool_form_domain_ids'];\n\n\t\t\t\t\t\t$tool_user_data \t\t\t\t= tool_admin_users_get_id($tool_user_update_id);\n\t\t\t\t\t\t$tool_user_group_id\t\t\t\t= $tool_user_data['user_group_id'];\n\n\t\t\t\t\t\ttool_admin_users_domains_update($tool_user_update_id, $tool_user_group_id, $tool_user_update_domain_ids);\n\n\t\t\t\t\t\t$_GET['user_id']\t\t= $tool_user_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update shards':\n\n\t\t\t\t\tif ($tool_action == 'update shards')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_user_update_id\t\t\t= $_POST['tool_form_user_id'];\n\t\t\t\t\t\t$tool_user_update_shard_ids\t\t= $_POST['tool_form_shard_ids'];\n\n\t\t\t\t\t\t$tool_user_data \t\t\t\t= tool_admin_users_get_id($tool_user_update_id);\n\t\t\t\t\t\t$tool_user_group_id\t\t\t\t= $tool_user_data['user_group_id'];\n\n\t\t\t\t\t\ttool_admin_users_shards_update($tool_user_update_id, $tool_user_group_id, $tool_user_update_shard_ids);\n\n\t\t\t\t\t\t$_GET['user_id']\t\t= $tool_user_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing User\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif ($tool_action == 'update')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_user_update_id\t\t= $_POST['tool_form_user_id'];\n\t\t\t\t\t\t$tool_user_update_name\t\t= $_POST['tool_form_user_name'];\n\t\t\t\t\t\t$tool_user_update_password\t= $_POST['tool_form_user_password'];\n\t\t\t\t\t\t$tool_user_update_group\t\t= $_POST['tool_form_user_group'];\n\t\t\t\t\t\t$tool_user_update_active\t= $_POST['tool_form_user_active'];\n\n\t\t\t\t\t\t$tool_error = tool_admin_users_update($tool_user_update_id, $tool_user_update_name, $tool_user_update_password, $tool_user_update_group, $tool_user_update_active);\n\t\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$_GET['user_id'] = $tool_user_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing User\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_user_edit_id\t\t= $_GET['user_id'];\n\t\t\t\t\t$tool_user_edit_data \t= tool_admin_users_get_id($tool_user_edit_id);\n\t\t\t\t\t$tool_user_group_id\t\t= $tool_user_edit_data['user_group_id'];\n\n\t\t\t\t\t$tpl->assign('tool_user_edit_data',\t\t$tool_user_edit_data);\n\n\t\t\t\t\t$tool_domain_list\t\t= tool_admin_domains_get_list();\n\t\t\t\t\t$tool_user_domain_list\t= tool_admin_users_domains_get_list($tool_user_edit_id, true);\n\t\t\t\t\t$tool_group_domain_list\t= tool_admin_groups_domains_get_list($tool_user_group_id, true);\n\t\t\t\t\t$tool_domain_list\t\t= tool_admin_users_domains_merge($tool_domain_list, $tool_user_domain_list, $tool_group_domain_list);\n\n\t\t\t\t\t$tpl->assign('tool_domain_list',\t\t$tool_domain_list);\n\n\t\t\t\t\t$tool_shard_list\t\t= tool_admin_shards_get_list();\n\t\t\t\t\t$tool_user_shard_list\t= tool_admin_users_shards_get_list($tool_user_edit_id, true);\n\t\t\t\t\t$tool_group_shard_list\t= tool_admin_groups_shards_get_list($tool_user_group_id, true);\n\t\t\t\t\t$tool_shard_list\t\t= tool_admin_users_shards_merge($tool_domain_list, $tool_shard_list, $tool_user_shard_list, $tool_group_shard_list);\n\n\t\t\t\t\t$tpl->assign('tool_shard_list',\t\t\t$tool_shard_list);\n\n\t\t\t\t\t$tool_appl_list\t\t\t= tool_admin_applications_get_list();\n\t\t\t\t\t$tool_user_appl_list\t= tool_admin_users_applications_get_list($tool_user_edit_id, true);\n\t\t\t\t\t$tool_group_appl_list\t= tool_admin_groups_applications_get_list($tool_user_group_id, true);\n\t\t\t\t\t$tool_appl_list\t\t\t= tool_admin_users_applications_merge($tool_appl_list, $tool_user_appl_list, $tool_group_appl_list);\n\n\t\t\t\t\t$tpl->assign('tool_application_list',\t$tool_appl_list);\n\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing User\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_user_delete_id\t\t= $_POST['tool_form_user_id'];\n\t\t\t\t\tif (!($tool_user_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid user!\");\n\t\t\t\t\t}\n\t\t\t\t\telseif ($tool_user_delete_id == $nel_user['user_id'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: did you just try to delete yourself ?!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_users_del($tool_user_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new User\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_user_create_name\t\t= $_POST['tool_form_user_name'];\n\t\t\t\t\t$tool_user_create_password\t= $_POST['tool_form_user_password'];\n\t\t\t\t\t$tool_user_create_group\t\t= $_POST['tool_form_user_group'];\n\t\t\t\t\t$tool_user_create_active\t= $_POST['tool_form_user_active'];\n\n\t\t\t\t\t$tool_error = tool_admin_users_add($tool_user_create_name, $tool_user_create_password, $tool_user_create_group, $tool_user_create_active);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\t$tool_group_list\t= tool_admin_groups_get_list();\n\t\t\t$tool_user_list\t\t= tool_admin_users_get_list($tool_group_list);\n\n\t\t\t$tpl->assign('tool_user_list',\t$tool_user_list);\n\t\t\t$tpl->assign('tool_group_list',\t$tool_group_list);\n\n\t\t\tbreak;\n\n\t\tcase 'groups':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Group Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_group'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update applications':\n\n\t\t\t\t\tif ($tool_action == 'update applications')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_update_appl_ids\t\t= $_POST['tool_form_application_ids'];\n\n\t\t\t\t\t\ttool_admin_groups_applications_update($tool_group_update_id, $tool_group_update_appl_ids);\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t// break;\n\n\t\t\t\tcase 'update domains':\n\n\t\t\t\t\tif ($tool_action == 'update domains')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_update_domain_ids\t= $_POST['tool_form_domain_ids'];\n\n\t\t\t\t\t\ttool_admin_groups_domains_update($tool_group_update_id, $tool_group_update_domain_ids);\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update shards':\n\n\t\t\t\t\tif ($tool_action == 'update shards')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_update_shard_ids\t= $_POST['tool_form_shard_ids'];\n\n\t\t\t\t\t\ttool_admin_groups_shards_update($tool_group_update_id, $tool_group_update_shard_ids);\n\n\t\t\t\t\t\t$_GET['group_id']\t\t= $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif ($tool_action == 'update')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_update_name\t\t= $_POST['tool_form_group_name'];\n\t\t\t\t\t\t$tool_group_update_level\t= $_POST['tool_form_group_level'];\n\t\t\t\t\t\t$tool_group_update_default\t= $_POST['tool_form_group_default'];\n\t\t\t\t\t\t$tool_group_update_active\t= $_POST['tool_form_group_active'];\n\n\t\t\t\t\t\t$tool_error = tool_admin_groups_update($tool_group_update_id, $tool_group_update_name, $tool_group_update_level, $tool_group_update_default, $tool_group_update_active);\n\t\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update default domain':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update group default domain\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif ($tool_action == 'update default domain')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_default_domain\t= $_POST['tool_form_domain_default'];\n\n\t\t\t\t\t\t$tool_error = tool_admin_groups_update_default_domain($tool_group_update_id, $tool_group_default_domain);\n\t\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update default shard':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update group default shard\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif ($tool_action == 'update default shard')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_default_shard\t= $_POST['tool_form_shard_default'];\n\n\t\t\t\t\t\t$tool_error = tool_admin_groups_update_default_shard($tool_group_update_id, $tool_group_default_shard);\n\t\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update default application':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update group default application\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif ($tool_action == 'update default application')\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_group_update_id\t\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\t\t$tool_group_default_application\t= $_POST['tool_form_application_default'];\n\n\t\t\t\t\t\t$tool_error = tool_admin_groups_update_default_application($tool_group_update_id, $tool_group_default_application);\n\t\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$_GET['group_id'] = $tool_group_update_id;\n\t\t\t\t\t}\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_group_edit_id\t\t= $_GET['group_id'];\n\t\t\t\t\t$tool_group_edit_data \t= tool_admin_groups_get_id($tool_group_edit_id);\n\t\t\t\t\t$tpl->assign('tool_group_edit_data',\t$tool_group_edit_data);\n\n\t\t\t\t\t$tool_domain_list\t\t= tool_admin_domains_get_list();\n\t\t\t\t\t$tool_group_domain_list\t= tool_admin_groups_domains_get_list($tool_group_edit_id, true);\n\t\t\t\t\t$tool_domain_list\t\t= tool_admin_groups_domains_merge($tool_domain_list, $tool_group_domain_list);\n\n\t\t\t\t\t$tpl->assign('tool_domain_list',\t\t$tool_domain_list);\n\n\t\t\t\t\t$tool_shard_list\t\t= tool_admin_shards_get_list();\n\t\t\t\t\t$tool_group_shard_list\t= tool_admin_groups_shards_get_list($tool_group_edit_id, true);\n\t\t\t\t\t$tool_shard_list\t\t= tool_admin_groups_shards_merge($tool_domain_list, $tool_shard_list, $tool_group_shard_list);\n\n\t\t\t\t\t$tpl->assign('tool_shard_list',\t\t\t$tool_shard_list);\n\n\t\t\t\t\t$tool_appl_list\t\t\t= tool_admin_applications_get_list();\n\t\t\t\t\t$tool_group_appl_list\t= tool_admin_groups_applications_get_list($tool_group_edit_id, true);\n\t\t\t\t\t$tool_appl_list\t\t\t= tool_admin_groups_applications_merge($tool_appl_list, $tool_group_appl_list);\n\n\t\t\t\t\t$tpl->assign('tool_application_list',\t$tool_appl_list);\n\n\t\t\t\t\t$tool_group_user_list\t= tool_admin_groups_get_user_list($tool_group_edit_id);\n\n\t\t\t\t\t$tpl->assign('tool_group_user_list',\t$tool_group_user_list);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_group_delete_id\t\t= $_POST['tool_form_group_id'];\n\t\t\t\t\tif (!($tool_group_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid group!\");\n\t\t\t\t\t}\n\t\t\t\t\telseif ($tool_group_delete_id == $nel_user['user_group_id'])\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: did you just try to delete your own group ?!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_groups_del($tool_group_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_group_create_name\t\t= $_POST['tool_form_group_name'];\n\t\t\t\t\t$tool_group_create_level\t= $_POST['tool_form_group_level'];\n\t\t\t\t\t$tool_group_create_default\t= $_POST['tool_form_group_default'];\n\t\t\t\t\t$tool_group_create_active\t= $_POST['tool_form_group_active'];\n\n\t\t\t\t\t$tool_error = tool_admin_groups_add($tool_group_create_name, $tool_group_create_level, $tool_group_create_default, $tool_group_create_active);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tool_group_list\t= tool_admin_groups_get_list();\n\t\t\t$tpl->assign('tool_group_list',\t$tool_group_list);\n\t\t\t$tpl->assign('tool_group_level_list',\t$nel_user_group_levels);\n\n\t\t\tbreak;\n\n\t\tcase 'applications':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Application Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_application'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_application_update_id\t\t\t\t= $_POST['tool_form_application_id'];\n\t\t\t\t\t$tool_application_update_name\t\t\t= $_POST['tool_form_application_name'];\n\t\t\t\t\t$tool_application_update_uri\t\t\t= $_POST['tool_form_application_uri'];\n\t\t\t\t\t$tool_application_update_restriction\t= $_POST['tool_form_application_restriction'];\n\t\t\t\t\t$tool_application_update_icon\t\t\t= $_POST['tool_form_application_icon'];\n\t\t\t\t\t$tool_application_update_order\t\t\t= $_POST['tool_form_application_order'];\n\t\t\t\t\t$tool_application_update_visible\t\t= $_POST['tool_form_application_visible'];\n\n\t\t\t\t\t$tool_error = tool_admin_applications_update($tool_application_update_id, $tool_application_update_name, $tool_application_update_uri, $tool_application_update_restriction, $tool_application_update_icon, $tool_application_update_order, $tool_application_update_visible);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\t$_GET['application_id'] = $tool_application_update_id;\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_application_edit_id\t\t= $_GET['application_id'];\n\t\t\t\t\t$tool_application_edit_data \t= tool_admin_applications_get_id($tool_application_edit_id);\n\t\t\t\t\t$tpl->assign('tool_application_edit_data',\t$tool_application_edit_data);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_application_delete_id\t\t= $_POST['tool_form_application_id'];\n\t\t\t\t\tif (!($tool_application_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid application!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_applications_del($tool_application_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_application_create_name\t\t\t= $_POST['tool_form_application_name'];\n\t\t\t\t\t$tool_application_create_uri\t\t\t= $_POST['tool_form_application_uri'];\n\t\t\t\t\t$tool_application_create_restriction\t= $_POST['tool_form_application_restriction'];\n\t\t\t\t\t$tool_application_create_icon\t\t\t= $_POST['tool_form_application_icon'];\n\t\t\t\t\t$tool_application_create_order\t\t\t= $_POST['tool_form_application_order'];\n\t\t\t\t\t$tool_application_create_visible\t\t= $_POST['tool_form_application_visible'];\n\n\t\t\t\t\t$tool_error = tool_admin_applications_add($tool_application_create_name, $tool_application_create_uri, $tool_application_create_restriction, $tool_application_create_icon, $tool_application_create_order, $tool_application_create_visible);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tool_application_list\t= tool_admin_applications_get_list();\n\t\t\t$tpl->assign('tool_application_list',\t$tool_application_list);\n\n\t\t\tbreak;\n\n\t\tcase 'domains':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Domain Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_domain'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Domain\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_domain_update_id\t\t\t\t= $_POST['tool_form_domain_id'];\n\t\t\t\t\t$tool_domain_update_name\t\t\t= $_POST['tool_form_domain_name'];\n\t\t\t\t\t$tool_domain_update_application\t\t= $_POST['tool_form_domain_application'];\n\t\t\t\t\t$tool_domain_update_as_host\t\t\t= $_POST['tool_form_domain_as_host'];\n\t\t\t\t\t$tool_domain_update_as_port\t\t\t= $_POST['tool_form_domain_as_port'];\n\t\t\t\t\t$tool_domain_update_mfs_web\t\t\t= $_POST['tool_form_domain_mfs_web'];\n\t\t\t\t\t$tool_domain_update_rrd_path\t\t= $_POST['tool_form_domain_rrd_path'];\n\t\t\t\t\t$tool_domain_update_las_admin_path\t= $_POST['tool_form_domain_las_admin_path'];\n\t\t\t\t\t$tool_domain_update_las_local_path\t= $_POST['tool_form_domain_las_local_path'];\n\t\t\t\t\t$tool_domain_update_sql_string\t\t= $_POST['tool_form_domain_sql_string'];\n\t\t\t\t\t$tool_domain_update_cs_sql_string\t= $_POST['tool_form_domain_cs_sql_string'];\n\t\t\t\t\t$tool_domain_update_hd_check\t\t= $_POST['tool_form_domain_hd_check'];\n\n\t\t\t\t\t$tool_error = tool_admin_domains_update($tool_domain_update_id, $tool_domain_update_name, $tool_domain_update_application,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_update_as_host, $tool_domain_update_as_port, $tool_domain_update_rrd_path,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_update_las_admin_path, $tool_domain_update_las_local_path,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_update_sql_string, $tool_domain_update_cs_sql_string,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_update_hd_check, $tool_domain_update_mfs_web);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\t$_GET['domain_id'] = $tool_domain_update_id;\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'update_nel':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Domain (in the nel.domain table)\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\tif (isset($_POST['tool_form_domain_nel_id']))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_domain_nel_update_id\t\t= $_POST['tool_form_domain_nel_id'];\n\t\t\t\t\t\t$tool_domain_nel_update_name\t= $_POST['tool_form_domain_nel_name'];\n\t\t\t\t\t\t$tool_domain_nel_update_status\t= $_POST['tool_form_domain_nel_status'];\n\t\t\t\t\t\t//$tool_domain_nel_update_version\t= $_POST['tool_form_domain_nel_version'];\n\n\t\t\t\t\t\t//tool_admin_domains_update_nel($tool_domain_nel_update_id, $tool_domain_nel_update_name, $tool_domain_nel_update_version, $tool_domain_nel_update_status);\n\t\t\t\t\t\ttool_admin_domains_update_nel($tool_domain_nel_update_id, $tool_domain_nel_update_name, $tool_domain_nel_update_status);\n\n\t\t\t\t\t\t$_GET['domain_id'] = $_POST['tool_form_domain_id'];\n\t\t\t\t\t}\n\n\t\t\t\t\t// break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Domain\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_domain_edit_id\t= $_GET['domain_id'];\n\t\t\t\t\t$tool_domain_edit_data \t= tool_admin_domains_get_id($tool_domain_edit_id);\n\t\t\t\t\t$tpl->assign('tool_domain_edit_data',\t$tool_domain_edit_data);\n\n\t\t\t\t\tif ($tool_domain_edit_data['domain_application'] != '')\n\t\t\t\t\t{\n\t\t\t\t\t\t$domain_nel_status = array('ds_close','ds_dev','ds_restricted','ds_open');\n\t\t\t\t\t\t$tpl->assign('tool_domain_nel_status',\t$domain_nel_status);\n\n\t\t\t\t\t\t$tool_domain_nel_data\t= tool_admin_domains_get_nel($tool_domain_edit_data['domain_application']);\n\t\t\t\t\t\t$tpl->assign('tool_domain_nel_data',\t$tool_domain_nel_data);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Domain\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_domain_delete_id\t= $_POST['tool_form_domain_id'];\n\t\t\t\t\tif (!($tool_domain_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid domain!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_domains_del($tool_domain_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Domain\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_domain_create_name\t\t\t= $_POST['tool_form_domain_name'];\n\t\t\t\t\t$tool_domain_create_application\t\t= $_POST['tool_form_domain_application'];\n\t\t\t\t\t$tool_domain_create_as_host\t\t\t= $_POST['tool_form_domain_as_host'];\n\t\t\t\t\t$tool_domain_create_as_port\t\t\t= $_POST['tool_form_domain_as_port'];\n\t\t\t\t\t$tool_domain_create_mfs_web\t\t\t= $_POST['tool_form_domain_mfs_web'];\n\t\t\t\t\t$tool_domain_create_rrd_path\t\t= $_POST['tool_form_domain_rrd_path'];\n\t\t\t\t\t$tool_domain_create_las_admin_path\t= $_POST['tool_form_domain_las_admin_path'];\n\t\t\t\t\t$tool_domain_create_las_local_path\t= $_POST['tool_form_domain_las_local_path'];\n\t\t\t\t\t$tool_domain_create_sql_string\t\t= $_POST['tool_form_domain_sql_string'];\n\t\t\t\t\t$tool_domain_create_cs_sql_string\t= $_POST['tool_form_domain_cs_sql_string'];\n\t\t\t\t\t$tool_domain_create_hd_check\t\t= $_POST['tool_form_domain_hd_check'];\n\n\t\t\t\t\t$tool_error = tool_admin_domains_add(\t$tool_domain_create_name, $tool_domain_create_application, $tool_domain_create_as_host,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_create_as_port, $tool_domain_create_rrd_path,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_create_las_admin_path, $tool_domain_create_las_local_path,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_create_sql_string, $tool_domain_create_cs_sql_string,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$tool_domain_create_hd_check, $tool_domain_create_mfs_web);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tool_domain_list\t= tool_admin_domains_get_list();\n\t\t\t$tpl->assign('tool_domain_list',\t$tool_domain_list);\n\n\t\t\tbreak;\n\n\t\tcase 'shards':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Shard Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_shard'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Shard\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_shard_update_id\t\t\t= $_POST['tool_form_shard_id'];\n\t\t\t\t\t$tool_shard_update_name\t\t\t= $_POST['tool_form_shard_name'];\n\t\t\t\t\t$tool_shard_update_as_id\t\t= $_POST['tool_form_shard_as_id'];\n\t\t\t\t\t$tool_shard_update_domain_id\t= $_POST['tool_form_shard_domain_id'];\n\t\t\t\t\t$tool_shard_update_language\t\t= $_POST['tool_form_shard_language'];\n\n\t\t\t\t\t$tool_error = tool_admin_shards_update($tool_shard_update_id, $tool_shard_update_name, $tool_shard_update_as_id, $tool_shard_update_domain_id, $tool_shard_update_language);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\t$_GET['shard_id'] = $tool_shard_update_id;\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Shard\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_shard_edit_id\t\t= $_GET['shard_id'];\n\t\t\t\t\t$tool_shard_edit_data \t= tool_admin_shards_get_id($tool_shard_edit_id);\n\t\t\t\t\t$tpl->assign('tool_shard_edit_data',\t$tool_shard_edit_data);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Shard\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_shard_delete_id\t= $_POST['tool_form_shard_id'];\n\t\t\t\t\tif (!($tool_shard_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid shard!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_shards_del($tool_shard_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Shard\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_shard_create_name\t\t\t= $_POST['tool_form_shard_name'];\n\t\t\t\t\t$tool_shard_create_as_id\t\t= $_POST['tool_form_shard_as_id'];\n\t\t\t\t\t$tool_shard_create_domain_id\t= $_POST['tool_form_shard_domain_id'];\n\t\t\t\t\t$tool_shard_create_language\t\t= $_POST['tool_form_shard_language'];\n\n\t\t\t\t\t$tool_error = tool_admin_shards_add($tool_shard_create_name, $tool_shard_create_as_id, $tool_shard_create_domain_id, $tool_shard_create_language);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tool_shard_list\t= tool_admin_shards_get_list();\n\t\t\t$tool_domain_list\t= tool_admin_domains_get_list();\n\n\t\t\t$tpl->assign('tool_shard_list',\t\t$tool_shard_list);\n\t\t\t$tpl->assign('tool_domain_list',\t$tool_domain_list);\n\t\t\t$tpl->assign('tool_language_list',\t$tool_language_list);\n\n\n\t\t\tbreak;\n\n\t\tcase 'restarts':\n\t\t\t/*\n\t\t\t * ###################################################################################################\n\t\t\t *  Restart Admin\n\t\t\t * ###################################################################################################\n\t\t\t */\n\n\t\t\tif (!tool_admin_applications_check('tool_admin_restart'))\tnt_common_redirect('index.php');\n\n\t\t\t$tool_action = null;\n\t\t\tif (isset($_POST['toolaction']))\t\t$tool_action = $_POST['toolaction'];\n\t\t\telseif (isset($_GET['toolaction']))\t$tool_action = $_GET['toolaction'];\n\n\t\t\tswitch ($tool_action)\n\t\t\t{\n\t\t\t\tcase 'update':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Restart Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_restart_update_id\t\t\t= $_POST['tool_form_restart_id'];\n\t\t\t\t\t$tool_restart_update_name\t\t= $_POST['tool_form_restart_name'];\n\t\t\t\t\t$tool_restart_update_services\t= $_POST['tool_form_restart_services'];\n\t\t\t\t\t$tool_restart_update_order\t\t= $_POST['tool_form_restart_order'];\n\n\t\t\t\t\t$tool_error = tool_admin_restarts_update($tool_restart_update_id, $tool_restart_update_name, $tool_restart_update_services, $tool_restart_update_order);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\t$_GET['restart_id'] = $tool_restart_update_id;\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'edit':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Restart Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_restart_edit_id\t\t= $_GET['restart_id'];\n\t\t\t\t\t$tool_restart_edit_data \t= tool_admin_restarts_get_id($tool_restart_edit_id);\n\t\t\t\t\t$tpl->assign('tool_restart_edit_data',\t$tool_restart_edit_data);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Restart Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_restart_delete_id\t= $_POST['tool_form_restart_id'];\n\t\t\t\t\tif (!($tool_restart_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid restart group!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_restarts_del($tool_restart_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'create':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Restart Group\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_restart_create_name\t\t= $_POST['tool_form_restart_name'];\n\t\t\t\t\t$tool_restart_create_services\t= $_POST['tool_form_restart_services'];\n\t\t\t\t\t$tool_restart_create_order\t\t= $_POST['tool_form_restart_order'];\n\n\t\t\t\t\t$tool_error = tool_admin_restarts_add($tool_restart_create_name, $tool_restart_create_services, $tool_restart_create_order);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'update message':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Update an existing Restart Message\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_message_update_id\t\t\t= $_POST['tool_form_message_id'];\n\t\t\t\t\t$tool_message_update_name\t\t= $_POST['tool_form_message_name'];\n\t\t\t\t\t$tool_message_update_value\t\t= $_POST['tool_form_message_value'];\n\t\t\t\t\t$tool_message_update_lang\t\t= $_POST['tool_form_message_lang'];\n\n\t\t\t\t\t$tool_error = tool_admin_restart_messages_update($tool_message_update_id, $tool_message_update_name, $tool_message_update_value, $tool_message_update_lang);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\t$_GET['msg_id'] = $tool_message_update_id;\n\n\t\t\t\t\t//break;\n\n\t\t\t\tcase 'editmsg':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Edit an existing Restart Message\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_message_edit_id\t\t= $_GET['msg_id'];\n\t\t\t\t\t$tool_message_edit_data \t= tool_admin_restart_messages_get_id($tool_message_edit_id);\n\t\t\t\t\t$tpl->assign('tool_message_edit_data',\t$tool_message_edit_data);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'delete message':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Delete an existing Restart Message\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_message_delete_id\t= $_POST['tool_form_message_id'];\n\t\t\t\t\tif (!($tool_message_delete_id > 0))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t\"/!\\ Error: invalid restart message!\");\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\ttool_admin_restart_messages_del($tool_message_delete_id);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\n\t\t\t\tcase 'create message':\n\t\t\t\t\t/*\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t *  Create a new Restart Message\n\t\t\t\t\t * -------------------------------------------------------------------------------------------\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_message_create_name\t\t= $_POST['tool_form_message_name'];\n\t\t\t\t\t$tool_message_create_value\t\t= $_POST['tool_form_message_value'];\n\t\t\t\t\t$tool_message_create_lang\t\t= $_POST['tool_form_message_lang'];\n\n\t\t\t\t\t$tool_error = tool_admin_restart_messages_add($tool_message_create_name, $tool_message_create_value, $tool_message_create_lang);\n\t\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tpl->assign('tool_language_list',\t\t$tool_language_list);\n\n\t\t\t$tool_restart_list\t= tool_admin_restarts_get_list();\n\t\t\t$tpl->assign('tool_restart_list',\t\t$tool_restart_list);\n\n\t\t\t$tool_message_list\t= tool_admin_restart_messages_get_list();\n\t\t\t$tpl->assign('tool_message_list',\t\t$tool_message_list);\n\n\t\t\tbreak;\n\n\t}\n\n\t$tpl->display($tool_menu_item['tpl']);\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_event_entities.php",
    "content": "<?php\n\n\n// SoniX: yop\n// SoniX: pour rcup les info de view, il faut utiliser la commande getView\n// SoniX: par ex, sur un AIS :  \"getView (0x0000000001:15:83:83).NamedEntityState\" rcupre le state de l'entit specifier\n// SoniX: \"getView *.NamedEntityName\" rcupre toutes les entit nomm de l'IA sur laquelle tu balance la commande\n// SoniX: et pour setter une valuer :\n// SoniX: \"getView (0x0000000001:15:83:83).NamedEntityState=1\" met le truc  1\n// SoniX: En gros, tu rcupres les info dans la table variables, et tu vire les 3 premier morceaux (par ex, *.*.AIS.*.NamedEntityName deviens *.NamedEntityName).\n// SoniX: Par contre, c'est a toi de faire le dispatch sur chaque AIS si besoin.\n// YoGiN: hum, fun fun fun :D\n// YoGiN: oki merci beaucoup, je vais voir ca :)\n// SoniX: j'ai tester sur linuxshard8, d'jon mark a ractiv un morceau d'poside 2 dessus avec 1 variable\n// YoGiN: d'accord\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_event_entities.php');\n\n\tif (!tool_admin_applications_check('tool_event_entities'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_event_entities.php\\'');\n\n\t$tpl->assign('tool_title', \"Event Entities\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['refdata']))\n\t{\n\t\t$tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata']));\n\t\tif (is_array($tmp_data))\n\t\t{\n\t\t\t$NELTOOL['POST_VARS'] = $tmp_data;\n\t\t}\n\t}\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\t//if (tool_admin_applications_check('tool_player_locator_display_players'))\t\t$tpl->assign('restriction_tool_player_locator_display_players',\ttrue);\n\t//if (tool_admin_applications_check('tool_player_locator_locate'))\t\t\t\t$tpl->assign('restriction_tool_player_locator_locate',\t\t\ttrue);\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name = tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host = tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port = tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t= tool_main_get_shard_name($view_shard_id);\n\n\t\t$tpl->assign('tool_page_title', 'Event Entities - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t$tool_as_error = null;\n\n\t\tif ($AS_Host && $AS_Port)\n\t\t{\n\t\t\t$adminService = new MyAdminService;\n\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t{\n\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$tool_services_ee = null;\n\t\t\t\tif\t\t(isset($NELTOOL['POST_VARS']['services_ee']))\t$tool_services_ee = $NELTOOL['POST_VARS']['services_ee'];\n\t\t\t\telseif\t(isset($NELTOOL['GET_VARS']['services_ee']))\t$tool_services_ee = $NELTOOL['GET_VARS']['services_ee'];\n\n\t\t\t\tif ($tool_services_ee)\n\t\t\t\t{\n\t\t\t\t\t$tpl->assign('tool_post_data',\tbase64_encode(serialize($NELTOOL['POST_VARS'])));\n\n\t\t\t\t\tswitch ($tool_services_ee)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'update entities':\n\n\t\t\t\t\t\t\t$requested_service_list\t= $NELTOOL['POST_VARS']['requested_service_list'];\n\t\t\t\t\t\t\t$service_list = unserialize(base64_decode($requested_service_list));\n\n\t\t\t\t\t\t\t//nt_common_add_debug($NELTOOL['POST_VARS']);\n\t\t\t\t\t\t\t$update_entities = tool_ee_get_entities($NELTOOL['POST_VARS']);\n\t\t\t\t\t\t\tnt_common_add_debug('update_entities');\n\t\t\t\t\t\t\tnt_common_add_debug($update_entities);\n\n\t\t\t\t\t\t\treset($update_entities);\n\t\t\t\t\t\t\tforeach($update_entities as $entity_data)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = '';\n\t\t\t\t\t\t\t\t$_commands = array();\n\n\t\t\t\t\t\t\t\tif ($entity_data['entity_state']\t!= $entity_data['source_entity_state'])\t\t$_commands[] = 'NamedEntityState='. $entity_data['entity_state'];\n\t\t\t\t\t\t\t\tif ($entity_data['entity_param1']\t!= $entity_data['source_entity_param1'])\t$_commands[] = 'NamedEntityParam1='. $entity_data['entity_param1'];\n\t\t\t\t\t\t\t\tif ($entity_data['entity_param2']\t!= $entity_data['source_entity_param2'])\t$_commands[] = 'NamedEntityParam2='. $entity_data['entity_param2'];\n\n\t\t\t\t\t\t\t\tif (sizeof($_commands) > 0)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"something has been updated in entity : \". $entity_data['source_entity']);\n\t\t\t\t\t\t\t\t\tif (sizeof($_commands) == 1)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$service_command = 'getView '. $entity_data['source_entity'] .'.'. $_commands[0];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$service_command = 'getView '. $entity_data['source_entity'] .'.['. implode(',', $_commands) .']';\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$service = strtolower($entity_data['source_service']);\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t//$requested_service\t\t= $NELTOOL['POST_VARS']['source_service'];\n\t\t\t\t\t\t\t//$requested_entity\t\t\t= $NELTOOL['POST_VARS']['source_entity'];\n\t\t\t\t\t\t\t//$requested_entity_name\t= $NELTOOL['POST_VARS']['source_entity_name'];\n                            //\n\t\t\t\t\t\t\t//$new_entity_state \t= $NELTOOL['POST_VARS']['entity_state'];\n\t\t\t\t\t\t\t//$new_entity_param1\t= $NELTOOL['POST_VARS']['entity_param1'];\n\t\t\t\t\t\t\t//$new_entity_param2\t= $NELTOOL['POST_VARS']['entity_param2'];\n                            //\n\t\t\t\t\t\t\t//$old_entity_state\t= $NELTOOL['POST_VARS']['source_entity_state'];\n\t\t\t\t\t\t\t//$old_entity_param1\t= $NELTOOL['POST_VARS']['source_entity_param1'];\n\t\t\t\t\t\t\t//$old_entity_param2\t= $NELTOOL['POST_VARS']['source_entity_param2'];\n                            //\n\t\t\t\t\t\t\t//$service_command = '';\n                            //\n\t\t\t\t\t\t\t//$_commands = array();\n                            //\n\t\t\t\t\t\t\t//if ($new_entity_state\t\t!= $old_entity_state)\t$_commands[] = 'NamedEntityState='. $new_entity_state;\n\t\t\t\t\t\t\t//if ($new_entity_param1\t!= $old_entity_param1)\t$_commands[] = 'NamedEntityParam1='. $new_entity_param1;\n\t\t\t\t\t\t\t//if ($new_entity_param2\t!= $old_entity_param2)\t$_commands[] = 'NamedEntityParam2='. $new_entity_param2;\n                            //\n\t\t\t\t\t\t\t//if (sizeof($_commands) > 0)\n\t\t\t\t\t\t\t//{\n\t\t\t\t\t\t\t//\tnt_common_add_debug(\"something has been updated in entity : \". $requested_entity);\n\t\t\t\t\t\t\t//\tif (sizeof($_commands) == 1)\n\t\t\t\t\t\t\t//\t{\n\t\t\t\t\t\t\t//\t\t$service_command = 'getView '. $requested_entity .'.'. $_commands[0];\n\t\t\t\t\t\t\t//\t}\n\t\t\t\t\t\t\t//\telse\n\t\t\t\t\t\t\t//\t{\n\t\t\t\t\t\t\t//\t\t$service_command = 'getView '. $requested_entity .'.['. implode(',', $_commands) .']';\n\t\t\t\t\t\t\t//\t}\n                            //\n\t\t\t\t\t\t\t//\t$service = strtolower($requested_service);\n                            //\n\t\t\t\t\t\t\t//\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n                            //\n\t\t\t\t\t\t\t//\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t//\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t//\t{\n\t\t\t\t\t\t\t//\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t//\t}\n                            //\n\t\t\t\t\t\t\t//}\n\n\t\t\t\t\t\t\t//break;\n\n\t\t\t\t\t\tcase 'display entities':\n\n\t\t\t\t\t\t\tif (!isset($service_list)) $service_list = tool_main_get_checked_services();\n\n\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = 'getView *.[NamedEntityName,NamedEntityState,NamedEntityParam1,NamedEntityParam2]';\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t//nt_common_add_debug(\"about to run 'displayPlayers' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$entity_data = tool_ee_parse_getview($command_return_data);\n\t\t\t\t\t\t\t\t\tnt_common_add_debug($entity_data);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_entity_data',\t$entity_data);\n\t\t\t\t\t\t\t\t\t$tpl->assign('requested_service_list',\tbase64_encode(serialize($service_list)));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$status = $adminService->getStates();\n\t\t\t\tnt_common_add_debug($status);\n\n\t\t\t\t$domainServices\t\t= tool_main_parse_status($status);\n\n\t\t\t\t$filteredServices\t= array();\n\t\t\t\treset($domainServices);\n\t\t\t\tforeach($domainServices as $aKey => $aService)\n\t\t\t\t{\n\t\t\t\t\t// we are only interested in EGS\n\t\t\t\t\tif ($aService['ShortName'] == 'AIS')\n\t\t\t\t\t{\n\t\t\t\t\t\t$filteredServices[] = $aService;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$tpl->assign('tool_services_list',\t$filteredServices);\n\t\t\t}\n\t\t}\n\t}\n\n\t$tpl->display('tool_event_entities.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_graphs.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_graphs.php');\n\n\trequire_once(\"jpgraph/jpgraph.php\");\n\trequire_once(\"jpgraph/jpgraph_line.php\");\n\trequire_once(\"jpgraph/jpgraph_log.php\");\n\n\n\tif (!tool_admin_applications_check('tool_graph'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_graphs.php\\'');\n\n\tif (!isset($NELTOOL['GET_VARS']['toolmode']))\n\t{\n\t\t$NELTOOL['GET_VARS']['toolmode'] = 'ccu';\n\t\tnt_auth_unset_session_var('view_shard_id');\n\t\tnt_auth_unset_session_var('view_time_highframe');\n\t\tnt_auth_unset_session_var('view_time_lowframe');\n\t}\n\n\t$tool_menu_item = tool_graphs_menu_get_item_from_key($NELTOOL['GET_VARS']['toolmode']);\n\t$tpl->assign('toolmode',\t$NELTOOL['GET_VARS']['toolmode']);\n\n\t$tpl->assign('tool_title',\t'Graphs&nbsp;/&nbsp;'. $tool_menu_item['title']);\n\t$tpl->assign('tool_menu',\ttool_graphs_menu_get_list());\n\n\t$view_domain_id \t\t= nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t\t\t= nt_auth_get_session_var('view_shard_id');\n\t$view_time_highframe\t= nt_auth_get_session_var('view_time_highframe');\n\t$view_time_lowframe\t\t= nt_auth_get_session_var('view_time_lowframe');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['highframe']))\n\t{\n\t\t$view_time_highframe = $NELTOOL['GET_VARS']['highframe'];\n\t\tnt_auth_set_session_var('view_time_highframe', $view_time_highframe);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['lowframe']))\n\t{\n\t\t$view_time_lowframe = $NELTOOL['GET_VARS']['lowframe'];\n\t\tnt_auth_set_session_var('view_time_lowframe', $view_time_lowframe);\n\t}\n\n\tif ($view_time_highframe == null)\n\t{\n\t\t$view_time_highframe = tool_graphs_time_frame_get_default($tool_hires_frames);\n\t}\n\n\tif ($view_time_lowframe == null)\n\t{\n\t\t$view_time_lowframe = tool_graphs_time_frame_get_default($tool_lowres_frames);\n\t}\n\n\n\t$current_refresh_rate = nt_auth_get_session_var('current_refresh_rate');\n\tif (isset($_POST['services_refresh']))\n\t{\n\t\tif ($current_refresh_rate != $_POST['services_refresh'])\n\t\t{\n\t\t\t$current_refresh_rate = $_POST['services_refresh'];\n\t\t\tnt_auth_set_session_var('current_refresh_rate',$current_refresh_rate);\n\t\t}\n\t}\n\n\tif ($current_refresh_rate == null)\n\t{\n\t\t$current_refresh_rate = 0;\n\t}\n\telseif ($current_refresh_rate > 0)\n\t{\n\t\t$tpl->assign('nel_tool_refresh',\t'<meta http-equiv=refresh content=\"'. $current_refresh_rate .'\">');\n\t}\n\n\t$tpl->assign('tool_refresh_list',\t\t$refresh_rates);\n\t$tpl->assign('tool_refresh_rate',\t\t$current_refresh_rate);\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name = tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host = tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port = tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t\t= tool_main_get_shard_name($view_shard_id);\n\t\t$AS_InternalName\t= tool_main_get_shard_as_id($view_shard_id);\n\t\t$AS_RRDPath\t\t\t= tool_main_get_domain_rrd_path($view_domain_id);\n\n\n\t\tif ($AS_RRDPath != \"\")\n\t\t{\n\t\t\t// lets make sure there is a trailing /\n\t\t\tif (substr($AS_RRDPath, -1) != '/') $AS_RRDPath .= '/';\n\n\t\t\t$tpl->assign('tool_page_title', 'Graphs - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t\tswitch($NELTOOL['GET_VARS']['toolmode'])\n\t\t\t{\n\t\t\t\tcase 'ccu':\n\t\t\t\t\t/*\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t *  CCU Pages\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t */\n\n\t\t\t\t\t$tpl->assign('tool_frame_list',\t\t$tool_lowres_frames);\n\t\t\t\t\t$tpl->assign('tool_frame_selected',\t$view_time_lowframe);\n\n\t\t\t\t\tif ($view_time_lowframe)\n\t\t\t\t\t{\n\t\t\t\t\t\t$graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), false, true);\n\t\t\t\t\t\t$tool_tech_graph_list = array(\tarray('service'\t=>\t'fes', \t'variable'\t=>\t'FPSProcessMsg'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t );\n\n\t\t\t\t\t\t$graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']);\n\t\t\t\t\t\tnt_common_add_debug($graph_list);\n\t\t\t\t\t\t$rrd_webs\t= array();\n\t\t\t\t\t\treset($graph_list);\n\n\t\t\t\t\t\tforeach($graph_list as $graph_item)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$rrd_path\t= $AS_RRDPath . $graph_item['rd_file'];\n\t\t\t\t\t\t\t$rrd_def\t= \"DEF:val=\". $rrd_path .\":var:AVERAGE\";\n\t\t\t\t\t\t\t$rrd_draw\t= \"LINE2:val#0000FF --no-legend\";\n\t\t\t\t\t\t\t$rrd_output\t= NELTOOL_RRDSYSBASE . $graph_item['rd_file'] .\"-\". $view_time_lowframe .\".gif\";\n\t\t\t\t\t\t\t$rrd_web\t= NELTOOL_RRDWEBBASE . $graph_item['rd_file'] .\"-\". $view_time_lowframe .\".gif\";\n\t\t\t\t\t\t\t$rrd_exec\t= NELTOOL_RRDTOOL .\" graph \". $rrd_output .\" --width 916 --height 110 --start -\". $view_time_lowframe .\" \". $rrd_def .\" \". $rrd_draw;\n\n\t\t\t\t\t\t\tnt_common_add_debug($rrd_exec);\n\t\t\t\t\t\t\texec($rrd_exec, $rrd_result, $rrd_code);\n\n\t\t\t\t\t\t\t$file_description = str_replace(array('.rrd','.hrd','.'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('',    '',    '&nbsp;-&nbsp;'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$graph_item['rd_file']);\n\n\t\t\t\t\t\t\t$time_string = '';\n\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($view_time_lowframe, $time_string);\n\n\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> $file_description .' over '. $time_string,\n\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> $rrd_web);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$tpl->assign('tool_rrd_output', $rrd_webs);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'tech':\n\t\t\t\t\t/*\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t *  Tech Shard Pages (Low Res)\n\t\t\t\t\t \t// ts_mainland01.TotalSpeedLoop.rrd\n\t\t\t\t\t\t// egs_mainland01.NbPlayers.rrd\n\t\t\t\t\t\t// egs_mainland01.ProcessUsedMemory.rrd\n\t\t\t\t\t\t// egs_mainland01.TickSpeedLoop.rrd\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t */\n\n\t\t\t\t\t$tpl->assign('tool_frame_list',\t\t$tool_lowres_frames);\n\t\t\t\t\t$tpl->assign('tool_frame_selected',\t$view_time_lowframe);\n\n\t\t\t\t\tif ($view_shard_id && $view_time_lowframe)\n\t\t\t\t\t{\n\t\t\t\t\t\t$graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), false);\n//print_r($graph_data_tmp);print_r('</br>');\n\n\t\t\t\t\t\t$tool_tech_graph_list = array(\tarray('service'\t=>\t'pds',\t'variable'\t=>\t'ProcessUsedMemory'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'egs',\t'variable'\t=>\t'ProcessUsedMemory'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'fes',\t'variable'\t=>\t'ProcessUsedMemory'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'fes', \t'variable'\t=>\t'FPSProcessMsg'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t );\n\n\t\t\t\t\t\t$graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']);\n\t\t\t\t\t\tnt_common_add_debug($graph_list);\n\n\t\t\t\t\t\t$rrd_webs\t= array();\n\t\t\t\t\t\treset($graph_list);\n\n\t\t\t\t\t\tforeach($graph_list as $graph_item)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$rrd_path\t= $AS_RRDPath . $graph_item['rd_file'];\n\t\t\t\t\t\t\t$rrd_path   = str_replace(\"\\\\\",\"\\\\\\\\\",$rrd_path);\n\t\t\t\t\t\t\t$rrd_def\t= \"DEF:val=\". $rrd_path .\":var:AVERAGE\";\n\t\t\t\t\t\t\t$rrd_draw\t= \"LINE2:val#0000FF --no-legend\";\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t$rrd_output\t= NELTOOL_RRDSYSBASE . $graph_item['rd_file'] .\"-\". $view_time_lowframe .\".gif\";\n\t\t\t\t\t\t\t$rrd_web\t= NELTOOL_RRDWEBBASE . $graph_item['rd_file'] .\"-\". $view_time_lowframe .\".gif\";\n\t\t\t\t\t\t\t$rrd_exec\t= NELTOOL_RRDTOOL .\" graph \". $rrd_output .\" --width 916 --height 110 --start -\". $view_time_lowframe .\" \". $rrd_def .\" \". $rrd_draw;\n\n\t\t\t\t\t\t\tnt_common_add_debug($rrd_exec);\n\t\t\t\t\t\t\texec($rrd_exec, $rrd_result, $rrd_code);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnt_common_add_debug($rrd_result);\n\t\t\t\t\t\t\tnt_common_add_debug($rrd_code);\n\n\t\t\t\t\t\t\t$file_description = str_replace(array('.rrd','.hrd','.'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('',    '',    '&nbsp;-&nbsp;'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$graph_item['rd_file']);\n\n\t\t\t\t\t\t\t$time_string = '';\n\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($view_time_lowframe, $time_string);\n\n\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> $file_description .' over '. $time_string,\n\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> $rrd_web);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t$tpl->assign('tool_rrd_output', $rrd_webs);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'hires':\n\t\t\t\t\t/*\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t *  Hi-Res Shard Pages\n\t\t\t\t\t\t// ts_mainland01.TotalSpeedLoop.hrd\n\t\t\t\t\t\t// egs_mainland01.TickSpeedLoop.hrd\n\t\t\t\t\t\t// ais_fyros_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// ais_matis_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// ais_zorai_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// ais_tryker_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// ais_pr_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// ais_newbyland_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// gpms_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t\t// fes_mainland01.ProcessUsedMemory.hrd\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t */\n\n\t\t\t\t\t$tpl->assign('tool_frame_list',\t\t$tool_hires_frames);\n\t\t\t\t\t$tpl->assign('tool_frame_selected',\t$view_time_highframe);\n\n\t\t\t\t\tif ($view_shard_id && $view_time_highframe)\n\t\t\t\t\t{\n\t\t\t\t\t\t$graph_data_tmp = tool_graphs_get_list_v2($AS_RRDPath, strtolower($AS_InternalName), true);\n\n\t\t\t\t\t\t$tool_tech_graph_list = array(\tarray('service'\t=>\t'ts', \t'variable'\t=>\t'TotalSpeedLoop'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'egs',\t'variable'\t=>\t'TickSpeedLoop'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'ais',\t'variable'\t=>\t'TickSpeedLoop'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'gpms',\t'variable'\t=>\t'TickSpeedLoop'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('service'\t=>\t'fes',\t'variable'\t=>\t'TickSpeedLoop'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t );\n\n\t\t\t\t\t\t$graph_list = tool_graphs_find($tool_tech_graph_list, $graph_data_tmp['datas']);\n\t\t\t\t\t\tnt_common_add_debug($graph_list);\n\n\t\t\t\t\t\t$adminService = new MyAdminService;\n\t\t\t\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$now = time();\n\t\t\t\t\t\t\t$rrd_webs\t= array();\n\n\t\t\t\t\t\t\treset($graph_list);\n\t\t\t\t\t\t\tforeach($graph_list as $graph_item)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tnt_common_add_debug(\" getHighRezGraph : \". $graph_item['service'] .\".\". $graph_item['variable'] .\" , \". ($now - ($view_time_highframe / 1000)) .\" , \". $now .\" , 0\");\n\t\t\t\t\t\t\t\t$tmp = $adminService->getHighRezGraph($graph_item['service'] .'.'. $graph_item['variable'], $now - ($view_time_highframe / 1000), $now, 0);\n\n\t\t\t\t\t\t\t\t//nt_common_add_debug($tmp);\n\n\t\t\t\t\t\t\t\t$mean_values = tool_graphs_extract_mean_values($tmp);\n\t\t\t\t\t\t\t\t//nt_common_add_debug($mean_values);\n\n\t\t\t\t\t\t\t\tif (sizeof($mean_values['val']))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$graph = new Graph(1000,150);\n\t\t\t\t\t\t\t\t\t$graph->SetMargin(35,10,5,25); // left - right - top - bottom\n\t\t\t\t\t\t\t\t\t$graph->SetScale(\"intlin\");\n\t\t\t\t\t\t\t\t\t$graph->xgrid->Show(true,true);\n\t\t\t\t\t\t\t\t\t$graph->ygrid->Show(true,true);\n\t\t\t\t\t\t\t\t\t$graph->xaxis->SetLabelFormatCallback('tool_graphs_xaxis_callback');\n\n\t\t\t\t\t\t\t\t\t$line = new LinePlot($mean_values['val'], $mean_values['ref']);\n\t\t\t\t\t\t\t\t\t$line->SetColor('blue');\n\t\t\t\t\t\t\t\t\t$line->SetFillColor('lightblue');\n\t\t\t\t\t\t\t\t\t$graph->Add($line);\n\n\t\t\t\t\t\t\t\t\t$high_sys_name = NELTOOL_RRDSYSBASE . $graph_item['rd_file'] .\"-\". $view_time_highframe .'_0.png';\n\t\t\t\t\t\t\t\t\t$high_web_name = NELTOOL_RRDWEBBASE . $graph_item['rd_file'] .\"-\". $view_time_highframe .'_0.png';\n\n\t\t\t\t\t\t\t\t\t$graph->Stroke($high_sys_name);\n\n\t\t\t\t\t\t\t\t\t$file_description = str_replace(array('.rrd','.hrd','.'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tarray('',    '',    '&nbsp;-&nbsp;'),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t$graph_item['rd_file']);\n\n\t\t\t\t\t\t\t\t\t$time_string = '';\n\t\t\t\t\t\t\t\t\ttool_main_get_elapsed_time_string($view_time_highframe / 1000, $time_string);\n\n\t\t\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> $file_description .' over '. $time_string .' - ('. sizeof($mean_values['val']) .' values)',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> $high_web_name);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> 'Not enough values to render plot for '. $graph_item['rd_file'] .' over '. ($view_time_highframe / 1000) .'s.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> '');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$tpl->assign('tool_rrd_high_output', $rrd_webs);\n\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'old':\n\t\t\t\t\t/*\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t *  Old Page\n\t\t\t\t\t * ###################################################################################################\n\t\t\t\t\t */\n\n\t\t\t\t\t$tool_as_error = null;\n\n\t\t\t\t\tif ($AS_Host && $AS_Port)\n\t\t\t\t\t{\n\t\t\t\t\t\t$graph_data_tmp\t\t= tool_graphs_get_list($AS_RRDPath, strtolower($AS_InternalName));\n\t\t\t\t\t\t$graph_variables\t= $graph_data_tmp['variables'];\n\t\t\t\t\t\t$graph_datas\t\t= $graph_data_tmp['datas'];\n\n\t\t\t\t\t\tif (sizeof($graph_datas))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign('tool_graph_list',\t\t\ttrue);\n\t\t\t\t\t\t\t$tpl->assign('tool_graph_variables',\t$graph_variables);\n\t\t\t\t\t\t\t$tpl->assign('tool_graph_datas',\t\t$graph_datas);\n\n\t\t\t\t\t\t\t$tool_variable_selected = $_GET['variable'];\n\t\t\t\t\t\t\t$tool_service_selected\t= $_GET['service'];\n\n\t\t\t\t\t\t\t$tpl->assign('tool_graph_variable_selected',\t$tool_variable_selected);\n\t\t\t\t\t\t\t$tpl->assign('tool_graph_service_selected',\t\t$tool_service_selected);\n\n\t\t\t\t\t\t\t$tool_selected_variable_data = tool_graphs_get_data($graph_datas, $tool_variable_selected, $tool_service_selected);\n\n\t\t\t\t\t\t\tif ($tool_selected_variable_data['low_file'] != '')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$rrd_values\t= array(1200, 10800, 86400, 604800, 2592000, 7776000); // 20mins, 3h, 24h, 7days, 30 days, 90 days (unit is 1 second)\n\t\t\t\t\t\t\t\t$rrd_path\t= $AS_RRDPath . $tool_selected_variable_data['low_file'];\n\t\t\t\t\t\t\t\t$rrd_def\t= \"DEF:val=\". $rrd_path .\":var:AVERAGE\";\n\t\t\t\t\t\t\t\t$rrd_draw\t= \"LINE2:val#0000FF\";\n\n\t\t\t\t\t\t\t\t$rrd_webs\t= array();\n\n\t\t\t\t\t\t\t\treset($rrd_values);\n\t\t\t\t\t\t\t\tforeach($rrd_values as $rrd_value)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$rrd_output\t= NELTOOL_RRDSYSBASE . $tool_selected_variable_data['low_file'] .\"-\". $rrd_value .\".gif\";\n\t\t\t\t\t\t\t\t\t$rrd_web\t= NELTOOL_RRDWEBBASE . $tool_selected_variable_data['low_file'] .\"-\". $rrd_value .\".gif\";\n\t\t\t\t\t\t\t\t\t$rrd_exec\t= NELTOOL_RRDTOOL .\" graph \". $rrd_output .\" --start -\". $rrd_value .\" \". $rrd_def .\" \". $rrd_draw;\n\t\t\t\t\t\t\t\t\tnt_common_add_debug($rrd_exec);\n\t\t\t\t\t\t\t\t\texec($rrd_exec, $rrd_result, $rrd_code);\n\t\t\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> $tool_selected_variable_data['low_file'] .' over '. $rrd_value .'s.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> $rrd_web);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_rrd_output', $rrd_webs);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ($tool_selected_variable_data['high_file'] != '')\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$rrd_webs\t= array();\n\t\t\t\t\t\t\t\t$rrd_values\t= array(array(10000,10), array(30000,10), array(90000,10)); // 10s, 30s, 90s (unit is 1 ms)\n\n\t\t\t\t\t\t\t\t$adminService = new MyAdminService;\n\t\t\t\t\t\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$now = time();\n\t\t\t\t\t\t\t\t\t$rrd_webs\t= array();\n\n\t\t\t\t\t\t\t\t\treset($rrd_values);\n\t\t\t\t\t\t\t\t\tforeach($rrd_values as $rrd_value)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\" getHighRezGraph : \". $tool_selected_variable_data['service'] .\".\". $tool_selected_variable_data['variable'] .\" , \". ($now - ($rrd_value[0] / 1000)) .\" , \". $now .\" , \". $rrd_value[1]);\n\t\t\t\t\t\t\t\t\t\t$tmp = $adminService->getHighRezGraph($tool_selected_variable_data['service'] .'.'. $tool_selected_variable_data['variable'], $now - ($rrd_value[0] / 1000), $now, $rrd_value[1]);\n\n\t\t\t\t\t\t\t\t\t\t//nt_common_add_debug(\" getHighRezGraph : \". $tool_selected_variable_data['service'] .\".\". $tool_selected_variable_data['variable'] .\" , \". ($rrd_value[0] / 1000) .\" , 0 , 0\");\n\t\t\t\t\t\t\t\t\t\t//$tmp = $adminService->getHighRezGraph($tool_selected_variable_data['service'] .'.'. $tool_selected_variable_data['variable'], ($rrd_value[0] / 1000), 0, 0);\n\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug($tmp);\n\n\t\t\t\t\t\t\t\t\t\t$mean_values = tool_graphs_extract_mean_values($tmp);\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug($mean_values);\n\n\t\t\t\t\t\t\t\t\t\tif (sizeof($mean_values['val']))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$graph = new Graph(480,160);\n\t\t\t\t\t\t\t\t\t\t\t$graph->SetMargin(35,10,5,25); // left - right - top - bottom\n\n\t\t\t\t\t\t\t\t\t\t\t// Now specify the X-scale explicit but let the Y-scale be auto-scaled\n\t\t\t\t\t\t\t\t\t\t\t//$graph->SetScale(\"intlin\",0,0,$adjstart,$adjend);\n\t\t\t\t\t\t\t\t\t\t\t$graph->SetScale(\"intlin\");\n\n\t\t\t\t\t\t\t\t\t\t\t// display grids\n\t\t\t\t\t\t\t\t\t\t\t$graph->xgrid->Show(true,true);\n\t\t\t\t\t\t\t\t\t\t\t$graph->ygrid->Show(true,true);\n\t\t\t\t\t\t\t\t\t\t\t//$graph->SetGridDepth(DEPTH_FRONT);\n\n\t\t\t\t\t\t\t\t\t\t\t// Setup the callback and adjust the angle of the labels\n\t\t\t\t\t\t\t\t\t\t\t$graph->xaxis->SetLabelFormatCallback('tool_graphs_xaxis_callback');\n\t\t\t\t\t\t\t\t\t\t\t//$graph->xaxis->title->Set(\"ms.\");\n\t\t\t\t\t\t\t\t\t\t\t//$graph->xaxis->SetLabelAngle(90);\n\n\t\t\t\t\t\t\t\t\t\t\t// Set the labels every 5min (i.e. 300seconds) and minor ticks every minute\n\t\t\t\t\t\t\t\t\t\t\t//$graph->xaxis->scale->ticks->Set(1000);\n\t\t\t\t\t\t\t\t\t\t\t//$graph->yscale->SetAutoTicks();\n\n\t\t\t\t\t\t\t\t\t\t\t$line = new LinePlot($mean_values['val'], $mean_values['ref']);\n\t\t\t\t\t\t\t\t\t\t\t$line->SetColor('blue');\n\t\t\t\t\t\t\t\t\t\t\t$line->SetFillColor('lightblue');\n\t\t\t\t\t\t\t\t\t\t\t$graph->Add($line);\n\n\t\t\t\t\t\t\t\t\t\t\t$high_sys_name = NELTOOL_RRDSYSBASE . $tool_selected_variable_data['high_file'] .\"-\". $rrd_value[0] .'_'. $rrd_value[1] .\".png\";\n\t\t\t\t\t\t\t\t\t\t\t$high_web_name = NELTOOL_RRDWEBBASE . $tool_selected_variable_data['high_file'] .\"-\". $rrd_value[0] .'_'. $rrd_value[1] .\".png\";\n\n\t\t\t\t\t\t\t\t\t\t\t$graph->Stroke($high_sys_name);\n\n\t\t\t\t\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> $tool_selected_variable_data['high_file'] .' over '. ($rrd_value[0] / 1000) .'s. ('. sizeof($mean_values['val']) .' values)',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> $high_web_name);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$rrd_webs[] = array('desc'\t=> 'Not enough values to render plot for '. $tool_selected_variable_data['high_file'] .' over '. ($rrd_value[0] / 1000) .'s.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'img'\t=> '');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_rrd_high_output', $rrd_webs);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t$tpl->assign('tool_domain_error',\t\"This domain has not been configured to handle graphs!\");\n\t\t}\n\t}\n\telse\n\t{\n\t}\n\n\t$tpl->display($tool_menu_item['tpl']);\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_guild_locator.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_guild_locator.php');\n\n\tif (!tool_admin_applications_check('tool_guild_locator'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_guild_locator.php\\'');\n\n\t$tpl->assign('tool_title', \"Guild Locator\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['refdata']))\n\t{\n\t\t$tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata']));\n\t\tif (is_array($tmp_data))\n\t\t{\n\t\t\t$NELTOOL['POST_VARS'] = $tmp_data;\n\t\t}\n\t}\n\n\t$current_refresh_rate = nt_auth_get_session_var('current_refresh_rate');\n\n\tif (isset($_POST['services_refresh']))\n\t{\n\t\tif ($current_refresh_rate != $_POST['services_refresh'])\n\t\t{\n\t\t\t$current_refresh_rate = $_POST['services_refresh'];\n\t\t\tnt_auth_set_session_var('current_refresh_rate',$current_refresh_rate);\n\t\t}\n\t}\n\n\tif ($current_refresh_rate == null)\n\t{\n\t\t$current_refresh_rate = 0;\n\t}\n\telseif ($current_refresh_rate > 0)\n\t{\n\t\t$tpl->assign('nel_tool_refresh',\t'<meta http-equiv=refresh content=\"'. $current_refresh_rate .'\">');\n\t}\n\n\t$tpl->assign('tool_refresh_list',\t\t$refresh_rates);\n\t$tpl->assign('tool_refresh_rate',\t\t$current_refresh_rate);\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\tif (tool_admin_applications_check('tool_guild_locator_manage_guild'))\t$tpl->assign('restriction_tool_guild_locator_manage_guild',true);\n\tif (tool_admin_applications_check('tool_guild_locator_manage_members'))\t$tpl->assign('restriction_tool_guild_locator_manage_members',true);\n\tif (tool_admin_applications_check('tool_guild_locator_manage_forums'))\t$tpl->assign('restriction_tool_guild_locator_manage_forums',true);\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name = tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host = tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port = tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t= tool_main_get_shard_name($view_shard_id);\n\t\t$MFS_Web\t\t= tool_main_get_domain_data($view_domain_id, 'domain_mfs_web');\n\n\t\t$tpl->assign('tool_page_title', 'Guild Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t$tool_as_error = null;\n\n\t\tif ($AS_Host && $AS_Port)\n\t\t{\n\t\t\t$adminService = new MyAdminService;\n\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t{\n\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$tool_services_gl = null;\n\t\t\t\tif\t\t(isset($NELTOOL['POST_VARS']['services_gl']))\t$tool_services_gl = $NELTOOL['POST_VARS']['services_gl'];\n\t\t\t\telseif\t(isset($NELTOOL['GET_VARS']['services_gl']))\t$tool_services_gl = $NELTOOL['GET_VARS']['services_gl'];\n\n\t\t\t\tif ($tool_services_gl)\n\t\t\t\t{\n\t\t\t\t\t$tpl->assign('tool_post_data',\tbase64_encode(serialize($NELTOOL['POST_VARS'])));\n\n\t\t\t\t\tswitch ($tool_services_gl)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'display guilds':\n\n\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = 'dumpGuildList local';\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t//nt_common_add_debug(\"about to run 'displayPlayers' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$guild_data = tool_gl_parse_dump_guild_list($command_return_data);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_data',\t$guild_data);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'update name':\n\n\t\t\t\t\t\t\tif (($tool_services_gl == 'update name') && tool_admin_applications_check('tool_guild_locator_manage_guild'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service\t\t= $NELTOOL['POST_VARS']['servicealias'];\n\t\t\t\t\t\t\t\t$guild_shard_id = $NELTOOL['POST_VARS']['guildshardid'];\n\t\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['POST_VARS']['guildid'];\n\t\t\t\t\t\t\t\t$new_guild_name = $NELTOOL['POST_VARS']['new_guild_name'];\n\n\t\t\t\t\t\t\t\t$new_guild_name = trim($new_guild_name);\n\t\t\t\t\t\t\t\tif (ereg(\"^[a-zA-Z0-9\\ ]+$\", $new_guild_name))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// this is a small hack that was done by daniel so i could use the renameGuild command without an EID\n\t\t\t\t\t\t\t\t\t$service_command = 'renameGuild admin_tool '. $guild_shard_id .':'. $guild_id .' \"'. $new_guild_name .'\"';\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// tool_guild_errors\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_errors',\tarray('New name contains illegal characters.'));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['servicealias']\t= $service;\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['guildshardid']\t= $guild_shard_id;\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['guildid']\t\t\t= $guild_id;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 'update description':\n\n\t\t\t\t\t\t\tif (($tool_services_gl == 'update description') && tool_admin_applications_check('tool_guild_locator_manage_guild'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service\t\t= $NELTOOL['POST_VARS']['servicealias'];\n\t\t\t\t\t\t\t\t$guild_shard_id = $NELTOOL['POST_VARS']['guildshardid'];\n\t\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['POST_VARS']['guildid'];\n\t\t\t\t\t\t\t\t$new_guild_desc\t= $NELTOOL['POST_VARS']['new_guild_description'];\n\n\t\t\t\t\t\t\t\t$new_guild_desc = trim($new_guild_desc);\n\t\t\t\t\t\t\t\tif (ereg(\"^[a-zA-Z0-9\\ ]+$\", $new_guild_desc))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'setGuildDescription '. $guild_shard_id .':'. $guild_id .' \"'. $new_guild_desc .'\"';\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t// tool_guild_errors\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_errors',\tarray('New description contains illegal characters.'));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['servicealias']\t= $service;\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['guildshardid']\t= $guild_shard_id;\n\t\t\t\t\t\t\t\t$NELTOOL['GET_VARS']['guildid']\t\t\t= $guild_id;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 'setleader':\n\n\t\t\t\t\t\t\tif (($tool_services_gl == 'setleader') && tool_admin_applications_check('tool_guild_locator_manage_members'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service\t\t= $NELTOOL['GET_VARS']['servicealias'];\n\t\t\t\t\t\t\t\t$guild_shard_id = $NELTOOL['GET_VARS']['guildshardid'];\n\t\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['GET_VARS']['guildid'];\n\t\t\t\t\t\t\t\t$member_eid\t\t= $NELTOOL['GET_VARS']['eid'];\n\n\t\t\t\t\t\t\t\t// guildSetLeader <guildName|<shardId>:<guildId> <member eid>\n\n\t\t\t\t\t\t\t\t$service_command = 'guildSetLeader '. $guild_shard_id .':'. $guild_id .' '. $member_eid;\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\tcase 'promote':\n\n\t\t\t\t\t\t\tif (($tool_services_gl == 'promote') && tool_admin_applications_check('tool_guild_locator_manage_members'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service\t\t= $NELTOOL['GET_VARS']['servicealias'];\n\t\t\t\t\t\t\t\t$guild_shard_id = $NELTOOL['GET_VARS']['guildshardid'];\n\t\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['GET_VARS']['guildid'];\n\t\t\t\t\t\t\t\t$member_eid\t\t= $NELTOOL['GET_VARS']['eid'];\n\t\t\t\t\t\t\t\t$member_grade\t= $NELTOOL['GET_VARS']['grade'];\n\n\t\t\t\t\t\t\t\t$new_grade\t\t= 'Member';\n\t\t\t\t\t\t\t\tif\t\t($member_grade == 'Officer')\t\t$new_grade = 'Officer';\n\t\t\t\t\t\t\t\telseif\t($member_grade == 'HighOfficer')\t$new_grade = 'HighOfficer';\n\n\t\t\t\t\t\t\t\t// guildSetGrade <guildName|<shardId>:<guildId> <member eid> <grade = Member/Officer/HighOfficer/Leader>\n\n\t\t\t\t\t\t\t\t$service_command = 'guildSetGrade '. $guild_shard_id .':'. $guild_id .' '. $member_eid .' '. $new_grade;\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data));\n\t\t\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 'demote':\n\n\t\t\t\t\t\t\tif (($tool_services_gl == 'demote') && tool_admin_applications_check('tool_guild_locator_manage_members'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service\t\t= $NELTOOL['GET_VARS']['servicealias'];\n\t\t\t\t\t\t\t\t$guild_shard_id = $NELTOOL['GET_VARS']['guildshardid'];\n\t\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['GET_VARS']['guildid'];\n\t\t\t\t\t\t\t\t$member_eid\t\t= $NELTOOL['GET_VARS']['eid'];\n\t\t\t\t\t\t\t\t$member_grade\t= $NELTOOL['GET_VARS']['grade'];\n\n\t\t\t\t\t\t\t\t$new_grade\t\t= 'Member';\n\t\t\t\t\t\t\t\tif \t\t($member_grade == 'Officer')\t$new_grade = 'Officer';\n\t\t\t\t\t\t\t\telseif\t($member_grade == 'Member')\t\t$new_grade = 'Member';\n\n\t\t\t\t\t\t\t\t// guildSetGrade <guildName|<shardId>:<guildId> <member eid> <grade = Member/Officer/HighOfficer/Leader>\n\n\t\t\t\t\t\t\t\t$service_command = 'guildSetGrade '. $guild_shard_id .':'. $guild_id .' '. $member_eid .' '. $new_grade;\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_errors', tool_gl_parse_grade_change($command_return_data));\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 'dumpguild':\n\n\t\t\t\t\t\t\t$service\t\t= $NELTOOL['GET_VARS']['servicealias'];\n\t\t\t\t\t\t\t$guild_shard_id\t= $NELTOOL['GET_VARS']['guildshardid'];\n\t\t\t\t\t\t\t$guild_id\t\t= $NELTOOL['GET_VARS']['guildid'];\n\n\t\t\t\t\t\t\tif (($guild_shard_id > 0) && ($guild_id > 0) && ($service != ''))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_command = 'dumpGuild '. $guild_shard_id .':'. $guild_id;\n\n\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". $service);\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$tool_sub_services_gl = null;\n\t\t\t\t\t\t\t\t\tif\t\t(isset($NELTOOL['POST_VARS']['subservices_gl']))\t$tool_sub_services_gl = $NELTOOL['POST_VARS']['subservices_gl'];\n\t\t\t\t\t\t\t\t\telseif\t(isset($NELTOOL['GET_VARS']['subservices_gl']))\t\t$tool_sub_services_gl = $NELTOOL['GET_VARS']['subservices_gl'];\n\n\t\t\t\t\t\t\t\t\t$guild_dump_data = tool_gl_parse_dump_guild($command_return_data);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_dump_data',\t$guild_dump_data);\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service',\t\t\t$service);\n\n\t\t\t\t\t\t\t\t\t// view ingame guild forums\n\t\t\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_guild_locator_manage_forums'))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tif ($tool_sub_services_gl)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tswitch ($tool_sub_services_gl)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tcase 'viewthread':\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t$view_forum_threadid\t\t= $NELTOOL['GET_VARS']['threadid'];\n\t\t\t\t\t\t\t\t\t\t\t\t\t$view_forum_recoverable\t\t= $NELTOOL['GET_VARS']['recoverable'];\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t$thread_name = ($view_forum_recoverable == 1 ? '_':'') .'thread_'. $view_forum_threadid .'.index';\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t$view_thread_data_raw \t\t= tool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name'], $thread_name);\n\t\t\t\t\t\t\t\t\t\t\t\t\t$view_thread_data\t\t\t= tool_gl_parse_thread_view($view_thread_data_raw);\n\t\t\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_guild_thread',\t$view_thread_data);\n\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\t\t\t\t\tcase 'recoverthread':\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t$recover_forum_threadid\t\t= $NELTOOL['GET_VARS']['threadid'];\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t$thread_name = '_thread_'. $recover_forum_threadid .'.index';\n\t\t\t\t\t\t\t\t\t\t\t\t\ttool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name'], $recover_forum_threadid, true);\n\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t$view_forum_data_raw \t= tool_gl_view_forum($MFS_Web, $guild_shard_id, $guild_dump_data['guild_name']);\n\t\t\t\t\t\t\t\t\t\t$view_forum_data\t\t= tool_gl_parse_forum_view($view_forum_data_raw);\n\n\t\t\t\t\t\t\t\t\t\tif (is_array($view_forum_data))\t$tpl->assign('tool_guild_forums', \t\t$view_forum_data);\n\t\t\t\t\t\t\t\t\t\telse\t\t\t\t\t\t\t$tpl->assign('tool_guild_forums_error', $view_forum_data);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isset($NELTOOL['GET_VARS']['eid']))\n\t\t\t\t{\n\t\t\t\t\t$locate_eid = $NELTOOL['GET_VARS']['eid'];\n\n\t\t\t\t}\n\n\t\t\t\t$status = $adminService->getStates();\n\t\t\t\tnt_common_add_debug($status);\n\n\t\t\t\t$domainServices\t\t= tool_main_parse_status($status);\n\n\t\t\t\t$filteredServices\t= array();\n\t\t\t\treset($domainServices);\n\t\t\t\tforeach($domainServices as $aKey => $aService)\n\t\t\t\t{\n\t\t\t\t\t// we are only interested in EGS\n\t\t\t\t\tif ($aService['ShortName'] == 'EGS')\n\t\t\t\t\t{\n\t\t\t\t\t\t$filteredServices[] = $aService;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$tpl->assign('tool_services_list',\t$filteredServices);\n\t\t\t}\n\t\t}\n\t}\n\n\t$tpl->display('tool_guild_locator.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_log_analyser.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_log_analyser.php');\n\n\tif (!tool_admin_applications_check('tool_las'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_log_analyser.php\\'');\n\n\t$tpl->assign('tool_title', \"Log Analyser\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\t//$nel_tool_notes_meta  = \"<script type=\\\"text/javascript\\\" src=\\\"overlib/overlib_mini.js\\\" ></script>\\n\";\n\t//$nel_tool_notes_meta .= \"<script type=\\\"text/javascript\\\" src=\\\"overlib/overlib_anchor_mini.js\\\" ></script>\\n\";\n\t//$nel_tool_notes_meta .= \"<script type=\\\"text/javascript\\\" src=\\\"overlib/overlib_draggable_mini.js\\\" ></script>\\n\";\n\t//$tpl->assign('nel_tool_notes_meta',\t$nel_tool_notes_meta);\n\n\t$template_file\t= 'tool_log_analyser.tpl';\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name = tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host = tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port = tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t= tool_main_get_shard_name($view_shard_id);\n\n\t\t$tpl->assign('tool_page_title', 'Log Analyser - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t$tool_as_error = null;\n\n\t\t$AS_LAS_AdminPath\t= tool_main_get_domain_data($view_domain_id, 'domain_las_admin_path');\n\t\t$AS_LAS_LocalPath\t= tool_main_get_domain_data($view_domain_id, 'domain_las_local_path');\n\t\t$tool_las_file_list\t= tool_las_get_file_list($AS_LAS_AdminPath);\n\n\t\tif (isset($NELTOOL['GET_VARS']['fileview']))\n\t\t{\n\t\t\t// FILE VIEWER\n\n\t\t\t$template_file\t= 'tool_log_analyser_file_view.tpl';\n\t\t\t$view_file_name = base64_decode($NELTOOL['GET_VARS']['fileview']);\n\t\t\t$tpl->assign('tool_file_list',\t$tool_las_file_list);\n\n\t\t\t$view_file_data = tool_las_check_for_file($tool_las_file_list, $view_file_name);\n\n\t\t\tif (isset($NELTOOL['GET_VARS']['downloadraw']))\n\t\t\t{\n\t\t\t\tif ($fp = fopen($view_file_data['path'] . $view_file_data['name'], 'r'))\n\t\t\t\t{\n\t\t\t\t\theader(\"Content-type: text/plain\");\n\t\t\t\t\theader(\"Content-Disposition: attachment; filename=las_raw_\". $view_file_data['name']);\n\t\t\t\t\theader(\"Pragma: no-cache\");\n\t\t\t\t\theader(\"Expires: 0\");\n\t\t\t\t\tfpassthru($fp);\n\t\t\t\t\tfclose($fp);\n\t\t\t\t\texit();\n\t\t\t\t}\n\t\t\t}\n\t\t\telseif (isset($NELTOOL['GET_VARS']['downloadparsed']))\n\t\t\t{\n\t\t\t\t$char_eid_data = tool_las_parse_file($view_file_data['path'] . $view_file_data['name']);\n\n\t\t\t\t// NOTE: 'ring_live' needs to be replace with the ringdb field from the domain table\n\t\t\t\t$db_char_data = tool_las_get_character_names('ring_live', $char_eid_data);\n\n\t\t\t\tif (sizeof($db_char_data))\n\t\t\t\t{\n\t\t\t\t\t$search_eid_ary\t\t= array();\n\t\t\t\t\t$search_char_ary\t= array();\n\n\t\t\t\t\treset($char_eid_data);\n\t\t\t\t\tforeach($char_eid_data as $char_id => $char_eid)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (isset($db_char_data[$char_id]))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$search_eid_ary[]\t= $char_eid;\n\t\t\t\t\t\t\t$search_char_ary[]\t= $db_char_data[$char_id];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ttool_las_fpassthru_replace($view_file_data['path'],$view_file_data['name'], $search_eid_ary, $search_char_ary);\n\t\t\t\t\texit();\n\t\t\t\t}\n\t\t\t}\n\t\t\t//elseif (isset($NELTOOL['GET_VARS']['delete']))\n\t\t\t//{\n\t\t\t//\tnt_common_add_debug('unlinking file : '. $view_file_data['path'] . $view_file_data['name']);\n\t\t\t//\t@unlink($view_file_data['path'] . $view_file_data['name']);\n\t\t\t//\tnt_common_redirect('tool_log_analyser.php');\n\t\t\t//\texit();\n\t\t\t//}\n\t\t\telseif (is_array($view_file_data))\n\t\t\t{\n\t\t\t\t$tpl->assign('tool_view_file_data', $view_file_data);\n\n\t\t\t\t$file_line_start = 0;\n\t\t\t\tif (isset($NELTOOL['GET_VARS']['viewstart']))\n\t\t\t\t{\n\t\t\t\t\t$file_line_start = $NELTOOL['GET_VARS']['viewstart'];\n\t\t\t\t}\n\n\t\t\t\t$file_line_read_max = 200;\n\n\t\t\t\t$view_file_output_data = tool_las_read_file($view_file_data['path'] . $view_file_data['name'], $file_line_read_max, $file_line_start, $file_line_start_previous, $file_line_start_next);\n\t\t\t\t$tpl->assign('tool_file_output', $view_file_output_data);\n\n\t\t\t\t$tpl->assign('tool_view_line_start_previous',\t$file_line_start_previous);\n\t\t\t\t$tpl->assign('tool_view_line_start_next',\t\t$file_line_start_next);\n\n\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$tpl->assign('tool_file_error', 'File not found !');\n\t\t\t}\n\t\t}\n\t\telseif (($AS_LAS_AdminPath != '') && ($AS_LAS_LocalPath != ''))\n\t\t{\n\t\t\t// REGULAR SERVICE VIEW WITH COMMANDS\n\n\t\t\t$tpl->assign('tool_file_list',\t$tool_las_file_list);\n\n\t\t\tif (substr($AS_LAS_AdminPath,-1) != '/') $AS_LAS_AdminPath .= '/';\n\t\t\tif (substr($AS_LAS_LocalPath,-1) != '/') $AS_LAS_LocalPath .= '/';\n\n\t\t\tif ($AS_Host && $AS_Port)\n\t\t\t{\n\t\t\t\t$adminService = new MyAdminService;\n\t\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t\t{\n\t\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (isset($NELTOOL['POST_VARS']['services_las']))\n\t\t\t\t\t{\n\t\t\t\t\t\t$tool_services_las = $NELTOOL['POST_VARS']['services_las'];\n\t\t\t\t\t\t$tpl->assign('tool_post_data',\tbase64_encode(serialize($NELTOOL['POST_VARS'])));\n\n\t\t\t\t\t\t$service_search_database\t= $NELTOOL['POST_VARS']['service_search_database'];\n\t\t\t\t\t\t$service_search_file_name\t= $NELTOOL['POST_VARS']['service_search_file_name'];\n\t\t\t\t\t\t$service_search_start_date\t= $NELTOOL['POST_VARS']['service_search_start_date'];\n\t\t\t\t\t\t$service_search_end_date\t= $NELTOOL['POST_VARS']['service_search_end_date'];\n\n\t\t\t\t\t\t$tpl->assign('tool_form_service_search_database',\t$service_search_database);\n\t\t\t\t\t\t$tpl->assign('tool_form_service_search_file_name',\t$service_search_file_name);\n\t\t\t\t\t\t$tpl->assign('tool_form_service_search_start_date',\t$service_search_start_date);\n\t\t\t\t\t\t$tpl->assign('tool_form_service_search_end_date',\t$service_search_end_date);\n\n\t\t\t\t\t\t$file_name_error_msg \t= null;\n\t\t\t\t\t\t$start_date_error_msg\t= null;\n\n\t\t\t\t\t\tswitch ($tool_services_las)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcase 'search eids':\n\n\t\t\t\t\t\t\t\tif ($service_search_file_name == '')\t$file_name_error_msg\t= \"Need to specify a filename !\";\n\t\t\t\t\t\t\t\tif ($service_search_start_date == '')\t$start_date_error_msg\t= \"Need to specify a start date !\";\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_file_name_error_msg',\t\t\t$file_name_error_msg);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_start_date_error_msg',\t\t\t$start_date_error_msg);\n\n\t\t\t\t\t\t\t\tif (isset($NELTOOL['POST_VARS']['service_eids']) && !$file_name_error_msg && !$start_date_error_msg)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_eids = trim(stripslashes($NELTOOL['POST_VARS']['service_eids']));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_form_service_eids', $service_eids);\n\n\t\t\t\t\t\t\t\t\t$service_eids_ary = tool_las_parse_eids_to_array($service_eids);\n\t\t\t\t\t\t\t\t\tnt_common_add_debug($service_eids_ary);\n\n\t\t\t\t\t\t\t\t\tif (sizeof($service_eids_ary) > 0)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$service_command = 'executeToFile '. $AS_LAS_LocalPath . $service_search_file_name ;\n\n\t\t\t\t\t\t\t\t\t\tif (sizeof($service_eids_ary) == 1)\t$service_command .= ' searchEId ';\n\t\t\t\t\t\t\t\t\t\telse\t\t\t\t\t\t\t\t$service_command .= ' searchEIds ';\n\n\t\t\t\t\t\t\t\t\t\t$service_command .= $service_search_database .' ';\n\t\t\t\t\t\t\t\t\t\t$service_command .= implode(' ', $service_eids_ary) .' ';\n\n\t\t\t\t\t\t\t\t\t\tif (sizeof($service_eids_ary) > 1)\t$service_command .= '- ';\n\t\t\t\t\t\t\t\t\t\t$service_command .= $service_search_start_date;\n\n\t\t\t\t\t\t\t\t\t\tif ($service_search_end_date != '')\t$service_command .= ' '. $service_search_end_date;\n\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug($service_command);\n\n\t\t\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'search text':\n\n\t\t\t\t\t\t\t\tif ($service_search_file_name == '')\t$file_name_error_msg\t= \"Need to specify a filename !\";\n\t\t\t\t\t\t\t\tif ($service_search_start_date == '')\t$start_date_error_msg\t= \"Need to specify a start date !\";\n\n\t\t\t\t\t\t\t\t$tpl->assign('tool_file_name_error_msg',\t\t\t$file_name_error_msg);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_start_date_error_msg',\t\t\t$start_date_error_msg);\n\n\t\t\t\t\t\t\t\tif (isset($NELTOOL['POST_VARS']['service_text']) && !$file_name_error_msg && !$start_date_error_msg)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_text = trim(stripslashes(html_entity_decode($NELTOOL['POST_VARS']['service_text'], ENT_QUOTES)));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_form_service_text', htmlentities($service_text,ENT_QUOTES));\n\n\t\t\t\t\t\t\t\t\tif ($service_text != '')\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$service_command = 'executeToFile '. $AS_LAS_LocalPath . $service_search_file_name ;\n\t\t\t\t\t\t\t\t\t\t$service_command .= ' searchString '. $service_search_database .' \"'. addslashes($service_text) .'\" ';\n\t\t\t\t\t\t\t\t\t\t$service_command .= $service_search_start_date;\n\t\t\t\t\t\t\t\t\t\tif ($service_search_end_date != '')\t$service_command .= ' '. $service_search_end_date;\n\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug($service_command);\n\n\t\t\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 'execute':\n\n\t\t\t\t\t\t\t\tif (isset($NELTOOL['POST_VARS']['service_command']))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = trim(stripslashes(html_entity_decode($NELTOOL['POST_VARS']['service_command'], ENT_QUOTES)));\n\t\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\t\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_command', \thtmlentities($service_command, ENT_QUOTES));\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$status = $adminService->getStates();\n\t\t\t\t\tnt_common_add_debug($status);\n\n\t\t\t\t\t$domainServices\t\t= tool_main_parse_status($status);\n\n\t\t\t\t\t$filteredServices\t= array();\n\t\t\t\t\treset($domainServices);\n\t\t\t\t\tforeach($domainServices as $aKey => $aService)\n\t\t\t\t\t{\n\t\t\t\t\t\t// we are only interested in EGS\n\t\t\t\t\t\tif ($aService['ShortName'] == 'LAS')\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$filteredServices[] = $aService;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t$tpl->assign('tool_services_list',\t$filteredServices);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t$tpl->display($template_file);\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_mfs.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_mfs.php');\n\n\tif (!tool_admin_applications_check('tool_mfs'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_mfs.php\\'');\n\n\t$tpl->assign('tool_title', \"Mails & Forums\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\t$template_file\t= 'tool_mfs.tpl';\n\n\tif ($view_domain_id && $view_shard_id)\n\t{\n\t\t$tpl->assign('tool_page_title', 'Mails & Forums');\n\n\t\t$tpl->assign('tool_curl_output',tool_mfs_HTTPOpen(\"http://\"));\n\n\t}\n\n\n\t$tpl->display($template_file);\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_notes.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_notes.php');\n\n\tif (!tool_admin_applications_check('tool_notes'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_notes.php\\'');\n\n\t$tpl->assign('tool_title', \"Notes\");\n\n\tif (tool_admin_applications_check('tool_notes_global'))\t$tpl->assign('restriction_tool_notes_global', true);\n\n\tif (isset($NELTOOL['GET_VARS']['note_id']))\n\t{\n\t\t$note_id\t\t= $NELTOOL['GET_VARS']['note_id'];\n\t\t$tool_note_data\t= tool_notes_get_id($nel_user['user_id'], $note_id);\n\n\t\t$tpl->assign('tool_note_edit_data',\t$tool_note_data);\n\t}\n\n\tif (isset($NELTOOL['POST_VARS']['toolaction']))\n\t{\n\t\t$tool_action = $NELTOOL['POST_VARS']['toolaction'];\n\n\t\tswitch($tool_action)\n\t\t{\n\t\t\tcase 'create':\n\n\t\t\t\t$note_title \t\t= $NELTOOL['POST_VARS']['tool_form_note_title'];\n\t\t\t\t$note_data \t\t\t= $NELTOOL['POST_VARS']['tool_form_note_data'];\n\t\t\t\t$note_active\t\t= $NELTOOL['POST_VARS']['tool_form_note_active'];\n\t\t\t\t$note_global\t\t= (isset($NELTOOL['POST_VARS']['tool_form_note_global']) ? $NELTOOL['POST_VARS']['tool_form_note_global'] : 0);\n\n\t\t\t\t$note_mode\t\t\t= $NELTOOL['POST_VARS']['tool_form_note_mode'];\n\t\t\t\t$note_uri\t\t\t= $NELTOOL['POST_VARS']['tool_form_note_popup_uri'];\n\t\t\t\t$note_restriction\t= $NELTOOL['POST_VARS']['tool_form_note_popup_restriction'];\n\n\t\t\t\t$tool_error = tool_notes_add($nel_user['user_id'], $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction);\n\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t{\n\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'update':\n\n\t\t\t\t$note_id \t\t\t= $NELTOOL['POST_VARS']['tool_form_note_id'];\n\t\t\t\t$note_title \t\t= $NELTOOL['POST_VARS']['tool_form_note_title'];\n\t\t\t\t$note_data \t\t\t= $NELTOOL['POST_VARS']['tool_form_note_data'];\n\t\t\t\t$note_active\t\t= $NELTOOL['POST_VARS']['tool_form_note_active'];\n\t\t\t\t$note_global\t\t= (isset($NELTOOL['POST_VARS']['tool_form_note_global']) ? $NELTOOL['POST_VARS']['tool_form_note_global'] : 0);\n\n\t\t\t\t$note_mode\t\t\t= $NELTOOL['POST_VARS']['tool_form_note_mode'];\n\t\t\t\t$note_uri\t\t\t= $NELTOOL['POST_VARS']['tool_form_note_popup_uri'];\n\t\t\t\t$note_restriction\t= $NELTOOL['POST_VARS']['tool_form_note_popup_restriction'];\n\n\t\t\t\t$tool_error = tool_notes_update($nel_user['user_id'], $note_id, $note_title, $note_data, $note_active, $note_global, $note_mode, $note_uri, $note_restriction);\n\t\t\t\tif ($tool_error != \"\")\n\t\t\t\t{\n\t\t\t\t\t$tpl->assign('tool_alert_message',\t$tool_error);\n\t\t\t\t}\n\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'delete':\n\n\t\t\t\t$note_id = $NELTOOL['POST_VARS']['tool_form_note_id'];\n\t\t\t\ttool_notes_del($nel_user['user_id'], $note_id);\n\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t$tool_note_list = tool_notes_get_list($nel_user['user_id']);\n\t$tpl->assign('tool_note_list',\t$tool_note_list);\n\n\n\t$tpl->display('tool_notes.tpl');\n\n?>\n"
  },
  {
    "path": "tools/server/admin/tool_player_locator.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_player_locator.php');\n\n\tif (!tool_admin_applications_check('tool_player_locator'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_player_locator.php\\'');\n\n\t$tpl->assign('tool_title', \"Player Locator\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['refdata']))\n\t{\n\t\t$tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata']));\n\t\tif (is_array($tmp_data))\n\t\t{\n\t\t\t$NELTOOL['POST_VARS'] = $tmp_data;\n\t\t}\n\t}\n\n\t$current_refresh_rate = nt_auth_get_session_var('current_refresh_rate');\n\n\tif (isset($_POST['services_refresh']))\n\t{\n\t\tif ($current_refresh_rate != $_POST['services_refresh'])\n\t\t{\n\t\t\t$current_refresh_rate = $_POST['services_refresh'];\n\t\t\tnt_auth_set_session_var('current_refresh_rate',$current_refresh_rate);\n\t\t}\n\t}\n\n\tif ($current_refresh_rate == null)\n\t{\n\t\t$current_refresh_rate = 0;\n\t}\n\telseif ($current_refresh_rate > 0)\n\t{\n\t\t$tpl->assign('nel_tool_refresh',\t'<meta http-equiv=refresh content=\"'. $current_refresh_rate .'\">');\n\t}\n\n\t$tpl->assign('tool_refresh_list',\t\t$refresh_rates);\n\t$tpl->assign('tool_refresh_rate',\t\t$current_refresh_rate);\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\tif (tool_admin_applications_check('tool_player_locator_display_players'))\t\t$tpl->assign('restriction_tool_player_locator_display_players',\ttrue);\n\tif (tool_admin_applications_check('tool_player_locator_locate'))\t\t\t\t$tpl->assign('restriction_tool_player_locator_locate',\t\t\ttrue);\n\tif (tool_admin_applications_check('tool_player_locator_userid_check'))\t\t\t$tpl->assign('restriction_tool_player_locator_userid_check', \ttrue);\n\tif (tool_admin_applications_check('tool_player_locator_csr_relocate'))\t\t\t$tpl->assign('restriction_tool_player_locator_csr_relocate', \ttrue);\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name \t\t= tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host \t\t= tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port \t\t= tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t= tool_main_get_shard_name($view_shard_id);\n\t\t$AS_Application\t= tool_main_get_domain_data($view_domain_id, 'domain_application');\n\t\t$AS_RingSQL\t\t= tool_main_get_domain_data($view_domain_id, 'domain_sql_string');\n\n\t\t$tpl->assign('tool_page_title', 'Player Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t$tool_as_error = null;\n\n\t\tif ($AS_Host && $AS_Port)\n\t\t{\n\t\t\t$adminService = new MyAdminService;\n\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t{\n\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (isset($NELTOOL['POST_VARS']['services_pl']))\n\t\t\t\t{\n\t\t\t\t\t$tool_services_pl = $NELTOOL['POST_VARS']['services_pl'];\n\t\t\t\t\t$tpl->assign('tool_post_data',\tbase64_encode(serialize($NELTOOL['POST_VARS'])));\n\n\t\t\t\t\tswitch ($tool_services_pl)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase 'display players':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_player_locator_display_players'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$tool_locate_plname\t= trim($NELTOOL['POST_VARS']['services_plname_locate']);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_locate_name_value', $tool_locate_plname);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list) && ($tool_locate_plname != ''))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'displayPlayers '. $tool_locate_plname;\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t//nt_common_add_debug(\"about to run 'displayPlayers' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$player_data = tool_pl_parse_display_players($command_return_data);\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_player_data',\t$player_data);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n//\t\t\t\t\t\tcase 'csr relocate':\n\t\t\t\t\t\tcase 'ani':\n\t\t\t\t\t\tcase 'ari':\n\t\t\t\t\t\tcase 'lea':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_player_locator_csr_relocate'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$relocate_su\t= $NELTOOL['POST_VARS']['pl_su'];\n\t\t\t\t\t\t\t\t$relocate_shardid\t= $NELTOOL['POST_VARS']['relocate_shardid'];\n\t\t\t\t\t\t\t\t$relocate_eid\t= $NELTOOL['POST_VARS']['relocate_eid'];\n\n\t\t\t\t\t\t\t\tif ($relocate_eid != 'na' && $relocate_shardid != 'na')\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service\t\t\t= $relocate_su;\n\t\t\t\t\t\t\t\t\t$service_command\t= 'cs.relocChar ' . $relocate_eid . ' ' . $relocate_shardid;\n\n\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$relocate_data = tool_pl_parse_relocate($command_return_data);\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_relocate_data',\t\t$relocate_data);\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t//break;\n\n\t\t\t\t\t\tcase 'locate':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_player_locator_locate'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$tool_locate_name\t= trim($NELTOOL['POST_VARS']['services_pl_locate']);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_locate_value', $tool_locate_name);\n\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list) && ($tool_locate_name != ''))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'playerinfo '. $tool_locate_name;\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'playerinfo' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_command', \thtmlentities($service_command, ENT_QUOTES));\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t//  不拆出来显示了，直接在上面显示了原结果\n\t\t\t\t\t\t\t\t\t//if (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t//{\n\t\t\t\t\t\t\t\t\t//\t$locate_data = tool_pl_parse_locate($command_return_data);\n\t\t\t\t\t\t\t\t\t//\t$tpl->assign('tool_locate_data',\t\t$locate_data);\n\t\t\t\t\t\t\t\t\t//}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase 'Compute User IDs and Clear SQL Cache':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_player_locator_userid_check'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$check_su = $NELTOOL['POST_VARS']['pl_su'];\n\n\t\t\t\t\t\t\t\ttool_pl_fix_character_check_list($AS_Application);\n\n\t\t\t\t\t\t\t\t$service = $check_su;\n\t\t\t\t\t\t\t\t$service_command = 'sqlObjectCache.clearCache';\n\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run command '$service_command' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isset($NELTOOL['GET_VARS']['eid']))\n\t\t\t\t{\n\t\t\t\t\t$locate_eid = $NELTOOL['GET_VARS']['eid'];\n\n\t\t\t\t\t// someday i'll do something here :)\n\t\t\t\t}\n\n\t\t\t\t$status = $adminService->getStates();\n\t\t\t\tnt_common_add_debug($status);\n\n\t\t\t\t$domainServices\t\t= tool_main_parse_status($status);\n\n\t\t\t\t$filteredServices\t= array();\n\t\t\t\treset($domainServices);\n\t\t\t\tforeach($domainServices as $aKey => $aService)\n\t\t\t\t{\n\t\t\t\t\t// we are only interested in EGS\n\t\t\t\t\tif ($aService['ShortName'] == 'EGS')\n\t\t\t\t\t{\n\t\t\t\t\t\t$filteredServices[] = $aService;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$tpl->assign('tool_services_list',\t$filteredServices);\n\n\t\t\t\t$tpl->assign('shard_su_name',\ttool_main_get_su_from_status($domainServices));\n\n\t\t\t\t// user_id == 0 check system\n\t\t\t\tif (tool_admin_applications_check('tool_player_locator_userid_check'))\n\t\t\t\t{\n\t\t\t\t\t$user_check_list = tool_pl_get_character_check_list($AS_Application, $AS_RingSQL);\n\t\t\t\t\t$tpl->assign('user_check_list', $user_check_list);\n\t\t\t\t}\n\n\n\t\t\t}\n\t\t}\n\t}\n\n\t$tpl->display('tool_player_locator.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_preferences.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_preferences.php');\n\n\tif (!tool_admin_applications_check('tool_preferences')) nt_common_redirect('index.php');\n\n\t$tpl->assign(\"tool_title\",\t\t\t\"My Preferences\");\n\t$tpl->assign(\"tool_v_login\",\t\t$nel_user['user_name']);\n\t$tpl->assign(\"tool_v_user_id\",\t\t$nel_user['user_id']);\n\t$tpl->assign(\"tool_v_menu\",\t\t\t$nel_user['user_menu_style']);\n\t$tpl->assign(\"tool_v_application\",\tisset($nel_user['user_default_application_id']) ? $nel_user['user_default_application_id']:'') ;\n\n\tif (isset($NELTOOL['POST_VARS']['tool_form_user_id']))\n\t{\n\t\t$post_user_id \t= $NELTOOL['POST_VARS']['tool_form_user_id'];\n\t\t$tool_action\t= $NELTOOL['POST_VARS']['toolaction'];\n\n\t\tswitch ($tool_action)\n\t\t{\n\t\t\t/*\n\t\t\t * update main preferences\n\t\t\t */\n\t\t\tcase 'update':\n\n\t\t\t\t$post_old_pwd \t= $NELTOOL['POST_VARS']['tool_form_password_old'];\n\t\t\t\t$post_new_pwd \t= $NELTOOL['POST_VARS']['tool_form_password_new'];\n\t\t\t\t$post_menu\t\t= $NELTOOL['POST_VARS']['tool_form_menu_style'];\n\n\t\t\t\t// update menu style\n\t\t\t\tif ($nel_user['user_menu_style'] != $post_menu)\n\t\t\t\t{\n\t\t\t\t\ttool_pref_update_menu_style($nel_user, $post_menu);\n\t\t\t\t\t$tpl->assign(\"tool_v_menu\",\t$post_menu);\n\t\t\t\t}\n\n\t\t\t\t// update password\n\t\t\t\tif (($post_old_pwd != '') && ($post_new_pwd != ''))\n\t\t\t\t{\n\t\t\t\t\tif (tool_pref_check_old_password($nel_user, $post_old_pwd))\n\t\t\t\t\t{\n\t\t\t\t\t\tif (tool_pref_update_user_password($nel_user, $post_new_pwd))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign(\"tool_error\", \"Password has been updated!\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$tpl->assign(\"tool_error\", \"Invalid new password!\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t$tpl->assign(\"tool_error\", \"Old password does not match!\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telseif (($post_old_pwd != '') || ($post_new_pwd != ''))\n\t\t\t\t{\n\t\t\t\t\t$tpl->assign(\"tool_error\", \"You need to type your current and new passwords!\");\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\t/*\n\t\t\t * update default application\n\t\t\t */\n\t\t\tcase 'update default application':\n\n\t\t\t\t$post_new_application = $NELTOOL['POST_VARS']['tool_form_application_default'];\n\n\t\t\t\tif ($nel_user['user_default_application_id'] != $post_new_application)\n\t\t\t\t{\n\t\t\t\t\ttool_pref_update_default_application($nel_user, $post_new_application);\n\t\t\t\t\t$tpl->assign(\"tool_v_application\",\t$post_new_application);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t}\n\n\t}\n\n\t$tpl->display('tool_preferences.tpl');\n\n?>"
  },
  {
    "path": "tools/server/admin/tool_shop.php",
    "content": "<?php\n\n\trequire_once('common.php');\n\trequire_once('functions_tool_main.php');\n\trequire_once('functions_tool_shop.php');\n\n\tif (!tool_admin_applications_check('tool_shop'))\tnt_common_redirect('index.php');\n\n\tnt_common_add_debug('-- Starting on \\'tool_shop.php\\'');\n\n\t$tpl->assign('tool_title', \"商城管理\");\n\n\t$view_domain_id = nt_auth_get_session_var('view_domain_id');\n\t$view_shard_id \t= nt_auth_get_session_var('view_shard_id');\n\n\tif (!$view_domain_id)\n\t{\n\t\t$view_domain_id\t= $nel_user['group_default_domain_id'];\n\t\t$view_shard_id\t= $nel_user['group_default_shard_id'];\n\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['domain']))\n\t{\n\t\tif ($view_domain_id != $NELTOOL['GET_VARS']['domain'])\n\t\t{\n\t\t\t$view_domain_id = $NELTOOL['GET_VARS']['domain'];\n\t\t\tnt_auth_set_session_var('view_domain_id', $view_domain_id);\n\n\t\t\t$view_shard_id = null;\n\t\t\tnt_auth_unset_session_var('view_shard_id');\n\t\t}\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['shard']))\n\t{\n\t\t$view_shard_id = $NELTOOL['GET_VARS']['shard'];\n\t\tnt_auth_set_session_var('view_shard_id', $view_shard_id);\n\t}\n\n\tif (isset($NELTOOL['GET_VARS']['refdata']))\n\t{\n\t\t$tmp_data = unserialize(base64_decode($NELTOOL['GET_VARS']['refdata']));\n\t\tif (is_array($tmp_data))\n\t\t{\n\t\t\t$NELTOOL['POST_VARS'] = $tmp_data;\n\t\t}\n\t}\n\n\t$current_refresh_rate = nt_auth_get_session_var('current_refresh_rate');\n\n\tif (isset($_POST['services_refresh']))\n\t{\n\t\tif ($current_refresh_rate != $_POST['services_refresh'])\n\t\t{\n\t\t\t$current_refresh_rate = $_POST['services_refresh'];\n\t\t\tnt_auth_set_session_var('current_refresh_rate',$current_refresh_rate);\n\t\t}\n\t}\n\n\tif ($current_refresh_rate == null)\n\t{\n\t\t$current_refresh_rate = 0;\n\t}\n\telseif ($current_refresh_rate > 0)\n\t{\n\t\t$tpl->assign('nel_tool_refresh',\t'<meta http-equiv=refresh content=\"'. $current_refresh_rate .'\">');\n\t}\n\n\t$tpl->assign('tool_refresh_list',\t\t$refresh_rates);\n\t$tpl->assign('tool_refresh_rate',\t\t$current_refresh_rate);\n\n\t$tpl->assign('tool_domain_list',\t\t$nel_user['access']['domains']);\n\t$tpl->assign('tool_domain_selected',\t$view_domain_id);\n\n\t$tpl->assign('tool_shard_list',\t\t\t$nel_user['access']['shards']);\n\t$tpl->assign('tool_shard_selected',\t\t$view_shard_id);\n\n\t$tool_shard_filters\t= tool_main_get_shard_ids($view_shard_id);\n\t$tpl->assign('tool_shard_filters',\t\t$tool_shard_filters);\n\n\tif (tool_admin_applications_check('tool_shop'))\t\t$tpl->assign('restriction_tool_shop',\ttrue);\n\n\tif ($view_domain_id)\n\t{\n\t\t$tool_as_error = null;\n\n\t\t$AS_Name \t\t= tool_main_get_domain_name($view_domain_id);\n\t\t$AS_Host \t\t= tool_main_get_domain_host($view_domain_id);\n\t\t$AS_Port \t\t= tool_main_get_domain_port($view_domain_id);\n\t\t$AS_ShardName\t= tool_main_get_shard_name($view_shard_id);\n\t\t$AS_Application\t= tool_main_get_domain_data($view_domain_id, 'domain_application');\n\t\t$AS_RingSQL\t\t= tool_main_get_domain_data($view_domain_id, 'domain_sql_string');\n\n\t\t$tpl->assign('tool_page_title', 'Player Locator - '. $AS_Name . ($AS_ShardName != '' ? ' / '. $AS_ShardName : ''));\n\n\t\t$tool_as_error = null;\n\n\t\tif ($AS_Host && $AS_Port)\n\t\t{\n\t\t\t$adminService = new MyAdminService;\n\t\t\tif (@$adminService->connect($AS_Host, $AS_Port, $res) === false)\n\t\t\t{\n\t\t\t\tnt_common_add_debug($res);\n\t\t\t\t$tpl->assign('tool_domain_error', $res );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (isset($NELTOOL['POST_VARS']['services_pl']))\n\t\t\t\t{\n\t\t\t\t\t$tool_services_pl = $NELTOOL['POST_VARS']['services_pl'];\n\t\t\t\t\t$tpl->assign('tool_post_data',\tbase64_encode(serialize($NELTOOL['POST_VARS'])));\n\n\t\t\t\t\tswitch ($tool_services_pl)\n\t\t\t\t\t{\n\t\t\t\t\t\tcase '刷新物品列表':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_shop'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'shoplist';\n\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_execute_result', '');\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t//nt_common_add_debug(\"about to run 'displayPlayers' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t// the locator displays a nice output, no need for the raw one\n\t\t\t\t\t\t\t\t\t\t\t//$tpl->assign('tool_execute_command', \t$service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$shop_list_data = tool_sp_parse_shop_list($command_return_data);\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_shop_list_data',\t$shop_list_data);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase '添加物品':\n\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_shop'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$tool_template_id\t= trim($NELTOOL['POST_VARS']['tpl_item_template_id']);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_template_id_value', $tool_template_id);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t$tool_item_num\t= trim($NELTOOL['POST_VARS']['tpl_item_num']);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_item_num_value', $tool_item_num);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t$tool_item_price\t= trim($NELTOOL['POST_VARS']['tpl_item_price']);\n\t\t\t\t\t\t\t\t$tpl->assign('tool_item_price_value', $tool_item_price);\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\tnt_common_add_debug('----- \\''. $tool_template_id .'\\' for command : '. $tool_item_num);\n\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\t\t\t\t\t\t\t\tif (sizeof($service_list) && ($tool_template_id != '') && ($tool_item_num != '') && ($tool_item_price != ''))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'addshopitem '. $tool_template_id. ' '. $tool_item_num. ' '. $tool_item_price;\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'addshopitem' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$shop_list_data = tool_sp_parse_shop_list($command_return_data);\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_shop_list_data',\t$shop_list_data);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase '删除物品':\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif (tool_admin_applications_check('tool_shop'))\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$check_item_list = tool_shop_get_check_items();\n\t\t\t\t\t\t\t\t$service_list = tool_main_get_checked_services();\n\n\t\t\t\t\t\t\t\tif (sizeof($service_list) && sizeof($check_item_list))\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$service_command = 'removeshopitem '. $check_item_list;\n\t\t\t\t\t\t\t\t\tnt_log(\"Domain '$AS_Name' : '$service_command' on \". implode(', ',array_values($service_list)));\n\n\t\t\t\t\t\t\t\t\t$tpl->assign('tool_service_select_list', array_combine($service_list, $service_list));\n\t\t\t\t\t\t\t\t\t$command_return_data = array();\n\n\t\t\t\t\t\t\t\t\treset($service_list);\n\t\t\t\t\t\t\t\t\tforeach($service_list as $service)\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tnt_common_add_debug(\"about to run 'removeshopitem' on '$service' ...\");\n\n\t\t\t\t\t\t\t\t\t\t$adminService->serviceCmd($service, $service_command);\n\t\t\t\t\t\t\t\t\t\tif (!$adminService->waitCallback())\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tnt_common_add_debug('Error while waiting for callback on service \\''. $service .'\\' for command : '. $service_command);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\tif (sizeof($command_return_data))\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$shop_list_data = tool_sp_parse_shop_list($command_return_data);\n\t\t\t\t\t\t\t\t\t\t$tpl->assign('tool_shop_list_data',\t$shop_list_data);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (isset($NELTOOL['GET_VARS']['eid']))\n\t\t\t\t{\n\t\t\t\t\t$locate_eid = $NELTOOL['GET_VARS']['eid'];\n\n\t\t\t\t\t// someday i'll do something here :)\n\t\t\t\t}\n\n\t\t\t\t$status = $adminService->getStates();\n\t\t\t\tnt_common_add_debug($status);\n\n\t\t\t\t$domainServices\t\t= tool_main_parse_status($status);\n\n\t\t\t\t$filteredServices\t= array();\n\t\t\t\treset($domainServices);\n\t\t\t\tforeach($domainServices as $aKey => $aService)\n\t\t\t\t{\n\t\t\t\t\t// we are only interested in EGS\n\t\t\t\t\tif ($aService['ShortName'] == 'EGS')\n\t\t\t\t\t{\n\t\t\t\t\t\t$filteredServices[] = $aService;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$tpl->assign('tool_services_list',\t$filteredServices);\n\t\t\t\t$tpl->assign('shard_su_name',\ttool_main_get_su_from_status($domainServices));\n\t\t\t}\n\t\t}\n\t}\n\n\t$tpl->display('tool_shop.tpl');\n\n?>"
  },
  {
    "path": "tools/server/sql/d_mt_account.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : localhost_3306\nSource Server Version : 50611\nSource Host           : localhost:3306\nSource Database       : d_mt_account\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50611\nFile Encoding         : 65001\n\nDate: 2013-05-05 14:05:10\n*/\n\ndrop database if exists d_mt_account ;\n\ncreate database d_mt_account default character set utf8mb4;\n\nuse d_mt_account ;\n\n-- ----------------------------\n-- Table structure for `t_account_id`\n-- ----------------------------\nCREATE TABLE `t_account_id` (\n  `f_account_id`    int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '帐号id' UNIQUE,\n  `f_appname`       varchar(16)  NOT NULL DEFAULT '' COMMENT '游戏类型',\n  `f_name`          varchar(128) NOT NULL DEFAULT '' COMMENT '帐号名称',\n  `f_chal`          varchar(16)  NOT NULL DEFAULT 0 COMMENT '渠道',\n  `f_mobile`        varchar(32) NOT NULL DEFAULT '' COMMENT '手机号',\n  `f_freeze_to`     int(10) unsigned NOT NULL DEFAULT 0 COMMENT '冻结到什么时间',\n  `f_inserttime`    timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间',\n  PRIMARY KEY (`f_appname`, `f_name`, `f_chal`)\n) ENGINE=MyISAM AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8mb4;\n\n\n-- ----------------------------\n-- Table structure for `t_account_mobile`\n-- ----------------------------\nCREATE TABLE `t_account_mobile` (\n  `f_mobile`        varchar(32) NOT NULL DEFAULT '' COMMENT '手机号',\n  `f_pwd`           varchar(32) NOT NULL DEFAULT '' COMMENT '密码',\n  `f_slat`          varchar(8) NOT NULL DEFAULT '' COMMENT 'salt',\n  `f_inserttime`    timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间',\n  PRIMARY KEY (`f_mobile`)\n) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;\n\n\n-- ----------------------------\n-- Table structure for `t_account_info`\n-- ----------------------------\nCREATE TABLE `t_account_info` (\n  `f_account_id`    int(10) unsigned NOT NULL COMMENT '帐号id',\n  `f_nickname`      varchar(128) NOT NULL DEFAULT '' COMMENT '普通用户昵称',\n  `f_sex`           smallint(4)  NOT NULL DEFAULT 0 COMMENT '普通用户性别，1为男性，2为女性',\n  `f_province`      varchar(64) NOT NULL DEFAULT '' COMMENT '普通用户个人资料填写的省份',\n  `f_city`          varchar(32) NOT NULL DEFAULT '' COMMENT '普通用户个人资料填写的城市',\n  `f_country`       varchar(32) NOT NULL DEFAULT '' COMMENT '国家，如中国为CN',\n  `f_headimgurl`    varchar(512) NOT NULL DEFAULT '' COMMENT '头像',\n  `f_inserttime`    timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间',\n  PRIMARY KEY(`f_account_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;\n\n\n\n\n"
  },
  {
    "path": "tools/server/sql/d_mt_player_procedure.sql",
    "content": "﻿use d_mt_player ;\n\ndrop procedure if exists _t_mt_add_player;\n\n/* t_playerinfo */\ndrop procedure if exists _t_mt_select_playerinfo;\ndrop procedure if exists _t_mt_insert_playerinfo;\ndrop procedure if exists _t_mt_update_playerinfo_low;\ndrop procedure if exists _t_mt_update_playerinfo;\n\nDELIMITER ;;\n\ncreate procedure _t_mt_select_playerinfo(\n\tin af_uid bigint(20) unsigned )\nbegin\n\tselect  f_uid,\n            f_nickname,\n            f_portrait,\n            f_money,\n            f_rmb,\n            f_main,\n            f_flag_bit\n\t\t   from t_playerinfo\n\t\t   where f_uid=af_uid;\nend;;\n\ncreate procedure _t_mt_insert_playerinfo(\n\tin af_uid bigint(20) unsigned\n\t)\nbegin\n\tinsert into t_playerinfo( f_uid ) values( af_uid );\n\nend;;\n\ncreate procedure _t_mt_update_playerinfo_low(\n\tin af_uid bigint(20) unsigned,\n\tin af_nickname varchar(64),\n    in af_portrait int(10)  unsigned \n    )\n\t\nbegin\n\tupdate t_playerinfo set\n\t\t   f_nickname = af_nickname,\n           f_portrait = af_portrait\n\t\t   \n    where  f_uid = af_uid;\nend;;\n\ncreate procedure _t_mt_update_playerinfo(\n\tin af_uid bigint(20) unsigned,\n\tin af_money bigint(20) unsigned,\n    in af_rmb bigint(20) unsigned,\n    in af_main int(10) unsigned,\n    in af_flag_bit bigint(20) unsigned\n    )\n\t\nbegin\n\tupdate t_playerinfo set\n\t\t   f_money = af_money,\n           f_rmb = af_rmb,\n           f_main = af_main,\n           f_flag_bit = af_flag_bit\n\t\t   \n    where  f_uid = af_uid;\nend;;\n\n\n\n\ncreate procedure _t_mt_add_player()\nbegin\n\tdeclare v int default 1;\n\tdeclare f_uid int default 1;\n\n\twhile v < 10000\n\tdo\n\t\tcall _t_mt_insert_playerinfo( f_uid+1 );\n\n\t\tset v = v + 1;\n\t\tset f_uid = f_uid + 1;\n\t\t\n\tend while;\nend\t;;\n\t\n\nDELIMITER ;\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "tools/server/sql/d_mt_player_table.sql",
    "content": "﻿/*\nNavicat MySQL Data Transfer\n\nSource Server         : localhost_3306\nSource Server Version : 50611\nSource Host           : localhost:3306\nSource Database       : d_mt_player\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50611\nFile Encoding         : 65001\n\nDate: 2013-05-05 14:05:24\n*/\n\n\ndrop database if exists d_mt_player ;\n\ncreate database d_mt_player default character set utf8mb4 ;\n\nuse d_mt_player ;\n\n/*==============================================================*/\n/* Table: t_playerinfo                                          */\n/*==============================================================*/\ndrop table if exists t_playerinfo;\ncreate table t_playerinfo\n(\n   f_uid                bigint(20) unsigned NOT NULL DEFAULT 0 comment '' ,\n   f_nickname           varchar(64) NOT NULL DEFAULT \" \" comment '昵称',\n   f_portrait           int(10) unsigned NOT NULL DEFAULT 0 comment '头像',\n   f_money              bigint(20) unsigned NOT NULL DEFAULT 0 comment '',\n   f_rmb                bigint(20) unsigned NOT NULL DEFAULT 0 comment '',\n   f_main               int(10) unsigned NOT NULL DEFAULT 0 comment '',\n   f_flag_bit           bigint(20) unsigned NOT NULL DEFAULT 0 comment '各种占一位的标识',\n   f_insert_time        timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录生成时间',\n   \n  primary key (f_uid)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;\nalter table t_playerinfo comment '角色基础信息';\n\n"
  },
  {
    "path": "tools/server/sql/nel_tool.sql",
    "content": "/*\nNavicat MySQL Data Transfer\n\nSource Server         : localhost\nSource Server Version : 50611\nSource Host           : localhost:3306\nSource Database       : nel_tool\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50611\nFile Encoding         : 65001\n\nDate: 2014-09-10 20:48:57\n*/\n\ndrop database if exists nel_tool ;\ncreate database nel_tool default character set utf8 ;\nuse nel_tool ;\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for `neltool_annotations`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_annotations`;\nCREATE TABLE `neltool_annotations` (\n  `annotation_id` int(11) NOT NULL AUTO_INCREMENT,\n  `annotation_domain_id` int(11) DEFAULT NULL,\n  `annotation_shard_id` int(11) DEFAULT NULL,\n  `annotation_data` varchar(255) NOT NULL DEFAULT '',\n  `annotation_user_name` varchar(32) NOT NULL DEFAULT '',\n  `annotation_date` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`annotation_id`),\n  UNIQUE KEY `annotation_shard_id` (`annotation_shard_id`),\n  UNIQUE KEY `annotation_domain_id` (`annotation_domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_annotations\n-- ----------------------------\nINSERT INTO `neltool_annotations` VALUES ('12', null, '106', 'Welcome to the Shard Admin Website!', 'admin', '1409802992');\nINSERT INTO `neltool_annotations` VALUES ('13', null, '302', '宽字节注入测试(縗) -- 这里是这组服务器的注释。', 'admin', '1409909065');\n\n-- ----------------------------\n-- Table structure for `neltool_applications`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_applications`;\nCREATE TABLE `neltool_applications` (\n  `application_id` int(11) NOT NULL AUTO_INCREMENT,\n  `application_name` varchar(64) NOT NULL DEFAULT '',\n  `application_uri` varchar(255) NOT NULL DEFAULT '',\n  `application_restriction` varchar(64) NOT NULL DEFAULT '',\n  `application_order` int(11) NOT NULL DEFAULT '0',\n  `application_visible` int(11) NOT NULL DEFAULT '0',\n  `application_icon` varchar(128) NOT NULL DEFAULT '',\n  PRIMARY KEY (`application_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=41 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_applications\n-- ----------------------------\nINSERT INTO `neltool_applications` VALUES ('1', 'Main', 'index.php', '', '100', '1', 'imgs/icon_main.gif');\nINSERT INTO `neltool_applications` VALUES ('2', 'Logout', 'index.php?mode=logout', '', '999999', '1', 'imgs/icon_logout.gif');\nINSERT INTO `neltool_applications` VALUES ('3', 'Admin', 'tool_administration.php', 'tool_admin', '1500', '1', 'imgs/icon_admin.gif');\nINSERT INTO `neltool_applications` VALUES ('4', 'Prefs', 'tool_preferences.php', 'tool_preferences', '1000', '1', 'imgs/icon_preferences.gif');\nINSERT INTO `neltool_applications` VALUES ('5', 'Admin/Users', '', 'tool_admin_user', '1502', '0', '');\nINSERT INTO `neltool_applications` VALUES ('6', 'Admin/Applications', '', 'tool_admin_application', '1501', '0', '');\nINSERT INTO `neltool_applications` VALUES ('7', 'Admin/Domains', '', 'tool_admin_domain', '1504', '0', '');\nINSERT INTO `neltool_applications` VALUES ('8', 'Admin/Shards', '', 'tool_admin_shard', '1505', '0', '');\nINSERT INTO `neltool_applications` VALUES ('9', 'Admin/Groups', '', 'tool_admin_group', '1503', '0', '');\nINSERT INTO `neltool_applications` VALUES ('10', 'Admin/Logs', '', 'tool_admin_logs', '1506', '0', '');\nINSERT INTO `neltool_applications` VALUES ('11', 'Main/Start', '', 'tool_main_start', '101', '0', '');\nINSERT INTO `neltool_applications` VALUES ('12', 'Main/Stop', '', 'tool_main_stop', '102', '0', '');\nINSERT INTO `neltool_applications` VALUES ('13', 'Main/Restart', '', 'tool_main_restart', '103', '0', '');\nINSERT INTO `neltool_applications` VALUES ('14', 'Main/Kill', '', 'tool_main_kill', '104', '0', '');\nINSERT INTO `neltool_applications` VALUES ('15', 'Main/Abort', '', 'tool_main_abort', '105', '0', '');\nINSERT INTO `neltool_applications` VALUES ('16', 'Main/Execute', '', 'tool_main_execute', '108', '0', '');\nINSERT INTO `neltool_applications` VALUES ('18', 'Notes', 'tool_notes.php', 'tool_notes', '900', '1', 'imgs/icon_notes.gif');\nINSERT INTO `neltool_applications` VALUES ('19', 'Player Locator', 'tool_player_locator.php', 'tool_player_locator', '200', '1', 'imgs/icon_player_locator.gif');\nINSERT INTO `neltool_applications` VALUES ('20', 'Player Locator/Display Players', '', 'tool_player_locator_display_players', '201', '0', '');\nINSERT INTO `neltool_applications` VALUES ('21', 'Player Locator/Locate', '', 'tool_player_locator_locate', '202', '0', '');\nINSERT INTO `neltool_applications` VALUES ('22', 'Main/LockDomain', '', 'tool_main_lock_domain', '110', '0', '');\nINSERT INTO `neltool_applications` VALUES ('23', 'Main/LockShard', '', 'tool_main_lock_shard', '111', '0', '');\nINSERT INTO `neltool_applications` VALUES ('24', 'Main/WS', '', 'tool_main_ws', '112', '0', '');\nINSERT INTO `neltool_applications` VALUES ('25', 'Main/ResetCounters', '', 'tool_main_reset_counters', '113', '0', '');\nINSERT INTO `neltool_applications` VALUES ('26', 'Main/ServiceAutoStart', '', 'tool_main_service_autostart', '114', '0', '');\nINSERT INTO `neltool_applications` VALUES ('27', 'Main/ShardAutoStart', '', 'tool_main_shard_autostart', '115', '0', '');\nINSERT INTO `neltool_applications` VALUES ('28', 'Main/WS/Old', '', 'tool_main_ws_old', '112', '0', '');\nINSERT INTO `neltool_applications` VALUES ('29', 'Graphs', 'tool_graphs.php', 'tool_graph', '500', '1', 'imgs/icon_graphs.gif');\nINSERT INTO `neltool_applications` VALUES ('30', 'Notes/Global', '', 'tool_notes_global', '901', '0', '');\nINSERT INTO `neltool_applications` VALUES ('31', 'Log Analyser', 'tool_log_analyser.php', 'tool_las', '400', '1', 'imgs/icon_log_analyser.gif');\nINSERT INTO `neltool_applications` VALUES ('32', 'Guild Locator', 'tool_guild_locator.php', 'tool_guild_locator', '300', '1', 'imgs/icon_guild_locator.gif');\nINSERT INTO `neltool_applications` VALUES ('33', 'Player Locator/UserID Check', '', 'tool_player_locator_userid_check', '203', '0', '');\nINSERT INTO `neltool_applications` VALUES ('34', 'Player Locator/CSR Relocate', '', 'tool_player_locator_csr_relocate', '204', '0', '');\nINSERT INTO `neltool_applications` VALUES ('35', 'Guild Locator/Guilds Update', '', 'tool_guild_locator_manage_guild', '301', '0', '');\nINSERT INTO `neltool_applications` VALUES ('36', 'Guild Locator/Members Update', '', 'tool_guild_locator_manage_members', '302', '0', '');\nINSERT INTO `neltool_applications` VALUES ('37', 'Entities', 'tool_event_entities.php', 'tool_event_entities', '350', '1', 'imgs/icon_entity.gif');\nINSERT INTO `neltool_applications` VALUES ('38', 'Admin/Restarts', '', 'tool_admin_restart', '1507', '0', '');\nINSERT INTO `neltool_applications` VALUES ('39', 'Main/EasyRestart', '', 'tool_main_easy_restart', '116', '0', '');\nINSERT INTO `neltool_applications` VALUES ('40', '商城管理', 'tool_shop.php', 'tool_shop', '340', '1', 'imgs/shop.png');\n\n-- ----------------------------\n-- Table structure for `neltool_domains`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_domains`;\nCREATE TABLE `neltool_domains` (\n  `domain_id` int(11) NOT NULL AUTO_INCREMENT,\n  `domain_name` varchar(128) NOT NULL DEFAULT '',\n  `domain_as_host` varchar(128) NOT NULL DEFAULT '',\n  `domain_as_port` int(11) NOT NULL DEFAULT '0',\n  `domain_rrd_path` varchar(255) NOT NULL DEFAULT '',\n  `domain_las_admin_path` varchar(255) NOT NULL DEFAULT '',\n  `domain_las_local_path` varchar(255) NOT NULL DEFAULT '',\n  `domain_application` varchar(128) NOT NULL DEFAULT '',\n  `domain_sql_string` varchar(128) NOT NULL DEFAULT '',\n  `domain_hd_check` int(11) NOT NULL DEFAULT '0',\n  `domain_mfs_web` text,\n  `domain_cs_sql_string` varchar(255) DEFAULT NULL,\n  PRIMARY KEY (`domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_domains\n-- ----------------------------\nINSERT INTO `neltool_domains` VALUES ('12', '测试一区', '127.0.0.1', '46700', 'D:/MT/trunk/code/EVA/server/save_shard/rrd_graphs', '', '', 'ryzom_open', 'mysql://shard@localhost/ring_open', '0', '', 'mysql://shard@localhost/atrium_forums');\n\n-- ----------------------------\n-- Table structure for `neltool_groups`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_groups`;\nCREATE TABLE `neltool_groups` (\n  `group_id` int(11) NOT NULL AUTO_INCREMENT,\n  `group_name` varchar(32) NOT NULL DEFAULT 'NewGroup',\n  `group_level` int(11) NOT NULL DEFAULT '0',\n  `group_default` int(11) NOT NULL DEFAULT '0',\n  `group_active` int(11) NOT NULL DEFAULT '0',\n  `group_default_domain_id` tinyint(3) unsigned DEFAULT NULL,\n  `group_default_shard_id` tinyint(3) unsigned DEFAULT NULL,\n  PRIMARY KEY (`group_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_groups\n-- ----------------------------\nINSERT INTO `neltool_groups` VALUES ('1', 'AdminGroup', '0', '0', '1', '12', '255');\nINSERT INTO `neltool_groups` VALUES ('2', 'NevraxGroup', '0', '1', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('3', 'AdminDebugGroup', '10', '0', '1', '12', '255');\nINSERT INTO `neltool_groups` VALUES ('4', 'SupportSGMGroup', '0', '0', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('5', 'NevraxATSGroup', '0', '0', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('6', 'SupportGMGroup', '0', '0', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('7', 'SupportReadOnlyGroup', '0', '0', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('8', 'NevraxLevelDesigners', '0', '0', '1', null, null);\nINSERT INTO `neltool_groups` VALUES ('9', 'NevraxReadOnlyGroup', '0', '0', '1', '9', '56');\nINSERT INTO `neltool_groups` VALUES ('10', 'YubDevGroup', '0', '0', '1', '12', '106');\nINSERT INTO `neltool_groups` VALUES ('11', 'GuestGroup', '0', '0', '1', '12', '106');\n\n-- ----------------------------\n-- Table structure for `neltool_group_applications`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_group_applications`;\nCREATE TABLE `neltool_group_applications` (\n  `group_application_id` int(11) NOT NULL AUTO_INCREMENT,\n  `group_application_group_id` int(11) NOT NULL DEFAULT '0',\n  `group_application_application_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`group_application_id`),\n  KEY `group_application_group_id` (`group_application_group_id`),\n  KEY `group_application_application_id` (`group_application_application_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=1003 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_group_applications\n-- ----------------------------\nINSERT INTO `neltool_group_applications` VALUES ('879', '1', '10');\nINSERT INTO `neltool_group_applications` VALUES ('878', '1', '8');\nINSERT INTO `neltool_group_applications` VALUES ('877', '1', '7');\nINSERT INTO `neltool_group_applications` VALUES ('876', '1', '9');\nINSERT INTO `neltool_group_applications` VALUES ('875', '1', '5');\nINSERT INTO `neltool_group_applications` VALUES ('874', '1', '6');\nINSERT INTO `neltool_group_applications` VALUES ('873', '1', '3');\nINSERT INTO `neltool_group_applications` VALUES ('872', '1', '4');\nINSERT INTO `neltool_group_applications` VALUES ('871', '1', '30');\nINSERT INTO `neltool_group_applications` VALUES ('870', '1', '18');\nINSERT INTO `neltool_group_applications` VALUES ('869', '1', '29');\nINSERT INTO `neltool_group_applications` VALUES ('868', '1', '31');\nINSERT INTO `neltool_group_applications` VALUES ('867', '1', '37');\nINSERT INTO `neltool_group_applications` VALUES ('866', '1', '36');\nINSERT INTO `neltool_group_applications` VALUES ('865', '1', '35');\nINSERT INTO `neltool_group_applications` VALUES ('864', '1', '32');\nINSERT INTO `neltool_group_applications` VALUES ('863', '1', '34');\nINSERT INTO `neltool_group_applications` VALUES ('862', '1', '33');\nINSERT INTO `neltool_group_applications` VALUES ('861', '1', '21');\nINSERT INTO `neltool_group_applications` VALUES ('860', '1', '20');\nINSERT INTO `neltool_group_applications` VALUES ('859', '1', '19');\nINSERT INTO `neltool_group_applications` VALUES ('858', '1', '39');\nINSERT INTO `neltool_group_applications` VALUES ('857', '1', '27');\nINSERT INTO `neltool_group_applications` VALUES ('856', '1', '26');\nINSERT INTO `neltool_group_applications` VALUES ('1001', '3', '10');\nINSERT INTO `neltool_group_applications` VALUES ('1000', '3', '8');\nINSERT INTO `neltool_group_applications` VALUES ('999', '3', '7');\nINSERT INTO `neltool_group_applications` VALUES ('998', '3', '9');\nINSERT INTO `neltool_group_applications` VALUES ('997', '3', '5');\nINSERT INTO `neltool_group_applications` VALUES ('996', '3', '6');\nINSERT INTO `neltool_group_applications` VALUES ('995', '3', '3');\nINSERT INTO `neltool_group_applications` VALUES ('994', '3', '4');\nINSERT INTO `neltool_group_applications` VALUES ('993', '3', '30');\nINSERT INTO `neltool_group_applications` VALUES ('992', '3', '18');\nINSERT INTO `neltool_group_applications` VALUES ('991', '3', '29');\nINSERT INTO `neltool_group_applications` VALUES ('990', '3', '31');\nINSERT INTO `neltool_group_applications` VALUES ('989', '3', '37');\nINSERT INTO `neltool_group_applications` VALUES ('988', '3', '36');\nINSERT INTO `neltool_group_applications` VALUES ('987', '3', '35');\nINSERT INTO `neltool_group_applications` VALUES ('986', '3', '32');\nINSERT INTO `neltool_group_applications` VALUES ('985', '3', '40');\nINSERT INTO `neltool_group_applications` VALUES ('984', '3', '34');\nINSERT INTO `neltool_group_applications` VALUES ('983', '3', '33');\nINSERT INTO `neltool_group_applications` VALUES ('982', '3', '21');\nINSERT INTO `neltool_group_applications` VALUES ('981', '3', '20');\nINSERT INTO `neltool_group_applications` VALUES ('980', '3', '19');\nINSERT INTO `neltool_group_applications` VALUES ('979', '3', '39');\nINSERT INTO `neltool_group_applications` VALUES ('978', '3', '27');\nINSERT INTO `neltool_group_applications` VALUES ('597', '4', '36');\nINSERT INTO `neltool_group_applications` VALUES ('596', '4', '35');\nINSERT INTO `neltool_group_applications` VALUES ('595', '4', '32');\nINSERT INTO `neltool_group_applications` VALUES ('594', '4', '21');\nINSERT INTO `neltool_group_applications` VALUES ('593', '4', '20');\nINSERT INTO `neltool_group_applications` VALUES ('592', '4', '19');\nINSERT INTO `neltool_group_applications` VALUES ('591', '4', '24');\nINSERT INTO `neltool_group_applications` VALUES ('590', '4', '23');\nINSERT INTO `neltool_group_applications` VALUES ('589', '4', '14');\nINSERT INTO `neltool_group_applications` VALUES ('588', '4', '12');\nINSERT INTO `neltool_group_applications` VALUES ('632', '2', '18');\nINSERT INTO `neltool_group_applications` VALUES ('631', '2', '37');\nINSERT INTO `neltool_group_applications` VALUES ('630', '2', '32');\nINSERT INTO `neltool_group_applications` VALUES ('629', '2', '21');\nINSERT INTO `neltool_group_applications` VALUES ('628', '2', '20');\nINSERT INTO `neltool_group_applications` VALUES ('627', '2', '19');\nINSERT INTO `neltool_group_applications` VALUES ('626', '2', '24');\nINSERT INTO `neltool_group_applications` VALUES ('625', '2', '23');\nINSERT INTO `neltool_group_applications` VALUES ('624', '2', '22');\nINSERT INTO `neltool_group_applications` VALUES ('623', '2', '16');\nINSERT INTO `neltool_group_applications` VALUES ('622', '2', '15');\nINSERT INTO `neltool_group_applications` VALUES ('621', '2', '14');\nINSERT INTO `neltool_group_applications` VALUES ('620', '2', '13');\nINSERT INTO `neltool_group_applications` VALUES ('977', '3', '26');\nINSERT INTO `neltool_group_applications` VALUES ('855', '1', '25');\nINSERT INTO `neltool_group_applications` VALUES ('619', '2', '12');\nINSERT INTO `neltool_group_applications` VALUES ('976', '3', '25');\nINSERT INTO `neltool_group_applications` VALUES ('854', '1', '28');\nINSERT INTO `neltool_group_applications` VALUES ('975', '3', '28');\nINSERT INTO `neltool_group_applications` VALUES ('718', '5', '18');\nINSERT INTO `neltool_group_applications` VALUES ('717', '5', '37');\nINSERT INTO `neltool_group_applications` VALUES ('716', '5', '32');\nINSERT INTO `neltool_group_applications` VALUES ('715', '5', '21');\nINSERT INTO `neltool_group_applications` VALUES ('714', '5', '20');\nINSERT INTO `neltool_group_applications` VALUES ('713', '5', '19');\nINSERT INTO `neltool_group_applications` VALUES ('712', '5', '27');\nINSERT INTO `neltool_group_applications` VALUES ('711', '5', '26');\nINSERT INTO `neltool_group_applications` VALUES ('710', '5', '24');\nINSERT INTO `neltool_group_applications` VALUES ('709', '5', '23');\nINSERT INTO `neltool_group_applications` VALUES ('708', '5', '22');\nINSERT INTO `neltool_group_applications` VALUES ('707', '5', '16');\nINSERT INTO `neltool_group_applications` VALUES ('706', '5', '15');\nINSERT INTO `neltool_group_applications` VALUES ('705', '5', '14');\nINSERT INTO `neltool_group_applications` VALUES ('974', '3', '24');\nINSERT INTO `neltool_group_applications` VALUES ('609', '6', '35');\nINSERT INTO `neltool_group_applications` VALUES ('608', '6', '32');\nINSERT INTO `neltool_group_applications` VALUES ('607', '6', '21');\nINSERT INTO `neltool_group_applications` VALUES ('606', '6', '20');\nINSERT INTO `neltool_group_applications` VALUES ('605', '6', '19');\nINSERT INTO `neltool_group_applications` VALUES ('604', '6', '24');\nINSERT INTO `neltool_group_applications` VALUES ('603', '6', '23');\nINSERT INTO `neltool_group_applications` VALUES ('602', '6', '14');\nINSERT INTO `neltool_group_applications` VALUES ('601', '6', '12');\nINSERT INTO `neltool_group_applications` VALUES ('600', '6', '11');\nINSERT INTO `neltool_group_applications` VALUES ('973', '3', '23');\nINSERT INTO `neltool_group_applications` VALUES ('972', '3', '22');\nINSERT INTO `neltool_group_applications` VALUES ('853', '1', '24');\nINSERT INTO `neltool_group_applications` VALUES ('704', '5', '13');\nINSERT INTO `neltool_group_applications` VALUES ('703', '5', '12');\nINSERT INTO `neltool_group_applications` VALUES ('852', '1', '23');\nINSERT INTO `neltool_group_applications` VALUES ('587', '4', '11');\nINSERT INTO `neltool_group_applications` VALUES ('618', '2', '11');\nINSERT INTO `neltool_group_applications` VALUES ('702', '5', '11');\nINSERT INTO `neltool_group_applications` VALUES ('612', '7', '19');\nINSERT INTO `neltool_group_applications` VALUES ('851', '1', '22');\nINSERT INTO `neltool_group_applications` VALUES ('971', '3', '16');\nINSERT INTO `neltool_group_applications` VALUES ('970', '3', '15');\nINSERT INTO `neltool_group_applications` VALUES ('598', '4', '18');\nINSERT INTO `neltool_group_applications` VALUES ('599', '4', '4');\nINSERT INTO `neltool_group_applications` VALUES ('610', '6', '18');\nINSERT INTO `neltool_group_applications` VALUES ('611', '6', '4');\nINSERT INTO `neltool_group_applications` VALUES ('613', '7', '20');\nINSERT INTO `neltool_group_applications` VALUES ('614', '7', '21');\nINSERT INTO `neltool_group_applications` VALUES ('615', '7', '32');\nINSERT INTO `neltool_group_applications` VALUES ('616', '7', '35');\nINSERT INTO `neltool_group_applications` VALUES ('617', '7', '4');\nINSERT INTO `neltool_group_applications` VALUES ('633', '2', '4');\nINSERT INTO `neltool_group_applications` VALUES ('969', '3', '14');\nINSERT INTO `neltool_group_applications` VALUES ('968', '3', '13');\nINSERT INTO `neltool_group_applications` VALUES ('850', '1', '16');\nINSERT INTO `neltool_group_applications` VALUES ('849', '1', '15');\nINSERT INTO `neltool_group_applications` VALUES ('848', '1', '14');\nINSERT INTO `neltool_group_applications` VALUES ('847', '1', '13');\nINSERT INTO `neltool_group_applications` VALUES ('846', '1', '12');\nINSERT INTO `neltool_group_applications` VALUES ('719', '5', '4');\nINSERT INTO `neltool_group_applications` VALUES ('720', '8', '11');\nINSERT INTO `neltool_group_applications` VALUES ('721', '8', '12');\nINSERT INTO `neltool_group_applications` VALUES ('722', '8', '13');\nINSERT INTO `neltool_group_applications` VALUES ('723', '8', '14');\nINSERT INTO `neltool_group_applications` VALUES ('724', '8', '15');\nINSERT INTO `neltool_group_applications` VALUES ('725', '8', '16');\nINSERT INTO `neltool_group_applications` VALUES ('726', '8', '22');\nINSERT INTO `neltool_group_applications` VALUES ('727', '8', '23');\nINSERT INTO `neltool_group_applications` VALUES ('728', '8', '24');\nINSERT INTO `neltool_group_applications` VALUES ('729', '8', '25');\nINSERT INTO `neltool_group_applications` VALUES ('730', '8', '26');\nINSERT INTO `neltool_group_applications` VALUES ('731', '8', '27');\nINSERT INTO `neltool_group_applications` VALUES ('732', '8', '19');\nINSERT INTO `neltool_group_applications` VALUES ('733', '8', '20');\nINSERT INTO `neltool_group_applications` VALUES ('734', '8', '21');\nINSERT INTO `neltool_group_applications` VALUES ('735', '8', '37');\nINSERT INTO `neltool_group_applications` VALUES ('736', '8', '4');\nINSERT INTO `neltool_group_applications` VALUES ('737', '9', '29');\nINSERT INTO `neltool_group_applications` VALUES ('738', '9', '4');\nINSERT INTO `neltool_group_applications` VALUES ('967', '3', '12');\nINSERT INTO `neltool_group_applications` VALUES ('845', '1', '11');\nINSERT INTO `neltool_group_applications` VALUES ('966', '3', '11');\nINSERT INTO `neltool_group_applications` VALUES ('880', '1', '38');\nINSERT INTO `neltool_group_applications` VALUES ('909', '10', '18');\nINSERT INTO `neltool_group_applications` VALUES ('908', '10', '29');\nINSERT INTO `neltool_group_applications` VALUES ('907', '10', '37');\nINSERT INTO `neltool_group_applications` VALUES ('906', '10', '36');\nINSERT INTO `neltool_group_applications` VALUES ('905', '10', '35');\nINSERT INTO `neltool_group_applications` VALUES ('904', '10', '32');\nINSERT INTO `neltool_group_applications` VALUES ('903', '10', '34');\nINSERT INTO `neltool_group_applications` VALUES ('902', '10', '33');\nINSERT INTO `neltool_group_applications` VALUES ('901', '10', '21');\nINSERT INTO `neltool_group_applications` VALUES ('900', '10', '20');\nINSERT INTO `neltool_group_applications` VALUES ('899', '10', '19');\nINSERT INTO `neltool_group_applications` VALUES ('898', '10', '23');\nINSERT INTO `neltool_group_applications` VALUES ('897', '10', '13');\nINSERT INTO `neltool_group_applications` VALUES ('910', '10', '30');\nINSERT INTO `neltool_group_applications` VALUES ('965', '11', '29');\nINSERT INTO `neltool_group_applications` VALUES ('964', '11', '37');\nINSERT INTO `neltool_group_applications` VALUES ('963', '11', '32');\nINSERT INTO `neltool_group_applications` VALUES ('962', '11', '34');\nINSERT INTO `neltool_group_applications` VALUES ('961', '11', '33');\nINSERT INTO `neltool_group_applications` VALUES ('960', '11', '21');\nINSERT INTO `neltool_group_applications` VALUES ('959', '11', '20');\nINSERT INTO `neltool_group_applications` VALUES ('958', '11', '19');\nINSERT INTO `neltool_group_applications` VALUES ('1002', '3', '38');\n\n-- ----------------------------\n-- Table structure for `neltool_group_domains`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_group_domains`;\nCREATE TABLE `neltool_group_domains` (\n  `group_domain_id` int(11) NOT NULL AUTO_INCREMENT,\n  `group_domain_group_id` int(11) NOT NULL DEFAULT '0',\n  `group_domain_domain_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`group_domain_id`),\n  KEY `group_domain_group_id` (`group_domain_group_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=91 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_group_domains\n-- ----------------------------\nINSERT INTO `neltool_group_domains` VALUES ('76', '1', '12');\nINSERT INTO `neltool_group_domains` VALUES ('90', '3', '12');\nINSERT INTO `neltool_group_domains` VALUES ('89', '11', '12');\n\n-- ----------------------------\n-- Table structure for `neltool_group_shards`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_group_shards`;\nCREATE TABLE `neltool_group_shards` (\n  `group_shard_id` int(11) NOT NULL AUTO_INCREMENT,\n  `group_shard_group_id` int(11) NOT NULL DEFAULT '0',\n  `group_shard_shard_id` int(11) NOT NULL DEFAULT '0',\n  `group_shard_domain_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`group_shard_id`),\n  KEY `group_shard_group_id` (`group_shard_group_id`),\n  KEY `group_shard_domain_id` (`group_shard_domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=1523 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_group_shards\n-- ----------------------------\nINSERT INTO `neltool_group_shards` VALUES ('1490', '1', '302', '12');\nINSERT INTO `neltool_group_shards` VALUES ('1522', '3', '302', '12');\nINSERT INTO `neltool_group_shards` VALUES ('1521', '11', '302', '12');\n\n-- ----------------------------\n-- Table structure for `neltool_locks`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_locks`;\nCREATE TABLE `neltool_locks` (\n  `lock_id` int(11) NOT NULL AUTO_INCREMENT,\n  `lock_domain_id` int(11) DEFAULT NULL,\n  `lock_shard_id` int(11) DEFAULT NULL,\n  `lock_user_name` varchar(32) NOT NULL DEFAULT '',\n  `lock_date` int(11) NOT NULL DEFAULT '0',\n  `lock_update` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`lock_id`),\n  UNIQUE KEY `lock_shard_id` (`lock_shard_id`),\n  UNIQUE KEY `lock_domain_id` (`lock_domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_locks\n-- ----------------------------\nINSERT INTO `neltool_locks` VALUES ('18', null, '302', 'admin', '1410346920', '1410346920');\n\n-- ----------------------------\n-- Table structure for `neltool_logs`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_logs`;\nCREATE TABLE `neltool_logs` (\n  `logs_id` int(11) NOT NULL AUTO_INCREMENT,\n  `logs_user_name` varchar(32) NOT NULL DEFAULT '0',\n  `logs_date` int(11) NOT NULL DEFAULT '0',\n  `logs_data` varchar(255) NOT NULL DEFAULT '',\n  PRIMARY KEY (`logs_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=258 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_logs\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for `neltool_notes`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_notes`;\nCREATE TABLE `neltool_notes` (\n  `note_id` int(11) NOT NULL AUTO_INCREMENT,\n  `note_user_id` int(11) NOT NULL DEFAULT '0',\n  `note_title` varchar(128) NOT NULL DEFAULT '',\n  `note_data` text NOT NULL,\n  `note_date` int(11) NOT NULL DEFAULT '0',\n  `note_active` int(11) NOT NULL DEFAULT '0',\n  `note_global` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`note_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_notes\n-- ----------------------------\nINSERT INTO `neltool_notes` VALUES ('2', '27', 'Welcome', 'Welcome to the shard administration website!\\r\\n\\r\\nThis website is used to monitor and restart shards.\\r\\n\\r\\nIt also gives some player characters information.', '1272378065', '1', '1');\nINSERT INTO `neltool_notes` VALUES ('3', '27', 'Shard Start', '# At the same time : NS and TS\\r\\n[1 min] : all MS, you can boot them all at the same time\\r\\n[1 min] : IOS\\r\\n[3 mins] : GMPS\\r\\n[3 mins] : EGS\\r\\n[5 mins] : AI Fyros\\r\\n[1 min 30] : AI Zorai\\r\\n[1 min 30] : AI Matis\\r\\n[1 min 30] : AI TNP\\r\\n[1 min 30] : AI NPE\\r\\n[1 min 30] : AI Tryker\\r\\n[1 min 30] : All FS and SBS at the same time\\r\\n[30 secs] : WS (atm the WS starts in OPEN mode by default, so be fast before CSR checkage, fix for that inc soon)\\r\\n\\r\\nNOTE: you can check the uptime for those timers in the right column of the admin tool: UpTime\\r\\n', '1158751126', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('5', '27', 'shutting supplementary', 'the writing wont change when lock the ws\\r\\n\\r\\nuntick previous boxes as you shut down\\r\\n\\r\\nwait 5 between the ws and the egs ie egs is 5 past rest is 10 past', '1153395380', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('4', '27', 'Shard Stop', '1. Broadcast to warn players\\r\\n\\r\\n2. 10 mins before shutdown, lock the WS\\r\\n\\r\\n3. At the right time shut down WS\\r\\n\\r\\n4. Shut down EGS\\r\\nOnly the EGS. Wait 5 reals minutes. Goal is to give enough time to egs, in order to save all the info he has to, and letting him sending those message to all services who need it.\\r\\n\\r\\n5. Shut down the rest, et voil&agrave;, you&#039;re done.', '1153314198', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('6', '27', 'Start (EGS to high?)', 'If [EGS] is to high on startup:\\r\\n\\r\\n[shut down egs]\\r\\n[5 mins]\\r\\n\\r\\n[IOS] &amp; [GPMS] (shut down at same time)\\r\\n\\r\\nAfter the services are down follow &quot;UP&quot; process with timers again.\\r\\n\\r\\nIOS\\r\\n[3 mins]\\r\\nGPMS\\r\\n[3 mins]\\r\\nEGS\\r\\n[5 mins]\\r\\nbla bla...', '1153395097', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('7', '27', 'opening if the egs is too high on reboot', '&lt;kadael&gt; here my note on admin about egs to high on startup\\r\\n&lt;kadael&gt; ---\\r\\n&lt;kadael&gt; If [EGS] is to high on startup:\\r\\n&lt;kadael&gt; [shut down egs]\\r\\n&lt;kadael&gt; [5 mins]\\r\\n&lt;kadael&gt; [IOS] &amp; [GPMS] (at same time shut down )\\r\\n&lt;kadael&gt; after the services are down follow &quot;UP&quot; process with timers again.\\r\\n&lt;kadael&gt; IOS\\r\\n&lt;kadael&gt; [3 mins]\\r\\n&lt;kadael&gt; GPMS\\r\\n&lt;kadael&gt; [3 mins]\\r\\n&lt;kadael&gt; EGS\\r\\n&lt;kadael&gt; [5 mins]\\r\\n&lt;kadael&gt; bla bla...\\r\\n&lt;kadael&gt; ---', '1153395362', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('10', '27', 'Ring points', 'Commande pour donner tout les points ring &agrave; tout le monde :\\r\\n\\r\\nDans le DSS d&#039;un Shard Ring entrer : DefaultCharRingAccess f7:j7:l6:d7:p13:g9:a9', '1155722296', '1', '0');\nINSERT INTO `neltool_notes` VALUES ('9', '27', 'Start (EGS to high?)', 'If [EGS] is to high on startup: \\r\\n  \\r\\n [shut down egs] \\r\\n [5 mins] \\r\\n  \\r\\n [IOS] &amp; [GPMS] (shut down at same time) \\r\\n  \\r\\n After the services are down follow &quot;UP&quot; process with timers again. \\r\\n  \\r\\n IOS \\r\\n [3 mins] \\r\\n GPMS \\r\\n [3 mins] \\r\\n EGS \\r\\n [5 mins] \\r\\n bla bla...', '1153929658', '1', '0');\n\n-- ----------------------------\n-- Table structure for `neltool_restart_groups`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_restart_groups`;\nCREATE TABLE `neltool_restart_groups` (\n  `restart_group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `restart_group_name` varchar(50) DEFAULT NULL,\n  `restart_group_list` varchar(50) DEFAULT NULL,\n  `restart_group_order` varchar(50) DEFAULT NULL,\n  PRIMARY KEY (`restart_group_id`),\n  UNIQUE KEY `restart_group_id` (`restart_group_id`),\n  KEY `restart_group_id_2` (`restart_group_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_restart_groups\n-- ----------------------------\nINSERT INTO `neltool_restart_groups` VALUES ('1', 'Low Level', 'rns,ts,ms', '1');\nINSERT INTO `neltool_restart_groups` VALUES ('3', 'Mid Level', 'ios,gpms,egs', '2');\nINSERT INTO `neltool_restart_groups` VALUES ('4', 'High Level', 'ais', '3');\nINSERT INTO `neltool_restart_groups` VALUES ('5', 'Front Level', 'fes,sbs,dss,rws', '4');\n\n-- ----------------------------\n-- Table structure for `neltool_restart_messages`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_restart_messages`;\nCREATE TABLE `neltool_restart_messages` (\n  `restart_message_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `restart_message_name` varchar(20) DEFAULT NULL,\n  `restart_message_value` varchar(128) DEFAULT NULL,\n  `restart_message_lang` varchar(5) DEFAULT NULL,\n  PRIMARY KEY (`restart_message_id`),\n  UNIQUE KEY `restart_message_id` (`restart_message_id`),\n  KEY `restart_message_id_2` (`restart_message_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_restart_messages\n-- ----------------------------\nINSERT INTO `neltool_restart_messages` VALUES ('5', 'reboot', 'The shard is about to go down. Please find a safe location and log out.', 'en');\nINSERT INTO `neltool_restart_messages` VALUES ('4', 'reboot', 'Le serveur va redemarrer dans $minutes$ minutes. Merci de vous deconnecter en lieu sur.', 'fr');\nINSERT INTO `neltool_restart_messages` VALUES ('6', 'reboot', 'Der Server wird heruntergefahren. Findet eine sichere Stelle und logt aus.', 'de');\nINSERT INTO `neltool_restart_messages` VALUES ('10', 'reboot', 'Arret du serveur dans $minutes+1$ minutes', 'fr');\n\n-- ----------------------------\n-- Table structure for `neltool_restart_sequences`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_restart_sequences`;\nCREATE TABLE `neltool_restart_sequences` (\n  `restart_sequence_id` int(10) unsigned NOT NULL AUTO_INCREMENT,\n  `restart_sequence_domain_id` int(10) unsigned NOT NULL DEFAULT '0',\n  `restart_sequence_shard_id` int(10) unsigned NOT NULL DEFAULT '0',\n  `restart_sequence_user_name` varchar(50) DEFAULT NULL,\n  `restart_sequence_step` int(10) unsigned NOT NULL DEFAULT '0',\n  `restart_sequence_date_start` int(11) DEFAULT NULL,\n  `restart_sequence_date_end` int(11) DEFAULT NULL,\n  `restart_sequence_timer` int(11) unsigned DEFAULT '0',\n  PRIMARY KEY (`restart_sequence_id`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_restart_sequences\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for `neltool_shards`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_shards`;\nCREATE TABLE `neltool_shards` (\n  `shard_id` int(11) NOT NULL AUTO_INCREMENT,\n  `shard_name` varchar(128) NOT NULL DEFAULT '',\n  `shard_as_id` varchar(255) NOT NULL DEFAULT '0',\n  `shard_domain_id` int(11) NOT NULL DEFAULT '0',\n  `shard_lang` char(2) NOT NULL DEFAULT 'en',\n  `shard_restart` int(10) unsigned NOT NULL DEFAULT '0',\n  PRIMARY KEY (`shard_id`),\n  KEY `shard_domain_id` (`shard_domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=303 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_shards\n-- ----------------------------\nINSERT INTO `neltool_shards` VALUES ('302', '测试一区', '测试一区', '12', 'en', '0');\n\n-- ----------------------------\n-- Table structure for `neltool_stats_hd_datas`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_stats_hd_datas`;\nCREATE TABLE `neltool_stats_hd_datas` (\n  `hd_id` int(11) NOT NULL AUTO_INCREMENT,\n  `hd_domain_id` int(11) NOT NULL DEFAULT '0',\n  `hd_server` varchar(32) NOT NULL DEFAULT '',\n  `hd_device` varchar(64) NOT NULL DEFAULT '',\n  `hd_size` varchar(16) NOT NULL DEFAULT '',\n  `hd_used` varchar(16) NOT NULL DEFAULT '',\n  `hd_free` varchar(16) NOT NULL DEFAULT '',\n  `hd_percent` int(11) NOT NULL DEFAULT '0',\n  `hd_mount` varchar(128) NOT NULL DEFAULT '',\n  PRIMARY KEY (`hd_id`),\n  KEY `hd_domain_id` (`hd_domain_id`),\n  KEY `hd_server` (`hd_server`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_stats_hd_datas\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for `neltool_stats_hd_times`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_stats_hd_times`;\nCREATE TABLE `neltool_stats_hd_times` (\n  `hd_domain_id` int(11) NOT NULL DEFAULT '0',\n  `hd_last_time` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`hd_domain_id`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_stats_hd_times\n-- ----------------------------\n\n-- ----------------------------\n-- Table structure for `neltool_users`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_users`;\nCREATE TABLE `neltool_users` (\n  `user_id` int(11) NOT NULL AUTO_INCREMENT,\n  `user_name` varchar(32) NOT NULL DEFAULT '',\n  `user_password` varchar(64) NOT NULL DEFAULT '',\n  `user_group_id` int(11) NOT NULL DEFAULT '0',\n  `user_created` int(11) NOT NULL DEFAULT '0',\n  `user_active` int(11) NOT NULL DEFAULT '0',\n  `user_logged_last` int(11) NOT NULL DEFAULT '0',\n  `user_logged_count` int(11) NOT NULL DEFAULT '0',\n  `user_menu_style` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`user_id`),\n  UNIQUE KEY `user_login` (`user_name`),\n  KEY `user_group_id` (`user_group_id`),\n  KEY `user_active` (`user_active`)\n) ENGINE=MyISAM AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_users\n-- ----------------------------\nINSERT INTO `neltool_users` VALUES ('27', 'admin', '084e0343a0486ff05530df6c705c8bb4', '3', '1213886454', '1', '1409731772', '383', '2');\nINSERT INTO `neltool_users` VALUES ('32', 'guest', '084e0343a0486ff05530df6c705c8bb4', '11', '1272379014', '1', '1273335407', '273', '2');\n\n-- ----------------------------\n-- Table structure for `neltool_user_applications`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_user_applications`;\nCREATE TABLE `neltool_user_applications` (\n  `user_application_id` int(11) NOT NULL AUTO_INCREMENT,\n  `user_application_user_id` int(11) NOT NULL DEFAULT '0',\n  `user_application_application_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`user_application_id`),\n  KEY `user_application_user_id` (`user_application_user_id`),\n  KEY `user_application_application_id` (`user_application_application_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_user_applications\n-- ----------------------------\nINSERT INTO `neltool_user_applications` VALUES ('8', '12', '33');\nINSERT INTO `neltool_user_applications` VALUES ('20', '6', '31');\nINSERT INTO `neltool_user_applications` VALUES ('19', '6', '34');\nINSERT INTO `neltool_user_applications` VALUES ('9', '12', '31');\nINSERT INTO `neltool_user_applications` VALUES ('21', '10', '34');\n\n-- ----------------------------\n-- Table structure for `neltool_user_domains`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_user_domains`;\nCREATE TABLE `neltool_user_domains` (\n  `user_domain_id` int(11) NOT NULL AUTO_INCREMENT,\n  `user_domain_user_id` int(11) NOT NULL DEFAULT '0',\n  `user_domain_domain_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`user_domain_id`),\n  KEY `user_domain_user_id` (`user_domain_user_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_user_domains\n-- ----------------------------\nINSERT INTO `neltool_user_domains` VALUES ('5', '6', '2');\nINSERT INTO `neltool_user_domains` VALUES ('9', '22', '1');\nINSERT INTO `neltool_user_domains` VALUES ('10', '23', '4');\nINSERT INTO `neltool_user_domains` VALUES ('4', '12', '3');\nINSERT INTO `neltool_user_domains` VALUES ('6', '6', '3');\nINSERT INTO `neltool_user_domains` VALUES ('11', '23', '2');\nINSERT INTO `neltool_user_domains` VALUES ('12', '23', '1');\nINSERT INTO `neltool_user_domains` VALUES ('13', '23', '8');\nINSERT INTO `neltool_user_domains` VALUES ('18', '15', '1');\nINSERT INTO `neltool_user_domains` VALUES ('17', '15', '2');\nINSERT INTO `neltool_user_domains` VALUES ('19', '31', '9');\n\n-- ----------------------------\n-- Table structure for `neltool_user_shards`\n-- ----------------------------\nDROP TABLE IF EXISTS `neltool_user_shards`;\nCREATE TABLE `neltool_user_shards` (\n  `user_shard_id` int(11) NOT NULL AUTO_INCREMENT,\n  `user_shard_user_id` int(11) NOT NULL DEFAULT '0',\n  `user_shard_shard_id` int(11) NOT NULL DEFAULT '0',\n  `user_shard_domain_id` int(11) NOT NULL DEFAULT '0',\n  PRIMARY KEY (`user_shard_id`),\n  KEY `user_shard_user_id` (`user_shard_user_id`),\n  KEY `user_shard_domain_id` (`user_shard_domain_id`)\n) ENGINE=MyISAM AUTO_INCREMENT=166 DEFAULT CHARSET=utf8;\n\n-- ----------------------------\n-- Records of neltool_user_shards\n-- ----------------------------\nINSERT INTO `neltool_user_shards` VALUES ('1', '8', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('2', '9', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('68', '7', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('143', '6', '4', '1');\nINSERT INTO `neltool_user_shards` VALUES ('142', '6', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('141', '6', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('140', '6', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('90', '23', '26', '4');\nINSERT INTO `neltool_user_shards` VALUES ('89', '23', '20', '4');\nINSERT INTO `neltool_user_shards` VALUES ('13', '14', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('14', '14', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('15', '14', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('139', '6', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('74', '17', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('73', '17', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('72', '17', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('71', '17', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('70', '17', '18', '4');\nINSERT INTO `neltool_user_shards` VALUES ('88', '23', '19', '4');\nINSERT INTO `neltool_user_shards` VALUES ('87', '23', '24', '4');\nINSERT INTO `neltool_user_shards` VALUES ('83', '23', '23', '4');\nINSERT INTO `neltool_user_shards` VALUES ('82', '23', '22', '4');\nINSERT INTO `neltool_user_shards` VALUES ('81', '23', '21', '4');\nINSERT INTO `neltool_user_shards` VALUES ('34', '12', '15', '3');\nINSERT INTO `neltool_user_shards` VALUES ('36', '18', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('138', '6', '7', '2');\nINSERT INTO `neltool_user_shards` VALUES ('80', '23', '17', '4');\nINSERT INTO `neltool_user_shards` VALUES ('79', '22', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('78', '22', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('77', '21', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('76', '21', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('75', '17', '4', '1');\nINSERT INTO `neltool_user_shards` VALUES ('69', '7', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('146', '6', '54', '3');\nINSERT INTO `neltool_user_shards` VALUES ('91', '23', '18', '4');\nINSERT INTO `neltool_user_shards` VALUES ('92', '23', '7', '2');\nINSERT INTO `neltool_user_shards` VALUES ('93', '23', '13', '2');\nINSERT INTO `neltool_user_shards` VALUES ('94', '23', '8', '2');\nINSERT INTO `neltool_user_shards` VALUES ('95', '23', '14', '2');\nINSERT INTO `neltool_user_shards` VALUES ('145', '6', '53', '3');\nINSERT INTO `neltool_user_shards` VALUES ('97', '23', '10', '2');\nINSERT INTO `neltool_user_shards` VALUES ('144', '6', '15', '3');\nINSERT INTO `neltool_user_shards` VALUES ('99', '23', '5', '1');\nINSERT INTO `neltool_user_shards` VALUES ('100', '23', '6', '1');\nINSERT INTO `neltool_user_shards` VALUES ('101', '23', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('102', '23', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('103', '23', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('104', '23', '46', '1');\nINSERT INTO `neltool_user_shards` VALUES ('105', '23', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('106', '23', '42', '1');\nINSERT INTO `neltool_user_shards` VALUES ('107', '23', '43', '1');\nINSERT INTO `neltool_user_shards` VALUES ('108', '23', '44', '1');\nINSERT INTO `neltool_user_shards` VALUES ('109', '23', '4', '1');\nINSERT INTO `neltool_user_shards` VALUES ('110', '23', '41', '8');\nINSERT INTO `neltool_user_shards` VALUES ('111', '23', '39', '8');\nINSERT INTO `neltool_user_shards` VALUES ('112', '23', '30', '8');\nINSERT INTO `neltool_user_shards` VALUES ('113', '23', '32', '8');\nINSERT INTO `neltool_user_shards` VALUES ('114', '23', '47', '8');\nINSERT INTO `neltool_user_shards` VALUES ('115', '23', '31', '8');\nINSERT INTO `neltool_user_shards` VALUES ('116', '23', '36', '8');\nINSERT INTO `neltool_user_shards` VALUES ('117', '23', '37', '8');\nINSERT INTO `neltool_user_shards` VALUES ('118', '23', '40', '8');\nINSERT INTO `neltool_user_shards` VALUES ('156', '15', '45', '1');\nINSERT INTO `neltool_user_shards` VALUES ('155', '15', '3', '1');\nINSERT INTO `neltool_user_shards` VALUES ('154', '15', '1', '1');\nINSERT INTO `neltool_user_shards` VALUES ('153', '15', '6', '1');\nINSERT INTO `neltool_user_shards` VALUES ('152', '15', '5', '1');\nINSERT INTO `neltool_user_shards` VALUES ('151', '15', '10', '2');\nINSERT INTO `neltool_user_shards` VALUES ('150', '15', '14', '2');\nINSERT INTO `neltool_user_shards` VALUES ('149', '15', '8', '2');\nINSERT INTO `neltool_user_shards` VALUES ('148', '15', '13', '2');\nINSERT INTO `neltool_user_shards` VALUES ('147', '15', '7', '2');\nINSERT INTO `neltool_user_shards` VALUES ('157', '15', '46', '1');\nINSERT INTO `neltool_user_shards` VALUES ('158', '15', '2', '1');\nINSERT INTO `neltool_user_shards` VALUES ('159', '15', '42', '1');\nINSERT INTO `neltool_user_shards` VALUES ('160', '15', '43', '1');\nINSERT INTO `neltool_user_shards` VALUES ('161', '15', '44', '1');\nINSERT INTO `neltool_user_shards` VALUES ('162', '15', '4', '1');\nINSERT INTO `neltool_user_shards` VALUES ('163', '31', '57', '9');\nINSERT INTO `neltool_user_shards` VALUES ('164', '31', '104', '9');\nINSERT INTO `neltool_user_shards` VALUES ('165', '31', '103', '9');\n"
  },
  {
    "path": "tools/server/www/login/code2accesstoken.php",
    "content": "<?php\n\n\tinclude_once('public_func.php');\n\n\terror_reporting(E_ERROR | E_PARSE);\n\tset_error_handler('err_callback');\n\n\t// For error handling, buffer all output\n\tob_start('ob_callback_r2login');\n\n\tinclude_once('config.php');\n\n\t\n    $Channel        = $_GET['Channel'];\n    $GameType       = $_GET['GameType'];\n    $JsCode         = $_GET['JsCode'];\n    $AppName        = $_GET['AppName'];\n    \n    $APPID          = $WX_APPID[$AppName];\n    $SECRET         = $WX_SECRET[$AppName];\n            \n    $RequestURL     = \"https://api.weixin.qq.com/sns/jscode2session?appid=$APPID&secret=$SECRET&js_code=$JsCode&grant_type=authorization_code\";\n    $wx_dejson      = RequestJson($RequestURL);\n\n    \n    if( !isset($wx_dejson['errcode']) && $Channel==\"WX\" )\n    {\n        $actIdDb = mysqli_connect($DBHost, $DBUserName, $DBPassword) or die(\"mysqli_connect die.\");\n\t\tmysqli_select_db ($actIdDb, $DBName) or die(\"mysqli_select_db die.\");\n        mysqli_query($actIdDb, \"SET NAMES utf8mb4\");\n        \n        $AppName        = mysqli_real_escape_string($actIdDb, $AppName);\n        $GameType       = mysqli_real_escape_string($actIdDb, $GameType);\n        $UserName       = $wx_dejson['openid'];\n        \n        $query = \"SELECT f_account_id,f_freeze_to FROM t_account_id WHERE f_name='$UserName' AND f_appname='$AppName' AND f_chal='$Channel'\";\n        $result = mysqli_query ($actIdDb, $query) or die();\n        \n        if (mysqli_num_rows($result) == 0)\n        {\n            // no user id record, build one\n            $query = \"INSERT INTO t_account_id (f_name,f_chal,f_appname) VALUES ('$UserName','$Channel','$AppName')\";\n            mysqli_query ($actIdDb, $query) or die();\n            \n            // re get\n            $query = \"SELECT f_account_id,f_freeze_to FROM t_account_id WHERE f_name='$UserName' AND f_appname='$AppName' AND f_chal='$Channel'\";\n            $result = mysqli_query ($actIdDb, $query) or die();\n        }\n        \n        \n        if (mysqli_num_rows($result) == 1)\n        {\n            $row = mysqli_fetch_array($result);\n            $freeze_to  = $row[\"f_freeze_to\"];\n            \n            \n            \n            if( time() >= $freeze_to )\n            {\n                $UserID         = $row[\"f_account_id\"];\n                $SessionKey     = $wx_dejson['session_key'];\n                $NonceStr       = RandomStr(20);\n                $Timestamp      = time();\n                \n                $login_sign_data    = $UserID . $Channel . $GameType . $AppName . $UserName . $NonceStr . $Timestamp . $SIG_KEY[$AppName];\n                $Token              = strtoupper(md5($login_sign_data));\n\n                $redata = array();\n                $redata['Token'] \t\t= $Token; \n                $redata['User']\t        = $UserName;\n                $redata['NonceStr']\t    = $NonceStr;\n                $redata['Timestamp']    = $Timestamp;\n                $redata['SessionKey']   = $SessionKey;\n                $redata['UID']          = $UserID;\n                $redata['FES']          = \"127.0.0.1:9999\";\n\n                echo json_encode($redata);\n            }\n            \n        }\n    }\n    else\n    {\n        echo $wx_dejson['errMsg'];\n    }\n\n\t// no more to do (other global statement are old garbage)\n\tdie();\n\n// ----------------------------------------------------------------------------------------\n// Functions\n// ----------------------------------------------------------------------------------------\n\n\n\n?>\n"
  },
  {
    "path": "tools/server/www/login/config.php",
    "content": "<?php\n\n// This file contains all variables needed by other php scripts\n\n$LogRelativePath = 'logs/';\n$LoginModuleIP   = \"localhost\";\n$LoginModulePort = 30001;\n\n\n// ----------------------------------------------------------------------------------------\n// Variables for database access\n// ----------------------------------------------------------------------------------------\n\n// where we can find the mysql database\n$DBHost         = \"localhost\";\n$DBUserName     = \"root\";\n$DBPassword     = \"\";\n$DBName         = \"d_mt_account\";\n\n\n$SIG_KEY['WX_5E8A']          = \"BLACKSHEEPWALL\";\n$WX_APPID['WX_5E8A']         = \"wxc1111111111111\";\n$WX_SECRET['WX_5E8A']        = \"38ccccccccccccccccccccccccccccc\";\n\n\n\n?>\n"
  },
  {
    "path": "tools/server/www/login/login_test.php",
    "content": "<?php\n    header(\"Access-Control-Allow-Origin: *\");\n\tinclude_once('public_func.php');\n\n\terror_reporting(E_ERROR | E_PARSE);\n\tset_error_handler('err_callback');\n\n\t// For error handling, buffer all output\n\tob_start('ob_callback_r2login');\n\n\tinclude_once('config.php');\n\t\n    $Channel        = $_GET['Channel'];\n    $UserName       = $_GET['User'];\n    $AppName        = $_GET['AppName'];\n    $GameType       = $_GET['GameType'];\n\n    if( $Channel == \"REG\" )\n    {\n        $actIdDb = mysqli_connect($DBHost, $DBUserName, $DBPassword) or die(\"mysqli_connect die.\");\n\t\tmysqli_select_db ($actIdDb, $DBName) or die(\"mysqli_select_db die.\");\n        mysqli_query($actIdDb, \"SET NAMES utf8mb4\");\n        \n        $UserName       = mysqli_real_escape_string($actIdDb, $UserName);\n        $AppName        = mysqli_real_escape_string($actIdDb, $AppName);\n        $GameType       = mysqli_real_escape_string($actIdDb, $GameType);\n        \n        $query = \"SELECT f_account_id,f_freeze_to FROM t_account_id WHERE f_name='$UserName' AND f_appname='$AppName' AND f_chal='$Channel'\";\n        $result = mysqli_query ($actIdDb, $query) or die();\n        \n        if (mysqli_num_rows($result) == 0)\n        {\n            // no user id record, build one\n            $query = \"INSERT INTO t_account_id (f_name,f_chal,f_appname) VALUES ('$UserName','$Channel','$AppName')\";\n            mysqli_query ($actIdDb, $query) or die();\n            \n            // re get\n            $query = \"SELECT f_account_id,f_freeze_to FROM t_account_id WHERE f_name='$UserName' AND f_appname='$AppName' AND f_chal='$Channel'\";\n            $result = mysqli_query ($actIdDb, $query) or die();\n        }\n\n        if (mysqli_num_rows($result) == 1)\n        {\n            $row = mysqli_fetch_array($result);\n            $freeze_to  = $row[\"f_freeze_to\"];\n\n            if( time() >= $freeze_to )\n            {\n                $UserID         = $row[\"f_account_id\"];\n                $NonceStr       = RandomStr(20);\n                $Timestamp      = time();\n\n                $login_sign_data    = $UserID . $Channel . $GameType . $AppName . $UserName . $NonceStr . $Timestamp . $SIG_KEY[$AppName];\n                $Token              = strtoupper(md5($login_sign_data));\n\n                $redata = array();\n                $redata['Token'] \t\t= $Token;\n                $redata['User']\t        = $UserName;\n                $redata['NonceStr']\t    = $NonceStr;\n                $redata['Timestamp']    = $Timestamp;\n                $redata['UID']          = $UserID;\n                $redata['FES']          = \"ws://127.0.0.1:9999\";\n\n                echo json_encode($redata);\n            }\n            else\n            {\n                $redata = array();\n                $redata['errcode'] \t\t= 1005; \n                $redata['errmsg']\t    = \"freezeto:\" . $freeze_to;\n                \n                echo json_encode($redata);\n            }\n            \n            die();\n        }\n    }\n\n\t// no more to do (other global statement are old garbage)\n\tdie();\n\n// ----------------------------------------------------------------------------------------\n// Functions\n// ----------------------------------------------------------------------------------------\n\n\n\n?>\n"
  },
  {
    "path": "tools/server/www/login/logs/placeholder",
    "content": " "
  },
  {
    "path": "tools/server/www/login/pay_service_itf.php",
    "content": "<?php\n\trequire_once('tools/nel_message.php');\n\n\tclass CPayServiceWeb extends CCallbackClient\n\t{\n\t\tfunction cb_unity_pay($userId, $oid)\n\t\t{\n\t\t\t$msg = new CMessage;\n\t\t\t$msg->setName(\"CBUP\");\n\t\t\t$msg->serialUint32($userId);\n\t\t\t$msg->serialUint32($oid);\n            \n            echo $userId;\n            echo $oid;\n\t\n\t\t\treturn parent::sendMessage($msg);\n\t\t}\n\n\t\tfunction waitCallback()\n\t\t{\n\t\t\t$message = parent::waitMessage();\n\n\t\t\tif ($message == false)\n\t\t\t\treturn false;\n\n\t\t\tswitch($message->MsgName)\n\t\t\t{\n\t\t\tcase \"CBUP\":\n            \n                $userId = 0;\n                $oid = 0;\n                $message->serialUint32($userId);\n                $message->serialUint32($oid);\n                \n                echo $userId;\n                echo $oid;\n                \n                break;\n\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n    \n?>\n"
  },
  {
    "path": "tools/server/www/login/public_func.php",
    "content": "<?php\n\n\tinclude_once('config.php');\n\n\t// see errorMsg\n\tfunction errorMsgBlock($errNum=GENERIC_ERROR_NUM) // $mixedArgs\n\t{\n\t\t$args = func_get_args();\n\t\treturn '0:'.call_user_func_array('errorMsg', $args);\n\t}\n\t\n\tfunction RandomKeys($length)\n\t{\n\t\t$output='';\n\t\tfor ($a = 0; $a < $length; $a++) {\n\t\t\t$output .= chr(mt_rand(33, 126));\n\t\t}\n\t\treturn $output;\n\t}\n\n\tfunction RandomNums($length)\n\t{\n\t\t$output='';\n\t\tfor ($a = 0; $a < $length; $a++) {\n\t\t\t$output .= chr(mt_rand(48, 57));\n\t\t}\n\t\treturn $output;\n\t}\n\t\n\t/**\n\t * 生成指定长度的随机字符串(包含大写英文字母, 小写英文字母, 数字)\n\t * @param $length int 需要生成的字符串的长度\n\t * @return string 包含 大小写英文字母 和 数字 的随机字符串\n\t */\n\tfunction RandomStr($length){    \n\t\t//生成一个包含 大写英文字母, 小写英文字母, 数字 的数组    \n\t\t$arr = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z'));    \n\t\t$str = '';    \n\t\t$arr_len = count($arr);    \n\t\tfor ($i = 0; $i < $length; $i++)    {        \n\t\t\t$rand = mt_rand(0, $arr_len-1);        \n\t\t\t$str.=$arr[$rand];    \n\t\t}    \n\t\treturn $str;\n\t}\n\t\n\tfunction RequestJson($RequestURL)\n\t{\n\t\t$ctx  = stream_context_create( array( 'http' => array( 'timeout' => 7 ) ) );\n\t\t$html = file_get_contents($RequestURL, 0, $ctx);\n\t\treturn json_decode($html, TRUE);\n\t}\n\t\n\tclass CWwwLog\n\t{\n\t\t//function CWwwLog() {}\n\n\t\t/*\n\t\t * Return the log directory. Create it if it does not exist, or return false if creation failed.\n\t\t */\n\t\tfunction getSafeLogDir()\n\t\t{\n\t\t\t// Examples:\n\t\t\t// __FILE__ = r:\\code\\ryzom\\www\\login\\config.php\n\t\t\t// $_SERVER['PATH_TRANSLATED'] = 'r:/code/ryzom/www/login//r2_login.php'\n\t\t\t// $_SERVER['SCRIPT_FILENAME'] = 'r:/code/ryzom/www/login//r2_login.php'\n\t\t\tglobal $LogRelativePath;\n\t\t\t$pathInfo = pathinfo(__FILE__);\n\t\t\t$logPath = $pathInfo['dirname'].'/'.$LogRelativePath;\n\t\t\tif (!is_dir($logPath))\n\t\t\t{\n\t\t\t\t$res = mkdir($LogPath, 0700);\n\t\t\t\treturn $res ? $logPath : false;\n\t\t\t}\n\t\t\treturn $logPath;\n\t\t}\n\n\t\tfunction logStr($str)\n\t\t{\n\t\t\t$logPath = $this->getSafeLogDir();\n\t\t\tif ($logPath !== false)\n\t\t\t{\n\t\t\t\t$fp = fopen($logPath.'/r2_login_'.date('Y-m-d').'.log', 'a');\n\t\t\t\tfwrite($fp, date('Y-m-d H:i:s').' ('.$_SERVER['REMOTE_ADDR'].':'.$_SERVER['REQUEST_URI'].\"): $str\\n\");\n\t\t\t\tfclose($fp);\n\t\t\t}\n\t\t}\n\t}\n\t\n\tfunction getIP()\n\t{\n\t\tstatic $realip;\n\t\tif (isset($_SERVER)){\n\t\t\tif (isset($_SERVER[\"HTTP_X_FORWARDED_FOR\"])){\n\t\t\t\t$realip = $_SERVER[\"HTTP_X_FORWARDED_FOR\"];\n\t\t\t} else if (isset($_SERVER[\"HTTP_CLIENT_IP\"])) {\n\t\t\t\t$realip = $_SERVER[\"HTTP_CLIENT_IP\"];\n\t\t\t} else {\n\t\t\t\t$realip = $_SERVER[\"REMOTE_ADDR\"];\n\t\t\t}\n\t\t} else {\n\t\t\tif (getenv(\"HTTP_X_FORWARDED_FOR\")){\n\t\t\t\t$realip = getenv(\"HTTP_X_FORWARDED_FOR\");\n\t\t\t} else if (getenv(\"HTTP_CLIENT_IP\")) {\n\t\t\t\t$realip = getenv(\"HTTP_CLIENT_IP\");\n\t\t\t} else {\n\t\t\t\t$realip = getenv(\"REMOTE_ADDR\");\n\t\t\t}\n\t\t}\n\t\treturn $realip;\n\t}\n\t\n\t// Callback called on end of output buffering\n\tfunction ob_callback_r2login($buffer)\n\t{\n\t\t// Log only in case of error or malformed result string\n\t\t$blockHd = substr($buffer, 0, 2);\n\t\tif ($blockHd != '1:')\n\t\t{\n\t\t\t$logFile = new CWwwLog();\n\t\t\t$logFile->logStr(str_replace(\"\\n\",'\\n',$buffer));\n\t\t}\n\t\treturn $buffer; // sent to output\n\t}\n\n\t// Callback called on error\n\tfunction err_callback($errno, $errmsg, $filename, $linenum, $vars)\n\t{\n\t\t$logFile = new CWwwLog();\n\t\t$logFile->logStr(\"PHP ERROR/$errno $errmsg ($filename:$linenum)\");\n\t\t// Never die after an error\n\t}\n\t\n?>\n"
  },
  {
    "path": "tools/server/www/tools/nel_message.php",
    "content": "<?php\n\t\n\t$SockTimeOut = 10;\n\t\n\tfunction debug($text)\n\t{\n//\t\tflush();\n//\t\techo $text;\n\t}\n\n\tclass CMemStream\n\t{\n\t\tvar $Buffer;\n\t\tvar $InputStream;\n\t\tvar $Pos;\n\n\t\tfunction CMemStream ()\n\t\t{\n\t\t\t$this->InputStream = false;\n\t\t\t$this->Pos = 0;\n\t\t\t$this->Buffer = \"\";\n\t\t\tdebug(\"A : \".gettype($this->Buffer).\"<br>\");\n\t\t}\n\n\t\tfunction setBuffer ($Buffer)\n\t\t{\n\t\t\t$this->InputStream = true;\n\t\t\t$this->Buffer = $Buffer;\n\t\t\t$this->Pos = 0;\n\t\t}\n\n\t\tfunction isReading () { return $this->InputStream; }\n\n\t\tfunction serialUInt8 (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$val = ord($this->Buffer{$this->Pos++});\n\t\t\t\tdebug(sprintf (\"read uint8 '%d'<br>\\n\", $val));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\tdebug(\"B\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint8 Buffer size before = %u<br>\\n\", strlen($this->Buffer)));\n\t\t\t\t$this->Buffer = $this->Buffer . chr($val & 0xFF);\n\t\t\t\t$this->Pos++;\n\t\t\tdebug(\"C\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint8 '%d' %d<br>\\n\", $val, $this->Pos));\n\t\t\tdebug(sprintf (\"write uint8 Buffer size after = %u<br>\\n\", strlen($this->Buffer)));\n\t\t\t}\n\t\t}\n\n\t\tfunction serialUInt32 (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$val = ord($this->Buffer{$this->Pos++});\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*256;\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*(double)256*256;\n\t\t\t\t$val += ord($this->Buffer{$this->Pos++})*(double)256*256*256;\n\t\t\t\tdebug(sprintf (\"read uint32 '%d'<br>\\n\", $val));\n//\t\t\t\tvar_dump($val);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\tdebug(\"D\".gettype($this->Buffer).\"<br>\");\n\t\t\t\t$this->Buffer .= chr($val & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>8) & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>16) & 0xFF);\n\t\t\t\t$this->Buffer .= chr(($val>>24) & 0xFF);\n\t\t\t\t$this->Pos += 4;\n\t\t\tdebug(\"E\".gettype($this->Buffer).\"<br>\");\n\t\t\tdebug(sprintf (\"write uint32 '%d' %d<br>\\n\", $val, $this->Pos));\n\t\t\t}\n\t\t}\n\n\t\tfunction serialString (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$this->serialUInt32($size);\n\t\t\t\tdebug(sprintf (\"read string : size = %u<br>\\n\", $size));\n\t\t\t\t$val = substr ($this->Buffer, $this->Pos, $size);\n\t\t\t\tdebug(sprintf (\"read string '%s'<br>\\n\", $val));\n\t\t\t\t$this->Pos += strlen($val);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$val_len = strlen($val);\n\t\t\t\t$this->serialUInt32($val_len);\n\t\t\t\t$this->Buffer .= $val;\n\t\t\t\t$this->Pos += strlen($val);\n\t\t\t\tdebug(sprintf (\"write string '%s' %d<br>\\n\", $val, $this->Pos));\n\t\t\t}\n\t\t}\n\t\tfunction serialEnum (&$val)\n\t\t{\n\t\t\tif ($this->isReading())\n\t\t\t{\n\t\t\t\t$intValue = 0;\n\t\t\t\t$this->serialUInt32($intValue);\n\t\t\t\t$val->fromInt((int)$intValue);\n\t\t\t\tdebug(sprintf (\"read enum '%s'<br>\\n\", $val->toString()));\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$this->serialUInt32($val->toInt());\n\t\t\t\tdebug(sprintf (\"write enum '%s' %d<br>\\n\", $val->toString(), $this->Pos));\n\t\t\t}\n\t\t}\n\t}\n\t\n\tclass CMessage extends CMemStream\n\t{\n\t\tvar $MsgName;\n\t\t\n\t\tfunction CMessage()\n\t\t{\n\t\t\t$this->CMemStream();\n\t\t}\n\t\t\n\t\tfunction setName($name)\n\t\t{\n\t\t\t$this->MsgName = $name;\n\t\t}\n\t}\n\t\n\tclass CCallbackClient\n\t{\n\t\tvar\t$ConSock = false;\n\n\t\tvar $MsgNum = 0;\n\t\t\n\t\tfunction connect($addr, $port, &$res)\n\t\t{\n\t\t\tglobal $SockTimeOut;\n\t\t\t\n\t\t\tdebug(sprintf(\"Connect<br>\"));\n\t\t\t$this->MsgNum = 0;\n\t\t\t\n\t\t\t$this->ConSock = fsockopen ($addr, $port, $errno, $errstr, $SockTimeOut);\n\t\t\tdebug(\"H\".gettype($this->ConSock).\"<br>\");\n\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\t$res = \"Can't connect to the callback server '$addr:$port' ($errno: $errstr)\";\n\t\t\t\t\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// set time out on the socket to 2 secondes\n\t\t\t\tstream_set_timeout($this->ConSock, $SockTimeOut);\t\n\t\t\t\t$res = \"\";\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\t\n\t\tfunction close()\n\t\t{\n\t\t\tif ($this->ConSock)\n\t\t\t{\n\t\t\t\tfclose($this->ConSock);\n\t\t\t\tdebug(sprintf(\"Close<br>\"));\n\t\t\t}\n\t\t\telse\n\t\t\t\tdebug(sprintf(\"Already Closed !<br>\"));\n\t\t}\n\t\t\n\t\tfunction sendMessage(&$message)\n\t\t{\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Socket is not valid\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdebug(sprintf (\"sendMessage : message Buffer is '%d'<br>\\n\", $message->Pos));\n\t\t\tdebug(sprintf (\"sendMessage : message Buffer is '%d'<br>\\n\", strlen($message->Buffer)));\n\t\t\t$hd = new CMemStream;\n\t\t\tdebug(sprintf(\"SendMessage number %u<br>\", $this->MsgNum));\n\t\t\t$hd->serialUInt32 ($this->MsgNum);\t\t\t// number the packet\n\t\t\t$this->MsgNum += 1;\n\t\t\tdebug(sprintf(\"After SendMessage, number %u<br>\", $this->MsgNum));\n\t\t\t$messageType = 0;\n\t\t\t$hd->serialUInt8 ($messageType);\n\t\t\t$hd->serialString ($message->MsgName);\n\n\t\t\tdebug(sprintf (\"sendMessage : header size is '%d'<br>\\n\", $hd->Pos));\n\t\t\t\n//\t\t\t$sb .= $message->Buffer;\n\n\t\t\t$size = $hd->Pos + $message->Pos;\n\t\t\t$Buffer = (string) chr(($size>>24)&0xFF);\n\t\t\t$Buffer .= chr(($size>>16)&0xFF);\n\t\t\t$Buffer .= chr(($size>>8)&0xFF);\n\t\t\t$Buffer .= chr($size&0xFF);\n\t\t\tdebug( \"E\".gettype($hd->Buffer).\"<br>\");\n\t\t\tdebug(\"F\".gettype($message->Buffer).\"<br>\");\n\t\t\t$Buffer .= (string) $hd->Buffer;\n\t\t\t$Buffer .= (string) $message->Buffer;\n\t\t\t\n\t\t\tdebug(\"G\".gettype($this->ConSock).\"<br>\");\n\n\t\t\tif (!fwrite ($this->ConSock, $Buffer))\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Error writing to socket\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdebug(sprintf (\"sent packet size '%d' (written size = %d) <br>\\n\", strlen($Buffer), $size));\n\t\t\tfflush ($this->ConSock);\n\t\t\t\n\t\t\treturn true;\n\t\t}\n\t\t\n\t\tfunction waitMessage()\n\t\t{\n\t\t\tif (!$this->ConSock)\n\t\t\t{\n\t\t\t\tdebug(sprintf (\"Socket is not valid\\n\"));\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t\n\n\t\t\t$size = 0;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size = ord($val) << 24;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size = ord($val) << 16;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size += ord($val) << 8;\n\t\t\t$val = fread ($this->ConSock, 1);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size += ord($val);\n\t\t\tdebug(sprintf (\"receive packet size '%d'<br>\\n\", $size));\n\t\t\t$fake = fread ($this->ConSock, 5);\n\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\tif ($info['timed_out']) \n\t\t\t{\n\t\t\t\tdebug('Connection timed out!');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t$size -= 5; // remove the fake\n\n\t\t\t$Buffer = \"\";\n\t\t\twhile ($size > 0 && strlen($Buffer) != $size)\n\t\t\t{\n\t\t\t\t$Buffer .= fread ($this->ConSock, $size - strlen($Buffer));\n\t\t\t\t$info = stream_get_meta_data($this->ConSock);\n\t\t\t\tif ($info['timed_out']) \n\t\t\t\t{\n\t\t\t\t\tdebug('Connection timed out!');\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$msgin = new CMemStream;\n\t\t\t$msgin->setBuffer ($Buffer);\n\t\t\t\n\t\t\t// decode msg name\n\t\t\t$msgin->serialString($name);\n\t\t\t\n\t\t\tdebug(sprintf(\"Message name = '%s'<BR>\", $name));\n\t\t\t$message = new CMessage;\n\t\t\t$message->setBuffer(substr($msgin->Buffer, $msgin->Pos));\n\t\t\t$message->setName($name);\n\t\t\t\n\t\t\tdebug(sprintf(\"In message name = '%s'<br>\", $message->MsgName));\n\t\t\t\n\t\t\treturn $message;\n\t\t}\n\t}\n\t\n\t\n//\tclass CSessionManagerProxy\n//\t{\n//\t\tfunction createSession($userId, $sessionType, $callbackClient)\n//\t\t{\n//\t\t\tdebug(sprintf(\"Creating session for user %u, type %s<BR>\", $userId, $sessionType));\n//\t\t\t$msg = new CMessage;\n//\t\t\t$msg->setName(\"CSS\");\n//\t\t\t$msg->serialUInt32($userId);\n//\t\t\t$msg->serialString($sessionType);\n//\t\t\t\n//\t\t\t$callbackClient->sendMessage($msg);\n//\t\t}\n//\t}\n\t\n//\tclass CSessionManagerClientSkel\n//\t{\t\n//\t\tfunction waitCallback($callbackClient)\n//\t\t{\n//\t\t\t$message = $callbackClient->waitMessage();\n//\n//\t\t\tdebug(sprintf(\"Received message '%s'<BR>\", $message->MsgName));\n//\t\t\t\n//\t\t\tswitch($message->MsgName)\n//\t\t\t{\n//\t\t\tcase \"CSSR\":\n//\t\t\t\tdebug(sprintf(\"Create session result<BR>\"));\n//\t\t\t\t$this->createSessionResult_skel($message);\n//\t\t\t\tbreak;\n//\t\t\t\t\t\n//\t\t\tcase \"CSNR\":\n//\t\t\t\tdebug(sprintf(\"Create scenario result<BR>\"));\n//\t\t\t\t$this->createScenarioResult_skel($message);\n//\t\t\t\tbreak;\n//\t\t\t};\n//\t\t}\n//\t\t\n//\t\tfunction createSessionResult_skel($message)\n//\t\t{\n//\t\t\t$userId = 0;\n//\t\t\t$sessionId = 0;\n//\t\t\t$result = false;\n//\t\t\t\n//\t\t\t$message->serialUInt32($userId);\n//\t\t\t$message->serialUInt32($sessionId);\n//\t\t\t$message->serialUInt8($result);\n//\t\t\t\n//\t\t\tcreateSessionResult($userId, $sessionId, $result);\n//\t\t}\n//\t}\n\t\n//\tprintf(\"creating callback client...<BR>\");\n//\t\n//\t$cb = new CCallbackClient;\n//\t$ret = \"\";\n//\t$cb->connect(\"192.168.0.1\", \"8060\", $ret);\n//\t\n//\t$smp = new CSessionManagerProxy;\n//\t\n//\tprintf(\"creating a new sessions...<BR>\");\n//\t$smp->createSession(10, \"st_edit\", $cb);\n//\t\n//\t$smcs = new CSessionManagerClientSkel;\n//\t$smcs->waitCallback($cb);\n//\t\n//\n//\tfunction createSessionResult($userId, $sessionId, $result)\n//\t{\n//\t\techo \"The session result for user $userId is the session $sessionId with a result of $result\\n\";\n//\t}\n//\t\n\n\t// This function connect to the AS.\n\t// If true, $res contains the url to connect.\n\t// If false, $res contains the reason why it s not okay.\n\n//\tfunction connectToAS(&$fp, &$res)\n//\t{\n//\t\tglobal\t$ASHost, $ASPort;\n///*\n//\t\t$sid = session_id();\n//\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket\");\n//\t\tif (!$result || sqlnumrows($result) == 0)\n//\t\t{\n//\t\t\t$fp = pfsockopen ($ASHost, $ASPort, $errno, $errstr, 30);\n//\t\t\techo \"opened resident socket '$fp'\\n\";\n//\t\t\t\n//\t\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket WHERE socket_id='$fp'\");\n//\t\t\tif ($result && sqlnumrows($result)>0)\n//\t\t\t\tsqlquery(\"DELETE FROM resident_socket WHERE socket_id='$fp'\");\n//\t\t\t\n//\t\t\tsqlquery(\"INSERT INTO resident_socket SET socket_id='$fp', session_id='$sid', last_access=NOW()\");\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t$result = sqlfetch($result);\n//\t\t\t$fp = $result[\"socket_id\"];\n//\t\t}\n//\t\t\n//\t\t// remove too old sockets\n//\t\tsqlquery(\"SELECT socket_id FROM resident_socket WHERE NOW()-last_access > 1800\");\n//\t\twhile ($result && ($arr=sqlfetch($result)))\n//\t\t{\n//\t\t\tfclose((int)($arr[\"socket_id\"]));\n//\t\t\tsqlquery(\"DELETE FROM resident_socket WHERE socket_id='\".$arr[\"socket_id\"].\"'\");\n//\t\t}\n//\n//\t\t// update current socket last access\n//\t\tsqlquery(\"UPDATE resident_socket SET last_access=NOW() WHERE socket_id='$fp' AND session_id='$sid'\");\n//*/\n//\n//\t\t// connect to the login service that must be $ASHost:$ASPort\n//\t\t$fp = fsockopen ($ASHost, $ASPort, $errno, $errstr, 30);\n//\t\tif (!$fp)\n//\t\t{\n//\t\t\t$res = \"Can't connect to the admin service '$ASHost:$ASPort' ($errno: $errstr)\";\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t$res = \"\";\n//\t\t}\n//\n//\t}\n//\t\n//\tfunction disconnectFromAS(&$fp)\n//\t{\n///*\n//\t\t$result = sqlquery(\"SELECT socket_id FROM resident_socket WHERE socket_id='$fp'\");\n//\t\tif (!$result || sqlnumrows($socket)==0)\n//\t\t\tfclose($fp);\n//*/\n//\t\tfclose($fp);\n//\t}\n//\n//\tfunction sendMessage ($fp, $msgout)\n//\t{\n//\t\t$size = $msgout->Pos;\n//\t\t$Buffer = chr(($size>>24)&0xFF);\n//\t\t$Buffer .= chr(($size>>16)&0xFF);\n//\t\t$Buffer .= chr(($size>>8)&0xFF);\n//\t\t$Buffer .= chr($size&0xFF);\n//\t\t$Buffer .= $msgout->Buffer;\n//\n//\t\tfwrite ($fp, $Buffer);\n//\n//\t\t//printf (\"sent packet size '%d'<br>\", strlen($Buffer));\n//\t\t\n//\t\tfflush ($fp);\n//\t}\n//\n//\tfunction waitMessage ($fp, &$msgin)\n//\t{\n//\t\t//echo \"waiting a message\";\n//\t\t$size = 0;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size = ord($val) << 24;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size = ord($val) << 16;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size += ord($val) << 8;\n//\t\t$val = fread ($fp, 1);\n//\t\t$size += ord($val);\n//\t\t//printf (\"receive packet size '%d'<br>\", $size);\n//\t\t$fake = fread ($fp, 4);\n//\t\t$size -= 4; // remove the fake\n//\n//\t\t$Buffer = fread ($fp, $size);\n//\t\t$msgin = new CMemStream;\n//\t\t$msgin->setBuffer ($Buffer);\n//\t}\n//\t\n//\tfunction logNelQuery($query)\n//\t{\n//\t\tglobal\t$uid;\n///*\n//\t\t$f = fopen(\"./nel_queries.log\", \"a\");\n//\t\tfwrite($f, date(\"Y/m/d H:i:s\").\" \".sprintf(\"%-16s\", $admlogin).\" $query\\n\");\n//\t\tfclose($f);\n//*/\n//\n//\t\tlogUser($uid, \"QUERY=\".$query);\n//\t}\n//\n//\tfunction nel_query($rawvarpath, &$result)\n//\t{\n//\t\tglobal\t\t\t$nel_queries;\n//\n//\t\t$nel_queries[] = $rawvarpath;\n//\t\t$ok = false;\n//\t\t//echo \"rawvarpath=$rawvarpath<br>\\n\";\n//\t\t\n//\t\t//logNelQuery($rawvarpath);\n//\n//\t\tconnectToAS($fp, $result);\n//\t\tif(strlen($result) != 0)\n//\t\t\treturn $ok;\n//\n//\t\t// send the message that say that we want to add a user\n//\t\t$msgout = new CMemStream;\n//\t\t$fake = 0;\n//\t\t$msgout->serialuint32 ($fake);\t\t\t// fake used to number the packet\n//\t\t$messageType = 0;\n//\t\t$msgout->serialuint8 ($messageType);\n//\t\t$msgout->serialstring ($rawvarpath);\n//\n//\t\tsendMessage ($fp, $msgout);\n//\n//\t\twaitMessage ($fp, $msgin);\n//\n//\t\t$msgin->serialstring($result);\n//\t\t\t\n//\t\tif(strlen($result) == 0)\n//\t\t{\n//\t\t\t// it failed\n//\t\t}\n//\t\telse\n//\t\t{\n//\t\t\t// it's ok\n//\t\t\t$ok = true;\n//\t\t}\n//\n//\t\t//printf(\"receive response '$result'<br>\\n\");\n//\n//\t\tdisconnectFromAS(&$fp);\n//\t\t//echo \"sent OK.<br><br>\\n\";\n//\n//\t\treturn $ok;\n//\t}\n?>\n"
  },
  {
    "path": "tools/xlsx2json/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 yulijun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "tools/xlsx2json/README.md",
    "content": "### xlsx2json ([English Document](./docs/doc_en.md))\n> 让excel支持表达复杂的json格式,将xlsx文件转成json。\n\n### 日志\n* 2017-10-31 v0.3.1\n  * 修复: 对象类型列，对象值里面有冒号值解析错误。\n  * 功能: 增加#id类型，主键索引(json格式以map形式输出，无id的表以数组格式输出)。\n  * 功能: 输出的json是否压缩可以在config.json里面配置。\n\n* 2017-10-26 v0.3.0\n  * 修复中文自动追加拼音问题。\n  * 修复日期解析错误。\n  * 去掉主外键功能(以后再追加)。\n  * 增加代码静态检查，核心代码重写并改成ES6语法。\n  * 更新依赖插件的版本。\n\n### npm相关\n* 如需当做npm模块引用请切换到`npm`分支。\n\n### 使用说明\n* 目前只支持.xlsx格式，不支持.xls格式。\n* 本项目是基于nodejs的，所以需要先安装nodejs环境。\n* 执行命令\n```bash\n# Clone this repository\ngit clone https://github.com/koalaylj/xlsx2json.git\n# Go into the repository\ncd xlsx2json\n# Install dependencies\nnpm install\n```\n\n* 配置config.json\n```javascript\n{\n    \"xlsx\": {\n        /**\n         * 表头所在的行，第一行可以是注释，第二行是表头\n         */\n        \"head\": 2,\n\n        /**\n         * xlsx文件所在的目录\n         * glob配置风格\n         */\n        \"src\": \"./excel/**/[^~$]*.xlsx\",\n\n        /**\n         * 导出的json存放的位置\n         */\n        \"dest\": \"./json\",\n\n        /**\n         * 数组的分隔符\n         * 有时候特殊需要，在excel单元格中里面逗号被当做他用。\n         * 已过时，将在v0.5.x移除。参考列类型是数组类型时候表头设置。\n         */\n        \"arraySeparator\":\",\"\n    },\n    \"json\": {\n      /**\n       * 导出的json是否需要压缩\n       * true:压缩，false:不压缩(便于阅读的格式)\n       */\n      \"uglify\": false\n    }\n}\n```\n* 执行`export.sh|export.bat`即可将`./excel/*.xlsx` 文件导成json并存放到 `./json` 下。json名字以excel的sheet名字命名。\n\n* 补充(一般用不上)：\n    * 执行`node index.js -h` 查看使用帮助。\n    * 命令行传参方式使用：执行 node `index.js --help` 查看。\n\n#### 示例1 test.xlsx\n| id   | desc         | flag   | nums#[] | words#[]    |   map#[]/   | data#{}      | hero#[{}]                     |\n| ---- | -------------| ------ | ------- | ----------- | ---------- | ------------ | --------------------------    |\n| 123  | description  | true   | 1,2     | 哈哈,呵呵     | true/true  | a:123;b:45   | id:2;level:30,id:3;level:80  |\n| 456  | 描述          | false  | 3,5,8   | shit,my god | false/true | a:11;b:22    | id:9;level:38,id:17;level:100 |\n\n\n输出如下：\n\n```json\n[{\n    \"id\": 123,\n    \"desc\": \"description\",\n    \"flag\": true,\n    \"nums\": [1, 2],\n    \"words\": [\"哈哈\", \"呵呵\"],\n    \"map\": [true, true],\n    \"data\": {\n        \"a\": 123,\n        \"b\": 45\n    },\n    \"hero\": [\n      {\"id\": 2,\"level\": 30},\n      {\"id\": 3,\"level\": 80}\n    ]\n}, {\n    \"id\": 456,\n    \"desc\": \"描述\",\n    \"flag\": false,\n    \"nums\": [3, 5, 8],\n    \"words\": [\"shit\", \"my god\"],\n    \"map\": [false, true],\n    \"data\": {\n        \"a\": 11,\n        \"b\": 22\n    },\n    \"hero\": [\n      {\"id\": 9, \"level\": 38 },\n      {\"id\": 17,\"level\": 100}\n    ]\n}]\n```\n\n### 支持以下数据类型\n* number 数字类型。\n* boolean  布尔。\n* string 字符串。\n* date 日期类型。\n* object 简单对象，暂时不支持对象里面有对象或数组这种。\n* number-array  数字数组。\n* boolean-array  布尔数组。\n* string-array  字符串数组。\n* object-array 对象数组。\n* id 主键类型(当表中有这个类型的时候，json会以map格式输出，否则以数组格式输出)。\n\n### 表头规则\n* 基本数据类型(string,number,bool)时候，一般不需要设置会自动判断，但是也可以明确声明数据类型。\n* 字符串类型：命名形式 `列名#string` 。\n* 数字类型：命名形式 `列名#number` 。\n* 日期类型：`列名#date` 。日期格式要符合标准日期格式。比如`YYYY/M/D H:m:s` or `YYYY/M/D` 等等。\n* 布尔类型：命名形式 `列名#bool` 。\n* 基本类型数组：命名形式 `列名#[]`，数组元素默认用逗号分隔(a,b,c),自定义数组元素分隔符`列名#[]/`(a/b/c)。\n* 对象：命名形式 `列名#{}` 。\n* 对象数组：命名形式`列名#[{}]` 。\n* 主键：命名形式`列名#id` 。\n\n\n### 数据规则\n* 关键符号都是半角符号。\n* 对象属性使用分号`;`分割。\n\n### TODO\n- [ ] 列为数组类型时候，嵌套复杂类型。\n- [ ] 列为对象类型时候，嵌套复杂类型。\n- [ ] 外键支持。\n- [ ] 将主分支的代码合并到npm分支。\n- [x] 数组分隔符的设置放到表头，默认用逗号。\n\n### 感谢\n某些想法也是借鉴了一个clojure的excel转json的开源项目 [excel-to-json](https://github.com/mhaemmerle/excel-to-json)。\n\n### 补充\n* windows/mac/linux都支持。\n* 项目地址 [xlsx2json master](https://github.com/koalaylj/xlsx2json)\n* 如有问题可以到QQ群内讨论：223460081\n* 招募协作开发者，有时间帮助一起维护下这个项目，可以发issue或者到qq群里把你github邮箱告诉我。\n"
  },
  {
    "path": "tools/xlsx2json/config.json",
    "content": "{\n  \"xlsx\": {\n    \"head\": 2,\n    \"src\": \"./excel/**/[^~$]*.xlsx\",\n    \"dest\": \"./json\",\n    \"arraySeparator\": \",\"\n  },\n  \"json\": {\n    \"uglify\": false\n  }\n}\n"
  },
  {
    "path": "tools/xlsx2json/export.bat",
    "content": "@echo off\ntitle [convert excel to json]\nrem echo press any button to start.\nrem @pause > nul\necho start converting ....\nnode index.js --export\ncopy json\\*.json ..\\..\\code\\EVA\\server\\script\\DataTable\\  /y\necho convert over!\n@pause"
  },
  {
    "path": "tools/xlsx2json/export.sh",
    "content": "#!/bin/sh\n\nchmod u+x ./export.sh\nnode index.js --export"
  },
  {
    "path": "tools/xlsx2json/index.js",
    "content": "const xlsx = require('./lib/xlsx-to-json.js');\nconst path = require('path');\nconst glob = require('glob');\nconst config = require('./config.json');\n\n/**\n * all commands\n */\nlet commands = {\n  \"--help\": {\n    \"alias\": [\"-h\"],\n    \"desc\": \"show this help manual.\",\n    \"action\": showHelp\n  },\n  \"--export\": {\n    \"alias\": [\"-e\"],\n    \"desc\": \"export excel to json. --export [files]\",\n    \"action\": exportJson,\n    \"default\": true\n  }\n};\n\nlet alias_map = {}; // mapping of alias_name -> name\nlet parsed_cmds = []; //cmds of parsed out.\n\n// process.on('uncaughtException', function(err) {\n//     console.log('error: ' + err);\n// });\n\n//cache of command's key (\"--help\"...)\nlet keys = Object.keys(commands);\n\nfor (let key in commands) {\n  let alias_array = commands[key].alias;\n  alias_array.forEach((e) => {\n    alias_map[e] = key;\n  });\n}\n\nparsed_cmds = parseCommandLine(process.argv);\n\n// console.log(\"%j\", parsed_cmds);\n\nparsed_cmds.forEach(function(e) {\n  exec(e);\n});\n\n\n/**\n * export json\n * args: --export [cmd_line_args] [.xlsx files list].\n */\nfunction exportJson(args) {\n\n  if (typeof args === 'undefined' || args.length === 0) {\n    glob(config.xlsx.src, function(err, files) {\n      if (err) {\n        console.error(\"exportJson error:\", err);\n        throw err;\n      }\n\n      files.forEach(function(element, index, array) {\n        xlsx.toJson(path.join(__dirname, element), path.join(__dirname, config.xlsx.dest),config);\n      });\n\n    });\n  } else {\n    if (args instanceof Array) {\n      args.forEach(function(element, index, array) {\n        xlsx.toJson(path.join(__dirname, element), path.join(__dirname, config.xlsx.dest),config);\n      });\n    }\n  }\n}\n\n/**\n * show help\n */\nfunction showHelp() {\n  let usage = \"usage: \\n\";\n  for (let p in commands) {\n    if (typeof commands[p] !== \"function\") {\n      usage += \"\\t \" + p + \"\\t \" + commands[p].alias + \"\\t \" + commands[p].desc + \"\\n \";\n    }\n  }\n\n  usage += \"\\nexamples: \";\n  usage += \"\\n\\n $node index.js --export\\n\\tthis will export all files configed to json.\";\n  usage += \"\\n\\n $node index.js --export ./excel/foo.xlsx ./excel/bar.xlsx\\n\\tthis will export foo and bar xlsx files.\";\n\n  console.log(usage);\n}\n\n\n/**************************** parse command line *********************************/\n\n/**\n * execute a command\n */\nfunction exec(cmd) {\n  if (typeof cmd.action === \"function\") {\n    cmd.action(cmd.args);\n  }\n}\n\n\n/**\n * parse command line args\n */\nfunction parseCommandLine(args) {\n\n  let parsed_cmds = [];\n\n  if (args.length <= 2) {\n    parsed_cmds.push(defaultCommand());\n  } else {\n\n    let cli = args.slice(2);\n\n    let pos = 0;\n    let cmd;\n\n    cli.forEach(function(element, index, array) {\n\n      //replace alias name with real name.\n      if (element.indexOf('--') === -1 && element.indexOf('-') === 0) {\n        cli[index] = alias_map[element];\n      }\n\n      //parse command and args\n      if (cli[index].indexOf('--') === -1) {\n        cmd.args.push(cli[index]);\n      } else {\n\n        if (keys[cli[index]] === \"undefined\") {\n          throw new Error(\"not support command:\" + cli[index]);\n        }\n\n        pos = index;\n        cmd = commands[cli[index]];\n        if (typeof cmd.args === 'undefined') {\n          cmd.args = [];\n        }\n        parsed_cmds.push(cmd);\n      }\n    });\n  }\n\n  return parsed_cmds;\n}\n\n/**\n * default command when no command line argas provided.\n */\nfunction defaultCommand() {\n  if (keys.length <= 0) {\n    throw new Error(\"Error: there is no command at all!\");\n  }\n\n  for (let p in commands) {\n    if (commands[p][\"default\"]) {\n      return commands[p];\n    }\n  }\n\n  if (keys[\"--help\"]) {\n    return commands[\"--help\"];\n  } else {\n    return commands[keys[0]];\n  }\n}\n\n/*************************************************************************/\n"
  },
  {
    "path": "tools/xlsx2json/lib/xlsx-to-json.js",
    "content": "const xlsx = require('node-xlsx');\nconst fs = require('fs');\nconst path = require('path');\n// const moment = require('moment');\n\nlet arraySeparator;\n\n/**\n * sheet(table) 的类型\n * 影响输出json的类型\n * 当有#id类型的时候  表输出json的是map形式(id:{xx:1})\n * 当没有#id类型的时候  表输出json的是数组类型 没有id索引\n */\nconst SheetType = {\n  /**\n   * 普通表\n   */\n  NORMAL: 0,\n\n  /**\n   * 有主外键关系的主表\n   * primary key\n   */\n  PRIMARY: 1,\n\n  /**\n   * 有主外键关系的附表\n   * foreign key\n   */\n  FOREIGN: 2\n};\n\n/**\n * 支持的数据类型\n */\nconst DataType = {\n  NUMBER: 'number',\n  STRING: 'string',\n  BOOL: 'bool',\n  DATE: 'date',\n  ID: 'id',\n  ARRAY: '[]',\n  OBJECT: '{}',\n  OBJECT_ARRAY: '[{}]',\n  UNKOWN: 'unkown'\n};\n\nmodule.exports = {\n\n  /**\n   * convert xlsx file to json and save it to file system.\n   * @param  {String} src path of .xlsx files.\n   * @param  {String} dest       directory for exported json files.\n   * @param  {Number} headIndex      index of head line.\n   * @param  {String} separator      array separator.\n   *\n   * excel structure\n   * workbook > worksheet > table(row column)\n   */\n  toJson: function(src, dest, config) {\n\n    let headIndex = config.xlsx.head - 1;\n    arraySeparator = config.xlsx.arraySeparator;\n    let uglifyJson = config.json.uglify;\n\n    if (!fs.existsSync(dest)) {\n      fs.mkdirSync(dest);\n    }\n\n    console.log(\"parsing excel:\", src);\n\n    let workbook = xlsx.parse(src);\n    parseWorkbook(workbook, dest, headIndex, uglifyJson);\n  }\n};\n\n/**\n * convert worksheet in workbook and save to file for each.\n * @param       {[Object]} workbook json object of excel's workbook.\n * @param       {[String]} dest     directory for exported json files.\n * @param       {[Number]} headIndex     index of head line.\n */\nfunction parseWorkbook(workbook, dest, headIndex, uglifyJson) {\n\n  workbook.forEach(sheet => {\n\n    // ignore sheet with external keys only, or start with a '#'\n    if (sheet.name.indexOf('@') === -1 && sheet.name[0] !== \"#\") {\n      let parsedSheet = parseSheet(sheet, headIndex);\n\n      let dest_file = path.resolve(dest, sheet.name + \".json\");\n      let formatedJson = JSON.stringify(parsedSheet, null, uglifyJson ? 0 : 2); //, null, 2\n      fs.writeFile(dest_file, formatedJson, err => {\n        if (err) {\n          console.error(\"error：\", err);\n          throw err;\n        }\n        console.log('exported successfully  -->  ', path.basename(dest_file));\n      });\n    }\n  });\n}\n\n/**\n * parse one sheet and return the result as a json object or array\n *\n * @param sheet\n * @param headIndex\n * @private\n */\nfunction parseSheet(sheet, headIndex) {\n\n  console.log('\\t parsing sheet', sheet.name);\n\n  if (sheet && sheet.data) {\n\n    let head = parseHead(sheet, headIndex);\n\n    let result;\n\n    if (head.sheetType === SheetType.NORMAL) {\n      result = [];\n    } else if (head.sheetType === SheetType.PRIMARY) {\n      result = {};\n    }\n\n    for (let i_row = headIndex + 1; i_row < sheet.data.length; i_row++) {\n\n      let row = sheet.data[i_row];\n\n      let parsedRow = parseRow(row, i_row, head);\n      if (head.sheetType === SheetType.NORMAL) { ////json以数组的格式输出\n        result.push(parsedRow);\n      } else if (head.sheetType === SheetType.PRIMARY) { //json以map的格式输出\n        let id = parsedRow[head.getIdKey()];\n        result[id] = parsedRow;\n      } else {\n        throw '无法识别表格类型!';\n      }\n    }\n    return result;\n  }\n}\n\nfunction parseHead(sheet, headIndex) {\n\n  let headRow = sheet.data[headIndex];\n\n  // console.log(\"\\t\\t parsing head\", headIndex, headRow);\n\n  let head = {\n    //所有名字 json的key\n    names: [],\n\n    //所有列的数据类型\n    types: [],\n\n    //表头所在的行索引\n    index: headIndex,\n\n    //表类型 普通表  主表 引用表\n    sheetType: SheetType.NORMAL,\n\n    getIdKey: function() {\n      let id_col_index = this.types.indexOf(DataType.ID);\n      if (id_col_index < 0) {\n        throw '获取不到id列的名字';\n      }\n      return this.names[id_col_index];\n    }\n  };\n\n  headRow.forEach(cell => {\n    let type = DataType.UNKOWN;\n    let name = cell;\n\n    if ((cell + '').indexOf('#') !== -1) {\n      let pair = cell.split('#');\n      name = pair[0].trim();\n      type = pair[1].toLowerCase().trim();\n      if (type === DataType.ID) {\n        head.sheetType = SheetType.PRIMARY;\n      }\n    }\n\n    head.types.push(type);\n    head.names.push(name);\n  });\n\n  return head;\n}\n\nfunction parseRow(row, rowIndex, head) {\n\n  let result = {};\n  let id;\n\n  console.log('parsing row', row);\n\n  row.forEach((cell, index) => {\n\n    // if (cell) {\n\n    let name = head.names[index];\n    let type = head.types[index];\n\n    switch (type) {\n      case DataType.ID: // number string boolean\n        if (isNumber(cell)) {\n          id = Number(cell);\n        } else {\n          id = cell;\n        }\n        result[name] = id;\n        break;\n      case DataType.UNKOWN: // number string boolean\n        if (isNumber(cell)) {\n          result[name] = Number(cell);\n        } else if (isBoolean(cell)) {\n          result[name] = toBoolean(cell);\n        } else {\n          if (cell) {\n            result[name] = cell;\n          }\n        }\n        break;\n      case DataType.DATE:\n        if (isNumber(cell)) {\n          //xlsx's bug!!!\n          result[name] = numdate(cell);\n        } else {\n          if (cell) {\n            result[name] = cell.toString();\n          }\n        }\n        break;\n      case DataType.STRING:\n        result[name] = cell.toString();\n        break;\n      case DataType.NUMBER:\n        //+xxx.toString() '+' means convert it to number\n        if (isNumber(cell)) {\n          result[name] = Number(cell);\n        } else {\n          console.warn(\"type error at [\" + rowIndex + \",\" + index + \"],\" + cell + \" is not a number\");\n        }\n        break;\n      case DataType.BOOL:\n        result[name] = toBoolean(cell);\n        break;\n      case DataType.OBJECT: //support {number boolean string date} property type\n        if (cell) {\n          result[name] = array2object(cell.split(';'));\n        }\n        break;\n      case DataType.ARRAY: //[number] [boolean] [string]  todo:support [date] type\n        result[name] = parseBasicArrayField(cell, arraySeparator);\n        break;\n      case DataType.OBJECT_ARRAY:\n        result[name] = parseObjectArrayField(cell);\n        break;\n      default:\n        // foo#[]| 处理自定义数组分隔符\n        if (type.indexOf(DataType.ARRAY) !== -1) {\n          // if (!type.endsWith(DataType.ARRAY)) {\n          let separator = type.substr(-1, 1); //get the last character\n          result[name] = parseBasicArrayField(cell, separator);\n          // }\n        } else {\n          console.log('unrecognized type', '[' + rowIndex + ',' + index + ']', cell, typeof(cell));\n        }\n        break;\n    }\n    // }\n  });\n\n  return result;\n\n  // switch (head.sheetType) {\n  //   case SheetType.NORMAL: //json以数组的格式输出\n  //     return result;\n  //   case SheetType.PRIMARY: //json以map的格式输出\n  //     let map = {};\n  //     map[id] = result;\n  //     return map;\n  //   default:\n  //     throw '无法识别表格类型!';\n  // }\n\n  // return result;\n}\n\n/**\n * parse object array.\n */\nfunction parseObjectArrayField(value) {\n\n  let obj_array = [];\n\n  if (value) {\n    if (value.indexOf(',') !== -1) {\n      obj_array = value.split(',');\n    } else {\n      obj_array.push(value.toString());\n    }\n  }\n\n  // if (typeof(value) === 'string' && value.indexOf(',') !== -1) {\n  //     obj_array = value.split(',');\n  // } else {\n  //     obj_array.push(value.toString());\n  // };\n\n  let result = [];\n\n  obj_array.forEach(function(e) {\n    if (e) {\n      result.push(array2object(e.split(';')));\n    }\n  });\n\n  // row[key] = result;\n  return result;\n}\n\n/**\n * parse object from array.\n *  for example : [a:123,b:45] => {'a':123,'b':45}\n */\nfunction array2object(array) {\n  let result = {};\n  array.forEach(function(e) {\n    if (e) {\n      let colonIndex = e.indexOf(':');\n      let key = e.substring(0, colonIndex);\n      let value = e.substring(colonIndex + 1);\n      if (isNumber(value)) {\n        value = Number(value);\n      } else if (isBoolean(value)) {\n        value = toBoolean(value);\n      }\n      result[key] = value;\n    }\n  });\n  return result;\n}\n\n/**\n * parse simple array.\n */\nfunction parseBasicArrayField(array, arraySeparator) {\n  let basic_array;\n\n  if (typeof array === \"string\") {\n    basic_array = array.split(arraySeparator);\n  } else {\n    basic_array = [];\n    basic_array.push(array);\n  }\n\n  let result = [];\n  if (isNumberArray(basic_array)) {\n    basic_array.forEach(function(element) {\n      result.push(Number(element));\n    });\n  } else if (isBooleanArray(basic_array)) {\n    basic_array.forEach(function(element) {\n      result.push(toBoolean(element));\n    });\n  } else { //string array\n    result = basic_array;\n  }\n  // console.log(\"basic_array\", result + \"|||\" + cell.value);\n  // field[key] = result;\n  return result;\n}\n\n/**\n * convert value to boolean.\n */\nfunction toBoolean(value) {\n  return value.toString().toLowerCase() === 'true';\n}\n\n/**\n * is a boolean array.\n */\nfunction isBooleanArray(arr) {\n  return arr.every(function(element, index, array) {\n    return isBoolean(element);\n  });\n}\n\n/**\n * is a number array.\n */\nfunction isNumberArray(arr) {\n  return arr.every(function(element, index, array) {\n    return isNumber(element);\n  });\n}\n\n/**\n * is a number.\n */\nfunction isNumber(value) {\n\n  if (typeof value === 'number') {\n    return true;\n  }\n\n  if (value) {\n    return !isNaN(+value.toString());\n  }\n\n  return false;\n}\n\n/**\n * boolean type check.\n */\nfunction isBoolean(value) {\n\n  if (typeof(value) === \"undefined\") {\n    return false;\n  }\n\n  if (typeof value === 'boolean') {\n    return true;\n  }\n\n  let b = value.toString().trim().toLowerCase();\n\n  return b === 'true' || b === 'false';\n}\n\n/**\n * date type check.\n */\n// function isDateType(value) {\n//   if (isNumber(value)) {\n//     return false;\n//   }\n//   if (value) {\n//     return moment(new Date(value), \"YYYY-M-D\", true).isValid() || moment(value, \"YYYY-M-D H:m:s\", true).isValid() || moment(value, \"YYYY/M/D H:m:s\", true).isValid() || moment(value, \"YYYY/M/D\", true).isValid();\n//   }\n//   return false;\n// }\n\n//fuck xlsx's bug\nvar basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000\n// var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;\nvar dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;\n// function datenum(v, date1904) {\n// \tvar epoch = v.getTime();\n// \tif(date1904) epoch -= 1462*24*60*60*1000;\n// \treturn (epoch - dnthresh) / (24 * 60 * 60 * 1000);\n// }\n\nfunction numdate(v) {\n  var out = new Date();\n  out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);\n  return out;\n}\n//fuck over\n"
  },
  {
    "path": "tools/xlsx2json/package.json",
    "content": "{\n  \"name\": \"xlsx2json\",\n  \"main\": \"index.js\",\n  \"version\": \"0.3.0\",\n  \"description\": \"convert complex xlsx to json\",\n  \"homepage\": \"https://github.com/koalaylj/xlsx2json\",\n  \"author\": \"于小懒\",\n  \"licenses\": \"MIT\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/koalaylj/xlsx2json.git\"\n  },\n  \"keywords\": [\n    \"xlsx\",\n    \"excel\",\n    \"json\",\n    \"convert\",\n    \"game developer\",\n    \"mongo\"\n  ],\n  \"scripts\": {\n    \"test\": \"mocha ./test/test.js\"\n  },\n  \"dependencies\": {\n    \"glob\": \"3.2.9\",\n    \"minimatch\": \"~3.0.4\",\n    \"moment\": \"^2.19.1\",\n    \"node-xlsx\": \"^0.11.0\",\n    \"xlsx\": \"^0.11.6\"\n  }\n}\n"
  }
]